refs #512. API Crud views
parent
020a731351
commit
7ba4deaafa
|
@ -30,6 +30,7 @@
|
|||
"symfony/runtime": "6.4.*",
|
||||
"symfony/security-bundle": "6.4.*",
|
||||
"symfony/serializer": "6.4.*",
|
||||
"symfony/translation": "6.4.*",
|
||||
"symfony/twig-bundle": "6.4.*",
|
||||
"symfony/validator": "6.4.*",
|
||||
"symfony/yaml": "6.4.*"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "e953b0066fb773aaf6b3835086280c86",
|
||||
"content-hash": "bf1165324e27bddd1a412f25e438fc4c",
|
||||
"packages": [
|
||||
{
|
||||
"name": "api-platform/core",
|
||||
|
@ -6061,6 +6061,101 @@
|
|||
],
|
||||
"time": "2024-05-31T14:49:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v6.4.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation.git",
|
||||
"reference": "a002933b13989fc4bd0b58e04bf7eec5210e438a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/a002933b13989fc4bd0b58e04bf7eec5210e438a",
|
||||
"reference": "a002933b13989fc4bd0b58e04bf7eec5210e438a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/polyfill-mbstring": "~1.0",
|
||||
"symfony/translation-contracts": "^2.5|^3.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/config": "<5.4",
|
||||
"symfony/console": "<5.4",
|
||||
"symfony/dependency-injection": "<5.4",
|
||||
"symfony/http-client-contracts": "<2.5",
|
||||
"symfony/http-kernel": "<5.4",
|
||||
"symfony/service-contracts": "<2.5",
|
||||
"symfony/twig-bundle": "<5.4",
|
||||
"symfony/yaml": "<5.4"
|
||||
},
|
||||
"provide": {
|
||||
"symfony/translation-implementation": "2.3|3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nikic/php-parser": "^4.18|^5.0",
|
||||
"psr/log": "^1|^2|^3",
|
||||
"symfony/config": "^5.4|^6.0|^7.0",
|
||||
"symfony/console": "^5.4|^6.0|^7.0",
|
||||
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
|
||||
"symfony/finder": "^5.4|^6.0|^7.0",
|
||||
"symfony/http-client-contracts": "^2.5|^3.0",
|
||||
"symfony/http-kernel": "^5.4|^6.0|^7.0",
|
||||
"symfony/intl": "^5.4|^6.0|^7.0",
|
||||
"symfony/polyfill-intl-icu": "^1.21",
|
||||
"symfony/routing": "^5.4|^6.0|^7.0",
|
||||
"symfony/service-contracts": "^2.5|^3",
|
||||
"symfony/yaml": "^5.4|^6.0|^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"Resources/functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Translation\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Provides tools to internationalize your application",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/translation/tree/v6.4.8"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-31T14:49:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation-contracts",
|
||||
"version": "v3.5.0",
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
resources:
|
||||
App\Entity\View:
|
||||
processor: App\State\Processor\ViewProcessor
|
||||
input: App\Dto\Input\ViewInput
|
||||
output: App\Dto\Output\ViewOutput
|
||||
normalizationContext:
|
||||
groups: ['default', 'view:read']
|
||||
denormalizationContext:
|
||||
groups: ['view:write']
|
||||
operations:
|
||||
ApiPlatform\Metadata\GetCollection:
|
||||
provider: App\State\Provider\ViewProvider
|
||||
filters:
|
||||
- 'api_platform.filter.view.order'
|
||||
- 'api_platform.filter.view.search'
|
||||
ApiPlatform\Metadata\Get:
|
||||
provider: App\State\Provider\ViewProvider
|
||||
ApiPlatform\Metadata\Put:
|
||||
provider: App\State\Provider\ViewProvider
|
||||
ApiPlatform\Metadata\Patch:
|
||||
provider: App\State\Provider\ViewProvider
|
||||
ApiPlatform\Metadata\Post: ~
|
||||
ApiPlatform\Metadata\Delete: ~
|
||||
|
||||
properties:
|
||||
App\Entity\View:
|
||||
id:
|
||||
identifier: false
|
||||
uuid:
|
||||
identifier: true
|
|
@ -11,7 +11,7 @@ security:
|
|||
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
||||
security: false
|
||||
main:
|
||||
stateless: true
|
||||
stateless: false
|
||||
provider: app_user_provider
|
||||
entry_point: jwt
|
||||
json_login:
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
framework:
|
||||
default_locale: es
|
||||
translator:
|
||||
default_path: '%kernel.project_dir%/translations'
|
||||
fallbacks:
|
||||
- en
|
||||
- es
|
||||
providers:
|
|
@ -21,6 +21,12 @@ services:
|
|||
- { name: api_platform.doctrine.orm.query_extension.collection }
|
||||
- { name: api_platform.doctrine.orm.query_extension.item }
|
||||
|
||||
App\EventListener\LocaleSubscriber:
|
||||
arguments:
|
||||
$defaultLocale: '%kernel.default_locale%'
|
||||
tags:
|
||||
- { name: kernel.event_subscriber }
|
||||
|
||||
App\OpenApi\OpenApiFactory:
|
||||
decorates: 'api_platform.openapi.factory'
|
||||
arguments: [ '@App\OpenApi\OpenApiFactory.inner' ]
|
||||
|
@ -90,3 +96,8 @@ services:
|
|||
bind:
|
||||
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
|
||||
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'
|
||||
|
||||
App\State\Provider\ViewProvider:
|
||||
bind:
|
||||
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
|
||||
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20240717094811 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TABLE view (id INT AUTO_INCREMENT NOT NULL, uuid CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', migration_id VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, created_by VARCHAR(255) DEFAULT NULL, updated_by VARCHAR(255) DEFAULT NULL, favourite TINYINT(1) NOT NULL, filters JSON DEFAULT NULL COMMENT \'(DC2Type:json)\', name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_FEFDAB8ED17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('DROP TABLE view');
|
||||
}
|
||||
}
|
|
@ -12,44 +12,67 @@ use Symfony\Component\Validator\Constraints as Assert;
|
|||
|
||||
final class ClientInput
|
||||
{
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\NotBlank(message: 'validators.client.name.not_blank')]
|
||||
#[Groups(['client:write'])]
|
||||
#[ApiProperty(description: 'The name of the client', example: "Client 1")]
|
||||
#[ApiProperty(
|
||||
description: 'descriptions.client.name',
|
||||
example: "examples.client.name",
|
||||
)]
|
||||
public ?string $name = null;
|
||||
|
||||
#[Groups(['client:write'])]
|
||||
#[ApiProperty(description: 'The serial number of the client', example: "123456")]
|
||||
#[ApiProperty(
|
||||
description: 'descriptions.client.serial_number',
|
||||
example: "examples.client.serial_number"
|
||||
)]
|
||||
public ?string $serialNumber = null;
|
||||
|
||||
#[Groups(['client:write'])]
|
||||
#[ApiProperty(description: 'The network interface of the client', example: "eth0")]
|
||||
#[ApiProperty(
|
||||
description: 'descriptions.client.network_interface',
|
||||
example: "examples.client.network_interface"
|
||||
)]
|
||||
public ?string $netiface = null;
|
||||
|
||||
#[Groups(['client:write'])]
|
||||
#[ApiProperty(description: 'The network driver of the client', example: "e1000e")]
|
||||
#[ApiProperty(
|
||||
description: 'descriptions.client.network_driver',
|
||||
example: "examples.client.network_driver"
|
||||
)]
|
||||
public ?string $netDriver = null;
|
||||
|
||||
#[Groups(['client:write'])]
|
||||
#[ApiProperty(description: 'The MAC address of the client', example: "00:11:22:33:44:55")]
|
||||
#[ApiProperty(
|
||||
description: 'descriptions.client.mac_address',
|
||||
example: "examples.client.mac_address"
|
||||
)]
|
||||
public ?string $mac = null;
|
||||
|
||||
#[Groups(['client:write'])]
|
||||
#[Assert\Ip]
|
||||
#[ApiProperty(description: 'The IP address of the client', example: "127.0.0.1")]
|
||||
#[Assert\Ip(message: 'validators.ip_address.invalid')]
|
||||
#[ApiProperty(
|
||||
description: 'descriptions.client.ip_address',
|
||||
example: "examples.client.ip_address"
|
||||
)]
|
||||
public ?string $ip = null;
|
||||
|
||||
#[Groups(['client:write'])]
|
||||
public ?string $status = null;
|
||||
|
||||
#[Assert\NotNull]
|
||||
#[Assert\NotNull(message: 'validators.organizational_unit.not_null')]
|
||||
#[Groups(['client:write', 'client:patch'])]
|
||||
#[ApiProperty(description: 'The organizational unit of the client')]
|
||||
#[ApiProperty(
|
||||
description: 'descriptions.client.organizational_unit'
|
||||
)]
|
||||
public ?OrganizationalUnitOutput $organizationalUnit = null;
|
||||
|
||||
#[Groups(['client:write'])]
|
||||
#[ApiProperty(
|
||||
description: 'descriptions.client.menu'
|
||||
)]
|
||||
public ?MenuOutput $menu = null;
|
||||
|
||||
#[Groups(['client:write'])]
|
||||
#[ApiProperty(
|
||||
description: 'descriptions.client.hardware_profile'
|
||||
)]
|
||||
public ?HardwareProfileOutput $hardwareProfile = null;
|
||||
|
||||
public function __construct(?Client $client = null)
|
||||
|
@ -65,7 +88,6 @@ final class ClientInput
|
|||
$this->netDriver = $client->getNetDriver();
|
||||
$this->mac = $client->getMac();
|
||||
$this->ip = $client->getIp();
|
||||
$this->status = $client->getStatus();
|
||||
|
||||
if ($client->getMenu()) {
|
||||
$this->menu = new MenuOutput($client->getMenu());
|
||||
|
@ -89,7 +111,6 @@ final class ClientInput
|
|||
$client->setNetDriver($this->netDriver);
|
||||
$client->setMac($this->mac);
|
||||
$client->setIp($this->ip);
|
||||
$client->setStatus($this->status);
|
||||
$client->setMenu($this->menu?->getEntity());
|
||||
$client->setHardwareProfile($this->hardwareProfile?->getEntity());
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dto\Input;
|
||||
|
||||
use ApiPlatform\Metadata\ApiProperty;
|
||||
use App\Entity\View;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
final class ViewInput
|
||||
{
|
||||
#[Assert\NotBlank(message: 'validators.view.name.not_blank')]
|
||||
#[Groups(['view:write'])]
|
||||
#[ApiProperty(description: 'The name of the view', example: "View 1")]
|
||||
public ?string $name = null;
|
||||
|
||||
#[Groups(['view:write'])]
|
||||
#[ApiProperty(description: 'The favourite status of the view', example: true)]
|
||||
public ?bool $favourite = null;
|
||||
|
||||
#[Groups(['view:write'])]
|
||||
#[ApiProperty(description: 'The filters of the view', example: ["filter1" => "value1"])]
|
||||
public ?array $filters = null;
|
||||
|
||||
public function __construct(?View $view = null)
|
||||
{
|
||||
if (!$view) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->name = $view->getName();
|
||||
$this->favourite = $view->isFavourite();
|
||||
$this->filters= $view->getFilters();
|
||||
}
|
||||
|
||||
public function createOrUpdateEntity(?View $view = null): View
|
||||
{
|
||||
if (!$view) {
|
||||
$view = new View();
|
||||
}
|
||||
|
||||
$view->setName($this->name);
|
||||
$view->setFavourite($this->favourite);
|
||||
$view->setFilters($this->filters);
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dto\Output;
|
||||
|
||||
use ApiPlatform\Metadata\Get;
|
||||
use App\Entity\View;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[Get(shortName: 'View')]
|
||||
final class ViewOutput extends AbstractOutput
|
||||
{
|
||||
#[Groups(['view:read'])]
|
||||
public string $name;
|
||||
|
||||
#[Groups(['view:read'])]
|
||||
public bool $favorite;
|
||||
|
||||
#[Groups(['view:read'])]
|
||||
public ?array $filters = null;
|
||||
|
||||
public function __construct(View $view)
|
||||
{
|
||||
parent::__construct($view);
|
||||
|
||||
$this->name = $view->getName();
|
||||
$this->favorite = $view->isFavourite();
|
||||
$this->filters = $view->getFilters();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\ViewRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: ViewRepository::class)]
|
||||
class View extends \App\Entity\AbstractEntity
|
||||
{
|
||||
use NameableTrait;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?bool $favourite = null;
|
||||
|
||||
#[ORM\Column(type: Types::JSON, nullable: true)]
|
||||
private ?array $filters = [];
|
||||
|
||||
public function setName(string $name): static
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isFavourite(): ?bool
|
||||
{
|
||||
return $this->favourite;
|
||||
}
|
||||
|
||||
public function setFavourite(bool $favourite): static
|
||||
{
|
||||
$this->favourite = $favourite;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFilters(): ?array
|
||||
{
|
||||
return $this->filters;
|
||||
}
|
||||
|
||||
public function setFilters(?array $filters): static
|
||||
{
|
||||
$this->filters = $filters;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
// src/EventListener/LocaleSubscriber.php
|
||||
namespace App\EventListener;
|
||||
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
class LocaleSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
private string $defaultLocale;
|
||||
private RequestStack $requestStack;
|
||||
|
||||
public function __construct(RequestStack $requestStack, string $defaultLocale = 'es')
|
||||
{
|
||||
$this->defaultLocale = $defaultLocale;
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
|
||||
public function onKernelRequest(RequestEvent $event): void
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
$locale = $request->getSession()->get('_locale', $this->defaultLocale);
|
||||
|
||||
if ($request->attributes->get('_locale')) {
|
||||
$locale = $request->attributes->get('_locale');
|
||||
}
|
||||
|
||||
$localeFromHeader = $request->getPreferredLanguage(['en', 'es']);
|
||||
if ($localeFromHeader) {
|
||||
$locale = $localeFromHeader;
|
||||
}
|
||||
|
||||
$request->setLocale($locale);
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
KernelEvents::REQUEST => [['onKernelRequest', 20]],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace App\Factory;
|
||||
|
||||
use App\Entity\View;
|
||||
use App\Repository\ViewRepository;
|
||||
use Zenstruck\Foundry\ModelFactory;
|
||||
use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory;
|
||||
use Zenstruck\Foundry\Persistence\Proxy;
|
||||
use Zenstruck\Foundry\Persistence\ProxyRepositoryDecorator;
|
||||
|
||||
/**
|
||||
* @extends PersistentProxyObjectFactory<View>
|
||||
*/
|
||||
final class ViewFactory extends ModelFactory
|
||||
{
|
||||
/**
|
||||
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services
|
||||
*
|
||||
* @todo inject services if required
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public static function class(): string
|
||||
{
|
||||
return View::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories
|
||||
*
|
||||
* @todo add your default values here
|
||||
*/
|
||||
protected function getDefaults(): array
|
||||
{
|
||||
return [
|
||||
'createdAt' => self::faker()->dateTime(),
|
||||
'favourite' => self::faker()->boolean(),
|
||||
'name' => self::faker()->text(255),
|
||||
'updatedAt' => self::faker()->dateTime()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization
|
||||
*/
|
||||
protected function initialize(): self
|
||||
{
|
||||
return $this
|
||||
// ->afterInstantiate(function(View $view): void {})
|
||||
;
|
||||
}
|
||||
|
||||
protected static function getClass(): string
|
||||
{
|
||||
return View::class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\View;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<View>
|
||||
*/
|
||||
class ViewRepository extends AbstractRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, View::class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace App\State\Processor;
|
||||
|
||||
use ApiPlatform\Metadata\Delete;
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\Metadata\Patch;
|
||||
use ApiPlatform\Metadata\Post;
|
||||
use ApiPlatform\Metadata\Put;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
use ApiPlatform\Validator\ValidatorInterface;
|
||||
use App\Dto\Input\ViewInput;
|
||||
use App\Dto\Output\ViewOutput;
|
||||
use App\Repository\ViewRepository;
|
||||
|
||||
readonly class ViewProcessor implements ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private ViewRepository $viewRepository,
|
||||
private ValidatorInterface $validator
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ViewOutput|null
|
||||
{
|
||||
switch ($operation){
|
||||
case $operation instanceof Post:
|
||||
case $operation instanceof Put:
|
||||
case $operation instanceof Patch:
|
||||
return $this->processCreateOrUpdate($data, $operation, $uriVariables, $context);
|
||||
case $operation instanceof Delete:
|
||||
return $this->processDelete($data, $operation, $uriVariables, $context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): ViewOutput
|
||||
{
|
||||
if (!($data instanceof ViewInput)) {
|
||||
throw new \Exception(sprintf('data is not instance of %s', ViewInput::class));
|
||||
}
|
||||
|
||||
$entity = null;
|
||||
if (isset($uriVariables['uuid'])) {
|
||||
$entity = $this->viewRepository->findOneByUuid($uriVariables['uuid']);
|
||||
}
|
||||
|
||||
$view = $data->createOrUpdateEntity($entity);
|
||||
$this->validator->validate($view);
|
||||
$this->viewRepository->save($view);
|
||||
|
||||
return new ViewOutput($view);
|
||||
}
|
||||
|
||||
private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null
|
||||
{
|
||||
$user = $this->viewRepository->findOneByUuid($uriVariables['uuid']);
|
||||
$this->viewRepository->delete($user);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace App\State\Provider;
|
||||
|
||||
use ApiPlatform\Metadata\Get;
|
||||
use ApiPlatform\Metadata\GetCollection;
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\Metadata\Patch;
|
||||
use ApiPlatform\Metadata\Put;
|
||||
use ApiPlatform\State\Pagination\TraversablePaginator;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Dto\Input\ViewInput;
|
||||
use App\Dto\Output\ViewOutput;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
readonly class ViewProvider implements ProviderInterface
|
||||
{
|
||||
public function __construct(
|
||||
private ProviderInterface $collectionProvider,
|
||||
private ProviderInterface $itemProvider
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
|
||||
{
|
||||
switch ($operation){
|
||||
case $operation instanceof GetCollection:
|
||||
return $this->provideCollection($operation, $uriVariables, $context);
|
||||
case $operation instanceof Patch:
|
||||
case $operation instanceof Put:
|
||||
return $this->provideInput($operation, $uriVariables, $context);
|
||||
case $operation instanceof Get:
|
||||
return $this->provideItem($operation, $uriVariables, $context);
|
||||
}
|
||||
}
|
||||
|
||||
private function provideCollection(Operation $operation, array $uriVariables = [], array $context = []): object
|
||||
{
|
||||
$paginator = $this->collectionProvider->provide($operation, $uriVariables, $context);
|
||||
|
||||
$items = new \ArrayObject();
|
||||
foreach ($paginator->getIterator() as $item){
|
||||
$items[] = new ViewOutput($item);
|
||||
}
|
||||
|
||||
return new TraversablePaginator($items, $paginator->getCurrentPage(), $paginator->getItemsPerPage(), $paginator->getTotalItems());
|
||||
}
|
||||
|
||||
public function provideItem(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
|
||||
{
|
||||
$item = $this->itemProvider->provide($operation, $uriVariables, $context);
|
||||
|
||||
if (!$item) {
|
||||
throw new NotFoundHttpException('View not found');
|
||||
}
|
||||
|
||||
return new ViewOutput($item);
|
||||
}
|
||||
|
||||
public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
|
||||
{
|
||||
if (isset($uriVariables['uuid'])) {
|
||||
$item = $this->itemProvider->provide($operation, $uriVariables, $context);
|
||||
|
||||
return $item !== null ? new ViewInput($item) : null;
|
||||
}
|
||||
|
||||
return new ViewInput();
|
||||
}
|
||||
}
|
13
symfony.lock
13
symfony.lock
|
@ -219,6 +219,19 @@
|
|||
"config/routes/security.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/translation": {
|
||||
"version": "6.4",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "6.3",
|
||||
"ref": "e28e27f53663cc34f0be2837aba18e3a1bef8e7b"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/translation.yaml",
|
||||
"translations/.gitignore"
|
||||
]
|
||||
},
|
||||
"symfony/twig-bundle": {
|
||||
"version": "6.4",
|
||||
"recipe": {
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
namespace Functional;
|
||||
|
||||
|
||||
use App\Entity\HardwareProfile;
|
||||
use App\Entity\OrganizationalUnit;
|
||||
use App\Entity\View;
|
||||
use App\Factory\HardwareProfileFactory;
|
||||
use App\Factory\OrganizationalUnitFactory;
|
||||
use App\Factory\UserFactory;
|
||||
use App\Factory\ViewFactory;
|
||||
use App\Model\OrganizationalUnitTypes;
|
||||
use App\Model\UserGroupPermissions;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
|
||||
class ViewTest extends AbstractTest
|
||||
{
|
||||
CONST string USER_ADMIN = 'ogadmin';
|
||||
CONST string VIEW_CREATE = 'test-view-create';
|
||||
CONST string VIEW_UPDATE = 'test-view-update';
|
||||
CONST string VIEW_DELETE = 'test-view-delete';
|
||||
|
||||
/**
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws DecodingExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
*/
|
||||
public function testGetCollectionViews(): void
|
||||
{
|
||||
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
|
||||
|
||||
ViewFactory::createMany(10);
|
||||
|
||||
$this->createClientWithCredentials()->request('GET', '/views');
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
|
||||
$this->assertJsonContains([
|
||||
'@context' => '/contexts/View',
|
||||
'@id' => '/views',
|
||||
'@type' => 'hydra:Collection',
|
||||
'hydra:totalItems' => 10,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws DecodingExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
*/
|
||||
public function testCreateView(): void
|
||||
{
|
||||
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
|
||||
|
||||
ViewFactory::createOne(['name' => self::VIEW_CREATE, 'favourite' => true]);
|
||||
$viewIri = $this->findIriBy(View::class, ['name' => self::VIEW_CREATE]);
|
||||
|
||||
$this->createClientWithCredentials()->request('POST', '/views',['json' => [
|
||||
'name' => self::VIEW_CREATE,
|
||||
'favourite' => true
|
||||
]]);
|
||||
|
||||
$this->assertResponseStatusCodeSame(201);
|
||||
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
|
||||
$this->assertJsonContains([
|
||||
'@context' => '/contexts/ViewOutput',
|
||||
'@type' => 'View',
|
||||
'name' => self::VIEW_CREATE
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws DecodingExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
*/
|
||||
public function testUpdateView(): void
|
||||
{
|
||||
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
|
||||
|
||||
ViewFactory::createOne(['name' => self::VIEW_CREATE, 'favourite' => true]);
|
||||
$viewIri = $this->findIriBy(View::class, ['name' => self::VIEW_CREATE]);
|
||||
|
||||
$this->createClientWithCredentials()->request('PUT', $viewIri, ['json' => [
|
||||
'name' => self::VIEW_UPDATE,
|
||||
'favourite' => false
|
||||
]]);
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
$this->assertJsonContains([
|
||||
'@id' => $viewIri,
|
||||
'name' => self::VIEW_UPDATE,
|
||||
'favorite' => false
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws DecodingExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
public function testDeleteView(): void
|
||||
{
|
||||
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
|
||||
|
||||
ViewFactory::createOne(['name' => self::VIEW_DELETE, 'favourite' => true]);
|
||||
$viewIri = $this->findIriBy(View::class, ['name' => self::VIEW_DELETE]);
|
||||
|
||||
$this->createClientWithCredentials()->request('DELETE', $viewIri);
|
||||
$this->assertResponseStatusCodeSame(204);
|
||||
$this->assertNull(
|
||||
static::getContainer()->get('doctrine')->getRepository(View::class)->findOneBy(['name' => self::VIEW_DELETE])
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
# messages.en.yaml
|
||||
validators:
|
||||
client:
|
||||
ip_address:
|
||||
invalid: 'The IP address "{{ value }}" is not valid.'
|
||||
name:
|
||||
not_blank: 'The name should not be blank.'
|
||||
organizational_unit:
|
||||
not_null: 'The organizational unit should not be null.'
|
||||
|
||||
view:
|
||||
name:
|
||||
not_blank: 'The name should not be blank.'
|
|
@ -0,0 +1,13 @@
|
|||
# messages.es.yaml
|
||||
validators:
|
||||
client:
|
||||
ip_address:
|
||||
invalid: 'La dirección IP "{{ value }}" no es válida.'
|
||||
name:
|
||||
not_blank: 'El nombre no debería estar vacío.'
|
||||
organizational_unit:
|
||||
not_null: 'La unidad organizativa no debería estar vacía.'
|
||||
|
||||
view:
|
||||
name:
|
||||
not_blank: 'El nombre no debería estar vacío.'
|
Loading…
Reference in New Issue