/** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $choiceLabels = (object) array('labels' => array()); $choiceListFactory = $this->choiceListFactory; $emptyData = function (Options $options) { if ($options['multiple'] || $options['expanded']) { return array(); } return ''; }; $placeholder = function (Options $options) { return $options['required'] ? null : ''; }; // BC closure, to be removed in 3.0 $choicesNormalizer = function (Options $options, $choices) use($choiceLabels) { // Unset labels from previous invocations $choiceLabels->labels = array(); // This closure is irrelevant when "choices_as_values" is set to true if ($options['choices_as_values']) { return $choices; } if (null === $choices) { return; } return ChoiceType::normalizeLegacyChoices($choices, $choiceLabels); }; // BC closure, to be removed in 3.0 $choiceLabel = function (Options $options) use($choiceLabels) { // If the choices contain duplicate labels, the normalizer of the // "choices" option stores them in the $choiceLabels variable // Trigger the normalizer $options->offsetGet('choices'); // Pick labels from $choiceLabels if available if ($choiceLabels->labels) { // Don't pass the labels by reference. We do want to create a // copy here so that every form has an own version of that // variable (contrary to the $choiceLabels object shared by all // forms) $labels = $choiceLabels->labels; // The $choiceLabels object is shared with the 'choices' closure. // Since that normalizer can be replaced, labels have to be cleared here. $choiceLabels->labels = array(); return function ($choice, $key) use($labels) { return $labels[$key]; }; } return; }; $that = $this; $choiceListNormalizer = function (Options $options, $choiceList) use($choiceListFactory, $that) { if ($choiceList) { @trigger_error(sprintf('The "choice_list" option of the "%s" form type (%s) is deprecated since version 2.7 and will be removed in 3.0. Use "choice_loader" instead.', $that->getName(), __CLASS__), E_USER_DEPRECATED); if ($choiceList instanceof LegacyChoiceListInterface) { return new LegacyChoiceListAdapter($choiceList); } return $choiceList; } if (null !== $options['choice_loader']) { return $choiceListFactory->createListFromLoader($options['choice_loader'], $options['choice_value']); } // Harden against NULL values (like in EntityType and ModelType) $choices = null !== $options['choices'] ? $options['choices'] : array(); // BC when choices are in the keys, not in the values if (!$options['choices_as_values']) { return $choiceListFactory->createListFromFlippedChoices($choices, $options['choice_value'], false); } return $choiceListFactory->createListFromChoices($choices, $options['choice_value']); }; $placeholderNormalizer = function (Options $options, $placeholder) use($that) { if (!is_object($options['empty_value']) || !$options['empty_value'] instanceof \Exception) { @trigger_error(sprintf('The form option "empty_value" of the "%s" form type (%s) is deprecated since version 2.6 and will be removed in 3.0. Use "placeholder" instead.', $that->getName(), __CLASS__), E_USER_DEPRECATED); $placeholder = $options['empty_value']; } if ($options['multiple']) { // never use an empty value for this case return; } elseif ($options['required'] && ($options['expanded'] || isset($options['attr']['size']) && $options['attr']['size'] > 1)) { // placeholder for required radio buttons or a select with size > 1 does not make sense return; } elseif (false === $placeholder) { // an empty value should be added but the user decided otherwise return; } elseif ($options['expanded'] && '' === $placeholder) { // never use an empty label for radio buttons return 'None'; } // empty value has been set explicitly return $placeholder; }; $compound = function (Options $options) { return $options['expanded']; }; $choiceTranslationDomainNormalizer = function (Options $options, $choiceTranslationDomain) { if (true === $choiceTranslationDomain) { return $options['translation_domain']; } return $choiceTranslationDomain; }; $resolver->setDefaults(array('multiple' => false, 'expanded' => false, 'choice_list' => null, 'choices' => array(), 'choices_as_values' => false, 'choice_loader' => null, 'choice_label' => $choiceLabel, 'choice_name' => null, 'choice_value' => null, 'choice_attr' => null, 'preferred_choices' => array(), 'group_by' => null, 'empty_data' => $emptyData, 'empty_value' => new \Exception(), 'placeholder' => $placeholder, 'error_bubbling' => false, 'compound' => $compound, 'data_class' => null, 'choice_translation_domain' => true)); $resolver->setNormalizer('choices', $choicesNormalizer); $resolver->setNormalizer('choice_list', $choiceListNormalizer); $resolver->setNormalizer('placeholder', $placeholderNormalizer); $resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer); $resolver->setAllowedTypes('choice_list', array('null', 'Symfony\\Component\\Form\\ChoiceList\\ChoiceListInterface', 'Symfony\\Component\\Form\\Extension\\Core\\ChoiceList\\ChoiceListInterface')); $resolver->setAllowedTypes('choices', array('null', 'array', '\\Traversable')); $resolver->setAllowedTypes('choice_translation_domain', array('null', 'bool', 'string')); $resolver->setAllowedTypes('choices_as_values', 'bool'); $resolver->setAllowedTypes('choice_loader', array('null', 'Symfony\\Component\\Form\\ChoiceList\\Loader\\ChoiceLoaderInterface')); $resolver->setAllowedTypes('choice_label', array('null', 'bool', 'callable', 'string', 'Symfony\\Component\\PropertyAccess\\PropertyPath')); $resolver->setAllowedTypes('choice_name', array('null', 'callable', 'string', 'Symfony\\Component\\PropertyAccess\\PropertyPath')); $resolver->setAllowedTypes('choice_value', array('null', 'callable', 'string', 'Symfony\\Component\\PropertyAccess\\PropertyPath')); $resolver->setAllowedTypes('choice_attr', array('null', 'array', 'callable', 'string', 'Symfony\\Component\\PropertyAccess\\PropertyPath')); $resolver->setAllowedTypes('preferred_choices', array('array', '\\Traversable', 'callable', 'string', 'Symfony\\Component\\PropertyAccess\\PropertyPath')); $resolver->setAllowedTypes('group_by', array('null', 'array', '\\Traversable', 'callable', 'string', 'Symfony\\Component\\PropertyAccess\\PropertyPath')); }