Merge pull request 'Setup API Platform' (#6) from feature/api-platform into main
Reviewed-on: https://codefirst.iut.uca.fr/git/clement.freville2/herbarium/pulls/6
This commit is contained in:
@@ -59,6 +59,8 @@ steps:
|
||||
environment:
|
||||
# Disable HTTPS redirection as it served by a reverse proxy
|
||||
CODEFIRST_CLIENTDRONE_ENV_SERVER_NAME: http://codefirst.iut.uca.fr
|
||||
CODEFIRST_CLIENTDRONE_ENV_CORS_ALLOW_ORIGIN: https://codefirst.iut.uca.fr
|
||||
CODEFIRST_CLIENTDRONE_ENV_ASSETS_BASE_PATH: /containers/clementfreville2-herbarium
|
||||
depends_on:
|
||||
- docker-image
|
||||
when:
|
||||
|
6
.env
6
.env
@@ -14,6 +14,8 @@
|
||||
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
|
||||
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
|
||||
|
||||
ASSETS_BASE_PATH=/
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
APP_ENV=dev
|
||||
APP_SECRET=654d4972fc24500c7b43763fc3b3efa7
|
||||
@@ -39,3 +41,7 @@ MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
|
||||
###> symfony/mailer ###
|
||||
# MAILER_DSN=null://null
|
||||
###< symfony/mailer ###
|
||||
|
||||
###> nelmio/cors-bundle ###
|
||||
CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$'
|
||||
###< nelmio/cors-bundle ###
|
||||
|
@@ -26,6 +26,7 @@ COPY . .
|
||||
RUN composer dump-autoload --classmap-authoritative --no-dev \
|
||||
&& composer dump-env prod \
|
||||
&& composer run-script --no-dev post-install-cmd \
|
||||
&& php bin/console asset-map:compile \
|
||||
;
|
||||
RUN rm -Rf frankenphp/
|
||||
|
||||
|
@@ -7,10 +7,12 @@
|
||||
"php": ">=8.2",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"api-platform/core": "^3.3",
|
||||
"doctrine/dbal": "^3",
|
||||
"doctrine/doctrine-bundle": "^2.12",
|
||||
"doctrine/doctrine-migrations-bundle": "^3.3",
|
||||
"doctrine/orm": "^3.1",
|
||||
"nelmio/cors-bundle": "^2.4",
|
||||
"phpdocumentor/reflection-docblock": "^5.4",
|
||||
"phpstan/phpdoc-parser": "^1.29",
|
||||
"runtime/frankenphp-symfony": "^0.2.0",
|
||||
@@ -97,6 +99,7 @@
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"dama/doctrine-test-bundle": "*",
|
||||
"doctrine/doctrine-fixtures-bundle": "^3.6",
|
||||
"fakerphp/faker": "^1.23",
|
||||
"phpstan/phpstan": "^1.11",
|
||||
|
375
composer.lock
generated
375
composer.lock
generated
@@ -4,8 +4,196 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "888e1953f86d0f1fe9b271b85aab0ed0",
|
||||
"content-hash": "cce9cbfaf4a49449e6431a8515f9d9eb",
|
||||
"packages": [
|
||||
{
|
||||
"name": "api-platform/core",
|
||||
"version": "v3.3.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/api-platform/core.git",
|
||||
"reference": "b5a93fb0bb855273aabb0807505ba61b68813246"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/api-platform/core/zipball/b5a93fb0bb855273aabb0807505ba61b68813246",
|
||||
"reference": "b5a93fb0bb855273aabb0807505ba61b68813246",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/inflector": "^1.0 || ^2.0",
|
||||
"php": ">=8.1",
|
||||
"psr/cache": "^1.0 || ^2.0 || ^3.0",
|
||||
"psr/container": "^1.0 || ^2.0",
|
||||
"symfony/deprecation-contracts": "^3.1",
|
||||
"symfony/http-foundation": "^6.4 || ^7.0",
|
||||
"symfony/http-kernel": "^6.4 || ^7.0",
|
||||
"symfony/property-access": "^6.4 || ^7.0",
|
||||
"symfony/property-info": "^6.4 || ^7.0",
|
||||
"symfony/serializer": "^6.4 || ^7.0",
|
||||
"symfony/translation-contracts": "^3.3",
|
||||
"symfony/web-link": "^6.4 || ^7.0",
|
||||
"willdurand/negotiation": "^3.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/common": "<3.2.2",
|
||||
"doctrine/dbal": "<2.10",
|
||||
"doctrine/mongodb-odm": "<2.4",
|
||||
"doctrine/orm": "<2.14.0",
|
||||
"doctrine/persistence": "<1.3",
|
||||
"elasticsearch/elasticsearch": ">=8.0,<8.4",
|
||||
"phpspec/prophecy": "<1.15",
|
||||
"phpunit/phpunit": "<9.5",
|
||||
"symfony/framework-bundle": "6.4.6 || 7.0.6",
|
||||
"symfony/var-exporter": "<6.1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"behat/behat": "^3.11",
|
||||
"behat/mink": "^1.9",
|
||||
"doctrine/cache": "^1.11 || ^2.1",
|
||||
"doctrine/common": "^3.2.2",
|
||||
"doctrine/dbal": "^3.4.0",
|
||||
"doctrine/doctrine-bundle": "^1.12 || ^2.0",
|
||||
"doctrine/mongodb-odm": "^2.2",
|
||||
"doctrine/mongodb-odm-bundle": "^4.0 || ^5.0",
|
||||
"doctrine/orm": "^2.14 || ^3.0",
|
||||
"elasticsearch/elasticsearch": "^7.11 || ^8.4",
|
||||
"friends-of-behat/mink-browserkit-driver": "^1.3.1",
|
||||
"friends-of-behat/mink-extension": "^2.2",
|
||||
"friends-of-behat/symfony-extension": "^2.1",
|
||||
"guzzlehttp/guzzle": "^6.0 || ^7.0",
|
||||
"jangregor/phpstan-prophecy": "^1.0",
|
||||
"justinrainbow/json-schema": "^5.2.1",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpdoc-parser": "^1.13",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpstan/phpstan-doctrine": "^1.0",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpstan/phpstan-symfony": "^1.0",
|
||||
"phpunit/phpunit": "^9.6",
|
||||
"psr/log": "^1.0 || ^2.0 || ^3.0",
|
||||
"ramsey/uuid": "^3.9.7 || ^4.0",
|
||||
"ramsey/uuid-doctrine": "^1.4 || ^2.0",
|
||||
"sebastian/comparator": "<5.0",
|
||||
"soyuka/contexts": "v3.3.9",
|
||||
"soyuka/pmu": "^0.0.2",
|
||||
"soyuka/stubs-mongodb": "^1.0",
|
||||
"symfony/asset": "^6.4 || ^7.0",
|
||||
"symfony/browser-kit": "^6.4 || ^7.0",
|
||||
"symfony/cache": "^6.4 || ^7.0",
|
||||
"symfony/config": "^6.4 || ^7.0",
|
||||
"symfony/console": "^6.4 || ^7.0",
|
||||
"symfony/css-selector": "^6.4 || ^7.0",
|
||||
"symfony/dependency-injection": "^6.4 || ^7.0.12",
|
||||
"symfony/doctrine-bridge": "^6.4 || ^7.0",
|
||||
"symfony/dom-crawler": "^6.4 || ^7.0",
|
||||
"symfony/error-handler": "^6.4 || ^7.0",
|
||||
"symfony/event-dispatcher": "^6.4 || ^7.0",
|
||||
"symfony/expression-language": "^6.4 || ^7.0",
|
||||
"symfony/finder": "^6.4 || ^7.0",
|
||||
"symfony/form": "^6.4 || ^7.0",
|
||||
"symfony/framework-bundle": "^6.4 || ^7.0",
|
||||
"symfony/http-client": "^6.4 || ^7.0",
|
||||
"symfony/intl": "^6.4 || ^7.0",
|
||||
"symfony/maker-bundle": "^1.24",
|
||||
"symfony/mercure-bundle": "*",
|
||||
"symfony/messenger": "^6.4 || ^7.0",
|
||||
"symfony/phpunit-bridge": "^6.4.1 || ^7.0",
|
||||
"symfony/routing": "^6.4 || ^7.0",
|
||||
"symfony/security-bundle": "^6.4 || ^7.0",
|
||||
"symfony/security-core": "^6.4 || ^7.0",
|
||||
"symfony/stopwatch": "^6.4 || ^7.0",
|
||||
"symfony/twig-bundle": "^6.4 || ^7.0",
|
||||
"symfony/uid": "^6.4 || ^7.0",
|
||||
"symfony/validator": "^6.4 || ^7.0",
|
||||
"symfony/web-profiler-bundle": "^6.4 || ^7.0",
|
||||
"symfony/yaml": "^6.4 || ^7.0",
|
||||
"twig/twig": "^1.42.3 || ^2.12 || ^3.0",
|
||||
"webonyx/graphql-php": "^14.0 || ^15.0"
|
||||
},
|
||||
"suggest": {
|
||||
"doctrine/mongodb-odm-bundle": "To support MongoDB. Only versions 4.0 and later are supported.",
|
||||
"elasticsearch/elasticsearch": "To support Elasticsearch.",
|
||||
"ocramius/package-versions": "To display the API Platform's version in the debug bar.",
|
||||
"phpstan/phpdoc-parser": "To support extracting metadata from PHPDoc.",
|
||||
"psr/cache-implementation": "To use metadata caching.",
|
||||
"ramsey/uuid": "To support Ramsey's UUID identifiers.",
|
||||
"symfony/cache": "To have metadata caching when using Symfony integration.",
|
||||
"symfony/config": "To load XML configuration files.",
|
||||
"symfony/expression-language": "To use authorization features.",
|
||||
"symfony/http-client": "To use the HTTP cache invalidation system.",
|
||||
"symfony/messenger": "To support messenger integration.",
|
||||
"symfony/security": "To use authorization features.",
|
||||
"symfony/twig-bundle": "To use the Swagger UI integration.",
|
||||
"symfony/uid": "To support Symfony UUID/ULID identifiers.",
|
||||
"symfony/web-profiler-bundle": "To use the data collector.",
|
||||
"webonyx/graphql-php": "To support GraphQL."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.3.x-dev"
|
||||
},
|
||||
"symfony": {
|
||||
"require": "^6.4 || ^7.0"
|
||||
},
|
||||
"projects": [
|
||||
"api-platform/doctrine-common",
|
||||
"api-platform/doctrine-orm",
|
||||
"api-platform/doctrine-odm",
|
||||
"api-platform/metadata",
|
||||
"api-platform/json-schema",
|
||||
"api-platform/elasticsearch",
|
||||
"api-platform/jsonld",
|
||||
"api-platform/hydra",
|
||||
"api-platform/openapi",
|
||||
"api-platform/graphql",
|
||||
"api-platform/http-cache",
|
||||
"api-platform/documentation",
|
||||
"api-platform/parameter-validator",
|
||||
"api-platform/ramsey-uuid",
|
||||
"api-platform/serializer",
|
||||
"api-platform/state",
|
||||
"api-platform/symfony",
|
||||
"api-platform/validator"
|
||||
]
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"ApiPlatform\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kévin Dunglas",
|
||||
"email": "kevin@dunglas.fr",
|
||||
"homepage": "https://dunglas.fr"
|
||||
}
|
||||
],
|
||||
"description": "Build a fully-featured hypermedia or GraphQL API in minutes!",
|
||||
"homepage": "https://api-platform.com",
|
||||
"keywords": [
|
||||
"Hydra",
|
||||
"JSON-LD",
|
||||
"api",
|
||||
"graphql",
|
||||
"hal",
|
||||
"jsonapi",
|
||||
"openapi",
|
||||
"rest",
|
||||
"swagger"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/api-platform/core/issues",
|
||||
"source": "https://github.com/api-platform/core/tree/v3.3.5"
|
||||
},
|
||||
"time": "2024-05-29T05:48:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
"version": "3.4.0",
|
||||
@@ -1478,6 +1666,68 @@
|
||||
],
|
||||
"time": "2024-04-12T21:02:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nelmio/cors-bundle",
|
||||
"version": "2.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nelmio/NelmioCorsBundle.git",
|
||||
"reference": "78fcdb91f76b080a1008133def9c7f613833933d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nelmio/NelmioCorsBundle/zipball/78fcdb91f76b080a1008133def9c7f613833933d",
|
||||
"reference": "78fcdb91f76b080a1008133def9c7f613833933d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"psr/log": "^1.0 || ^2.0 || ^3.0",
|
||||
"symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.3.6",
|
||||
"symfony/phpunit-bridge": "^5.4 || ^6.0 || ^7.0"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Nelmio\\CorsBundle\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nelmio",
|
||||
"homepage": "http://nelm.io"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://github.com/nelmio/NelmioCorsBundle/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Adds CORS (Cross-Origin Resource Sharing) headers support in your Symfony application",
|
||||
"keywords": [
|
||||
"api",
|
||||
"cors",
|
||||
"crossdomain"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nelmio/NelmioCorsBundle/issues",
|
||||
"source": "https://github.com/nelmio/NelmioCorsBundle/tree/2.4.0"
|
||||
},
|
||||
"time": "2023-11-30T16:41:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
"version": "2.2.0",
|
||||
@@ -7548,9 +7798,132 @@
|
||||
"source": "https://github.com/webmozarts/assert/tree/1.11.0"
|
||||
},
|
||||
"time": "2022-06-03T18:03:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "willdurand/negotiation",
|
||||
"version": "3.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/willdurand/Negotiation.git",
|
||||
"reference": "68e9ea0553ef6e2ee8db5c1d98829f111e623ec2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/willdurand/Negotiation/zipball/68e9ea0553ef6e2ee8db5c1d98829f111e623ec2",
|
||||
"reference": "68e9ea0553ef6e2ee8db5c1d98829f111e623ec2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "^5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Negotiation\\": "src/Negotiation"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "William Durand",
|
||||
"email": "will+git@drnd.me"
|
||||
}
|
||||
],
|
||||
"description": "Content Negotiation tools for PHP provided as a standalone library.",
|
||||
"homepage": "http://williamdurand.fr/Negotiation/",
|
||||
"keywords": [
|
||||
"accept",
|
||||
"content",
|
||||
"format",
|
||||
"header",
|
||||
"negotiation"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/willdurand/Negotiation/issues",
|
||||
"source": "https://github.com/willdurand/Negotiation/tree/3.1.0"
|
||||
},
|
||||
"time": "2022-01-30T20:08:53+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "dama/doctrine-test-bundle",
|
||||
"version": "v8.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dmaicher/doctrine-test-bundle.git",
|
||||
"reference": "1f81a280ea63f049d24e9c8ce00e557b18e0ff2f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dmaicher/doctrine-test-bundle/zipball/1f81a280ea63f049d24e9c8ce00e557b18e0ff2f",
|
||||
"reference": "1f81a280ea63f049d24e9c8ce00e557b18e0ff2f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/dbal": "^3.3 || ^4.0",
|
||||
"doctrine/doctrine-bundle": "^2.11.0",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"psr/cache": "^1.0 || ^2.0 || ^3.0",
|
||||
"symfony/cache": "^5.4 || ^6.3 || ^7.0",
|
||||
"symfony/framework-bundle": "^5.4 || ^6.3 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"behat/behat": "^3.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.27",
|
||||
"phpstan/phpstan": "^1.2",
|
||||
"phpunit/phpunit": "^8.0 || ^9.0 || ^10.0 || ^11.0",
|
||||
"symfony/phpunit-bridge": "^6.3",
|
||||
"symfony/process": "^5.4 || ^6.3 || ^7.0",
|
||||
"symfony/yaml": "^5.4 || ^6.3 || ^7.0"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "8.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"DAMA\\DoctrineTestBundle\\": "src/DAMA/DoctrineTestBundle"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "David Maicher",
|
||||
"email": "mail@dmaicher.de"
|
||||
}
|
||||
],
|
||||
"description": "Symfony bundle to isolate doctrine database tests and improve test performance",
|
||||
"keywords": [
|
||||
"doctrine",
|
||||
"isolation",
|
||||
"performance",
|
||||
"symfony",
|
||||
"testing",
|
||||
"tests"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/dmaicher/doctrine-test-bundle/issues",
|
||||
"source": "https://github.com/dmaicher/doctrine-test-bundle/tree/v8.2.0"
|
||||
},
|
||||
"time": "2024-05-28T15:41:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/data-fixtures",
|
||||
"version": "1.7.0",
|
||||
|
@@ -15,4 +15,7 @@ return [
|
||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
|
||||
SymfonyCasts\Bundle\VerifyEmail\SymfonyCastsVerifyEmailBundle::class => ['all' => true],
|
||||
Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
|
||||
ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
|
||||
DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],
|
||||
];
|
||||
|
19
config/packages/api_platform.yaml
Normal file
19
config/packages/api_platform.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
api_platform:
|
||||
title: Hello API Platform
|
||||
version: 1.0.0
|
||||
formats:
|
||||
jsonld: ['application/ld+json']
|
||||
json: ['application/json']
|
||||
docs_formats:
|
||||
jsonld: ['application/ld+json']
|
||||
jsonopenapi: ['application/vnd.openapi+json']
|
||||
html: ['text/html']
|
||||
defaults:
|
||||
stateless: true
|
||||
cache_headers:
|
||||
vary: ['Content-Type', 'Authorization', 'Origin']
|
||||
extra_properties:
|
||||
standard_put: true
|
||||
rfc_7807_compliant_errors: true
|
||||
keep_legacy_inflector: false
|
||||
use_symfony_listeners: true
|
5
config/packages/dama_doctrine_test_bundle.yaml
Normal file
5
config/packages/dama_doctrine_test_bundle.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
when@test:
|
||||
dama_doctrine_test:
|
||||
enable_static_connection: true
|
||||
enable_static_meta_data_cache: true
|
||||
enable_static_query_cache: true
|
@@ -3,6 +3,9 @@ framework:
|
||||
secret: '%env(APP_SECRET)%'
|
||||
#csrf_protection: true
|
||||
|
||||
assets:
|
||||
base_path: '%env(ASSETS_BASE_PATH)%'
|
||||
|
||||
# Note that the session will be started ONLY if you read or write from it.
|
||||
session: true
|
||||
|
||||
|
10
config/packages/nelmio_cors.yaml
Normal file
10
config/packages/nelmio_cors.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
nelmio_cors:
|
||||
defaults:
|
||||
origin_regex: true
|
||||
allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
|
||||
allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
|
||||
allow_headers: ['Content-Type', 'Authorization']
|
||||
expose_headers: ['Link']
|
||||
max_age: 3600
|
||||
paths:
|
||||
'^/': null
|
4
config/routes/api_platform.yaml
Normal file
4
config/routes/api_platform.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
api_platform:
|
||||
resource: .
|
||||
type: api_platform
|
||||
prefix: /api
|
@@ -20,5 +20,9 @@ services:
|
||||
- '../src/Entity/'
|
||||
- '../src/Kernel.php'
|
||||
|
||||
App\State\UserPasswordHasher:
|
||||
bind:
|
||||
$processor: '@api_platform.doctrine.orm.state.persist_processor'
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
# please note that last definitions always *replace* previous ones
|
||||
|
@@ -34,5 +34,6 @@
|
||||
</listeners>
|
||||
|
||||
<extensions>
|
||||
<extension class="DAMA\DoctrineTestBundle\PHPUnit\PHPUnitExtension" />
|
||||
</extensions>
|
||||
</phpunit>
|
||||
|
@@ -2,38 +2,62 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
|
||||
use ApiPlatform\Metadata;
|
||||
use ApiPlatform\Metadata\ApiProperty;
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\GetCollection;
|
||||
use App\Repository\PostRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: PostRepository::class)]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
#[ApiResource(
|
||||
operations: [new Metadata\Post(), new Metadata\Get(), new Metadata\Put(), new Metadata\Delete(), new Metadata\Patch()],
|
||||
normalizationContext: ['groups' => ['post:collection:read', 'post:read']],
|
||||
)]
|
||||
#[GetCollection(normalizationContext: ['groups' => ['post:collection:read']])]
|
||||
#[Metadata\ApiFilter(filterClass: SearchFilter::class, properties: ['species' => 'exact'])]
|
||||
class Post
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
#[Groups(['post:collection:read'])]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column]
|
||||
#[Groups(['post:collection:read'])]
|
||||
private ?\DateTimeImmutable $foundDate = null;
|
||||
|
||||
#[ORM\Column]
|
||||
#[ApiProperty(writable: false)]
|
||||
#[Groups(['post:collection:read'])]
|
||||
private ?\DateTimeImmutable $publicationDate = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
#[Groups(['post:collection:read'])]
|
||||
private ?float $latitude = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
#[Groups(['post:collection:read'])]
|
||||
private ?float $longitude = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
#[Groups(['post:collection:read'])]
|
||||
private ?float $altitude = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT)]
|
||||
#[Groups(['post:read'])]
|
||||
private ?string $commentary = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'posts')]
|
||||
#[ApiProperty(readableLink: false)]
|
||||
#[Groups(['post:collection:read'])]
|
||||
private ?Species $species = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
@@ -122,4 +146,13 @@ class Post
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
#[ORM\PrePersist]
|
||||
#[ORM\PreUpdate]
|
||||
public function setPublicationDateValue(): void
|
||||
{
|
||||
if ($this->publicationDate === null) {
|
||||
$this->publicationDate = new \DateTimeImmutable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,32 +2,45 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use ApiPlatform\Metadata;
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use App\Repository\SpeciesRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: SpeciesRepository::class)]
|
||||
#[ApiResource(
|
||||
operations: [new Metadata\Post(), new Metadata\Get(), new Metadata\Put(), new Metadata\Delete(), new Metadata\Patch()],
|
||||
normalizationContext: ['groups' => ['species:collection:read', 'species:read']],
|
||||
)]
|
||||
#[Metadata\GetCollection(normalizationContext: ['groups' => ['species:collection:read']])]
|
||||
class Species
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
#[Groups(['species:collection:read'])]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
#[Groups(['species:collection:read'])]
|
||||
private ?string $scientific_name = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
#[Groups(['species:collection:read'])]
|
||||
private ?string $vernacular_name = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
#[Groups(['species:collection:read'])]
|
||||
private ?string $region = null;
|
||||
|
||||
/**
|
||||
* @var Collection<int, Post>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: Post::class, mappedBy: 'species')]
|
||||
#[Groups(['species:read'])]
|
||||
private Collection $posts;
|
||||
|
||||
public function __construct()
|
||||
|
@@ -2,15 +2,36 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\Delete;
|
||||
use ApiPlatform\Metadata\Get;
|
||||
use ApiPlatform\Metadata\GetCollection;
|
||||
use ApiPlatform\Metadata\Patch;
|
||||
use ApiPlatform\Metadata\Put;
|
||||
use App\Repository\UserRepository;
|
||||
use App\State\UserPasswordHasher;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Serializer\Attribute\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
||||
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])]
|
||||
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(),
|
||||
new \ApiPlatform\Metadata\Post(validationContext: ['groups' => ['Default', 'user:create']], processor: UserPasswordHasher::class),
|
||||
new Get(),
|
||||
new Put(processor: UserPasswordHasher::class),
|
||||
new Patch(processor: UserPasswordHasher::class),
|
||||
new Delete(),
|
||||
],
|
||||
normalizationContext: ['groups' => ['user:read']],
|
||||
denormalizationContext: ['groups' => ['user:create', 'user:update']],
|
||||
)]
|
||||
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
{
|
||||
#[ORM\Id]
|
||||
@@ -18,6 +39,8 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[Assert\Email]
|
||||
#[Groups(['user:read', 'user:create', 'user:update'])]
|
||||
#[ORM\Column(length: 180)]
|
||||
private ?string $email = null;
|
||||
|
||||
@@ -33,6 +56,10 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
#[ORM\Column]
|
||||
private ?string $password = null;
|
||||
|
||||
#[Assert\NotBlank(groups: ['user:create'])]
|
||||
#[Groups(['user:create', 'user:update'])]
|
||||
private ?string $plainPassword = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
@@ -99,6 +126,18 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPlainPassword(): ?string
|
||||
{
|
||||
return $this->plainPassword;
|
||||
}
|
||||
|
||||
public function setPlainPassword(?string $plainPassword): self
|
||||
{
|
||||
$this->plainPassword = $plainPassword;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserInterface
|
||||
*/
|
||||
|
44
src/State/UserPasswordHasher.php
Normal file
44
src/State/UserPasswordHasher.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
use App\Entity\User;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* @implements ProcessorInterface<User, User>
|
||||
*/
|
||||
final readonly class UserPasswordHasher implements ProcessorInterface
|
||||
{
|
||||
/**
|
||||
* @param ProcessorInterface<User, User> $processor
|
||||
* @param UserPasswordHasherInterface $passwordHasher
|
||||
*/
|
||||
public function __construct(
|
||||
private ProcessorInterface $processor,
|
||||
private UserPasswordHasherInterface $passwordHasher,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $data
|
||||
*/
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): User
|
||||
{
|
||||
if (!$data->getPlainPassword()) {
|
||||
return $this->processor->process($data, $operation, $uriVariables, $context);
|
||||
}
|
||||
|
||||
$hashedPassword = $this->passwordHasher->hashPassword(
|
||||
$data,
|
||||
$data->getPlainPassword()
|
||||
);
|
||||
$data->setPassword($hashedPassword);
|
||||
$data->eraseCredentials();
|
||||
|
||||
return $this->processor->process($data, $operation, $uriVariables, $context);
|
||||
}
|
||||
}
|
38
symfony.lock
38
symfony.lock
@@ -1,4 +1,30 @@
|
||||
{
|
||||
"api-platform/core": {
|
||||
"version": "3.3",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "3.3",
|
||||
"ref": "74b45ac570c57eb1fbe56c984091a9ff87e18bab"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/api_platform.yaml",
|
||||
"config/routes/api_platform.yaml",
|
||||
"src/ApiResource/.gitignore"
|
||||
]
|
||||
},
|
||||
"dama/doctrine-test-bundle": {
|
||||
"version": "8.2",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes-contrib",
|
||||
"branch": "main",
|
||||
"version": "7.2",
|
||||
"ref": "896306d79d4ee143af9eadf9b09fd34a8c391b70"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/dama_doctrine_test_bundle.yaml"
|
||||
]
|
||||
},
|
||||
"doctrine/doctrine-bundle": {
|
||||
"version": "2.12",
|
||||
"recipe": {
|
||||
@@ -38,6 +64,18 @@
|
||||
"migrations/.gitignore"
|
||||
]
|
||||
},
|
||||
"nelmio/cors-bundle": {
|
||||
"version": "2.4",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "1.5",
|
||||
"ref": "6bea22e6c564fba3a1391615cada1437d0bde39c"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/nelmio_cors.yaml"
|
||||
]
|
||||
},
|
||||
"phpstan/phpstan": {
|
||||
"version": "1.11",
|
||||
"recipe": {
|
||||
|
114
tests/Api/PostApiTest.php
Normal file
114
tests/Api/PostApiTest.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Api;
|
||||
|
||||
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
|
||||
use App\Entity\Post;
|
||||
use App\Entity\Species;
|
||||
|
||||
class PostApiTest extends ApiTestCase
|
||||
{
|
||||
private int $speciesId;
|
||||
private int $postId;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$kernel = self::bootKernel();
|
||||
$manager = $kernel->getContainer()->get('doctrine')->getManager();
|
||||
$species = (new Species())
|
||||
->setVernacularName('Oak')
|
||||
->setScientificName('Quercus')
|
||||
->setRegion('Europe');
|
||||
$post = (new Post())
|
||||
->setPublicationDate(new \DateTimeImmutable('2024-06-07'))
|
||||
->setFoundDate(new \DateTimeImmutable('2024-06-06'))
|
||||
->setCommentary("maple")
|
||||
->setSpecies($species);
|
||||
$manager->persist($species);
|
||||
$manager->persist($post);
|
||||
$manager->flush();
|
||||
$this->speciesId = $species->getId();
|
||||
$this->postId = $post->getId();
|
||||
}
|
||||
|
||||
public function testFindInSpecies(): void
|
||||
{
|
||||
$response = static::createClient()->request('GET', '/api/species/' . $this->speciesId);
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
$this->assertJsonEquals([
|
||||
'@context' => '/api/contexts/Species',
|
||||
'@id' => '/api/species/' . $this->speciesId,
|
||||
'@type' => 'Species',
|
||||
'id' => $this->speciesId,
|
||||
'vernacular_name' => 'Oak',
|
||||
'scientific_name' => 'Quercus',
|
||||
'region' => 'Europe',
|
||||
'posts' => ['/api/posts/' . $this->postId],
|
||||
]);
|
||||
}
|
||||
|
||||
public function testGetExisting(): void
|
||||
{
|
||||
$response = static::createClient()->request('GET', '/api/posts/' . $this->postId);
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
$this->assertJsonEquals([
|
||||
'@context' => '/api/contexts/Post',
|
||||
'@id' => '/api/posts/' . $this->postId,
|
||||
'@type' => 'Post',
|
||||
'id' => $this->postId,
|
||||
'foundDate' => '2024-06-06T00:00:00+00:00',
|
||||
'publicationDate' => '2024-06-07T00:00:00+00:00',
|
||||
'commentary' => 'maple',
|
||||
'species' => '/api/species/' . $this->speciesId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testFilterBySpecies(): void
|
||||
{
|
||||
$response = static::createClient()->request('GET', '/api/posts', [
|
||||
'query' => [
|
||||
'species' => $this->speciesId,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
$this->assertJsonContains([
|
||||
'@context' => '/api/contexts/Post',
|
||||
'@id' => '/api/posts',
|
||||
'@type' => 'hydra:Collection',
|
||||
'hydra:totalItems' => 1,
|
||||
'hydra:member' => [
|
||||
[
|
||||
'@type' => 'Post',
|
||||
'id' => $this->postId,
|
||||
'foundDate' => '2024-06-06T00:00:00+00:00',
|
||||
'species' => '/api/species/' . $this->speciesId,
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function testPostSetPublicationDate(): void
|
||||
{
|
||||
$response = static::createClient()->request('POST', '/api/posts', [
|
||||
'json' => [
|
||||
'foundDate' => '2024-06-06',
|
||||
'publicationDate' => '2024-06-07',
|
||||
'commentary' => 'maple',
|
||||
'species' => '/api/species/' . $this->speciesId,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
$this->assertJsonContains([
|
||||
'@context' => '/api/contexts/Post',
|
||||
'@type' => 'Post',
|
||||
'foundDate' => '2024-06-06T00:00:00+00:00',
|
||||
'commentary' => 'maple',
|
||||
'species' => '/api/species/' . $this->speciesId,
|
||||
]);
|
||||
$this->assertArrayHasKey('publicationDate', $response->toArray(false));
|
||||
}
|
||||
}
|
31
tests/Api/UserApiTest.php
Normal file
31
tests/Api/UserApiTest.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Api;
|
||||
|
||||
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
|
||||
|
||||
class UserApiTest extends ApiTestCase
|
||||
{
|
||||
public function testInsertUser(): void
|
||||
{
|
||||
$response = static::createClient()->request('POST', '/api/users', [
|
||||
'json' => [
|
||||
'email' => 'test@test.com',
|
||||
'plainPassword' => 'password',
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertResponseStatusCodeSame(201);
|
||||
$this->assertResponseHasHeader('Content-Location');
|
||||
|
||||
$location = $response->getHeaders()['content-location'][0];
|
||||
static::createClient()->request('GET', $location);
|
||||
$this->assertResponseIsSuccessful();
|
||||
$this->assertJsonEquals([
|
||||
'@context' => '/api/contexts/User',
|
||||
'@id' => $location,
|
||||
'@type' => 'User',
|
||||
'email' => 'test@test.com',
|
||||
]);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user