Skip to content

Commit

Permalink
Updated symfony/validator
Browse files Browse the repository at this point in the history
  • Loading branch information
condor2 committed Dec 21, 2024
1 parent 500a6b7 commit 9efa250
Show file tree
Hide file tree
Showing 219 changed files with 9,218 additions and 2,683 deletions.
77 changes: 77 additions & 0 deletions upload/system/storage/vendor/symfony/validator/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,83 @@
CHANGELOG
=========

5.4
---

* Add a `Cidr` constraint to validate CIDR notations
* Add a `CssColor` constraint to validate CSS colors
* Add support for `ConstraintViolationList::createFromMessage()`
* Add error's uid to `Count` and `Length` constraints with "exactly" option enabled

5.3
---

* Add the `normalizer` option to the `Unique` constraint
* Add `Validation::createIsValidCallable()` that returns true/false instead of throwing exceptions

5.2.0
-----

* added a `Cascade` constraint to ease validating nested typed object properties
* deprecated the `allowEmptyString` option of the `Length` constraint

Before:

```php
use Symfony\Component\Validator\Constraints as Assert;

/**
* @Assert\Length(min=5, allowEmptyString=true)
*/
```

After:

```php
use Symfony\Component\Validator\Constraints as Assert;

/**
* @Assert\AtLeastOneOf({
* @Assert\Blank(),
* @Assert\Length(min=5)
* })
*/
```
* added the `Isin` constraint and validator
* added the `ULID` constraint and validator
* added support for UUIDv6 in `Uuid` constraint
* enabled the validator to load constraints from PHP attributes
* deprecated the `NumberConstraintTrait` trait
* deprecated setting or creating a Doctrine annotation reader via `ValidatorBuilder::enableAnnotationMapping()`, pass `true` as first parameter and additionally call `setDoctrineAnnotationReader()` or `addDefaultDoctrineAnnotationReader()` to set up the annotation reader

5.1.0
-----

* Add `AtLeastOneOf` constraint that is considered to be valid if at least one of the nested constraints is valid
* added the `Hostname` constraint and validator
* added the `alpha3` option to the `Country` and `Language` constraints
* allow to define a reusable set of constraints by extending the `Compound` constraint
* added `Sequentially` constraint, to sequentially validate a set of constraints (any violation raised will prevent further validation of the nested constraints)
* added the `divisibleBy` option to the `Count` constraint
* added the `ExpressionLanguageSyntax` constraint

5.0.0
-----

* an `ExpressionLanguage` instance or null must be passed as the first argument of `ExpressionValidator::__construct()`
* removed the `checkDNS` and `dnsMessage` options of the `Url` constraint
* removed the `checkMX`, `checkHost` and `strict` options of the `Email` constraint
* removed support for validating instances of `\DateTimeInterface` in `DateTimeValidator`, `DateValidator` and `TimeValidator`
* removed support for using the `Bic`, `Country`, `Currency`, `Language` and `Locale` constraints without `symfony/intl`
* removed support for using the `Email` constraint without `egulias/email-validator`
* removed support for using the `Expression` constraint without `symfony/expression-language`
* changed default value of `canonicalize` option of `Locale` constraint to `true`
* removed `ValidatorBuilderInterface`
* passing a null message when instantiating a `ConstraintViolation` is not allowed
* changed the default value of `Length::$allowEmptyString` to `false` and made it optional
* removed `Symfony\Component\Validator\Mapping\Cache\CacheInterface` in favor of PSR-6.
* removed `ValidatorBuilder::setMetadataCache`, use `ValidatorBuilder::setMappingCache` instead.

4.4.0
-----

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Validator\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Dumper;
use Symfony\Component\Console\Helper\Table;
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\Finder\Exception\DirectoryNotFoundException;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Mapping\AutoMappingStrategy;
use Symfony\Component\Validator\Mapping\CascadingStrategy;
use Symfony\Component\Validator\Mapping\ClassMetadataInterface;
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
use Symfony\Component\Validator\Mapping\GenericMetadata;
use Symfony\Component\Validator\Mapping\TraversalStrategy;

