10000 [Feature] Hydrate client generated ids into Eloquent models · tooshay/laravel-json-api@33bad87 · GitHub
[go: up one dir, main page]

Skip to content

Commit 33bad87

Browse files
committed
[Feature] Hydrate client generated ids into Eloquent models
Hydration will only occur if the `$clientId` property on the hydrator is `true` or a string key name. It will also only be executed when creating the record.
1 parent a1767b3 commit 33bad87

File tree

9 files changed

+189
-3
lines changed

9 files changed

+189
-3
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
All notable changes to this project will be documented in this file. This project adheres to
33
[Semantic Versioning](http://semver.org/) and [this changelog format](http://keepachangelog.com/).
44

5+
## Unreleased
6+
7+
### Added
8+
- Client supplied ids will now be hydrated into Eloquent models, configurable via the `$clientId` property
9+
on the Eloquent hydrator.
10+
511
## [0.10.0] - 2017-07-29
612

713
### Added

src/Hydrator/EloquentHydrator.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@ class EloquentHydrator extends AbstractHydrator implements HydratesRelatedInterf
4646

4747
use RelatedHydratorTrait;
4848

49+
/**
50+
* Whether the resource has a client generated id.
51+
*
52+
* If true, the resource id will be transferred to the Model's id key
53+
* (using `getKeyName`) if the model does not exist.
54+
*
55+
* If `getKeyName` is not the correct model key to transfer the resource
56+
* id to, set this property to the string key name.
57+
*
58+
* @var bool
59+
*/
60+
protected $clientId = false;
61+
4962
/**
5063
* The resource attribute keys to hydrate.
5164
*
@@ -128,6 +141,31 @@ public function __construct(JsonApiService $service)
128141
$this->service = $service;
129142
}
130143

144+
/**
145+
* @param ResourceObjectInterface $resource
146+
* @param Model $record
147+
* @return object
148+
*/
149+
public function hydrate(ResourceObjectInterface $resource, $record)
150+
{
151+
if (!$record->exists && $this->clientId) {
152+
$this->clientId($resource->getIdentifier()->getId(), $record);
153+
}
154+
155+
return parent::hydrate($resource, $record);
156+
}
157+
158+
/**
159+
* @param $resourceId
160+
* @param Model $record
161+
* @return void
162+
*/
163+
protected function clientId($resourceId, Model $record)
164+
{
165+
$key = !is_string($this->clientId) ? $record->getKeyName() : $this->clientId;
166+
$record->{$key} = $resourceId;
167+
}
168+
131169
/**
132170
* @param StandardObjectInterface $attributes
133171
* the attributes received from the client.

tests/Http/Controllers/CommentsController.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@
33
namespace CloudCreativity\LaravelJsonApi\Tests\Http\Controllers;
44

55
use CloudCreativity\LaravelJsonApi\Http\Controllers\EloquentController;
6+
use CloudCreativity\LaravelJsonApi\Tests\JsonApi\Comments\Hydrator;
67
use CloudCreativity\LaravelJsonApi\Tests\Models\Comment;
78

89
class CommentsController extends EloquentController
910
{
1011

1112
/**
1213
* CommentsController constructor.
14+
*
15+
* @param Hydrator $hydrator
1316
*/
14-
public function __construct()
17+
public function __construct(Hydrator $hydrator)
1518
{
16-
parent::__construct(new Comment());
19+
parent::__construct(new Comment(), $hydrator);
1720
}
1821
}

tests/Integration/Eloquent/CommentsTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,36 @@ class CommentsTest extends TestCase
1212
*/
1313
protected $resourceType = 'comments';
1414

