Add explicit dependencies instead of container

This commit is contained in:
Ilyas Salikhov 2024-07-02 16:24:26 +03:00
parent ed2e185fe2
commit 0808e8421a
9 changed files with 83 additions and 158 deletions

View File

@ -12,12 +12,15 @@
namespace Nelmio\ApiDocBundle\Command;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Nelmio\ApiDocBundle\Extractor\ApiDocExtractor;
use Nelmio\ApiDocBundle\Formatter\HtmlFormatter;
use Nelmio\ApiDocBundle\Formatter\MarkdownFormatter;
use Nelmio\ApiDocBundle\Formatter\SimpleFormatter;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Contracts\Translation\LocaleAwareInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
@ -27,29 +30,28 @@ use Symfony\Contracts\Translation\TranslatorInterface;
)]
class DumpCommand extends Command
{
/**
* @var array
*/
protected $availableFormats = array('markdown', 'json', 'html');
private const AVAILABLE_FORMATS = ['markdown', 'json', 'html'];
/**
* @param TranslatorInterface&LocaleAwareInterface $translator
*/
public function __construct(
private ContainerInterface $container,
private TranslatorInterface $translator,
string $name = null
private readonly SimpleFormatter $simpleFormatter,
private readonly MarkdownFormatter $markdownFormatter,
private readonly HtmlFormatter $htmlFormatter,
private readonly ApiDocExtractor $apiDocExtractor,
private readonly TranslatorInterface $translator
) {
parent::__construct($name);
parent::__construct();
}
protected function configure()
protected function configure(): void
{
$this
->addOption(
'format', '', InputOption::VALUE_REQUIRED,
'Output format like: ' . implode(', ', $this->availableFormats),
$this->availableFormats[0]
'Output format like: ' . implode(', ', self::AVAILABLE_FORMATS),
self::AVAILABLE_FORMATS[0]
)
->addOption('api-version', null, InputOption::VALUE_REQUIRED, 'The API version')
->addOption('locale', null, InputOption::VALUE_REQUIRED, 'Locale for translation')
@ -63,15 +65,12 @@ class DumpCommand extends Command
$format = $input->getOption('format');
$view = $input->getOption('view');
if ($format === 'json') {
$formatter = $this->container->get('nelmio_api_doc.formatter.simple_formatter');
} else {
if (!in_array($format, $this->availableFormats)) {
throw new \RuntimeException(sprintf('Format "%s" not supported.', $format));
}
$formatter = $this->container->get(sprintf('nelmio_api_doc.formatter.%s_formatter', $format));
}
$formatter = match ($format) {
'json' => $this->simpleFormatter,
'markdown' => $this->markdownFormatter,
'html' => $this->htmlFormatter,
default => throw new \RuntimeException(sprintf('Format "%s" not supported.', $format)),
};
if ($input->hasOption('locale')) {
$this->translator->setLocale($input->getOption('locale') ?? '');
@ -81,19 +80,18 @@ class DumpCommand extends Command
$formatter->setVersion($input->getOption('api-version'));
}
if ($input->getOption('no-sandbox') && 'html' === $format) {
if ($formatter instanceof HtmlFormatter && $input->getOption('no-sandbox')) {
$formatter->setEnableSandbox(false);
}
$extractor = $this->container->get('nelmio_api_doc.extractor.api_doc_extractor');
$extractedDoc = $input->hasOption('api-version') ?
$extractor->allForVersion($input->getOption('api-version'), $view) :
$extractor->all($view);
$this->apiDocExtractor->allForVersion($input->getOption('api-version'), $view) :
$this->apiDocExtractor->all($view);
$formattedDoc = $formatter->format($extractedDoc);
if ('json' === $format) {
$output->writeln(json_encode($formattedDoc));
$output->writeln(json_encode($formattedDoc, JSON_THROW_ON_ERROR));
} else {
$output->writeln($formattedDoc, OutputInterface::OUTPUT_RAW);
}

View File

@ -11,6 +11,7 @@
namespace Nelmio\ApiDocBundle\Command;
use Nelmio\ApiDocBundle\Extractor\ApiDocExtractor;
use Nelmio\ApiDocBundle\Formatter\SwaggerFormatter;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
@ -18,7 +19,6 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
@ -33,24 +33,16 @@ use Symfony\Component\Filesystem\Filesystem;
)]
class SwaggerDumpCommand extends Command
{
/**
* @var Filesystem
*/
protected $filesystem;
/**
* @var SwaggerFormatter
*/
protected $formatter;
private Filesystem $filesystem;
public function __construct(
private ContainerInterface $container,
string $name = null
private readonly ApiDocExtractor $extractor,
private readonly SwaggerFormatter $formatter
) {
parent::__construct($name);
parent::__construct();
}
protected function configure()
protected function configure(): void
{
$this->filesystem = new Filesystem();
@ -64,24 +56,21 @@ class SwaggerDumpCommand extends Command
protected function execute(InputInterface $input, OutputInterface $output): int
{
$extractor = $this->container->get('nelmio_api_doc.extractor.api_doc_extractor');
$this->formatter = $this->container->get('nelmio_api_doc.formatter.swagger_formatter');
if ($input->getOption('list-only') && $input->getOption('resource')) {
throw new \RuntimeException('Cannot selectively dump a resource with the --list-only flag.');
}
$apiDocs = $extractor->all();
$apiDocs = $this->extractor->all();
if ($input->getOption('list-only')) {
$data = $this->getResourceList($apiDocs, $output);
$data = $this->getResourceList($apiDocs);
$this->dump($data, null, $input, $output);
return 0;
}
if (false != ($resource = $input->getOption('resource'))) {
$data = $this->getApiDeclaration($apiDocs, $resource, $output);
if (false !== ($resource = $input->getOption('resource'))) {
$data = $this->getApiDeclaration($apiDocs, $resource);
if (count($data['apis']) === 0) {
throw new \InvalidArgumentException(sprintf('Resource "%s" does not exist.', $resource));
}
@ -116,7 +105,7 @@ class SwaggerDumpCommand extends Command
return 0;
}
protected function dump(array $data, $resource, InputInterface $input, OutputInterface $output, $treatAsFile = true)
protected function dump(array $data, $resource, InputInterface $input, OutputInterface $output, $treatAsFile = true): void
{
$destination = $input->getArgument('destination');
@ -154,7 +143,7 @@ class SwaggerDumpCommand extends Command
}
protected function writeToFile($content, $file, OutputInterface $output, $message)
protected function writeToFile($content, $file, OutputInterface $output, $message): void
{
try {
$this->filesystem->dumpFile($file, $content);

View File

@ -11,9 +11,11 @@
namespace Nelmio\ApiDocBundle\Controller;
use Nelmio\ApiDocBundle\Extractor\ApiDocExtractor;
use Nelmio\ApiDocBundle\Formatter\HtmlFormatter;
use Nelmio\ApiDocBundle\Formatter\RequestAwareSwaggerFormatter;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Nelmio\ApiDocBundle\Formatter\SwaggerFormatter;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@ -22,23 +24,23 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class ApiDocController extends AbstractController
{
public function __construct(
private ContainerInterface $c
private readonly ApiDocExtractor $extractor,
private readonly HtmlFormatter $htmlFormatter,
private readonly SwaggerFormatter $swaggerFormatter
) {
}
public function index(Request $request, $view = ApiDoc::DEFAULT_VIEW)
{
$extractor = $this->c->get('nelmio_api_doc.extractor.api_doc_extractor');
$formatter = $this->c->get('nelmio_api_doc.formatter.html_formatter');
$apiVersion = $request->query->get('_version', null);
if ($apiVersion) {
$formatter->setVersion($apiVersion);
$extractedDoc = $extractor->allForVersion($apiVersion, $view);
$this->htmlFormatter->setVersion($apiVersion);
$extractedDoc = $this->extractor->allForVersion($apiVersion, $view);
} else {
$extractedDoc = $extractor->all($view);
$extractedDoc = $this->extractor->all($view);
}
$htmlContent = $formatter->format($extractedDoc);
$htmlContent = $this->htmlFormatter->format($extractedDoc);
return new Response($htmlContent, 200, array('Content-Type' => 'text/html'));
}
@ -46,8 +48,8 @@ class ApiDocController extends AbstractController
public function swagger(Request $request, $resource = null)
{
$docs = $this->c->get('nelmio_api_doc.extractor.api_doc_extractor')->all();
$formatter = new RequestAwareSwaggerFormatter($request, $this->c->get('nelmio_api_doc.formatter.swagger_formatter'));
$docs = $this->extractor->all();
$formatter = new RequestAwareSwaggerFormatter($request, $this->swaggerFormatter);
$spec = $formatter->format($docs, $resource ? '/' . $resource : null);

View File

@ -34,7 +34,7 @@ class AnnotationsProviderCompilerPass implements CompilerPassInterface
$container
->getDefinition('nelmio_api_doc.extractor.api_doc_extractor')
->replaceArgument(5, $annotationsProviders)
->replaceArgument(4, $annotationsProviders)
;
}
}

View File

@ -29,6 +29,6 @@ class ExtractorHandlerCompilerPass implements CompilerPassInterface
$container
->getDefinition('nelmio_api_doc.extractor.api_doc_extractor')
->replaceArgument(4, $handlers);
->replaceArgument(3, $handlers);
}
}

View File

@ -12,65 +12,36 @@
namespace Nelmio\ApiDocBundle\Extractor;
use Doctrine\Common\Annotations\Reader;
use Doctrine\Common\Util\ClassUtils;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Nelmio\ApiDocBundle\DataTypes;
use Nelmio\ApiDocBundle\Parser\ParserInterface;
use Nelmio\ApiDocBundle\Parser\PostParserInterface;
use Nelmio\ApiDocBundle\Util\DocCommentExtractor;
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouterInterface;
class ApiDocExtractor
{
const ANNOTATION_CLASS = 'Nelmio\\ApiDocBundle\\Annotation\\ApiDoc';
/**
* @var ContainerInterface
*/
protected $container;
/**
* @var RouterInterface
*/
protected $router;
/**
* @var Reader
*/
protected $reader;
/**
* @var DocCommentExtractor
*/
private $commentExtractor;
public const ANNOTATION_CLASS = ApiDoc::class;
/**
* @var ParserInterface[]
*/
protected $parsers = array();
protected array $parsers = [];
/**
* @var HandlerInterface[]
* @param HandlerInterface[] $handlers
* @param AnnotationsProviderInterface[] $annotationsProviders
* @param string[] $excludeSections
*/
protected $handlers;
/**
* @var AnnotationsProviderInterface[]
*/
protected $annotationsProviders;
public function __construct(ContainerInterface $container, RouterInterface $router, Reader $reader, DocCommentExtractor $commentExtractor, array $handlers, array $annotationsProviders)
{
$this->container = $container;
$this->router = $router;
$this->reader = $reader;
$this->commentExtractor = $commentExtractor;
$this->handlers = $handlers;
$this->annotationsProviders = $annotationsProviders;
public function __construct(
protected RouterInterface $router,
protected Reader $reader,
protected DocCommentExtractor $commentExtractor,
protected array $handlers,
protected array $annotationsProviders,
protected array $excludeSections
) {
}
/**
@ -131,7 +102,6 @@ class ApiDocExtractor
{
$array = array();
$resources = array();
$excludeSections = $this->container->getParameter('nelmio_api_doc.exclude_sections');
foreach ($routes as $route) {
if (!$route instanceof Route) {
@ -141,7 +111,7 @@ class ApiDocExtractor
if ($method = $this->getReflectionMethod($route->getDefault('_controller'))) {
$annotation = $this->reader->getMethodAnnotation($method, static::ANNOTATION_CLASS);
if (
$annotation && !in_array($annotation->getSection(), $excludeSections) &&
$annotation && !in_array($annotation->getSection(), $this->excludeSections) &&
(in_array($view, $annotation->getViews()) || (0 === count($annotation->getViews()) && $view === ApiDoc::DEFAULT_VIEW))
) {
if ($annotation->isResource()) {
@ -228,28 +198,6 @@ class ApiDocExtractor
if (preg_match('#(.+)::([\w]+)#', $controller, $matches)) {
$class = $matches[1];
$method = $matches[2];
} else {
if (preg_match('#(.+):([\w]+)#', $controller, $matches)) {
$controller = $matches[1];
$method = $matches[2];
}
if ($this->container->has($controller)) {
// BC SF < 3.0
if (method_exists($this->container, 'enterScope')) {
$this->container->enterScope('request');
$this->container->set('request', new Request(), 'request');
}
$class = ClassUtils::getRealClass(get_class($this->container->get($controller)));
// BC SF < 3.0
if (method_exists($this->container, 'enterScope')) {
$this->container->leaveScope('request');
}
if (!isset($method) && method_exists($class, '__invoke')) {
$method = '__invoke';
}
}
}
if (isset($class) && isset($method)) {

View File

@ -14,10 +14,8 @@ namespace Nelmio\ApiDocBundle\Extractor;
use Doctrine\Common\Annotations\Reader;
use Nelmio\ApiDocBundle\Util\DocCommentExtractor;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\RouterInterface;
/**
@ -28,39 +26,23 @@ use Symfony\Component\Routing\RouterInterface;
class CachingApiDocExtractor extends ApiDocExtractor
{
/**
* @var string
*/
private $cacheFile;
/**
* @var bool
*/
private $debug;
/**
* @param ContainerInterface $container
* @param RouterInterface $router
* @param Reader $reader
* @param DocCommentExtractor $commentExtractor
* @param array $handlers
* @param array $annotationsProviders
* @param HandlerInterface[] $handlers
* @param AnnotationsProviderInterface[] $annotationsProviders
* @param string[] $excludeSections
* @param string $cacheFile
* @param bool|false $debug
*/
public function __construct(
ContainerInterface $container,
RouterInterface $router,
Reader $reader,
DocCommentExtractor $commentExtractor,
array $handlers,
array $annotationsProviders,
$cacheFile,
$debug = false
array $excludeSections,
private string $cacheFile,
private bool $debug = false
) {
parent::__construct($container, $router, $reader, $commentExtractor, $handlers, $annotationsProviders);
$this->cacheFile = $cacheFile;
$this->debug = $debug;
parent::__construct($router, $reader, $commentExtractor, $handlers, $annotationsProviders, $excludeSections);
}
/**

View File

@ -6,12 +6,18 @@ services:
Nelmio\ApiDocBundle\Command\DumpCommand:
arguments:
$container: '@service_container'
$simpleFormatter: '@nelmio_api_doc.formatter.simple_formatter'
$markdownFormatter: '@nelmio_api_doc.formatter.markdown_formatter'
$htmlFormatter: '@nelmio_api_doc.formatter.html_formatter'
$apiDocExtractor: '@nelmio_api_doc.extractor.api_doc_extractor'
Nelmio\ApiDocBundle\Command\SwaggerDumpCommand:
arguments:
$container: '@service_container'
$extractor: '@nelmio_api_doc.extractor.api_doc_extractor'
$formatter: '@nelmio_api_doc.formatter.swagger_formatter'
Nelmio\ApiDocBundle\Controller\ApiDocController:
arguments:
$c: '@service_container'
$extractor: '@nelmio_api_doc.extractor.api_doc_extractor'
$htmlFormatter: '@nelmio_api_doc.formatter.html_formatter'
$swaggerFormatter: '@nelmio_api_doc.formatter.swagger_formatter'

View File

@ -27,12 +27,12 @@
</service>
<service id="nelmio_api_doc.extractor.api_doc_extractor" class="%nelmio_api_doc.extractor.api_doc_extractor.class%" public="true">
<argument type="service" id="service_container" />
<argument type="service" id="router" />
<argument type="service" id="annotation_reader" />
<argument type="service" id="nelmio_api_doc.doc_comment_extractor" />
<argument type="collection" />
<argument type="collection" />
<argument>%nelmio_api_doc.exclude_sections%</argument>
</service>
<service id="nelmio_api_doc.form.extension.description_form_type_extension" class="%nelmio_api_doc.form.extension.description_form_type_extension.class%">