Skip to content

Commit 7c7ef0e

Browse files
committed
[Feature-WIP] Rewiring to use controller middleware
For Laravel 5.3, it is necessary to use controller middleware to run the validation of the HTTP request once for a specific resource type. This commit refactors the architecture so that: 1. JSON API suppprt is initiated and as HTTP content is parsed for conformance to the spec. This happens in route middleware and has no knowledge of what specific resource type is the subject of the request. This process does content negotiation, parses encoding parameters and parses document content checking it conforms to the spec. 2. Other application middleware is now executed, knowing that any exceptions thrown will be cast to JSON API errors. 3. The JSON API request is finalised with knowledge of what resource type is expected. A JSON API request object is built from all finalised parameters, and then this is validated according to business logic. This is all done by a new piece of middleware - `json-api-request` - that is registered as controller middleware as that is the only point at which the specific resource type is known, plus therefore the business rules for validating request parameters and content. Refer to issue #13
1 parent 989c743 commit 7c7ef0e

21 files changed

+1113
-970
lines changed

src/Contracts/Http/Requests/RequestHandlerInterface.php

Lines changed: 12 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -18,64 +18,30 @@
1818

1919
namespace CloudCreativity\LaravelJsonApi\Contracts\Http\Requests;
2020

21-
use CloudCreativity\JsonApi\Contracts\Object\DocumentInterface;
22-
use CloudCreativity\LaravelJsonApi\Exceptions\RequestException;
23-
use Illuminate\Contracts\Validation\ValidatesWhenResolved;
24-
use Illuminate\Http\Request;
25-
use Neomerx\JsonApi\Contracts\Encoder\Parameters\EncodingParametersInterface;
21+
use CloudCreativity\JsonApi\Contracts\Http\RequestInterpreterInterface;
22+
use CloudCreativity\LaravelJsonApi\Http\Requests\JsonApiRequest;
23+
use Neomerx\JsonApi\Exceptions\JsonApiException;
2624

2725
/**
2826
* Interface RequestHandlerInterface
2927
* @package CloudCreativity\LaravelJsonApi
3028
*/
31-
interface RequestHandlerInterface extends ValidatesWhenResolved
29+
interface RequestHandlerInterface
3230
{
3331

3432
/**
35-
* The resource type that this request handles.
36-
*
37-
* @return string
38-
*/
39-
public function getResourceType();
40-
41-
/**
42-
* Get the record that the request relates to.
43-
*
44-
* E.g. if the request is `GET /posts/1`, then the record is the object that the
45-
* store resolves as being `post` with id 1.
46-
*
47-
* @return object
48-
* @throws RequestException
49-
* if the request does not related to a specific record.
50-
*/
51-
public function getRecord();
52-
53-
/**
54-
* Get the request body content as a JSON API document.
55-
*
56-
* @return DocumentInterface
57-
*/
58-
public function getDocument();
59-
60-
/**
61-
* Get the encoding parameters that the client sent.
62-
*
63-
* @return EncodingParametersInterface
33+
* @param RequestInterpreterInterface $interpreter
34+
* @param JsonApiRequest $request
35+
* @return void
36+
* @throws JsonApiException
6437
*/
65-
public function getEncodingParameters();
38+
public function handle(RequestInterpreterInterface $interpreter, JsonApiRequest $request);
6639

6740
/**
68-
* Get the underlying HTTP request.
41+
* Get the resource type that the handler validates
6942
*
70-
* @return Request
71-
*/
72-
public function getHttpRequest();
73-
74-
/**
75-
* Did validation complete successfully?
76-
*
77-
* @return bool
43+
* @return string
7844
*/
79-
public function isValid();
45+
public function getResourceType();
8046

8147
}

