Skip to content

Commit

Permalink
add fixtures and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelbigard committed Oct 5, 2021
1 parent a6623f2 commit 1496702
Show file tree
Hide file tree
Showing 6 changed files with 305 additions and 40 deletions.
112 changes: 112 additions & 0 deletions features/main/crud_uri_variables.feature
@@ -0,0 +1,112 @@
Feature: Uri Variables

@createSchema
@php8
Scenario: Create a resource Company
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/companies" with body:
"""
{
"name": "Api Platform"
}
"""
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/ld+json; charset=utf-8"
And the header "Content-Location" should be equal to "/companies/1"
And the header "Location" should be equal to "/companies/1"
And the JSON should be equal to:
"""
{
"@context": "/contexts/Company",
"@id": "/companies/1",
"@type": "Company",
"id": 1,
"name": "Api Platform"
}
"""

@php8
Scenario: Create a second resource Company
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/companies" with body:
"""
{
"name": "Les Tilleuls.coop"
}
"""
Then the response status code should be 201

@php8
Scenario: Create first Employee
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/employees" with body:
"""
{
"name": "foo",
"company": "/companies/1"
}
"""
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/ld+json; charset=utf-8"
And the header "Content-Location" should be equal to "/companies/1/employees/1"
And the header "Location" should be equal to "/companies/1/employees/1"
And the JSON should be equal to:
"""
{
"@context": "/contexts/Employee",
"@id": "/companies/1/employees/1",
"@type": "Employee",
"id": 1,
"name": "foo",
"company": "/companies/1"
}
"""

@php8
Scenario: Create second Employee
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/employees" with body:
"""
{
"name": "foo2",
"company": "/companies/2"
}
"""
Then the response status code should be 201

@php8
Scenario: Create thirf Employee
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/employees" with body:
"""
{
"name": "foo3",
"company": "/companies/2"
}
"""
Then the response status code should be 201
@php8
Scenario: Create a resource Company
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/companies" with body:
"""
{
"name": "bar",
"company": "/companies/1"
}
"""
Then the response status code should be 201

