Skip to content

Commit

Permalink
Merge ea96b52 into cc8ae0b
Browse files Browse the repository at this point in the history
  • Loading branch information
vincentchalamon committed Dec 23, 2021
2 parents cc8ae0b + ea96b52 commit 587916f
Show file tree
Hide file tree
Showing 64 changed files with 4,943 additions and 115 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Expand Up @@ -132,12 +132,12 @@ jobs:
run: |
composer remove --dev --no-interaction --no-progress --no-update --ansi \
doctrine/mongodb-odm \
doctrine/mongodb-odm-bundle \
doctrine/mongodb-odm-bundle
- name: Remove ElasticSearch
if: startsWith(matrix.php, '7.1') || startsWith(matrix.php, '7.2')
run: |
composer remove --dev --no-interaction --no-progress --no-update --ansi \
elasticsearch/elasticsearch \
elasticsearch/elasticsearch
- name: Update project dependencies
run: composer update --no-interaction --no-progress --ansi
- name: Require Symfony components
Expand Down Expand Up @@ -228,12 +228,12 @@ jobs:
run: |
composer remove --dev --no-interaction --no-progress --no-update --ansi \
doctrine/mongodb-odm \
doctrine/mongodb-odm-bundle \
doctrine/mongodb-odm-bundle
- name: Remove ElasticSearch
if: startsWith(matrix.php, '7.1') || startsWith(matrix.php, '7.2')
run: |
composer remove --dev --no-interaction --no-progress --no-update --ansi \
elasticsearch/elasticsearch \
elasticsearch/elasticsearch
- name: Update project dependencies
run: composer update --no-interaction --no-progress --ansi
- name: Require Symfony components
Expand Down Expand Up @@ -1143,7 +1143,7 @@ jobs:
- name: Run Behat tests
run: |
mkdir -p build/logs/behat
vendor/bin/behat --out=std --format=progress --format=junit --out=build/logs/behat/junit --profile=default --no-interaction --tags='~@php8'
vendor/bin/behat --out=std --format=progress --format=junit --out=build/logs/behat/junit --profile=default --no-interaction --tags='~@php8' --tags='~@v3'
- name: Run Behat tests
if: (startsWith(matrix.php, '8.0'))
run: |
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -11,5 +11,7 @@
/swagger.yaml
/tests/Fixtures/app/var/
/tests/Fixtures/app/public/bundles/
/tests/Metadata/Extractor/Adapter/*.xml
/tests/Metadata/Extractor/Adapter/*.yaml
/vendor/
/Dockerfile
1 change: 0 additions & 1 deletion behat.yml.dist
Expand Up @@ -142,4 +142,3 @@ elasticsearch-coverage:
- 'ApiPlatform\Core\Tests\Behat\CoverageContext'
- 'Behat\MinkExtension\Context\MinkContext'
- 'behatch:context:rest'

127 changes: 127 additions & 0 deletions features/main/crud.feature
@@ -1,3 +1,4 @@
# todo remove @v3 tag in 3.0
Feature: Create-Retrieve-Update-Delete
In order to use an hypermedia API
As a client software developer
Expand Down Expand Up @@ -649,3 +650,129 @@ Feature: Create-Retrieve-Update-Delete
"foo": "bar"
}
"""

@v3
Scenario: Get a resource in v3 configured in YAML
Given there is a Program
When I send a "GET" request to "/programs/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/Program",
"@id": "/programs/1",
"@type": "Program",
"id": 1,
"name": "Lorem ipsum 1",
"date": "2015-03-01T10:00:00+00:00",
"author": "/users/1"
}
"""

@v3
Scenario: Get a collection resource in v3 configured in YAML
Given there are 3 Programs
When I send a "GET" request to "/users/1/programs"
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/Program",
"@id": "/users/1/programs",
"@type": "hydra:Collection",
"hydra:member": [
{
"@id": "/programs/1",
"@type": "Program",
"id": 1,
"name": "Lorem ipsum 1",
"date": "2015-03-01T10:00:00+00:00",
"author": "/users/1"
},
{
"@id": "/programs/2",
"@type": "Program",
"id": 2,
"name": "Lorem ipsum 2",
"date": "2015-03-02T10:00:00+00:00",
"author": "/users/1"
},
{
"@id": "/programs/3",
"@type": "Program",
"id": 3,
"name": "Lorem ipsum 3",
"date": "2015-03-03T10:00:00+00:00",
"author": "/users/1"
}
],
"hydra:totalItems": 3
}
"""

@v3
Scenario: Get a resource in v3 configured in XML
Given there is a Comment
When I send a "GET" request to "/comments/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/Comment",
"@id": "/comments/1",
"@type": "Comment",
"id": 1,
"comment": "Lorem ipsum dolor sit amet 1",
"date": "2015-03-01T10:00:00+00:00",
"author": "/users/1"
}
"""

@v3
Scenario: Get a collection resource in v3 configured in XML
Given there are 3 Comments
When I send a "GET" request to "/users/1/comments"
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/Comment",
"@id": "/users/1/comments",
"@type": "hydra:Collection",
"hydra:member": [
{
"@id": "/comments/1",
"@type": "Comment",
"id": 1,
"comment": "Lorem ipsum dolor sit amet 1",
"date": "2015-03-01T10:00:00+00:00",
"author": "/users/1"
},
{
"@id": "/comments/2",
"@type": "Comment",
"id": 2,
"comment": "Lorem ipsum dolor sit amet 2",
"date": "2015-03-02T10:00:00+00:00",
"author": "/users/1"
},
{
"@id": "/comments/3",
"@type": "Comment",
"id": 3,
"comment": "Lorem ipsum dolor sit amet 3",
"date": "2015-03-03T10:00:00+00:00",
"author": "/users/1"
}
],
"hydra:totalItems": 3
}
"""
2 changes: 1 addition & 1 deletion features/main/table_inheritance.feature
Expand Up @@ -445,7 +445,7 @@ Feature: Table inheritance
}
"""

Scenario: Get the parent interface collection
Scenario: Get the parent interface collection
When I send a "GET" request to "/resource_interfaces"
Then the response status code should be 200
And the response should be in JSON
Expand Down
53 changes: 39 additions & 14 deletions src/Core/Metadata/Extractor/XmlExtractor.php
Expand Up @@ -14,6 +14,8 @@
namespace ApiPlatform\Core\Metadata\Extractor;

use ApiPlatform\Exception\InvalidArgumentException;
use ApiPlatform\Metadata\Extractor\AbstractResourceExtractor;
use ApiPlatform\Metadata\Extractor\PropertyExtractorInterface;
use Symfony\Component\Config\Util\XmlUtils;

/**
Expand All @@ -22,11 +24,33 @@
* @author Kévin Dunglas <dunglas@gmail.com>
* @author Antoine Bluchet <soyuka@gmail.com>
* @author Baptiste Meyer <baptiste.meyer@gmail.com>
* @author Vincent Chalamon <vincentchalamon@gmail.com>
*
* @deprecated since 2.7, to remove in 3.0 (replaced by ApiPlatform\Metadata\Extractor\XmlExtractor)
*/
final class XmlExtractor extends AbstractExtractor
final class XmlExtractor extends AbstractResourceExtractor implements PropertyExtractorInterface
{
public const RESOURCE_SCHEMA = __DIR__.'/../schema/metadata.xsd';

private $properties;

/**
* {@inheritdoc}
*/
public function getProperties(): array
{
if (null !== $this->properties) {
return $this->properties;
}

$this->properties = [];
foreach ($this->paths as $path) {
$this->extractPath($path);
}

return $this->properties;
}

/**
* {@inheritdoc}
*/
Expand All @@ -46,23 +70,24 @@ protected function extractPath(string $path)
'shortName' => $this->phpizeAttribute($resource, 'shortName', 'string'),
'description' => $this->phpizeAttribute($resource, 'description', 'string'),
'iri' => $this->phpizeAttribute($resource, 'iri', 'string'),
'itemOperations' => $this->getOperations($resource, 'itemOperation'),
'collectionOperations' => $this->getOperations($resource, 'collectionOperation'),
'subresourceOperations' => $this->getOperations($resource, 'subresourceOperation'),
'graphql' => $this->getOperations($resource, 'operation'),
'attributes' => $this->getAttributes($resource, 'attribute') ?: null,
'properties' => $this->getProperties($resource) ?: null,
'itemOperations' => $this->extractOperations($resource, 'itemOperation'),
'collectionOperations' => $this->extractOperations($resource, 'collectionOperation'),
'subresourceOperations' => $this->extractOperations($resource, 'subresourceOperation'),
'graphql' => $this->extractOperations($resource, 'operation'),
'attributes' => $this->extractAttributes($resource, 'attribute') ?: null,
'properties' => $this->extractProperties($resource) ?: null,
];
$this->properties[$resourceClass] = $this->resources[$resourceClass]['properties'];
}
}

