ヤミRoot VoidGate
User / IP
:
216.73.216.143
Host / Server
:
146.88.233.70 / dev.loger.cm
System
:
Linux hybrid1120.fr.ns.planethoster.net 3.10.0-957.21.2.el7.x86_64 #1 SMP Wed Jun 5 14:26:44 UTC 2019 x86_64
Command
|
Upload
|
Create
Mass Deface
|
Jumping
|
Symlink
|
Reverse Shell
Ping
|
Port Scan
|
DNS Lookup
|
Whois
|
Header
|
cURL
:
/
home
/
logercm
/
dev.loger.cm
/
fixtures
/
assert
/
Viewing: form.tar
ResolvedFormType.php 0000644 00000013367 15120211543 0010532 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\OptionsResolver\Exception\ExceptionInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** * A wrapper for a form type and its extensions. * * @author Bernhard Schussek <bschussek@gmail.com> */ class ResolvedFormType implements ResolvedFormTypeInterface { /** * @var FormTypeInterface */ private $innerType; /** * @var FormTypeExtensionInterface[] */ private $typeExtensions; /** * @var ResolvedFormTypeInterface|null */ private $parent; /** * @var OptionsResolver */ private $optionsResolver; /** * @param FormTypeExtensionInterface[] $typeExtensions */ public function __construct(FormTypeInterface $innerType, array $typeExtensions = [], ResolvedFormTypeInterface $parent = null) { foreach ($typeExtensions as $extension) { if (!$extension instanceof FormTypeExtensionInterface) { throw new UnexpectedTypeException($extension, FormTypeExtensionInterface::class); } } $this->innerType = $innerType; $this->typeExtensions = $typeExtensions; $this->parent = $parent; } /** * {@inheritdoc} */ public function getBlockPrefix() { return $this->innerType->getBlockPrefix(); } /** * {@inheritdoc} */ public function getParent() { return $this->parent; } /** * {@inheritdoc} */ public function getInnerType() { return $this->innerType; } /** * {@inheritdoc} */ public function getTypeExtensions() { return $this->typeExtensions; } /** * {@inheritdoc} */ public function createBuilder(FormFactoryInterface $factory, string $name, array $options = []) { try { $options = $this->getOptionsResolver()->resolve($options); } catch (ExceptionInterface $e) { throw new $e(sprintf('An error has occurred resolving the options of the form "%s": ', get_debug_type($this->getInnerType())).$e->getMessage(), $e->getCode(), $e); } // Should be decoupled from the specific option at some point $dataClass = $options['data_class'] ?? null; $builder = $this->newBuilder($name, $dataClass, $factory, $options); $builder->setType($this); return $builder; } /** * {@inheritdoc} */ public function createView(FormInterface $form, FormView $parent = null) { return $this->newView($parent); } /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { if (null !== $this->parent) { $this->parent->buildForm($builder, $options); } $this->innerType->buildForm($builder, $options); foreach ($this->typeExtensions as $extension) { $extension->buildForm($builder, $options); } } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { if (null !== $this->parent) { $this->parent->buildView($view, $form, $options); } $this->innerType->buildView($view, $form, $options); foreach ($this->typeExtensions as $extension) { $extension->buildView($view, $form, $options); } } /** * {@inheritdoc} */ public function finishView(FormView $view, FormInterface $form, array $options) { if (null !== $this->parent) { $this->parent->finishView($view, $form, $options); } $this->innerType->finishView($view, $form, $options); foreach ($this->typeExtensions as $extension) { /* @var FormTypeExtensionInterface $extension */ $extension->finishView($view, $form, $options); } } /** * {@inheritdoc} */ public function getOptionsResolver() { if (null === $this->optionsResolver) { if (null !== $this->parent) { $this->optionsResolver = clone $this->parent->getOptionsResolver(); } else { $this->optionsResolver = new OptionsResolver(); } $this->innerType->configureOptions($this->optionsResolver); foreach ($this->typeExtensions as $extension) { $extension->configureOptions($this->optionsResolver); } } return $this->optionsResolver; } /** * Creates a new builder instance. * * Override this method if you want to customize the builder class. * * @return FormBuilderInterface */ protected function newBuilder(string $name, ?string $dataClass, FormFactoryInterface $factory, array $options) { if ($this->innerType instanceof ButtonTypeInterface) { return new ButtonBuilder($name, $options); } if ($this->innerType instanceof SubmitButtonTypeInterface) { return new SubmitButtonBuilder($name, $options); } return new FormBuilder($name, $dataClass, new EventDispatcher(), $factory, $options); } /** * Creates a new view instance. * * Override this method if you want to customize the view class. * * @return FormView */ protected function newView(FormView $parent = null) { return new FormView($parent); } } SubmitButton.php 0000644 00000002273 15120211543 0007712 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * A button that submits the form. * * @author Bernhard Schussek <bschussek@gmail.com> */ class SubmitButton extends Button implements ClickableInterface { private $clicked = false; /** * {@inheritdoc} */ public function isClicked() { return $this->clicked; } /** * Submits data to the button. * * @param array|string|null $submittedData The data * @param bool $clearMissing Not used * * @return $this * * @throws Exception\AlreadySubmittedException if the form has already been submitted */ public function submit($submittedData, bool $clearMissing = true) { if ($this->getConfig()->getDisabled()) { $this->clicked = false; return $this; } parent::submit($submittedData, $clearMissing); $this->clicked = null !== $submittedData; return $this; } } SubmitButtonTypeInterface.php 0000644 00000000732 15120211543 0012373 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * A type that should be converted into a {@link SubmitButton} instance. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface SubmitButtonTypeInterface extends FormTypeInterface { } ChoiceList/Factory/Cache/AbstractStaticOption.php 0000644 00000004162 15120211543 0016016 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory\Cache; use Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeInterface; /** * A template decorator for static {@see ChoiceType} options. * * Used as fly weight for {@see CachingFactoryDecorator}. * * @internal * * @author Jules Pietri <jules@heahprod.com> */ abstract class AbstractStaticOption { private static $options = []; /** @var bool|callable|string|array|\Closure|ChoiceLoaderInterface */ private $option; /** * @param FormTypeInterface|FormTypeExtensionInterface $formType A form type or type extension configuring a cacheable choice list * @param mixed $option Any pseudo callable, array, string or bool to define a choice list option * @param mixed|null $vary Dynamic data used to compute a unique hash when caching the option */ final public function __construct($formType, $option, $vary = null) { if (!$formType instanceof FormTypeInterface && !$formType instanceof FormTypeExtensionInterface) { throw new \TypeError(sprintf('Expected an instance of "%s" or "%s", but got "%s".', FormTypeInterface::class, FormTypeExtensionInterface::class, get_debug_type($formType))); } $hash = CachingFactoryDecorator::generateHash([static::class, $formType, $vary]); $this->option = self::$options[$hash] ?? self::$options[$hash] = $option; } /** * @return mixed */ final public function getOption() { return $this->option; } final public static function reset(): void { self::$options = []; } } ChoiceList/Factory/Cache/ChoiceAttr.php 0000644 00000001231 15120211543 0013731 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory\Cache; use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeInterface; /** * A cacheable wrapper for any {@see FormTypeInterface} or {@see FormTypeExtensionInterface} * which configures a "choice_attr" option. * * @internal * * @author Jules Pietri <jules@heahprod.com> */ final class ChoiceAttr extends AbstractStaticOption { } ChoiceList/Factory/Cache/ChoiceFieldName.php 0000644 00000001240 15120211543 0014643 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory\Cache; use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeInterface; /** * A cacheable wrapper for any {@see FormTypeInterface} or {@see FormTypeExtensionInterface} * which configures a "choice_name" callback. * * @internal * * @author Jules Pietri <jules@heahprod.com> */ final class ChoiceFieldName extends AbstractStaticOption { } ChoiceList/Factory/Cache/ChoiceFilter.php 0000644 00000001235 15120211543 0014250 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory\Cache; use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeInterface; /** * A cacheable wrapper for any {@see FormTypeInterface} or {@see FormTypeExtensionInterface} * which configures a "choice_filter" option. * * @internal * * @author Jules Pietri <jules@heahprod.com> */ final class ChoiceFilter extends AbstractStaticOption { } ChoiceList/Factory/Cache/ChoiceLabel.php 0000644 00000001233 15120211543 0014040 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory\Cache; use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeInterface; /** * A cacheable wrapper for any {@see FormTypeInterface} or {@see FormTypeExtensionInterface} * which configures a "choice_label" option. * * @internal * * @author Jules Pietri <jules@heahprod.com> */ final class ChoiceLabel extends AbstractStaticOption { } ChoiceList/Factory/Cache/ChoiceLoader.php 0000644 00000002635 15120211543 0014236 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory\Cache; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeInterface; /** * A cacheable wrapper for {@see FormTypeInterface} or {@see FormTypeExtensionInterface} * which configures a "choice_loader" option. * * @internal * * @author Jules Pietri <jules@heahprod.com> */ final class ChoiceLoader extends AbstractStaticOption implements ChoiceLoaderInterface { /** * {@inheritdoc} */ public function loadChoiceList(callable $value = null): ChoiceListInterface { return $this->getOption()->loadChoiceList($value); } /** * {@inheritdoc} */ public function loadChoicesForValues(array $values, callable $value = null): array { return $this->getOption()->loadChoicesForValues($values, $value); } /** * {@inheritdoc} */ public function loadValuesForChoices(array $choices, callable $value = null): array { return $this->getOption()->loadValuesForChoices($choices, $value); } } ChoiceList/Factory/Cache/ChoiceTranslationParameters.php 0000644 00000001324 15120211543 0017344 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory\Cache; use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeInterface; /** * A cacheable wrapper for any {@see FormTypeInterface} or {@see FormTypeExtensionInterface} * which configures a "choice_translation_parameters" option. * * @internal * * @author Vincent Langlet <vincentlanglet@users.noreply.github.com> */ final class ChoiceTranslationParameters extends AbstractStaticOption { } ChoiceList/Factory/Cache/ChoiceValue.php 0000644 00000001235 15120211543 0014077 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory\Cache; use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeInterface; /** * A cacheable wrapper for any {@see FormTypeInterface} or {@see FormTypeExtensionInterface} * which configures a "choice_value" callback. * * @internal * * @author Jules Pietri <jules@heahprod.com> */ final class ChoiceValue extends AbstractStaticOption { } ChoiceList/Factory/Cache/GroupBy.php 0000644 00000001225 15120211543 0013276 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory\Cache; use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeInterface; /** * A cacheable wrapper for any {@see FormTypeInterface} or {@see FormTypeExtensionInterface} * which configures a "group_by" callback. * * @internal * * @author Jules Pietri <jules@heahprod.com> */ final class GroupBy extends AbstractStaticOption { } ChoiceList/Factory/Cache/PreferredChoice.php 0000644 00000001244 15120211543 0014741 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory\Cache; use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeInterface; /** * A cacheable wrapper for any {@see FormTypeInterface} or {@see FormTypeExtensionInterface} * which configures a "preferred_choices" option. * * @internal * * @author Jules Pietri <jules@heahprod.com> */ final class PreferredChoice extends AbstractStaticOption { } ChoiceList/Factory/CachingFactoryDecorator.php 0000644 00000016322 15120211543 0015437 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\View\ChoiceListView; use Symfony\Contracts\Service\ResetInterface; /** * Caches the choice lists created by the decorated factory. * * To cache a list based on its options, arguments must be decorated * by a {@see Cache\AbstractStaticOption} implementation. * * @author Bernhard Schussek <bschussek@gmail.com> * @author Jules Pietri <jules@heahprod.com> */ class CachingFactoryDecorator implements ChoiceListFactoryInterface, ResetInterface { private $decoratedFactory; /** * @var ChoiceListInterface[] */ private $lists = []; /** * @var ChoiceListView[] */ private $views = []; /** * Generates a SHA-256 hash for the given value. * * Optionally, a namespace string can be passed. Calling this method will * the same values, but different namespaces, will return different hashes. * * @param mixed $value The value to hash * * @return string The SHA-256 hash * * @internal */ public static function generateHash($value, string $namespace = ''): string { if (\is_object($value)) { $value = spl_object_hash($value); } elseif (\is_array($value)) { array_walk_recursive($value, function (&$v) { if (\is_object($v)) { $v = spl_object_hash($v); } }); } return hash('sha256', $namespace.':'.serialize($value)); } public function __construct(ChoiceListFactoryInterface $decoratedFactory) { $this->decoratedFactory = $decoratedFactory; } /** * Returns the decorated factory. * * @return ChoiceListFactoryInterface */ public function getDecoratedFactory() { return $this->decoratedFactory; } /** * {@inheritdoc} * * @param mixed $value * @param mixed $filter */ public function createListFromChoices(iterable $choices, $value = null/* , $filter = null */) { $filter = \func_num_args() > 2 ? func_get_arg(2) : null; if ($choices instanceof \Traversable) { $choices = iterator_to_array($choices); } $cache = true; // Only cache per value and filter when needed. The value is not validated on purpose. // The decorated factory may decide which values to accept and which not. if ($value instanceof Cache\ChoiceValue) { $value = $value->getOption(); } elseif ($value) { $cache = false; } if ($filter instanceof Cache\ChoiceFilter) { $filter = $filter->getOption(); } elseif ($filter) { $cache = false; } if (!$cache) { return $this->decoratedFactory->createListFromChoices($choices, $value, $filter); } $hash = self::generateHash([$choices, $value, $filter], 'fromChoices'); if (!isset($this->lists[$hash])) { $this->lists[$hash] = $this->decoratedFactory->createListFromChoices($choices, $value, $filter); } return $this->lists[$hash]; } /** * {@inheritdoc} * * @param mixed $value * @param mixed $filter */ public function createListFromLoader(ChoiceLoaderInterface $loader, $value = null/* , $filter = null */) { $filter = \func_num_args() > 2 ? func_get_arg(2) : null; $cache = true; if ($loader instanceof Cache\ChoiceLoader) { $loader = $loader->getOption(); } else { $cache = false; } if ($value instanceof Cache\ChoiceValue) { $value = $value->getOption(); } elseif ($value) { $cache = false; } if ($filter instanceof Cache\ChoiceFilter) { $filter = $filter->getOption(); } elseif ($filter) { $cache = false; } if (!$cache) { return $this->decoratedFactory->createListFromLoader($loader, $value, $filter); } $hash = self::generateHash([$loader, $value, $filter], 'fromLoader'); if (!isset($this->lists[$hash])) { $this->lists[$hash] = $this->decoratedFactory->createListFromLoader($loader, $value, $filter); } return $this->lists[$hash]; } /** * {@inheritdoc} * * @param mixed $preferredChoices * @param mixed $label * @param mixed $index * @param mixed $groupBy * @param mixed $attr * @param mixed $labelTranslationParameters */ public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null/* , $labelTranslationParameters = [] */) { $labelTranslationParameters = \func_num_args() > 6 ? func_get_arg(6) : []; $cache = true; if ($preferredChoices instanceof Cache\PreferredChoice) { $preferredChoices = $preferredChoices->getOption(); } elseif ($preferredChoices) { $cache = false; } if ($label instanceof Cache\ChoiceLabel) { $label = $label->getOption(); } elseif (null !== $label) { $cache = false; } if ($index instanceof Cache\ChoiceFieldName) { $index = $index->getOption(); } elseif ($index) { $cache = false; } if ($groupBy instanceof Cache\GroupBy) { $groupBy = $groupBy->getOption(); } elseif ($groupBy) { $cache = false; } if ($attr instanceof Cache\ChoiceAttr) { $attr = $attr->getOption(); } elseif ($attr) { $cache = false; } if ($labelTranslationParameters instanceof Cache\ChoiceTranslationParameters) { $labelTranslationParameters = $labelTranslationParameters->getOption(); } elseif ([] !== $labelTranslationParameters) { $cache = false; } if (!$cache) { return $this->decoratedFactory->createView( $list, $preferredChoices, $label, $index, $groupBy, $attr, $labelTranslationParameters ); } $hash = self::generateHash([$list, $preferredChoices, $label, $index, $groupBy, $attr, $labelTranslationParameters]); if (!isset($this->views[$hash])) { $this->views[$hash] = $this->decoratedFactory->createView( $list, $preferredChoices, $label, $index, $groupBy, $attr, $labelTranslationParameters ); } return $this->views[$hash]; } public function reset() { $this->lists = []; $this->views = []; Cache\AbstractStaticOption::reset(); } } ChoiceList/Factory/ChoiceListFactoryInterface.php 0000644 00000007370 15120211543 0016112 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\View\ChoiceListView; /** * Creates {@link ChoiceListInterface} instances. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface ChoiceListFactoryInterface { /** * Creates a choice list for the given choices. * * The choices should be passed in the values of the choices array. * * Optionally, a callable can be passed for generating the choice values. * The callable receives the choice as only argument. * Null may be passed when the choice list contains the empty value. * * @param callable|null $filter The callable filtering the choices * * @return ChoiceListInterface */ public function createListFromChoices(iterable $choices, callable $value = null/* , callable $filter = null */); /** * Creates a choice list that is loaded with the given loader. * * Optionally, a callable can be passed for generating the choice values. * The callable receives the choice as only argument. * Null may be passed when the choice list contains the empty value. * * @param callable|null $filter The callable filtering the choices * * @return ChoiceListInterface */ public function createListFromLoader(ChoiceLoaderInterface $loader, callable $value = null/* , callable $filter = null */); /** * Creates a view for the given choice list. * * Callables may be passed for all optional arguments. The callables receive * the choice as first and the array key as the second argument. * * * The callable for the label and the name should return the generated * label/choice name. * * The callable for the preferred choices should return true or false, * depending on whether the choice should be preferred or not. * * The callable for the grouping should return the group name or null if * a choice should not be grouped. * * The callable for the attributes should return an array of HTML * attributes that will be inserted in the tag of the choice. * * If no callable is passed, the labels will be generated from the choice * keys. The view indices will be generated using an incrementing integer * by default. * * The preferred choices can also be passed as array. Each choice that is * contained in that array will be marked as preferred. * * The attributes can be passed as multi-dimensional array. The keys should * match the keys of the choices. The values should be arrays of HTML * attributes that should be added to the respective choice. * * @param array|callable|null $preferredChoices The preferred choices * @param callable|false|null $label The callable generating the choice labels; * pass false to discard the label * @param array|callable|null $attr The callable generating the HTML attributes * @param array|callable $labelTranslationParameters The parameters used to translate the choice labels * * @return ChoiceListView */ public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, callable $index = null, callable $groupBy = null, $attr = null/* , $labelTranslationParameters = [] */); } ChoiceList/Factory/DefaultChoiceListFactory.php 0000644 00000027515 15120211543 0015601 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory; use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\ChoiceList\LazyChoiceList; use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\FilterChoiceLoaderDecorator; use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView; use Symfony\Component\Form\ChoiceList\View\ChoiceListView; use Symfony\Component\Form\ChoiceList\View\ChoiceView; use Symfony\Component\Translation\TranslatableMessage; /** * Default implementation of {@link ChoiceListFactoryInterface}. * * @author Bernhard Schussek <bschussek@gmail.com> * @author Jules Pietri <jules@heahprod.com> */ class DefaultChoiceListFactory implements ChoiceListFactoryInterface { /** * {@inheritdoc} * * @param callable|null $filter */ public function createListFromChoices(iterable $choices, callable $value = null/* , callable $filter = null */) { $filter = \func_num_args() > 2 ? func_get_arg(2) : null; if ($filter) { // filter the choice list lazily return $this->createListFromLoader(new FilterChoiceLoaderDecorator( new CallbackChoiceLoader(static function () use ($choices) { return $choices; } ), $filter), $value); } return new ArrayChoiceList($choices, $value); } /** * {@inheritdoc} * * @param callable|null $filter */ public function createListFromLoader(ChoiceLoaderInterface $loader, callable $value = null/* , callable $filter = null */) { $filter = \func_num_args() > 2 ? func_get_arg(2) : null; if ($filter) { $loader = new FilterChoiceLoaderDecorator($loader, $filter); } return new LazyChoiceList($loader, $value); } /** * {@inheritdoc} * * @param array|callable $labelTranslationParameters The parameters used to translate the choice labels */ public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, callable $index = null, callable $groupBy = null, $attr = null/* , $labelTranslationParameters = [] */) { $labelTranslationParameters = \func_num_args() > 6 ? func_get_arg(6) : []; $preferredViews = []; $preferredViewsOrder = []; $otherViews = []; $choices = $list->getChoices(); $keys = $list->getOriginalKeys(); if (!\is_callable($preferredChoices)) { if (empty($preferredChoices)) { $preferredChoices = null; } else { // make sure we have keys that reflect order $preferredChoices = array_values($preferredChoices); $preferredChoices = static function ($choice) use ($preferredChoices) { return array_search($choice, $preferredChoices, true); }; } } // The names are generated from an incrementing integer by default if (null === $index) { $index = 0; } // If $groupBy is a callable returning a string // choices are added to the group with the name returned by the callable. // If $groupBy is a callable returning an array // choices are added to the groups with names returned by the callable // If the callable returns null, the choice is not added to any group if (\is_callable($groupBy)) { foreach ($choices as $value => $choice) { self::addChoiceViewsGroupedByCallable( $groupBy, $choice, $value, $label, $keys, $index, $attr, $labelTranslationParameters, $preferredChoices, $preferredViews, $preferredViewsOrder, $otherViews ); } // Remove empty group views that may have been created by // addChoiceViewsGroupedByCallable() foreach ($preferredViews as $key => $view) { if ($view instanceof ChoiceGroupView && 0 === \count($view->choices)) { unset($preferredViews[$key]); } } foreach ($otherViews as $key => $view) { if ($view instanceof ChoiceGroupView && 0 === \count($view->choices)) { unset($otherViews[$key]); } } foreach ($preferredViewsOrder as $key => $groupViewsOrder) { if ($groupViewsOrder) { $preferredViewsOrder[$key] = min($groupViewsOrder); } else { unset($preferredViewsOrder[$key]); } } } else { // Otherwise use the original structure of the choices self::addChoiceViewsFromStructuredValues( $list->getStructuredValues(), $label, $choices, $keys, $index, $attr, $labelTranslationParameters, $preferredChoices, $preferredViews, $preferredViewsOrder, $otherViews ); } uksort($preferredViews, static function ($a, $b) use ($preferredViewsOrder): int { return isset($preferredViewsOrder[$a], $preferredViewsOrder[$b]) ? $preferredViewsOrder[$a] <=> $preferredViewsOrder[$b] : 0; }); return new ChoiceListView($otherViews, $preferredViews); } private static function addChoiceView($choice, string $value, $label, array $keys, &$index, $attr, $labelTranslationParameters, ?callable $isPreferred, array &$preferredViews, array &$preferredViewsOrder, array &$otherViews) { // $value may be an integer or a string, since it's stored in the array // keys. We want to guarantee it's a string though. $key = $keys[$value]; $nextIndex = \is_int($index) ? $index++ : $index($choice, $key, $value); // BC normalize label to accept a false value if (null === $label) { // If the labels are null, use the original choice key by default $label = (string) $key; } elseif (false !== $label) { // If "choice_label" is set to false and "expanded" is true, the value false // should be passed on to the "label" option of the checkboxes/radio buttons $dynamicLabel = $label($choice, $key, $value); if (false === $dynamicLabel) { $label = false; } elseif ($dynamicLabel instanceof TranslatableMessage) { $label = $dynamicLabel; } else { $label = (string) $dynamicLabel; } } $view = new ChoiceView( $choice, $value, $label, // The attributes may be a callable or a mapping from choice indices // to nested arrays \is_callable($attr) ? $attr($choice, $key, $value) : ($attr[$key] ?? []), // The label translation parameters may be a callable or a mapping from choice indices // to nested arrays \is_callable($labelTranslationParameters) ? $labelTranslationParameters($choice, $key, $value) : ($labelTranslationParameters[$key] ?? []) ); // $isPreferred may be null if no choices are preferred if (null !== $isPreferred && false !== $preferredKey = $isPreferred($choice, $key, $value)) { $preferredViews[$nextIndex] = $view; $preferredViewsOrder[$nextIndex] = $preferredKey; } $otherViews[$nextIndex] = $view; } private static function addChoiceViewsFromStructuredValues(array $values, $label, array $choices, array $keys, &$index, $attr, $labelTranslationParameters, ?callable $isPreferred, array &$preferredViews, array &$preferredViewsOrder, array &$otherViews) { foreach ($values as $key => $value) { if (null === $value) { continue; } // Add the contents of groups to new ChoiceGroupView instances if (\is_array($value)) { $preferredViewsForGroup = []; $otherViewsForGroup = []; self::addChoiceViewsFromStructuredValues( $value, $label, $choices, $keys, $index, $attr, $labelTranslationParameters, $isPreferred, $preferredViewsForGroup, $preferredViewsOrder, $otherViewsForGroup ); if (\count($preferredViewsForGroup) > 0) { $preferredViews[$key] = new ChoiceGroupView($key, $preferredViewsForGroup); } if (\count($otherViewsForGroup) > 0) { $otherViews[$key] = new ChoiceGroupView($key, $otherViewsForGroup); } continue; } // Add ungrouped items directly self::addChoiceView( $choices[$value], $value, $label, $keys, $index, $attr, $labelTranslationParameters, $isPreferred, $preferredViews, $preferredViewsOrder, $otherViews ); } } private static function addChoiceViewsGroupedByCallable(callable $groupBy, $choice, string $value, $label, array $keys, &$index, $attr, $labelTranslationParameters, ?callable $isPreferred, array &$preferredViews, array &$preferredViewsOrder, array &$otherViews) { $groupLabels = $groupBy($choice, $keys[$value], $value); if (null === $groupLabels) { // If the callable returns null, don't group the choice self::addChoiceView( $choice, $value, $label, $keys, $index, $attr, $labelTranslationParameters, $isPreferred, $preferredViews, $preferredViewsOrder, $otherViews ); return; } $groupLabels = \is_array($groupLabels) ? array_map('strval', $groupLabels) : [(string) $groupLabels]; foreach ($groupLabels as $groupLabel) { // Initialize the group views if necessary. Unnecessarily built group // views will be cleaned up at the end of createView() if (!isset($preferredViews[$groupLabel])) { $preferredViews[$groupLabel] = new ChoiceGroupView($groupLabel); $otherViews[$groupLabel] = new ChoiceGroupView($groupLabel); } if (!isset($preferredViewsOrder[$groupLabel])) { $preferredViewsOrder[$groupLabel] = []; } self::addChoiceView( $choice, $value, $label, $keys, $index, $attr, $labelTranslationParameters, $isPreferred, $preferredViews[$groupLabel]->choices, $preferredViewsOrder[$groupLabel], $otherViews[$groupLabel]->choices ); } } } ChoiceList/Factory/PropertyAccessDecorator.php 0000644 00000017722 15120211543 0015526 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Factory; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\View\ChoiceListView; use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\PropertyAccess\PropertyPath; use Symfony\Component\PropertyAccess\PropertyPathInterface; /** * Adds property path support to a choice list factory. * * Pass the decorated factory to the constructor: * * $decorator = new PropertyAccessDecorator($factory); * * You can now pass property paths for generating choice values, labels, view * indices, HTML attributes and for determining the preferred choices and the * choice groups: * * // extract values from the $value property * $list = $createListFromChoices($objects, 'value'); * * @author Bernhard Schussek <bschussek@gmail.com> */ class PropertyAccessDecorator implements ChoiceListFactoryInterface { private $decoratedFactory; private $propertyAccessor; public function __construct(ChoiceListFactoryInterface $decoratedFactory, PropertyAccessorInterface $propertyAccessor = null) { $this->decoratedFactory = $decoratedFactory; $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); } /** * Returns the decorated factory. * * @return ChoiceListFactoryInterface */ public function getDecoratedFactory() { return $this->decoratedFactory; } /** * {@inheritdoc} * * @param mixed $value * @param mixed $filter * * @return ChoiceListInterface */ public function createListFromChoices(iterable $choices, $value = null/* , $filter = null */) { $filter = \func_num_args() > 2 ? func_get_arg(2) : null; if (\is_string($value)) { $value = new PropertyPath($value); } if ($value instanceof PropertyPathInterface) { $accessor = $this->propertyAccessor; $value = function ($choice) use ($accessor, $value) { // The callable may be invoked with a non-object/array value // when such values are passed to // ChoiceListInterface::getValuesForChoices(). Handle this case // so that the call to getValue() doesn't break. return \is_object($choice) || \is_array($choice) ? $accessor->getValue($choice, $value) : null; }; } if (\is_string($filter)) { $filter = new PropertyPath($filter); } if ($filter instanceof PropertyPath) { $accessor = $this->propertyAccessor; $filter = static function ($choice) use ($accessor, $filter) { return (\is_object($choice) || \is_array($choice)) && $accessor->getValue($choice, $filter); }; } return $this->decoratedFactory->createListFromChoices($choices, $value, $filter); } /** * {@inheritdoc} * * @param mixed $value * @param mixed $filter * * @return ChoiceListInterface */ public function createListFromLoader(ChoiceLoaderInterface $loader, $value = null/* , $filter = null */) { $filter = \func_num_args() > 2 ? func_get_arg(2) : null; if (\is_string($value)) { $value = new PropertyPath($value); } if ($value instanceof PropertyPathInterface) { $accessor = $this->propertyAccessor; $value = function ($choice) use ($accessor, $value) { // The callable may be invoked with a non-object/array value // when such values are passed to // ChoiceListInterface::getValuesForChoices(). Handle this case // so that the call to getValue() doesn't break. return \is_object($choice) || \is_array($choice) ? $accessor->getValue($choice, $value) : null; }; } if (\is_string($filter)) { $filter = new PropertyPath($filter); } if ($filter instanceof PropertyPath) { $accessor = $this->propertyAccessor; $filter = static function ($choice) use ($accessor, $filter) { return (\is_object($choice) || \is_array($choice)) && $accessor->getValue($choice, $filter); }; } return $this->decoratedFactory->createListFromLoader($loader, $value, $filter); } /** * {@inheritdoc} * * @param mixed $preferredChoices * @param mixed $label * @param mixed $index * @param mixed $groupBy * @param mixed $attr * @param mixed $labelTranslationParameters * * @return ChoiceListView */ public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null/* , $labelTranslationParameters = [] */) { $labelTranslationParameters = \func_num_args() > 6 ? func_get_arg(6) : []; $accessor = $this->propertyAccessor; if (\is_string($label)) { $label = new PropertyPath($label); } if ($label instanceof PropertyPathInterface) { $label = function ($choice) use ($accessor, $label) { return $accessor->getValue($choice, $label); }; } if (\is_string($preferredChoices)) { $preferredChoices = new PropertyPath($preferredChoices); } if ($preferredChoices instanceof PropertyPathInterface) { $preferredChoices = function ($choice) use ($accessor, $preferredChoices) { try { return $accessor->getValue($choice, $preferredChoices); } catch (UnexpectedTypeException $e) { // Assume not preferred if not readable return false; } }; } if (\is_string($index)) { $index = new PropertyPath($index); } if ($index instanceof PropertyPathInterface) { $index = function ($choice) use ($accessor, $index) { return $accessor->getValue($choice, $index); }; } if (\is_string($groupBy)) { $groupBy = new PropertyPath($groupBy); } if ($groupBy instanceof PropertyPathInterface) { $groupBy = function ($choice) use ($accessor, $groupBy) { try { return $accessor->getValue($choice, $groupBy); } catch (UnexpectedTypeException $e) { // Don't group if path is not readable return null; } }; } if (\is_string($attr)) { $attr = new PropertyPath($attr); } if ($attr instanceof PropertyPathInterface) { $attr = function ($choice) use ($accessor, $attr) { return $accessor->getValue($choice, $attr); }; } if (\is_string($labelTranslationParameters)) { $labelTranslationParameters = new PropertyPath($labelTranslationParameters); } if ($labelTranslationParameters instanceof PropertyPath) { $labelTranslationParameters = static function ($choice) use ($accessor, $labelTranslationParameters) { return $accessor->getValue($choice, $labelTranslationParameters); }; } return $this->decoratedFactory->createView( $list, $preferredChoices, $label, $index, $groupBy, $attr, $labelTranslationParameters ); } } ChoiceList/Loader/AbstractChoiceLoader.php 0000644 00000003642 15120211543 0014515 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Loader; use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; /** * @author Jules Pietri <jules@heahprod.com> */ abstract class AbstractChoiceLoader implements ChoiceLoaderInterface { /** * The loaded choices. * * @var iterable|null */ private $choices; /** * @final * * {@inheritdoc} */ public function loadChoiceList(callable $value = null): ChoiceListInterface { return new ArrayChoiceList($this->choices ?? $this->choices = $this->loadChoices(), $value); } /** * {@inheritdoc} */ public function loadChoicesForValues(array $values, callable $value = null) { if (!$values) { return []; } return $this->doLoadChoicesForValues($values, $value); } /** * {@inheritdoc} */ public function loadValuesForChoices(array $choices, callable $value = null) { if (!$choices) { return []; } if ($value) { // if a value callback exists, use it return array_map(function ($item) use ($value) { return (string) $value($item); }, $choices); } return $this->doLoadValuesForChoices($choices); } abstract protected function loadChoices(): iterable; protected function doLoadChoicesForValues(array $values, ?callable $value): array { return $this->loadChoiceList($value)->getChoicesForValues($values); } protected function doLoadValuesForChoices(array $choices): array { return $this->loadChoiceList()->getValuesForChoices($choices); } } ChoiceList/Loader/CallbackChoiceLoader.php 0000644 00000001446 15120211543 0014446 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Loader; /** * Loads an {@link ArrayChoiceList} instance from a callable returning iterable choices. * * @author Jules Pietri <jules@heahprod.com> */ class CallbackChoiceLoader extends AbstractChoiceLoader { private $callback; /** * @param callable $callback The callable returning iterable choices */ public function __construct(callable $callback) { $this->callback = $callback; } protected function loadChoices(): iterable { return ($this->callback)(); } } ChoiceList/Loader/ChoiceLoaderInterface.php 0000644 00000005204 15120211543 0014646 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Loader; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; /** * Loads a choice list. * * The methods {@link loadChoicesForValues()} and {@link loadValuesForChoices()} * can be used to load the list only partially in cases where a fully-loaded * list is not necessary. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface ChoiceLoaderInterface { /** * Loads a list of choices. * * Optionally, a callable can be passed for generating the choice values. * The callable receives the choice as only argument. * Null may be passed when the choice list contains the empty value. * * @param callable|null $value The callable which generates the values * from choices * * @return ChoiceListInterface */ public function loadChoiceList(callable $value = null); /** * Loads the choices corresponding to the given values. * * The choices are returned with the same keys and in the same order as the * corresponding values in the given array. * * Optionally, a callable can be passed for generating the choice values. * The callable receives the choice as only argument. * Null may be passed when the choice list contains the empty value. * * @param string[] $values An array of choice values. Non-existing * values in this array are ignored * @param callable|null $value The callable generating the choice values * * @return array */ public function loadChoicesForValues(array $values, callable $value = null); /** * Loads the values corresponding to the given choices. * * The values are returned with the same keys and in the same order as the * corresponding choices in the given array. * * Optionally, a callable can be passed for generating the choice values. * The callable receives the choice as only argument. * Null may be passed when the choice list contains the empty value. * * @param array $choices An array of choices. Non-existing choices in * this array are ignored * @param callable|null $value The callable generating the choice values * * @return string[] */ public function loadValuesForChoices(array $choices, callable $value = null); } ChoiceList/Loader/FilterChoiceLoaderDecorator.php 0000644 00000004106 15120211543 0016036 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Loader; /** * A decorator to filter choices only when they are loaded or partially loaded. * * @author Jules Pietri <jules@heahprod.com> */ class FilterChoiceLoaderDecorator extends AbstractChoiceLoader { private $decoratedLoader; private $filter; public function __construct(ChoiceLoaderInterface $loader, callable $filter) { $this->decoratedLoader = $loader; $this->filter = $filter; } protected function loadChoices(): iterable { $list = $this->decoratedLoader->loadChoiceList(); if (array_values($list->getValues()) === array_values($structuredValues = $list->getStructuredValues())) { return array_filter(array_combine($list->getOriginalKeys(), $list->getChoices()), $this->filter); } foreach ($structuredValues as $group => $values) { if (\is_array($values)) { if ($values && $filtered = array_filter($list->getChoicesForValues($values), $this->filter)) { $choices[$group] = $filtered; } continue; // filter empty groups } if ($filtered = array_filter($list->getChoicesForValues([$values]), $this->filter)) { $choices[$group] = $filtered[0]; } } return $choices ?? []; } /** * {@inheritdoc} */ public function loadChoicesForValues(array $values, callable $value = null): array { return array_filter($this->decoratedLoader->loadChoicesForValues($values, $value), $this->filter); } /** * {@inheritdoc} */ public function loadValuesForChoices(array $choices, callable $value = null): array { return $this->decoratedLoader->loadValuesForChoices(array_filter($choices, $this->filter), $value); } } ChoiceList/Loader/IntlCallbackChoiceLoader.php 0000644 00000002111 15120211543 0015263 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\Loader; /** * Callback choice loader optimized for Intl choice types. * * @author Jules Pietri <jules@heahprod.com> * @author Yonel Ceruto <yonelceruto@gmail.com> */ class IntlCallbackChoiceLoader extends CallbackChoiceLoader { /** * {@inheritdoc} */ public function loadChoicesForValues(array $values, callable $value = null) { return parent::loadChoicesForValues(array_filter($values), $value); } /** * {@inheritdoc} */ public function loadValuesForChoices(array $choices, callable $value = null) { $choices = array_filter($choices); // If no callable is set, choices are the same as values if (null === $value) { return $choices; } return parent::loadValuesForChoices($choices, $value); } } ChoiceList/View/ChoiceGroupView.php 0000644 00000002134 15120211543 0013251 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\View; /** * Represents a group of choices in templates. * * @author Bernhard Schussek <bschussek@gmail.com> * * @implements \IteratorAggregate<array-key, ChoiceGroupView|ChoiceView> */ class ChoiceGroupView implements \IteratorAggregate { public $label; public $choices; /** * Creates a new choice group view. * * @param array<array-key, ChoiceGroupView|ChoiceView> $choices the choice views in the group */ public function __construct(string $label, array $choices = []) { $this->label = $label; $this->choices = $choices; } /** * {@inheritdoc} * * @return \Traversable<array-key, ChoiceGroupView|ChoiceView> */ #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->choices); } } ChoiceList/View/ChoiceListView.php 0000644 00000003220 15120211543 0013065 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\View; /** * Represents a choice list in templates. * * A choice list contains choices and optionally preferred choices which are * displayed in the very beginning of the list. Both choices and preferred * choices may be grouped in {@link ChoiceGroupView} instances. * * @author Bernhard Schussek <bschussek@gmail.com> */ class ChoiceListView { public $choices; public $preferredChoices; /** * Creates a new choice list view. * * @param ChoiceGroupView[]|ChoiceView[] $choices The choice views * @param ChoiceGroupView[]|ChoiceView[] $preferredChoices the preferred choice views */ public function __construct(array $choices = [], array $preferredChoices = []) { $this->choices = $choices; $this->preferredChoices = $preferredChoices; } /** * Returns whether a placeholder is in the choices. * * A placeholder must be the first child element, not be in a group and have an empty value. * * @return bool */ public function hasPlaceholder() { if ($this->preferredChoices) { $firstChoice = reset($this->preferredChoices); return $firstChoice instanceof ChoiceView && '' === $firstChoice->value; } $firstChoice = reset($this->choices); return $firstChoice instanceof ChoiceView && '' === $firstChoice->value; } } ChoiceList/View/ChoiceView.php 0000644 00000003226 15120211543 0012237 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList\View; use Symfony\Component\Translation\TranslatableMessage; /** * Represents a choice in templates. * * @author Bernhard Schussek <bschussek@gmail.com> */ class ChoiceView { public $label; public $value; public $data; /** * Additional attributes for the HTML tag. */ public $attr; /** * Additional parameters used to translate the label. */ public $labelTranslationParameters; /** * Creates a new choice view. * * @param mixed $data The original choice * @param string $value The view representation of the choice * @param string|TranslatableMessage|false $label The label displayed to humans; pass false to discard the label * @param array $attr Additional attributes for the HTML tag * @param array $labelTranslationParameters Additional parameters used to translate the label */ public function __construct($data, string $value, $label, array $attr = [], array $labelTranslationParameters = []) { $this->data = $data; $this->value = $value; $this->label = $label; $this->attr = $attr; $this->labelTranslationParameters = $labelTranslationParameters; } } ChoiceList/ArrayChoiceList.php 0000644 00000015237 15120211543 0012332 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList; /** * A list of choices with arbitrary data types. * * The user of this class is responsible for assigning string values to the * choices and for their uniqueness. * Both the choices and their values are passed to the constructor. * Each choice must have a corresponding value (with the same key) in * the values array. * * @author Bernhard Schussek <bschussek@gmail.com> */ class ArrayChoiceList implements ChoiceListInterface { /** * The choices in the list. * * @var array */ protected $choices; /** * The values indexed by the original keys. * * @var array */ protected $structuredValues; /** * The original keys of the choices array. * * @var int[]|string[] */ protected $originalKeys; protected $valueCallback; /** * Creates a list with the given choices and values. * * The given choice array must have the same array keys as the value array. * * @param iterable $choices The selectable choices * @param callable|null $value The callable for creating the value * for a choice. If `null` is passed, * incrementing integers are used as * values */ public function __construct(iterable $choices, callable $value = null) { if ($choices instanceof \Traversable) { $choices = iterator_to_array($choices); } if (null === $value && $this->castableToString($choices)) { $value = function ($choice) { return false === $choice ? '0' : (string) $choice; }; } if (null !== $value) { // If a deterministic value generator was passed, use it later $this->valueCallback = $value; } else { // Otherwise generate incrementing integers as values $i = 0; $value = function () use (&$i) { return $i++; }; } // If the choices are given as recursive array (i.e. with explicit // choice groups), flatten the array. The grouping information is needed // in the view only. $this->flatten($choices, $value, $choicesByValues, $keysByValues, $structuredValues); $this->choices = $choicesByValues; $this->originalKeys = $keysByValues; $this->structuredValues = $structuredValues; } /** * {@inheritdoc} */ public function getChoices() { return $this->choices; } /** * {@inheritdoc} */ public function getValues() { return array_map('strval', array_keys($this->choices)); } /** * {@inheritdoc} */ public function getStructuredValues() { return $this->structuredValues; } /** * {@inheritdoc} */ public function getOriginalKeys() { return $this->originalKeys; } /** * {@inheritdoc} */ public function getChoicesForValues(array $values) { $choices = []; foreach ($values as $i => $givenValue) { if (\array_key_exists($givenValue, $this->choices)) { $choices[$i] = $this->choices[$givenValue]; } } return $choices; } /** * {@inheritdoc} */ public function getValuesForChoices(array $choices) { $values = []; // Use the value callback to compare choices by their values, if present if ($this->valueCallback) { $givenValues = []; foreach ($choices as $i => $givenChoice) { $givenValues[$i] = (string) ($this->valueCallback)($givenChoice); } return array_intersect($givenValues, array_keys($this->choices)); } // Otherwise compare choices by identity foreach ($choices as $i => $givenChoice) { foreach ($this->choices as $value => $choice) { if ($choice === $givenChoice) { $values[$i] = (string) $value; break; } } } return $values; } /** * Flattens an array into the given output variables. * * @param array $choices The array to flatten * @param callable $value The callable for generating choice values * @param array|null $choicesByValues The flattened choices indexed by the * corresponding values * @param array|null $keysByValues The original keys indexed by the * corresponding values * @param array|null $structuredValues The values indexed by the original keys * * @internal */ protected function flatten(array $choices, callable $value, ?array &$choicesByValues, ?array &$keysByValues, ?array &$structuredValues) { if (null === $choicesByValues) { $choicesByValues = []; $keysByValues = []; $structuredValues = []; } foreach ($choices as $key => $choice) { if (\is_array($choice)) { $this->flatten($choice, $value, $choicesByValues, $keysByValues, $structuredValues[$key]); continue; } $choiceValue = (string) $value($choice); $choicesByValues[$choiceValue] = $choice; $keysByValues[$choiceValue] = $key; $structuredValues[$key] = $choiceValue; } } /** * Checks whether the given choices can be cast to strings without * generating duplicates. * This method is responsible for preventing conflict between scalar values * and the empty value. */ private function castableToString(array $choices, array &$cache = []): bool { foreach ($choices as $choice) { if (\is_array($choice)) { if (!$this->castableToString($choice, $cache)) { return false; } continue; } elseif (!\is_scalar($choice)) { return false; } // prevent having false casted to the empty string by isset() $choice = false === $choice ? '0' : (string) $choice; if (isset($cache[$choice])) { return false; } $cache[$choice] = true; } return true; } } ChoiceList/ChoiceList.php 0000644 00000017452 15120211543 0011334 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceAttr; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceFieldName; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceFilter; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceLabel; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceLoader; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceTranslationParameters; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceValue; use Symfony\Component\Form\ChoiceList\Factory\Cache\GroupBy; use Symfony\Component\Form\ChoiceList\Factory\Cache\PreferredChoice; use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeInterface; /** * A set of convenient static methods to create cacheable choice list options. * * @author Jules Pietri <jules@heahprod.com> */ final class ChoiceList { /** * Creates a cacheable loader from any callable providing iterable choices. * * @param FormTypeInterface|FormTypeExtensionInterface $formType A form type or type extension configuring a cacheable choice list * @param callable $choices A callable that must return iterable choices or grouped choices * @param mixed|null $vary Dynamic data used to compute a unique hash when caching the loader */ public static function lazy($formType, callable $choices, $vary = null): ChoiceLoader { return self::loader($formType, new CallbackChoiceLoader($choices), $vary); } /** * Decorates a loader to make it cacheable. * * @param FormTypeInterface|FormTypeExtensionInterface $formType A form type or type extension configuring a cacheable choice list * @param ChoiceLoaderInterface $loader A loader responsible for creating loading choices or grouped choices * @param mixed|null $vary Dynamic data used to compute a unique hash when caching the loader */ public static function loader($formType, ChoiceLoaderInterface $loader, $vary = null): ChoiceLoader { return new ChoiceLoader($formType, $loader, $vary); } /** * Decorates a "choice_value" callback to make it cacheable. * * @param FormTypeInterface|FormTypeExtensionInterface $formType A form type or type extension configuring a cacheable choice list * @param callable $value Any pseudo callable to create a unique string value from a choice * @param mixed|null $vary Dynamic data used to compute a unique hash when caching the callback */ public static function value($formType, $value, $vary = null): ChoiceValue { return new ChoiceValue($formType, $value, $vary); } /** * @param FormTypeInterface|FormTypeExtensionInterface $formType A form type or type extension configuring a cacheable choice list * @param callable $filter Any pseudo callable to filter a choice list * @param mixed|null $vary Dynamic data used to compute a unique hash when caching the callback */ public static function filter($formType, $filter, $vary = null): ChoiceFilter { return new ChoiceFilter($formType, $filter, $vary); } /** * Decorates a "choice_label" option to make it cacheable. * * @param FormTypeInterface|FormTypeExtensionInterface $formType A form type or type extension configuring a cacheable choice list * @param callable|false $label Any pseudo callable to create a label from a choice or false to discard it * @param mixed|null $vary Dynamic data used to compute a unique hash when caching the option */ public static function label($formType, $label, $vary = null): ChoiceLabel { return new ChoiceLabel($formType, $label, $vary); } /** * Decorates a "choice_name" callback to make it cacheable. * * @param FormTypeInterface|FormTypeExtensionInterface $formType A form type or type extension configuring a cacheable choice list * @param callable $fieldName Any pseudo callable to create a field name from a choice * @param mixed|null $vary Dynamic data used to compute a unique hash when caching the callback */ public static function fieldName($formType, $fieldName, $vary = null): ChoiceFieldName { return new ChoiceFieldName($formType, $fieldName, $vary); } /** * Decorates a "choice_attr" option to make it cacheable. * * @param FormTypeInterface|FormTypeExtensionInterface $formType A form type or type extension configuring a cacheable choice list * @param callable|array $attr Any pseudo callable or array to create html attributes from a choice * @param mixed|null $vary Dynamic data used to compute a unique hash when caching the option */ public static function attr($formType, $attr, $vary = null): ChoiceAttr { return new ChoiceAttr($formType, $attr, $vary); } /** * Decorates a "choice_translation_parameters" option to make it cacheable. * * @param FormTypeInterface|FormTypeExtensionInterface $formType A form type or type extension configuring a cacheable choice list * @param callable|array $translationParameters Any pseudo callable or array to create translation parameters from a choice * @param mixed|null $vary Dynamic data used to compute a unique hash when caching the option */ public static function translationParameters($formType, $translationParameters, $vary = null): ChoiceTranslationParameters { return new ChoiceTranslationParameters($formType, $translationParameters, $vary); } /** * Decorates a "group_by" callback to make it cacheable. * * @param FormTypeInterface|FormTypeExtensionInterface $formType A form type or type extension configuring a cacheable choice list * @param callable $groupBy Any pseudo callable to return a group name from a choice * @param mixed|null $vary Dynamic data used to compute a unique hash when caching the callback */ public static function groupBy($formType, $groupBy, $vary = null): GroupBy { return new GroupBy($formType, $groupBy, $vary); } /** * Decorates a "preferred_choices" option to make it cacheable. * * @param FormTypeInterface|FormTypeExtensionInterface $formType A form type or type extension configuring a cacheable choice list * @param callable|array $preferred Any pseudo callable or array to return a group name from a choice * @param mixed|null $vary Dynamic data used to compute a unique hash when caching the option */ public static function preferred($formType, $preferred, $vary = null): PreferredChoice { return new PreferredChoice($formType, $preferred, $vary); } /** * Should not be instantiated. */ private function __construct() { } } ChoiceList/ChoiceListInterface.php 0000644 00000010621 15120211543 0013144 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList; /** * A list of choices that can be selected in a choice field. * * A choice list assigns unique string values to each of a list of choices. * These string values are displayed in the "value" attributes in HTML and * submitted back to the server. * * The acceptable data types for the choices depend on the implementation. * Values must always be strings and (within the list) free of duplicates. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface ChoiceListInterface { /** * Returns all selectable choices. * * @return array The selectable choices indexed by the corresponding values */ public function getChoices(); /** * Returns the values for the choices. * * The values are strings that do not contain duplicates: * * $form->add('field', 'choice', [ * 'choices' => [ * 'Decided' => ['Yes' => true, 'No' => false], * 'Undecided' => ['Maybe' => null], * ], * ]); * * In this example, the result of this method is: * * [ * 'Yes' => '0', * 'No' => '1', * 'Maybe' => '2', * ] * * Null and false MUST NOT conflict when being casted to string. * For this some default incremented values SHOULD be computed. * * @return string[] */ public function getValues(); /** * Returns the values in the structure originally passed to the list. * * Contrary to {@link getValues()}, the result is indexed by the original * keys of the choices. If the original array contained nested arrays, these * nested arrays are represented here as well: * * $form->add('field', 'choice', [ * 'choices' => [ * 'Decided' => ['Yes' => true, 'No' => false], * 'Undecided' => ['Maybe' => null], * ], * ]); * * In this example, the result of this method is: * * [ * 'Decided' => ['Yes' => '0', 'No' => '1'], * 'Undecided' => ['Maybe' => '2'], * ] * * Nested arrays do not make sense in a view format unless * they are used as a convenient way of grouping. * If the implementation does not intend to support grouped choices, * this method SHOULD be equivalent to {@link getValues()}. * The $groupBy callback parameter SHOULD be used instead. * * @return string[] */ public function getStructuredValues(); /** * Returns the original keys of the choices. * * The original keys are the keys of the choice array that was passed in the * "choice" option of the choice type. Note that this array may contain * duplicates if the "choice" option contained choice groups: * * $form->add('field', 'choice', [ * 'choices' => [ * 'Decided' => [true, false], * 'Undecided' => [null], * ], * ]); * * In this example, the original key 0 appears twice, once for `true` and * once for `null`. * * @return int[]|string[] The original choice keys indexed by the * corresponding choice values */ public function getOriginalKeys(); /** * Returns the choices corresponding to the given values. * * The choices are returned with the same keys and in the same order as the * corresponding values in the given array. * * @param string[] $values An array of choice values. Non-existing values in * this array are ignored * * @return array */ public function getChoicesForValues(array $values); /** * Returns the values corresponding to the given choices. * * The values are returned with the same keys and in the same order as the * corresponding choices in the given array. * * @param array $choices An array of choices. Non-existing choices in this * array are ignored * * @return string[] */ public function getValuesForChoices(array $choices); } ChoiceList/LazyChoiceList.php 0000644 00000005015 15120211543 0012164 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\ChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; /** * A choice list that loads its choices lazily. * * The choices are fetched using a {@link ChoiceLoaderInterface} instance. * If only {@link getChoicesForValues()} or {@link getValuesForChoices()} is * called, the choice list is only loaded partially for improved performance. * * Once {@link getChoices()} or {@link getValues()} is called, the list is * loaded fully. * * @author Bernhard Schussek <bschussek@gmail.com> */ class LazyChoiceList implements ChoiceListInterface { private $loader; /** * The callable creating string values for each choice. * * If null, choices are cast to strings. * * @var callable|null */ private $value; /** * Creates a lazily-loaded list using the given loader. * * Optionally, a callable can be passed for generating the choice values. * The callable receives the choice as first and the array key as the second * argument. * * @param callable|null $value The callable generating the choice values */ public function __construct(ChoiceLoaderInterface $loader, callable $value = null) { $this->loader = $loader; $this->value = $value; } /** * {@inheritdoc} */ public function getChoices() { return $this->loader->loadChoiceList($this->value)->getChoices(); } /** * {@inheritdoc} */ public function getValues() { return $this->loader->loadChoiceList($this->value)->getValues(); } /** * {@inheritdoc} */ public function getStructuredValues() { return $this->loader->loadChoiceList($this->value)->getStructuredValues(); } /** * {@inheritdoc} */ public function getOriginalKeys() { return $this->loader->loadChoiceList($this->value)->getOriginalKeys(); } /** * {@inheritdoc} */ public function getChoicesForValues(array $values) { return $this->loader->loadChoicesForValues($values, $this->value); } /** * {@inheritdoc} */ public function getValuesForChoices(array $choices) { return $this->loader->loadValuesForChoices($choices, $this->value); } } Command/DebugCommand.php 0000644 00000026211 15120211543 0011154 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Form\Console\Helper\DescriptorHelper; use Symfony\Component\Form\Extension\Core\CoreExtension; use Symfony\Component\Form\FormRegistryInterface; use Symfony\Component\Form\FormTypeInterface; use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; /** * A console command for retrieving information about form types. * * @author Yonel Ceruto <yonelceruto@gmail.com> */ class DebugCommand extends Command { protected static $defaultName = 'debug:form'; protected static $defaultDescription = 'Display form type information'; private $formRegistry; private $namespaces; private $types; private $extensions; private $guessers; private $fileLinkFormatter; public function __construct(FormRegistryInterface $formRegistry, array $namespaces = ['Symfony\Component\Form\Extension\Core\Type'], array $types = [], array $extensions = [], array $guessers = [], FileLinkFormatter $fileLinkFormatter = null) { parent::__construct(); $this->formRegistry = $formRegistry; $this->namespaces = $namespaces; $this->types = $types; $this->extensions = $extensions; $this->guessers = $guessers; $this->fileLinkFormatter = $fileLinkFormatter; } /** * {@inheritdoc} */ protected function configure() { $this ->setDefinition([ new InputArgument('class', InputArgument::OPTIONAL, 'The form type class'), new InputArgument('option', InputArgument::OPTIONAL, 'The form type option'), new InputOption('show-deprecated', null, InputOption::VALUE_NONE, 'Display deprecated options in form types'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt or json)', 'txt'), ]) ->setDescription(self::$defaultDescription) ->setHelp(<<<'EOF' The <info>%command.name%</info> command displays information about form types. <info>php %command.full_name%</info> The command lists all built-in types, services types, type extensions and guessers currently available. <info>php %command.full_name% Symfony\Component\Form\Extension\Core\Type\ChoiceType</info> <info>php %command.full_name% ChoiceType</info> The command lists all defined options that contains the given form type, as well as their parents and type extensions. <info>php %command.full_name% ChoiceType choice_value</info> Use the <info>--show-deprecated</info> option to display form types with deprecated options or the deprecated options of the given form type: <info>php %command.full_name% --show-deprecated</info> <info>php %command.full_name% ChoiceType --show-deprecated</info> The command displays the definition of the given option name. <info>php %command.full_name% --format=json</info> The command lists everything in a machine readable json format. EOF ) ; } /** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $io = new SymfonyStyle($input, $output); if (null === $class = $input->getArgument('class')) { $object = null; $options['core_types'] = $this->getCoreTypes(); $options['service_types'] = array_values(array_diff($this->types, $options['core_types'])); if ($input->getOption('show-deprecated')) { $options['core_types'] = $this->filterTypesByDeprecated($options['core_types']); $options['service_types'] = $this->filterTypesByDeprecated($options['service_types']); } $options['extensions'] = $this->extensions; $options['guessers'] = $this->guessers; foreach ($options as $k => $list) { sort($options[$k]); } } else { if (!class_exists($class) || !is_subclass_of($class, FormTypeInterface::class)) { $class = $this->getFqcnTypeClass($input, $io, $class); } $resolvedType = $this->formRegistry->getType($class); if ($option = $input->getArgument('option')) { $object = $resolvedType->getOptionsResolver(); if (!$object->isDefined($option)) { $message = sprintf('Option "%s" is not defined in "%s".', $option, \get_class($resolvedType->getInnerType())); if ($alternatives = $this->findAlternatives($option, $object->getDefinedOptions())) { if (1 === \count($alternatives)) { $message .= "\n\nDid you mean this?\n "; } else { $message .= "\n\nDid you mean one of these?\n "; } $message .= implode("\n ", $alternatives); } throw new InvalidArgumentException($message); } $options['type'] = $resolvedType->getInnerType(); $options['option'] = $option; } else { $object = $resolvedType; } } $helper = new DescriptorHelper($this->fileLinkFormatter); $options['format'] = $input->getOption('format'); $options['show_deprecated'] = $input->getOption('show-deprecated'); $helper->describe($io, $object, $options); return 0; } private function getFqcnTypeClass(InputInterface $input, SymfonyStyle $io, string $shortClassName): string { $classes = $this->getFqcnTypeClasses($shortClassName); if (0 === $count = \count($classes)) { $message = sprintf("Could not find type \"%s\" into the following namespaces:\n %s", $shortClassName, implode("\n ", $this->namespaces)); $allTypes = array_merge($this->getCoreTypes(), $this->types); if ($alternatives = $this->findAlternatives($shortClassName, $allTypes)) { if (1 === \count($alternatives)) { $message .= "\n\nDid you mean this?\n "; } else { $message .= "\n\nDid you mean one of these?\n "; } $message .= implode("\n ", $alternatives); } throw new InvalidArgumentException($message); } if (1 === $count) { return $classes[0]; } if (!$input->isInteractive()) { throw new InvalidArgumentException(sprintf("The type \"%s\" is ambiguous.\n\nDid you mean one of these?\n %s.", $shortClassName, implode("\n ", $classes))); } return $io->choice(sprintf("The type \"%s\" is ambiguous.\n\nSelect one of the following form types to display its information:", $shortClassName), $classes, $classes[0]); } private function getFqcnTypeClasses(string $shortClassName): array { $classes = []; sort($this->namespaces); foreach ($this->namespaces as $namespace) { if (class_exists($fqcn = $namespace.'\\'.$shortClassName)) { $classes[] = $fqcn; } elseif (class_exists($fqcn = $namespace.'\\'.ucfirst($shortClassName))) { $classes[] = $fqcn; } elseif (class_exists($fqcn = $namespace.'\\'.ucfirst($shortClassName).'Type')) { $classes[] = $fqcn; } elseif (str_ends_with($shortClassName, 'type') && class_exists($fqcn = $namespace.'\\'.ucfirst(substr($shortClassName, 0, -4).'Type'))) { $classes[] = $fqcn; } } return $classes; } private function getCoreTypes(): array { $coreExtension = new CoreExtension(); $loadTypesRefMethod = (new \ReflectionObject($coreExtension))->getMethod('loadTypes'); $loadTypesRefMethod->setAccessible(true); $coreTypes = $loadTypesRefMethod->invoke($coreExtension); $coreTypes = array_map(function (FormTypeInterface $type) { return \get_class($type); }, $coreTypes); sort($coreTypes); return $coreTypes; } private function filterTypesByDeprecated(array $types): array { $typesWithDeprecatedOptions = []; foreach ($types as $class) { $optionsResolver = $this->formRegistry->getType($class)->getOptionsResolver(); foreach ($optionsResolver->getDefinedOptions() as $option) { if ($optionsResolver->isDeprecated($option)) { $typesWithDeprecatedOptions[] = $class; break; } } } return $typesWithDeprecatedOptions; } private function findAlternatives(string $name, array $collection): array { $alternatives = []; foreach ($collection as $item) { $lev = levenshtein($name, $item); if ($lev <= \strlen($name) / 3 || str_contains($item, $name)) { $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev; } } $threshold = 1e3; $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; }); ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE); return array_keys($alternatives); } public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { if ($input->mustSuggestArgumentValuesFor('class')) { $suggestions->suggestValues(array_merge($this->getCoreTypes(), $this->types)); return; } if ($input->mustSuggestArgumentValuesFor('option') && null !== $class = $input->getArgument('class')) { $this->completeOptions($class, $suggestions); return; } if ($input->mustSuggestOptionValuesFor('format')) { $helper = new DescriptorHelper(); $suggestions->suggestValues($helper->getFormats()); } } private function completeOptions(string $class, CompletionSuggestions $suggestions): void { if (!class_exists($class) || !is_subclass_of($class, FormTypeInterface::class)) { $classes = $this->getFqcnTypeClasses($class); if (1 === \count($classes)) { $class = $classes[0]; } } if (!$this->formRegistry->hasType($class)) { return; } $resolvedType = $this->formRegistry->getType($class); $suggestions->suggestValues($resolvedType->getOptionsResolver()->getDefinedOptions()); } } Console/Descriptor/Descriptor.php 0000644 00000020004 15120211543 0013101 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Console\Descriptor; use Symfony\Component\Console\Descriptor\DescriptorInterface; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\OutputStyle; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Form\ResolvedFormTypeInterface; use Symfony\Component\Form\Util\OptionsResolverWrapper; use Symfony\Component\OptionsResolver\Debug\OptionsResolverIntrospector; use Symfony\Component\OptionsResolver\Exception\NoConfigurationException; use Symfony\Component\OptionsResolver\OptionsResolver; /** * @author Yonel Ceruto <yonelceruto@gmail.com> * * @internal */ abstract class Descriptor implements DescriptorInterface { /** @var OutputStyle */ protected $output; protected $type; protected $ownOptions = []; protected $overriddenOptions = []; protected $parentOptions = []; protected $extensionOptions = []; protected $requiredOptions = []; protected $parents = []; protected $extensions = []; /** * {@inheritdoc} */ public function describe(OutputInterface $output, $object, array $options = []) { $this->output = $output instanceof OutputStyle ? $output : new SymfonyStyle(new ArrayInput([]), $output); switch (true) { case null === $object: $this->describeDefaults($options); break; case $object instanceof ResolvedFormTypeInterface: $this->describeResolvedFormType($object, $options); break; case $object instanceof OptionsResolver: $this->describeOption($object, $options); break; default: throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_debug_type($object))); } } abstract protected function describeDefaults(array $options); abstract protected function describeResolvedFormType(ResolvedFormTypeInterface $resolvedFormType, array $options = []); abstract protected function describeOption(OptionsResolver $optionsResolver, array $options); protected function collectOptions(ResolvedFormTypeInterface $type) { $this->parents = []; $this->extensions = []; if (null !== $type->getParent()) { $optionsResolver = clone $this->getParentOptionsResolver($type->getParent()); } else { $optionsResolver = new OptionsResolver(); } $type->getInnerType()->configureOptions($ownOptionsResolver = new OptionsResolverWrapper()); $this->ownOptions = array_diff($ownOptionsResolver->getDefinedOptions(), $optionsResolver->getDefinedOptions()); $overriddenOptions = array_intersect(array_merge($ownOptionsResolver->getDefinedOptions(), $ownOptionsResolver->getUndefinedOptions()), $optionsResolver->getDefinedOptions()); $this->parentOptions = []; foreach ($this->parents as $class => $parentOptions) { $this->overriddenOptions[$class] = array_intersect($overriddenOptions, $parentOptions); $this->parentOptions[$class] = array_diff($parentOptions, $overriddenOptions); } $type->getInnerType()->configureOptions($optionsResolver); $this->collectTypeExtensionsOptions($type, $optionsResolver); $this->extensionOptions = []; foreach ($this->extensions as $class => $extensionOptions) { $this->overriddenOptions[$class] = array_intersect($overriddenOptions, $extensionOptions); $this->extensionOptions[$class] = array_diff($extensionOptions, $overriddenOptions); } $this->overriddenOptions = array_filter($this->overriddenOptions); $this->parentOptions = array_filter($this->parentOptions); $this->extensionOptions = array_filter($this->extensionOptions); $this->requiredOptions = $optionsResolver->getRequiredOptions(); $this->parents = array_keys($this->parents); $this->extensions = array_keys($this->extensions); } protected function getOptionDefinition(OptionsResolver $optionsResolver, string $option) { $definition = []; if ($info = $optionsResolver->getInfo($option)) { $definition = [ 'info' => $info, ]; } $definition += [ 'required' => $optionsResolver->isRequired($option), 'deprecated' => $optionsResolver->isDeprecated($option), ]; $introspector = new OptionsResolverIntrospector($optionsResolver); $map = [ 'default' => 'getDefault', 'lazy' => 'getLazyClosures', 'allowedTypes' => 'getAllowedTypes', 'allowedValues' => 'getAllowedValues', 'normalizers' => 'getNormalizers', 'deprecation' => 'getDeprecation', ]; foreach ($map as $key => $method) { try { $definition[$key] = $introspector->{$method}($option); } catch (NoConfigurationException $e) { // noop } } if (isset($definition['deprecation']) && isset($definition['deprecation']['message']) && \is_string($definition['deprecation']['message'])) { $definition['deprecationMessage'] = strtr($definition['deprecation']['message'], ['%name%' => $option]); $definition['deprecationPackage'] = $definition['deprecation']['package']; $definition['deprecationVersion'] = $definition['deprecation']['version']; } return $definition; } protected function filterOptionsByDeprecated(ResolvedFormTypeInterface $type) { $deprecatedOptions = []; $resolver = $type->getOptionsResolver(); foreach ($resolver->getDefinedOptions() as $option) { if ($resolver->isDeprecated($option)) { $deprecatedOptions[] = $option; } } $filterByDeprecated = function (array $options) use ($deprecatedOptions) { foreach ($options as $class => $opts) { if ($deprecated = array_intersect($deprecatedOptions, $opts)) { $options[$class] = $deprecated; } else { unset($options[$class]); } } return $options; }; $this->ownOptions = array_intersect($deprecatedOptions, $this->ownOptions); $this->overriddenOptions = $filterByDeprecated($this->overriddenOptions); $this->parentOptions = $filterByDeprecated($this->parentOptions); $this->extensionOptions = $filterByDeprecated($this->extensionOptions); } private function getParentOptionsResolver(ResolvedFormTypeInterface $type): OptionsResolver { $this->parents[$class = \get_class($type->getInnerType())] = []; if (null !== $type->getParent()) { $optionsResolver = clone $this->getParentOptionsResolver($type->getParent()); } else { $optionsResolver = new OptionsResolver(); } $inheritedOptions = $optionsResolver->getDefinedOptions(); $type->getInnerType()->configureOptions($optionsResolver); $this->parents[$class] = array_diff($optionsResolver->getDefinedOptions(), $inheritedOptions); $this->collectTypeExtensionsOptions($type, $optionsResolver); return $optionsResolver; } private function collectTypeExtensionsOptions(ResolvedFormTypeInterface $type, OptionsResolver $optionsResolver) { foreach ($type->getTypeExtensions() as $extension) { $inheritedOptions = $optionsResolver->getDefinedOptions(); $extension->configureOptions($optionsResolver); $this->extensions[\get_class($extension)] = array_diff($optionsResolver->getDefinedOptions(), $inheritedOptions); } } } Console/Descriptor/JsonDescriptor.php 0000644 00000007035 15120211543 0013744 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Console\Descriptor; use Symfony\Component\Form\ResolvedFormTypeInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** * @author Yonel Ceruto <yonelceruto@gmail.com> * * @internal */ class JsonDescriptor extends Descriptor { protected function describeDefaults(array $options) { $data['builtin_form_types'] = $options['core_types']; $data['service_form_types'] = $options['service_types']; if (!$options['show_deprecated']) { $data['type_extensions'] = $options['extensions']; $data['type_guessers'] = $options['guessers']; } $this->writeData($data, $options); } protected function describeResolvedFormType(ResolvedFormTypeInterface $resolvedFormType, array $options = []) { $this->collectOptions($resolvedFormType); if ($options['show_deprecated']) { $this->filterOptionsByDeprecated($resolvedFormType); } $formOptions = [ 'own' => $this->ownOptions, 'overridden' => $this->overriddenOptions, 'parent' => $this->parentOptions, 'extension' => $this->extensionOptions, 'required' => $this->requiredOptions, ]; $this->sortOptions($formOptions); $data = [ 'class' => \get_class($resolvedFormType->getInnerType()), 'block_prefix' => $resolvedFormType->getInnerType()->getBlockPrefix(), 'options' => $formOptions, 'parent_types' => $this->parents, 'type_extensions' => $this->extensions, ]; $this->writeData($data, $options); } protected function describeOption(OptionsResolver $optionsResolver, array $options) { $definition = $this->getOptionDefinition($optionsResolver, $options['option']); $map = []; if ($definition['deprecated']) { $map['deprecated'] = 'deprecated'; if (\is_string($definition['deprecationMessage'])) { $map['deprecation_message'] = 'deprecationMessage'; } } $map += [ 'info' => 'info', 'required' => 'required', 'default' => 'default', 'allowed_types' => 'allowedTypes', 'allowed_values' => 'allowedValues', ]; foreach ($map as $label => $name) { if (\array_key_exists($name, $definition)) { $data[$label] = $definition[$name]; if ('default' === $name) { $data['is_lazy'] = isset($definition['lazy']); } } } $data['has_normalizer'] = isset($definition['normalizers']); $this->writeData($data, $options); } private function writeData(array $data, array $options) { $flags = $options['json_encoding'] ?? 0; $this->output->write(json_encode($data, $flags | \JSON_PRETTY_PRINT)."\n"); } private function sortOptions(array &$options) { foreach ($options as &$opts) { $sorted = false; foreach ($opts as &$opt) { if (\is_array($opt)) { sort($opt); $sorted = true; } } if (!$sorted) { sort($opts); } } } } Console/Descriptor/TextDescriptor.php 0000644 00000016600 15120211543 0013755 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Console\Descriptor; use Symfony\Component\Console\Helper\Dumper; use Symfony\Component\Console\Helper\TableSeparator; use Symfony\Component\Form\ResolvedFormTypeInterface; use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; use Symfony\Component\OptionsResolver\OptionsResolver; /** * @author Yonel Ceruto <yonelceruto@gmail.com> * * @internal */ class TextDescriptor extends Descriptor { private $fileLinkFormatter; public function __construct(FileLinkFormatter $fileLinkFormatter = null) { $this->fileLinkFormatter = $fileLinkFormatter; } protected function describeDefaults(array $options) { if ($options['core_types']) { $this->output->section('Built-in form types (Symfony\Component\Form\Extension\Core\Type)'); $shortClassNames = array_map(function ($fqcn) { return $this->formatClassLink($fqcn, \array_slice(explode('\\', $fqcn), -1)[0]); }, $options['core_types']); for ($i = 0, $loopsMax = \count($shortClassNames); $i * 5 < $loopsMax; ++$i) { $this->output->writeln(' '.implode(', ', \array_slice($shortClassNames, $i * 5, 5))); } } if ($options['service_types']) { $this->output->section('Service form types'); $this->output->listing(array_map([$this, 'formatClassLink'], $options['service_types'])); } if (!$options['show_deprecated']) { if ($options['extensions']) { $this->output->section('Type extensions'); $this->output->listing(array_map([$this, 'formatClassLink'], $options['extensions'])); } if ($options['guessers']) { $this->output->section('Type guessers'); $this->output->listing(array_map([$this, 'formatClassLink'], $options['guessers'])); } } } protected function describeResolvedFormType(ResolvedFormTypeInterface $resolvedFormType, array $options = []) { $this->collectOptions($resolvedFormType); if ($options['show_deprecated']) { $this->filterOptionsByDeprecated($resolvedFormType); } $formOptions = $this->normalizeAndSortOptionsColumns(array_filter([ 'own' => $this->ownOptions, 'overridden' => $this->overriddenOptions, 'parent' => $this->parentOptions, 'extension' => $this->extensionOptions, ])); // setting headers and column order $tableHeaders = array_intersect_key([ 'own' => 'Options', 'overridden' => 'Overridden options', 'parent' => 'Parent options', 'extension' => 'Extension options', ], $formOptions); $this->output->title(sprintf('%s (Block prefix: "%s")', \get_class($resolvedFormType->getInnerType()), $resolvedFormType->getInnerType()->getBlockPrefix())); if ($formOptions) { $this->output->table($tableHeaders, $this->buildTableRows($tableHeaders, $formOptions)); } if ($this->parents) { $this->output->section('Parent types'); $this->output->listing(array_map([$this, 'formatClassLink'], $this->parents)); } if ($this->extensions) { $this->output->section('Type extensions'); $this->output->listing(array_map([$this, 'formatClassLink'], $this->extensions)); } } protected function describeOption(OptionsResolver $optionsResolver, array $options) { $definition = $this->getOptionDefinition($optionsResolver, $options['option']); $dump = new Dumper($this->output); $map = []; if ($definition['deprecated']) { $map = [ 'Deprecated' => 'deprecated', 'Deprecation package' => 'deprecationPackage', 'Deprecation version' => 'deprecationVersion', 'Deprecation message' => 'deprecationMessage', ]; } $map += [ 'Info' => 'info', 'Required' => 'required', 'Default' => 'default', 'Allowed types' => 'allowedTypes', 'Allowed values' => 'allowedValues', 'Normalizers' => 'normalizers', ]; $rows = []; foreach ($map as $label => $name) { $value = \array_key_exists($name, $definition) ? $dump($definition[$name]) : '-'; if ('default' === $name && isset($definition['lazy'])) { $value = "Value: $value\n\nClosure(s): ".$dump($definition['lazy']); } $rows[] = ["<info>$label</info>", $value]; $rows[] = new TableSeparator(); } array_pop($rows); $this->output->title(sprintf('%s (%s)', \get_class($options['type']), $options['option'])); $this->output->table([], $rows); } private function buildTableRows(array $headers, array $options): array { $tableRows = []; $count = \count(max($options)); for ($i = 0; $i < $count; ++$i) { $cells = []; foreach (array_keys($headers) as $group) { $option = $options[$group][$i] ?? null; if (\is_string($option) && \in_array($option, $this->requiredOptions, true)) { $option .= ' <info>(required)</info>'; } $cells[] = $option; } $tableRows[] = $cells; } return $tableRows; } private function normalizeAndSortOptionsColumns(array $options): array { foreach ($options as $group => $opts) { $sorted = false; foreach ($opts as $class => $opt) { if (\is_string($class)) { unset($options[$group][$class]); } if (!\is_array($opt) || 0 === \count($opt)) { continue; } if (!$sorted) { $options[$group] = []; } else { $options[$group][] = null; } $options[$group][] = sprintf('<info>%s</info>', (new \ReflectionClass($class))->getShortName()); $options[$group][] = new TableSeparator(); sort($opt); $sorted = true; $options[$group] = array_merge($options[$group], $opt); } if (!$sorted) { sort($options[$group]); } } return $options; } private function formatClassLink(string $class, string $text = null): string { if (null === $text) { $text = $class; } if ('' === $fileLink = $this->getFileLink($class)) { return $text; } return sprintf('<href=%s>%s</>', $fileLink, $text); } private function getFileLink(string $class): string { if (null === $this->fileLinkFormatter) { return ''; } try { $r = new \ReflectionClass($class); } catch (\ReflectionException $e) { return ''; } return (string) $this->fileLinkFormatter->format($r->getFileName(), $r->getStartLine()); } } Console/Helper/DescriptorHelper.php 0000644 00000001622 15120211543 0013347 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Console\Helper; use Symfony\Component\Console\Helper\DescriptorHelper as BaseDescriptorHelper; use Symfony\Component\Form\Console\Descriptor\JsonDescriptor; use Symfony\Component\Form\Console\Descriptor\TextDescriptor; use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; /** * @author Yonel Ceruto <yonelceruto@gmail.com> * * @internal */ class DescriptorHelper extends BaseDescriptorHelper { public function __construct(FileLinkFormatter $fileLinkFormatter = null) { $this ->register('txt', new TextDescriptor($fileLinkFormatter)) ->register('json', new JsonDescriptor()) ; } } DependencyInjection/FormPass.php 0000644 00000014221 15120211543 0012722 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\DependencyInjection; use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; /** * Adds all services with the tags "form.type", "form.type_extension" and * "form.type_guesser" as arguments of the "form.extension" service. * * @author Bernhard Schussek <bschussek@gmail.com> */ class FormPass implements CompilerPassInterface { use PriorityTaggedServiceTrait; private $formExtensionService; private $formTypeTag; private $formTypeExtensionTag; private $formTypeGuesserTag; private $formDebugCommandService; public function __construct(string $formExtensionService = 'form.extension', string $formTypeTag = 'form.type', string $formTypeExtensionTag = 'form.type_extension', string $formTypeGuesserTag = 'form.type_guesser', string $formDebugCommandService = 'console.command.form_debug') { if (0 < \func_num_args()) { trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); } $this->formExtensionService = $formExtensionService; $this->formTypeTag = $formTypeTag; $this->formTypeExtensionTag = $formTypeExtensionTag; $this->formTypeGuesserTag = $formTypeGuesserTag; $this->formDebugCommandService = $formDebugCommandService; } public function process(ContainerBuilder $container) { if (!$container->hasDefinition($this->formExtensionService)) { return; } $definition = $container->getDefinition($this->formExtensionService); $definition->replaceArgument(0, $this->processFormTypes($container)); $definition->replaceArgument(1, $this->processFormTypeExtensions($container)); $definition->replaceArgument(2, $this->processFormTypeGuessers($container)); } private function processFormTypes(ContainerBuilder $container): Reference { // Get service locator argument $servicesMap = []; $namespaces = ['Symfony\Component\Form\Extension\Core\Type' => true]; // Builds an array with fully-qualified type class names as keys and service IDs as values foreach ($container->findTaggedServiceIds($this->formTypeTag, true) as $serviceId => $tag) { // Add form type service to the service locator $serviceDefinition = $container->getDefinition($serviceId); $servicesMap[$formType = $serviceDefinition->getClass()] = new Reference($serviceId); $namespaces[substr($formType, 0, strrpos($formType, '\\'))] = true; } if ($container->hasDefinition($this->formDebugCommandService)) { $commandDefinition = $container->getDefinition($this->formDebugCommandService); $commandDefinition->setArgument(1, array_keys($namespaces)); $commandDefinition->setArgument(2, array_keys($servicesMap)); } return ServiceLocatorTagPass::register($container, $servicesMap); } private function processFormTypeExtensions(ContainerBuilder $container): array { $typeExtensions = []; $typeExtensionsClasses = []; foreach ($this->findAndSortTaggedServices($this->formTypeExtensionTag, $container) as $reference) { $serviceId = (string) $reference; $serviceDefinition = $container->getDefinition($serviceId); $tag = $serviceDefinition->getTag($this->formTypeExtensionTag); $typeExtensionClass = $container->getParameterBag()->resolveValue($serviceDefinition->getClass()); if (isset($tag[0]['extended_type'])) { $typeExtensions[$tag[0]['extended_type']][] = new Reference($serviceId); $typeExtensionsClasses[] = $typeExtensionClass; } else { $extendsTypes = false; $typeExtensionsClasses[] = $typeExtensionClass; foreach ($typeExtensionClass::getExtendedTypes() as $extendedType) { $typeExtensions[$extendedType][] = new Reference($serviceId); $extendsTypes = true; } if (!$extendsTypes) { throw new InvalidArgumentException(sprintf('The getExtendedTypes() method for service "%s" does not return any extended types.', $serviceId)); } } } foreach ($typeExtensions as $extendedType => $extensions) { $typeExtensions[$extendedType] = new IteratorArgument($extensions); } if ($container->hasDefinition($this->formDebugCommandService)) { $commandDefinition = $container->getDefinition($this->formDebugCommandService); $commandDefinition->setArgument(3, $typeExtensionsClasses); } return $typeExtensions; } private function processFormTypeGuessers(ContainerBuilder $container): ArgumentInterface { $guessers = []; $guessersClasses = []; foreach ($container->findTaggedServiceIds($this->formTypeGuesserTag, true) as $serviceId => $tags) { $guessers[] = new Reference($serviceId); $serviceDefinition = $container->getDefinition($serviceId); $guessersClasses[] = $serviceDefinition->getClass(); } if ($container->hasDefinition($this->formDebugCommandService)) { $commandDefinition = $container->getDefinition($this->formDebugCommandService); $commandDefinition->setArgument(4, $guessersClasses); } return new IteratorArgument($guessers); } } Event/PostSetDataEvent.php 0000644 00000001025 15120211543 0011523 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Event; use Symfony\Component\Form\FormEvent; /** * This event is dispatched at the end of the Form::setData() method. * * This event is mostly here for reading data after having pre-populated the form. */ final class PostSetDataEvent extends FormEvent { } Event/PostSubmitEvent.php 0000644 00000001037 15120211543 0011444 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Event; use Symfony\Component\Form\FormEvent; /** * This event is dispatched after the Form::submit() * once the model and view data have been denormalized. * * It can be used to fetch data after denormalization. */ final class PostSubmitEvent extends FormEvent { } Event/PreSetDataEvent.php 0000644 00000001161 15120211543 0011325 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Event; use Symfony\Component\Form\FormEvent; /** * This event is dispatched at the beginning of the Form::setData() method. * * It can be used to: * - Modify the data given during pre-population; * - Modify a form depending on the pre-populated data (adding or removing fields dynamically). */ final class PreSetDataEvent extends FormEvent { } Event/PreSubmitEvent.php 0000644 00000001160 15120211543 0011242 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Event; use Symfony\Component\Form\FormEvent; /** * This event is dispatched at the beginning of the Form::submit() method. * * It can be used to: * - Change data from the request, before submitting the data to the form. * - Add or remove form fields, before submitting the data to the form. */ final class PreSubmitEvent extends FormEvent { } Event/SubmitEvent.php 0000644 00000001115 15120211543 0010573 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Event; use Symfony\Component\Form\FormEvent; /** * This event is dispatched just before the Form::submit() method * transforms back the normalized data to the model and view data. * * It can be used to change data from the normalized representation of the data. */ final class SubmitEvent extends FormEvent { } Exception/AccessException.php 0000644 00000000516 15120211543 0012267 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Exception; class AccessException extends RuntimeException { } Exception/AlreadySubmittedException.php 0000644 00000000755 15120211543 0014335 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Exception; /** * Thrown when an operation is called that is not acceptable after submitting * a form. * * @author Bernhard Schussek <bschussek@gmail.com> */ class AlreadySubmittedException extends LogicException { } Exception/BadMethodCallException.php 0000644 00000000757 15120211543 0013520 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Exception; /** * Base BadMethodCallException for the Form component. * * @author Bernhard Schussek <bschussek@gmail.com> */ class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface { } Exception/ErrorMappingException.php 0000644 00000000524 15120211543 0013472 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Exception; class ErrorMappingException extends RuntimeException { } Exception/ExceptionInterface.php 0000644 00000000700 15120211543 0012761 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Exception; /** * Base ExceptionInterface for the Form component. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface ExceptionInterface extends \Throwable { } Exception/InvalidArgumentException.php 0000644 00000000765 15120211543 0014165 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Exception; /** * Base InvalidArgumentException for the Form component. * * @author Bernhard Schussek <bschussek@gmail.com> */ class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface { } Exception/InvalidConfigurationException.php 0000644 00000000544 15120211543 0015205 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Exception; class InvalidConfigurationException extends InvalidArgumentException { } Exception/LogicException.php 0000644 00000000730 15120211543 0012121 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Exception; /** * Base LogicException for Form component. * * @author Alexander Kotynia <aleksander.kot@gmail.com> */ class LogicException extends \LogicException implements ExceptionInterface { } Exception/OutOfBoundsException.php 0000644 00000000752 15120211543 0013277 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Exception; /** * Base OutOfBoundsException for Form component. * * @author Alexander Kotynia <aleksander.kot@gmail.com> */ class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface { } Exception/RuntimeException.php 0000644 00000000735 15120211543 0012514 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Exception; /** * Base RuntimeException for the Form component. * * @author Bernhard Schussek <bschussek@gmail.com> */ class RuntimeException extends \RuntimeException implements ExceptionInterface { } Exception/StringCastException.php 0000644 00000000522 15120211543 0013144 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Exception; class StringCastException extends RuntimeException { } Exception/TransformationFailedException.php 0000644 00000003013 15120211543 0015174 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Exception; /** * Indicates a value transformation error. * * @author Bernhard Schussek <bschussek@gmail.com> */ class TransformationFailedException extends RuntimeException { private $invalidMessage; private $invalidMessageParameters; public function __construct(string $message = '', int $code = 0, \Throwable $previous = null, string $invalidMessage = null, array $invalidMessageParameters = []) { parent::__construct($message, $code, $previous); $this->setInvalidMessage($invalidMessage, $invalidMessageParameters); } /** * Sets the message that will be shown to the user. * * @param string|null $invalidMessage The message or message key * @param array $invalidMessageParameters Data to be passed into the translator */ public function setInvalidMessage(string $invalidMessage = null, array $invalidMessageParameters = []): void { $this->invalidMessage = $invalidMessage; $this->invalidMessageParameters = $invalidMessageParameters; } public function getInvalidMessage(): ?string { return $this->invalidMessage; } public function getInvalidMessageParameters(): array { return $this->invalidMessageParameters; } } Exception/UnexpectedTypeException.php 0000644 00000001043 15120211543 0014030 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Exception; class UnexpectedTypeException extends InvalidArgumentException { public function __construct($value, string $expectedType) { parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, get_debug_type($value))); } } Extension/Core/DataAccessor/CallbackAccessor.php 0000644 00000003246 15120211543 0015633 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataAccessor; use Symfony\Component\Form\DataAccessorInterface; use Symfony\Component\Form\Exception\AccessException; use Symfony\Component\Form\FormInterface; /** * Writes and reads values to/from an object or array using callback functions. * * @author Yonel Ceruto <yonelceruto@gmail.com> */ class CallbackAccessor implements DataAccessorInterface { /** * {@inheritdoc} */ public function getValue($data, FormInterface $form) { if (null === $getter = $form->getConfig()->getOption('getter')) { throw new AccessException('Unable to read from the given form data as no getter is defined.'); } return ($getter)($data, $form); } /** * {@inheritdoc} */ public function setValue(&$data, $value, FormInterface $form): void { if (null === $setter = $form->getConfig()->getOption('setter')) { throw new AccessException('Unable to write the given value as no setter is defined.'); } ($setter)($data, $form->getData(), $form); } /** * {@inheritdoc} */ public function isReadable($data, FormInterface $form): bool { return null !== $form->getConfig()->getOption('getter'); } /** * {@inheritdoc} */ public function isWritable($data, FormInterface $form): bool { return null !== $form->getConfig()->getOption('setter'); } } Extension/Core/DataAccessor/ChainAccessor.php 0000644 00000004302 15120211543 0015153 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataAccessor; use Symfony\Component\Form\DataAccessorInterface; use Symfony\Component\Form\Exception\AccessException; use Symfony\Component\Form\FormInterface; /** * @author Yonel Ceruto <yonelceruto@gmail.com> */ class ChainAccessor implements DataAccessorInterface { private $accessors; /** * @param DataAccessorInterface[]|iterable $accessors */ public function __construct(iterable $accessors) { $this->accessors = $accessors; } /** * {@inheritdoc} */ public function getValue($data, FormInterface $form) { foreach ($this->accessors as $accessor) { if ($accessor->isReadable($data, $form)) { return $accessor->getValue($data, $form); } } throw new AccessException('Unable to read from the given form data as no accessor in the chain is able to read the data.'); } /** * {@inheritdoc} */ public function setValue(&$data, $value, FormInterface $form): void { foreach ($this->accessors as $accessor) { if ($accessor->isWritable($data, $form)) { $accessor->setValue($data, $value, $form); return; } } throw new AccessException('Unable to write the given value as no accessor in the chain is able to set the data.'); } /** * {@inheritdoc} */ public function isReadable($data, FormInterface $form): bool { foreach ($this->accessors as $accessor) { if ($accessor->isReadable($data, $form)) { return true; } } return false; } /** * {@inheritdoc} */ public function isWritable($data, FormInterface $form): bool { foreach ($this->accessors as $accessor) { if ($accessor->isWritable($data, $form)) { return true; } } return false; } } Extension/Core/DataAccessor/PropertyPathAccessor.php 0000644 00000007205 15120211543 0016577 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataAccessor; use Symfony\Component\Form\DataAccessorInterface; use Symfony\Component\Form\Exception\AccessException; use Symfony\Component\Form\FormInterface; use Symfony\Component\PropertyAccess\Exception\AccessException as PropertyAccessException; use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException; use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\PropertyAccess\PropertyPathInterface; /** * Writes and reads values to/from an object or array using property path. * * @author Yonel Ceruto <yonelceruto@gmail.com> * @author Bernhard Schussek <bschussek@gmail.com> */ class PropertyPathAccessor implements DataAccessorInterface { private $propertyAccessor; public function __construct(PropertyAccessorInterface $propertyAccessor = null) { $this->propertyAccessor = $propertyAccessor ?? PropertyAccess::createPropertyAccessor(); } /** * {@inheritdoc} */ public function getValue($data, FormInterface $form) { if (null === $propertyPath = $form->getPropertyPath()) { throw new AccessException('Unable to read from the given form data as no property path is defined.'); } return $this->getPropertyValue($data, $propertyPath); } /** * {@inheritdoc} */ public function setValue(&$data, $propertyValue, FormInterface $form): void { if (null === $propertyPath = $form->getPropertyPath()) { throw new AccessException('Unable to write the given value as no property path is defined.'); } // If the field is of type DateTimeInterface and the data is the same skip the update to // keep the original object hash if ($propertyValue instanceof \DateTimeInterface && $propertyValue == $this->getPropertyValue($data, $propertyPath)) { return; } // If the data is identical to the value in $data, we are // dealing with a reference if (!\is_object($data) || !$form->getConfig()->getByReference() || $propertyValue !== $this->getPropertyValue($data, $propertyPath)) { $this->propertyAccessor->setValue($data, $propertyPath, $propertyValue); } } /** * {@inheritdoc} */ public function isReadable($data, FormInterface $form): bool { return null !== $form->getPropertyPath(); } /** * {@inheritdoc} */ public function isWritable($data, FormInterface $form): bool { return null !== $form->getPropertyPath(); } private function getPropertyValue($data, PropertyPathInterface $propertyPath) { try { return $this->propertyAccessor->getValue($data, $propertyPath); } catch (PropertyAccessException $e) { if (\is_array($data) && $e instanceof NoSuchIndexException) { return null; } if (!$e instanceof UninitializedPropertyException // For versions without UninitializedPropertyException check the exception message && (class_exists(UninitializedPropertyException::class) || false === strpos($e->getMessage(), 'You should initialize it')) ) { throw $e; } return null; } } } Extension/Core/DataMapper/CheckboxListMapper.php 0000644 00000004316 15120211543 0015664 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataMapper; use Symfony\Component\Form\DataMapperInterface; use Symfony\Component\Form\Exception\UnexpectedTypeException; /** * Maps choices to/from checkbox forms. * * A {@link ChoiceListInterface} implementation is used to find the * corresponding string values for the choices. Each checkbox form whose "value" * option corresponds to any of the selected values is marked as selected. * * @author Bernhard Schussek <bschussek@gmail.com> */ class CheckboxListMapper implements DataMapperInterface { /** * {@inheritdoc} */ public function mapDataToForms($choices, iterable $checkboxes) { if (\is_array($checkboxes)) { trigger_deprecation('symfony/form', '5.3', 'Passing an array as the second argument of the "%s()" method is deprecated, pass "\Traversable" instead.', __METHOD__); } if (null === $choices) { $choices = []; } if (!\is_array($choices)) { throw new UnexpectedTypeException($choices, 'array'); } foreach ($checkboxes as $checkbox) { $value = $checkbox->getConfig()->getOption('value'); $checkbox->setData(\in_array($value, $choices, true)); } } /** * {@inheritdoc} */ public function mapFormsToData(iterable $checkboxes, &$choices) { if (\is_array($checkboxes)) { trigger_deprecation('symfony/form', '5.3', 'Passing an array as the first argument of the "%s()" method is deprecated, pass "\Traversable" instead.', __METHOD__); } if (!\is_array($choices)) { throw new UnexpectedTypeException($choices, 'array'); } $values = []; foreach ($checkboxes as $checkbox) { if ($checkbox->getData()) { // construct an array of choice values $values[] = $checkbox->getConfig()->getOption('value'); } } $choices = $values; } } Extension/Core/DataMapper/DataMapper.php 0000644 00000006036 15120211543 0014154 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataMapper; use Symfony\Component\Form\DataAccessorInterface; use Symfony\Component\Form\DataMapperInterface; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Extension\Core\DataAccessor\CallbackAccessor; use Symfony\Component\Form\Extension\Core\DataAccessor\ChainAccessor; use Symfony\Component\Form\Extension\Core\DataAccessor\PropertyPathAccessor; /** * Maps arrays/objects to/from forms using data accessors. * * @author Bernhard Schussek <bschussek@gmail.com> */ class DataMapper implements DataMapperInterface { private $dataAccessor; public function __construct(DataAccessorInterface $dataAccessor = null) { $this->dataAccessor = $dataAccessor ?? new ChainAccessor([ new CallbackAccessor(), new PropertyPathAccessor(), ]); } /** * {@inheritdoc} */ public function mapDataToForms($data, iterable $forms): void { if (\is_array($forms)) { trigger_deprecation('symfony/form', '5.3', 'Passing an array as the second argument of the "%s()" method is deprecated, pass "\Traversable" instead.', __METHOD__); } $empty = null === $data || [] === $data; if (!$empty && !\is_array($data) && !\is_object($data)) { throw new UnexpectedTypeException($data, 'object, array or empty'); } foreach ($forms as $form) { $config = $form->getConfig(); if (!$empty && $config->getMapped() && $this->dataAccessor->isReadable($data, $form)) { $form->setData($this->dataAccessor->getValue($data, $form)); } else { $form->setData($config->getData()); } } } /** * {@inheritdoc} */ public function mapFormsToData(iterable $forms, &$data): void { if (\is_array($forms)) { trigger_deprecation('symfony/form', '5.3', 'Passing an array as the first argument of the "%s()" method is deprecated, pass "\Traversable" instead.', __METHOD__); } if (null === $data) { return; } if (!\is_array($data) && !\is_object($data)) { throw new UnexpectedTypeException($data, 'object, array or empty'); } foreach ($forms as $form) { $config = $form->getConfig(); // Write-back is disabled if the form is not synchronized (transformation failed), // if the form was not submitted and if the form is disabled (modification not allowed) if ($config->getMapped() && $form->isSubmitted() && $form->isSynchronized() && !$form->isDisabled() && $this->dataAccessor->isWritable($data, $form)) { $this->dataAccessor->setValue($data, $form->getData(), $form); } } } } Extension/Core/DataMapper/PropertyPathMapper.php 0000644 00000010363 15120211543 0015742 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataMapper; use Symfony\Component\Form\DataMapperInterface; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\PropertyAccess\Exception\AccessException; use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException; use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; trigger_deprecation('symfony/form', '5.2', 'The "%s" class is deprecated. Use "%s" instead.', PropertyPathMapper::class, DataMapper::class); /** * Maps arrays/objects to/from forms using property paths. * * @author Bernhard Schussek <bschussek@gmail.com> * * @deprecated since symfony/form 5.2. Use {@see DataMapper} instead. */ class PropertyPathMapper implements DataMapperInterface { private $propertyAccessor; public function __construct(PropertyAccessorInterface $propertyAccessor = null) { $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); } /** * {@inheritdoc} */ public function mapDataToForms($data, iterable $forms) { $empty = null === $data || [] === $data; if (!$empty && !\is_array($data) && !\is_object($data)) { throw new UnexpectedTypeException($data, 'object, array or empty'); } foreach ($forms as $form) { $propertyPath = $form->getPropertyPath(); $config = $form->getConfig(); if (!$empty && null !== $propertyPath && $config->getMapped()) { $form->setData($this->getPropertyValue($data, $propertyPath)); } else { $form->setData($config->getData()); } } } /** * {@inheritdoc} */ public function mapFormsToData(iterable $forms, &$data) { if (null === $data) { return; } if (!\is_array($data) && !\is_object($data)) { throw new UnexpectedTypeException($data, 'object, array or empty'); } foreach ($forms as $form) { $propertyPath = $form->getPropertyPath(); $config = $form->getConfig(); // Write-back is disabled if the form is not synchronized (transformation failed), // if the form was not submitted and if the form is disabled (modification not allowed) if (null !== $propertyPath && $config->getMapped() && $form->isSubmitted() && $form->isSynchronized() && !$form->isDisabled()) { $propertyValue = $form->getData(); // If the field is of type DateTimeInterface and the data is the same skip the update to // keep the original object hash if ($propertyValue instanceof \DateTimeInterface && $propertyValue == $this->getPropertyValue($data, $propertyPath)) { continue; } // If the data is identical to the value in $data, we are // dealing with a reference if (!\is_object($data) || !$config->getByReference() || $propertyValue !== $this->getPropertyValue($data, $propertyPath)) { $this->propertyAccessor->setValue($data, $propertyPath, $propertyValue); } } } } private function getPropertyValue($data, $propertyPath) { try { return $this->propertyAccessor->getValue($data, $propertyPath); } catch (AccessException $e) { if (\is_array($data) && $e instanceof NoSuchIndexException) { return null; } if (!$e instanceof UninitializedPropertyException // For versions without UninitializedPropertyException check the exception message && (class_exists(UninitializedPropertyException::class) || !str_contains($e->getMessage(), 'You should initialize it')) ) { throw $e; } return null; } } } Extension/Core/DataMapper/RadioListMapper.php 0000644 00000004205 15120211543 0015171 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataMapper; use Symfony\Component\Form\DataMapperInterface; use Symfony\Component\Form\Exception\UnexpectedTypeException; /** * Maps choices to/from radio forms. * * A {@link ChoiceListInterface} implementation is used to find the * corresponding string values for the choices. The radio form whose "value" * option corresponds to the selected value is marked as selected. * * @author Bernhard Schussek <bschussek@gmail.com> */ class RadioListMapper implements DataMapperInterface { /** * {@inheritdoc} */ public function mapDataToForms($choice, iterable $radios) { if (\is_array($radios)) { trigger_deprecation('symfony/form', '5.3', 'Passing an array as the second argument of the "%s()" method is deprecated, pass "\Traversable" instead.', __METHOD__); } if (!\is_string($choice)) { throw new UnexpectedTypeException($choice, 'string'); } foreach ($radios as $radio) { $value = $radio->getConfig()->getOption('value'); $radio->setData($choice === $value); } } /** * {@inheritdoc} */ public function mapFormsToData(iterable $radios, &$choice) { if (\is_array($radios)) { trigger_deprecation('symfony/form', '5.3', 'Passing an array as the first argument of the "%s()" method is deprecated, pass "\Traversable" instead.', __METHOD__); } if (null !== $choice && !\is_string($choice)) { throw new UnexpectedTypeException($choice, 'null or string'); } $choice = null; foreach ($radios as $radio) { if ($radio->getData()) { if ('placeholder' === $radio->getName()) { return; } $choice = $radio->getConfig()->getOption('value'); return; } } } } Extension/Core/DataTransformer/ArrayToPartsTransformer.php 0000644 00000004341 15120211543 0020027 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class ArrayToPartsTransformer implements DataTransformerInterface { private $partMapping; public function __construct(array $partMapping) { $this->partMapping = $partMapping; } public function transform($array) { if (null === $array) { $array = []; } if (!\is_array($array)) { throw new TransformationFailedException('Expected an array.'); } $result = []; foreach ($this->partMapping as $partKey => $originalKeys) { if (empty($array)) { $result[$partKey] = null; } else { $result[$partKey] = array_intersect_key($array, array_flip($originalKeys)); } } return $result; } public function reverseTransform($array) { if (!\is_array($array)) { throw new TransformationFailedException('Expected an array.'); } $result = []; $emptyKeys = []; foreach ($this->partMapping as $partKey => $originalKeys) { if (!empty($array[$partKey])) { foreach ($originalKeys as $originalKey) { if (isset($array[$partKey][$originalKey])) { $result[$originalKey] = $array[$partKey][$originalKey]; } } } else { $emptyKeys[] = $partKey; } } if (\count($emptyKeys) > 0) { if (\count($emptyKeys) === \count($this->partMapping)) { // All parts empty return null; } throw new TransformationFailedException(sprintf('The keys "%s" should not be empty.', implode('", "', $emptyKeys))); } return $result; } } Extension/Core/DataTransformer/BaseDateTimeTransformer.php 0000644 00000003446 15120211543 0017730 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\InvalidArgumentException; abstract class BaseDateTimeTransformer implements DataTransformerInterface { protected static $formats = [ \IntlDateFormatter::NONE, \IntlDateFormatter::FULL, \IntlDateFormatter::LONG, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT, ]; protected $inputTimezone; protected $outputTimezone; /** * @param string|null $inputTimezone The name of the input timezone * @param string|null $outputTimezone The name of the output timezone * * @throws InvalidArgumentException if a timezone is not valid */ public function __construct(string $inputTimezone = null, string $outputTimezone = null) { $this->inputTimezone = $inputTimezone ?: date_default_timezone_get(); $this->outputTimezone = $outputTimezone ?: date_default_timezone_get(); // Check if input and output timezones are valid try { new \DateTimeZone($this->inputTimezone); } catch (\Exception $e) { throw new InvalidArgumentException(sprintf('Input timezone is invalid: "%s".', $this->inputTimezone), $e->getCode(), $e); } try { new \DateTimeZone($this->outputTimezone); } catch (\Exception $e) { throw new InvalidArgumentException(sprintf('Output timezone is invalid: "%s".', $this->outputTimezone), $e->getCode(), $e); } } } Extension/Core/DataTransformer/BooleanToStringTransformer.php 0000644 00000004350 15120211543 0020505 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Exception\TransformationFailedException; /** * Transforms between a Boolean and a string. * * @author Bernhard Schussek <bschussek@gmail.com> * @author Florian Eckerstorfer <florian@eckerstorfer.org> */ class BooleanToStringTransformer implements DataTransformerInterface { private $trueValue; private $falseValues; /** * @param string $trueValue The value emitted upon transform if the input is true */ public function __construct(string $trueValue, array $falseValues = [null]) { $this->trueValue = $trueValue; $this->falseValues = $falseValues; if (\in_array($this->trueValue, $this->falseValues, true)) { throw new InvalidArgumentException('The specified "true" value is contained in the false-values.'); } } /** * Transforms a Boolean into a string. * * @param bool $value Boolean value * * @return string|null * * @throws TransformationFailedException if the given value is not a Boolean */ public function transform($value) { if (null === $value) { return null; } if (!\is_bool($value)) { throw new TransformationFailedException('Expected a Boolean.'); } return $value ? $this->trueValue : null; } /** * Transforms a string into a Boolean. * * @param string $value String value * * @return bool * * @throws TransformationFailedException if the given value is not a string */ public function reverseTransform($value) { if (\in_array($value, $this->falseValues, true)) { return false; } if (!\is_string($value)) { throw new TransformationFailedException('Expected a string.'); } return true; } } Extension/Core/DataTransformer/ChoiceToValueTransformer.php 0000644 00000002711 15120211543 0020125 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class ChoiceToValueTransformer implements DataTransformerInterface { private $choiceList; public function __construct(ChoiceListInterface $choiceList) { $this->choiceList = $choiceList; } public function transform($choice) { return (string) current($this->choiceList->getValuesForChoices([$choice])); } public function reverseTransform($value) { if (null !== $value && !\is_string($value)) { throw new TransformationFailedException('Expected a string or null.'); } $choices = $this->choiceList->getChoicesForValues([(string) $value]); if (1 !== \count($choices)) { if (null === $value || '' === $value) { return null; } throw new TransformationFailedException(sprintf('The choice "%s" does not exist or is not unique.', $value)); } return current($choices); } } Extension/Core/DataTransformer/ChoicesToValuesTransformer.php 0000644 00000003663 15120211543 0020502 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class ChoicesToValuesTransformer implements DataTransformerInterface { private $choiceList; public function __construct(ChoiceListInterface $choiceList) { $this->choiceList = $choiceList; } /** * @return array * * @throws TransformationFailedException if the given value is not an array */ public function transform($array) { if (null === $array) { return []; } if (!\is_array($array)) { throw new TransformationFailedException('Expected an array.'); } return $this->choiceList->getValuesForChoices($array); } /** * @return array * * @throws TransformationFailedException if the given value is not an array * or if no matching choice could be * found for some given value */ public function reverseTransform($array) { if (null === $array) { return []; } if (!\is_array($array)) { throw new TransformationFailedException('Expected an array.'); } $choices = $this->choiceList->getChoicesForValues($array); if (\count($choices) !== \count($array)) { throw new TransformationFailedException('Could not find all matching choices for the given values.'); } return $choices; } } Extension/Core/DataTransformer/DataTransformerChain.php 0000644 00000004656 15120211543 0017261 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; /** * Passes a value through multiple value transformers. * * @author Bernhard Schussek <bschussek@gmail.com> */ class DataTransformerChain implements DataTransformerInterface { protected $transformers; /** * Uses the given value transformers to transform values. * * @param DataTransformerInterface[] $transformers */ public function __construct(array $transformers) { $this->transformers = $transformers; } /** * Passes the value through the transform() method of all nested transformers. * * The transformers receive the value in the same order as they were passed * to the constructor. Each transformer receives the result of the previous * transformer as input. The output of the last transformer is returned * by this method. * * @param mixed $value The original value * * @return mixed * * @throws TransformationFailedException */ public function transform($value) { foreach ($this->transformers as $transformer) { $value = $transformer->transform($value); } return $value; } /** * Passes the value through the reverseTransform() method of all nested * transformers. * * The transformers receive the value in the reverse order as they were passed * to the constructor. Each transformer receives the result of the previous * transformer as input. The output of the last transformer is returned * by this method. * * @param mixed $value The transformed value * * @return mixed * * @throws TransformationFailedException */ public function reverseTransform($value) { for ($i = \count($this->transformers) - 1; $i >= 0; --$i) { $value = $this->transformers[$i]->reverseTransform($value); } return $value; } /** * @return DataTransformerInterface[] */ public function getTransformers() { return $this->transformers; } } Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php 0000644 00000014060 15120211543 0021317 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\UnexpectedTypeException; /** * Transforms between a normalized date interval and an interval string/array. * * @author Steffen Roßkamp <steffen.rosskamp@gimmickmedia.de> */ class DateIntervalToArrayTransformer implements DataTransformerInterface { public const YEARS = 'years'; public const MONTHS = 'months'; public const DAYS = 'days'; public const HOURS = 'hours'; public const MINUTES = 'minutes'; public const SECONDS = 'seconds'; public const INVERT = 'invert'; private const AVAILABLE_FIELDS = [ self::YEARS => 'y', self::MONTHS => 'm', self::DAYS => 'd', self::HOURS => 'h', self::MINUTES => 'i', self::SECONDS => 's', self::INVERT => 'r', ]; private $fields; private $pad; /** * @param string[]|null $fields The date fields * @param bool $pad Whether to use padding */ public function __construct(array $fields = null, bool $pad = false) { $this->fields = $fields ?? ['years', 'months', 'days', 'hours', 'minutes', 'seconds', 'invert']; $this->pad = $pad; } /** * Transforms a normalized date interval into an interval array. * * @param \DateInterval $dateInterval Normalized date interval * * @return array * * @throws UnexpectedTypeException if the given value is not a \DateInterval instance */ public function transform($dateInterval) { if (null === $dateInterval) { return array_intersect_key( [ 'years' => '', 'months' => '', 'weeks' => '', 'days' => '', 'hours' => '', 'minutes' => '', 'seconds' => '', 'invert' => false, ], array_flip($this->fields) ); } if (!$dateInterval instanceof \DateInterval) { throw new UnexpectedTypeException($dateInterval, \DateInterval::class); } $result = []; foreach (self::AVAILABLE_FIELDS as $field => $char) { $result[$field] = $dateInterval->format('%'.($this->pad ? strtoupper($char) : $char)); } if (\in_array('weeks', $this->fields, true)) { $result['weeks'] = '0'; if (isset($result['days']) && (int) $result['days'] >= 7) { $result['weeks'] = (string) floor($result['days'] / 7); $result['days'] = (string) ($result['days'] % 7); } } $result['invert'] = '-' === $result['invert']; $result = array_intersect_key($result, array_flip($this->fields)); return $result; } /** * Transforms an interval array into a normalized date interval. * * @param array $value Interval array * * @return \DateInterval|null * * @throws UnexpectedTypeException if the given value is not an array * @throws TransformationFailedException if the value could not be transformed */ public function reverseTransform($value) { if (null === $value) { return null; } if (!\is_array($value)) { throw new UnexpectedTypeException($value, 'array'); } if ('' === implode('', $value)) { return null; } $emptyFields = []; foreach ($this->fields as $field) { if (!isset($value[$field])) { $emptyFields[] = $field; } } if (\count($emptyFields) > 0) { throw new TransformationFailedException(sprintf('The fields "%s" should not be empty.', implode('", "', $emptyFields))); } if (isset($value['invert']) && !\is_bool($value['invert'])) { throw new TransformationFailedException('The value of "invert" must be boolean.'); } foreach (self::AVAILABLE_FIELDS as $field => $char) { if ('invert' !== $field && isset($value[$field]) && !ctype_digit((string) $value[$field])) { throw new TransformationFailedException(sprintf('This amount of "%s" is invalid.', $field)); } } try { if (!empty($value['weeks'])) { $interval = sprintf( 'P%sY%sM%sWT%sH%sM%sS', empty($value['years']) ? '0' : $value['years'], empty($value['months']) ? '0' : $value['months'], empty($value['weeks']) ? '0' : $value['weeks'], empty($value['hours']) ? '0' : $value['hours'], empty($value['minutes']) ? '0' : $value['minutes'], empty($value['seconds']) ? '0' : $value['seconds'] ); } else { $interval = sprintf( 'P%sY%sM%sDT%sH%sM%sS', empty($value['years']) ? '0' : $value['years'], empty($value['months']) ? '0' : $value['months'], empty($value['days']) ? '0' : $value['days'], empty($value['hours']) ? '0' : $value['hours'], empty($value['minutes']) ? '0' : $value['minutes'], empty($value['seconds']) ? '0' : $value['seconds'] ); } $dateInterval = new \DateInterval($interval); if (isset($value['invert'])) { $dateInterval->invert = $value['invert'] ? 1 : 0; } } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } return $dateInterval; } } Extension/Core/DataTransformer/DateIntervalToStringTransformer.php 0000644 00000006327 15120211543 0021516 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\UnexpectedTypeException; /** * Transforms between a date string and a DateInterval object. * * @author Steffen Roßkamp <steffen.rosskamp@gimmickmedia.de> */ class DateIntervalToStringTransformer implements DataTransformerInterface { private $format; /** * Transforms a \DateInterval instance to a string. * * @see \DateInterval::format() for supported formats * * @param string $format The date format */ public function __construct(string $format = 'P%yY%mM%dDT%hH%iM%sS') { $this->format = $format; } /** * Transforms a DateInterval object into a date string with the configured format. * * @param \DateInterval|null $value A DateInterval object * * @return string * * @throws UnexpectedTypeException if the given value is not a \DateInterval instance */ public function transform($value) { if (null === $value) { return ''; } if (!$value instanceof \DateInterval) { throw new UnexpectedTypeException($value, \DateInterval::class); } return $value->format($this->format); } /** * Transforms a date string in the configured format into a DateInterval object. * * @param string $value An ISO 8601 or date string like date interval presentation * * @return \DateInterval|null * * @throws UnexpectedTypeException if the given value is not a string * @throws TransformationFailedException if the date interval could not be parsed */ public function reverseTransform($value) { if (null === $value) { return null; } if (!\is_string($value)) { throw new UnexpectedTypeException($value, 'string'); } if ('' === $value) { return null; } if (!$this->isISO8601($value)) { throw new TransformationFailedException('Non ISO 8601 date strings are not supported yet.'); } $valuePattern = '/^'.preg_replace('/%([yYmMdDhHiIsSwW])(\w)/', '(?P<$1>\d+)$2', $this->format).'$/'; if (!preg_match($valuePattern, $value)) { throw new TransformationFailedException(sprintf('Value "%s" contains intervals not accepted by format "%s".', $value, $this->format)); } try { $dateInterval = new \DateInterval($value); } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } return $dateInterval; } private function isISO8601(string $string): bool { return preg_match('/^P(?=\w*(?:\d|%\w))(?:\d+Y|%[yY]Y)?(?:\d+M|%[mM]M)?(?:(?:\d+D|%[dD]D)|(?:\d+W|%[wW]W))?(?:T(?:\d+H|[hH]H)?(?:\d+M|[iI]M)?(?:\d+S|[sS]S)?)?$/', $string); } } Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformer.php 0000644 00000003710 15120211543 0022707 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; /** * Transforms between a DateTimeImmutable object and a DateTime object. * * @author Valentin Udaltsov <udaltsov.valentin@gmail.com> */ final class DateTimeImmutableToDateTimeTransformer implements DataTransformerInterface { /** * Transforms a DateTimeImmutable into a DateTime object. * * @param \DateTimeImmutable|null $value A DateTimeImmutable object * * @throws TransformationFailedException If the given value is not a \DateTimeImmutable */ public function transform($value): ?\DateTime { if (null === $value) { return null; } if (!$value instanceof \DateTimeImmutable) { throw new TransformationFailedException('Expected a \DateTimeImmutable.'); } if (\PHP_VERSION_ID >= 70300) { return \DateTime::createFromImmutable($value); } return \DateTime::createFromFormat('U.u', $value->format('U.u'))->setTimezone($value->getTimezone()); } /** * Transforms a DateTime object into a DateTimeImmutable object. * * @param \DateTime|null $value A DateTime object * * @throws TransformationFailedException If the given value is not a \DateTime */ public function reverseTransform($value): ?\DateTimeImmutable { if (null === $value) { return null; } if (!$value instanceof \DateTime) { throw new TransformationFailedException('Expected a \DateTime.'); } return \DateTimeImmutable::createFromMutable($value); } } Extension/Core/DataTransformer/DateTimeToArrayTransformer.php 0000644 00000014457 15120211543 0020443 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\Exception\TransformationFailedException; /** * Transforms between a normalized time and a localized time string/array. * * @author Bernhard Schussek <bschussek@gmail.com> * @author Florian Eckerstorfer <florian@eckerstorfer.org> */ class DateTimeToArrayTransformer extends BaseDateTimeTransformer { private $pad; private $fields; private $referenceDate; /** * @param string|null $inputTimezone The input timezone * @param string|null $outputTimezone The output timezone * @param string[]|null $fields The date fields * @param bool $pad Whether to use padding */ public function __construct(string $inputTimezone = null, string $outputTimezone = null, array $fields = null, bool $pad = false, \DateTimeInterface $referenceDate = null) { parent::__construct($inputTimezone, $outputTimezone); $this->fields = $fields ?? ['year', 'month', 'day', 'hour', 'minute', 'second']; $this->pad = $pad; $this->referenceDate = $referenceDate ?? new \DateTimeImmutable('1970-01-01 00:00:00'); } /** * Transforms a normalized date into a localized date. * * @param \DateTimeInterface $dateTime A DateTimeInterface object * * @return array * * @throws TransformationFailedException If the given value is not a \DateTimeInterface */ public function transform($dateTime) { if (null === $dateTime) { return array_intersect_key([ 'year' => '', 'month' => '', 'day' => '', 'hour' => '', 'minute' => '', 'second' => '', ], array_flip($this->fields)); } if (!$dateTime instanceof \DateTimeInterface) { throw new TransformationFailedException('Expected a \DateTimeInterface.'); } if ($this->inputTimezone !== $this->outputTimezone) { if (!$dateTime instanceof \DateTimeImmutable) { $dateTime = clone $dateTime; } $dateTime = $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone)); } $result = array_intersect_key([ 'year' => $dateTime->format('Y'), 'month' => $dateTime->format('m'), 'day' => $dateTime->format('d'), 'hour' => $dateTime->format('H'), 'minute' => $dateTime->format('i'), 'second' => $dateTime->format('s'), ], array_flip($this->fields)); if (!$this->pad) { foreach ($result as &$entry) { // remove leading zeros $entry = (string) (int) $entry; } // unset reference to keep scope clear unset($entry); } return $result; } /** * Transforms a localized date into a normalized date. * * @param array $value Localized date * * @return \DateTime|null * * @throws TransformationFailedException If the given value is not an array, * if the value could not be transformed */ public function reverseTransform($value) { if (null === $value) { return null; } if (!\is_array($value)) { throw new TransformationFailedException('Expected an array.'); } if ('' === implode('', $value)) { return null; } $emptyFields = []; foreach ($this->fields as $field) { if (!isset($value[$field])) { $emptyFields[] = $field; } } if (\count($emptyFields) > 0) { throw new TransformationFailedException(sprintf('The fields "%s" should not be empty.', implode('", "', $emptyFields))); } if (isset($value['month']) && !ctype_digit((string) $value['month'])) { throw new TransformationFailedException('This month is invalid.'); } if (isset($value['day']) && !ctype_digit((string) $value['day'])) { throw new TransformationFailedException('This day is invalid.'); } if (isset($value['year']) && !ctype_digit((string) $value['year'])) { throw new TransformationFailedException('This year is invalid.'); } if (!empty($value['month']) && !empty($value['day']) && !empty($value['year']) && false === checkdate($value['month'], $value['day'], $value['year'])) { throw new TransformationFailedException('This is an invalid date.'); } if (isset($value['hour']) && !ctype_digit((string) $value['hour'])) { throw new TransformationFailedException('This hour is invalid.'); } if (isset($value['minute']) && !ctype_digit((string) $value['minute'])) { throw new TransformationFailedException('This minute is invalid.'); } if (isset($value['second']) && !ctype_digit((string) $value['second'])) { throw new TransformationFailedException('This second is invalid.'); } try { $dateTime = new \DateTime(sprintf( '%s-%s-%s %s:%s:%s', empty($value['year']) ? $this->referenceDate->format('Y') : $value['year'], empty($value['month']) ? $this->referenceDate->format('m') : $value['month'], empty($value['day']) ? $this->referenceDate->format('d') : $value['day'], $value['hour'] ?? $this->referenceDate->format('H'), $value['minute'] ?? $this->referenceDate->format('i'), $value['second'] ?? $this->referenceDate->format('s') ), new \DateTimeZone($this->outputTimezone) ); if ($this->inputTimezone !== $this->outputTimezone) { $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone)); } } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } return $dateTime; } } Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformer.php 0000644 00000007425 15120211543 0022743 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\Exception\TransformationFailedException; /** * @author Franz Wilding <franz.wilding@me.com> * @author Bernhard Schussek <bschussek@gmail.com> * @author Fred Cox <mcfedr@gmail.com> */ class DateTimeToHtml5LocalDateTimeTransformer extends BaseDateTimeTransformer { public const HTML5_FORMAT = 'Y-m-d\\TH:i:s'; /** * Transforms a \DateTime into a local date and time string. * * According to the HTML standard, the input string of a datetime-local * input is an RFC3339 date followed by 'T', followed by an RFC3339 time. * https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-local-date-and-time-string * * @param \DateTime|\DateTimeInterface $dateTime A DateTime object * * @return string * * @throws TransformationFailedException If the given value is not an * instance of \DateTime or \DateTimeInterface */ public function transform($dateTime) { if (null === $dateTime) { return ''; } if (!$dateTime instanceof \DateTime && !$dateTime instanceof \DateTimeInterface) { throw new TransformationFailedException('Expected a \DateTime or \DateTimeInterface.'); } if ($this->inputTimezone !== $this->outputTimezone) { if (!$dateTime instanceof \DateTimeImmutable) { $dateTime = clone $dateTime; } $dateTime = $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone)); } return $dateTime->format(self::HTML5_FORMAT); } /** * Transforms a local date and time string into a \DateTime. * * When transforming back to DateTime the regex is slightly laxer, taking into * account rules for parsing a local date and time string * https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-local-date-and-time-string * * @param string $dateTimeLocal Formatted string * * @return \DateTime|null * * @throws TransformationFailedException If the given value is not a string, * if the value could not be transformed */ public function reverseTransform($dateTimeLocal) { if (!\is_string($dateTimeLocal)) { throw new TransformationFailedException('Expected a string.'); } if ('' === $dateTimeLocal) { return null; } // to maintain backwards compatibility we do not strictly validate the submitted date // see https://github.com/symfony/symfony/issues/28699 if (!preg_match('/^(\d{4})-(\d{2})-(\d{2})[T ]\d{2}:\d{2}(?::\d{2})?/', $dateTimeLocal, $matches)) { throw new TransformationFailedException(sprintf('The date "%s" is not a valid date.', $dateTimeLocal)); } try { $dateTime = new \DateTime($dateTimeLocal, new \DateTimeZone($this->outputTimezone)); } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } if ($this->inputTimezone !== $dateTime->getTimezone()->getName()) { $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone)); } if (!checkdate($matches[2], $matches[3], $matches[1])) { throw new TransformationFailedException(sprintf('The date "%s-%s-%s" is not a valid date.', $matches[1], $matches[2], $matches[3])); } return $dateTime; } } Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php 0000644 00000017037 15120211543 0022457 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\UnexpectedTypeException; /** * Transforms between a normalized time and a localized time string. * * @author Bernhard Schussek <bschussek@gmail.com> * @author Florian Eckerstorfer <florian@eckerstorfer.org> */ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer { private $dateFormat; private $timeFormat; private $pattern; private $calendar; /** * @see BaseDateTimeTransformer::formats for available format options * * @param string|null $inputTimezone The name of the input timezone * @param string|null $outputTimezone The name of the output timezone * @param int|null $dateFormat The date format * @param int|null $timeFormat The time format * @param int $calendar One of the \IntlDateFormatter calendar constants * @param string|null $pattern A pattern to pass to \IntlDateFormatter * * @throws UnexpectedTypeException If a format is not supported or if a timezone is not a string */ public function __construct(string $inputTimezone = null, string $outputTimezone = null, int $dateFormat = null, int $timeFormat = null, int $calendar = \IntlDateFormatter::GREGORIAN, string $pattern = null) { parent::__construct($inputTimezone, $outputTimezone); if (null === $dateFormat) { $dateFormat = \IntlDateFormatter::MEDIUM; } if (null === $timeFormat) { $timeFormat = \IntlDateFormatter::SHORT; } if (!\in_array($dateFormat, self::$formats, true)) { throw new UnexpectedTypeException($dateFormat, implode('", "', self::$formats)); } if (!\in_array($timeFormat, self::$formats, true)) { throw new UnexpectedTypeException($timeFormat, implode('", "', self::$formats)); } $this->dateFormat = $dateFormat; $this->timeFormat = $timeFormat; $this->calendar = $calendar; $this->pattern = $pattern; } /** * Transforms a normalized date into a localized date string/array. * * @param \DateTimeInterface $dateTime A DateTimeInterface object * * @return string * * @throws TransformationFailedException if the given value is not a \DateTimeInterface * or if the date could not be transformed */ public function transform($dateTime) { if (null === $dateTime) { return ''; } if (!$dateTime instanceof \DateTimeInterface) { throw new TransformationFailedException('Expected a \DateTimeInterface.'); } $value = $this->getIntlDateFormatter()->format($dateTime->getTimestamp()); if (0 != intl_get_error_code()) { throw new TransformationFailedException(intl_get_error_message()); } return $value; } /** * Transforms a localized date string/array into a normalized date. * * @param string|array $value Localized date string/array * * @return \DateTime|null * * @throws TransformationFailedException if the given value is not a string, * if the date could not be parsed */ public function reverseTransform($value) { if (!\is_string($value)) { throw new TransformationFailedException('Expected a string.'); } if ('' === $value) { return null; } // date-only patterns require parsing to be done in UTC, as midnight might not exist in the local timezone due // to DST changes $dateOnly = $this->isPatternDateOnly(); $dateFormatter = $this->getIntlDateFormatter($dateOnly); try { $timestamp = @$dateFormatter->parse($value); } catch (\IntlException $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } if (0 != intl_get_error_code()) { throw new TransformationFailedException(intl_get_error_message(), intl_get_error_code()); } elseif ($timestamp > 253402214400) { // This timestamp represents UTC midnight of 9999-12-31 to prevent 5+ digit years throw new TransformationFailedException('Years beyond 9999 are not supported.'); } elseif (false === $timestamp) { // the value couldn't be parsed but the Intl extension didn't report an error code, this // could be the case when the Intl polyfill is used which always returns 0 as the error code throw new TransformationFailedException(sprintf('"%s" could not be parsed as a date.', $value)); } try { if ($dateOnly) { // we only care about year-month-date, which has been delivered as a timestamp pointing to UTC midnight $dateTime = new \DateTime(gmdate('Y-m-d', $timestamp), new \DateTimeZone($this->outputTimezone)); } else { // read timestamp into DateTime object - the formatter delivers a timestamp $dateTime = new \DateTime(sprintf('@%s', $timestamp)); } // set timezone separately, as it would be ignored if set via the constructor, // see https://php.net/datetime.construct $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone)); } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } if ($this->outputTimezone !== $this->inputTimezone) { $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone)); } return $dateTime; } /** * Returns a preconfigured IntlDateFormatter instance. * * @param bool $ignoreTimezone Use UTC regardless of the configured timezone * * @return \IntlDateFormatter * * @throws TransformationFailedException in case the date formatter cannot be constructed */ protected function getIntlDateFormatter(bool $ignoreTimezone = false) { $dateFormat = $this->dateFormat; $timeFormat = $this->timeFormat; $timezone = new \DateTimeZone($ignoreTimezone ? 'UTC' : $this->outputTimezone); $calendar = $this->calendar; $pattern = $this->pattern; $intlDateFormatter = new \IntlDateFormatter(\Locale::getDefault(), $dateFormat, $timeFormat, $timezone, $calendar, $pattern ?? ''); // new \intlDateFormatter may return null instead of false in case of failure, see https://bugs.php.net/66323 if (!$intlDateFormatter) { throw new TransformationFailedException(intl_get_error_message(), intl_get_error_code()); } $intlDateFormatter->setLenient(false); return $intlDateFormatter; } /** * Checks if the pattern contains only a date. * * @return bool */ protected function isPatternDateOnly() { if (null === $this->pattern) { return false; } // strip escaped text $pattern = preg_replace("#'(.*?)'#", '', $this->pattern); // check for the absence of time-related placeholders return 0 === preg_match('#[ahHkKmsSAzZOvVxX]#', $pattern); } } Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php 0000644 00000005513 15120211543 0020412 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\Exception\TransformationFailedException; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class DateTimeToRfc3339Transformer extends BaseDateTimeTransformer { /** * Transforms a normalized date into a localized date. * * @param \DateTimeInterface $dateTime A DateTimeInterface object * * @return string * * @throws TransformationFailedException If the given value is not a \DateTimeInterface */ public function transform($dateTime) { if (null === $dateTime) { return ''; } if (!$dateTime instanceof \DateTimeInterface) { throw new TransformationFailedException('Expected a \DateTimeInterface.'); } if ($this->inputTimezone !== $this->outputTimezone) { if (!$dateTime instanceof \DateTimeImmutable) { $dateTime = clone $dateTime; } $dateTime = $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone)); } return preg_replace('/\+00:00$/', 'Z', $dateTime->format('c')); } /** * Transforms a formatted string following RFC 3339 into a normalized date. * * @param string $rfc3339 Formatted string * * @return \DateTime|null * * @throws TransformationFailedException If the given value is not a string, * if the value could not be transformed */ public function reverseTransform($rfc3339) { if (!\is_string($rfc3339)) { throw new TransformationFailedException('Expected a string.'); } if ('' === $rfc3339) { return null; } if (!preg_match('/^(\d{4})-(\d{2})-(\d{2})T\d{2}:\d{2}(?::\d{2})?(?:\.\d+)?(?:Z|(?:(?:\+|-)\d{2}:\d{2}))$/', $rfc3339, $matches)) { throw new TransformationFailedException(sprintf('The date "%s" is not a valid date.', $rfc3339)); } try { $dateTime = new \DateTime($rfc3339); } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } if ($this->inputTimezone !== $dateTime->getTimezone()->getName()) { $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone)); } if (!checkdate($matches[2], $matches[3], $matches[1])) { throw new TransformationFailedException(sprintf('The date "%s-%s-%s" is not a valid date.', $matches[1], $matches[2], $matches[3])); } return $dateTime; } } Extension/Core/DataTransformer/DateTimeToStringTransformer.php 0000644 00000011237 15120211543 0020624 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\Exception\TransformationFailedException; /** * Transforms between a date string and a DateTime object. * * @author Bernhard Schussek <bschussek@gmail.com> * @author Florian Eckerstorfer <florian@eckerstorfer.org> */ class DateTimeToStringTransformer extends BaseDateTimeTransformer { /** * Format used for generating strings. * * @var string */ private $generateFormat; /** * Format used for parsing strings. * * Different than the {@link $generateFormat} because formats for parsing * support additional characters in PHP that are not supported for * generating strings. * * @var string */ private $parseFormat; /** * Transforms a \DateTime instance to a string. * * @see \DateTime::format() for supported formats * * @param string|null $inputTimezone The name of the input timezone * @param string|null $outputTimezone The name of the output timezone * @param string $format The date format * @param string|null $parseFormat The parse format when different from $format */ public function __construct(string $inputTimezone = null, string $outputTimezone = null, string $format = 'Y-m-d H:i:s', string $parseFormat = null) { parent::__construct($inputTimezone, $outputTimezone); $this->generateFormat = $format; $this->parseFormat = $parseFormat ?? $format; // See https://php.net/datetime.createfromformat // The character "|" in the format makes sure that the parts of a date // that are *not* specified in the format are reset to the corresponding // values from 1970-01-01 00:00:00 instead of the current time. // Without "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 12:32:47", // where the time corresponds to the current server time. // With "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 00:00:00", // which is at least deterministic and thus used here. if (!str_contains($this->parseFormat, '|')) { $this->parseFormat .= '|'; } } /** * Transforms a DateTime object into a date string with the configured format * and timezone. * * @param \DateTimeInterface $dateTime A DateTimeInterface object * * @return string * * @throws TransformationFailedException If the given value is not a \DateTimeInterface */ public function transform($dateTime) { if (null === $dateTime) { return ''; } if (!$dateTime instanceof \DateTimeInterface) { throw new TransformationFailedException('Expected a \DateTimeInterface.'); } if (!$dateTime instanceof \DateTimeImmutable) { $dateTime = clone $dateTime; } $dateTime = $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone)); return $dateTime->format($this->generateFormat); } /** * Transforms a date string in the configured timezone into a DateTime object. * * @param string $value A value as produced by PHP's date() function * * @return \DateTime|null * * @throws TransformationFailedException If the given value is not a string, * or could not be transformed */ public function reverseTransform($value) { if (empty($value)) { return null; } if (!\is_string($value)) { throw new TransformationFailedException('Expected a string.'); } $outputTz = new \DateTimeZone($this->outputTimezone); $dateTime = \DateTime::createFromFormat($this->parseFormat, $value, $outputTz); $lastErrors = \DateTime::getLastErrors() ?: ['error_count' => 0, 'warning_count' => 0]; if (0 < $lastErrors['warning_count'] || 0 < $lastErrors['error_count']) { throw new TransformationFailedException(implode(', ', array_merge(array_values($lastErrors['warnings']), array_values($lastErrors['errors'])))); } try { if ($this->inputTimezone !== $this->outputTimezone) { $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone)); } } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } return $dateTime; } } Extension/Core/DataTransformer/DateTimeToTimestampTransformer.php 0000644 00000004454 15120211543 0021324 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\Exception\TransformationFailedException; /** * Transforms between a timestamp and a DateTime object. * * @author Bernhard Schussek <bschussek@gmail.com> * @author Florian Eckerstorfer <florian@eckerstorfer.org> */ class DateTimeToTimestampTransformer extends BaseDateTimeTransformer { /** * Transforms a DateTime object into a timestamp in the configured timezone. * * @param \DateTimeInterface $dateTime A DateTimeInterface object * * @return int|null * * @throws TransformationFailedException If the given value is not a \DateTimeInterface */ public function transform($dateTime) { if (null === $dateTime) { return null; } if (!$dateTime instanceof \DateTimeInterface) { throw new TransformationFailedException('Expected a \DateTimeInterface.'); } return $dateTime->getTimestamp(); } /** * Transforms a timestamp in the configured timezone into a DateTime object. * * @param string $value A timestamp * * @return \DateTime|null * * @throws TransformationFailedException If the given value is not a timestamp * or if the given timestamp is invalid */ public function reverseTransform($value) { if (null === $value) { return null; } if (!is_numeric($value)) { throw new TransformationFailedException('Expected a numeric.'); } try { $dateTime = new \DateTime(); $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone)); $dateTime->setTimestamp($value); if ($this->inputTimezone !== $this->outputTimezone) { $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone)); } } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } return $dateTime; } } Extension/Core/DataTransformer/DateTimeZoneToStringTransformer.php 0000644 00000004222 15120211543 0021454 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; /** * Transforms between a timezone identifier string and a DateTimeZone object. * * @author Roland Franssen <franssen.roland@gmail.com> */ class DateTimeZoneToStringTransformer implements DataTransformerInterface { private $multiple; public function __construct(bool $multiple = false) { $this->multiple = $multiple; } /** * {@inheritdoc} */ public function transform($dateTimeZone) { if (null === $dateTimeZone) { return null; } if ($this->multiple) { if (!\is_array($dateTimeZone)) { throw new TransformationFailedException('Expected an array of \DateTimeZone objects.'); } return array_map([new self(), 'transform'], $dateTimeZone); } if (!$dateTimeZone instanceof \DateTimeZone) { throw new TransformationFailedException('Expected a \DateTimeZone object.'); } return $dateTimeZone->getName(); } /** * {@inheritdoc} */ public function reverseTransform($value) { if (null === $value) { return null; } if ($this->multiple) { if (!\is_array($value)) { throw new TransformationFailedException('Expected an array of timezone identifier strings.'); } return array_map([new self(), 'reverseTransform'], $value); } if (!\is_string($value)) { throw new TransformationFailedException('Expected a timezone identifier string.'); } try { return new \DateTimeZone($value); } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } } } Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php 0000644 00000003341 15120211543 0022351 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\Exception\TransformationFailedException; /** * Transforms between an integer and a localized number with grouping * (each thousand) and comma separators. * * @author Bernhard Schussek <bschussek@gmail.com> */ class IntegerToLocalizedStringTransformer extends NumberToLocalizedStringTransformer { /** * Constructs a transformer. * * @param bool $grouping Whether thousands should be grouped * @param int|null $roundingMode One of the ROUND_ constants in this class * @param string|null $locale locale used for transforming */ public function __construct(?bool $grouping = false, ?int $roundingMode = \NumberFormatter::ROUND_DOWN, string $locale = null) { parent::__construct(0, $grouping, $roundingMode, $locale); } /** * {@inheritdoc} */ public function reverseTransform($value) { $decimalSeparator = $this->getNumberFormatter()->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL); if (\is_string($value) && str_contains($value, $decimalSeparator)) { throw new TransformationFailedException(sprintf('The value "%s" is not a valid integer.', $value)); } $result = parent::reverseTransform($value); return null !== $result ? (int) $result : null; } /** * @internal */ protected function castParsedValue($value) { return $value; } } Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php 0000644 00000004325 15120211543 0021511 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; /** * Transforms between a timezone identifier string and a IntlTimeZone object. * * @author Roland Franssen <franssen.roland@gmail.com> */ class IntlTimeZoneToStringTransformer implements DataTransformerInterface { private $multiple; public function __construct(bool $multiple = false) { $this->multiple = $multiple; } /** * {@inheritdoc} */ public function transform($intlTimeZone) { if (null === $intlTimeZone) { return null; } if ($this->multiple) { if (!\is_array($intlTimeZone)) { throw new TransformationFailedException('Expected an array of \IntlTimeZone objects.'); } return array_map([new self(), 'transform'], $intlTimeZone); } if (!$intlTimeZone instanceof \IntlTimeZone) { throw new TransformationFailedException('Expected a \IntlTimeZone object.'); } return $intlTimeZone->getID(); } /** * {@inheritdoc} */ public function reverseTransform($value) { if (null === $value) { return; } if ($this->multiple) { if (!\is_array($value)) { throw new TransformationFailedException('Expected an array of timezone identifier strings.'); } return array_map([new self(), 'reverseTransform'], $value); } if (!\is_string($value)) { throw new TransformationFailedException('Expected a timezone identifier string.'); } $intlTimeZone = \IntlTimeZone::createTimeZone($value); if ('Etc/Unknown' === $intlTimeZone->getID()) { throw new TransformationFailedException(sprintf('Unknown timezone identifier "%s".', $value)); } return $intlTimeZone; } } Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php 0000644 00000004335 15120211543 0022047 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\Exception\TransformationFailedException; /** * Transforms between a normalized format and a localized money string. * * @author Bernhard Schussek <bschussek@gmail.com> * @author Florian Eckerstorfer <florian@eckerstorfer.org> */ class MoneyToLocalizedStringTransformer extends NumberToLocalizedStringTransformer { private $divisor; public function __construct(?int $scale = 2, ?bool $grouping = true, ?int $roundingMode = \NumberFormatter::ROUND_HALFUP, ?int $divisor = 1, string $locale = null) { parent::__construct($scale ?? 2, $grouping ?? true, $roundingMode, $locale); $this->divisor = $divisor ?? 1; } /** * Transforms a normalized format into a localized money string. * * @param int|float|null $value Normalized number * * @return string * * @throws TransformationFailedException if the given value is not numeric or * if the value cannot be transformed */ public function transform($value) { if (null !== $value && 1 !== $this->divisor) { if (!is_numeric($value)) { throw new TransformationFailedException('Expected a numeric.'); } $value /= $this->divisor; } return parent::transform($value); } /** * Transforms a localized money string into a normalized format. * * @param string $value Localized money string * * @return int|float|null * * @throws TransformationFailedException if the given value is not a string * or if the value cannot be transformed */ public function reverseTransform($value) { $value = parent::reverseTransform($value); if (null !== $value && 1 !== $this->divisor) { $value = (float) (string) ($value * $this->divisor); } return $value; } } Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php 0000644 00000021274 15120211543 0022211 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; /** * Transforms between a number type and a localized number with grouping * (each thousand) and comma separators. * * @author Bernhard Schussek <bschussek@gmail.com> * @author Florian Eckerstorfer <florian@eckerstorfer.org> */ class NumberToLocalizedStringTransformer implements DataTransformerInterface { /** * @deprecated since Symfony 5.1, use \NumberFormatter::ROUND_CEILING instead. */ public const ROUND_CEILING = \NumberFormatter::ROUND_CEILING; /** * @deprecated since Symfony 5.1, use \NumberFormatter::ROUND_FLOOR instead. */ public const ROUND_FLOOR = \NumberFormatter::ROUND_FLOOR; /** * @deprecated since Symfony 5.1, use \NumberFormatter::ROUND_UP instead. */ public const ROUND_UP = \NumberFormatter::ROUND_UP; /** * @deprecated since Symfony 5.1, use \NumberFormatter::ROUND_DOWN instead. */ public const ROUND_DOWN = \NumberFormatter::ROUND_DOWN; /** * @deprecated since Symfony 5.1, use \NumberFormatter::ROUND_HALFEVEN instead. */ public const ROUND_HALF_EVEN = \NumberFormatter::ROUND_HALFEVEN; /** * @deprecated since Symfony 5.1, use \NumberFormatter::ROUND_HALFUP instead. */ public const ROUND_HALF_UP = \NumberFormatter::ROUND_HALFUP; /** * @deprecated since Symfony 5.1, use \NumberFormatter::ROUND_HALFDOWN instead. */ public const ROUND_HALF_DOWN = \NumberFormatter::ROUND_HALFDOWN; protected $grouping; protected $roundingMode; private $scale; private $locale; public function __construct(int $scale = null, ?bool $grouping = false, ?int $roundingMode = \NumberFormatter::ROUND_HALFUP, string $locale = null) { $this->scale = $scale; $this->grouping = $grouping ?? false; $this->roundingMode = $roundingMode ?? \NumberFormatter::ROUND_HALFUP; $this->locale = $locale; } /** * Transforms a number type into localized number. * * @param int|float|null $value Number value * * @return string * * @throws TransformationFailedException if the given value is not numeric * or if the value cannot be transformed */ public function transform($value) { if (null === $value) { return ''; } if (!is_numeric($value)) { throw new TransformationFailedException('Expected a numeric.'); } $formatter = $this->getNumberFormatter(); $value = $formatter->format($value); if (intl_is_failure($formatter->getErrorCode())) { throw new TransformationFailedException($formatter->getErrorMessage()); } // Convert non-breaking and narrow non-breaking spaces to normal ones $value = str_replace(["\xc2\xa0", "\xe2\x80\xaf"], ' ', $value); return $value; } /** * Transforms a localized number into an integer or float. * * @param string $value The localized value * * @return int|float|null * * @throws TransformationFailedException if the given value is not a string * or if the value cannot be transformed */ public function reverseTransform($value) { if (null !== $value && !\is_string($value)) { throw new TransformationFailedException('Expected a string.'); } if (null === $value || '' === $value) { return null; } if (\in_array($value, ['NaN', 'NAN', 'nan'], true)) { throw new TransformationFailedException('"NaN" is not a valid number.'); } $position = 0; $formatter = $this->getNumberFormatter(); $groupSep = $formatter->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL); $decSep = $formatter->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL); if ('.' !== $decSep && (!$this->grouping || '.' !== $groupSep)) { $value = str_replace('.', $decSep, $value); } if (',' !== $decSep && (!$this->grouping || ',' !== $groupSep)) { $value = str_replace(',', $decSep, $value); } if (str_contains($value, $decSep)) { $type = \NumberFormatter::TYPE_DOUBLE; } else { $type = \PHP_INT_SIZE === 8 ? \NumberFormatter::TYPE_INT64 : \NumberFormatter::TYPE_INT32; } $result = $formatter->parse($value, $type, $position); if (intl_is_failure($formatter->getErrorCode())) { throw new TransformationFailedException($formatter->getErrorMessage()); } if ($result >= \PHP_INT_MAX || $result <= -\PHP_INT_MAX) { throw new TransformationFailedException('I don\'t have a clear idea what infinity looks like.'); } $result = $this->castParsedValue($result); if (false !== $encoding = mb_detect_encoding($value, null, true)) { $length = mb_strlen($value, $encoding); $remainder = mb_substr($value, $position, $length, $encoding); } else { $length = \strlen($value); $remainder = substr($value, $position, $length); } // After parsing, position holds the index of the character where the // parsing stopped if ($position < $length) { // Check if there are unrecognized characters at the end of the // number (excluding whitespace characters) $remainder = trim($remainder, " \t\n\r\0\x0b\xc2\xa0"); if ('' !== $remainder) { throw new TransformationFailedException(sprintf('The number contains unrecognized characters: "%s".', $remainder)); } } // NumberFormatter::parse() does not round return $this->round($result); } /** * Returns a preconfigured \NumberFormatter instance. * * @return \NumberFormatter */ protected function getNumberFormatter() { $formatter = new \NumberFormatter($this->locale ?? \Locale::getDefault(), \NumberFormatter::DECIMAL); if (null !== $this->scale) { $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $this->scale); $formatter->setAttribute(\NumberFormatter::ROUNDING_MODE, $this->roundingMode); } $formatter->setAttribute(\NumberFormatter::GROUPING_USED, $this->grouping); return $formatter; } /** * @internal */ protected function castParsedValue($value) { if (\is_int($value) && $value === (int) $float = (float) $value) { return $float; } return $value; } /** * Rounds a number according to the configured scale and rounding mode. * * @param int|float $number A number * * @return int|float */ private function round($number) { if (null !== $this->scale && null !== $this->roundingMode) { // shift number to maintain the correct scale during rounding $roundingCoef = 10 ** $this->scale; // string representation to avoid rounding errors, similar to bcmul() $number = (string) ($number * $roundingCoef); switch ($this->roundingMode) { case \NumberFormatter::ROUND_CEILING: $number = ceil($number); break; case \NumberFormatter::ROUND_FLOOR: $number = floor($number); break; case \NumberFormatter::ROUND_UP: $number = $number > 0 ? ceil($number) : floor($number); break; case \NumberFormatter::ROUND_DOWN: $number = $number > 0 ? floor($number) : ceil($number); break; case \NumberFormatter::ROUND_HALFEVEN: $number = round($number, 0, \PHP_ROUND_HALF_EVEN); break; case \NumberFormatter::ROUND_HALFUP: $number = round($number, 0, \PHP_ROUND_HALF_UP); break; case \NumberFormatter::ROUND_HALFDOWN: $number = round($number, 0, \PHP_ROUND_HALF_DOWN); break; } $number = 1 === $roundingCoef ? (int) $number : $number / $roundingCoef; } return $number; } } Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php 0000644 00000021123 15120211543 0022352 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\UnexpectedTypeException; /** * Transforms between a normalized format (integer or float) and a percentage value. * * @author Bernhard Schussek <bschussek@gmail.com> * @author Florian Eckerstorfer <florian@eckerstorfer.org> */ class PercentToLocalizedStringTransformer implements DataTransformerInterface { public const FRACTIONAL = 'fractional'; public const INTEGER = 'integer'; protected static $types = [ self::FRACTIONAL, self::INTEGER, ]; private $roundingMode; private $type; private $scale; private $html5Format; /** * @see self::$types for a list of supported types * * @param int|null $roundingMode A value from \NumberFormatter, such as \NumberFormatter::ROUND_HALFUP * @param bool $html5Format Use an HTML5 specific format, see https://www.w3.org/TR/html51/sec-forms.html#date-time-and-number-formats * * @throws UnexpectedTypeException if the given value of type is unknown */ public function __construct(int $scale = null, string $type = null, int $roundingMode = null, bool $html5Format = false) { if (null === $type) { $type = self::FRACTIONAL; } if (null === $roundingMode && (\func_num_args() < 4 || func_get_arg(3))) { trigger_deprecation('symfony/form', '5.1', 'Not passing a rounding mode to "%s()" is deprecated. Starting with Symfony 6.0 it will default to "\NumberFormatter::ROUND_HALFUP".', __METHOD__); } if (!\in_array($type, self::$types, true)) { throw new UnexpectedTypeException($type, implode('", "', self::$types)); } $this->type = $type; $this->scale = $scale ?? 0; $this->roundingMode = $roundingMode; $this->html5Format = $html5Format; } /** * Transforms between a normalized format (integer or float) into a percentage value. * * @param int|float $value Normalized value * * @return string * * @throws TransformationFailedException if the given value is not numeric or * if the value could not be transformed */ public function transform($value) { if (null === $value) { return ''; } if (!is_numeric($value)) { throw new TransformationFailedException('Expected a numeric.'); } if (self::FRACTIONAL == $this->type) { $value *= 100; } $formatter = $this->getNumberFormatter(); $value = $formatter->format($value); if (intl_is_failure($formatter->getErrorCode())) { throw new TransformationFailedException($formatter->getErrorMessage()); } // replace the UTF-8 non break spaces return $value; } /** * Transforms between a percentage value into a normalized format (integer or float). * * @param string $value Percentage value * * @return int|float|null * * @throws TransformationFailedException if the given value is not a string or * if the value could not be transformed */ public function reverseTransform($value) { if (!\is_string($value)) { throw new TransformationFailedException('Expected a string.'); } if ('' === $value) { return null; } $position = 0; $formatter = $this->getNumberFormatter(); $groupSep = $formatter->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL); $decSep = $formatter->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL); $grouping = $formatter->getAttribute(\NumberFormatter::GROUPING_USED); if ('.' !== $decSep && (!$grouping || '.' !== $groupSep)) { $value = str_replace('.', $decSep, $value); } if (',' !== $decSep && (!$grouping || ',' !== $groupSep)) { $value = str_replace(',', $decSep, $value); } if (str_contains($value, $decSep)) { $type = \NumberFormatter::TYPE_DOUBLE; } else { $type = \PHP_INT_SIZE === 8 ? \NumberFormatter::TYPE_INT64 : \NumberFormatter::TYPE_INT32; } // replace normal spaces so that the formatter can read them $result = $formatter->parse(str_replace(' ', "\xc2\xa0", $value), $type, $position); if (intl_is_failure($formatter->getErrorCode())) { throw new TransformationFailedException($formatter->getErrorMessage()); } if (self::FRACTIONAL == $this->type) { $result /= 100; } if (\function_exists('mb_detect_encoding') && false !== $encoding = mb_detect_encoding($value, null, true)) { $length = mb_strlen($value, $encoding); $remainder = mb_substr($value, $position, $length, $encoding); } else { $length = \strlen($value); $remainder = substr($value, $position, $length); } // After parsing, position holds the index of the character where the // parsing stopped if ($position < $length) { // Check if there are unrecognized characters at the end of the // number (excluding whitespace characters) $remainder = trim($remainder, " \t\n\r\0\x0b\xc2\xa0"); if ('' !== $remainder) { throw new TransformationFailedException(sprintf('The number contains unrecognized characters: "%s".', $remainder)); } } return $this->round($result); } /** * Returns a preconfigured \NumberFormatter instance. * * @return \NumberFormatter */ protected function getNumberFormatter() { // Values used in HTML5 number inputs should be formatted as in "1234.5", ie. 'en' format without grouping, // according to https://www.w3.org/TR/html51/sec-forms.html#date-time-and-number-formats $formatter = new \NumberFormatter($this->html5Format ? 'en' : \Locale::getDefault(), \NumberFormatter::DECIMAL); if ($this->html5Format) { $formatter->setAttribute(\NumberFormatter::GROUPING_USED, 0); } $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $this->scale); if (null !== $this->roundingMode) { $formatter->setAttribute(\NumberFormatter::ROUNDING_MODE, $this->roundingMode); } return $formatter; } /** * Rounds a number according to the configured scale and rounding mode. * * @param int|float $number A number * * @return int|float */ private function round($number) { if (null !== $this->scale && null !== $this->roundingMode) { // shift number to maintain the correct scale during rounding $roundingCoef = 10 ** $this->scale; if (self::FRACTIONAL == $this->type) { $roundingCoef *= 100; } // string representation to avoid rounding errors, similar to bcmul() $number = (string) ($number * $roundingCoef); switch ($this->roundingMode) { case \NumberFormatter::ROUND_CEILING: $number = ceil($number); break; case \NumberFormatter::ROUND_FLOOR: $number = floor($number); break; case \NumberFormatter::ROUND_UP: $number = $number > 0 ? ceil($number) : floor($number); break; case \NumberFormatter::ROUND_DOWN: $number = $number > 0 ? floor($number) : ceil($number); break; case \NumberFormatter::ROUND_HALFEVEN: $number = round($number, 0, \PHP_ROUND_HALF_EVEN); break; case \NumberFormatter::ROUND_HALFUP: $number = round($number, 0, \PHP_ROUND_HALF_UP); break; case \NumberFormatter::ROUND_HALFDOWN: $number = round($number, 0, \PHP_ROUND_HALF_DOWN); break; } $number = 1 === $roundingCoef ? (int) $number : $number / $roundingCoef; } return $number; } } Extension/Core/DataTransformer/StringToFloatTransformer.php 0000644 00000002710 15120211543 0020171 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; class StringToFloatTransformer implements DataTransformerInterface { private $scale; public function __construct(int $scale = null) { $this->scale = $scale; } /** * @param mixed $value * * @return float|null */ public function transform($value) { if (null === $value) { return null; } if (!\is_string($value) || !is_numeric($value)) { throw new TransformationFailedException('Expected a numeric string.'); } return (float) $value; } /** * @param mixed $value * * @return string|null */ public function reverseTransform($value) { if (null === $value) { return null; } if (!\is_int($value) && !\is_float($value)) { throw new TransformationFailedException('Expected a numeric.'); } if ($this->scale > 0) { return number_format((float) $value, $this->scale, '.', ''); } return (string) $value; } } Extension/Core/DataTransformer/UlidToStringTransformer.php 0000644 00000003675 15120211543 0020034 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Uid\Ulid; /** * Transforms between a ULID string and a Ulid object. * * @author Pavel Dyakonov <wapinet@mail.ru> */ class UlidToStringTransformer implements DataTransformerInterface { /** * Transforms a Ulid object into a string. * * @param Ulid $value A Ulid object * * @return string|null * * @throws TransformationFailedException If the given value is not a Ulid object */ public function transform($value) { if (null === $value) { return null; } if (!$value instanceof Ulid) { throw new TransformationFailedException('Expected a Ulid.'); } return (string) $value; } /** * Transforms a ULID string into a Ulid object. * * @param string $value A ULID string * * @return Ulid|null * * @throws TransformationFailedException If the given value is not a string, * or could not be transformed */ public function reverseTransform($value) { if (null === $value || '' === $value) { return null; } if (!\is_string($value)) { throw new TransformationFailedException('Expected a string.'); } try { $ulid = new Ulid($value); } catch (\InvalidArgumentException $e) { throw new TransformationFailedException(sprintf('The value "%s" is not a valid ULID.', $value), $e->getCode(), $e); } return $ulid; } } Extension/Core/DataTransformer/UuidToStringTransformer.php 0000644 00000004113 15120211543 0020031 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Uid\Uuid; /** * Transforms between a UUID string and a Uuid object. * * @author Pavel Dyakonov <wapinet@mail.ru> */ class UuidToStringTransformer implements DataTransformerInterface { /** * Transforms a Uuid object into a string. * * @param Uuid $value A Uuid object * * @return string|null * * @throws TransformationFailedException If the given value is not a Uuid object */ public function transform($value) { if (null === $value) { return null; } if (!$value instanceof Uuid) { throw new TransformationFailedException('Expected a Uuid.'); } return (string) $value; } /** * Transforms a UUID string into a Uuid object. * * @param string $value A UUID string * * @return Uuid|null * * @throws TransformationFailedException If the given value is not a string, * or could not be transformed */ public function reverseTransform($value) { if (null === $value || '' === $value) { return null; } if (!\is_string($value)) { throw new TransformationFailedException('Expected a string.'); } if (!Uuid::isValid($value)) { throw new TransformationFailedException(sprintf('The value "%s" is not a valid UUID.', $value)); } try { return Uuid::fromString($value); } catch (\InvalidArgumentException $e) { throw new TransformationFailedException(sprintf('The value "%s" is not a valid UUID.', $value), $e->getCode(), $e); } } } Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php 0000644 00000004314 15120211543 0021031 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class ValueToDuplicatesTransformer implements DataTransformerInterface { private $keys; public function __construct(array $keys) { $this->keys = $keys; } /** * Duplicates the given value through the array. * * @param mixed $value The value * * @return array */ public function transform($value) { $result = []; foreach ($this->keys as $key) { $result[$key] = $value; } return $result; } /** * Extracts the duplicated value from an array. * * @return mixed * * @throws TransformationFailedException if the given value is not an array or * if the given array cannot be transformed */ public function reverseTransform($array) { if (!\is_array($array)) { throw new TransformationFailedException('Expected an array.'); } $result = current($array); $emptyKeys = []; foreach ($this->keys as $key) { if (isset($array[$key]) && '' !== $array[$key] && false !== $array[$key] && [] !== $array[$key]) { if ($array[$key] !== $result) { throw new TransformationFailedException('All values in the array should be the same.'); } } else { $emptyKeys[] = $key; } } if (\count($emptyKeys) > 0) { if (\count($emptyKeys) == \count($this->keys)) { // All keys empty return null; } throw new TransformationFailedException(sprintf('The keys "%s" should not be empty.', implode('", "', $emptyKeys))); } return $result; } } Extension/Core/DataTransformer/WeekToArrayTransformer.php 0000644 00000007365 15120211543 0017642 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; /** * Transforms between an ISO 8601 week date string and an array. * * @author Damien Fayet <damienf1521@gmail.com> */ class WeekToArrayTransformer implements DataTransformerInterface { /** * Transforms a string containing an ISO 8601 week date into an array. * * @param string|null $value A week date string * * @return array{year: int|null, week: int|null} * * @throws TransformationFailedException If the given value is not a string, * or if the given value does not follow the right format */ public function transform($value) { if (null === $value) { return ['year' => null, 'week' => null]; } if (!\is_string($value)) { throw new TransformationFailedException(sprintf('Value is expected to be a string but was "%s".', get_debug_type($value))); } if (0 === preg_match('/^(?P<year>\d{4})-W(?P<week>\d{2})$/', $value, $matches)) { throw new TransformationFailedException('Given data does not follow the date format "Y-\WW".'); } return [ 'year' => (int) $matches['year'], 'week' => (int) $matches['week'], ]; } /** * Transforms an array into a week date string. * * @param array{year: int|null, week: int|null} $value * * @return string|null A week date string following the format Y-\WW * * @throws TransformationFailedException If the given value cannot be merged in a valid week date string, * or if the obtained week date does not exists */ public function reverseTransform($value) { if (null === $value || [] === $value) { return null; } if (!\is_array($value)) { throw new TransformationFailedException(sprintf('Value is expected to be an array, but was "%s".', get_debug_type($value))); } if (!\array_key_exists('year', $value)) { throw new TransformationFailedException('Key "year" is missing.'); } if (!\array_key_exists('week', $value)) { throw new TransformationFailedException('Key "week" is missing.'); } if ($additionalKeys = array_diff(array_keys($value), ['year', 'week'])) { throw new TransformationFailedException(sprintf('Expected only keys "year" and "week" to be present, but also got ["%s"].', implode('", "', $additionalKeys))); } if (null === $value['year'] && null === $value['week']) { return null; } if (!\is_int($value['year'])) { throw new TransformationFailedException(sprintf('Year is expected to be an integer, but was "%s".', get_debug_type($value['year']))); } if (!\is_int($value['week'])) { throw new TransformationFailedException(sprintf('Week is expected to be an integer, but was "%s".', get_debug_type($value['week']))); } // The 28th December is always in the last week of the year if (date('W', strtotime('28th December '.$value['year'])) < $value['week']) { throw new TransformationFailedException(sprintf('Week "%d" does not exist for year "%d".', $value['week'], $value['year'])); } return sprintf('%d-W%02d', $value['year'], $value['week']); } } Extension/Core/EventListener/FixUrlProtocolListener.php 0000644 00000002474 15120211543 0017352 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; /** * Adds a protocol to a URL if it doesn't already have one. * * @author Bernhard Schussek <bschussek@gmail.com> */ class FixUrlProtocolListener implements EventSubscriberInterface { private $defaultProtocol; /** * @param string|null $defaultProtocol The URL scheme to add when there is none or null to not modify the data */ public function __construct(?string $defaultProtocol = 'http') { $this->defaultProtocol = $defaultProtocol; } public function onSubmit(FormEvent $event) { $data = $event->getData(); if ($this->defaultProtocol && $data && \is_string($data) && !preg_match('~^(?:[/.]|[\w+.-]+://|[^:/?@#]++@)~', $data)) { $event->setData($this->defaultProtocol.'://'.$data); } } public static function getSubscribedEvents() { return [FormEvents::SUBMIT => 'onSubmit']; } } Extension/Core/EventListener/MergeCollectionListener.php 0000644 00000007126 15120211543 0017471 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class MergeCollectionListener implements EventSubscriberInterface { private $allowAdd; private $allowDelete; /** * @param bool $allowAdd Whether values might be added to the collection * @param bool $allowDelete Whether values might be removed from the collection */ public function __construct(bool $allowAdd = false, bool $allowDelete = false) { $this->allowAdd = $allowAdd; $this->allowDelete = $allowDelete; } public static function getSubscribedEvents() { return [ FormEvents::SUBMIT => 'onSubmit', ]; } public function onSubmit(FormEvent $event) { $dataToMergeInto = $event->getForm()->getNormData(); $data = $event->getData(); if (null === $data) { $data = []; } if (!\is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) { throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)'); } if (null !== $dataToMergeInto && !\is_array($dataToMergeInto) && !($dataToMergeInto instanceof \Traversable && $dataToMergeInto instanceof \ArrayAccess)) { throw new UnexpectedTypeException($dataToMergeInto, 'array or (\Traversable and \ArrayAccess)'); } // If we are not allowed to change anything, return immediately if ($data === $dataToMergeInto || (!$this->allowAdd && !$this->allowDelete)) { $event->setData($dataToMergeInto); return; } if (null === $dataToMergeInto) { // No original data was set. Set it if allowed if ($this->allowAdd) { $dataToMergeInto = $data; } } else { // Calculate delta $itemsToAdd = \is_object($data) ? clone $data : $data; $itemsToDelete = []; foreach ($dataToMergeInto as $beforeKey => $beforeItem) { foreach ($data as $afterKey => $afterItem) { if ($afterItem === $beforeItem) { // Item found, next original item unset($itemsToAdd[$afterKey]); continue 2; } } // Item not found, remember for deletion $itemsToDelete[] = $beforeKey; } // Remove deleted items before adding to free keys that are to be // replaced if ($this->allowDelete) { foreach ($itemsToDelete as $key) { unset($dataToMergeInto[$key]); } } // Add remaining items if ($this->allowAdd) { foreach ($itemsToAdd as $key => $item) { if (!isset($dataToMergeInto[$key])) { $dataToMergeInto[$key] = $item; } else { $dataToMergeInto[] = $item; } } } } $event->setData($dataToMergeInto); } } Extension/Core/EventListener/ResizeFormListener.php 0000644 00000012253 15120211543 0016500 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormInterface; /** * Resize a collection form element based on the data sent from the client. * * @author Bernhard Schussek <bschussek@gmail.com> */ class ResizeFormListener implements EventSubscriberInterface { protected $type; protected $options; protected $allowAdd; protected $allowDelete; private $deleteEmpty; /** * @param bool $allowAdd Whether children could be added to the group * @param bool $allowDelete Whether children could be removed from the group * @param bool|callable $deleteEmpty */ public function __construct(string $type, array $options = [], bool $allowAdd = false, bool $allowDelete = false, $deleteEmpty = false) { $this->type = $type; $this->allowAdd = $allowAdd; $this->allowDelete = $allowDelete; $this->options = $options; $this->deleteEmpty = $deleteEmpty; } public static function getSubscribedEvents() { return [ FormEvents::PRE_SET_DATA => 'preSetData', FormEvents::PRE_SUBMIT => 'preSubmit', // (MergeCollectionListener, MergeDoctrineCollectionListener) FormEvents::SUBMIT => ['onSubmit', 50], ]; } public function preSetData(FormEvent $event) { $form = $event->getForm(); $data = $event->getData(); if (null === $data) { $data = []; } if (!\is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) { throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)'); } // First remove all rows foreach ($form as $name => $child) { $form->remove($name); } // Then add all rows again in the correct order foreach ($data as $name => $value) { $form->add($name, $this->type, array_replace([ 'property_path' => '['.$name.']', ], $this->options)); } } public function preSubmit(FormEvent $event) { $form = $event->getForm(); $data = $event->getData(); if (!\is_array($data)) { $data = []; } // Remove all empty rows if ($this->allowDelete) { foreach ($form as $name => $child) { if (!isset($data[$name])) { $form->remove($name); } } } // Add all additional rows if ($this->allowAdd) { foreach ($data as $name => $value) { if (!$form->has($name)) { $form->add($name, $this->type, array_replace([ 'property_path' => '['.$name.']', ], $this->options)); } } } } public function onSubmit(FormEvent $event) { $form = $event->getForm(); $data = $event->getData(); // At this point, $data is an array or an array-like object that already contains the // new entries, which were added by the data mapper. The data mapper ignores existing // entries, so we need to manually unset removed entries in the collection. if (null === $data) { $data = []; } if (!\is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) { throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)'); } if ($this->deleteEmpty) { $previousData = $form->getData(); /** @var FormInterface $child */ foreach ($form as $name => $child) { if (!$child->isValid() || !$child->isSynchronized()) { continue; } $isNew = !isset($previousData[$name]); $isEmpty = \is_callable($this->deleteEmpty) ? ($this->deleteEmpty)($child->getData()) : $child->isEmpty(); // $isNew can only be true if allowAdd is true, so we don't // need to check allowAdd again if ($isEmpty && ($isNew || $this->allowDelete)) { unset($data[$name]); $form->remove($name); } } } // The data mapper only adds, but does not remove items, so do this // here if ($this->allowDelete) { $toDelete = []; foreach ($data as $name => $child) { if (!$form->has($name)) { $toDelete[] = $name; } } foreach ($toDelete as $name) { unset($data[$name]); } } $event->setData($data); } } Extension/Core/EventListener/TransformationFailureListener.php 0000644 00000004136 15120211543 0020732 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Contracts\Translation\TranslatorInterface; /** * @author Christian Flothmann <christian.flothmann@sensiolabs.de> */ class TransformationFailureListener implements EventSubscriberInterface { private $translator; public function __construct(TranslatorInterface $translator = null) { $this->translator = $translator; } public static function getSubscribedEvents() { return [ FormEvents::POST_SUBMIT => ['convertTransformationFailureToFormError', -1024], ]; } public function convertTransformationFailureToFormError(FormEvent $event) { $form = $event->getForm(); if (null === $form->getTransformationFailure() || !$form->isValid()) { return; } foreach ($form as $child) { if (!$child->isSynchronized()) { return; } } $clientDataAsString = \is_scalar($form->getViewData()) ? (string) $form->getViewData() : get_debug_type($form->getViewData()); $messageTemplate = $form->getConfig()->getOption('invalid_message', 'The value {{ value }} is not valid.'); $messageParameters = array_replace(['{{ value }}' => $clientDataAsString], $form->getConfig()->getOption('invalid_message_parameters', [])); if (null !== $this->translator) { $message = $this->translator->trans($messageTemplate, $messageParameters); } else { $message = strtr($messageTemplate, $messageParameters); } $form->addError(new FormError($message, $messageTemplate, $messageParameters, null, $form->getTransformationFailure())); } } Extension/Core/EventListener/TrimListener.php 0000644 00000001700 15120211543 0015321 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\Util\StringUtil; /** * Trims string data. * * @author Bernhard Schussek <bschussek@gmail.com> */ class TrimListener implements EventSubscriberInterface { public function preSubmit(FormEvent $event) { $data = $event->getData(); if (!\is_string($data)) { return; } $event->setData(StringUtil::trim($data)); } public static function getSubscribedEvents() { return [FormEvents::PRE_SUBMIT => 'preSubmit']; } } Extension/Core/Type/BaseType.php 0000644 00000014701 15120211543 0012553 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractRendererEngine; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\OptionsResolver; /** * Encapsulates common logic of {@link FormType} and {@link ButtonType}. * * This type does not appear in the form's type inheritance chain and as such * cannot be extended (via {@link \Symfony\Component\Form\FormExtensionInterface}) nor themed. * * @author Bernhard Schussek <bschussek@gmail.com> */ abstract class BaseType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder->setDisabled($options['disabled']); $builder->setAutoInitialize($options['auto_initialize']); } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { $name = $form->getName(); $blockName = $options['block_name'] ?: $form->getName(); $translationDomain = $options['translation_domain']; $labelTranslationParameters = $options['label_translation_parameters']; $attrTranslationParameters = $options['attr_translation_parameters']; $labelFormat = $options['label_format']; if ($view->parent) { if ('' !== ($parentFullName = $view->parent->vars['full_name'])) { $id = sprintf('%s_%s', $view->parent->vars['id'], $name); $fullName = sprintf('%s[%s]', $parentFullName, $name); $uniqueBlockPrefix = sprintf('%s_%s', $view->parent->vars['unique_block_prefix'], $blockName); } else { $id = $name; $fullName = $name; $uniqueBlockPrefix = '_'.$blockName; } if (null === $translationDomain) { $translationDomain = $view->parent->vars['translation_domain']; } $labelTranslationParameters = array_merge($view->parent->vars['label_translation_parameters'], $labelTranslationParameters); $attrTranslationParameters = array_merge($view->parent->vars['attr_translation_parameters'], $attrTranslationParameters); if (!$labelFormat) { $labelFormat = $view->parent->vars['label_format']; } $rootFormAttrOption = $form->getRoot()->getConfig()->getOption('form_attr'); if ($options['form_attr'] || $rootFormAttrOption) { $options['attr']['form'] = \is_string($rootFormAttrOption) ? $rootFormAttrOption : $form->getRoot()->getName(); if (empty($options['attr']['form'])) { throw new LogicException('"form_attr" option must be a string identifier on root form when it has no id.'); } } } else { $id = \is_string($options['form_attr']) ? $options['form_attr'] : $name; $fullName = $name; $uniqueBlockPrefix = '_'.$blockName; // Strip leading underscores and digits. These are allowed in // form names, but not in HTML4 ID attributes. // https://www.w3.org/TR/html401/struct/global#adef-id $id = ltrim($id, '_0123456789'); } $blockPrefixes = []; for ($type = $form->getConfig()->getType(); null !== $type; $type = $type->getParent()) { array_unshift($blockPrefixes, $type->getBlockPrefix()); } if (null !== $options['block_prefix']) { $blockPrefixes[] = $options['block_prefix']; } $blockPrefixes[] = $uniqueBlockPrefix; $view->vars = array_replace($view->vars, [ 'form' => $view, 'id' => $id, 'name' => $name, 'full_name' => $fullName, 'disabled' => $form->isDisabled(), 'label' => $options['label'], 'label_format' => $labelFormat, 'label_html' => $options['label_html'], 'multipart' => false, 'attr' => $options['attr'], 'block_prefixes' => $blockPrefixes, 'unique_block_prefix' => $uniqueBlockPrefix, 'row_attr' => $options['row_attr'], 'translation_domain' => $translationDomain, 'label_translation_parameters' => $labelTranslationParameters, 'attr_translation_parameters' => $attrTranslationParameters, 'priority' => $options['priority'], // Using the block name here speeds up performance in collection // forms, where each entry has the same full block name. // Including the type is important too, because if rows of a // collection form have different types (dynamically), they should // be rendered differently. // https://github.com/symfony/symfony/issues/5038 AbstractRendererEngine::CACHE_KEY_VAR => $uniqueBlockPrefix.'_'.$form->getConfig()->getType()->getBlockPrefix(), ]); } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'block_name' => null, 'block_prefix' => null, 'disabled' => false, 'label' => null, 'label_format' => null, 'row_attr' => [], 'label_html' => false, 'label_translation_parameters' => [], 'attr_translation_parameters' => [], 'attr' => [], 'translation_domain' => null, 'auto_initialize' => true, 'priority' => 0, 'form_attr' => false, ]); $resolver->setAllowedTypes('block_prefix', ['null', 'string']); $resolver->setAllowedTypes('attr', 'array'); $resolver->setAllowedTypes('row_attr', 'array'); $resolver->setAllowedTypes('label_html', 'bool'); $resolver->setAllowedTypes('priority', 'int'); $resolver->setAllowedTypes('form_attr', ['bool', 'string']); $resolver->setInfo('priority', 'The form rendering priority (higher priorities will be rendered first)'); } } Extension/Core/Type/BirthdayType.php 0000644 00000002331 15120211543 0013443 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class BirthdayType extends AbstractType { /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'years' => range((int) date('Y') - 120, date('Y')), 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a valid birthdate.'; }, ]); $resolver->setAllowedTypes('years', 'array'); } /** * {@inheritdoc} */ public function getParent() { return DateType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'birthday'; } } Extension/Core/Type/ButtonType.php 0000644 00000001721 15120211543 0013152 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\ButtonTypeInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** * A form button. * * @author Bernhard Schussek <bschussek@gmail.com> */ class ButtonType extends BaseType implements ButtonTypeInterface { /** * {@inheritdoc} */ public function getParent() { return null; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'button'; } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { parent::configureOptions($resolver); $resolver->setDefault('auto_initialize', false); } } Extension/Core/Type/CheckboxType.php 0000644 00000005117 15120211543 0013430 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\DataTransformer\BooleanToStringTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class CheckboxType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { // Unlike in other types, where the data is NULL by default, it // needs to be a Boolean here. setData(null) is not acceptable // for checkboxes and radio buttons (unless a custom model // transformer handles this case). // We cannot solve this case via overriding the "data" option, because // doing so also calls setDataLocked(true). $builder->setData($options['data'] ?? false); $builder->addViewTransformer(new BooleanToStringTransformer($options['value'], $options['false_values'])); } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars = array_replace($view->vars, [ 'value' => $options['value'], 'checked' => null !== $form->getViewData(), ]); } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $emptyData = function (FormInterface $form, $viewData) { return $viewData; }; $resolver->setDefaults([ 'value' => '1', 'empty_data' => $emptyData, 'compound' => false, 'false_values' => [null], 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'The checkbox has an invalid value.'; }, 'is_empty_callback' => static function ($modelData): bool { return false === $modelData; }, ]); $resolver->setAllowedTypes('false_values', 'array'); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'checkbox'; } } Extension/Core/Type/ChoiceType.php 0000644 00000052612 15120211543 0013076 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceAttr; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceFieldName; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceFilter; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceLabel; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceLoader; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceTranslationParameters; use Symfony\Component\Form\ChoiceList\Factory\Cache\ChoiceValue; use Symfony\Component\Form\ChoiceList\Factory\Cache\GroupBy; use Symfony\Component\Form\ChoiceList\Factory\Cache\PreferredChoice; use Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator; use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface; use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView; use Symfony\Component\Form\ChoiceList\View\ChoiceListView; use Symfony\Component\Form\ChoiceList\View\ChoiceView; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Extension\Core\DataMapper\CheckboxListMapper; use Symfony\Component\Form\Extension\Core\DataMapper\RadioListMapper; use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer; use Symfony\Component\Form\Extension\Core\EventListener\MergeCollectionListener; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyPath; use Symfony\Contracts\Translation\TranslatorInterface; class ChoiceType extends AbstractType { private $choiceListFactory; private $translator; /** * @param TranslatorInterface $translator */ public function __construct(ChoiceListFactoryInterface $choiceListFactory = null, $translator = null) { $this->choiceListFactory = $choiceListFactory ?? new CachingFactoryDecorator( new PropertyAccessDecorator( new DefaultChoiceListFactory() ) ); if (null !== $translator && !$translator instanceof TranslatorInterface) { throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be han instance of "%s", "%s" given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator))); } $this->translator = $translator; // BC, to be removed in 6.0 if ($this->choiceListFactory instanceof CachingFactoryDecorator) { return; } $ref = new \ReflectionMethod($this->choiceListFactory, 'createListFromChoices'); if ($ref->getNumberOfParameters() < 3) { trigger_deprecation('symfony/form', '5.1', 'Not defining a third parameter "callable|null $filter" in "%s::%s()" is deprecated.', $ref->class, $ref->name); } } /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $unknownValues = []; $choiceList = $this->createChoiceList($options); $builder->setAttribute('choice_list', $choiceList); if ($options['expanded']) { $builder->setDataMapper($options['multiple'] ? new CheckboxListMapper() : new RadioListMapper()); // Initialize all choices before doing the index check below. // This helps in cases where index checks are optimized for non // initialized choice lists. For example, when using an SQL driver, // the index check would read in one SQL query and the initialization // requires another SQL query. When the initialization is done first, // one SQL query is sufficient. $choiceListView = $this->createChoiceListView($choiceList, $options); $builder->setAttribute('choice_list_view', $choiceListView); // Check if the choices already contain the empty value // Only add the placeholder option if this is not the case if (null !== $options['placeholder'] && 0 === \count($choiceList->getChoicesForValues(['']))) { $placeholderView = new ChoiceView(null, '', $options['placeholder']); // "placeholder" is a reserved name $this->addSubForm($builder, 'placeholder', $placeholderView, $options); } $this->addSubForms($builder, $choiceListView->preferredChoices, $options); $this->addSubForms($builder, $choiceListView->choices, $options); } if ($options['expanded'] || $options['multiple']) { // Make sure that scalar, submitted values are converted to arrays // which can be submitted to the checkboxes/radio buttons $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($choiceList, $options, &$unknownValues) { $form = $event->getForm(); $data = $event->getData(); // Since the type always use mapper an empty array will not be // considered as empty in Form::submit(), we need to evaluate // empty data here so its value is submitted to sub forms if (null === $data) { $emptyData = $form->getConfig()->getEmptyData(); $data = $emptyData instanceof \Closure ? $emptyData($form, $data) : $emptyData; } // Convert the submitted data to a string, if scalar, before // casting it to an array if (!\is_array($data)) { if ($options['multiple']) { throw new TransformationFailedException('Expected an array.'); } $data = (array) (string) $data; } // A map from submitted values to integers $valueMap = array_flip($data); // Make a copy of the value map to determine whether any unknown // values were submitted $unknownValues = $valueMap; // Reconstruct the data as mapping from child names to values $knownValues = []; if ($options['expanded']) { /** @var FormInterface $child */ foreach ($form as $child) { $value = $child->getConfig()->getOption('value'); // Add the value to $data with the child's name as key if (isset($valueMap[$value])) { $knownValues[$child->getName()] = $value; unset($unknownValues[$value]); continue; } else { $knownValues[$child->getName()] = null; } } } else { foreach ($data as $value) { if ($choiceList->getChoicesForValues([$value])) { $knownValues[] = $value; unset($unknownValues[$value]); } } } // The empty value is always known, independent of whether a // field exists for it or not unset($unknownValues['']); // Throw exception if unknown values were submitted (multiple choices will be handled in a different event listener below) if (\count($unknownValues) > 0 && !$options['multiple']) { throw new TransformationFailedException(sprintf('The choices "%s" do not exist in the choice list.', implode('", "', array_keys($unknownValues)))); } $event->setData($knownValues); }); } if ($options['multiple']) { $messageTemplate = $options['invalid_message'] ?? 'The value {{ value }} is not valid.'; $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use (&$unknownValues, $messageTemplate) { // Throw exception if unknown values were submitted if (\count($unknownValues) > 0) { $form = $event->getForm(); $clientDataAsString = \is_scalar($form->getViewData()) ? (string) $form->getViewData() : (\is_array($form->getViewData()) ? implode('", "', array_keys($unknownValues)) : \gettype($form->getViewData())); if (null !== $this->translator) { $message = $this->translator->trans($messageTemplate, ['{{ value }}' => $clientDataAsString], 'validators'); } else { $message = strtr($messageTemplate, ['{{ value }}' => $clientDataAsString]); } $form->addError(new FormError($message, $messageTemplate, ['{{ value }}' => $clientDataAsString], null, new TransformationFailedException(sprintf('The choices "%s" do not exist in the choice list.', $clientDataAsString)))); } }); // <select> tag with "multiple" option or list of checkbox inputs $builder->addViewTransformer(new ChoicesToValuesTransformer($choiceList)); } else { // <select> tag without "multiple" option or list of radio inputs $builder->addViewTransformer(new ChoiceToValueTransformer($choiceList)); } if ($options['multiple'] && $options['by_reference']) { // Make sure the collection created during the client->norm // transformation is merged back into the original collection $builder->addEventSubscriber(new MergeCollectionListener(true, true)); } // To avoid issues when the submitted choices are arrays (i.e. array to string conversions), // we have to ensure that all elements of the submitted choice data are NULL, strings or ints. $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) { $data = $event->getData(); if (!\is_array($data)) { return; } foreach ($data as $v) { if (null !== $v && !\is_string($v) && !\is_int($v)) { throw new TransformationFailedException('All choices submitted must be NULL, strings or ints.'); } } }, 256); } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { $choiceTranslationDomain = $options['choice_translation_domain']; if ($view->parent && null === $choiceTranslationDomain) { $choiceTranslationDomain = $view->vars['translation_domain']; } /** @var ChoiceListInterface $choiceList */ $choiceList = $form->getConfig()->getAttribute('choice_list'); /** @var ChoiceListView $choiceListView */ $choiceListView = $form->getConfig()->hasAttribute('choice_list_view') ? $form->getConfig()->getAttribute('choice_list_view') : $this->createChoiceListView($choiceList, $options); $view->vars = array_replace($view->vars, [ 'multiple' => $options['multiple'], 'expanded' => $options['expanded'], 'preferred_choices' => $choiceListView->preferredChoices, 'choices' => $choiceListView->choices, 'separator' => '-------------------', 'placeholder' => null, 'choice_translation_domain' => $choiceTranslationDomain, 'choice_translation_parameters' => $options['choice_translation_parameters'], ]); // The decision, whether a choice is selected, is potentially done // thousand of times during the rendering of a template. Provide a // closure here that is optimized for the value of the form, to // avoid making the type check inside the closure. if ($options['multiple']) { $view->vars['is_selected'] = function ($choice, array $values) { return \in_array($choice, $values, true); }; } else { $view->vars['is_selected'] = function ($choice, $value) { return $choice === $value; }; } // Check if the choices already contain the empty value $view->vars['placeholder_in_choices'] = $choiceListView->hasPlaceholder(); // Only add the empty value option if this is not the case if (null !== $options['placeholder'] && !$view->vars['placeholder_in_choices']) { $view->vars['placeholder'] = $options['placeholder']; } if ($options['multiple'] && !$options['expanded']) { // Add "[]" to the name in case a select tag with multiple options is // displayed. Otherwise only one of the selected options is sent in the // POST request. $view->vars['full_name'] .= '[]'; } } /** * {@inheritdoc} */ public function finishView(FormView $view, FormInterface $form, array $options) { if ($options['expanded']) { // Radio buttons should have the same name as the parent $childName = $view->vars['full_name']; // Checkboxes should append "[]" to allow multiple selection if ($options['multiple']) { $childName .= '[]'; } foreach ($view as $childView) { $childView->vars['full_name'] = $childName; } } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $emptyData = function (Options $options) { if ($options['expanded'] && !$options['multiple']) { return null; } if ($options['multiple']) { return []; } return ''; }; $placeholderDefault = function (Options $options) { return $options['required'] ? null : ''; }; $placeholderNormalizer = function (Options $options, $placeholder) { if ($options['multiple']) { // never use an empty value for this case return null; } 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 null; } elseif (false === $placeholder) { // an empty value should be added but the user decided otherwise return null; } 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([ 'multiple' => false, 'expanded' => false, 'choices' => [], 'choice_filter' => null, 'choice_loader' => null, 'choice_label' => null, 'choice_name' => null, 'choice_value' => null, 'choice_attr' => null, 'choice_translation_parameters' => [], 'preferred_choices' => [], 'group_by' => null, 'empty_data' => $emptyData, 'placeholder' => $placeholderDefault, 'error_bubbling' => false, 'compound' => $compound, // The view data is always a string or an array of strings, // even if the "data" option is manually set to an object. // See https://github.com/symfony/symfony/pull/5582 'data_class' => null, 'choice_translation_domain' => true, 'trim' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'The selected choice is invalid.'; }, ]); $resolver->setNormalizer('placeholder', $placeholderNormalizer); $resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer); $resolver->setAllowedTypes('choices', ['null', 'array', \Traversable::class]); $resolver->setAllowedTypes('choice_translation_domain', ['null', 'bool', 'string']); $resolver->setAllowedTypes('choice_loader', ['null', ChoiceLoaderInterface::class, ChoiceLoader::class]); $resolver->setAllowedTypes('choice_filter', ['null', 'callable', 'string', PropertyPath::class, ChoiceFilter::class]); $resolver->setAllowedTypes('choice_label', ['null', 'bool', 'callable', 'string', PropertyPath::class, ChoiceLabel::class]); $resolver->setAllowedTypes('choice_name', ['null', 'callable', 'string', PropertyPath::class, ChoiceFieldName::class]); $resolver->setAllowedTypes('choice_value', ['null', 'callable', 'string', PropertyPath::class, ChoiceValue::class]); $resolver->setAllowedTypes('choice_attr', ['null', 'array', 'callable', 'string', PropertyPath::class, ChoiceAttr::class]); $resolver->setAllowedTypes('choice_translation_parameters', ['null', 'array', 'callable', ChoiceTranslationParameters::class]); $resolver->setAllowedTypes('preferred_choices', ['array', \Traversable::class, 'callable', 'string', PropertyPath::class, PreferredChoice::class]); $resolver->setAllowedTypes('group_by', ['null', 'callable', 'string', PropertyPath::class, GroupBy::class]); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'choice'; } /** * Adds the sub fields for an expanded choice field. */ private function addSubForms(FormBuilderInterface $builder, array $choiceViews, array $options) { foreach ($choiceViews as $name => $choiceView) { // Flatten groups if (\is_array($choiceView)) { $this->addSubForms($builder, $choiceView, $options); continue; } if ($choiceView instanceof ChoiceGroupView) { $this->addSubForms($builder, $choiceView->choices, $options); continue; } $this->addSubForm($builder, $name, $choiceView, $options); } } private function addSubForm(FormBuilderInterface $builder, string $name, ChoiceView $choiceView, array $options) { $choiceOpts = [ 'value' => $choiceView->value, 'label' => $choiceView->label, 'label_html' => $options['label_html'], 'attr' => $choiceView->attr, 'label_translation_parameters' => $choiceView->labelTranslationParameters, 'translation_domain' => $options['choice_translation_domain'], 'block_name' => 'entry', ]; if ($options['multiple']) { $choiceType = CheckboxType::class; // The user can check 0 or more checkboxes. If required // is true, they are required to check all of them. $choiceOpts['required'] = false; } else { $choiceType = RadioType::class; } $builder->add($name, $choiceType, $choiceOpts); } private function createChoiceList(array $options) { if (null !== $options['choice_loader']) { return $this->choiceListFactory->createListFromLoader( $options['choice_loader'], $options['choice_value'], $options['choice_filter'] ); } // Harden against NULL values (like in EntityType and ModelType) $choices = null !== $options['choices'] ? $options['choices'] : []; return $this->choiceListFactory->createListFromChoices( $choices, $options['choice_value'], $options['choice_filter'] ); } private function createChoiceListView(ChoiceListInterface $choiceList, array $options) { return $this->choiceListFactory->createView( $choiceList, $options['preferred_choices'], $options['choice_label'], $options['choice_name'], $options['group_by'], $options['choice_attr'], $options['choice_translation_parameters'] ); } } Extension/Core/Type/CollectionType.php 0000644 00000010625 15120211543 0013775 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class CollectionType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { if ($options['allow_add'] && $options['prototype']) { $prototypeOptions = array_replace([ 'required' => $options['required'], 'label' => $options['prototype_name'].'label__', ], $options['entry_options']); if (null !== $options['prototype_data']) { $prototypeOptions['data'] = $options['prototype_data']; } $prototype = $builder->create($options['prototype_name'], $options['entry_type'], $prototypeOptions); $builder->setAttribute('prototype', $prototype->getForm()); } $resizeListener = new ResizeFormListener( $options['entry_type'], $options['entry_options'], $options['allow_add'], $options['allow_delete'], $options['delete_empty'] ); $builder->addEventSubscriber($resizeListener); } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars = array_replace($view->vars, [ 'allow_add' => $options['allow_add'], 'allow_delete' => $options['allow_delete'], ]); if ($form->getConfig()->hasAttribute('prototype')) { $prototype = $form->getConfig()->getAttribute('prototype'); $view->vars['prototype'] = $prototype->setParent($form)->createView($view); } } /** * {@inheritdoc} */ public function finishView(FormView $view, FormInterface $form, array $options) { $prefixOffset = -2; // check if the entry type also defines a block prefix /** @var FormInterface $entry */ foreach ($form as $entry) { if ($entry->getConfig()->getOption('block_prefix')) { --$prefixOffset; } break; } foreach ($view as $entryView) { array_splice($entryView->vars['block_prefixes'], $prefixOffset, 0, 'collection_entry'); } /** @var FormInterface $prototype */ if ($prototype = $form->getConfig()->getAttribute('prototype')) { if ($view->vars['prototype']->vars['multipart']) { $view->vars['multipart'] = true; } if ($prefixOffset > -3 && $prototype->getConfig()->getOption('block_prefix')) { --$prefixOffset; } array_splice($view->vars['prototype']->vars['block_prefixes'], $prefixOffset, 0, 'collection_entry'); } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $entryOptionsNormalizer = function (Options $options, $value) { $value['block_name'] = 'entry'; return $value; }; $resolver->setDefaults([ 'allow_add' => false, 'allow_delete' => false, 'prototype' => true, 'prototype_data' => null, 'prototype_name' => '__name__', 'entry_type' => TextType::class, 'entry_options' => [], 'delete_empty' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'The collection is invalid.'; }, ]); $resolver->setNormalizer('entry_options', $entryOptionsNormalizer); $resolver->setAllowedTypes('delete_empty', ['bool', 'callable']); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'collection'; } } Extension/Core/Type/ColorType.php 0000644 00000005246 15120211543 0012763 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Contracts\Translation\TranslatorInterface; class ColorType extends AbstractType { /** * @see https://www.w3.org/TR/html52/sec-forms.html#color-state-typecolor */ private const HTML5_PATTERN = '/^#[0-9a-f]{6}$/i'; private $translator; public function __construct(TranslatorInterface $translator = null) { $this->translator = $translator; } /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { if (!$options['html5']) { return; } $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event): void { $value = $event->getData(); if (null === $value || '' === $value) { return; } if (\is_string($value) && preg_match(self::HTML5_PATTERN, $value)) { return; } $messageTemplate = 'This value is not a valid HTML5 color.'; $messageParameters = [ '{{ value }}' => \is_scalar($value) ? (string) $value : \gettype($value), ]; $message = $this->translator ? $this->translator->trans($messageTemplate, $messageParameters, 'validators') : $messageTemplate; $event->getForm()->addError(new FormError($message, $messageTemplate, $messageParameters)); }); } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'html5' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please select a valid color.'; }, ]); $resolver->setAllowedTypes('html5', 'bool'); } /** * {@inheritdoc} */ public function getParent() { return TextType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'color'; } } Extension/Core/Type/CountryType.php 0000644 00000004566 15120211543 0013354 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\ChoiceList\ChoiceList; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Intl\Countries; use Symfony\Component\Intl\Intl; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class CountryType extends AbstractType { /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'choice_loader' => function (Options $options) { if (!class_exists(Intl::class)) { throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s". Try running "composer require symfony/intl".', static::class)); } $choiceTranslationLocale = $options['choice_translation_locale']; $alpha3 = $options['alpha3']; return ChoiceList::loader($this, new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale, $alpha3) { return array_flip($alpha3 ? Countries::getAlpha3Names($choiceTranslationLocale) : Countries::getNames($choiceTranslationLocale)); }), [$choiceTranslationLocale, $alpha3]); }, 'choice_translation_domain' => false, 'choice_translation_locale' => null, 'alpha3' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please select a valid country.'; }, ]); $resolver->setAllowedTypes('choice_translation_locale', ['null', 'string']); $resolver->setAllowedTypes('alpha3', 'bool'); } /** * {@inheritdoc} */ public function getParent() { return ChoiceType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'country'; } } Extension/Core/Type/CurrencyType.php 0000644 00000004244 15120211543 0013474 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\ChoiceList\ChoiceList; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Intl\Currencies; use Symfony\Component\Intl\Intl; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class CurrencyType extends AbstractType { /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'choice_loader' => function (Options $options) { if (!class_exists(Intl::class)) { throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s". Try running "composer require symfony/intl".', static::class)); } $choiceTranslationLocale = $options['choice_translation_locale']; return ChoiceList::loader($this, new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { return array_flip(Currencies::getNames($choiceTranslationLocale)); }), $choiceTranslationLocale); }, 'choice_translation_domain' => false, 'choice_translation_locale' => null, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please select a valid currency.'; }, ]); $resolver->setAllowedTypes('choice_translation_locale', ['null', 'string']); } /** * {@inheritdoc} */ public function getParent() { return ChoiceType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'currency'; } } Extension/Core/Type/DateIntervalType.php 0000644 00000025150 15120211543 0014263 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Exception\InvalidConfigurationException; use Symfony\Component\Form\Extension\Core\DataTransformer\DateIntervalToArrayTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateIntervalToStringTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\IntegerToLocalizedStringTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\Form\ReversedTransformer; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; /** * @author Steffen Roßkamp <steffen.rosskamp@gimmickmedia.de> */ class DateIntervalType extends AbstractType { private const TIME_PARTS = [ 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', ]; private const WIDGETS = [ 'text' => TextType::class, 'integer' => IntegerType::class, 'choice' => ChoiceType::class, ]; /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { if (!$options['with_years'] && !$options['with_months'] && !$options['with_weeks'] && !$options['with_days'] && !$options['with_hours'] && !$options['with_minutes'] && !$options['with_seconds']) { throw new InvalidConfigurationException('You must enable at least one interval field.'); } if ($options['with_invert'] && 'single_text' === $options['widget']) { throw new InvalidConfigurationException('The single_text widget does not support invertible intervals.'); } if ($options['with_weeks'] && $options['with_days']) { throw new InvalidConfigurationException('You cannot enable weeks and days fields together.'); } $format = 'P'; $parts = []; if ($options['with_years']) { $format .= '%yY'; $parts[] = 'years'; } if ($options['with_months']) { $format .= '%mM'; $parts[] = 'months'; } if ($options['with_weeks']) { $format .= '%wW'; $parts[] = 'weeks'; } if ($options['with_days']) { $format .= '%dD'; $parts[] = 'days'; } if ($options['with_hours'] || $options['with_minutes'] || $options['with_seconds']) { $format .= 'T'; } if ($options['with_hours']) { $format .= '%hH'; $parts[] = 'hours'; } if ($options['with_minutes']) { $format .= '%iM'; $parts[] = 'minutes'; } if ($options['with_seconds']) { $format .= '%sS'; $parts[] = 'seconds'; } if ($options['with_invert']) { $parts[] = 'invert'; } if ('single_text' === $options['widget']) { $builder->addViewTransformer(new DateIntervalToStringTransformer($format)); } else { foreach (self::TIME_PARTS as $part) { if ($options['with_'.$part]) { $childOptions = [ 'error_bubbling' => true, 'label' => $options['labels'][$part], // Append generic carry-along options 'required' => $options['required'], 'translation_domain' => $options['translation_domain'], // when compound the array entries are ignored, we need to cascade the configuration here 'empty_data' => $options['empty_data'][$part] ?? null, ]; if ('choice' === $options['widget']) { $childOptions['choice_translation_domain'] = false; $childOptions['choices'] = $options[$part]; $childOptions['placeholder'] = $options['placeholder'][$part]; } $childForm = $builder->create($part, self::WIDGETS[$options['widget']], $childOptions); if ('integer' === $options['widget']) { $childForm->addModelTransformer( new ReversedTransformer( new IntegerToLocalizedStringTransformer() ) ); } $builder->add($childForm); } } if ($options['with_invert']) { $builder->add('invert', CheckboxType::class, [ 'label' => $options['labels']['invert'], 'error_bubbling' => true, 'required' => false, 'translation_domain' => $options['translation_domain'], ]); } $builder->addViewTransformer(new DateIntervalToArrayTransformer($parts, 'text' === $options['widget'])); } if ('string' === $options['input']) { $builder->addModelTransformer( new ReversedTransformer( new DateIntervalToStringTransformer($format) ) ); } elseif ('array' === $options['input']) { $builder->addModelTransformer( new ReversedTransformer( new DateIntervalToArrayTransformer($parts) ) ); } } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { $vars = [ 'widget' => $options['widget'], 'with_invert' => $options['with_invert'], ]; foreach (self::TIME_PARTS as $part) { $vars['with_'.$part] = $options['with_'.$part]; } $view->vars = array_replace($view->vars, $vars); } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $compound = function (Options $options) { return 'single_text' !== $options['widget']; }; $emptyData = function (Options $options) { return 'single_text' === $options['widget'] ? '' : []; }; $placeholderDefault = function (Options $options) { return $options['required'] ? null : ''; }; $placeholderNormalizer = function (Options $options, $placeholder) use ($placeholderDefault) { if (\is_array($placeholder)) { $default = $placeholderDefault($options); return array_merge(array_fill_keys(self::TIME_PARTS, $default), $placeholder); } return array_fill_keys(self::TIME_PARTS, $placeholder); }; $labelsNormalizer = function (Options $options, array $labels) { return array_replace([ 'years' => null, 'months' => null, 'days' => null, 'weeks' => null, 'hours' => null, 'minutes' => null, 'seconds' => null, 'invert' => 'Negative interval', ], array_filter($labels, function ($label) { return null !== $label; })); }; $resolver->setDefaults([ 'with_years' => true, 'with_months' => true, 'with_days' => true, 'with_weeks' => false, 'with_hours' => false, 'with_minutes' => false, 'with_seconds' => false, 'with_invert' => false, 'years' => range(0, 100), 'months' => range(0, 12), 'weeks' => range(0, 52), 'days' => range(0, 31), 'hours' => range(0, 24), 'minutes' => range(0, 60), 'seconds' => range(0, 60), 'widget' => 'choice', 'input' => 'dateinterval', 'placeholder' => $placeholderDefault, 'by_reference' => true, 'error_bubbling' => false, // If initialized with a \DateInterval object, FormType initializes // this option to "\DateInterval". Since the internal, normalized // representation is not \DateInterval, but an array, we need to unset // this option. 'data_class' => null, 'compound' => $compound, 'empty_data' => $emptyData, 'labels' => [], 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please choose a valid date interval.'; }, ]); $resolver->setNormalizer('placeholder', $placeholderNormalizer); $resolver->setNormalizer('labels', $labelsNormalizer); $resolver->setAllowedValues( 'input', [ 'dateinterval', 'string', 'array', ] ); $resolver->setAllowedValues( 'widget', [ 'single_text', 'text', 'integer', 'choice', ] ); // Don't clone \DateInterval classes, as i.e. format() // does not work after that $resolver->setAllowedValues('by_reference', true); $resolver->setAllowedTypes('years', 'array'); $resolver->setAllowedTypes('months', 'array'); $resolver->setAllowedTypes('weeks', 'array'); $resolver->setAllowedTypes('days', 'array'); $resolver->setAllowedTypes('hours', 'array'); $resolver->setAllowedTypes('minutes', 'array'); $resolver->setAllowedTypes('seconds', 'array'); $resolver->setAllowedTypes('with_years', 'bool'); $resolver->setAllowedTypes('with_months', 'bool'); $resolver->setAllowedTypes('with_weeks', 'bool'); $resolver->setAllowedTypes('with_days', 'bool'); $resolver->setAllowedTypes('with_hours', 'bool'); $resolver->setAllowedTypes('with_minutes', 'bool'); $resolver->setAllowedTypes('with_seconds', 'bool'); $resolver->setAllowedTypes('with_invert', 'bool'); $resolver->setAllowedTypes('labels', 'array'); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'dateinterval'; } } Extension/Core/Type/DateTimeType.php 0000644 00000033602 15120211543 0013376 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\ArrayToPartsTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToHtml5LocalDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\Form\ReversedTransformer; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class DateTimeType extends AbstractType { public const DEFAULT_DATE_FORMAT = \IntlDateFormatter::MEDIUM; public const DEFAULT_TIME_FORMAT = \IntlDateFormatter::MEDIUM; /** * The HTML5 datetime-local format as defined in * http://w3c.github.io/html-reference/datatypes.html#form.data.datetime-local. */ public const HTML5_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; private const ACCEPTED_FORMATS = [ \IntlDateFormatter::FULL, \IntlDateFormatter::LONG, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT, ]; /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $parts = ['year', 'month', 'day', 'hour']; $dateParts = ['year', 'month', 'day']; $timeParts = ['hour']; if ($options['with_minutes']) { $parts[] = 'minute'; $timeParts[] = 'minute'; } if ($options['with_seconds']) { $parts[] = 'second'; $timeParts[] = 'second'; } $dateFormat = \is_int($options['date_format']) ? $options['date_format'] : self::DEFAULT_DATE_FORMAT; $timeFormat = self::DEFAULT_TIME_FORMAT; $calendar = \IntlDateFormatter::GREGORIAN; $pattern = \is_string($options['format']) ? $options['format'] : null; if (!\in_array($dateFormat, self::ACCEPTED_FORMATS, true)) { throw new InvalidOptionsException('The "date_format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom format.'); } if ('single_text' === $options['widget']) { if (self::HTML5_FORMAT === $pattern) { $builder->addViewTransformer(new DateTimeToHtml5LocalDateTimeTransformer( $options['model_timezone'], $options['view_timezone'] )); } else { $builder->addViewTransformer(new DateTimeToLocalizedStringTransformer( $options['model_timezone'], $options['view_timezone'], $dateFormat, $timeFormat, $calendar, $pattern )); } } else { // when the form is compound the entries of the array are ignored in favor of children data // so we need to handle the cascade setting here $emptyData = $builder->getEmptyData() ?: []; // Only pass a subset of the options to children $dateOptions = array_intersect_key($options, array_flip([ 'years', 'months', 'days', 'placeholder', 'choice_translation_domain', 'required', 'translation_domain', 'html5', 'invalid_message', 'invalid_message_parameters', ])); if ($emptyData instanceof \Closure) { $lazyEmptyData = static function ($option) use ($emptyData) { return static function (FormInterface $form) use ($emptyData, $option) { $emptyData = $emptyData($form->getParent()); return $emptyData[$option] ?? ''; }; }; $dateOptions['empty_data'] = $lazyEmptyData('date'); } elseif (isset($emptyData['date'])) { $dateOptions['empty_data'] = $emptyData['date']; } $timeOptions = array_intersect_key($options, array_flip([ 'hours', 'minutes', 'seconds', 'with_minutes', 'with_seconds', 'placeholder', 'choice_translation_domain', 'required', 'translation_domain', 'html5', 'invalid_message', 'invalid_message_parameters', ])); if ($emptyData instanceof \Closure) { $timeOptions['empty_data'] = $lazyEmptyData('time'); } elseif (isset($emptyData['time'])) { $timeOptions['empty_data'] = $emptyData['time']; } if (false === $options['label']) { $dateOptions['label'] = false; $timeOptions['label'] = false; } if (null !== $options['date_widget']) { $dateOptions['widget'] = $options['date_widget']; } if (null !== $options['date_label']) { $dateOptions['label'] = $options['date_label']; } if (null !== $options['time_widget']) { $timeOptions['widget'] = $options['time_widget']; } if (null !== $options['time_label']) { $timeOptions['label'] = $options['time_label']; } if (null !== $options['date_format']) { $dateOptions['format'] = $options['date_format']; } $dateOptions['input'] = $timeOptions['input'] = 'array'; $dateOptions['error_bubbling'] = $timeOptions['error_bubbling'] = true; $builder ->addViewTransformer(new DataTransformerChain([ new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts), new ArrayToPartsTransformer([ 'date' => $dateParts, 'time' => $timeParts, ]), ])) ->add('date', DateType::class, $dateOptions) ->add('time', TimeType::class, $timeOptions) ; } if ('datetime_immutable' === $options['input']) { $builder->addModelTransformer(new DateTimeImmutableToDateTimeTransformer()); } elseif ('string' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], $options['input_format']) )); } elseif ('timestamp' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone']) )); } elseif ('array' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], $parts) )); } } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars['widget'] = $options['widget']; // Change the input to an HTML5 datetime input if // * the widget is set to "single_text" // * the format matches the one expected by HTML5 // * the html5 is set to true if ($options['html5'] && 'single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) { $view->vars['type'] = 'datetime-local'; // we need to force the browser to display the seconds by // adding the HTML attribute step if not already defined. // Otherwise the browser will not display and so not send the seconds // therefore the value will always be considered as invalid. if ($options['with_seconds'] && !isset($view->vars['attr']['step'])) { $view->vars['attr']['step'] = 1; } } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $compound = function (Options $options) { return 'single_text' !== $options['widget']; }; // Defaults to the value of "widget" $dateWidget = function (Options $options) { return 'single_text' === $options['widget'] ? null : $options['widget']; }; // Defaults to the value of "widget" $timeWidget = function (Options $options) { return 'single_text' === $options['widget'] ? null : $options['widget']; }; $resolver->setDefaults([ 'input' => 'datetime', 'model_timezone' => null, 'view_timezone' => null, 'format' => self::HTML5_FORMAT, 'date_format' => null, 'widget' => null, 'date_widget' => $dateWidget, 'time_widget' => $timeWidget, 'with_minutes' => true, 'with_seconds' => false, 'html5' => true, // Don't modify \DateTime classes by reference, we treat // them like immutable value objects 'by_reference' => false, 'error_bubbling' => false, // If initialized with a \DateTime object, FormType initializes // this option to "\DateTime". Since the internal, normalized // representation is not \DateTime, but an array, we need to unset // this option. 'data_class' => null, 'compound' => $compound, 'date_label' => null, 'time_label' => null, 'empty_data' => function (Options $options) { return $options['compound'] ? [] : ''; }, 'input_format' => 'Y-m-d H:i:s', 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a valid date and time.'; }, ]); // Don't add some defaults in order to preserve the defaults // set in DateType and TimeType $resolver->setDefined([ 'placeholder', 'choice_translation_domain', 'years', 'months', 'days', 'hours', 'minutes', 'seconds', ]); $resolver->setAllowedValues('input', [ 'datetime', 'datetime_immutable', 'string', 'timestamp', 'array', ]); $resolver->setAllowedValues('date_widget', [ null, // inherit default from DateType 'single_text', 'text', 'choice', ]); $resolver->setAllowedValues('time_widget', [ null, // inherit default from TimeType 'single_text', 'text', 'choice', ]); // This option will overwrite "date_widget" and "time_widget" options $resolver->setAllowedValues('widget', [ null, // default, don't overwrite options 'single_text', 'text', 'choice', ]); $resolver->setAllowedTypes('input_format', 'string'); $resolver->setNormalizer('date_format', function (Options $options, $dateFormat) { if (null !== $dateFormat && 'single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) { throw new LogicException(sprintf('Cannot use the "date_format" option of the "%s" with an HTML5 date.', self::class)); } return $dateFormat; }); $resolver->setNormalizer('date_widget', function (Options $options, $dateWidget) { if (null !== $dateWidget && 'single_text' === $options['widget']) { throw new LogicException(sprintf('Cannot use the "date_widget" option of the "%s" when the "widget" option is set to "single_text".', self::class)); } return $dateWidget; }); $resolver->setNormalizer('time_widget', function (Options $options, $timeWidget) { if (null !== $timeWidget && 'single_text' === $options['widget']) { throw new LogicException(sprintf('Cannot use the "time_widget" option of the "%s" when the "widget" option is set to "single_text".', self::class)); } return $timeWidget; }); $resolver->setNormalizer('html5', function (Options $options, $html5) { if ($html5 && self::HTML5_FORMAT !== $options['format']) { throw new LogicException(sprintf('Cannot use the "format" option of "%s" when the "html5" option is enabled.', self::class)); } return $html5; }); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'datetime'; } } Extension/Core/Type/DateType.php 0000644 00000040117 15120211543 0012556 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\Form\ReversedTransformer; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class DateType extends AbstractType { public const DEFAULT_FORMAT = \IntlDateFormatter::MEDIUM; public const HTML5_FORMAT = 'yyyy-MM-dd'; private const ACCEPTED_FORMATS = [ \IntlDateFormatter::FULL, \IntlDateFormatter::LONG, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT, ]; private const WIDGETS = [ 'text' => TextType::class, 'choice' => ChoiceType::class, ]; /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $dateFormat = \is_int($options['format']) ? $options['format'] : self::DEFAULT_FORMAT; $timeFormat = \IntlDateFormatter::NONE; $calendar = \IntlDateFormatter::GREGORIAN; $pattern = \is_string($options['format']) ? $options['format'] : ''; if (!\in_array($dateFormat, self::ACCEPTED_FORMATS, true)) { throw new InvalidOptionsException('The "format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom format.'); } if ('single_text' === $options['widget']) { if ('' !== $pattern && !str_contains($pattern, 'y') && !str_contains($pattern, 'M') && !str_contains($pattern, 'd')) { throw new InvalidOptionsException(sprintf('The "format" option should contain the letters "y", "M" or "d". Its current value is "%s".', $pattern)); } $builder->addViewTransformer(new DateTimeToLocalizedStringTransformer( $options['model_timezone'], $options['view_timezone'], $dateFormat, $timeFormat, $calendar, $pattern )); } else { if ('' !== $pattern && (!str_contains($pattern, 'y') || !str_contains($pattern, 'M') || !str_contains($pattern, 'd'))) { throw new InvalidOptionsException(sprintf('The "format" option should contain the letters "y", "M" and "d". Its current value is "%s".', $pattern)); } $yearOptions = $monthOptions = $dayOptions = [ 'error_bubbling' => true, 'empty_data' => '', ]; // when the form is compound the entries of the array are ignored in favor of children data // so we need to handle the cascade setting here $emptyData = $builder->getEmptyData() ?: []; if ($emptyData instanceof \Closure) { $lazyEmptyData = static function ($option) use ($emptyData) { return static function (FormInterface $form) use ($emptyData, $option) { $emptyData = $emptyData($form->getParent()); return $emptyData[$option] ?? ''; }; }; $yearOptions['empty_data'] = $lazyEmptyData('year'); $monthOptions['empty_data'] = $lazyEmptyData('month'); $dayOptions['empty_data'] = $lazyEmptyData('day'); } else { if (isset($emptyData['year'])) { $yearOptions['empty_data'] = $emptyData['year']; } if (isset($emptyData['month'])) { $monthOptions['empty_data'] = $emptyData['month']; } if (isset($emptyData['day'])) { $dayOptions['empty_data'] = $emptyData['day']; } } if (isset($options['invalid_message'])) { $dayOptions['invalid_message'] = $options['invalid_message']; $monthOptions['invalid_message'] = $options['invalid_message']; $yearOptions['invalid_message'] = $options['invalid_message']; } if (isset($options['invalid_message_parameters'])) { $dayOptions['invalid_message_parameters'] = $options['invalid_message_parameters']; $monthOptions['invalid_message_parameters'] = $options['invalid_message_parameters']; $yearOptions['invalid_message_parameters'] = $options['invalid_message_parameters']; } $formatter = new \IntlDateFormatter( \Locale::getDefault(), $dateFormat, $timeFormat, // see https://bugs.php.net/66323 class_exists(\IntlTimeZone::class, false) ? \IntlTimeZone::createDefault() : null, $calendar, $pattern ); // new \IntlDateFormatter may return null instead of false in case of failure, see https://bugs.php.net/66323 if (!$formatter) { throw new InvalidOptionsException(intl_get_error_message(), intl_get_error_code()); } $formatter->setLenient(false); if ('choice' === $options['widget']) { // Only pass a subset of the options to children $yearOptions['choices'] = $this->formatTimestamps($formatter, '/y+/', $this->listYears($options['years'])); $yearOptions['placeholder'] = $options['placeholder']['year']; $yearOptions['choice_translation_domain'] = $options['choice_translation_domain']['year']; $monthOptions['choices'] = $this->formatTimestamps($formatter, '/[M|L]+/', $this->listMonths($options['months'])); $monthOptions['placeholder'] = $options['placeholder']['month']; $monthOptions['choice_translation_domain'] = $options['choice_translation_domain']['month']; $dayOptions['choices'] = $this->formatTimestamps($formatter, '/d+/', $this->listDays($options['days'])); $dayOptions['placeholder'] = $options['placeholder']['day']; $dayOptions['choice_translation_domain'] = $options['choice_translation_domain']['day']; } // Append generic carry-along options foreach (['required', 'translation_domain'] as $passOpt) { $yearOptions[$passOpt] = $monthOptions[$passOpt] = $dayOptions[$passOpt] = $options[$passOpt]; } $builder ->add('year', self::WIDGETS[$options['widget']], $yearOptions) ->add('month', self::WIDGETS[$options['widget']], $monthOptions) ->add('day', self::WIDGETS[$options['widget']], $dayOptions) ->addViewTransformer(new DateTimeToArrayTransformer( $options['model_timezone'], $options['view_timezone'], ['year', 'month', 'day'] )) ->setAttribute('formatter', $formatter) ; } if ('datetime_immutable' === $options['input']) { $builder->addModelTransformer(new DateTimeImmutableToDateTimeTransformer()); } elseif ('string' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], $options['input_format']) )); } elseif ('timestamp' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone']) )); } elseif ('array' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], ['year', 'month', 'day']) )); } } /** * {@inheritdoc} */ public function finishView(FormView $view, FormInterface $form, array $options) { $view->vars['widget'] = $options['widget']; // Change the input to an HTML5 date input if // * the widget is set to "single_text" // * the format matches the one expected by HTML5 // * the html5 is set to true if ($options['html5'] && 'single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) { $view->vars['type'] = 'date'; } if ($form->getConfig()->hasAttribute('formatter')) { $pattern = $form->getConfig()->getAttribute('formatter')->getPattern(); // remove special characters unless the format was explicitly specified if (!\is_string($options['format'])) { // remove quoted strings first $pattern = preg_replace('/\'[^\']+\'/', '', $pattern); // remove remaining special chars $pattern = preg_replace('/[^yMd]+/', '', $pattern); } // set right order with respect to locale (e.g.: de_DE=dd.MM.yy; en_US=M/d/yy) // lookup various formats at http://userguide.icu-project.org/formatparse/datetime if (preg_match('/^([yMd]+)[^yMd]*([yMd]+)[^yMd]*([yMd]+)$/', $pattern)) { $pattern = preg_replace(['/y+/', '/M+/', '/d+/'], ['{{ year }}', '{{ month }}', '{{ day }}'], $pattern); } else { // default fallback $pattern = '{{ year }}{{ month }}{{ day }}'; } $view->vars['date_pattern'] = $pattern; } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $compound = function (Options $options) { return 'single_text' !== $options['widget']; }; $placeholderDefault = function (Options $options) { return $options['required'] ? null : ''; }; $placeholderNormalizer = function (Options $options, $placeholder) use ($placeholderDefault) { if (\is_array($placeholder)) { $default = $placeholderDefault($options); return array_merge( ['year' => $default, 'month' => $default, 'day' => $default], $placeholder ); } return [ 'year' => $placeholder, 'month' => $placeholder, 'day' => $placeholder, ]; }; $choiceTranslationDomainNormalizer = function (Options $options, $choiceTranslationDomain) { if (\is_array($choiceTranslationDomain)) { $default = false; return array_replace( ['year' => $default, 'month' => $default, 'day' => $default], $choiceTranslationDomain ); } return [ 'year' => $choiceTranslationDomain, 'month' => $choiceTranslationDomain, 'day' => $choiceTranslationDomain, ]; }; $format = function (Options $options) { return 'single_text' === $options['widget'] ? self::HTML5_FORMAT : self::DEFAULT_FORMAT; }; $resolver->setDefaults([ 'years' => range((int) date('Y') - 5, (int) date('Y') + 5), 'months' => range(1, 12), 'days' => range(1, 31), 'widget' => 'choice', 'input' => 'datetime', 'format' => $format, 'model_timezone' => null, 'view_timezone' => null, 'placeholder' => $placeholderDefault, 'html5' => true, // Don't modify \DateTime classes by reference, we treat // them like immutable value objects 'by_reference' => false, 'error_bubbling' => false, // If initialized with a \DateTime object, FormType initializes // this option to "\DateTime". Since the internal, normalized // representation is not \DateTime, but an array, we need to unset // this option. 'data_class' => null, 'compound' => $compound, 'empty_data' => function (Options $options) { return $options['compound'] ? [] : ''; }, 'choice_translation_domain' => false, 'input_format' => 'Y-m-d', 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a valid date.'; }, ]); $resolver->setNormalizer('placeholder', $placeholderNormalizer); $resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer); $resolver->setAllowedValues('input', [ 'datetime', 'datetime_immutable', 'string', 'timestamp', 'array', ]); $resolver->setAllowedValues('widget', [ 'single_text', 'text', 'choice', ]); $resolver->setAllowedTypes('format', ['int', 'string']); $resolver->setAllowedTypes('years', 'array'); $resolver->setAllowedTypes('months', 'array'); $resolver->setAllowedTypes('days', 'array'); $resolver->setAllowedTypes('input_format', 'string'); $resolver->setNormalizer('html5', function (Options $options, $html5) { if ($html5 && 'single_text' === $options['widget'] && self::HTML5_FORMAT !== $options['format']) { throw new LogicException(sprintf('Cannot use the "format" option of "%s" when the "html5" option is enabled.', self::class)); } return $html5; }); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'date'; } private function formatTimestamps(\IntlDateFormatter $formatter, string $regex, array $timestamps) { $pattern = $formatter->getPattern(); $timezone = $formatter->getTimeZoneId(); $formattedTimestamps = []; $formatter->setTimeZone('UTC'); if (preg_match($regex, $pattern, $matches)) { $formatter->setPattern($matches[0]); foreach ($timestamps as $timestamp => $choice) { $formattedTimestamps[$formatter->format($timestamp)] = $choice; } // I'd like to clone the formatter above, but then we get a // segmentation fault, so let's restore the old state instead $formatter->setPattern($pattern); } $formatter->setTimeZone($timezone); return $formattedTimestamps; } private function listYears(array $years) { $result = []; foreach ($years as $year) { $result[\PHP_INT_SIZE === 4 ? \DateTime::createFromFormat('Y e', $year.' UTC')->format('U') : gmmktime(0, 0, 0, 6, 15, $year)] = $year; } return $result; } private function listMonths(array $months) { $result = []; foreach ($months as $month) { $result[gmmktime(0, 0, 0, $month, 15)] = $month; } return $result; } private function listDays(array $days) { $result = []; foreach ($days as $day) { $result[gmmktime(0, 0, 0, 5, $day)] = $day; } return $result; } } Extension/Core/Type/EmailType.php 0000644 00000002140 15120211543 0012722 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class EmailType extends AbstractType { /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a valid email address.'; }, ]); } /** * {@inheritdoc} */ public function getParent() { return TextType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'email'; } } Extension/Core/Type/EnumType.php 0000644 00000003252 15120211543 0012604 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; /** * A choice type for native PHP enums. * * @author Alexander M. Turek <me@derrabus.de> */ final class EnumType extends AbstractType { public function configureOptions(OptionsResolver $resolver): void { $resolver ->setRequired(['class']) ->setAllowedTypes('class', 'string') ->setAllowedValues('class', \Closure::fromCallable('enum_exists')) ->setDefault('choices', static function (Options $options): array { return $options['class']::cases(); }) ->setDefault('choice_label', static function (\UnitEnum $choice): string { return $choice->name; }) ->setDefault('choice_value', static function (Options $options): ?\Closure { if (!is_a($options['class'], \BackedEnum::class, true)) { return null; } return static function (?\BackedEnum $choice): ?string { if (null === $choice) { return null; } return (string) $choice->value; }; }) ; } public function getParent(): string { return ChoiceType::class; } } Extension/Core/Type/FileType.php 0000644 00000020414 15120211543 0012556 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FileUploadError; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Contracts\Translation\TranslatorInterface; class FileType extends AbstractType { public const KIB_BYTES = 1024; public const MIB_BYTES = 1048576; private const SUFFIXES = [ 1 => 'bytes', self::KIB_BYTES => 'KiB', self::MIB_BYTES => 'MiB', ]; private $translator; public function __construct(TranslatorInterface $translator = null) { $this->translator = $translator; } /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { // Ensure that submitted data is always an uploaded file or an array of some $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($options) { $form = $event->getForm(); $requestHandler = $form->getConfig()->getRequestHandler(); if ($options['multiple']) { $data = []; $files = $event->getData(); if (!\is_array($files)) { $files = []; } foreach ($files as $file) { if ($requestHandler->isFileUpload($file)) { $data[] = $file; if (method_exists($requestHandler, 'getUploadFileError') && null !== $errorCode = $requestHandler->getUploadFileError($file)) { $form->addError($this->getFileUploadError($errorCode)); } } } // Since the array is never considered empty in the view data format // on submission, we need to evaluate the configured empty data here if ([] === $data) { $emptyData = $form->getConfig()->getEmptyData(); $data = $emptyData instanceof \Closure ? $emptyData($form, $data) : $emptyData; } $event->setData($data); } elseif ($requestHandler->isFileUpload($event->getData()) && method_exists($requestHandler, 'getUploadFileError') && null !== $errorCode = $requestHandler->getUploadFileError($event->getData())) { $form->addError($this->getFileUploadError($errorCode)); } elseif (!$requestHandler->isFileUpload($event->getData())) { $event->setData(null); } }); } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { if ($options['multiple']) { $view->vars['full_name'] .= '[]'; $view->vars['attr']['multiple'] = 'multiple'; } $view->vars = array_replace($view->vars, [ 'type' => 'file', 'value' => '', ]); } /** * {@inheritdoc} */ public function finishView(FormView $view, FormInterface $form, array $options) { $view->vars['multipart'] = true; } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $dataClass = null; if (class_exists(\Symfony\Component\HttpFoundation\File\File::class)) { $dataClass = function (Options $options) { return $options['multiple'] ? null : 'Symfony\Component\HttpFoundation\File\File'; }; } $emptyData = function (Options $options) { return $options['multiple'] ? [] : null; }; $resolver->setDefaults([ 'compound' => false, 'data_class' => $dataClass, 'empty_data' => $emptyData, 'multiple' => false, 'allow_file_upload' => true, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please select a valid file.'; }, ]); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'file'; } private function getFileUploadError(int $errorCode) { $messageParameters = []; if (\UPLOAD_ERR_INI_SIZE === $errorCode) { [$limitAsString, $suffix] = $this->factorizeSizes(0, self::getMaxFilesize()); $messageTemplate = 'The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.'; $messageParameters = [ '{{ limit }}' => $limitAsString, '{{ suffix }}' => $suffix, ]; } elseif (\UPLOAD_ERR_FORM_SIZE === $errorCode) { $messageTemplate = 'The file is too large.'; } else { $messageTemplate = 'The file could not be uploaded.'; } if (null !== $this->translator) { $message = $this->translator->trans($messageTemplate, $messageParameters, 'validators'); } else { $message = strtr($messageTemplate, $messageParameters); } return new FileUploadError($message, $messageTemplate, $messageParameters); } /** * Returns the maximum size of an uploaded file as configured in php.ini. * * This method should be kept in sync with Symfony\Component\HttpFoundation\File\UploadedFile::getMaxFilesize(). * * @return int|float The maximum size of an uploaded file in bytes (returns float if size > PHP_INT_MAX) */ private static function getMaxFilesize() { $iniMax = strtolower(\ini_get('upload_max_filesize')); if ('' === $iniMax) { return \PHP_INT_MAX; } $max = ltrim($iniMax, '+'); if (str_starts_with($max, '0x')) { $max = \intval($max, 16); } elseif (str_starts_with($max, '0')) { $max = \intval($max, 8); } else { $max = (int) $max; } switch (substr($iniMax, -1)) { case 't': $max *= 1024; // no break case 'g': $max *= 1024; // no break case 'm': $max *= 1024; // no break case 'k': $max *= 1024; } return $max; } /** * Converts the limit to the smallest possible number * (i.e. try "MB", then "kB", then "bytes"). * * This method should be kept in sync with Symfony\Component\Validator\Constraints\FileValidator::factorizeSizes(). * * @param int|float $limit */ private function factorizeSizes(int $size, $limit) { $coef = self::MIB_BYTES; $coefFactor = self::KIB_BYTES; $limitAsString = (string) ($limit / $coef); // Restrict the limit to 2 decimals (without rounding! we // need the precise value) while (self::moreDecimalsThan($limitAsString, 2)) { $coef /= $coefFactor; $limitAsString = (string) ($limit / $coef); } // Convert size to the same measure, but round to 2 decimals $sizeAsString = (string) round($size / $coef, 2); // If the size and limit produce the same string output // (due to rounding), reduce the coefficient while ($sizeAsString === $limitAsString) { $coef /= $coefFactor; $limitAsString = (string) ($limit / $coef); $sizeAsString = (string) round($size / $coef, 2); } return [$limitAsString, self::SUFFIXES[$coef]]; } /** * This method should be kept in sync with Symfony\Component\Validator\Constraints\FileValidator::moreDecimalsThan(). */ private static function moreDecimalsThan(string $double, int $numberOfDecimals): bool { return \strlen($double) > \strlen(round($double, $numberOfDecimals)); } } Extension/Core/Type/FormType.php 0000644 00000021704 15120211543 0012605 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataAccessor\CallbackAccessor; use Symfony\Component\Form\Extension\Core\DataAccessor\ChainAccessor; use Symfony\Component\Form\Extension\Core\DataAccessor\PropertyPathAccessor; use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper; use Symfony\Component\Form\Extension\Core\EventListener\TrimListener; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormConfigBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\Translation\TranslatableMessage; class FormType extends BaseType { private $dataMapper; public function __construct(PropertyAccessorInterface $propertyAccessor = null) { $this->dataMapper = new DataMapper(new ChainAccessor([ new CallbackAccessor(), new PropertyPathAccessor($propertyAccessor ?? PropertyAccess::createPropertyAccessor()), ])); } /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { parent::buildForm($builder, $options); $isDataOptionSet = \array_key_exists('data', $options); $builder ->setRequired($options['required']) ->setErrorBubbling($options['error_bubbling']) ->setEmptyData($options['empty_data']) ->setPropertyPath($options['property_path']) ->setMapped($options['mapped']) ->setByReference($options['by_reference']) ->setInheritData($options['inherit_data']) ->setCompound($options['compound']) ->setData($isDataOptionSet ? $options['data'] : null) ->setDataLocked($isDataOptionSet) ->setDataMapper($options['compound'] ? $this->dataMapper : null) ->setMethod($options['method']) ->setAction($options['action']); if ($options['trim']) { $builder->addEventSubscriber(new TrimListener()); } if (!method_exists($builder, 'setIsEmptyCallback')) { trigger_deprecation('symfony/form', '5.1', 'Not implementing the "%s::setIsEmptyCallback()" method in "%s" is deprecated.', FormConfigBuilderInterface::class, get_debug_type($builder)); return; } $builder->setIsEmptyCallback($options['is_empty_callback']); } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { parent::buildView($view, $form, $options); $name = $form->getName(); $helpTranslationParameters = $options['help_translation_parameters']; if ($view->parent) { if ('' === $name) { throw new LogicException('Form node with empty name can be used only as root form node.'); } // Complex fields are read-only if they themselves or their parents are. if (!isset($view->vars['attr']['readonly']) && isset($view->parent->vars['attr']['readonly']) && false !== $view->parent->vars['attr']['readonly']) { $view->vars['attr']['readonly'] = true; } $helpTranslationParameters = array_merge($view->parent->vars['help_translation_parameters'], $helpTranslationParameters); } $formConfig = $form->getConfig(); $view->vars = array_replace($view->vars, [ 'errors' => $form->getErrors(), 'valid' => $form->isSubmitted() ? $form->isValid() : true, 'value' => $form->getViewData(), 'data' => $form->getNormData(), 'required' => $form->isRequired(), 'size' => null, 'label_attr' => $options['label_attr'], 'help' => $options['help'], 'help_attr' => $options['help_attr'], 'help_html' => $options['help_html'], 'help_translation_parameters' => $helpTranslationParameters, 'compound' => $formConfig->getCompound(), 'method' => $formConfig->getMethod(), 'action' => $formConfig->getAction(), 'submitted' => $form->isSubmitted(), ]); } /** * {@inheritdoc} */ public function finishView(FormView $view, FormInterface $form, array $options) { $multipart = false; foreach ($view->children as $child) { if ($child->vars['multipart']) { $multipart = true; break; } } $view->vars['multipart'] = $multipart; } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { parent::configureOptions($resolver); // Derive "data_class" option from passed "data" object $dataClass = function (Options $options) { return isset($options['data']) && \is_object($options['data']) ? \get_class($options['data']) : null; }; // Derive "empty_data" closure from "data_class" option $emptyData = function (Options $options) { $class = $options['data_class']; if (null !== $class) { return function (FormInterface $form) use ($class) { return $form->isEmpty() && !$form->isRequired() ? null : new $class(); }; } return function (FormInterface $form) { return $form->getConfig()->getCompound() ? [] : ''; }; }; // Wrap "post_max_size_message" in a closure to translate it lazily $uploadMaxSizeMessage = function (Options $options) { return function () use ($options) { return $options['post_max_size_message']; }; }; // For any form that is not represented by a single HTML control, // errors should bubble up by default $errorBubbling = function (Options $options) { return $options['compound'] && !$options['inherit_data']; }; // If data is given, the form is locked to that data // (independent of its value) $resolver->setDefined([ 'data', ]); $resolver->setDefaults([ 'data_class' => $dataClass, 'empty_data' => $emptyData, 'trim' => true, 'required' => true, 'property_path' => null, 'mapped' => true, 'by_reference' => true, 'error_bubbling' => $errorBubbling, 'label_attr' => [], 'inherit_data' => false, 'compound' => true, 'method' => 'POST', // According to RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt) // section 4.2., empty URIs are considered same-document references 'action' => '', 'attr' => [], 'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.', 'upload_max_size_message' => $uploadMaxSizeMessage, // internal 'allow_file_upload' => false, 'help' => null, 'help_attr' => [], 'help_html' => false, 'help_translation_parameters' => [], 'invalid_message' => 'This value is not valid.', 'invalid_message_parameters' => [], 'is_empty_callback' => null, 'getter' => null, 'setter' => null, ]); $resolver->setAllowedTypes('label_attr', 'array'); $resolver->setAllowedTypes('action', 'string'); $resolver->setAllowedTypes('upload_max_size_message', ['callable']); $resolver->setAllowedTypes('help', ['string', 'null', TranslatableMessage::class]); $resolver->setAllowedTypes('help_attr', 'array'); $resolver->setAllowedTypes('help_html', 'bool'); $resolver->setAllowedTypes('is_empty_callback', ['null', 'callable']); $resolver->setAllowedTypes('getter', ['null', 'callable']); $resolver->setAllowedTypes('setter', ['null', 'callable']); $resolver->setInfo('getter', 'A callable that accepts two arguments (the view data and the current form field) and must return a value.'); $resolver->setInfo('setter', 'A callable that accepts three arguments (a reference to the view data, the submitted value and the current form field).'); } /** * {@inheritdoc} */ public function getParent() { return null; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'form'; } } Extension/Core/Type/HiddenType.php 0000644 00000002270 15120211543 0013072 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class HiddenType extends AbstractType { /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ // hidden fields cannot have a required attribute 'required' => false, // Pass errors to the parent 'error_bubbling' => true, 'compound' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'The hidden field is invalid.'; }, ]); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'hidden'; } } Extension/Core/Type/IntegerType.php 0000644 00000004423 15120211543 0013276 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\DataTransformer\IntegerToLocalizedStringTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class IntegerType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder->addViewTransformer(new IntegerToLocalizedStringTransformer($options['grouping'], $options['rounding_mode'], !$options['grouping'] ? 'en' : null)); } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { if ($options['grouping']) { $view->vars['type'] = 'text'; } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'grouping' => false, // Integer cast rounds towards 0, so do the same when displaying fractions 'rounding_mode' => \NumberFormatter::ROUND_DOWN, 'compound' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter an integer.'; }, ]); $resolver->setAllowedValues('rounding_mode', [ \NumberFormatter::ROUND_FLOOR, \NumberFormatter::ROUND_DOWN, \NumberFormatter::ROUND_HALFDOWN, \NumberFormatter::ROUND_HALFEVEN, \NumberFormatter::ROUND_HALFUP, \NumberFormatter::ROUND_UP, \NumberFormatter::ROUND_CEILING, ]); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'integer'; } } Extension/Core/Type/LanguageType.php 0000644 00000007473 15120211543 0013434 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\ChoiceList\ChoiceList; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Intl\Exception\MissingResourceException; use Symfony\Component\Intl\Intl; use Symfony\Component\Intl\Languages; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class LanguageType extends AbstractType { /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'choice_loader' => function (Options $options) { if (!class_exists(Intl::class)) { throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s". Try running "composer require symfony/intl".', static::class)); } $choiceTranslationLocale = $options['choice_translation_locale']; $useAlpha3Codes = $options['alpha3']; $choiceSelfTranslation = $options['choice_self_translation']; return ChoiceList::loader($this, new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale, $useAlpha3Codes, $choiceSelfTranslation) { if (true === $choiceSelfTranslation) { foreach (Languages::getLanguageCodes() as $alpha2Code) { try { $languageCode = $useAlpha3Codes ? Languages::getAlpha3Code($alpha2Code) : $alpha2Code; $languagesList[$languageCode] = Languages::getName($alpha2Code, $alpha2Code); } catch (MissingResourceException $e) { // ignore errors like "Couldn't read the indices for the locale 'meta'" } } } else { $languagesList = $useAlpha3Codes ? Languages::getAlpha3Names($choiceTranslationLocale) : Languages::getNames($choiceTranslationLocale); } return array_flip($languagesList); }), [$choiceTranslationLocale, $useAlpha3Codes, $choiceSelfTranslation]); }, 'choice_translation_domain' => false, 'choice_translation_locale' => null, 'alpha3' => false, 'choice_self_translation' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please select a valid language.'; }, ]); $resolver->setAllowedTypes('choice_self_translation', ['bool']); $resolver->setAllowedTypes('choice_translation_locale', ['null', 'string']); $resolver->setAllowedTypes('alpha3', 'bool'); $resolver->setNormalizer('choice_self_translation', function (Options $options, $value) { if (true === $value && $options['choice_translation_locale']) { throw new LogicException('Cannot use the "choice_self_translation" and "choice_translation_locale" options at the same time. Remove one of them.'); } return $value; }); } /** * {@inheritdoc} */ public function getParent() { return ChoiceType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'language'; } } Extension/Core/Type/LocaleType.php 0000644 00000004230 15120211543 0013074 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\ChoiceList\ChoiceList; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Intl\Intl; use Symfony\Component\Intl\Locales; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class LocaleType extends AbstractType { /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'choice_loader' => function (Options $options) { if (!class_exists(Intl::class)) { throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s". Try running "composer require symfony/intl".', static::class)); } $choiceTranslationLocale = $options['choice_translation_locale']; return ChoiceList::loader($this, new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { return array_flip(Locales::getNames($choiceTranslationLocale)); }), $choiceTranslationLocale); }, 'choice_translation_domain' => false, 'choice_translation_locale' => null, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please select a valid locale.'; }, ]); $resolver->setAllowedTypes('choice_translation_locale', ['null', 'string']); } /** * {@inheritdoc} */ public function getParent() { return ChoiceType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'locale'; } } Extension/Core/Type/MoneyType.php 0000644 00000011267 15120211543 0012774 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\MoneyToLocalizedStringTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class MoneyType extends AbstractType { protected static $patterns = []; /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { // Values used in HTML5 number inputs should be formatted as in "1234.5", ie. 'en' format without grouping, // according to https://www.w3.org/TR/html51/sec-forms.html#date-time-and-number-formats $builder ->addViewTransformer(new MoneyToLocalizedStringTransformer( $options['scale'], $options['grouping'], $options['rounding_mode'], $options['divisor'], $options['html5'] ? 'en' : null )) ; } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars['money_pattern'] = self::getPattern($options['currency']); if ($options['html5']) { $view->vars['type'] = 'number'; } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'scale' => 2, 'grouping' => false, 'rounding_mode' => \NumberFormatter::ROUND_HALFUP, 'divisor' => 1, 'currency' => 'EUR', 'compound' => false, 'html5' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a valid money amount.'; }, ]); $resolver->setAllowedValues('rounding_mode', [ \NumberFormatter::ROUND_FLOOR, \NumberFormatter::ROUND_DOWN, \NumberFormatter::ROUND_HALFDOWN, \NumberFormatter::ROUND_HALFEVEN, \NumberFormatter::ROUND_HALFUP, \NumberFormatter::ROUND_UP, \NumberFormatter::ROUND_CEILING, ]); $resolver->setAllowedTypes('scale', 'int'); $resolver->setAllowedTypes('html5', 'bool'); $resolver->setNormalizer('grouping', function (Options $options, $value) { if ($value && $options['html5']) { throw new LogicException('Cannot use the "grouping" option when the "html5" option is enabled.'); } return $value; }); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'money'; } /** * Returns the pattern for this locale in UTF-8. * * The pattern contains the placeholder "{{ widget }}" where the HTML tag should * be inserted */ protected static function getPattern(?string $currency) { if (!$currency) { return '{{ widget }}'; } $locale = \Locale::getDefault(); if (!isset(self::$patterns[$locale])) { self::$patterns[$locale] = []; } if (!isset(self::$patterns[$locale][$currency])) { $format = new \NumberFormatter($locale, \NumberFormatter::CURRENCY); $pattern = $format->formatCurrency('123', $currency); // the spacings between currency symbol and number are ignored, because // a single space leads to better readability in combination with input // fields // the regex also considers non-break spaces (0xC2 or 0xA0 in UTF-8) preg_match('/^([^\s\xc2\xa0]*)[\s\xc2\xa0]*123(?:[,.]0+)?[\s\xc2\xa0]*([^\s\xc2\xa0]*)$/u', $pattern, $matches); if (!empty($matches[1])) { self::$patterns[$locale][$currency] = $matches[1].' {{ widget }}'; } elseif (!empty($matches[2])) { self::$patterns[$locale][$currency] = '{{ widget }} '.$matches[2]; } else { self::$patterns[$locale][$currency] = '{{ widget }}'; } } return self::$patterns[$locale][$currency]; } } Extension/Core/Type/NumberType.php 0000644 00000006443 15120211543 0013135 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\StringToFloatTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class NumberType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder->addViewTransformer(new NumberToLocalizedStringTransformer( $options['scale'], $options['grouping'], $options['rounding_mode'], $options['html5'] ? 'en' : null )); if ('string' === $options['input']) { $builder->addModelTransformer(new StringToFloatTransformer($options['scale'])); } } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { if ($options['html5']) { $view->vars['type'] = 'number'; if (!isset($view->vars['attr']['step'])) { $view->vars['attr']['step'] = 'any'; } } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ // default scale is locale specific (usually around 3) 'scale' => null, 'grouping' => false, 'rounding_mode' => \NumberFormatter::ROUND_HALFUP, 'compound' => false, 'input' => 'number', 'html5' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a number.'; }, ]); $resolver->setAllowedValues('rounding_mode', [ \NumberFormatter::ROUND_FLOOR, \NumberFormatter::ROUND_DOWN, \NumberFormatter::ROUND_HALFDOWN, \NumberFormatter::ROUND_HALFEVEN, \NumberFormatter::ROUND_HALFUP, \NumberFormatter::ROUND_UP, \NumberFormatter::ROUND_CEILING, ]); $resolver->setAllowedValues('input', ['number', 'string']); $resolver->setAllowedTypes('scale', ['null', 'int']); $resolver->setAllowedTypes('html5', 'bool'); $resolver->setNormalizer('grouping', function (Options $options, $value) { if (true === $value && $options['html5']) { throw new LogicException('Cannot use the "grouping" option when the "html5" option is enabled.'); } return $value; }); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'number'; } } Extension/Core/Type/PasswordType.php 0000644 00000002742 15120211543 0013505 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class PasswordType extends AbstractType { /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { if ($options['always_empty'] || !$form->isSubmitted()) { $view->vars['value'] = ''; } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'always_empty' => true, 'trim' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'The password is invalid.'; }, ]); } /** * {@inheritdoc} */ public function getParent() { return TextType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'password'; } } Extension/Core/Type/PercentType.php 0000644 00000006403 15120211543 0013301 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\DataTransformer\PercentToLocalizedStringTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class PercentType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder->addViewTransformer(new PercentToLocalizedStringTransformer( $options['scale'], $options['type'], $options['rounding_mode'], $options['html5'] )); } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars['symbol'] = $options['symbol']; if ($options['html5']) { $view->vars['type'] = 'number'; } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'scale' => 0, 'rounding_mode' => function (Options $options) { trigger_deprecation('symfony/form', '5.1', 'Not configuring the "rounding_mode" option is deprecated. It will default to "\NumberFormatter::ROUND_HALFUP" in Symfony 6.0.'); return null; }, 'symbol' => '%', 'type' => 'fractional', 'compound' => false, 'html5' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a percentage value.'; }, ]); $resolver->setAllowedValues('type', [ 'fractional', 'integer', ]); $resolver->setAllowedValues('rounding_mode', [ null, \NumberFormatter::ROUND_FLOOR, \NumberFormatter::ROUND_DOWN, \NumberFormatter::ROUND_HALFDOWN, \NumberFormatter::ROUND_HALFEVEN, \NumberFormatter::ROUND_HALFUP, \NumberFormatter::ROUND_UP, \NumberFormatter::ROUND_CEILING, ]); $resolver->setAllowedTypes('scale', 'int'); $resolver->setAllowedTypes('symbol', ['bool', 'string']); $resolver->setDeprecated('rounding_mode', 'symfony/form', '5.1', function (Options $options, $roundingMode) { if (null === $roundingMode) { return 'Not configuring the "rounding_mode" option is deprecated. It will default to "\NumberFormatter::ROUND_HALFUP" in Symfony 6.0.'; } return ''; }); $resolver->setAllowedTypes('html5', 'bool'); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'percent'; } } Extension/Core/Type/RadioType.php 0000644 00000002136 15120211543 0012736 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class RadioType extends AbstractType { /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please select a valid option.'; }, ]); } /** * {@inheritdoc} */ public function getParent() { return CheckboxType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'radio'; } } Extension/Core/Type/RangeType.php 0000644 00000002131 15120211543 0012727 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class RangeType extends AbstractType { /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please choose a valid range.'; }, ]); } /** * {@inheritdoc} */ public function getParent() { return TextType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'range'; } } Extension/Core/Type/RepeatedType.php 0000644 00000005067 15120211543 0013437 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\DataTransformer\ValueToDuplicatesTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class RepeatedType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { // Overwrite required option for child fields $options['first_options']['required'] = $options['required']; $options['second_options']['required'] = $options['required']; if (!isset($options['options']['error_bubbling'])) { $options['options']['error_bubbling'] = $options['error_bubbling']; } // children fields must always be mapped $defaultOptions = ['mapped' => true]; $builder ->addViewTransformer(new ValueToDuplicatesTransformer([ $options['first_name'], $options['second_name'], ])) ->add($options['first_name'], $options['type'], array_merge($options['options'], $options['first_options'], $defaultOptions)) ->add($options['second_name'], $options['type'], array_merge($options['options'], $options['second_options'], $defaultOptions)) ; } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'type' => TextType::class, 'options' => [], 'first_options' => [], 'second_options' => [], 'first_name' => 'first', 'second_name' => 'second', 'error_bubbling' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'The values do not match.'; }, ]); $resolver->setAllowedTypes('options', 'array'); $resolver->setAllowedTypes('first_options', 'array'); $resolver->setAllowedTypes('second_options', 'array'); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'repeated'; } } Extension/Core/Type/ResetType.php 0000644 00000001372 15120211543 0012763 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\ButtonTypeInterface; /** * A reset button. * * @author Bernhard Schussek <bschussek@gmail.com> */ class ResetType extends AbstractType implements ButtonTypeInterface { /** * {@inheritdoc} */ public function getParent() { return ButtonType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'reset'; } } Extension/Core/Type/SearchType.php 0000644 00000002140 15120211543 0013100 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class SearchType extends AbstractType { /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a valid search term.'; }, ]); } /** * {@inheritdoc} */ public function getParent() { return TextType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'search'; } } Extension/Core/Type/SubmitType.php 0000644 00000002551 15120211543 0013144 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\Form\SubmitButtonTypeInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** * A submit button. * * @author Bernhard Schussek <bschussek@gmail.com> */ class SubmitType extends AbstractType implements SubmitButtonTypeInterface { public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars['clicked'] = $form->isClicked(); if (!$options['validate']) { $view->vars['attr']['formnovalidate'] = true; } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefault('validate', true); $resolver->setAllowedTypes('validate', 'bool'); } /** * {@inheritdoc} */ public function getParent() { return ButtonType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'submit'; } } Extension/Core/Type/TelType.php 0000644 00000002135 15120211543 0012423 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class TelType extends AbstractType { /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please provide a valid phone number.'; }, ]); } /** * {@inheritdoc} */ public function getParent() { return TextType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'tel'; } } Extension/Core/Type/TextType.php 0000644 00000003247 15120211543 0012630 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class TextType extends AbstractType implements DataTransformerInterface { public function buildForm(FormBuilderInterface $builder, array $options) { // When empty_data is explicitly set to an empty string, // a string should always be returned when NULL is submitted // This gives more control and thus helps preventing some issues // with PHP 7 which allows type hinting strings in functions // See https://github.com/symfony/symfony/issues/5906#issuecomment-203189375 if ('' === $options['empty_data']) { $builder->addViewTransformer($this); } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'compound' => false, ]); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'text'; } /** * {@inheritdoc} */ public function transform($data) { // Model data should not be transformed return $data; } /** * {@inheritdoc} */ public function reverseTransform($data) { return $data ?? ''; } } Extension/Core/Type/TextareaType.php 0000644 00000001610 15120211543 0013451 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; class TextareaType extends AbstractType { /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars['pattern'] = null; unset($view->vars['attr']['pattern']); } /** * {@inheritdoc} */ public function getParent() { return TextType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'textarea'; } } Extension/Core/Type/TimeType.php 0000644 00000037316 15120211543 0012606 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Exception\InvalidConfigurationException; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\Form\ReversedTransformer; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class TimeType extends AbstractType { private const WIDGETS = [ 'text' => TextType::class, 'choice' => ChoiceType::class, ]; /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $parts = ['hour']; $format = 'H'; if ($options['with_seconds'] && !$options['with_minutes']) { throw new InvalidConfigurationException('You cannot disable minutes if you have enabled seconds.'); } if (null !== $options['reference_date'] && $options['reference_date']->getTimezone()->getName() !== $options['model_timezone']) { throw new InvalidConfigurationException(sprintf('The configured "model_timezone" (%s) must match the timezone of the "reference_date" (%s).', $options['model_timezone'], $options['reference_date']->getTimezone()->getName())); } if ($options['with_minutes']) { $format .= ':i'; $parts[] = 'minute'; } if ($options['with_seconds']) { $format .= ':s'; $parts[] = 'second'; } if ('single_text' === $options['widget']) { $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $e) use ($options) { $data = $e->getData(); if ($data && preg_match('/^(?P<hours>\d{2}):(?P<minutes>\d{2})(?::(?P<seconds>\d{2})(?:\.\d+)?)?$/', $data, $matches)) { if ($options['with_seconds']) { // handle seconds ignored by user's browser when with_seconds enabled // https://codereview.chromium.org/450533009/ $e->setData(sprintf('%s:%s:%s', $matches['hours'], $matches['minutes'], $matches['seconds'] ?? '00')); } else { $e->setData(sprintf('%s:%s', $matches['hours'], $matches['minutes'])); } } }); $parseFormat = null; if (null !== $options['reference_date']) { $parseFormat = 'Y-m-d '.$format; $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($options) { $data = $event->getData(); if (preg_match('/^\d{2}:\d{2}(:\d{2})?$/', $data)) { $event->setData($options['reference_date']->format('Y-m-d ').$data); } }); } $builder->addViewTransformer(new DateTimeToStringTransformer($options['model_timezone'], $options['view_timezone'], $format, $parseFormat)); } else { $hourOptions = $minuteOptions = $secondOptions = [ 'error_bubbling' => true, 'empty_data' => '', ]; // when the form is compound the entries of the array are ignored in favor of children data // so we need to handle the cascade setting here $emptyData = $builder->getEmptyData() ?: []; if ($emptyData instanceof \Closure) { $lazyEmptyData = static function ($option) use ($emptyData) { return static function (FormInterface $form) use ($emptyData, $option) { $emptyData = $emptyData($form->getParent()); return $emptyData[$option] ?? ''; }; }; $hourOptions['empty_data'] = $lazyEmptyData('hour'); } elseif (isset($emptyData['hour'])) { $hourOptions['empty_data'] = $emptyData['hour']; } if (isset($options['invalid_message'])) { $hourOptions['invalid_message'] = $options['invalid_message']; $minuteOptions['invalid_message'] = $options['invalid_message']; $secondOptions['invalid_message'] = $options['invalid_message']; } if (isset($options['invalid_message_parameters'])) { $hourOptions['invalid_message_parameters'] = $options['invalid_message_parameters']; $minuteOptions['invalid_message_parameters'] = $options['invalid_message_parameters']; $secondOptions['invalid_message_parameters'] = $options['invalid_message_parameters']; } if ('choice' === $options['widget']) { $hours = $minutes = []; foreach ($options['hours'] as $hour) { $hours[str_pad($hour, 2, '0', \STR_PAD_LEFT)] = $hour; } // Only pass a subset of the options to children $hourOptions['choices'] = $hours; $hourOptions['placeholder'] = $options['placeholder']['hour']; $hourOptions['choice_translation_domain'] = $options['choice_translation_domain']['hour']; if ($options['with_minutes']) { foreach ($options['minutes'] as $minute) { $minutes[str_pad($minute, 2, '0', \STR_PAD_LEFT)] = $minute; } $minuteOptions['choices'] = $minutes; $minuteOptions['placeholder'] = $options['placeholder']['minute']; $minuteOptions['choice_translation_domain'] = $options['choice_translation_domain']['minute']; } if ($options['with_seconds']) { $seconds = []; foreach ($options['seconds'] as $second) { $seconds[str_pad($second, 2, '0', \STR_PAD_LEFT)] = $second; } $secondOptions['choices'] = $seconds; $secondOptions['placeholder'] = $options['placeholder']['second']; $secondOptions['choice_translation_domain'] = $options['choice_translation_domain']['second']; } // Append generic carry-along options foreach (['required', 'translation_domain'] as $passOpt) { $hourOptions[$passOpt] = $options[$passOpt]; if ($options['with_minutes']) { $minuteOptions[$passOpt] = $options[$passOpt]; } if ($options['with_seconds']) { $secondOptions[$passOpt] = $options[$passOpt]; } } } $builder->add('hour', self::WIDGETS[$options['widget']], $hourOptions); if ($options['with_minutes']) { if ($emptyData instanceof \Closure) { $minuteOptions['empty_data'] = $lazyEmptyData('minute'); } elseif (isset($emptyData['minute'])) { $minuteOptions['empty_data'] = $emptyData['minute']; } $builder->add('minute', self::WIDGETS[$options['widget']], $minuteOptions); } if ($options['with_seconds']) { if ($emptyData instanceof \Closure) { $secondOptions['empty_data'] = $lazyEmptyData('second'); } elseif (isset($emptyData['second'])) { $secondOptions['empty_data'] = $emptyData['second']; } $builder->add('second', self::WIDGETS[$options['widget']], $secondOptions); } $builder->addViewTransformer(new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts, 'text' === $options['widget'], $options['reference_date'])); } if ('datetime_immutable' === $options['input']) { $builder->addModelTransformer(new DateTimeImmutableToDateTimeTransformer()); } elseif ('string' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], $options['input_format']) )); } elseif ('timestamp' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone']) )); } elseif ('array' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], $parts, 'text' === $options['widget'], $options['reference_date']) )); } } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars = array_replace($view->vars, [ 'widget' => $options['widget'], 'with_minutes' => $options['with_minutes'], 'with_seconds' => $options['with_seconds'], ]); // Change the input to an HTML5 time input if // * the widget is set to "single_text" // * the html5 is set to true if ($options['html5'] && 'single_text' === $options['widget']) { $view->vars['type'] = 'time'; // we need to force the browser to display the seconds by // adding the HTML attribute step if not already defined. // Otherwise the browser will not display and so not send the seconds // therefore the value will always be considered as invalid. if ($options['with_seconds'] && !isset($view->vars['attr']['step'])) { $view->vars['attr']['step'] = 1; } } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $compound = function (Options $options) { return 'single_text' !== $options['widget']; }; $placeholderDefault = function (Options $options) { return $options['required'] ? null : ''; }; $placeholderNormalizer = function (Options $options, $placeholder) use ($placeholderDefault) { if (\is_array($placeholder)) { $default = $placeholderDefault($options); return array_merge( ['hour' => $default, 'minute' => $default, 'second' => $default], $placeholder ); } return [ 'hour' => $placeholder, 'minute' => $placeholder, 'second' => $placeholder, ]; }; $choiceTranslationDomainNormalizer = function (Options $options, $choiceTranslationDomain) { if (\is_array($choiceTranslationDomain)) { $default = false; return array_replace( ['hour' => $default, 'minute' => $default, 'second' => $default], $choiceTranslationDomain ); } return [ 'hour' => $choiceTranslationDomain, 'minute' => $choiceTranslationDomain, 'second' => $choiceTranslationDomain, ]; }; $modelTimezone = static function (Options $options, $value): ?string { if (null !== $value) { return $value; } if (null !== $options['reference_date']) { return $options['reference_date']->getTimezone()->getName(); } return null; }; $viewTimezone = static function (Options $options, $value): ?string { if (null !== $value) { return $value; } if (null !== $options['model_timezone'] && null === $options['reference_date']) { return $options['model_timezone']; } return null; }; $resolver->setDefaults([ 'hours' => range(0, 23), 'minutes' => range(0, 59), 'seconds' => range(0, 59), 'widget' => 'choice', 'input' => 'datetime', 'input_format' => 'H:i:s', 'with_minutes' => true, 'with_seconds' => false, 'model_timezone' => $modelTimezone, 'view_timezone' => $viewTimezone, 'reference_date' => null, 'placeholder' => $placeholderDefault, 'html5' => true, // Don't modify \DateTime classes by reference, we treat // them like immutable value objects 'by_reference' => false, 'error_bubbling' => false, // If initialized with a \DateTime object, FormType initializes // this option to "\DateTime". Since the internal, normalized // representation is not \DateTime, but an array, we need to unset // this option. 'data_class' => null, 'empty_data' => function (Options $options) { return $options['compound'] ? [] : ''; }, 'compound' => $compound, 'choice_translation_domain' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a valid time.'; }, ]); $resolver->setNormalizer('view_timezone', function (Options $options, $viewTimezone): ?string { if (null !== $options['model_timezone'] && $viewTimezone !== $options['model_timezone'] && null === $options['reference_date']) { throw new LogicException('Using different values for the "model_timezone" and "view_timezone" options without configuring a reference date is not supported.'); } return $viewTimezone; }); $resolver->setNormalizer('placeholder', $placeholderNormalizer); $resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer); $resolver->setAllowedValues('input', [ 'datetime', 'datetime_immutable', 'string', 'timestamp', 'array', ]); $resolver->setAllowedValues('widget', [ 'single_text', 'text', 'choice', ]); $resolver->setAllowedTypes('hours', 'array'); $resolver->setAllowedTypes('minutes', 'array'); $resolver->setAllowedTypes('seconds', 'array'); $resolver->setAllowedTypes('input_format', 'string'); $resolver->setAllowedTypes('model_timezone', ['null', 'string']); $resolver->setAllowedTypes('view_timezone', ['null', 'string']); $resolver->setAllowedTypes('reference_date', ['null', \DateTimeInterface::class]); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'time'; } } Extension/Core/Type/TimezoneType.php 0000644 00000011770 15120211543 0013476 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\ChoiceList\ChoiceList; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeZoneToStringTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\IntlTimeZoneToStringTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Intl\Intl; use Symfony\Component\Intl\Timezones; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class TimezoneType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { if ('datetimezone' === $options['input']) { $builder->addModelTransformer(new DateTimeZoneToStringTransformer($options['multiple'])); } elseif ('intltimezone' === $options['input']) { $builder->addModelTransformer(new IntlTimeZoneToStringTransformer($options['multiple'])); } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'intl' => false, 'choice_loader' => function (Options $options) { $input = $options['input']; if ($options['intl']) { if (!class_exists(Intl::class)) { throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s" with option "intl=true". Try running "composer require symfony/intl".', static::class)); } $choiceTranslationLocale = $options['choice_translation_locale']; return ChoiceList::loader($this, new IntlCallbackChoiceLoader(function () use ($input, $choiceTranslationLocale) { return self::getIntlTimezones($input, $choiceTranslationLocale); }), [$input, $choiceTranslationLocale]); } return ChoiceList::lazy($this, function () use ($input) { return self::getPhpTimezones($input); }, $input); }, 'choice_translation_domain' => false, 'choice_translation_locale' => null, 'input' => 'string', 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please select a valid timezone.'; }, 'regions' => \DateTimeZone::ALL, ]); $resolver->setAllowedTypes('intl', ['bool']); $resolver->setAllowedTypes('choice_translation_locale', ['null', 'string']); $resolver->setNormalizer('choice_translation_locale', function (Options $options, $value) { if (null !== $value && !$options['intl']) { throw new LogicException('The "choice_translation_locale" option can only be used if the "intl" option is set to true.'); } return $value; }); $resolver->setAllowedValues('input', ['string', 'datetimezone', 'intltimezone']); $resolver->setNormalizer('input', function (Options $options, $value) { if ('intltimezone' === $value && !class_exists(\IntlTimeZone::class)) { throw new LogicException('Cannot use "intltimezone" input because the PHP intl extension is not available.'); } return $value; }); } /** * {@inheritdoc} */ public function getParent() { return ChoiceType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'timezone'; } private static function getPhpTimezones(string $input): array { $timezones = []; foreach (\DateTimeZone::listIdentifiers(\DateTimeZone::ALL) as $timezone) { if ('intltimezone' === $input && 'Etc/Unknown' === \IntlTimeZone::createTimeZone($timezone)->getID()) { continue; } $timezones[str_replace(['/', '_'], [' / ', ' '], $timezone)] = $timezone; } return $timezones; } private static function getIntlTimezones(string $input, string $locale = null): array { $timezones = array_flip(Timezones::getNames($locale)); if ('intltimezone' === $input) { foreach ($timezones as $name => $timezone) { if ('Etc/Unknown' === \IntlTimeZone::createTimeZone($timezone)->getID()) { unset($timezones[$name]); } } } return $timezones; } } Extension/Core/Type/TransformationFailureExtension.php 0000644 00000002277 15120211543 0017257 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\Extension\Core\EventListener\TransformationFailureListener; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Contracts\Translation\TranslatorInterface; /** * @author Christian Flothmann <christian.flothmann@sensiolabs.de> */ class TransformationFailureExtension extends AbstractTypeExtension { private $translator; public function __construct(TranslatorInterface $translator = null) { $this->translator = $translator; } public function buildForm(FormBuilderInterface $builder, array $options) { if (!isset($options['constraints'])) { $builder->addEventSubscriber(new TransformationFailureListener($this->translator)); } } /** * {@inheritdoc} */ public static function getExtendedTypes(): iterable { return [FormType::class]; } } Extension/Core/Type/UlidType.php 0000644 00000002450 15120211543 0012574 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\DataTransformer\UlidToStringTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; /** * @author Pavel Dyakonov <wapinet@mail.ru> */ class UlidType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->addViewTransformer(new UlidToStringTransformer()) ; } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'compound' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a valid ULID.'; }, ]); } } Extension/Core/Type/UrlType.php 0000644 00000003726 15120211543 0012450 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\EventListener\FixUrlProtocolListener; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class UrlType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { if (null !== $options['default_protocol']) { $builder->addEventSubscriber(new FixUrlProtocolListener($options['default_protocol'])); } } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { if ($options['default_protocol']) { $view->vars['attr']['inputmode'] = 'url'; $view->vars['type'] = 'text'; } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'default_protocol' => 'http', 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a valid URL.'; }, ]); $resolver->setAllowedTypes('default_protocol', ['null', 'string']); } /** * {@inheritdoc} */ public function getParent() { return TextType::class; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'url'; } } Extension/Core/Type/UuidType.php 0000644 00000002450 15120211543 0012605 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\DataTransformer\UuidToStringTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; /** * @author Pavel Dyakonov <wapinet@mail.ru> */ class UuidType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->addViewTransformer(new UuidToStringTransformer()) ; } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'compound' => false, 'invalid_message' => function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a valid UUID.'; }, ]); } } Extension/Core/Type/WeekType.php 0000644 00000015546 15120211543 0012604 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\WeekToArrayTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\Form\ReversedTransformer; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class WeekType extends AbstractType { private const WIDGETS = [ 'text' => IntegerType::class, 'choice' => ChoiceType::class, ]; /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { if ('string' === $options['input']) { $builder->addModelTransformer(new WeekToArrayTransformer()); } if ('single_text' === $options['widget']) { $builder->addViewTransformer(new ReversedTransformer(new WeekToArrayTransformer())); } else { $yearOptions = $weekOptions = [ 'error_bubbling' => true, 'empty_data' => '', ]; // when the form is compound the entries of the array are ignored in favor of children data // so we need to handle the cascade setting here $emptyData = $builder->getEmptyData() ?: []; $yearOptions['empty_data'] = $emptyData['year'] ?? ''; $weekOptions['empty_data'] = $emptyData['week'] ?? ''; if (isset($options['invalid_message'])) { $yearOptions['invalid_message'] = $options['invalid_message']; $weekOptions['invalid_message'] = $options['invalid_message']; } if (isset($options['invalid_message_parameters'])) { $yearOptions['invalid_message_parameters'] = $options['invalid_message_parameters']; $weekOptions['invalid_message_parameters'] = $options['invalid_message_parameters']; } if ('choice' === $options['widget']) { // Only pass a subset of the options to children $yearOptions['choices'] = array_combine($options['years'], $options['years']); $yearOptions['placeholder'] = $options['placeholder']['year']; $yearOptions['choice_translation_domain'] = $options['choice_translation_domain']['year']; $weekOptions['choices'] = array_combine($options['weeks'], $options['weeks']); $weekOptions['placeholder'] = $options['placeholder']['week']; $weekOptions['choice_translation_domain'] = $options['choice_translation_domain']['week']; // Append generic carry-along options foreach (['required', 'translation_domain'] as $passOpt) { $yearOptions[$passOpt] = $options[$passOpt]; $weekOptions[$passOpt] = $options[$passOpt]; } } $builder->add('year', self::WIDGETS[$options['widget']], $yearOptions); $builder->add('week', self::WIDGETS[$options['widget']], $weekOptions); } } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars['widget'] = $options['widget']; if ($options['html5']) { $view->vars['type'] = 'week'; } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $compound = function (Options $options) { return 'single_text' !== $options['widget']; }; $placeholderDefault = function (Options $options) { return $options['required'] ? null : ''; }; $placeholderNormalizer = function (Options $options, $placeholder) use ($placeholderDefault) { if (\is_array($placeholder)) { $default = $placeholderDefault($options); return array_merge( ['year' => $default, 'week' => $default], $placeholder ); } return [ 'year' => $placeholder, 'week' => $placeholder, ]; }; $choiceTranslationDomainNormalizer = function (Options $options, $choiceTranslationDomain) { if (\is_array($choiceTranslationDomain)) { $default = false; return array_replace( ['year' => $default, 'week' => $default], $choiceTranslationDomain ); } return [ 'year' => $choiceTranslationDomain, 'week' => $choiceTranslationDomain, ]; }; $resolver->setDefaults([ 'years' => range(date('Y') - 10, date('Y') + 10), 'weeks' => array_combine(range(1, 53), range(1, 53)), 'widget' => 'single_text', 'input' => 'array', 'placeholder' => $placeholderDefault, 'html5' => static function (Options $options) { return 'single_text' === $options['widget']; }, 'error_bubbling' => false, 'empty_data' => function (Options $options) { return $options['compound'] ? [] : ''; }, 'compound' => $compound, 'choice_translation_domain' => false, 'invalid_message' => static function (Options $options, $previousValue) { return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a valid week.'; }, ]); $resolver->setNormalizer('placeholder', $placeholderNormalizer); $resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer); $resolver->setNormalizer('html5', function (Options $options, $html5) { if ($html5 && 'single_text' !== $options['widget']) { throw new LogicException(sprintf('The "widget" option of "%s" must be set to "single_text" when the "html5" option is enabled.', self::class)); } return $html5; }); $resolver->setAllowedValues('input', [ 'string', 'array', ]); $resolver->setAllowedValues('widget', [ 'single_text', 'text', 'choice', ]); $resolver->setAllowedTypes('years', 'int[]'); $resolver->setAllowedTypes('weeks', 'int[]'); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'week'; } } Extension/Core/CoreExtension.php 0000644 00000006212 15120211543 0012701 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Core; use Symfony\Component\Form\AbstractExtension; use Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator; use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface; use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator; use Symfony\Component\Form\Extension\Core\Type\TransformationFailureExtension; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Contracts\Translation\TranslatorInterface; /** * Represents the main form extension, which loads the core functionality. * * @author Bernhard Schussek <bschussek@gmail.com> */ class CoreExtension extends AbstractExtension { private $propertyAccessor; private $choiceListFactory; private $translator; public function __construct(PropertyAccessorInterface $propertyAccessor = null, ChoiceListFactoryInterface $choiceListFactory = null, TranslatorInterface $translator = null) { $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); $this->choiceListFactory = $choiceListFactory ?? new CachingFactoryDecorator(new PropertyAccessDecorator(new DefaultChoiceListFactory(), $this->propertyAccessor)); $this->translator = $translator; } protected function loadTypes() { return [ new Type\FormType($this->propertyAccessor), new Type\BirthdayType(), new Type\CheckboxType(), new Type\ChoiceType($this->choiceListFactory, $this->translator), new Type\CollectionType(), new Type\CountryType(), new Type\DateIntervalType(), new Type\DateType(), new Type\DateTimeType(), new Type\EmailType(), new Type\HiddenType(), new Type\IntegerType(), new Type\LanguageType(), new Type\LocaleType(), new Type\MoneyType(), new Type\NumberType(), new Type\PasswordType(), new Type\PercentType(), new Type\RadioType(), new Type\RangeType(), new Type\RepeatedType(), new Type\SearchType(), new Type\TextareaType(), new Type\TextType(), new Type\TimeType(), new Type\TimezoneType(), new Type\UrlType(), new Type\FileType($this->translator), new Type\ButtonType(), new Type\SubmitType(), new Type\ResetType(), new Type\CurrencyType(), new Type\TelType(), new Type\ColorType($this->translator), new Type\WeekType(), ]; } protected function loadTypeExtensions() { return [ new TransformationFailureExtension($this->translator), ]; } } Extension/Csrf/EventListener/CsrfValidationListener.php 0000644 00000005446 15120211544 0017337 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Csrf\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\Util\ServerParams; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Contracts\Translation\TranslatorInterface; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class CsrfValidationListener implements EventSubscriberInterface { private $fieldName; private $tokenManager; private $tokenId; private $errorMessage; private $translator; private $translationDomain; private $serverParams; public static function getSubscribedEvents() { return [ FormEvents::PRE_SUBMIT => 'preSubmit', ]; } public function __construct(string $fieldName, CsrfTokenManagerInterface $tokenManager, string $tokenId, string $errorMessage, TranslatorInterface $translator = null, string $translationDomain = null, ServerParams $serverParams = null) { $this->fieldName = $fieldName; $this->tokenManager = $tokenManager; $this->tokenId = $tokenId; $this->errorMessage = $errorMessage; $this->translator = $translator; $this->translationDomain = $translationDomain; $this->serverParams = $serverParams ?? new ServerParams(); } public function preSubmit(FormEvent $event) { $form = $event->getForm(); $postRequestSizeExceeded = 'POST' === $form->getConfig()->getMethod() && $this->serverParams->hasPostMaxSizeBeenExceeded(); if ($form->isRoot() && $form->getConfig()->getOption('compound') && !$postRequestSizeExceeded) { $data = $event->getData(); $csrfValue = \is_string($data[$this->fieldName] ?? null) ? $data[$this->fieldName] : null; $csrfToken = new CsrfToken($this->tokenId, $csrfValue); if (null === $csrfValue || !$this->tokenManager->isTokenValid($csrfToken)) { $errorMessage = $this->errorMessage; if (null !== $this->translator) { $errorMessage = $this->translator->trans($errorMessage, [], $this->translationDomain); } $form->addError(new FormError($errorMessage, $errorMessage, [], null, $csrfToken)); } if (\is_array($data)) { unset($data[$this->fieldName]); $event->setData($data); } } } } Extension/Csrf/Type/FormTypeCsrfExtension.php 0000644 00000007510 15120211544 0015325 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Csrf\Type; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\Form\Util\ServerParams; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Contracts\Translation\TranslatorInterface; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class FormTypeCsrfExtension extends AbstractTypeExtension { private $defaultTokenManager; private $defaultEnabled; private $defaultFieldName; private $translator; private $translationDomain; private $serverParams; public function __construct(CsrfTokenManagerInterface $defaultTokenManager, bool $defaultEnabled = true, string $defaultFieldName = '_token', TranslatorInterface $translator = null, string $translationDomain = null, ServerParams $serverParams = null) { $this->defaultTokenManager = $defaultTokenManager; $this->defaultEnabled = $defaultEnabled; $this->defaultFieldName = $defaultFieldName; $this->translator = $translator; $this->translationDomain = $translationDomain; $this->serverParams = $serverParams; } /** * Adds a CSRF field to the form when the CSRF protection is enabled. */ public function buildForm(FormBuilderInterface $builder, array $options) { if (!$options['csrf_protection']) { return; } $builder ->addEventSubscriber(new CsrfValidationListener( $options['csrf_field_name'], $options['csrf_token_manager'], $options['csrf_token_id'] ?: ($builder->getName() ?: \get_class($builder->getType()->getInnerType())), $options['csrf_message'], $this->translator, $this->translationDomain, $this->serverParams )) ; } /** * Adds a CSRF field to the root form view. */ public function finishView(FormView $view, FormInterface $form, array $options) { if ($options['csrf_protection'] && !$view->parent && $options['compound']) { $factory = $form->getConfig()->getFormFactory(); $tokenId = $options['csrf_token_id'] ?: ($form->getName() ?: \get_class($form->getConfig()->getType()->getInnerType())); $data = (string) $options['csrf_token_manager']->getToken($tokenId); $csrfForm = $factory->createNamed($options['csrf_field_name'], HiddenType::class, $data, [ 'block_prefix' => 'csrf_token', 'mapped' => false, ]); $view->children[$options['csrf_field_name']] = $csrfForm->createView($view); } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'csrf_protection' => $this->defaultEnabled, 'csrf_field_name' => $this->defaultFieldName, 'csrf_message' => 'The CSRF token is invalid. Please try to resubmit the form.', 'csrf_token_manager' => $this->defaultTokenManager, 'csrf_token_id' => null, ]); } /** * {@inheritdoc} */ public static function getExtendedTypes(): iterable { return [FormType::class]; } } Extension/Csrf/CsrfExtension.php 0000644 00000002346 15120211544 0012720 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Csrf; use Symfony\Component\Form\AbstractExtension; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Contracts\Translation\TranslatorInterface; /** * This extension protects forms by using a CSRF token. * * @author Bernhard Schussek <bschussek@gmail.com> */ class CsrfExtension extends AbstractExtension { private $tokenManager; private $translator; private $translationDomain; public function __construct(CsrfTokenManagerInterface $tokenManager, TranslatorInterface $translator = null, string $translationDomain = null) { $this->tokenManager = $tokenManager; $this->translator = $translator; $this->translationDomain = $translationDomain; } /** * {@inheritdoc} */ protected function loadTypeExtensions() { return [ new Type\FormTypeCsrfExtension($this->tokenManager, true, '_token', $this->translator, $this->translationDomain), ]; } } Extension/DataCollector/EventListener/DataCollectorListener.php 0000644 00000004451 15120211544 0020765 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\DataCollector\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; /** * Listener that invokes a data collector for the {@link FormEvents::POST_SET_DATA} * and {@link FormEvents::POST_SUBMIT} events. * * @author Bernhard Schussek <bschussek@gmail.com> */ class DataCollectorListener implements EventSubscriberInterface { private $dataCollector; public function __construct(FormDataCollectorInterface $dataCollector) { $this->dataCollector = $dataCollector; } /** * {@inheritdoc} */ public static function getSubscribedEvents() { return [ // High priority in order to be called as soon as possible FormEvents::POST_SET_DATA => ['postSetData', 255], // Low priority in order to be called as late as possible FormEvents::POST_SUBMIT => ['postSubmit', -255], ]; } /** * Listener for the {@link FormEvents::POST_SET_DATA} event. */ public function postSetData(FormEvent $event) { if ($event->getForm()->isRoot()) { // Collect basic information about each form $this->dataCollector->collectConfiguration($event->getForm()); // Collect the default data $this->dataCollector->collectDefaultData($event->getForm()); } } /** * Listener for the {@link FormEvents::POST_SUBMIT} event. */ public function postSubmit(FormEvent $event) { if ($event->getForm()->isRoot()) { // Collect the submitted data of each form $this->dataCollector->collectSubmittedData($event->getForm()); // Assemble a form tree // This is done again after the view is built, but we need it here as the view is not always created. $this->dataCollector->buildPreliminaryFormTree($event->getForm()); } } } Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php 0000644 00000007524 15120211544 0021225 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\DataCollector\Proxy; use Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\Form\ResolvedFormTypeInterface; /** * Proxy that invokes a data collector when creating a form and its view. * * @author Bernhard Schussek <bschussek@gmail.com> */ class ResolvedTypeDataCollectorProxy implements ResolvedFormTypeInterface { private $proxiedType; private $dataCollector; public function __construct(ResolvedFormTypeInterface $proxiedType, FormDataCollectorInterface $dataCollector) { $this->proxiedType = $proxiedType; $this->dataCollector = $dataCollector; } /** * {@inheritdoc} */ public function getBlockPrefix() { return $this->proxiedType->getBlockPrefix(); } /** * {@inheritdoc} */ public function getParent() { return $this->proxiedType->getParent(); } /** * {@inheritdoc} */ public function getInnerType() { return $this->proxiedType->getInnerType(); } /** * {@inheritdoc} */ public function getTypeExtensions() { return $this->proxiedType->getTypeExtensions(); } /** * {@inheritdoc} */ public function createBuilder(FormFactoryInterface $factory, string $name, array $options = []) { $builder = $this->proxiedType->createBuilder($factory, $name, $options); $builder->setAttribute('data_collector/passed_options', $options); $builder->setType($this); return $builder; } /** * {@inheritdoc} */ public function createView(FormInterface $form, FormView $parent = null) { return $this->proxiedType->createView($form, $parent); } /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $this->proxiedType->buildForm($builder, $options); } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { $this->proxiedType->buildView($view, $form, $options); } /** * {@inheritdoc} */ public function finishView(FormView $view, FormInterface $form, array $options) { $this->proxiedType->finishView($view, $form, $options); // Remember which view belongs to which form instance, so that we can // get the collected data for a view when its form instance is not // available (e.g. CSRF token) $this->dataCollector->associateFormWithView($form, $view); // Since the CSRF token is only present in the FormView tree, we also // need to check the FormView tree instead of calling isRoot() on the // FormInterface tree if (null === $view->parent) { $this->dataCollector->collectViewVariables($view); // Re-assemble data, in case FormView instances were added, for // which no FormInterface instances were present (e.g. CSRF token). // Since finishView() is called after finishing the views of all // children, we can safely assume that information has been // collected about the complete form tree. $this->dataCollector->buildFinalFormTree($form, $view); } } /** * {@inheritdoc} */ public function getOptionsResolver() { return $this->proxiedType->getOptionsResolver(); } } Extension/DataCollector/Proxy/ResolvedTypeFactoryDataCollectorProxy.php 0000644 00000002644 15120211544 0022553 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\DataCollector\Proxy; use Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface; use Symfony\Component\Form\FormTypeInterface; use Symfony\Component\Form\ResolvedFormTypeFactoryInterface; use Symfony\Component\Form\ResolvedFormTypeInterface; /** * Proxy that wraps resolved types into {@link ResolvedTypeDataCollectorProxy} * instances. * * @author Bernhard Schussek <bschussek@gmail.com> */ class ResolvedTypeFactoryDataCollectorProxy implements ResolvedFormTypeFactoryInterface { private $proxiedFactory; private $dataCollector; public function __construct(ResolvedFormTypeFactoryInterface $proxiedFactory, FormDataCollectorInterface $dataCollector) { $this->proxiedFactory = $proxiedFactory; $this->dataCollector = $dataCollector; } /** * {@inheritdoc} */ public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null) { return new ResolvedTypeDataCollectorProxy( $this->proxiedFactory->createResolvedType($type, $typeExtensions, $parent), $this->dataCollector ); } } Extension/DataCollector/Type/DataCollectorTypeExtension.php 0000644 00000002626 15120211544 0020152 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\DataCollector\Type; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\DataCollector\EventListener\DataCollectorListener; use Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface; use Symfony\Component\Form\FormBuilderInterface; /** * Type extension for collecting data of a form with this type. * * @author Robert Schönthal <robert.schoenthal@gmail.com> * @author Bernhard Schussek <bschussek@gmail.com> */ class DataCollectorTypeExtension extends AbstractTypeExtension { /** * @var DataCollectorListener */ private $listener; public function __construct(FormDataCollectorInterface $dataCollector) { $this->listener = new DataCollectorListener($dataCollector); } /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder->addEventSubscriber($this->listener); } /** * {@inheritdoc} */ public static function getExtendedTypes(): iterable { return [FormType::class]; } } Extension/DataCollector/DataCollectorExtension.php 0000644 00000001651 15120211544 0016364 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\DataCollector; use Symfony\Component\Form\AbstractExtension; /** * Extension for collecting data of the forms on a page. * * @author Robert Schönthal <robert.schoenthal@gmail.com> * @author Bernhard Schussek <bschussek@gmail.com> */ class DataCollectorExtension extends AbstractExtension { private $dataCollector; public function __construct(FormDataCollectorInterface $dataCollector) { $this->dataCollector = $dataCollector; } /** * {@inheritdoc} */ protected function loadTypeExtensions() { return [ new Type\DataCollectorTypeExtension($this->dataCollector), ]; } } Extension/DataCollector/FormDataCollector.php 0000644 00000023754 15120211544 0015323 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\DataCollector; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\DataCollector; use Symfony\Component\Validator\ConstraintViolationInterface; use Symfony\Component\VarDumper\Caster\Caster; use Symfony\Component\VarDumper\Caster\ClassStub; use Symfony\Component\VarDumper\Caster\StubCaster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Data collector for {@link FormInterface} instances. * * @author Robert Schönthal <robert.schoenthal@gmail.com> * @author Bernhard Schussek <bschussek@gmail.com> * * @final */ class FormDataCollector extends DataCollector implements FormDataCollectorInterface { private $dataExtractor; /** * Stores the collected data per {@link FormInterface} instance. * * Uses the hashes of the forms as keys. This is preferable over using * {@link \SplObjectStorage}, because in this way no references are kept * to the {@link FormInterface} instances. * * @var array */ private $dataByForm; /** * Stores the collected data per {@link FormView} instance. * * Uses the hashes of the views as keys. This is preferable over using * {@link \SplObjectStorage}, because in this way no references are kept * to the {@link FormView} instances. * * @var array */ private $dataByView; /** * Connects {@link FormView} with {@link FormInterface} instances. * * Uses the hashes of the views as keys and the hashes of the forms as * values. This is preferable over storing the objects directly, because * this way they can safely be discarded by the GC. * * @var array */ private $formsByView; public function __construct(FormDataExtractorInterface $dataExtractor) { if (!class_exists(ClassStub::class)) { throw new \LogicException(sprintf('The VarDumper component is needed for using the "%s" class. Install symfony/var-dumper version 3.4 or above.', __CLASS__)); } $this->dataExtractor = $dataExtractor; $this->reset(); } /** * Does nothing. The data is collected during the form event listeners. */ public function collect(Request $request, Response $response, \Throwable $exception = null) { } public function reset() { $this->data = [ 'forms' => [], 'forms_by_hash' => [], 'nb_errors' => 0, ]; } /** * {@inheritdoc} */ public function associateFormWithView(FormInterface $form, FormView $view) { $this->formsByView[spl_object_hash($view)] = spl_object_hash($form); } /** * {@inheritdoc} */ public function collectConfiguration(FormInterface $form) { $hash = spl_object_hash($form); if (!isset($this->dataByForm[$hash])) { $this->dataByForm[$hash] = []; } $this->dataByForm[$hash] = array_replace( $this->dataByForm[$hash], $this->dataExtractor->extractConfiguration($form) ); foreach ($form as $child) { $this->collectConfiguration($child); } } /** * {@inheritdoc} */ public function collectDefaultData(FormInterface $form) { $hash = spl_object_hash($form); if (!isset($this->dataByForm[$hash])) { // field was created by form event $this->collectConfiguration($form); } $this->dataByForm[$hash] = array_replace( $this->dataByForm[$hash], $this->dataExtractor->extractDefaultData($form) ); foreach ($form as $child) { $this->collectDefaultData($child); } } /** * {@inheritdoc} */ public function collectSubmittedData(FormInterface $form) { $hash = spl_object_hash($form); if (!isset($this->dataByForm[$hash])) { // field was created by form event $this->collectConfiguration($form); $this->collectDefaultData($form); } $this->dataByForm[$hash] = array_replace( $this->dataByForm[$hash], $this->dataExtractor->extractSubmittedData($form) ); // Count errors if (isset($this->dataByForm[$hash]['errors'])) { $this->data['nb_errors'] += \count($this->dataByForm[$hash]['errors']); } foreach ($form as $child) { $this->collectSubmittedData($child); // Expand current form if there are children with errors if (empty($this->dataByForm[$hash]['has_children_error'])) { $childData = $this->dataByForm[spl_object_hash($child)]; $this->dataByForm[$hash]['has_children_error'] = !empty($childData['has_children_error']) || !empty($childData['errors']); } } } /** * {@inheritdoc} */ public function collectViewVariables(FormView $view) { $hash = spl_object_hash($view); if (!isset($this->dataByView[$hash])) { $this->dataByView[$hash] = []; } $this->dataByView[$hash] = array_replace( $this->dataByView[$hash], $this->dataExtractor->extractViewVariables($view) ); foreach ($view->children as $child) { $this->collectViewVariables($child); } } /** * {@inheritdoc} */ public function buildPreliminaryFormTree(FormInterface $form) { $this->data['forms'][$form->getName()] = &$this->recursiveBuildPreliminaryFormTree($form, $this->data['forms_by_hash']); } /** * {@inheritdoc} */ public function buildFinalFormTree(FormInterface $form, FormView $view) { $this->data['forms'][$form->getName()] = &$this->recursiveBuildFinalFormTree($form, $view, $this->data['forms_by_hash']); } /** * {@inheritdoc} */ public function getName(): string { return 'form'; } /** * {@inheritdoc} */ public function getData() { return $this->data; } /** * @internal */ public function __sleep(): array { foreach ($this->data['forms_by_hash'] as &$form) { if (isset($form['type_class']) && !$form['type_class'] instanceof ClassStub) { $form['type_class'] = new ClassStub($form['type_class']); } } $this->data = $this->cloneVar($this->data); return parent::__sleep(); } /** * {@inheritdoc} */ protected function getCasters(): array { return parent::getCasters() + [ \Exception::class => function (\Exception $e, array $a, Stub $s) { foreach (["\0Exception\0previous", "\0Exception\0trace"] as $k) { if (isset($a[$k])) { unset($a[$k]); ++$s->cut; } } return $a; }, FormInterface::class => function (FormInterface $f, array $a) { return [ Caster::PREFIX_VIRTUAL.'name' => $f->getName(), Caster::PREFIX_VIRTUAL.'type_class' => new ClassStub(\get_class($f->getConfig()->getType()->getInnerType())), ]; }, FormView::class => [StubCaster::class, 'cutInternals'], ConstraintViolationInterface::class => function (ConstraintViolationInterface $v, array $a) { return [ Caster::PREFIX_VIRTUAL.'root' => $v->getRoot(), Caster::PREFIX_VIRTUAL.'path' => $v->getPropertyPath(), Caster::PREFIX_VIRTUAL.'value' => $v->getInvalidValue(), ]; }, ]; } private function &recursiveBuildPreliminaryFormTree(FormInterface $form, array &$outputByHash) { $hash = spl_object_hash($form); $output = &$outputByHash[$hash]; $output = $this->dataByForm[$hash] ?? []; $output['children'] = []; foreach ($form as $name => $child) { $output['children'][$name] = &$this->recursiveBuildPreliminaryFormTree($child, $outputByHash); } return $output; } private function &recursiveBuildFinalFormTree(FormInterface $form = null, FormView $view, array &$outputByHash) { $viewHash = spl_object_hash($view); $formHash = null; if (null !== $form) { $formHash = spl_object_hash($form); } elseif (isset($this->formsByView[$viewHash])) { // The FormInterface instance of the CSRF token is never contained in // the FormInterface tree of the form, so we need to get the // corresponding FormInterface instance for its view in a different way $formHash = $this->formsByView[$viewHash]; } if (null !== $formHash) { $output = &$outputByHash[$formHash]; } $output = $this->dataByView[$viewHash] ?? []; if (null !== $formHash) { $output = array_replace( $output, $this->dataByForm[$formHash] ?? [] ); } $output['children'] = []; foreach ($view->children as $name => $childView) { // The CSRF token, for example, is never added to the form tree. // It is only present in the view. $childForm = null !== $form && $form->has($name) ? $form->get($name) : null; $output['children'][$name] = &$this->recursiveBuildFinalFormTree($childForm, $childView, $outputByHash); } return $output; } } Extension/DataCollector/FormDataCollectorInterface.php 0000644 00000005357 15120211544 0017143 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\DataCollector; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; use Symfony\Component\VarDumper\Cloner\Data; /** * Collects and structures information about forms. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface FormDataCollectorInterface extends DataCollectorInterface { /** * Stores configuration data of the given form and its children. */ public function collectConfiguration(FormInterface $form); /** * Stores the default data of the given form and its children. */ public function collectDefaultData(FormInterface $form); /** * Stores the submitted data of the given form and its children. */ public function collectSubmittedData(FormInterface $form); /** * Stores the view variables of the given form view and its children. */ public function collectViewVariables(FormView $view); /** * Specifies that the given objects represent the same conceptual form. */ public function associateFormWithView(FormInterface $form, FormView $view); /** * Assembles the data collected about the given form and its children as * a tree-like data structure. * * The result can be queried using {@link getData()}. */ public function buildPreliminaryFormTree(FormInterface $form); /** * Assembles the data collected about the given form and its children as * a tree-like data structure. * * The result can be queried using {@link getData()}. * * Contrary to {@link buildPreliminaryFormTree()}, a {@link FormView} * object has to be passed. The tree structure of this view object will be * used for structuring the resulting data. That means, if a child is * present in the view, but not in the form, it will be present in the final * data array anyway. * * When {@link FormView} instances are present in the view tree, for which * no corresponding {@link FormInterface} objects can be found in the form * tree, only the view data will be included in the result. If a * corresponding {@link FormInterface} exists otherwise, call * {@link associateFormWithView()} before calling this method. */ public function buildFinalFormTree(FormInterface $form, FormView $view); /** * Returns all collected data. * * @return array|Data */ public function getData(); } Extension/DataCollector/FormDataExtractor.php 0000644 00000010524 15120211544 0015337 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\DataCollector; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\Validator\ConstraintViolationInterface; /** * Default implementation of {@link FormDataExtractorInterface}. * * @author Bernhard Schussek <bschussek@gmail.com> */ class FormDataExtractor implements FormDataExtractorInterface { /** * {@inheritdoc} */ public function extractConfiguration(FormInterface $form) { $data = [ 'id' => $this->buildId($form), 'name' => $form->getName(), 'type_class' => \get_class($form->getConfig()->getType()->getInnerType()), 'synchronized' => $form->isSynchronized(), 'passed_options' => [], 'resolved_options' => [], ]; foreach ($form->getConfig()->getAttribute('data_collector/passed_options', []) as $option => $value) { $data['passed_options'][$option] = $value; } foreach ($form->getConfig()->getOptions() as $option => $value) { $data['resolved_options'][$option] = $value; } ksort($data['passed_options']); ksort($data['resolved_options']); return $data; } /** * {@inheritdoc} */ public function extractDefaultData(FormInterface $form) { $data = [ 'default_data' => [ 'norm' => $form->getNormData(), ], 'submitted_data' => [], ]; if ($form->getData() !== $form->getNormData()) { $data['default_data']['model'] = $form->getData(); } if ($form->getViewData() !== $form->getNormData()) { $data['default_data']['view'] = $form->getViewData(); } return $data; } /** * {@inheritdoc} */ public function extractSubmittedData(FormInterface $form) { $data = [ 'submitted_data' => [ 'norm' => $form->getNormData(), ], 'errors' => [], ]; if ($form->getViewData() !== $form->getNormData()) { $data['submitted_data']['view'] = $form->getViewData(); } if ($form->getData() !== $form->getNormData()) { $data['submitted_data']['model'] = $form->getData(); } foreach ($form->getErrors() as $error) { $errorData = [ 'message' => $error->getMessage(), 'origin' => \is_object($error->getOrigin()) ? spl_object_hash($error->getOrigin()) : null, 'trace' => [], ]; $cause = $error->getCause(); while (null !== $cause) { if ($cause instanceof ConstraintViolationInterface) { $errorData['trace'][] = $cause; $cause = method_exists($cause, 'getCause') ? $cause->getCause() : null; continue; } if ($cause instanceof \Exception) { $errorData['trace'][] = $cause; $cause = $cause->getPrevious(); continue; } $errorData['trace'][] = $cause; break; } $data['errors'][] = $errorData; } $data['synchronized'] = $form->isSynchronized(); return $data; } /** * {@inheritdoc} */ public function extractViewVariables(FormView $view) { $data = [ 'id' => $view->vars['id'] ?? null, 'name' => $view->vars['name'] ?? null, 'view_vars' => [], ]; foreach ($view->vars as $varName => $value) { $data['view_vars'][$varName] = $value; } ksort($data['view_vars']); return $data; } /** * Recursively builds an HTML ID for a form. */ private function buildId(FormInterface $form): string { $id = $form->getName(); if (null !== $form->getParent()) { $id = $this->buildId($form->getParent()).'_'.$id; } return $id; } } Extension/DataCollector/FormDataExtractorInterface.php 0000644 00000002162 15120211544 0017157 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\DataCollector; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; /** * Extracts arrays of information out of forms. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface FormDataExtractorInterface { /** * Extracts the configuration data of a form. * * @return array */ public function extractConfiguration(FormInterface $form); /** * Extracts the default data of a form. * * @return array */ public function extractDefaultData(FormInterface $form); /** * Extracts the submitted data of a form. * * @return array */ public function extractSubmittedData(FormInterface $form); /** * Extracts the view variables of a form. * * @return array */ public function extractViewVariables(FormView $view); } Extension/DependencyInjection/DependencyInjectionExtension.php 0000644 00000006202 15120211544 0020763 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\DependencyInjection; use Psr\Container\ContainerInterface; use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\FormExtensionInterface; use Symfony\Component\Form\FormTypeGuesserChain; class DependencyInjectionExtension implements FormExtensionInterface { private $guesser; private $guesserLoaded = false; private $typeContainer; private $typeExtensionServices; private $guesserServices; /** * @param iterable[] $typeExtensionServices */ public function __construct(ContainerInterface $typeContainer, array $typeExtensionServices, iterable $guesserServices) { $this->typeContainer = $typeContainer; $this->typeExtensionServices = $typeExtensionServices; $this->guesserServices = $guesserServices; } /** * {@inheritdoc} */ public function getType(string $name) { if (!$this->typeContainer->has($name)) { throw new InvalidArgumentException(sprintf('The field type "%s" is not registered in the service container.', $name)); } return $this->typeContainer->get($name); } /** * {@inheritdoc} */ public function hasType(string $name) { return $this->typeContainer->has($name); } /** * {@inheritdoc} */ public function getTypeExtensions(string $name) { $extensions = []; if (isset($this->typeExtensionServices[$name])) { foreach ($this->typeExtensionServices[$name] as $extension) { $extensions[] = $extension; $extendedTypes = []; foreach ($extension::getExtendedTypes() as $extendedType) { $extendedTypes[] = $extendedType; } // validate the result of getExtendedTypes() to ensure it is consistent with the service definition if (!\in_array($name, $extendedTypes, true)) { throw new InvalidArgumentException(sprintf('The extended type "%s" specified for the type extension class "%s" does not match any of the actual extended types (["%s"]).', $name, \get_class($extension), implode('", "', $extendedTypes))); } } } return $extensions; } /** * {@inheritdoc} */ public function hasTypeExtensions(string $name) { return isset($this->typeExtensionServices[$name]); } /** * {@inheritdoc} */ public function getTypeGuesser() { if (!$this->guesserLoaded) { $this->guesserLoaded = true; $guessers = []; foreach ($this->guesserServices as $serviceId => $service) { $guessers[] = $service; } if ($guessers) { $this->guesser = new FormTypeGuesserChain($guessers); } } return $this->guesser; } } Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php 0000644 00000002355 15120211544 0021451 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\HttpFoundation\Type; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\RequestHandlerInterface; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class FormTypeHttpFoundationExtension extends AbstractTypeExtension { private $requestHandler; public function __construct(RequestHandlerInterface $requestHandler = null) { $this->requestHandler = $requestHandler ?? new HttpFoundationRequestHandler(); } /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder->setRequestHandler($this->requestHandler); } /** * {@inheritdoc} */ public static function getExtendedTypes(): iterable { return [FormType::class]; } } Extension/HttpFoundation/HttpFoundationExtension.php 0000644 00000001241 15120211544 0017033 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\HttpFoundation; use Symfony\Component\Form\AbstractExtension; /** * Integrates the HttpFoundation component with the Form library. * * @author Bernhard Schussek <bschussek@gmail.com> */ class HttpFoundationExtension extends AbstractExtension { protected function loadTypeExtensions() { return [ new Type\FormTypeHttpFoundationExtension(), ]; } } Extension/HttpFoundation/HttpFoundationRequestHandler.php 0000644 00000010265 15120211544 0020013 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\HttpFoundation; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\RequestHandlerInterface; use Symfony\Component\Form\Util\ServerParams; use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\Request; /** * A request processor using the {@link Request} class of the HttpFoundation * component. * * @author Bernhard Schussek <bschussek@gmail.com> */ class HttpFoundationRequestHandler implements RequestHandlerInterface { private $serverParams; public function __construct(ServerParams $serverParams = null) { $this->serverParams = $serverParams ?? new ServerParams(); } /** * {@inheritdoc} */ public function handleRequest(FormInterface $form, $request = null) { if (!$request instanceof Request) { throw new UnexpectedTypeException($request, 'Symfony\Component\HttpFoundation\Request'); } $name = $form->getName(); $method = $form->getConfig()->getMethod(); if ($method !== $request->getMethod()) { return; } // For request methods that must not have a request body we fetch data // from the query string. Otherwise we look for data in the request body. if ('GET' === $method || 'HEAD' === $method || 'TRACE' === $method) { if ('' === $name) { $data = $request->query->all(); } else { // Don't submit GET requests if the form's name does not exist // in the request if (!$request->query->has($name)) { return; } $data = $request->query->all()[$name]; } } else { // Mark the form with an error if the uploaded size was too large // This is done here and not in FormValidator because $_POST is // empty when that error occurs. Hence the form is never submitted. if ($this->serverParams->hasPostMaxSizeBeenExceeded()) { // Submit the form, but don't clear the default values $form->submit(null, false); $form->addError(new FormError( $form->getConfig()->getOption('upload_max_size_message')(), null, ['{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()] )); return; } if ('' === $name) { $params = $request->request->all(); $files = $request->files->all(); } elseif ($request->request->has($name) || $request->files->has($name)) { $default = $form->getConfig()->getCompound() ? [] : null; $params = $request->request->all()[$name] ?? $default; $files = $request->files->get($name, $default); } else { // Don't submit the form if it is not present in the request return; } if (\is_array($params) && \is_array($files)) { $data = array_replace_recursive($params, $files); } else { $data = $params ?: $files; } } // Don't auto-submit the form unless at least one field is present. if ('' === $name && \count(array_intersect_key($data, $form->all())) <= 0) { return; } $form->submit($data, 'PATCH' !== $method); } /** * {@inheritdoc} */ public function isFileUpload($data) { return $data instanceof File; } /** * @return int|null */ public function getUploadFileError($data) { if (!$data instanceof UploadedFile || $data->isValid()) { return null; } return $data->getError(); } } Extension/Validator/Constraints/Form.php 0000644 00000001601 15120211544 0014361 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\Constraints; use Symfony\Component\Validator\Constraint; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class Form extends Constraint { public const NOT_SYNCHRONIZED_ERROR = '1dafa156-89e1-4736-b832-419c2e501fca'; public const NO_SUCH_FIELD_ERROR = '6e5212ed-a197-4339-99aa-5654798a4854'; protected static $errorNames = [ self::NOT_SYNCHRONIZED_ERROR => 'NOT_SYNCHRONIZED_ERROR', self::NO_SUCH_FIELD_ERROR => 'NO_SUCH_FIELD_ERROR', ]; /** * {@inheritdoc} */ public function getTargets() { return self::CLASS_CONSTRAINT; } } Extension/Validator/Constraints/FormValidator.php 0000644 00000025446 15120211544 0016244 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\Constraints; use Symfony\Component\Form\FormInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\Composite; use Symfony\Component\Validator\Constraints\GroupSequence; use Symfony\Component\Validator\Constraints\Valid; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class FormValidator extends ConstraintValidator { /** * @var \SplObjectStorage<FormInterface, array<int, string|string[]|GroupSequence>> */ private $resolvedGroups; /** * {@inheritdoc} */ public function validate($form, Constraint $formConstraint) { if (!$formConstraint instanceof Form) { throw new UnexpectedTypeException($formConstraint, Form::class); } if (!$form instanceof FormInterface) { return; } /* @var FormInterface $form */ $config = $form->getConfig(); $validator = $this->context->getValidator()->inContext($this->context); if ($form->isSubmitted() && $form->isSynchronized()) { // Validate the form data only if transformation succeeded $groups = $this->getValidationGroups($form); if (!$groups) { return; } $data = $form->getData(); // Validate the data against its own constraints $validateDataGraph = $form->isRoot() && (\is_object($data) || \is_array($data)) && (($groups && \is_array($groups)) || ($groups instanceof GroupSequence && $groups->groups)) ; // Validate the data against the constraints defined in the form /** @var Constraint[] $constraints */ $constraints = $config->getOption('constraints', []); $hasChildren = $form->count() > 0; if ($hasChildren && $form->isRoot()) { $this->resolvedGroups = new \SplObjectStorage(); } if ($groups instanceof GroupSequence) { // Validate the data, the form AND nested fields in sequence $violationsCount = $this->context->getViolations()->count(); foreach ($groups->groups as $group) { if ($validateDataGraph) { $validator->atPath('data')->validate($data, null, $group); } if ($groupedConstraints = self::getConstraintsInGroups($constraints, $group)) { $validator->atPath('data')->validate($data, $groupedConstraints, $group); } foreach ($form->all() as $field) { if ($field->isSubmitted()) { // remember to validate this field in one group only // otherwise resolving the groups would reuse the same // sequence recursively, thus some fields could fail // in different steps without breaking early enough $this->resolvedGroups[$field] = (array) $group; $fieldFormConstraint = new Form(); $fieldFormConstraint->groups = $group; $this->context->setNode($this->context->getValue(), $field, $this->context->getMetadata(), $this->context->getPropertyPath()); $validator->atPath(sprintf('children[%s]', $field->getName()))->validate($field, $fieldFormConstraint, $group); } } if ($violationsCount < $this->context->getViolations()->count()) { break; } } } else { if ($validateDataGraph) { $validator->atPath('data')->validate($data, null, $groups); } $groupedConstraints = []; foreach ($constraints as $constraint) { // For the "Valid" constraint, validate the data in all groups if ($constraint instanceof Valid) { if (\is_object($data) || \is_array($data)) { $validator->atPath('data')->validate($data, $constraint, $groups); } continue; } // Otherwise validate a constraint only once for the first // matching group foreach ($groups as $group) { if (\in_array($group, $constraint->groups)) { $groupedConstraints[$group][] = $constraint; // Prevent duplicate validation if (!$constraint instanceof Composite) { continue 2; } } } } foreach ($groupedConstraints as $group => $constraint) { $validator->atPath('data')->validate($data, $constraint, $group); } foreach ($form->all() as $field) { if ($field->isSubmitted()) { $this->resolvedGroups[$field] = $groups; $this->context->setNode($this->context->getValue(), $field, $this->context->getMetadata(), $this->context->getPropertyPath()); $validator->atPath(sprintf('children[%s]', $field->getName()))->validate($field, $formConstraint); } } } if ($hasChildren && $form->isRoot()) { // destroy storage to avoid memory leaks $this->resolvedGroups = new \SplObjectStorage(); } } elseif (!$form->isSynchronized()) { $childrenSynchronized = true; /** @var FormInterface $child */ foreach ($form as $child) { if (!$child->isSynchronized()) { $childrenSynchronized = false; $this->context->setNode($this->context->getValue(), $child, $this->context->getMetadata(), $this->context->getPropertyPath()); $validator->atPath(sprintf('children[%s]', $child->getName()))->validate($child, $formConstraint); } } // Mark the form with an error if it is not synchronized BUT all // of its children are synchronized. If any child is not // synchronized, an error is displayed there already and showing // a second error in its parent form is pointless, or worse, may // lead to duplicate errors if error bubbling is enabled on the // child. // See also https://github.com/symfony/symfony/issues/4359 if ($childrenSynchronized) { $clientDataAsString = \is_scalar($form->getViewData()) ? (string) $form->getViewData() : get_debug_type($form->getViewData()); $failure = $form->getTransformationFailure(); $this->context->setConstraint($formConstraint); $this->context->buildViolation($failure->getInvalidMessage() ?? $config->getOption('invalid_message')) ->setParameters(array_replace( ['{{ value }}' => $clientDataAsString], $config->getOption('invalid_message_parameters'), $failure->getInvalidMessageParameters() )) ->setInvalidValue($form->getViewData()) ->setCode(Form::NOT_SYNCHRONIZED_ERROR) ->setCause($failure) ->addViolation(); } } // Mark the form with an error if it contains extra fields if (!$config->getOption('allow_extra_fields') && \count($form->getExtraData()) > 0) { $this->context->setConstraint($formConstraint); $this->context->buildViolation($config->getOption('extra_fields_message', '')) ->setParameter('{{ extra_fields }}', '"'.implode('", "', array_keys($form->getExtraData())).'"') ->setPlural(\count($form->getExtraData())) ->setInvalidValue($form->getExtraData()) ->setCode(Form::NO_SUCH_FIELD_ERROR) ->addViolation(); } } /** * Returns the validation groups of the given form. * * @return string|GroupSequence|array<string|GroupSequence> */ private function getValidationGroups(FormInterface $form) { // Determine the clicked button of the complete form tree $clickedButton = null; if (method_exists($form, 'getClickedButton')) { $clickedButton = $form->getClickedButton(); } if (null !== $clickedButton) { $groups = $clickedButton->getConfig()->getOption('validation_groups'); if (null !== $groups) { return self::resolveValidationGroups($groups, $form); } } do { $groups = $form->getConfig()->getOption('validation_groups'); if (null !== $groups) { return self::resolveValidationGroups($groups, $form); } if (isset($this->resolvedGroups[$form])) { return $this->resolvedGroups[$form]; } $form = $form->getParent(); } while (null !== $form); return [Constraint::DEFAULT_GROUP]; } /** * Post-processes the validation groups option for a given form. * * @param string|GroupSequence|array<string|GroupSequence>|callable $groups The validation groups * * @return GroupSequence|array<string|GroupSequence> */ private static function resolveValidationGroups($groups, FormInterface $form) { if (!\is_string($groups) && \is_callable($groups)) { $groups = $groups($form); } if ($groups instanceof GroupSequence) { return $groups; } return (array) $groups; } private static function getConstraintsInGroups($constraints, $group) { $groups = (array) $group; return array_filter($constraints, static function (Constraint $constraint) use ($groups) { foreach ($groups as $group) { if (\in_array($group, $constraint->groups, true)) { return true; } } return false; }); } } Extension/Validator/EventListener/ValidationListener.php 0000644 00000003602 15120211544 0017541 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\Extension\Validator\Constraints\Form; use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapperInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\Validator\Validator\ValidatorInterface; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class ValidationListener implements EventSubscriberInterface { private $validator; private $violationMapper; /** * {@inheritdoc} */ public static function getSubscribedEvents() { return [FormEvents::POST_SUBMIT => 'validateForm']; } public function __construct(ValidatorInterface $validator, ViolationMapperInterface $violationMapper) { $this->validator = $validator; $this->violationMapper = $violationMapper; } public function validateForm(FormEvent $event) { $form = $event->getForm(); if ($form->isRoot()) { // Form groups are validated internally (FormValidator). Here we don't set groups as they are retrieved into the validator. foreach ($this->validator->validate($form) as $violation) { // Allow the "invalid" constraint to be put onto // non-synchronized forms $allowNonSynchronized = $violation->getConstraint() instanceof Form && Form::NOT_SYNCHRONIZED_ERROR === $violation->getCode(); $this->violationMapper->mapViolation($violation, $form, $allowNonSynchronized); } } } } Extension/Validator/Type/BaseValidatorExtension.php 0000644 00000003062 15120211544 0016510 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\Type; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Validator\Constraints\GroupSequence; /** * Encapsulates common logic of {@link FormTypeValidatorExtension} and * {@link SubmitTypeValidatorExtension}. * * @author Bernhard Schussek <bschussek@gmail.com> */ abstract class BaseValidatorExtension extends AbstractTypeExtension { /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { // Make sure that validation groups end up as null, closure or array $validationGroupsNormalizer = function (Options $options, $groups) { if (false === $groups) { return []; } if (empty($groups)) { return null; } if (\is_callable($groups)) { return $groups; } if ($groups instanceof GroupSequence) { return $groups; } return (array) $groups; }; $resolver->setDefaults([ 'validation_groups' => null, ]); $resolver->setNormalizer('validation_groups', $validationGroupsNormalizer); } } Extension/Validator/Type/FormTypeValidatorExtension.php 0000644 00000006227 15120211544 0017411 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\Type; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener; use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormRendererInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Contracts\Translation\TranslatorInterface; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class FormTypeValidatorExtension extends BaseValidatorExtension { private $validator; private $violationMapper; private $legacyErrorMessages; public function __construct(ValidatorInterface $validator, bool $legacyErrorMessages = true, FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null) { $this->validator = $validator; $this->violationMapper = new ViolationMapper($formRenderer, $translator); $this->legacyErrorMessages = $legacyErrorMessages; } /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder->addEventSubscriber(new ValidationListener($this->validator, $this->violationMapper)); } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { parent::configureOptions($resolver); // Constraint should always be converted to an array $constraintsNormalizer = function (Options $options, $constraints) { return \is_object($constraints) ? [$constraints] : (array) $constraints; }; $resolver->setDefaults([ 'error_mapping' => [], 'constraints' => [], 'invalid_message' => 'This value is not valid.', 'invalid_message_parameters' => [], 'legacy_error_messages' => $this->legacyErrorMessages, 'allow_extra_fields' => false, 'extra_fields_message' => 'This form should not contain extra fields.', ]); $resolver->setAllowedTypes('constraints', [Constraint::class, Constraint::class.'[]']); $resolver->setAllowedTypes('legacy_error_messages', 'bool'); $resolver->setDeprecated('legacy_error_messages', 'symfony/form', '5.2', function (Options $options, $value) { if (true === $value) { return 'Setting the "legacy_error_messages" option to "true" is deprecated. It will be disabled in Symfony 6.0.'; } return ''; }); $resolver->setNormalizer('constraints', $constraintsNormalizer); } /** * {@inheritdoc} */ public static function getExtendedTypes(): iterable { return [FormType::class]; } } Extension/Validator/Type/RepeatedTypeValidatorExtension.php 0000644 00000002175 15120211544 0020235 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\Type; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\Extension\Core\Type\RepeatedType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class RepeatedTypeValidatorExtension extends AbstractTypeExtension { /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { // Map errors to the first field $errorMapping = function (Options $options) { return ['.' => $options['first_name']]; }; $resolver->setDefaults([ 'error_mapping' => $errorMapping, ]); } /** * {@inheritdoc} */ public static function getExtendedTypes(): iterable { return [RepeatedType::class]; } } Extension/Validator/Type/SubmitTypeValidatorExtension.php 0000644 00000001164 15120211544 0017744 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\Type; use Symfony\Component\Form\Extension\Core\Type\SubmitType; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class SubmitTypeValidatorExtension extends BaseValidatorExtension { /** * {@inheritdoc} */ public static function getExtendedTypes(): iterable { return [SubmitType::class]; } } Extension/Validator/Type/UploadValidatorExtension.php 0000644 00000003220 15120211544 0017056 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\Type; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Contracts\Translation\TranslatorInterface; /** * @author Abdellatif Ait boudad <a.aitboudad@gmail.com> * @author David Badura <d.a.badura@gmail.com> */ class UploadValidatorExtension extends AbstractTypeExtension { private $translator; private $translationDomain; public function __construct(TranslatorInterface $translator, string $translationDomain = null) { $this->translator = $translator; $this->translationDomain = $translationDomain; } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $translator = $this->translator; $translationDomain = $this->translationDomain; $resolver->setNormalizer('upload_max_size_message', function (Options $options, $message) use ($translator, $translationDomain) { return function () use ($translator, $translationDomain, $message) { return $translator->trans($message(), [], $translationDomain); }; }); } /** * {@inheritdoc} */ public static function getExtendedTypes(): iterable { return [FormType::class]; } } Extension/Validator/Util/ServerParams.php 0000644 00000001260 15120211544 0014477 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\Util; use Symfony\Component\Form\Util\ServerParams as BaseServerParams; trigger_deprecation('symfony/form', '5.1', 'The "%s" class is deprecated. Use "%s" instead.', ServerParams::class, BaseServerParams::class); /** * @author Bernhard Schussek <bschussek@gmail.com> * * @deprecated since Symfony 5.1. Use {@see BaseServerParams} instead. */ class ServerParams extends BaseServerParams { } Extension/Validator/ViolationMapper/MappingRule.php 0000644 00000004414 15120211544 0016510 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\ViolationMapper; use Symfony\Component\Form\Exception\ErrorMappingException; use Symfony\Component\Form\FormInterface; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class MappingRule { private $origin; private $propertyPath; private $targetPath; public function __construct(FormInterface $origin, string $propertyPath, string $targetPath) { $this->origin = $origin; $this->propertyPath = $propertyPath; $this->targetPath = $targetPath; } /** * @return FormInterface */ public function getOrigin() { return $this->origin; } /** * Matches a property path against the rule path. * * If the rule matches, the form mapped by the rule is returned. * Otherwise this method returns false. * * @return FormInterface|null */ public function match(string $propertyPath) { return $propertyPath === $this->propertyPath ? $this->getTarget() : null; } /** * Matches a property path against a prefix of the rule path. * * @return bool */ public function isPrefix(string $propertyPath) { $length = \strlen($propertyPath); $prefix = substr($this->propertyPath, 0, $length); $next = $this->propertyPath[$length] ?? null; return $prefix === $propertyPath && ('[' === $next || '.' === $next); } /** * @return FormInterface * * @throws ErrorMappingException */ public function getTarget() { $childNames = explode('.', $this->targetPath); $target = $this->origin; foreach ($childNames as $childName) { if (!$target->has($childName)) { throw new ErrorMappingException(sprintf('The child "%s" of "%s" mapped by the rule "%s" in "%s" does not exist.', $childName, $target->getName(), $this->targetPath, $this->origin->getName())); } $target = $target->get($childName); } return $target; } } Extension/Validator/ViolationMapper/RelativePath.php 0000644 00000001443 15120211544 0016654 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\ViolationMapper; use Symfony\Component\Form\FormInterface; use Symfony\Component\PropertyAccess\PropertyPath; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class RelativePath extends PropertyPath { private $root; public function __construct(FormInterface $root, string $propertyPath) { parent::__construct($propertyPath); $this->root = $root; } /** * @return FormInterface */ public function getRoot() { return $this->root; } } Extension/Validator/ViolationMapper/ViolationMapper.php 0000644 00000031434 15120211544 0017400 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\ViolationMapper; use Symfony\Component\Form\FileUploadError; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormRendererInterface; use Symfony\Component\Form\Util\InheritDataAwareIterator; use Symfony\Component\PropertyAccess\PropertyPathBuilder; use Symfony\Component\PropertyAccess\PropertyPathIterator; use Symfony\Component\PropertyAccess\PropertyPathIteratorInterface; use Symfony\Component\Validator\Constraints\File; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Contracts\Translation\TranslatorInterface; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class ViolationMapper implements ViolationMapperInterface { private $formRenderer; private $translator; private $allowNonSynchronized = false; public function __construct(FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null) { $this->formRenderer = $formRenderer; $this->translator = $translator; } /** * {@inheritdoc} */ public function mapViolation(ConstraintViolation $violation, FormInterface $form, bool $allowNonSynchronized = false) { $this->allowNonSynchronized = $allowNonSynchronized; // The scope is the currently found most specific form that // an error should be mapped to. After setting the scope, the // mapper will try to continue to find more specific matches in // the children of scope. If it cannot, the error will be // mapped to this scope. $scope = null; $violationPath = null; $relativePath = null; $match = false; // Don't create a ViolationPath instance for empty property paths if ('' !== $violation->getPropertyPath()) { $violationPath = new ViolationPath($violation->getPropertyPath()); $relativePath = $this->reconstructPath($violationPath, $form); } // This case happens if the violation path is empty and thus // the violation should be mapped to the root form if (null === $violationPath) { $scope = $form; } // In general, mapping happens from the root form to the leaf forms // First, the rules of the root form are applied to determine // the subsequent descendant. The rules of this descendant are then // applied to find the next and so on, until we have found the // most specific form that matches the violation. // If any of the forms found in this process is not synchronized, // mapping is aborted. Non-synchronized forms could not reverse // transform the value entered by the user, thus any further violations // caused by the (invalid) reverse transformed value should be // ignored. if (null !== $relativePath) { // Set the scope to the root of the relative path // This root will usually be $form. If the path contains // an unmapped form though, the last unmapped form found // will be the root of the path. $scope = $relativePath->getRoot(); $it = new PropertyPathIterator($relativePath); while ($this->acceptsErrors($scope) && null !== ($child = $this->matchChild($scope, $it))) { $scope = $child; $it->next(); $match = true; } } // This case happens if an error happened in the data under a // form inheriting its parent data that does not match any of the // children of that form. if (null !== $violationPath && !$match) { // If we could not map the error to anything more specific // than the root element, map it to the innermost directly // mapped form of the violation path // e.g. "children[foo].children[bar].data.baz" // Here the innermost directly mapped child is "bar" $scope = $form; $it = new ViolationPathIterator($violationPath); // Note: acceptsErrors() will always return true for forms inheriting // their parent data, because these forms can never be non-synchronized // (they don't do any data transformation on their own) while ($this->acceptsErrors($scope) && $it->valid() && $it->mapsForm()) { if (!$scope->has($it->current())) { // Break if we find a reference to a non-existing child break; } $scope = $scope->get($it->current()); $it->next(); } } // Follow dot rules until we have the final target $mapping = $scope->getConfig()->getOption('error_mapping'); while ($this->acceptsErrors($scope) && isset($mapping['.'])) { $dotRule = new MappingRule($scope, '.', $mapping['.']); $scope = $dotRule->getTarget(); $mapping = $scope->getConfig()->getOption('error_mapping'); } // Only add the error if the form is synchronized if ($this->acceptsErrors($scope)) { if ($violation->getConstraint() instanceof File && (string) \UPLOAD_ERR_INI_SIZE === $violation->getCode()) { $errorsTarget = $scope; while (null !== $errorsTarget->getParent() && $errorsTarget->getConfig()->getErrorBubbling()) { $errorsTarget = $errorsTarget->getParent(); } $errors = $errorsTarget->getErrors(); $errorsTarget->clearErrors(); foreach ($errors as $error) { if (!$error instanceof FileUploadError) { $errorsTarget->addError($error); } } } $message = $violation->getMessage(); $messageTemplate = $violation->getMessageTemplate(); if (false !== strpos($message, '{{ label }}') || false !== strpos($messageTemplate, '{{ label }}')) { $form = $scope; do { $labelFormat = $form->getConfig()->getOption('label_format'); } while (null === $labelFormat && null !== $form = $form->getParent()); if (null !== $labelFormat) { $label = str_replace( [ '%name%', '%id%', ], [ $scope->getName(), (string) $scope->getPropertyPath(), ], $labelFormat ); } else { $label = $scope->getConfig()->getOption('label'); } if (false !== $label) { if (null === $label && null !== $this->formRenderer) { $label = $this->formRenderer->humanize($scope->getName()); } elseif (null === $label) { $label = $scope->getName(); } if (null !== $this->translator) { $form = $scope; $translationParameters[] = $form->getConfig()->getOption('label_translation_parameters', []); do { $translationDomain = $form->getConfig()->getOption('translation_domain'); array_unshift( $translationParameters, $form->getConfig()->getOption('label_translation_parameters', []) ); } while (null === $translationDomain && null !== $form = $form->getParent()); $translationParameters = array_merge([], ...$translationParameters); $label = $this->translator->trans( $label, $translationParameters, $translationDomain ); } $message = str_replace('{{ label }}', $label, $message); $messageTemplate = str_replace('{{ label }}', $label, $messageTemplate); } } $scope->addError(new FormError( $message, $messageTemplate, $violation->getParameters(), $violation->getPlural(), $violation )); } } /** * Tries to match the beginning of the property path at the * current position against the children of the scope. * * If a matching child is found, it is returned. Otherwise * null is returned. */ private function matchChild(FormInterface $form, PropertyPathIteratorInterface $it): ?FormInterface { $target = null; $chunk = ''; $foundAtIndex = null; // Construct mapping rules for the given form $rules = []; foreach ($form->getConfig()->getOption('error_mapping') as $propertyPath => $targetPath) { // Dot rules are considered at the very end if ('.' !== $propertyPath) { $rules[] = new MappingRule($form, $propertyPath, $targetPath); } } $children = iterator_to_array(new \RecursiveIteratorIterator(new InheritDataAwareIterator($form)), false); while ($it->valid()) { if ($it->isIndex()) { $chunk .= '['.$it->current().']'; } else { $chunk .= ('' === $chunk ? '' : '.').$it->current(); } // Test mapping rules as long as we have any foreach ($rules as $key => $rule) { /* @var MappingRule $rule */ // Mapping rule matches completely, terminate. if (null !== ($form = $rule->match($chunk))) { return $form; } // Keep only rules that have $chunk as prefix if (!$rule->isPrefix($chunk)) { unset($rules[$key]); } } /** @var FormInterface $child */ foreach ($children as $i => $child) { $childPath = (string) $child->getPropertyPath(); if ($childPath === $chunk) { $target = $child; $foundAtIndex = $it->key(); } elseif (str_starts_with($childPath, $chunk)) { continue; } unset($children[$i]); } $it->next(); } if (null !== $foundAtIndex) { $it->seek($foundAtIndex); } return $target; } /** * Reconstructs a property path from a violation path and a form tree. */ private function reconstructPath(ViolationPath $violationPath, FormInterface $origin): ?RelativePath { $propertyPathBuilder = new PropertyPathBuilder($violationPath); $it = $violationPath->getIterator(); $scope = $origin; // Remember the current index in the builder $i = 0; // Expand elements that map to a form (like "children[address]") for ($it->rewind(); $it->valid() && $it->mapsForm(); $it->next()) { if (!$scope->has($it->current())) { // Scope relates to a form that does not exist // Bail out break; } // Process child form $scope = $scope->get($it->current()); if ($scope->getConfig()->getInheritData()) { // Form inherits its parent data // Cut the piece out of the property path and proceed $propertyPathBuilder->remove($i); } else { /* @var \Symfony\Component\PropertyAccess\PropertyPathInterface $propertyPath */ $propertyPath = $scope->getPropertyPath(); if (null === $propertyPath) { // Property path of a mapped form is null // Should not happen, bail out break; } $propertyPathBuilder->replace($i, 1, $propertyPath); $i += $propertyPath->getLength(); } } $finalPath = $propertyPathBuilder->getPropertyPath(); return null !== $finalPath ? new RelativePath($origin, $finalPath) : null; } private function acceptsErrors(FormInterface $form): bool { return $this->allowNonSynchronized || $form->isSynchronized(); } } Extension/Validator/ViolationMapper/ViolationMapperInterface.php 0000644 00000001500 15120211544 0021210 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\ViolationMapper; use Symfony\Component\Form\FormInterface; use Symfony\Component\Validator\ConstraintViolation; /** * @author Bernhard Schussek <bschussek@gmail.com> */ interface ViolationMapperInterface { /** * Maps a constraint violation to a form in the form tree under * the given form. * * @param bool $allowNonSynchronized Whether to allow mapping to non-synchronized forms */ public function mapViolation(ConstraintViolation $violation, FormInterface $form, bool $allowNonSynchronized = false); } Extension/Validator/ViolationMapper/ViolationPath.php 0000644 00000015261 15120211544 0017050 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\ViolationMapper; use Symfony\Component\Form\Exception\OutOfBoundsException; use Symfony\Component\PropertyAccess\PropertyPath; use Symfony\Component\PropertyAccess\PropertyPathInterface; /** * @author Bernhard Schussek <bschussek@gmail.com> * * @implements \IteratorAggregate<int, string> */ class ViolationPath implements \IteratorAggregate, PropertyPathInterface { /** * @var list<string> */ private $elements = []; /** * @var array */ private $isIndex = []; /** * @var array */ private $mapsForm = []; /** * @var string */ private $pathAsString = ''; /** * @var int */ private $length = 0; /** * Creates a new violation path from a string. * * @param string $violationPath The property path of a {@link \Symfony\Component\Validator\ConstraintViolation} object */ public function __construct(string $violationPath) { $path = new PropertyPath($violationPath); $elements = $path->getElements(); $data = false; for ($i = 0, $l = \count($elements); $i < $l; ++$i) { if (!$data) { // The element "data" has not yet been passed if ('children' === $elements[$i] && $path->isProperty($i)) { // Skip element "children" ++$i; // Next element must exist and must be an index // Otherwise consider this the end of the path if ($i >= $l || !$path->isIndex($i)) { break; } // All the following index items (regardless if .children is // explicitly used) are children and grand-children for (; $i < $l && $path->isIndex($i); ++$i) { $this->elements[] = $elements[$i]; $this->isIndex[] = true; $this->mapsForm[] = true; } // Rewind the pointer as the last element above didn't match // (even if the pointer was moved forward) --$i; } elseif ('data' === $elements[$i] && $path->isProperty($i)) { // Skip element "data" ++$i; // End of path if ($i >= $l) { break; } $this->elements[] = $elements[$i]; $this->isIndex[] = $path->isIndex($i); $this->mapsForm[] = false; $data = true; } else { // Neither "children" nor "data" property found // Consider this the end of the path break; } } else { // Already after the "data" element // Pick everything as is $this->elements[] = $elements[$i]; $this->isIndex[] = $path->isIndex($i); $this->mapsForm[] = false; } } $this->length = \count($this->elements); $this->buildString(); } /** * {@inheritdoc} */ public function __toString() { return $this->pathAsString; } /** * {@inheritdoc} */ public function getLength() { return $this->length; } /** * {@inheritdoc} */ public function getParent() { if ($this->length <= 1) { return null; } $parent = clone $this; --$parent->length; array_pop($parent->elements); array_pop($parent->isIndex); array_pop($parent->mapsForm); $parent->buildString(); return $parent; } /** * {@inheritdoc} */ public function getElements() { return $this->elements; } /** * {@inheritdoc} */ public function getElement(int $index) { if (!isset($this->elements[$index])) { throw new OutOfBoundsException(sprintf('The index "%s" is not within the violation path.', $index)); } return $this->elements[$index]; } /** * {@inheritdoc} */ public function isProperty(int $index) { if (!isset($this->isIndex[$index])) { throw new OutOfBoundsException(sprintf('The index "%s" is not within the violation path.', $index)); } return !$this->isIndex[$index]; } /** * {@inheritdoc} */ public function isIndex(int $index) { if (!isset($this->isIndex[$index])) { throw new OutOfBoundsException(sprintf('The index "%s" is not within the violation path.', $index)); } return $this->isIndex[$index]; } /** * Returns whether an element maps directly to a form. * * Consider the following violation path: * * children[address].children[office].data.street * * In this example, "address" and "office" map to forms, while * "street does not. * * @return bool * * @throws OutOfBoundsException if the offset is invalid */ public function mapsForm(int $index) { if (!isset($this->mapsForm[$index])) { throw new OutOfBoundsException(sprintf('The index "%s" is not within the violation path.', $index)); } return $this->mapsForm[$index]; } /** * Returns a new iterator for this path. * * @return ViolationPathIterator */ #[\ReturnTypeWillChange] public function getIterator() { return new ViolationPathIterator($this); } /** * Builds the string representation from the elements. */ private function buildString() { $this->pathAsString = ''; $data = false; foreach ($this->elements as $index => $element) { if ($this->mapsForm[$index]) { $this->pathAsString .= ".children[$element]"; } elseif (!$data) { $this->pathAsString .= '.data'.($this->isIndex[$index] ? "[$element]" : ".$element"); $data = true; } else { $this->pathAsString .= $this->isIndex[$index] ? "[$element]" : ".$element"; } } if ('' !== $this->pathAsString) { // remove leading dot $this->pathAsString = substr($this->pathAsString, 1); } } } Extension/Validator/ViolationMapper/ViolationPathIterator.php 0000644 00000001300 15120211544 0020547 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator\ViolationMapper; use Symfony\Component\PropertyAccess\PropertyPathIterator; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class ViolationPathIterator extends PropertyPathIterator { public function __construct(ViolationPath $violationPath) { parent::__construct($violationPath); } public function mapsForm() { return $this->path->mapsForm($this->key()); } } Extension/Validator/ValidatorExtension.php 0000644 00000004416 15120211544 0015000 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator; use Symfony\Component\Form\AbstractExtension; use Symfony\Component\Form\Extension\Validator\Constraints\Form; use Symfony\Component\Form\FormRendererInterface; use Symfony\Component\Validator\Constraints\Traverse; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Contracts\Translation\TranslatorInterface; /** * Extension supporting the Symfony Validator component in forms. * * @author Bernhard Schussek <bschussek@gmail.com> */ class ValidatorExtension extends AbstractExtension { private $validator; private $formRenderer; private $translator; private $legacyErrorMessages; public function __construct(ValidatorInterface $validator, bool $legacyErrorMessages = true, FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null) { $this->legacyErrorMessages = $legacyErrorMessages; $metadata = $validator->getMetadataFor('Symfony\Component\Form\Form'); // Register the form constraints in the validator programmatically. // This functionality is required when using the Form component without // the DIC, where the XML file is loaded automatically. Thus the following // code must be kept synchronized with validation.xml /* @var $metadata ClassMetadata */ $metadata->addConstraint(new Form()); $metadata->addConstraint(new Traverse(false)); $this->validator = $validator; $this->formRenderer = $formRenderer; $this->translator = $translator; } public function loadTypeGuesser() { return new ValidatorTypeGuesser($this->validator); } protected function loadTypeExtensions() { return [ new Type\FormTypeValidatorExtension($this->validator, $this->legacyErrorMessages, $this->formRenderer, $this->translator), new Type\RepeatedTypeValidatorExtension(), new Type\SubmitTypeValidatorExtension(), ]; } } Extension/Validator/ValidatorTypeGuesser.php 0000644 00000026271 15120211544 0015306 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Extension\Validator; use Symfony\Component\Form\FormTypeGuesserInterface; use Symfony\Component\Form\Guess\Guess; use Symfony\Component\Form\Guess\TypeGuess; use Symfony\Component\Form\Guess\ValueGuess; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Mapping\ClassMetadataInterface; use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface; class ValidatorTypeGuesser implements FormTypeGuesserInterface { private $metadataFactory; public function __construct(MetadataFactoryInterface $metadataFactory) { $this->metadataFactory = $metadataFactory; } /** * {@inheritdoc} */ public function guessType(string $class, string $property) { return $this->guess($class, $property, function (Constraint $constraint) { return $this->guessTypeForConstraint($constraint); }); } /** * {@inheritdoc} */ public function guessRequired(string $class, string $property) { return $this->guess($class, $property, function (Constraint $constraint) { return $this->guessRequiredForConstraint($constraint); // If we don't find any constraint telling otherwise, we can assume // that a field is not required (with LOW_CONFIDENCE) }, false); } /** * {@inheritdoc} */ public function guessMaxLength(string $class, string $property) { return $this->guess($class, $property, function (Constraint $constraint) { return $this->guessMaxLengthForConstraint($constraint); }); } /** * {@inheritdoc} */ public function guessPattern(string $class, string $property) { return $this->guess($class, $property, function (Constraint $constraint) { return $this->guessPatternForConstraint($constraint); }); } /** * Guesses a field class name for a given constraint. * * @return TypeGuess|null */ public function guessTypeForConstraint(Constraint $constraint) { switch (\get_class($constraint)) { case 'Symfony\Component\Validator\Constraints\Type': switch ($constraint->type) { case 'array': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CollectionType', [], Guess::MEDIUM_CONFIDENCE); case 'boolean': case 'bool': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CheckboxType', [], Guess::MEDIUM_CONFIDENCE); case 'double': case 'float': case 'numeric': case 'real': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\NumberType', [], Guess::MEDIUM_CONFIDENCE); case 'integer': case 'int': case 'long': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\IntegerType', [], Guess::MEDIUM_CONFIDENCE); case \DateTime::class: case '\DateTime': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateType', [], Guess::MEDIUM_CONFIDENCE); case 'string': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TextType', [], Guess::LOW_CONFIDENCE); } break; case 'Symfony\Component\Validator\Constraints\Country': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CountryType', [], Guess::HIGH_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\Currency': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CurrencyType', [], Guess::HIGH_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\Date': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateType', ['input' => 'string'], Guess::HIGH_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\DateTime': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateTimeType', ['input' => 'string'], Guess::HIGH_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\Email': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\EmailType', [], Guess::HIGH_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\File': case 'Symfony\Component\Validator\Constraints\Image': $options = []; if ($constraint->mimeTypes) { $options = ['attr' => ['accept' => implode(',', (array) $constraint->mimeTypes)]]; } return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\FileType', $options, Guess::HIGH_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\Language': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\LanguageType', [], Guess::HIGH_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\Locale': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\LocaleType', [], Guess::HIGH_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\Time': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TimeType', ['input' => 'string'], Guess::HIGH_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\Url': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\UrlType', [], Guess::HIGH_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\Ip': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TextType', [], Guess::MEDIUM_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\Length': case 'Symfony\Component\Validator\Constraints\Regex': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TextType', [], Guess::LOW_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\Range': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\NumberType', [], Guess::LOW_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\Count': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CollectionType', [], Guess::LOW_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\IsTrue': case 'Symfony\Component\Validator\Constraints\IsFalse': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CheckboxType', [], Guess::MEDIUM_CONFIDENCE); } return null; } /** * Guesses whether a field is required based on the given constraint. * * @return ValueGuess|null */ public function guessRequiredForConstraint(Constraint $constraint) { switch (\get_class($constraint)) { case 'Symfony\Component\Validator\Constraints\NotNull': case 'Symfony\Component\Validator\Constraints\NotBlank': case 'Symfony\Component\Validator\Constraints\IsTrue': return new ValueGuess(true, Guess::HIGH_CONFIDENCE); } return null; } /** * Guesses a field's maximum length based on the given constraint. * * @return ValueGuess|null */ public function guessMaxLengthForConstraint(Constraint $constraint) { switch (\get_class($constraint)) { case 'Symfony\Component\Validator\Constraints\Length': if (is_numeric($constraint->max)) { return new ValueGuess($constraint->max, Guess::HIGH_CONFIDENCE); } break; case 'Symfony\Component\Validator\Constraints\Type': if (\in_array($constraint->type, ['double', 'float', 'numeric', 'real'])) { return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE); } break; case 'Symfony\Component\Validator\Constraints\Range': if (is_numeric($constraint->max)) { return new ValueGuess(\strlen((string) $constraint->max), Guess::LOW_CONFIDENCE); } break; } return null; } /** * Guesses a field's pattern based on the given constraint. * * @return ValueGuess|null */ public function guessPatternForConstraint(Constraint $constraint) { switch (\get_class($constraint)) { case 'Symfony\Component\Validator\Constraints\Length': if (is_numeric($constraint->min)) { return new ValueGuess(sprintf('.{%s,}', (string) $constraint->min), Guess::LOW_CONFIDENCE); } break; case 'Symfony\Component\Validator\Constraints\Regex': $htmlPattern = $constraint->getHtmlPattern(); if (null !== $htmlPattern) { return new ValueGuess($htmlPattern, Guess::HIGH_CONFIDENCE); } break; case 'Symfony\Component\Validator\Constraints\Range': if (is_numeric($constraint->min)) { return new ValueGuess(sprintf('.{%s,}', \strlen((string) $constraint->min)), Guess::LOW_CONFIDENCE); } break; case 'Symfony\Component\Validator\Constraints\Type': if (\in_array($constraint->type, ['double', 'float', 'numeric', 'real'])) { return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE); } break; } return null; } /** * Iterates over the constraints of a property, executes a constraints on * them and returns the best guess. * * @param \Closure $closure The closure that returns a guess * for a given constraint * @param mixed $defaultValue The default value assumed if no other value * can be guessed * * @return Guess|null */ protected function guess(string $class, string $property, \Closure $closure, $defaultValue = null) { $guesses = []; $classMetadata = $this->metadataFactory->getMetadataFor($class); if ($classMetadata instanceof ClassMetadataInterface && $classMetadata->hasPropertyMetadata($property)) { foreach ($classMetadata->getPropertyMetadata($property) as $memberMetadata) { foreach ($memberMetadata->getConstraints() as $constraint) { if ($guess = $closure($constraint)) { $guesses[] = $guess; } } } } if (null !== $defaultValue) { $guesses[] = new ValueGuess($defaultValue, Guess::LOW_CONFIDENCE); } return Guess::getBestGuess($guesses); } } FormExtensionInterface.php 0000644 00000002753 15120211544 0011700 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * Interface for extensions which provide types, type extensions and a guesser. */ interface FormExtensionInterface { /** * Returns a type by name. * * @param string $name The name of the type * * @return FormTypeInterface * * @throws Exception\InvalidArgumentException if the given type is not supported by this extension */ public function getType(string $name); /** * Returns whether the given type is supported. * * @param string $name The name of the type * * @return bool */ public function hasType(string $name); /** * Returns the extensions for the given type. * * @param string $name The name of the type * * @return FormTypeExtensionInterface[] */ public function getTypeExtensions(string $name); /** * Returns whether this extension provides type extensions for the given type. * * @param string $name The name of the type * * @return bool */ public function hasTypeExtensions(string $name); /** * Returns the type guesser provided by this extension. * * @return FormTypeGuesserInterface|null */ public function getTypeGuesser(); } FormFactory.php 0000644 00000007551 15120211544 0007513 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\TextType; class FormFactory implements FormFactoryInterface { private $registry; public function __construct(FormRegistryInterface $registry) { $this->registry = $registry; } /** * {@inheritdoc} */ public function create(string $type = FormType::class, $data = null, array $options = []) { return $this->createBuilder($type, $data, $options)->getForm(); } /** * {@inheritdoc} */ public function createNamed(string $name, string $type = FormType::class, $data = null, array $options = []) { return $this->createNamedBuilder($name, $type, $data, $options)->getForm(); } /** * {@inheritdoc} */ public function createForProperty(string $class, string $property, $data = null, array $options = []) { return $this->createBuilderForProperty($class, $property, $data, $options)->getForm(); } /** * {@inheritdoc} */ public function createBuilder(string $type = FormType::class, $data = null, array $options = []) { return $this->createNamedBuilder($this->registry->getType($type)->getBlockPrefix(), $type, $data, $options); } /** * {@inheritdoc} */ public function createNamedBuilder(string $name, string $type = FormType::class, $data = null, array $options = []) { if (null !== $data && !\array_key_exists('data', $options)) { $options['data'] = $data; } $type = $this->registry->getType($type); $builder = $type->createBuilder($this, $name, $options); // Explicitly call buildForm() in order to be able to override either // createBuilder() or buildForm() in the resolved form type $type->buildForm($builder, $builder->getOptions()); return $builder; } /** * {@inheritdoc} */ public function createBuilderForProperty(string $class, string $property, $data = null, array $options = []) { if (null === $guesser = $this->registry->getTypeGuesser()) { return $this->createNamedBuilder($property, TextType::class, $data, $options); } $typeGuess = $guesser->guessType($class, $property); $maxLengthGuess = $guesser->guessMaxLength($class, $property); $requiredGuess = $guesser->guessRequired($class, $property); $patternGuess = $guesser->guessPattern($class, $property); $type = $typeGuess ? $typeGuess->getType() : TextType::class; $maxLength = $maxLengthGuess ? $maxLengthGuess->getValue() : null; $pattern = $patternGuess ? $patternGuess->getValue() : null; if (null !== $pattern) { $options = array_replace_recursive(['attr' => ['pattern' => $pattern]], $options); } if (null !== $maxLength) { $options = array_replace_recursive(['attr' => ['maxlength' => $maxLength]], $options); } if ($requiredGuess) { $options = array_merge(['required' => $requiredGuess->getValue()], $options); } // user options may override guessed options if ($typeGuess) { $attrs = []; $typeGuessOptions = $typeGuess->getOptions(); if (isset($typeGuessOptions['attr']) && isset($options['attr'])) { $attrs = ['attr' => array_merge($typeGuessOptions['attr'], $options['attr'])]; } $options = array_merge($typeGuessOptions, $options, $attrs); } return $this->createNamedBuilder($property, $type, $data, $options); } } FormFactoryBuilder.php 0000644 00000010170 15120211544 0011011 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Extension\Core\CoreExtension; /** * The default implementation of FormFactoryBuilderInterface. * * @author Bernhard Schussek <bschussek@gmail.com> */ class FormFactoryBuilder implements FormFactoryBuilderInterface { private $forceCoreExtension; /** * @var ResolvedFormTypeFactoryInterface */ private $resolvedTypeFactory; /** * @var FormExtensionInterface[] */ private $extensions = []; /** * @var FormTypeInterface[] */ private $types = []; /** * @var FormTypeExtensionInterface[][] */ private $typeExtensions = []; /** * @var FormTypeGuesserInterface[] */ private $typeGuessers = []; public function __construct(bool $forceCoreExtension = false) { $this->forceCoreExtension = $forceCoreExtension; } /** * {@inheritdoc} */ public function setResolvedTypeFactory(ResolvedFormTypeFactoryInterface $resolvedTypeFactory) { $this->resolvedTypeFactory = $resolvedTypeFactory; return $this; } /** * {@inheritdoc} */ public function addExtension(FormExtensionInterface $extension) { $this->extensions[] = $extension; return $this; } /** * {@inheritdoc} */ public function addExtensions(array $extensions) { $this->extensions = array_merge($this->extensions, $extensions); return $this; } /** * {@inheritdoc} */ public function addType(FormTypeInterface $type) { $this->types[] = $type; return $this; } /** * {@inheritdoc} */ public function addTypes(array $types) { foreach ($types as $type) { $this->types[] = $type; } return $this; } /** * {@inheritdoc} */ public function addTypeExtension(FormTypeExtensionInterface $typeExtension) { foreach ($typeExtension::getExtendedTypes() as $extendedType) { $this->typeExtensions[$extendedType][] = $typeExtension; } return $this; } /** * {@inheritdoc} */ public function addTypeExtensions(array $typeExtensions) { foreach ($typeExtensions as $typeExtension) { $this->addTypeExtension($typeExtension); } return $this; } /** * {@inheritdoc} */ public function addTypeGuesser(FormTypeGuesserInterface $typeGuesser) { $this->typeGuessers[] = $typeGuesser; return $this; } /** * {@inheritdoc} */ public function addTypeGuessers(array $typeGuessers) { $this->typeGuessers = array_merge($this->typeGuessers, $typeGuessers); return $this; } /** * {@inheritdoc} */ public function getFormFactory() { $extensions = $this->extensions; if ($this->forceCoreExtension) { $hasCoreExtension = false; foreach ($extensions as $extension) { if ($extension instanceof CoreExtension) { $hasCoreExtension = true; break; } } if (!$hasCoreExtension) { array_unshift($extensions, new CoreExtension()); } } if (\count($this->types) > 0 || \count($this->typeExtensions) > 0 || \count($this->typeGuessers) > 0) { if (\count($this->typeGuessers) > 1) { $typeGuesser = new FormTypeGuesserChain($this->typeGuessers); } else { $typeGuesser = $this->typeGuessers[0] ?? null; } $extensions[] = new PreloadedExtension($this->types, $this->typeExtensions, $typeGuesser); } $registry = new FormRegistry($extensions, $this->resolvedTypeFactory ?? new ResolvedFormTypeFactory()); return new FormFactory($registry); } } FormFactoryBuilderInterface.php 0000644 00000004457 15120211544 0012645 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * A builder for FormFactoryInterface objects. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface FormFactoryBuilderInterface { /** * Sets the factory for creating ResolvedFormTypeInterface instances. * * @return $this */ public function setResolvedTypeFactory(ResolvedFormTypeFactoryInterface $resolvedTypeFactory); /** * Adds an extension to be loaded by the factory. * * @return $this */ public function addExtension(FormExtensionInterface $extension); /** * Adds a list of extensions to be loaded by the factory. * * @param FormExtensionInterface[] $extensions The extensions * * @return $this */ public function addExtensions(array $extensions); /** * Adds a form type to the factory. * * @return $this */ public function addType(FormTypeInterface $type); /** * Adds a list of form types to the factory. * * @param FormTypeInterface[] $types The form types * * @return $this */ public function addTypes(array $types); /** * Adds a form type extension to the factory. * * @return $this */ public function addTypeExtension(FormTypeExtensionInterface $typeExtension); /** * Adds a list of form type extensions to the factory. * * @param FormTypeExtensionInterface[] $typeExtensions The form type extensions * * @return $this */ public function addTypeExtensions(array $typeExtensions); /** * Adds a type guesser to the factory. * * @return $this */ public function addTypeGuesser(FormTypeGuesserInterface $typeGuesser); /** * Adds a list of type guessers to the factory. * * @param FormTypeGuesserInterface[] $typeGuessers The type guessers * * @return $this */ public function addTypeGuessers(array $typeGuessers); /** * Builds and returns the factory. * * @return FormFactoryInterface */ public function getFormFactory(); } FormFactoryInterface.php 0000644 00000006233 15120211544 0011330 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; /** * Allows creating a form based on a name, a class or a property. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface FormFactoryInterface { /** * Returns a form. * * @see createBuilder() * * @param mixed $data The initial data * * @return FormInterface * * @throws InvalidOptionsException if any given option is not applicable to the given type */ public function create(string $type = FormType::class, $data = null, array $options = []); /** * Returns a form. * * @see createNamedBuilder() * * @param mixed $data The initial data * * @return FormInterface * * @throws InvalidOptionsException if any given option is not applicable to the given type */ public function createNamed(string $name, string $type = FormType::class, $data = null, array $options = []); /** * Returns a form for a property of a class. * * @see createBuilderForProperty() * * @param string $class The fully qualified class name * @param string $property The name of the property to guess for * @param mixed $data The initial data * * @return FormInterface * * @throws InvalidOptionsException if any given option is not applicable to the form type */ public function createForProperty(string $class, string $property, $data = null, array $options = []); /** * Returns a form builder. * * @param mixed $data The initial data * * @return FormBuilderInterface * * @throws InvalidOptionsException if any given option is not applicable to the given type */ public function createBuilder(string $type = FormType::class, $data = null, array $options = []); /** * Returns a form builder. * * @param mixed $data The initial data * * @return FormBuilderInterface * * @throws InvalidOptionsException if any given option is not applicable to the given type */ public function createNamedBuilder(string $name, string $type = FormType::class, $data = null, array $options = []); /** * Returns a form builder for a property of a class. * * If any of the 'required' and type options can be guessed, * and are not provided in the options argument, the guessed value is used. * * @param string $class The fully qualified class name * @param string $property The name of the property to guess for * @param mixed $data The initial data * * @return FormBuilderInterface * * @throws InvalidOptionsException if any given option is not applicable to the form type */ public function createBuilderForProperty(string $class, string $property, $data = null, array $options = []); } FormInterface.php 0000644 00000023125 15120211544 0007777 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\PropertyAccess\PropertyPathInterface; /** * A form group bundling multiple forms in a hierarchical structure. * * @author Bernhard Schussek <bschussek@gmail.com> * * @extends \ArrayAccess<string, FormInterface> * @extends \Traversable<string, FormInterface> */ interface FormInterface extends \ArrayAccess, \Traversable, \Countable { /** * Sets the parent form. * * @param FormInterface|null $parent The parent form or null if it's the root * * @return $this * * @throws Exception\AlreadySubmittedException if the form has already been submitted * @throws Exception\LogicException when trying to set a parent for a form with * an empty name */ public function setParent(self $parent = null); /** * Returns the parent form. * * @return self|null */ public function getParent(); /** * Adds or replaces a child to the form. * * @param FormInterface|string $child The FormInterface instance or the name of the child * @param string|null $type The child's type, if a name was passed * @param array $options The child's options, if a name was passed * * @return $this * * @throws Exception\AlreadySubmittedException if the form has already been submitted * @throws Exception\LogicException when trying to add a child to a non-compound form * @throws Exception\UnexpectedTypeException if $child or $type has an unexpected type */ public function add($child, string $type = null, array $options = []); /** * Returns the child with the given name. * * @return self * * @throws Exception\OutOfBoundsException if the named child does not exist */ public function get(string $name); /** * Returns whether a child with the given name exists. * * @return bool */ public function has(string $name); /** * Removes a child from the form. * * @return $this * * @throws Exception\AlreadySubmittedException if the form has already been submitted */ public function remove(string $name); /** * Returns all children in this group. * * @return self[] */ public function all(); /** * Returns the errors of this form. * * @param bool $deep Whether to include errors of child forms as well * @param bool $flatten Whether to flatten the list of errors in case * $deep is set to true * * @return FormErrorIterator */ public function getErrors(bool $deep = false, bool $flatten = true); /** * Updates the form with default model data. * * @param mixed $modelData The data formatted as expected for the underlying object * * @return $this * * @throws Exception\AlreadySubmittedException If the form has already been submitted * @throws Exception\LogicException if the view data does not match the expected type * according to {@link FormConfigInterface::getDataClass} * @throws Exception\RuntimeException If listeners try to call setData in a cycle or if * the form inherits data from its parent * @throws Exception\TransformationFailedException if the synchronization failed */ public function setData($modelData); /** * Returns the model data in the format needed for the underlying object. * * @return mixed When the field is not submitted, the default data is returned. * When the field is submitted, the default data has been bound * to the submitted view data. * * @throws Exception\RuntimeException If the form inherits data but has no parent */ public function getData(); /** * Returns the normalized data of the field, used as internal bridge * between model data and view data. * * @return mixed When the field is not submitted, the default data is returned. * When the field is submitted, the normalized submitted data * is returned if the field is synchronized with the view data, * null otherwise. * * @throws Exception\RuntimeException If the form inherits data but has no parent */ public function getNormData(); /** * Returns the view data of the field. * * It may be defined by {@link FormConfigInterface::getDataClass}. * * There are two cases: * * - When the form is compound the view data is mapped to the children. * Each child will use its mapped data as model data. * It can be an array, an object or null. * * - When the form is simple its view data is used to be bound * to the submitted data. * It can be a string or an array. * * In both cases the view data is the actual altered data on submission. * * @return mixed * * @throws Exception\RuntimeException If the form inherits data but has no parent */ public function getViewData(); /** * Returns the extra submitted data. * * @return array The submitted data which do not belong to a child */ public function getExtraData(); /** * Returns the form's configuration. * * @return FormConfigInterface */ public function getConfig(); /** * Returns whether the form is submitted. * * @return bool */ public function isSubmitted(); /** * Returns the name by which the form is identified in forms. * * Only root forms are allowed to have an empty name. * * @return string */ public function getName(); /** * Returns the property path that the form is mapped to. * * @return PropertyPathInterface|null */ public function getPropertyPath(); /** * Adds an error to this form. * * @return $this */ public function addError(FormError $error); /** * Returns whether the form and all children are valid. * * @return bool * * @throws Exception\LogicException if the form is not submitted */ public function isValid(); /** * Returns whether the form is required to be filled out. * * If the form has a parent and the parent is not required, this method * will always return false. Otherwise the value set with setRequired() * is returned. * * @return bool */ public function isRequired(); /** * Returns whether this form is disabled. * * The content of a disabled form is displayed, but not allowed to be * modified. The validation of modified disabled forms should fail. * * Forms whose parents are disabled are considered disabled regardless of * their own state. * * @return bool */ public function isDisabled(); /** * Returns whether the form is empty. * * @return bool */ public function isEmpty(); /** * Returns whether the data in the different formats is synchronized. * * If the data is not synchronized, you can get the transformation failure * by calling {@link getTransformationFailure()}. * * If the form is not submitted, this method always returns true. * * @return bool */ public function isSynchronized(); /** * Returns the data transformation failure, if any, during submission. * * @return Exception\TransformationFailedException|null */ public function getTransformationFailure(); /** * Initializes the form tree. * * Should be called on the root form after constructing the tree. * * @return $this * * @throws Exception\RuntimeException If the form is not the root */ public function initialize(); /** * Inspects the given request and calls {@link submit()} if the form was * submitted. * * Internally, the request is forwarded to the configured * {@link RequestHandlerInterface} instance, which determines whether to * submit the form or not. * * @param mixed $request The request to handle * * @return $this */ public function handleRequest($request = null); /** * Submits data to the form. * * @param string|array|null $submittedData The submitted data * @param bool $clearMissing Whether to set fields to NULL * when they are missing in the * submitted data. This argument * is only used in compound form * * @return $this * * @throws Exception\AlreadySubmittedException if the form has already been submitted */ public function submit($submittedData, bool $clearMissing = true); /** * Returns the root of the form tree. * * @return self */ public function getRoot(); /** * Returns whether the field is the root of the form tree. * * @return bool */ public function isRoot(); /** * @return FormView */ public function createView(FormView $parent = null); } FormRegistry.php 0000644 00000011311 15120211544 0007701 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\ExceptionInterface; use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Exception\UnexpectedTypeException; /** * The central registry of the Form component. * * @author Bernhard Schussek <bschussek@gmail.com> */ class FormRegistry implements FormRegistryInterface { /** * @var FormExtensionInterface[] */ private $extensions = []; /** * @var ResolvedFormTypeInterface[] */ private $types = []; /** * @var FormTypeGuesserInterface|false|null */ private $guesser = false; /** * @var ResolvedFormTypeFactoryInterface */ private $resolvedTypeFactory; private $checkedTypes = []; /** * @param FormExtensionInterface[] $extensions * * @throws UnexpectedTypeException if any extension does not implement FormExtensionInterface */ public function __construct(array $extensions, ResolvedFormTypeFactoryInterface $resolvedTypeFactory) { foreach ($extensions as $extension) { if (!$extension instanceof FormExtensionInterface) { throw new UnexpectedTypeException($extension, FormExtensionInterface::class); } } $this->extensions = $extensions; $this->resolvedTypeFactory = $resolvedTypeFactory; } /** * {@inheritdoc} */ public function getType(string $name) { if (!isset($this->types[$name])) { $type = null; foreach ($this->extensions as $extension) { if ($extension->hasType($name)) { $type = $extension->getType($name); break; } } if (!$type) { // Support fully-qualified class names if (!class_exists($name)) { throw new InvalidArgumentException(sprintf('Could not load type "%s": class does not exist.', $name)); } if (!is_subclass_of($name, FormTypeInterface::class)) { throw new InvalidArgumentException(sprintf('Could not load type "%s": class does not implement "Symfony\Component\Form\FormTypeInterface".', $name)); } $type = new $name(); } $this->types[$name] = $this->resolveType($type); } return $this->types[$name]; } /** * Wraps a type into a ResolvedFormTypeInterface implementation and connects it with its parent type. */ private function resolveType(FormTypeInterface $type): ResolvedFormTypeInterface { $parentType = $type->getParent(); $fqcn = \get_class($type); if (isset($this->checkedTypes[$fqcn])) { $types = implode(' > ', array_merge(array_keys($this->checkedTypes), [$fqcn])); throw new LogicException(sprintf('Circular reference detected for form type "%s" (%s).', $fqcn, $types)); } $this->checkedTypes[$fqcn] = true; $typeExtensions = []; try { foreach ($this->extensions as $extension) { $typeExtensions[] = $extension->getTypeExtensions($fqcn); } return $this->resolvedTypeFactory->createResolvedType( $type, array_merge([], ...$typeExtensions), $parentType ? $this->getType($parentType) : null ); } finally { unset($this->checkedTypes[$fqcn]); } } /** * {@inheritdoc} */ public function hasType(string $name) { if (isset($this->types[$name])) { return true; } try { $this->getType($name); } catch (ExceptionInterface $e) { return false; } return true; } /** * {@inheritdoc} */ public function getTypeGuesser() { if (false === $this->guesser) { $guessers = []; foreach ($this->extensions as $extension) { $guesser = $extension->getTypeGuesser(); if ($guesser) { $guessers[] = $guesser; } } $this->guesser = !empty($guessers) ? new FormTypeGuesserChain($guessers) : null; } return $this->guesser; } /** * {@inheritdoc} */ public function getExtensions() { return $this->extensions; } } FormRegistryInterface.php 0000644 00000002302 15120211544 0011522 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * The central registry of the Form component. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface FormRegistryInterface { /** * Returns a form type by name. * * This methods registers the type extensions from the form extensions. * * @return ResolvedFormTypeInterface * * @throws Exception\InvalidArgumentException if the type cannot be retrieved from any extension */ public function getType(string $name); /** * Returns whether the given form type is supported. * * @return bool */ public function hasType(string $name); /** * Returns the guesser responsible for guessing types. * * @return FormTypeGuesserInterface|null */ public function getTypeGuesser(); /** * Returns the extensions loaded by the framework. * * @return FormExtensionInterface[] */ public function getExtensions(); } FormRenderer.php 0000644 00000027610 15120211544 0007650 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\BadMethodCallException; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Twig\Environment; /** * Renders a form into HTML using a rendering engine. * * @author Bernhard Schussek <bschussek@gmail.com> */ class FormRenderer implements FormRendererInterface { public const CACHE_KEY_VAR = 'unique_block_prefix'; private $engine; private $csrfTokenManager; private $blockNameHierarchyMap = []; private $hierarchyLevelMap = []; private $variableStack = []; public function __construct(FormRendererEngineInterface $engine, CsrfTokenManagerInterface $csrfTokenManager = null) { $this->engine = $engine; $this->csrfTokenManager = $csrfTokenManager; } /** * {@inheritdoc} */ public function getEngine() { return $this->engine; } /** * {@inheritdoc} */ public function setTheme(FormView $view, $themes, bool $useDefaultThemes = true) { $this->engine->setTheme($view, $themes, $useDefaultThemes); } /** * {@inheritdoc} */ public function renderCsrfToken(string $tokenId) { if (null === $this->csrfTokenManager) { throw new BadMethodCallException('CSRF tokens can only be generated if a CsrfTokenManagerInterface is injected in FormRenderer::__construct(). Try running "composer require symfony/security-csrf".'); } return $this->csrfTokenManager->getToken($tokenId)->getValue(); } /** * {@inheritdoc} */ public function renderBlock(FormView $view, string $blockName, array $variables = []) { $resource = $this->engine->getResourceForBlockName($view, $blockName); if (!$resource) { throw new LogicException(sprintf('No block "%s" found while rendering the form.', $blockName)); } $viewCacheKey = $view->vars[self::CACHE_KEY_VAR]; // The variables are cached globally for a view (instead of for the // current suffix) if (!isset($this->variableStack[$viewCacheKey])) { $this->variableStack[$viewCacheKey] = []; // The default variable scope contains all view variables, merged with // the variables passed explicitly to the helper $scopeVariables = $view->vars; $varInit = true; } else { // Reuse the current scope and merge it with the explicitly passed variables $scopeVariables = end($this->variableStack[$viewCacheKey]); $varInit = false; } // Merge the passed with the existing attributes if (isset($variables['attr']) && isset($scopeVariables['attr'])) { $variables['attr'] = array_replace($scopeVariables['attr'], $variables['attr']); } // Merge the passed with the exist *label* attributes if (isset($variables['label_attr']) && isset($scopeVariables['label_attr'])) { $variables['label_attr'] = array_replace($scopeVariables['label_attr'], $variables['label_attr']); } // Do not use array_replace_recursive(), otherwise array variables // cannot be overwritten $variables = array_replace($scopeVariables, $variables); $this->variableStack[$viewCacheKey][] = $variables; // Do the rendering $html = $this->engine->renderBlock($view, $resource, $blockName, $variables); // Clear the stack array_pop($this->variableStack[$viewCacheKey]); if ($varInit) { unset($this->variableStack[$viewCacheKey]); } return $html; } /** * {@inheritdoc} */ public function searchAndRenderBlock(FormView $view, string $blockNameSuffix, array $variables = []) { $renderOnlyOnce = 'row' === $blockNameSuffix || 'widget' === $blockNameSuffix; if ($renderOnlyOnce && $view->isRendered()) { // This is not allowed, because it would result in rendering same IDs multiple times, which is not valid. throw new BadMethodCallException(sprintf('Field "%s" has already been rendered, save the result of previous render call to a variable and output that instead.', $view->vars['name'])); } // The cache key for storing the variables and types $viewCacheKey = $view->vars[self::CACHE_KEY_VAR]; $viewAndSuffixCacheKey = $viewCacheKey.$blockNameSuffix; // In templates, we have to deal with two kinds of block hierarchies: // // +---------+ +---------+ // | Theme B | -------> | Theme A | // +---------+ +---------+ // // form_widget -------> form_widget // ^ // | // choice_widget -----> choice_widget // // The first kind of hierarchy is the theme hierarchy. This allows to // override the block "choice_widget" from Theme A in the extending // Theme B. This kind of inheritance needs to be supported by the // template engine and, for example, offers "parent()" or similar // functions to fall back from the custom to the parent implementation. // // The second kind of hierarchy is the form type hierarchy. This allows // to implement a custom "choice_widget" block (no matter in which theme), // or to fallback to the block of the parent type, which would be // "form_widget" in this example (again, no matter in which theme). // If the designer wants to explicitly fallback to "form_widget" in their // custom "choice_widget", for example because they only want to wrap // a <div> around the original implementation, they can call the // widget() function again to render the block for the parent type. // // The second kind is implemented in the following blocks. if (!isset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey])) { // INITIAL CALL // Calculate the hierarchy of template blocks and start on // the bottom level of the hierarchy (= "_<id>_<section>" block) $blockNameHierarchy = []; foreach ($view->vars['block_prefixes'] as $blockNamePrefix) { $blockNameHierarchy[] = $blockNamePrefix.'_'.$blockNameSuffix; } $hierarchyLevel = \count($blockNameHierarchy) - 1; $hierarchyInit = true; } else { // RECURSIVE CALL // If a block recursively calls searchAndRenderBlock() again, resume rendering // using the parent type in the hierarchy. $blockNameHierarchy = $this->blockNameHierarchyMap[$viewAndSuffixCacheKey]; $hierarchyLevel = $this->hierarchyLevelMap[$viewAndSuffixCacheKey] - 1; $hierarchyInit = false; } // The variables are cached globally for a view (instead of for the // current suffix) if (!isset($this->variableStack[$viewCacheKey])) { $this->variableStack[$viewCacheKey] = []; // The default variable scope contains all view variables, merged with // the variables passed explicitly to the helper $scopeVariables = $view->vars; $varInit = true; } else { // Reuse the current scope and merge it with the explicitly passed variables $scopeVariables = end($this->variableStack[$viewCacheKey]); $varInit = false; } // Load the resource where this block can be found $resource = $this->engine->getResourceForBlockNameHierarchy($view, $blockNameHierarchy, $hierarchyLevel); // Update the current hierarchy level to the one at which the resource was // found. For example, if looking for "choice_widget", but only a resource // is found for its parent "form_widget", then the level is updated here // to the parent level. $hierarchyLevel = $this->engine->getResourceHierarchyLevel($view, $blockNameHierarchy, $hierarchyLevel); // The actually existing block name in $resource $blockName = $blockNameHierarchy[$hierarchyLevel]; // Escape if no resource exists for this block if (!$resource) { if (\count($blockNameHierarchy) !== \count(array_unique($blockNameHierarchy))) { throw new LogicException(sprintf('Unable to render the form because the block names array contains duplicates: "%s".', implode('", "', array_reverse($blockNameHierarchy)))); } throw new LogicException(sprintf('Unable to render the form as none of the following blocks exist: "%s".', implode('", "', array_reverse($blockNameHierarchy)))); } // Merge the passed with the existing attributes if (isset($variables['attr']) && isset($scopeVariables['attr'])) { $variables['attr'] = array_replace($scopeVariables['attr'], $variables['attr']); } // Merge the passed with the exist *label* attributes if (isset($variables['label_attr']) && isset($scopeVariables['label_attr'])) { $variables['label_attr'] = array_replace($scopeVariables['label_attr'], $variables['label_attr']); } // Do not use array_replace_recursive(), otherwise array variables // cannot be overwritten $variables = array_replace($scopeVariables, $variables); // In order to make recursive calls possible, we need to store the block hierarchy, // the current level of the hierarchy and the variables so that this method can // resume rendering one level higher of the hierarchy when it is called recursively. // // We need to store these values in maps (associative arrays) because within a // call to widget() another call to widget() can be made, but for a different view // object. These nested calls should not override each other. $this->blockNameHierarchyMap[$viewAndSuffixCacheKey] = $blockNameHierarchy; $this->hierarchyLevelMap[$viewAndSuffixCacheKey] = $hierarchyLevel; // We also need to store the variables for the view so that we can render other // blocks for the same view using the same variables as in the outer block. $this->variableStack[$viewCacheKey][] = $variables; // Do the rendering $html = $this->engine->renderBlock($view, $resource, $blockName, $variables); // Clear the stack array_pop($this->variableStack[$viewCacheKey]); // Clear the caches if they were filled for the first time within // this function call if ($hierarchyInit) { unset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey], $this->hierarchyLevelMap[$viewAndSuffixCacheKey]); } if ($varInit) { unset($this->variableStack[$viewCacheKey]); } if ($renderOnlyOnce) { $view->setRendered(); } return $html; } /** * {@inheritdoc} */ public function humanize(string $text) { return ucfirst(strtolower(trim(preg_replace(['/([A-Z])/', '/[_\s]+/'], ['_$1', ' '], $text)))); } /** * @internal */ public function encodeCurrency(Environment $environment, string $text, string $widget = ''): string { if ('UTF-8' === $charset = $environment->getCharset()) { $text = htmlspecialchars($text, \ENT_QUOTES | \ENT_SUBSTITUTE, 'UTF-8'); } else { $text = htmlentities($text, \ENT_QUOTES | \ENT_SUBSTITUTE, 'UTF-8'); $text = iconv('UTF-8', $charset, $text); $widget = iconv('UTF-8', $charset, $widget); } return str_replace('{{ widget }}', $widget, $text); } } FormRendererEngineInterface.php 0000644 00000014120 15120211544 0012607 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * Adapter for rendering form templates with a specific templating engine. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface FormRendererEngineInterface { /** * Sets the theme(s) to be used for rendering a view and its children. * * @param FormView $view The view to assign the theme(s) to * @param mixed $themes The theme(s). The type of these themes * is open to the implementation. */ public function setTheme(FormView $view, $themes, bool $useDefaultThemes = true); /** * Returns the resource for a block name. * * The resource is first searched in the themes attached to $view, then * in the themes of its parent view and so on, until a resource was found. * * The type of the resource is decided by the implementation. The resource * is later passed to {@link renderBlock()} by the rendering algorithm. * * @param FormView $view The view for determining the used themes. * First the themes attached directly to the * view with {@link setTheme()} are considered, * then the ones of its parent etc. * * @return mixed the renderer resource or false, if none was found */ public function getResourceForBlockName(FormView $view, string $blockName); /** * Returns the resource for a block hierarchy. * * A block hierarchy is an array which starts with the root of the hierarchy * and continues with the child of that root, the child of that child etc. * The following is an example for a block hierarchy: * * form_widget * text_widget * url_widget * * In this example, "url_widget" is the most specific block, while the other * blocks are its ancestors in the hierarchy. * * The second parameter $hierarchyLevel determines the level of the hierarchy * that should be rendered. For example, if $hierarchyLevel is 2 for the * above hierarchy, the engine will first look for the block "url_widget", * then, if that does not exist, for the block "text_widget" etc. * * The type of the resource is decided by the implementation. The resource * is later passed to {@link renderBlock()} by the rendering algorithm. * * @param FormView $view The view for determining the used themes. * First the themes attached directly to * the view with {@link setTheme()} are * considered, then the ones of its parent etc. * @param string[] $blockNameHierarchy The block name hierarchy, with the root block * at the beginning * @param int $hierarchyLevel The level in the hierarchy at which to start * looking. Level 0 indicates the root block, i.e. * the first element of $blockNameHierarchy. * * @return mixed The renderer resource or false, if none was found */ public function getResourceForBlockNameHierarchy(FormView $view, array $blockNameHierarchy, int $hierarchyLevel); /** * Returns the hierarchy level at which a resource can be found. * * A block hierarchy is an array which starts with the root of the hierarchy * and continues with the child of that root, the child of that child etc. * The following is an example for a block hierarchy: * * form_widget * text_widget * url_widget * * The second parameter $hierarchyLevel determines the level of the hierarchy * that should be rendered. * * If we call this method with the hierarchy level 2, the engine will first * look for a resource for block "url_widget". If such a resource exists, * the method returns 2. Otherwise it tries to find a resource for block * "text_widget" (at level 1) and, again, returns 1 if a resource was found. * The method continues to look for resources until the root level was * reached and nothing was found. In this case false is returned. * * The type of the resource is decided by the implementation. The resource * is later passed to {@link renderBlock()} by the rendering algorithm. * * @param FormView $view The view for determining the used themes. * First the themes attached directly to * the view with {@link setTheme()} are * considered, then the ones of its parent etc. * @param string[] $blockNameHierarchy The block name hierarchy, with the root block * at the beginning * @param int $hierarchyLevel The level in the hierarchy at which to start * looking. Level 0 indicates the root block, i.e. * the first element of $blockNameHierarchy. * * @return int|false */ public function getResourceHierarchyLevel(FormView $view, array $blockNameHierarchy, int $hierarchyLevel); /** * Renders a block in the given renderer resource. * * The resource can be obtained by calling {@link getResourceForBlock()} * or {@link getResourceForBlockHierarchy()}. The type of the resource is * decided by the implementation. * * @param FormView $view The view to render * @param mixed $resource The renderer resource * @param array $variables The variables to pass to the template * * @return string */ public function renderBlock(FormView $view, $resource, string $blockName, array $variables = []); } FormRendererInterface.php 0000644 00000006107 15120211544 0011467 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * Renders a form into HTML. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface FormRendererInterface { /** * Returns the engine used by this renderer. * * @return FormRendererEngineInterface */ public function getEngine(); /** * Sets the theme(s) to be used for rendering a view and its children. * * @param FormView $view The view to assign the theme(s) to * @param mixed $themes The theme(s). The type of these themes * is open to the implementation. * @param bool $useDefaultThemes If true, will use default themes specified * in the renderer */ public function setTheme(FormView $view, $themes, bool $useDefaultThemes = true); /** * Renders a named block of the form theme. * * @param FormView $view The view for which to render the block * @param array $variables The variables to pass to the template * * @return string */ public function renderBlock(FormView $view, string $blockName, array $variables = []); /** * Searches and renders a block for a given name suffix. * * The block is searched by combining the block names stored in the * form view with the given suffix. If a block name is found, that * block is rendered. * * If this method is called recursively, the block search is continued * where a block was found before. * * @param FormView $view The view for which to render the block * @param array $variables The variables to pass to the template * * @return string */ public function searchAndRenderBlock(FormView $view, string $blockNameSuffix, array $variables = []); /** * Renders a CSRF token. * * Use this helper for CSRF protection without the overhead of creating a * form. * * <input type="hidden" name="token" value="<?php $renderer->renderCsrfToken('rm_user_'.$user->getId()) ?>"> * * Check the token in your action using the same token ID. * * // $csrfProvider being an instance of Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface * if (!$csrfProvider->isCsrfTokenValid('rm_user_'.$user->getId(), $token)) { * throw new \RuntimeException('CSRF attack detected.'); * } * * @return string */ public function renderCsrfToken(string $tokenId); /** * Makes a technical name human readable. * * Sequences of underscores are replaced by single spaces. The first letter * of the resulting string is capitalized, while all other letters are * turned to lowercase. * * @return string */ public function humanize(string $text); } FormTypeExtensionInterface.php 0000644 00000002711 15120211544 0012534 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\OptionsResolver\OptionsResolver; /** * @author Bernhard Schussek <bschussek@gmail.com> */ interface FormTypeExtensionInterface { /** * Builds the form. * * This method is called after the extended type has built the form to * further modify it. * * @see FormTypeInterface::buildForm() */ public function buildForm(FormBuilderInterface $builder, array $options); /** * Builds the view. * * This method is called after the extended type has built the view to * further modify it. * * @see FormTypeInterface::buildView() */ public function buildView(FormView $view, FormInterface $form, array $options); /** * Finishes the view. * * This method is called after the extended type has finished the view to * further modify it. * * @see FormTypeInterface::finishView() */ public function finishView(FormView $view, FormInterface $form, array $options); public function configureOptions(OptionsResolver $resolver); /** * Gets the extended types. * * @return string[] */ public static function getExtendedTypes(): iterable; } FormTypeGuesserChain.php 0000644 00000005412 15120211544 0011320 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Guess\Guess; class FormTypeGuesserChain implements FormTypeGuesserInterface { private $guessers = []; /** * @param FormTypeGuesserInterface[] $guessers * * @throws UnexpectedTypeException if any guesser does not implement FormTypeGuesserInterface */ public function __construct(iterable $guessers) { $tmpGuessers = []; foreach ($guessers as $guesser) { if (!$guesser instanceof FormTypeGuesserInterface) { throw new UnexpectedTypeException($guesser, FormTypeGuesserInterface::class); } if ($guesser instanceof self) { $tmpGuessers[] = $guesser->guessers; } else { $tmpGuessers[] = [$guesser]; } } $this->guessers = array_merge([], ...$tmpGuessers); } /** * {@inheritdoc} */ public function guessType(string $class, string $property) { return $this->guess(function ($guesser) use ($class, $property) { return $guesser->guessType($class, $property); }); } /** * {@inheritdoc} */ public function guessRequired(string $class, string $property) { return $this->guess(function ($guesser) use ($class, $property) { return $guesser->guessRequired($class, $property); }); } /** * {@inheritdoc} */ public function guessMaxLength(string $class, string $property) { return $this->guess(function ($guesser) use ($class, $property) { return $guesser->guessMaxLength($class, $property); }); } /** * {@inheritdoc} */ public function guessPattern(string $class, string $property) { return $this->guess(function ($guesser) use ($class, $property) { return $guesser->guessPattern($class, $property); }); } /** * Executes a closure for each guesser and returns the best guess from the * return values. * * @param \Closure $closure The closure to execute. Accepts a guesser * as argument and should return a Guess instance */ private function guess(\Closure $closure): ?Guess { $guesses = []; foreach ($this->guessers as $guesser) { if ($guess = $closure($guesser)) { $guesses[] = $guess; } } return Guess::getBestGuess($guesses); } } FormTypeGuesserInterface.php 0000644 00000002772 15120211544 0012204 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * @author Bernhard Schussek <bschussek@gmail.com> */ interface FormTypeGuesserInterface { /** * Returns a field guess for a property name of a class. * * @return Guess\TypeGuess|null */ public function guessType(string $class, string $property); /** * Returns a guess whether a property of a class is required. * * @return Guess\ValueGuess|null */ public function guessRequired(string $class, string $property); /** * Returns a guess about the field's maximum length. * * @return Guess\ValueGuess|null */ public function guessMaxLength(string $class, string $property); /** * Returns a guess about the field's pattern. * * - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE) * - Then line below, if this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess. * Example: * You want a float greater than 5, 4.512313 is not valid but length(4.512314) > length(5) * * @see https://github.com/symfony/symfony/pull/3927 * * @return Guess\ValueGuess|null */ public function guessPattern(string $class, string $property); } FormTypeInterface.php 0000644 00000005225 15120211544 0010642 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\OptionsResolver\OptionsResolver; /** * @author Bernhard Schussek <bschussek@gmail.com> */ interface FormTypeInterface { /** * Builds the form. * * This method is called for each type in the hierarchy starting from the * top most type. Type extensions can further modify the form. * * @param array<string, mixed> $options * * @see FormTypeExtensionInterface::buildForm() */ public function buildForm(FormBuilderInterface $builder, array $options); /** * Builds the form view. * * This method is called for each type in the hierarchy starting from the * top most type. Type extensions can further modify the view. * * A view of a form is built before the views of the child forms are built. * This means that you cannot access child views in this method. If you need * to do so, move your logic to {@link finishView()} instead. * * @param array<string, mixed> $options * * @see FormTypeExtensionInterface::buildView() */ public function buildView(FormView $view, FormInterface $form, array $options); /** * Finishes the form view. * * This method gets called for each type in the hierarchy starting from the * top most type. Type extensions can further modify the view. * * When this method is called, views of the form's children have already * been built and finished and can be accessed. You should only implement * such logic in this method that actually accesses child views. For everything * else you are recommended to implement {@link buildView()} instead. * * @param array<string, mixed> $options * * @see FormTypeExtensionInterface::finishView() */ public function finishView(FormView $view, FormInterface $form, array $options); /** * Configures the options for this type. */ public function configureOptions(OptionsResolver $resolver); /** * Returns the prefix of the template block name for this type. * * The block prefix defaults to the underscored short class name with * the "Type" suffix removed (e.g. "UserProfileType" => "user_profile"). * * @return string */ public function getBlockPrefix(); /** * Returns the name of the parent type. * * @return string|null */ public function getParent(); } Forms.php 0000644 00000005350 15120211544 0006341 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * Entry point of the Form component. * * Use this class to conveniently create new form factories: * * use Symfony\Component\Form\Forms; * * $formFactory = Forms::createFormFactory(); * * $form = $formFactory->createBuilder() * ->add('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType') * ->add('lastName', 'Symfony\Component\Form\Extension\Core\Type\TextType') * ->add('age', 'Symfony\Component\Form\Extension\Core\Type\IntegerType') * ->add('color', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', [ * 'choices' => ['Red' => 'r', 'Blue' => 'b'], * ]) * ->getForm(); * * You can also add custom extensions to the form factory: * * $formFactory = Forms::createFormFactoryBuilder() * ->addExtension(new AcmeExtension()) * ->getFormFactory(); * * If you create custom form types or type extensions, it is * generally recommended to create your own extensions that lazily * load these types and type extensions. In projects where performance * does not matter that much, you can also pass them directly to the * form factory: * * $formFactory = Forms::createFormFactoryBuilder() * ->addType(new PersonType()) * ->addType(new PhoneNumberType()) * ->addTypeExtension(new FormTypeHelpTextExtension()) * ->getFormFactory(); * * Support for the Validator component is provided by ValidatorExtension. * This extension needs a validator object to function properly: * * use Symfony\Component\Validator\Validation; * use Symfony\Component\Form\Extension\Validator\ValidatorExtension; * * $validator = Validation::createValidator(); * $formFactory = Forms::createFormFactoryBuilder() * ->addExtension(new ValidatorExtension($validator)) * ->getFormFactory(); * * @author Bernhard Schussek <bschussek@gmail.com> */ final class Forms { /** * Creates a form factory with the default configuration. */ public static function createFormFactory(): FormFactoryInterface { return self::createFormFactoryBuilder()->getFormFactory(); } /** * Creates a form factory builder with the default configuration. */ public static function createFormFactoryBuilder(): FormFactoryBuilderInterface { return new FormFactoryBuilder(true); } /** * This class cannot be instantiated. */ private function __construct() { } } LICENSE 0000644 00000002054 15120211544 0005545 0 ustar 00 Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PreloadedExtension.php 0000644 00000004071 15120211544 0011046 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\InvalidArgumentException; /** * A form extension with preloaded types, type extensions and type guessers. * * @author Bernhard Schussek <bschussek@gmail.com> */ class PreloadedExtension implements FormExtensionInterface { private $types = []; private $typeExtensions = []; private $typeGuesser; /** * Creates a new preloaded extension. * * @param FormTypeInterface[] $types The types that the extension should support * @param FormTypeExtensionInterface[][] $typeExtensions The type extensions that the extension should support */ public function __construct(array $types, array $typeExtensions, FormTypeGuesserInterface $typeGuesser = null) { $this->typeExtensions = $typeExtensions; $this->typeGuesser = $typeGuesser; foreach ($types as $type) { $this->types[\get_class($type)] = $type; } } /** * {@inheritdoc} */ public function getType(string $name) { if (!isset($this->types[$name])) { throw new InvalidArgumentException(sprintf('The type "%s" cannot be loaded by this extension.', $name)); } return $this->types[$name]; } /** * {@inheritdoc} */ public function hasType(string $name) { return isset($this->types[$name]); } /** * {@inheritdoc} */ public function getTypeExtensions(string $name) { return $this->typeExtensions[$name] ?? []; } /** * {@inheritdoc} */ public function hasTypeExtensions(string $name) { return !empty($this->typeExtensions[$name]); } /** * {@inheritdoc} */ public function getTypeGuesser() { return $this->typeGuesser; } } RequestHandlerInterface.php 0000644 00000001434 15120211544 0012021 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * Submits forms if they were submitted. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface RequestHandlerInterface { /** * Submits a form if it was submitted. * * @param mixed $request The current request */ public function handleRequest(FormInterface $form, $request = null); /** * Returns true if the given data is a file upload. * * @param mixed $data The form field data * * @return bool */ public function isFileUpload($data); } ResolvedFormTypeInterface.php 0000644 00000004326 15120211544 0012347 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\OptionsResolver\OptionsResolver; /** * A wrapper for a form type and its extensions. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface ResolvedFormTypeInterface { /** * Returns the prefix of the template block name for this type. * * @return string */ public function getBlockPrefix(); /** * Returns the parent type. * * @return self|null */ public function getParent(); /** * Returns the wrapped form type. * * @return FormTypeInterface */ public function getInnerType(); /** * Returns the extensions of the wrapped form type. * * @return FormTypeExtensionInterface[] */ public function getTypeExtensions(); /** * Creates a new form builder for this type. * * @param string $name The name for the builder * * @return FormBuilderInterface */ public function createBuilder(FormFactoryInterface $factory, string $name, array $options = []); /** * Creates a new form view for a form of this type. * * @return FormView */ public function createView(FormInterface $form, FormView $parent = null); /** * Configures a form builder for the type hierarchy. */ public function buildForm(FormBuilderInterface $builder, array $options); /** * Configures a form view for the type hierarchy. * * It is called before the children of the view are built. */ public function buildView(FormView $view, FormInterface $form, array $options); /** * Finishes a form view for the type hierarchy. * * It is called after the children of the view have been built. */ public function finishView(FormView $view, FormInterface $form, array $options); /** * Returns the configured options resolver used for this type. * * @return OptionsResolver */ public function getOptionsResolver(); } composer.json 0000644 00000004634 15120211544 0007270 0 ustar 00 { "name": "symfony/form", "type": "library", "description": "Allows to easily create, process and reuse HTML forms", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1|^3", "symfony/event-dispatcher": "^4.4|^5.0|^6.0", "symfony/options-resolver": "^5.1|^6.0", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-icu": "^1.21", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php80": "^1.16", "symfony/polyfill-php81": "^1.23", "symfony/property-access": "^5.0.8|^6.0", "symfony/service-contracts": "^1.1|^2|^3" }, "require-dev": { "doctrine/collections": "^1.0|^2.0", "symfony/validator": "^4.4.17|^5.1.9|^6.0", "symfony/dependency-injection": "^4.4|^5.0|^6.0", "symfony/expression-language": "^4.4|^5.0|^6.0", "symfony/config": "^4.4|^5.0|^6.0", "symfony/console": "^5.4|^6.0", "symfony/http-foundation": "^4.4|^5.0|^6.0", "symfony/http-kernel": "^4.4|^5.0|^6.0", "symfony/intl": "^4.4|^5.0|^6.0", "symfony/security-csrf": "^4.4|^5.0|^6.0", "symfony/translation": "^4.4|^5.0|^6.0", "symfony/var-dumper": "^4.4|^5.0|^6.0", "symfony/uid": "^5.1|^6.0" }, "conflict": { "symfony/console": "<4.4", "symfony/dependency-injection": "<4.4", "symfony/doctrine-bridge": "<5.4.21|>=6,<6.2.7", "symfony/error-handler": "<4.4.5", "symfony/framework-bundle": "<4.4", "symfony/http-kernel": "<4.4", "symfony/translation": "<4.4", "symfony/translation-contracts": "<1.1.7", "symfony/twig-bridge": "<5.4.21|>=6,<6.2.7" }, "suggest": { "symfony/validator": "For form validation.", "symfony/security-csrf": "For protecting forms against CSRF attacks.", "symfony/twig-bridge": "For templating with Twig." }, "autoload": { "psr-4": { "Symfony\\Component\\Form\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "minimum-stability": "dev" } Guess/Guess.php 0000644 00000005604 15120211544 0007431 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Guess; use Symfony\Component\Form\Exception\InvalidArgumentException; /** * Base class for guesses made by TypeGuesserInterface implementation. * * Each instance contains a confidence value about the correctness of the guess. * Thus an instance with confidence HIGH_CONFIDENCE is more likely to be * correct than an instance with confidence LOW_CONFIDENCE. * * @author Bernhard Schussek <bschussek@gmail.com> */ abstract class Guess { /** * Marks an instance with a value that is extremely likely to be correct. */ public const VERY_HIGH_CONFIDENCE = 3; /** * Marks an instance with a value that is very likely to be correct. */ public const HIGH_CONFIDENCE = 2; /** * Marks an instance with a value that is likely to be correct. */ public const MEDIUM_CONFIDENCE = 1; /** * Marks an instance with a value that may be correct. */ public const LOW_CONFIDENCE = 0; /** * The confidence about the correctness of the value. * * One of VERY_HIGH_CONFIDENCE, HIGH_CONFIDENCE, MEDIUM_CONFIDENCE * and LOW_CONFIDENCE. * * @var int */ private $confidence; /** * Returns the guess most likely to be correct from a list of guesses. * * If there are multiple guesses with the same, highest confidence, the * returned guess is any of them. * * @param static[] $guesses An array of guesses * * @return static|null */ public static function getBestGuess(array $guesses) { $result = null; $maxConfidence = -1; foreach ($guesses as $guess) { if ($maxConfidence < $confidence = $guess->getConfidence()) { $maxConfidence = $confidence; $result = $guess; } } return $result; } /** * @throws InvalidArgumentException if the given value of confidence is unknown */ public function __construct(int $confidence) { if (self::VERY_HIGH_CONFIDENCE !== $confidence && self::HIGH_CONFIDENCE !== $confidence && self::MEDIUM_CONFIDENCE !== $confidence && self::LOW_CONFIDENCE !== $confidence) { throw new InvalidArgumentException('The confidence should be one of the constants defined in Guess.'); } $this->confidence = $confidence; } /** * Returns the confidence that the guessed value is correct. * * @return int One of the constants VERY_HIGH_CONFIDENCE, HIGH_CONFIDENCE, * MEDIUM_CONFIDENCE and LOW_CONFIDENCE */ public function getConfidence() { return $this->confidence; } } Guess/TypeGuess.php 0000644 00000002546 15120211544 0010275 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Guess; /** * Contains a guessed class name and a list of options for creating an instance * of that class. * * @author Bernhard Schussek <bschussek@gmail.com> */ class TypeGuess extends Guess { private $type; private $options; /** * @param string $type The guessed field type * @param array $options The options for creating instances of the * guessed class * @param int $confidence The confidence that the guessed class name * is correct */ public function __construct(string $type, array $options, int $confidence) { parent::__construct($confidence); $this->type = $type; $this->options = $options; } /** * Returns the guessed field type. * * @return string */ public function getType() { return $this->type; } /** * Returns the guessed options for creating instances of the guessed type. * * @return array */ public function getOptions() { return $this->options; } } Guess/ValueGuess.php 0000644 00000001704 15120211544 0010423 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Guess; /** * Contains a guessed value. * * @author Bernhard Schussek <bschussek@gmail.com> */ class ValueGuess extends Guess { private $value; /** * @param string|int|bool|null $value The guessed value * @param int $confidence The confidence that the guessed class name * is correct */ public function __construct($value, int $confidence) { parent::__construct($confidence); $this->value = $value; } /** * Returns the guessed value. * * @return string|int|bool|null */ public function getValue() { return $this->value; } } ResolvedFormTypeFactoryInterface.php 0000644 00000002253 15120211544 0013674 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * Creates ResolvedFormTypeInterface instances. * * This interface allows you to use your custom ResolvedFormTypeInterface * implementation, within which you can customize the concrete FormBuilderInterface * implementations or FormView subclasses that are used by the framework. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface ResolvedFormTypeFactoryInterface { /** * Resolves a form type. * * @param FormTypeExtensionInterface[] $typeExtensions * * @return ResolvedFormTypeInterface * * @throws Exception\UnexpectedTypeException if the types parent {@link FormTypeInterface::getParent()} is not a string * @throws Exception\InvalidArgumentException if the types parent cannot be retrieved from any extension */ public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null); } ReversedTransformer.php 0000644 00000002040 15120211544 0011246 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * Reverses a transformer. * * When the transform() method is called, the reversed transformer's * reverseTransform() method is called and vice versa. * * @author Bernhard Schussek <bschussek@gmail.com> */ class ReversedTransformer implements DataTransformerInterface { protected $reversedTransformer; public function __construct(DataTransformerInterface $reversedTransformer) { $this->reversedTransformer = $reversedTransformer; } /** * {@inheritdoc} */ public function transform($value) { return $this->reversedTransformer->reverseTransform($value); } /** * {@inheritdoc} */ public function reverseTransform($value) { return $this->reversedTransformer->transform($value); } } Resources/config/validation.xml 0000644 00000001144 15120211544 0012632 0 ustar 00 <?xml version="1.0" ?> <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> <class name="Symfony\Component\Form\Form"> <constraint name="Symfony\Component\Form\Extension\Validator\Constraints\Form" /> <constraint name="Symfony\Component\Validator\Constraints\Traverse"> <option name="traverse">false</option> </constraint> </class> </constraint-mapping> Resources/translations/validators.lv.xlf 0000644 00000015236 15120211544 0014544 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Šajā veidlapā nevajadzētu būt papildus ievades laukiem.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Augšupielādētā faila izmērs bija par lielu. Lūdzu mēģiniet augšupielādēt mazāka izmēra failu.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>Dotais CSRF talons nav derīgs. Lūdzu mēģiniet vēlreiz iesniegt veidlapu.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Šī vertība nav derīga HTML5 krāsa.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Lūdzu, ievadiet derīgu dzimšanas datumu.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Iezīmētā izvēle nav derīga.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Kolekcija nav derīga.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Lūdzu, izvēlieties derīgu krāsu.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Lūdzu, izvēlieties derīgu valsti.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Lūdzu, izvēlieties derīgu valūtu.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Lūdzu, izvēlieties derīgu datumu intervālu.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Lūdzu, ievadiet derīgu datumu un laiku.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Lūdzu, ievadiet derīgu datumu.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Lūdzu, izvēlieties derīgu failu.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Slēptā lauka vērtība ir nederīga.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Lūdzu, ievadiet veselu skaitli.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Lūdzu, izvēlieties derīgu valodu.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Lūdzu, izvēlieties derīgu lokalizāciju.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Lūdzu, ievadiet derīgu naudas lielumu.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Lūdzu, ievadiet skaitli.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Parole ir nederīga.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Lūdzu, ievadiet procentuālo lielumu.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Vērtības nesakrīt.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Lūdzu, ievadiet derīgu laiku.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Lūdzu, izvēlieties derīgu laika zonu.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Lūdzu, ievadiet derīgu URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Lūdzu, ievadiet derīgu meklēšanas nosacījumu.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Lūdzu, ievadiet derīgu tālruņa numuru.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Izvēles rūtiņai ir nederīga vērtība.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Lūdzu, ievadiet derīgu e-pasta adresi.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Lūdzu, izvēlieties derīgu opciju.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Lūdzu, izvēlieties derīgu diapazonu.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Lūdzu, ievadiet derīgu nedēļu.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.mn.xlf 0000644 00000016147 15120211544 0014537 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Форм нэмэлт талбар багтаах боломжгүй.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Upload хийсэн файл хэтэрхий том байна. Бага хэмжээтэй файл оруулна уу.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF token буруу байна. Формоо дахин илгээнэ үү.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Энэ утга зөв HTML5 өнгө биш байна.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Зөв төрсөн он сар оруулна уу.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Сонгосон утга буруу байна.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Цуглуулга буруу байна.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Үнэн зөв өнгө сонгоно уу.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Үнэн зөв улс сонгоно уу.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Үнэн зөв мөнгөн тэмдэгт сонгоно уу.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Үнэн зөв цагын зай сонгоно уу.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Үнэн зөв он цаг оруулна уу.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Үнэн зөв он цаг өдөр оруулна уу.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Үнэн зөв файл сонгоно уу.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Нууц талбарын утга буруу байна.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Бүхэл тоо оруулна уу.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Үнэн зөв хэл сонгоно уу.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Үнэн зөв бүс сонгоно уу.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Үнэн зөв мөнгөний хэмжээ сонгоно уу.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Тоо оруулна уу.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Нууц үг буруу байна.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Хувь утга оруулна уу.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Утга хоорондоо таарахгүй байна.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Үнэн зөв цаг оруулна уу.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Үнэн зөв цагын бүс оруулна уу.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Үнэн зөв URL оруулна уу.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Үнэн зөв хайх утга оруулна уу.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Үнэн зөв утасны дугаар оруулна уу.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Сонгох хайрцаг буруу утгатай байна.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Үнэн зөв и-мэйл хаяг оруулна уу.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Үнэн зөв сонголт сонгоно уу.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Үнэн зөв хязгаарын утга сонгоно уу.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Үнэн зөв долоо хоног сонгоно уу.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.my.xlf 0000644 00000022441 15120211544 0014544 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>ဤ ဖောင်သည် field အပိုများ မပါ၀င်သင့်ပါ။</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Upload တင်သောဖိုင်သည်အလွန်ကြီးလွန်းသည်။ ကျေးဇူးပြု၍ သေးငယ်သည့်ဖိုင်ကိုတင်ရန်ကြိုးစားပါ။</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>သင့်လျှော်သော် CSRF တိုကင် မဟုတ်ပါ။ ကျေးဇူးပြု၍ဖောင်ကိုပြန်တင်ပါ။</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>ဤတန်ဖိုးသည် သင့်လျှော်သော် HTML5 အရောင်မဟုတ်ပါ။</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သောမွေးနေ့ကိုထည့်ပါ။</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>သင့် ရွေးချယ်မှုသည်မမှန်ကန်ပါ။</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>ဤ collection သည်သင့်လျှော်သော် collection မဟုတ်ပါ။</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သောအရောင်ကိုရွေးပါ။</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သောနိုင်ငံကိုရွေးပါ။</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သောငွေကြေးကိုရွေးပါ။</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သောနေ ရက်စွဲကိုရွေးပါ။</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သောနေ ရက်စွဲနှင့်အချိန် ကိုထည့်ပါ။</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သောနေ ရက်စွဲကိုထည့်ပါ။</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သောနေ ဖိုင်ကိုရွေးချယ်ပါ။</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>မသင့် လျှော်သော် hidden field ဖြစ်နေသည်။</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>ကျေးဇူးပြု၍ Integer တန်ဖိုးသာထည့်ပါ။</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သော ဘာသာစကားကိုရွေးချယ်ပါ။</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သော locale ကိုရွေးချယ်ပါ။</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သော ပိုက်ဆံပမာဏ ကိုထည့်ပါ။</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သော နံပါတ် ကိုရွေးချယ်ပါ။</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>မှန်ကန်သောစကား၀ှက်မဟုတ်ပါ။</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>ကျေးဇူးပြု၍ ရာခိုင်နှုန်းတန်ဖိုးထည့်ပါ။</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>တန်ဖိုးများကိုက်ညီမှုမရှိပါ။</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သောအချိန်ကိုထည့်ပါ။</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သောအချိန်ဇုန်ကိုရွေးပါ။</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>ကျေးဇူးပြု၍ သင့်လျှော်သော် URL ကိုရွေးပါ။</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>ကျေးဇူးပြု၍ သင့် လျှော်သော်ရှာဖွေမှု term များထည့်ပါ။</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>ကျေးဇူးပြု၍ သင့် လျှော်သော်ရှာဖွေမှု ဖုန်းနံပါတ်ထည့်ပါ။</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Checkbox တန်ဖိုးသည် မှန်ကန်မှုမရှိပါ။</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သော် email လိပ်စာထည့်ပါ။</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သော် ရွေးချယ်မှု ကိုရွေးပါ။</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သော အပိုင်းအခြား ကိုရွေးပါ။</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>ကျေးဇူးပြု၍ မှန်ကန်သောရက်သတ္တပတ်ကိုထည့်ပါ။</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.nb.xlf 0000644 00000014673 15120211544 0014526 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Feltgruppen må ikke inneholde ekstra felter.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Den opplastede filen var for stor. Vennligst last opp en mindre fil.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid.</source> <target>CSRF nøkkelen er ugyldig.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Denne verdien er ikke en gyldig HTML5-farge.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Vennligst oppgi gyldig fødselsdato.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Det valgte valget er ugyldig.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Samlingen er ugyldig.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Velg en gyldig farge.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Vennligst velg et gyldig land.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Vennligst velg en gyldig valuta.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Vennligst velg et gyldig datointervall.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Vennligst angi en gyldig dato og tid.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Vennligst oppgi en gyldig dato.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Vennligst velg en gyldig fil.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Det skjulte feltet er ugyldig.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Vennligst skriv inn et heltall.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Vennligst velg et gyldig språk.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Vennligst velg et gyldig sted.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Vennligst angi et gyldig pengebeløp.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Vennligst skriv inn et nummer.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Passordet er ugyldig.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Vennligst angi en prosentverdi.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Verdiene stemmer ikke overens.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Vennligst angi et gyldig tidspunkt.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Vennligst velg en gyldig tidssone.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Vennligst skriv inn en gyldig URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Vennligst angi et gyldig søketerm.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Vennligst oppgi et gyldig telefonnummer.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Avkrysningsboksen har en ugyldig verdi.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Vennligst skriv inn en gyldig e-post adresse.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Vennligst velg et gyldig alternativ.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Vennligst velg et gyldig område.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Vennligst skriv inn en gyldig uke.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.nl.xlf 0000644 00000014543 15120211544 0014534 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Dit formulier mag geen extra velden bevatten.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Het geüploade bestand is te groot. Probeer een kleiner bestand te uploaden.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>De CSRF-token is ongeldig. Probeer het formulier opnieuw te versturen.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Dit is geen geldige HTML5 kleur.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Vul een geldige geboortedatum in.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Deze keuze is ongeldig.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Deze collectie is ongeldig.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Kies een geldige kleur.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Kies een geldige landnaam.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Kies een geldige valuta.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Kies een geldig tijdinterval.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Vul een geldige datum en tijd in.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Vul een geldige datum in.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Kies een geldig bestand.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Het verborgen veld is incorrect.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Vul een geldig getal in.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Kies een geldige taal.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Kies een geldige locale.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Vul een geldig bedrag in.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Vul een geldig getal in.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Het wachtwoord is incorrect.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Vul een geldig percentage in.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>De waardes komen niet overeen.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Vul een geldige tijd in.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Vul een geldige tijdzone in.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Vul een geldige URL in.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Vul een geldige zoekterm in.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Vul een geldig telefoonnummer in.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>De checkbox heeft een incorrecte waarde.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Vul een geldig e-mailadres in.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Kies een geldige optie.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Kies een geldig bereik.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Vul een geldige week in.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.nn.xlf 0000644 00000014377 15120211544 0014543 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Feltgruppa kan ikkje innehalde ekstra felt.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Fila du lasta opp var for stor. Last opp ei mindre fil.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid.</source> <target>CSRF-nøkkelen er ikkje gyldig.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Verdien er ikkje ein gyldig HTML5-farge.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Gje opp ein gyldig fødselsdato.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Valget du gjorde er ikkje gyldig.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Samlinga er ikkje gyldig.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Gje opp ein gyldig farge.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Gje opp eit gyldig land.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Gje opp ein gyldig valuta.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Gje opp eit gyldig datointervall.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Gje opp ein gyldig dato og tid.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Gje opp ein gyldig dato.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Velg ei gyldig fil.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Det skjulte feltet er ikkje gyldig.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Gje opp eit heiltal.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Gje opp eit gyldig språk.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Gje opp eit gyldig locale.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Gje opp ein gyldig sum pengar.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Gje opp eit nummer.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Passordet er ikkje gyldig.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Gje opp ein prosentverdi.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Verdiane er ikkje eins.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Gje opp ei gyldig tid.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Gje opp ei gyldig tidssone.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Gje opp ein gyldig URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Gje opp gyldige søkjeord.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Gje opp eit gyldig telefonnummer.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Sjekkboksen har ein ugyldig verdi.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Gje opp ei gyldig e-postadresse.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Velg eit gyldig vilkår.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Velg eit gyldig spenn.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Gje opp ei gyldig veke.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.no.xlf 0000644 00000014673 15120211544 0014543 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Feltgruppen må ikke inneholde ekstra felter.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Den opplastede filen var for stor. Vennligst last opp en mindre fil.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid.</source> <target>CSRF nøkkelen er ugyldig.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Denne verdien er ikke en gyldig HTML5-farge.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Vennligst oppgi gyldig fødselsdato.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Det valgte valget er ugyldig.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Samlingen er ugyldig.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Velg en gyldig farge.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Vennligst velg et gyldig land.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Vennligst velg en gyldig valuta.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Vennligst velg et gyldig datointervall.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Vennligst angi en gyldig dato og tid.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Vennligst oppgi en gyldig dato.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Vennligst velg en gyldig fil.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Det skjulte feltet er ugyldig.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Vennligst skriv inn et heltall.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Vennligst velg et gyldig språk.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Vennligst velg et gyldig sted.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Vennligst angi et gyldig pengebeløp.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Vennligst skriv inn et nummer.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Passordet er ugyldig.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Vennligst angi en prosentverdi.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Verdiene stemmer ikke overens.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Vennligst angi et gyldig tidspunkt.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Vennligst velg en gyldig tidssone.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Vennligst skriv inn en gyldig URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Vennligst angi et gyldig søketerm.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Vennligst oppgi et gyldig telefonnummer.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Avkrysningsboksen har en ugyldig verdi.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Vennligst skriv inn en gyldig e-post adresse.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Vennligst velg et gyldig alternativ.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Vennligst velg et gyldig område.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Vennligst skriv inn en gyldig uke.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.pl.xlf 0000644 00000015332 15120211544 0014533 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Ten formularz nie powinien zawierać dodatkowych pól.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Wgrany plik był za duży. Proszę spróbować wgrać mniejszy plik.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>Token CSRF jest nieprawidłowy. Proszę spróbować wysłać formularz ponownie.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Ta wartość nie jest prawidłowym kolorem HTML5.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Proszę wprowadzić prawidłową datę urodzenia.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Wybrana wartość jest nieprawidłowa.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Zbiór jest nieprawidłowy.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Proszę wybrać prawidłowy kolor.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Proszę wybrać prawidłowy kraj.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Proszę wybrać prawidłową walutę.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Proszę wybrać prawidłowy przedział czasowy.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Proszę wprowadzić prawidłową datę i czas.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Proszę wprowadzić prawidłową datę.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Proszę wybrać prawidłowy plik.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Ukryte pole jest nieprawidłowe.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Proszę wprowadzić liczbę całkowitą.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Proszę wybrać prawidłowy język.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Proszę wybrać prawidłową lokalizację.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Proszę wybrać prawidłową ilość pieniędzy.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Proszę wprowadzić liczbę.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Hasło jest nieprawidłowe.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Proszę wprowadzić wartość procentową.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Wartości się nie zgadzają.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Proszę wprowadzić prawidłowy czas.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Proszę wybrać prawidłową strefę czasową.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Proszę wprowadzić prawidłowy adres URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Proszę wprowadzić prawidłowy termin wyszukiwania.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Proszę wprowadzić prawidłowy numer telefonu.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Pole wyboru posiada nieprawidłową wartość.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Proszę wprowadzić prawidłowy adres email.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Proszę wybrać prawidłową opcję.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Proszę wybrać prawidłowy zakres.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Proszę wybrać prawidłowy tydzień.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.pt.xlf 0000644 00000015330 15120211544 0014541 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Este formulário não deveria possuir mais campos.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>O ficheiro enviado é muito grande. Por favor, tente enviar um ficheiro menor.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>O token CSRF está inválido. Por favor, tente enviar o formulário novamente.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Este valor não é uma cor HTML5 válida.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Por favor, informe uma data de nascimento válida.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>A escolha seleccionada é inválida.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>A coleção é inválida.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Por favor, selecione uma cor válida.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Por favor, selecione um país válido.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Por favor, selecione uma moeda válida.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Por favor, escolha um intervalo de datas válido.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Por favor, informe uma data e horário válidos.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Por favor, informe uma data válida.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Por favor, selecione um ficheiro válido.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>O campo oculto é inválido.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Por favor, informe um inteiro.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Por favor selecione um idioma válido.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Por favor, selecione um locale válido.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Por favor, informe um valor monetário válido.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Por favor, informe um número.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>A palavra-passe é inválida.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Por favor, informe um valor percentual.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Os valores não correspondem.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Por favor, informe uma hora válida.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Por favor, selecione um fuso horário válido.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Por favor, informe uma URL válida.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Por favor, informe um termo de busca válido.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Por favor, infome um número de telefone válido.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>O checkbox possui um valor inválido.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Por favor, informe um endereço de email válido.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Por favor, selecione uma opção válida.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Por favor, selecione um intervalo válido.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Por favor, selecione uma semana válida.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.pt_BR.xlf 0000644 00000015332 15120211544 0015126 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Este formulário não deve conter campos adicionais.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>O arquivo enviado é muito grande. Por favor, tente enviar um arquivo menor.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>O token CSRF é inválido. Por favor, tente reenviar o formulário.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Este valor não é uma cor HTML5 válida.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Por favor, informe uma data de nascimento válida.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>A escolha selecionada é inválida.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>A coleção é inválida.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Por favor, selecione uma cor válida.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Por favor, selecione um país válido.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Por favor, selecione uma moeda válida.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Por favor, escolha um intervalo de datas válido.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Por favor, informe uma data e horário válidos.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Por favor, informe uma data válida.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Por favor, selecione um arquivo válido.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>O campo oculto é inválido.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Por favor, informe um número inteiro.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Por favor, selecione um idioma válido.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Por favor, selecione uma configuração de local válida.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Por favor, informe um valor monetário válido.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Por favor, informe um número.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>A senha é inválida.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Por favor, informe um valor percentual.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Os valores não conferem.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Por favor, informe um horário válido.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Por favor, selecione um fuso horário válido.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Por favor, informe uma URL válida.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Por favor, informe um termo de busca válido.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Por favor, informe um telefone válido.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>A caixa de seleção possui um valor inválido.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Por favor, informe um endereço de e-mail válido.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Por favor, selecione uma opção válida.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Por favor, selecione um intervalo válido.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Por favor, informe uma semana válida.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.ro.xlf 0000644 00000015566 15120211544 0014551 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Acest formular nu ar trebui să conțină câmpuri suplimentare.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Fișierul încărcat a fost prea mare. Vă rugăm sa încărcați un fișier mai mic.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>Token-ul CSRF este invalid. Vă rugăm să retrimiteți formularul.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Această valoare nu este un cod de culoare HTML5 valid.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Vă rugăm să introduceți o dată de naștere validă.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Valoarea selectată este invalidă.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Colecția nu este validă.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Vă rugăm să selectați o culoare validă.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Vă rugăm să selectați o țară validă.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Vă rugăm să selectați o monedă validă.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Vă rugăm să selectați un interval de zile valid.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Vă rugăm să introduceți o dată și o oră validă.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Vă rugăm să introduceți o dată validă.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Vă rugăm să selectați un fișier valid.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Câmpul ascuns este invalid.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Vă rugăm să introduceți un număr întreg.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Vă rugăm să selectați o limbă validă.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Vă rugăm să selectați o setare locală validă.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Vă rugăm să introduceți o valoare monetară corectă.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Vă rugăm să introduceți un număr.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Parola nu este validă.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Vă rugăm să introduceți o valoare procentuală.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Valorile nu coincid.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Vă rugăm să introduceți o oră validă.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Vă rugăm să selectați un fus orar valid.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Vă rugăm să introduceți un URL valid.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Vă rugăm să introduceți un termen de căutare valid.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Vă rugăm să introduceți un număr de telefon valid.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Bifa nu are o valoare validă.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Vă rugăm să introduceți o adresă de email validă.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Vă rugăm să selectați o opțiune validă.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Vă rugăm să selectați un interval valid.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Vă rugăm să introduceți o săptămână validă.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.ru.xlf 0000644 00000017607 15120211544 0014555 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Эта форма не должна содержать дополнительных полей.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Загруженный файл слишком большой. Пожалуйста, попробуйте загрузить файл меньшего размера.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF значение недопустимо. Пожалуйста, попробуйте повторить отправку формы.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Значение не является допустимым HTML5 цветом.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Пожалуйста, введите действительную дату рождения.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Выбранный вариант недопустим.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Коллекция недопустима.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Пожалуйста, выберите допустимый цвет.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Пожалуйста, выберите действительную страну.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Пожалуйста, выберите действительную валюту.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Пожалуйста, выберите действительный период.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Пожалуйста, введите действительные дату и время.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Пожалуйста, введите действительную дату.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Пожалуйста, выберите допустимый файл.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Значение скрытого поля недопустимо.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Пожалуйста, введите целое число.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Пожалуйста, выберите допустимый язык.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Пожалуйста, выберите допустимую локаль.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Пожалуйста, введите допустимое количество денег.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Пожалуйста, введите номер.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Пароль недействителен.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Пожалуйста, введите процентное значение.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Значения не совпадают.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Пожалуйста, введите действительное время.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Пожалуйста, выберите действительный часовой пояс.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Пожалуйста, введите действительный URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Пожалуйста, введите действительный поисковый запрос.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Пожалуйста, введите действительный номер телефона.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Флажок имеет недопустимое значение.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Пожалуйста, введите допустимый email адрес.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Пожалуйста, выберите допустимый вариант.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Пожалуйста, выберите допустимый диапазон.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Пожалуйста, введите действительную неделю.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.sk.xlf 0000644 00000015043 15120211544 0014534 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Polia by nemali obsahovať ďalšie prvky.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Odoslaný súbor je príliš veľký. Prosím odošlite súbor s menšou veľkosťou.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF token je neplatný. Prosím skúste znovu odoslať formulár.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Táto hodnota nie je platná HTML5 farba.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Prosím zadajte platný dátum narodenia.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Vybraná možnosť je neplatná.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Kolekcia je neplatná.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Prosím vyberte platnú farbu.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Prosím vyberte platnú krajinu.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Prosím vyberte platnú menu.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Prosím vyberte platný rozsah dát.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Prosím zadajte platný dátum a čas.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Prosím zadajte platný dátum.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Prosím vyberte platný súbor.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Skryté pole je neplatné.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Prosím zadajte celé číslo.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Prosím vyberte platný jazyk.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Prosím vyberte platné miestne nastavenia.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Prosím zadajte platnú čiastku.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Prosím zadajte číslo.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Heslo je neprávne.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Prosím zadajte percentuálnu hodnotu.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Hodnoty nie sú zhodné.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Prosím zadajte platný čas.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Prosím vyberte platné časové pásmo.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Prosím zadajte platnú URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Prosím zadajte platný vyhľadávací výraz.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Prosím zadajte platné telefónne číslo.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Zaškrtávacie políčko má neplatnú hodnotu.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Prosím zadajte platnú emailovú adresu.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Prosím vyberte platnú možnosť.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Prosím vyberte platný rozsah.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Prosím zadajte platný týždeň.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.sl.xlf 0000644 00000015054 15120211544 0014537 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Ta obrazec ne sme vsebovati dodatnih polj.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Naložena datoteka je prevelika. Prosimo, poizkusite naložiti manjšo.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF vrednost je napačna. Prosimo, ponovno pošljite obrazec.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Ta vrednost ni veljavna barva HTML5.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Prosimo, vnesite veljaven rojstni datum.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Izbira ni veljavna.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Zbirka ni veljavna.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Prosimo, izberite veljavno barvo.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Prosimo, izberite veljavno državo.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Prosimo, izberite veljavno valuto.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Prosimo, izberite veljaven datumski interval.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Prosimo, vnesite veljaven datum in čas.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Prosimo, izberite veljaven datum.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Prosimo, izberite veljavno datoteko.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Skrito polje ni veljavno.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Prosimo, vnesite celo število.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Prosimo, izberite veljaven jezik.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Prosimo, izberite veljavne področne nastavitve.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Prosimo, vnesite veljaven denarni znesek.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Prosimo, vnesite številko.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Geslo ni veljavno.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Prosimo, vnesite odstotno vrednost.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Vrednosti se ne ujemajo.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Prosimo, vnesite veljaven čas.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Prosimo, izberite veljaven časovni pas.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Prosimo, vnesite veljaven URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Prosimo, vnesite veljaven iskalni izraz.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Prosimo, podajte veljavno telefonsko številko.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Potrditveno polje vsebuje neveljavno vrednost.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Prosimo, vnesite veljaven e-poštni naslov.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Prosimo, izberite veljavno možnost.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Prosimo, izberite veljaven obseg.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Prosimo, vnesite veljaven teden.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.sq.xlf 0000644 00000015573 15120211544 0014552 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Kjo formë nuk duhet të përmbajë fusha shtesë.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Skedari i ngarkuar ishte shumë i madh. Ju lutemi provoni të ngarkoni një skedar më të vogël.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>Vlera CSRF është e pavlefshme. Ju lutemi provoni të ridërgoni formën.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Kjo vlerë nuk është një ngjyrë e vlefshme HTML5.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Ju lutemi shkruani një datëlindje të vlefshme.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Opsioni i zgjedhur është i pavlefshëm.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Koleksioni është i pavlefshëm.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Ju lutemi zgjidhni një ngjyrë të vlefshme.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Ju lutemi zgjidhni një shtet të vlefshëm.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Ju lutemi zgjidhni një monedhë të vlefshme.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Ju lutemi zgjidhni një interval të vlefshëm të datës.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Ju lutemi shkruani një datë dhe orë të vlefshme.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Ju lutemi shkruani një datë të vlefshme.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Ju lutemi zgjidhni një skedar të vlefshëm.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Fusha e fshehur është e pavlefshme.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Ju lutemi shkruani një numër të plotë.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Please select a valid language.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Ju lutemi zgjidhni një lokale të vlefshme.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Ju lutemi shkruani një shumë të vlefshme parash.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Ju lutemi shkruani një numër.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Fjalëkalimi është i pavlefshëm.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Ju lutemi shkruani një vlerë përqindjeje.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Vlerat nuk përputhen.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Ju lutemi shkruani një kohë të vlefshme.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Ju lutemi zgjidhni një zonë kohore të vlefshme.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Ju lutemi shkruani një URL të vlefshme.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Ju lutemi shkruani një term të vlefshëm kërkimi.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Ju lutemi jepni një numër telefoni të vlefshëm.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Kutia e zgjedhjes ka një vlerë të pavlefshme.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Ju lutemi shkruani një adresë të vlefshme emaili.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Ju lutemi zgjidhni një opsion të vlefshëm.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Ju lutemi zgjidhni një diapazon të vlefshëm.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Ju lutemi shkruani një javë të vlefshme.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.sr_Cyrl.xlf 0000644 00000016734 15120211544 0015544 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Овај формулар не треба да садржи додатна поља.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Отпремљена датотека је била превелика. Молим покушајте отпремање мање датотеке.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF вредност није исправна. Покушајте поново.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Ова вредност није исправна HTML5 боја.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Молим упишите исправан датум рођења.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Одабрани избор није исправан.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Ова колекција није исправна.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Молим изаберите исправну боју.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Молим изаберите исправну државу.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Молим изаберите исправну валуту.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Молим изаберите исправан датумски интервал.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Молим упишите исправан датум и време.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Молим упишите исправан датум.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Молим изаберите исправну датотеку.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Скривено поље није исправно.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Молим упишите цео број (integer).</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Молим изаберите исправан језик.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Молим изаберите исправну локализацију.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Молим упишите исправну количину новца.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Молим упишите број.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Ова лозинка није исправна.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Молим упишите процентуалну вредност.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Дате вредности се не поклапају.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Молим упишите исправно време.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Молим изаберите исправну временску зону.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Молим упишите исправан URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Молим упишите исправан термин за претрагу.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Молим наведите исправан број телефона.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Поље за потврду садржи неисправну вредност.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Молим упишите исправну email адресу.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Молим изаберите исправну опцију.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Молим изаберите исправан опсег.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Молим упишите исправну седмицу.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.sr_Latn.xlf 0000644 00000015041 15120211544 0015517 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Ovaj formular ne treba da sadrži dodatna polja.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Otpremljena datoteka je bila prevelika. Molim pokušajte otpremanje manje datoteke.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF vrednost nije ispravna. Pokušajte ponovo.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Ova vrednost nije ispravna HTML5 boja.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Molim upišite ispravan datum rođenja.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Odabrani izbor nije ispravan.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Ova kolekcija nije ispravna.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Molim izaberite ispravnu boju.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Molim izaberite ispravnu državu.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Molim izaberite ispravnu valutu.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Molim izaberite ispravan datumski interval.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Molim upišite ispravan datum i vreme.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Molim upišite ispravan datum.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Molim izaberite ispravnu datoteku.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Skriveno polje nije ispravno.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Molim upišite ceo broj (integer).</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Molim izaberite ispravan jezik.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Molim izaberite ispravnu lokalizaciju.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Molim upišite ispravnu količinu novca.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Molim upišite broj.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Ova lozinka nije ispravna.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Molim upišite procentualnu vrednost.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Date vrednosti se ne poklapaju.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Molim upišite ispravno vreme.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Molim izaberite ispravnu vremensku zonu.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Molim upišite ispravan URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Molim upišite ispravan termin za pretragu.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Molim navedite ispravan broj telefona.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Polje za potvrdu sadrži neispravnu vrednost.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Molim upišite ispravnu email adresu.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Molim izaberite ispravnu opciju.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Molim izaberite ispravan opseg.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Molim upišite ispravnu sedmicu.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.sv.xlf 0000644 00000014424 15120211544 0014551 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Formuläret kan inte innehålla extra fält.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Den uppladdade filen var för stor. Försök ladda upp en mindre fil.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF-elementet är inte giltigt. Försök att skicka formuläret igen.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Värdet är inte en giltig HTML5-färg.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Ange ett giltigt födelsedatum.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Det valda alternativet är ogiltigt.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Den här samlingen är ogiltig.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Välj en giltig färg.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Välj ett land.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Välj en valuta.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Välj ett giltigt datumintervall.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Ange ett giltigt datum och tid.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Ange ett giltigt datum.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Välj en fil.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Det dolda fältet är ogiltigt.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Ange ett heltal.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Välj språk.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Välj plats.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Ange en giltig summa pengar.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Ange en siffra.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Lösenordet är ogiltigt.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Ange ett procentuellt värde.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>De angivna värdena stämmer inte överens.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Ange en giltig tid.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Välj en tidszon.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Ange en giltig URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Ange ett giltigt sökbegrepp.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Ange ett giltigt telefonnummer.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Kryssrutan har ett ogiltigt värde.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Ange en giltig e-postadress.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Välj ett alternativ.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Välj ett intervall.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Ange en giltig vecka.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.th.xlf 0000644 00000020105 15120211544 0014525 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="th" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>ฟอร์มนี้ไม่ควรมี extra fields</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>ไฟล์ที่อัพโหลดมีขนาดใหญ่เกินไป กรุณาลองอัพโหลดใหม่อีกครั้งด้วยไฟล์ที่มีขนาดเล็กลง</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF token ไม่ถูกต้อง กรุณาลองส่งแบบฟอร์มใหม่</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>ค่านี้ไม่ใช่ค่าที่ถูกต้องของค่าสี HTML5</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>กรุณากรอกวันเดือนปีเกิดที่ถูกต้อง</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>ตัวเลือกที่เลิอกไม่ถูกต้อง</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>คอเล็กชั่นไม่ถูกต้อง</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>กรุณาเลือกค่าสีที่ถูกต้อง</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>กรุณาเลือกประเทศที่ถูกต้อง</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>กรุุณาเลิอกค่าสกุลเงินที่ถูกต้อง</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>กรุณณากรอกช่วงวันที่ที่ถูกต้อง</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>กรุณณากรอกค่าเวลาและวันที่ที่ถูกต้อง</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>กรุณณากรอกค่าวันที่ที่ถูกต้อง</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>กรุณาเลือกไฟล์ที่ถูกต้อง</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>ค่า Hidden field ไม่ถูกต้อง</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>กรุณากรอกตัวเลขจำนวนเต็ม</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>กรุณาเลือกภาษาที่ถูกต้อง</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>กรุณาเลือกท้องถิ่นที่ถูกต้อง</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>กรุณากรอกจำนวนเงินที่ถูกต้อง</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>กรุณากรอกตัวเลข</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>รหัสผ่านไม่ถูกต้อง</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>กรุณากรอกค่าเปอร์เซ็นต์</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>ค่าทั้งสองไม่ตรงกัน</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>กรุณากรอกค่าเวลาที่ถูกต้อง</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>กรุณาเลือกค่าเขตเวลาที่ถูกต้อง</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>กรุณากรอก URL ที่ถูกต้อง</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>กรุณากรอกคำค้นหาที่ถูกต้อง</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>กรุณากรอกเบอร์โทรศัพท์ที่ถูกต้อง</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Checkbox มีค่าที่ไม่ถูกต้อง</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>กรุณากรอกที่อยู่อีเมล์ที่ถูกต้อง</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>กรุณาเลือกตัวเลือกที่ถูกต้อง</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>กรุณาเลือกค่าช่วงที่ถูกต้อง</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>กรุณากรอกค่าสัปดาห์ที่ถูกต้อง</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.tl.xlf 0000644 00000015073 15120211544 0014541 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Ang pormang itong ay hindi dapat magkarron ng dagdag na mga patlang.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Ang ini-upload na file ay masyadong malaki. Pakiulit muling mag-upload ng mas maliit na file.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>Hindi balido ang CSRF token. Maagpasa muli ng isang pang porma.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Ang halagang ito ay hindi wastong HTML5 color.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Pakilagay ang tamang petsa ng kapanganakan.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Ang pinagpiliang sagot ay hindi tama.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Hindi balido ang koleksyon.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Pakipiliin ang nararapat na kulay.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Pakipiliin ang nararapat na bansa.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Pakipiliin ang tamang pananalapi.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Piliin ang wastong agwat ng petsa.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Piliin ang wastong petsa at oras.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Ilagay ang wastong petsa.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Piliin ang balidong file.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Hindi balido ang field na nakatago.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Pakilagay ang integer.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Piliin ang nararapat na lengguwahe.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Pakipili ang nararapat na locale.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Pakilagay ang tamang halaga ng pera.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Ilagay ang numero.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Hindi balido ang password.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Pakilagay ang tamang porsyento ng halaga.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Hindi tugma ang mga halaga.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Pakilagay ang tamang oras.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Pakilagay ang tamang sona ng oras.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Pakilagay ang balidong URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Pakilagay ang balidong katagang sinasaliksik.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Pakilagay ang balidong numero ng telepono.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Ang checkbox ay mayroon hindi balidong halaga.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Pakilagay ang balidong email address.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Pakipiliin ang balidong pagpipilian.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Pakipilian ang balidong layo.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Pakilagay ang balidong linggo.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.tr.xlf 0000644 00000015061 15120211544 0014544 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Form ekstra alanlar içeremez.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Yüklenen dosya boyutu çok yüksek. Lütfen daha küçük bir dosya yüklemeyi deneyin.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF fişi geçersiz. Formu tekrar göndermeyi deneyin.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Bu değer, geçerli bir HTML5 rengi değil.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Lütfen geçerli bir doğum tarihi girin.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Seçilen seçim geçersiz.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Koleksiyon geçersiz.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Lütfen geçerli bir renk seçin.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Lütfen geçerli bir ülke seçin.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Lütfen geçerli bir para birimi seçin.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Lütfen geçerli bir tarih aralığı seçin.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Lütfen geçerli bir tarih ve saat girin.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Lütfen geçerli bir tarih giriniz.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Lütfen geçerli bir dosya seçin.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Gizli alan geçersiz.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Lütfen bir tam sayı girin.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Lütfen geçerli bir dil seçin.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Lütfen geçerli bir yerel ayar seçin.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Lütfen geçerli bir para tutarı girin.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Lütfen bir numara giriniz.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Şifre geçersiz.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Lütfen bir yüzde değeri girin.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Değerler eşleşmiyor.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Lütfen geçerli bir zaman girin.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Lütfen geçerli bir saat dilimi seçin.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Lütfen geçerli bir giriniz URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Lütfen geçerli bir arama terimi girin.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>lütfen geçerli bir telefon numarası sağlayın.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Onay kutusunda geçersiz bir değer var.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Lütfen geçerli bir e-posta adresi girin.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Lütfen geçerli bir seçenek seçin.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Lütfen geçerli bir aralık seçin.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Lütfen geçerli bir hafta girin.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.uk.xlf 0000644 00000017124 15120211544 0014540 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Ця форма не повинна містити додаткових полів.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Завантажений файл занадто великий. Будь ласка, спробуйте завантажити файл меншого розміру.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF значення недопустиме. Будь ласка, спробуйте відправити форму знову.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Це значення не є допустимим кольором HTML5.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Будь ласка, введіть дійсну дату народження.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Обраний варіант недійсний.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Колекція недійсна.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Будь ласка, оберіть дійсний колір.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Будь ласка, оберіть дійсну країну.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Будь ласка, оберіть дійсну валюту.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Будь ласка, оберіть дійсний інтервал дати.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Будь ласка, введіть дійсну дату та час.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Будь ласка, введіть дійсну дату.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Будь ласка, оберіть дійсний файл.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Приховане поле недійсне.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Будь ласка, введіть ціле число.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Будь ласка, оберіть дійсну мову.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Будь ласка, оберіть дійсну локаль.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Будь ласка, введіть дійсну суму грошей.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Будь ласка, введіть число.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Пароль недійсний.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Будь ласка, введіть процентне значення.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Значення не збігаються.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Будь ласка, введіть дійсний час.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Будь ласка, оберіть дійсний часовий пояс.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Будь ласка, введіть дійсну URL-адресу.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Будь ласка, введіть дійсний пошуковий термін.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Будь ласка, введіть дійсний номер телефону.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Прапорець має недійсне значення.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Будь ласка, введіть дійсну адресу електронної пошти.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Будь ласка, оберіть дійсний варіант.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Будь ласка, оберіть дійсний діапазон.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Будь ласка, введіть дійсний тиждень.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.ur.xlf 0000644 00000016477 15120211544 0014561 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="ur" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>اس فارم میں اضافی فیلڈز نہیں ہونی چاہئیں</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>اپ لوڈ کردھ فائل بہت بڑی تھی۔ براہ کرم ایک چھوٹی فائل اپ لوڈ کرنے کی کوشش کریں</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>ٹوکن غلط ہے۔ براۓ کرم فارم کو دوبارہ جمع کرانے کی کوشش کریں CSRF</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>ر نگ نھیں ھےHTML یھ ولیو در ست</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>براۓ کرم درست تاریخ پیدائش درج کریں</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>منتخب کردہ انتخاب غلط ہے</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>یھ مجموعہ غلط ہے</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>براۓ کرم ایک درست رنگ منتخب کریں</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>براۓ کرم ایک درست ملک منتخب کریں</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>براۓ کرم ایک درست کرنسی منتخب کریں</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>براۓ کرم ایک درست تاریخی وقفھہ منتخب کریں</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>براۓ کرم ایک درست تاریخ اور وقت درج کریں</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>براۓ کرم ایک درست تاریخ درج کریں</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>براۓ کرم ایک درست فائل منتخب کریں</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>پوشیدھہ فیلڈ غلط ہے</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>براۓ کرم ایک عدد درج کریں</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>براۓ کرم ایک درست زبان منتخب کریں</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>براۓ کرم ایک درست مقام منتخب کریں</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>براۓ کرم ایک درست رقم درج کریں</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>براۓ کرم ایک نمبر درج کریں</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>پاس ورڈ غلط ہے</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>براہ کرم فیصد کی ويلو درج کریں</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>ويليوذ ٹھيک نہیں ہیں</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>براۓ کرم ایک درست وقت درج کریں</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>براۓ کرم ایک درست ٹائم زون منتخب کریں</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>براۓ کرم ایک درست ادريس درج کریں</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>براۓ کرم ایک درست ويلو تلاش کيلۓ درج کریں</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>براۓ کرم ایک درست فون نمبر فراہم کریں</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>چیک باکس میں ایک غلط ويلو ہے</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>براۓ مہربانی قابل قبول ای میل ایڈریس لکھیں</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>براۓ کرم ایک درست آپشن منتخب کریں</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>براۓ کرم ایک درست رینج منتخب کریں</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>براۓ کرم ایک درست ہفتہ درج کریں</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.uz.xlf 0000644 00000015057 15120211544 0014562 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Ushbu fo'rmada qo'shimcha maydonlar bo'lmasligi kerak.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Yuklab olingan fayl juda katta. Iltimos, kichikroq faylni yuklashga harakat qiling.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF qiymati yaroqsiz. Fo'rmani qayta yuborishga harakat qiling.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Qiymat noto'g'ri, HTML5 rangi emas.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Iltimos, tug'ilgan kuningizni to'g'ri kiriting.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Tanlangan parametr noto'g'ri.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Kolleksiya noto'g'ri</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Iltimos, to'g'ri rang tanlang.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Iltimos, to'g'ri mamlakatni tanlang.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Iltimos, to'g'ri valyutani tanlang.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Iltimos, to'g'ri sana oralig'ini tanlang.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Iltimos, to'g'ri sana va vaqtni kiriting.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Iltimos, to'g'ri sanani kiriting.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Iltimos, to'g'ri faylni tanlang.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Yashirin maydon qiymati yaroqsiz.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Iltimos, butun son kiriting.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Iltimos, to'g'ri tilni tanlang.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Iltimos, to'g'ri localni tanlang.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Iltimos, tegishli miqdordagi pulni kiriting.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Iltimos, raqam kiriting.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Parol noto'g'ri.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Iltimos, foyizli qiymat kiriting.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Qiymatlar mos kelmaydi.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Iltimos, to'g'ri vaqtni tanlang.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Iltimos, to'g'ri vaqt zonasini tanlang.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Iltimos, to'g'ri URL kiriting.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Iltimos, to'g'ri qidiruv so'zini kiriting.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Iltimos, to'g'ri telefon raqamini kiriting.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Belgilash katagida yaroqsiz qiymat mavjud.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Iltimos, to'g'ri email kiriting.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Iltimos, yaroqli variantni tanlang.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Iltimos, yaroqli oraliqni tanlang.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Iltimos, haqiqiy haftani kiriting.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.vi.xlf 0000644 00000015616 15120211544 0014543 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Mẫu này không nên chứa trường mở rộng.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Tập tin tải lên quá lớn. Vui lòng thử lại với tập tin nhỏ hơn.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF token không hợp lệ. Vui lòng thử lại.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Giá trị này không phải là màu HTML5 hợp lệ.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Vui lòng nhập ngày sinh hợp lệ.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Lựa chọn không hợp lệ.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Danh sách không hợp lệ.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Vui lòng chọn một màu hợp lệ.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Vui lòng chọn đất nước hợp lệ.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Vui lòng chọn tiền tệ hợp lệ.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Vui lòng chọn một khoảng thời gian hợp lệ.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Vui lòng nhập ngày và thời gian hợp lệ.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Vui lòng nhập ngày hợp lệ.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Vui lòng chọn tệp hợp lệ.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Phạm vi ẩn không hợp lệ.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Vui lòng nhập một số nguyên.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Vui lòng chọn ngôn ngữ hợp lệ.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Vui lòng chọn miền hợp lệ.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Vui lòng nhập một khoảng tiền hợp lệ.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Vui lòng nhập một con số.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Mật khẩu không hợp lệ.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Vui lòng nhập một giá trị phần trăm.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Các giá trị không phù hợp.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Vui lòng nhập thời gian hợp lệ.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Vui lòng chọn múi giờ hợp lệ.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Vui lòng nhập một URL hợp lệ.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Vui lòng nhập chuỗi tìm kiếm hợp lệ.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Vui lòng cung cấp số điện thoại hợp lệ.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Hộp kiểm có một giá trị không hợp lệ.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Vui lòng nhập địa chỉ email hợp lệ.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Vui lòng chọn một phương án hợp lệ.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Vui lòng nhập một phạm vi hợp lệ.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Vui lòng nhập một tuần hợp lệ.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.zh_CN.xlf 0000644 00000014447 15120211544 0015127 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>该表单中不可有额外字段.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>上传文件太大, 请重新尝试上传一个较小的文件.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF 验证符无效, 请重新提交.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>该数值不是个有效的 HTML5 颜色。</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>请输入有效的生日日期。</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>所选的选项无效。</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>集合无效。</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>请选择有效的颜色。</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>请选择有效的国家。</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>请选择有效的货币。</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>请选择有效的日期间隔。</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>请输入有效的日期与时间。</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>请输入有效的日期。</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>请选择有效的文件。</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>隐藏字段无效。</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>请输入整数。</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>请选择有效的语言。</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>请选择有效的语言环境。</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>请输入正确的金额。</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>请输入数字。</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>密码无效。</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>请输入百分比值。</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>数值不匹配。</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>请输入有效的时间。</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>请选择有效的时区。</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>请输入有效的网址。</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>请输入有效的搜索词。</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>请提供有效的手机号码。</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>无效的选框值。</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>请输入有效的电子邮件地址。</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>请选择有效的选项。</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>请选择有效的范围。</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>请输入有效的星期。</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.zh_TW.xlf 0000644 00000014455 15120211544 0015160 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>該表單中不可有額外字段。</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>上傳文件太大, 請重新嘗試上傳一個較小的文件。</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF 驗證符無效, 請重新提交。</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>該數值不是個有效的 HTML5 顏色。</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>請輸入有效的生日日期。</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>所選的選項無效。</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>集合無效。</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>請選擇有效的顏色。</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>請選擇有效的國家。</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>請選擇有效的貨幣。</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>請選擇有效的日期間隔。</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>請輸入有效的日期與時間。</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>請輸入有效的日期。</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>請選擇有效的文件。</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>隱藏字段無效。</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>請輸入整數。</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>請選擇有效的語言。</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>請選擇有效的語言環境。</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>請輸入正確的金額。</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>請輸入數字。</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>密碼無效。</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>請輸入百分比值。</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>數值不匹配。</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>請輸入有效的時間。</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>請選擇有效的時區。</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>請輸入有效的網址。</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>請輸入有效的搜索詞。</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>請提供有效的手機號碼。</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>無效的選框值。</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>請輸入有效的電子郵件地址。</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>請選擇有效的選項。</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>請選擇有效的範圍。</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>請輸入有效的星期。</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.af.xlf 0000644 00000015165 15120211544 0014512 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Hierdie vorm moet nie ekstra velde bevat nie.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Die opgelaaide lêer was te groot. Probeer asseblief 'n kleiner lêer.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>Die CSRF-teken is ongeldig. Probeer asseblief om die vorm weer in te dien.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Hierdie waarde is nie 'n geldige HTML5 kleur nie.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Voer asseblief 'n geldige geboortedatum in.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Die gekiesde opsie is nie geldig nie.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Die versameling is nie geldig nie.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Kies asseblief 'n geldige kleur.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Kies asseblief 'n geldige land.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Kies asseblief 'n geldige geldeenheid.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Kies asseblief 'n geldige datum interval.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Voer asseblilef 'n geldige datum en tyd in.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Voer asseblief 'n geldige datum in.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Kies asseblief 'n geldige lêer.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Die versteekte veld is nie geldig nie.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Voer asseblief 'n geldige heeltal in.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Kies assblief 'n geldige taal.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Voer assebliefn 'n geldige locale in.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Voer asseblief 'n geldige bedrag in.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Voer asseblief 'n nommer in.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Die wagwoord is ongeldig.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Voer asseblief 'n geldige persentasie waarde in.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Die waardes is nie dieselfde nie.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Voer asseblief 'n geldige tyd in time.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Kies asseblief 'n geldige tydsone.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Voer asseblief 'n geldige URL in.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Voer asseblief 'n geldige soek term in.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Verskaf asseblief 'n geldige telefoonnommer.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Die blokkie het 'n ongeldige waarde.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Voer asseblief 'n geldige e-pos adres in.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Kies asseblief 'n geldige opsie.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Kies asseblief 'n geldige reeks.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Voer assblief 'n geldige week in.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.ar.xlf 0000644 00000016012 15120211544 0014516 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>هذا النموذج يجب الا يحتوى على اى حقول اضافية.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>مساحة الملف المرسل كبيرة. من فضلك حاول ارسال ملف اصغر.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>قيمة رمز الموقع غير صحيحة. من فضلك اعد ارسال النموذج.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>هذه القيمة ليست لون HTML5 صالحًا.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>الرجاء ادخال تاريخ ميلاد صالح.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>الاختيار المحدد غير صالح.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>المجموعة غير صالحة.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>الرجاء اختيار لون صالح.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>الرجاء اختيار بلد صالح.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>الرجاء اختيار عملة صالحة.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>الرجاء اختيار فاصل زمني صالح.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>الرجاء إدخال تاريخ ووقت صالحين.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>الرجاء إدخال تاريخ صالح.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>الرجاء اختيار ملف صالح.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>الحقل المخفي غير صالح.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>الرجاء إدخال عدد صحيح.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>الرجاء اختيار لغة صالحة.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>الرجاء اختيار لغة صالحة.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>الرجاء إدخال مبلغ مالي صالح.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>الرجاء إدخال رقم.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>كلمة المرور غير صحيحة.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>الرجاء إدخال قيمة النسبة المئوية.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>القيم لا تتطابق.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>الرجاء إدخال وقت صالح.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>الرجاء تحديد منطقة زمنية صالحة.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>أدخل عنوان الرابط صحيح من فضلك.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>الرجاء إدخال مصطلح البحث ساري المفعول.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>يرجى تقديم رقم هاتف صالح.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>خانة الاختيار لها قيمة غير صالحة.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>رجاء قم بإدخال بريد الكتروني صحيح</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>الرجاء تحديد خيار صالح.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>يرجى تحديد نطاق صالح.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>الرجاء إدخال أسبوع صالح.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.az.xlf 0000644 00000015407 15120211544 0014535 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Bu formada əlavə sahə olmamalıdır.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Yüklənən fayl çox böyükdür. Lütfən daha kiçik fayl yükləyin.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF nişanı yanlışdır. Lütfen formanı yenidən göndərin.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Bu dəyər doğru bir HTML5 rəngi deyil.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Zəhmət olmasa doğru bir doğum günü daxil edin.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Seçilmiş seçim doğru deyil.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Kolleksiya doğru deyil.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Zəhmət olmasa doğru bir rəng seçin.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Zəhmət olmasa doğru bir ölkə seçin.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Zəhmət olmasa doğru bir valyuta seçin.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Zəhmət olmasa doğru bir tarix aralığı seçin.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Zəhmət olmasa doğru bir tarix ve saat daxil edin.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Zəhmət olmasa doğru bir tarix daxil edin.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Zəhmət olmasa doğru bir fayl seçin.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Gizli sahə doğru deyil.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Zəhmət olmasa bir tam ədəd daxil edin.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Zəhmət olmasa doğru bir dil seçin.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Zəhmət olmasa doğru bir yer seçin.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Zəhmət olmasa doğru bir pul miqdarı daxil edin.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Zəhmət olmasa doğru bir rəqəm daxil edin.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Parol doğru deyil.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Zəhmət olmasa doğru bir faiz dəyəri daxil edin.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Dəyərlər örtüşmür.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Zəhmət olmasa doğru bir saat daxil edin.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Zəhmət olmasa doğru bir saat qurşağı seçin.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Zəhmət olmasa doğru bir URL daxil edin.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Zəhmət olmasa doğru bir axtarış termini daxil edin.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Zəhmət olmasa doğru bir telefon nömrəsi seçin.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Seçim qutusunda doğru olmayan dəyər var.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Zəhmət olmasa doğru bir e-poçt seçin.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Zəhmət olmasa doğru bir variant seçin.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Zəhmət olmasa doğru bir aralıq seçin.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Zəhmət olmasa doğru bir həftə seçin.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.be.xlf 0000644 00000017355 15120211544 0014515 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Гэта форма не павінна мець дадатковых палей.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Запампаваны файл быў занадта вялікім. Калі ласка, паспрабуйце запампаваць файл меншага памеру.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF-токен не сапраўдны. Калі ласка, паспрабуйце яшчэ раз адправіць форму.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Значэнне не з'яўляецца карэктным HTML5 колерам.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Калі ласка, увядзіце карэктную дату нараджэння.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Выбраны варыянт некарэктны.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Калекцыя некарэктна.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Калі ласка, выберыце карэктны колер.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Калі ласка, выберыце карэктную краіну.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Калі ласка, выберыце карэктную валюту.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Калі ласка, выберыце карэктны інтэрвал дат.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Калі ласка, увядзіце карэктныя дату і час.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Калі ласка, увядзіце карэктную дату.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Калі ласка, выберыце карэктны файл.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Значэнне схаванага поля некарэктна.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Калі ласка, увядзіце цэлы лік.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Калі ласка, выберыце карэктную мову.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Калі ласка, выберыце карэктную лакаль.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Калі ласка, увядзіце карэктную колькасць грошай.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Калі ласка, увядзіце нумар.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Няправільны пароль.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Калі ласка, увядзіце працэнтнае значэнне.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Значэнні не супадаюць.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Калі ласка, увядзіце карэктны час.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Калі ласка, выберыце карэктны гадзінны пояс.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Калі ласка, увядзіце карэктны URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Калі ласка, увядзіце карэктны пошукавы запыт.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Калі ласка, увядзіце карэктны нумар тэлефона.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Флажок мае некарэктнае значэнне.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Калі ласка, увядзіце карэктны адрас электроннай пошты.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Калі ласка, выберыце карэктны варыянт.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Калі ласка, выберыце карэктны дыяпазон.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Калі ласка, увядзіце карэктны тыдзень.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.bg.xlf 0000644 00000016457 15120211544 0014521 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Тази форма не трябва да съдържа допълнителни полета.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Каченият файл е твърде голям. Моля, опитайте да качите по-малък файл.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>Невалиден CSRF токен. Моля, опитайте да изпратите формата отново.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Стойността не е валиден HTML5 цвят.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Моля въведете валидна дата на раждане.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Избраните стойности не са валидни.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Колекцията не е валидна.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Моля изберете валиден цвят.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Моля изберете валидна държава.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Моля изберете валидна валута.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Моля изберете валиден интервал от дати.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Моля въведете валидни дата и час.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Моля въведете валидна дата.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Моля изберете валиден файл.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Скритото поле е невалидно.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Моля попълнете цяло число.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Моля изберете валиден език.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Моля изберете валиден език.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Моля въведете валидна парична сума.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Моля въведете число.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Паролата е невалидна.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Моля въведете процентна стойност.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Стойностите не съвпадат.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Моля въведете валидно време.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Моля изберете валидна часова зона.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Моля въведете валиден URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Моля въведете валидно търсене.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Моля осигурете валиден телефонен номер.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Отметката има невалидна стойност.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Моля въведете валидна ел. поща.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Моля изберете валидна опция.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Моля изберете валиден обхват.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Моля въведете валидна седмица.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.bs.xlf 0000644 00000015125 15120211544 0014524 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Ovaj obrazac ne bi trebalo da sadrži dodatna polja.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Prenijeta (uploaded) datoteka je prevelika. Molim pokušajte prenijeti manju datoteku.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF vrijednost nije ispravna. Molim pokušajte ponovo da pošaljete obrazac.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Ova vrijednost nije važeća HTML5 boja.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Molim upišite ispravan datum rođenja.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Odabrani izbor nije ispravan.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Ova kolekcija nije ispravna.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Molim izaberite ispravnu boju.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Molim izaberite ispravnu državu.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Molim izaberite ispravnu valutu.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Molim izaberite ispravan datumski interval.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Molim upišite ispravan datum i vrijeme.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Molim upišite ispravan datum.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Molim izaberite ispravnu datoteku.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Skriveno polje nije ispravno.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Molim upišite cijeli broj (integer).</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Molim izaberite ispravan jezik.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Molim izaberite ispravnu lokalizaciju.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Molim upišite ispravnu količinu novca.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Molim upišite broj.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Ova lozinka nije ispravna.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Molim upišite procentualnu vrijednost.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Date vrijednosti se ne poklapaju.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Molim upišite ispravno vrijeme.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Molim izaberite ispravnu vremensku zonu.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Molim upišite ispravan URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Molim upišite ispravan termin za pretragu.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Molim navedite ispravan broj telefona.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Polje za potvrdu sadrži neispravnu vrijednost.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Molim upišite ispravnu email adresu.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Molim izaberite ispravnu opciju.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Molim izaberite ispravan opseg.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Molim upišite ispravnu sedmicu.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.ca.xlf 0000644 00000015360 15120211544 0014504 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Aquest formulari no hauria de contenir camps addicionals.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>L'arxiu pujat és massa gran. Per favor, pugi un arxiu més petit.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>El token CSRF no és vàlid. Per favor, provi d'enviar novament el formulari.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Aquest valor no és un color HTML5 valid.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Per favor introdueix una data d'aniversari valida.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>L'opció escollida és invalida.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>La col·lecció és invalida.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Per favor selecciona un color vàlid.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Per favor selecciona una ciutat vàlida.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Per favor selecciona una moneda vàlida.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Per favor escull un interval de dates vàlides.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Per favor introdueix una data i temps vàlid.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Per favor introdueix una data vàlida.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Per favor selecciona un arxiu vàlid.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>El camp ocult és invàlid.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Per favor introdueix un enter.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Per favor selecciona un idioma vàlid.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Per favor seleccioneu una configuració regional vàlida</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Per favor introdueix una quantitat de diners vàlids.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Per favor introdueix un número.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>La contrasenya es invàlida.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Per favor introdueix un valor percentual.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Els valors no coincideixen.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Per favor introdueix un temps vàlid.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Per favor selecciona una zona horària vàlida.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Per favor introdueix una URL vàlida.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Per favor introdueix un concepte de cerca vàlid.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Per favor introdueix un número de telèfon vàlid.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>La casella de selecció te un valor invàlid.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Per favor introdueix un correu electrònic vàlid.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Per favor selecciona una opció vàlida.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Per favor selecciona un rang vàlid.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Per favor introdueix una setmana vàlida.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.cs.xlf 0000644 00000014775 15120211544 0014537 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Tato skupina polí nesmí obsahovat další pole.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Nahraný soubor je příliš velký. Nahrajte prosím menší soubor.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF token je neplatný. Zkuste prosím znovu odeslat formulář.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Tato hodnota není platná HTML5 barva.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Prosím zadejte platný datum narození.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Vybraná možnost není platná.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Kolekce není platná.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Prosím vyberte platnou barvu.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Prosím vyberte platnou zemi.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Prosím vyberte platnou měnu.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Prosím vyberte platné rozpětí dat.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Prosím zadejte platný datum a čas.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Prosím zadejte platný datum.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Prosím vyberte platný soubor.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Skryté pole není platné.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Prosím zadejte číslo.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Prosím zadejte platný jazyk.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Prosím zadejte platný jazyk.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Prosím zadejte platnou částku.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Prosím zadejte číslo.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Heslo není platné.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Prosím zadejte procentuální hodnotu.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Hodnoty se neshodují.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Prosím zadejte platný čas.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Prosím vyberte platné časové pásmo.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Prosím zadejte platnou URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Prosím zadejte platný výraz k vyhledání.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Prosím zadejte platné telefonní číslo.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Zaškrtávací políčko má neplatnou hodnotu.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Prosím zadejte platnou emailovou adresu.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Prosím vyberte platnou možnost.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Prosím vyberte platný rozsah.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Prosím zadejte platný týden.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.da.xlf 0000644 00000014742 15120211544 0014510 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Feltgruppen må ikke indeholde ekstra felter.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Den uploadede fil var for stor. Upload venligst en mindre fil.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF-token er ugyldig. Prøv venligst at genindsende.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Værdien er ikke en gyldig HTML5 farve.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Indtast venligst en gyldig fødselsdato.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Den valgte mulighed er ugyldig .</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Samlingen er ugyldig.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Vælg venligst en gyldig farve.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Vælg venligst et gyldigt land.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Vælg venligst en gyldig valuta.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Vælg venligst et gyldigt datointerval.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Vælg venligst en gyldig dato og tid.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Vælg venligst en gyldig dato.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Vælg venligst en gyldig fil.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Det skjulte felt er ugyldigt.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Indsæt veligst et heltal.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Vælg venligst et gyldigt sprog.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Vælg venligst en gyldigt sprogkode.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Vælg venligst et gyldigt beløb.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Indtast venligst et nummer.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Passwordet er ugyldigt.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Indtast venligst en procentværdi.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Værdierne er ikke ens.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Indtast venligst en gyldig tid.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Vælg venligst en gyldig tidszone.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Indtast venligst en gyldig URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Indtast venligst et gyldigt søgeord.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Giv venligst et gyldigt telefonnummer.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Checkboxen har en ugyldigt værdi.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Indtast venligst en gyldig e-mailadresse.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Vælg venligst en gyldig mulighed.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Vælg venligst et gyldigt interval .</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Indtast venligst en gyldig uge.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.de.xlf 0000644 00000015504 15120211544 0014511 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Dieses Formular sollte keine zusätzlichen Felder enthalten.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Die hochgeladene Datei ist zu groß. Versuchen Sie bitte eine kleinere Datei hochzuladen.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>Der CSRF-Token ist ungültig. Versuchen Sie bitte, das Formular erneut zu senden.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Dieser Wert ist keine gültige HTML5 Farbe.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Bitte geben Sie ein gültiges Geburtsdatum ein.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Die Auswahl ist ungültig.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Diese Gruppe von Feldern ist ungültig.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Bitte geben Sie eine gültige Farbe ein.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Bitte wählen Sie ein gültiges Land aus.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Bitte wählen Sie eine gültige Währung aus.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Bitte wählen Sie ein gültiges Datumsintervall.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Bitte geben Sie ein gültiges Datum samt Uhrzeit ein.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Bitte geben Sie ein gültiges Datum ein.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Bitte wählen Sie eine gültige Datei.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Das versteckte Feld ist ungültig.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Bitte geben Sie eine ganze Zahl ein.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Bitte wählen Sie eine gültige Sprache.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Bitte wählen Sie eine gültige Locale-Einstellung aus.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Bitte geben Sie einen gültigen Geldbetrag ein.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Bitte geben Sie eine gültige Zahl ein.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Das Kennwort ist ungültig.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Bitte geben Sie einen gültigen Prozentwert ein.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Die Werte stimmen nicht überein.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Bitte geben Sie eine gültige Uhrzeit ein.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Bitte wählen Sie eine gültige Zeitzone.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Bitte geben Sie eine gültige URL ein.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Bitte geben Sie einen gültigen Suchbegriff ein.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Bitte geben Sie eine gültige Telefonnummer ein.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Das Kontrollkästchen hat einen ungültigen Wert.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Bitte geben Sie eine gültige E-Mail-Adresse ein.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Bitte wählen Sie eine gültige Option.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Bitte wählen Sie einen gültigen Bereich.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Bitte geben Sie eine gültige Woche ein.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.el.xlf 0000644 00000017745 15120211544 0014532 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Αυτή η φόρμα δεν πρέπει να περιέχει επιπλέον πεδία.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Το αρχείο είναι πολύ μεγάλο. Παρακαλούμε προσπαθήστε να ανεβάσετε ένα μικρότερο αρχείο.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>Το CSRF token δεν είναι έγκυρο. Παρακαλούμε δοκιμάστε να υποβάλετε τη φόρμα ξανά.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Αυτή η τιμή δέν έναι έγκυρο χρώμα HTML5.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Παρακαλόυμε ειχάγεται μία έγκυρη ημερομηνία γέννησης.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Η επιλεγμένη επιλογή δέν είναι έγκυρη.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Η συλλογή δέν είναι έγκυρη.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Παρακαλούμε επιλέξτε ένα έγκυρο χρώμα.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Παρακαλούμε επιλέξτε μία έγκυρη χώρα.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Παρακαλούμε επιλέξτε ένα έγυρο νόμισμα.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Παρακαλούμε επιλέξτε ένα έγκυρο διάστημα ημερομηνίας.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Παρακαλούμε εισαγάγετε μια έγκυρη ημερομηνία και ώρα.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Παρακαλούμε εισάγετε μία έγκυρη ημερομηνία.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Παρακαλούμε επιλέξτε ένα έγκυρο αρχείο.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Το κρυφό πεδίο δέν είναι έγκυρο.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Παρακαλούμε εισάγετε έναν ακέραιο αριθμό.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Παρακαλούμε επιλέξτε μία έγκυρη γλώσσα.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Παρακαλούμε επιλέξτε μία έγκυρη τοπικοποίηση.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Παρακαλούμε εισάγετε ένα έγκυρο χρηματικό ποσό.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Παρακαλούμε εισάγετε έναν αριθμό.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Ο κωδικός δέν είναι έγκυρος.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Παρακαλούμε εισάγετε μία ποσοστιαία τιμή.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Οι τιμές δέν ταιριάζουν.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Παρακαλούμε εισάγετε μία έγκυρη ώρα.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Παρακαλούμε επιλέξτε μία έγυρη ζώνη ώρας.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Παρακαλούμε εισάγετε μια έγκυρη διεύθυνση URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Παρακαλούμε εισάγετε έναν έγκυρο όρο αναζήτησης.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Παρακαλούμε καταχωρίστε έναν έγκυρο αριθμό τηλεφώνου.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Το πλαίσιο ελέγχου έχει μή έγκυρη τιμή.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Παρακαλούμε εισάγετε μία έγκυρη ηλεκτρονική διεύθυνση.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Παρακαλούμε επιλέξτε μία έγκυρη επιλογή.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Παρακαλούμε επιλέξτε ένα έγυρο εύρος.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Παρακαλούμε εισάγετε μία έγκυρη εβδομάδα.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.en.xlf 0000644 00000014633 15120211544 0014525 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>This form should not contain extra fields.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>The uploaded file was too large. Please try to upload a smaller file.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>The CSRF token is invalid. Please try to resubmit the form.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>This value is not a valid HTML5 color.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Please enter a valid birthdate.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>The selected choice is invalid.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>The collection is invalid.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Please select a valid color.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Please select a valid country.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Please select a valid currency.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Please choose a valid date interval.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Please enter a valid date and time.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Please enter a valid date.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Please select a valid file.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>The hidden field is invalid.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Please enter an integer.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Please select a valid language.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Please select a valid locale.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Please enter a valid money amount.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Please enter a number.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>The password is invalid.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Please enter a percentage value.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>The values do not match.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Please enter a valid time.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Please select a valid timezone.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Please enter a valid URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Please enter a valid search term.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Please provide a valid phone number.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>The checkbox has an invalid value.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Please enter a valid email address.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Please select a valid option.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Please select a valid range.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Please enter a valid week.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.es.xlf 0000644 00000015457 15120211544 0014537 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Este formulario no debería contener campos adicionales.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>El archivo subido es demasiado grande. Por favor, suba un archivo más pequeño.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>El token CSRF no es válido. Por favor, pruebe a enviar nuevamente el formulario.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Este valor no es un color HTML5 válido.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Por favor, ingrese una fecha de cumpleaños válida.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>La opción seleccionada no es válida.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>La colección no es válida.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Por favor, seleccione un color válido.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Por favor, seleccione un país válido.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Por favor, seleccione una moneda válida.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Por favor, elija un intervalo de fechas válido.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Por favor, ingrese una fecha y hora válidas.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Por favor, ingrese una fecha valida.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Por favor, seleccione un archivo válido.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>El campo oculto no es válido.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Por favor, ingrese un número entero.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Por favor, seleccione un idioma válido.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Por favor, seleccione una configuración regional válida.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Por favor, ingrese una cantidad de dinero válida.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Por favor, ingrese un número.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>La contraseña no es válida.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Por favor, ingrese un valor porcentual.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Los valores no coinciden.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Por favor, ingrese una hora válida.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Por favor, seleccione una zona horaria válida.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Por favor, ingrese una URL válida.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Por favor, ingrese un término de búsqueda válido.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Por favor, proporcione un número de teléfono válido.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>La casilla de verificación tiene un valor inválido.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Por favor, ingrese una dirección de correo electrónico válida.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Por favor, seleccione una opción válida.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Por favor, seleccione un rango válido.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Por favor, ingrese una semana válida.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.et.xlf 0000644 00000014672 15120211544 0014536 0 ustar 00 <?xml version='1.0'?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Väljade grupp ei tohiks sisalda lisaväljasid.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Üleslaaditud fail oli liiga suur. Palun proovi uuesti väiksema failiga.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF-märgis on vigane. Palun proovi vormi uuesti esitada.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>See väärtus ei ole korrektne HTML5 värv.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Palun sisesta korrektne sünnikuupäev.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Tehtud valik on vigane.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Kogum on vigane.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Palun vali korrektne värv.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Palun vali korrektne riik.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Palun vali korrektne valuuta.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Palun vali korrektne kuupäevade vahemik.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Palun sisesta korrektne kuupäev ja kellaaeg.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Palun sisesta korrektne kuupäev.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Palun vali korrektne fail.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Peidetud väli on vigane.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Palun sisesta täisarv.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Palun vali korrektne keel.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Palun vali korrektne keelekood.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Palun sisesta korrektne rahaline väärtus.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Palun sisesta number.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Vigane parool.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Palun sisesta protsendiline väärtus.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Väärtused ei klapi.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Palun sisesta korrektne aeg.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Palun vali korrektne ajavöönd.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Palun sisesta korrektne URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Palun sisesta korrektne otsingutermin.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Palun sisesta korrektne telefoninumber.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Märkeruudu väärtus on vigane.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Palun sisesta korrektne e-posti aadress.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Palun tee korrektne valik.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Palun vali korrektne vahemik.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Palun sisesta korrektne nädal.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.eu.xlf 0000644 00000015075 15120211544 0014535 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Formulario honek ez luke aparteko eremurik eduki behar.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Igotako fitxategia handiegia da. Mesedez saiatu fitxategi txikiago bat igotzen.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid.</source> <target>CSRF tokena ez da egokia.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Balio hori ez da HTML5 kolore onargarria.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Mesedez, sartu baliozko urtebetetze-eguna.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Hautatutako aukera ez da egokia.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Bilduma ez da baliozkoa.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Mesedez, hautatu baliozko kolore bat.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Mesedez, hautatu baliozko herrialde bat.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Mesedez, hautatu baliozko moneta bat.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Mesedez, hautatu baliozko data-tarte bat.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Mesedez, sartu baliozko data eta ordua.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Mesedez, sartu baliozko data bat.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Mesedez, hautatu baliozko fitxategi bat.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Eremu ezkutua ez da baliozkoa.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Mesedez, sartu zenbaki oso bat.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Mesedez, hautatu baliozko hizkuntza bat.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Mesedez, hautatu baliozko eskualde-konfigurazio bat.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Mesedez, sartu baliozko diru-kopuru bat.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Mesedez, sartu zenbaki bat.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Pasahitza ez da zuzena.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Mesedez, sartu portzentajezko balio bat.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Balioak ez datoz bat.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Mesedez, sartu baliozko ordu bat.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Mesedez, hautatu baliozko ordu-eremua.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Mesedez, sartu baliozko URL bat.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Mesedez, sartu bilaketa-termino onargarri bat.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Mesedez, eman baliozko telefono-zenbaki bat.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Egiaztatze-laukiak balio baliogabea du.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Mesedez, sartu baliozko helbide elektroniko bat.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Mesedez, hautatu baliozko aukera bat.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Mesedez, hautatu baliozko tarte bat.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Mesedez, sartu baliozko aste bat.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.fa.xlf 0000644 00000016635 15120211544 0014515 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>این فرم نباید شامل فیلدهای اضافی باشد.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>فایل بارگذاریشده بسیار بزرگ است. لطفاً فایل کوچکتری را بارگذاری نمایید.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>توکن CSRF نامعتبر است. لطفاً فرم را مجدداً ارسال نمایید.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>این مقدار یک رنگ معتبر HTML5 نیست.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>لطفاً یک تاریخ تولد معتبر وارد نمایید.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>گزینه انتخاب شده نامعتبر است.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>این مجموعه نامعتبر است.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>لطفاً یک رنگ معتبر انتخاب کنید.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>لطفاً یک کشور معتبر انتخاب کنید.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>لطفاً یک واحد پول معتبر انتخاب کنید.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>لطفاً یک بازه زمانی معتبر انتخاب کنید.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>لطفاً یک تاریخ و زمان معتبر وارد کنید.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>لطفاً یک تاریخ معتبر وارد کنید.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>لطفاً یک فایل معتبر انتخاب کنید.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>فیلد مخفی نامعتبر است.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>لطفاً یک عدد صحیح وارد کنید.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>لطفاً یک زبان معتبر انتخاب کنید.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>لطفاً یک منطقهجغرافیایی (locale) معتبر انتخاب کنید.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>لطفاً یک مقدار پول معتبر وارد کنید.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>لطفاً یک عدد وارد کنید.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>رمزعبور نامعتبر است.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>لطفاً یک درصد معتبر وارد کنید.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>مقادیر تطابق ندارند.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>لطفاً یک زمان معتبر وارد کنید.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>لطفاً یک منطقهزمانی معتبر وارد کنید.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>لطفاً یک URL معتبر وارد کنید.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>لطفاً یک عبارت جستجوی معتبر وارد کنید.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>لطفاً یک شماره تلفن معتبر وارد کنید.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>کادر انتخاب (checkbox) دارای مقداری نامعتبر است.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>لطفاً یک آدرس رایانامه (ایمیل) معتبر وارد کنید.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>لطفاً یک گزینه معتبر انتخاب کنید.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>لطفاً یک محدوده معتبر انتخاب کنید.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>لطفاً یک هفته معتبر وارد کنید.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.fi.xlf 0000644 00000014636 15120211544 0014524 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Tämä lomake ei voi sisältää ylimääräisiä kenttiä.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Ladattu tiedosto on liian iso. Ole hyvä ja lataa pienempi tiedosto.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF-tarkiste on virheellinen. Ole hyvä ja yritä lähettää lomake uudestaan.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Tämä arvo ei ole kelvollinen HTML5-väri.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Syötä kelvollinen syntymäaika.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Valittu vaihtoehto ei kelpaa.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Ryhmä ei kelpaa.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Valitse kelvollinen väri.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Valitse kelvollinen maa.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Valitse kelvollinen valuutta.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Valitse kelvollinen aikaväli.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Syötä kelvolliset päivä ja aika.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Syötä kelvollinen päivä.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Valitse kelvollinen tiedosto.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Piilotettu kenttä ei ole kelvollinen.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Syötä kokonaisluku.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Valitse kelvollinen kieli.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Valitse kelvollinen kielikoodi.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Syötä kelvollinen rahasumma.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Syötä numero.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Salasana ei kelpaa.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Syötä prosenttiluku.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Arvot eivät vastaa toisiaan.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Syötä kelvollinen kellonaika.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Valitse kelvollinen aikavyöhyke.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Syötä kelvollinen URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Syötä kelvollinen hakusana.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Anna kelvollinen puhelinnumero.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Valintaruudun arvo ei kelpaa.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Syötä kelvollinen sähköpostiosoite.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Valitse kelvollinen vaihtoehto.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Valitse kelvollinen väli.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Syötä kelvollinen viikko.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.fr.xlf 0000644 00000015316 15120211544 0014531 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Ce formulaire ne doit pas contenir de champs supplémentaires.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Le fichier téléchargé est trop volumineux. Merci d'essayer d'envoyer un fichier plus petit.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>Le jeton CSRF est invalide. Veuillez renvoyer le formulaire.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Cette valeur n'est pas une couleur HTML5 valide.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Veuillez entrer une date de naissance valide.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Le choix sélectionné est invalide.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>La collection est invalide.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Veuillez sélectionner une couleur valide.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Veuillez sélectionner un pays valide.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Veuillez sélectionner une devise valide.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Veuillez choisir un intervalle de dates valide.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Veuillez saisir une date et une heure valides.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Veuillez entrer une date valide.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Veuillez sélectionner un fichier valide.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Le champ masqué n'est pas valide.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Veuillez saisir un entier.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Veuillez sélectionner une langue valide.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Veuillez sélectionner une langue valide.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Veuillez saisir un montant valide.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Veuillez saisir un nombre.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Le mot de passe est invalide.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Veuillez saisir un pourcentage valide.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Les valeurs ne correspondent pas.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Veuillez saisir une heure valide.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Veuillez sélectionner un fuseau horaire valide.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Veuillez saisir une URL valide.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Veuillez saisir un terme de recherche valide.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Veuillez fournir un numéro de téléphone valide.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>La case à cocher a une valeur non valide.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Veuillez saisir une adresse email valide.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Veuillez sélectionner une option valide.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Veuillez sélectionner une plage valide.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Veuillez entrer une semaine valide.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.gl.xlf 0000644 00000015464 15120211544 0014530 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Este formulario non debería conter campos adicionais.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>O arquivo subido é demasiado grande. Por favor, suba un arquivo máis pequeno.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>O token CSRF non é válido. Por favor, probe a enviar novamente o formulario.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Este valor non é unha cor HTML5 válida.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Insire unha data de aniversario válida.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>A opción seleccionada non é válida.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>A colección non é válida.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Por favor, seleccione unha cor válida.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Por favor, seleccione un país válido.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Por favor, seleccione unha moeda válida.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Por favor, escolla un intervalo de datas válido.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Por favor, introduza unha data e hora válidas.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Por favor, introduce unha data válida.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Por favor, seleccione un ficheiro válido.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>O campo oculto non é válido.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Por favor, introduza un número enteiro.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Por favor, selecciona un idioma válido.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Por favor, seleccione unha configuración rexional válida.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Por favor, introduza unha cantidade de diñeiro válida.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Por favor, introduza un número.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>O contrasinal non é válido.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Por favor, introduza un valor porcentual.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Os valores non coinciden.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Por favor, introduza unha hora válida.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Por favor, selecciona unha zona horaria válida.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Por favor, introduce un URL válido.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Por favor, introduce un termo de busca válido.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Por favor, fornecer un número de teléfono válido.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>A caixa de verificación ten un valor non válido.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Por favor, introduce un enderezo de correo electrónico válido.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Por favor, seleccione unha opción válida.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Por favor, seleccione un intervalo válido.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Por favor, introduce unha semana válida.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.he.xlf 0000644 00000015303 15120211544 0014512 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>הטופס לא צריך להכיל שדות נוספים.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>הקובץ שהועלה גדול מדי. נסה להעלות קובץ קטן יותר.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>אסימון CSRF אינו חוקי. אנא נסה לשלוח שוב את הטופס.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>ערך זה אינו צבע HTML5 חוקי.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>נא להזין את תאריך לידה תקני.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>הבחירה שנבחרה אינה חוקית.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>האוסף אינו חוקי.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>אנא בחר צבע חוקי.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>אנא בחר מדינה חוקית.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>אנא בחר מטבע חוקי.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>אנא בחר מרווח תאריכים חוקי.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>אנא הזן תאריך ושעה תקנים.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>נא להזין תאריך חוקי.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>אנא בחר קובץ חוקי.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>השדה הנסתר אינו חוקי.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>אנא הזן מספר שלם.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>אנא בחר שפה חוקי.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>אנא בחר שפה מקומית.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>אנא הזן סכום כסף חוקי.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>אנא הזן מספר.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>הסיסמה אינה חוקית.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>אנא הזן ערך באחוזים.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>הערכים אינם תואמים.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>אנא הזן שעה חוקי.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>אנא בחר אזור זמן חוקי.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>נא להזין את כתובת אתר חוקית.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>אנא הזן מונח חיפוש חוקי.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>אנא ספק מספר טלפון חוקי.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>לתיבת הסימון יש ערך לא חוקי.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>אנא הזן כתובת דוא"ל תקנית.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>אנא בחר אפשרות חוקית.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>אנא בחר טווח חוקי.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>אנא הזן שבוע תקף.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.hr.xlf 0000644 00000015056 15120211544 0014534 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Ovaj obrazac ne smije sadržavati dodatna polja.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Prenesena datoteka je prevelika. Molim pokušajte prenijeti manju datoteku.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF vrijednost nije ispravna. Pokušajte ponovo poslati obrazac.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Ova vrijednost nije važeća HTML5 boja.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Molim upišite ispravan datum rođenja.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Odabrani izbor nije ispravan.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Kolekcija nije ispravna.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Molim odaberite ispravnu boju.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Molim odaberite ispravnu državu.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Molim odaberite ispravnu valutu.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Molim odaberite ispravni vremenski interval.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Molim unesite ispravni datum i vrijeme.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Molim odaberite ispravan datum.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Molim odaberite ispravnu datoteku.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Skriveno polje nije ispravno.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Molim unesite cijeli broj.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Molim odaberite ispravan jezik.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Molim odaberite ispravnu lokalizaciju.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Molim unesite ispravan iznos novca.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Molim unesite broj.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Ova lozinka nije ispravna.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Molim unesite vrijednost postotka.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Ove vrijednosti se ne poklapaju.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Molim unesite ispravno vrijeme.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Molim odaberite ispravnu vremensku zonu.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Molim unesite ispravan URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Molim unesite ispravan pojam za pretraživanje.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Molim navedite ispravan telefonski broj.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Polje za potvrdu sadrži neispravnu vrijednost.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Molim unesite valjanu adresu elektronske pošte.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Molim odaberite ispravnu opciju.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Molim odaberite ispravan raspon.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Molim unesite ispravni tjedan.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.hu.xlf 0000644 00000015540 15120211545 0014536 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Ez a mezőcsoport nem tartalmazhat extra mezőket.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>A feltöltött fájl túl nagy. Kérem, próbáljon egy kisebb fájlt feltölteni.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>Érvénytelen CSRF token. Kérem, próbálja újra elküldeni az űrlapot.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Ez az érték nem egy érvényes HTML5 szín.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Kérjük, adjon meg egy valós születési dátumot.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>A kiválasztott opció érvénytelen.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>A gyűjtemény érvénytelen.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Kérjük, válasszon egy érvényes színt.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Kérjük, válasszon egy érvényes országot.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Kérjük, válasszon egy érvényes pénznemet.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Kérjük, válasszon egy érvényes dátumintervallumot.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Kérjük, adjon meg egy érvényes dátumot és időpontot.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Kérjük, adjon meg egy érvényes dátumot.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Kérjük, válasszon egy érvényes fájlt.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>A rejtett mező érvénytelen.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Kérjük, adjon meg egy egész számot.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Kérjük, válasszon egy érvényes nyelvet.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Kérjük, válasszon egy érvényes területi beállítást.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Kérjük, adjon meg egy érvényes pénzösszeget.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Kérjük, adjon meg egy számot.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>A jelszó érvénytelen.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Kérjük, adjon meg egy százalékos értéket.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Az értékek nem egyeznek.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Kérjük, adjon meg egy érvényes időpontot.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Kérjük, válasszon érvényes időzónát.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Kérjük, adjon meg egy érvényes URL-t.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Kérjük, adjon meg egy érvényes keresési kifejezést.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Kérjük, adjon egy érvényes telefonszámot</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>A jelölőnégyzet értéke érvénytelen.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Kérjük valós e-mail címet adjon meg.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Kérjük, válasszon egy érvényes beállítást.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Kérjük, válasszon egy érvényes tartományt.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Kérjük, adjon meg egy érvényes hetet.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.hy.xlf 0000644 00000016776 15120211545 0014556 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Այս ձևը չպետք է պարունակի լրացուցիչ տողեր։</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Վերբեռնված ֆայլը չափազանց մեծ է. Խնդրվում է վերբեռնել ավելի փոքր չափսի ֆայլ։</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF արժեքը անթույլատրելի է. Փորձեք նորից ուղարկել ձևը։</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Այս արժեքը վավեր HTML5 գույն չէ։</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Խնդրում ենք մուտքագրել վավեր ծննդյան ամսաթիվ։</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Ընտրված ընտրությունն անվավեր է։</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Համախումբն անվավեր է։</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Խնդրում ենք ընտրել վավեր գույն։</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Խնդրում ենք ընտրել վավեր երկիր։</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Խնդրում ենք ընտրել վավեր արժույթ։</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Խնդրում ենք ընտրել ճիշտ ամսաթվերի միջակայք։</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Խնդրում ենք մուտքագրել վավեր ամսաթիվ և ժամ։</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Խնդրում ենք մուտքագրել վավեր ամսաթիվ։</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Խնդրում ենք ընտրել վավեր ֆայլ։</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Թաքնված դաշտը անվավեր է։</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Խնդրում ենք մուտքագրել ամբողջ թիվ։</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Խնդրում ենք ընտրել վավեր լեզու։</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Խնդրում ենք ընտրել վավեր տեղայնացում։</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Խնդրում ենք մուտքագրել վավեր գումար։</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Խնդրում ենք մուտքագրել համար։</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Գաղտնաբառն անվավեր է։</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Խնդրում ենք մուտքագրել տոկոսային արժեք։</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Արժեքները չեն համընկնում։</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Մուտքագրեք վավեր ժամանակ։</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Խնդրում ենք ընտրել վավեր ժամային գոտի։</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Խնդրում ենք մուտքագրել վավեր URL։</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Խնդրում ենք մուտքագրել վավեր որոնման տերմին։</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Խնդրում ենք տրամադրել վավեր հեռախոսահամար։</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Նշման վանդակը անվավեր արժեք ունի։</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Խնդրում ենք մուտքագրել վավեր էլ-հասցե։</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Խնդրում ենք ընտրել ճիշտ տարբերակ։</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Խնդրում ենք ընտրել վավեր տիրույթ։</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Մուտքագրեք վավեր շաբաթ։</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.id.xlf 0000644 00000015037 15120211545 0014517 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Gabungan kolom tidak boleh mengandung kolom tambahan.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Berkas yang di unggah terlalu besar. Silahkan coba unggah berkas yang lebih kecil.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF-Token tidak sah. Silahkan coba kirim ulang formulir.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Nilai ini bukan merupakan HTML5 color yang sah.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Silahkan masukkan tanggal lahir yang sah.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Pilihan yang dipilih tidak sah.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Koleksi tidak sah.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Silahkan pilih warna yang sah.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Silahkan pilih negara yang sah.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Silahkan pilih mata uang yang sah.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Silahkan pilih interval tanggal yang sah.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Silahkan masukkan tanggal dan waktu yang sah.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Silahkan masukkan tanggal yang sah.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Silahkan pilih berkas yang sah.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Ruas yang tersembunyi tidak sah.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Silahkan masukkan angka.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Silahlan pilih bahasa yang sah.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Silahkan pilih local yang sah.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Silahkan masukkan nilai uang yang sah.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Silahkan masukkan sebuah angka</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Kata sandi tidak sah.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Silahkan masukkan sebuah nilai persentase.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Nilainya tidak cocok.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Silahkan masukkan waktu yang sah.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Silahkan pilih zona waktu yang sah.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Silahkan masukkan URL yang sah.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Silahkan masukkan kata pencarian yang sah.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Silahkan sediakan nomor telepon yang sah.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Nilai dari checkbox tidak sah.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Silahkan masukkan alamat surel yang sah.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Silahkan pilih opsi yang sah.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Silahkan pilih rentang yang sah.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Silahkan masukkan minggu yang sah.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.it.xlf 0000644 00000015334 15120211545 0014537 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Questo form non dovrebbe contenere nessun campo extra.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Il file caricato è troppo grande. Per favore, carica un file più piccolo.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>Il token CSRF non è valido. Prova a reinviare il form.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Il valore non è un colore HTML5 valido.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Per favore, inserisci una data di compleanno valida.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>La scelta selezionata non è valida.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>La collezione non è valida.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Per favore, seleziona un colore valido.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Per favore, seleziona un paese valido.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Per favore, seleziona una valuta valida.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Per favore, scegli un intervallo di date valido.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Per favore, inserisci una data e ora valida.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Per favore, inserisci una data valida.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Per favore, seleziona un file valido.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Il campo nascosto non è valido.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Per favore, inserisci un numero intero.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Per favore, seleziona una lingua valida.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Per favore, seleziona una lingua valida.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Per favore, inserisci un importo valido.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Per favore, inserisci un numero.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>La password non è valida.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Per favore, inserisci un valore percentuale.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>I valori non corrispondono.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Per favore, inserisci un orario valido.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Per favore, seleziona un fuso orario valido.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Per favore, inserisci un URL valido.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Per favore, inserisci un termine di ricerca valido.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Per favore, indica un numero di telefono valido.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>La casella di selezione non ha un valore valido.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Per favore, indica un indirizzo email valido.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Per favore, seleziona un'opzione valida.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Per favore, seleziona un intervallo valido.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Per favore, inserisci una settimana valida.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.ja.xlf 0000644 00000016066 15120211545 0014520 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>フィールドグループに追加のフィールドを含んではなりません。</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>アップロードされたファイルが大きすぎます。小さなファイルで再度アップロードしてください。</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRFトークンが無効です、再送信してください。</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>有効なHTML5の色ではありません。</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>有効な生年月日を入力してください。</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>選択した値は無効です。</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>コレクションは無効です。</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>有効な色を選択してください。</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>有効な国を選択してください。</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>有効な通貨を選択してください。</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>有効な日付間隔を選択してください。</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>有効な日時を入力してください。</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>有効な日付を入力してください。</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>有効なファイルを選択してください。</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>隠しフィールドが無効です。</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>整数で入力してください。</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>有効な言語を選択してください。</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>有効なロケールを選択してください。</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>有効な金額を入力してください。</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>数値で入力してください。</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>パスワードが無効です。</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>パーセント値で入力してください。</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>値が一致しません。</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>有効な時間を入力してください。</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>有効なタイムゾーンを選択してください。</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>有効なURLを入力してください。</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>有効な検索語を入力してください。</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>有効な電話番号を入力してください。</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>チェックボックスの値が無効です。</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>有効なメールアドレスを入力してください。</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>有効な値を選択してください。</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>有効な範囲を選択してください。</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>有効な週を入力してください。</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.lb.xlf 0000644 00000015214 15120211545 0014515 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Dës Feldergrupp sollt keng zousätzlech Felder enthalen.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>De geschécktene Fichier ass ze grouss. Versicht wann ech gelift ee méi klenge Fichier eropzelueden.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>Den CSRF-Token ass ongëlteg. Versicht wann ech gelift de Formulaire nach eng Kéier ze schécken.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Dëse Wäert ass keng gëlteg HTML5-Faarf.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>W.e.g. e gëltege Gebuertsdatum aginn.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Den ausgewielte Choix ass ongëlteg.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>D'Kollektioun ass ongëlteg.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>W.e.g. eng gëlteg Faarf auswielen.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>W.e.g. e gëltegt Land auswielen.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>W.e.g. eng gëlteg Wärung auswielen.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>W.e.g. e gëltegen Datumsinterval aginn.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>W.e.g. eng gëlteg Datum an Zäit aginn.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>W.e.g. eng gëltegen Datum aginn.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>W.e.g. e gëltege Fichier auswielen.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Dat verstoppte Feld ass ongëlteg.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>W.e.g. eng ganz Zuel aginn.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>W.e.g. e gëltegt Sprooch auswielen.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>W.e.g. e gëltegt Regionalschema auswielen.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>W.e.g. eng gëlteg Geldzomm aginn.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>W.e.g. eng Zuel aginn.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>D'Passwuert ass ongëlteg.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>W.e.g. e Prozentwäert aginn.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>D'Wäerter stëmmen net iwwereneen.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>W.e.g. eng gëlteg Zäit aginn.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>W.e.g. eng gëlteg Zäitzon auswielen.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>W.e.g. eng gëlteg URL aginn.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>W.e.g. e gëltege Sichbegrëff aginn.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>W.e.g. eng gëlteg Telefonsnummer uginn.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>D'Ukräizfeld huet en ongëltege Wäert.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>W.e.g. eng gëlteg E-Mail-Adress aginn.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>W.e.g. eng gëlteg Optioun auswielen.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>W.e.g. eng gëlteg Spannbreet auswielen.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>W.e.g. eng gëlteg Woch aginn.</target> </trans-unit> </body> </file> </xliff> Resources/translations/validators.lt.xlf 0000644 00000015130 15120211545 0014534 0 ustar 00 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="28"> <source>This form should not contain extra fields.</source> <target>Forma negali turėti papildomų laukų.</target> </trans-unit> <trans-unit id="29"> <source>The uploaded file was too large. Please try to upload a smaller file.</source> <target>Įkelta byla yra per didelė. bandykite įkelti mažesnę.</target> </trans-unit> <trans-unit id="30"> <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF kodas nepriimtinas. Bandykite siųsti formos užklausą dar kartą.</target> </trans-unit> <trans-unit id="99"> <source>This value is not a valid HTML5 color.</source> <target>Ši reikšmė nėra HTML5 spalva.</target> </trans-unit> <trans-unit id="100"> <source>Please enter a valid birthdate.</source> <target>Prašome įvesti tinkamą gimimo datą.</target> </trans-unit> <trans-unit id="101"> <source>The selected choice is invalid.</source> <target>Pasirinktas pasirinkimas yra neteisingas.</target> </trans-unit> <trans-unit id="102"> <source>The collection is invalid.</source> <target>Neteisingas sąrašas.</target> </trans-unit> <trans-unit id="103"> <source>Please select a valid color.</source> <target>Prašome pasirinkti tinkamą spalvą.</target> </trans-unit> <trans-unit id="104"> <source>Please select a valid country.</source> <target>Prašome pasirinkti tinkamą šalį.</target> </trans-unit> <trans-unit id="105"> <source>Please select a valid currency.</source> <target>Prašome pasirinkti tinkamą valiutą.</target> </trans-unit> <trans-unit id="106"> <source>Please choose a valid date interval.</source> <target>Prašome pasirinkti tinkamą datos intervalą.</target> </trans-unit> <trans-unit id="107"> <source>Please enter a valid date and time.</source> <target>Prašome įvesti tinkamą datą ir laiką.</target> </trans-unit> <trans-unit id="108"> <source>Please enter a valid date.</source> <target>Prašome įvesti tinkamą datą.</target> </trans-unit> <trans-unit id="109"> <source>Please select a valid file.</source> <target>Prašome pasirinkti tinkamą bylą.</target> </trans-unit> <trans-unit id="110"> <source>The hidden field is invalid.</source> <target>Klaidingas paslėptasis laukas.</target> </trans-unit> <trans-unit id="111"> <source>Please enter an integer.</source> <target>Prašome įvesti sveiką skaičių.</target> </trans-unit> <trans-unit id="112"> <source>Please select a valid language.</source> <target>Prašome pasirinkti tinkamą kalbą.</target> </trans-unit> <trans-unit id="113"> <source>Please select a valid locale.</source> <target>Prašome pasirinkti tinkamą lokalę.</target> </trans-unit> <trans-unit id="114"> <source>Please enter a valid money amount.</source> <target>Prašome įvesti tinkamą pinigų sumą.</target> </trans-unit> <trans-unit id="115"> <source>Please enter a number.</source> <target>Prašome įvesti numerį.</target> </trans-unit> <trans-unit id="116"> <source>The password is invalid.</source> <target>Klaidingas slaptažodis.</target> </trans-unit> <trans-unit id="117"> <source>Please enter a percentage value.</source> <target>Prašome įvesti procentinę reikšmę.</target> </trans-unit> <trans-unit id="118"> <source>The values do not match.</source> <target>Reikšmės nesutampa.</target> </trans-unit> <trans-unit id="119"> <source>Please enter a valid time.</source> <target>Prašome įvesti tinkamą laiką.</target> </trans-unit> <trans-unit id="120"> <source>Please select a valid timezone.</source> <target>Prašome pasirinkti tinkamą laiko zoną.</target> </trans-unit> <trans-unit id="121"> <source>Please enter a valid URL.</source> <target>Prašome įvesti tinkamą URL.</target> </trans-unit> <trans-unit id="122"> <source>Please enter a valid search term.</source> <target>Prašome įvesti tinkamą paieškos terminą.</target> </trans-unit> <trans-unit id="123"> <source>Please provide a valid phone number.</source> <target>Prašome pateikti tinkamą telefono numerį.</target> </trans-unit> <trans-unit id="124"> <source>The checkbox has an invalid value.</source> <target>Klaidinga žymimajo langelio reikšmė.</target> </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> <target>Prašome įvesti tinkamą el. pašto adresą.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> <target>Prašome pasirinkti tinkamą parinktį.</target> </trans-unit> <trans-unit id="127"> <source>Please select a valid range.</source> <target>Prašome pasirinkti tinkamą diapozoną.</target> </trans-unit> <trans-unit id="128"> <source>Please enter a valid week.</source> <target>Prašome įvesti tinkamą savaitę.</target> </trans-unit> </body> </file> </xliff> Test/Traits/ValidatorExtensionTrait.php 0000644 00000003241 15120211545 0014264 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Test\Traits; use Symfony\Component\Form\Extension\Validator\ValidatorExtension; use Symfony\Component\Form\Test\TypeTestCase; use Symfony\Component\Validator\ConstraintViolationList; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Validator\ValidatorInterface; trait ValidatorExtensionTrait { /** * @var ValidatorInterface|null */ protected $validator; protected function getValidatorExtension(): ValidatorExtension { if (!interface_exists(ValidatorInterface::class)) { throw new \Exception('In order to use the "ValidatorExtensionTrait", the symfony/validator component must be installed.'); } if (!$this instanceof TypeTestCase) { throw new \Exception(sprintf('The trait "ValidatorExtensionTrait" can only be added to a class that extends "%s".', TypeTestCase::class)); } $this->validator = $this->createMock(ValidatorInterface::class); $metadata = $this->getMockBuilder(ClassMetadata::class)->setConstructorArgs([''])->onlyMethods(['addPropertyConstraint'])->getMock(); $this->validator->expects($this->any())->method('getMetadataFor')->will($this->returnValue($metadata)); $this->validator->expects($this->any())->method('validate')->will($this->returnValue(new ConstraintViolationList())); return new ValidatorExtension($this->validator, false); } } Test/FormBuilderInterface.php 0000644 00000000663 15120211545 0012230 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Test; use Symfony\Component\Form\FormBuilderInterface as BaseFormBuilderInterface; interface FormBuilderInterface extends \Iterator, BaseFormBuilderInterface { } Test/FormIntegrationTestCase.php 0000644 00000002306 15120211545 0012734 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Test; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\Forms; /** * @author Bernhard Schussek <bschussek@gmail.com> */ abstract class FormIntegrationTestCase extends TestCase { /** * @var FormFactoryInterface */ protected $factory; protected function setUp(): void { $this->factory = Forms::createFormFactoryBuilder() ->addExtensions($this->getExtensions()) ->addTypeExtensions($this->getTypeExtensions()) ->addTypes($this->getTypes()) ->addTypeGuessers($this->getTypeGuessers()) ->getFormFactory(); } protected function getExtensions() { return []; } protected function getTypeExtensions() { return []; } protected function getTypes() { return []; } protected function getTypeGuessers() { return []; } } Test/FormInterface.php 0000644 00000000627 15120211545 0010721 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Test; use Symfony\Component\Form\FormInterface as BaseFormInterface; interface FormInterface extends \Iterator, BaseFormInterface { } Test/FormPerformanceTestCase.php 0000644 00000002642 15120211545 0012715 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Test; use Symfony\Component\Form\Tests\VersionAwareTest; /** * Base class for performance tests. * * Copied from Doctrine 2's OrmPerformanceTestCase. * * @author robo * @author Bernhard Schussek <bschussek@gmail.com> */ abstract class FormPerformanceTestCase extends FormIntegrationTestCase { use VersionAwareTest; /** * @var int */ protected $maxRunningTime = 0; /** * {@inheritdoc} */ protected function runTest() { $s = microtime(true); parent::runTest(); $time = microtime(true) - $s; if (0 != $this->maxRunningTime && $time > $this->maxRunningTime) { $this->fail(sprintf('expected running time: <= %s but was: %s', $this->maxRunningTime, $time)); } } /** * @throws \InvalidArgumentException */ public function setMaxRunningTime(int $maxRunningTime) { if ($maxRunningTime < 0) { throw new \InvalidArgumentException(); } $this->maxRunningTime = $maxRunningTime; } /** * @return int */ public function getMaxRunningTime() { return $this->maxRunningTime; } } Test/TypeTestCase.php 0000644 00000003305 15120211545 0010546 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Test; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\Test\Traits\ValidatorExtensionTrait; abstract class TypeTestCase extends FormIntegrationTestCase { /** * @var FormBuilder */ protected $builder; /** * @var EventDispatcherInterface */ protected $dispatcher; protected function setUp(): void { parent::setUp(); $this->dispatcher = $this->createMock(EventDispatcherInterface::class); $this->builder = new FormBuilder('', null, $this->dispatcher, $this->factory); } protected function tearDown(): void { if (\in_array(ValidatorExtensionTrait::class, class_uses($this))) { $this->validator = null; } } protected function getExtensions() { $extensions = []; if (\in_array(ValidatorExtensionTrait::class, class_uses($this))) { $extensions[] = $this->getValidatorExtension(); } return $extensions; } public static function assertDateTimeEquals(\DateTime $expected, \DateTime $actual) { self::assertEquals($expected->format('c'), $actual->format('c')); } public static function assertDateIntervalEquals(\DateInterval $expected, \DateInterval $actual) { self::assertEquals($expected->format('%RP%yY%mM%dDT%hH%iM%sS'), $actual->format('%RP%yY%mM%dDT%hH%iM%sS')); } } Util/FormUtil.php 0000644 00000002043 15120211545 0007726 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Util; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class FormUtil { /** * This class should not be instantiated. */ private function __construct() { } /** * Returns whether the given data is empty. * * This logic is reused multiple times throughout the processing of * a form and needs to be consistent. PHP keyword `empty` cannot * be used as it also considers 0 and "0" to be empty. * * @param mixed $data * * @return bool */ public static function isEmpty($data) { // Should not do a check for [] === $data!!! // This method is used in occurrences where arrays are // not considered to be empty, ever. return null === $data || '' === $data; } } Util/InheritDataAwareIterator.php 0000644 00000002174 15120211545 0013060 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Util; /** * Iterator that traverses an array of forms. * * Contrary to \ArrayIterator, this iterator recognizes changes in the original * array during iteration. * * You can wrap the iterator into a {@link \RecursiveIteratorIterator} in order to * enter any child form that inherits its parent's data and iterate the children * of that form as well. * * @author Bernhard Schussek <bschussek@gmail.com> */ class InheritDataAwareIterator extends \IteratorIterator implements \RecursiveIterator { /** * {@inheritdoc} * * @return static */ #[\ReturnTypeWillChange] public function getChildren() { return new static($this->current()); } /** * @return bool */ #[\ReturnTypeWillChange] public function hasChildren() { return (bool) $this->current()->getConfig()->getInheritData(); } } Util/OptionsResolverWrapper.php 0000644 00000005067 15120211545 0012714 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Util; use Symfony\Component\OptionsResolver\Exception\AccessException; use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException; use Symfony\Component\OptionsResolver\OptionsResolver; /** * @author Yonel Ceruto <yonelceruto@gmail.com> * * @internal */ class OptionsResolverWrapper extends OptionsResolver { private $undefined = []; /** * @return $this */ public function setNormalizer(string $option, \Closure $normalizer): self { try { parent::setNormalizer($option, $normalizer); } catch (UndefinedOptionsException $e) { $this->undefined[$option] = true; } return $this; } /** * @return $this */ public function setAllowedValues(string $option, $allowedValues): self { try { parent::setAllowedValues($option, $allowedValues); } catch (UndefinedOptionsException $e) { $this->undefined[$option] = true; } return $this; } /** * @return $this */ public function addAllowedValues(string $option, $allowedValues): self { try { parent::addAllowedValues($option, $allowedValues); } catch (UndefinedOptionsException $e) { $this->undefined[$option] = true; } return $this; } /** * @param string|array $allowedTypes * * @return $this */ public function setAllowedTypes(string $option, $allowedTypes): self { try { parent::setAllowedTypes($option, $allowedTypes); } catch (UndefinedOptionsException $e) { $this->undefined[$option] = true; } return $this; } /** * @param string|array $allowedTypes * * @return $this */ public function addAllowedTypes(string $option, $allowedTypes): self { try { parent::addAllowedTypes($option, $allowedTypes); } catch (UndefinedOptionsException $e) { $this->undefined[$option] = true; } return $this; } public function resolve(array $options = []): array { throw new AccessException('Resolve options is not supported.'); } public function getUndefinedOptions(): array { return array_keys($this->undefined); } } Util/OrderedHashMap.php 0000644 00000011471 15120211545 0011020 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Util; /** * A hash map which keeps track of deletions and additions. * * Like in associative arrays, elements can be mapped to integer or string keys. * Unlike associative arrays, the map keeps track of the order in which keys * were added and removed. This order is reflected during iteration. * * The map supports concurrent modification during iteration. That means that * you can insert and remove elements from within a foreach loop and the * iterator will reflect those changes accordingly. * * While elements that are added during the loop are recognized by the iterator, * changed elements are not. Otherwise the loop could be infinite if each loop * changes the current element: * * $map = new OrderedHashMap(); * $map[1] = 1; * $map[2] = 2; * $map[3] = 3; * * foreach ($map as $index => $value) { * echo "$index: $value\n" * if (1 === $index) { * $map[1] = 4; * $map[] = 5; * } * } * * print_r(iterator_to_array($map)); * * // => 1: 1 * // 2: 2 * // 3: 3 * // 4: 5 * // Array * // ( * // [1] => 4 * // [2] => 2 * // [3] => 3 * // [4] => 5 * // ) * * The map also supports multiple parallel iterators. That means that you can * nest foreach loops without affecting each other's iteration: * * foreach ($map as $index => $value) { * foreach ($map as $index2 => $value2) { * // ... * } * } * * @author Bernhard Schussek <bschussek@gmail.com> * * @template TKey of array-key * @template TValue * * @implements \ArrayAccess<TKey, TValue> * @implements \IteratorAggregate<TKey, TValue> */ class OrderedHashMap implements \ArrayAccess, \IteratorAggregate, \Countable { /** * The elements of the map, indexed by their keys. * * @var array<TKey, TValue> */ private $elements = []; /** * The keys of the map in the order in which they were inserted or changed. * * @var list<TKey> */ private $orderedKeys = []; /** * References to the cursors of all open iterators. * * @var array<int, int> */ private $managedCursors = []; /** * Creates a new map. * * @param array<TKey, TValue> $elements The elements to insert initially */ public function __construct(array $elements = []) { $this->elements = $elements; $this->orderedKeys = array_keys($elements); } /** * @return bool */ #[\ReturnTypeWillChange] public function offsetExists($key) { return isset($this->elements[$key]); } /** * {@inheritdoc} * * @return TValue */ #[\ReturnTypeWillChange] public function offsetGet($key) { if (!isset($this->elements[$key])) { throw new \OutOfBoundsException(sprintf('The offset "%s" does not exist.', $key)); } return $this->elements[$key]; } /** * {@inheritdoc} * * @return void */ #[\ReturnTypeWillChange] public function offsetSet($key, $value) { if (null === $key || !isset($this->elements[$key])) { if (null === $key) { $key = [] === $this->orderedKeys // If the array is empty, use 0 as key ? 0 // Imitate PHP behavior of generating a key that equals // the highest existing integer key + 1 : 1 + (int) max($this->orderedKeys); } $this->orderedKeys[] = (string) $key; } $this->elements[$key] = $value; } /** * {@inheritdoc} * * @return void */ #[\ReturnTypeWillChange] public function offsetUnset($key) { if (false !== ($position = array_search((string) $key, $this->orderedKeys))) { array_splice($this->orderedKeys, $position, 1); unset($this->elements[$key]); foreach ($this->managedCursors as $i => $cursor) { if ($cursor >= $position) { --$this->managedCursors[$i]; } } } } /** * @return \Traversable<TKey, TValue> */ #[\ReturnTypeWillChange] public function getIterator() { return new OrderedHashMapIterator($this->elements, $this->orderedKeys, $this->managedCursors); } /** * @return int */ #[\ReturnTypeWillChange] public function count() { return \count($this->elements); } } Util/OrderedHashMapIterator.php 0000644 00000007776 15120211545 0012547 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Util; /** * Iterator for {@link OrderedHashMap} objects. * * @author Bernhard Schussek <bschussek@gmail.com> * * @internal * * @template-covariant TKey of array-key * @template-covariant TValue * * @implements \Iterator<TKey, TValue> */ class OrderedHashMapIterator implements \Iterator { /** * @var array<TKey, TValue> */ private $elements; /** * @var list<TKey> */ private $orderedKeys; /** * @var int */ private $cursor = 0; /** * @var int */ private $cursorId; /** * @var array<int, int> */ private $managedCursors; /** * @var TKey|null */ private $key; /** * @var TValue|null */ private $current; /** * @param array<TKey, TValue> $elements The elements of the map, indexed by their * keys * @param list<TKey> $orderedKeys The keys of the map in the order in which * they should be iterated * @param array<int, int> $managedCursors An array from which to reference the * iterator's cursor as long as it is alive. * This array is managed by the corresponding * {@link OrderedHashMap} instance to support * recognizing the deletion of elements. */ public function __construct(array &$elements, array &$orderedKeys, array &$managedCursors) { $this->elements = &$elements; $this->orderedKeys = &$orderedKeys; $this->managedCursors = &$managedCursors; $this->cursorId = \count($managedCursors); $this->managedCursors[$this->cursorId] = &$this->cursor; } public function __sleep(): array { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } public function __wakeup() { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } /** * Removes the iterator's cursors from the managed cursors of the * corresponding {@link OrderedHashMap} instance. */ public function __destruct() { // Use array_splice() instead of unset() to prevent holes in the // array indices, which would break the initialization of $cursorId array_splice($this->managedCursors, $this->cursorId, 1); } /** * {@inheritdoc} * * @return mixed */ #[\ReturnTypeWillChange] public function current() { return $this->current; } /** * {@inheritdoc} */ public function next(): void { ++$this->cursor; if (isset($this->orderedKeys[$this->cursor])) { $this->key = $this->orderedKeys[$this->cursor]; $this->current = $this->elements[$this->key]; } else { $this->key = null; $this->current = null; } } /** * {@inheritdoc} * * @return mixed */ #[\ReturnTypeWillChange] public function key() { if (null === $this->key) { return null; } $array = [$this->key => null]; return key($array); } /** * {@inheritdoc} */ public function valid(): bool { return null !== $this->key; } /** * {@inheritdoc} */ public function rewind(): void { $this->cursor = 0; if (isset($this->orderedKeys[0])) { $this->key = $this->orderedKeys[0]; $this->current = $this->elements[$this->key]; } else { $this->key = null; $this->current = null; } } } Util/ServerParams.php 0000644 00000004577 15120211545 0010615 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Util; use Symfony\Component\HttpFoundation\RequestStack; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class ServerParams { private $requestStack; public function __construct(RequestStack $requestStack = null) { $this->requestStack = $requestStack; } /** * Returns true if the POST max size has been exceeded in the request. * * @return bool */ public function hasPostMaxSizeBeenExceeded() { $contentLength = $this->getContentLength(); $maxContentLength = $this->getPostMaxSize(); return $maxContentLength && $contentLength > $maxContentLength; } /** * Returns maximum post size in bytes. * * @return int|float|null */ public function getPostMaxSize() { $iniMax = strtolower($this->getNormalizedIniPostMaxSize()); if ('' === $iniMax) { return null; } $max = ltrim($iniMax, '+'); if (str_starts_with($max, '0x')) { $max = \intval($max, 16); } elseif (str_starts_with($max, '0')) { $max = \intval($max, 8); } else { $max = (int) $max; } switch (substr($iniMax, -1)) { case 't': $max *= 1024; // no break case 'g': $max *= 1024; // no break case 'm': $max *= 1024; // no break case 'k': $max *= 1024; } return $max; } /** * Returns the normalized "post_max_size" ini setting. * * @return string */ public function getNormalizedIniPostMaxSize() { return strtoupper(trim(\ini_get('post_max_size'))); } /** * Returns the content length of the request. * * @return mixed */ public function getContentLength() { if (null !== $this->requestStack && null !== $request = $this->requestStack->getCurrentRequest()) { return $request->server->get('CONTENT_LENGTH'); } return isset($_SERVER['CONTENT_LENGTH']) ? (int) $_SERVER['CONTENT_LENGTH'] : null; } } Util/StringUtil.php 0000644 00000002541 15120211545 0010274 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Util; /** * @author Issei Murasawa <issei.m7@gmail.com> * @author Bernhard Schussek <bschussek@gmail.com> */ class StringUtil { /** * This class should not be instantiated. */ private function __construct() { } /** * Returns the trimmed data. * * @return string */ public static function trim(string $string) { if (null !== $result = @preg_replace('/^[\pZ\p{Cc}\p{Cf}]+|[\pZ\p{Cc}\p{Cf}]+$/u', '', $string)) { return $result; } return trim($string); } /** * Converts a fully-qualified class name to a block prefix. * * @param string $fqcn The fully-qualified class name * * @return string|null */ public static function fqcnToBlockPrefix(string $fqcn) { // Non-greedy ("+?") to match "type" suffix, if present if (preg_match('~([^\\\\]+?)(type)?$~i', $fqcn, $matches)) { return strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], ['\\1_\\2', '\\1_\\2'], $matches[1])); } return null; } } AbstractExtension.php 0000644 00000011130 15120211545 0010705 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Exception\UnexpectedTypeException; /** * @author Bernhard Schussek <bschussek@gmail.com> */ abstract class AbstractExtension implements FormExtensionInterface { /** * The types provided by this extension. * * @var FormTypeInterface[] */ private $types; /** * The type extensions provided by this extension. * * @var FormTypeExtensionInterface[][] */ private $typeExtensions; /** * The type guesser provided by this extension. * * @var FormTypeGuesserInterface|null */ private $typeGuesser; /** * Whether the type guesser has been loaded. * * @var bool */ private $typeGuesserLoaded = false; /** * {@inheritdoc} */ public function getType(string $name) { if (null === $this->types) { $this->initTypes(); } if (!isset($this->types[$name])) { throw new InvalidArgumentException(sprintf('The type "%s" cannot be loaded by this extension.', $name)); } return $this->types[$name]; } /** * {@inheritdoc} */ public function hasType(string $name) { if (null === $this->types) { $this->initTypes(); } return isset($this->types[$name]); } /** * {@inheritdoc} */ public function getTypeExtensions(string $name) { if (null === $this->typeExtensions) { $this->initTypeExtensions(); } return $this->typeExtensions[$name] ?? []; } /** * {@inheritdoc} */ public function hasTypeExtensions(string $name) { if (null === $this->typeExtensions) { $this->initTypeExtensions(); } return isset($this->typeExtensions[$name]) && \count($this->typeExtensions[$name]) > 0; } /** * {@inheritdoc} */ public function getTypeGuesser() { if (!$this->typeGuesserLoaded) { $this->initTypeGuesser(); } return $this->typeGuesser; } /** * Registers the types. * * @return FormTypeInterface[] */ protected function loadTypes() { return []; } /** * Registers the type extensions. * * @return FormTypeExtensionInterface[] */ protected function loadTypeExtensions() { return []; } /** * Registers the type guesser. * * @return FormTypeGuesserInterface|null */ protected function loadTypeGuesser() { return null; } /** * Initializes the types. * * @throws UnexpectedTypeException if any registered type is not an instance of FormTypeInterface */ private function initTypes() { $this->types = []; foreach ($this->loadTypes() as $type) { if (!$type instanceof FormTypeInterface) { throw new UnexpectedTypeException($type, FormTypeInterface::class); } $this->types[\get_class($type)] = $type; } } /** * Initializes the type extensions. * * @throws UnexpectedTypeException if any registered type extension is not * an instance of FormTypeExtensionInterface */ private function initTypeExtensions() { $this->typeExtensions = []; foreach ($this->loadTypeExtensions() as $extension) { if (!$extension instanceof FormTypeExtensionInterface) { throw new UnexpectedTypeException($extension, FormTypeExtensionInterface::class); } foreach ($extension::getExtendedTypes() as $extendedType) { $this->typeExtensions[$extendedType][] = $extension; } } } /** * Initializes the type guesser. * * @throws UnexpectedTypeException if the type guesser is not an instance of FormTypeGuesserInterface */ private function initTypeGuesser() { $this->typeGuesserLoaded = true; $this->typeGuesser = $this->loadTypeGuesser(); if (null !== $this->typeGuesser && !$this->typeGuesser instanceof FormTypeGuesserInterface) { throw new UnexpectedTypeException($this->typeGuesser, FormTypeGuesserInterface::class); } } } AbstractRendererEngine.php 0000644 00000015773 15120211545 0011646 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Contracts\Service\ResetInterface; /** * Default implementation of {@link FormRendererEngineInterface}. * * @author Bernhard Schussek <bschussek@gmail.com> */ abstract class AbstractRendererEngine implements FormRendererEngineInterface, ResetInterface { /** * The variable in {@link FormView} used as cache key. */ public const CACHE_KEY_VAR = 'cache_key'; /** * @var array */ protected $defaultThemes; /** * @var array[] */ protected $themes = []; /** * @var bool[] */ protected $useDefaultThemes = []; /** * @var array[] */ protected $resources = []; /** * @var array<array<int|false>> */ private $resourceHierarchyLevels = []; /** * Creates a new renderer engine. * * @param array $defaultThemes The default themes. The type of these * themes is open to the implementation. */ public function __construct(array $defaultThemes = []) { $this->defaultThemes = $defaultThemes; } /** * {@inheritdoc} */ public function setTheme(FormView $view, $themes, bool $useDefaultThemes = true) { $cacheKey = $view->vars[self::CACHE_KEY_VAR]; // Do not cast, as casting turns objects into arrays of properties $this->themes[$cacheKey] = \is_array($themes) ? $themes : [$themes]; $this->useDefaultThemes[$cacheKey] = $useDefaultThemes; // Unset instead of resetting to an empty array, in order to allow // implementations (like TwigRendererEngine) to check whether $cacheKey // is set at all. unset($this->resources[$cacheKey], $this->resourceHierarchyLevels[$cacheKey]); } /** * {@inheritdoc} */ public function getResourceForBlockName(FormView $view, string $blockName) { $cacheKey = $view->vars[self::CACHE_KEY_VAR]; if (!isset($this->resources[$cacheKey][$blockName])) { $this->loadResourceForBlockName($cacheKey, $view, $blockName); } return $this->resources[$cacheKey][$blockName]; } /** * {@inheritdoc} */ public function getResourceForBlockNameHierarchy(FormView $view, array $blockNameHierarchy, int $hierarchyLevel) { $cacheKey = $view->vars[self::CACHE_KEY_VAR]; $blockName = $blockNameHierarchy[$hierarchyLevel]; if (!isset($this->resources[$cacheKey][$blockName])) { $this->loadResourceForBlockNameHierarchy($cacheKey, $view, $blockNameHierarchy, $hierarchyLevel); } return $this->resources[$cacheKey][$blockName]; } /** * {@inheritdoc} */ public function getResourceHierarchyLevel(FormView $view, array $blockNameHierarchy, int $hierarchyLevel) { $cacheKey = $view->vars[self::CACHE_KEY_VAR]; $blockName = $blockNameHierarchy[$hierarchyLevel]; if (!isset($this->resources[$cacheKey][$blockName])) { $this->loadResourceForBlockNameHierarchy($cacheKey, $view, $blockNameHierarchy, $hierarchyLevel); } // If $block was previously rendered loaded with loadTemplateForBlock(), the template // is cached but the hierarchy level is not. In this case, we know that the block // exists at this very hierarchy level, so we can just set it. if (!isset($this->resourceHierarchyLevels[$cacheKey][$blockName])) { $this->resourceHierarchyLevels[$cacheKey][$blockName] = $hierarchyLevel; } return $this->resourceHierarchyLevels[$cacheKey][$blockName]; } /** * Loads the cache with the resource for a given block name. * * @see getResourceForBlock() * * @return bool */ abstract protected function loadResourceForBlockName(string $cacheKey, FormView $view, string $blockName); /** * Loads the cache with the resource for a specific level of a block hierarchy. * * @see getResourceForBlockHierarchy() */ private function loadResourceForBlockNameHierarchy(string $cacheKey, FormView $view, array $blockNameHierarchy, int $hierarchyLevel): bool { $blockName = $blockNameHierarchy[$hierarchyLevel]; // Try to find a template for that block if ($this->loadResourceForBlockName($cacheKey, $view, $blockName)) { // If loadTemplateForBlock() returns true, it was able to populate the // cache. The only missing thing is to set the hierarchy level at which // the template was found. $this->resourceHierarchyLevels[$cacheKey][$blockName] = $hierarchyLevel; return true; } if ($hierarchyLevel > 0) { $parentLevel = $hierarchyLevel - 1; $parentBlockName = $blockNameHierarchy[$parentLevel]; // The next two if statements contain slightly duplicated code. This is by intention // and tries to avoid execution of unnecessary checks in order to increase performance. if (isset($this->resources[$cacheKey][$parentBlockName])) { // It may happen that the parent block is already loaded, but its level is not. // In this case, the parent block must have been loaded by loadResourceForBlock(), // which does not check the hierarchy of the block. Subsequently the block must have // been found directly on the parent level. if (!isset($this->resourceHierarchyLevels[$cacheKey][$parentBlockName])) { $this->resourceHierarchyLevels[$cacheKey][$parentBlockName] = $parentLevel; } // Cache the shortcuts for further accesses $this->resources[$cacheKey][$blockName] = $this->resources[$cacheKey][$parentBlockName]; $this->resourceHierarchyLevels[$cacheKey][$blockName] = $this->resourceHierarchyLevels[$cacheKey][$parentBlockName]; return true; } if ($this->loadResourceForBlockNameHierarchy($cacheKey, $view, $blockNameHierarchy, $parentLevel)) { // Cache the shortcuts for further accesses $this->resources[$cacheKey][$blockName] = $this->resources[$cacheKey][$parentBlockName]; $this->resourceHierarchyLevels[$cacheKey][$blockName] = $this->resourceHierarchyLevels[$cacheKey][$parentBlockName]; return true; } } // Cache the result for further accesses $this->resources[$cacheKey][$blockName] = false; $this->resourceHierarchyLevels[$cacheKey][$blockName] = false; return false; } public function reset(): void { $this->themes = []; $this->useDefaultThemes = []; $this->resources = []; $this->resourceHierarchyLevels = []; } } AbstractType.php 0000644 00000002455 15120211545 0007664 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Util\StringUtil; use Symfony\Component\OptionsResolver\OptionsResolver; /** * @author Bernhard Schussek <bschussek@gmail.com> */ abstract class AbstractType implements FormTypeInterface { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { } /** * {@inheritdoc} */ public function finishView(FormView $view, FormInterface $form, array $options) { } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { } /** * {@inheritdoc} */ public function getBlockPrefix() { return StringUtil::fqcnToBlockPrefix(static::class) ?: ''; } /** * {@inheritdoc} */ public function getParent() { return FormType::class; } } AbstractTypeExtension.php 0000644 00000001716 15120211545 0011560 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\OptionsResolver\OptionsResolver; /** * @author Bernhard Schussek <bschussek@gmail.com> */ abstract class AbstractTypeExtension implements FormTypeExtensionInterface { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options) { } /** * {@inheritdoc} */ public function finishView(FormView $view, FormInterface $form, array $options) { } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { } } Button.php 0000644 00000021057 15120211545 0006531 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\AlreadySubmittedException; use Symfony\Component\Form\Exception\BadMethodCallException; /** * A form button. * * @author Bernhard Schussek <bschussek@gmail.com> * * @implements \IteratorAggregate<string, FormInterface> */ class Button implements \IteratorAggregate, FormInterface { /** * @var FormInterface|null */ private $parent; /** * @var FormConfigInterface */ private $config; /** * @var bool */ private $submitted = false; /** * Creates a new button from a form configuration. */ public function __construct(FormConfigInterface $config) { $this->config = $config; } /** * Unsupported method. * * @param string $offset * * @return bool */ #[\ReturnTypeWillChange] public function offsetExists($offset) { return false; } /** * Unsupported method. * * This method should not be invoked. * * @param string $offset * * @return FormInterface * * @throws BadMethodCallException */ #[\ReturnTypeWillChange] public function offsetGet($offset) { throw new BadMethodCallException('Buttons cannot have children.'); } /** * Unsupported method. * * This method should not be invoked. * * @param string $offset * @param FormInterface $value * * @return void * * @throws BadMethodCallException */ #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { throw new BadMethodCallException('Buttons cannot have children.'); } /** * Unsupported method. * * This method should not be invoked. * * @param string $offset * * @return void * * @throws BadMethodCallException */ #[\ReturnTypeWillChange] public function offsetUnset($offset) { throw new BadMethodCallException('Buttons cannot have children.'); } /** * {@inheritdoc} */ public function setParent(FormInterface $parent = null) { if ($this->submitted) { throw new AlreadySubmittedException('You cannot set the parent of a submitted button.'); } $this->parent = $parent; return $this; } /** * {@inheritdoc} */ public function getParent() { return $this->parent; } /** * Unsupported method. * * This method should not be invoked. * * @throws BadMethodCallException */ public function add($child, string $type = null, array $options = []) { throw new BadMethodCallException('Buttons cannot have children.'); } /** * Unsupported method. * * This method should not be invoked. * * @throws BadMethodCallException */ public function get(string $name) { throw new BadMethodCallException('Buttons cannot have children.'); } /** * Unsupported method. * * @return bool */ public function has(string $name) { return false; } /** * Unsupported method. * * This method should not be invoked. * * @throws BadMethodCallException */ public function remove(string $name) { throw new BadMethodCallException('Buttons cannot have children.'); } /** * {@inheritdoc} */ public function all() { return []; } /** * {@inheritdoc} */ public function getErrors(bool $deep = false, bool $flatten = true) { return new FormErrorIterator($this, []); } /** * Unsupported method. * * This method should not be invoked. * * @param mixed $modelData * * @return $this */ public function setData($modelData) { // no-op, called during initialization of the form tree return $this; } /** * Unsupported method. */ public function getData() { return null; } /** * Unsupported method. */ public function getNormData() { return null; } /** * Unsupported method. */ public function getViewData() { return null; } /** * Unsupported method. * * @return array */ public function getExtraData() { return []; } /** * Returns the button's configuration. * * @return FormConfigInterface */ public function getConfig() { return $this->config; } /** * Returns whether the button is submitted. * * @return bool */ public function isSubmitted() { return $this->submitted; } /** * Returns the name by which the button is identified in forms. * * @return string */ public function getName() { return $this->config->getName(); } /** * Unsupported method. */ public function getPropertyPath() { return null; } /** * Unsupported method. * * @throws BadMethodCallException */ public function addError(FormError $error) { throw new BadMethodCallException('Buttons cannot have errors.'); } /** * Unsupported method. * * @return bool */ public function isValid() { return true; } /** * Unsupported method. * * @return bool */ public function isRequired() { return false; } /** * {@inheritdoc} */ public function isDisabled() { if ($this->parent && $this->parent->isDisabled()) { return true; } return $this->config->getDisabled(); } /** * Unsupported method. * * @return bool */ public function isEmpty() { return true; } /** * Unsupported method. * * @return bool */ public function isSynchronized() { return true; } /** * Unsupported method. */ public function getTransformationFailure() { return null; } /** * Unsupported method. * * @throws BadMethodCallException */ public function initialize() { throw new BadMethodCallException('Buttons cannot be initialized. Call initialize() on the root form instead.'); } /** * Unsupported method. * * @param mixed $request * * @throws BadMethodCallException */ public function handleRequest($request = null) { throw new BadMethodCallException('Buttons cannot handle requests. Call handleRequest() on the root form instead.'); } /** * Submits data to the button. * * @param array|string|null $submittedData Not used * @param bool $clearMissing Not used * * @return $this * * @throws Exception\AlreadySubmittedException if the button has already been submitted */ public function submit($submittedData, bool $clearMissing = true) { if ($this->submitted) { throw new AlreadySubmittedException('A form can only be submitted once.'); } $this->submitted = true; return $this; } /** * {@inheritdoc} */ public function getRoot() { return $this->parent ? $this->parent->getRoot() : $this; } /** * {@inheritdoc} */ public function isRoot() { return null === $this->parent; } /** * {@inheritdoc} */ public function createView(FormView $parent = null) { if (null === $parent && $this->parent) { $parent = $this->parent->createView(); } $type = $this->config->getType(); $options = $this->config->getOptions(); $view = $type->createView($this, $parent); $type->buildView($view, $this, $options); $type->finishView($view, $this, $options); return $view; } /** * Unsupported method. * * @return int */ #[\ReturnTypeWillChange] public function count() { return 0; } /** * Unsupported method. * * @return \EmptyIterator */ #[\ReturnTypeWillChange] public function getIterator() { return new \EmptyIterator(); } } ButtonBuilder.php 0000644 00000035623 15120211545 0010044 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\Exception\BadMethodCallException; use Symfony\Component\Form\Exception\InvalidArgumentException; /** * A builder for {@link Button} instances. * * @author Bernhard Schussek <bschussek@gmail.com> * * @implements \IteratorAggregate<string, FormBuilderInterface> */ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface { protected $locked = false; /** * @var bool */ private $disabled = false; /** * @var ResolvedFormTypeInterface */ private $type; /** * @var string */ private $name; /** * @var array */ private $attributes = []; /** * @var array */ private $options; /** * @throws InvalidArgumentException if the name is empty */ public function __construct(?string $name, array $options = []) { if ('' === $name || null === $name) { throw new InvalidArgumentException('Buttons cannot have empty names.'); } $this->name = $name; $this->options = $options; FormConfigBuilder::validateName($name); } /** * Unsupported method. * * @throws BadMethodCallException */ public function add($child, string $type = null, array $options = []) { throw new BadMethodCallException('Buttons cannot have children.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function create(string $name, string $type = null, array $options = []) { throw new BadMethodCallException('Buttons cannot have children.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function get(string $name) { throw new BadMethodCallException('Buttons cannot have children.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function remove(string $name) { throw new BadMethodCallException('Buttons cannot have children.'); } /** * Unsupported method. * * @return bool */ public function has(string $name) { return false; } /** * Returns the children. * * @return array */ public function all() { return []; } /** * Creates the button. * * @return Button */ public function getForm() { return new Button($this->getFormConfig()); } /** * Unsupported method. * * @throws BadMethodCallException */ public function addEventListener(string $eventName, callable $listener, int $priority = 0) { throw new BadMethodCallException('Buttons do not support event listeners.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function addEventSubscriber(EventSubscriberInterface $subscriber) { throw new BadMethodCallException('Buttons do not support event subscribers.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function addViewTransformer(DataTransformerInterface $viewTransformer, bool $forcePrepend = false) { throw new BadMethodCallException('Buttons do not support data transformers.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function resetViewTransformers() { throw new BadMethodCallException('Buttons do not support data transformers.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function addModelTransformer(DataTransformerInterface $modelTransformer, bool $forceAppend = false) { throw new BadMethodCallException('Buttons do not support data transformers.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function resetModelTransformers() { throw new BadMethodCallException('Buttons do not support data transformers.'); } /** * {@inheritdoc} */ public function setAttribute(string $name, $value) { $this->attributes[$name] = $value; return $this; } /** * {@inheritdoc} */ public function setAttributes(array $attributes) { $this->attributes = $attributes; return $this; } /** * Unsupported method. * * @throws BadMethodCallException */ public function setDataMapper(DataMapperInterface $dataMapper = null) { throw new BadMethodCallException('Buttons do not support data mappers.'); } /** * Set whether the button is disabled. * * @return $this */ public function setDisabled(bool $disabled) { $this->disabled = $disabled; return $this; } /** * Unsupported method. * * @throws BadMethodCallException */ public function setEmptyData($emptyData) { throw new BadMethodCallException('Buttons do not support empty data.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function setErrorBubbling(bool $errorBubbling) { throw new BadMethodCallException('Buttons do not support error bubbling.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function setRequired(bool $required) { throw new BadMethodCallException('Buttons cannot be required.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function setPropertyPath($propertyPath) { throw new BadMethodCallException('Buttons do not support property paths.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function setMapped(bool $mapped) { throw new BadMethodCallException('Buttons do not support data mapping.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function setByReference(bool $byReference) { throw new BadMethodCallException('Buttons do not support data mapping.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function setCompound(bool $compound) { throw new BadMethodCallException('Buttons cannot be compound.'); } /** * Sets the type of the button. * * @return $this */ public function setType(ResolvedFormTypeInterface $type) { $this->type = $type; return $this; } /** * Unsupported method. * * @throws BadMethodCallException */ public function setData($data) { throw new BadMethodCallException('Buttons do not support data.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function setDataLocked(bool $locked) { throw new BadMethodCallException('Buttons do not support data locking.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function setFormFactory(FormFactoryInterface $formFactory) { throw new BadMethodCallException('Buttons do not support form factories.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function setAction(string $action) { throw new BadMethodCallException('Buttons do not support actions.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function setMethod(string $method) { throw new BadMethodCallException('Buttons do not support methods.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function setRequestHandler(RequestHandlerInterface $requestHandler) { throw new BadMethodCallException('Buttons do not support request handlers.'); } /** * Unsupported method. * * @return $this * * @throws BadMethodCallException */ public function setAutoInitialize(bool $initialize) { if (true === $initialize) { throw new BadMethodCallException('Buttons do not support automatic initialization.'); } return $this; } /** * Unsupported method. * * @throws BadMethodCallException */ public function setInheritData(bool $inheritData) { throw new BadMethodCallException('Buttons do not support data inheritance.'); } /** * Builds and returns the button configuration. * * @return FormConfigInterface */ public function getFormConfig() { // This method should be idempotent, so clone the builder $config = clone $this; $config->locked = true; return $config; } /** * Unsupported method. * * @throws BadMethodCallException */ public function setIsEmptyCallback(?callable $isEmptyCallback) { throw new BadMethodCallException('Buttons do not support "is empty" callback.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function getEventDispatcher() { throw new BadMethodCallException('Buttons do not support event dispatching.'); } /** * {@inheritdoc} */ public function getName() { return $this->name; } /** * Unsupported method. */ public function getPropertyPath() { return null; } /** * Unsupported method. * * @return bool */ public function getMapped() { return false; } /** * Unsupported method. * * @return bool */ public function getByReference() { return false; } /** * Unsupported method. * * @return bool */ public function getCompound() { return false; } /** * Returns the form type used to construct the button. * * @return ResolvedFormTypeInterface */ public function getType() { return $this->type; } /** * Unsupported method. * * @return array */ public function getViewTransformers() { return []; } /** * Unsupported method. * * @return array */ public function getModelTransformers() { return []; } /** * Unsupported method. */ public function getDataMapper() { return null; } /** * Unsupported method. * * @return bool */ public function getRequired() { return false; } /** * Returns whether the button is disabled. * * @return bool */ public function getDisabled() { return $this->disabled; } /** * Unsupported method. * * @return bool */ public function getErrorBubbling() { return false; } /** * Unsupported method. */ public function getEmptyData() { return null; } /** * Returns additional attributes of the button. * * @return array */ public function getAttributes() { return $this->attributes; } /** * Returns whether the attribute with the given name exists. * * @return bool */ public function hasAttribute(string $name) { return \array_key_exists($name, $this->attributes); } /** * Returns the value of the given attribute. * * @param mixed $default The value returned if the attribute does not exist * * @return mixed */ public function getAttribute(string $name, $default = null) { return \array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; } /** * Unsupported method. */ public function getData() { return null; } /** * Unsupported method. */ public function getDataClass() { return null; } /** * Unsupported method. * * @return bool */ public function getDataLocked() { return false; } /** * Unsupported method. */ public function getFormFactory() { throw new BadMethodCallException('Buttons do not support adding children.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function getAction() { throw new BadMethodCallException('Buttons do not support actions.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function getMethod() { throw new BadMethodCallException('Buttons do not support methods.'); } /** * Unsupported method. * * @throws BadMethodCallException */ public function getRequestHandler() { throw new BadMethodCallException('Buttons do not support request handlers.'); } /** * Unsupported method. * * @return bool */ public function getAutoInitialize() { return false; } /** * Unsupported method. * * @return bool */ public function getInheritData() { return false; } /** * Returns all options passed during the construction of the button. * * @return array */ public function getOptions() { return $this->options; } /** * Returns whether a specific option exists. * * @return bool */ public function hasOption(string $name) { return \array_key_exists($name, $this->options); } /** * Returns the value of a specific option. * * @param mixed $default The value returned if the option does not exist * * @return mixed */ public function getOption(string $name, $default = null) { return \array_key_exists($name, $this->options) ? $this->options[$name] : $default; } /** * Unsupported method. * * @throws BadMethodCallException */ public function getIsEmptyCallback(): ?callable { throw new BadMethodCallException('Buttons do not support "is empty" callback.'); } /** * Unsupported method. * * @return int */ #[\ReturnTypeWillChange] public function count() { return 0; } /** * Unsupported method. * * @return \EmptyIterator */ #[\ReturnTypeWillChange] public function getIterator() { return new \EmptyIterator(); } } ButtonTypeInterface.php 0000644 00000000716 15120211545 0011213 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * A type that should be converted into a {@link Button} instance. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface ButtonTypeInterface extends FormTypeInterface { } CHANGELOG.md 0000644 00000073536 15120211545 0006367 0 ustar 00 CHANGELOG ========= 5.4 --- * Deprecate calling `FormErrorIterator::children()` if the current element is not iterable. * Allow to pass `TranslatableMessage` objects to the `help` option * Add the `EnumType` 5.3 --- * Changed `$forms` parameter type of the `DataMapperInterface::mapDataToForms()` method from `iterable` to `\Traversable`. * Changed `$forms` parameter type of the `DataMapperInterface::mapFormsToData()` method from `iterable` to `\Traversable`. * Deprecated passing an array as the second argument of the `DataMapper::mapDataToForms()` method, pass `\Traversable` instead. * Deprecated passing an array as the first argument of the `DataMapper::mapFormsToData()` method, pass `\Traversable` instead. * Deprecated passing an array as the second argument of the `CheckboxListMapper::mapDataToForms()` method, pass `\Traversable` instead. * Deprecated passing an array as the first argument of the `CheckboxListMapper::mapFormsToData()` method, pass `\Traversable` instead. * Deprecated passing an array as the second argument of the `RadioListMapper::mapDataToForms()` method, pass `\Traversable` instead. * Deprecated passing an array as the first argument of the `RadioListMapper::mapFormsToData()` method, pass `\Traversable` instead. * Added a `choice_translation_parameters` option to `ChoiceType` * Add `UuidType` and `UlidType` * Dependency on `symfony/intl` was removed. Install `symfony/intl` if you are using `LocaleType`, `CountryType`, `CurrencyType`, `LanguageType` or `TimezoneType`. * Add `priority` option to `BaseType` and sorting view fields 5.2.0 ----- * Added support for using the `{{ label }}` placeholder in constraint messages, which is replaced in the `ViolationMapper` by the corresponding field form label. * Added `DataMapper`, `ChainAccessor`, `PropertyPathAccessor` and `CallbackAccessor` with new callable `getter` and `setter` options for each form type * Deprecated `PropertyPathMapper` in favor of `DataMapper` and `PropertyPathAccessor` * Added an `html5` option to `MoneyType` and `PercentType`, to use `<input type="number" />` 5.1.0 ----- * Deprecated not configuring the `rounding_mode` option of the `PercentType`. It will default to `\NumberFormatter::ROUND_HALFUP` in Symfony 6. * Deprecated not passing a rounding mode to the constructor of `PercentToLocalizedStringTransformer`. It will default to `\NumberFormatter::ROUND_HALFUP` in Symfony 6. * Added `collection_entry` block prefix to `CollectionType` entries * Added a `choice_filter` option to `ChoiceType` * Added argument `callable|null $filter` to `ChoiceListFactoryInterface::createListFromChoices()` and `createListFromLoader()` - not defining them is deprecated. * Added a `ChoiceList` facade to leverage explicit choice list caching based on options * Added an `AbstractChoiceLoader` to simplify implementations and handle global optimizations * The `view_timezone` option defaults to the `model_timezone` if no `reference_date` is configured. * Implementing the `FormConfigInterface` without implementing the `getIsEmptyCallback()` method is deprecated. The method will be added to the interface in 6.0. * Implementing the `FormConfigBuilderInterface` without implementing the `setIsEmptyCallback()` method is deprecated. The method will be added to the interface in 6.0. * Added a `rounding_mode` option for the PercentType and correctly round the value when submitted * Deprecated `Symfony\Component\Form\Extension\Validator\Util\ServerParams` in favor of its parent class `Symfony\Component\Form\Util\ServerParams` * Added the `html5` option to the `ColorType` to validate the input * Deprecated `NumberToLocalizedStringTransformer::ROUND_*` constants, use `\NumberFormatter::ROUND_*` instead 5.0.0 ----- * Removed support for using different values for the "model_timezone" and "view_timezone" options of the `TimeType` without configuring a reference date. * Removed the `scale` option of the `IntegerType`. * Using the `date_format`, `date_widget`, and `time_widget` options of the `DateTimeType` when the `widget` option is set to `single_text` is not supported anymore. * The `format` option of `DateType` and `DateTimeType` cannot be used when the `html5` option is enabled. * Using names for buttons that do not start with a letter, a digit, or an underscore throw an exception * Using names for buttons that do not contain only letters, digits, underscores, hyphens, and colons throw an exception. * removed the `ChoiceLoaderInterface` implementation in `CountryType`, `LanguageType`, `LocaleType` and `CurrencyType` * removed `getExtendedType()` method of the `FormTypeExtensionInterface` * added static `getExtendedTypes()` method to the `FormTypeExtensionInterface` * calling to `FormRenderer::searchAndRenderBlock()` method for fields which were already rendered throw a `BadMethodCallException` * removed the `regions` option of the `TimezoneType` * removed the `$scale` argument of the `IntegerToLocalizedStringTransformer` * removed `TemplatingExtension` and `TemplatingRendererEngine` classes, use Twig instead * passing a null message when instantiating a `Symfony\Component\Form\FormError` is not allowed * removed support for using `int` or `float` as data for the `NumberType` when the `input` option is set to `string` 4.4.0 ----- * add new `WeekType` * using different values for the "model_timezone" and "view_timezone" options of the `TimeType` without configuring a reference date is deprecated * preferred choices are repeated in the list of all choices * deprecated using `int` or `float` as data for the `NumberType` when the `input` option is set to `string` * The type guesser guesses the HTML accept attribute when a mime type is configured in the File or Image constraint. * Overriding the methods `FormIntegrationTestCase::setUp()`, `TypeTestCase::setUp()` and `TypeTestCase::tearDown()` without the `void` return-type is deprecated. * marked all dispatched event classes as `@final` * Added the `validate` option to `SubmitType` to toggle the browser built-in form validation. * Added the `alpha3` option to `LanguageType` and `CountryType` to use alpha3 instead of alpha2 codes 4.3.0 ----- * added a `symbol` option to the `PercentType` that allows to disable or customize the output of the percent character * Using the `format` option of `DateType` and `DateTimeType` when the `html5` option is enabled is deprecated. * Using names for buttons that do not start with a letter, a digit, or an underscore is deprecated and will lead to an exception in 5.0. * Using names for buttons that do not contain only letters, digits, underscores, hyphens, and colons is deprecated and will lead to an exception in 5.0. * added `html5` option to `NumberType` that allows to render `type="number"` input fields * deprecated using the `date_format`, `date_widget`, and `time_widget` options of the `DateTimeType` when the `widget` option is set to `single_text` * added `block_prefix` option to `BaseType`. * added `help_html` option to display the `help` text as HTML. * `FormError` doesn't implement `Serializable` anymore * `FormDataCollector` has been marked as `final` * added `label_translation_parameters`, `attr_translation_parameters`, `help_translation_parameters` options to `FormType` to pass translation parameters to form labels, attributes (`placeholder` and `title`) and help text respectively. The passed parameters will replace placeholders in translation messages. ```php class OrderType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('comment', TextType::class, [ 'label' => 'Comment to the order to %company%', 'label_translation_parameters' => [ '%company%' => 'Acme', ], 'help' => 'The address of the %company% is %address%', 'help_translation_parameters' => [ '%company%' => 'Acme Ltd.', '%address%' => '4 Form street, Symfonyville', ], ]) } } ``` * added the `input_format` option to `DateType`, `DateTimeType`, and `TimeType` to specify the input format when setting the `input` option to `string` * dispatch `PreSubmitEvent` on `form.pre_submit` * dispatch `SubmitEvent` on `form.submit` * dispatch `PostSubmitEvent` on `form.post_submit` * dispatch `PreSetDataEvent` on `form.pre_set_data` * dispatch `PostSetDataEvent` on `form.post_set_data` * added an `input` option to `NumberType` * removed default option grouping in `TimezoneType`, use `group_by` instead 4.2.0 ----- * The `getExtendedType()` method of the `FormTypeExtensionInterface` is deprecated and will be removed in 5.0. Type extensions must implement the static `getExtendedTypes()` method instead and return an iterable of extended types. Before: ```php class FooTypeExtension extends AbstractTypeExtension { public function getExtendedType() { return FormType::class; } // ... } ``` After: ```php class FooTypeExtension extends AbstractTypeExtension { public static function getExtendedTypes(): iterable { return [FormType::class]; } // ... } ``` * deprecated the `$scale` argument of the `IntegerToLocalizedStringTransformer` * added `Symfony\Component\Form\ClearableErrorsInterface` * deprecated calling `FormRenderer::searchAndRenderBlock` for fields which were already rendered * added a cause when a CSRF error has occurred * deprecated the `scale` option of the `IntegerType` * removed restriction on allowed HTTP methods * deprecated the `regions` option of the `TimezoneType` 4.1.0 ----- * added `input=datetime_immutable` to `DateType`, `TimeType`, `DateTimeType` * added `rounding_mode` option to `MoneyType` * added `choice_translation_locale` option to `CountryType`, `LanguageType`, `LocaleType` and `CurrencyType` * deprecated the `ChoiceLoaderInterface` implementation in `CountryType`, `LanguageType`, `LocaleType` and `CurrencyType` * added `input=datetime_immutable` to DateType, TimeType, DateTimeType * added `rounding_mode` option to MoneyType 4.0.0 ----- * using the `choices` option in `CountryType`, `CurrencyType`, `LanguageType`, `LocaleType`, and `TimezoneType` when the `choice_loader` option is not `null` is not supported anymore and the configured choices will be ignored * callable strings that are passed to the options of the `ChoiceType` are treated as property paths * the `choices_as_values` option of the `ChoiceType` has been removed * removed the support for caching loaded choice lists in `LazyChoiceList`, cache the choice list in the used `ChoiceLoaderInterface` implementation instead * removed the support for objects implementing both `\Traversable` and `\ArrayAccess` in `ResizeFormListener::preSubmit()` * removed the ability to use `FormDataCollector` without the `symfony/var-dumper` component * removed passing a `ValueExporter` instance to the `FormDataExtractor::__construct()` method * removed passing guesser services ids as the fourth argument of `DependencyInjectionExtension::__construct()` * removed the ability to validate an unsubmitted form. * removed `ChoiceLoaderInterface` implementation in `TimezoneType` * added the `false_values` option to the `CheckboxType` which allows to configure custom values which will be treated as `false` during submission 3.4.0 ----- * added `DebugCommand` * deprecated `ChoiceLoaderInterface` implementation in `TimezoneType` * added options "input" and "regions" to `TimezoneType` * added an option to ``Symfony\Component\Form\FormRendererEngineInterface::setTheme()`` and ``Symfony\Component\Form\FormRendererInterface::setTheme()`` to disable usage of default themes when rendering a form 3.3.0 ----- * deprecated using "choices" option in ``CountryType``, ``CurrencyType``, ``LanguageType``, ``LocaleType``, and ``TimezoneType`` when "choice_loader" is not ``null`` * added `Symfony\Component\Form\FormErrorIterator::findByCodes()` * added `getTypedExtensions`, `getTypes`, and `getTypeGuessers` to `Symfony\Component\Form\Test\FormIntegrationTestCase` * added `FormPass` 3.2.0 ----- * added `CallbackChoiceLoader` * implemented `ChoiceLoaderInterface` in children of `ChoiceType` 3.1.0 ----- * deprecated the "choices_as_values" option of ChoiceType * deprecated support for data objects that implements both `Traversable` and `ArrayAccess` in `ResizeFormListener::preSubmit` method * Using callable strings as choice options in `ChoiceType` has been deprecated and will be used as `PropertyPath` instead of callable in Symfony 4.0. * implemented `DataTransformerInterface` in `TextType` * deprecated caching loaded choice list in `LazyChoiceList::$loadedList` 3.0.0 ----- * removed `FormTypeInterface::setDefaultOptions()` method * removed `AbstractType::setDefaultOptions()` method * removed `FormTypeExtensionInterface::setDefaultOptions()` method * removed `AbstractTypeExtension::setDefaultOptions()` method * added `FormTypeInterface::configureOptions()` method * added `FormTypeExtensionInterface::configureOptions()` method 2.8.0 ----- * added option "choice_translation_domain" to DateType, TimeType and DateTimeType. * deprecated option "read_only" in favor of "attr['readonly']" * added the html5 "range" FormType * deprecated the "cascade_validation" option in favor of setting "constraints" with the Valid constraint * moved data trimming logic of TrimListener into StringUtil * [BC BREAK] When registering a type extension through the DI extension, the tag alias has to match the actual extended type. 2.7.38 ------ * [BC BREAK] the `isFileUpload()` method was added to the `RequestHandlerInterface` 2.7.0 ----- * added option "choice_translation_domain" to ChoiceType. * deprecated option "precision" in favor of "scale" * deprecated the overwriting of AbstractType::setDefaultOptions() in favor of overwriting AbstractType::configureOptions(). * deprecated the overwriting of AbstractTypeExtension::setDefaultOptions() in favor of overwriting AbstractTypeExtension::configureOptions(). * added new ChoiceList interface and implementations in the Symfony\Component\Form\ChoiceList namespace * added new ChoiceView in the Symfony\Component\Form\ChoiceList\View namespace * choice groups are now represented by ChoiceGroupView objects in the view * deprecated the old ChoiceList interface and implementations * deprecated the old ChoiceView class * added CheckboxListMapper and RadioListMapper * deprecated ChoiceToBooleanArrayTransformer and ChoicesToBooleanArrayTransformer * deprecated FixCheckboxInputListener and FixRadioInputListener * deprecated the "choice_list" option of ChoiceType * added new options to ChoiceType: * "choices_as_values" * "choice_loader" * "choice_label" * "choice_name" * "choice_value" * "choice_attr" * "group_by" 2.6.2 ----- * Added back the `model_timezone` and `view_timezone` options for `TimeType`, `DateType` and `BirthdayType` 2.6.0 ----- * added "html5" option to Date, Time and DateTimeFormType to be able to enable/disable HTML5 input date when widget option is "single_text" * added "label_format" option with possible placeholders "%name%" and "%id%" * [BC BREAK] drop support for model_timezone and view_timezone options in TimeType, DateType and BirthdayType, update to 2.6.2 to get back support for these options 2.5.0 ------ * deprecated options "max_length" and "pattern" in favor of putting these values in "attr" option * added an option for multiple files upload * form errors now reference their cause (constraint violation, exception, ...) * form errors now remember which form they were originally added to * [BC BREAK] added two optional parameters to FormInterface::getErrors() and changed the method to return a Symfony\Component\Form\FormErrorIterator instance instead of an array * errors mapped to unsubmitted forms are discarded now * ObjectChoiceList now compares choices by their value, if a value path is given * you can now pass interface names in the "data_class" option * [BC BREAK] added `FormInterface::getTransformationFailure()` 2.4.0 ----- * moved CSRF implementation to the new Security CSRF sub-component * deprecated CsrfProviderInterface and its implementations * deprecated options "csrf_provider" and "intention" in favor of the new options "csrf_token_manager" and "csrf_token_id" 2.3.0 ----- * deprecated FormPerformanceTestCase and FormIntegrationTestCase in the Symfony\Component\Form\Tests namespace and moved them to the Symfony\Component\Form\Test namespace * deprecated TypeTestCase in the Symfony\Component\Form\Tests\Extension\Core\Type namespace and moved it to the Symfony\Component\Form\Test namespace * changed FormRenderer::humanize() to humanize also camel cased field name * added RequestHandlerInterface and FormInterface::handleRequest() * deprecated passing a Request instance to FormInterface::bind() * added options "method" and "action" to FormType * deprecated option "virtual" in favor "inherit_data" * deprecated VirtualFormAwareIterator in favor of InheritDataAwareIterator * [BC BREAK] removed the "array" type hint from DataMapperInterface * improved forms inheriting their parent data to actually return that data from getData(), getNormData() and getViewData() * added component-level exceptions for various SPL exceptions changed all uses of the deprecated Exception class to use more specialized exceptions instead removed NotInitializedException, NotValidException, TypeDefinitionException, TypeLoaderException, CreationException * added events PRE_SUBMIT, SUBMIT and POST_SUBMIT * deprecated events PRE_BIND, BIND and POST_BIND * [BC BREAK] renamed bind() and isBound() in FormInterface to submit() and isSubmitted() * added methods submit() and isSubmitted() to Form * deprecated bind() and isBound() in Form * deprecated AlreadyBoundException in favor of AlreadySubmittedException * added support for PATCH requests * [BC BREAK] added initialize() to FormInterface * [BC BREAK] added getAutoInitialize() to FormConfigInterface * [BC BREAK] added setAutoInitialize() to FormConfigBuilderInterface * [BC BREAK] initialization for Form instances added to a form tree must be manually disabled * PRE_SET_DATA is now guaranteed to be called after children were added by the form builder, unless FormInterface::setData() is called manually * fixed CSRF error message to be translated * custom CSRF error messages can now be set through the "csrf_message" option * fixed: expanded single-choice fields now show a radio button for the empty value 2.2.0 ----- * TrimListener now removes unicode whitespaces * deprecated getParent(), setParent() and hasParent() in FormBuilderInterface * FormInterface::add() now accepts a FormInterface instance OR a field's name, type and options * removed special characters between the choice or text fields of DateType unless the option "format" is set to a custom value * deprecated FormException and introduced ExceptionInterface instead * [BC BREAK] FormException is now an interface * protected FormBuilder methods from being called when it is turned into a FormConfigInterface with getFormConfig() * [BC BREAK] inserted argument `$message` in the constructor of `FormError` * the PropertyPath class and related classes were moved to a dedicated PropertyAccess component. During the move, InvalidPropertyException was renamed to NoSuchPropertyException. FormUtil was split: FormUtil::singularify() can now be found in Symfony\Component\PropertyAccess\StringUtil. The methods getValue() and setValue() from PropertyPath were extracted into a new class PropertyAccessor. * added an optional PropertyAccessorInterface parameter to FormType, ObjectChoiceList and PropertyPathMapper * [BC BREAK] PropertyPathMapper and FormType now have a constructor * [BC BREAK] setting the option "validation_groups" to ``false`` now disables validation instead of assuming group "Default" 2.1.0 ----- * [BC BREAK] ``read_only`` field attribute now renders as ``readonly="readonly"``, use ``disabled`` instead * [BC BREAK] child forms now aren't validated anymore by default * made validation of form children configurable (new option: cascade_validation) * added support for validation groups as callbacks * made the translation catalogue configurable via the "translation_domain" option * added Form::getErrorsAsString() to help debugging forms * allowed setting different options for RepeatedType fields (like the label) * added support for empty form name at root level, this enables rendering forms without form name prefix in field names * [BC BREAK] form and field names must start with a letter, digit or underscore and only contain letters, digits, underscores, hyphens and colons * [BC BREAK] changed default name of the prototype in the "collection" type from "$$name$$" to "\__name\__". No dollars are appended/prepended to custom names anymore. * [BC BREAK] improved ChoiceListInterface * [BC BREAK] added SimpleChoiceList and LazyChoiceList as replacement of ArrayChoiceList * added ChoiceList and ObjectChoiceList to use objects as choices * [BC BREAK] removed EntitiesToArrayTransformer and EntityToIdTransformer. The former has been replaced by CollectionToArrayTransformer in combination with EntityChoiceList, the latter is not required in the core anymore. * [BC BREAK] renamed * ArrayToBooleanChoicesTransformer to ChoicesToBooleanArrayTransformer * ScalarToBooleanChoicesTransformer to ChoiceToBooleanArrayTransformer * ArrayToChoicesTransformer to ChoicesToValuesTransformer * ScalarToChoiceTransformer to ChoiceToValueTransformer to be consistent with the naming in ChoiceListInterface. They were merged into ChoiceList and have no public equivalent anymore. * choice fields now throw a FormException if neither the "choices" nor the "choice_list" option is set * the radio type is now a child of the checkbox type * the collection, choice (with multiple selection) and entity (with multiple selection) types now make use of addXxx() and removeXxx() methods in your model if you set "by_reference" to false. For a custom, non-recognized singular form, set the "property_path" option like this: "plural|singular" * forms now don't create an empty object anymore if they are completely empty and not required. The empty value for such forms is null. * added constant Guess::VERY_HIGH_CONFIDENCE * [BC BREAK] The methods `add`, `remove`, `setParent`, `bind` and `setData` in class Form now throw an exception if the form is already bound * fields of constrained classes without a NotBlank or NotNull constraint are set to not required now, as stated in the docs * fixed TimeType and DateTimeType to not display seconds when "widget" is "single_text" unless "with_seconds" is set to true * checkboxes of in an expanded multiple-choice field don't include the choice in their name anymore. Their names terminate with "[]" now. * deprecated FormValidatorInterface and substituted its implementations by event subscribers * simplified CSRF protection and removed the csrf type * deprecated FieldType and merged it into FormType * added new option "compound" that lets you switch between field and form behavior * [BC BREAK] renamed theme blocks * "field_*" to "form_*" * "field_widget" to "form_widget_simple" * "widget_choice_options" to "choice_widget_options" * "generic_label" to "form_label" * added theme blocks "form_widget_compound", "choice_widget_expanded" and "choice_widget_collapsed" to make theming more modular * ValidatorTypeGuesser now guesses "collection" for array type constraint * added method `guessPattern` to FormTypeGuesserInterface to guess which pattern to use in the HTML5 attribute "pattern" * deprecated method `guessMinLength` in favor of `guessPattern` * labels don't display field attributes anymore. Label attributes can be passed in the "label_attr" option/variable * added option "mapped" which should be used instead of setting "property_path" to false * [BC BREAK] "data_class" now *must* be set if a form maps to an object and should be left empty otherwise * improved error mapping on forms * dot (".") rules are now allowed to map errors assigned to a form to one of its children * errors are not mapped to unsynchronized forms anymore * [BC BREAK] changed Form constructor to accept a single `FormConfigInterface` object * [BC BREAK] changed argument order in the FormBuilder constructor * added Form method `getViewData` * deprecated Form methods * `getTypes` * `getErrorBubbling` * `getNormTransformers` * `getClientTransformers` * `getAttribute` * `hasAttribute` * `getClientData` * added FormBuilder methods * `getTypes` * `addViewTransformer` * `getViewTransformers` * `resetViewTransformers` * `addModelTransformer` * `getModelTransformers` * `resetModelTransformers` * deprecated FormBuilder methods * `prependClientTransformer` * `appendClientTransformer` * `getClientTransformers` * `resetClientTransformers` * `prependNormTransformer` * `appendNormTransformer` * `getNormTransformers` * `resetNormTransformers` * deprecated the option "validation_constraint" in favor of the new option "constraints" * removed superfluous methods from DataMapperInterface * `mapFormToData` * `mapDataToForm` * added `setDefaultOptions` to FormTypeInterface and FormTypeExtensionInterface which accepts an OptionsResolverInterface instance * deprecated the methods `getDefaultOptions` and `getAllowedOptionValues` in FormTypeInterface and FormTypeExtensionInterface * options passed during construction can now be accessed from FormConfigInterface * added FormBuilderInterface and FormConfigEditorInterface * [BC BREAK] the method `buildForm` in FormTypeInterface and FormTypeExtensionInterface now receives a FormBuilderInterface instead of a FormBuilder instance * [BC BREAK] the method `buildViewBottomUp` was renamed to `finishView` in FormTypeInterface and FormTypeExtensionInterface * [BC BREAK] the options array is now passed as last argument of the methods * `buildView` * `finishView` in FormTypeInterface and FormTypeExtensionInterface * [BC BREAK] no options are passed to `getParent` of FormTypeInterface anymore * deprecated DataEvent and FilterDataEvent in favor of the new FormEvent which is now passed to all events thrown by the component * FormEvents::BIND now replaces FormEvents::BIND_NORM_DATA * FormEvents::PRE_SET_DATA now replaces FormEvents::SET_DATA * FormEvents::PRE_BIND now replaces FormEvents::BIND_CLIENT_DATA * deprecated FormEvents::SET_DATA, FormEvents::BIND_CLIENT_DATA and FormEvents::BIND_NORM_DATA * [BC BREAK] reversed the order of the first two arguments to `createNamed` and `createNamedBuilder` in `FormFactoryInterface` * deprecated `getChildren` in Form and FormBuilder in favor of `all` * deprecated `hasChildren` in Form and FormBuilder in favor of `count` * FormBuilder now implements \IteratorAggregate * [BC BREAK] compound forms now always need a data mapper * FormBuilder now maintains the order when explicitly adding form builders as children * ChoiceType now doesn't add the empty value anymore if the choices already contain an empty element * DateType, TimeType and DateTimeType now show empty values again if not required * [BC BREAK] fixed rendering of errors for DateType, BirthdayType and similar ones * [BC BREAK] fixed: form constraints are only validated if they belong to the validated group * deprecated `bindRequest` in `Form` and replaced it by a listener to FormEvents::PRE_BIND * fixed: the "data" option supersedes default values from the model * changed DateType to refer to the "format" option for calculating the year and day choices instead of padding them automatically * [BC BREAK] DateType defaults to the format "yyyy-MM-dd" now if the widget is "single_text", in order to support the HTML 5 date field out of the box * added the option "format" to DateTimeType * [BC BREAK] DateTimeType now outputs RFC 3339 dates by default, as generated and consumed by HTML5 browsers, if the widget is "single_text" * deprecated the options "data_timezone" and "user_timezone" in DateType, DateTimeType and TimeType and renamed them to "model_timezone" and "view_timezone" * fixed: TransformationFailedExceptions thrown in the model transformer are now caught by the form * added FormRegistryInterface, ResolvedFormTypeInterface and ResolvedFormTypeFactoryInterface * deprecated FormFactory methods * `addType` * `hasType` * `getType` * [BC BREAK] FormFactory now expects a FormRegistryInterface and a ResolvedFormTypeFactoryInterface as constructor argument * [BC BREAK] The method `createBuilder` in FormTypeInterface is not supported anymore for performance reasons * [BC BREAK] Removed `setTypes` from FormBuilder * deprecated AbstractType methods * `getExtensions` * `setExtensions` * ChoiceType now caches its created choice lists to improve performance * [BC BREAK] Rows of a collection field cannot be themed individually anymore. All rows in the collection field now have the same block names, which contains "entry" where it previously contained the row index. * [BC BREAK] When registering a type through the DI extension, the tag alias has to match the actual type name. * added FormRendererInterface, FormRendererEngineInterface and implementations of these interfaces * [BC BREAK] removed the following methods from FormUtil: * `toArrayKey` * `toArrayKeys` * `isChoiceGroup` * `isChoiceSelected` * [BC BREAK] renamed method `renderBlock` in FormHelper to `block` and changed its signature * made FormView properties public and deprecated their accessor methods * made the normalized data of a form accessible in the template through the variable "form.vars.data" * made the original data of a choice accessible in the template through the property "choice.data" * added convenience class Forms and FormFactoryBuilderInterface CallbackTransformer.php 0000644 00000001764 15120211545 0011200 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; class CallbackTransformer implements DataTransformerInterface { private $transform; private $reverseTransform; /** * @param callable $transform The forward transform callback * @param callable $reverseTransform The reverse transform callback */ public function __construct(callable $transform, callable $reverseTransform) { $this->transform = $transform; $this->reverseTransform = $reverseTransform; } /** * {@inheritdoc} */ public function transform($data) { return ($this->transform)($data); } /** * {@inheritdoc} */ public function reverseTransform($data) { return ($this->reverseTransform)($data); } } ClearableErrorsInterface.php 0000644 00000001200 15120211545 0012132 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * A form element whose errors can be cleared. * * @author Colin O'Dell <colinodell@gmail.com> */ interface ClearableErrorsInterface { /** * Removes all the errors of this form. * * @param bool $deep Whether to remove errors from child forms as well * * @return $this */ public function clearErrors(bool $deep = false); } ClickableInterface.php 0000644 00000001012 15120211545 0010735 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * A clickable form element. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface ClickableInterface { /** * Returns whether this element was clicked. * * @return bool */ public function isClicked(); } DataAccessorInterface.php 0000644 00000004410 15120211545 0011425 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * Writes and reads values to/from an object or array bound to a form. * * @author Yonel Ceruto <yonelceruto@gmail.com> */ interface DataAccessorInterface { /** * Returns the value at the end of the property of the object graph. * * @param object|array $viewData The view data of the compound form * @param FormInterface $form The {@link FormInterface()} instance to check * * @return mixed * * @throws Exception\AccessException If unable to read from the given form data */ public function getValue($viewData, FormInterface $form); /** * Sets the value at the end of the property of the object graph. * * @param object|array $viewData The view data of the compound form * @param mixed $value The value to set at the end of the object graph * @param FormInterface $form The {@link FormInterface()} instance to check * * @throws Exception\AccessException If unable to write the given value */ public function setValue(&$viewData, $value, FormInterface $form): void; /** * Returns whether a value can be read from an object graph. * * Whenever this method returns true, {@link getValue()} is guaranteed not * to throw an exception when called with the same arguments. * * @param object|array $viewData The view data of the compound form * @param FormInterface $form The {@link FormInterface()} instance to check */ public function isReadable($viewData, FormInterface $form): bool; /** * Returns whether a value can be written at a given object graph. * * Whenever this method returns true, {@link setValue()} is guaranteed not * to throw an exception when called with the same arguments. * * @param object|array $viewData The view data of the compound form * @param FormInterface $form The {@link FormInterface()} instance to check */ public function isWritable($viewData, FormInterface $form): bool; } DataMapperInterface.php 0000644 00000004572 15120211545 0011120 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * @author Bernhard Schussek <bschussek@gmail.com> */ interface DataMapperInterface { /** * Maps the view data of a compound form to its children. * * The method is responsible for calling {@link FormInterface::setData()} * on the children of compound forms, defining their underlying model data. * * @param mixed $viewData View data of the compound form being initialized * @param FormInterface[]|\Traversable $forms A list of {@link FormInterface} instances * * @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported */ public function mapDataToForms($viewData, \Traversable $forms); /** * Maps the model data of a list of children forms into the view data of their parent. * * This is the internal cascade call of FormInterface::submit for compound forms, since they * cannot be bound to any input nor the request as scalar, but their children may: * * $compoundForm->submit($arrayOfChildrenViewData) * // inside: * $childForm->submit($childViewData); * // for each entry, do the same and/or reverse transform * $this->dataMapper->mapFormsToData($compoundForm, $compoundInitialViewData) * // then reverse transform * * When a simple form is submitted the following is happening: * * $simpleForm->submit($submittedViewData) * // inside: * $this->viewData = $submittedViewData * // then reverse transform * * The model data can be an array or an object, so this second argument is always passed * by reference. * * @param FormInterface[]|\Traversable $forms A list of {@link FormInterface} instances * @param mixed $viewData The compound form's view data that get mapped * its children model data * * @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported */ public function mapFormsToData(\Traversable $forms, &$viewData); } DataTransformerInterface.php 0000644 00000007330 15120211545 0012171 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\TransformationFailedException; /** * Transforms a value between different representations. * * @author Bernhard Schussek <bschussek@gmail.com> */ interface DataTransformerInterface { /** * Transforms a value from the original representation to a transformed representation. * * This method is called when the form field is initialized with its default data, on * two occasions for two types of transformers: * * 1. Model transformers which normalize the model data. * This is mainly useful when the same form type (the same configuration) * has to handle different kind of underlying data, e.g The DateType can * deal with strings or \DateTime objects as input. * * 2. View transformers which adapt the normalized data to the view format. * a/ When the form is simple, the value returned by convention is used * directly in the view and thus can only be a string or an array. In * this case the data class should be null. * * b/ When the form is compound the returned value should be an array or * an object to be mapped to the children. Each property of the compound * data will be used as model data by each child and will be transformed * too. In this case data class should be the class of the object, or null * when it is an array. * * All transformers are called in a configured order from model data to view value. * At the end of this chain the view data will be validated against the data class * setting. * * This method must be able to deal with empty values. Usually this will * be NULL, but depending on your implementation other empty values are * possible as well (such as empty strings). The reasoning behind this is * that data transformers must be chainable. If the transform() method * of the first data transformer outputs NULL, the second must be able to * process that value. * * @param mixed $value The value in the original representation * * @return mixed * * @throws TransformationFailedException when the transformation fails */ public function transform($value); /** * Transforms a value from the transformed representation to its original * representation. * * This method is called when {@link Form::submit()} is called to transform the requests tainted data * into an acceptable format. * * The same transformers are called in the reverse order so the responsibility is to * return one of the types that would be expected as input of transform(). * * This method must be able to deal with empty values. Usually this will * be an empty string, but depending on your implementation other empty * values are possible as well (such as NULL). The reasoning behind * this is that value transformers must be chainable. If the * reverseTransform() method of the first value transformer outputs an * empty string, the second value transformer must be able to process that * value. * * By convention, reverseTransform() should return NULL if an empty string * is passed. * * @param mixed $value The value in the transformed representation * * @return mixed * * @throws TransformationFailedException when the transformation fails */ public function reverseTransform($value); } FileUploadError.php 0000644 00000000522 15120211545 0010306 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * @internal */ class FileUploadError extends FormError { } Form.php 0000644 00000113663 15120211545 0006166 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Event\PostSetDataEvent; use Symfony\Component\Form\Event\PostSubmitEvent; use Symfony\Component\Form\Event\PreSetDataEvent; use Symfony\Component\Form\Event\PreSubmitEvent; use Symfony\Component\Form\Event\SubmitEvent; use Symfony\Component\Form\Exception\AlreadySubmittedException; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Exception\OutOfBoundsException; use Symfony\Component\Form\Exception\RuntimeException; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Util\FormUtil; use Symfony\Component\Form\Util\InheritDataAwareIterator; use Symfony\Component\Form\Util\OrderedHashMap; use Symfony\Component\PropertyAccess\PropertyPath; use Symfony\Component\PropertyAccess\PropertyPathInterface; /** * Form represents a form. * * To implement your own form fields, you need to have a thorough understanding * of the data flow within a form. A form stores its data in three different * representations: * * (1) the "model" format required by the form's object * (2) the "normalized" format for internal processing * (3) the "view" format used for display simple fields * or map children model data for compound fields * * A date field, for example, may store a date as "Y-m-d" string (1) in the * object. To facilitate processing in the field, this value is normalized * to a DateTime object (2). In the HTML representation of your form, a * localized string (3) may be presented to and modified by the user, or it could be an array of values * to be mapped to choices fields. * * In most cases, format (1) and format (2) will be the same. For example, * a checkbox field uses a Boolean value for both internal processing and * storage in the object. In these cases you need to set a view transformer * to convert between formats (2) and (3). You can do this by calling * addViewTransformer(). * * In some cases though it makes sense to make format (1) configurable. To * demonstrate this, let's extend our above date field to store the value * either as "Y-m-d" string or as timestamp. Internally we still want to * use a DateTime object for processing. To convert the data from string/integer * to DateTime you can set a model transformer by calling * addModelTransformer(). The normalized data is then converted to the displayed * data as described before. * * The conversions (1) -> (2) -> (3) use the transform methods of the transformers. * The conversions (3) -> (2) -> (1) use the reverseTransform methods of the transformers. * * @author Fabien Potencier <fabien@symfony.com> * @author Bernhard Schussek <bschussek@gmail.com> * * @implements \IteratorAggregate<string, FormInterface> */ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterface { /** * @var FormConfigInterface */ private $config; /** * @var FormInterface|null */ private $parent; /** * A map of FormInterface instances. * * @var OrderedHashMap<string, FormInterface> */ private $children; /** * @var FormError[] */ private $errors = []; /** * @var bool */ private $submitted = false; /** * The button that was used to submit the form. * * @var FormInterface|ClickableInterface|null */ private $clickedButton; /** * @var mixed */ private $modelData; /** * @var mixed */ private $normData; /** * @var mixed */ private $viewData; /** * The submitted values that don't belong to any children. * * @var array */ private $extraData = []; /** * The transformation failure generated during submission, if any. * * @var TransformationFailedException|null */ private $transformationFailure; /** * Whether the form's data has been initialized. * * When the data is initialized with its default value, that default value * is passed through the transformer chain in order to synchronize the * model, normalized and view format for the first time. This is done * lazily in order to save performance when {@link setData()} is called * manually, making the initialization with the configured default value * superfluous. * * @var bool */ private $defaultDataSet = false; /** * Whether setData() is currently being called. * * @var bool */ private $lockSetData = false; /** * @var string */ private $name = ''; /** * Whether the form inherits its underlying data from its parent. * * @var bool */ private $inheritData; /** * @var PropertyPathInterface|null */ private $propertyPath; /** * @throws LogicException if a data mapper is not provided for a compound form */ public function __construct(FormConfigInterface $config) { // Compound forms always need a data mapper, otherwise calls to // `setData` and `add` will not lead to the correct population of // the child forms. if ($config->getCompound() && !$config->getDataMapper()) { throw new LogicException('Compound forms need a data mapper.'); } // If the form inherits the data from its parent, it is not necessary // to call setData() with the default data. if ($this->inheritData = $config->getInheritData()) { $this->defaultDataSet = true; } $this->config = $config; $this->children = new OrderedHashMap(); $this->name = $config->getName(); } public function __clone() { $this->children = clone $this->children; foreach ($this->children as $key => $child) { $this->children[$key] = clone $child; } } /** * {@inheritdoc} */ public function getConfig() { return $this->config; } /** * {@inheritdoc} */ public function getName() { return $this->name; } /** * {@inheritdoc} */ public function getPropertyPath() { if ($this->propertyPath || $this->propertyPath = $this->config->getPropertyPath()) { return $this->propertyPath; } if ('' === $this->name) { return null; } $parent = $this->parent; while ($parent && $parent->getConfig()->getInheritData()) { $parent = $parent->getParent(); } if ($parent && null === $parent->getConfig()->getDataClass()) { $this->propertyPath = new PropertyPath('['.$this->name.']'); } else { $this->propertyPath = new PropertyPath($this->name); } return $this->propertyPath; } /** * {@inheritdoc} */ public function isRequired() { if (null === $this->parent || $this->parent->isRequired()) { return $this->config->getRequired(); } return false; } /** * {@inheritdoc} */ public function isDisabled() { if (null === $this->parent || !$this->parent->isDisabled()) { return $this->config->getDisabled(); } return true; } /** * {@inheritdoc} */ public function setParent(FormInterface $parent = null) { if ($this->submitted) { throw new AlreadySubmittedException('You cannot set the parent of a submitted form.'); } if (null !== $parent && '' === $this->name) { throw new LogicException('A form with an empty name cannot have a parent form.'); } $this->parent = $parent; return $this; } /** * {@inheritdoc} */ public function getParent() { return $this->parent; } /** * {@inheritdoc} */ public function getRoot() { return $this->parent ? $this->parent->getRoot() : $this; } /** * {@inheritdoc} */ public function isRoot() { return null === $this->parent; } /** * {@inheritdoc} */ public function setData($modelData) { // If the form is submitted while disabled, it is set to submitted, but the data is not // changed. In such cases (i.e. when the form is not initialized yet) don't // abort this method. if ($this->submitted && $this->defaultDataSet) { throw new AlreadySubmittedException('You cannot change the data of a submitted form.'); } // If the form inherits its parent's data, disallow data setting to // prevent merge conflicts if ($this->inheritData) { throw new RuntimeException('You cannot change the data of a form inheriting its parent data.'); } // Don't allow modifications of the configured data if the data is locked if ($this->config->getDataLocked() && $modelData !== $this->config->getData()) { return $this; } if (\is_object($modelData) && !$this->config->getByReference()) { $modelData = clone $modelData; } if ($this->lockSetData) { throw new RuntimeException('A cycle was detected. Listeners to the PRE_SET_DATA event must not call setData(). You should call setData() on the FormEvent object instead.'); } $this->lockSetData = true; $dispatcher = $this->config->getEventDispatcher(); // Hook to change content of the model data before transformation and mapping children if ($dispatcher->hasListeners(FormEvents::PRE_SET_DATA)) { $event = new PreSetDataEvent($this, $modelData); $dispatcher->dispatch($event, FormEvents::PRE_SET_DATA); $modelData = $event->getData(); } // Treat data as strings unless a transformer exists if (\is_scalar($modelData) && !$this->config->getViewTransformers() && !$this->config->getModelTransformers()) { $modelData = (string) $modelData; } // Synchronize representations - must not change the content! // Transformation exceptions are not caught on initialization $normData = $this->modelToNorm($modelData); $viewData = $this->normToView($normData); // Validate if view data matches data class (unless empty) if (!FormUtil::isEmpty($viewData)) { $dataClass = $this->config->getDataClass(); if (null !== $dataClass && !$viewData instanceof $dataClass) { $actualType = get_debug_type($viewData); throw new LogicException('The form\'s view data is expected to be a "'.$dataClass.'", but it is a "'.$actualType.'". You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms "'.$actualType.'" to an instance of "'.$dataClass.'".'); } } $this->modelData = $modelData; $this->normData = $normData; $this->viewData = $viewData; $this->defaultDataSet = true; $this->lockSetData = false; // Compound forms don't need to invoke this method if they don't have children if (\count($this->children) > 0) { // Update child forms from the data (unless their config data is locked) $this->config->getDataMapper()->mapDataToForms($viewData, new \RecursiveIteratorIterator(new InheritDataAwareIterator($this->children))); } if ($dispatcher->hasListeners(FormEvents::POST_SET_DATA)) { $event = new PostSetDataEvent($this, $modelData); $dispatcher->dispatch($event, FormEvents::POST_SET_DATA); } return $this; } /** * {@inheritdoc} */ public function getData() { if ($this->inheritData) { if (!$this->parent) { throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.'); } return $this->parent->getData(); } if (!$this->defaultDataSet) { if ($this->lockSetData) { throw new RuntimeException('A cycle was detected. Listeners to the PRE_SET_DATA event must not call getData() if the form data has not already been set. You should call getData() on the FormEvent object instead.'); } $this->setData($this->config->getData()); } return $this->modelData; } /** * {@inheritdoc} */ public function getNormData() { if ($this->inheritData) { if (!$this->parent) { throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.'); } return $this->parent->getNormData(); } if (!$this->defaultDataSet) { if ($this->lockSetData) { throw new RuntimeException('A cycle was detected. Listeners to the PRE_SET_DATA event must not call getNormData() if the form data has not already been set.'); } $this->setData($this->config->getData()); } return $this->normData; } /** * {@inheritdoc} */ public function getViewData() { if ($this->inheritData) { if (!$this->parent) { throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.'); } return $this->parent->getViewData(); } if (!$this->defaultDataSet) { if ($this->lockSetData) { throw new RuntimeException('A cycle was detected. Listeners to the PRE_SET_DATA event must not call getViewData() if the form data has not already been set.'); } $this->setData($this->config->getData()); } return $this->viewData; } /** * {@inheritdoc} */ public function getExtraData() { return $this->extraData; } /** * {@inheritdoc} */ public function initialize() { if (null !== $this->parent) { throw new RuntimeException('Only root forms should be initialized.'); } // Guarantee that the *_SET_DATA events have been triggered once the // form is initialized. This makes sure that dynamically added or // removed fields are already visible after initialization. if (!$this->defaultDataSet) { $this->setData($this->config->getData()); } return $this; } /** * {@inheritdoc} */ public function handleRequest($request = null) { $this->config->getRequestHandler()->handleRequest($this, $request); return $this; } /** * {@inheritdoc} */ public function submit($submittedData, bool $clearMissing = true) { if ($this->submitted) { throw new AlreadySubmittedException('A form can only be submitted once.'); } // Initialize errors in the very beginning so we're sure // they are collectable during submission only $this->errors = []; // Obviously, a disabled form should not change its data upon submission. if ($this->isDisabled()) { $this->submitted = true; return $this; } // The data must be initialized if it was not initialized yet. // This is necessary to guarantee that the *_SET_DATA listeners // are always invoked before submit() takes place. if (!$this->defaultDataSet) { $this->setData($this->config->getData()); } // Treat false as NULL to support binding false to checkboxes. // Don't convert NULL to a string here in order to determine later // whether an empty value has been submitted or whether no value has // been submitted at all. This is important for processing checkboxes // and radio buttons with empty values. if (false === $submittedData) { $submittedData = null; } elseif (\is_scalar($submittedData)) { $submittedData = (string) $submittedData; } elseif ($this->config->getRequestHandler()->isFileUpload($submittedData)) { if (!$this->config->getOption('allow_file_upload')) { $submittedData = null; $this->transformationFailure = new TransformationFailedException('Submitted data was expected to be text or number, file upload given.'); } } elseif (\is_array($submittedData) && !$this->config->getCompound() && !$this->config->getOption('multiple', false)) { $submittedData = null; $this->transformationFailure = new TransformationFailedException('Submitted data was expected to be text or number, array given.'); } $dispatcher = $this->config->getEventDispatcher(); $modelData = null; $normData = null; $viewData = null; try { if (null !== $this->transformationFailure) { throw $this->transformationFailure; } // Hook to change content of the data submitted by the browser if ($dispatcher->hasListeners(FormEvents::PRE_SUBMIT)) { $event = new PreSubmitEvent($this, $submittedData); $dispatcher->dispatch($event, FormEvents::PRE_SUBMIT); $submittedData = $event->getData(); } // Check whether the form is compound. // This check is preferable over checking the number of children, // since forms without children may also be compound. // (think of empty collection forms) if ($this->config->getCompound()) { if (null === $submittedData) { $submittedData = []; } if (!\is_array($submittedData)) { throw new TransformationFailedException('Compound forms expect an array or NULL on submission.'); } foreach ($this->children as $name => $child) { $isSubmitted = \array_key_exists($name, $submittedData); if ($isSubmitted || $clearMissing) { $child->submit($isSubmitted ? $submittedData[$name] : null, $clearMissing); unset($submittedData[$name]); if (null !== $this->clickedButton) { continue; } if ($child instanceof ClickableInterface && $child->isClicked()) { $this->clickedButton = $child; continue; } if (method_exists($child, 'getClickedButton') && null !== $child->getClickedButton()) { $this->clickedButton = $child->getClickedButton(); } } } $this->extraData = $submittedData; } // Forms that inherit their parents' data also are not processed, // because then it would be too difficult to merge the changes in // the child and the parent form. Instead, the parent form also takes // changes in the grandchildren (i.e. children of the form that inherits // its parent's data) into account. // (see InheritDataAwareIterator below) if (!$this->inheritData) { // If the form is compound, the view data is merged with the data // of the children using the data mapper. // If the form is not compound, the view data is assigned to the submitted data. $viewData = $this->config->getCompound() ? $this->viewData : $submittedData; if (FormUtil::isEmpty($viewData)) { $emptyData = $this->config->getEmptyData(); if ($emptyData instanceof \Closure) { $emptyData = $emptyData($this, $viewData); } $viewData = $emptyData; } // Merge form data from children into existing view data // It is not necessary to invoke this method if the form has no children, // even if it is compound. if (\count($this->children) > 0) { // Use InheritDataAwareIterator to process children of // descendants that inherit this form's data. // These descendants will not be submitted normally (see the check // for $this->config->getInheritData() above) $this->config->getDataMapper()->mapFormsToData( new \RecursiveIteratorIterator(new InheritDataAwareIterator($this->children)), $viewData ); } // Normalize data to unified representation $normData = $this->viewToNorm($viewData); // Hook to change content of the data in the normalized // representation if ($dispatcher->hasListeners(FormEvents::SUBMIT)) { $event = new SubmitEvent($this, $normData); $dispatcher->dispatch($event, FormEvents::SUBMIT); $normData = $event->getData(); } // Synchronize representations - must not change the content! $modelData = $this->normToModel($normData); $viewData = $this->normToView($normData); } } catch (TransformationFailedException $e) { $this->transformationFailure = $e; // If $viewData was not yet set, set it to $submittedData so that // the erroneous data is accessible on the form. // Forms that inherit data never set any data, because the getters // forward to the parent form's getters anyway. if (null === $viewData && !$this->inheritData) { $viewData = $submittedData; } } $this->submitted = true; $this->modelData = $modelData; $this->normData = $normData; $this->viewData = $viewData; if ($dispatcher->hasListeners(FormEvents::POST_SUBMIT)) { $event = new PostSubmitEvent($this, $viewData); $dispatcher->dispatch($event, FormEvents::POST_SUBMIT); } return $this; } /** * {@inheritdoc} */ public function addError(FormError $error) { if (null === $error->getOrigin()) { $error->setOrigin($this); } if ($this->parent && $this->config->getErrorBubbling()) { $this->parent->addError($error); } else { $this->errors[] = $error; } return $this; } /** * {@inheritdoc} */ public function isSubmitted() { return $this->submitted; } /** * {@inheritdoc} */ public function isSynchronized() { return null === $this->transformationFailure; } /** * {@inheritdoc} */ public function getTransformationFailure() { return $this->transformationFailure; } /** * {@inheritdoc} */ public function isEmpty() { foreach ($this->children as $child) { if (!$child->isEmpty()) { return false; } } if (!method_exists($this->config, 'getIsEmptyCallback')) { trigger_deprecation('symfony/form', '5.1', 'Not implementing the "%s::getIsEmptyCallback()" method in "%s" is deprecated.', FormConfigInterface::class, \get_class($this->config)); $isEmptyCallback = null; } else { $isEmptyCallback = $this->config->getIsEmptyCallback(); } if (null !== $isEmptyCallback) { return $isEmptyCallback($this->modelData); } return FormUtil::isEmpty($this->modelData) || // arrays, countables ((\is_array($this->modelData) || $this->modelData instanceof \Countable) && 0 === \count($this->modelData)) || // traversables that are not countable ($this->modelData instanceof \Traversable && 0 === iterator_count($this->modelData)); } /** * {@inheritdoc} */ public function isValid() { if (!$this->submitted) { throw new LogicException('Cannot check if an unsubmitted form is valid. Call Form::isSubmitted() before Form::isValid().'); } if ($this->isDisabled()) { return true; } return 0 === \count($this->getErrors(true)); } /** * Returns the button that was used to submit the form. * * @return FormInterface|ClickableInterface|null */ public function getClickedButton() { if ($this->clickedButton) { return $this->clickedButton; } return $this->parent && method_exists($this->parent, 'getClickedButton') ? $this->parent->getClickedButton() : null; } /** * {@inheritdoc} */ public function getErrors(bool $deep = false, bool $flatten = true) { $errors = $this->errors; // Copy the errors of nested forms to the $errors array if ($deep) { foreach ($this as $child) { /** @var FormInterface $child */ if ($child->isSubmitted() && $child->isValid()) { continue; } $iterator = $child->getErrors(true, $flatten); if (0 === \count($iterator)) { continue; } if ($flatten) { foreach ($iterator as $error) { $errors[] = $error; } } else { $errors[] = $iterator; } } } return new FormErrorIterator($this, $errors); } /** * {@inheritdoc} */ public function clearErrors(bool $deep = false): self { $this->errors = []; if ($deep) { // Clear errors from children foreach ($this as $child) { if ($child instanceof ClearableErrorsInterface) { $child->clearErrors(true); } } } return $this; } /** * {@inheritdoc} */ public function all() { return iterator_to_array($this->children); } /** * {@inheritdoc} */ public function add($child, string $type = null, array $options = []) { if ($this->submitted) { throw new AlreadySubmittedException('You cannot add children to a submitted form.'); } if (!$this->config->getCompound()) { throw new LogicException('You cannot add children to a simple form. Maybe you should set the option "compound" to true?'); } if (!$child instanceof FormInterface) { if (!\is_string($child) && !\is_int($child)) { throw new UnexpectedTypeException($child, 'string or Symfony\Component\Form\FormInterface'); } $child = (string) $child; if (null !== $type && !\is_string($type)) { throw new UnexpectedTypeException($type, 'string or null'); } // Never initialize child forms automatically $options['auto_initialize'] = false; if (null === $type && null === $this->config->getDataClass()) { $type = TextType::class; } if (null === $type) { $child = $this->config->getFormFactory()->createForProperty($this->config->getDataClass(), $child, null, $options); } else { $child = $this->config->getFormFactory()->createNamed($child, $type, null, $options); } } elseif ($child->getConfig()->getAutoInitialize()) { throw new RuntimeException(sprintf('Automatic initialization is only supported on root forms. You should set the "auto_initialize" option to false on the field "%s".', $child->getName())); } $this->children[$child->getName()] = $child; $child->setParent($this); // If setData() is currently being called, there is no need to call // mapDataToForms() here, as mapDataToForms() is called at the end // of setData() anyway. Not doing this check leads to an endless // recursion when initializing the form lazily and an event listener // (such as ResizeFormListener) adds fields depending on the data: // // * setData() is called, the form is not initialized yet // * add() is called by the listener (setData() is not complete, so // the form is still not initialized) // * getViewData() is called // * setData() is called since the form is not initialized yet // * ... endless recursion ... // // Also skip data mapping if setData() has not been called yet. // setData() will be called upon form initialization and data mapping // will take place by then. if (!$this->lockSetData && $this->defaultDataSet && !$this->inheritData) { $viewData = $this->getViewData(); $this->config->getDataMapper()->mapDataToForms( $viewData, new \RecursiveIteratorIterator(new InheritDataAwareIterator(new \ArrayIterator([$child->getName() => $child]))) ); } return $this; } /** * {@inheritdoc} */ public function remove(string $name) { if ($this->submitted) { throw new AlreadySubmittedException('You cannot remove children from a submitted form.'); } if (isset($this->children[$name])) { if (!$this->children[$name]->isSubmitted()) { $this->children[$name]->setParent(null); } unset($this->children[$name]); } return $this; } /** * {@inheritdoc} */ public function has(string $name) { return isset($this->children[$name]); } /** * {@inheritdoc} */ public function get(string $name) { if (isset($this->children[$name])) { return $this->children[$name]; } throw new OutOfBoundsException(sprintf('Child "%s" does not exist.', $name)); } /** * Returns whether a child with the given name exists (implements the \ArrayAccess interface). * * @param string $name The name of the child * * @return bool */ #[\ReturnTypeWillChange] public function offsetExists($name) { return $this->has($name); } /** * Returns the child with the given name (implements the \ArrayAccess interface). * * @param string $name The name of the child * * @return FormInterface * * @throws OutOfBoundsException if the named child does not exist */ #[\ReturnTypeWillChange] public function offsetGet($name) { return $this->get($name); } /** * Adds a child to the form (implements the \ArrayAccess interface). * * @param string $name Ignored. The name of the child is used * @param FormInterface $child The child to be added * * @return void * * @throws AlreadySubmittedException if the form has already been submitted * @throws LogicException when trying to add a child to a non-compound form * * @see self::add() */ #[\ReturnTypeWillChange] public function offsetSet($name, $child) { $this->add($child); } /** * Removes the child with the given name from the form (implements the \ArrayAccess interface). * * @param string $name The name of the child to remove * * @return void * * @throws AlreadySubmittedException if the form has already been submitted */ #[\ReturnTypeWillChange] public function offsetUnset($name) { $this->remove($name); } /** * Returns the iterator for this group. * * @return \Traversable<string, FormInterface> */ #[\ReturnTypeWillChange] public function getIterator() { return $this->children; } /** * Returns the number of form children (implements the \Countable interface). * * @return int */ #[\ReturnTypeWillChange] public function count() { return \count($this->children); } /** * {@inheritdoc} */ public function createView(FormView $parent = null) { if (null === $parent && $this->parent) { $parent = $this->parent->createView(); } $type = $this->config->getType(); $options = $this->config->getOptions(); // The methods createView(), buildView() and finishView() are called // explicitly here in order to be able to override either of them // in a custom resolved form type. $view = $type->createView($this, $parent); $type->buildView($view, $this, $options); foreach ($this->children as $name => $child) { $view->children[$name] = $child->createView($view); } $this->sort($view->children); $type->finishView($view, $this, $options); return $view; } /** * Sorts view fields based on their priority value. */ private function sort(array &$children): void { $c = []; $i = 0; $needsSorting = false; foreach ($children as $name => $child) { $c[$name] = ['p' => $child->vars['priority'] ?? 0, 'i' => $i++]; if (0 !== $c[$name]['p']) { $needsSorting = true; } } if (!$needsSorting) { return; } uksort($children, static function ($a, $b) use ($c): int { return [$c[$b]['p'], $c[$a]['i']] <=> [$c[$a]['p'], $c[$b]['i']]; }); } /** * Normalizes the underlying data if a model transformer is set. * * @return mixed * * @throws TransformationFailedException If the underlying data cannot be transformed to "normalized" format */ private function modelToNorm($value) { try { foreach ($this->config->getModelTransformers() as $transformer) { $value = $transformer->transform($value); } } catch (TransformationFailedException $exception) { throw new TransformationFailedException(sprintf('Unable to transform data for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); } return $value; } /** * Reverse transforms a value if a model transformer is set. * * @return mixed * * @throws TransformationFailedException If the value cannot be transformed to "model" format */ private function normToModel($value) { try { $transformers = $this->config->getModelTransformers(); for ($i = \count($transformers) - 1; $i >= 0; --$i) { $value = $transformers[$i]->reverseTransform($value); } } catch (TransformationFailedException $exception) { throw new TransformationFailedException(sprintf('Unable to reverse value for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); } return $value; } /** * Transforms the value if a view transformer is set. * * @return mixed * * @throws TransformationFailedException If the normalized value cannot be transformed to "view" format */ private function normToView($value) { // Scalar values should be converted to strings to // facilitate differentiation between empty ("") and zero (0). // Only do this for simple forms, as the resulting value in // compound forms is passed to the data mapper and thus should // not be converted to a string before. if (!($transformers = $this->config->getViewTransformers()) && !$this->config->getCompound()) { return null === $value || \is_scalar($value) ? (string) $value : $value; } try { foreach ($transformers as $transformer) { $value = $transformer->transform($value); } } catch (TransformationFailedException $exception) { throw new TransformationFailedException(sprintf('Unable to transform value for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); } return $value; } /** * Reverse transforms a value if a view transformer is set. * * @return mixed * * @throws TransformationFailedException If the submitted value cannot be transformed to "normalized" format */ private function viewToNorm($value) { if (!$transformers = $this->config->getViewTransformers()) { return '' === $value ? null : $value; } try { for ($i = \count($transformers) - 1; $i >= 0; --$i) { $value = $transformers[$i]->reverseTransform($value); } } catch (TransformationFailedException $exception) { throw new TransformationFailedException(sprintf('Unable to reverse value for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); } return $value; } } FormBuilder.php 0000644 00000016335 15120211545 0007473 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\Exception\BadMethodCallException; use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Extension\Core\Type\TextType; /** * A builder for creating {@link Form} instances. * * @author Bernhard Schussek <bschussek@gmail.com> * * @implements \IteratorAggregate<string, FormBuilderInterface> */ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormBuilderInterface { /** * The children of the form builder. * * @var FormBuilderInterface[] */ private $children = []; /** * The data of children who haven't been converted to form builders yet. * * @var array */ private $unresolvedChildren = []; public function __construct(?string $name, ?string $dataClass, EventDispatcherInterface $dispatcher, FormFactoryInterface $factory, array $options = []) { parent::__construct($name, $dataClass, $dispatcher, $options); $this->setFormFactory($factory); } /** * {@inheritdoc} */ public function add($child, string $type = null, array $options = []) { if ($this->locked) { throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } if ($child instanceof FormBuilderInterface) { $this->children[$child->getName()] = $child; // In case an unresolved child with the same name exists unset($this->unresolvedChildren[$child->getName()]); return $this; } if (!\is_string($child) && !\is_int($child)) { throw new UnexpectedTypeException($child, 'string or Symfony\Component\Form\FormBuilderInterface'); } if (null !== $type && !\is_string($type)) { throw new UnexpectedTypeException($type, 'string or null'); } // Add to "children" to maintain order $this->children[$child] = null; $this->unresolvedChildren[$child] = [$type, $options]; return $this; } /** * {@inheritdoc} */ public function create($name, string $type = null, array $options = []) { if ($this->locked) { throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } if (null === $type && null === $this->getDataClass()) { $type = TextType::class; } if (null !== $type) { return $this->getFormFactory()->createNamedBuilder($name, $type, null, $options); } return $this->getFormFactory()->createBuilderForProperty($this->getDataClass(), $name, null, $options); } /** * {@inheritdoc} */ public function get($name) { if ($this->locked) { throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } if (isset($this->unresolvedChildren[$name])) { return $this->resolveChild($name); } if (isset($this->children[$name])) { return $this->children[$name]; } throw new InvalidArgumentException(sprintf('The child with the name "%s" does not exist.', $name)); } /** * {@inheritdoc} */ public function remove($name) { if ($this->locked) { throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } unset($this->unresolvedChildren[$name], $this->children[$name]); return $this; } /** * {@inheritdoc} */ public function has($name) { if ($this->locked) { throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } return isset($this->unresolvedChildren[$name]) || isset($this->children[$name]); } /** * {@inheritdoc} */ public function all() { if ($this->locked) { throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->resolveChildren(); return $this->children; } /** * @return int */ #[\ReturnTypeWillChange] public function count() { if ($this->locked) { throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } return \count($this->children); } /** * {@inheritdoc} */ public function getFormConfig() { /** @var $config self */ $config = parent::getFormConfig(); $config->children = []; $config->unresolvedChildren = []; return $config; } /** * {@inheritdoc} */ public function getForm() { if ($this->locked) { throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->resolveChildren(); $form = new Form($this->getFormConfig()); foreach ($this->children as $child) { // Automatic initialization is only supported on root forms $form->add($child->setAutoInitialize(false)->getForm()); } if ($this->getAutoInitialize()) { // Automatically initialize the form if it is configured so $form->initialize(); } return $form; } /** * {@inheritdoc} * * @return \Traversable<string, FormBuilderInterface> */ #[\ReturnTypeWillChange] public function getIterator() { if ($this->locked) { throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } return new \ArrayIterator($this->all()); } /** * Converts an unresolved child into a {@link FormBuilderInterface} instance. */ private function resolveChild(string $name): FormBuilderInterface { [$type, $options] = $this->unresolvedChildren[$name]; unset($this->unresolvedChildren[$name]); return $this->children[$name] = $this->create($name, $type, $options); } /** * Converts all unresolved children into {@link FormBuilder} instances. */ private function resolveChildren() { foreach ($this->unresolvedChildren as $name => $info) { $this->children[$name] = $this->create($name, $info[0], $info[1]); } $this->unresolvedChildren = []; } } FormBuilderInterface.php 0000644 00000004025 15120211545 0011305 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * @author Bernhard Schussek <bschussek@gmail.com> * * @extends \Traversable<string, FormBuilderInterface> */ interface FormBuilderInterface extends \Traversable, \Countable, FormConfigBuilderInterface { /** * Adds a new field to this group. A field must have a unique name within * the group. Otherwise the existing field is overwritten. * * If you add a nested group, this group should also be represented in the * object hierarchy. * * @param string|FormBuilderInterface $child * @param array<string, mixed> $options * * @return static */ public function add($child, string $type = null, array $options = []); /** * Creates a form builder. * * @param string $name The name of the form or the name of the property * @param string|null $type The type of the form or null if name is a property * @param array<string, mixed> $options * * @return self */ public function create(string $name, string $type = null, array $options = []); /** * Returns a child by name. * * @return self * * @throws Exception\InvalidArgumentException if the given child does not exist */ public function get(string $name); /** * Removes the field with the given name. * * @return static */ public function remove(string $name); /** * Returns whether a field with the given name exists. * * @return bool */ public function has(string $name); /** * Returns the children. * * @return array<string, self> */ public function all(); /** * Creates the form. * * @return FormInterface */ public function getForm(); } FormConfigBuilder.php 0000644 00000045750 15120211545 0010624 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\ImmutableEventDispatcher; use Symfony\Component\Form\Exception\BadMethodCallException; use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\PropertyAccess\PropertyPath; use Symfony\Component\PropertyAccess\PropertyPathInterface; /** * A basic form configuration. * * @author Bernhard Schussek <bschussek@gmail.com> */ class FormConfigBuilder implements FormConfigBuilderInterface { /** * Caches a globally unique {@link NativeRequestHandler} instance. * * @var NativeRequestHandler */ private static $nativeRequestHandler; protected $locked = false; private $dispatcher; private $name; /** * @var PropertyPathInterface|string|null */ private $propertyPath; private $mapped = true; private $byReference = true; private $inheritData = false; private $compound = false; /** * @var ResolvedFormTypeInterface */ private $type; private $viewTransformers = []; private $modelTransformers = []; /** * @var DataMapperInterface|null */ private $dataMapper; private $required = true; private $disabled = false; private $errorBubbling = false; /** * @var mixed */ private $emptyData; private $attributes = []; /** * @var mixed */ private $data; /** * @var string|null */ private $dataClass; private $dataLocked = false; /** * @var FormFactoryInterface|null */ private $formFactory; private $action = ''; private $method = 'POST'; /** * @var RequestHandlerInterface|null */ private $requestHandler; private $autoInitialize = false; private $options; private $isEmptyCallback; /** * Creates an empty form configuration. * * @param string|null $name The form name * @param string|null $dataClass The class of the form's data * * @throws InvalidArgumentException if the data class is not a valid class or if * the name contains invalid characters */ public function __construct(?string $name, ?string $dataClass, EventDispatcherInterface $dispatcher, array $options = []) { self::validateName($name); if (null !== $dataClass && !class_exists($dataClass) && !interface_exists($dataClass, false)) { throw new InvalidArgumentException(sprintf('Class "%s" not found. Is the "data_class" form option set correctly?', $dataClass)); } $this->name = (string) $name; $this->dataClass = $dataClass; $this->dispatcher = $dispatcher; $this->options = $options; } /** * {@inheritdoc} */ public function addEventListener(string $eventName, callable $listener, int $priority = 0) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->dispatcher->addListener($eventName, $listener, $priority); return $this; } /** * {@inheritdoc} */ public function addEventSubscriber(EventSubscriberInterface $subscriber) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->dispatcher->addSubscriber($subscriber); return $this; } /** * {@inheritdoc} */ public function addViewTransformer(DataTransformerInterface $viewTransformer, bool $forcePrepend = false) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } if ($forcePrepend) { array_unshift($this->viewTransformers, $viewTransformer); } else { $this->viewTransformers[] = $viewTransformer; } return $this; } /** * {@inheritdoc} */ public function resetViewTransformers() { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->viewTransformers = []; return $this; } /** * {@inheritdoc} */ public function addModelTransformer(DataTransformerInterface $modelTransformer, bool $forceAppend = false) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } if ($forceAppend) { $this->modelTransformers[] = $modelTransformer; } else { array_unshift($this->modelTransformers, $modelTransformer); } return $this; } /** * {@inheritdoc} */ public function resetModelTransformers() { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->modelTransformers = []; return $this; } /** * {@inheritdoc} */ public function getEventDispatcher() { if ($this->locked && !$this->dispatcher instanceof ImmutableEventDispatcher) { $this->dispatcher = new ImmutableEventDispatcher($this->dispatcher); } return $this->dispatcher; } /** * {@inheritdoc} */ public function getName() { return $this->name; } /** * {@inheritdoc} */ public function getPropertyPath() { return $this->propertyPath; } /** * {@inheritdoc} */ public function getMapped() { return $this->mapped; } /** * {@inheritdoc} */ public function getByReference() { return $this->byReference; } /** * {@inheritdoc} */ public function getInheritData() { return $this->inheritData; } /** * {@inheritdoc} */ public function getCompound() { return $this->compound; } /** * {@inheritdoc} */ public function getType() { return $this->type; } /** * {@inheritdoc} */ public function getViewTransformers() { return $this->viewTransformers; } /** * {@inheritdoc} */ public function getModelTransformers() { return $this->modelTransformers; } /** * {@inheritdoc} */ public function getDataMapper() { return $this->dataMapper; } /** * {@inheritdoc} */ public function getRequired() { return $this->required; } /** * {@inheritdoc} */ public function getDisabled() { return $this->disabled; } /** * {@inheritdoc} */ public function getErrorBubbling() { return $this->errorBubbling; } /** * {@inheritdoc} */ public function getEmptyData() { return $this->emptyData; } /** * {@inheritdoc} */ public function getAttributes() { return $this->attributes; } /** * {@inheritdoc} */ public function hasAttribute(string $name) { return \array_key_exists($name, $this->attributes); } /** * {@inheritdoc} */ public function getAttribute(string $name, $default = null) { return \array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; } /** * {@inheritdoc} */ public function getData() { return $this->data; } /** * {@inheritdoc} */ public function getDataClass() { return $this->dataClass; } /** * {@inheritdoc} */ public function getDataLocked() { return $this->dataLocked; } /** * {@inheritdoc} */ public function getFormFactory() { if (!isset($this->formFactory)) { throw new BadMethodCallException('The form factory must be set before retrieving it.'); } return $this->formFactory; } /** * {@inheritdoc} */ public function getAction() { return $this->action; } /** * {@inheritdoc} */ public function getMethod() { return $this->method; } /** * {@inheritdoc} */ public function getRequestHandler() { if (null === $this->requestHandler) { if (null === self::$nativeRequestHandler) { self::$nativeRequestHandler = new NativeRequestHandler(); } $this->requestHandler = self::$nativeRequestHandler; } return $this->requestHandler; } /** * {@inheritdoc} */ public function getAutoInitialize() { return $this->autoInitialize; } /** * {@inheritdoc} */ public function getOptions() { return $this->options; } /** * {@inheritdoc} */ public function hasOption(string $name) { return \array_key_exists($name, $this->options); } /** * {@inheritdoc} */ public function getOption(string $name, $default = null) { return \array_key_exists($name, $this->options) ? $this->options[$name] : $default; } /** * {@inheritdoc} */ public function getIsEmptyCallback(): ?callable { return $this->isEmptyCallback; } /** * {@inheritdoc} */ public function setAttribute(string $name, $value) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->attributes[$name] = $value; return $this; } /** * {@inheritdoc} */ public function setAttributes(array $attributes) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->attributes = $attributes; return $this; } /** * {@inheritdoc} */ public function setDataMapper(DataMapperInterface $dataMapper = null) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->dataMapper = $dataMapper; return $this; } /** * {@inheritdoc} */ public function setDisabled(bool $disabled) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->disabled = $disabled; return $this; } /** * {@inheritdoc} */ public function setEmptyData($emptyData) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->emptyData = $emptyData; return $this; } /** * {@inheritdoc} */ public function setErrorBubbling(bool $errorBubbling) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->errorBubbling = $errorBubbling; return $this; } /** * {@inheritdoc} */ public function setRequired(bool $required) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->required = $required; return $this; } /** * {@inheritdoc} */ public function setPropertyPath($propertyPath) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } if (null !== $propertyPath && !$propertyPath instanceof PropertyPathInterface) { $propertyPath = new PropertyPath($propertyPath); } $this->propertyPath = $propertyPath; return $this; } /** * {@inheritdoc} */ public function setMapped(bool $mapped) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->mapped = $mapped; return $this; } /** * {@inheritdoc} */ public function setByReference(bool $byReference) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->byReference = $byReference; return $this; } /** * {@inheritdoc} */ public function setInheritData(bool $inheritData) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->inheritData = $inheritData; return $this; } /** * {@inheritdoc} */ public function setCompound(bool $compound) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->compound = $compound; return $this; } /** * {@inheritdoc} */ public function setType(ResolvedFormTypeInterface $type) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->type = $type; return $this; } /** * {@inheritdoc} */ public function setData($data) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->data = $data; return $this; } /** * {@inheritdoc} */ public function setDataLocked(bool $locked) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->dataLocked = $locked; return $this; } /** * {@inheritdoc} */ public function setFormFactory(FormFactoryInterface $formFactory) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->formFactory = $formFactory; return $this; } /** * {@inheritdoc} */ public function setAction(string $action) { if ($this->locked) { throw new BadMethodCallException('The config builder cannot be modified anymore.'); } $this->action = $action; return $this; } /** * {@inheritdoc} */ public function setMethod(string $method) { if ($this->locked) { throw new BadMethodCallException('The config builder cannot be modified anymore.'); } $this->method = strtoupper($method); return $this; } /** * {@inheritdoc} */ public function setRequestHandler(RequestHandlerInterface $requestHandler) { if ($this->locked) { throw new BadMethodCallException('The config builder cannot be modified anymore.'); } $this->requestHandler = $requestHandler; return $this; } /** * {@inheritdoc} */ public function setAutoInitialize(bool $initialize) { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } $this->autoInitialize = $initialize; return $this; } /** * {@inheritdoc} */ public function getFormConfig() { if ($this->locked) { throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } // This method should be idempotent, so clone the builder $config = clone $this; $config->locked = true; return $config; } /** * {@inheritdoc} */ public function setIsEmptyCallback(?callable $isEmptyCallback) { $this->isEmptyCallback = $isEmptyCallback; return $this; } /** * Validates whether the given variable is a valid form name. * * @throws InvalidArgumentException if the name contains invalid characters * * @internal */ final public static function validateName(?string $name) { if (!self::isValidName($name)) { throw new InvalidArgumentException(sprintf('The name "%s" contains illegal characters. Names should start with a letter, digit or underscore and only contain letters, digits, numbers, underscores ("_"), hyphens ("-") and colons (":").', $name)); } } /** * Returns whether the given variable contains a valid form name. * * A name is accepted if it * * * is empty * * starts with a letter, digit or underscore * * contains only letters, digits, numbers, underscores ("_"), * hyphens ("-") and colons (":") */ final public static function isValidName(?string $name): bool { return '' === $name || null === $name || preg_match('/^[a-zA-Z0-9_][a-zA-Z0-9_\-:]*$/D', $name); } } FormConfigBuilderInterface.php 0000644 00000015617 15120211545 0012444 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\PropertyAccess\PropertyPathInterface; /** * @author Bernhard Schussek <bschussek@gmail.com> * * @method $this setIsEmptyCallback(callable|null $isEmptyCallback) Sets the callback that will be called to determine if the model data of the form is empty or not - not implementing it is deprecated since Symfony 5.1 */ interface FormConfigBuilderInterface extends FormConfigInterface { /** * Adds an event listener to an event on this form. * * @param int $priority The priority of the listener. Listeners * with a higher priority are called before * listeners with a lower priority. * * @return $this */ public function addEventListener(string $eventName, callable $listener, int $priority = 0); /** * Adds an event subscriber for events on this form. * * @return $this */ public function addEventSubscriber(EventSubscriberInterface $subscriber); /** * Appends / prepends a transformer to the view transformer chain. * * The transform method of the transformer is used to convert data from the * normalized to the view format. * The reverseTransform method of the transformer is used to convert from the * view to the normalized format. * * @param bool $forcePrepend If set to true, prepend instead of appending * * @return $this */ public function addViewTransformer(DataTransformerInterface $viewTransformer, bool $forcePrepend = false); /** * Clears the view transformers. * * @return $this */ public function resetViewTransformers(); /** * Prepends / appends a transformer to the normalization transformer chain. * * The transform method of the transformer is used to convert data from the * model to the normalized format. * The reverseTransform method of the transformer is used to convert from the * normalized to the model format. * * @param bool $forceAppend If set to true, append instead of prepending * * @return $this */ public function addModelTransformer(DataTransformerInterface $modelTransformer, bool $forceAppend = false); /** * Clears the normalization transformers. * * @return $this */ public function resetModelTransformers(); /** * Sets the value for an attribute. * * @param mixed $value The value of the attribute * * @return $this */ public function setAttribute(string $name, $value); /** * Sets the attributes. * * @return $this */ public function setAttributes(array $attributes); /** * Sets the data mapper used by the form. * * @return $this */ public function setDataMapper(DataMapperInterface $dataMapper = null); /** * Sets whether the form is disabled. * * @return $this */ public function setDisabled(bool $disabled); /** * Sets the data used for the client data when no value is submitted. * * @param mixed $emptyData The empty data * * @return $this */ public function setEmptyData($emptyData); /** * Sets whether errors bubble up to the parent. * * @return $this */ public function setErrorBubbling(bool $errorBubbling); /** * Sets whether this field is required to be filled out when submitted. * * @return $this */ public function setRequired(bool $required); /** * Sets the property path that the form should be mapped to. * * @param string|PropertyPathInterface|null $propertyPath The property path or null if the path should be set * automatically based on the form's name * * @return $this */ public function setPropertyPath($propertyPath); /** * Sets whether the form should be mapped to an element of its * parent's data. * * @return $this */ public function setMapped(bool $mapped); /** * Sets whether the form's data should be modified by reference. * * @return $this */ public function setByReference(bool $byReference); /** * Sets whether the form should read and write the data of its parent. * * @return $this */ public function setInheritData(bool $inheritData); /** * Sets whether the form should be compound. * * @return $this * * @see FormConfigInterface::getCompound() */ public function setCompound(bool $compound); /** * Sets the resolved type. * * @return $this */ public function setType(ResolvedFormTypeInterface $type); /** * Sets the initial data of the form. * * @param mixed $data The data of the form in model format * * @return $this */ public function setData($data); /** * Locks the form's data to the data passed in the configuration. * * A form with locked data is restricted to the data passed in * this configuration. The data can only be modified then by * submitting the form or using PRE_SET_DATA event. * * It means data passed to a factory method or mapped from the * parent will be ignored. * * @return $this */ public function setDataLocked(bool $locked); /** * Sets the form factory used for creating new forms. */ public function setFormFactory(FormFactoryInterface $formFactory); /** * Sets the target URL of the form. * * @return $this */ public function setAction(string $action); /** * Sets the HTTP method used by the form. * * @return $this */ public function setMethod(string $method); /** * Sets the request handler used by the form. * * @return $this */ public function setRequestHandler(RequestHandlerInterface $requestHandler); /** * Sets whether the form should be initialized automatically. * * Should be set to true only for root forms. * * @param bool $initialize True to initialize the form automatically, * false to suppress automatic initialization. * In the second case, you need to call * {@link FormInterface::initialize()} manually. * * @return $this */ public function setAutoInitialize(bool $initialize); /** * Builds and returns the form configuration. * * @return FormConfigInterface */ public function getFormConfig(); } FormConfigInterface.php 0000644 00000013522 15120211545 0011126 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\PropertyAccess\PropertyPathInterface; /** * The configuration of a {@link Form} object. * * @author Bernhard Schussek <bschussek@gmail.com> * * @method callable|null getIsEmptyCallback() Returns a callable that takes the model data as argument and that returns if it is empty or not - not implementing it is deprecated since Symfony 5.1 */ interface FormConfigInterface { /** * Returns the event dispatcher used to dispatch form events. * * @return EventDispatcherInterface */ public function getEventDispatcher(); /** * Returns the name of the form used as HTTP parameter. * * @return string */ public function getName(); /** * Returns the property path that the form should be mapped to. * * @return PropertyPathInterface|null */ public function getPropertyPath(); /** * Returns whether the form should be mapped to an element of its * parent's data. * * @return bool */ public function getMapped(); /** * Returns whether the form's data should be modified by reference. * * @return bool */ public function getByReference(); /** * Returns whether the form should read and write the data of its parent. * * @return bool */ public function getInheritData(); /** * Returns whether the form is compound. * * This property is independent of whether the form actually has * children. A form can be compound and have no children at all, like * for example an empty collection form. * The contrary is not possible, a form which is not compound * cannot have any children. * * @return bool */ public function getCompound(); /** * Returns the resolved form type used to construct the form. * * @return ResolvedFormTypeInterface */ public function getType(); /** * Returns the view transformers of the form. * * @return DataTransformerInterface[] */ public function getViewTransformers(); /** * Returns the model transformers of the form. * * @return DataTransformerInterface[] */ public function getModelTransformers(); /** * Returns the data mapper of the compound form or null for a simple form. * * @return DataMapperInterface|null */ public function getDataMapper(); /** * Returns whether the form is required. * * @return bool */ public function getRequired(); /** * Returns whether the form is disabled. * * @return bool */ public function getDisabled(); /** * Returns whether errors attached to the form will bubble to its parent. * * @return bool */ public function getErrorBubbling(); /** * Used when the view data is empty on submission. * * When the form is compound it will also be used to map the * children data. * * The empty data must match the view format as it will passed to the first view transformer's * "reverseTransform" method. * * @return mixed */ public function getEmptyData(); /** * Returns additional attributes of the form. * * @return array */ public function getAttributes(); /** * Returns whether the attribute with the given name exists. * * @return bool */ public function hasAttribute(string $name); /** * Returns the value of the given attribute. * * @param mixed $default The value returned if the attribute does not exist * * @return mixed */ public function getAttribute(string $name, $default = null); /** * Returns the initial data of the form. * * @return mixed */ public function getData(); /** * Returns the class of the view data or null if the data is scalar or an array. * * @return string|null */ public function getDataClass(); /** * Returns whether the form's data is locked. * * A form with locked data is restricted to the data passed in * this configuration. The data can only be modified then by * submitting the form. * * @return bool */ public function getDataLocked(); /** * Returns the form factory used for creating new forms. * * @return FormFactoryInterface */ public function getFormFactory(); /** * Returns the target URL of the form. * * @return string */ public function getAction(); /** * Returns the HTTP method used by the form. * * @return string */ public function getMethod(); /** * Returns the request handler used by the form. * * @return RequestHandlerInterface */ public function getRequestHandler(); /** * Returns whether the form should be initialized upon creation. * * @return bool */ public function getAutoInitialize(); /** * Returns all options passed during the construction of the form. * * @return array<string, mixed> The passed options */ public function getOptions(); /** * Returns whether a specific option exists. * * @return bool */ public function hasOption(string $name); /** * Returns the value of a specific option. * * @param mixed $default The value returned if the option does not exist * * @return mixed */ public function getOption(string $name, $default = null); } FormError.php 0000644 00000006361 15120211545 0007174 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\BadMethodCallException; /** * Wraps errors in forms. * * @author Bernhard Schussek <bschussek@gmail.com> */ class FormError { protected $messageTemplate; protected $messageParameters; protected $messagePluralization; private $message; private $cause; /** * The form that spawned this error. * * @var FormInterface */ private $origin; /** * Any array key in $messageParameters will be used as a placeholder in * $messageTemplate. * * @param string $message The translated error message * @param string|null $messageTemplate The template for the error message * @param array $messageParameters The parameters that should be * substituted in the message template * @param int|null $messagePluralization The value for error message pluralization * @param mixed $cause The cause of the error * * @see \Symfony\Component\Translation\Translator */ public function __construct(string $message, string $messageTemplate = null, array $messageParameters = [], int $messagePluralization = null, $cause = null) { $this->message = $message; $this->messageTemplate = $messageTemplate ?: $message; $this->messageParameters = $messageParameters; $this->messagePluralization = $messagePluralization; $this->cause = $cause; } /** * Returns the error message. * * @return string */ public function getMessage() { return $this->message; } /** * Returns the error message template. * * @return string */ public function getMessageTemplate() { return $this->messageTemplate; } /** * Returns the parameters to be inserted in the message template. * * @return array */ public function getMessageParameters() { return $this->messageParameters; } /** * Returns the value for error message pluralization. * * @return int|null */ public function getMessagePluralization() { return $this->messagePluralization; } /** * Returns the cause of this error. * * @return mixed */ public function getCause() { return $this->cause; } /** * Sets the form that caused this error. * * This method must only be called once. * * @throws BadMethodCallException If the method is called more than once */ public function setOrigin(FormInterface $origin) { if (null !== $this->origin) { throw new BadMethodCallException('setOrigin() must only be called once.'); } $this->origin = $origin; } /** * Returns the form that caused this error. * * @return FormInterface|null */ public function getOrigin() { return $this->origin; } } FormErrorIterator.php 0000644 00000020222 15120211545 0010676 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\BadMethodCallException; use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Exception\OutOfBoundsException; use Symfony\Component\Validator\ConstraintViolation; /** * Iterates over the errors of a form. * * This class supports recursive iteration. In order to iterate recursively, * pass a structure of {@link FormError} and {@link FormErrorIterator} objects * to the $errors constructor argument. * * You can also wrap the iterator into a {@link \RecursiveIteratorIterator} to * flatten the recursive structure into a flat list of errors. * * @author Bernhard Schussek <bschussek@gmail.com> * * @template T of FormError|FormErrorIterator * * @implements \ArrayAccess<int, T> * @implements \RecursiveIterator<int, T> * @implements \SeekableIterator<int, T> */ class FormErrorIterator implements \RecursiveIterator, \SeekableIterator, \ArrayAccess, \Countable { /** * The prefix used for indenting nested error messages. */ public const INDENTATION = ' '; private $form; /** * @var list<T> */ private $errors; /** * @param list<T> $errors * * @throws InvalidArgumentException If the errors are invalid */ public function __construct(FormInterface $form, array $errors) { foreach ($errors as $error) { if (!($error instanceof FormError || $error instanceof self)) { throw new InvalidArgumentException(sprintf('The errors must be instances of "Symfony\Component\Form\FormError" or "%s". Got: "%s".', __CLASS__, get_debug_type($error))); } } $this->form = $form; $this->errors = $errors; } /** * Returns all iterated error messages as string. * * @return string */ public function __toString() { $string = ''; foreach ($this->errors as $error) { if ($error instanceof FormError) { $string .= 'ERROR: '.$error->getMessage()."\n"; } else { /* @var self $error */ $string .= $error->getForm()->getName().":\n"; $string .= self::indent((string) $error); } } return $string; } /** * Returns the iterated form. * * @return FormInterface */ public function getForm() { return $this->form; } /** * Returns the current element of the iterator. * * @return T An error or an iterator containing nested errors */ #[\ReturnTypeWillChange] public function current() { return current($this->errors); } /** * Advances the iterator to the next position. */ #[\ReturnTypeWillChange] public function next() { next($this->errors); } /** * Returns the current position of the iterator. * * @return int */ #[\ReturnTypeWillChange] public function key() { return key($this->errors); } /** * Returns whether the iterator's position is valid. * * @return bool */ #[\ReturnTypeWillChange] public function valid() { return null !== key($this->errors); } /** * Sets the iterator's position to the beginning. * * This method detects if errors have been added to the form since the * construction of the iterator. */ #[\ReturnTypeWillChange] public function rewind() { reset($this->errors); } /** * Returns whether a position exists in the iterator. * * @param int $position The position * * @return bool */ #[\ReturnTypeWillChange] public function offsetExists($position) { return isset($this->errors[$position]); } /** * Returns the element at a position in the iterator. * * @param int $position The position * * @return T * * @throws OutOfBoundsException If the given position does not exist */ #[\ReturnTypeWillChange] public function offsetGet($position) { if (!isset($this->errors[$position])) { throw new OutOfBoundsException('The offset '.$position.' does not exist.'); } return $this->errors[$position]; } /** * Unsupported method. * * @return void * * @throws BadMethodCallException */ #[\ReturnTypeWillChange] public function offsetSet($position, $value) { throw new BadMethodCallException('The iterator doesn\'t support modification of elements.'); } /** * Unsupported method. * * @return void * * @throws BadMethodCallException */ #[\ReturnTypeWillChange] public function offsetUnset($position) { throw new BadMethodCallException('The iterator doesn\'t support modification of elements.'); } /** * Returns whether the current element of the iterator can be recursed * into. * * @return bool */ #[\ReturnTypeWillChange] public function hasChildren() { return current($this->errors) instanceof self; } /** * @return self */ #[\ReturnTypeWillChange] public function getChildren() { if (!$this->hasChildren()) { trigger_deprecation('symfony/form', '5.4', 'Calling "%s()" if the current element is not iterable is deprecated, call "%s" to get the current element.', __METHOD__, self::class.'::current()'); // throw new LogicException(sprintf('The current element is not iterable. Use "%s" to get the current element.', self::class.'::current()')); } /** @var self $children */ $children = current($this->errors); return $children; } /** * Returns the number of elements in the iterator. * * Note that this is not the total number of errors, if the constructor * parameter $deep was set to true! In that case, you should wrap the * iterator into a {@link \RecursiveIteratorIterator} with the standard mode * {@link \RecursiveIteratorIterator::LEAVES_ONLY} and count the result. * * $iterator = new \RecursiveIteratorIterator($form->getErrors(true)); * $count = count(iterator_to_array($iterator)); * * Alternatively, set the constructor argument $flatten to true as well. * * $count = count($form->getErrors(true, true)); * * @return int */ #[\ReturnTypeWillChange] public function count() { return \count($this->errors); } /** * Sets the position of the iterator. * * @param int $position The new position * * @return void * * @throws OutOfBoundsException If the position is invalid */ #[\ReturnTypeWillChange] public function seek($position) { if (!isset($this->errors[$position])) { throw new OutOfBoundsException('The offset '.$position.' does not exist.'); } reset($this->errors); while ($position !== key($this->errors)) { next($this->errors); } } /** * Creates iterator for errors with specific codes. * * @param string|string[] $codes The codes to find * * @return static */ public function findByCodes($codes) { $codes = (array) $codes; $errors = []; foreach ($this as $error) { $cause = $error->getCause(); if ($cause instanceof ConstraintViolation && \in_array($cause->getCode(), $codes, true)) { $errors[] = $error; } } return new static($this->form, $errors); } /** * Utility function for indenting multi-line strings. */ private static function indent(string $string): string { return rtrim(self::INDENTATION.str_replace("\n", "\n".self::INDENTATION, $string), ' '); } } FormEvent.php 0000644 00000002176 15120211545 0007164 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Contracts\EventDispatcher\Event; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class FormEvent extends Event { private $form; protected $data; /** * @param mixed $data The data */ public function __construct(FormInterface $form, $data) { $this->form = $form; $this->data = $data; } /** * Returns the form at the source of the event. * * @return FormInterface */ public function getForm() { return $this->form; } /** * Returns the data associated with this event. * * @return mixed */ public function getData() { return $this->data; } /** * Allows updating with some filtered data. * * @param mixed $data */ public function setData($data) { $this->data = $data; } } FormEvents.php 0000644 00000010031 15120211545 0007334 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Event\PostSetDataEvent; use Symfony\Component\Form\Event\PostSubmitEvent; use Symfony\Component\Form\Event\PreSetDataEvent; use Symfony\Component\Form\Event\PreSubmitEvent; use Symfony\Component\Form\Event\SubmitEvent; /** * To learn more about how form events work check the documentation * entry at {@link https://symfony.com/doc/any/components/form/form_events.html}. * * To learn how to dynamically modify forms using events check the cookbook * entry at {@link https://symfony.com/doc/any/cookbook/form/dynamic_form_modification.html}. * * @author Bernhard Schussek <bschussek@gmail.com> */ final class FormEvents { /** * The PRE_SUBMIT event is dispatched at the beginning of the Form::submit() method. * * It can be used to: * - Change data from the request, before submitting the data to the form. * - Add or remove form fields, before submitting the data to the form. * * @Event("Symfony\Component\Form\Event\PreSubmitEvent") */ public const PRE_SUBMIT = 'form.pre_submit'; /** * The SUBMIT event is dispatched after the Form::submit() method * has changed the view data by the request data, or submitted and mapped * the children if the form is compound, and after reverse transformation * to normalized representation. * * It's also dispatched just before the Form::submit() method transforms back * the normalized data to the model and view data. * * So at this stage children of compound forms are submitted and synchronized, unless * their transformation failed, but a parent would still be at the PRE_SUBMIT level. * * Since the current form is not synchronized yet, it is still possible to add and * remove fields. * * @Event("Symfony\Component\Form\Event\SubmitEvent") */ public const SUBMIT = 'form.submit'; /** * The FormEvents::POST_SUBMIT event is dispatched at the very end of the Form::submit(). * * It this stage the model and view data may have been denormalized. Otherwise the form * is desynchronized because transformation failed during submission. * * It can be used to fetch data after denormalization. * * The event attaches the current view data. To know whether this is the renormalized data * or the invalid request data, call Form::isSynchronized() first. * * @Event("Symfony\Component\Form\Event\PostSubmitEvent") */ public const POST_SUBMIT = 'form.post_submit'; /** * The FormEvents::PRE_SET_DATA event is dispatched at the beginning of the Form::setData() method. * * It can be used to: * - Modify the data given during pre-population; * - Keep synchronized the form depending on the data (adding or removing fields dynamically). * * @Event("Symfony\Component\Form\Event\PreSetDataEvent") */ public const PRE_SET_DATA = 'form.pre_set_data'; /** * The FormEvents::POST_SET_DATA event is dispatched at the end of the Form::setData() method. * * This event can be used to modify the form depending on the final state of the underlying data * accessible in every representation: model, normalized and view. * * @Event("Symfony\Component\Form\Event\PostSetDataEvent") */ public const POST_SET_DATA = 'form.post_set_data'; /** * Event aliases. * * These aliases can be consumed by RegisterListenersPass. */ public const ALIASES = [ PreSubmitEvent::class => self::PRE_SUBMIT, SubmitEvent::class => self::SUBMIT, PostSubmitEvent::class => self::POST_SUBMIT, PreSetDataEvent::class => self::PRE_SET_DATA, PostSetDataEvent::class => self::POST_SET_DATA, ]; private function __construct() { } } FormView.php 0000644 00000007376 15120211545 0007024 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\BadMethodCallException; /** * @author Bernhard Schussek <bschussek@gmail.com> * * @implements \ArrayAccess<int|string, FormView> * @implements \IteratorAggregate<int|string, FormView> */ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable { /** * The variables assigned to this view. */ public $vars = [ 'value' => null, 'attr' => [], ]; /** * The parent view. */ public $parent; /** * The child views. * * @var array<int|string, FormView> */ public $children = []; /** * Is the form attached to this renderer rendered? * * Rendering happens when either the widget or the row method was called. * Row implicitly includes widget, however certain rendering mechanisms * have to skip widget rendering when a row is rendered. * * @var bool */ private $rendered = false; private $methodRendered = false; public function __construct(self $parent = null) { $this->parent = $parent; } /** * Returns whether the view was already rendered. * * @return bool */ public function isRendered() { if (true === $this->rendered || 0 === \count($this->children)) { return $this->rendered; } foreach ($this->children as $child) { if (!$child->isRendered()) { return false; } } return $this->rendered = true; } /** * Marks the view as rendered. * * @return $this */ public function setRendered() { $this->rendered = true; return $this; } /** * @return bool */ public function isMethodRendered() { return $this->methodRendered; } public function setMethodRendered() { $this->methodRendered = true; } /** * Returns a child by name (implements \ArrayAccess). * * @param int|string $name The child name * * @return self */ #[\ReturnTypeWillChange] public function offsetGet($name) { return $this->children[$name]; } /** * Returns whether the given child exists (implements \ArrayAccess). * * @param int|string $name The child name * * @return bool */ #[\ReturnTypeWillChange] public function offsetExists($name) { return isset($this->children[$name]); } /** * Implements \ArrayAccess. * * @return void * * @throws BadMethodCallException always as setting a child by name is not allowed */ #[\ReturnTypeWillChange] public function offsetSet($name, $value) { throw new BadMethodCallException('Not supported.'); } /** * Removes a child (implements \ArrayAccess). * * @param int|string $name The child name * * @return void */ #[\ReturnTypeWillChange] public function offsetUnset($name) { unset($this->children[$name]); } /** * Returns an iterator to iterate over children (implements \IteratorAggregate). * * @return \ArrayIterator<int|string, FormView> */ #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->children); } /** * Implements \Countable. * * @return int */ #[\ReturnTypeWillChange] public function count() { return \count($this->children); } } NativeRequestHandler.php 0000644 00000017032 15120211545 0011351 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Util\ServerParams; /** * A request handler using PHP super globals $_GET, $_POST and $_SERVER. * * @author Bernhard Schussek <bschussek@gmail.com> */ class NativeRequestHandler implements RequestHandlerInterface { private $serverParams; /** * The allowed keys of the $_FILES array. */ private const FILE_KEYS = [ 'error', 'name', 'size', 'tmp_name', 'type', ]; public function __construct(ServerParams $params = null) { $this->serverParams = $params ?? new ServerParams(); } /** * {@inheritdoc} * * @throws Exception\UnexpectedTypeException If the $request is not null */ public function handleRequest(FormInterface $form, $request = null) { if (null !== $request) { throw new UnexpectedTypeException($request, 'null'); } $name = $form->getName(); $method = $form->getConfig()->getMethod(); if ($method !== self::getRequestMethod()) { return; } // For request methods that must not have a request body we fetch data // from the query string. Otherwise we look for data in the request body. if ('GET' === $method || 'HEAD' === $method || 'TRACE' === $method) { if ('' === $name) { $data = $_GET; } else { // Don't submit GET requests if the form's name does not exist // in the request if (!isset($_GET[$name])) { return; } $data = $_GET[$name]; } } else { // Mark the form with an error if the uploaded size was too large // This is done here and not in FormValidator because $_POST is // empty when that error occurs. Hence the form is never submitted. if ($this->serverParams->hasPostMaxSizeBeenExceeded()) { // Submit the form, but don't clear the default values $form->submit(null, false); $form->addError(new FormError( $form->getConfig()->getOption('upload_max_size_message')(), null, ['{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()] )); return; } $fixedFiles = []; foreach ($_FILES as $fileKey => $file) { $fixedFiles[$fileKey] = self::stripEmptyFiles(self::fixPhpFilesArray($file)); } if ('' === $name) { $params = $_POST; $files = $fixedFiles; } elseif (\array_key_exists($name, $_POST) || \array_key_exists($name, $fixedFiles)) { $default = $form->getConfig()->getCompound() ? [] : null; $params = \array_key_exists($name, $_POST) ? $_POST[$name] : $default; $files = \array_key_exists($name, $fixedFiles) ? $fixedFiles[$name] : $default; } else { // Don't submit the form if it is not present in the request return; } if (\is_array($params) && \is_array($files)) { $data = array_replace_recursive($params, $files); } else { $data = $params ?: $files; } } // Don't auto-submit the form unless at least one field is present. if ('' === $name && \count(array_intersect_key($data, $form->all())) <= 0) { return; } if (\is_array($data) && \array_key_exists('_method', $data) && $method === $data['_method'] && !$form->has('_method')) { unset($data['_method']); } $form->submit($data, 'PATCH' !== $method); } /** * {@inheritdoc} */ public function isFileUpload($data) { // POST data will always be strings or arrays of strings. Thus, we can be sure // that the submitted data is a file upload if the "error" value is an integer // (this value must have been injected by PHP itself). return \is_array($data) && isset($data['error']) && \is_int($data['error']); } /** * @return int|null */ public function getUploadFileError($data) { if (!\is_array($data)) { return null; } if (!isset($data['error'])) { return null; } if (!\is_int($data['error'])) { return null; } if (\UPLOAD_ERR_OK === $data['error']) { return null; } return $data['error']; } /** * Returns the method used to submit the request to the server. */ private static function getRequestMethod(): string { $method = isset($_SERVER['REQUEST_METHOD']) ? strtoupper($_SERVER['REQUEST_METHOD']) : 'GET'; if ('POST' === $method && isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) { $method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']); } return $method; } /** * Fixes a malformed PHP $_FILES array. * * PHP has a bug that the format of the $_FILES array differs, depending on * whether the uploaded file fields had normal field names or array-like * field names ("normal" vs. "parent[child]"). * * This method fixes the array to look like the "normal" $_FILES array. * * It's safe to pass an already converted array, in which case this method * just returns the original array unmodified. * * This method is identical to {@link \Symfony\Component\HttpFoundation\FileBag::fixPhpFilesArray} * and should be kept as such in order to port fixes quickly and easily. * * @return mixed */ private static function fixPhpFilesArray($data) { if (!\is_array($data)) { return $data; } // Remove extra key added by PHP 8.1. unset($data['full_path']); $keys = array_keys($data); sort($keys); if (self::FILE_KEYS !== $keys || !isset($data['name']) || !\is_array($data['name'])) { return $data; } $files = $data; foreach (self::FILE_KEYS as $k) { unset($files[$k]); } foreach ($data['name'] as $key => $name) { $files[$key] = self::fixPhpFilesArray([ 'error' => $data['error'][$key], 'name' => $name, 'type' => $data['type'][$key], 'tmp_name' => $data['tmp_name'][$key], 'size' => $data['size'][$key], ]); } return $files; } /** * Sets empty uploaded files to NULL in the given uploaded files array. * * @return mixed */ private static function stripEmptyFiles($data) { if (!\is_array($data)) { return $data; } $keys = array_keys($data); sort($keys); if (self::FILE_KEYS === $keys) { if (\UPLOAD_ERR_NO_FILE === $data['error']) { return null; } return $data; } foreach ($data as $key => $value) { $data[$key] = self::stripEmptyFiles($value); } return $data; } } README.md 0000644 00000000743 15120211545 0006023 0 ustar 00 Form Component ============== The Form component allows you to easily create, process and reuse HTML forms. Resources --------- * [Documentation](https://symfony.com/doc/current/components/form.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) ResolvedFormTypeFactory.php 0000644 00000001222 15120211545 0012047 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * @author Bernhard Schussek <bschussek@gmail.com> */ class ResolvedFormTypeFactory implements ResolvedFormTypeFactoryInterface { /** * {@inheritdoc} */ public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null) { return new ResolvedFormType($type, $typeExtensions, $parent); } } SubmitButtonBuilder.php 0000644 00000001145 15120211545 0011220 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form; /** * A builder for {@link SubmitButton} instances. * * @author Bernhard Schussek <bschussek@gmail.com> */ class SubmitButtonBuilder extends ButtonBuilder { /** * Creates the button. * * @return SubmitButton */ public function getForm() { return new SubmitButton($this->getFormConfig()); } }
Coded With 💗 by
0x6ick