├── .gitignore
├── DataTransformer
└── EntityToIdTransformer.php
├── DependencyInjection
└── GregwarFormExtension.php
├── GregwarFormBundle.php
├── LICENSE
├── README.md
├── Resources
└── config
│ └── services.yml
├── Tests
├── Functional
│ ├── AppKernel.php
│ ├── FormTest.php
│ ├── Resources
│ │ └── views
│ │ │ └── view.html.twig
│ ├── config.yml
│ └── routing.yml
└── bootstrap.php
├── Type
└── EntityIdType.php
├── composer.json
└── phpunit.xml.dist
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | composer.lock
3 |
--------------------------------------------------------------------------------
/DataTransformer/EntityToIdTransformer.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class EntityToIdTransformer implements DataTransformerInterface
22 | {
23 | protected $em;
24 | private $class;
25 | private $property;
26 | private $queryBuilder;
27 | private $multiple;
28 |
29 | private $unitOfWork;
30 |
31 | public function __construct(EntityManager $em, $class, $property, $queryBuilder, $multiple)
32 | {
33 | if (!(null === $queryBuilder || $queryBuilder instanceof QueryBuilder || $queryBuilder instanceof \Closure)) {
34 | throw new UnexpectedTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder or \Closure');
35 | }
36 |
37 | if (null == $class) {
38 | throw new UnexpectedTypeException($class, 'string');
39 | }
40 |
41 | $this->em = $em;
42 | $this->unitOfWork = $this->em->getUnitOfWork();
43 | $this->class = $class;
44 | $this->queryBuilder = $queryBuilder;
45 | $this->multiple = $multiple;
46 |
47 | if ($property) {
48 | $this->property = $property;
49 | }
50 | }
51 |
52 | public function transform($data)
53 | {
54 | if (null === $data) {
55 | return null;
56 | }
57 |
58 | if (!$this->multiple) {
59 | return $this->transformSingleEntity($data);
60 | }
61 |
62 | $return = array();
63 |
64 | foreach ($data as $element) {
65 | $return[] = $this->transformSingleEntity($element);
66 | }
67 |
68 | return implode(', ', $return);
69 | }
70 |
71 | protected function splitData($data)
72 | {
73 | return is_array($data) ? $data : explode(',', $data);
74 | }
75 |
76 |
77 | protected function transformSingleEntity($data)
78 | {
79 | if (!$this->unitOfWork->isInIdentityMap($data)) {
80 | throw new TransformationFailedException('Entities passed to the choice field must be managed');
81 | }
82 |
83 | if ($this->property) {
84 | $propertyAccessor = new PropertyAccessor();
85 | return $propertyAccessor->getValue($data, $this->property);
86 | }
87 |
88 | return current($this->unitOfWork->getEntityIdentifier($data));
89 | }
90 |
91 | public function reverseTransform($data)
92 | {
93 | if (!$data) {
94 | return null;
95 | }
96 |
97 | if (!$this->multiple) {
98 | return $this->reverseTransformSingleEntity($data);
99 | }
100 |
101 | $return = array();
102 |
103 | foreach ($this->splitData($data) as $element) {
104 | $return[] = $this->reverseTransformSingleEntity($element);
105 | }
106 |
107 | return $return;
108 | }
109 |
110 | protected function reverseTransformSingleEntity($data)
111 | {
112 | $em = $this->em;
113 | $class = $this->class;
114 | $repository = $em->getRepository($class);
115 |
116 | if ($qb = $this->queryBuilder) {
117 | if ($qb instanceof \Closure) {
118 | $qb = $qb($repository, $data);
119 | }
120 |
121 | try {
122 | $result = $qb->getQuery()->getSingleResult();
123 | } catch (NoResultException $e) {
124 | $result = null;
125 | }
126 | } else {
127 | if ($this->property) {
128 | $result = $repository->findOneBy(array($this->property => $data));
129 | } else {
130 | $result = $repository->find($data);
131 | }
132 | }
133 |
134 | if (!$result) {
135 | throw new TransformationFailedException('Can not find entity');
136 | }
137 |
138 | return $result;
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/DependencyInjection/GregwarFormExtension.php:
--------------------------------------------------------------------------------
1 | load('services.yml');
17 | }
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/GregwarFormBundle.php:
--------------------------------------------------------------------------------
1 | Grégoire Passault
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is furnished
8 | to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Gregwar's FormBundle
2 | =====================
3 |
4 | [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YUXRLWHQSWS6L)
5 |
6 | `GregwarFormBundle` provides the form type "entity_id"
7 |
8 | Installation
9 | ============
10 |
11 | To install `GregwarFormBundle`, run `composer require gregwar/form-bundle`.
12 |
13 | Then, register the bundle in the application kernel :
14 |
15 | ```php
16 | add('city', EntityIdType::class, array(
48 | 'class' => 'Project\Entity\City',
49 | 'query_builder' => function(EntityRepository $repo, $id) {
50 | return $repo->createQueryBuilder('c')
51 | ->where('c.id = :id AND c.available = 1')
52 | ->setParameter('id', $id);
53 | }
54 | ))
55 | ;
56 | ```
57 |
58 | Note that if you don't provide any query builder, `->find($id)` will be used.
59 |
60 | You can also chose to show the field, by passing the `hidden` option to `false`:
61 |
62 | ```php
63 | add('city', EntityIdType::class, array(
67 | 'class' => 'Project\Entity\City',
68 | 'hidden' => false,
69 | 'label' => 'Enter the City id'
70 | ))
71 | ;
72 | ```
73 |
74 | Using the `property` option, you can also use another identifier than the primary
75 | key:
76 |
77 | ```php
78 | add('recipient', EntityIdType::class, array(
82 | 'class' => 'Project\Entity\User',
83 | 'hidden' => false,
84 | 'property' => 'login',
85 | 'label' => 'Recipient login'
86 | ))
87 | ;
88 | ```
89 |
90 | Notes
91 | =====
92 |
93 | There is maybe bugs in this implementations, this package is just an idea of a form
94 | field type which can be very useful for the Symfony2 project.
95 |
96 | License
97 | =======
98 |
99 | This bundle is under MIT license
100 |
--------------------------------------------------------------------------------
/Resources/config/services.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | # entity_id type
4 | entity_id.type:
5 | class: Gregwar\FormBundle\Type\EntityIdType
6 | arguments: ["@doctrine"]
7 | tags:
8 | - { name: form.type, alias: entity_id }
9 |
--------------------------------------------------------------------------------
/Tests/Functional/AppKernel.php:
--------------------------------------------------------------------------------
1 | load(__DIR__.'/config.yml');
24 | }
25 |
26 | public function getCacheDir()
27 | {
28 | return sys_get_temp_dir().'/GregwarFormBundle';
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Tests/Functional/FormTest.php:
--------------------------------------------------------------------------------
1 | createKernel();
22 | $kernel->boot();
23 |
24 | $formBuilder = $kernel->getContainer()->get('form.factory')->createBuilder(FormType::class);
25 | $formBuilder->add('user', EntityIdType::class, array(
26 | 'class' => 'Gregwar\FormBundle\Tests\Functional\User',
27 | 'hidden' => $hidden,
28 | ));
29 | $form = $formBuilder->getForm();
30 |
31 | $html = $kernel->getContainer()->get('twig')->render('::view.html.twig', array(
32 | 'form' => $form->createView(),
33 | ));
34 |
35 | $this->assertEquals('', trim($html));
36 | }
37 |
38 | /**
39 | * @expectedException Symfony\Component\OptionsResolver\Exception\MissingOptionsException
40 | * @expectedExceptionMessage The required option "class" is missing.
41 | */
42 | public function testFormWithNoClass()
43 | {
44 | $kernel = $this->createKernel();
45 | $kernel->boot();
46 |
47 | $formBuilder = $kernel->getContainer()->get('form.factory')->createBuilder(FormType::class);
48 | $formBuilder->add('user', EntityIdType::class);
49 | $form = $formBuilder->getForm();
50 | }
51 |
52 | public function getTestFormData()
53 | {
54 | return array(
55 | array(true, 'hidden'),
56 | array(false, 'text')
57 | );
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Tests/Functional/Resources/views/view.html.twig:
--------------------------------------------------------------------------------
1 | {{ form_widget(form.user) }}
2 |
--------------------------------------------------------------------------------
/Tests/Functional/config.yml:
--------------------------------------------------------------------------------
1 | framework:
2 | secret: test
3 | test: ~
4 | form: true
5 | templating:
6 | engines: ['twig']
7 | router:
8 | resource: "%kernel.root_dir%/config/routing.yml"
9 | strict_requirements: "%kernel.debug%"
10 | session:
11 | storage_id: session.storage.mock_file
12 |
13 | doctrine:
14 | dbal:
15 | driver: pdo_sqlite
16 | path: "%kernel.cache_dir%/data.sqlite"
17 | orm:
18 | auto_generate_proxy_classes: "%kernel.debug%"
19 | entity_managers:
20 | default:
21 | auto_mapping: true
22 |
--------------------------------------------------------------------------------
/Tests/Functional/routing.yml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Gregwar/FormBundle/b84c52fcbf8c9d3caac55a30c04696297e7413d0/Tests/Functional/routing.yml
--------------------------------------------------------------------------------
/Tests/bootstrap.php:
--------------------------------------------------------------------------------
1 |
19 | */
20 | class EntityIdType extends AbstractType
21 | {
22 | protected $registry;
23 |
24 | public function __construct(RegistryInterface $registry)
25 | {
26 | $this->registry = $registry;
27 | }
28 |
29 | public function buildForm(FormBuilderInterface $builder, array $options)
30 | {
31 | $builder->addModelTransformer(new EntityToIdTransformer(
32 | $this->registry->getManager($options['em']),
33 | $options['class'],
34 | $options['property'],
35 | $options['query_builder'],
36 | $options['multiple']
37 | ));
38 | }
39 |
40 | // Todo: remove when Symfony < 2.7 support is dropped
41 | public function setDefaultOptions(OptionsResolverInterface $resolver)
42 | {
43 | $this->configureOptions($resolver);
44 | }
45 |
46 | public function configureOptions(OptionsResolver $resolver)
47 | {
48 | $resolver->setRequired(array(
49 | 'class',
50 | ));
51 |
52 | $resolver->setDefaults(array(
53 | 'em' => null,
54 | 'property' => null,
55 | 'query_builder' => null,
56 | 'hidden' => true,
57 | 'multiple' => false,
58 | ));
59 | }
60 |
61 | public function buildView(FormView $view, FormInterface $form, array $options)
62 | {
63 | if (true === $options['hidden']) {
64 | $view->vars['type'] = 'hidden';
65 | }
66 | }
67 |
68 | public function getParent()
69 | {
70 | // BC for SF < 2.8
71 | if (!method_exists('Symfony\Component\Form\AbstractType', 'getBlockPrefix')) {
72 | return 'text';
73 | }
74 |
75 | return 'Symfony\Component\Form\Extension\Core\Type\TextType';
76 | }
77 |
78 | public function getBlockPrefix()
79 | {
80 | return 'entity_id';
81 | }
82 |
83 | // BC for SF < 2.8
84 | public function getName()
85 | {
86 | return $this->getBlockPrefix();
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gregwar/form-bundle",
3 | "description": "Provides the \"entity_id\" type (read \"entity identifier\")",
4 | "license": "MIT",
5 | "require": {
6 | "symfony/framework-bundle": "^2.8 || ^3.0 || ^4.0",
7 | "symfony/form": "^2.8 || ^3.0 || ^4.0",
8 | "symfony/validator": "^2.8 || ^3.0 || ^4.0",
9 | "symfony/property-access": "^2.8 || ^3.0 || ^4.0",
10 | "doctrine/orm": "^2.2"
11 | },
12 | "require-dev": {
13 | "doctrine/doctrine-bundle": "^1.3",
14 | "symfony/twig-bundle": "^2.8 || ^3.0 || ^4.0",
15 | "symfony/twig-bridge": "^2.8 || ^3.0 || ^4.0",
16 | "symfony/yaml": "^2.8 || ^3.0 || ^4.0",
17 | "symfony/templating": "^2.8 || ^3.0 || ^4.0"
18 | },
19 | "autoload": {
20 | "psr-0": { "Gregwar\\FormBundle": "" }
21 | },
22 | "target-dir": "Gregwar/FormBundle",
23 | "extra": {
24 | "branch-alias": {
25 | "dev-master": "2.6-dev"
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
15 | ./Tests/
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------