vendor/skyfox/propel-bundle/Form/Type/ModelType.php line 57

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  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 Propel\Bundle\PropelBundle\Form\Type;
  11. use Propel\Bundle\PropelBundle\Form\ChoiceList\PropelChoiceLoader;
  12. use Propel\Bundle\PropelBundle\Form\DataTransformer\CollectionToArrayTransformer;
  13. use Propel\Runtime\ActiveQuery\ModelCriteria;
  14. use Propel\Runtime\Map\ColumnMap;
  15. use Symfony\Component\Form\AbstractType;
  16. use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface;
  17. use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
  18. use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator;
  19. use Symfony\Component\Form\FormBuilderInterface;
  20. use Symfony\Component\OptionsResolver\Options;
  21. use Symfony\Component\OptionsResolver\OptionsResolver;
  22. use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
  23. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  24. use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
  25. /**
  26.  * ModelType class.
  27.  *
  28.  * @author William Durand <william.durand1@gmail.com>
  29.  * @author Toni Uebernickel <tuebernickel@gmail.com>
  30.  *
  31.  * Example using the preferred_choices option.
  32.  *
  33.  * <code>
  34.  *  public function buildForm(FormBuilderInterface $builder, array $options)
  35.  *  {
  36.  *      $builder
  37.  *          ->add('product', 'model', array(
  38.  *              'class' => 'Model\Product',
  39.  *              'query' => ProductQuery::create()
  40.  *                  ->filterIsActive(true)
  41.  *                  ->useI18nQuery($options['locale'])
  42.  *                      ->orderByName()
  43.  *                  ->endUse()
  44.  *              ,
  45.  *              'preferred_choices' => ProductQuery::create()
  46.  *                  ->filterByIsTopProduct(true)
  47.  *              ,
  48.  *          ))
  49.  *      ;
  50.  *   }
  51.  * </code>
  52.  */
  53. class ModelType extends AbstractType
  54. {
  55.     /**
  56.      * @var ChoiceListFactoryInterface
  57.      */
  58.     private $choiceListFactory;
  59.     /**
  60.      * ModelType constructor.
  61.      *
  62.      * @param PropertyAccessorInterface|null  $propertyAccessor
  63.      * @param ChoiceListFactoryInterface|null $choiceListFactory
  64.      */
  65.     public function __construct(PropertyAccessorInterface $propertyAccessor nullChoiceListFactoryInterface $choiceListFactory null)
  66.     {
  67.         $this->choiceListFactory $choiceListFactory ?: new PropertyAccessDecorator(
  68.             new DefaultChoiceListFactory(),
  69.             $propertyAccessor
  70.         );
  71.     }
  72.     /**
  73.      * Creates the label for a choice.
  74.      *
  75.      * For backwards compatibility, objects are cast to strings by default.
  76.      *
  77.      * @param object $choice The object.
  78.      *
  79.      * @return string The string representation of the object.
  80.      *
  81.      * @internal This method is public to be usable as callback. It should not
  82.      *           be used in user code.
  83.      */
  84.     public static function createChoiceLabel($choice)
  85.     {
  86.         return (string) $choice;
  87.     }
  88.     /**
  89.      * Creates the field name for a choice.
  90.      *
  91.      * This method is used to generate field names if the underlying object has
  92.      * a single-column integer ID. In that case, the value of the field is
  93.      * the ID of the object. That ID is also used as field name.
  94.      *
  95.      * @param object     $choice The object.
  96.      * @param int|string $key    The choice key.
  97.      * @param string     $value  The choice value. Corresponds to the object's
  98.      *                           ID here.
  99.      *
  100.      * @return string The field name.
  101.      *
  102.      * @internal This method is public to be usable as callback. It should not
  103.      *           be used in user code.
  104.      */
  105.     public static function createChoiceName($choice$key$value)
  106.     {
  107.         return str_replace('-''_', (string) $value);
  108.     }
  109.     /**
  110.      * {@inheritDoc}
  111.      */
  112.     public function buildForm(FormBuilderInterface $builder, array $options)
  113.     {
  114.         if ($options['multiple']) {
  115.             $builder
  116.                 ->addViewTransformer(new CollectionToArrayTransformer(), true)
  117.             ;
  118.         }
  119.     }
  120.     /**
  121.      * {@inheritDoc}
  122.      */
  123.     public function configureOptions(OptionsResolver $resolver)
  124.     {
  125.         $choiceLoader = function (Options $options) {
  126.             // Unless the choices are given explicitly, load them on demand
  127.             if (null === $options['choices']) {
  128.                 $propelChoiceLoader = new PropelChoiceLoader(
  129.                     $this->choiceListFactory,
  130.                     $options['class'],
  131.                     $options['query'],
  132.                     $options['index_property']
  133.                 );
  134.                 return $propelChoiceLoader;
  135.             }
  136.             return null;
  137.         };
  138.         $choiceName = function (Options $options) {
  139.             /** @var ModelCriteria $query */
  140.             $query $options['query'];
  141.             if ($options['index_property']) {
  142.                 $identifier = array($query->getTableMap()->getColumn($options['index_property']));
  143.             } else {
  144.                 $identifier $query->getTableMap()->getPrimaryKeys();
  145.             }
  146.             /** @var ColumnMap $firstIdentifier */
  147.             $firstIdentifier current($identifier);
  148.             if (count($identifier) === && $firstIdentifier->getPdoType() === \PDO::PARAM_INT) {
  149.                 return array(__CLASS__'createChoiceName');
  150.             }
  151.             return null;
  152.         };
  153.         $choiceValue = function (Options $options) {
  154.             /** @var ModelCriteria $query */
  155.             $query $options['query'];
  156.             if ($options['index_property']) {
  157.                 $identifier = array($query->getTableMap()->getColumn($options['index_property']));
  158.             } else {
  159.                 $identifier $query->getTableMap()->getPrimaryKeys();
  160.             }
  161.             /** @var ColumnMap $firstIdentifier */
  162.             $firstIdentifier current($identifier);
  163.             if (count($identifier) === && in_array($firstIdentifier->getPdoType(), [\PDO::PARAM_BOOL\PDO::PARAM_INT\PDO::PARAM_STR])) {
  164.                 return function($object) use ($firstIdentifier) {
  165.                     if ($object) {
  166.                         return call_user_func([$object'get' ucfirst($firstIdentifier->getPhpName())]);
  167.                     }
  168.                     return null;
  169.                 };
  170.             }
  171.             return null;
  172.         };
  173.         $queryNormalizer = function (Options $options$query) {
  174.             if ($query === null) {
  175.                 $queryClass $options['class'] . 'Query';
  176.                 if (!class_exists($queryClass)) {
  177.                     if (empty($options['class'])) {
  178.                         throw new MissingOptionsException('The "class" parameter is empty, you should provide the model class');
  179.                     }
  180.                     throw new InvalidOptionsException(
  181.                         sprintf(
  182.                             'The query class "%s" is not found, you should provide the FQCN of the model class',
  183.                             $queryClass
  184.                         )
  185.                     );
  186.                 }
  187.                 $query = new $queryClass();
  188.             }
  189.             return $query;
  190.         };
  191.         $choiceLabelNormalizer = function (Options $options$choiceLabel) {
  192.             if ($choiceLabel === null) {
  193.                 if ($options['property'] == null) {
  194.                     $choiceLabel = array(__CLASS__'createChoiceLabel');
  195.                 } else {
  196.                     $valueProperty $options['property'];
  197.                     /** @var ModelCriteria $query */
  198.                     $query $options['query'];
  199.                     $choiceLabel = function($choice) use ($valueProperty$query) {
  200.                         $getter 'get'.ucfirst($valueProperty);
  201.                         if (!method_exists($choice$getter)) {
  202.                             $getter 'get' ucfirst($query->getTableMap()->getColumn($valueProperty)->getPhpName());
  203.                         }
  204.                         return call_user_func([$choice$getter]);
  205.                     };
  206.                 }
  207.             }
  208.             return $choiceLabel;
  209.         };
  210.         $resolver->setDefaults([
  211.             'query' => null,
  212.             'index_property' => null,
  213.             'property' => null,
  214.             'choices' => null,
  215.             'choice_loader' => $choiceLoader,
  216.             'choice_label' => null,
  217.             'choice_name' => $choiceName,
  218.             'choice_value' => $choiceValue,
  219.             'choice_translation_domain' => false,
  220.             'by_reference' => false,
  221.         ]);
  222.         $resolver->setRequired(array('class'));
  223.         $resolver->setNormalizer('query'$queryNormalizer);
  224.         $resolver->setNormalizer('choice_label'$choiceLabelNormalizer);
  225.         $resolver->setAllowedTypes('query', ['null''Propel\Runtime\ActiveQuery\ModelCriteria']);
  226.     }
  227.     /**
  228.      * {@inheritdoc}
  229.      */
  230.     public function getBlockPrefix()
  231.     {
  232.         return 'model';
  233.     }
  234.     public function getParent()
  235.     {
  236.         return 'Symfony\Component\Form\Extension\Core\Type\ChoiceType';
  237.     }
  238. }