/**
* A console command to debug Validators information.
*
* @author Loïc Frémont <[email protected]>
*/
class DebugCommand extends Command
{
protected static $defaultName = 'debug:validator';
protected static $defaultDescription = 'Display validation constraints for classes';

private $validator;

public function __construct(MetadataFactoryInterface $validator)
{
parent::__construct();

$this->validator = $validator;
}

protected function configure()
{
$this
->addArgument('class', InputArgument::REQUIRED, 'A fully qualified class name or a path')
->addOption('show-all', null, InputOption::VALUE_NONE, 'Show all classes even if they have no validation constraints')
->setDescription(self::$defaultDescription)
->setHelp(<<<'EOF'
The <info>%command.name% 'App\Entity\Dummy'</info> command dumps the validators for the dummy class.
The <info>%command.name% src/</info> command dumps the validators for the `src` directory.
EOF
)
;
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$class = $input->getArgument('class');

if (class_exists($class)) {
$this->dumpValidatorsForClass($input, $output, $class);

return 0;
}

try {
foreach ($this->getResourcesByPath($class) as $class) {
$this->dumpValidatorsForClass($input, $output, $class);
}
} catch (DirectoryNotFoundException $exception) {
$io = new SymfonyStyle($input, $output);
$io->error(sprintf('Neither class nor path were found with "%s" argument.', $input->getArgument('class')));

return 1;
}

return 0;
}

private function dumpValidatorsForClass(InputInterface $input, OutputInterface $output, string $class): void
{
$io = new SymfonyStyle($input, $output);
$title = sprintf('<info>%s</info>', $class);
$rows = [];
$dump = new Dumper($output);

/** @var ClassMetadataInterface $classMetadata */
$classMetadata = $this->validator->getMetadataFor($class);

foreach ($this->getClassConstraintsData($classMetadata) as $data) {
$rows[] = [
'-',
$data['class'],
implode(', ', $data['groups']),
$dump($data['options']),
];
}

foreach ($this->getConstrainedPropertiesData($classMetadata) as $propertyName => $constraintsData) {
foreach ($constraintsData as $data) {
$rows[] = [
$propertyName,
$data['class'],
implode(', ', $data['groups']),
$dump($data['options']),
];
}
}

if (!$rows) {
if (false === $input->getOption('show-all')) {
return;
}

$io->section($title);
$io->text('No validators were found for this class.');

return;
}

$io->section($title);

$table = new Table($output);
$table->setHeaders(['Property', 'Name', 'Groups', 'Options']);
$table->setRows($rows);
$table->setColumnMaxWidth(3, 80);
$table->render();
}

private function getClassConstraintsData(ClassMetadataInterface $classMetadata): iterable
{
foreach ($classMetadata->getConstraints() as $constraint) {
yield [
'class' => \get_class($constraint),
'groups' => $constraint->groups,
'options' => $this->getConstraintOptions($constraint),
];
}
}

private function getConstrainedPropertiesData(ClassMetadataInterface $classMetadata): array
{
$data = [];

foreach ($classMetadata->getConstrainedProperties() as $constrainedProperty) {
$data[$constrainedProperty] = $this->getPropertyData($classMetadata, $constrainedProperty);
}

return $data;
}

private function getPropertyData(ClassMetadataInterface $classMetadata, string $constrainedProperty): array
{
$data = [];

$propertyMetadata = $classMetadata->getPropertyMetadata($constrainedProperty);
foreach ($propertyMetadata as $metadata) {
$autoMapingStrategy = 'Not supported';
if ($metadata instanceof GenericMetadata) {
switch ($metadata->getAutoMappingStrategy()) {
case AutoMappingStrategy::ENABLED: $autoMapingStrategy = 'Enabled'; break;
case AutoMappingStrategy::DISABLED: $autoMapingStrategy = 'Disabled'; break;
case AutoMappingStrategy::NONE: $autoMapingStrategy = 'None'; break;
}
}
$traversalStrategy = 'None';
if (TraversalStrategy::TRAVERSE === $metadata->getTraversalStrategy()) {
$traversalStrategy = 'Traverse';
}
if (TraversalStrategy::IMPLICIT === $metadata->getTraversalStrategy()) {
$traversalStrategy = 'Implicit';
}

$data[] = [
'class' => 'property options',
'groups' => [],
'options' => [
'cascadeStrategy' => CascadingStrategy::CASCADE === $metadata->getCascadingStrategy() ? 'Cascade' : 'None',
'autoMappingStrategy' => $autoMapingStrategy,
'traversalStrategy' => $traversalStrategy,
],
];
foreach ($metadata->getConstraints() as $constraint) {
$data[] = [
'class' => \get_class($constraint),
'groups' => $constraint->groups,
'options' => $this->getConstraintOptions($constraint),
];
}
}

return $data;
}

private function getConstraintOptions(Constraint $constraint): array
{
$options = [];

foreach (array_keys(get_object_vars($constraint)) as $propertyName) {
// Groups are dumped on a specific column.
if ('groups' === $propertyName) {
continue;
}

$options[$propertyName] = $constraint->$propertyName;
}

ksort($options);

return $options;
}

private function getResourcesByPath(string $path): array
{
$finder = new Finder();
$finder->files()->in($path)->name('*.php')->sortByName(true);
$classes = [];

foreach ($finder as $file) {
$fileContent = file_get_contents($file->getRealPath());

preg_match('/namespace (.+);/', $fileContent, $matches);

$namespace = $matches[1] ?? null;

if (!preg_match('/class +([^{ ]+)/', $fileContent, $matches)) {
// no class found
continue;
}

$className = trim($matches[1]);

if (null !== $namespace) {
$classes[] = $namespace.'\\'.$className;
} else {
$classes[] = $className;
}
}

return $classes;
}
}
Loading

0 comments on commit 9efa250

Please sign in to comment.