Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
54662ee
Unwrap nested HandlerFailedException
teohhanhui Jul 29, 2019
6fe4593
Merge pull request #2960 from teohhanhui/fix/messenger-nested-handler…
teohhanhui Jul 30, 2019
cd1bfbc
Update changelog for GraphQL (#2973)
alanpoulain Aug 8, 2019
d910fb0
Unwrap Messenger HandlerFailedException at the dispatch call site
teohhanhui Aug 8, 2019
092818a
Use correct resource configuration for filter args of nested collecti…
lukasluecke Aug 9, 2019
df359cd
Merge pull request #2975 from teohhanhui/fix/unwrap-messenger-handler…
teohhanhui Aug 9, 2019
f1802ea
Use correct resource configuration for filter args of nested collecti…
alanpoulain Aug 9, 2019
3958b81
Merge branch '2.4' into merge-2.4
teohhanhui Aug 9, 2019
92f655c
Merge pull request #2977 from teohhanhui/merge-2.4
teohhanhui Aug 9, 2019
e8f26ca
[OpenAPI] Extract the JSON Schema builder (#2983)
dunglas Aug 19, 2019
51997f6
Prevent cloning generator when instanciating previous_data
nitneuk Aug 19, 2019
dc6b746
Fix : Throw a better message if http-client is not installed
Zowac Aug 19, 2019
ee4bf84
Merge pull request #2990 from Nitneuk2/fix-previous_data
dunglas Aug 19, 2019
1bee909
Add test for Hydra json schema factory
nitneuk Aug 19, 2019
197b4ab
[JSON Schema] Add test for TypeFactory
dunglas Aug 19, 2019
dec408a
Use __invoke instead of apply for stages (#2989)
alanpoulain Aug 19, 2019
6ad07ad
Merge pull request #2997 from dunglas/json-schema-test-typefactory
dunglas Aug 19, 2019
db1a956
Merge pull request #2995 from Nitneuk2/test-hydra-schema-factory
dunglas Aug 19, 2019
204c21a
Merge pull request #2994 from Zowac/throw-better-message
dunglas Aug 19, 2019
1ddf3af
[Test] Throw a better error HttpClient is not installed
dunglas Aug 19, 2019
8d625d0
Merge branch '2.4'
dunglas Aug 19, 2019
be6f828
Add missing call to Clone::clone
dunglas Aug 19, 2019
6dfe8f3
Fix AppVeyor tests
dunglas Aug 19, 2019
7d98224
Update CHANGELOG.md
dunglas Aug 19, 2019
96bfc4d
Merge pull request #3000 from dunglas/follow-2990
dunglas Aug 19, 2019
e4f45dc
Merge branch '2.4'
dunglas Aug 19, 2019
2c904ef
Merge pull request #2999 from dunglas/better-2994
dunglas Aug 20, 2019
c2e7ef4
Add default, min, max specification in pagination parameter API docs
fredericbarthelet Aug 19, 2019
03e743b
Update JS deps
dunglas Aug 20, 2019
849fd28
Merge pull request #3006 from dunglas/update-js-deps
dunglas Aug 20, 2019
3c98fdb
Merge pull request #3002 from fredericbarthelet/improve-pagination-ge…
dunglas Aug 20, 2019
1f06b4e
Fix #1646
vincentchalamon Aug 19, 2019
23d0f8f
Merge pull request #2992 from vincentchalamon/issue/1646
dunglas Aug 20, 2019
d047d85
Handle activation of swagger through versions (#2998)
GregoireHebert Aug 20, 2019
8dbf90f
Add enum specification in order filter API docs
fredericbarthelet Aug 7, 2019
1c19bf5
Merge pull request #2971 from fredericbarthelet/improve-filter-genera…
teohhanhui Aug 20, 2019
7ac5857
add command to generate json schema (#2996)
jockos Aug 21, 2019
0c6b7a7
Implement FilterDescription object
fredericbarthelet Aug 22, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,27 @@

## 2.5.0 beta 1

* GraphQL: Add support for custom queries and mutations
* GraphQL: Add support for custom types
* GraphQL: Better pagination support (backwards pagination)
* GraphQL: Add the concept of *stages* in the workflow of the resolvers and add the possibility to disable them with operation attributes
* GraphQL: Add GraphQL Playground besides GraphiQL and add the possibility to change the default IDE (or to disable it) for the GraphQL endpoint
* GraphQL: Add a command to print the schema in SDL
* GraphQL: Improve serialization performance by avoiding calls to the `serialize` PHP function
* GraphQL: Allow to use a search and an exist filter on the same resource
* GraphQL: Refactor the architecture of the whole system to allow the decoration of useful services (`TypeConverter` to manage custom types, `SerializerContextBuilder` to modify the (de)serialization context dynamically, etc.)

## 2.4.6

* GraphQL: Use correct resource configuration for filter arguments of nested collection
* Swagger UI: compatibility with Internet Explorer 11
* Varnish: Prevent cache miss by generating IRI for child related resources
* Messenger: Unwrap exception thrown in handler for Symfony Messenger 4.3
* Fix remaining Symfony 4.3 deprecation notices
* Prevent cloning non clonable objects in `previous_data`
* Return a 415 HTTP status code instead of a 406 one when a faulty `Content-Type` is sent
* Fix `WriteListener` trying to generate IRI for non-resources
* Allow to extract blank values from composite identifier

## 2.4.5

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
"symfony/http-client": "^4.3",
"symfony/mercure-bundle": "*",
"symfony/messenger": "^4.3",
"symfony/phpunit-bridge": "^4.3.1",
"symfony/phpunit-bridge": "^4.3@dev",
"symfony/routing": "^3.4 || ^4.0",
"symfony/security-bundle": "^3.4 || ^4.0",
"symfony/security-core": "^4.3",
Expand Down
6 changes: 6 additions & 0 deletions features/authorization/deny.feature
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ Feature: Authorization checking
Then the response status code should be 200
And the response should be in JSON

Scenario: Data provider that's return generator has null previous object
When I add "Accept" header equal to "application/ld+json"
And I add "Authorization" header equal to "Basic ZHVuZ2xhczprZXZpbg=="
And I send a "GET" request to "/custom_data_provider_generator"
Then the response status code should be 200

Scenario: A standard user cannot create a secured resource
When I add "Accept" header equal to "application/ld+json"
And I add "Content-Type" header equal to "application/ld+json"
Expand Down
96 changes: 96 additions & 0 deletions features/authorization/legacy_deny.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
Feature: Authorization checking
In order to use the API
As a client software user
I need to be authorized to access a given resource using legacy access_control attribute.

@createSchema
Scenario: An anonymous user retrieves a secured resource
When I add "Accept" header equal to "application/ld+json"
And I send a "GET" request to "/legacy_secured_dummies"
Then the response status code should be 401

Scenario: An authenticated user retrieve a secured resource
When I add "Accept" header equal to "application/ld+json"
And I add "Authorization" header equal to "Basic ZHVuZ2xhczprZXZpbg=="
And I send a "GET" request to "/legacy_secured_dummies"
Then the response status code should be 200
And the response should be in JSON

Scenario: A standard user cannot create a secured resource
When I add "Accept" header equal to "application/ld+json"
And I add "Content-Type" header equal to "application/ld+json"
And I add "Authorization" header equal to "Basic ZHVuZ2xhczprZXZpbg=="
And I send a "POST" request to "/legacy_secured_dummies" with body:
"""
{
"title": "Title",
"description": "Description",
"owner": "foo"
}
"""
Then the response status code should be 403

Scenario: An admin can create a secured resource
When I add "Accept" header equal to "application/ld+json"
And I add "Content-Type" header equal to "application/ld+json"
And I add "Authorization" header equal to "Basic YWRtaW46a2l0dGVu"
And I send a "POST" request to "/legacy_secured_dummies" with body:
"""
{
"title": "Title",
"description": "Description",
"owner": "someone"
}
"""
Then the response status code should be 201

Scenario: An admin can create another secured resource
When I add "Accept" header equal to "application/ld+json"
And I add "Content-Type" header equal to "application/ld+json"
And I add "Authorization" header equal to "Basic YWRtaW46a2l0dGVu"
And I send a "POST" request to "/legacy_secured_dummies" with body:
"""
{
"title": "Special Title",
"description": "Description",
"owner": "dunglas"
}
"""
Then the response status code should be 201

Scenario: A user cannot retrieve an item they doesn't own
When I add "Accept" header equal to "application/ld+json"
And I add "Authorization" header equal to "Basic ZHVuZ2xhczprZXZpbg=="
And I send a "GET" request to "/legacy_secured_dummies/1"
Then the response status code should be 403
And the response should be in JSON

Scenario: A user can retrieve an item they owns
When I add "Accept" header equal to "application/ld+json"
And I add "Authorization" header equal to "Basic ZHVuZ2xhczprZXZpbg=="
And I send a "GET" request to "/legacy_secured_dummies/2"
Then the response status code should be 200

Scenario: A user can't assign to themself an item they doesn't own
When I add "Accept" header equal to "application/ld+json"
And I add "Content-Type" header equal to "application/ld+json"
And I add "Authorization" header equal to "Basic YWRtaW46a2l0dGVu"
And I send a "PUT" request to "/legacy_secured_dummies/2" with body:
"""
{
"owner": "kitten"
}
"""
Then the response status code should be 403

Scenario: A user can update an item they owns and transfer it
When I add "Accept" header equal to "application/ld+json"
And I add "Content-Type" header equal to "application/ld+json"
And I add "Authorization" header equal to "Basic ZHVuZ2xhczprZXZpbg=="
And I send a "PUT" request to "/legacy_secured_dummies/2" with body:
"""
{
"owner": "vincent"
}
"""
Then the response status code should be 200
24 changes: 23 additions & 1 deletion features/graphql/filters.feature
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,33 @@ Feature: Collections filtering
}
}
"""
And the JSON node "data.dummies.edges[0].node.relatedDummies.edges" should have 0 elements
Then the JSON node "data.dummies.edges[0].node.relatedDummies.edges" should have 0 elements
And the JSON node "data.dummies.edges[1].node.relatedDummies.edges" should have 0 elements
And the JSON node "data.dummies.edges[2].node.relatedDummies.edges" should have 1 element
And the JSON node "data.dummies.edges[2].node.relatedDummies.edges[0].node.name" should be equal to "RelatedDummy13"

@createSchema
Scenario: Use a filter of a nested collection
Given there is a DummyCar entity with related colors
When I send the following GraphQL request:
"""
{
dummyCar(id: "/dummy_cars/1") {
id
colors(prop: "blue") {
edges {
node {
id
prop
}
}
}
}
}
"""
Then the JSON node "data.dummyCar.colors.edges" should have 1 element
And the JSON node "data.dummyCar.colors.edges[0].node.prop" should be equal to "blue"

@createSchema
Scenario: Retrieve a collection filtered using the related search filter
Given there are 1 dummy objects having each 2 relatedDummies
Expand Down
2 changes: 1 addition & 1 deletion features/openapi/docs.feature
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ Feature: Documentation support
And the JSON node "paths./related_dummies/{id}/related_to_dummy_friends.get.parameters" should have 6 elements

# Subcollection - check schema
And the JSON node "paths./related_dummies/{id}/related_to_dummy_friends.get.responses.200.content.application/ld+json.schema.items.$ref" should be equal to "#/components/schemas/RelatedToDummyFriend-fakemanytomany"
And the JSON node "paths./related_dummies/{id}/related_to_dummy_friends.get.responses.200.content.application/ld+json.schema.properties.hydra:member.items.$ref" should be equal to "#/components/schemas/RelatedToDummyFriend:jsonld-fakemanytomany"

# Deprecations
And the JSON node "paths./dummies.get.deprecated" should not exist
Expand Down
3 changes: 0 additions & 3 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ parameters:
- '#Parameter \#1 \$defaultContext of class Symfony\\Component\\Serializer\\Encoder\\Json(De|En)code constructor expects array, (int|true) given\.#'
- '#Parameter \#(2|3) \$(resourceMetadataFactory|pagination) of class ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Extension\\PaginationExtension constructor expects (ApiPlatform\\Core\\Metadata\\Resource\\Factory\\ResourceMetadataFactoryInterface\|Symfony\\Component\\HttpFoundation\\RequestStack|ApiPlatform\\Core\\DataProvider\\Pagination\|ApiPlatform\\Core\\Metadata\\Resource\\Factory\\ResourceMetadataFactoryInterface), stdClass given\.#'
- '#Parameter \#[0-9] \$filterLocator of class ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Extension\\FilterExtension constructor expects ApiPlatform\\Core\\Api\\FilterCollection|Psr\\Container\\ContainerInterface(\|null)?, ArrayObject given\.#'
-
message: '#Parameter \#9 \$nameConverter of class ApiPlatform\\Core\\Swagger\\Serializer\\DocumentationNormalizer constructor expects Symfony\\Component\\Serializer\\NameConverter\\NameConverterInterface\|null, object given\.#'
path: %currentWorkingDirectory%/tests/Swagger/Serializer/DocumentationNormalizer*Test.php
-
message: '#Parameter \#1 \$resource of method ApiPlatform\\Core\\Metadata\\Extractor\\XmlExtractor::getAttributes\(\) expects SimpleXMLElement, object given\.#'
path: %currentWorkingDirectory%/src/Metadata/Extractor/XmlExtractor.php
Expand Down
22 changes: 20 additions & 2 deletions src/Annotation/ApiResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
* @Attributes(
* @Attribute("accessControl", type="string"),
* @Attribute("accessControlMessage", type="string"),
* @Attribute("security", type="string"),
* @Attribute("securityMessage", type="string"),
* @Attribute("securityPostDenormalize", type="string"),
* @Attribute("securityPostDenormalizeMessage", type="string"),
* @Attribute("attributes", type="array"),
* @Attribute("cacheHeaders", type="array"),
* @Attribute("collectionOperations", type="array"),
Expand Down Expand Up @@ -108,14 +112,28 @@ final class ApiResource
*
* @var string
*/
private $accessControl;
private $security;

/**
* @see https://github.com/Haehnchen/idea-php-annotation-plugin/issues/112
*
* @var string
*/
private $accessControlMessage;
private $securityMessage;

/**
* @see https://github.com/Haehnchen/idea-php-annotation-plugin/issues/112
*
* @var string
*/
private $securityPostDenormalize;

/**
* @see https://github.com/Haehnchen/idea-php-annotation-plugin/issues/112
*
* @var string
*/
private $securityPostDenormalizeMessage;

/**
* @see https://github.com/Haehnchen/idea-php-annotation-plugin/issues/112
Expand Down
84 changes: 84 additions & 0 deletions src/Api/FilterDescription.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Core\Api;

use ApiPlatform\Core\JsonSchema\Schema;

class FilterDescription
{
public const ALLOWED_VERSIONS = [
Schema::VERSION_SWAGGER,
Schema::VERSION_OPENAPI,
];

private $name;
private $property;
private $type;
private $required;
private $strategy;
private $collection;
private $swagger;
private $openapi;

public function __construct(string $name, ?string $property, string $type, bool $required, ?string $strategy, ?bool $collection = false, ?array $swagger = null, ?array $openapi = null)
{
$this->name = $name;
$this->property = $property;
$this->type = $type;
$this->required = $required;
$this->strategy = $strategy;
$this->collection = $collection;
$this->swagger = $swagger;
$this->openapi = $openapi;
}

public function getName(): string
{
return $this->name;
}

public function getProperty(): ?string
{
return $this->property;
}

public function getType(): string
{
return $this->type;
}

public function isRequired(): bool
{
return $this->required;
}

public function getStrategy(): ?string
{
return $this->strategy;
}

public function isCollection(): bool
{
return $this->collection;
}

public function getAdditionalParameters(string $version)
{
if (!\in_array($version, self::ALLOWED_VERSIONS, true)) {
throw new \LogicException('Please provide either of the following allowed parameter versions: '.implode(', ', self::ALLOWED_VERSIONS));
}

return $this->{$version};
}
}
24 changes: 1 addition & 23 deletions src/Api/FilterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,7 @@ interface FilterInterface
/**
* Gets the description of this filter for the given resource.
*
* Returns an array with the filter parameter names as keys and array with the following data as values:
* - property: the property where the filter is applied
* - type: the type of the filter
* - required: if this filter is required
* - strategy: the used strategy
* - is_collection (optional): is this filter is collection
* - swagger (optional): additional parameters for the path operation,
* e.g. 'swagger' => [
* 'description' => 'My Description',
* 'name' => 'My Name',
* 'type' => 'integer',
* ]
* - openapi (optional): additional parameters for the path operation in the version 3 spec,
* e.g. 'openapi' => [
* 'description' => 'My Description',
* 'name' => 'My Name',
* 'schema' => [
* 'type' => 'integer',
* ]
* ]
* The description can contain additional data specific to a filter.
*
* @see \ApiPlatform\Core\Swagger\Serializer\DocumentationNormalizer::getFiltersParameters
* @return FilterDescription[]
*/
public function getDescription(string $resourceClass): array;
}
25 changes: 20 additions & 5 deletions src/Bridge/Doctrine/Common/Filter/OrderFilterTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@

namespace ApiPlatform\Core\Bridge\Doctrine\Common\Filter;

use ApiPlatform\Core\Api\FilterDescription;
use ApiPlatform\Core\Bridge\Doctrine\Common\PropertyHelperTrait;
use Symfony\Component\PropertyInfo\Type;

/**
* Trait for ordering the collection by given properties.
Expand Down Expand Up @@ -48,11 +50,24 @@ public function getDescription(string $resourceClass): array
continue;
}
$propertyName = $this->normalizePropertyName($property);
$description[sprintf('%s[%s]', $this->orderParameterName, $propertyName)] = [
'property' => $propertyName,
'type' => 'string',
'required' => false,
];
$description[] = new FilterDescription(
sprintf('%s[%s]', $this->orderParameterName, $propertyName),
$propertyName,
Type::BUILTIN_TYPE_STRING,
false,
null,
false,
null,
[
'schema' => [
'type' => 'string',
'enum' => [
strtolower(OrderFilterInterface::DIRECTION_ASC),
strtolower(OrderFilterInterface::DIRECTION_DESC),
],
],
]
);
}

return $description;
Expand Down
Loading