@php8
Scenario: Create a second resource Company
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/companies" with body:
"""
{
"name": "toto",
"company": "/companies/2"
}
"""
Then the response status code should be 201
22 changes: 10 additions & 12 deletions src/Bridge/Doctrine/Orm/State/UriVariablesHandlerTrait.php
Expand Up @@ -32,38 +32,36 @@ private function handleUriVariables(QueryBuilder $queryBuilder, array $identifie
$uriVariable = $uriVariables[$identifier] ?? $uriVariables['id'];

$placeholder = ':id_'.$identifier;
if (isset($uriVariable['property'])) {
$property = $uriVariable['property'];
$propertyIdentifier = $uriVariable['identifiers'][0];
$joinAlias = $queryNameGenerator->generateJoinAlias($property);
if ($inverseProperty = $uriVariable->getInverseProperty()) {
$propertyIdentifier = $uriVariable->getIdentifiers()[0];
$joinAlias = $queryNameGenerator->generateJoinAlias($inverseProperty);

$queryBuilder->join(
"$alias.$property",
$uriVariable->getTargetClass(),
$joinAlias,
'with',
"$alias.$propertyIdentifier = $joinAlias.$inverseProperty"
);

$expression = $queryBuilder->expr()->eq(
"{$joinAlias}.{$propertyIdentifier}",
$placeholder
);
} elseif (isset($uriVariable['inverseProperty'])) {
$property = $uriVariable['inverseProperty'];
$propertyIdentifier = $uriVariable['identifiers'][0];
} elseif ($property = $uriVariable->getProperty()) {
$propertyIdentifier = $uriVariable->getIdentifiers()[0];
$joinAlias = $queryNameGenerator->generateJoinAlias($property);

$queryBuilder->join(
$uriVariable['class'],
"$alias.$property",
$joinAlias,
'with',
"$alias.$propertyIdentifier = $joinAlias.$property"
);

$expression = $queryBuilder->expr()->eq(
"{$joinAlias}.{$propertyIdentifier}",
$placeholder
);
} else {
$propertyIdentifier = $uriVariable['identifiers'][0];
$propertyIdentifier = $uriVariable->getIdentifiers()[0];
$expression = $queryBuilder->expr()->eq(
"{$alias}.{$propertyIdentifier}",
$placeholder
Expand Down
Expand Up @@ -143,18 +143,20 @@ private function configureUriVariables($operation)
});

if (\count($variables) < \count($uriVariables)) {
$uriVariables = [];
}
$newUriVariables = [];
foreach ($variables as $variable) {
if (isset($uriVariables[$variable])) {
$newUriVariables[$variable] = $uriVariables[$variable];
continue;
}

foreach ($variables as $variable) {
if (isset($uriVariables[$variable])) {
continue;
$newUriVariables[$variable] = (new UriVariable())->withTargetClass($operation->getClass())->withIdentifiers([$variable]);
}

$uriVariables[$variable] = (new UriVariable())->withTargetClass($operation->getClass())->withIdentifiers([$variable]);
return $operation->withUriVariables($newUriVariables);
}

return $operation->withUriVariables($uriVariables);
return $operation;
}

/**
Expand Down Expand Up @@ -252,9 +254,16 @@ private function mergeUriVariablesAttributes($operation)

foreach ($reflectionProperty->getAttributes(UriVariable::class) ?? [] as $attributeUriVariable) {
$metadata = $this->propertyMetadataFactory->create($resourceClass, $property);
$attributeUriVariable = $attributeUriVariable->newInstance()
->withProperty($property)
->withTargetClass($this->getPropertyClassType($metadata->getBuiltinTypes()) ?? $resourceClass);

// TODO in 3.0: Remove if and else and let code of if
if (!isset($attributeUriVariable->getArguments()['targetClass'])) {
$attributeUriVariable = $attributeUriVariable->newInstance()
->withProperty($property)
->withTargetClass($this->getPropertyClassType($metadata->getBuiltinTypes()) ?? $resourceClass);
} else {
$attributeUriVariable = $attributeUriVariable->newInstance()
->withProperty($property);
}

if (isset($uriVariables[$parameterName = $attributeUriVariable->getParameterName()])) {
$uriVariables[$parameterName] = $uriVariables[$parameterName]->withUriVariable($attributeUriVariable);
Expand Down
32 changes: 14 additions & 18 deletions tests/Bridge/Doctrine/Orm/State/ItemProviderTest.php
Expand Up @@ -32,6 +32,7 @@
use ApiPlatform\Metadata\Property\PropertyNameCollection;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
use ApiPlatform\Metadata\UriVariable;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\OperationResource;
use Doctrine\DBAL\Connection;
Expand Down Expand Up @@ -86,11 +87,10 @@ public function testGetItemSingleIdentifier()
], $queryBuilder);

$resourceMetadataFactoryProphecy->create(OperationResource::class)->willReturn(new ResourceMetadataCollection(OperationResource::class, [(new ApiResource())->withOperations(new Operations(['get' => (new Get())->withUriVariables([
'identifier' => ['class' => "ApiPlatform\Tests\Fixtures\TestBundle\Entity\OperationResource",
'identifiers' => [
0 => 'identifier',
],
],
'identifier' => (new UriVariable())->withTargetClass("ApiPlatform\Tests\Fixtures\TestBundle\Entity\OperationResource")
->withIdentifiers([
0 => 'identifier',
]),
])]))]));

$extensionProphecy = $this->prophesize(QueryItemExtensionInterface::class);
Expand Down Expand Up @@ -125,16 +125,14 @@ public function testGetItemDoubleIdentifier()
$queryBuilderProphecy->getRootAliases()->shouldBeCalled()->willReturn(['o']);

$resourceMetadataFactoryProphecy->create(OperationResource::class)->willReturn(new ResourceMetadataCollection(OperationResource::class, [(new ApiResource())->withOperations(new Operations(['get' => (new Get())->withUriVariables([
'ida' => ['class' => "ApiPlatform\Tests\Fixtures\TestBundle\Entity\OperationResource",
'identifiers' => [
'ida' => (new UriVariable())->withTargetClass('ApiPlatform\Tests\Fixtures\TestBundle\Entity\OperationResource')
->withIdentifiers([
0 => 'ida',
],
],
'idb' => ['class' => "ApiPlatform\Tests\Fixtures\TestBundle\Entity\OperationResource",
'identifiers' => [
]),
'idb' => (new UriVariable())->withTargetClass('ApiPlatform\Tests\Fixtures\TestBundle\Entity\OperationResource')
->withIdentifiers([
0 => 'idb',
],
],
]),
])]))]));

$queryBuilderProphecy->setParameter(':id_ida', 1)->shouldBeCalled();
Expand Down Expand Up @@ -194,11 +192,9 @@ public function testQueryResultExtension()
$extensionProphecy->getResult($queryBuilder, OperationResource::class, 'get', $context)->willReturn([])->shouldBeCalled();

$resourceMetadataFactoryProphecy->create(OperationResource::class)->willReturn(new ResourceMetadataCollection(OperationResource::class, [(new ApiResource())->withOperations(new Operations(['get' => (new Get())->withUriVariables([
'identifier' => ['class' => "ApiPlatform\Tests\Fixtures\TestBundle\Entity\OperationResource",
'identifiers' => [
0 => 'identifier',
],
],
'identifier' => (new UriVariable())->withTargetClass("ApiPlatform\Tests\Fixtures\TestBundle\Entity\OperationResource")->withIdentifiers([
0 => 'identifier',
]),
])]))]));

$dataProvider = new ItemProvider($resourceMetadataFactoryProphecy->reveal(), $managerRegistry, [$extensionProphecy->reveal()]);
Expand Down
70 changes: 70 additions & 0 deletions tests/Fixtures/TestBundle/Entity/Company.php
@@ -0,0 +1,70 @@
<?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\Tests\Fixtures\TestBundle\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\UriVariable;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Ignore;

/**
* @ORM\Entity
*/
#[ApiResource]
#[Get]
#[Post]
#[ApiResource('/employee/{employeeId}/company')]
#[Get]
class Company
{
/**
* @var int The id
*
* @ORM\Column(type="integer", nullable=true)
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

/**
* @var string The dummy name
*
* @ORM\Column
*/
public string $name;

// TODO 3.0: Set the uri variable directly in the api resource and remove this property
#[UriVariable(parameterName: 'employeeId', inverseProperty: 'company', property: null, targetClass: Employee::class)]
/**
* @Ignore
*/
public $employees; // only used to set metadata

public function getId()
{
return $this->id;
}

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

public function setName(string $name): void
{
$this->name = $name;
}
}

0 comments on commit 1496702

Please sign in to comment.