1
|
|
|
<?php namespace Anomaly\Streams\Platform\Addon; |
2
|
|
|
|
3
|
|
|
use Anomaly\Streams\Platform\Addon\Extension\Extension; |
4
|
|
|
use Anomaly\Streams\Platform\Addon\Module\Module; |
5
|
|
|
use Anomaly\Streams\Platform\Http\Middleware\MiddlewareCollection; |
6
|
|
|
use Anomaly\Streams\Platform\View\Event\RegisteringTwigPlugins; |
7
|
|
|
use Anomaly\Streams\Platform\View\ViewMobileOverrides; |
8
|
|
|
use Anomaly\Streams\Platform\View\ViewOverrides; |
9
|
|
|
use Illuminate\Console\Events\ArtisanStarting; |
10
|
|
|
use Illuminate\Console\Scheduling\Schedule; |
11
|
|
|
use Illuminate\Contracts\Events\Dispatcher; |
12
|
|
|
use Illuminate\Contracts\Foundation\Application; |
13
|
|
|
use Illuminate\Routing\Router; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Class AddonProvider |
17
|
|
|
* |
18
|
|
|
* @link http://pyrocms.com/ |
19
|
|
|
* @author PyroCMS, Inc. <[email protected]> |
20
|
|
|
* @author Ryan Thompson <[email protected]> |
21
|
|
|
*/ |
22
|
|
|
class AddonProvider |
23
|
|
|
{ |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* The cached services. |
27
|
|
|
* |
28
|
|
|
* @var array |
29
|
|
|
*/ |
30
|
|
|
protected $cached = []; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* The registered providers. |
34
|
|
|
* |
35
|
|
|
* @var array |
36
|
|
|
*/ |
37
|
|
|
protected $providers = []; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* The router instance. |
41
|
|
|
* |
42
|
|
|
* @var Router |
43
|
|
|
*/ |
44
|
|
|
protected $router; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* The event dispatcher. |
48
|
|
|
* |
49
|
|
|
* @var Dispatcher |
50
|
|
|
*/ |
51
|
|
|
protected $events; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* The scheduler instance. |
55
|
|
|
* |
56
|
|
|
* @var Schedule |
57
|
|
|
*/ |
58
|
|
|
protected $schedule; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* The application container. |
62
|
|
|
* |
63
|
|
|
* @var Application |
64
|
|
|
*/ |
65
|
|
|
protected $application; |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* The middleware collection. |
69
|
|
|
* |
70
|
|
|
* @var MiddlewareCollection |
71
|
|
|
*/ |
72
|
|
|
protected $middlewares; |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* The view overrides. |
76
|
|
|
* |
77
|
|
|
* @var ViewOverrides |
78
|
|
|
*/ |
79
|
|
|
protected $viewOverrides; |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* The mobile view overrides. |
83
|
|
|
* |
84
|
|
|
* @var ViewMobileOverrides |
85
|
|
|
*/ |
86
|
|
|
protected $viewMobileOverrides; |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* Create a new AddonProvider instance. |
90
|
|
|
* |
91
|
|
|
* @param Router $router |
92
|
|
|
* @param Dispatcher $events |
93
|
|
|
* @param Schedule $schedule |
94
|
|
|
* @param Application $application |
95
|
|
|
*/ |
96
|
|
|
public function __construct( |
97
|
|
|
Router $router, |
98
|
|
|
Dispatcher $events, |
99
|
|
|
Schedule $schedule, |
100
|
|
|
Application $application, |
101
|
|
|
ViewOverrides $viewOverrides, |
102
|
|
|
MiddlewareCollection $middlewares, |
103
|
|
|
ViewMobileOverrides $viewMobileOverrides |
104
|
|
|
) { |
105
|
|
|
$this->router = $router; |
106
|
|
|
$this->events = $events; |
107
|
|
|
$this->schedule = $schedule; |
108
|
|
|
$this->application = $application; |
109
|
|
|
$this->middlewares = $middlewares; |
110
|
|
|
$this->viewOverrides = $viewOverrides; |
111
|
|
|
$this->viewMobileOverrides = $viewMobileOverrides; |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* Register the service provider for an addon. |
116
|
|
|
* |
117
|
|
|
* @param Addon $addon |
118
|
|
|
*/ |
119
|
|
|
public function register(Addon $addon) |
120
|
|
|
{ |
121
|
|
|
if ($addon instanceof Module && !$addon->isEnabled() && $addon->getSlug() !== 'installer') { |
122
|
|
|
return; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
if ($addon instanceof Extension && !$addon->isEnabled()) { |
126
|
|
|
return; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
$provider = $addon->getServiceProvider(); |
130
|
|
|
|
131
|
|
|
if (!class_exists($provider)) { |
132
|
|
|
return; |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
$this->providers[] = $provider = $addon->newServiceProvider(); |
136
|
|
|
|
137
|
|
|
$this->bindAliases($provider); |
138
|
|
|
$this->bindClasses($provider); |
139
|
|
|
$this->bindSingletons($provider); |
140
|
|
|
|
141
|
|
|
$this->registerRoutes($provider, $addon); |
142
|
|
|
$this->registerOverrides($provider, $addon); |
143
|
|
|
$this->registerApi($provider, $addon); |
144
|
|
|
|
145
|
|
|
$this->registerEvents($provider); |
146
|
|
|
$this->registerPlugins($provider); |
147
|
|
|
$this->registerCommands($provider); |
148
|
|
|
$this->registerSchedules($provider); |
149
|
|
|
$this->registerProviders($provider); |
150
|
|
|
$this->registerMiddleware($provider); |
151
|
|
|
$this->registerRouteMiddleware($provider); |
152
|
|
|
|
153
|
|
|
if (method_exists($provider, 'register')) { |
154
|
|
|
$this->application->call([$provider, 'register']); |
155
|
|
|
} |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Boot the service providers. |
160
|
|
|
*/ |
161
|
|
|
public function boot() |
162
|
|
|
{ |
163
|
|
|
foreach ($this->providers as $provider) { |
164
|
|
|
if (method_exists($provider, 'boot')) { |
165
|
|
|
$this->application->call([$provider, 'boot']); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
$this->registerAdditionalRoutes($provider); |
169
|
|
|
} |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Register the addon providers. |
174
|
|
|
* |
175
|
|
|
* @param AddonServiceProvider $provider |
176
|
|
|
*/ |
177
|
|
|
protected function registerProviders(AddonServiceProvider $provider) |
178
|
|
|
{ |
179
|
|
|
foreach ($provider->getProviders() as $provider) { |
180
|
|
|
$this->application->register($provider); |
181
|
|
|
} |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* Register the addon commands. |
186
|
|
|
* |
187
|
|
|
* @param AddonServiceProvider $provider |
188
|
|
|
*/ |
189
|
|
|
protected function registerCommands(AddonServiceProvider $provider) |
190
|
|
|
{ |
191
|
|
|
if ($commands = $provider->getCommands()) { |
192
|
|
|
|
193
|
|
|
// To register the commands with Artisan, we will grab each of the arguments |
194
|
|
|
// passed into the method and listen for Artisan "start" event which will |
195
|
|
|
// give us the Artisan console instance which we will give commands to. |
196
|
|
|
$this->events->listen( |
197
|
|
|
'Illuminate\Console\Events\ArtisanStarting', |
198
|
|
|
function (ArtisanStarting $event) use ($commands) { |
199
|
|
|
$event->artisan->resolveCommands($commands); |
200
|
|
|
} |
201
|
|
|
); |
202
|
|
|
} |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* Bind class aliases. |
207
|
|
|
* |
208
|
|
|
* @param AddonServiceProvider $provider |
209
|
|
|
*/ |
210
|
|
|
protected function bindAliases(AddonServiceProvider $provider) |
211
|
|
|
{ |
212
|
|
|
foreach ($provider->getAliases() as $abstract => $alias) { |
213
|
|
|
$this->application->alias($abstract, $alias); |
214
|
|
|
} |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* Bind addon classes. |
219
|
|
|
* |
220
|
|
|
* @param AddonServiceProvider $provider |
221
|
|
|
*/ |
222
|
|
|
protected function bindClasses(AddonServiceProvider $provider) |
223
|
|
|
{ |
224
|
|
|
foreach ($provider->getBindings() as $abstract => $concrete) { |
225
|
|
|
$this->application->bind($abstract, $concrete); |
226
|
|
|
} |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* Bind addon singletons. |
231
|
|
|
* |
232
|
|
|
* @param AddonServiceProvider $provider |
233
|
|
|
*/ |
234
|
|
|
protected function bindSingletons(AddonServiceProvider $provider) |
235
|
|
|
{ |
236
|
|
|
foreach ($provider->getSingletons() as $abstract => $concrete) { |
237
|
|
|
$this->application->singleton($abstract, $concrete); |
238
|
|
|
} |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Register the addon events. |
243
|
|
|
* |
244
|
|
|
* @param AddonServiceProvider $provider |
245
|
|
|
*/ |
246
|
|
|
protected function registerEvents(AddonServiceProvider $provider) |
247
|
|
|
{ |
248
|
|
|
if (!$listen = $provider->getListeners()) { |
249
|
|
|
return; |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
foreach ($listen as $event => $listeners) { |
253
|
|
View Code Duplication |
foreach ($listeners as $key => $listener) { |
|
|
|
|
254
|
|
|
if (is_integer($listener)) { |
255
|
|
|
$listener = $key; |
256
|
|
|
$priority = $listener; |
257
|
|
|
} else { |
258
|
|
|
$priority = 0; |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
$this->events->listen($event, $listener, $priority); |
262
|
|
|
} |
263
|
|
|
} |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* Register the addon routes. |
268
|
|
|
* |
269
|
|
|
* @param AddonServiceProvider $provider |
270
|
|
|
* @param Addon $addon |
271
|
|
|
*/ |
272
|
|
|
protected function registerRoutes(AddonServiceProvider $provider, Addon $addon) |
273
|
|
|
{ |
274
|
|
|
if ($this->routesAreCached()) { |
275
|
|
|
return; |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
if (!$routes = $provider->getRoutes()) { |
279
|
|
|
return; |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
foreach ($routes as $uri => $route) { |
283
|
|
|
|
284
|
|
|
/* |
285
|
|
|
* If the route definition is an |
286
|
|
|
* not an array then let's make it one. |
287
|
|
|
* Array type routes give us more control |
288
|
|
|
* and allow us to pass information in the |
289
|
|
|
* request's route action array. |
290
|
|
|
*/ |
291
|
|
|
if (!is_array($route)) { |
292
|
|
|
$route = [ |
293
|
|
|
'uses' => $route, |
294
|
|
|
]; |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
$verb = array_pull($route, 'verb', 'any'); |
298
|
|
|
$middleware = array_pull($route, 'middleware', []); |
299
|
|
|
$constraints = array_pull($route, 'constraints', []); |
300
|
|
|
|
301
|
|
|
array_set($route, 'streams::addon', $addon->getNamespace()); |
302
|
|
|
|
303
|
|
|
if (is_string($route['uses']) && !str_contains($route['uses'], '@')) { |
304
|
|
|
$this->router->resource($uri, $route['uses']); |
305
|
|
View Code Duplication |
} else { |
|
|
|
|
306
|
|
|
|
307
|
|
|
$route = $this->router->{$verb}($uri, $route)->where($constraints); |
308
|
|
|
|
309
|
|
|
if ($middleware) { |
310
|
|
|
call_user_func_array([$route, 'middleware'], (array)$middleware); |
311
|
|
|
} |
312
|
|
|
} |
313
|
|
|
} |
314
|
|
|
} |
315
|
|
|
|
316
|
|
|
/** |
317
|
|
|
* Register the addon routes. |
318
|
|
|
* |
319
|
|
|
* @param AddonServiceProvider $provider |
320
|
|
|
* @param Addon $addon |
321
|
|
|
*/ |
322
|
|
|
protected function registerApi(AddonServiceProvider $provider, Addon $addon) |
323
|
|
|
{ |
324
|
|
|
if ($this->routesAreCached()) { |
325
|
|
|
return; |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
if (!$routes = $provider->getApi()) { |
329
|
|
|
return; |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
$this->router->group( |
333
|
|
|
[ |
334
|
|
|
'middleware' => 'auth:api', |
335
|
|
|
'prefix' => 'api', |
336
|
|
|
], |
337
|
|
|
function (Router $router) use ($routes, $addon) { |
338
|
|
|
|
339
|
|
|
foreach ($routes as $uri => $route) { |
340
|
|
|
|
341
|
|
|
/* |
342
|
|
|
* If the route definition is an |
343
|
|
|
* not an array then let's make it one. |
344
|
|
|
* Array type routes give us more control |
345
|
|
|
* and allow us to pass information in the |
346
|
|
|
* request's route action array. |
347
|
|
|
*/ |
348
|
|
|
if (!is_array($route)) { |
349
|
|
|
$route = [ |
350
|
|
|
'uses' => $route, |
351
|
|
|
]; |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
$verb = array_pull($route, 'verb', 'any'); |
355
|
|
|
$middleware = array_pull($route, 'middleware', []); |
356
|
|
|
$constraints = array_pull($route, 'constraints', []); |
357
|
|
|
|
358
|
|
|
array_set($route, 'streams::addon', $addon->getNamespace()); |
359
|
|
|
|
360
|
|
|
if (is_string($route['uses']) && !str_contains($route['uses'], '@')) { |
361
|
|
|
$router->resource($uri, $route['uses']); |
362
|
|
View Code Duplication |
} else { |
|
|
|
|
363
|
|
|
|
364
|
|
|
$route = $router->{$verb}($uri, $route)->where($constraints); |
365
|
|
|
|
366
|
|
|
if ($middleware) { |
367
|
|
|
call_user_func_array([$route, 'middleware'], (array)$middleware); |
368
|
|
|
} |
369
|
|
|
} |
370
|
|
|
} |
371
|
|
|
} |
372
|
|
|
); |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
/** |
376
|
|
|
* Register the addon plugins. |
377
|
|
|
* |
378
|
|
|
* @param AddonServiceProvider $provider |
379
|
|
|
*/ |
380
|
|
|
protected function registerPlugins(AddonServiceProvider $provider) |
381
|
|
|
{ |
382
|
|
|
if (!$plugins = $provider->getPlugins()) { |
383
|
|
|
return; |
384
|
|
|
} |
385
|
|
|
|
386
|
|
|
$this->events->listen( |
387
|
|
|
'Anomaly\Streams\Platform\View\Event\RegisteringTwigPlugins', |
388
|
|
|
function (RegisteringTwigPlugins $event) use ($plugins) { |
389
|
|
|
$twig = $event->getTwig(); |
390
|
|
|
|
391
|
|
|
foreach ($plugins as $plugin) { |
392
|
|
|
$twig->addExtension(app($plugin)); |
393
|
|
|
} |
394
|
|
|
} |
395
|
|
|
); |
396
|
|
|
} |
397
|
|
|
|
398
|
|
|
/** |
399
|
|
|
* Register the addon schedules. |
400
|
|
|
* |
401
|
|
|
* @param AddonServiceProvider $provider |
402
|
|
|
*/ |
403
|
|
|
protected function registerSchedules(AddonServiceProvider $provider) |
404
|
|
|
{ |
405
|
|
|
if (!$schedules = $provider->getSchedules()) { |
406
|
|
|
return; |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
foreach ($schedules as $frequency => $commands) { |
410
|
|
|
foreach (array_filter($commands) as $command) { |
411
|
|
|
if (str_is('* * * *', $frequency)) { |
412
|
|
|
$this->schedule->command($command)->cron($frequency); |
413
|
|
|
} else { |
414
|
|
|
|
415
|
|
|
$parts = explode('|', $frequency); |
416
|
|
|
|
417
|
|
|
$method = array_shift($parts); |
418
|
|
|
$arguments = explode(',', array_shift($parts)); |
419
|
|
|
|
420
|
|
|
call_user_func_array([$this->schedule->command($command), $method], $arguments); |
421
|
|
|
} |
422
|
|
|
} |
423
|
|
|
} |
424
|
|
|
} |
425
|
|
|
|
426
|
|
|
/** |
427
|
|
|
* Register view overrides. |
428
|
|
|
* |
429
|
|
|
* @param AddonServiceProvider $provider |
430
|
|
|
* @param Addon $addon |
431
|
|
|
*/ |
432
|
|
|
protected function registerOverrides(AddonServiceProvider $provider, Addon $addon) |
433
|
|
|
{ |
434
|
|
|
$overrides = $provider->getOverrides(); |
435
|
|
|
$mobiles = $provider->getMobile(); |
436
|
|
|
|
437
|
|
|
if (!$overrides && !$mobiles) { |
|
|
|
|
438
|
|
|
return; |
439
|
|
|
} |
440
|
|
|
|
441
|
|
|
$this->viewOverrides->put($addon->getNamespace(), $overrides); |
442
|
|
|
$this->viewMobileOverrides->put($addon->getNamespace(), $mobiles); |
443
|
|
|
} |
444
|
|
|
|
445
|
|
|
/** |
446
|
|
|
* Register middleware. |
447
|
|
|
* |
448
|
|
|
* @param AddonServiceProvider $provider |
449
|
|
|
*/ |
450
|
|
|
protected function registerMiddleware(AddonServiceProvider $provider) |
451
|
|
|
{ |
452
|
|
|
foreach ($provider->getMiddleware() as $middleware) { |
453
|
|
|
$this->middlewares->push($middleware); |
454
|
|
|
} |
455
|
|
|
} |
456
|
|
|
|
457
|
|
|
/** |
458
|
|
|
* Register route middleware. |
459
|
|
|
* |
460
|
|
|
* @param AddonServiceProvider $provider |
461
|
|
|
*/ |
462
|
|
|
protected function registerRouteMiddleware(AddonServiceProvider $provider) |
463
|
|
|
{ |
464
|
|
|
foreach ($provider->getRouteMiddleware() as $name => $class) { |
465
|
|
|
$this->router->middleware($name, $class); |
466
|
|
|
} |
467
|
|
|
} |
468
|
|
|
|
469
|
|
|
/** |
470
|
|
|
* Register additional routes. |
471
|
|
|
* |
472
|
|
|
* @param AddonServiceProvider $provider |
473
|
|
|
*/ |
474
|
|
|
protected function registerAdditionalRoutes(AddonServiceProvider $provider) |
475
|
|
|
{ |
476
|
|
|
if ($this->routesAreCached()) { |
477
|
|
|
return; |
478
|
|
|
} |
479
|
|
|
|
480
|
|
|
if (method_exists($provider, 'map')) { |
481
|
|
|
try { |
482
|
|
|
$this->application->call([$provider, 'map']); |
483
|
|
|
} catch (\Exception $e) { |
|
|
|
|
484
|
|
|
/* |
485
|
|
|
* If, for whatever reason, this fails let |
486
|
|
|
* it fail silently. Mapping additional routes |
487
|
|
|
* could be volatile at certain application states. |
488
|
|
|
*/ |
489
|
|
|
} |
490
|
|
|
} |
491
|
|
|
} |
492
|
|
|
|
493
|
|
|
/** |
494
|
|
|
* Check if routes are cached. |
495
|
|
|
*/ |
496
|
|
|
protected function routesAreCached() |
497
|
|
|
{ |
498
|
|
|
if (in_array('routes', $this->cached)) { |
499
|
|
|
return true; |
500
|
|
|
} |
501
|
|
|
|
502
|
|
|
if (file_exists(base_path('bootstrap/cache/routes.php'))) { |
503
|
|
|
return $this->cached[] = 'routes'; |
504
|
|
|
} |
505
|
|
|
|
506
|
|
|
return false; |
507
|
|
|
} |
508
|
|
|
} |
509
|
|
|
|
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.