Skip to content

Commit 93bab59

Browse files
committed
Merge branch '2.0'
2 parents 225a861 + 01303fa commit 93bab59

File tree

17 files changed

+272
-14
lines changed

17 files changed

+272
-14
lines changed

.travis.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ cache:
1010
matrix:
1111
include:
1212
- php: '7.0'
13+
- php: '7.1'
1314
env: coverage=1 lint=1
1415
- php: '7.1'
1516
env: deps='low'
1617

1718
before_install:
1819
- phpenv config-rm xdebug.ini || echo "xdebug not available"
20+
- echo "memory_limit=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
1921
- npm install -g swagger-cli
2022
- if [[ $coverage = 1 ]]; then mkdir -p build/logs build/cov; fi
2123
- if [[ $coverage = 1 ]]; then wget https://phar.phpunit.de/phpcov.phar; fi
@@ -30,7 +32,7 @@ install:
3032
- if [[ $deps = 'low' ]]; then composer update --prefer-dist --no-progress --no-suggest --prefer-stable --prefer-lowest --ansi; fi
3133

3234
script:
33-
- if [[ $coverage = 1 ]]; then phpdbg -qrr -dmemory_limit=-1 vendor/bin/phpunit --coverage-php build/cov/coverage-phpunit.cov; else vendor/bin/phpunit; fi
35+
- if [[ $coverage = 1 ]]; then phpdbg -qrr vendor/bin/phpunit --coverage-php build/cov/coverage-phpunit.cov; else vendor/bin/phpunit; fi
3436
- if [[ $coverage = 1 ]]; then for feature in $(ls -d features/*/ | cut -f2 -d'/' | grep -v bootstrap); do FEATURE=$feature phpdbg -qrr vendor/bin/behat --profile coverage features/$feature; done; else vendor/bin/behat; fi
3537
- if [[ $coverage = 1 ]]; then phpdbg -qrr phpcov.phar merge --clover build/logs/clover.xml build/cov; fi
3638
- tests/Fixtures/app/console api:swagger:export > swagger.json && swagger validate swagger.json && rm swagger.json

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ publicly**. We will disclose details of the issue and credit you after having re
2828
### Writing a Pull Request
2929

3030
First of all, you must decide on what branch your changes will be based. If the changes your are going to make are
31-
fully backward-compatible, you should base your changes on the latest stable branch (`1.0` at the moment).
31+
fully backward-compatible, you should base your changes on the latest stable branch (`2.0` at the moment).
3232
Otherwise, you should base your changes on the `master` branch.
3333

3434
### Matching coding standards

features/main/custom_normalized.feature

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,67 @@ Feature: Using custom normalized entity
2222
"@context": "/contexts/CustomNormalizedDummy",
2323
"@id": "/custom_normalized_dummies/1",
2424
"@type": "CustomNormalizedDummy",
25+
"id": 1,
2526
"name": "My Dummy",
2627
"alias": "My alias"
2728
}
2829
"""
2930

30-
Scenario: Get a resource
31+
Scenario: Create a resource with a custom normalized dummy
32+
When I add "Content-Type" header equal to "application/json"
33+
When I add "Accept" header equal to "application/json"
34+
And I send a "POST" request to "/related_normalized_dummies" with body:
35+
"""
36+
{
37+
"name": "My Dummy"
38+
}
39+
"""
40+
Then the response status code should be 201
41+
And the response should be in JSON
42+
And the header "Content-Type" should be equal to "application/json; charset=utf-8"
43+
And the JSON should be equal to:
44+
"""
45+
{
46+
"id": 1,
47+
"name": "My Dummy",
48+
"customNormalizedDummy": []
49+
}
50+
"""
51+
52+
Scenario: Create a resource with a custom normalized dummy and an id
53+
When I add "Content-Type" header equal to "application/json"
54+
When I add "Accept" header equal to "application/json"
55+
And I send a "PUT" request to "/related_normalized_dummies/1" with body:
56+
"""
57+
{
58+
"name": "My Dummy",
59+
"customNormalizedDummy":[{
60+
"@context": "/contexts/CustomNormalizedDummy",
61+
"@id": "/custom_normalized_dummies/1",
62+
"@type": "CustomNormalizedDummy",
63+
"id": 1,
64+
"name": "My Dummy"
65+
}]
66+
}
67+
"""
68+
Then the response status code should be 200
69+
And the response should be in JSON
70+
And the header "Content-Type" should be equal to "application/json; charset=utf-8"
71+
And the JSON should be equal to:
72+
"""
73+
{
74+
"id": 1,
75+
"name": "My Dummy",
76+
"customNormalizedDummy":[{
77+
"id": 1,
78+
"name": "My Dummy",
79+
"alias": "My alias"
80+
}]
81+
}
82+
"""
83+
84+
85+
Scenario: Get a custom normalized dummy resource
3186
When I send a "GET" request to "/custom_normalized_dummies/1"
3287
Then the response status code should be 200
3388
And the response should be in JSON
@@ -38,6 +93,7 @@ Feature: Using custom normalized entity
3893
"@context": "/contexts/CustomNormalizedDummy",
3994
"@id": "/custom_normalized_dummies/1",
4095
"@type": "CustomNormalizedDummy",
96+
"id": 1,
4197
"name": "My Dummy",
4298
"alias": "My alias"
4399
}
@@ -58,6 +114,7 @@ Feature: Using custom normalized entity
58114
{
59115
"@id": "/custom_normalized_dummies/1",
60116
"@type": "CustomNormalizedDummy",
117+
"id": 1,
61118
"name": "My Dummy",
62119
"alias": "My alias"
63120
}
@@ -83,6 +140,7 @@ Feature: Using custom normalized entity
83140
"@context": "/contexts/CustomNormalizedDummy",
84141
"@id": "/custom_normalized_dummies/1",
85142
"@type": "CustomNormalizedDummy",
143+
"id": 1,
86144
"name": "My Dummy modified",
87145
"alias": "My alias"
88146
}

features/main/relation.feature

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,18 @@ Feature: Relations support
303303
And the response should be in JSON
304304
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
305305

306+
Scenario: Post a relation with a not existing IRI
307+
When I add "Content-Type" header equal to "application/ld+json"
308+
And I send a "POST" request to "/relation_embedders" with body:
309+
"""
310+
{
311+
"related": "/related_dummies/123"
312+
}
313+
"""
314+
Then the response status code should be 400
315+
And the response should be in JSON
316+
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
317+
306318
@dropSchema
307319
Scenario: Update an embedded relation
308320
When I add "Content-Type" header equal to "application/ld+json"

src/Bridge/Symfony/Routing/IriConverter.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use ApiPlatform\Core\Api\UrlGeneratorInterface;
1616
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
1717
use ApiPlatform\Core\Exception\InvalidArgumentException;
18+
use ApiPlatform\Core\Exception\ItemNotFoundException;
1819
use ApiPlatform\Core\Exception\RuntimeException;
1920
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
2021
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
@@ -69,7 +70,7 @@ public function getItemFromIri(string $iri, array $context = [])
6970
return $item;
7071
}
7172

72-
throw new InvalidArgumentException(sprintf('Item not found for "%s".', $iri));
73+
throw new ItemNotFoundException(sprintf('Item not found for "%s".', $iri));
7374
}
7475

7576
/**
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace ApiPlatform\Core\Exception;
13+
14+
/**
15+
* Item not found exception.
16+
*
17+
* @author Amrouche Hamza <[email protected]>
18+
*/
19+
class ItemNotFoundException extends InvalidArgumentException
20+
{
21+
}

src/JsonLd/Serializer/ItemNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public function denormalize($data, $class, $format = null, array $context = [])
9696
throw new InvalidArgumentException('Update is not allowed for this operation.');
9797
}
9898

