login consent app sql
This commit is contained in:
198
vendor/symfony/form/AbstractExtension.php
vendored
Normal file
198
vendor/symfony/form/AbstractExtension.php
vendored
Normal file
@ -0,0 +1,198 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
}
|
206
vendor/symfony/form/AbstractRendererEngine.php
vendored
Normal file
206
vendor/symfony/form/AbstractRendererEngine.php
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
<?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 = [];
|
||||
}
|
||||
}
|
66
vendor/symfony/form/AbstractType.php
vendored
Normal file
66
vendor/symfony/form/AbstractType.php
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
48
vendor/symfony/form/AbstractTypeExtension.php
vendored
Normal file
48
vendor/symfony/form/AbstractTypeExtension.php
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<?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)
|
||||
{
|
||||
}
|
||||
}
|
455
vendor/symfony/form/Button.php
vendored
Normal file
455
vendor/symfony/form/Button.php
vendored
Normal file
@ -0,0 +1,455 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
744
vendor/symfony/form/ButtonBuilder.php
vendored
Normal file
744
vendor/symfony/form/ButtonBuilder.php
vendored
Normal file
@ -0,0 +1,744 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
21
vendor/symfony/form/ButtonTypeInterface.php
vendored
Normal file
21
vendor/symfony/form/ButtonTypeInterface.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?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
|
||||
{
|
||||
}
|
567
vendor/symfony/form/CHANGELOG.md
vendored
Normal file
567
vendor/symfony/form/CHANGELOG.md
vendored
Normal file
@ -0,0 +1,567 @@
|
||||
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
|
44
vendor/symfony/form/CallbackTransformer.php
vendored
Normal file
44
vendor/symfony/form/CallbackTransformer.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
238
vendor/symfony/form/ChoiceList/ArrayChoiceList.php
vendored
Normal file
238
vendor/symfony/form/ChoiceList/ArrayChoiceList.php
vendored
Normal file
@ -0,0 +1,238 @@
|
||||
<?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 annd 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;
|
||||
}
|
||||
}
|
159
vendor/symfony/form/ChoiceList/ChoiceList.php
vendored
Normal file
159
vendor/symfony/form/ChoiceList/ChoiceList.php
vendored
Normal file
@ -0,0 +1,159 @@
|
||||
<?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()
|
||||
{
|
||||
}
|
||||
}
|
140
vendor/symfony/form/ChoiceList/ChoiceListInterface.php
vendored
Normal file
140
vendor/symfony/form/ChoiceList/ChoiceListInterface.php
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
<?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);
|
||||
}
|
64
vendor/symfony/form/ChoiceList/Factory/Cache/AbstractStaticOption.php
vendored
Normal file
64
vendor/symfony/form/ChoiceList/Factory/Cache/AbstractStaticOption.php
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
<?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 = [];
|
||||
}
|
||||
}
|
27
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceAttr.php
vendored
Normal file
27
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceAttr.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?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
|
||||
{
|
||||
}
|
27
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceFieldName.php
vendored
Normal file
27
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceFieldName.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?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
|
||||
{
|
||||
}
|
27
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceFilter.php
vendored
Normal file
27
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceFilter.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?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
|
||||
{
|
||||
}
|
27
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceLabel.php
vendored
Normal file
27
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceLabel.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?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
|
||||
{
|
||||
}
|
52
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceLoader.php
vendored
Normal file
52
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceLoader.php
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
27
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceTranslationParameters.php
vendored
Normal file
27
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceTranslationParameters.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?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
|
||||
{
|
||||
}
|
27
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceValue.php
vendored
Normal file
27
vendor/symfony/form/ChoiceList/Factory/Cache/ChoiceValue.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?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
|
||||
{
|
||||
}
|
27
vendor/symfony/form/ChoiceList/Factory/Cache/GroupBy.php
vendored
Normal file
27
vendor/symfony/form/ChoiceList/Factory/Cache/GroupBy.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?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
|
||||
{
|
||||
}
|
27
vendor/symfony/form/ChoiceList/Factory/Cache/PreferredChoice.php
vendored
Normal file
27
vendor/symfony/form/ChoiceList/Factory/Cache/PreferredChoice.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?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
|
||||
{
|
||||
}
|
254
vendor/symfony/form/ChoiceList/Factory/CachingFactoryDecorator.php
vendored
Normal file
254
vendor/symfony/form/ChoiceList/Factory/CachingFactoryDecorator.php
vendored
Normal file
@ -0,0 +1,254 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
88
vendor/symfony/form/ChoiceList/Factory/ChoiceListFactoryInterface.php
vendored
Normal file
88
vendor/symfony/form/ChoiceList/Factory/ChoiceListFactoryInterface.php
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
<?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 = []*/);
|
||||
}
|
322
vendor/symfony/form/ChoiceList/Factory/DefaultChoiceListFactory.php
vendored
Normal file
322
vendor/symfony/form/ChoiceList/Factory/DefaultChoiceListFactory.php
vendored
Normal file
@ -0,0 +1,322 @@
|
||||
<?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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
239
vendor/symfony/form/ChoiceList/Factory/PropertyAccessDecorator.php
vendored
Normal file
239
vendor/symfony/form/ChoiceList/Factory/PropertyAccessDecorator.php
vendored
Normal file
@ -0,0 +1,239 @@
|
||||
<?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
|
||||
);
|
||||
}
|
||||
}
|
103
vendor/symfony/form/ChoiceList/LazyChoiceList.php
vendored
Normal file
103
vendor/symfony/form/ChoiceList/LazyChoiceList.php
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
87
vendor/symfony/form/ChoiceList/Loader/AbstractChoiceLoader.php
vendored
Normal file
87
vendor/symfony/form/ChoiceList/Loader/AbstractChoiceLoader.php
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
<?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 choice list.
|
||||
*
|
||||
* @var ArrayChoiceList
|
||||
*/
|
||||
private $choiceList;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadChoiceList(callable $value = null): ChoiceListInterface
|
||||
{
|
||||
return $this->choiceList ?? ($this->choiceList = new ArrayChoiceList($this->loadChoices(), $value));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadChoicesForValues(array $values, callable $value = null)
|
||||
{
|
||||
if (!$values) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($this->choiceList) {
|
||||
return $this->choiceList->getChoicesForValues($values);
|
||||
}
|
||||
|
||||
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($value, $choices);
|
||||
}
|
||||
|
||||
if ($this->choiceList) {
|
||||
return $this->choiceList->getValuesForChoices($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);
|
||||
}
|
||||
}
|
35
vendor/symfony/form/ChoiceList/Loader/CallbackChoiceLoader.php
vendored
Normal file
35
vendor/symfony/form/ChoiceList/Loader/CallbackChoiceLoader.php
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
<?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)();
|
||||
}
|
||||
}
|
76
vendor/symfony/form/ChoiceList/Loader/ChoiceLoaderInterface.php
vendored
Normal file
76
vendor/symfony/form/ChoiceList/Loader/ChoiceLoaderInterface.php
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
<?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);
|
||||
}
|
63
vendor/symfony/form/ChoiceList/Loader/FilterChoiceLoaderDecorator.php
vendored
Normal file
63
vendor/symfony/form/ChoiceList/Loader/FilterChoiceLoaderDecorator.php
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
<?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 ($values && $filtered = array_filter($list->getChoicesForValues($values), $this->filter)) {
|
||||
$choices[$group] = $filtered;
|
||||
}
|
||||
// filter empty groups
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
44
vendor/symfony/form/ChoiceList/Loader/IntlCallbackChoiceLoader.php
vendored
Normal file
44
vendor/symfony/form/ChoiceList/Loader/IntlCallbackChoiceLoader.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
47
vendor/symfony/form/ChoiceList/View/ChoiceGroupView.php
vendored
Normal file
47
vendor/symfony/form/ChoiceList/View/ChoiceGroupView.php
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
59
vendor/symfony/form/ChoiceList/View/ChoiceListView.php
vendored
Normal file
59
vendor/symfony/form/ChoiceList/View/ChoiceListView.php
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
54
vendor/symfony/form/ChoiceList/View/ChoiceView.php
vendored
Normal file
54
vendor/symfony/form/ChoiceList/View/ChoiceView.php
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
29
vendor/symfony/form/ClearableErrorsInterface.php
vendored
Normal file
29
vendor/symfony/form/ClearableErrorsInterface.php
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
<?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);
|
||||
}
|
27
vendor/symfony/form/ClickableInterface.php
vendored
Normal file
27
vendor/symfony/form/ClickableInterface.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?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();
|
||||
}
|
292
vendor/symfony/form/Command/DebugCommand.php
vendored
Normal file
292
vendor/symfony/form/Command/DebugCommand.php
vendored
Normal file
@ -0,0 +1,292 @@
|
||||
<?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());
|
||||
}
|
||||
}
|
207
vendor/symfony/form/Console/Descriptor/Descriptor.php
vendored
Normal file
207
vendor/symfony/form/Console/Descriptor/Descriptor.php
vendored
Normal file
@ -0,0 +1,207 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
}
|
118
vendor/symfony/form/Console/Descriptor/JsonDescriptor.php
vendored
Normal file
118
vendor/symfony/form/Console/Descriptor/JsonDescriptor.php
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
222
vendor/symfony/form/Console/Descriptor/TextDescriptor.php
vendored
Normal file
222
vendor/symfony/form/Console/Descriptor/TextDescriptor.php
vendored
Normal file
@ -0,0 +1,222 @@
|
||||
<?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());
|
||||
}
|
||||
}
|
33
vendor/symfony/form/Console/Helper/DescriptorHelper.php
vendored
Normal file
33
vendor/symfony/form/Console/Helper/DescriptorHelper.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?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())
|
||||
;
|
||||
}
|
||||
}
|
65
vendor/symfony/form/DataAccessorInterface.php
vendored
Normal file
65
vendor/symfony/form/DataAccessorInterface.php
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
<?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;
|
||||
}
|
62
vendor/symfony/form/DataMapperInterface.php
vendored
Normal file
62
vendor/symfony/form/DataMapperInterface.php
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
<?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);
|
||||
}
|
92
vendor/symfony/form/DataTransformerInterface.php
vendored
Normal file
92
vendor/symfony/form/DataTransformerInterface.php
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
<?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);
|
||||
}
|
146
vendor/symfony/form/DependencyInjection/FormPass.php
vendored
Normal file
146
vendor/symfony/form/DependencyInjection/FormPass.php
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
23
vendor/symfony/form/Event/PostSetDataEvent.php
vendored
Normal file
23
vendor/symfony/form/Event/PostSetDataEvent.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?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
|
||||
{
|
||||
}
|
24
vendor/symfony/form/Event/PostSubmitEvent.php
vendored
Normal file
24
vendor/symfony/form/Event/PostSubmitEvent.php
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
<?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
|
||||
{
|
||||
}
|
25
vendor/symfony/form/Event/PreSetDataEvent.php
vendored
Normal file
25
vendor/symfony/form/Event/PreSetDataEvent.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?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
|
||||
{
|
||||
}
|
25
vendor/symfony/form/Event/PreSubmitEvent.php
vendored
Normal file
25
vendor/symfony/form/Event/PreSubmitEvent.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?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
|
||||
{
|
||||
}
|
24
vendor/symfony/form/Event/SubmitEvent.php
vendored
Normal file
24
vendor/symfony/form/Event/SubmitEvent.php
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
<?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
|
||||
{
|
||||
}
|
16
vendor/symfony/form/Exception/AccessException.php
vendored
Normal file
16
vendor/symfony/form/Exception/AccessException.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?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
|
||||
{
|
||||
}
|
22
vendor/symfony/form/Exception/AlreadySubmittedException.php
vendored
Normal file
22
vendor/symfony/form/Exception/AlreadySubmittedException.php
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<?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
|
||||
{
|
||||
}
|
21
vendor/symfony/form/Exception/BadMethodCallException.php
vendored
Normal file
21
vendor/symfony/form/Exception/BadMethodCallException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?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
|
||||
{
|
||||
}
|
16
vendor/symfony/form/Exception/ErrorMappingException.php
vendored
Normal file
16
vendor/symfony/form/Exception/ErrorMappingException.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?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
|
||||
{
|
||||
}
|
21
vendor/symfony/form/Exception/ExceptionInterface.php
vendored
Normal file
21
vendor/symfony/form/Exception/ExceptionInterface.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?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
|
||||
{
|
||||
}
|
21
vendor/symfony/form/Exception/InvalidArgumentException.php
vendored
Normal file
21
vendor/symfony/form/Exception/InvalidArgumentException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?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
|
||||
{
|
||||
}
|
16
vendor/symfony/form/Exception/InvalidConfigurationException.php
vendored
Normal file
16
vendor/symfony/form/Exception/InvalidConfigurationException.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?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
|
||||
{
|
||||
}
|
21
vendor/symfony/form/Exception/LogicException.php
vendored
Normal file
21
vendor/symfony/form/Exception/LogicException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?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
|
||||
{
|
||||
}
|
21
vendor/symfony/form/Exception/OutOfBoundsException.php
vendored
Normal file
21
vendor/symfony/form/Exception/OutOfBoundsException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?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
|
||||
{
|
||||
}
|
21
vendor/symfony/form/Exception/RuntimeException.php
vendored
Normal file
21
vendor/symfony/form/Exception/RuntimeException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?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
|
||||
{
|
||||
}
|
16
vendor/symfony/form/Exception/StringCastException.php
vendored
Normal file
16
vendor/symfony/form/Exception/StringCastException.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?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
|
||||
{
|
||||
}
|
52
vendor/symfony/form/Exception/TransformationFailedException.php
vendored
Normal file
52
vendor/symfony/form/Exception/TransformationFailedException.php
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
20
vendor/symfony/form/Exception/UnexpectedTypeException.php
vendored
Normal file
20
vendor/symfony/form/Exception/UnexpectedTypeException.php
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<?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)));
|
||||
}
|
||||
}
|
89
vendor/symfony/form/Extension/Core/CoreExtension.php
vendored
Normal file
89
vendor/symfony/form/Extension/Core/CoreExtension.php
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
<?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),
|
||||
];
|
||||
}
|
||||
}
|
64
vendor/symfony/form/Extension/Core/DataAccessor/CallbackAccessor.php
vendored
Normal file
64
vendor/symfony/form/Extension/Core/DataAccessor/CallbackAccessor.php
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
90
vendor/symfony/form/Extension/Core/DataAccessor/ChainAccessor.php
vendored
Normal file
90
vendor/symfony/form/Extension/Core/DataAccessor/ChainAccessor.php
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
103
vendor/symfony/form/Extension/Core/DataAccessor/PropertyPathAccessor.php
vendored
Normal file
103
vendor/symfony/form/Extension/Core/DataAccessor/PropertyPathAccessor.php
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
<?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\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 (!$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;
|
||||
}
|
||||
}
|
||||
}
|
75
vendor/symfony/form/Extension/Core/DataMapper/CheckboxListMapper.php
vendored
Normal file
75
vendor/symfony/form/Extension/Core/DataMapper/CheckboxListMapper.php
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
91
vendor/symfony/form/Extension/Core/DataMapper/DataMapper.php
vendored
Normal file
91
vendor/symfony/form/Extension/Core/DataMapper/DataMapper.php
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
113
vendor/symfony/form/Extension/Core/DataMapper/PropertyPathMapper.php
vendored
Normal file
113
vendor/symfony/form/Extension/Core/DataMapper/PropertyPathMapper.php
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
<?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\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 (!$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;
|
||||
}
|
||||
}
|
||||
}
|
74
vendor/symfony/form/Extension/Core/DataMapper/RadioListMapper.php
vendored
Normal file
74
vendor/symfony/form/Extension/Core/DataMapper/RadioListMapper.php
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
84
vendor/symfony/form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php
vendored
Normal file
84
vendor/symfony/form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
55
vendor/symfony/form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php
vendored
Normal file
55
vendor/symfony/form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
}
|
85
vendor/symfony/form/Extension/Core/DataTransformer/BooleanToStringTransformer.php
vendored
Normal file
85
vendor/symfony/form/Extension/Core/DataTransformer/BooleanToStringTransformer.php
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
53
vendor/symfony/form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php
vendored
Normal file
53
vendor/symfony/form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
73
vendor/symfony/form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php
vendored
Normal file
73
vendor/symfony/form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
90
vendor/symfony/form/Extension/Core/DataTransformer/DataTransformerChain.php
vendored
Normal file
90
vendor/symfony/form/Extension/Core/DataTransformer/DataTransformerChain.php
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
171
vendor/symfony/form/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php
vendored
Normal file
171
vendor/symfony/form/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
101
vendor/symfony/form/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php
vendored
Normal file
101
vendor/symfony/form/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
67
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformer.php
vendored
Normal file
67
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformer.php
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
184
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php
vendored
Normal file
184
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php
vendored
Normal file
@ -0,0 +1,184 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
106
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformer.php
vendored
Normal file
106
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformer.php
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
208
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
vendored
Normal file
208
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
91
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php
vendored
Normal file
91
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
138
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php
vendored
Normal file
138
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
<?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
|
||||
*/
|
||||
public function __construct(string $inputTimezone = null, string $outputTimezone = null, string $format = 'Y-m-d H:i:s')
|
||||
{
|
||||
parent::__construct($inputTimezone, $outputTimezone);
|
||||
|
||||
$this->generateFormat = $this->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();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
80
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeToTimestampTransformer.php
vendored
Normal file
80
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeToTimestampTransformer.php
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
82
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeZoneToStringTransformer.php
vendored
Normal file
82
vendor/symfony/form/Extension/Core/DataTransformer/DateTimeZoneToStringTransformer.php
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
}
|
59
vendor/symfony/form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php
vendored
Normal file
59
vendor/symfony/form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
<?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 $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;
|
||||
}
|
||||
}
|
84
vendor/symfony/form/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php
vendored
Normal file
84
vendor/symfony/form/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
74
vendor/symfony/form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php
vendored
Normal file
74
vendor/symfony/form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
265
vendor/symfony/form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
vendored
Normal file
265
vendor/symfony/form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
vendored
Normal file
@ -0,0 +1,265 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
249
vendor/symfony/form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php
vendored
Normal file
249
vendor/symfony/form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php
vendored
Normal file
@ -0,0 +1,249 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
65
vendor/symfony/form/Extension/Core/DataTransformer/StringToFloatTransformer.php
vendored
Normal file
65
vendor/symfony/form/Extension/Core/DataTransformer/StringToFloatTransformer.php
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
75
vendor/symfony/form/Extension/Core/DataTransformer/UlidToStringTransformer.php
vendored
Normal file
75
vendor/symfony/form/Extension/Core/DataTransformer/UlidToStringTransformer.php
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
75
vendor/symfony/form/Extension/Core/DataTransformer/UuidToStringTransformer.php
vendored
Normal file
75
vendor/symfony/form/Extension/Core/DataTransformer/UuidToStringTransformer.php
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
<?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.');
|
||||
}
|
||||
|
||||
try {
|
||||
$uuid = new Uuid($value);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new TransformationFailedException(sprintf('The value "%s" is not a valid UUID.', $value), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $uuid;
|
||||
}
|
||||
}
|
85
vendor/symfony/form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php
vendored
Normal file
85
vendor/symfony/form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
105
vendor/symfony/form/Extension/Core/DataTransformer/WeekToArrayTransformer.php
vendored
Normal file
105
vendor/symfony/form/Extension/Core/DataTransformer/WeekToArrayTransformer.php
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
<?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']);
|
||||
}
|
||||
}
|
48
vendor/symfony/form/Extension/Core/EventListener/FixUrlProtocolListener.php
vendored
Normal file
48
vendor/symfony/form/Extension/Core/EventListener/FixUrlProtocolListener.php
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<?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'];
|
||||
}
|
||||
}
|
113
vendor/symfony/form/Extension/Core/EventListener/MergeCollectionListener.php
vendored
Normal file
113
vendor/symfony/form/Extension/Core/EventListener/MergeCollectionListener.php
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user