authenticatedClient('alice', 'alice'); $response = $client->request('GET', '/api/me'); self::assertResponseIsSuccessful(); $data = $response->toArray(); self::assertArrayHasKey('sites', $data); self::assertIsArray($data['sites']); self::assertCount(1, $data['sites']); $firstSite = $data['sites'][0]; self::assertIsArray($firstSite, 'Un site doit etre serialise en objet, pas en IRI string.'); self::assertArrayHasKey('id', $firstSite); self::assertArrayHasKey('name', $firstSite); self::assertArrayHasKey('street', $firstSite); self::assertArrayHasKey('city', $firstSite); self::assertArrayHasKey('color', $firstSite); // Le getter computed est expose en lecture pour eviter au front // de redupliquer la logique de concatenation. self::assertArrayHasKey('fullAddress', $firstSite); self::assertSame('Chatellerault', $firstSite['name']); // Garde anti-cycle (cf. Site::$users sans Groups, ticket 2 spec // section 12 risque 6) : la collection inverse ne doit JAMAIS etre // serialisee dans /api/me sous peine de boucle infinie // User → sites → users → sites → ... self::assertArrayNotHasKey( 'users', $firstSite, 'Site.users ne doit JAMAIS etre serialise dans /api/me (cycle infini).', ); } public function testMeExposesCurrentSiteAsObject(): void { $client = $this->authenticatedClient('alice', 'alice'); $response = $client->request('GET', '/api/me'); self::assertResponseIsSuccessful(); $data = $response->toArray(); self::assertArrayHasKey('currentSite', $data); self::assertIsArray($data['currentSite'], 'currentSite doit etre un objet, pas une IRI.'); self::assertSame('Chatellerault', $data['currentSite']['name']); } public function testAdminHasAllThreeSites(): void { $client = $this->authenticatedClient('admin', 'admin'); $response = $client->request('GET', '/api/me'); $data = $response->toArray(); self::assertCount(3, $data['sites']); $names = array_column($data['sites'], 'name'); sort($names); self::assertSame(['Chatellerault', 'Pommevic', 'Saint-Jean'], $names); } public function testUserWithoutSitesHasEmptyArrayAndNullCurrent(): void { // Creer un user jetable sans rattachement a un site. $em = $this->getEm(); $suffix = substr(bin2hex(random_bytes(4)), 0, 8); $username = 'orphan_'.$suffix; $hasher = self::getContainer()->get('security.user_password_hasher'); $user = new User(); $user->setUsername($username); $user->setIsAdmin(false); $user->setPassword($hasher->hashPassword($user, 'testpass')); $em->persist($user); $em->flush(); try { $client = $this->authenticatedClient($username, 'testpass'); $response = $client->request('GET', '/api/me'); self::assertResponseIsSuccessful(); $data = $response->toArray(); self::assertSame([], $data['sites']); self::assertNull($data['currentSite']); } finally { $em = $this->getEm(); $reloaded = $em->getRepository(User::class)->findOneBy(['username' => $username]); if (null !== $reloaded) { $em->remove($reloaded); $em->flush(); } } } }