All
This commit is contained in:
4
api/.env
4
api/.env
@@ -14,7 +14,7 @@
|
||||
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
|
||||
|
||||
MERCURE_SUBSCRIBE_URL=http://localhost:1337/hub
|
||||
VARNISH_URL=http://cache-proxy
|
||||
#VARNISH_URL=http://cache-proxy
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
APP_ENV=dev
|
||||
@@ -31,7 +31,7 @@ DATABASE_URL=postgres://api-platform:!ChangeMe!@db/api
|
||||
###< doctrine/doctrine-bundle ###
|
||||
|
||||
###> nelmio/cors-bundle ###
|
||||
CORS_ALLOW_ORIGIN=^https?://localhost(:[0-9]+)?$
|
||||
CORS_ALLOW_ORIGIN=^https?://.*$
|
||||
###< nelmio/cors-bundle ###
|
||||
|
||||
###> symfony/mercure-bundle ###
|
||||
|
||||
7
api/Readme.md
Normal file
7
api/Readme.md
Normal file
@@ -0,0 +1,7 @@
|
||||
Enable prod mode: `docker-compose exec php composer dump-env prod`
|
||||
|
||||
Disable prod mode: delete `.env.local.php`
|
||||
|
||||
Clear Prod cache `docker-compose exec php bin/console cache:clear --env=prod`
|
||||
|
||||
Swagger: https://api-platform.com/docs/core/swagger/#using-the-openapi-and-swagger-contexts
|
||||
@@ -9,16 +9,12 @@ api_platform:
|
||||
mapping:
|
||||
paths: ['%kernel.project_dir%/src/Entity']
|
||||
title: Hello API Platform
|
||||
description: สวัสดีเพื่อนๆ
|
||||
version: 1.0.0
|
||||
# Varnish integration, remove if unwanted
|
||||
http_cache:
|
||||
invalidation:
|
||||
enabled: true
|
||||
varnish_urls: ['%env(VARNISH_URL)%']
|
||||
max_age: 0
|
||||
shared_max_age: 3600
|
||||
vary: ['Content-Type', 'Authorization']
|
||||
public: true
|
||||
# Mercure integration, remove if unwanted
|
||||
mercure:
|
||||
hub_url: '%env(MERCURE_SUBSCRIBE_URL)%'
|
||||
show_webby: false
|
||||
formats:
|
||||
json: ['application/json']
|
||||
xml: ['application/xml', 'text/xml']
|
||||
yaml: ['application/x-yaml']
|
||||
csv: ['text/csv']
|
||||
html: ['text/html']
|
||||
|
||||
@@ -2,7 +2,7 @@ nelmio_cors:
|
||||
defaults:
|
||||
origin_regex: true
|
||||
allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
|
||||
allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
|
||||
allow_methods: ['GET', 'OPTIONS']
|
||||
allow_headers: ['Content-Type', 'Authorization']
|
||||
expose_headers: ['Link']
|
||||
max_age: 3600
|
||||
|
||||
71
api/src/DataProvider/CircleDataProvider.php
Normal file
71
api/src/DataProvider/CircleDataProvider.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\DataProvider;
|
||||
|
||||
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
|
||||
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
|
||||
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
|
||||
use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface;
|
||||
use ApiPlatform\Core\Exception\InvalidValueException;
|
||||
use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;
|
||||
use App\Entity\Creation;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use App\Entity\Circle;
|
||||
|
||||
final class CircleDataProvider implements CollectionDataProviderInterface, ItemDataProviderInterface, SubresourceDataProviderInterface, RestrictedDataProviderInterface
|
||||
{
|
||||
private $requestStack;
|
||||
|
||||
/**
|
||||
* CircleDataProvider constructor.
|
||||
* @param $requestStack
|
||||
*/
|
||||
public function __construct(RequestStack $requestStack)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
|
||||
|
||||
public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
|
||||
{
|
||||
return Circle::class === $resourceClass;
|
||||
}
|
||||
|
||||
public function getCollection(string $resourceClass, string $operationName = null): \Generator
|
||||
{
|
||||
$query = $this->requestStack->getCurrentRequest()->query;
|
||||
$ids = $query->get('ids');
|
||||
if ($ids !== null) {
|
||||
if (!preg_match('/^\d+(,\d+)*$/', $ids)) {
|
||||
throw new InvalidValueException('ids must be comma-seperated integers', 400);
|
||||
//BadQueryStringException('ids must be comma-seperated integer', 400);
|
||||
}
|
||||
$ids = explode(',', $ids);
|
||||
foreach ($ids as $id) {
|
||||
yield new Circle((int)$id, $operationName, 'bla');
|
||||
}
|
||||
}
|
||||
else {
|
||||
for($i = 0; $i< 10; $i++) {
|
||||
yield new Circle($i, $operationName, json_encode($ids));
|
||||
}
|
||||
}
|
||||
// Returning array works too
|
||||
// Return empty array if no data
|
||||
|
||||
}
|
||||
|
||||
public function getItem(string $resourceClass, $id, string $operationName = null, array $context = [])
|
||||
{
|
||||
//return null; for 404
|
||||
$tmp = new Circle($id, is_string($id)? 'true' : 'false', 'a01');
|
||||
$tmp->creations = [new Creation(55,'55'), new Creation(66,'66')];
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
public function getSubresource(string $resourceClass, array $identifiers, array $context, string $operationName = null)
|
||||
{
|
||||
return $context['property'];
|
||||
// TODO: Implement getSubresource() method.
|
||||
}
|
||||
}
|
||||
131
api/src/Entity/Circle.php
Normal file
131
api/src/Entity/Circle.php
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use ApiPlatform\Core\Annotation\ApiProperty;
|
||||
use ApiPlatform\Core\Annotation\ApiResource;
|
||||
use ApiPlatform\Core\Annotation\ApiSubresource;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* A circle
|
||||
* @ApiResource(
|
||||
* attributes={"pagination_enabled"=false},
|
||||
* collectionOperations={
|
||||
* "get"={
|
||||
* "method"="GET",
|
||||
* "swagger_context"={
|
||||
* "summary"="Get the list of circles",
|
||||
* "description"="Get the list of circles",
|
||||
* "parameters" = {
|
||||
* {
|
||||
* "name"="ids",
|
||||
* "in"="query",
|
||||
* "description"="Comma-seperated list of circle ids. If not specified, will return all circles",
|
||||
* "example"="123,456",
|
||||
* "pattern"="^\d+(,\d+)*$",
|
||||
* "type":"string"
|
||||
* }
|
||||
* }
|
||||
* },
|
||||
* "requirements"={"ids"="\d+(,\d+)*"}
|
||||
* }
|
||||
* },
|
||||
* itemOperations={
|
||||
* "get"={
|
||||
* "method"="GET",
|
||||
* "requirements"={"id"="\d+"}
|
||||
* }
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class Circle
|
||||
{
|
||||
/**
|
||||
* @var int Circle Id
|
||||
* @ApiProperty(identifier=true)
|
||||
* @Assert\NotBlank
|
||||
* @Assert\Type(type="int")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var string Circle name
|
||||
* @Assert\NotBlank
|
||||
*/
|
||||
public $name = '';
|
||||
|
||||
/**
|
||||
* @var string Booth location
|
||||
* @Assert\NotBlank
|
||||
*/
|
||||
public $booth = '';
|
||||
|
||||
/**
|
||||
* @var string Description
|
||||
*/
|
||||
public $description;
|
||||
|
||||
/**
|
||||
* @var string Cutout image url
|
||||
*/
|
||||
|
||||
public $cutout;
|
||||
/**
|
||||
* @var string Menu image url
|
||||
*/
|
||||
|
||||
public $menu;
|
||||
|
||||
/**
|
||||
* @var string Cover image url
|
||||
*/
|
||||
public $cover;
|
||||
|
||||
|
||||
/**
|
||||
* @var int Spaces
|
||||
* @Assert\Type(type="int")
|
||||
*/
|
||||
public $sp;
|
||||
|
||||
/**
|
||||
* @var string Type of circle
|
||||
*/
|
||||
public $type;
|
||||
|
||||
// Members
|
||||
/**
|
||||
* @ApiSubresource()
|
||||
* @var integer[] Members
|
||||
*/
|
||||
public $members;
|
||||
|
||||
// Creations
|
||||
/**
|
||||
* @ApiSubresource()
|
||||
* @var Creation[] Creations
|
||||
*/
|
||||
public $creations;
|
||||
|
||||
/**
|
||||
* Circle constructor.
|
||||
* @param int $id
|
||||
* @param string $name
|
||||
* @param string $booth
|
||||
*/
|
||||
public function __construct(int $id, string $name, string $booth)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
$this->booth = $booth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
}
|
||||
62
api/src/Entity/Creation.php
Normal file
62
api/src/Entity/Creation.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use ApiPlatform\Core\Annotation\ApiProperty;
|
||||
use ApiPlatform\Core\Annotation\ApiResource;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* A Creation
|
||||
* @ApiResource(
|
||||
* attributes={"pagination_enabled"=false},
|
||||
* collectionOperations={"get"},
|
||||
* itemOperations={
|
||||
* "get"={
|
||||
* "method"="GET",
|
||||
* "requirements"={"id"="\d+"}
|
||||
* }
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class Creation
|
||||
{
|
||||
/**
|
||||
* @var int Circle Id
|
||||
* @ApiProperty(identifier=true)
|
||||
* @Assert\NotBlank
|
||||
* @Assert\Type(type="int")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var string Creation name
|
||||
* @Assert\NotBlank
|
||||
*/
|
||||
public $name = '';
|
||||
|
||||
/**
|
||||
* @var integer Circle ID
|
||||
* @Assert\NotBlank
|
||||
*/
|
||||
public $circleId;
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct(int $id, string $name)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use ApiPlatform\Core\Annotation\ApiResource;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* This is a dummy entity. Remove it!
|
||||
*
|
||||
* @ApiResource
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class Greeting
|
||||
{
|
||||
/**
|
||||
* @var int The entity Id
|
||||
*
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var string A nice person
|
||||
*
|
||||
* @ORM\Column
|
||||
* @Assert\NotBlank
|
||||
*/
|
||||
public $name = '';
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% if title %}{{ title }} - {% endif %}API Platform</title>
|
||||
|
||||
{% block stylesheet %}
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700">
|
||||
<link rel="stylesheet" href="{{ asset('bundles/apiplatform/swagger-ui/swagger-ui.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('bundles/apiplatform/style.css') }}">
|
||||
{% endblock %}
|
||||
|
||||
{# json_encode(65) is for JSON_UNESCAPED_SLASHES|JSON_HEX_TAG to avoid JS XSS #}
|
||||
<script id="swagger-data" type="application/json">{{ swagger_data|json_encode(65)|raw }}</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="position:absolute;width:0;height:0">
|
||||
<defs>
|
||||
<symbol viewBox="0 0 20 20" id="unlocked">
|
||||
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="locked">
|
||||
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"></path>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="close">
|
||||
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"></path>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="large-arrow">
|
||||
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"></path>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="large-arrow-down">
|
||||
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"></path>
|
||||
</symbol>
|
||||
|
||||
|
||||
<symbol viewBox="0 0 24 24" id="jump-to">
|
||||
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"></path>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 24 24" id="expand">
|
||||
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"></path>
|
||||
</symbol>
|
||||
|
||||
</defs>
|
||||
</svg>
|
||||
<header>
|
||||
<a id="logo" href="https://api-platform.com"><img src="{{ asset('bundles/apiplatform/logo-header.svg') }}" alt="API Platform"></a>
|
||||
</header>
|
||||
|
||||
{% if showWebby %}
|
||||
<div class="web"><img src="{{ asset('bundles/apiplatform/web.png') }}"></div>
|
||||
<div class="webby"><img src="{{ asset('bundles/apiplatform/webby.png') }}"></div>
|
||||
{% endif %}
|
||||
|
||||
<div id="swagger-ui" class="api-platform"></div>
|
||||
|
||||
<div class="swagger-ui" id="formats">
|
||||
<div class="information-container wrapper">
|
||||
<div class="info">
|
||||
Other API docs:
|
||||
{% set active_ui = app.request.get('ui', 'swagger_ui') %}
|
||||
{% if swaggerUiEnabled and active_ui != 'swagger_ui' %}<a href="{{ path('api_entrypoint') }}">Swagger UI</a>{% endif %}
|
||||
{% if reDocEnabled and active_ui != 're_doc' %}<a href="{{ path('api_entrypoint', {'ui': 're_doc'}) }}">ReDoc</a>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block javascript %}
|
||||
{% if (reDocEnabled and not swaggerUiEnabled) or (reDocEnabled and 're_doc' == active_ui) %}
|
||||
<script src="{{ asset('bundles/apiplatform/redoc/redoc.standalone.js') }}"></script>
|
||||
<script src="{{ asset('bundles/apiplatform/init-redoc-ui.js') }}"></script>
|
||||
{% elseif (swaggerUiEnabled) %}
|
||||
<script src="{{ asset('bundles/apiplatform/swagger-ui/swagger-ui-bundle.js') }}"></script>
|
||||
<script src="{{ asset('bundles/apiplatform/swagger-ui/swagger-ui-standalone-preset.js') }}"></script>
|
||||
<script src="{{ asset('bundles/apiplatform/init-swagger-ui.js') }}"></script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user