From 1112cca7841dc27aec83cb515024c0f01f4613b0 Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Thu, 7 Nov 2013 14:11:09 +0100 Subject: [PATCH] Add support of `All` constraint --- Parser/ValidationParser.php | 47 +++++++++++++++++++++-- Tests/Fixtures/Model/MultipleTest.php | 7 ++++ Tests/Fixtures/Model/Test.php | 1 + Tests/Formatter/MarkdownFormatterTest.php | 12 ++++++ Tests/Formatter/SimpleFormatterTest.php | 18 +++++++++ 5 files changed, 82 insertions(+), 3 deletions(-) diff --git a/Parser/ValidationParser.php b/Parser/ValidationParser.php index e7df881..646b4f5 100644 --- a/Parser/ValidationParser.php +++ b/Parser/ValidationParser.php @@ -14,6 +14,7 @@ namespace Nelmio\ApiDocBundle\Parser; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; use Symfony\Component\Validator\MetadataFactoryInterface; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Constraints\Type; /** * Uses the Symfony Validation component to extract information about API objects. @@ -50,9 +51,20 @@ class ValidationParser implements ParserInterface, PostParserInterface */ public function parse(array $input) { - $params = array(); $className = $input['class']; + return $this->doParse($className, array()); + } + /** + * Recursively parse constraints. + * + * @param $className + * @param array $visited + * @return array + */ + protected function doParse ($className, array $visited) + { + $params = array(); $classdata = $this->factory->getMetadataFor($className); $properties = $classdata->getConstrainedProperties(); @@ -63,7 +75,7 @@ class ValidationParser implements ParserInterface, PostParserInterface $constraints = $propdata->getConstraints(); foreach ($constraints as $constraint) { - $vparams = $this->parseConstraint($constraint, $vparams, $className); + $vparams = $this->parseConstraint($constraint, $vparams, $className, $visited); } } @@ -77,6 +89,12 @@ class ValidationParser implements ParserInterface, PostParserInterface } } + // check for nested classes with All constraint + if (isset($vparams['class']) && !in_array($vparams['class'], $visited) && null !== $this->factory->getMetadataFor($vparams['class'])) { + $visited[] = $vparams['class']; + $vparams['children'] = $this->doParse($vparams['class'], $visited); + } + $params[$property] = $vparams; } @@ -119,7 +137,7 @@ class ValidationParser implements ParserInterface, PostParserInterface * @param array $vparams The existing validation parameters. * @return mixed The parsed list of validation parameters. */ - protected function parseConstraint(Constraint $constraint, $vparams, $className) + protected function parseConstraint(Constraint $constraint, $vparams, $className, &$visited = array()) { $class = substr(get_class($constraint), strlen('Symfony\\Component\\Validator\\Constraints\\')); @@ -183,6 +201,29 @@ class ValidationParser implements ParserInterface, PostParserInterface $vparams['format'][] = '{not match: ' . $constraint->pattern . '}'; } break; + case 'All': + foreach ($constraint->constraints as $childConstraint) { + if ($childConstraint instanceof Type) { + $nestedType = $childConstraint->type; + $exp = explode("\\", $nestedType); + if (!class_exists($nestedType)) { + $nestedType = substr($className, 0, strrpos($className, '\\') + 1).$nestedType; + + if (!class_exists($nestedType)) { + continue; + } + } + + $vparams['dataType'] = sprintf("array of objects (%s)", end($exp)); + $vparams['class'] = $nestedType; + + if (!in_array($nestedType, $visited)) { + $visited[] = $nestedType; + $vparams['children'] = $this->doParse($nestedType, $visited); + } + } + } + break; } return $vparams; diff --git a/Tests/Fixtures/Model/MultipleTest.php b/Tests/Fixtures/Model/MultipleTest.php index a0077fe..4942cf1 100644 --- a/Tests/Fixtures/Model/MultipleTest.php +++ b/Tests/Fixtures/Model/MultipleTest.php @@ -20,4 +20,11 @@ class MultipleTest */ public $baz; + /** + * @Assert\Type(type="array") + * @Assert\All({ + * @Assert\Type(type="Test") + * }) + */ + public $objects; } diff --git a/Tests/Fixtures/Model/Test.php b/Tests/Fixtures/Model/Test.php index 8037d3a..51febf7 100644 --- a/Tests/Fixtures/Model/Test.php +++ b/Tests/Fixtures/Model/Test.php @@ -18,6 +18,7 @@ class Test /** * @Assert\Length(min="foo"); * @Assert\NotBlank + * @Assert\Type("string") */ public $a; diff --git a/Tests/Formatter/MarkdownFormatterTest.php b/Tests/Formatter/MarkdownFormatterTest.php index 233cf2d..af6b3f6 100644 --- a/Tests/Formatter/MarkdownFormatterTest.php +++ b/Tests/Formatter/MarkdownFormatterTest.php @@ -479,6 +479,18 @@ bar: * type: DateTime +objects[]: + + * type: array of objects (Test) + +objects[][a]: + + * type: string + +objects[][b]: + + * type: DateTime + number: * type: DateTime diff --git a/Tests/Formatter/SimpleFormatterTest.php b/Tests/Formatter/SimpleFormatterTest.php index 3bc8a47..0ef745c 100644 --- a/Tests/Formatter/SimpleFormatterTest.php +++ b/Tests/Formatter/SimpleFormatterTest.php @@ -840,6 +840,24 @@ With multiple lines.', 'readonly' => false, 'sinceVersion' => null, 'untilVersion' => null + ), + 'objects' => array( + 'dataType' => 'array of objects (Test)', + 'readonly' => null, + 'required' => null, + 'children' => array( + 'a' => array( + 'dataType' => 'string', + 'format' => '{length: min: foo}, {not blank}', + 'required' => true, + 'readonly' => null + ), + 'b' => array( + 'dataType' => 'DateTime', + 'required' => null, + 'readonly' => null + ) + ) ) ), 'authenticationRoles' => array(),