Completed
Push — master ( 6d636a...8bc8ac )
by Nil
05:12
created

JsonApiController::listAction()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 27
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 27
rs 8.8571
cc 2
eloc 18
nc 2
nop 1
1
<?php
2
/**
3
 * Author: Nil Portugués Calderó <[email protected]>
4
 * Date: 12/7/15
5
 * Time: 12:17 AM.
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace NilPortugues\Laravel5\JsonApi\Controller;
12
13
use App\Http\Controllers\Controller;
14
use Illuminate\Database\Eloquent\Model;
15
use Illuminate\Http\Request;
16
use NilPortugues\Api\JsonApi\Http\Factory\RequestFactory;
17
use NilPortugues\Api\JsonApi\Server\Actions\CreateResource;
18
use NilPortugues\Api\JsonApi\Server\Actions\DeleteResource;
19
use NilPortugues\Api\JsonApi\Server\Actions\ListResource;
20
use NilPortugues\Api\JsonApi\Server\Actions\GetResource;
21
use NilPortugues\Api\JsonApi\Server\Actions\PatchResource;
22
use NilPortugues\Api\JsonApi\Server\Actions\PutResource;
23
use NilPortugues\Api\JsonApi\Server\Errors\Error;
24
use NilPortugues\Api\JsonApi\Server\Errors\ErrorBag;
25
use NilPortugues\Laravel5\JsonApi\Eloquent\EloquentHelper;
26
use NilPortugues\Laravel5\JsonApi\JsonApiSerializer;
27
use Symfony\Component\HttpFoundation\Response;
28
29
/**
30
 * Class JsonApiController.
31
 */
