addOption('count', null, InputOption::VALUE_OPTIONAL, 'Number of demo albums to create', 40) ->addOption('attach-users', null, InputOption::VALUE_NONE, 'If set, randomly assigns existing users as creators'); } protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); $count = max(1, (int) $input->getOption('count')); $attachUsers = (bool) $input->getOption('attach-users'); $users = $attachUsers ? $this->userRepository->findAll() : []; $created = 0; // Track generated localIds so we never attempt to persist obvious duplicates. $seenLocalIds = []; while ($created < $count) { // Generate a localId that is unique in-memory and in the database to avoid constraint violations. $localId = $this->generateLocalId(); if (isset($seenLocalIds[$localId]) || $this->albumRepository->findOneBy(['localId' => $localId]) !== null) { // Only accept IDs that are unique both in-memory and in the DB to avoid constraint errors. continue; } $album = new Album(); $album->setSource('user'); $album->setLocalId($localId); $album->setName($this->generateAlbumName()); $album->setArtists($this->generateArtists()); $album->setGenres($this->generateGenres()); $album->setReleaseDate($this->generateReleaseDate()); $album->setTotalTracks(random_int(6, 16)); $album->setCoverUrl($this->generateCoverUrl($localId)); $album->setExternalUrl(sprintf('https://example.com/demo-albums/%s', $localId)); if ($attachUsers && $users !== []) { /** @var User $user */ $user = $users[array_rand($users)]; $album->setCreatedBy($user); } $this->entityManager->persist($album); $seenLocalIds[$localId] = true; $created++; } $this->entityManager->flush(); $io->success(sprintf('Created %d demo albums%s.', $created, $attachUsers ? ' with random owners' : '')); return Command::SUCCESS; } private function generateLocalId(): string { return 'demo_' . bin2hex(random_bytes(4)); } private function generateAlbumName(): string { $adj = self::ADJECTIVES[random_int(0, count(self::ADJECTIVES) - 1)]; $noun = self::NOUNS[random_int(0, count(self::NOUNS) - 1)]; $genre = self::GENRES[random_int(0, count(self::GENRES) - 1)]; return sprintf('%s %s of %s', $adj, $noun, $genre); } /** * @return list */ private function generateArtists(): array { $artists = []; $artistCount = random_int(1, 3); for ($i = 0; $i < $artistCount; $i++) { $artists[] = sprintf( '%s %s', self::ADJECTIVES[random_int(0, count(self::ADJECTIVES) - 1)], self::NOUNS[random_int(0, count(self::NOUNS) - 1)] ); } return array_values(array_unique($artists)); } private function generateReleaseDate(): string { $year = random_int(1990, (int) date('Y')); $month = random_int(1, 12); $day = random_int(1, 28); return sprintf('%04d-%02d-%02d', $year, $month, $day); } /** * @return list */ private function generateGenres(): array { $count = random_int(1, 3); $genres = []; for ($i = 0; $i < $count; $i++) { $genres[] = self::GENRES[random_int(0, count(self::GENRES) - 1)]; } return array_values(array_unique($genres)); } private function generateCoverUrl(string $seed): string { return sprintf('https://picsum.photos/seed/%s/640/640', $seed); } }