mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-10-31 01:08:26 +00:00 
			
		
		
		
	
							
								
								
									
										161
									
								
								Form/Type/PickPersonType.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								Form/Type/PickPersonType.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,161 @@ | ||||
| <?php | ||||
|  | ||||
| /* | ||||
|  * Copyright (C) 2016 Champs-Libres <info@champs-libres.coop> | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\PersonBundle\Form\Type; | ||||
|  | ||||
| use Symfony\Component\Form\AbstractType; | ||||
| use Symfony\Component\Form\FormBuilderInterface; | ||||
| use Symfony\Component\OptionsResolver\OptionsResolver; | ||||
| use Chill\MainBundle\Entity\Center; | ||||
| use Chill\PersonBundle\Entity\PersonRepository; | ||||
| use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | ||||
| use Chill\MainBundle\Security\Authorization\AuthorizationHelper; | ||||
| use Symfony\Component\Security\Core\Exception\AccessDeniedException; | ||||
| use Symfony\Component\Security\Core\Role\Role; | ||||
| use Chill\MainBundle\Entity\GroupCenter; | ||||
| use Chill\PersonBundle\Entity\Person; | ||||
|  | ||||
| /** | ||||
|  * This type allow to pick a person. | ||||
|  *  | ||||
|  * The form is embedded in a select2 input. | ||||
|  *  | ||||
|  * The people may be filtered :  | ||||
|  *  | ||||
|  * - with the `centers` option, only the people associated with the given center(s) | ||||
|  * are seen. May be an instance of `Chill\MainBundle\Entity\Center`, or an array of  | ||||
|  * `Chill\MainBundle\Entity\Center`. By default, all the reachable centers as selected. | ||||
|  * - with the `role` option, only the people belonging to the reachable center for the | ||||
|  * given role are displayed. | ||||
|  *  | ||||
|  * | ||||
|  * @author Julien Fastré <julien.fastre@champs-libres.coop> | ||||
|  */ | ||||
| class PickPersonType extends AbstractType | ||||
| { | ||||
|     /** | ||||
|      * @var PersonRepository | ||||
|      */ | ||||
|     protected $personRepository; | ||||
|      | ||||
|     /** | ||||
|      * | ||||
|      * @var \Chill\MainBundle\Entity\User | ||||
|      */ | ||||
|     protected $user; | ||||
|      | ||||
|     /** | ||||
|      * | ||||
|      * @var AuthorizationHelper | ||||
|      */ | ||||
|     protected $authorizationHelper; | ||||
|      | ||||
|     public function __construct( | ||||
|             PersonRepository $personRepository, | ||||
|             TokenStorageInterface $tokenStorage, | ||||
|             AuthorizationHelper $authorizationHelper | ||||
|             ) | ||||
|     { | ||||
|         $this->personRepository = $personRepository; | ||||
|         $this->user = $tokenStorage->getToken()->getUser(); | ||||
|         $this->authorizationHelper = $authorizationHelper; | ||||
|     } | ||||
|      | ||||
|     public function buildForm(FormBuilderInterface $builder, array $options) | ||||
|     { | ||||
|         $qb = $options['query_builder']; | ||||
|          | ||||
|         if ($options['role'] === NULL) { | ||||
|             $centers = array_map(function (GroupCenter $g) {  | ||||
|                  | ||||
|                 return $g->getCenter();  | ||||
|             }, $this->user->getGroupCenters()->toArray()); | ||||
|         } else { | ||||
|             $centers = $this->authorizationHelper | ||||
|                     ->getReachableCenters($this->user, $options['role']); | ||||
|         } | ||||
|          | ||||
|         if ($options['centers'] === NULL) { | ||||
|             // we select all selected centers | ||||
|             $selectedCenters = $centers; | ||||
|         } else { | ||||
|             $selectedCenters = array(); | ||||
|             $options['centers'] = is_array($options['centers']) ? | ||||
|                     $options['centers'] : array($options['centers']); | ||||
|              | ||||
|             foreach ($options['centers'] as $c) { | ||||
|                 // check that every member of the array is a center | ||||
|                 if (!$c instanceof Center) {  | ||||
|                     throw new \RuntimeException('Every member of the "centers" ' | ||||
|                             . 'option must be an instance of '.Center::class); | ||||
|                 } | ||||
|                 if (!in_array($c->getId(), array_map( | ||||
|                         function(Center $c) { return $c->getId();}, | ||||
|                         $centers))) { | ||||
|                     throw new AccessDeniedException('The given center is not reachable'); | ||||
|                 } | ||||
|                 $selectedCenters[] = $c; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|          | ||||
|         $qb | ||||
|                 ->orderBy('p.firstName', 'ASC') | ||||
|                 ->orderBy('p.lastName', 'ASC') | ||||
|                 ->where($qb->expr()->in('p.center', ':centers')) | ||||
|                 ->setParameter('centers', $selectedCenters) | ||||
|                 ; | ||||
|     } | ||||
|      | ||||
|     public function configureOptions(OptionsResolver $resolver) | ||||
|     { | ||||
|         parent::configureOptions($resolver); | ||||
|          | ||||
|         // add the possibles options for this type | ||||
|         $resolver->setDefined('centers') | ||||
|                 ->addAllowedTypes('centers', array('array', Center::class, 'null')) | ||||
|                 ->setDefault('centers', null) | ||||
|                 ->setDefined('role') | ||||
|                 ->addAllowedTypes('role', array(Role::class, 'null')) | ||||
|                 ->setDefault('role', null) | ||||
|                 ; | ||||
|          | ||||
|         // add the default options | ||||
|         $resolver->setDefaults(array( | ||||
|             'class' => Person::class, | ||||
|             'choice_label' => function(Person $p) { | ||||
|                 return $p->getFirstname().' '.$p->getLastname(); | ||||
|             }, | ||||
|             'placeholder' => 'Pick a person', | ||||
|             'choice_attr' => function(Person $p) { | ||||
|                 return array( | ||||
|                     'data-center' => $p->getCenter()->getId() | ||||
|                 ); | ||||
|             }, | ||||
|             'attr' => array('class' => 'select2 '), | ||||
|             'query_builder' => $this->personRepository->createQueryBuilder('p') | ||||
|         )); | ||||
|     } | ||||
|      | ||||
|     public function getParent() | ||||
|     { | ||||
|         return \Symfony\Bridge\Doctrine\Form\Type\EntityType::class; | ||||
|     } | ||||
|      | ||||
| } | ||||
| @@ -69,4 +69,18 @@ services: | ||||
|             - "@chill.main.form.data_transformer.center_transformer" | ||||
|         tags: | ||||
|             - { name: form.type, alias: chill_personbundle_person_creation } | ||||
|              | ||||
|              | ||||
|     chill.person.form.type.pick_person: | ||||
|         class: Chill\PersonBundle\Form\Type\PickPersonType | ||||
|         arguments: | ||||
|             - "@chill.person.repository.person" | ||||
|             - "@security.token_storage" | ||||
|             - "@chill.main.security.authorization.helper" | ||||
|         tags: | ||||
|             - { name: form.type } | ||||
|              | ||||
|     chill.person.repository.person: | ||||
|         class: Chill\PersonBundle\Entity\PersonRepository | ||||
|         factory: ['@doctrine.orm.entity_manager', getRepository] | ||||
|         arguments: | ||||
|             - 'Chill\PersonBundle\Entity\Person' | ||||
| @@ -71,6 +71,9 @@ Reset: 'Remise à zéro' | ||||
| 'Update details for %name%': 'Modifier détails de %name%' | ||||
| Accompanying period list: Périodes d'accompagnement | ||||
|  | ||||
| # pickAPersonType | ||||
| Pick a person: Choisir une personne | ||||
|  | ||||
| #address | ||||
| Since %date%: Depuis le %date% | ||||
| No address given: Pas d'adresse renseignée | ||||
|   | ||||
							
								
								
									
										181
									
								
								Tests/Form/Type/PickPersonTypeTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								Tests/Form/Type/PickPersonTypeTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | ||||
| <?php | ||||
|  | ||||
| /* | ||||
|  * Copyright (C) 2016 Champs-Libres <info@champs-libres.coop> | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\PersonBundle\Tests\Form\Type; | ||||
|  | ||||
| use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; | ||||
| use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; | ||||
| use Chill\PersonBundle\Form\Type\PickPersonType; | ||||
|  | ||||
| /** | ||||
|  *  | ||||
|  * | ||||
|  * @author Julien Fastré <julien.fastre@champs-libres.coop> | ||||
|  */ | ||||
| class PickPersonTypeTest extends KernelTestCase | ||||
| { | ||||
|     /** | ||||
|      * | ||||
|      * @var \Chill\MainBundle\Entity\User | ||||
|      */ | ||||
|     protected $user; | ||||
|      | ||||
|     /** | ||||
|      * | ||||
|      * @var \Symfony\Component\DependencyInjection\ContainerInterface | ||||
|      */ | ||||
|     protected $container; | ||||
|      | ||||
|     /** | ||||
|      * | ||||
|      * @var \Symfony\Component\Form\FormFactoryInterface | ||||
|      */ | ||||
|     protected $formFactory; | ||||
|      | ||||
|     public function setUp() | ||||
|     { | ||||
|         self::bootKernel(); | ||||
|          | ||||
|         $this->container = self::$kernel->getContainer(); | ||||
|          | ||||
|         $this->user = $this->container->get('doctrine.orm.entity_manager') | ||||
|                 ->getRepository('ChillMainBundle:User') | ||||
|                 ->findOneBy(array('username' => 'multi_center')); | ||||
|          | ||||
|         $this->formFactory = $this->container->get('form.factory'); | ||||
|          | ||||
|         $token = (new UsernamePasswordToken($this->user, 'password', 'firewall')); | ||||
|         $this->container->get('security.token_storage') | ||||
|                 ->setToken($token); | ||||
|     } | ||||
|      | ||||
|     public function testWithoutOption() | ||||
|     { | ||||
|         $form = $this->formFactory | ||||
|                 ->createBuilder(PickPersonType::class, null, array()) | ||||
|                 ->getForm(); | ||||
|          | ||||
|         $this->assertInstanceOf(\Symfony\Component\Form\FormInterface::class, | ||||
|                 $form); | ||||
|          | ||||
|         // transform into a view to have data-center attr | ||||
|         $view = $form->createView(); | ||||
|          | ||||
|         $centerIds = array(); | ||||
|          | ||||
|         /* @var $centerIds \Symfony\Component\Form\ChoiceList\View\ChoiceView */ | ||||
|         foreach($view->vars['choices'] as $choice) { | ||||
|             $centerIds[] = $choice->attr['data-center']; | ||||
|         } | ||||
|          | ||||
|         $this->assertEquals(2, count(array_unique($centerIds)), | ||||
|                 "test that the form contains people from 2 centers"); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Test the form with an option 'centers' with an unique center  | ||||
|      * entity (not in an array) | ||||
|      */ | ||||
|     public function testWithOptionCenter() | ||||
|     { | ||||
|         $center = $this->container->get('doctrine.orm.entity_manager') | ||||
|                 ->getRepository('ChillMainBundle:Center') | ||||
|                 ->findOneBy(array('name' => 'Center A')) | ||||
|                 ; | ||||
|          | ||||
|         $form = $this->formFactory | ||||
|                 ->createBuilder(PickPersonType::class, null, array( | ||||
|                     'centers' => $center | ||||
|                 )) | ||||
|                 ->getForm(); | ||||
|          | ||||
|         // transform into a view to have data-center attr | ||||
|         $view = $form->createView(); | ||||
|          | ||||
|         /* @var $centerIds \Symfony\Component\Form\ChoiceList\View\ChoiceView */ | ||||
|         foreach($view->vars['choices'] as $choice) { | ||||
|             $centerIds[] = $choice->attr['data-center']; | ||||
|         } | ||||
|          | ||||
|         $this->assertEquals(1, count(array_unique($centerIds)), | ||||
|                 "test that the form contains people from only one centers"); | ||||
|          | ||||
|         $this->assertEquals($center->getId(), array_unique($centerIds)[0]); | ||||
|          | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Test the form with multiple centers | ||||
|      */ | ||||
|     public function testWithOptionCenters() | ||||
|     { | ||||
|         $centers = $this->container->get('doctrine.orm.entity_manager') | ||||
|                 ->getRepository('ChillMainBundle:Center') | ||||
|                 ->findAll() | ||||
|                 ; | ||||
|          | ||||
|         $form = $this->formFactory | ||||
|                 ->createBuilder(PickPersonType::class, null, array( | ||||
|                     'centers' => $centers | ||||
|                 )) | ||||
|                 ->getForm(); | ||||
|          | ||||
|         // transform into a view to have data-center attr | ||||
|         $view = $form->createView(); | ||||
|          | ||||
|         /* @var $centerIds \Symfony\Component\Form\ChoiceList\View\ChoiceView */ | ||||
|         foreach($view->vars['choices'] as $choice) { | ||||
|             $centerIds[] = $choice->attr['data-center']; | ||||
|         } | ||||
|          | ||||
|         $this->assertEquals(2, count(array_unique($centerIds)), | ||||
|                 "test that the form contains people from only one centers"); | ||||
|          | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * test with an invalid center type in the option 'centers' (in an array) | ||||
|      *  | ||||
|      * @expectedException \RuntimeException | ||||
|      */ | ||||
|     public function testWithInvalidOptionCenters() | ||||
|     { | ||||
|          | ||||
|         $form = $this->formFactory | ||||
|                 ->createBuilder(PickPersonType::class, null, array( | ||||
|                     'centers' => array('string') | ||||
|                 )) | ||||
|                 ->getForm(); | ||||
|     } | ||||
|      | ||||
|     public function testWithOptionRoleInvalid() | ||||
|     { | ||||
|         $form = $this->formFactory | ||||
|                 ->createBuilder(PickPersonType::class, null, array( | ||||
|                     'role' => new \Symfony\Component\Security\Core\Role\Role('INVALID') | ||||
|                 )) | ||||
|                 ->getForm(); | ||||
|          | ||||
|         // transform into a view to have data-center attr | ||||
|         $view = $form->createView(); | ||||
|          | ||||
|         $this->assertEquals(0, count($view->vars['choices'])); | ||||
|     } | ||||
|      | ||||
| } | ||||
		Reference in New Issue
	
	Block a user