refs #375. Crear modelo de base de datos de usuario. Primera version API

pull/5/head
Manuel Aranda Rosales 2024-05-24 12:46:04 +02:00
parent 94d3d3f541
commit 68ea45a1f9
30 changed files with 1140 additions and 200 deletions

View File

@ -11,7 +11,7 @@
"doctrine/dbal": "^3",
"doctrine/doctrine-bundle": "^2.12",
"doctrine/doctrine-migrations-bundle": "^3.3",
"doctrine/orm": "^3.1",
"doctrine/orm": "^2.19.5",
"gesdinet/jwt-refresh-token-bundle": "^1.3",
"lexik/jwt-authentication-bundle": "^3.0",
"nelmio/cors-bundle": "^2.4",

225
composer.lock generated
View File

@ -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": "8a178ee08c8bef147097b85e84af9dd7",
"content-hash": "a03ea4d76774164d557cb2ecb327de33",
"packages": [
{
"name": "api-platform/core",
@ -303,82 +303,6 @@
],
"time": "2023-11-29T23:19:16+00:00"
},
{
"name": "doctrine/annotations",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
"shasum": ""
},
"require": {
"doctrine/lexer": "^2 || ^3",
"ext-tokenizer": "*",
"php": "^7.2 || ^8.0",
"psr/cache": "^1 || ^2 || ^3"
},
"require-dev": {
"doctrine/cache": "^2.0",
"doctrine/coding-standard": "^10",
"phpstan/phpstan": "^1.8.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"symfony/cache": "^5.4 || ^6",
"vimeo/psalm": "^4.10"
},
"suggest": {
"php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Docblock Annotations Parser",
"homepage": "https://www.doctrine-project.org/projects/annotations.html",
"keywords": [
"annotations",
"docblock",
"parser"
],
"support": {
"issues": "https://github.com/doctrine/annotations/issues",
"source": "https://github.com/doctrine/annotations/tree/2.0.1"
},
"time": "2023-02-02T22:02:53+00:00"
},
{
"name": "doctrine/cache",
"version": "2.2.0",
@ -1023,16 +947,16 @@
},
{
"name": "doctrine/event-manager",
"version": "2.0.0",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/event-manager.git",
"reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32"
"reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/event-manager/zipball/750671534e0241a7c50ea5b43f67e23eb5c96f32",
"reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32",
"url": "https://api.github.com/repos/doctrine/event-manager/zipball/b680156fa328f1dfd874fd48c7026c41570b9c6e",
"reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e",
"shasum": ""
},
"require": {
@ -1042,10 +966,10 @@
"doctrine/common": "<2.9"
},
"require-dev": {
"doctrine/coding-standard": "^10",
"doctrine/coding-standard": "^12",
"phpstan/phpstan": "^1.8.8",
"phpunit/phpunit": "^9.5",
"vimeo/psalm": "^4.28"
"phpunit/phpunit": "^10.5",
"vimeo/psalm": "^5.24"
},
"type": "library",
"autoload": {
@ -1094,7 +1018,7 @@
],
"support": {
"issues": "https://github.com/doctrine/event-manager/issues",
"source": "https://github.com/doctrine/event-manager/tree/2.0.0"
"source": "https://github.com/doctrine/event-manager/tree/2.0.1"
},
"funding": [
{
@ -1110,7 +1034,7 @@
"type": "tidelift"
}
],
"time": "2022-10-12T20:59:15+00:00"
"time": "2024-05-22T20:47:39+00:00"
},
{
"name": "doctrine/inflector",
@ -1454,48 +1378,61 @@
},
{
"name": "doctrine/orm",
"version": "3.1.3",
"version": "2.19.5",
"source": {
"type": "git",
"url": "https://github.com/doctrine/orm.git",
"reference": "8ca99fdfdca3dc129ed93124e95e7f88b791a354"
"reference": "94986af28452da42a46a4489d1c958a2e5d710e5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/orm/zipball/8ca99fdfdca3dc129ed93124e95e7f88b791a354",
"reference": "8ca99fdfdca3dc129ed93124e95e7f88b791a354",
"url": "https://api.github.com/repos/doctrine/orm/zipball/94986af28452da42a46a4489d1c958a2e5d710e5",
"reference": "94986af28452da42a46a4489d1c958a2e5d710e5",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2",
"doctrine/collections": "^2.2",
"doctrine/dbal": "^3.8.2 || ^4",
"doctrine/cache": "^1.12.1 || ^2.1.1",
"doctrine/collections": "^1.5 || ^2.1",
"doctrine/common": "^3.0.3",
"doctrine/dbal": "^2.13.1 || ^3.2",
"doctrine/deprecations": "^0.5.3 || ^1",
"doctrine/event-manager": "^1.2 || ^2",
"doctrine/inflector": "^1.4 || ^2.0",
"doctrine/instantiator": "^1.3 || ^2",
"doctrine/lexer": "^3",
"doctrine/persistence": "^3.3.1",
"doctrine/lexer": "^2 || ^3",
"doctrine/persistence": "^2.4 || ^3",
"ext-ctype": "*",
"php": "^8.1",
"php": "^7.1 || ^8.0",
"psr/cache": "^1 || ^2 || ^3",
"symfony/console": "^5.4 || ^6.0 || ^7.0",
"symfony/var-exporter": "^6.3.9 || ^7.0"
"symfony/console": "^4.2 || ^5.0 || ^6.0 || ^7.0",
"symfony/polyfill-php72": "^1.23",
"symfony/polyfill-php80": "^1.16"
},
"conflict": {
"doctrine/annotations": "<1.13 || >= 3.0"
},
"require-dev": {
"doctrine/coding-standard": "^12.0",
"phpbench/phpbench": "^1.0",
"phpstan/phpstan": "1.10.59",
"phpunit/phpunit": "^10.4.0",
"doctrine/annotations": "^1.13 || ^2",
"doctrine/coding-standard": "^9.0.2 || ^12.0",
"phpbench/phpbench": "^0.16.10 || ^1.0",
"phpstan/phpstan": "~1.4.10 || 1.10.59",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
"psr/log": "^1 || ^2 || ^3",
"squizlabs/php_codesniffer": "3.7.2",
"symfony/cache": "^5.4 || ^6.2 || ^7.0",
"vimeo/psalm": "5.22.2"
"symfony/cache": "^4.4 || ^5.4 || ^6.4 || ^7.0",
"symfony/var-exporter": "^4.4 || ^5.4 || ^6.2 || ^7.0",
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0",
"vimeo/psalm": "4.30.0 || 5.22.2"
},
"suggest": {
"ext-dom": "Provides support for XSD validation for XML mapping files",
"symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0"
"symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0",
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
},
"bin": [
"bin/doctrine"
],
"type": "library",
"autoload": {
"psr-4": {
@ -1536,9 +1473,9 @@
],
"support": {
"issues": "https://github.com/doctrine/orm/issues",
"source": "https://github.com/doctrine/orm/tree/3.1.3"
"source": "https://github.com/doctrine/orm/tree/2.19.5"
},
"time": "2024-04-30T07:14:13+00:00"
"time": "2024-04-30T06:49:54+00:00"
},
{
"name": "doctrine/persistence",
@ -1695,49 +1632,50 @@
},
{
"name": "gedmo/doctrine-extensions",
"version": "v3.14.0",
"version": "v3.15.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine-extensions/DoctrineExtensions.git",
"reference": "3b5b5cba476b4ae32a55ef69ef2e59d64d5893cf"
"reference": "2a89103f4984d8970f3855284c8c04e6e6a63c0f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine-extensions/DoctrineExtensions/zipball/3b5b5cba476b4ae32a55ef69ef2e59d64d5893cf",
"reference": "3b5b5cba476b4ae32a55ef69ef2e59d64d5893cf",
"url": "https://api.github.com/repos/doctrine-extensions/DoctrineExtensions/zipball/2a89103f4984d8970f3855284c8c04e6e6a63c0f",
"reference": "2a89103f4984d8970f3855284c8c04e6e6a63c0f",
"shasum": ""
},
"require": {
"behat/transliterator": "^1.2",
"doctrine/annotations": "^1.13 || ^2.0",
"doctrine/collections": "^1.2 || ^2.0",
"doctrine/common": "^2.13 || ^3.0",
"doctrine/deprecations": "^1.0",
"doctrine/event-manager": "^1.2 || ^2.0",
"doctrine/persistence": "^2.2 || ^3.0",
"php": "^7.4 || ^8.0",
"psr/cache": "^1 || ^2 || ^3",
"symfony/cache": "^5.4 || ^6.0 || ^7.0",
"symfony/deprecation-contracts": "^2.1 || ^3.0"
"psr/clock": "^1",
"symfony/cache": "^5.4 || ^6.0 || ^7.0"
},
"conflict": {
"doctrine/dbal": "<3.2",
"doctrine/mongodb-odm": "<2.3",
"doctrine/orm": "<2.14.0 || 2.16.0 || 2.16.1",
"sebastian/comparator": "<2.0"
"doctrine/annotations": "<1.13 || >=3.0",
"doctrine/dbal": "<3.2 || >=4.0",
"doctrine/mongodb-odm": "<2.3 || >=3.0",
"doctrine/orm": "<2.14.0 || 2.16.0 || 2.16.1 || >=3.0"
},
"require-dev": {
"doctrine/annotations": "^1.13 || ^2.0",
"doctrine/cache": "^1.11 || ^2.0",
"doctrine/dbal": "^3.2",
"doctrine/doctrine-bundle": "^2.3",
"doctrine/mongodb-odm": "^2.3",
"doctrine/orm": "^2.14.0",
"friendsofphp/php-cs-fixer": "^3.14.0",
"nesbot/carbon": "^2.71 || 3.x-dev as 3.0",
"nesbot/carbon": "^2.71 || ^3.0",
"phpstan/phpstan": "^1.10.2",
"phpstan/phpstan-doctrine": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^9.6",
"rector/rector": "^0.18",
"rector/rector": "^0.19",
"symfony/console": "^5.4 || ^6.0 || ^7.0",
"symfony/phpunit-bridge": "^6.0 || ^7.0",
"symfony/yaml": "^5.4 || ^6.0 || ^7.0"
@ -1797,7 +1735,7 @@
"support": {
"email": "gediminas.morkevicius@gmail.com",
"issues": "https://github.com/doctrine-extensions/DoctrineExtensions/issues",
"source": "https://github.com/doctrine-extensions/DoctrineExtensions/tree/v3.14.0",
"source": "https://github.com/doctrine-extensions/DoctrineExtensions/tree/v3.15.0",
"wiki": "https://github.com/Atlantic18/DoctrineExtensions/tree/main/doc"
},
"funding": [
@ -1818,7 +1756,7 @@
"type": "github"
}
],
"time": "2023-12-03T09:10:34+00:00"
"time": "2024-02-12T15:17:22+00:00"
},
{
"name": "gesdinet/jwt-refresh-token-bundle",
@ -2269,16 +2207,16 @@
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "5.4.0",
"version": "5.4.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "298d2febfe79d03fe714eb871d5538da55205b1a"
"reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/298d2febfe79d03fe714eb871d5538da55205b1a",
"reference": "298d2febfe79d03fe714eb871d5538da55205b1a",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c",
"reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c",
"shasum": ""
},
"require": {
@ -2327,9 +2265,9 @@
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.0"
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1"
},
"time": "2024-04-09T21:13:58+00:00"
"time": "2024-05-21T05:55:05+00:00"
},
{
"name": "phpdocumentor/type-resolver",
@ -3012,21 +2950,21 @@
},
{
"name": "stof/doctrine-extensions-bundle",
"version": "v1.10.1",
"version": "v1.11.0",
"source": {
"type": "git",
"url": "https://github.com/stof/StofDoctrineExtensionsBundle.git",
"reference": "299d5333ce83941069852be36b949abbc776bf1d"
"reference": "9f7023e4c8a1c00a5627d41c1027a3f89e477630"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/stof/StofDoctrineExtensionsBundle/zipball/299d5333ce83941069852be36b949abbc776bf1d",
"reference": "299d5333ce83941069852be36b949abbc776bf1d",
"url": "https://api.github.com/repos/stof/StofDoctrineExtensionsBundle/zipball/9f7023e4c8a1c00a5627d41c1027a3f89e477630",
"reference": "9f7023e4c8a1c00a5627d41c1027a3f89e477630",
"shasum": ""
},
"require": {
"gedmo/doctrine-extensions": "^3.5.0",
"php": "^7.2.5 || ^8.0",
"gedmo/doctrine-extensions": "^3.15.0",
"php": "^7.4 || ^8.0",
"symfony/cache": "^5.4 || ^6.0 || ^7.0",
"symfony/config": "^5.4 || ^6.0 || ^7.0",
"symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0",
@ -3034,6 +2972,11 @@
"symfony/http-kernel": "^5.4 || ^6.0 || ^7.0"
},
"require-dev": {
"phpstan/phpstan": "^1.10",
"phpstan/phpstan-deprecation-rules": "^1.1",
"phpstan/phpstan-phpunit": "^1.3",
"phpstan/phpstan-strict-rules": "^1.5",
"phpstan/phpstan-symfony": "^1.3",
"symfony/mime": "^5.4 || ^6.0 || ^7.0",
"symfony/phpunit-bridge": "^v6.4.1 || ^7.0.1",
"symfony/security-core": "^5.4 || ^6.0 || ^7.0"
@ -3081,9 +3024,9 @@
],
"support": {
"issues": "https://github.com/stof/StofDoctrineExtensionsBundle/issues",
"source": "https://github.com/stof/StofDoctrineExtensionsBundle/tree/v1.10.1"
"source": "https://github.com/stof/StofDoctrineExtensionsBundle/tree/v1.11.0"
},
"time": "2023-12-09T09:33:39+00:00"
"time": "2024-02-13T14:43:20+00:00"
},
{
"name": "symfony/asset",
@ -6866,16 +6809,16 @@
},
{
"name": "twig/twig",
"version": "v3.10.2",
"version": "v3.10.3",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "7aaed0b8311a557cc8c4047a71fd03153a00e755"
"reference": "67f29781ffafa520b0bbfbd8384674b42db04572"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/7aaed0b8311a557cc8c4047a71fd03153a00e755",
"reference": "7aaed0b8311a557cc8c4047a71fd03153a00e755",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/67f29781ffafa520b0bbfbd8384674b42db04572",
"reference": "67f29781ffafa520b0bbfbd8384674b42db04572",
"shasum": ""
},
"require": {
@ -6929,7 +6872,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.10.2"
"source": "https://github.com/twigphp/Twig/tree/v3.10.3"
},
"funding": [
{
@ -6941,7 +6884,7 @@
"type": "tidelift"
}
],
"time": "2024-05-14T06:04:16+00:00"
"time": "2024-05-16T10:04:27+00:00"
},
{
"name": "webmozart/assert",

View File

@ -1,18 +1,24 @@
resources:
App\Entity\User:
processor: App\State\Processor\UserProcessor
input: App\Dto\Input\UserInput
output: App\Dto\Output\UserOutput
normalization_context:
groups: ['user:read']
groups: ['default', 'user:read']
denormalization_context:
groups: ['user:write']
operations:
ApiPlatform\Metadata\GetCollection:
provider: App\State\Provider\UserProvider
filters:
- 'api_platform.filter.user.order'
- 'api_platform.filter.user.search'
ApiPlatform\Metadata\Get: ~
ApiPlatform\Metadata\Put: ~
ApiPlatform\Metadata\Patch: ~
ApiPlatform\Metadata\Get:
provider: App\State\Provider\UserProvider
ApiPlatform\Metadata\Put:
provider: App\State\Provider\UserProvider
ApiPlatform\Metadata\Patch:
provider: App\State\Provider\UserProvider
ApiPlatform\Metadata\Post: ~
ApiPlatform\Metadata\Delete: ~

View File

@ -1,7 +1,7 @@
resources:
App\Entity\UserGroup:
normalization_context:
groups: ['user-group:read']
groups: ['default', 'user-group:read']
denormalization_context:
groups: ['user-group:write']
operations:

View File

@ -4,19 +4,15 @@ api_platform:
version: 1.0.0
path_segment_name_generator: 'api_platform.path_segment_name_generator.dash'
formats:
jsonld: ['application/ld+json']
jsonld: ['application/ld+json', 'application/json']
mapping:
paths: ['%kernel.project_dir%/config/api_platform']
paths: ['%kernel.project_dir%/config/api_platform', '%kernel.project_dir%/src/Dto']
defaults:
pagination_client_items_per_page: true
docs_formats:
jsonld: ['application/ld+json']
jsonopenapi: ['application/vnd.openapi+json']
html: ['text/html']
keep_legacy_inflector: false
use_symfony_listeners: true
graphql:
enabled: true
swagger:
versions: [3]
api_keys:

View File

@ -1,13 +1,10 @@
doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%'
# IMPORTANT: You MUST configure your server version,
# either here or in the DATABASE_URL env var (see .env file)
#server_version: '16'
profiling_collect_backtrace: '%kernel.debug%'
use_savepoints: true
mapping_types:
enum: string
orm:
auto_generate_proxy_classes: true
enable_lazy_ghost_objects: true

View File

@ -1,4 +1,6 @@
# Read the documentation: https://symfony.com/doc/current/bundles/StofDoctrineExtensionsBundle/index.html
# See the official DoctrineExtensions documentation for more details: https://github.com/doctrine-extensions/DoctrineExtensions/tree/main/doc
stof_doctrine_extensions:
default_locale: en_US
default_locale: es_ES
orm:
default:
timestampable: true
blameable: true

View File

@ -24,3 +24,8 @@ services:
decorates: 'api_platform.openapi.factory'
arguments: [ '@App\OpenApi\OpenApiFactory.inner' ]
autoconfigure: false
App\State\Provider\UserProvider:
bind:
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'

View File

@ -0,0 +1,33 @@
<?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 Version20240524063952 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 organizational_unit (id INT AUTO_INCREMENT NOT NULL, parent_id INT DEFAULT 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, description VARCHAR(255) DEFAULT NULL, comments VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_749AEB2DD17F50A6 (uuid), INDEX IDX_749AEB2D727ACA70 (parent_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D727ACA70 FOREIGN KEY (parent_id) REFERENCES organizational_unit (id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE organizational_unit DROP FOREIGN KEY FK_749AEB2D727ACA70');
$this->addSql('DROP TABLE organizational_unit');
}
}

View File

@ -0,0 +1,38 @@
<?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 Version20240524065625 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 network_settings (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, proxy VARCHAR(255) DEFAULT NULL, dns VARCHAR(255) DEFAULT NULL, netmask VARCHAR(255) DEFAULT NULL, router VARCHAR(255) DEFAULT NULL, ntp VARCHAR(255) DEFAULT NULL, p2p_time INT DEFAULT NULL, p2p_mode VARCHAR(255) DEFAULT NULL, mcast_ip VARCHAR(255) DEFAULT NULL, mcast_speed INT NOT NULL, mcast_mode VARCHAR(255) DEFAULT NULL, mcast_port INT DEFAULT NULL, UNIQUE INDEX UNIQ_48869B54D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE organizational_unit ADD network_settings_id INT DEFAULT NULL, ADD path VARCHAR(255) DEFAULT NULL');
$this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D9B9A36D0 FOREIGN KEY (network_settings_id) REFERENCES network_settings (id)');
$this->addSql('CREATE INDEX IDX_749AEB2D9B9A36D0 ON organizational_unit (network_settings_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE organizational_unit DROP FOREIGN KEY FK_749AEB2D9B9A36D0');
$this->addSql('DROP TABLE network_settings');
$this->addSql('DROP INDEX IDX_749AEB2D9B9A36D0 ON organizational_unit');
$this->addSql('ALTER TABLE organizational_unit DROP network_settings_id, DROP path');
}
}

View File

@ -0,0 +1,35 @@
<?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 Version20240524083309 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 user_organizational_unit (user_id INT NOT NULL, organizational_unit_id INT NOT NULL, INDEX IDX_5E59845FA76ED395 (user_id), INDEX IDX_5E59845FFB84408A (organizational_unit_id), PRIMARY KEY(user_id, organizational_unit_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE user_organizational_unit ADD CONSTRAINT FK_5E59845FA76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE');
$this->addSql('ALTER TABLE user_organizational_unit ADD CONSTRAINT FK_5E59845FFB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id) ON DELETE CASCADE');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE user_organizational_unit DROP FOREIGN KEY FK_5E59845FA76ED395');
$this->addSql('ALTER TABLE user_organizational_unit DROP FOREIGN KEY FK_5E59845FFB84408A');
$this->addSql('DROP TABLE user_organizational_unit');
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Dto\Input;
use App\Entity\UserGroup;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
final class UserGroupInput
{
#[Assert\NotBlank]
#[Groups(['user-group:write'])]
public ?string $name = null;
#[Groups(['user-group:write'])]
public array $roles = [];
#[Assert\NotNull]
#[Groups(['user-group:write'])]
public ?bool $enabled = false;
public function __construct(?UserGroup $userGroup = null)
{
if (!$userGroup) {
return;
}
$this->name = $userGroup->getName();
$this->roles = $userGroup->getRoles();
$this->enabled= $userGroup->isEnabled();
}
}

View File

@ -0,0 +1,69 @@
<?php
namespace App\Dto\Input;
use App\Entity\OrganizationalUnit;
use App\Entity\User;
use App\Entity\UserGroup;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
final class UserInput
{
#[Assert\NotBlank]
#[Groups(['user:write'])]
public ?string $username = null;
#[Groups(['user:write'])]
public array $roles = [];
/**
* @var OrganizationalUnit[]
*/
#[Groups(['user:write'])]
public array $allowedOrganizationalUnits = [];
#[Assert\NotBlank]
#[Assert\Length(min: 8)]
#[Groups(['user:write'])]
public string $password;
#[Assert\NotNull]
#[Groups(['user:write'])]
public ?bool $enabled = true;
/**
* @var UserGroup[]
*/
#[Groups(['user:write'])]
public array $userGroups = [];
public function __construct(?User $user = null)
{
if (!$user) {
return;
}
$this->username = $user->getUsername();
$this->roles = $user->getRoles();
$this->enabled= $user->isEnabled();
$this->userGroups = $user->getUserGroups()->toArray();
$this->allowedOrganizationalUnits = $user->getAllowedOrganizationalUnits()->toArray();
}
public function createOrUpdateEntity(?User $user = null): User
{
if (!$user) {
$user = new User();
}
$user->setUsername($this->username);
$user->setRoles($this->roles);
$user->setPassword($this->password);
$user->setEnabled($this->enabled);
$user->setUserGroups($this->userGroups);
//$user->setAllowedOrganizationalUnits($this->allowedOrganizationalUnits);
return $user;
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use App\Entity\AbstractEntity;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\Serializer\Annotation\Groups;
abstract class AbstractOutput
{
#[ApiProperty(identifier: true)]
#[Groups(['default'])]
public UuidInterface $uuid;
#[ApiProperty(identifier: false)]
#[Groups(['default'])]
public int $id;
public function __construct(AbstractEntity $entity)
{
$this->uuid = $entity->getUuid();
$this->id = $entity->getId();
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\Dto\Output;
use ApiPlatform\Metadata\Get;
use App\Entity\User;
use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'User')]
final class UserOutput extends AbstractOutput
{
#[Groups(['user:read'])]
public string $username;
#[Groups(['user:read'])]
public array $roles;
#[Groups(['user:read'])]
public bool $enabled;
#[Groups(['user:read'])]
public array $allowedOrganizationalUnits;
#[Groups(['user:read'])]
public \DateTime $createAt;
#[Groups(['user:read'])]
public ?string $createBy = null;
public function __construct(User $user)
{
parent::__construct($user);
$this->username = $user->getUsername();
$this->roles = $user->getRoles();
$this->enabled = $user->isEnabled();
$this->allowedOrganizationalUnits = $user->getAllowedOrganizationalUnits()->toArray();
$this->createAt = $user->getCreatedAt();
$this->createBy = $user->getCreatedBy();
}
}

View File

@ -36,6 +36,11 @@ abstract class AbstractEntity
return $this->id;
}
public function getUuid(): UuidInterface
{
return $this->uuid;
}
public function getMigrationId(): ?string
{
return $this->migrationId;

View File

@ -0,0 +1,23 @@
<?php
namespace App\Entity;
trait NameableTrait
{
#[ORM\Column(length: 255)]
private ?string $name = null;
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
}

View File

@ -0,0 +1,224 @@
<?php
namespace App\Entity;
use App\Repository\NetworkSettingsRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: NetworkSettingsRepository::class)]
class NetworkSettings extends AbstractEntity
{
#[ORM\Column(length: 255, nullable: true)]
private ?string $proxy = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $dns = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $netmask = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $router = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $ntp = null;
#[ORM\Column(nullable: true)]
private ?int $p2pTime = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $p2pMode = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $mcastIp = null;
#[ORM\Column]
private ?int $mcastSpeed = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $mcastMode = null;
#[ORM\Column(nullable: true)]
private ?int $mcastPort = null;
/**
* @var Collection<int, OrganizationalUnit>
*/
#[ORM\OneToMany(targetEntity: OrganizationalUnit::class, mappedBy: 'networkSettings')]
private Collection $organizationalUnits;
public function __construct()
{
parent::__construct();
$this->organizationalUnits = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getProxy(): ?string
{
return $this->proxy;
}
public function setProxy(?string $proxy): static
{
$this->proxy = $proxy;
return $this;
}
public function getDns(): ?string
{
return $this->dns;
}
public function setDns(?string $dns): static
{
$this->dns = $dns;
return $this;
}
public function getNetmask(): ?string
{
return $this->netmask;
}
public function setNetmask(?string $netmask): static
{
$this->netmask = $netmask;
return $this;
}
public function getRouter(): ?string
{
return $this->router;
}
public function setRouter(?string $router): static
{
$this->router = $router;
return $this;
}
public function getNtp(): ?string
{
return $this->ntp;
}
public function setNtp(?string $ntp): static
{
$this->ntp = $ntp;
return $this;
}
public function getP2pTime(): ?int
{
return $this->p2pTime;
}
public function setP2pTime(?int $p2pTime): static
{
$this->p2pTime = $p2pTime;
return $this;
}
public function getP2pMode(): ?string
{
return $this->p2pMode;
}
public function setP2pMode(?string $p2pMode): static
{
$this->p2pMode = $p2pMode;
return $this;
}
public function getMcastIp(): ?string
{
return $this->mcastIp;
}
public function setMcastIp(?string $mcastIp): static
{
$this->mcastIp = $mcastIp;
return $this;
}
public function getMcastSpeed(): ?int
{
return $this->mcastSpeed;
}
public function setMcastSpeed(int $mcastSpeed): static
{
$this->mcastSpeed = $mcastSpeed;
return $this;
}
public function getMcastMode(): ?string
{
return $this->mcastMode;
}
public function setMcastMode(?string $mcastMode): static
{
$this->mcastMode = $mcastMode;
return $this;
}
public function getMcastPort(): ?int
{
return $this->mcastPort;
}
public function setMcastPort(?int $mcastPort): static
{
$this->mcastPort = $mcastPort;
return $this;
}
/**
* @return Collection<int, OrganizationalUnit>
*/
public function getOrganizationalUnits(): Collection
{
return $this->organizationalUnits;
}
public function addOrganizationalUnit(OrganizationalUnit $organizationalUnit): static
{
if (!$this->organizationalUnits->contains($organizationalUnit)) {
$this->organizationalUnits->add($organizationalUnit);
$organizationalUnit->setNetworkSettings($this);
}
return $this;
}
public function removeOrganizationalUnit(OrganizationalUnit $organizationalUnit): static
{
if ($this->organizationalUnits->removeElement($organizationalUnit)) {
// set the owning side to null (unless already changed)
if ($organizationalUnit->getNetworkSettings() === $this) {
$organizationalUnit->setNetworkSettings(null);
}
}
return $this;
}
}

View File

@ -0,0 +1,169 @@
<?php
namespace App\Entity;
use App\Repository\OrganizationalUnitRepository;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[Gedmo\Tree(type: 'materialized-path')]
#[ORM\Entity(repositoryClass: OrganizationalUnitRepository::class)]
class OrganizationalUnit extends AbstractEntity
{
use NameableTrait;
#[ORM\Column(length: 255, nullable: true)]
private ?string $description = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $comments = null;
#[Gedmo\TreePath(separator: '/', appendId: true)]
#[ORM\Column(length: 255, nullable: true)]
private ?string $path = null;
#[Gedmo\TreeParent]
#[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'organizationalUnits')]
private ?self $parent = null;
/**
* @var Collection<int, self>
*/
#[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')]
private Collection $organizationalUnits;
#[ORM\ManyToOne(inversedBy: 'organizationalUnits')]
private ?NetworkSettings $networkSettings = null;
/**
* @var Collection<int, User>
*/
#[ORM\ManyToMany(targetEntity: User::class, mappedBy: 'allowedOrganizationalUnits')]
private Collection $users;
public function __construct()
{
parent::__construct();
$this->organizationalUnits = new ArrayCollection();
$this->users = new ArrayCollection();
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
public function getComments(): ?string
{
return $this->comments;
}
public function setComments(?string $comments): static
{
$this->comments = $comments;
return $this;
}
public function getPath(): ?string
{
return $this->path;
}
public function setPath(?string $path): static
{
$this->path = $path;
return $this;
}
public function getParent(): ?self
{
return $this->parent;
}
public function setParent(?self $parent): static
{
$this->parent = $parent;
return $this;
}
/**
* @return Collection<int, self>
*/
public function getOrganizationalUnits(): Collection
{
return $this->organizationalUnits;
}
public function addOrganizationalUnit(self $organizationalUnit): static
{
if (!$this->organizationalUnits->contains($organizationalUnit)) {
$this->organizationalUnits->add($organizationalUnit);
$organizationalUnit->setParent($this);
}
return $this;
}
public function removeOrganizationalUnit(self $organizationalUnit): static
{
if ($this->organizationalUnits->removeElement($organizationalUnit)) {
// set the owning side to null (unless already changed)
if ($organizationalUnit->getParent() === $this) {
$organizationalUnit->setParent(null);
}
}
return $this;
}
public function getNetworkSettings(): ?NetworkSettings
{
return $this->networkSettings;
}
public function setNetworkSettings(?NetworkSettings $networkSettings): static
{
$this->networkSettings = $networkSettings;
return $this;
}
/**
* @return Collection<int, User>
*/
public function getUsers(): Collection
{
return $this->users;
}
public function addUser(User $user): static
{
if (!$this->users->contains($user)) {
$this->users->add($user);
$user->addAllowedOrganizationalUnit($this);
}
return $this;
}
public function removeUser(User $user): static
{
if ($this->users->removeElement($user)) {
$user->removeAllowedOrganizationalUnit($this);
}
return $this;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Entity;
trait ToggleableTrait
{
#[ORM\Column(type: 'boolean')]
private bool $enabled = true;
public function isEnabled(): bool
{
return $this->enabled;
}
public function setEnabled(bool $enabled): static
{
$this->enabled = $enabled;
return $this;
}
}

View File

@ -13,6 +13,11 @@ use Symfony\Component\Security\Core\User\UserInterface;
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_USERNAME', fields: ['username'])]
class User extends AbstractEntity implements UserInterface, PasswordAuthenticatedUserInterface
{
use ToggleableTrait;
const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN';
const ROLE_USER = 'ROLE_USER';
#[ORM\Column(length: 180)]
private ?string $username = null;
@ -34,10 +39,17 @@ class User extends AbstractEntity implements UserInterface, PasswordAuthenticate
#[ORM\ManyToMany(targetEntity: UserGroup::class, mappedBy: 'users')]
private Collection $userGroups;
/**
* @var Collection<int, OrganizationalUnit>
*/
#[ORM\ManyToMany(targetEntity: OrganizationalUnit::class, inversedBy: 'users')]
private Collection $allowedOrganizationalUnits;
public function __construct()
{
parent::__construct();
$this->userGroups = new ArrayCollection();
$this->allowedOrganizationalUnits = new ArrayCollection();
}
public function getUsername(): ?string
@ -70,10 +82,18 @@ class User extends AbstractEntity implements UserInterface, PasswordAuthenticate
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
if (!array_search(self::ROLE_USER, $roles, true)){
$roles[] = self::ROLE_USER;
}
foreach ($this->getUserGroups() as $userGroup) {
if ($userGroup->isEnabled()){
$roles = array_merge($roles, $userGroup->getRoles());
}
}
return array_merge(array_unique($roles));
}
/**
@ -118,6 +138,17 @@ class User extends AbstractEntity implements UserInterface, PasswordAuthenticate
return $this->userGroups;
}
public function setUserGroups(array $userGroup): static
{
$this->userGroups->clear();
foreach ($userGroup as $group){
$this->addUserGroup($group);
}
return $this;
}
public function addUserGroup(UserGroup $userGroup): static
{
if (!$this->userGroups->contains($userGroup)) {
@ -136,4 +167,28 @@ class User extends AbstractEntity implements UserInterface, PasswordAuthenticate
return $this;
}
/**
* @return Collection<int, OrganizationalUnit>
*/
public function getAllowedOrganizationalUnits(): Collection
{
return $this->allowedOrganizationalUnits;
}
public function addAllowedOrganizationalUnit(OrganizationalUnit $allowedOrganizationalUnit): static
{
if (!$this->allowedOrganizationalUnits->contains($allowedOrganizationalUnit)) {
$this->allowedOrganizationalUnits->add($allowedOrganizationalUnit);
}
return $this;
}
public function removeAllowedOrganizationalUnit(OrganizationalUnit $allowedOrganizationalUnit): static
{
$this->allowedOrganizationalUnits->removeElement($allowedOrganizationalUnit);
return $this;
}
}

View File

@ -11,6 +11,8 @@ use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: UserGroupRepository::class)]
class UserGroup extends AbstractEntity
{
use ToggleableTrait;
#[ORM\Column(length: 255)]
private ?string $name = null;

View File

View File

@ -0,0 +1,35 @@
<?php
namespace App\Repository;
use App\Entity\AbstractEntity;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
abstract class AbstractRepository extends ServiceEntityRepository
{
public function __construct(
ManagerRegistry $registry,
string $entityClass)
{
parent::__construct($registry, $entityClass);
}
public function save(AbstractEntity $entity, bool $flush = true, ?string $action = null): void
{
$this->getEntityManager()->persist($entity);
if ($flush) {
$this->getEntityManager()->flush();
}
}
public function delete (AbstractEntity $entity, bool $flush = true): void
{
$this->getEntityManager()->remove($entity);
if ($flush) {
$this->getEntityManager()->flush();
}
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\Repository;
use App\Entity\NetworkSettings;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<NetworkSettings>
*/
class NetworkSettingsRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, NetworkSettings::class);
}
// /**
// * @return NetworkSettings[] Returns an array of NetworkSettings objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('n')
// ->andWhere('n.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('n.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?NetworkSettings
// {
// return $this->createQueryBuilder('n')
// ->andWhere('n.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\Repository;
use App\Entity\OrganizationalUnit;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<OrganizationalUnit>
*/
class OrganizationalUnitRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, OrganizationalUnit::class);
}
// /**
// * @return OrganizationalUnit[] Returns an array of OrganizationalUnit objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('o')
// ->andWhere('o.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('o.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?OrganizationalUnit
// {
// return $this->createQueryBuilder('o')
// ->andWhere('o.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@ -12,7 +12,7 @@ use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
/**
* @extends ServiceEntityRepository<User>
*/
class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface
class UserRepository extends AbstractRepository implements PasswordUpgraderInterface
{
public function __construct(ManagerRegistry $registry)
{
@ -32,29 +32,4 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader
$this->getEntityManager()->persist($user);
$this->getEntityManager()->flush();
}
// /**
// * @return User[] Returns an array of User objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('u')
// ->andWhere('u.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('u.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?User
// {
// return $this->createQueryBuilder('u')
// ->andWhere('u.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@ -0,0 +1,62 @@
<?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\UserInput;
use App\Dto\Output\UserOutput;
use App\Repository\UserRepository;
class UserProcessor implements ProcessorInterface
{
public function __construct(
private UserRepository $userRepository,
private ValidatorInterface $validator
)
{
}
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = [])
{
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);
}
}
private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): UserOutput
{
if (!($data instanceof UserInput)) {
throw new \Exception(sprintf('data is not instance of %s', UserInput::class));
}
$entity = null;
if (isset($uriVariables['uuid'])) {
$entity = $this->userRepository->findOneByUuid($uriVariables['id']);
}
$user = $data->createOrUpdateEntity($entity);
$this->validator->validate($user);
$this->userRepository->save($user);
return new UserOutput($user);
}
private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null
{
$user = $this->userRepository->findOneByUuid($uriVariables['id']);
$this->userRepository->delete($user);
return null;
}
}

View File

@ -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\UserInput;
use App\Dto\Output\UserOutput;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class UserProvider implements ProviderInterface
{
public function __construct(
private readonly ProviderInterface $collectionProvider,
private readonly 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|array|null
{
$paginator = $this->collectionProvider->provide($operation, $uriVariables, $context);
$items = new \ArrayObject();
foreach ($paginator->getIterator() as $item){
$items[] = new UserOutput($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('User not found');
}
return new UserOutput($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 ? new UserInput($item) : null;
}
return new UserInput();
}
}

View File

@ -13,15 +13,6 @@
"src/ApiResource/.gitignore"
]
},
"doctrine/annotations": {
"version": "2.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.10",
"ref": "64d8583af5ea57b7afa4aba4b159907f3a148b05"
}
},
"doctrine/doctrine-bundle": {
"version": "2.12",
"recipe": {