mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-02 15:51:48 +03:00
Enhanced DunglasApiBundle support
This commit is contained in:
parent
ad70ff96fa
commit
79c1c4e4f4
@ -22,7 +22,7 @@ matrix:
|
||||
|
||||
before_script:
|
||||
- composer self-update
|
||||
- sh -c 'if [ "$SYMFONY_VERSION" != "dev-master" ] && [ "$SYMFONY_VERSION" != "2.6.*" ]; then sed -i "/dunglas\/json-ld-api-bundle/d;/symfony\/serializer/d" composer.json; fi;'
|
||||
- sh -c 'if [ "$SYMFONY_VERSION" != "dev-master" ] && [ "$SYMFONY_VERSION" != "2.6.*" ]; then sed -i "/dunglas\/api-bundle/d;/symfony\/serializer/d" composer.json; fi;'
|
||||
- sh -c 'if [ "$SYMFONY_VERSION" != "" ]; then composer require --no-update symfony/symfony=$SYMFONY_VERSION; fi;'
|
||||
- composer install
|
||||
|
||||
|
@ -34,8 +34,8 @@ class LoadExtractorParsersPass implements CompilerPassInterface
|
||||
}
|
||||
|
||||
// DunglasJsonLdApiBundle may or may not be installed, if it is, load that config as well
|
||||
if ($container->hasDefinition('dunglas_json_ld_api.resource_collection')) {
|
||||
$loader->load('services.dunglas_json_ld_api.xml');
|
||||
if ($container->hasDefinition('api.resource_collection')) {
|
||||
$loader->load('services.dunglas_api.xml');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
193
Extractor/AnnotationsProvider/DunglasApiProvider.php
Normal file
193
Extractor/AnnotationsProvider/DunglasApiProvider.php
Normal file
@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Extractor\AnnotationsProvider;
|
||||
|
||||
use Dunglas\ApiBundle\Api\Operation\OperationInterface;
|
||||
use Dunglas\ApiBundle\Api\ResourceCollectionInterface;
|
||||
use Dunglas\ApiBundle\Api\ResourceInterface;
|
||||
use Dunglas\ApiBundle\Hydra\ApiDocumentationBuilderInterface;
|
||||
use Dunglas\ApiBundle\Mapping\ClassMetadataFactoryInterface;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Nelmio\ApiDocBundle\Extractor\AnnotationsProviderInterface;
|
||||
use Nelmio\ApiDocBundle\Parser\DunglasApiParser;
|
||||
|
||||
/**
|
||||
* Creates ApiDoc annotations for DunglasApiBundle.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class DunglasApiProvider implements AnnotationsProviderInterface
|
||||
{
|
||||
/**
|
||||
* @var ResourceCollectionInterface
|
||||
*/
|
||||
private $resourceCollection;
|
||||
/**
|
||||
* @var ApiDocumentationBuilderInterface
|
||||
*/
|
||||
private $apiDocumentationBuilder;
|
||||
/**
|
||||
* @var ClassMetadataFactoryInterface
|
||||
*/
|
||||
private $classMetadataFactory;
|
||||
|
||||
public function __construct(
|
||||
ResourceCollectionInterface $resourceCollection,
|
||||
ApiDocumentationBuilderInterface $apiDocumentationBuilder,
|
||||
ClassMetadataFactoryInterface $classMetadataFactory
|
||||
) {
|
||||
$this->resourceCollection = $resourceCollection;
|
||||
$this->apiDocumentationBuilder = $apiDocumentationBuilder;
|
||||
$this->classMetadataFactory = $classMetadataFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAnnotations()
|
||||
{
|
||||
$annotations = [];
|
||||
$hydraDoc = $this->apiDocumentationBuilder->getApiDocumentation();
|
||||
$entrypointHydraDoc = $this->getResourceHydraDoc($hydraDoc, '#Entrypoint');
|
||||
|
||||
/**
|
||||
* @var ResourceInterface
|
||||
*/
|
||||
foreach ($this->resourceCollection as $resource) {
|
||||
$classMetadata = $this->classMetadataFactory->getMetadataFor($resource->getEntityClass());
|
||||
$prefixedShortName = ($iri = $classMetadata->getIri()) ? $iri : '#'.$resource->getShortName();
|
||||
$resourceHydraDoc = $this->getResourceHydraDoc($hydraDoc, $prefixedShortName);
|
||||
|
||||
if ($hydraDoc) {
|
||||
foreach ($resource->getCollectionOperations() as $operation) {
|
||||
$annotations[] = $this->getApiDoc(true, $resource, $operation, $resourceHydraDoc, $entrypointHydraDoc);
|
||||
}
|
||||
|
||||
foreach ($resource->getItemOperations() as $operation) {
|
||||
$annotations[] = $this->getApiDoc(false, $resource, $operation, $resourceHydraDoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $annotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds ApiDoc annotation from DunglasApiBundle data.
|
||||
*
|
||||
* @param bool $collection
|
||||
* @param ResourceInterface $resource
|
||||
* @param OperationInterface $operation
|
||||
* @param array $resourceHydraDoc
|
||||
* @param array $entrypointHydraDoc
|
||||
*
|
||||
* @return ApiDoc
|
||||
*/
|
||||
private function getApiDoc(
|
||||
$collection,
|
||||
ResourceInterface $resource,
|
||||
OperationInterface $operation,
|
||||
array $resourceHydraDoc,
|
||||
array $entrypointHydraDoc = []
|
||||
) {
|
||||
$method = $operation->getRoute()->getMethods()[0];
|
||||
|
||||
if ($collection) {
|
||||
$operationHydraDoc = $this->getCollectionOperationHydraDoc($resource->getShortName(), $method, $entrypointHydraDoc);
|
||||
} else {
|
||||
$operationHydraDoc = $this->getOperationHydraDoc($operation->getRoute()->getMethods()[0], $resourceHydraDoc);
|
||||
}
|
||||
|
||||
$route = $operation->getRoute();
|
||||
|
||||
$data = [
|
||||
'resource' => $route->getPath(),
|
||||
'description' => $operationHydraDoc['hydra:title'],
|
||||
'resourceDescription' => $resourceHydraDoc['hydra:title'],
|
||||
];
|
||||
|
||||
$entityClass = $resource->getEntityClass();
|
||||
|
||||
if (isset($operationHydraDoc['expects']) && 'owl:Nothing' !== $operationHydraDoc['expects']) {
|
||||
$data['input'] = sprintf('%s:%s', DunglasApiParser::IN_PREFIX, $entityClass);
|
||||
}
|
||||
|
||||
if (isset($operationHydraDoc['returns']) && 'owl:Nothing' !== $operationHydraDoc['returns']) {
|
||||
$data['output'] = sprintf('%s:%s', DunglasApiParser::OUT_PREFIX, $entityClass);
|
||||
}
|
||||
|
||||
$data['filters'] = [];
|
||||
foreach ($resource->getFilters() as $filter) {
|
||||
$data['filters'][] = ['name' => $filter->getName()];
|
||||
}
|
||||
|
||||
$apiDoc = new ApiDoc($data);
|
||||
$apiDoc->setRoute($route);
|
||||
|
||||
return $apiDoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets Hydra documentation for the given resource.
|
||||
*
|
||||
* @param array $hydraApiDoc
|
||||
* @param string $prefixedShortName
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function getResourceHydraDoc(array $hydraApiDoc, $prefixedShortName)
|
||||
{
|
||||
foreach ($hydraApiDoc['hydra:supportedClass'] as $supportedClass) {
|
||||
if ($supportedClass['@id'] === $prefixedShortName) {
|
||||
return $supportedClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Hydra documentation of a given operation.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $hydraDoc
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function getOperationHydraDoc($method, array $hydraDoc)
|
||||
{
|
||||
foreach ($hydraDoc['hydra:supportedOperation'] as $supportedOperation) {
|
||||
if ($supportedOperation['hydra:method'] === $method) {
|
||||
return $supportedOperation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Hydra documentation for the collection operation.
|
||||
*
|
||||
* @param string $shortName
|
||||
* @param string $method
|
||||
* @param array $hydraEntrypointDoc
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function getCollectionOperationHydraDoc($shortName, $method, array $hydraEntrypointDoc)
|
||||
{
|
||||
$propertyName = '#Entrypoint/'.lcfirst($shortName);
|
||||
|
||||
foreach ($hydraEntrypointDoc['hydra:supportedProperty'] as $supportedProperty) {
|
||||
$hydraProperty = $supportedProperty['hydra:property'];
|
||||
if ($hydraProperty['@id'] === $propertyName) {
|
||||
return $this->getOperationHydraDoc($method, $hydraProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Extractor\AnnotationsProvider;
|
||||
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
use Dunglas\JsonLdApiBundle\JsonLd\ResourceCollectionInterface;
|
||||
use Dunglas\JsonLdApiBundle\JsonLd\ResourceInterface;
|
||||
use Dunglas\JsonLdApiBundle\Mapping\ClassMetadataFactory;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Nelmio\ApiDocBundle\Extractor\AnnotationsProviderInterface;
|
||||
|
||||
/**
|
||||
* Creates ApiDoc annotations for DunglasJsonLdApiBundle.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class DunglasJsonLdApiProvider implements AnnotationsProviderInterface
|
||||
{
|
||||
/**
|
||||
* @var ResourceCollectionInterface
|
||||
*/
|
||||
private $resourceCollection;
|
||||
/**
|
||||
* @var ClassMetadataFactory
|
||||
*/
|
||||
private $classMetadataFactory;
|
||||
|
||||
public function __construct(ResourceCollectionInterface $resourceCollection, ClassMetadataFactory $classMetadataFactory)
|
||||
{
|
||||
$this->resourceCollection = $resourceCollection;
|
||||
$this->classMetadataFactory = $classMetadataFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAnnotations()
|
||||
{
|
||||
$annotations = [];
|
||||
/**
|
||||
* @var ResourceInterface $resource
|
||||
*/
|
||||
foreach ($this->resourceCollection as $resource) {
|
||||
$resource->getRouteCollection(); // Populate !route
|
||||
|
||||
foreach ($resource->getCollectionOperations() as $operation) {
|
||||
$annotations[] = $this->getApiDoc($resource, $operation);
|
||||
}
|
||||
|
||||
foreach ($resource->getItemOperations() as $operation) {
|
||||
$annotations[] = $this->getApiDoc($resource, $operation);
|
||||
}
|
||||
}
|
||||
|
||||
return $annotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds ApiDoc annotation from DunglasJsonLdApiBundle data.
|
||||
*
|
||||
* @param ResourceInterface $resource
|
||||
* @param array $operation
|
||||
*
|
||||
* @return ApiDoc
|
||||
*/
|
||||
private function getApiDoc(ResourceInterface $resource, array $operation)
|
||||
{
|
||||
$data = [
|
||||
'resource' => $operation['!route_path'],
|
||||
'description' => $operation['rdfs:label'],
|
||||
'resourceDescription' => $this->classMetadataFactory->getMetadataFor($resource->getEntityClass())->getDescription(),
|
||||
];
|
||||
|
||||
if (isset($operation['expects']) && $operation['expects'] !== 'owl:Nothing') {
|
||||
$data['input'] = $resource->getEntityClass();
|
||||
}
|
||||
|
||||
if (isset($operation['returns']) && $operation['returns'] !== 'owl:Nothing') {
|
||||
$data['output'] = $resource->getEntityClass();
|
||||
}
|
||||
|
||||
$data['filters'] = $resource->getFilters();
|
||||
|
||||
$apiDoc = new ApiDoc($data);
|
||||
$apiDoc->setRoute($operation['!route']);
|
||||
|
||||
return $apiDoc;
|
||||
}
|
||||
}
|
190
Parser/DunglasApiParser.php
Normal file
190
Parser/DunglasApiParser.php
Normal file
@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Parser;
|
||||
|
||||
use Dunglas\ApiBundle\Api\ResourceCollectionInterface;
|
||||
use Dunglas\ApiBundle\Api\ResourceInterface;
|
||||
use Dunglas\ApiBundle\Mapping\AttributeMetadataInterface;
|
||||
use Dunglas\ApiBundle\Mapping\ClassMetadataFactoryInterface;
|
||||
use Nelmio\ApiDocBundle\DataTypes;
|
||||
use PropertyInfo\Type;
|
||||
|
||||
/**
|
||||
* Use DunglasApiBundle to extract input and output information.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class DunglasApiParser implements ParserInterface
|
||||
{
|
||||
const IN_PREFIX = 'dunglas_api_in';
|
||||
const OUT_PREFIX = 'dunglas_api_out';
|
||||
const IRI = 'IRI';
|
||||
|
||||
private static $typeMap = array(
|
||||
'int' => DataTypes::INTEGER,
|
||||
'bool' => DataTypes::BOOLEAN,
|
||||
'string' => DataTypes::STRING,
|
||||
'float' => DataTypes::FLOAT,
|
||||
);
|
||||
|
||||
/**
|
||||
* @var ResourceCollectionInterface
|
||||
*/
|
||||
private $resourceCollection;
|
||||
/**
|
||||
* @var ClassMetadataFactory
|
||||
*/
|
||||
private $classMetadataFactory;
|
||||
|
||||
public function __construct(
|
||||
ResourceCollectionInterface $resourceCollection,
|
||||
ClassMetadataFactoryInterface $classMetadataFactory
|
||||
) {
|
||||
$this->resourceCollection = $resourceCollection;
|
||||
$this->classMetadataFactory = $classMetadataFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(array $item)
|
||||
{
|
||||
list(, $class) = explode(':', $item['class'], 2);
|
||||
|
||||
return null !== $this->resourceCollection->getResourceForEntity($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parse(array $item)
|
||||
{
|
||||
list($io, $entityClass) = explode(':', $item['class'], 2);
|
||||
$resource = $this->resourceCollection->getResourceForEntity($entityClass);
|
||||
|
||||
return $this->parseClass($resource, $entityClass, $io);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a class.
|
||||
*
|
||||
* @param ResourceInterface $resource
|
||||
* @param string $entityClass
|
||||
* @param string $io
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function parseClass(ResourceInterface $resource, $entityClass, $io)
|
||||
{
|
||||
$classMetadata = $this->classMetadataFactory->getMetadataFor(
|
||||
$entityClass,
|
||||
$resource->getNormalizationGroups(),
|
||||
$resource->getDenormalizationGroups(),
|
||||
$resource->getValidationGroups()
|
||||
);
|
||||
|
||||
$data = array();
|
||||
foreach ($classMetadata->getAttributes() as $attributeMetadata) {
|
||||
if (
|
||||
($attributeMetadata->isReadable() && self::OUT_PREFIX === $io) ||
|
||||
($attributeMetadata->isWritable() && self::IN_PREFIX === $io)
|
||||
) {
|
||||
$data[$attributeMetadata->getName()] = $this->parseAttribute($resource, $attributeMetadata, $io);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an attribute.
|
||||
*
|
||||
* @param ResourceInterface $resource
|
||||
* @param AttributeMetadataInterface $attributeMetadata
|
||||
* @param string $io
|
||||
* @param Type|null $type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function parseAttribute(ResourceInterface $resource, AttributeMetadataInterface $attributeMetadata, $io, Type $type = null)
|
||||
{
|
||||
$data = array(
|
||||
'dataType' => null,
|
||||
'required' => $attributeMetadata->isRequired(),
|
||||
'description' => $attributeMetadata->getDescription(),
|
||||
'readonly' => !$attributeMetadata->isWritable(),
|
||||
);
|
||||
|
||||
if (null == $type) {
|
||||
if (!isset($attributeMetadata->getTypes()[0])) {
|
||||
// Default to string
|
||||
$data['dataType'] = DataTypes::STRING;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
// Use the first type found as primary
|
||||
$type = $attributeMetadata->getTypes()[0];
|
||||
}
|
||||
|
||||
if ($type->isCollection()) {
|
||||
$data['actualType'] = DataTypes::COLLECTION;
|
||||
|
||||
if ($collectionType = $type->getCollectionType()) {
|
||||
$subAttribute = $this->parseAttribute($resource, $attributeMetadata, $io, $collectionType);
|
||||
if (self::IRI === $subAttribute['dataType']) {
|
||||
$data['dataType'] = 'array of IRIs';
|
||||
$data['subType'] = DataTypes::STRING;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
$data['subType'] = $subAttribute['subType'];
|
||||
$data['children'] = $subAttribute['children'];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
$phpType = $type->getType();
|
||||
if ('object' === $phpType) {
|
||||
$class = $type->getClass();
|
||||
|
||||
if ('DateTime' === $class) {
|
||||
$data['dataType'] = DataTypes::DATETIME;
|
||||
$data['format'] = sprintf('{DateTime %s}', \DateTime::ATOM);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
if (
|
||||
(self::OUT_PREFIX === $io && $attributeMetadata->isNormalizationLink()) ||
|
||||
(self::IN_PREFIX === $io && $attributeMetadata->isDenormalizationLink())
|
||||
) {
|
||||
$data['dataType'] = self::IRI;
|
||||
$data['actualType'] = DataTypes::STRING;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
$data['actualType'] = DataTypes::MODEL;
|
||||
$data['subType'] = $class;
|
||||
$data['children'] = $this->parseClass($resource, $class, $io);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
$data['dataType'] = isset(self::$typeMap[$type->getType()]) ? self::$typeMap[$type->getType()] : DataTypes::STRING;
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Parser;
|
||||
|
||||
use Dunglas\JsonLdApiBundle\JsonLd\ResourceCollectionInterface;
|
||||
use Dunglas\JsonLdApiBundle\JsonLd\ResourceInterface;
|
||||
use Dunglas\JsonLdApiBundle\Mapping\ClassMetadataFactory;
|
||||
use Nelmio\ApiDocBundle\DataTypes;
|
||||
|
||||
/**
|
||||
* Use DunglasJsonLdApi to extract input and output information.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class DunglasJsonLdApiParser implements ParserInterface
|
||||
{
|
||||
/**
|
||||
* @var ResourceCollectionInterface
|
||||
*/
|
||||
private $resourceCollection;
|
||||
/**
|
||||
* @var ClassMetadataFactory
|
||||
*/
|
||||
private $classMetadataFactory;
|
||||
|
||||
public function __construct(ResourceCollectionInterface $resourceCollection, ClassMetadataFactory $classMetadataFactory)
|
||||
{
|
||||
$this->resourceCollection = $resourceCollection;
|
||||
$this->classMetadataFactory = $classMetadataFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(array $item)
|
||||
{
|
||||
return null !== $this->resourceCollection->getResourceForEntity($item['class']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parse(array $item)
|
||||
{
|
||||
/**
|
||||
* @var $resource ResourceInterface
|
||||
*/
|
||||
$resource = $this->resourceCollection->getResourceForEntity($item['class']);
|
||||
$classMetadata = $this->classMetadataFactory->getMetadataFor(
|
||||
$resource->getEntityClass(),
|
||||
$resource->getNormalizationGroups(),
|
||||
$resource->getDenormalizationGroups(),
|
||||
$resource->getValidationGroups()
|
||||
);
|
||||
|
||||
$data = array();
|
||||
foreach ($classMetadata->getAttributes() as $attribute) {
|
||||
$data[$attribute->getName()] = [
|
||||
'required' => $attribute->isRequired(),
|
||||
'description' => $attribute->getDescription(),
|
||||
'readonly' => $attribute->isReadable() && !$attribute->isWritable(),
|
||||
'class' => $resource->getEntityClass(),
|
||||
];
|
||||
|
||||
if (isset($attribute->getTypes()[0])) {
|
||||
$type = $attribute->getTypes()[0];
|
||||
if ($type->isCollection()) {
|
||||
$dataType = DataTypes::COLLECTION;
|
||||
} elseif ('object' === $type->getType()) {
|
||||
if ('DateTime' === $type->getClass()) {
|
||||
$dataType = DataTypes::DATETIME;
|
||||
} else {
|
||||
$dataType = DataTypes::STRING;
|
||||
}
|
||||
} else {
|
||||
$dataType = $type->getType();
|
||||
}
|
||||
|
||||
$data[$attribute->getName()]['dataType'] = $dataType;
|
||||
} else {
|
||||
$data[$attribute->getName()]['dataType'] = DataTypes::STRING;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ interface ParserInterface
|
||||
* - class (optional) the fully-qualified class name of the item, if
|
||||
* it is represented by an object
|
||||
*
|
||||
* @param string $item The string type of input to parse.
|
||||
* @param array $item The string type of input to parse.
|
||||
* @return array
|
||||
*/
|
||||
public function parse(array $item);
|
||||
|
23
Resources/config/services.dunglas_api.xml
Normal file
23
Resources/config/services.dunglas_api.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" ?>
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<services>
|
||||
<service id="nelmio_api_doc.annotations_provider.dunglas_api_annotation_provider" class="Nelmio\ApiDocBundle\Extractor\AnnotationsProvider\DunglasApiProvider">
|
||||
<argument type="service" id="api.resource_collection" />
|
||||
<argument type="service" id="api.hydra.documentation_builder" />
|
||||
<argument type="service" id="api.mapping.class_metadata_factory" />
|
||||
|
||||
<tag name="nelmio_api_doc.extractor.annotations_provider" />
|
||||
</service>
|
||||
|
||||
<service id="nelmio_api_doc.parser.dunglas_api_parser" class="Nelmio\ApiDocBundle\Parser\DunglasApiParser">
|
||||
<argument type="service" id="api.resource_collection" />
|
||||
<argument type="service" id="api.mapping.class_metadata_factory" />
|
||||
|
||||
<tag name="nelmio_api_doc.extractor.parser" />
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</container>
|
@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<services>
|
||||
<service id="nelmio_api_doc.annotations_provider.dunglas_json_ld_api_annotation_provider" class="Nelmio\ApiDocBundle\Extractor\AnnotationsProvider\DunglasJsonLdApiProvider">
|
||||
<argument type="service" id="dunglas_json_ld_api.resource_collection" />
|
||||
<argument type="service" id="dunglas_json_ld_api.mapping.class_metadata_factory" />
|
||||
|
||||
<tag name="nelmio_api_doc.extractor.annotations_provider" />
|
||||
</service>
|
||||
|
||||
<service id="nelmio_api_doc.parser.dunglas_json_ld_api_parser" class="Nelmio\ApiDocBundle\Parser\DunglasJsonLdApiParser">
|
||||
<argument type="service" id="dunglas_json_ld_api.resource_collection" />
|
||||
<argument type="service" id="dunglas_json_ld_api.mapping.class_metadata_factory" />
|
||||
|
||||
<tag name="nelmio_api_doc.extractor.parser" />
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</container>
|
@ -14,7 +14,7 @@ Require the `nelmio/api-doc-bundle` package in your composer.json and update you
|
||||
|
||||
Register the bundle in `app/AppKernel.php`:
|
||||
|
||||
``` php
|
||||
```php
|
||||
// app/AppKernel.php
|
||||
public function registerBundles()
|
||||
{
|
||||
@ -33,7 +33,7 @@ NelmioApiDocBundle:
|
||||
prefix: /api/doc
|
||||
```
|
||||
Enable the bundle's configuration in `app/config/config.yml`:
|
||||
``` yaml
|
||||
```yaml
|
||||
# app/config/config.yml
|
||||
nelmio_api_doc: ~
|
||||
```
|
||||
@ -48,7 +48,7 @@ uses introspection a lot. Thanks to an annotation, it's really easy to document
|
||||
|
||||
The bundle provides an `ApiDoc()` annotation for your controllers:
|
||||
|
||||
``` php
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace Your\Namespace;
|
||||
@ -122,7 +122,7 @@ The following properties are available:
|
||||
|
||||
* `tags`: allow to tag a method (e.g. `beta` or `in-development`). Either a single tag or an array of tags. Each tag can have an optional hex colorcode attached.
|
||||
|
||||
``` php
|
||||
```php
|
||||
<?php
|
||||
|
||||
class YourController
|
||||
@ -156,7 +156,7 @@ class YourController
|
||||
|
||||
* `statusCodes`: an array of HTTP status codes and a description of when that status is returned; Example:
|
||||
|
||||
``` php
|
||||
```php
|
||||
<?php
|
||||
|
||||
class YourController
|
||||
@ -190,7 +190,7 @@ For classes parsed with JMS metadata, description will be taken from the propert
|
||||
|
||||
For Form Types, you can add an extra option named `description` on each field:
|
||||
|
||||
``` php
|
||||
```php
|
||||
<?php
|
||||
|
||||
class YourType extends AbstractType
|
||||
@ -383,14 +383,34 @@ If you want to generate a static version of your documentation without sandbox,
|
||||
Read the [documentation for Swagger integration](https://github.com/nelmio/NelmioApiDocBundle/blob/master/Resources/doc/swagger-support.md)
|
||||
for the necessary steps to make a Swagger-compliant documentation for your API.
|
||||
|
||||
### DunglasApiBundle support
|
||||
|
||||
This bundle recognizes and documents resources exposed with [DunglasApiBundle](https://github.com/dunglas/DunglasApiBundle).
|
||||
Just install NelmioApiDoc and the documentation will be automatically available. To enable the sandbox, use the following
|
||||
configuration:
|
||||
|
||||
```yaml
|
||||
# app/config/config.yml
|
||||
nelmio_api_doc:
|
||||
sandbox:
|
||||
accept_type: "application/json"
|
||||
body_format:
|
||||
formats: [ "json" ]
|
||||
default_format: "json"
|
||||
request_format:
|
||||
formats:
|
||||
json: "application/json"
|
||||
```
|
||||
|
||||
### Caching
|
||||
|
||||
It is a good idea to enable the internal caching mechanism on production:
|
||||
|
||||
# app/config/config.yml
|
||||
nelmio_api_doc:
|
||||
cache:
|
||||
enabled: true
|
||||
```yaml
|
||||
# app/config/config.yml
|
||||
nelmio_api_doc:
|
||||
cache:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
Configuration In-Depth
|
||||
----------------------
|
||||
|
@ -34,9 +34,9 @@ class AppKernel extends Kernel
|
||||
new \Nelmio\ApiDocBundle\Tests\Fixtures\NelmioApiDocTestBundle(),
|
||||
);
|
||||
|
||||
if (class_exists('Dunglas\JsonLdApiBundle\DunglasJsonLdApiBundle')) {
|
||||
if (class_exists('Dunglas\ApiBundle\DunglasApiBundle')) {
|
||||
$bundles[] = new \Doctrine\Bundle\DoctrineBundle\DoctrineBundle();
|
||||
$bundles[] = new \Dunglas\JsonLdApiBundle\DunglasJsonLdApiBundle();
|
||||
$bundles[] = new \Dunglas\ApiBundle\DunglasApiBundle();
|
||||
}
|
||||
|
||||
return $bundles;
|
||||
@ -61,8 +61,8 @@ class AppKernel extends Kernel
|
||||
{
|
||||
$loader->load(__DIR__.'/config/'.$this->environment.'.yml');
|
||||
|
||||
if (class_exists('Dunglas\JsonLdApiBundle\DunglasJsonLdApiBundle')) {
|
||||
$loader->load(__DIR__.'/config/dunglas_json_ld_api.yml');
|
||||
if (class_exists('Dunglas\ApiBundle\DunglasApiBundle')) {
|
||||
$loader->load(__DIR__.'/config/dunglas_api.yml');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,14 +9,14 @@ doctrine:
|
||||
auto_mapping: true
|
||||
|
||||
framework:
|
||||
router: { resource: "%kernel.root_dir%/config/dunglas_json_ld_api_routing.yml" }
|
||||
router: { resource: "%kernel.root_dir%/config/dunglas_api_routing.yml" }
|
||||
|
||||
dunglas_json_ld_api:
|
||||
dunglas_api:
|
||||
title: API
|
||||
description: Test API
|
||||
|
||||
services:
|
||||
dunglas_json_ld_api.popo:
|
||||
class: "Dunglas\JsonLdApiBundle\JsonLd\Resource"
|
||||
parent: "api.resource"
|
||||
arguments: [ "Nelmio\\ApiDocBundle\\Tests\\Fixtures\\Model\\Popo" ]
|
||||
tags: [ { name: "json-ld.resource" } ]
|
||||
tags: [ { name: "api.resource" } ]
|
6
Tests/Fixtures/app/config/dunglas_api_routing.yml
Normal file
6
Tests/Fixtures/app/config/dunglas_api_routing.yml
Normal file
@ -0,0 +1,6 @@
|
||||
main:
|
||||
resource: "routing.yml"
|
||||
|
||||
dunglas_api:
|
||||
resource: "."
|
||||
type: "api"
|
@ -1,9 +0,0 @@
|
||||
main:
|
||||
resource: "routing.yml"
|
||||
|
||||
dunglas_json_ld_api_doc:
|
||||
resource: "@DunglasJsonLdApiBundle/Resources/config/routing.xml"
|
||||
|
||||
dunglas_json_ld_api:
|
||||
resource: "."
|
||||
type: "json-ld"
|
@ -11,18 +11,20 @@
|
||||
|
||||
namespace NelmioApiDocBundle\Tests\Parser;
|
||||
|
||||
use Nelmio\ApiDocBundle\DataTypes;
|
||||
use Nelmio\ApiDocBundle\Parser\DunglasApiParser;
|
||||
use Nelmio\ApiDocBundle\Tests\WebTestCase;
|
||||
|
||||
/**
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class DunglasJsonLdApiParserTest extends WebTestCase
|
||||
class DunglasApiParserTest extends WebTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
if (!class_exists('Dunglas\JsonLdApiBundle\DunglasJsonLdApiBundle')) {
|
||||
if (!class_exists('Dunglas\ApiBundle\DunglasApiBundle')) {
|
||||
$this->markTestSkipped(
|
||||
'DunglasJsonLdApiBundle is not available.'
|
||||
'DunglasApiBundle is not available.'
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -30,9 +32,9 @@ class DunglasJsonLdApiParserTest extends WebTestCase
|
||||
public function testParser()
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
$parser = $container->get('nelmio_api_doc.parser.dunglas_json_ld_api_parser');
|
||||
$parser = $container->get('nelmio_api_doc.parser.dunglas_api_parser');
|
||||
|
||||
$item = array('class' => 'Nelmio\ApiDocBundle\Tests\Fixtures\Model\Popo');
|
||||
$item = array('class' => DunglasApiParser::OUT_PREFIX.':Nelmio\ApiDocBundle\Tests\Fixtures\Model\Popo');
|
||||
|
||||
$expected = array (
|
||||
'foo' =>
|
||||
@ -40,8 +42,7 @@ class DunglasJsonLdApiParserTest extends WebTestCase
|
||||
'required' => false,
|
||||
'description' => '',
|
||||
'readonly' => false,
|
||||
'class' => 'Nelmio\ApiDocBundle\Tests\Fixtures\Model\Popo',
|
||||
'dataType' => 'string',
|
||||
'dataType' => DataTypes::STRING,
|
||||
),
|
||||
);
|
||||
|
@ -33,14 +33,14 @@
|
||||
"symfony/serializer": "~2.7@dev",
|
||||
"friendsofsymfony/rest-bundle": "~1.0",
|
||||
"jms/serializer-bundle": ">=0.11",
|
||||
"dunglas/json-ld-api-bundle": "dev-master",
|
||||
"dunglas/api-bundle": "dev-master",
|
||||
"sensio/framework-extra-bundle": "~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/form": "For using form definitions as input.",
|
||||
"symfony/validator": "For making use of validator information in the doc.",
|
||||
"friendsofsymfony/rest-bundle": "For making use of REST information in the doc.",
|
||||
"dunglas/json-ld-api-bundle": "For making use of resources definitions of DunglasJsonLdApiBundle.",
|
||||
"dunglas/api-bundle": "For making use of resources definitions of DunglasApiBundle.",
|
||||
"jms/serializer": "For making use of serializer information in the doc."
|
||||
},
|
||||
"autoload": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user