get('doctrine')->getManager(); } /** * Cree un client authentifie via /login_check. La configuration du projet * pose le JWT dans un cookie HTTP-only `BEARER` (cf. lexik_jwt_authentication.yaml) * et retire le token du body de reponse ; le client BrowserKit persiste * automatiquement le cookie pour les requetes suivantes. */ protected function authenticatedClient(string $username, string $password): Client { $client = self::createClient(); $response = $client->request('POST', '/login_check', [ 'headers' => ['Content-Type' => 'application/json'], 'json' => ['username' => $username, 'password' => $password], ]); self::assertContains( $response->getStatusCode(), [200, 204], 'Login failed for '.$username.': '.$response->getStatusCode(), ); return $client; } /** * Cree un utilisateur non-admin portant une permission specifique via un * role custom jetable. A utiliser dans les tests fonctionnels qui doivent * prouver qu'un non-admin avec la permission requise obtient 200, et * sans la permission obtient 403. * * Le user et le role sont persistes avec un suffixe aleatoire pour eviter * les collisions inter-tests. Le password est "testpass". * * Prerequis : la permission identifiee par $permissionCode doit exister en * base (seeder via `app:sync-permissions`). Si elle est introuvable, le test * echoue immediatement avec un message explicite. * * @param string $permissionCode Le code de la permission (ex: "core.users.view") * * @return array{username: string, password: string} Les identifiants pour authenticatedClient() */ protected function createUserWithPermission(string $permissionCode): array { if (!self::$kernel) { self::bootKernel(); } $em = $this->getEm(); /** @var null|Permission $permission */ $permission = $em->getRepository(Permission::class)->findOneBy(['code' => $permissionCode]); self::assertNotNull( $permission, sprintf( 'Permission "%s" introuvable en base. Assurez-vous que `app:sync-permissions` a ete execute.', $permissionCode, ), ); $suffix = substr(bin2hex(random_bytes(4)), 0, 8); $username = 'testuser_'.$suffix; $password = 'testpass'; /** @var UserPasswordHasherInterface $hasher */ $hasher = self::getContainer()->get(UserPasswordHasherInterface::class); $role = new Role('test_'.$suffix, 'Test Role '.$suffix, false); $role->addPermission($permission); $em->persist($role); $user = new User(); $user->setUsername($username); $user->setIsAdmin(false); $user->setPassword($hasher->hashPassword($user, $password)); $user->addRbacRole($role); $em->persist($user); $em->flush(); $em->clear(); return ['username' => $username, 'password' => $password]; } /** * Skip le test courant si le module Sites est desactive dans * `config/modules.php` de l'environnement de test. * * Mecanisme : on cherche la permission `sites.view` en base. Si le * module Sites est desactive, `app:sync-permissions` aura marque cette * permission comme orpheline et l'aura supprimee de la table — donc * `findOneBy(['code' => 'sites.view'])` renvoie null. * * Quand utiliser ce helper : tests qui s'appuient sur * `createUserWithPermission('sites.*')`. Les tests qui utilisent * uniquement l'admin (qui bypass via isAdmin) n'en ont pas besoin : * la classe Site reste mappee Doctrine et exposee via API Platform * meme module desactive (mapping inconditionnel, decision assumee * ticket 1). */ protected function skipIfSitesModuleDisabled(): void { if (!self::$kernel) { self::bootKernel(); } $perm = $this->getEm() ->getRepository(Permission::class) ->findOneBy(['code' => 'sites.view']) ; if (null === $perm) { self::markTestSkipped('Module Sites desactive : permission sites.view introuvable en base.'); } } }