Skip to content

Commit

Permalink
Collection of Resource Metadata implementation (api-platform#4351)
Browse files Browse the repository at this point in the history
* chore(ci): php 8 on php-cs-fixer and phpstan

* chore: Create the new namespace

* feat(metadata): Resource Collection

* feat(graphql): graphql resource metadata collection

* chore(graphql): Change namespace to ApiPlatform\GraphQl

* chore(test): move fixtures and tests

* chore(tests): flag @legacy tests

* chore(ci): Behat symfony 5.4

* chore: phpstan false positive

* feat(mongodb): resource metadata collection

* fixes for php 7

* fix: Behat Elasticsearch

* chore(phpstan): non-empty-string

* test: fix tests

* Changelog

Co-authored-by: Vincent Chalamon <[email protected]>
  • Loading branch information
soyuka and vincentchalamon authored Aug 10, 2021
1 parent 24eb718 commit 1259ee5
Show file tree
Hide file tree
Showing 1,480 changed files with 16,913 additions and 5,111 deletions.
50 changes: 29 additions & 21 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ on:
env:
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERAGE: '0'
SYMFONY_DEPRECATIONS_HELPER: disabled=1

jobs:
php-cs-fixer:
name: PHP-cs-fixer (PHP ${{ matrix.php }})
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
matrix:
php:
- '7.4'
- '8'
fail-fast: false
env:
PHP_CS_FIXER_FUTURE_MODE: '1'
Expand All @@ -34,16 +36,17 @@ jobs:
run: php-cs-fixer fix --dry-run --diff --ansi

phpstan:
name: PHPStan
name: PHPStan (PHP ${{ matrix.php }})
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
matrix:
php:
- '7.4'
- '8'
fail-fast: false
env:
APP_DEBUG: '1' # https://github.com/phpstan/phpstan-symfony/issues/37
SYMFONY_PHPUNIT_VERSION: '9.5'
steps:
- name: Checkout
uses: actions/checkout@v2
Expand All @@ -69,8 +72,6 @@ jobs:
- name: Require Symfony components
run: composer require symfony/intl symfony/uid --dev --no-interaction --no-progress --ansi
- name: Install PHPUnit
env:
SYMFONY_PHPUNIT_VERSION: '9.5'
run: vendor/bin/simple-phpunit --version
- name: Cache PHPStan results
uses: actions/cache@v2
Expand Down Expand Up @@ -134,10 +135,6 @@ jobs:
composer remove --dev --no-interaction --no-progress --no-update --ansi \
doctrine/mongodb-odm \
doctrine/mongodb-odm-bundle \
- name: Set Composer platform config
if: (startsWith(matrix.php, '8.0'))
run: |
composer config platform.php 7.4.99
- name: Update project dependencies
run: composer update --no-interaction --no-progress --ansi
- name: Require Symfony components
Expand All @@ -146,16 +143,12 @@ jobs:
- name: Install PHPUnit
run: vendor/bin/simple-phpunit --version
- name: Clear test app cache
if: (!startsWith(matrix.php, '8.0'))
run: tests/Fixtures/app/console cache:clear --ansi
- name: Clear test app cache (php 8.0)
if: (startsWith(matrix.php, '8.0'))
run: rm -Rf tests/Fixtures/app/var/cache/*
- name: Run PHPUnit tests
run: |
mkdir -p build/logs/phpunit
if [ "$COVERAGE" = '1' ]; then
vendor/bin/simple-phpunit --coverage-clover build/logs/phpunit/clover.xml --log-junit build/logs/phpunit/junit.xml
vendor/bin/simple-phpunit --log-junit build/logs/phpunit/junit.xml --coverage-clover build/logs/phpunit/clover.xml
else
vendor/bin/simple-phpunit --log-junit build/logs/phpunit/junit.xml
fi
Expand Down Expand Up @@ -247,17 +240,27 @@ jobs:
if: (startsWith(matrix.php, '8.0'))
run: rm -Rf tests/Fixtures/app/var/cache/*
- name: Run Behat tests
if: (!startsWith(matrix.php, '8.0'))
run: |
mkdir -p build/logs/behat
if [ "$COVERAGE" = '1' ]; then
vendor/bin/behat --out=std --format=progress --format=junit --out=build/logs/behat/junit --profile=default-coverage --no-interaction
vendor/bin/behat --out=std --format=progress --format=junit --out=build/logs/behat/junit --profile=default-coverage --no-interaction --tags='~@php8'
else
if [ "${{ matrix.php }}" = '7.1' ]; then
vendor/bin/behat --out=std --format=progress --format=junit --out=build/logs/behat/junit --profile=default --no-interaction --tags='~@symfony/uid'
vendor/bin/behat --out=std --format=progress --format=junit --out=build/logs/behat/junit --profile=default --no-interaction --tags='~@symfony/uid&&~@php8'
else
vendor/bin/behat --out=std --format=progress --format=junit --out=build/logs/behat/junit --profile=default --no-interaction
vendor/bin/behat --out=std --format=progress --format=junit --out=build/logs/behat/junit --profile=default --no-interaction --tags='~@php8'
fi
fi
- name: Run Behat tests
if: (startsWith(matrix.php, '8.0'))
run: |
mkdir -p build/logs/behat
if [ "$COVERAGE" = '1' ]; then
vendor/bin/behat --out=std --format=progress --format=junit --out=build/logs/behat/junit --profile=default-coverage --no-interaction
else
vendor/bin/behat --out=std --format=progress --format=junit --out=build/logs/behat/junit --profile=default --no-interaction
fi
- name: Merge code coverage reports
if: matrix.coverage
run: |
Expand Down Expand Up @@ -389,7 +392,7 @@ jobs:
run: tests/Fixtures/app/console cache:clear --ansi
- name: Run Behat tests
# @TODO remove the tag "@symfony/uid" in 3.0
run: vendor/bin/behat --out=std --format=progress --profile=default --no-interaction --tags='~@symfony/uid'
run: vendor/bin/behat --out=std --format=progress --profile=default --no-interaction --tags='~@symfony/uid&&~php8'

postgresql:
name: Behat (PHP ${{ matrix.php }}) (PostgreSQL)
Expand Down Expand Up @@ -440,7 +443,7 @@ jobs:
run: tests/Fixtures/app/console cache:clear --ansi
- name: Run Behat tests
run: |
vendor/bin/behat --out=std --format=progress --profile=postgres --no-interaction -vv
vendor/bin/behat --out=std --format=progress --profile=postgres --no-interaction -vv --tags='~php8'
mysql:
name: Behat (PHP ${{ matrix.php }}) (MySQL)
Expand Down Expand Up @@ -500,7 +503,7 @@ jobs:
strategy:
matrix:
php:
- '7.4'
- '8'
fail-fast: false
env:
APP_ENV: mongodb
Expand Down Expand Up @@ -858,5 +861,10 @@ jobs:
- name: Clear test app cache
run: tests/Fixtures/app/console cache:clear --ansi
- name: Run Behat tests
run: vendor/bin/behat --out=std --format=progress --profile=default --no-interaction
run: |
if ( "${{ matrix.php }}" -eq '7.4' ) {
vendor/bin/behat --out=std --format=progress --profile=default --no-interaction --tags='~@php8'
} else {
vendor/bin/behat --out=std --format=progress --profile=default --no-interaction
}
2 changes: 1 addition & 1 deletion .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
$finder = PhpCsFixer\Finder::create()
->in(__DIR__)
->exclude([
'src/Bridge/Symfony/Maker/Resources/skeleton',
'src/Core/Bridge/Symfony/Maker/Resources/skeleton',
'tests/Fixtures/app/var',
])
->notPath('src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php')
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@
* Exception: Add the ability to customize multiple status codes based on the validation exception (#4017)
* GraphQL: Fix graphql fetching with Elasticsearch (#4217)
* ApiLoader: Support `_format` resolving (#4292)
* Metadata: new namespace `ApiPlatform\Metadata` instead of `ApiPlatform\Core\Metadata`, for example `ApiPlatform\Metadata\ApiResource` (#4351)
* Metadata: deprecation of `ApiPlatform\Core\Annotation` (#4351)
* Metadata: `ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface` is deprecated in favor of `ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface` (#4351)
* Metadata: item and collection prefixes for operations are deprecated, as well as the `ApiPlatform\Core\Api\OperationType` class (#4351)
* Graphql: `ApiPlatform\Metadata\GraphQl` follow the same metadata conventions (a Subscription operation is available and isn't hidden behind an update Mutation anymore), interfaces got simplified (beeing @experimental) (#4351)
* IriConverter: new interface for `ApiPlatform\Bridge\Symfony\Routing\IriConverter` that adds an operationName, same for `ApiPlatform\Api\IdentifiersExtractor` (#4351)
* DataProvider: new `ApiPlatform\State\ProviderInterface` that replaces DataProviders (#4351)
* DataPersister: new `ApiPlatform\State\ProcessorInterface` that replaces DataPersisters (#4351)
* A new configuration is available to keep old services (IriConverter, IdentifiersExtractor and OpenApiFactory) `metadata_backward_compatibility_layer` (defaults to false) (#4351)

## 2.6.5

Expand Down
10 changes: 7 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,16 @@
},
"autoload": {
"psr-4": {
"ApiPlatform\\Core\\": "src/"
}
"ApiPlatform\\": "src/"
},
"files": [
"src/deprecation.php"
]
},
"autoload-dev": {
"psr-4": {
"ApiPlatform\\Core\\Tests\\": "tests/",
"ApiPlatform\\Core\\Tests\\": "tests/Core/",
"ApiPlatform\\Tests\\": "tests/",
"App\\": "tests/Fixtures/app/var/tmp/src/"
}
},
Expand Down
11 changes: 6 additions & 5 deletions docs/adr/0002-resource-definition.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ In API Platform, this resource identifier is also named [IRI (Internationalized
```php
<?php

#[Get]
#[Post]
#[Resource]
class Users
{
#[ApiProperty(iri="hydra:member")]
Expand All @@ -34,9 +33,11 @@ class Users
public float $averageRate;
}

#[Get]
#[Put]
#[Delete]
#[Resource("/companies/{companyId}/users/{id}", normalization_context=["groups"= [....]]), operations={}]
#[Resource(normalization_context=["groups"= [....]], operations=[
new Get(),
new Post(),
])]
class User
{
#[ApiProperty(identifier=true)]
Expand Down
16 changes: 8 additions & 8 deletions features/doctrine/eager_loading.feature
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Feature: Eager Loading
And the DQL should be equal to:
"""
SELECT o, thirdLevel_a1, relatedToDummyFriend_a2, dummyFriend_a3
FROM ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy o
FROM ApiPlatform\Tests\Fixtures\TestBundle\Entity\RelatedDummy o
LEFT JOIN o.thirdLevel thirdLevel_a1
LEFT JOIN o.relatedToDummyFriend relatedToDummyFriend_a2
LEFT JOIN relatedToDummyFriend_a2.dummyFriend dummyFriend_a3
Expand All @@ -26,12 +26,12 @@ Feature: Eager Loading
And the DQL should be equal to:
"""
SELECT o
FROM ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy o
FROM ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy o
INNER JOIN o.relatedDummy relatedDummy_a1
INNER JOIN relatedDummy_a1.thirdLevel thirdLevel_a2
WHERE o IN(
SELECT o_a3
FROM ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy o_a3
FROM ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy o_a3
INNER JOIN o_a3.relatedDummy relatedDummy_a4
INNER JOIN relatedDummy_a4.thirdLevel thirdLevel_a5
WHERE thirdLevel_a5.level = :level_p1
Expand All @@ -46,13 +46,13 @@ Feature: Eager Loading
And the DQL should be equal to:
"""
SELECT o, thirdLevel_a4, relatedToDummyFriend_a1, dummyFriend_a5
FROM ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy o
FROM ApiPlatform\Tests\Fixtures\TestBundle\Entity\RelatedDummy o
INNER JOIN o.relatedToDummyFriend relatedToDummyFriend_a1
LEFT JOIN o.thirdLevel thirdLevel_a4
INNER JOIN relatedToDummyFriend_a1.dummyFriend dummyFriend_a5
WHERE o IN(
SELECT o_a2
FROM ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy o_a2
FROM ApiPlatform\Tests\Fixtures\TestBundle\Entity\RelatedDummy o_a2
INNER JOIN o_a2.relatedToDummyFriend relatedToDummyFriend_a3
WHERE relatedToDummyFriend_a3.dummyFriend = :dummyFriend_p1
)
Expand All @@ -69,7 +69,7 @@ Feature: Eager Loading
And the DQL should be equal to:
"""
SELECT o, car_a1, passenger_a2
FROM ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyTravel o
FROM ApiPlatform\Tests\Fixtures\TestBundle\Entity\DummyTravel o
LEFT JOIN o.car car_a1
LEFT JOIN o.passenger passenger_a2
WHERE o.id = :id_id
Expand All @@ -82,13 +82,13 @@ Feature: Eager Loading
And the DQL should be equal to:
"""
SELECT o, thirdLevel_a3, relatedToDummyFriend_a4, dummyFriend_a5
FROM ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy o
FROM ApiPlatform\Tests\Fixtures\TestBundle\Entity\RelatedDummy o
LEFT JOIN o.thirdLevel thirdLevel_a3
LEFT JOIN o.relatedToDummyFriend relatedToDummyFriend_a4
LEFT JOIN relatedToDummyFriend_a4.dummyFriend dummyFriend_a5
WHERE o.id IN (
SELECT related_dummy_a1.id
FROM ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy related_dummy_a1
FROM ApiPlatform\Tests\Fixtures\TestBundle\Entity\RelatedDummy related_dummy_a1
INNER JOIN related_dummy_a1.relatedToDummyFriend related_to_dummy_friend_a2
WITH related_to_dummy_friend_a2.name = :name_p1
)
Expand Down
103 changes: 103 additions & 0 deletions features/main/attribute_resource.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
Feature: Resource attributes
In order to use the Resource attribute
As a developer
I should be able to fetch data from a state provider

@php8
@!mysql
@!mongodb
Scenario: Retrieve a Resource collection
When I add "Content-Type" header equal to "application/ld+json"
And I send a "GET" request to "/attribute_resources"
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be equal to:
"""
{
"@context": "/contexts/AttributeResources",
"@id": "/attribute_resources",
"@type": "hydra:Collection",
"hydra:member": [
{
"@id": "/attribute_resources/1",
"@type": "AttributeResource",
"identifier": 1,
"name": "Foo"
},
{
"@id": "/attribute_resources/2",
"@type": "AttributeResource",
"identifier": 2,
"name": "Bar"
}
]
}
"""

@php8
@!mysql
@!mongodb
Scenario: Retrieve the first resource
When I add "Content-Type" header equal to "application/ld+json"
And I send a "GET" request to "/attribute_resources/1"
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be equal to:
"""
{
"@context": "/contexts/AttributeResource",
"@id": "/attribute_resources/1",
"@type": "AttributeResource",
"identifier": 1,
"name": "Foo"
}
"""

@php8
@!mysql
@!mongodb
Scenario: Retrieve the aliased resource
When I add "Content-Type" header equal to "application/ld+json"
And I send a "GET" request to "/dummy/1/attribute_resources/2"
Then the response status code should be 301
And the header "Location" should be equal to "/attribute_resources/2"
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be equal to:
"""
{
"@context": "/contexts/AttributeResource",
"@id": "/attribute_resources/2",
"@type": "AttributeResource",
"identifier": 2,
"dummy": "/dummies/1",
"name": "Foo"
}
"""

@php8
@!mysql
@!mongodb
Scenario: Patch the aliased resource
When I add "Content-Type" header equal to "application/merge-patch+json"
And I send a "PATCH" request to "/dummy/1/attribute_resources/2" with body:
"""
{"name": "Patched"}
"""
Then the response status code should be 301
And the header "Location" should be equal to "/attribute_resources/2"
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be equal to:
"""
{
"@context": "/contexts/AttributeResource",
"@id": "/attribute_resources/2",
"@type": "AttributeResource",
"identifier": 2,
"dummy": "/dummies/1",
"name": "Patched"
}
"""
2 changes: 1 addition & 1 deletion features/main/relation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ Feature: Relations support
"pattern": "^An error occurred$"
},
"hydra:description": {
"pattern": "^Expected IRI or document for resource \"ApiPlatform\\\\Core\\\\Tests\\\\Fixtures\\\\TestBundle\\\\(Document|Entity)\\\\RelatedDummy\", \"integer\" given.$"
"pattern": "^Expected IRI or document for resource \"ApiPlatform\\\\Tests\\\\Fixtures\\\\TestBundle\\\\(Document|Entity)\\\\RelatedDummy\", \"integer\" given.$"
}
},
"required": [
Expand Down
Loading

0 comments on commit 1259ee5

Please sign in to comment.