src/Http/Controllers/EloquentController.php

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use CloudCreativity\JsonApi\Contracts\Object\ResourceInterface;
2424
use CloudCreativity\LaravelJsonApi\Contracts\Http\Requests\RequestHandlerInterface;
2525
use CloudCreativity\LaravelJsonApi\Contracts\Search\SearchInterface;
26+
use CloudCreativity\LaravelJsonApi\Http\Requests\JsonApiRequest;
2627
use CloudCreativity\LaravelJsonApi\Search\SearchAll;
2728
use Exception;
2829
use Illuminate\Contracts\Pagination\Paginator;
@@ -35,7 +36,7 @@
3536
* Class EloquentController
3637
* @package CloudCreativity\LaravelJsonApi
3738
*/
38-
class EloquentController extends JsonApiController
39+
abstract class EloquentController extends JsonApiController
3940
{
4041

4142
/**
@@ -68,40 +69,40 @@ class EloquentController extends JsonApiController
6869
/**
6970
* EloquentController constructor.
7071
* @param Model $model
71-
* @param RequestHandlerInterface $request
7272
* @param HydratorInterface|null $hydrator
7373
* @param SearchInterface|null $search
7474
*/
7575
public function __construct(
7676
Model $model,
77-
RequestHandlerInterface $request,
7877
HydratorInterface $hydrator = null,
7978
SearchInterface $search = null
8079
) {
81-
parent::__construct($request);
80+
parent::__construct();
8281
$this->model = $model;
8382
$this->hydrator = $hydrator;
8483
$this->search = $search ?: new SearchAll();
8584
}
8685

8786
/**
87+
* @param JsonApiRequest $request
8888
* @return Response
8989
*/
90-
public function index()
90+
public function index(JsonApiRequest $request)
9191
{
92-
$result = $this->search();
92+
$result = $this->search($request);
9393

9494
return $this
9595
->reply()
9696
->content($result);
9797
}
9898

9999
/**
100+
* @param JsonApiRequest $request
100101
* @return Response
101102
*/
102-
public function create()
103+
public function create(JsonApiRequest $request)
103104
{
104-
$model = $this->hydrate($this->getResource(), $this->model);
105+
$model = $this->hydrate($request->getDocument()->getResource(), $this->model);
105106
$result = ($model instanceof Response) ? $model : $this->doCommit($model);
106107

107108
if ($result instanceof Response) {
@@ -116,23 +117,23 @@ public function create()
116117
}
117118

118119
/**
119-
* @param $resourceId
120+
* @param JsonApiRequest $request
120121
* @return Response
121122
*/
122-
public function read($resourceId)
123+
public function read(JsonApiRequest $request)
123124
{
124125
return $this
125126
->reply()
126-
->content($this->getRecord());
127+
->content($this->getRecord($request));
127128
}
128129

129130
/**
130-
* @param $resourceId
131+
* @param JsonApiRequest $request
131132
* @return Response
132133
*/
133-
public function update($resourceId)
134+
public function update(JsonApiRequest $request)
134135
{
135-
$model = $this->hydrate($this->getResource(), $this->getRecord());
136+
$model = $this->hydrate($request->getDocument()->getResource(), $this->getRecord($request));
136137
$result = ($model instanceof Response) ? $model : $this->doCommit($model);
137138

138139
if ($result instanceof Response) {
@@ -147,12 +148,12 @@ public function update($resourceId)
147148
}
148149

149150
/**
150-
* @param $resourceId
151+
* @param JsonApiRequest $request
151152
* @return Response
152153
*/
153-
public function delete($resourceId)
154+
public function delete(JsonApiRequest $request)
154155
{
155-
$model = $this->getRecord();
156+
$model = $this->getRecord($request);
156157
$result = $this->doDestroy($model);
157158

158159
if ($result instanceof Response) {
@@ -167,48 +168,42 @@ public function delete($resourceId)
167168
}
168169

169170
/**
170-
* @param $resourceId
171-
* @param $relationshipName
171+
* @param JsonApiRequest $request
172172
* @return Response
173173
*/
174-
public function readRelatedResource($resourceId, $relationshipName)
174+
public function readRelatedResource(JsonApiRequest $request)
175175
{
176-
$model = $this->getRecord();
177-
$key = $this->keyForRelationship($relationshipName);
176+
$model = $this->getRecord($request);
177+
$key = $this->keyForRelationship($request->getRelationshipName());
178178

179179
return $this
180180
->reply()
181181
->content($model->{$key});
182182
}
183183

184184
/**
185-
* @param $resourceId
186-
* @param $relationshipName
185+
* @param JsonApiRequest $request
187186
* @return Response
188187
*/
189-
public function readRelationship($resourceId, $relationshipName)
188+
public function readRelationship(JsonApiRequest $request)
190189
{
191-
$model = $this->getRecord();
192-
$key = $this->keyForRelationship($relationshipName);
190+
$model = $this->getRecord($request);
191+
$key = $this->keyForRelationship($request->getRelationshipName());
193192

194193
return $this
195194
->reply()
196195
->relationship($model->{$key});
197196
}
198197

199198
/**
199+
* @param JsonApiRequest $request
200200
* @return Paginator|Collection|Model|null
201201
*/
202-
protected function search()
202+
protected function search(JsonApiRequest $request)
203203
{
204-
if (!$this->search) {
205-
return $this->model->all();
206-
}
207-
208204
$builder = $this->model->newQuery();
209-
$parameters = $this->getRequestHandler()->getEncodingParameters();
210205

211-
return $this->search->search($builder, $parameters);
206+
return $this->search->search($builder, $request->getParameters());
212207
}
213208

214209
/**
@@ -342,11 +337,12 @@ protected function keyForRelationship($relationshipName)
342337
}
343338

344339
/**
340+
* @param JsonApiRequest $request
345341
* @return Model
346342
*/
347-
protected function getRecord()
343+
protected function getRecord(JsonApiRequest $request)
348344
{
349-
$record = parent::getRecord();
345+
$record = $request->getRecord();
350346

351347
if (!$record instanceof Model) {
352348
throw new RuntimeException(sprintf('%s expects to be used with a %s record.', static::class, Model::class));

0 commit comments

Comments
 (0)