32
abstract class JsonApiController extends Controller
33
{
34
    /**
35
     * @var JsonApiSerializer
36
     */
37
    protected $serializer;
38
39
    /**
40
     * @param JsonApiSerializer $serializer
41
     */
42
    public function __construct(JsonApiSerializer $serializer)
43
    {
44
        $this->serializer = $serializer;
45
    }
46
47
    /**
48
     * @param int $pageSize
49
     *
50
     * @return \Symfony\Component\HttpFoundation\Response
51
     */
52
    public function listAction($pageSize = 10)
53
    {
54
        $apiRequest = RequestFactory::create();
55
        $page = $apiRequest->getPage();
56
57
        if (!$page->size()) {
58
            $page->setSize($pageSize);
59
        }
60
61
        $resource = new ListResource(
62
            $this->serializer,
63
            $page,
64
            $apiRequest->getFields(),
65
            $apiRequest->getSort(),
66
            $apiRequest->getIncludedRelationships(),
67
            $apiRequest->getFilters()
68
        );
69
70
        $response = $resource->get(
71
            $this->totalAmountResourceCallable(),
72
            $this->listResourceCallable(),
73
            action('\\'.get_class($this).'@listAction', []),
74
            get_class($this->getDataModel())
75
        );
76
77
        return $this->addHeaders($response);
78
    }
79
80
    /**
81
     * Returns the total number of results available for the current resource.
82
     *
83
     * @return callable
84
     * @codeCoverageIgnore
85
     */
86
    protected function totalAmountResourceCallable()
87
    {
88
        return function () {
89
            $idKey = $this->getDataModel()->getKeyName();
90
91
            return $this->getDataModel()->query()->get([$idKey])->count();
92
        };
93
    }
94
95
    /**
96
     * Returns an Eloquent Model.
97
     *
98
     * @return Model
99
     */
100
    abstract public function getDataModel();
101
102
    /**
103
     * Returns a list of resources based on pagination criteria.
104
     *
105
     * @return callable
106
     * @codeCoverageIgnore
107
     */
108
    protected function listResourceCallable()
109
    {
110
        return function () {
111
            return EloquentHelper::paginate($this->serializer, $this->getDataModel()->query())->get();
112
        };
113
    }
114
115
    /**
116
     * @param Response $response
117
     *
118
     * @return \Symfony\Component\HttpFoundation\Response
119
     */
120
    protected function addHeaders(Response $response)
121
    {
122
        return $response;
123
    }
124
125
    /**
126
     * @param Request $request
127
     *
128
     * @return \Symfony\Component\HttpFoundation\Response
129
     */
130 View Code Duplication
    public function getAction(Request $request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
131
    {
132
        $apiRequest = RequestFactory::create();
133
134
        $resource = new GetResource(
135
            $this->serializer,
136
            $apiRequest->getFields(),
137
            $apiRequest->getIncludedRelationships()
138
        );
139
140
        $response = $resource->get(
141
            $request->id,
142
            get_class($this->getDataModel()),
143
            $this->findResourceCallable($request)
144
        );
145
146
        return $this->addHeaders($response);
147
    }
148
149
    /**
150
     * @param Request $request
151
     *
152
     * @return callable
153
     * @codeCoverageIgnore
154
     */
155 View Code Duplication
    protected function findResourceCallable(Request $request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
156
    {
157
        return function () use ($request) {
158
            $idKey = $this->getDataModel()->getKeyName();
159
            $model = $this->getDataModel()->query()->where($idKey, $request->id)->first();
160
161
            return $model;
162
        };
163
    }
164
165
    /**
166
     * @param Request $request
167
     *
168
     * @return \Symfony\Component\HttpFoundation\Response
169
     */
170 View Code Duplication
    public function postAction(Request $request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
171
    {
172
        $resource = new CreateResource($this->serializer);
173
174
        $response = $resource->get(
175
            (array) $request->get('data'),
176
            get_class($this->getDataModel()),
177
            $this->createResourceCallable()
178
        );
179
180
        return $this->addHeaders($response);
181
    }
182
183
    /**
184
     * Reads the input and creates and saves a new Eloquent Model.
185
     *
186
     * @return callable
187
     * @codeCoverageIgnore
188
     */
189
    protected function createResourceCallable()
190
    {
191
        return function (array $data, array $values) {
192
            $model = $this->getDataModel()->newInstance();
193
194
            foreach ($values as $attribute => $value) {
195
                $model->setAttribute($attribute, $value);
196
            }
197
198
            if (!empty($data['id'])) {
199
                $model->setAttribute($model->getKeyName(), $values['id']);
200
            }
201
202
            try {
203
                $model->save();
204
            } catch (\Exception $e) {
205
                $errorBag[] = new Error('creation_error', 'Resource could not be created');
0 ignored issues
show
Coding Style Comprehensibility introduced by
$errorBag was never initialized. Although not strictly required by PHP, it is generally a good practice to add $errorBag = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
206
                throw $e;
207
            }
208
209
            return $model;
210
        };
211
    }
212
213
    /**
214
     * @param Request $request
215
     *
216
     * @return \Symfony\Component\HttpFoundation\Response
217
     */
218 View Code Duplication
    public function patchAction(Request $request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
219
    {
220
        $resource = new PatchResource($this->serializer);
221
222
        $response = $resource->get(
223
            $request->id,
224
            (array) $request->get('data'),
225
            get_class($this->getDataModel()),
226
            $this->findResourceCallable($request),
227
            $this->updateResourceCallable()
228
        );
229
230
        return $this->addHeaders($response);
231
    }
232
233
    /**
234
     * @return callable
235
     * @codeCoverageIgnore
236
     */
237
    protected function updateResourceCallable()
238
    {
239
        return function (Model $model, array $values, ErrorBag $errorBag) {
240
            foreach ($values as $attribute => $value) {
241
                $model->$attribute = $value;
242
            }
243
            try {
244
                $model->update();
245
            } catch (\Exception $e) {
246
                $errorBag[] = new Error('update_failed', 'Could not update resource.');
247
                throw $e;
248
            }
249
        };
250
    }
251
252
    /**
253
     * @param Request $request
254
     *
255
     * @return \Symfony\Component\HttpFoundation\Response
256
     */
257 View Code Duplication
    public function putAction(Request $request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
    {
259
        $resource = new PutResource($this->serializer);
260
261
        $response = $resource->get(
262
            $request->id,
263
            (array) $request->get('data'),
264
            get_class($this->getDataModel()),
265
            $this->findResourceCallable($request),
266
            $this->updateResourceCallable()
267
        );
268
269
        return $this->addHeaders($response);
270
    }
271
272
    /**
273
     * @param Request $request
274
     *
275
     * @return \Symfony\Component\HttpFoundation\Response
276
     */
277 View Code Duplication
    public function deleteAction(Request $request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
278
    {
279
        $resource = new DeleteResource($this->serializer);
280
281
        $response = $resource->get(
282
            $request->id,
283
            get_class($this->getDataModel()),
284
            $this->findResourceCallable($request),
285
            $this->deleteResourceCallable($request)
286
        );
287
288
        return $this->addHeaders($response);
289
    }
290
291
    /**
292
     * @param Request $request
293
     *
294
     * @return callable
295
     * @codeCoverageIgnore
296
     */
297 View Code Duplication
    protected function deleteResourceCallable(Request $request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
298
    {
299
        return function () use ($request) {
300
            $idKey = $this->getDataModel()->getKeyName();
301
            $model = $this->getDataModel()->query()->where($idKey, $request->id)->first();
302
303
            return $model->delete();
304
        };
305
    }
306
}
307