99-
$context['object_to_populate'] = $this->iriConverter->getItemFromIri($data['@id'], $context + ['fetch_data' => false]);
99+
$context['object_to_populate'] = $this->iriConverter->getItemFromIri($data['@id'], $context + ['fetch_data' => true]);
100100
}
101101

102102
return parent::denormalize($data, $class, $format, $context);

src/Metadata/Property/Factory/AnnotationPropertyNameCollectionFactory.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ public function create(string $resourceClass, array $options = []): PropertyName
6969

7070
// Methods
7171
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
72+
if ($reflectionMethod->isStatic()) {
73+
continue;
74+
}
75+
7276
$propertyName = $this->reflection->getProperty($reflectionMethod->name);
7377
if (!preg_match('/^[A-Z]{2,}/', $propertyName)) {
7478
$propertyName = lcfirst($propertyName);

src/Serializer/AbstractItemNormalizer.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use ApiPlatform\Core\Api\IriConverterInterface;
1515
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
1616
use ApiPlatform\Core\Exception\InvalidArgumentException;
17+
use ApiPlatform\Core\Exception\ItemNotFoundException;
1718
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
1819
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
1920
use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
@@ -273,7 +274,9 @@ private function denormalizeRelation(string $attributeName, PropertyMetadata $pr
273274
{
274275
if (is_string($value)) {
275276
try {
276-
return $this->iriConverter->getItemFromIri($value, $context + ['fetch_data' => false]);
277+
return $this->iriConverter->getItemFromIri($value, $context + ['fetch_data' => true]);
278+
} catch (ItemNotFoundException $e) {
279+
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
277280
} catch (InvalidArgumentException $e) {
278281
// Give a chance to other normalizers (e.g.: DateTimeNormalizer)
279282
}

src/Serializer/ItemNormalizer.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,30 @@ public function denormalize($data, $class, $format = null, array $context = [])
3333
throw new InvalidArgumentException('Update is not allowed for this operation.');
3434
}
3535

36-
$context['object_to_populate'] = $this->iriConverter->getItemFromIri($data['id'], $context + ['fetch_data' => false]);
36+
$this->updateObjectToPopulate($data, $context);
3737
}
3838

3939
return parent::denormalize($data, $class, $format, $context);
4040
}
41+
42+
private function updateObjectToPopulate(array $data, array &$context)
43+
{
44+
try {
45+
$context['object_to_populate'] = $this->iriConverter->getItemFromIri($data['id'], $context + ['fetch_data' => false]);
46+
} catch (InvalidArgumentException $e) {
47+
$identifier = null;
48+
foreach ($this->propertyNameCollectionFactory->create($context['resource_class'], $context) as $propertyName) {
49+
if (true === $this->propertyMetadataFactory->create($context['resource_class'], $propertyName)->isIdentifier()) {
50+
$identifier = $propertyName;
51+
break;
52+
}
53+
}
54+
55+
if (null === $identifier) {
56+
throw $e;
57+
}
58+
59+
$context['object_to_populate'] = $this->iriConverter->getItemFromIri(sprintf('%s/%s', $this->iriConverter->getIriFromResourceClass($context['resource_class']), $data[$identifier]), $context + ['fetch_data' => false]);
60+
}
61+
}
4162
}

