$topTagSlugs Top tag slugs by weighted score (up to 20) * @param array $topCategorySlugs Top category slugs (up to 5) * @param array $strongCreatorIds Followed creator user IDs (up to 50) * @param array $tagWeights Tag slug → normalised weight (0–1) * @param array $categoryWeights Category slug → normalised weight * @param array $dislikedTagSlugs Future: blocked/hidden tag slugs */ public function __construct( public readonly array $topTagSlugs = [], public readonly array $topCategorySlugs = [], public readonly array $strongCreatorIds = [], public readonly array $tagWeights = [], public readonly array $categoryWeights = [], public readonly array $dislikedTagSlugs = [], ) {} /** * True if the user has enough signals to drive personalised recommendations. */ public function hasSignals(): bool { return $this->topTagSlugs !== [] || $this->strongCreatorIds !== []; } /** * Returns the normalised tag weight for a given slug (0.0 if unknown). */ public function tagWeight(string $slug): float { return (float) ($this->tagWeights[$slug] ?? 0.0); } /** * Returns true when the creator is in the user's strong-follow list. */ public function followsCreator(int $userId): bool { return in_array($userId, $this->strongCreatorIds, true); } /** * Serialise for storage in the DB / Redis cache. * * @return array */ public function toArray(): array { return [ 'top_tags' => $this->topTagSlugs, 'top_categories' => $this->topCategorySlugs, 'strong_creators' => $this->strongCreatorIds, 'tag_weights' => $this->tagWeights, 'category_weights' => $this->categoryWeights, 'disliked_tags' => $this->dislikedTagSlugs, ]; } /** * Re-hydrate from a stored array (e.g. from the DB JSON column). * * @param array $data */ public static function fromArray(array $data): self { return new self( topTagSlugs: (array) ($data['top_tags'] ?? []), topCategorySlugs: (array) ($data['top_categories'] ?? []), strongCreatorIds: array_map('intval', (array) ($data['strong_creators'] ?? [])), tagWeights: array_map('floatval', (array) ($data['tag_weights'] ?? [])), categoryWeights: array_map('floatval', (array) ($data['category_weights'] ?? [])), dislikedTagSlugs: (array) ($data['disliked_tags'] ?? []), ); } }