welcome back to dyb-tech

This commit is contained in:
Daniel Guzman
2024-05-18 02:28:01 +02:00
parent 9513cdba09
commit 9f30bc98c7
6149 changed files with 668407 additions and 0 deletions
@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the NelmioApiDocBundle package.
*
* (c) Nelmio
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\DependencyInjection\Compiler;
use Nelmio\ApiDocBundle\ModelDescriber\FormModelDescriber;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
/**
* Enables the FormModelDescriber only if forms are enabled.
*
* @internal
*/
final class ConfigurationPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if ($container->hasDefinition('form.factory')) {
$container->register('nelmio_api_doc.model_describers.form', FormModelDescriber::class)
->setPublic(false)
->addArgument(new Reference('form.factory'))
->addArgument(new Reference('annotations.reader', ContainerInterface::NULL_ON_INVALID_REFERENCE))
->addArgument($container->getParameter('nelmio_api_doc.media_types'))
->addArgument($container->getParameter('nelmio_api_doc.use_validation_groups'))
->addArgument($container->getParameter('form.type_extension.csrf.enabled'))
->addTag('nelmio_api_doc.model_describer', ['priority' => 100]);
}
$container->getParameterBag()->remove('nelmio_api_doc.media_types');
}
}
@@ -0,0 +1,59 @@
<?php
/*
* This file is part of the NelmioApiDocBundle package.
*
* (c) Nelmio
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Compiler Pass to identify and register custom processors.
* *
* @internal
*/
final class CustomProcessorPass implements CompilerPassInterface
{
use PriorityTaggedServiceTrait;
/**
* Process services tagged as 'swagger.processor'.
*
* @param ContainerBuilder $container The container builder
*/
public function process(ContainerBuilder $container): void
{
// Find the OpenAPI generator service.
$definition = $container->findDefinition('nelmio_api_doc.open_api.generator');
foreach ($this->findAndSortTaggedServices('nelmio_api_doc.swagger.processor', $container) as $reference) {
$id = (string) $reference;
$tags = $container->findDefinition($id)->getTags();
/**
* Before which processor should this processor be run?
*
* @var string|null
*/
$before = null;
// See if the processor has a 'before' attribute.
foreach ($tags as $tag) {
if (isset($tag['before'])) {
$before = $tag['before'];
}
}
$definition->addMethodCall('addProcessor', [new Reference($id), $before]);
}
}
}
@@ -0,0 +1,35 @@
<?php
/*
* This file is part of the NelmioApiDocBundle package.
*
* (c) Nelmio
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Enables the `PhpDocExtractor` manually if Symfony did not. Covers the cases where the `phpdocumentor/reflection-docblock` dependency is considered
* dev only and not automatically enabled by Symfony because `nelmio/api-doc-bundle` (which requires it) is required for dev environment only.
*
* @see https://github.com/symfony/symfony/blob/6.1/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php#L1889
*
* @internal
*/
final class PhpDocExtractorPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if (!$container->hasDefinition('property_info.php_doc_extractor')) {
$definition = $container->register('property_info.php_doc_extractor', 'Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor');
$definition->addTag('property_info.description_extractor', ['priority' => -1000]);
$definition->addTag('property_info.type_extractor', ['priority' => -1001]);
}
}
}
@@ -0,0 +1,33 @@
<?php
/*
* This file is part of the NelmioApiDocBundle package.
*
* (c) Nelmio
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* @internal
*/
final class TagDescribersPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
foreach ($container->findTaggedServiceIds('nelmio_api_doc.describer') as $id => $tags) {
$describer = $container->getDefinition($id);
foreach ($container->getParameter('nelmio_api_doc.areas') as $area) {
foreach ($tags as $tag) {
$describer->addTag(sprintf('nelmio_api_doc.describer.%s', $area), $tag);
}
}
}
}
}
@@ -0,0 +1,142 @@
<?php
/*
* This file is part of the NelmioApiDocBundle package.
*
* (c) Nelmio
*
* 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\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
final class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('nelmio_api_doc');
if (method_exists($treeBuilder, 'getRootNode')) {
$rootNode = $treeBuilder->getRootNode();
} else {
// symfony < 4.2 support
$rootNode = $treeBuilder->root('nelmio_api_doc');
}
$rootNode
->children()
->booleanNode('use_validation_groups')
->info('If true, `groups` passed to @Model annotations will be used to limit validation constraints')
->defaultFalse()
->end()
->arrayNode('documentation')
->useAttributeAsKey('key')
->info('The documentation used as base')
->example(['info' => ['title' => 'My App']])
->prototype('variable')->end()
->end()
->arrayNode('media_types')
->info('List of enabled Media Types')
->defaultValue(['json'])
->prototype('scalar')->end()
->end()
->arrayNode('areas')
->info('Filter the routes that are documented')
->defaultValue(
[
'default' => [
'path_patterns' => [],
'host_patterns' => [],
'with_annotation' => false,
'documentation' => [],
'name_patterns' => [],
'disable_default_routes' => false,
],
]
)
->beforeNormalization()
->ifTrue(function ($v) {
return 0 === count($v) || isset($v['path_patterns']) || isset($v['host_patterns']) || isset($v['documentation']);
})
->then(function ($v) {
return ['default' => $v];
})
->end()
->validate()
->ifTrue(function ($v) {
return !isset($v['default']);
})
->thenInvalid('You must specify a `default` area under `nelmio_api_doc.areas`.')
->end()
->useAttributeAsKey('name')
->prototype('array')
->addDefaultsIfNotSet()
->children()
->arrayNode('path_patterns')
->defaultValue([])
->example(['^/api', '^/api(?!/admin)'])
->prototype('scalar')->end()
->end()
->arrayNode('host_patterns')
->defaultValue([])
->example(['^api\.'])
->prototype('scalar')->end()
->end()
->arrayNode('name_patterns')
->defaultValue([])
->example(['^api_v1'])
->prototype('scalar')->end()
->end()
->booleanNode('with_annotation')
->defaultFalse()
->info('whether to filter by annotation')
->end()
->booleanNode('disable_default_routes')
->defaultFalse()
->info('if set disables default routes without annotations')
->end()
->arrayNode('documentation')
->useAttributeAsKey('key')
->defaultValue([])
->info('The documentation used for area')
->example(['info' => ['title' => 'My App']])
->prototype('variable')->end()
->end()
->end()
->end()
->end()
->arrayNode('models')
->addDefaultsIfNotSet()
->children()
->booleanNode('use_jms')->defaultFalse()->end()
->end()
->children()
->arrayNode('names')
->prototype('array')
->children()
->scalarNode('alias')->isRequired()->end()
->scalarNode('type')->isRequired()->end()
->variableNode('groups')
->defaultValue(null)
->validate()
->ifTrue(function ($v) { return null !== $v && !is_array($v); })
->thenInvalid('Model groups must be either `null` or an array.')
->end()
->end()
->arrayNode('areas')
->defaultValue([])
->prototype('scalar')->end()
->end()
->end()
->end()
->end()
->end()
->end();
return $treeBuilder;
}
}
@@ -0,0 +1,300 @@
<?php
/*
* This file is part of the NelmioApiDocBundle package.
*
* (c) Nelmio
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\DependencyInjection;
use FOS\RestBundle\Controller\Annotations\ParamInterface;
use JMS\Serializer\ContextFactory\SerializationContextFactoryInterface;
use JMS\Serializer\Visitor\SerializationVisitorInterface;
use Nelmio\ApiDocBundle\ApiDocGenerator;
use Nelmio\ApiDocBundle\Describer\ExternalDocDescriber;
use Nelmio\ApiDocBundle\Describer\OpenApiPhpDescriber;
use Nelmio\ApiDocBundle\Describer\RouteDescriber;
use Nelmio\ApiDocBundle\ModelDescriber\BazingaHateoasModelDescriber;
use Nelmio\ApiDocBundle\ModelDescriber\JMSModelDescriber;
use Nelmio\ApiDocBundle\ModelDescriber\ModelDescriberInterface;
use Nelmio\ApiDocBundle\Processor\MapQueryStringProcessor;
use Nelmio\ApiDocBundle\Processor\MapRequestPayloadProcessor;
use Nelmio\ApiDocBundle\RouteDescriber\RouteArgumentDescriber;
use Nelmio\ApiDocBundle\RouteDescriber\RouteArgumentDescriber\RouteArgumentDescriberInterface;
use Nelmio\ApiDocBundle\RouteDescriber\RouteArgumentDescriber\SymfonyMapQueryParameterDescriber;
use Nelmio\ApiDocBundle\RouteDescriber\RouteArgumentDescriber\SymfonyMapQueryStringDescriber;
use Nelmio\ApiDocBundle\RouteDescriber\RouteArgumentDescriber\SymfonyMapRequestPayloadDescriber;
use Nelmio\ApiDocBundle\Routing\FilteredRouteCollectionBuilder;
use OpenApi\Generator;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\HttpKernel\Attribute\MapQueryParameter;
use Symfony\Component\HttpKernel\Attribute\MapQueryString;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\Routing\RouteCollection;
final class NelmioApiDocExtension extends Extension implements PrependExtensionInterface
{
/**
* {@inheritdoc}
*/
public function prepend(ContainerBuilder $container): void
{
$container->prependExtensionConfig('framework', ['property_info' => ['enabled' => true]]);
$bundles = $container->getParameter('kernel.bundles');
// JMS Serializer support
if (isset($bundles['JMSSerializerBundle'])) {
$container->prependExtensionConfig('nelmio_api_doc', ['models' => ['use_jms' => true]]);
}
}
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container): void
{
$config = $this->processConfiguration(new Configuration(), $configs);
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.xml');
// Filter routes
$routesDefinition = (new Definition(RouteCollection::class))
->setFactory([new Reference('router'), 'getRouteCollection']);
$container->setParameter('nelmio_api_doc.areas', array_keys($config['areas']));
$container->setParameter('nelmio_api_doc.media_types', $config['media_types']);
$container->setParameter('nelmio_api_doc.use_validation_groups', $config['use_validation_groups']);
// Register the OpenAPI Generator as a service.
$container->register('nelmio_api_doc.open_api.generator', Generator::class)
->setPublic(false);
foreach ($config['areas'] as $area => $areaConfig) {
$nameAliases = $this->findNameAliases($config['models']['names'], $area);
$container->register(sprintf('nelmio_api_doc.generator.%s', $area), ApiDocGenerator::class)
->setPublic(true)
->addMethodCall('setAlternativeNames', [$nameAliases])
->addMethodCall('setMediaTypes', [$config['media_types']])
->addMethodCall('setLogger', [new Reference('logger')])
->addMethodCall('setOpenApiVersion', [$config['documentation']['openapi'] ?? null])
->addTag('monolog.logger', ['channel' => 'nelmio_api_doc'])
->setArguments([
new TaggedIteratorArgument(sprintf('nelmio_api_doc.describer.%s', $area)),
new TaggedIteratorArgument('nelmio_api_doc.model_describer'),
null,
null,
new Reference('nelmio_api_doc.open_api.generator'),
]);
$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'),
])
->addTag(sprintf('nelmio_api_doc.describer.%s', $area), ['priority' => -400]);
$container->register(sprintf('nelmio_api_doc.describers.openapi_php.%s', $area), OpenApiPhpDescriber::class)
->setPublic(false)
->setArguments([
new Reference(sprintf('nelmio_api_doc.routes.%s', $area)),
new Reference('nelmio_api_doc.controller_reflector'),
new Reference('annotations.reader', ContainerInterface::NULL_ON_INVALID_REFERENCE), // We cannot use the cached version of the annotation reader since the construction of the annotations is context dependant...
new Reference('logger'),
])
->addTag(sprintf('nelmio_api_doc.describer.%s', $area), ['priority' => -200]);
$container->register(sprintf('nelmio_api_doc.describers.config.%s', $area), ExternalDocDescriber::class)
->setPublic(false)
->setArguments([
$areaConfig['documentation'],
true,
])
->addTag(sprintf('nelmio_api_doc.describer.%s', $area), ['priority' => 990]);
unset($areaConfig['documentation']);
if (0 === count($areaConfig['path_patterns'])
&& 0 === count($areaConfig['host_patterns'])
&& 0 === count($areaConfig['name_patterns'])
&& false === $areaConfig['with_annotation']
&& false === $areaConfig['disable_default_routes']
) {
$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))
->setArguments(
[
new Reference('annotation_reader', ContainerInterface::NULL_ON_INVALID_REFERENCE), // Here we use the cached version as we don't deal with @OA annotations in this service
new Reference('nelmio_api_doc.controller_reflector'),
$area,
$areaConfig,
]
),
'filter',
])
->addArgument($routesDefinition);
}
}
$container->register('nelmio_api_doc.generator_locator', ServiceLocator::class)
->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']))
));
$container->getDefinition('nelmio_api_doc.model_describers.object')
->setArgument(3, $config['media_types']);
// Add autoconfiguration for model describer
$container->registerForAutoconfiguration(ModelDescriberInterface::class)
->addTag('nelmio_api_doc.model_describer');
// Import services needed for each library
$loader->load('php_doc.xml');
if (interface_exists(ParamInterface::class)) {
$loader->load('fos_rest.xml');
$container->getDefinition('nelmio_api_doc.route_describers.fos_rest')
->setArgument(1, $config['media_types']);
}
if (PHP_VERSION_ID > 80100) {
// Add autoconfiguration for route argument describer
$container->registerForAutoconfiguration(RouteArgumentDescriberInterface::class)
->addTag('nelmio_api_doc.route_argument_describer');
$container->register('nelmio_api_doc.route_describers.route_argument', RouteArgumentDescriber::class)
->setPublic(false)
->addTag('nelmio_api_doc.route_describer', ['priority' => -225])
->setArguments([
new Reference('argument_metadata_factory'),
new TaggedIteratorArgument('nelmio_api_doc.route_argument_describer'),
])
;
if (class_exists(MapQueryString::class)) {
$container->register('nelmio_api_doc.route_argument_describer.map_query_string', SymfonyMapQueryStringDescriber::class)
->setPublic(false)
->addTag('nelmio_api_doc.route_argument_describer', ['priority' => 0]);
$container->register('nelmio_api_doc.swagger.processor.map_query_string', MapQueryStringProcessor::class)
->setPublic(false)
->addTag('nelmio_api_doc.swagger.processor', ['priority' => 0]);
}
if (class_exists(MapRequestPayload::class)) {
$container->register('nelmio_api_doc.route_argument_describer.map_request_payload', SymfonyMapRequestPayloadDescriber::class)
->setPublic(false)
->addTag('nelmio_api_doc.route_argument_describer', ['priority' => 0]);
$container->register('nelmio_api_doc.swagger.processor.map_request_payload', MapRequestPayloadProcessor::class)
->setPublic(false)
->addTag('nelmio_api_doc.swagger.processor', ['priority' => 0]);
}
if (class_exists(MapQueryParameter::class)) {
$container->register('nelmio_api_doc.route_argument_describer.map_query_parameter', SymfonyMapQueryParameterDescriber::class)
->setPublic(false)
->addTag('nelmio_api_doc.route_argument_describer', ['priority' => 0]);
}
}
$bundles = $container->getParameter('kernel.bundles');
if (!isset($bundles['TwigBundle']) || !class_exists('Symfony\Component\Asset\Packages')) {
$container->removeDefinition('nelmio_api_doc.controller.swagger_ui');
$container->removeDefinition('nelmio_api_doc.render_docs.html');
$container->removeDefinition('nelmio_api_doc.render_docs.html.asset');
}
// ApiPlatform support
if (isset($bundles['ApiPlatformBundle']) && class_exists('ApiPlatform\Documentation\Documentation')) {
$loader->load('api_platform.xml');
}
// JMS metadata support
if ($config['models']['use_jms']) {
$jmsNamingStrategy = interface_exists(SerializationVisitorInterface::class) ? null : new Reference('jms_serializer.naming_strategy');
$contextFactory = interface_exists(SerializationContextFactoryInterface::class) ? new Reference('jms_serializer.serialization_context_factory') : null;
$container->register('nelmio_api_doc.model_describers.jms', JMSModelDescriber::class)
->setPublic(false)
->setArguments([
new Reference('jms_serializer.metadata_factory'),
new Reference('annotations.reader', ContainerInterface::NULL_ON_INVALID_REFERENCE),
$config['media_types'],
$jmsNamingStrategy,
$container->getParameter('nelmio_api_doc.use_validation_groups'),
$contextFactory,
])
->addTag('nelmio_api_doc.model_describer', ['priority' => 50]);
// 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'),
]);
}
} else {
$container->removeDefinition('nelmio_api_doc.model_describers.object_fallback');
}
// Import the base configuration
$container->getDefinition('nelmio_api_doc.describers.config')->replaceArgument(0, $config['documentation']);
// 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);
}
}
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;
}
}