src/Serializer/JsonEncoder.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace ApiPlatform\Core\Serializer;
1313

14-
use Symfony\Component\HttpFoundation\JsonResponse;
1514
use Symfony\Component\Serializer\Encoder\DecoderInterface;
1615
use Symfony\Component\Serializer\Encoder\EncoderInterface;
1716
use Symfony\Component\Serializer\Encoder\JsonDecode;
@@ -32,9 +31,9 @@ public function __construct(string $format, BaseJsonEncoder $jsonEncoder = null)
3231
{
3332
$this->format = $format;
3433

35-
// Encode <, >, ', &, and " for RFC4627-compliant JSON, which may also be embedded into HTML.
34+
// Encode <, >, ', &, and " characters in the JSON, making it also safe to be embedded into HTML.
3635
$this->jsonEncoder = $jsonEncoder ?: new BaseJsonEncoder(
37-
new JsonEncode(JsonResponse::DEFAULT_ENCODING_OPTIONS), new JsonDecode(true)
36+
new JsonEncode(JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_UNESCAPED_UNICODE), new JsonDecode(true)
3837
);
3938
}
4039

tests/Fixtures/TestBundle/Entity/CustomNormalizedDummy.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class CustomNormalizedDummy
3636
* @ORM\Column(type="integer")
3737
* @ORM\Id
3838
* @ORM\GeneratedValue(strategy="AUTO")
39+
* @Groups({"input", "output"})
3940
*/
4041
private $id;
4142

tests/Fixtures/TestBundle/Entity/Dummy.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ class Dummy
130130
*/
131131
public $nameConverted;
132132

133+
public static function staticMethod()
134+
{
135+
}
136+
133137
public function __construct()
134138
{
135139
$this->relatedDummies = new ArrayCollection();

tests/Fixtures/TestBundle/Entity/DummyFriend.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class DummyFriend
4949
/**
5050
* Get id.
5151
*
52-
* @return id
52+
* @return int
5353
*/
5454
public function getId()
5555
{
@@ -69,7 +69,7 @@ public function setId($id)
6969
/**
7070
* Get name.
7171
*
72-
* @return name
72+
* @return string
7373
*/
7474
public function getName()
7575
{
@@ -79,7 +79,7 @@ public function getName()
7979
/**
8080
* Set name.
8181
*
82-
* @param name the value to set
82+
* @param string the value to set
8383
*/
8484
public function setName($name)
8585
{

0 commit comments

Comments
 (0)