1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Anavel\Crud\Http\Controllers; |
4
|
|
|
|
5
|
|
|
use ANavallaSuiza\Laravel\Database\Contracts\Manager\ModelManager; |
6
|
|
|
use ANavallaSuiza\Laravel\Database\Repository\Eloquent\Repository; |
7
|
|
|
use Anavel\Crud\Contracts\Abstractor\Model; |
8
|
|
|
use Anavel\Crud\Contracts\Abstractor\ModelFactory as ModelAbstractorFactory; |
9
|
|
|
use Anavel\Crud\Contracts\Controllers\CustomController; |
10
|
|
|
use Anavel\Crud\Contracts\Form\Generator as FormGenerator; |
11
|
|
|
use Anavel\Crud\Repository\Criteria\OrderByCriteria; |
12
|
|
|
use Anavel\Crud\Repository\Criteria\SearchCriteria; |
13
|
|
|
use Anavel\Crud\Repository\Criteria\WithCriteria; |
14
|
|
|
use Anavel\Foundation\Http\Controllers\Controller; |
15
|
|
|
use Anavel\Crud\Services\Export\Csv; |
16
|
|
|
use App; |
17
|
|
|
use Illuminate\Http\Request; |
18
|
|
|
|
19
|
|
|
class ModelController extends Controller |
20
|
|
|
{ |
21
|
|
|
protected $modelFactory; |
22
|
|
|
protected $modelManager; |
23
|
|
|
protected $formGenerator; |
24
|
|
|
|
25
|
|
|
public function __construct(ModelAbstractorFactory $modelFactory, ModelManager $modelManager, FormGenerator $formGenerator) |
26
|
|
|
{ |
27
|
|
|
$this->modelFactory = $modelFactory; |
28
|
|
|
$this->modelManager = $modelManager; |
29
|
|
|
$this->formGenerator = $formGenerator; |
30
|
|
|
} |
31
|
|
|
|
32
|
|
|
private function authorizeMethod(Model $modelAbstractor, $methodName) |
33
|
|
|
{ |
34
|
|
|
$config = $modelAbstractor->getConfig(); |
35
|
|
|
|
36
|
|
|
if (array_key_exists('authorize', $config) && $config['authorize'] === true) { |
37
|
|
|
$this->authorize($methodName, $modelAbstractor->getInstance()); |
38
|
|
|
} |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @param Model $modelAbstractor |
43
|
|
|
* |
44
|
|
|
* @return null|CustomController |
45
|
|
|
*/ |
46
|
|
|
private function customController(Model $modelAbstractor) |
47
|
|
|
{ |
48
|
|
|
if ($this instanceof CustomController) { //Avoid infinite recursion |
49
|
|
|
return; |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
$config = $modelAbstractor->getConfig(); |
53
|
|
|
|
54
|
|
|
if (!array_key_exists('controller', $config) || empty($config['controller'])) { |
55
|
|
|
return; |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
/** @var CustomController $controller */ |
59
|
|
|
$controller = App::make($config['controller']); |
60
|
|
|
$controller->setAbstractor($modelAbstractor); |
61
|
|
|
|
62
|
|
|
return $controller; |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Prepare contents to be used |
67
|
|
|
* |
68
|
|
|
* @param Request $request |
69
|
|
|
* @param Model $modelAbstractor |
70
|
|
|
* @param Repository $repository |
71
|
|
|
* |
72
|
|
|
* @return void |
73
|
|
|
*/ |
74
|
|
|
public function getIndexRequirements(Request $request, Model $modelAbstractor, Repository $repository) |
75
|
|
|
{ |
76
|
|
|
foreach ($modelAbstractor->getListFields()['main'] as $field) { |
77
|
|
|
if (strpos($field->getName(), '.')) { |
78
|
|
|
$repository->pushCriteria(new WithCriteria(preg_replace('/\.[^\.]+$/', '', $field->getName()))); |
79
|
|
|
} |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
if ($search = $request->input('search')) { |
83
|
|
|
$searchByColumns = []; |
84
|
|
|
|
85
|
|
|
foreach ($modelAbstractor->getListFields()['main'] as $field) { |
86
|
|
|
$searchByColumns[] = $field->getName(); |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
$repository->pushCriteria(new SearchCriteria($searchByColumns, $search)); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
$sort = $request->input('sort') ?: 'id'; |
93
|
|
|
$direction = $request->input('direction') ?: 'desc'; |
94
|
|
|
|
95
|
|
|
$repository->pushCriteria(new OrderByCriteria($sort, ($direction === 'desc') ? true : false)); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* Display a listing of the resource. |
100
|
|
|
* |
101
|
|
|
* @param Request $request |
102
|
|
|
* @param string $model |
103
|
|
|
* |
104
|
|
|
* @return Response |
105
|
|
|
*/ |
106
|
|
|
public function index(Request $request, $model) |
107
|
|
|
{ |
108
|
|
|
$modelAbstractor = $this->modelFactory->getBySlug($model); |
109
|
|
|
|
110
|
|
|
$this->authorizeMethod($modelAbstractor, 'adminIndex'); |
111
|
|
|
|
112
|
|
|
if ($customController = $this->customController($modelAbstractor)) { |
113
|
|
|
return $customController->index($request, $model); |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
$repository = $this->modelManager->getRepository($modelAbstractor->getModel()); |
117
|
|
|
|
118
|
|
|
$this->getIndexRequirements($request, $modelAbstractor, $repository); |
119
|
|
|
|
120
|
|
|
return view('anavel-crud::pages.index', [ |
|
|
|
|
121
|
|
|
'abstractor' => $modelAbstractor, |
122
|
|
|
'items' => $repository->paginate(config('anavel-crud.list_max_results')), |
123
|
|
|
]); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Display a listing of the resource. |
128
|
|
|
* |
129
|
|
|
* @param Request $request |
130
|
|
|
* @param string $model |
131
|
|
|
* |
132
|
|
|
* @return Response |
133
|
|
|
*/ |
134
|
|
|
public function exportCsv(Request $request, $model) |
135
|
|
|
{ |
136
|
|
|
$modelAbstractor = $this->modelFactory->getBySlug($model); |
137
|
|
|
|
138
|
|
|
$this->authorizeMethod($modelAbstractor, 'exportCsv'); |
139
|
|
|
|
140
|
|
|
if ($customController = $this->customController($modelAbstractor)) { |
141
|
|
|
return $customController->exportCsv($request, $model); |
|
|
|
|
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
$repository = $this->modelManager->getRepository($modelAbstractor->getModel()); |
145
|
|
|
|
146
|
|
|
$this->getIndexRequirements($request, $modelAbstractor, $repository); |
147
|
|
|
|
148
|
|
|
$csv = (string)(new Csv)->fromArray($repository->all()->toArray()); |
149
|
|
|
|
150
|
|
|
return response()->make($csv, 200, [ |
|
|
|
|
151
|
|
|
'Content-Encoding' => 'UTF-8', |
152
|
|
|
'Content-Type' => 'application/octet-stream', |
153
|
|
|
'Content-disposition' => 'attachment; filename='.$model.'.csv', |
154
|
|
|
]); |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* Show the form for creating a new resource. |
159
|
|
|
* |
160
|
|
|
* @param string $model |
161
|
|
|
* |
162
|
|
|
* @return Response |
163
|
|
|
*/ |
164
|
|
|
public function create($model) |
165
|
|
|
{ |
166
|
|
|
$modelAbstractor = $this->modelFactory->getBySlug($model); |
167
|
|
|
|
168
|
|
|
$this->authorizeMethod($modelAbstractor, 'adminCreate'); |
169
|
|
|
|
170
|
|
|
if ($customController = $this->customController($modelAbstractor)) { |
171
|
|
|
return $customController->create($model); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
$form = $modelAbstractor->getForm(route('anavel-crud.model.store', $modelAbstractor->getSlug())); |
175
|
|
|
|
176
|
|
|
return view('anavel-crud::pages.create', [ |
|
|
|
|
177
|
|
|
'abstractor' => $modelAbstractor, |
178
|
|
|
'form' => $form, |
179
|
|
|
'relations' => $modelAbstractor->getRelations(), |
180
|
|
|
]); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* Store a newly created resource in storage. |
185
|
|
|
* |
186
|
|
|
* @param Request $request |
187
|
|
|
* @param string $model |
188
|
|
|
* |
189
|
|
|
* @return Response |
190
|
|
|
*/ |
191
|
|
|
public function store(Request $request, $model) |
192
|
|
|
{ |
193
|
|
|
$modelAbstractor = $this->modelFactory->getBySlug($model); |
194
|
|
|
|
195
|
|
|
$this->authorizeMethod($modelAbstractor, 'adminCreate'); |
196
|
|
|
|
197
|
|
|
if ($customController = $this->customController($modelAbstractor)) { |
198
|
|
|
return $customController->store($request, $model); |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
// Sets the validation rules |
202
|
|
|
$modelAbstractor->getForm(route('anavel-crud.model.store', $modelAbstractor->getSlug())); |
203
|
|
|
|
204
|
|
|
$this->validate($request, $modelAbstractor->getValidationRules()); |
205
|
|
|
|
206
|
|
|
$modelAbstractor->persist($request); |
207
|
|
|
|
208
|
|
|
session()->flash('anavel-alert', [ |
209
|
|
|
'type' => 'success', |
210
|
|
|
'icon' => 'fa-check', |
211
|
|
|
'title' => trans('anavel-crud::messages.alert_success_model_store_title'), |
212
|
|
|
'text' => trans('anavel-crud::messages.alert_success_model_store_text'), |
213
|
|
|
]); |
214
|
|
|
|
215
|
|
|
return redirect()->route('anavel-crud.model.index', $model); |
|
|
|
|
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* Display the specified resource. |
220
|
|
|
* |
221
|
|
|
* @param string $model |
222
|
|
|
* @param int $id |
223
|
|
|
* |
224
|
|
|
* @return Response |
225
|
|
|
*/ |
226
|
|
|
public function show($model, $id) |
227
|
|
|
{ |
228
|
|
|
$modelAbstractor = $this->modelFactory->getBySlug($model); |
229
|
|
|
|
230
|
|
|
$this->authorizeMethod($modelAbstractor, 'adminShow'); |
231
|
|
|
|
232
|
|
|
if ($customController = $this->customController($modelAbstractor)) { |
233
|
|
|
return $customController->show($model, $id); |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
$repository = $this->modelManager->getRepository($modelAbstractor->getModel()); |
237
|
|
|
$item = $repository->findByOrFail($repository->getModel()->getKeyName(), $id); |
238
|
|
|
|
239
|
|
|
return view('anavel-crud::pages.show', [ |
|
|
|
|
240
|
|
|
'abstractor' => $modelAbstractor, |
241
|
|
|
'item' => $item, |
242
|
|
|
]); |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* Show the form for editing the specified resource. |
247
|
|
|
* |
248
|
|
|
* @param string $model |
249
|
|
|
* @param int $id |
250
|
|
|
* |
251
|
|
|
* @return Response |
252
|
|
|
*/ |
253
|
|
|
public function edit($model, $id) |
254
|
|
|
{ |
255
|
|
|
/** @var Model $modelAbstractor */ |
256
|
|
|
$modelAbstractor = $this->modelFactory->getBySlug($model, $id); |
257
|
|
|
|
258
|
|
|
$this->authorizeMethod($modelAbstractor, 'adminUpdate'); |
259
|
|
|
|
260
|
|
|
if ($customController = $this->customController($modelAbstractor)) { |
261
|
|
|
return $customController->edit($model, $id); |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
$form = $modelAbstractor->getForm(route('anavel-crud.model.update', [$modelAbstractor->getSlug(), $id])); |
265
|
|
|
$repository = $this->modelManager->getRepository($modelAbstractor->getModel()); |
266
|
|
|
$item = $repository->findByOrFail($repository->getModel()->getKeyName(), $id); |
267
|
|
|
|
268
|
|
|
return view('anavel-crud::pages.edit', [ |
|
|
|
|
269
|
|
|
'abstractor' => $modelAbstractor, |
270
|
|
|
'form' => $form, |
271
|
|
|
'item' => $item, |
272
|
|
|
'relations' => $modelAbstractor->getRelations(), |
273
|
|
|
]); |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
/** |
277
|
|
|
* Update the specified resource in storage. |
278
|
|
|
* |
279
|
|
|
* @param Request $request |
280
|
|
|
* @param string $model |
281
|
|
|
* @param int $id |
282
|
|
|
* |
283
|
|
|
* @return Response |
284
|
|
|
*/ |
285
|
|
|
public function update(Request $request, $model, $id) |
286
|
|
|
{ |
287
|
|
|
$modelAbstractor = $this->modelFactory->getBySlug($model, $id); |
288
|
|
|
|
289
|
|
|
$this->authorizeMethod($modelAbstractor, 'adminUpdate'); |
290
|
|
|
|
291
|
|
|
if ($customController = $this->customController($modelAbstractor)) { |
292
|
|
|
return $customController->update($request, $model, $id); |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
// Sets the validation rules |
296
|
|
|
$modelAbstractor->getForm(route('anavel-crud.model.update', [$modelAbstractor->getSlug(), $id])); |
297
|
|
|
|
298
|
|
|
$this->validate($request, $modelAbstractor->getValidationRules()); |
299
|
|
|
|
300
|
|
|
$modelAbstractor->persist($request); |
301
|
|
|
|
302
|
|
|
session()->flash('anavel-alert', [ |
303
|
|
|
'type' => 'success', |
304
|
|
|
'icon' => 'fa-check', |
305
|
|
|
'title' => trans('anavel-crud::messages.alert_success_model_update_title'), |
306
|
|
|
'text' => trans('anavel-crud::messages.alert_success_model_update_text'), |
307
|
|
|
]); |
308
|
|
|
|
309
|
|
|
return redirect()->route('anavel-crud.model.edit', [$model, $id]); |
|
|
|
|
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
/** |
313
|
|
|
* Remove the specified resource from storage. |
314
|
|
|
* |
315
|
|
|
* @param Request $request |
316
|
|
|
* @param string $model |
317
|
|
|
* @param int $id |
318
|
|
|
* |
319
|
|
|
* @return Response |
320
|
|
|
*/ |
321
|
|
|
public function destroy(Request $request, $model, $id) |
322
|
|
|
{ |
323
|
|
|
$modelAbstractor = $this->modelFactory->getBySlug($model); |
324
|
|
|
|
325
|
|
|
$this->authorizeMethod($modelAbstractor, 'adminDestroy'); |
326
|
|
|
|
327
|
|
|
if ($customController = $this->customController($modelAbstractor)) { |
328
|
|
|
return $customController->destroy($request, $model, $id); |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
$repository = $this->modelManager->getRepository($modelAbstractor->getModel()); |
332
|
|
|
$item = $repository->findByOrFail($repository->getModel()->getKeyName(), $id); |
333
|
|
|
|
334
|
|
|
$item->delete(); |
335
|
|
|
|
336
|
|
|
session()->flash('anavel-alert', [ |
337
|
|
|
'type' => 'success', |
338
|
|
|
'icon' => 'fa-check', |
339
|
|
|
'title' => trans('anavel-crud::messages.alert_success_model_destroy_title'), |
340
|
|
|
'text' => trans('anavel-crud::messages.alert_success_model_destroy_text'), |
341
|
|
|
]); |
342
|
|
|
|
343
|
|
|
return redirect()->route('anavel-crud.model.index', $model); |
|
|
|
|
344
|
|
|
} |
345
|
|
|
} |
346
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.