mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-02 15:51:48 +03:00
Introduced ApiBundle
This commit is contained in:
commit
0dc8883e09
61
Annotation/ApiDoc.php
Normal file
61
Annotation/ApiDoc.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Nelmio\ApiBundle\Annotation;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class ApiDoc
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $filters = array();
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $formType = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $comment = null;
|
||||
|
||||
public function __construct(array $data)
|
||||
{
|
||||
if (isset($data['formType'])) {
|
||||
$this->formType = $data['formType'];
|
||||
} else if (isset($data['filters'])) {
|
||||
foreach ($data['filters'] as $filter) {
|
||||
if (!isset($filter['name'])) {
|
||||
throw new \InvalidArgumentException('A "filter" element has to contain a "name" attribute');
|
||||
}
|
||||
|
||||
$name = $filter['name'];
|
||||
unset($filter['name']);
|
||||
|
||||
$this->filters[$name] = $filter;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($data['comment'])) {
|
||||
$this->comment = $data['comment'];
|
||||
}
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return $this->filters;
|
||||
}
|
||||
|
||||
public function getFormType()
|
||||
{
|
||||
return $this->formType;
|
||||
}
|
||||
|
||||
public function getComment()
|
||||
{
|
||||
return $this->comment;
|
||||
}
|
||||
}
|
21
DependencyInjection/NelmioApiExtension.php
Normal file
21
DependencyInjection/NelmioApiExtension.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Nelmio\ApiBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
|
||||
class NelmioApiExtension extends Extension
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load(array $configs, ContainerBuilder $container)
|
||||
{
|
||||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load('request_listener.xml');
|
||||
$loader->load('services.xml');
|
||||
}
|
||||
}
|
57
EventListener/RequestListener.php
Normal file
57
EventListener/RequestListener.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Nelmio\ApiBundle\EventListener;
|
||||
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
use Nelmio\ApiBundle\Formatter\ApiDocFormatter;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
|
||||
class RequestListener
|
||||
{
|
||||
protected $annotationClass = 'Nelmio\\ApiBundle\\Annotation\\ApiDoc';
|
||||
|
||||
protected $reader;
|
||||
|
||||
protected $router;
|
||||
|
||||
protected $formatter;
|
||||
|
||||
public function __construct(Reader $reader, RouterInterface $router, ApiDocFormatter $formatter)
|
||||
{
|
||||
$this->reader = $reader;
|
||||
$this->router = $router;
|
||||
$this->formatter = $formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onKernelRequest(GetResponseEvent $event)
|
||||
{
|
||||
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$request = $event->getRequest();
|
||||
|
||||
if (!$request->get('_doc')) {
|
||||
return;
|
||||
}
|
||||
|
||||
preg_match('#(.+)::([\w]+)#', $request->get('_controller'), $matches);
|
||||
$method = new \ReflectionMethod($matches[1], $matches[2]);
|
||||
$route = $request->get('_route');
|
||||
|
||||
if ($annot = $this->reader->getMethodAnnotation($method, $this->annotationClass)) {
|
||||
if ($route = $this->router->getRouteCollection()->get($route)) {
|
||||
$result = $this->formatter->format($annot, $route);
|
||||
|
||||
$event->setResponse(new JsonResponse($result));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
53
Formatter/ApiDocFormatter.php
Normal file
53
Formatter/ApiDocFormatter.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Nelmio\ApiBundle\Formatter;
|
||||
|
||||
use Nelmio\ApiBundle\Annotation\ApiDoc;
|
||||
use Nelmio\ApiBundle\Parser\FormTypeParser;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
class ApiDocFormatter
|
||||
{
|
||||
/**
|
||||
* @var \Nelmio\ApiBundle\Parser\FormTypeParser
|
||||
*/
|
||||
protected $parser;
|
||||
|
||||
public function __construct(FormTypeParser $parser)
|
||||
{
|
||||
$this->parser = $parser;
|
||||
}
|
||||
|
||||
public function format(ApiDoc $apiDoc, Route $route)
|
||||
{
|
||||
$method = $route->getRequirement('_method');
|
||||
$data = array(
|
||||
'method' => $method,
|
||||
'uri' => $route->compile()->getPattern(),
|
||||
'requirements' => $route->compile()->getRequirements(),
|
||||
);
|
||||
|
||||
unset($data['requirements']['_method']);
|
||||
|
||||
if (null !== $formType = $apiDoc->getFormType()) {
|
||||
$data['parameters'] = $this->parser->parse(new $formType());
|
||||
|
||||
if ('PUT' === $method) {
|
||||
// All parameters are optional with PUT (update)
|
||||
array_walk($data['parameters'], function($val, $key) use (&$data) {
|
||||
$data['parameters'][$key]['is_required'] = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ($filters = $apiDoc->getFilters()) {
|
||||
$data['filters'] = $filters;
|
||||
}
|
||||
|
||||
if ($comment = $apiDoc->getComment()) {
|
||||
$data['comment'] = $comment;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
9
NelmioApiBundle.php
Normal file
9
NelmioApiBundle.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Nelmio\ApiBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
class NelmioApiBundle extends Bundle
|
||||
{
|
||||
}
|
53
Parser/FormTypeParser.php
Normal file
53
Parser/FormTypeParser.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Nelmio\ApiBundle\Parser;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilder;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
|
||||
class FormTypeParser
|
||||
{
|
||||
protected $formFactory;
|
||||
|
||||
protected $mapTypes = array(
|
||||
'text' => 'string',
|
||||
'date' => 'date',
|
||||
'datetime' => 'datetime',
|
||||
'checkbox' => 'boolean',
|
||||
'time' => 'time',
|
||||
'number' => 'float',
|
||||
'integer' => 'int',
|
||||
'textarea' => 'string',
|
||||
);
|
||||
|
||||
public function __construct(FormFactoryInterface $formFactory)
|
||||
{
|
||||
$this->formFactory = $formFactory;
|
||||
}
|
||||
|
||||
public function parse(AbstractType $type)
|
||||
{
|
||||
$builder = $this->formFactory->createBuilder($type);
|
||||
|
||||
$parameters = array();
|
||||
foreach ($builder->all() as $name => $child) {
|
||||
$b = $builder->create($name, $child['type'], $child['options']);
|
||||
|
||||
$bestType = '';
|
||||
foreach ($b->getTypes() as $type) {
|
||||
if (isset($this->mapTypes[$type->getName()])) {
|
||||
$bestType = $this->mapTypes[$type->getName()];
|
||||
}
|
||||
}
|
||||
|
||||
$parameters[] = array(
|
||||
'name' => $name,
|
||||
'type' => $bestType,
|
||||
'is_required' => $b->getRequired()
|
||||
);
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
}
|
19
Resources/config/request_listener.xml
Normal file
19
Resources/config/request_listener.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?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">
|
||||
|
||||
<parameters>
|
||||
<parameter key="nelmio.api.event_listener.request.class">Nelmio\ApiBundle\EventListener\RequestListener</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="nelmio.api.event_listener.request" class="%nelmio.api.event_listener.request.class%">
|
||||
<argument type="service" id="annotation_reader" />
|
||||
<argument type="service" id="router" />
|
||||
<argument type="service" id="nelmio.api.formatter.api_doc_formatter" />
|
||||
<tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" />
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</container>
|
20
Resources/config/services.xml
Normal file
20
Resources/config/services.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?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">
|
||||
|
||||
<parameters>
|
||||
<parameter key="nelmio.api.parser.form_type_parser.class">Nelmio\ApiBundle\Parser\FormTypeParser</parameter>
|
||||
<parameter key="nelmio.api.formatter.api_doc_formatter.class">Nelmio\ApiBundle\Formatter\ApiDocFormatter</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="nelmio.api.parser.form_type_parser" class="%nelmio.api.parser.form_type_parser.class%">
|
||||
<argument type="service" id="form.factory" />
|
||||
</service>
|
||||
<service id="nelmio.api.formatter.api_doc_formatter" class="%nelmio.api.formatter.api_doc_formatter.class%">
|
||||
<argument type="service" id="nelmio.api.parser.form_type_parser" />
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</container>
|
Loading…
x
Reference in New Issue
Block a user