Skip to content
This repository has been archived by the owner on Jan 15, 2024. It is now read-only.

Commit

Permalink
Refs #21
Browse files Browse the repository at this point in the history
  • Loading branch information
kleijnweb committed Sep 14, 2015
1 parent bb9dafd commit 5717428
Show file tree
Hide file tree
Showing 8 changed files with 1,257 additions and 46 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,12 @@ __NOTE__: SwaggerBundle currently does not support `multi` for `collectionFormat

### Content Validation

If the content cannot be deserialized using the format specified by the request's Content-Type header, or if validation
If the content cannot be decoded using the format specified by the request's Content-Type header, or if validation
of the content using the resource schema failed, SwaggerBundle will return a `vnd.error` response with a 400 status code.

### Object (De-) Serialization

By default Swagger bundle will only serialize and deserialize arrays. This means your controllers can expect `$request->getContent()`
By default Swagger bundle will simply encode and decode arrays. This means your controllers can expect `$request->getContent()`
to contain an associative array, and are expected to return those as well.

Optionally SwaggerBundle can do object de- serialization. You will need to pass the Symfony Components Serializer,
Expand All @@ -158,7 +158,7 @@ or JMS\Serializer to the SerializerAdapter, which can be done by configuration:
```yml
swagger:
serializer:
type: symfony # Overriding the default: array
type: symfony
namespace: My\Bundle\Resource\Namespace # Required for 'symfony' and 'jms' serializers
```

Expand Down
1 change: 0 additions & 1 deletion src/Dev/Command/GenerateResourceClassesCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ protected function execute(InputInterface $input, OutputInterface $output)
$kernel = $this->getContainer()->get('kernel');
$bundle = $kernel->getBundle($input->getArgument('bundle'));
$document = $this->documentRepository->get($input->getArgument('file'));
$document->resolveReferences();
$this->generator->setSkeletonDirs(__DIR__ . '/../Resources/skeleton');
$this->generator->generate($bundle, $document, $input->getOption('namespace'));
}
Expand Down
94 changes: 72 additions & 22 deletions src/Document/SwaggerDocument.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,29 +37,12 @@ public function __construct($pathFileName)
"Document file '$pathFileName' does not exist'"
);
}
$this->pathFileName = $pathFileName;
$this->definition = new \ArrayObject(
Yaml::parse(file_get_contents($pathFileName)),
\ArrayObject::ARRAY_AS_PROPS | \ArrayObject::STD_PROP_LIST
);
}

/**
* Resolve all references
*
* @return void
*/
public function resolveReferences()
{
$retriever = new UriRetriever();
$retriever->setUriRetriever(new YamlCapableUriRetriever);
$resolver = new RefResolver($retriever);
foreach ($this->definition->definitions as &$schema) {
// TODO Solve this mess
$schema = json_decode(json_encode($schema));
$resolver->resolve($schema, 'file://' . realpath($this->pathFileName));
$schema = json_decode(json_encode($schema), true);
}
$data = Yaml::parse(file_get_contents($pathFileName));
$data = self::resolveSelfReferences($data, $data);

$this->pathFileName = $pathFileName;
$this->definition = new \ArrayObject($data, \ArrayObject::ARRAY_AS_PROPS | \ArrayObject::STD_PROP_LIST);
}

/**
Expand Down Expand Up @@ -126,6 +109,7 @@ public function getArrayCopy()
public function write($targetPath = null)
{
$data = $this->getArrayCopy();
$data = self::unresolveSelfReferences($data, $data);
$yaml = Yaml::dump($data, 10, 2);
$yaml = str_replace(': { }', ': []', $yaml);
file_put_contents($targetPath ?: $this->pathFileName, $yaml);
Expand All @@ -137,4 +121,70 @@ public function write($targetPath = null)
private function __clone()
{
}

/**
* @param array $segments
* @param array $context
*
* @return mixed
*/
private static function lookupUsingSegments(array $segments, array $context)
{
$segment = array_shift($segments);
if (isset($context[$segment])) {
if (!count($segments)) {
return $context[$segment];
}

return self::lookupUsingSegments($segments, $context[$segment]);
}

return null;
}

/**
* @param array $doc
* @param array $data
*
* @return array
*/
private function resolveSelfReferences(array $doc, array &$data)
{
foreach ($data as $key => &$value) {
if (is_array($value)) {
$value = self::resolveSelfReferences($doc, $value);
}
if ($key === '$ref' && '#' === $value[0]) {
$data = self::lookupUsingSegments(
explode('/', trim(substr($value, 1), '/')),
$doc
);
$data['id'] = $value;
// Use something a little less generic for more reliable qnd restoring of original
$data['x-swagger-id'] = $value;
}
}

return $data;
}

/**
* @param array $doc
* @param array $data
*
* @return array
*/
private function unresolveSelfReferences(array $doc, array &$data)
{
foreach ($data as $key => &$value) {
if (is_array($value)) {
$value = self::unresolveSelfReferences($doc, $value);
}
if ($key === 'x-swagger-id') {
$data = ['$ref' => $value];
}
}

return $data;
}
}
51 changes: 34 additions & 17 deletions src/Request/RequestTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,7 @@ public function coerceRequest(Request $request, array $operationDefinition)
// This modifies the Request object (and adds the content to the 'attributes' ParameterBag
$this->coerceRequestParameters($request, $operationDefinition, $content);

// This retrieves the modified parameters
$parameters = $this->assembleParameterData($request, $operationDefinition);

// Validate the parameters using a schema created from the operation definition
$validator = new Validator();
$schema = $this->assembleRequestSchema($operationDefinition);
$validator->check($parameters, $schema);

if (!$validator->isValid()) {
// TODO Better utilize $validator->getErrors() so we can assemble a more helpful vnd.error response
throw new InvalidParametersException(
"Parameters incompatible with operation schema: " . implode(', ', $validator->getErrors()[0]),
400
);
}
$this->validateRequest($request, $operationDefinition);

// Needed to be able to set the decoded body
$request->initialize(
Expand Down Expand Up @@ -161,13 +147,43 @@ public function coerceRequestParameters(Request $request, array $operationDefini
}

/**
* TODO Move to new RequestValidator
*
* @param Request $request
* @param array $operationDefinition
*
* @throws InvalidParametersException
* @throws UnsupportedException
*/
private function validateRequest(Request $request, array $operationDefinition)
{
// This retrieves the modified parameters
$parameters = $this->assembleParameterDataForValidation($request, $operationDefinition);

// Validate the parameters using a schema created from the operation definition
$validator = new Validator();
$schema = $this->assembleRequestSchema($operationDefinition);
$validator->check($parameters, $schema);

if (!$validator->isValid()) {
// TODO Better utilize $validator->getErrors() so we can assemble a more helpful vnd.error response
throw new InvalidParametersException(
"Parameters incompatible with operation schema: " . implode(', ', $validator->getErrors()[0]),
400
);
}
}

/**
* TODO Move to new RequestValidator
*
* @param Request $request
* @param array $operationDefinition
*
* @return \stdClass
* @throws UnsupportedException
*/
public function assembleParameterData(Request $request, array $operationDefinition)
private function assembleParameterDataForValidation(Request $request, array $operationDefinition)
{
if (!isset($operationDefinition['parameters'])) {
return new \stdClass;
Expand Down Expand Up @@ -195,6 +211,7 @@ public function assembleParameterData(Request $request, array $operationDefiniti
$parameters[$paramName] = $request->$paramBagName->get($paramName);
}

return (object)$parameters;
// TODO Hack, probably not the best performing of solutions
return (object)json_decode(json_encode($parameters));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ protected function setUp()
{
$bundle = new PetStoreBundle();
$document = SwaggerDocumentTest::getPetStoreDocument();
$document->resolveReferences();
$generator = new ResourceGenerator();
$generator->setSkeletonDirs('src/Dev/Resources/skeleton');
$generator->generate($bundle, $document, 'Model\Jms');
Expand Down
1 change: 0 additions & 1 deletion src/Tests/Dev/Generator/ResourceGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public function canRenderResourcesFromPetStore()
{
$bundle = new PetStoreBundle();
$document = SwaggerDocumentTest::getPetStoreDocument();
$document->resolveReferences();
$generator = new ResourceGenerator();
$generator->setSkeletonDirs('src/Dev/Resources/skeleton');
$generator->generate($bundle, $document, 'Foo\Bar');
Expand Down
14 changes: 13 additions & 1 deletion src/Tests/Document/SwaggerDocumentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,14 +169,26 @@ public function canModifiedYamlWrittenToFileSystemHandlesEmptyArraysCorrectly()
public function canResolveResourceSchemaReferences()
{
$document = self::getPetStoreDocument();
$document->resolveReferences();
$schemas = $document->getResourceSchemas();
$propertySchema = $schemas['Pet']['properties']['category'];
$this->assertArrayNotHasKey('$ref', $propertySchema);
$this->assertArrayHasKey('id', $propertySchema);
$this->assertSame('object', $propertySchema['type']);
}

/**
* @test
*/
public function canResolveParameterSchemaReferences()
{
$document = new SwaggerDocument('src/Tests/Functional/PetStore/app/instagram.yml');
$pathDefinitions = $document->getPathDefinitions();
$argumentPseudoSchema = $pathDefinitions['/users/{user-id}']['parameters'][0];
$this->assertArrayNotHasKey('$ref', $argumentPseudoSchema);
$this->assertArrayHasKey('in', $argumentPseudoSchema);
$this->assertSame('user-id', $argumentPseudoSchema['name']);
}

/**
* @return SwaggerDocument
*/
Expand Down
Loading

0 comments on commit 5717428

Please sign in to comment.