Completed
Push — master ( 08635e...dd4786 )
by Nil
10:03
created

JsonApiController::listAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 12
rs 9.4286
cc 1
eloc 7
nc 1
nop 0
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\Server\Actions\CreateResource;
17
use NilPortugues\Api\JsonApi\Server\Actions\DeleteResource;
18
use NilPortugues\Api\JsonApi\Server\Actions\ListResource;
19
use NilPortugues\Api\JsonApi\Server\Actions\GetResource;
20
use NilPortugues\Api\JsonApi\Server\Actions\PatchResource;
21
use NilPortugues\Api\JsonApi\Server\Actions\PutResource;
22
use NilPortugues\Api\JsonApi\Server\Errors\Error;
23
use NilPortugues\Api\JsonApi\Server\Errors\ErrorBag;
24
use NilPortugues\Laravel5\JsonApi\Eloquent\EloquentHelper;
25
use NilPortugues\Laravel5\JsonApi\JsonApiSerializer;
26
use Symfony\Component\HttpFoundation\Response;
27
28
/**
29
 * Class JsonApiController.
30
 */
31
abstract class JsonApiController extends Controller
32
{
33
    /**
34
     * @var JsonApiSerializer
35
     */
36
    protected $serializer;
37
38
    /**
39
     * @param JsonApiSerializer $serializer
40
     */
41
    public function __construct(JsonApiSerializer $serializer)
42
    {
43
        $this->serializer = $serializer;
44
    }
45
46
    /**
47
     * @return \Symfony\Component\HttpFoundation\Response
48
     */
49
    public function listAction()
50
    {
51
        $resource = new ListResource($this->serializer);
52
53
        $totalAmount = $this->totalAmountResourceCallable();
54
        $results = $this->listResourceCallable();
55
56
        $controllerAction = '\\'.get_class($this).'@listAction';
57
        $uri = action($controllerAction, []);
58
59
        return $this->addHeaders($resource->get($totalAmount, $results, $uri, get_class($this->getDataModel())));
60
    }
61
62
    /**
63
     * Returns the total number of results available for the current resource.
64
     *
65
     * @return callable
66
     */
67 View Code Duplication
    protected function totalAmountResourceCallable()
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...
68
    {
69
        return function () {
70
            $idKey = $this->getDataModel()->getKeyName();
71
72
            return $this->getDataModel()->query()->get([$idKey])->count();
73
        };
74
    }
75
76
    /**
77
     * Returns an Eloquent Model.
78
     *
79
     * @return Model
80
     */
81
    abstract public function getDataModel();
82
83
    /**
84
     * Returns a list of resources based on pagination criteria.
85
     *
86
     * @return callable
87
     */
88
    protected function listResourceCallable()
89
    {
90
        return function () {
91
            return EloquentHelper::paginate($this->serializer, $this->getDataModel()->query())->get();
92
        };
93
    }
94
95
    /**
96
     * @param Response $response
97
     *
98
     * @return \Symfony\Component\HttpFoundation\Response
99
     */
100
    protected function addHeaders(Response $response)
101
    {
102
        return $response;
103
    }
104
105
    /**
106
     * @param Request $request
107
     *
108
     * @return \Symfony\Component\HttpFoundation\Response
109
     */
110 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...
111
    {
112
        $find = $this->findResourceCallable($request);
113
        $resource = new GetResource($this->serializer);
114
115
        return $this->addHeaders($resource->get($request->id, get_class($this->getDataModel()), $find));
116
    }
117
118
    /**
119
     * @param Request $request
120
     *
121
     * @return callable
122
     */
123
    protected function findResourceCallable(Request $request)
124
    {
125 View Code Duplication
        return function () use ($request) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
126
            $idKey = $this->getDataModel()->getKeyName();
127
128
            return $this->getDataModel()->query()->where($idKey, $request->id)->first();
129
        };
130
    }
131
132
    /**
133
     * @param Request $request
134
     *
135
     * @return \Symfony\Component\HttpFoundation\Response
136
     */
137 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...
138
    {
139
        $createResource = $this->createResourceCallable();
140
141
        $resource = new CreateResource($this->serializer);
142
143
        return $this->addHeaders(
144
            $resource->get((array) $request->get('data'), get_class($this->getDataModel()), $createResource)
145
        );
146
    }
147
148
    /**
149
     * Reads the input and creates and saves a new Eloquent Model.
150
     *
151
     * @return callable
152
     */
153
    protected function createResourceCallable()
154
    {
155
        return function (array $data, array $values) {
156
            $model = $this->getDataModel()->newInstance();
157
158
            foreach ($values as $attribute => $value) {
159
                $model->setAttribute($attribute, $value);
160
            }
161
162
            if (!empty($data['id'])) {
163
                $model->setAttribute($model->getKeyName(), $values['id']);
164
            }
165
166
            try {
167
                $model->save();
168
            } catch (\Exception $e) {
169
                $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...
170
                throw $e;
171
            }
172
173
            return $model;
174
        };
175
    }
176
177
    /**
178
     * @param Request $request
179
     *
180
     * @return \Symfony\Component\HttpFoundation\Response
181
     */
182 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...
183
    {
184
        $find = $this->findResourceCallable($request);
185
        $update = $this->updateResourceCallable();
186
187
        $resource = new PatchResource($this->serializer);
188
189
        return $this->addHeaders(
190
            $resource->get(
191
                $request->id,
192
                (array) $request->get('data'),
193
                get_class($this->getDataModel()),
194
                $find,
195
                $update
196
            )
197
        );
198
    }
199
200
    /**
201
     * @return callable
202
     */
203
    protected function updateResourceCallable()
204
    {
205
        return function (Model $model, array $values, ErrorBag $errorBag) {
206
            foreach ($values as $attribute => $value) {
207
                $model->$attribute = $value;
208
            }
209
            try {
210
                $model->update();
211
            } catch (\Exception $e) {
212
                $errorBag[] = new Error('update_failed', 'Could not update resource.');
213
                throw $e;
214
            }
215
        };
216
    }
217
218
    /**
219
     * @param Request $request
220
     *
221
     * @return \Symfony\Component\HttpFoundation\Response
222
     */
223 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...
224
    {
225
        $find = $this->findResourceCallable($request);
226
        $update = $this->updateResourceCallable();
227
228
        $resource = new PutResource($this->serializer);
229
230
        return $this->addHeaders(
231
            $resource->get(
232
                $request->id,
233
                (array) $request->get('data'),
234
                get_class($this->getDataModel()),
235
                $find,
236
                $update
237
            )
238
        );
239
    }
240
241
    /**
242
     * @param Request $request
243
     *
244
     * @return \Symfony\Component\HttpFoundation\Response
245
     */
246 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...
247
    {
248
        $find = $this->findResourceCallable($request);
249
        $resource = new DeleteResource($this->serializer);
250
251
        return $this->addHeaders($resource->get($request->id, get_class($this->getDataModel()), $find));
252
    }
253
}
254