Last active
February 17, 2020 15:07
-
-
Save walva/0cb89b7f7f8cda59313c757a6573ee6d to your computer and use it in GitHub Desktop.
Use NelmioAPiDocBundle with JmsSerializerBundle : handling snakecase and groups in the same time
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
services: | |
myapp.api_doc.parser.validation_parser: | |
class: SulivanDotEu\ApiBundle\Parser\SnakeCaseValidationParser | |
arguments: | |
- "@validator.mapping.class_metadata_factory" | |
tags: | |
- { name: nelmio_api_doc.extractor.parser } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @ApiDoc( | |
* resource=true, | |
* views = { "default", "partner" }, | |
* description="Ask for an offer", | |
* input= { | |
* "class"="Company\ThirdPartyAPIBundle\Action\GetOfferAction", | |
* "groups"={"offer", "Default"}, | |
* "parsers" = { | |
* "SulivanDotEu\ApiBundle\Parser\SnakeCaseValidationParser", | |
* "Nelmio\ApiDocBundle\Parser\JmsMetadataParser" | |
* } | |
* }, | |
* output= { | |
* "class"="Company\ThirdPartyAPIBundle\Action\GetOfferAction", | |
* "groups"={"offer", "Default", "read"}, | |
* "parsers" = { | |
* "Nelmio\ApiDocBundle\Parser\JmsMetadataParser", | |
* "SulivanDotEu\ApiBundle\Parser\SnakeCaseValidationParser" | |
* } | |
* }) | |
**/ | |
public function postOfferAction( Request $request ) { | |
// ... | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace SulivanDotEu\ApiBundle\Parser; | |
use Nelmio\ApiDocBundle\DataTypes; | |
use Nelmio\ApiDocBundle\Parser\ValidationParser; | |
use Symfony\Component\Validator\Mapping\PropertyMetadata; | |
class SnakeCaseGroupsValidationParser extends ValidationParser | |
{ | |
/** | |
* {@inheritdoc} | |
*/ | |
public function parse( array $input ) | |
{ | |
$className = $input[ 'class' ]; | |
$groups = isset($input[ 'groups' ])?$input[ 'groups' ]:["Default"]; | |
$parsed = $this->doParse( $className, [], $groups ); | |
if ( isset( $input[ 'name' ] ) && ! empty( $input[ 'name' ] ) ) | |
{ | |
$output = []; | |
$output[ $input[ 'name' ] ] = [ | |
'dataType' => 'object', | |
'actualType' => 'object', | |
'class' => $className, | |
'subType' => NULL, | |
'required' => NULL, | |
'description' => NULL, | |
'readonly' => NULL, | |
'children' => $parsed, | |
]; | |
return $output; | |
} | |
return $parsed; | |
} | |
/** | |
* Recursively parse constraints. | |
* | |
* @param $className | |
* @param array $visited | |
* | |
* @return array | |
*/ | |
protected function doParse( $className, array $visited, $groups = [] ) | |
{ | |
$params = []; | |
$classdata = $this->factory->getMetadataFor( $className ); | |
$properties = $classdata->getConstrainedProperties(); | |
$refl = $classdata->getReflectionClass(); | |
$defaults = $refl->getDefaultProperties(); | |
foreach ( $properties as $property ) | |
{ | |
$vparams = []; | |
$vparams[ 'default' ] = isset( $defaults[ $property ] ) ? $defaults[ $property ] : NULL; | |
$pds = $classdata->getPropertyMetadata( $property ); | |
foreach ( $pds as $propdata ) | |
{ | |
// apply exclusion strategies | |
if ( TRUE === $this->shouldSkipProperty( $propdata, $groups ) ) | |
{ | |
dump("CONTINUE"); | |
continue 2; | |
} | |
$constraints = $propdata->getConstraints(); | |
foreach ( $constraints as $constraint ) | |
{ | |
$vparams = $this->parseConstraint( $constraint, $vparams, $className, $visited ); | |
} | |
} | |
if ( isset( $vparams[ 'format' ] ) ) | |
{ | |
$vparams[ 'format' ] = join( ', ', $vparams[ 'format' ] ); | |
} | |
foreach ( [ 'dataType', 'readonly', 'required', 'subType' ] as $reqprop ) | |
{ | |
if ( ! isset( $vparams[ $reqprop ] ) ) | |
{ | |
$vparams[ $reqprop ] = NULL; | |
} | |
} | |
// 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 ); | |
} | |
$vparams[ 'actualType' ] = isset( $vparams[ 'actualType' ] ) ? $vparams[ 'actualType' ] : DataTypes::STRING; | |
$property = ltrim( strtolower( preg_replace( '/[A-Z]/', '_$0', $property ) ) ); | |
$params[ $property ] = $vparams; | |
} | |
return $params; | |
} | |
protected function shouldSkipProperty( PropertyMetadata $propdata, $groups = array() ) | |
{ | |
return count(array_intersect($groups, array_keys($propdata->constraintsByGroup))) == 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment