2016-07-12 00:33:55 +02:00
< ? php
/*
2016-12-29 12:09:26 +01:00
* This file is part of the NelmioApiDocBundle package .
2016-07-12 00:33:55 +02:00
*
2016-12-29 12:09:26 +01:00
* ( c ) Nelmio
2016-07-12 00:33:55 +02:00
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
2016-12-29 12:09:26 +01:00
namespace Nelmio\ApiDocBundle\DependencyInjection ;
2016-07-12 00:33:55 +02:00
2016-08-04 22:36:20 +02:00
use FOS\RestBundle\Controller\Annotations\ParamInterface ;
2018-11-11 16:12:15 +01:00
use JMS\Serializer\Visitor\SerializationVisitorInterface ;
2018-01-05 13:08:02 +01:00
use Nelmio\ApiDocBundle\ApiDocGenerator ;
2018-07-26 10:16:10 +05:00
use Nelmio\ApiDocBundle\Describer\ExternalDocDescriber ;
2020-05-28 13:19:11 +02:00
use Nelmio\ApiDocBundle\Describer\OpenApiPhpDescriber ;
2018-01-05 13:08:02 +01:00
use Nelmio\ApiDocBundle\Describer\RouteDescriber ;
2018-05-05 14:49:17 +02:00
use Nelmio\ApiDocBundle\ModelDescriber\BazingaHateoasModelDescriber ;
2017-06-25 15:40:07 +02:00
use Nelmio\ApiDocBundle\ModelDescriber\JMSModelDescriber ;
2017-06-26 10:34:42 +02:00
use Nelmio\ApiDocBundle\Routing\FilteredRouteCollectionBuilder ;
2016-07-12 00:33:55 +02:00
use Symfony\Component\Config\FileLocator ;
2018-01-05 13:08:02 +01:00
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument ;
2016-07-12 00:33:55 +02:00
use Symfony\Component\DependencyInjection\ContainerBuilder ;
2017-06-22 22:28:30 +02:00
use Symfony\Component\DependencyInjection\Definition ;
2017-01-25 19:38:56 +01:00
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface ;
2017-03-16 19:35:04 +01:00
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader ;
2017-06-26 10:34:42 +02:00
use Symfony\Component\DependencyInjection\Reference ;
2021-04-18 17:48:12 +02:00
use Symfony\Component\DependencyInjection\ServiceLocator ;
2016-07-15 00:04:07 +02:00
use Symfony\Component\HttpKernel\DependencyInjection\Extension ;
2017-06-22 22:28:30 +02:00
use Symfony\Component\Routing\RouteCollection ;
2016-07-12 00:33:55 +02:00
2017-01-25 19:38:56 +01:00
final class NelmioApiDocExtension extends Extension implements PrependExtensionInterface
2016-07-12 00:33:55 +02:00
{
2017-01-25 19:38:56 +01:00
/**
* { @ inheritdoc }
*/
public function prepend ( ContainerBuilder $container )
{
$container -> prependExtensionConfig ( 'framework' , [ 'property_info' => [ 'enabled' => true ]]);
2017-06-25 15:40:07 +02:00
$bundles = $container -> getParameter ( 'kernel.bundles' );
2018-05-05 14:49:17 +02:00
// JMS Serializer support
2017-06-25 15:40:07 +02:00
if ( isset ( $bundles [ 'JMSSerializerBundle' ])) {
$container -> prependExtensionConfig ( 'nelmio_api_doc' , [ 'models' => [ 'use_jms' => true ]]);
}
2017-01-25 19:38:56 +01:00
}
2016-07-12 00:33:55 +02:00
/**
* { @ inheritdoc }
*/
public function load ( array $configs , ContainerBuilder $container )
{
$config = $this -> processConfiguration ( new Configuration (), $configs );
$loader = new XmlFileLoader ( $container , new FileLocator ( __DIR__ . '/../Resources/config' ));
$loader -> load ( 'services.xml' );
2016-07-13 23:05:14 +02:00
2016-11-30 14:08:10 +01:00
// Filter routes
2017-06-22 22:28:30 +02:00
$routesDefinition = ( new Definition ( RouteCollection :: class ))
-> setFactory ([ new Reference ( 'router' ), 'getRouteCollection' ]);
2018-01-05 13:08:02 +01:00
$container -> setParameter ( 'nelmio_api_doc.areas' , array_keys ( $config [ 'areas' ]));
2020-12-10 22:28:55 +01:00
$container -> setParameter ( 'nelmio_api_doc.media_types' , $config [ 'media_types' ]);
2018-01-05 13:08:02 +01:00
foreach ( $config [ 'areas' ] as $area => $areaConfig ) {
2018-06-10 09:56:38 +02:00
$nameAliases = $this -> findNameAliases ( $config [ 'models' ][ 'names' ], $area );
2018-01-05 13:08:02 +01:00
$container -> register ( sprintf ( 'nelmio_api_doc.generator.%s' , $area ), ApiDocGenerator :: class )
2018-10-06 14:42:47 +02:00
-> setPublic ( true )
2018-06-10 09:56:38 +02:00
-> addMethodCall ( 'setAlternativeNames' , [ $nameAliases ])
2020-07-06 19:50:34 +02:00
-> addMethodCall ( 'setMediaTypes' , [ $config [ 'media_types' ]])
2021-08-17 21:51:11 +02:00
-> addMethodCall ( 'setLogger' , [ new Reference ( 'logger' )])
-> addTag ( 'monolog.logger' , [ 'channel' => 'nelmio_api_doc' ])
2018-01-05 13:08:02 +01:00
-> setArguments ([
new TaggedIteratorArgument ( sprintf ( 'nelmio_api_doc.describer.%s' , $area )),
new TaggedIteratorArgument ( 'nelmio_api_doc.model_describer' ),
]);
$container -> register ( sprintf ( 'nelmio_api_doc.describers.route.%s' , $area ), RouteDescriber :: class )
-> setPublic ( false )
-> setArguments ([
new Reference ( sprintf ( 'nelmio_api_doc.routes.%s' , $area )),
new Reference ( 'nelmio_api_doc.controller_reflector' ),
new TaggedIteratorArgument ( 'nelmio_api_doc.route_describer' ),
2017-06-26 10:34:42 +02:00
])
2018-01-05 13:08:02 +01:00
-> addTag ( sprintf ( 'nelmio_api_doc.describer.%s' , $area ), [ 'priority' => - 400 ]);
2020-05-28 13:19:11 +02:00
$container -> register ( sprintf ( 'nelmio_api_doc.describers.openapi_php.%s' , $area ), OpenApiPhpDescriber :: class )
2018-01-05 13:08:02 +01:00
-> setPublic ( false )
-> setArguments ([
new Reference ( sprintf ( 'nelmio_api_doc.routes.%s' , $area )),
new Reference ( 'nelmio_api_doc.controller_reflector' ),
2020-05-29 21:52:06 +02:00
new Reference ( 'annotations.reader' ), // We cannot use the cached version of the annotation reader since the construction of the annotations is context dependant...
2018-04-20 10:34:55 +02:00
new Reference ( 'logger' ),
2018-01-05 13:08:02 +01:00
])
-> addTag ( sprintf ( 'nelmio_api_doc.describer.%s' , $area ), [ 'priority' => - 200 ]);
2018-07-26 10:16:10 +05:00
2018-08-14 15:09:29 +05:00
$container -> register ( sprintf ( 'nelmio_api_doc.describers.config.%s' , $area ), ExternalDocDescriber :: class )
-> setPublic ( false )
-> setArguments ([
2018-10-05 16:35:25 +02:00
$areaConfig [ 'documentation' ],
2018-08-14 15:09:29 +05:00
true ,
])
2018-10-05 10:36:48 +05:00
-> addTag ( sprintf ( 'nelmio_api_doc.describer.%s' , $area ), [ 'priority' => 990 ]);
2018-07-26 10:16:10 +05:00
2018-10-05 16:35:25 +02:00
unset ( $areaConfig [ 'documentation' ]);
2019-01-05 16:37:43 +01:00
if ( 0 === count ( $areaConfig [ 'path_patterns' ])
&& 0 === count ( $areaConfig [ 'host_patterns' ])
2019-04-16 18:22:51 +03:00
&& 0 === count ( $areaConfig [ 'name_patterns' ])
2019-01-05 16:37:43 +01:00
&& false === $areaConfig [ 'with_annotation' ]
) {
2018-10-05 16:35:25 +02:00
$container -> setDefinition ( sprintf ( 'nelmio_api_doc.routes.%s' , $area ), $routesDefinition )
-> setPublic ( false );
} else {
$container -> register ( sprintf ( 'nelmio_api_doc.routes.%s' , $area ), RouteCollection :: class )
-> setPublic ( false )
-> setFactory ([
( new Definition ( FilteredRouteCollectionBuilder :: class ))
2019-01-05 16:37:43 +01:00
-> setArguments (
[
2020-05-29 21:52:06 +02:00
new Reference ( 'annotation_reader' ), // Here we use the cached version as we don't deal with @OA annotations in this service
2019-01-05 16:37:43 +01:00
new Reference ( 'nelmio_api_doc.controller_reflector' ),
$area ,
$areaConfig ,
]
),
2018-10-05 16:35:25 +02:00
'filter' ,
])
-> addArgument ( $routesDefinition );
}
2017-06-22 22:28:30 +02:00
}
2016-11-30 14:08:10 +01:00
2021-04-18 17:48:12 +02:00
$container -> register ( 'nelmio_api_doc.generator_locator' , ServiceLocator :: class )
2018-01-05 13:08:02 +01:00
-> setPublic ( false )
-> addTag ( 'container.service_locator' )
-> addArgument ( array_combine (
array_keys ( $config [ 'areas' ]),
array_map ( function ( $area ) { return new Reference ( sprintf ( 'nelmio_api_doc.generator.%s' , $area )); }, array_keys ( $config [ 'areas' ]))
));
2020-05-28 13:19:11 +02:00
$container -> getDefinition ( 'nelmio_api_doc.model_describers.object' )
-> setArgument ( 3 , $config [ 'media_types' ]);
2016-08-04 22:27:10 +02:00
// Import services needed for each library
2018-01-13 14:18:13 +01:00
$loader -> load ( 'php_doc.xml' );
2016-08-04 22:36:20 +02:00
if ( interface_exists ( ParamInterface :: class )) {
$loader -> load ( 'fos_rest.xml' );
2020-05-28 13:19:11 +02:00
$container -> getDefinition ( 'nelmio_api_doc.route_describers.fos_rest' )
-> setArgument ( 1 , $config [ 'media_types' ]);
2016-08-04 22:36:20 +02:00
}
2016-07-29 10:22:40 +02:00
// ApiPlatform support
2017-06-25 15:40:07 +02:00
$bundles = $container -> getParameter ( 'kernel.bundles' );
2017-08-27 17:58:22 +02:00
if ( ! isset ( $bundles [ 'TwigBundle' ])) {
$container -> removeDefinition ( 'nelmio_api_doc.controller.swagger_ui' );
}
2016-07-29 10:22:40 +02:00
if ( isset ( $bundles [ 'ApiPlatformBundle' ]) && class_exists ( 'ApiPlatform\Core\Documentation\Documentation' )) {
$loader -> load ( 'api_platform.xml' );
}
2017-01-25 18:53:19 +01:00
2017-06-25 15:40:07 +02:00
// JMS metadata support
if ( $config [ 'models' ][ 'use_jms' ]) {
2018-11-11 16:12:15 +01:00
$jmsNamingStrategy = interface_exists ( SerializationVisitorInterface :: class ) ? null : new Reference ( 'jms_serializer.naming_strategy' );
2017-06-25 15:40:07 +02:00
$container -> register ( 'nelmio_api_doc.model_describers.jms' , JMSModelDescriber :: class )
-> setPublic ( false )
2018-01-13 14:18:13 +01:00
-> setArguments ([
new Reference ( 'jms_serializer.metadata_factory' ),
2020-05-29 21:52:06 +02:00
new Reference ( 'annotations.reader' ),
2020-05-28 13:19:11 +02:00
$config [ 'media_types' ],
$jmsNamingStrategy ,
2018-01-13 14:18:13 +01:00
])
2017-06-25 15:40:07 +02:00
-> addTag ( 'nelmio_api_doc.model_describer' , [ 'priority' => 50 ]);
2018-05-05 14:49:17 +02:00
// Bazinga Hateoas metadata support
if ( isset ( $bundles [ 'BazingaHateoasBundle' ])) {
$container -> register ( 'nelmio_api_doc.model_describers.jms.bazinga_hateoas' , BazingaHateoasModelDescriber :: class )
-> setDecoratedService ( 'nelmio_api_doc.model_describers.jms' , 'nelmio_api_doc.model_describers.jms.inner' )
-> setPublic ( false )
-> setArguments ([
new Reference ( 'hateoas.configuration.metadata_factory' ),
new Reference ( 'nelmio_api_doc.model_describers.jms.inner' ),
]);
}
2019-04-16 12:13:33 +02:00
} else {
$container -> removeDefinition ( 'nelmio_api_doc.model_describers.object_fallback' );
2017-06-25 15:40:07 +02:00
}
2018-10-05 10:36:48 +05:00
// Import the base configuration
$container -> getDefinition ( 'nelmio_api_doc.describers.config' ) -> replaceArgument ( 0 , $config [ 'documentation' ]);
2019-11-19 17:23:12 +01:00
// Compatibility Symfony
$controllerNameConverter = null ;
if ( $container -> hasDefinition ( '.legacy_controller_name_converter' )) { // 4.4
$controllerNameConverter = $container -> getDefinition ( '.legacy_controller_name_converter' );
} elseif ( $container -> hasDefinition ( 'controller_name_converter' )) { // < 4.4
$controllerNameConverter = $container -> getDefinition ( 'controller_name_converter' );
}
if ( null !== $controllerNameConverter ) {
$container -> getDefinition ( 'nelmio_api_doc.controller_reflector' ) -> setArgument ( 1 , $controllerNameConverter );
}
2016-07-12 00:33:55 +02:00
}
2018-06-10 09:56:38 +02:00
private function findNameAliases ( array $names , string $area ) : array
{
$nameAliases = array_filter ( $names , function ( array $aliasInfo ) use ( $area ) {
return empty ( $aliasInfo [ 'areas' ]) || in_array ( $area , $aliasInfo [ 'areas' ], true );
});
$aliases = [];
foreach ( $nameAliases as $nameAlias ) {
$aliases [ $nameAlias [ 'alias' ]] = [
'type' => $nameAlias [ 'type' ],
'groups' => $nameAlias [ 'groups' ],
];
}
return $aliases ;
}
2016-07-12 00:33:55 +02:00
}