Skip to content

Commit 0edf6a7

Browse files
committed
Add tests
1 parent e6d04dc commit 0edf6a7

File tree

6 files changed

+467
-1
lines changed

6 files changed

+467
-1
lines changed

JsonLd/Serializer/ItemNormalizer.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,20 @@ public function denormalize($data, $class, $format = null, array $context = [])
211211
$overrideClass = false;
212212
}
213213

214+
$instanceClass = $overrideClass ? get_class($context['object_to_populate']) : $class;
215+
$reflectionClass = new \ReflectionClass($instanceClass);
216+
if ($reflectionClass->isAbstract()) {
217+
throw new InvalidArgumentException(
218+
sprintf(
219+
'Cannot create an instance of %s from serialized data because it is an abstract resource',
220+
$instanceClass
221+
)
222+
);
223+
}
224+
214225
$object = $this->instantiateObject(
215226
$normalizedData,
216-
$overrideClass ? get_class($context['object_to_populate']) : $class,
227+
$instanceClass,
217228
$context,
218229
$reflectionClass,
219230
$allowedAttributes
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the DunglasApiBundle package.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.com>
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 Dunglas\ApiBundle\Tests\Behat\TestBundle\Entity;
13+
14+
use Doctrine\Common\Collections\ArrayCollection;
15+
use Doctrine\ORM\Mapping as ORM;
16+
use Dunglas\ApiBundle\Annotation\Iri;
17+
use Symfony\Component\Validator\Constraints as Assert;
18+
19+
/**
20+
* AbstractDummy.
21+
*
22+
* @author Jérémy Derusse jeremy@derusse.com
23+
*
24+
* @ORM\Entity
25+
* @ORM\InheritanceType("SINGLE_TABLE")
26+
* @ORM\DiscriminatorColumn(name="discr", type="string", length=16)
27+
* @ORM\DiscriminatorMap({"concrete" = "ConcreteDummy"})
28+
*/
29+
abstract class AbstractDummy
30+
{
31+
/**
32+
* @var int The id.
33+
*
34+
* @ORM\Column(type="integer")
35+
* @ORM\Id
36+
* @ORM\GeneratedValue(strategy="AUTO")
37+
*/
38+
private $id;
39+
/**
40+
* @var string The dummy name.
41+
*
42+
* @ORM\Column
43+
* @Assert\NotBlank
44+
* @Iri("http://schema.org/name")
45+
*/
46+
private $name;
47+
48+
public function getId()
49+
{
50+
return $this->id;
51+
}
52+
53+
public function setName($name)
54+
{
55+
$this->name = $name;
56+
}
57+
58+
public function getName()
59+
{
60+
return $this->name;
61+
}
62+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the DunglasApiBundle package.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.com>
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 Dunglas\ApiBundle\Tests\Behat\TestBundle\Entity;
13+
14+
use Doctrine\Common\Collections\ArrayCollection;
15+
use Doctrine\ORM\Mapping as ORM;
16+
use Dunglas\ApiBundle\Annotation\Iri;
17+
use Symfony\Component\Validator\Constraints as Assert;
18+
19+
/**
20+
* ConcreteDummy.
21+
*
22+
* @author Jérémy Derusse jeremy@derusse.com
23+
*
24+
* @ORM\Entity
25+
*/
26+
class ConcreteDummy extends AbstractDummy
27+
{
28+
/**
29+
* @var string a concrete thing
30+
*
31+
* @ORM\Column
32+
* @Assert\NotBlank
33+
*/
34+
private $instance;
35+
36+
public function setInstance($instance)
37+
{
38+
$this->instance = $instance;
39+
}
40+
41+
public function getInstance()
42+
{
43+
return $this->instance;
44+
}
45+
}

features/crud_abstract.feature

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
Feature: Create-Retrieve-Update-Delete on abstract resource
2+
In order to use an hypermedia API
3+
As a client software developer
4+
I need to be able to retrieve, create, update and delete JSON-LD encoded resources even if they are abstract.
5+
6+
@createSchema
7+
Scenario: Create an abstract resource
8+
When I send a "POST" request to "/abstract_dummies" with body:
9+
"""
10+
{
11+
"instance": "Concrete",
12+
"name": "My Dummy"
13+
}
14+
"""
15+
Then the response status code should be 400
16+
And the response should be in JSON
17+
And the header "Content-Type" should be equal to "application/ld+json"
18+
And the JSON node "@context" should be equal to "/contexts/Error"
19+
And the JSON node "@type" should be equal to "Error"
20+
And the JSON node "hydra:title" should be equal to "An error occurred"
21+
And the JSON node "hydra:description" should be equal to "Cannot create an instance of Dunglas\ApiBundle\Tests\Behat\TestBundle\Entity\AbstractDummy from serialized data because it is an abstract resource"
22+
And the JSON node "trace" should exist
23+
24+
Scenario: Create a concrete resource
25+
When I send a "POST" request to "/concrete_dummies" with body:
26+
"""
27+
{
28+
"instance": "Concrete",
29+
"name": "My Dummy"
30+
}
31+
"""
32+
Then the response status code should be 201
33+
And the response should be in JSON
34+
And the header "Content-Type" should be equal to "application/ld+json"
35+
And the JSON should be equal to:
36+
"""
37+
{
38+
"@context": "/contexts/ConcreteDummy",
39+
"@id": "/concrete_dummies/1",
40+
"@type": "ConcreteDummy",
41+
"instance": "Concrete",
42+
"name": "My Dummy"
43+
}
44+
"""
45+
46+
Scenario: Get a resource
47+
When I send a "GET" request to "/abstract_dummies/1"
48+
Then the response status code should be 200
49+
And the response should be in JSON
50+
And the header "Content-Type" should be equal to "application/ld+json"
51+
And the JSON should be equal to:
52+
"""
53+
{
54+
"@context": "/contexts/ConcreteDummy",
55+
"@id": "/concrete_dummies/1",
56+
"@type": "ConcreteDummy",
57+
"instance": "Concrete",
58+
"name": "My Dummy"
59+
}
60+
"""
61+
62+
Scenario: Get a collection
63+
When I send a "GET" request to "/abstract_dummies"
64+
Then the response status code should be 200
65+
And the response should be in JSON
66+
And the header "Content-Type" should be equal to "application/ld+json"
67+
And the JSON should be equal to:
68+
"""
69+
{
70+
"@context": "/contexts/AbstractDummy",
71+
"@id": "/abstract_dummies",
72+
"@type": "hydra:PagedCollection",
73+
"hydra:totalItems": 1,
74+
"hydra:itemsPerPage": 3,
75+
"hydra:firstPage": "/abstract_dummies",
76+
"hydra:lastPage": "/abstract_dummies",
77+
"hydra:member": [
78+
{
79+
"@id":"/concrete_dummies/1",
80+
"@type":"ConcreteDummy",
81+
"instance": "Concrete",
82+
"name": "My Dummy"
83+
}
84+
],
85+
"hydra:search": {
86+
"@type": "hydra:IriTemplate",
87+
"hydra:template": "\/abstract_dummies{?id,name,order[id],order[name]}",
88+
"hydra:variableRepresentation": "BasicRepresentation",
89+
"hydra:mapping": [
90+
{
91+
"@type": "IriTemplateMapping",
92+
"variable": "id",
93+
"property": "id",
94+
"required": false
95+
},
96+
{
97+
"@type": "IriTemplateMapping",
98+
"variable": "name",
99+
"property": "name",
100+
"required": false
101+
},
102+
{
103+
"@type": "IriTemplateMapping",
104+
"variable": "order[id]",
105+
"property": "id",
106+
"required": false
107+
},
108+
{
109+
"@type": "IriTemplateMapping",
110+
"variable": "order[name]",
111+
"property": "name",
112+
"required": false
113+
}
114+
]
115+
}
116+
}
117+
"""
118+
119+
Scenario: Update an abstract resource
120+
When I send a "PUT" request to "/abstract_dummies/1" with body:
121+
"""
122+
{
123+
"@id": "/concrete_dummies/1",
124+
"instance": "Become real",
125+
"name": "A nice dummy"
126+
}
127+
"""
128+
Then the response status code should be 400
129+
And the response should be in JSON
130+
And the header "Content-Type" should be equal to "application/ld+json"
131+
And the JSON node "@context" should be equal to "/contexts/Error"
132+
And the JSON node "@type" should be equal to "Error"
133+
And the JSON node "hydra:title" should be equal to "An error occurred"
134+
And the JSON node "hydra:description" should be equal to "Cannot create an instance of Dunglas\ApiBundle\Tests\Behat\TestBundle\Entity\AbstractDummy from serialized data because it is an abstract resource"
135+
And the JSON node "trace" should exist
136+
137+
Scenario: Update a concrete resource
138+
When I send a "PUT" request to "/concrete_dummies/1" with body:
139+
"""
140+
{
141+
"@id": "/concrete_dummies/1",
142+
"instance": "Become real",
143+
"name": "A nice dummy"
144+
}
145+
"""
146+
Then the response status code should be 200
147+
And the response should be in JSON
148+
And the header "Content-Type" should be equal to "application/ld+json"
149+
And the JSON should be equal to:
150+
"""
151+
{
152+
"@context": "/contexts/ConcreteDummy",
153+
"@id": "/concrete_dummies/1",
154+
"@type": "ConcreteDummy",
155+
"instance": "Become real",
156+
"name": "A nice dummy"
157+
}
158+
"""
159+
160+
@dropSchema
161+
Scenario: Delete a resource
162+
When I send a "DELETE" request to "/abstract_dummies/1"
163+
Then the response status code should be 204
164+
And the response should be empty

features/fixtures/TestApp/config/config.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,19 @@ services:
112112
- "@my_relation_embedder_resource.item_operation.custom_get"
113113
tags: [ { name: "api.resource" } ]
114114

115+
my_abstract_dummy_resource:
116+
parent: "api.resource"
117+
arguments: [ "Dunglas\ApiBundle\Tests\Behat\TestBundle\Entity\AbstractDummy" ]
118+
calls:
119+
- method: "initFilters"
120+
arguments: [ [ "@my_dummy_resource.search_filter", "@my_dummy_resource.order_filter", "@my_dummy_resource.date_filter" ] ]
121+
tags: [ { name: "api.resource" } ]
122+
123+
my_concrete_dummy_resource:
124+
parent: "api.resource"
125+
arguments: [ "Dunglas\ApiBundle\Tests\Behat\TestBundle\Entity\ConcreteDummy" ]
126+
tags: [ { name: "api.resource" } ]
127+
115128
custom_resource:
116129
parent: "api.resource"
117130
class: "Dunglas\ApiBundle\Tests\Behat\TestBundle\Api\CustomResource"

0 commit comments

Comments
 (0)