From 4834eadc186f5274e4b803f7ab1ff93cf11e6367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 10 Oct 2022 20:33:45 +0200 Subject: [PATCH] Feature: do not show desactivated Scope in ScopePickerType --- .../Form/Type/ScopePickerType.php | 79 +++-------- .../Tests/Form/Type/ScopePickerTypeTest.php | 127 ++++++++++++++++++ 2 files changed, 145 insertions(+), 61 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Tests/Form/Type/ScopePickerTypeTest.php diff --git a/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php b/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php index 06f6019d7..1cba1ba58 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php @@ -15,9 +15,9 @@ use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Form\DataMapper\ScopePickerDataMapper; -use Chill\MainBundle\Repository\ScopeRepository; use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; -use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; +use RuntimeException; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\HiddenType; @@ -26,11 +26,9 @@ use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Role\Role; -use Symfony\Component\Security\Core\Security; -use function array_map; +use Symfony\Component\Security\Core\Security; use function count; /** @@ -44,47 +42,37 @@ use function count; */ class ScopePickerType extends AbstractType { - protected AuthorizationHelperInterface $authorizationHelper; + private AuthorizationHelperInterface $authorizationHelper; - /** - * @var ScopeRepository - */ - protected $scopeRepository; + private Security $security; - protected Security $security; - - /** - * @var TokenStorageInterface - */ - protected $tokenStorage; - - /** - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; + private TranslatableStringHelperInterface $translatableStringHelper; public function __construct( AuthorizationHelperInterface $authorizationHelper, - TokenStorageInterface $tokenStorage, - ScopeRepository $scopeRepository, Security $security, - TranslatableStringHelper $translatableStringHelper + TranslatableStringHelperInterface $translatableStringHelper ) { $this->authorizationHelper = $authorizationHelper; - $this->tokenStorage = $tokenStorage; - $this->scopeRepository = $scopeRepository; $this->security = $security; $this->translatableStringHelper = $translatableStringHelper; } public function buildForm(FormBuilderInterface $builder, array $options) { - $items = $this->authorizationHelper->getReachableScopes( - $this->security->getUser(), - $options['role'] instanceof Role ? $options['role']->getRole() : $options['role'], - $options['center'] + $items = array_filter( + $this->authorizationHelper->getReachableScopes( + $this->security->getUser(), + $options['role'] instanceof Role ? $options['role']->getRole() : $options['role'], + $options['center'] + ), + static function (Scope $s) { return $s->isActive(); } ); + if (0 === count($items)) { + throw new RuntimeException('no scopes are reachable. This form should not be shown to user'); + } + if (1 !== count($items)) { $builder->add('scope', EntityType::class, [ 'class' => Scope::class, @@ -123,35 +111,4 @@ class ScopePickerType extends AbstractType ->setRequired('role') ->setAllowedTypes('role', ['string', Role::class]); } - - /** - * @param array|Center|Center[] $center - * @param string $role - * - * @return \Doctrine\ORM\QueryBuilder - */ - protected function buildAccessibleScopeQuery($center, $role) - { - $roles = $this->authorizationHelper->getParentRoles($role); - $roles[] = $role; - $centers = $center instanceof Center ? [$center] : $center; - - $qb = $this->scopeRepository->createQueryBuilder('s'); - $qb - // jointure to center - ->join('s.roleScopes', 'rs') - ->join('rs.permissionsGroups', 'pg') - ->join('pg.groupCenters', 'gc') - // add center constraint - ->where($qb->expr()->in('IDENTITY(gc.center)', ':centers')) - ->setParameter('centers', array_map(static fn (Center $c) => $c->getId(), $centers)) - // role constraints - ->andWhere($qb->expr()->in('rs.role', ':roles')) - ->setParameter('roles', $roles) - // user contraint - ->andWhere(':user MEMBER OF gc.users') - ->setParameter('user', $this->tokenStorage->getToken()->getUser()); - - return $qb; - } } diff --git a/src/Bundle/ChillMainBundle/Tests/Form/Type/ScopePickerTypeTest.php b/src/Bundle/ChillMainBundle/Tests/Form/Type/ScopePickerTypeTest.php new file mode 100644 index 000000000..869bbfeae --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Form/Type/ScopePickerTypeTest.php @@ -0,0 +1,127 @@ +factory->create(ScopePickerType::class, null, [ + 'center' => new Center(), + 'role' => 'ONE_SCOPE', + ]); + + $view = $form->createView(); + + $this->assertContains('hidden', $view['scope']->vars['block_prefixes']); + } + + public function testBuildThreeScopesIsSuccessful() + { + $form = $this->factory->create(ScopePickerType::class, null, [ + 'center' => new Center(), + 'role' => 'THREE_SCOPE', + ]); + + $view = $form->createView(); + + $this->assertContains('entity', $view['scope']->vars['block_prefixes']); + } + + public function testBuildTwoScopesIsSuccessful() + { + $form = $this->factory->create(ScopePickerType::class, null, [ + 'center' => new Center(), + 'role' => 'TWO_SCOPE', + ]); + + $view = $form->createView(); + + $this->assertContains('entity', $view['scope']->vars['block_prefixes']); + } + + protected function getExtensions() + { + $user = new User(); + $role1Scope = 'ONE_SCOPE'; + $role2Scope = 'TWO_SCOPE'; + $role3Scope = 'THREE_SCOPE'; + $scopeA = (new Scope())->setName(['fr' => 'scope a']); + $scopeB = (new Scope())->setName(['fr' => 'scope b']); + $scopeC = (new Scope())->setName(['fr' => 'scope b'])->setActive(false); + + $authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class); + $authorizationHelper->getReachableScopes($user, $role1Scope, Argument::any()) + ->willReturn([$scopeA]); + $authorizationHelper->getReachableScopes($user, $role2Scope, Argument::any()) + ->willReturn([$scopeA, $scopeB]); + $authorizationHelper->getReachableScopes($user, $role3Scope, Argument::any()) + ->willReturn([$scopeA, $scopeB, $scopeC]); + + $security = $this->prophesize(Security::class); + $security->getUser()->willReturn($user); + + $translatableStringHelper = $this->prophesize(TranslatableStringHelperInterface::class); + $translatableStringHelper->localize(Argument::type('array'))->will( + static function ($args) { return $args[0]['fr']; } + ); + + $type = new ScopePickerType( + $authorizationHelper->reveal(), + $security->reveal(), + $translatableStringHelper->reveal() + ); + + // add the mocks for creating EntityType + $entityManager = DoctrineTestHelper::createTestEntityManager(); + $em = $this->prophesize(EntityManagerInterface::class); + $em->getClassMetadata(Scope::class)->willReturn($entityManager->getClassMetadata(Scope::class)); + $em->contains(Argument::type(Scope::class))->willReturn(true); + $em->initializeObject(Argument::type(Scope::class))->willReturn(null); + $emRevealed = $em->reveal(); + $managerRegistry = $this->prophesize(ManagerRegistry::class); + $managerRegistry->getManager(Argument::any())->willReturn($emRevealed); + $managerRegistry->getManagerForClass(Scope::class)->willReturn($emRevealed); + + $entityType = $this->prophesize(EntityType::class); + $entityType->getParent()->willReturn(ChoiceType::class); + + return [ + new PreloadedExtension([$type], []), + new DoctrineOrmExtension($managerRegistry->reveal()), + ]; + } +}