add api docs via swagger and use jms serializer
This commit is contained in:
parent
14755d8343
commit
49538b037d
@ -7,10 +7,12 @@
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-json": "*",
|
||||
"jms/serializer-bundle": "^3.5",
|
||||
"nelmio/api-doc-bundle": "^3.5",
|
||||
"nesbot/carbon": "^1.33",
|
||||
"ocramius/proxy-manager": "^2.0",
|
||||
"sensio/framework-extra-bundle": "^5.2",
|
||||
"symfony/asset": "*",
|
||||
"symfony/asset": "4.1.*",
|
||||
"symfony/console": "*",
|
||||
"symfony/flex": "^1.1",
|
||||
"symfony/framework-bundle": "*",
|
||||
@ -33,7 +35,7 @@
|
||||
"sort-packages": true,
|
||||
"secure-http": false,
|
||||
"platform": {
|
||||
"php": "7.1.12"
|
||||
"php": "7.3.12"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
2499
composer.lock
generated
2499
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -9,4 +9,6 @@ return [
|
||||
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
||||
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||
Nelmio\ApiDocBundle\NelmioApiDocBundle::class => ['all' => true],
|
||||
JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true],
|
||||
];
|
||||
|
7
config/packages/dev/jms_serializer.yaml
Normal file
7
config/packages/dev/jms_serializer.yaml
Normal file
@ -0,0 +1,7 @@
|
||||
jms_serializer:
|
||||
visitors:
|
||||
json_serialization:
|
||||
options:
|
||||
- JSON_PRETTY_PRINT
|
||||
- JSON_UNESCAPED_SLASHES
|
||||
- JSON_PRESERVE_ZERO_FRACTION
|
13
config/packages/jms_serializer.yaml
Normal file
13
config/packages/jms_serializer.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
jms_serializer:
|
||||
visitors:
|
||||
xml_serialization:
|
||||
format_output: '%kernel.debug%'
|
||||
# metadata:
|
||||
# auto_detection: false
|
||||
# directories:
|
||||
# any-name:
|
||||
# namespace_prefix: "My\\FooBundle"
|
||||
# path: "@MyFooBundle/Resources/config/serializer"
|
||||
# another-name:
|
||||
# namespace_prefix: "My\\BarBundle"
|
||||
# path: "@MyBarBundle/Resources/config/serializer"
|
19
config/packages/nelmio_api_doc.yaml
Normal file
19
config/packages/nelmio_api_doc.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
nelmio_api_doc:
|
||||
documentation:
|
||||
info:
|
||||
title: Czy Dojadę?
|
||||
version: 0.1.0
|
||||
parameters:
|
||||
provider:
|
||||
in: path
|
||||
name: provider
|
||||
type: string
|
||||
description: Data provider identificator, e.g. trojmiasto for ZTM Gdańsk.
|
||||
required: true
|
||||
|
||||
areas:
|
||||
path_patterns:
|
||||
- ^/[^\/]+/api(?!/doc$) # Accepts routes under /api except /api/doc
|
||||
|
||||
|
||||
|
6
config/packages/prod/jms_serializer.yaml
Normal file
6
config/packages/prod/jms_serializer.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
jms_serializer:
|
||||
visitors:
|
||||
json_serialization:
|
||||
options:
|
||||
- JSON_UNESCAPED_SLASHES
|
||||
- JSON_PRESERVE_ZERO_FRACTION
|
12
config/routes/nelmio_api_doc.yaml
Normal file
12
config/routes/nelmio_api_doc.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
# Expose your documentation as JSON swagger compliant
|
||||
app.swagger:
|
||||
path: /api/doc.json
|
||||
methods: GET
|
||||
defaults: { _controller: nelmio_api_doc.controller.swagger }
|
||||
|
||||
## Requires the Asset component and the Twig bundle
|
||||
## $ composer require twig asset
|
||||
app.swagger_ui:
|
||||
path: /api/doc
|
||||
methods: GET
|
||||
defaults: { _controller: nelmio_api_doc.controller.swagger_ui }
|
@ -42,6 +42,15 @@ services:
|
||||
assets.modified_time_version_strategy:
|
||||
class: App\Asset\ModifiedTimeVersionStrategy
|
||||
|
||||
#eerialziser
|
||||
jms_serializer.serialized_name_annotation_strategy:
|
||||
class: JMS\Serializer\Naming\SerializedNameAnnotationStrategy
|
||||
arguments:
|
||||
- '@jms_serializer.identical_property_naming_strategy'
|
||||
|
||||
App\Serialization\CarbonHandler:
|
||||
arguments: ['@jms_serializer.datetime_handler']
|
||||
|
||||
#proxy configuration
|
||||
proxy.locator:
|
||||
class: 'ProxyManager\FileLocator\FileLocator'
|
||||
|
@ -32,6 +32,7 @@ if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? false) {
|
||||
Request::setTrustedHosts(explode(',', $trustedHosts));
|
||||
}
|
||||
|
||||
\Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredName('alias');
|
||||
$kernel = new Kernel($env, $debug);
|
||||
$request = Request::createFromGlobals();
|
||||
$response = $kernel->handle($request);
|
||||
|
@ -35,10 +35,10 @@ export class FinderComponent extends Vue {
|
||||
|
||||
this.state = 'fetching';
|
||||
|
||||
const response = await fetch(urls.prepare(urls.stops.search, { name: this.filter }));
|
||||
const response = await fetch(urls.prepare(urls.stops.grouped, { name: this.filter }));
|
||||
|
||||
if (response.ok) {
|
||||
this.found = await response.json();
|
||||
this.found = (await response.json()).reduce((accumulator, { name, stops }) => Object.assign(accumulator, { [name]: stops }), {});
|
||||
this.state = 'ready';
|
||||
} else {
|
||||
this.state = 'error';
|
||||
|
@ -51,10 +51,10 @@ export default {
|
||||
departures: `${base}/departures`,
|
||||
messages: `${base}/messages`,
|
||||
stops: {
|
||||
all: `${base}/stops`,
|
||||
search: `${base}/stops/search`,
|
||||
get: `${base}/stops/{id}`,
|
||||
tracks: `${base}/stops/{id}/tracks`
|
||||
all: `${base}/stops`,
|
||||
grouped: `${base}/stops/groups`,
|
||||
get: `${base}/stops/{id}`,
|
||||
tracks: `${base}/stops/{id}/tracks`
|
||||
},
|
||||
prepare: (url: string, params: UrlParams = { }) => prepare(url, Object.assign({}, { provider: window['data'].provider }, params))
|
||||
}
|
106
ruleset.xml
Normal file
106
ruleset.xml
Normal file
@ -0,0 +1,106 @@
|
||||
<?xml version="1.0"?>
|
||||
<rulset name="Kadet.CzyDojade">
|
||||
<description>Czy Dojadę ruleset</description>
|
||||
|
||||
<arg name="colors"/>
|
||||
<arg name="parallel" value="75"/>
|
||||
|
||||
<rule ref="Internal.Tokenizer.Exception">
|
||||
<type>error</type>
|
||||
</rule>
|
||||
|
||||
<!-- PSR 2 -->
|
||||
<rule ref="PSR2">
|
||||
<exclude name="PSR2.Namespaces"/>
|
||||
<exclude name="PSR2.Classes.PropertyDeclaration.Underscore"/>
|
||||
<exclude name="PSR2.Classes.MethodDeclaration.Underscore"/>
|
||||
</rule>
|
||||
|
||||
<!-- No More Than 2 lines -->
|
||||
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace">
|
||||
<properties>
|
||||
<property name="ignoreBlankLines" value="false"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace.StartFile">
|
||||
<severity>10</severity>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace.EndFile">
|
||||
<severity>10</severity>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace.EmptyLines">
|
||||
<severity>5</severity>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.WhiteSpace.OperatorSpacing">
|
||||
<properties>
|
||||
<property name="ignoreNewlines" value="true"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!-- Make this sniff more sensitive to commented out code blocks. -->
|
||||
<rule ref="Squiz.PHP.CommentedOutCode">
|
||||
<properties>
|
||||
<property name="maxPercentage" value="60"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!-- Line length -->
|
||||
<rule ref="Generic.Files.LineLength">
|
||||
<properties>
|
||||
<property name="lineLimit" value="120"/>
|
||||
<property name="absoluteLineLimit" value="180"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!-- Linus rule -->
|
||||
<rule ref="Generic.Metrics.NestingLevel">
|
||||
<properties>
|
||||
<property name="nestingLevel" value="3"/>
|
||||
<property name="absoluteNestingLevel" value="6"/>
|
||||
</properties>
|
||||
<severity>50</severity>
|
||||
</rule>
|
||||
|
||||
<rule ref="Generic.Strings.UnnecessaryStringConcat">
|
||||
<properties>
|
||||
<property name="allowMultiline" value="true"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.Arrays.ArrayDeclaration">
|
||||
<exclude name="Squiz.Arrays.ArrayDeclaration.KeyNotAligned"/>
|
||||
<exclude name="Squiz.Arrays.ArrayDeclaration.ValueNotAligned"/>
|
||||
<exclude name="Squiz.Arrays.ArrayDeclaration.CloseBraceNotAligned"/>
|
||||
<exclude name="Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed"/>
|
||||
</rule>
|
||||
|
||||
<rule ref="Generic.Arrays.ArrayIndent"/>
|
||||
|
||||
<rule ref="Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed">
|
||||
<severity>0</severity>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.Arrays.ArrayDeclaration.MultiLineNotAllowed">
|
||||
<severity>1</severity>
|
||||
</rule>
|
||||
|
||||
<!-- Ban some functions -->
|
||||
<rule ref="Generic.PHP.ForbiddenFunctions">
|
||||
<properties>
|
||||
<property name="forbiddenFunctions" type="array">
|
||||
<element key="sizeof" value="count"/>
|
||||
<element key="delete" value="unset"/>
|
||||
<element key="print" value="echo"/>
|
||||
<element key="is_null" value="null"/>
|
||||
<element key="create_function" value="null"/>
|
||||
</property>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!-- a feee -->
|
||||
<rule ref="Generic.Arrays.DisallowLongArraySyntax"/>
|
||||
</rulset>
|
@ -7,6 +7,8 @@ use App\Controller\Controller;
|
||||
use App\Model\Departure;
|
||||
use App\Provider\DepartureRepository;
|
||||
use App\Provider\StopRepository;
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use Swagger\Annotations as SWG;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
@ -18,17 +20,22 @@ use Symfony\Component\Routing\Annotation\Route;
|
||||
class DeparturesController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/{id}")
|
||||
* @Route("/{stop}", methods={"GET"})
|
||||
* @SWG\Response(
|
||||
* description="Gets departures from particular stop.",
|
||||
* response=200,
|
||||
* @SWG\Schema(type="array", @SWG\Items(ref=@Model(type=Departure::class)))
|
||||
* )
|
||||
*/
|
||||
public function stop(DepartureRepository $departures, StopRepository $stops, $id)
|
||||
public function stop(DepartureRepository $departures, StopRepository $stops, $stop)
|
||||
{
|
||||
$stop = $stops->getById($id);
|
||||
$stop = $stops->getById($stop);
|
||||
|
||||
return $this->json($departures->getForStop($stop));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/")
|
||||
* @Route("/", methods={"GET"})
|
||||
*/
|
||||
public function stops(DepartureRepository $departures, StopRepository $stops, Request $request)
|
||||
{
|
||||
|
@ -5,14 +5,20 @@ namespace App\Controller\Api\v1;
|
||||
|
||||
use App\Controller\Controller;
|
||||
use App\Provider\MessageRepository;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use Swagger\Annotations as SWG;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use App\Model\Message;
|
||||
|
||||
/**
|
||||
* @Route("/messages")
|
||||
* @SWG\Tag(name="Messages")
|
||||
* @SWG\Parameter(ref="#/parameters/provider")
|
||||
*/
|
||||
class MessagesController extends Controller
|
||||
{
|
||||
/**
|
||||
* @SWG\Response(response=200, description="Returns all messages from carrier at given moment.", @SWG\Schema(type="array", @SWG\Items(ref=@Model(type=Message::class))))
|
||||
* @Route("/", methods={"GET"})
|
||||
*/
|
||||
public function all(MessageRepository $messages)
|
||||
|
@ -5,9 +5,12 @@ namespace App\Controller\Api\v1;
|
||||
|
||||
use App\Controller\Controller;
|
||||
use App\Model\Stop;
|
||||
use App\Model\StopGroup;
|
||||
use App\Provider\StopRepository;
|
||||
use App\Provider\TrackRepository;
|
||||
use App\Service\Proxy\ReferenceFactory;
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use Swagger\Annotations as SWG;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
@ -16,34 +19,95 @@ use Symfony\Component\Routing\Annotation\Route;
|
||||
*
|
||||
* @package App\Controller
|
||||
* @Route("/stops")
|
||||
*
|
||||
* @SWG\Tag(name="stops")
|
||||
* @SWG\Parameter(ref="#/parameters/provider")
|
||||
*/
|
||||
class StopsController extends Controller
|
||||
{
|
||||
/**
|
||||
* @SWG\Response(
|
||||
* response=200,
|
||||
* description="Returns all stops for specific provider, e.g. ZTM Gdańsk.",
|
||||
* @SWG\Schema(type="array", @SWG\Items(ref=@Model(type=Stop::class)))
|
||||
* )
|
||||
*
|
||||
* @SWG\Parameter(
|
||||
* name="id",
|
||||
* in="query",
|
||||
* type="array",
|
||||
* description="Stop identificators to retrieve at once. Can be used to bulk load data. If not specified will return all data.",
|
||||
* @SWG\Items(type="string")
|
||||
* )
|
||||
*
|
||||
* @Route("/", methods={"GET"})
|
||||
*/
|
||||
public function index(Request $request, StopRepository $stops)
|
||||
{
|
||||
$result = $request->query->has('id')
|
||||
? $stops->getManyById($request->query->get('id'))
|
||||
: $stops->getAllGroups();
|
||||
switch (true) {
|
||||
case $request->query->has('id'):
|
||||
$result = $stops->getManyById($request->query->get('id'));
|
||||
break;
|
||||
|
||||
case $request->query->has('name'):
|
||||
$result = $stops->findGroupsByName($request->query->get('name'));
|
||||
break;
|
||||
|
||||
default:
|
||||
$result = $stops->getAllGroups();
|
||||
}
|
||||
|
||||
return $this->json($result->all());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/search", methods={"GET"})
|
||||
* @SWG\Response(
|
||||
* response=200,
|
||||
* description="Returns grouped stops for specific provider, e.g. ZTM Gdańsk.",
|
||||
* @SWG\Schema(type="array", @SWG\Items(ref=@Model(type=StopGroup::class)))
|
||||
* )
|
||||
*
|
||||
* @SWG\Parameter(
|
||||
* name="name",
|
||||
* in="query",
|
||||
* type="string",
|
||||
* description="Part of the stop name to search for.",
|
||||
* )
|
||||
*
|
||||
* @Route("/groups", methods={"GET"})
|
||||
*/
|
||||
public function find(Request $request, StopRepository $stops)
|
||||
public function groups(Request $request, StopRepository $stops)
|
||||
{
|
||||
$result = $request->query->has('name')
|
||||
? $stops->findGroupsByName($request->query->get('name'))
|
||||
: $stops->getAllGroups();
|
||||
switch (true) {
|
||||
case $request->query->has('id'):
|
||||
$result = $stops->getManyById($request->query->get('id'));
|
||||
break;
|
||||
|
||||
case $request->query->has('name'):
|
||||
$result = $stops->findGroupsByName($request->query->get('name'));
|
||||
break;
|
||||
|
||||
default:
|
||||
$result = $stops->getAllGroups();
|
||||
}
|
||||
|
||||
return $this->json($result->all());
|
||||
}
|
||||
|
||||
/**
|
||||
* @SWG\Response(
|
||||
* response=200,
|
||||
* description="Returns specific stop referenced via identificator.",
|
||||
* @SWG\Schema(ref=@Model(type=Stop::class))
|
||||
* )
|
||||
*
|
||||
* @SWG\Parameter(
|
||||
* name="id",
|
||||
* in="path",
|
||||
* type="string",
|
||||
* description="Stop identificator as provided by data provider."
|
||||
* )
|
||||
*
|
||||
* @Route("/{id}", methods={"GET"})
|
||||
*/
|
||||
public function one(Request $request, StopRepository $stops, $id)
|
||||
|
@ -4,10 +4,13 @@ namespace App\Controller\Api\v1;
|
||||
|
||||
use App\Controller\Controller;
|
||||
use App\Model\Stop;
|
||||
use App\Model\Track;
|
||||
use App\Provider\TrackRepository;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use Swagger\Annotations as SWG;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use function App\Functions\encapsulate;
|
||||
|
||||
/**
|
||||
@ -16,7 +19,12 @@ use function App\Functions\encapsulate;
|
||||
class TracksController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/")
|
||||
* @SWG\Response(
|
||||
* response=200,
|
||||
* description="Returns all tracks for specific provider, e.g. ZTM Gdańsk.",
|
||||
* )
|
||||
* @SWG\Tag(name="tracks")
|
||||
* @Route("/", methods={"GET"})
|
||||
*/
|
||||
public function index(Request $request, TrackRepository $repository)
|
||||
{
|
||||
@ -28,7 +36,12 @@ class TracksController extends Controller
|
||||
case $request->query->has('id'):
|
||||
return $this->byId($request, $repository);
|
||||
default:
|
||||
throw new BadRequestHttpException(sprintf('At least one parameter of %s must be set.', implode(', ', ['stop', 'line', 'id'])));
|
||||
throw new BadRequestHttpException(
|
||||
sprintf(
|
||||
'At least one parameter of %s must be set.',
|
||||
implode(', ', ['stop', 'line', 'id'])
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,21 @@
|
||||
namespace App\Controller;
|
||||
|
||||
|
||||
use JMS\Serializer\SerializerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller as SymfonyController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
|
||||
abstract class Controller extends SymfonyController
|
||||
{
|
||||
private $serializer;
|
||||
|
||||
public function __construct(SerializerInterface $serializer)
|
||||
{
|
||||
$this->serializer = $serializer;
|
||||
}
|
||||
|
||||
protected function json($data, int $status = 200, array $headers = [], array $context = []): JsonResponse
|
||||
{
|
||||
return new JsonResponse($this->serializer->serialize($data, "json"), $status, $headers, true);
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ class MainController extends Controller
|
||||
$state = json_decode($request->query->get('state', '{}'), true) ?: [];
|
||||
$state = array_merge([
|
||||
'version' => 1,
|
||||
'stops' => []
|
||||
'stops' => [],
|
||||
], $state);
|
||||
|
||||
return $this->render('app.html.twig', compact('state', 'provider'));
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App;
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Model;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
|
||||
class Departure implements Fillable
|
||||
{
|
||||
@ -104,6 +105,7 @@ class Departure implements Fillable
|
||||
$this->stop = $stop;
|
||||
}
|
||||
|
||||
/** @Serializer\VirtualProperty() */
|
||||
public function getDelay(): ?int
|
||||
{
|
||||
return $this->getEstimated()
|
||||
|
@ -3,6 +3,8 @@
|
||||
namespace App\Model;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
use Swagger\Annotations as SWG;
|
||||
|
||||
class Message implements Fillable
|
||||
{
|
||||
@ -14,18 +16,23 @@ class Message implements Fillable
|
||||
|
||||
/**
|
||||
* Message content.
|
||||
* @Serializer\Type("string")
|
||||
* @var string
|
||||
*/
|
||||
private $message;
|
||||
|
||||
/**
|
||||
* Message type, see TYPE_* constants
|
||||
* @Serializer\Type("string")
|
||||
* @SWG\Property(type="string", enum={ Message::TYPE_INFO, Message::TYPE_BREAKDOWN, Message::TYPE_UNKNOWN })
|
||||
* @var string
|
||||
*/
|
||||
private $type = self::TYPE_UNKNOWN;
|
||||
|
||||
/**
|
||||
* Message validity time span start
|
||||
* @Serializer\Type("Carbon")
|
||||
* @SWG\Property(type="string")
|
||||
* @var Carbon|null
|
||||
*/
|
||||
private $validFrom;
|
||||
@ -33,6 +40,8 @@ class Message implements Fillable
|
||||
/**
|
||||
* Message validity time span end
|
||||
* @var Carbon|null
|
||||
* @Serializer\Type("Carbon")
|
||||
* @SWG\Property(type="string")
|
||||
*/
|
||||
private $validTo;
|
||||
|
||||
|
@ -2,11 +2,15 @@
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use Swagger\Annotations as SWG;
|
||||
|
||||
trait ReferableTrait
|
||||
{
|
||||
/**
|
||||
* Identifier coming from provider service
|
||||
* @var string
|
||||
*
|
||||
* @SWG\Property(example="1045")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
|
@ -2,11 +2,18 @@
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
use Swagger\Annotations as SWG;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizableInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
use Tightenco\Collect\Support\Arr;
|
||||
|
||||
/**
|
||||
* Class Stop
|
||||
*
|
||||
* @package App\Model
|
||||
*/
|
||||
class Stop implements Referable, Fillable, NormalizableInterface
|
||||
{
|
||||
use FillTrait, ReferableTrait;
|
||||
@ -14,36 +21,45 @@ class Stop implements Referable, Fillable, NormalizableInterface
|
||||
/**
|
||||
* Stop name
|
||||
* @var string
|
||||
* @SWG\Property(example="Jasień PKM")
|
||||
* @Serializer\Type("string")
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* Optional stop description, should not be longer than 255 chars
|
||||
* Optional stop description, should not be longer than 255 chars.
|
||||
* @var string|null
|
||||
* @Serializer\Type("string")
|
||||
*/
|
||||
private $description;
|
||||
|
||||
/**
|
||||
* Optional stop variant - for example number of shed
|
||||
* Optional stop variant - for example number of shed.
|
||||
* @var string|null
|
||||
* @SWG\Property(example="01")
|
||||
* @Serializer\Type("string")
|
||||
*/
|
||||
private $variant;
|
||||
|
||||
/**
|
||||
* Latitude of stop
|
||||
* @var float|null
|
||||
* @Serializer\Exclude()
|
||||
*/
|
||||
private $latitude;
|
||||
|
||||
/**
|
||||
* Longitude of stop
|
||||
* @var float|null
|
||||
* @Serializer\Exclude()
|
||||
*/
|
||||
private $longitude;
|
||||
|
||||
/**
|
||||
* True if stop is available only on demand
|
||||
* @var bool
|
||||
* @Serializer\Type("bool")
|
||||
* @SWG\Property(example=false)
|
||||
*/
|
||||
private $onDemand = false;
|
||||
|
||||
@ -77,7 +93,6 @@ class Stop implements Referable, Fillable, NormalizableInterface
|
||||
$this->variant = $variant;
|
||||
}
|
||||
|
||||
/** @Groups({"hidden"}) */
|
||||
public function getLatitude(): ?float
|
||||
{
|
||||
return $this->latitude;
|
||||
@ -88,7 +103,6 @@ class Stop implements Referable, Fillable, NormalizableInterface
|
||||
$this->latitude = $latitude;
|
||||
}
|
||||
|
||||
/** @Groups({"hidden"}) */
|
||||
public function getLongitude(): ?float
|
||||
{
|
||||
return $this->longitude;
|
||||
@ -99,6 +113,12 @@ class Stop implements Referable, Fillable, NormalizableInterface
|
||||
$this->longitude = $longitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
* @Serializer\VirtualProperty()
|
||||
* @Serializer\Type("array<string>")
|
||||
* @SWG\Property(type="array", @SWG\Items(type="string", example="1"))
|
||||
*/
|
||||
public function getLocation(): array
|
||||
{
|
||||
return [ $this->latitude, $this->longitude ];
|
||||
@ -106,7 +126,7 @@ class Stop implements Referable, Fillable, NormalizableInterface
|
||||
|
||||
public function setLocation(array $location)
|
||||
{
|
||||
list($this->latitude, $this->longitude) = $location;
|
||||
[$this->latitude, $this->longitude] = $location;
|
||||
}
|
||||
|
||||
public function isOnDemand(): bool
|
||||
|
@ -2,16 +2,42 @@
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use Swagger\Annotations as SWG;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
use App\Model\Stop;
|
||||
|
||||
class StopGroup extends Collection
|
||||
/**
|
||||
* Class StopGroup
|
||||
*
|
||||
* @package App\Model
|
||||
*/
|
||||
class StopGroup
|
||||
{
|
||||
/**
|
||||
* Name of stop group
|
||||
* Name of stop group.
|
||||
* @SWG\Property(example="Jasień PKM")
|
||||
* @Serializer\Type("string")
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* All stops in group.
|
||||
* @var Collection|Stop[]
|
||||
* @SWG\Property(
|
||||
* type="array",
|
||||
* @SWG\Items(ref=@Model(type=Stop::class))
|
||||
* )
|
||||
*/
|
||||
private $stops;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->stops = new Collection();
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
@ -21,4 +47,14 @@ class StopGroup extends Collection
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function setStops($stops)
|
||||
{
|
||||
$this->stops = new Collection($stops);
|
||||
}
|
||||
|
||||
public function getStops()
|
||||
{
|
||||
return $this->stops;
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use Swagger\Annotations as SWG;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
|
||||
class Track implements Referable, Fillable
|
||||
@ -29,11 +30,11 @@ class Track implements Referable, Fillable
|
||||
|
||||
/**
|
||||
* Stops in track
|
||||
* @var Collection
|
||||
* @var Stop[]|Collection
|
||||
* @SWG\Property(type="Stop")
|
||||
*/
|
||||
private $stops;
|
||||
|
||||
|
||||
/**
|
||||
* Track constructor.
|
||||
*/
|
||||
|
@ -56,11 +56,13 @@ class GenericStopRepository extends DatabaseRepository implements StopRepository
|
||||
{
|
||||
return $stops->groupBy(function (Stop $stop) {
|
||||
return $stop->getName();
|
||||
})->map(function ($group, $key) {
|
||||
$group = new StopGroup($group);
|
||||
})->map(function ($stops, $key) {
|
||||
$group = new StopGroup();
|
||||
|
||||
$group->setName($key);
|
||||
$group->setStops($stops);
|
||||
|
||||
return $group;
|
||||
});
|
||||
})->values();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
90
src/Serialization/CarbonHandler.php
Normal file
90
src/Serialization/CarbonHandler.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Serialization;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use JMS\Serializer\DeserializationContext;
|
||||
use JMS\Serializer\GraphNavigatorInterface;
|
||||
use JMS\Serializer\Handler\DateHandler;
|
||||
use JMS\Serializer\Handler\SubscribingHandlerInterface;
|
||||
use JMS\Serializer\SerializationContext;
|
||||
use JMS\Serializer\Visitor\DeserializationVisitorInterface;
|
||||
use JMS\Serializer\Visitor\SerializationVisitorInterface;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class LaravelCollectionHandler
|
||||
*
|
||||
* Shamelessly copied from https://github.com/schmittjoh/serializer/blob/master/src/Handler/ArrayCollectionHandler.php
|
||||
*
|
||||
* @package App\Serialization
|
||||
*/
|
||||
final class CarbonHandler implements SubscribingHandlerInterface
|
||||
{
|
||||
private $dateTimeHandler;
|
||||
|
||||
public function __construct(DateHandler $dateHandler)
|
||||
{
|
||||
$this->dateTimeHandler = $dateHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribingMethods()
|
||||
{
|
||||
$methods = [];
|
||||
$formats = ['json', 'xml', 'yml'];
|
||||
|
||||
$collectionTypes = [
|
||||
'Carbon',
|
||||
Carbon::class,
|
||||
];
|
||||
|
||||
foreach ($collectionTypes as $type) {
|
||||
foreach ($formats as $format) {
|
||||
$methods[] = [
|
||||
'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
|
||||
'type' => $type,
|
||||
'format' => $format,
|
||||
'method' => 'serialize',
|
||||
];
|
||||
|
||||
$methods[] = [
|
||||
'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
|
||||
'type' => $type,
|
||||
'format' => $format,
|
||||
'method' => 'deserialize',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|\ArrayObject
|
||||
*/
|
||||
public function serialize(
|
||||
SerializationVisitorInterface $visitor,
|
||||
Carbon $date,
|
||||
array $type,
|
||||
SerializationContext $context
|
||||
) {
|
||||
return $this->dateTimeHandler->serializeDateTime($visitor, $date, $type, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
*/
|
||||
public function deserialize(
|
||||
DeserializationVisitorInterface $visitor,
|
||||
$data,
|
||||
array $type,
|
||||
DeserializationContext $context
|
||||
): Collection {
|
||||
return new Collection($visitor->visitArray($data, $type));
|
||||
}
|
||||
}
|
87
src/Serialization/LaravelCollectionHandler.php
Normal file
87
src/Serialization/LaravelCollectionHandler.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Serialization;
|
||||
|
||||
use JMS\Serializer\DeserializationContext;
|
||||
use JMS\Serializer\GraphNavigatorInterface;
|
||||
use JMS\Serializer\Handler\SubscribingHandlerInterface;
|
||||
use JMS\Serializer\SerializationContext;
|
||||
use JMS\Serializer\Visitor\DeserializationVisitorInterface;
|
||||
use JMS\Serializer\Visitor\SerializationVisitorInterface;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class LaravelCollectionHandler
|
||||
*
|
||||
* Shamelessly copied from https://github.com/schmittjoh/serializer/blob/master/src/Handler/ArrayCollectionHandler.php
|
||||
*
|
||||
* @package App\Serialization
|
||||
*/
|
||||
final class LaravelCollectionHandler implements SubscribingHandlerInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribingMethods()
|
||||
{
|
||||
$methods = [];
|
||||
$formats = ['json', 'xml', 'yml'];
|
||||
$collectionTypes = [
|
||||
'Collection',
|
||||
Collection::class,
|
||||
];
|
||||
|
||||
foreach ($collectionTypes as $type) {
|
||||
foreach ($formats as $format) {
|
||||
$methods[] = [
|
||||
'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
|
||||
'type' => $type,
|
||||
'format' => $format,
|
||||
'method' => 'serializeCollection',
|
||||
];
|
||||
|
||||
$methods[] = [
|
||||
'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
|
||||
'type' => $type,
|
||||
'format' => $format,
|
||||
'method' => 'deserializeCollection',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|\ArrayObject
|
||||
*/
|
||||
public function serializeCollection(
|
||||
SerializationVisitorInterface $visitor,
|
||||
Collection $collection,
|
||||
array $type,
|
||||
SerializationContext $context
|
||||
) {
|
||||
// We change the base type, and pass through possible parameters.
|
||||
$type['name'] = 'array';
|
||||
$result = $visitor->visitArray($collection->all(), $type);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
*/
|
||||
public function deserializeCollection(
|
||||
DeserializationVisitorInterface $visitor,
|
||||
$data,
|
||||
array $type,
|
||||
DeserializationContext $context
|
||||
): Collection {
|
||||
// See above.
|
||||
$type['name'] = 'array';
|
||||
|
||||
return new Collection($visitor->visitArray($data, $type));
|
||||
}
|
||||
}
|
86
symfony.lock
86
symfony.lock
@ -65,15 +65,89 @@
|
||||
"doctrine/reflection": {
|
||||
"version": "v1.0.0"
|
||||
},
|
||||
"exsyst/swagger": {
|
||||
"version": "v0.4.1"
|
||||
},
|
||||
"hoa/compiler": {
|
||||
"version": "3.17.08.08"
|
||||
},
|
||||
"hoa/consistency": {
|
||||
"version": "1.17.05.02"
|
||||
},
|
||||
"hoa/event": {
|
||||
"version": "1.17.01.13"
|
||||
},
|
||||
"hoa/exception": {
|
||||
"version": "1.17.01.16"
|
||||
},
|
||||
"hoa/file": {
|
||||
"version": "1.17.07.11"
|
||||
},
|
||||
"hoa/iterator": {
|
||||
"version": "2.17.01.10"
|
||||
},
|
||||
"hoa/math": {
|
||||
"version": "1.17.05.16"
|
||||
},
|
||||
"hoa/protocol": {
|
||||
"version": "1.17.01.14"
|
||||
},
|
||||
"hoa/regex": {
|
||||
"version": "1.17.01.13"
|
||||
},
|
||||
"hoa/stream": {
|
||||
"version": "1.17.02.21"
|
||||
},
|
||||
"hoa/ustring": {
|
||||
"version": "4.17.01.16"
|
||||
},
|
||||
"hoa/visitor": {
|
||||
"version": "2.17.01.16"
|
||||
},
|
||||
"hoa/zformat": {
|
||||
"version": "1.17.01.10"
|
||||
},
|
||||
"jdorn/sql-formatter": {
|
||||
"version": "v1.2.17"
|
||||
},
|
||||
"jms/metadata": {
|
||||
"version": "1.7.0"
|
||||
},
|
||||
"jms/serializer": {
|
||||
"version": "1.14.0"
|
||||
},
|
||||
"jms/serializer-bundle": {
|
||||
"version": "3.0",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes-contrib",
|
||||
"branch": "master",
|
||||
"version": "3.0",
|
||||
"ref": "384cec52df45f3bfd46a09930d6960a58872b268"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/dev/jms_serializer.yaml",
|
||||
"config/packages/jms_serializer.yaml",
|
||||
"config/packages/prod/jms_serializer.yaml"
|
||||
]
|
||||
},
|
||||
"kadet/functional": {
|
||||
"version": "dev-master"
|
||||
},
|
||||
"kylekatarnls/update-helper": {
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"monolog/monolog": {
|
||||
"version": "1.23.0"
|
||||
},
|
||||
"nelmio/api-doc-bundle": {
|
||||
"version": "3.0",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes-contrib",
|
||||
"branch": "master",
|
||||
"version": "3.0",
|
||||
"ref": "c8e0c38e1a280ab9e37587a8fa32b251d5bc1c94"
|
||||
}
|
||||
},
|
||||
"nesbot/carbon": {
|
||||
"version": "1.33.0"
|
||||
},
|
||||
@ -83,6 +157,9 @@
|
||||
"ocramius/proxy-manager": {
|
||||
"version": "2.2.1"
|
||||
},
|
||||
"php": {
|
||||
"version": "7.3.12"
|
||||
},
|
||||
"phpdocumentor/reflection-common": {
|
||||
"version": "1.0.1"
|
||||
},
|
||||
@ -191,6 +268,9 @@
|
||||
"ref": "18ebf5a940573a20de06f9c4060101eeb438cf3d"
|
||||
}
|
||||
},
|
||||
"symfony/options-resolver": {
|
||||
"version": "v4.1.12"
|
||||
},
|
||||
"symfony/orm-pack": {
|
||||
"version": "v1.0.5"
|
||||
},
|
||||
@ -224,6 +304,9 @@
|
||||
"symfony/serializer-pack": {
|
||||
"version": "v1.0.1"
|
||||
},
|
||||
"symfony/stopwatch": {
|
||||
"version": "v4.1.12"
|
||||
},
|
||||
"symfony/translation": {
|
||||
"version": "3.3",
|
||||
"recipe": {
|
||||
@ -274,5 +357,8 @@
|
||||
},
|
||||
"zendframework/zend-eventmanager": {
|
||||
"version": "3.2.1"
|
||||
},
|
||||
"zircote/swagger-php": {
|
||||
"version": "2.0.14"
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
{% extends '@!NelmioApiDoc/SwaggerUi/index.html.twig' %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700">
|
||||
{{ parent() }}
|
||||
<style type="text/css" rel="stylesheet">
|
||||
#formats {
|
||||
font-family: Open Sans,sans-serif;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock-tag,
|
||||
.swagger-ui .opblock .opblock-section-header label,
|
||||
.swagger-ui .opblock .opblock-section-header h4,
|
||||
.swagger-ui .opblock .opblock-summary-method,
|
||||
.swagger-ui .tab li,
|
||||
.swagger-ui .scheme-container .schemes>label,
|
||||
.swagger-ui .loading-container .loading:after,
|
||||
.swagger-ui .btn,
|
||||
.swagger-ui .btn.cancel,
|
||||
.swagger-ui select,
|
||||
.swagger-ui label,
|
||||
.swagger-ui .dialog-ux .modal-ux-content h4,
|
||||
.swagger-ui .dialog-ux .modal-ux-header h3,
|
||||
.swagger-ui section.models h4,
|
||||
.swagger-ui section.models h5,
|
||||
.swagger-ui .model-title,
|
||||
.swagger-ui .parameter__name,
|
||||
.swagger-ui .topbar a,
|
||||
.swagger-ui .topbar .download-url-wrapper .download-url-button,
|
||||
.swagger-ui .info .title small pre,
|
||||
.swagger-ui .scopes h2,
|
||||
.swagger-ui .errors-wrapper hgroup h4 {
|
||||
font-family: Open Sans,sans-serif!important;
|
||||
}
|
||||
</style>
|
||||
{% endblock stylesheets %}
|
Loading…
Reference in New Issue
Block a user