diff --git a/DependencyInjection/AnnotationsProviderCompilerPass.php b/DependencyInjection/AnnotationsProviderCompilerPass.php deleted file mode 100644 index bd9c110..0000000 --- a/DependencyInjection/AnnotationsProviderCompilerPass.php +++ /dev/null @@ -1,37 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Nelmio\ApiDocBundle\DependencyInjection; - -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; - -/** - * AnnotationsProvider compiler pass. - * - * @author Kévin Dunglas - */ -class AnnotationsProviderCompilerPass implements CompilerPassInterface -{ - public function process(ContainerBuilder $container): void - { - $annotationsProviders = []; - foreach ($container->findTaggedServiceIds('nelmio_api_doc.extractor.annotations_provider') as $id => $attributes) { - $annotationsProviders[] = new Reference($id); - } - - $container - ->getDefinition('nelmio_api_doc.extractor.api_doc_extractor') - ->replaceArgument(4, $annotationsProviders) - ; - } -} diff --git a/Extractor/AnnotationsProvider/DunglasApiProvider.php b/Extractor/AnnotationsProvider/DunglasApiProvider.php deleted file mode 100644 index e17adc5..0000000 --- a/Extractor/AnnotationsProvider/DunglasApiProvider.php +++ /dev/null @@ -1,189 +0,0 @@ - - * - * 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; -use Symfony\Component\HttpFoundation\Request; - -/** - * Creates ApiDoc annotations for DunglasApiBundle. - * - * @author Kévin Dunglas - */ -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; - } - - 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 - * - * @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'], - 'section' => $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); - } - - if (Request::METHOD_GET === $method && $collection) { - $data['filters'] = []; - foreach ($resource->getFilters() as $filter) { - foreach ($filter->getDescription($resource) as $name => $definition) { - $data['filters'][] = ['name' => $name] + $definition; - } - } - } - - $apiDoc = new ApiDoc($data); - $apiDoc->setRoute($route); - - return $apiDoc; - } - - /** - * Gets Hydra documentation for the given resource. - * - * @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 - * - * @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 - * - * @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); - } - } - } -} diff --git a/Extractor/AnnotationsProviderInterface.php b/Extractor/AnnotationsProviderInterface.php deleted file mode 100644 index 1881c87..0000000 --- a/Extractor/AnnotationsProviderInterface.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Nelmio\ApiDocBundle\Extractor; - -/** - * Interface for annotations providers. - * - * @author Kévin Dunglas - */ -interface AnnotationsProviderInterface -{ - /** - * Returns an array ApiDoc annotations. - * - * @return \Nelmio\ApiDocBundle\Annotation\ApiDoc[] - */ - public function getAnnotations(); -} diff --git a/Extractor/ApiDocExtractor.php b/Extractor/ApiDocExtractor.php index ae4e1ab..7e76a58 100644 --- a/Extractor/ApiDocExtractor.php +++ b/Extractor/ApiDocExtractor.php @@ -30,16 +30,14 @@ class ApiDocExtractor protected array $parsers = []; /** - * @param HandlerInterface[] $handlers - * @param AnnotationsProviderInterface[] $annotationsProviders - * @param string[] $excludeSections + * @param HandlerInterface[] $handlers + * @param string[] $excludeSections */ public function __construct( protected RouterInterface $router, protected Reader $reader, protected DocCommentExtractor $commentExtractor, protected array $handlers, - protected array $annotationsProviders, protected array $excludeSections, ) { } @@ -129,13 +127,6 @@ class ApiDocExtractor } } - foreach ($this->annotationsProviders as $annotationProvider) { - foreach ($annotationProvider->getAnnotations() as $annotation) { - $route = $annotation->getRoute(); - $array[] = ['annotation' => $this->extractData($annotation, $route, $this->getReflectionMethod($route->getDefault('_controller')))]; - } - } - rsort($resources); foreach ($array as $index => $element) { $hasResource = false; diff --git a/Extractor/CachingApiDocExtractor.php b/Extractor/CachingApiDocExtractor.php index d425a77..e761633 100644 --- a/Extractor/CachingApiDocExtractor.php +++ b/Extractor/CachingApiDocExtractor.php @@ -26,22 +26,20 @@ use Symfony\Component\Routing\RouterInterface; class CachingApiDocExtractor extends ApiDocExtractor { /** - * @param HandlerInterface[] $handlers - * @param AnnotationsProviderInterface[] $annotationsProviders - * @param string[] $excludeSections - * @param bool|false $debug + * @param HandlerInterface[] $handlers + * @param string[] $excludeSections + * @param bool|false $debug */ public function __construct( RouterInterface $router, Reader $reader, DocCommentExtractor $commentExtractor, array $handlers, - array $annotationsProviders, array $excludeSections, private string $cacheFile, private bool $debug = false, ) { - parent::__construct($router, $reader, $commentExtractor, $handlers, $annotationsProviders, $excludeSections); + parent::__construct($router, $reader, $commentExtractor, $handlers, $excludeSections); } /** diff --git a/NelmioApiDocBundle.php b/NelmioApiDocBundle.php index 306ac92..7279973 100644 --- a/NelmioApiDocBundle.php +++ b/NelmioApiDocBundle.php @@ -2,7 +2,6 @@ namespace Nelmio\ApiDocBundle; -use Nelmio\ApiDocBundle\DependencyInjection\AnnotationsProviderCompilerPass; use Nelmio\ApiDocBundle\DependencyInjection\ExtractorHandlerCompilerPass; use Nelmio\ApiDocBundle\DependencyInjection\FormInfoParserCompilerPass; use Nelmio\ApiDocBundle\DependencyInjection\LoadExtractorParsersPass; @@ -20,7 +19,6 @@ class NelmioApiDocBundle extends Bundle $container->addCompilerPass(new LoadExtractorParsersPass()); $container->addCompilerPass(new RegisterExtractorParsersPass()); $container->addCompilerPass(new ExtractorHandlerCompilerPass()); - $container->addCompilerPass(new AnnotationsProviderCompilerPass()); $container->addCompilerPass(new SwaggerConfigCompilerPass()); $container->addCompilerPass(new FormInfoParserCompilerPass()); } diff --git a/Parser/DunglasApiParser.php b/Parser/DunglasApiParser.php deleted file mode 100644 index 39173f2..0000000 --- a/Parser/DunglasApiParser.php +++ /dev/null @@ -1,187 +0,0 @@ - - * - * 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 - */ -class DunglasApiParser implements ParserInterface -{ - public const IN_PREFIX = 'dunglas_api_in'; - public const OUT_PREFIX = 'dunglas_api_out'; - public const IRI = 'IRI'; - - private static $typeMap = [ - '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; - } - - public function supports(array $item) - { - $data = explode(':', $item['class'], 2); - if (isset($data[1])) { - return null !== $this->resourceCollection->getResourceForEntity($data[1]); - } - - return false; - } - - public function parse(array $item) - { - [$io, $entityClass] = explode(':', $item['class'], 2); - $resource = $this->resourceCollection->getResourceForEntity($entityClass); - - return $this->parseClass($resource, $entityClass, $io); - } - - /** - * Parses a class. - * - * @param string $entityClass - * @param string $io - * @param string[] $visited - * - * @return array - */ - private function parseClass(ResourceInterface $resource, $entityClass, $io, array $visited = []) - { - $visited[] = $entityClass; - - $classMetadata = $this->classMetadataFactory->getMetadataFor( - $entityClass, - $resource->getNormalizationGroups(), - $resource->getDenormalizationGroups(), - $resource->getValidationGroups() - ); - - $data = []; - foreach ($classMetadata->getAttributes() as $attributeMetadata) { - if ( - (!$attributeMetadata->isIdentifier() && $attributeMetadata->isReadable() && self::OUT_PREFIX === $io) - || ($attributeMetadata->isWritable() && self::IN_PREFIX === $io) - ) { - $data[$attributeMetadata->getName()] = $this->parseAttribute($resource, $attributeMetadata, $io, null, $visited); - } - } - - return $data; - } - - /** - * Parses an attribute. - * - * @param string $io - * @param string[] $visited - * - * @return array - */ - private function parseAttribute(ResourceInterface $resource, AttributeMetadataInterface $attributeMetadata, $io, ?Type $type = null, array $visited = []) - { - $data = [ - '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, $visited); - 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'] = in_array($class, $visited) ? [] : $this->parseClass($resource, $class, $io, $visited); - - return $data; - } - - $data['dataType'] = isset(self::$typeMap[$type->getType()]) ? self::$typeMap[$type->getType()] : DataTypes::STRING; - - return $data; - } -} diff --git a/Resources/config/services.dunglas_api.xml b/Resources/config/services.dunglas_api.xml deleted file mode 100644 index 67f668d..0000000 --- a/Resources/config/services.dunglas_api.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/Resources/config/services.xml b/Resources/config/services.xml index 321420a..87ec925 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -30,7 +30,6 @@ - %nelmio_api_doc.exclude_sections% diff --git a/Tests/Parser/DunglasApiParserTest.php b/Tests/Parser/DunglasApiParserTest.php deleted file mode 100644 index 8bdfd03..0000000 --- a/Tests/Parser/DunglasApiParserTest.php +++ /dev/null @@ -1,51 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace NelmioApiDocBundle\Tests\Parser; - -use Nelmio\ApiDocBundle\DataTypes; -use Nelmio\ApiDocBundle\Parser\DunglasApiParser; -use Nelmio\ApiDocBundle\Tests\WebTestCase; - -/** - * @author Kévin Dunglas - */ -class DunglasApiParserTest extends WebTestCase -{ - protected function setUp(): void - { - if (!class_exists('Dunglas\ApiBundle\DunglasApiBundle')) { - $this->markTestSkipped( - 'DunglasApiBundle is not available.' - ); - } - } - - public function testParser(): void - { - $container = $this->getContainer(); - $parser = $container->get('nelmio_api_doc.parser.dunglas_api_parser'); - - $item = ['class' => DunglasApiParser::OUT_PREFIX . ':Nelmio\ApiDocBundle\Tests\Fixtures\Model\Popo']; - - $expected = [ - 'foo' => [ - 'required' => false, - 'description' => '', - 'readonly' => false, - 'dataType' => DataTypes::STRING, - ], - ]; - - $this->assertTrue($parser->supports($item)); - $this->assertEquals($expected, $parser->parse($item)); - } -} diff --git a/composer.json b/composer.json index 13f9670..6de6f23 100644 --- a/composer.json +++ b/composer.json @@ -46,7 +46,6 @@ "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/api-bundle": "For making use of resources definitions of DunglasApiBundle.", "jms/serializer": "For making use of serializer information in the doc." }, "autoload": {