1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Encore\Admin; |
4
|
|
|
|
5
|
|
|
use Encore\Admin\Show\Divider; |
6
|
|
|
use Encore\Admin\Show\Field; |
7
|
|
|
use Encore\Admin\Show\Panel; |
8
|
|
|
use Encore\Admin\Show\Relation; |
9
|
|
|
use Illuminate\Contracts\Support\Renderable; |
10
|
|
|
use Illuminate\Database\Eloquent\Model; |
11
|
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
12
|
|
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany; |
13
|
|
|
use Illuminate\Database\Eloquent\Relations\HasMany; |
14
|
|
|
use Illuminate\Database\Eloquent\Relations\HasManyThrough; |
15
|
|
|
use Illuminate\Database\Eloquent\Relations\HasOne; |
16
|
|
|
use Illuminate\Database\Eloquent\Relations\MorphMany; |
17
|
|
|
use Illuminate\Database\Eloquent\Relations\MorphOne; |
18
|
|
|
use Illuminate\Database\Eloquent\Relations\Relation as EloquentRelation; |
19
|
|
|
use Illuminate\Support\Arr; |
20
|
|
|
use Illuminate\Support\Collection; |
21
|
|
|
|
22
|
|
|
class Show implements Renderable |
23
|
|
|
{ |
24
|
|
|
/** |
25
|
|
|
* The Eloquent model to show. |
26
|
|
|
* |
27
|
|
|
* @var Model |
28
|
|
|
*/ |
29
|
|
|
protected $model; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Show panel builder. |
33
|
|
|
* |
34
|
|
|
* @var callable |
35
|
|
|
*/ |
36
|
|
|
protected $builder; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Resource path for this show page. |
40
|
|
|
* |
41
|
|
|
* @var string |
42
|
|
|
*/ |
43
|
|
|
protected $resource; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* Fields to be show. |
47
|
|
|
* |
48
|
|
|
* @var Collection |
49
|
|
|
*/ |
50
|
|
|
protected $fields; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Relations to be show. |
54
|
|
|
* |
55
|
|
|
* @var Collection |
56
|
|
|
*/ |
57
|
|
|
protected $relations; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* @var Panel |
61
|
|
|
*/ |
62
|
|
|
protected $panel; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* @var Closure |
66
|
|
|
*/ |
67
|
|
|
protected static $initCallback; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* Show constructor. |
71
|
|
|
* |
72
|
|
|
* @param Model $model |
73
|
|
|
* @param mixed $builder |
74
|
|
|
*/ |
75
|
|
|
public function __construct($model, $builder = null) |
76
|
|
|
{ |
77
|
|
|
$this->model = $model; |
78
|
|
|
$this->builder = $builder; |
79
|
|
|
|
80
|
|
|
$this->initPanel(); |
81
|
|
|
$this->initContents(); |
82
|
|
|
|
83
|
|
|
if (static::$initCallback instanceof Closure) { |
|
|
|
|
84
|
|
|
call_user_func(static::$initCallback, $this); |
85
|
|
|
} |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* Initialize with user pre-defined default disables, etc. |
90
|
|
|
* |
91
|
|
|
* @param Closure $callback |
92
|
|
|
*/ |
93
|
|
|
public static function init(Closure $callback = null) |
94
|
|
|
{ |
95
|
|
|
static::$initCallback = $callback; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* Initialize the contents to show. |
100
|
|
|
*/ |
101
|
|
|
protected function initContents() |
102
|
|
|
{ |
103
|
|
|
$this->fields = new Collection(); |
104
|
|
|
$this->relations = new Collection(); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Initialize panel. |
109
|
|
|
*/ |
110
|
|
|
protected function initPanel() |
111
|
|
|
{ |
112
|
|
|
$this->panel = new Panel($this); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* Get panel instance. |
117
|
|
|
* |
118
|
|
|
* @return Panel |
119
|
|
|
*/ |
120
|
|
|
public function panel() |
121
|
|
|
{ |
122
|
|
|
return $this->panel; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Add a model field to show. |
127
|
|
|
* |
128
|
|
|
* @param string $name |
129
|
|
|
* @param string $label |
130
|
|
|
* |
131
|
|
|
* @return Field |
132
|
|
|
*/ |
133
|
|
|
public function field($name, $label = '') |
134
|
|
|
{ |
135
|
|
|
return $this->addField($name, $label); |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Add multiple fields. |
140
|
|
|
* |
141
|
|
|
* @param array $fields |
142
|
|
|
* |
143
|
|
|
* @return $this |
144
|
|
|
*/ |
145
|
|
|
public function fields(array $fields = []) |
146
|
|
|
{ |
147
|
|
|
if (!Arr::isAssoc($fields)) { |
148
|
|
|
$fields = array_combine($fields, $fields); |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
foreach ($fields as $field => $label) { |
152
|
|
|
$this->field($field, $label); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
return $this; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Show all fields. |
160
|
|
|
* |
161
|
|
|
* @return Show |
162
|
|
|
*/ |
163
|
|
|
public function all() |
164
|
|
|
{ |
165
|
|
|
$fields = array_keys($this->model->getAttributes()); |
166
|
|
|
|
167
|
|
|
return $this->fields($fields); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* Add a relation to show. |
172
|
|
|
* |
173
|
|
|
* @param string $name |
174
|
|
|
* @param string|\Closure $label |
175
|
|
|
* @param null|\Closure $builder |
176
|
|
|
* |
177
|
|
|
* @return Relation |
178
|
|
|
*/ |
179
|
|
|
public function relation($name, $label, $builder = null) |
180
|
|
|
{ |
181
|
|
|
if (is_null($builder)) { |
182
|
|
|
$builder = $label; |
183
|
|
|
$label = ''; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
return $this->addRelation($name, $builder, $label); |
|
|
|
|
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* Add a model field to show. |
191
|
|
|
* |
192
|
|
|
* @param string $name |
193
|
|
|
* @param string $label |
194
|
|
|
* |
195
|
|
|
* @return Field |
196
|
|
|
*/ |
197
|
|
|
protected function addField($name, $label = '') |
198
|
|
|
{ |
199
|
|
|
$field = new Field($name, $label); |
200
|
|
|
|
201
|
|
|
$field->setParent($this); |
202
|
|
|
|
203
|
|
|
$this->overwriteExistingField($name); |
204
|
|
|
|
205
|
|
|
return tap($field, function ($field) { |
206
|
|
|
$this->fields->push($field); |
207
|
|
|
}); |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
/** |
211
|
|
|
* Add a relation panel to show. |
212
|
|
|
* |
213
|
|
|
* @param string $name |
214
|
|
|
* @param \Closure $builder |
215
|
|
|
* @param string $label |
216
|
|
|
* |
217
|
|
|
* @return Relation |
218
|
|
|
*/ |
219
|
|
|
protected function addRelation($name, $builder, $label = '') |
220
|
|
|
{ |
221
|
|
|
$relation = new Relation($name, $builder, $label); |
222
|
|
|
|
223
|
|
|
$relation->setParent($this); |
224
|
|
|
|
225
|
|
|
$this->overwriteExistingRelation($name); |
226
|
|
|
|
227
|
|
|
return tap($relation, function ($relation) { |
228
|
|
|
$this->relations->push($relation); |
229
|
|
|
}); |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
/** |
233
|
|
|
* Overwrite existing field. |
234
|
|
|
* |
235
|
|
|
* @param string $name |
236
|
|
|
*/ |
237
|
|
|
protected function overwriteExistingField($name) |
238
|
|
|
{ |
239
|
|
|
if ($this->fields->isEmpty()) { |
240
|
|
|
return; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
$this->fields = $this->fields->filter( |
244
|
|
|
function (Field $field) use ($name) { |
245
|
|
|
return $field->getName() != $name; |
246
|
|
|
} |
247
|
|
|
); |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* Overwrite existing relation. |
252
|
|
|
* |
253
|
|
|
* @param string $name |
254
|
|
|
*/ |
255
|
|
|
protected function overwriteExistingRelation($name) |
256
|
|
|
{ |
257
|
|
|
if ($this->relations->isEmpty()) { |
258
|
|
|
return; |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
$this->relations = $this->relations->filter( |
262
|
|
|
function (Relation $relation) use ($name) { |
263
|
|
|
return $relation->getName() != $name; |
264
|
|
|
} |
265
|
|
|
); |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* Show a divider. |
270
|
|
|
*/ |
271
|
|
|
public function divider() |
272
|
|
|
{ |
273
|
|
|
$this->fields->push(new Divider()); |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
/** |
277
|
|
|
* Set resource path. |
278
|
|
|
* |
279
|
|
|
* @param string $resource |
280
|
|
|
* |
281
|
|
|
* @return $this |
282
|
|
|
*/ |
283
|
|
|
public function setResource($resource) |
284
|
|
|
{ |
285
|
|
|
$this->resource = $resource; |
286
|
|
|
|
287
|
|
|
return $this; |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
/** |
291
|
|
|
* Get resource path. |
292
|
|
|
* |
293
|
|
|
* @return string |
294
|
|
|
*/ |
295
|
|
|
public function getResourcePath() |
296
|
|
|
{ |
297
|
|
|
if (empty($this->resource)) { |
298
|
|
|
$path = request()->path(); |
299
|
|
|
|
300
|
|
|
$segments = explode('/', $path); |
301
|
|
|
array_pop($segments); |
302
|
|
|
|
303
|
|
|
$this->resource = implode('/', $segments); |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
return $this->resource; |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* Set the model instance. |
311
|
|
|
* |
312
|
|
|
* @param Model $model |
313
|
|
|
* |
314
|
|
|
* @return $this |
315
|
|
|
*/ |
316
|
|
|
public function setModel($model) |
317
|
|
|
{ |
318
|
|
|
$this->model = $model; |
319
|
|
|
|
320
|
|
|
return $this; |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
/** |
324
|
|
|
* Get the model instance being queried. |
325
|
|
|
* |
326
|
|
|
* @return Model |
327
|
|
|
*/ |
328
|
|
|
public function getModel() |
329
|
|
|
{ |
330
|
|
|
return $this->model; |
331
|
|
|
} |
332
|
|
|
|
333
|
|
|
/** |
334
|
|
|
* Add field and relation dynamically. |
335
|
|
|
* |
336
|
|
|
* @param string $method |
337
|
|
|
* @param array $arguments |
338
|
|
|
* |
339
|
|
|
* @return bool|mixed |
340
|
|
|
*/ |
341
|
|
|
public function __call($method, $arguments = []) |
342
|
|
|
{ |
343
|
|
|
$label = isset($arguments[0]) ? $arguments[0] : ucfirst($method); |
344
|
|
|
|
345
|
|
|
if ($field = $this->handleGetMutatorField($method, $label)) { |
346
|
|
|
return $field; |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
if ($field = $this->handleRelationField($method, $arguments)) { |
350
|
|
|
return $field; |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
if ($field = $this->handleModelField($method, $label)) { |
354
|
|
|
return $field; |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
return $this->addField($method, $label); |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
/** |
361
|
|
|
* Handle the get mutator field. |
362
|
|
|
* |
363
|
|
|
* @param string $method |
364
|
|
|
* @param string $label |
365
|
|
|
* |
366
|
|
|
* @return bool|Field |
367
|
|
|
*/ |
368
|
|
|
protected function handleGetMutatorField($method, $label) |
369
|
|
|
{ |
370
|
|
|
if (is_null($this->model)) { |
371
|
|
|
return false; |
372
|
|
|
} |
373
|
|
|
|
374
|
|
|
if ($this->model->hasGetMutator($method)) { |
375
|
|
|
return $this->addField($method, $label); |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
return false; |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
/** |
382
|
|
|
* Handle relation field. |
383
|
|
|
* |
384
|
|
|
* @param string $method |
385
|
|
|
* @param array $arguments |
386
|
|
|
* |
387
|
|
|
* @return $this|bool|Relation|Field |
388
|
|
|
*/ |
389
|
|
|
protected function handleRelationField($method, $arguments) |
390
|
|
|
{ |
391
|
|
|
if (!method_exists($this->model, $method)) { |
392
|
|
|
return false; |
393
|
|
|
} |
394
|
|
|
|
395
|
|
|
if (!($relation = $this->model->$method()) instanceof EloquentRelation) { |
396
|
|
|
return false; |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
if ($relation instanceof HasOne |
400
|
|
|
|| $relation instanceof BelongsTo |
401
|
|
|
|| $relation instanceof MorphOne |
402
|
|
|
) { |
403
|
|
|
$this->model->with($method); |
404
|
|
|
|
405
|
|
|
if (count($arguments) == 1 && $arguments[0] instanceof \Closure) { |
406
|
|
|
return $this->addRelation($method, $arguments[0]); |
407
|
|
|
} |
408
|
|
|
|
409
|
|
View Code Duplication |
if (count($arguments) == 2 && $arguments[1] instanceof \Closure) { |
|
|
|
|
410
|
|
|
return $this->addRelation($method, $arguments[1], $arguments[0]); |
411
|
|
|
} |
412
|
|
|
|
413
|
|
|
return $this->addField($method, array_get($arguments, 0))->setRelation(snake_case($method)); |
414
|
|
|
} |
415
|
|
|
|
416
|
|
|
if ($relation instanceof HasMany |
417
|
|
|
|| $relation instanceof MorphMany |
418
|
|
|
|| $relation instanceof BelongsToMany |
419
|
|
|
|| $relation instanceof HasManyThrough |
420
|
|
|
) { |
421
|
|
|
if (empty($arguments) || (count($arguments) == 1 && is_string($arguments[0]))) { |
422
|
|
|
return $this->showRelationAsField($method, $arguments[0] ?? ''); |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
$this->model->with($method); |
426
|
|
|
|
427
|
|
|
if (count($arguments) == 1 && is_callable($arguments[0])) { |
428
|
|
|
return $this->addRelation($method, $arguments[0]); |
|
|
|
|
429
|
|
View Code Duplication |
} elseif (count($arguments) == 2 && is_callable($arguments[1])) { |
|
|
|
|
430
|
|
|
return $this->addRelation($method, $arguments[1], $arguments[0]); |
|
|
|
|
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
throw new \InvalidArgumentException('Invalid eloquent relation'); |
434
|
|
|
} |
435
|
|
|
|
436
|
|
|
return false; |
437
|
|
|
} |
438
|
|
|
|
439
|
|
|
protected function showRelationAsField($relation = '', $label = '') |
440
|
|
|
{ |
441
|
|
|
return $this->addField($relation, $label); |
442
|
|
|
} |
443
|
|
|
|
444
|
|
|
/** |
445
|
|
|
* Handle model field. |
446
|
|
|
* |
447
|
|
|
* @param string $method |
448
|
|
|
* @param string $label |
449
|
|
|
* |
450
|
|
|
* @return bool|Field |
451
|
|
|
*/ |
452
|
|
|
protected function handleModelField($method, $label) |
453
|
|
|
{ |
454
|
|
|
if (in_array($method, $this->model->getAttributes())) { |
455
|
|
|
return $this->addField($method, $label); |
456
|
|
|
} |
457
|
|
|
|
458
|
|
|
return false; |
459
|
|
|
} |
460
|
|
|
|
461
|
|
|
/** |
462
|
|
|
* Render the show panels. |
463
|
|
|
* |
464
|
|
|
* @return string |
465
|
|
|
*/ |
466
|
|
|
public function render() |
467
|
|
|
{ |
468
|
|
|
if (is_callable($this->builder)) { |
469
|
|
|
call_user_func($this->builder, $this); |
470
|
|
|
} |
471
|
|
|
|
472
|
|
|
if ($this->fields->isEmpty()) { |
473
|
|
|
$this->all(); |
474
|
|
|
} |
475
|
|
|
|
476
|
|
|
if (is_array($this->builder)) { |
477
|
|
|
$this->fields($this->builder); |
478
|
|
|
} |
479
|
|
|
|
480
|
|
|
$this->fields->each->setValue($this->model); |
481
|
|
|
$this->relations->each->setModel($this->model); |
482
|
|
|
|
483
|
|
|
$data = [ |
484
|
|
|
'panel' => $this->panel->fill($this->fields), |
485
|
|
|
'relations' => $this->relations, |
486
|
|
|
]; |
487
|
|
|
|
488
|
|
|
return view('admin::show', $data)->render(); |
|
|
|
|
489
|
|
|
} |
490
|
|
|
} |
491
|
|
|
|
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.