/**
* Returns the array containing configured operations. Returns NULL if there is no operation configuration.
*/
private function getOperations(\SimpleXMLElement $resource, string $operationType): ?array
private function extractOperations(\SimpleXMLElement $resource, string $operationType): ?array
{
$graphql = 'operation' === $operationType;
if (!$graphql && $legacyOperations = $this->getAttributes($resource, $operationType)) {
if (!$graphql && $legacyOperations = $this->extractAttributes($resource, $operationType)) {
@trigger_error(
sprintf('Configuring "%1$s" tags without using a parent "%1$ss" tag is deprecated since API Platform 2.1 and will not be possible anymore in API Platform 3', $operationType),
\E_USER_DEPRECATED
Expand All @@ -76,17 +101,17 @@ private function getOperations(\SimpleXMLElement $resource, string $operationTyp
return null;
}

return $this->getAttributes($resource->{$operationsParent}, $operationType, true);
return $this->extractAttributes($resource->{$operationsParent}, $operationType, true);
}

/**
* Recursively transforms an attribute structure into an associative array.
*/
private function getAttributes(\SimpleXMLElement $resource, string $elementName, bool $topLevel = false): array
private function extractAttributes(\SimpleXMLElement $resource, string $elementName, bool $topLevel = false): array
{
$attributes = [];
foreach ($resource->{$elementName} as $attribute) {
$value = isset($attribute->attribute[0]) ? $this->getAttributes($attribute, 'attribute') : $this->phpizeContent($attribute);
$value = isset($attribute->attribute[0]) ? $this->extractAttributes($attribute, 'attribute') : $this->phpizeContent($attribute);
// allow empty operations definition, like <collectionOperation name="post" />
if ($topLevel && '' === $value) {
$value = [];
Expand All @@ -104,7 +129,7 @@ private function getAttributes(\SimpleXMLElement $resource, string $elementName,
/**
* Gets metadata of a property.
*/
private function getProperties(\SimpleXMLElement $resource): array
private function extractProperties(\SimpleXMLElement $resource): array
{
$properties = [];
foreach ($resource->property as $property) {
Expand All @@ -117,7 +142,7 @@ private function getProperties(\SimpleXMLElement $resource): array
'required' => $this->phpizeAttribute($property, 'required', 'bool'),
'identifier' => $this->phpizeAttribute($property, 'identifier', 'bool'),
'iri' => $this->phpizeAttribute($property, 'iri', 'string'),
'attributes' => $this->getAttributes($property, 'attribute'),
'attributes' => $this->extractAttributes($property, 'attribute'),
'subresource' => $property->subresource ? [
'collection' => $this->phpizeAttribute($property->subresource, 'collection', 'bool'),
'resourceClass' => $this->resolve($this->phpizeAttribute($property->subresource, 'resourceClass', 'string')),
Expand Down
32 changes: 28 additions & 4 deletions src/Core/Metadata/Extractor/YamlExtractor.php
Expand Up @@ -14,6 +14,8 @@
namespace ApiPlatform\Core\Metadata\Extractor;

use ApiPlatform\Exception\InvalidArgumentException;
use ApiPlatform\Metadata\Extractor\AbstractResourceExtractor;
use ApiPlatform\Metadata\Extractor\PropertyExtractorInterface;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;

Expand All @@ -23,9 +25,31 @@
* @author Antoine Bluchet <soyuka@gmail.com>
* @author Baptiste Meyer <baptiste.meyer@gmail.com>
* @author Kévin Dunglas <dunglas@gmail.com>
* @author Vincent Chalamon <vincentchalamon@gmail.com>
*
* @deprecated since 2.7, to remove in 3.0 (replaced by ApiPlatform\Metadata\Extractor\YamlExtractor)
*/
final class YamlExtractor extends AbstractExtractor
final class YamlExtractor extends AbstractResourceExtractor implements PropertyExtractorInterface
{
private $properties;

/**
* {@inheritdoc}
*/
public function getProperties(): array
{
if (null !== $this->properties) {
return $this->properties;
}

$this->properties = [];
foreach ($this->paths as $path) {
$this->extractPath($path);
}

return $this->properties;
}

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -75,7 +99,7 @@ private function extractResources(array $resourcesYaml, string $path): void
];

if (!isset($resourceYaml['properties'])) {
$this->resources[$resourceName]['properties'] = null;
$this->properties[$resourceName] = $this->resources[$resourceName]['properties'] = null;

continue;
}
Expand All @@ -92,7 +116,7 @@ private function extractProperties(array $resourceYaml, string $resourceName, st
{
foreach ($resourceYaml['properties'] as $propertyName => $propertyValues) {
if (null === $propertyValues) {
$this->resources[$resourceName]['properties'][$propertyName] = null;
$this->properties[$resourceName][$propertyName] = $this->resources[$resourceName]['properties'][$propertyName] = null;

continue;
}
Expand All @@ -104,7 +128,7 @@ private function extractProperties(array $resourceYaml, string $resourceName, st
$propertyValues['subresource']['resourceClass'] = $this->resolve($propertyValues['subresource']['resourceClass']);
}

$this->resources[$resourceName]['properties'][$propertyName] = [
$this->properties[$resourceName][$propertyName] = $this->resources[$resourceName]['properties'][$propertyName] = [
'description' => $this->phpize($propertyValues, 'description', 'string'),
'readable' => $this->phpize($propertyValues, 'readable', 'bool'),
'writable' => $this->phpize($propertyValues, 'writable', 'bool'),
Expand Down

0 comments on commit 587916f

Please sign in to comment.