15+
public function testCreate()
16+
{
17+
$model = $this->createComment(false);
18+
19+
$data = [
20+
'type' => 'comments',
21+
'id' => $id = $model->getKey(), // client generated id.
22+
'attributes' => [
23+
'content' => $model->content,
24+
],
25+
'relationships' => [
26+
'post' => [
27+
'data' => [
28+
'type' => 'posts',
29+
'id' => (string) $model->post_id,
30+
],
31+
],
32+
],
33+
];
34+
35+
$this->actingAs($model->user);
36+
$this->doCreate($data)->assertCreateResponse($data);
37+
$this->assertNotNull(Comment::find($id));
38+
}
39+
40+
public function testCreateWithInvalidClientId()
41+
{
42+
$this->markTestIncomplete('@todo when it is possible to validate client ids.');
43+
}
44+
1545
public function testRead()
1646
{
1747
$model = $this->createComment();

tests/Integration/TestCase.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ protected function createPostsTable(Schema $schema)
139139
protected function createCommentsTable(Schema $schema)
140140
{
141141
$schema->create('comments', function (Blueprint $table) {
142-
$table->increments('id');
142+
$table->uuid('id');
143143
$table->timestamps();
144144
$table->text('content');
145145
$table->unsignedInteger('post_id');

tests/JsonApi/Comments/Hydrator.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace CloudCreativity\LaravelJsonApi\Tests\JsonApi\Comments;
4+
5+
use CloudCreativity\JsonApi\Contracts\Object\ResourceObjectInterface;
6+
use CloudCreativity\LaravelJsonApi\Hydrator\EloquentHydrator;
7+
use CloudCreativity\LaravelJsonApi\Tests\Models\Comment;
8+
use Illuminate\Support\Facades\Auth;
9+
10+
class Hydrator extends EloquentHydrator
11+
{
12+
13+
/**
14+
* @var bool
15+
*/
16+
protected $clientId = true;
17+
18+
/**
19+
* @var array
20+
*/
21+
protected $attributes = [
22+
'content',
23+
];
24+
25+
/**
26+
* @var array
27+
*/
28+
protected $relationships = [
29+
'post',
30+
];
31+
32+
/**
33+
* @param ResourceObjectInterface $resource
34+
* @param Comment $record
35+
*/
36+
protected function hydrating(ResourceObjectInterface $resource, $record)
37+
{
38+
if (!$record->exists) {
39+
$record->user()->associate(Auth::user());
40+
}
41+
}
42+
}

tests/JsonApi/Comments/Validators.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace CloudCreativity\LaravelJsonApi\Tests\JsonApi\Comments;
4+
5+
use CloudCreativity\JsonApi\Contracts\Validators\RelationshipsValidatorInterface;
6+
use CloudCreativity\LaravelJsonApi\Validators\AbstractValidatorProvider;
7+
8+
class Validators extends AbstractValidatorProvider
9+
{
10+
11+
/**
12+
* @var string
13+
*/
14+
protected $resourceType = 'comments';
15+
16+
/**
17+
* @var array
18+
*/
19+
protected $queryRules = [
20 10000 +
'page.number' => 'integer|min:1',
21+
'page.size' => 'integer|between:1,50',
22+
];
23+
24+
/**
25+
* @var array
26+
*/
27+
protected $allowedSortParameters = [
28+
'created-at',
29+
'updated-at',
30+
];
31+
32+
/**
33+
* @var array
34+
*/
35+
protected $allowedFilteringParameters = [
36+
'id',
37+
];
38+
39+
/**
40+
* @inheritdoc
41+
*/
42+
protected function attributeRules($record = null)
43+
{
44+
$required = is_null($record) ? 'required' : 'filled';
45+
46+
return [
47+
'content' => "$required|string|min:1",
48+
];
49+
}
50+
51+
/**
52+
* @inheritdoc
53+
*/
54+
protected function relationshipRules(RelationshipsValidatorInterface $relationships, $record = null)
55+
{
56+
$relationships->hasOne('post', 'posts', is_null($record), false);
57+
}
58+
59+
}

tests/Models/Comment.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@
99
class Comment extends Model
1010
{
1111

12+
/**
13+
* For test purposes, our Comment model has client supplied ids.
14+
*
15+
* @var bool
16+
*/
17+
public $incrementing = false;
18+
1219
/**
1320
* @var array
1421
*/

tests/factories/ModelFactory.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
/** Comment */
1111
$factory->define(Models\Comment::class, function (Faker $faker) {
1212
return [
13+
'id' => $faker->unique()->uuid,
1314
'content' => $faker->paragraph,
1415
'post_id' => function () {
1516
return factory(Models\Post::class)->create()->getKey();

0 commit comments

Comments
 (0)
0