ModelType.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <?php
  2. /*
  3. * This file is part of the Sonata Project package.
  4. *
  5. * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Sonata\AdminBundle\Form\Type;
  11. use Sonata\AdminBundle\Form\ChoiceList\ModelChoiceList;
  12. use Sonata\AdminBundle\Form\ChoiceList\ModelChoiceLoader;
  13. use Sonata\AdminBundle\Form\DataTransformer\LegacyModelsToArrayTransformer;
  14. use Sonata\AdminBundle\Form\DataTransformer\ModelsToArrayTransformer;
  15. use Sonata\AdminBundle\Form\DataTransformer\ModelToIdTransformer;
  16. use Sonata\AdminBundle\Form\EventListener\MergeCollectionListener;
  17. use Symfony\Component\Form\AbstractType;
  18. use Symfony\Component\Form\FormBuilderInterface;
  19. use Symfony\Component\Form\FormInterface;
  20. use Symfony\Component\Form\FormView;
  21. use Symfony\Component\OptionsResolver\Options;
  22. use Symfony\Component\OptionsResolver\OptionsResolver;
  23. use Symfony\Component\OptionsResolver\OptionsResolverInterface;
  24. use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
  25. /**
  26. * Class ModelType
  27. * This type define a standard select input with a + sign to add new associated object.
  28. *
  29. * @author Thomas Rabaix <thomas.rabaix@sonata-project.org>
  30. */
  31. class ModelType extends AbstractType
  32. {
  33. /**
  34. * @var PropertyAccessorInterface
  35. */
  36. protected $propertyAccessor;
  37. public function __construct(PropertyAccessorInterface $propertyAccessor)
  38. {
  39. $this->propertyAccessor = $propertyAccessor;
  40. }
  41. /**
  42. * {@inheritdoc}
  43. */
  44. public function buildForm(FormBuilderInterface $builder, array $options)
  45. {
  46. if ($options['multiple']) {
  47. if (array_key_exists('choice_loader', $options) && $options['choice_loader'] !== null) { // SF2.7+
  48. $builder->addViewTransformer(new ModelsToArrayTransformer(
  49. $options['choice_loader'],
  50. $options['model_manager'],
  51. $options['class']), true);
  52. } else {
  53. $builder->addViewTransformer(new LegacyModelsToArrayTransformer($options['choice_list']), true);
  54. }
  55. $builder
  56. ->addEventSubscriber(new MergeCollectionListener($options['model_manager']))
  57. ;
  58. } else {
  59. $builder
  60. ->addViewTransformer(new ModelToIdTransformer($options['model_manager'], $options['class']), true)
  61. ;
  62. }
  63. }
  64. /**
  65. * {@inheritdoc}
  66. */
  67. public function buildView(FormView $view, FormInterface $form, array $options)
  68. {
  69. $view->vars['btn_add'] = $options['btn_add'];
  70. $view->vars['btn_list'] = $options['btn_list'];
  71. $view->vars['btn_delete'] = $options['btn_delete'];
  72. $view->vars['btn_catalogue'] = $options['btn_catalogue'];
  73. }
  74. /**
  75. * {@inheritdoc}
  76. *
  77. * @todo Remove it when bumping requirements to SF 2.7+
  78. */
  79. public function setDefaultOptions(OptionsResolverInterface $resolver)
  80. {
  81. $this->configureOptions($resolver);
  82. }
  83. /**
  84. * {@inheritdoc}
  85. */
  86. public function configureOptions(OptionsResolver $resolver)
  87. {
  88. $options = array();
  89. $propertyAccessor = $this->propertyAccessor;
  90. if (interface_exists('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')) { // SF2.7+
  91. $options['choice_loader'] = function (Options $options, $previousValue) use ($propertyAccessor) {
  92. if ($previousValue && count($choices = $previousValue->getChoices())) {
  93. return $choices;
  94. }
  95. return new ModelChoiceLoader(
  96. $options['model_manager'],
  97. $options['class'],
  98. $options['property'],
  99. $options['query'],
  100. $options['choices'],
  101. $propertyAccessor
  102. );
  103. };
  104. } else {
  105. $options['choice_list'] = function (Options $options, $previousValue) use ($propertyAccessor) {
  106. if ($previousValue && count($choices = $previousValue->getChoices())) {
  107. return $choices;
  108. }
  109. return new ModelChoiceList(
  110. $options['model_manager'],
  111. $options['class'],
  112. $options['property'],
  113. $options['query'],
  114. $options['choices'],
  115. $propertyAccessor
  116. );
  117. };
  118. }
  119. $resolver->setDefaults(array_merge($options, array(
  120. 'compound' => function (Options $options) {
  121. if (isset($options['multiple']) && $options['multiple']) {
  122. if (isset($options['expanded']) && $options['expanded']) {
  123. //checkboxes
  124. return true;
  125. }
  126. //select tag (with multiple attribute)
  127. return false;
  128. }
  129. if (isset($options['expanded']) && $options['expanded']) {
  130. //radio buttons
  131. return true;
  132. }
  133. //select tag
  134. return false;
  135. },
  136. 'template' => 'choice',
  137. 'multiple' => false,
  138. 'expanded' => false,
  139. 'model_manager' => null,
  140. 'class' => null,
  141. 'property' => null,
  142. 'query' => null,
  143. 'choices' => array(),
  144. 'preferred_choices' => array(),
  145. 'btn_add' => 'link_add',
  146. 'btn_list' => 'link_list',
  147. 'btn_delete' => 'link_delete',
  148. 'btn_catalogue' => 'SonataAdminBundle',
  149. )));
  150. }
  151. /**
  152. * {@inheritdoc}
  153. */
  154. public function getParent()
  155. {
  156. return 'choice';
  157. }
  158. /**
  159. * {@inheritdoc}
  160. *
  161. * @todo Remove when dropping Symfony <2.8 support
  162. */
  163. public function getName()
  164. {
  165. return $this->getBlockPrefix();
  166. }
  167. /**
  168. * {@inheritdoc}
  169. */
  170. public function getBlockPrefix()
  171. {
  172. return 'sonata_type_model';
  173. }
  174. }