1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Sco\Admin\Component; |
4
|
|
|
|
5
|
|
|
use BadMethodCallException; |
6
|
|
|
use Illuminate\Database\Eloquent\Model; |
7
|
|
|
use InvalidArgumentException; |
8
|
|
|
use Illuminate\Foundation\Application; |
9
|
|
|
use Sco\Admin\Component\Concerns\HasAccess; |
10
|
|
|
use Sco\Admin\Component\Concerns\HasEvents; |
11
|
|
|
use Sco\Admin\Component\Concerns\HasNavigation; |
12
|
|
|
use Sco\Admin\Contracts\ComponentInterface; |
13
|
|
|
use Sco\Admin\Contracts\Form\FormInterface; |
14
|
|
|
use Sco\Admin\Contracts\RepositoryInterface; |
15
|
|
|
use Sco\Admin\Contracts\Display\DisplayInterface; |
16
|
|
|
|
17
|
|
|
abstract class Component implements ComponentInterface |
18
|
|
|
{ |
19
|
|
|
use HasAccess, HasEvents, HasNavigation; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @var |
23
|
|
|
*/ |
24
|
|
|
protected $name; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* @var \Illuminate\Foundation\Application |
28
|
|
|
*/ |
29
|
|
|
protected $app; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* The component display name |
33
|
|
|
* |
34
|
|
|
* @var string |
35
|
|
|
*/ |
36
|
|
|
protected $title; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @var mixed|\Sco\Admin\Contracts\RepositoryInterface |
40
|
|
|
*/ |
41
|
|
|
protected $repository; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @var \Illuminate\Database\Eloquent\Model |
45
|
|
|
*/ |
46
|
|
|
protected $model; |
47
|
|
|
|
48
|
|
|
protected static $booted = []; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @var \Illuminate\Contracts\Events\Dispatcher |
52
|
|
|
*/ |
53
|
|
|
protected static $dispatcher; |
54
|
|
|
|
55
|
|
|
abstract public function model(); |
56
|
|
|
|
57
|
|
|
public function __construct(Application $app) |
58
|
|
|
{ |
59
|
|
|
$this->app = $app; |
60
|
|
|
|
61
|
|
|
$this->bootIfNotBooted(); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* {@inheritdoc} |
66
|
|
|
*/ |
67
|
|
|
public function getName() |
68
|
|
|
{ |
69
|
|
|
if (is_null($this->name)) { |
70
|
|
|
$this->setName($this->getDefaultName()); |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
return $this->name; |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* {@inheritdoc} |
78
|
|
|
*/ |
79
|
|
|
public function setName(string $value) |
80
|
|
|
{ |
81
|
|
|
$this->name = $value; |
82
|
|
|
|
83
|
|
|
return $this; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* {@inheritdoc} |
88
|
|
|
*/ |
89
|
|
|
public function getTitle() |
90
|
|
|
{ |
91
|
|
|
return $this->title; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* {@inheritdoc} |
96
|
|
|
*/ |
97
|
|
|
public function setTitle(string $value) |
98
|
|
|
{ |
99
|
|
|
$this->title = $value; |
100
|
|
|
|
101
|
|
|
return $this; |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
protected function getDefaultName() |
105
|
|
|
{ |
106
|
|
|
return $this->getModelClassName(); |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* @return string |
111
|
|
|
*/ |
112
|
|
|
protected function getModelClassName() |
113
|
|
|
{ |
114
|
|
|
return snake_case( // 蛇形命名 |
115
|
|
|
str_plural( // 复数 |
116
|
|
|
class_basename( |
117
|
|
|
get_class($this->getModel()) |
118
|
|
|
) |
119
|
|
|
) |
120
|
|
|
); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* {@inheritdoc} |
125
|
|
|
*/ |
126
|
|
|
public function setModel(Model $model) |
127
|
|
|
{ |
128
|
|
|
$this->model = $model; |
129
|
|
|
|
130
|
|
|
return $this; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* {@inheritdoc} |
135
|
|
|
*/ |
136
|
|
|
public function getModel() |
137
|
|
|
{ |
138
|
|
|
if (is_null($this->model)) { |
139
|
|
|
$this->setModel($this->makeModel()); |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
return $this->model; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* @return \Illuminate\Database\Eloquent\Model|mixed |
147
|
|
|
*/ |
148
|
|
|
protected function makeModel() |
149
|
|
|
{ |
150
|
|
|
$class = $this->model(); |
151
|
|
|
if (empty($class)) { |
152
|
|
|
throw new InvalidArgumentException( |
153
|
|
|
sprintf( |
154
|
|
|
'The component(%s) method "model()" not found value', |
155
|
|
|
get_class($this) |
156
|
|
|
) |
157
|
|
|
); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
$model = $this->app->make($this->model()); |
161
|
|
|
|
162
|
|
|
if (! ($model instanceof Model)) { |
163
|
|
|
throw new InvalidArgumentException( |
164
|
|
|
sprintf( |
165
|
|
|
"Class %s must be an instance of %s", |
166
|
|
|
$this->model(), |
167
|
|
|
Model::class |
168
|
|
|
) |
169
|
|
|
); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
return $model; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* {@inheritdoc} |
177
|
|
|
*/ |
178
|
|
|
public function getRepository() |
179
|
|
|
{ |
180
|
|
|
if (is_null($this->repository)) { |
181
|
|
|
$this->setRepository($this->makeRepository()); |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
return $this->repository; |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* {@inheritdoc} |
189
|
|
|
*/ |
190
|
|
|
public function setRepository(RepositoryInterface $repository) |
191
|
|
|
{ |
192
|
|
|
$this->repository = $repository; |
193
|
|
|
|
194
|
|
|
return $this; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
protected function makeRepository() |
198
|
|
|
{ |
199
|
|
|
$repository = $this->app->make(RepositoryInterface::class); |
200
|
|
|
$repository->setModel($this->getModel()); |
201
|
|
|
|
202
|
|
|
return $repository; |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* {@inheritdoc} |
207
|
|
|
*/ |
208
|
|
|
public function getConfigs() |
209
|
|
|
{ |
210
|
|
|
return collect([ |
211
|
|
|
'title' => $this->getTitle(), |
212
|
|
|
'accesses' => $this->getAccesses(), |
213
|
|
|
'display' => $this->fireDisplay(), |
214
|
|
|
]); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* {@inheritdoc} |
219
|
|
|
*/ |
220
|
|
View Code Duplication |
final public function fireDisplay() |
|
|
|
|
221
|
|
|
{ |
222
|
|
|
if (! method_exists($this, 'callDisplay')) { |
223
|
|
|
throw new BadMethodCallException('Not Found Method "callDisplay"'); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
$display = $this->app->call([$this, 'callDisplay']); |
227
|
|
|
|
228
|
|
|
if (! ($display instanceof DisplayInterface)) { |
229
|
|
|
throw new InvalidArgumentException( |
230
|
|
|
sprintf( |
231
|
|
|
'callDisplay must be instanced of "%s".', |
232
|
|
|
DisplayInterface::class |
233
|
|
|
) |
234
|
|
|
); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
$display->setModel($this->getModel()); |
|
|
|
|
238
|
|
|
$display->initialize(); |
239
|
|
|
|
240
|
|
|
return $display; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
public function get() |
244
|
|
|
{ |
245
|
|
|
$display = $this->fireDisplay(); |
246
|
|
|
|
247
|
|
|
return $display->get(); |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* {@inheritdoc} |
252
|
|
|
*/ |
253
|
|
View Code Duplication |
final public function fireCreate() |
|
|
|
|
254
|
|
|
{ |
255
|
|
|
if (! method_exists($this, 'callCreate')) { |
256
|
|
|
return; |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
$form = $this->app->call([$this, 'callCreate']); |
260
|
|
|
if (! $form instanceof FormInterface) { |
261
|
|
|
throw new InvalidArgumentException( |
262
|
|
|
sprintf( |
263
|
|
|
'callCreate must be instanced of "%s".', |
264
|
|
|
FormInterface::class |
265
|
|
|
) |
266
|
|
|
); |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
$form->setModel($this->getModel()); |
270
|
|
|
|
271
|
|
|
return $form; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
/** |
275
|
|
|
* {@inheritdoc} |
276
|
|
|
*/ |
277
|
|
|
public function store() |
278
|
|
|
{ |
279
|
|
|
$form = $this->fireCreate(); |
280
|
|
|
|
281
|
|
|
$form->validate()->save(); |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
/** |
285
|
|
|
* {@inheritdoc} |
286
|
|
|
*/ |
287
|
|
|
final public function fireEdit($id) |
288
|
|
|
{ |
289
|
|
|
if (! method_exists($this, 'callEdit')) { |
290
|
|
|
return; |
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
$form = $this->app->call([$this, 'callEdit'], ['id' => $id]); |
294
|
|
|
|
295
|
|
|
if (! $form instanceof FormInterface) { |
296
|
|
|
throw new InvalidArgumentException( |
297
|
|
|
sprintf( |
298
|
|
|
'callEdit must be instanced of "%s".', |
299
|
|
|
FormInterface::class |
300
|
|
|
) |
301
|
|
|
); |
302
|
|
|
} |
303
|
|
|
|
304
|
|
|
$model = $this->getRepository()->findOrFail($id); |
305
|
|
|
|
306
|
|
|
$form->setModel($model); |
307
|
|
|
|
308
|
|
|
return $form; |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
/** |
312
|
|
|
* {@inheritdoc} |
313
|
|
|
*/ |
314
|
|
|
public function update($id) |
315
|
|
|
{ |
316
|
|
|
$form = $this->fireEdit($id); |
317
|
|
|
$form->validate()->save(); |
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
public function delete($id) |
321
|
|
|
{ |
322
|
|
|
$this->getRepository()->delete($id); |
323
|
|
|
|
324
|
|
|
return true; |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
public function forceDelete($id) |
328
|
|
|
{ |
329
|
|
|
$this->getRepository()->forceDelete($id); |
330
|
|
|
|
331
|
|
|
return true; |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
public function restore($id) |
335
|
|
|
{ |
336
|
|
|
$this->getRepository()->restore($id); |
337
|
|
|
|
338
|
|
|
return true; |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
protected function bootIfNotBooted() |
342
|
|
|
{ |
343
|
|
|
if (! isset(static::$booted[static::class])) { |
344
|
|
|
static::$booted[static::class] = true; |
345
|
|
|
|
346
|
|
|
$this->fireEvent('booting', false); |
347
|
|
|
|
348
|
|
|
$this->boot(); |
349
|
|
|
|
350
|
|
|
$this->fireEvent('booted', false); |
351
|
|
|
} |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
/** |
355
|
|
|
* The "booting" method of the model. |
356
|
|
|
* |
357
|
|
|
* @return void |
358
|
|
|
*/ |
359
|
|
|
protected function boot() |
360
|
|
|
{ |
361
|
|
|
$this->bootTraits(); |
362
|
|
|
} |
363
|
|
|
|
364
|
|
|
/** |
365
|
|
|
* Boot all of the bootable traits on the model. |
366
|
|
|
* |
367
|
|
|
* @return void |
368
|
|
|
*/ |
369
|
|
|
protected function bootTraits() |
370
|
|
|
{ |
371
|
|
|
foreach (class_uses_recursive($this) as $trait) { |
372
|
|
|
if (method_exists($this, $method = 'boot' . class_basename($trait))) { |
373
|
|
|
$this->$method(); |
374
|
|
|
} |
375
|
|
|
} |
376
|
|
|
} |
377
|
|
|
} |
378
|
|
|
|
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.