Skip to content

Commit

Permalink
Merge branch '2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
dunglas committed Jan 25, 2017
2 parents 225a861 + 01303fa commit 93bab59
Show file tree
Hide file tree
Showing 17 changed files with 272 additions and 14 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ cache:
matrix:
include:
- php: '7.0'
- php: '7.1'
env: coverage=1 lint=1
- php: '7.1'
env: deps='low'

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

script:
- if [[ $coverage = 1 ]]; then phpdbg -qrr -dmemory_limit=-1 vendor/bin/phpunit --coverage-php build/cov/coverage-phpunit.cov; else vendor/bin/phpunit; fi
- if [[ $coverage = 1 ]]; then phpdbg -qrr vendor/bin/phpunit --coverage-php build/cov/coverage-phpunit.cov; else vendor/bin/phpunit; fi
- 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
- if [[ $coverage = 1 ]]; then phpdbg -qrr phpcov.phar merge --clover build/logs/clover.xml build/cov; fi
- tests/Fixtures/app/console api:swagger:export > swagger.json && swagger validate swagger.json && rm swagger.json
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ publicly**. We will disclose details of the issue and credit you after having re
### Writing a Pull Request

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

### Matching coding standards
Expand Down
60 changes: 59 additions & 1 deletion features/main/custom_normalized.feature
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,67 @@ Feature: Using custom normalized entity
"@context": "/contexts/CustomNormalizedDummy",
"@id": "/custom_normalized_dummies/1",
"@type": "CustomNormalizedDummy",
"id": 1,
"name": "My Dummy",
"alias": "My alias"
}
"""

Scenario: Get a resource
Scenario: Create a resource with a custom normalized dummy
When I add "Content-Type" header equal to "application/json"
When I add "Accept" header equal to "application/json"
And I send a "POST" request to "/related_normalized_dummies" with body:
"""
{
"name": "My Dummy"
}
"""
Then the response status code should be 201
And the response should be in JSON
And the header "Content-Type" should be equal to "application/json; charset=utf-8"
And the JSON should be equal to:
"""
{
"id": 1,
"name": "My Dummy",
"customNormalizedDummy": []
}
"""

Scenario: Create a resource with a custom normalized dummy and an id
When I add "Content-Type" header equal to "application/json"
When I add "Accept" header equal to "application/json"
And I send a "PUT" request to "/related_normalized_dummies/1" with body:
"""
{
"name": "My Dummy",
"customNormalizedDummy":[{
"@context": "/contexts/CustomNormalizedDummy",
"@id": "/custom_normalized_dummies/1",
"@type": "CustomNormalizedDummy",
"id": 1,
"name": "My Dummy"
}]
}
"""
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/json; charset=utf-8"
And the JSON should be equal to:
"""
{
"id": 1,
"name": "My Dummy",
"customNormalizedDummy":[{
"id": 1,
"name": "My Dummy",
"alias": "My alias"
}]
}
"""


Scenario: Get a custom normalized dummy resource
When I send a "GET" request to "/custom_normalized_dummies/1"
Then the response status code should be 200
And the response should be in JSON
Expand All @@ -38,6 +93,7 @@ Feature: Using custom normalized entity
"@context": "/contexts/CustomNormalizedDummy",
"@id": "/custom_normalized_dummies/1",
"@type": "CustomNormalizedDummy",
"id": 1,
"name": "My Dummy",
"alias": "My alias"
}
Expand All @@ -58,6 +114,7 @@ Feature: Using custom normalized entity
{
"@id": "/custom_normalized_dummies/1",
"@type": "CustomNormalizedDummy",
"id": 1,
"name": "My Dummy",
"alias": "My alias"
}
Expand All @@ -83,6 +140,7 @@ Feature: Using custom normalized entity
"@context": "/contexts/CustomNormalizedDummy",
"@id": "/custom_normalized_dummies/1",
"@type": "CustomNormalizedDummy",
"id": 1,
"name": "My Dummy modified",
"alias": "My alias"
}
Expand Down
12 changes: 12 additions & 0 deletions features/main/relation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,18 @@ Feature: Relations support
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"

Scenario: Post a relation with a not existing IRI
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/relation_embedders" with body:
"""
{
"related": "/related_dummies/123"
}
"""
Then the response status code should be 400
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"

@dropSchema
Scenario: Update an embedded relation
When I add "Content-Type" header equal to "application/ld+json"
Expand Down
3 changes: 2 additions & 1 deletion src/Bridge/Symfony/Routing/IriConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use ApiPlatform\Core\Api\UrlGeneratorInterface;
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
use ApiPlatform\Core\Exception\InvalidArgumentException;
use ApiPlatform\Core\Exception\ItemNotFoundException;
use ApiPlatform\Core\Exception\RuntimeException;
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
Expand Down Expand Up @@ -69,7 +70,7 @@ public function getItemFromIri(string $iri, array $context = [])
return $item;
}

throw new InvalidArgumentException(sprintf('Item not found for "%s".', $iri));
throw new ItemNotFoundException(sprintf('Item not found for "%s".', $iri));
}

/**
Expand Down
21 changes: 21 additions & 0 deletions src/Exception/ItemNotFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?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.
*/

namespace ApiPlatform\Core\Exception;

/**
* Item not found exception.
*
* @author Amrouche Hamza <hamza.simperfit@gmail.com>
*/
class ItemNotFoundException extends InvalidArgumentException
{
}
2 changes: 1 addition & 1 deletion src/JsonLd/Serializer/ItemNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public function denormalize($data, $class, $format = null, array $context = [])
throw new InvalidArgumentException('Update is not allowed for this operation.');
}

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

return parent::denormalize($data, $class, $format, $context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ public function create(string $resourceClass, array $options = []): PropertyName

// Methods
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
if ($reflectionMethod->isStatic()) {
continue;
}

$propertyName = $this->reflection->getProperty($reflectionMethod->name);
if (!preg_match('/^[A-Z]{2,}/', $propertyName)) {
$propertyName = lcfirst($propertyName);
Expand Down
5 changes: 4 additions & 1 deletion src/Serializer/AbstractItemNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
use ApiPlatform\Core\Exception\InvalidArgumentException;
use ApiPlatform\Core\Exception\ItemNotFoundException;
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
Expand Down Expand Up @@ -273,7 +274,9 @@ private function denormalizeRelation(string $attributeName, PropertyMetadata $pr
{
if (is_string($value)) {
try {
return $this->iriConverter->getItemFromIri($value, $context + ['fetch_data' => false]);
return $this->iriConverter->getItemFromIri($value, $context + ['fetch_data' => true]);
} catch (ItemNotFoundException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
} catch (InvalidArgumentException $e) {
// Give a chance to other normalizers (e.g.: DateTimeNormalizer)
}
Expand Down
23 changes: 22 additions & 1 deletion src/Serializer/ItemNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,30 @@ public function denormalize($data, $class, $format = null, array $context = [])
throw new InvalidArgumentException('Update is not allowed for this operation.');
}

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

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

private function updateObjectToPopulate(array $data, array &$context)
{
try {
$context['object_to_populate'] = $this->iriConverter->getItemFromIri($data['id'], $context + ['fetch_data' => false]);
} catch (InvalidArgumentException $e) {
$identifier = null;
foreach ($this->propertyNameCollectionFactory->create($context['resource_class'], $context) as $propertyName) {
if (true === $this->propertyMetadataFactory->create($context['resource_class'], $propertyName)->isIdentifier()) {
$identifier = $propertyName;
break;
}
}

if (null === $identifier) {
throw $e;
}

$context['object_to_populate'] = $this->iriConverter->getItemFromIri(sprintf('%s/%s', $this->iriConverter->getIriFromResourceClass($context['resource_class']), $data[$identifier]), $context + ['fetch_data' => false]);
}
}
}
5 changes: 2 additions & 3 deletions src/Serializer/JsonEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

namespace ApiPlatform\Core\Serializer;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Serializer\Encoder\DecoderInterface;
use Symfony\Component\Serializer\Encoder\EncoderInterface;
use Symfony\Component\Serializer\Encoder\JsonDecode;
Expand All @@ -32,9 +31,9 @@ public function __construct(string $format, BaseJsonEncoder $jsonEncoder = null)
{
$this->format = $format;

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

Expand Down
1 change: 1 addition & 0 deletions tests/Fixtures/TestBundle/Entity/CustomNormalizedDummy.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class CustomNormalizedDummy
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @Groups({"input", "output"})
*/
private $id;

Expand Down
4 changes: 4 additions & 0 deletions tests/Fixtures/TestBundle/Entity/Dummy.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ class Dummy
*/
public $nameConverted;

public static function staticMethod()
{
}

public function __construct()
{
$this->relatedDummies = new ArrayCollection();
Expand Down
6 changes: 3 additions & 3 deletions tests/Fixtures/TestBundle/Entity/DummyFriend.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class DummyFriend
/**
* Get id.
*
* @return id
* @return int
*/
public function getId()
{
Expand All @@ -69,7 +69,7 @@ public function setId($id)
/**
* Get name.
*
* @return name
* @return string
*/
public function getName()
{
Expand All @@ -79,7 +79,7 @@ public function getName()
/**
* Set name.
*
* @param name the value to set
* @param string the value to set
*/
public function setName($name)
{
Expand Down
Loading

0 comments on commit 93bab59

Please sign in to comment.