Overview

Namespaces

  • Charcoal
    • App
      • Action
      • Config
      • Handler
      • Middleware
      • Module
      • Route
      • Script
      • ServiceProvider
      • Template

Classes

  • Charcoal\App\Action\AbstractAction
  • Charcoal\App\App
  • Charcoal\App\AppConfig
  • Charcoal\App\AppContainer
  • Charcoal\App\Config\CacheConfig
  • Charcoal\App\Config\DatabaseConfig
  • Charcoal\App\Config\FilesystemConfig
  • Charcoal\App\Config\LoggerConfig
  • Charcoal\App\Config\MemcacheCacheConfig
  • Charcoal\App\Config\MemcacheCacheServerConfig
  • Charcoal\App\Handler\AbstractHandler
  • Charcoal\App\Handler\Error
  • Charcoal\App\Handler\HandlerConfig
  • Charcoal\App\Handler\NotAllowed
  • Charcoal\App\Handler\NotFound
  • Charcoal\App\Handler\PhpError
  • Charcoal\App\Handler\Shutdown
  • Charcoal\App\Middleware\CacheMiddleware
  • Charcoal\App\Module\AbstractModule
  • Charcoal\App\Module\ModuleConfig
  • Charcoal\App\Module\ModuleManager
  • Charcoal\App\Route\ActionRoute
  • Charcoal\App\Route\ActionRouteConfig
  • Charcoal\App\Route\RouteConfig
  • Charcoal\App\Route\RouteManager
  • Charcoal\App\Route\ScriptRoute
  • Charcoal\App\Route\ScriptRouteConfig
  • Charcoal\App\Route\TemplateRoute
  • Charcoal\App\Route\TemplateRouteConfig
  • Charcoal\App\Script\AbstractScript
  • Charcoal\App\ServiceProvider\AppServiceProvider
  • Charcoal\App\ServiceProvider\CacheServiceProvider
  • Charcoal\App\ServiceProvider\DatabaseServiceProvider
  • Charcoal\App\ServiceProvider\FilesystemServiceProvider
  • Charcoal\App\ServiceProvider\LoggerServiceProvider
  • Charcoal\App\ServiceProvider\ViewServiceProvider
  • Charcoal\App\Template\AbstractTemplate
  • Charcoal\App\Template\AbstractWidget
  • Charcoal\App\Template\WidgetBuilder

Interfaces

  • Charcoal\App\Action\ActionInterface
  • Charcoal\App\AppAwareInterface
  • Charcoal\App\Handler\HandlerInterface
  • Charcoal\App\Module\ModuleInterface
  • Charcoal\App\Route\RouteInterface
  • Charcoal\App\Script\CronScriptInterface
  • Charcoal\App\Script\ScriptInterface
  • Charcoal\App\Template\TemplateInterface
  • Charcoal\App\Template\WidgetInterface

Traits

  • Charcoal\App\AppAwareTrait
  • Charcoal\App\CallableResolverAwareTrait
  • Charcoal\App\Script\ArgScriptTrait
  • Charcoal\App\Script\CronScriptTrait
  • Charcoal\App\Script\PathScriptTrait
  • Overview
  • Namespace
  • Class
  1: <?php
  2: 
  3: namespace Charcoal\App\ServiceProvider;
  4: 
  5: // Dependencies from Pimple
  6: use Pimple\ServiceProviderInterface;
  7: use Pimple\Container;
  8: 
  9: // From PSR-7
 10: use Psr\Http\Message\UriInterface;
 11: 
 12: // Dependencies from Slim
 13: use Slim\Http\Uri;
 14: 
 15: // Dependencies from league/climate
 16: use League\CLImate\CLImate;
 17: 
 18: // Dependencies from Mustache
 19: use Mustache_LambdaHelper as LambdaHelper;
 20: 
 21: // Dependencies from charcoal-factory
 22: use Charcoal\Factory\GenericFactory as Factory;
 23: 
 24: // Intra-module (`charcoal-app`) dependencies
 25: use Charcoal\App\Action\ActionInterface;
 26: use Charcoal\App\Script\ScriptInterface;
 27: use Charcoal\App\Module\ModuleInterface;
 28: 
 29: use Charcoal\App\Route\ActionRoute;
 30: use Charcoal\App\Route\RouteInterface;
 31: use Charcoal\App\Route\ScriptRoute;
 32: use Charcoal\App\Route\TemplateRoute;
 33: 
 34: use Charcoal\App\Handler\Error;
 35: use Charcoal\App\Handler\PhpError;
 36: use Charcoal\App\Handler\Shutdown;
 37: use Charcoal\App\Handler\NotAllowed;
 38: use Charcoal\App\Handler\NotFound;
 39: 
 40: use Charcoal\App\Template\TemplateInterface;
 41: use Charcoal\App\Template\TemplateBuilder;
 42: use Charcoal\App\Template\WidgetInterface;
 43: use Charcoal\App\Template\WidgetBuilder;
 44: 
 45: /**
 46:  * Application Service Provider
 47:  *
 48:  * Configures Charcoal and Slim and provides various Charcoal services to a container.
 49:  *
 50:  * ## Services
 51:  * - `logger` `\Psr\Log\Logger`
 52:  *
 53:  * ## Helpers
 54:  * - `logger/config` `\Charcoal\App\Config\LoggerConfig`
 55:  *
 56:  * ## Requirements / Dependencies
 57:  * - `config` A `ConfigInterface` must have been previously registered on the container.
 58:  */
 59: class AppServiceProvider implements ServiceProviderInterface
 60: {
 61:     /**
 62:      * Registers services on the given container.
 63:      *
 64:      * This method should only be used to configure services and parameters.
 65:      * It should not get services.
 66:      *
 67:      * @param Container $container A container instance.
 68:      * @return void
 69:      */
 70:     public function register(Container $container)
 71:     {
 72:         $this->registerHandlerServices($container);
 73:         $this->registerRouteServices($container);
 74:         $this->registerRequestControllerServices($container);
 75:         $this->registerScriptServices($container);
 76:         $this->registerModuleServices($container);
 77:         $this->registerViewServices($container);
 78:     }
 79: 
 80:     /**
 81:      * @param Container $container The DI container.
 82:      * @return void
 83:      */
 84:     protected function registerHandlerServices(Container $container)
 85:     {
 86:         $config = $container['config'];
 87: 
 88:         if (!isset($container['debug'])) {
 89:             /**
 90:              * Application Debug Mode
 91:              *
 92:              * @param Container $container
 93:              * @return boolean
 94:              */
 95:             $container['debug'] = function (Container $container) {
 96:                 if (isset($container['config']['debug'])) {
 97:                     $debug = !!$container['config']['debug'];
 98:                 } elseif (isset($container['config']['dev_mode'])) {
 99:                     $debug = !!$container['config']['dev_mode'];
100:                 } else {
101:                     $debug = false;
102:                 }
103: 
104:                 return $debug;
105:             };
106:         }
107: 
108:         if (!isset($container['base-url'])) {
109:             /**
110:              * Base URL as a PSR-7 UriInterface object for the current request
111:              * or the Charcoal application.
112:              *
113:              * @param Container $container
114:              * @return \Psr\Http\Message\UriInterface
115:              */
116:             $container['base-url'] = function (Container $container) {
117:                 if (isset($container['config']['base_url'])) {
118:                     $baseUrl = $container['config']['base_url'];
119:                 } else {
120:                     $baseUrl = $container['request']->getUri()->getBaseUrl();
121:                 }
122: 
123:                 $baseUrl = Uri::createFromString($baseUrl)->withUserInfo('');
124: 
125:                 /** Fix the base path */
126:                 $path = $baseUrl->getPath();
127:                 if ($path) {
128:                     $baseUrl = $baseUrl->withBasePath($path)->withPath('');
129:                 }
130: 
131:                 return $baseUrl;
132:             };
133:         }
134: 
135:         if (!isset($config['handlers'])) {
136:             return;
137:         }
138: 
139:         /**
140:          * HTTP 404 (Not Found) handler.
141:          *
142:          * @param  object|HandlerInterface $handler   An error handler instance.
143:          * @param  Container               $container A container instance.
144:          * @return HandlerInterface
145:          */
146:         $container->extend('notFoundHandler', function ($handler, Container $container) use ($config) {
147:             if ($handler instanceof \Slim\Handlers\NotFound) {
148:                 $handler = new NotFound($container);
149: 
150:                 if (isset($config['handlers']['notFound'])) {
151:                     $handler->config()->merge($config['handlers']['notFound']);
152:                 }
153: 
154:                 $handler->init();
155:             }
156: 
157:             return $handler;
158:         });
159: 
160:         /**
161:          * HTTP 405 (Not Allowed) handler.
162:          *
163:          * @param  object|HandlerInterface $handler   An error handler instance.
164:          * @param  Container               $container A container instance.
165:          * @return HandlerInterface
166:          */
167:         $container->extend('notAllowedHandler', function ($handler, Container $container) use ($config) {
168:             if ($handler instanceof \Slim\Handlers\NotAllowed) {
169:                 $handler = new NotAllowed($container);
170: 
171:                 if (isset($config['handlers']['notAllowed'])) {
172:                     $handler->config()->merge($config['handlers']['notAllowed']);
173:                 }
174: 
175:                 $handler->init();
176:             }
177: 
178:             return $handler;
179:         });
180: 
181:         /**
182:          * HTTP 500 (Error) handler for PHP 7+ Throwables.
183:          *
184:          * @param  object|HandlerInterface $handler   An error handler instance.
185:          * @param  Container               $container A container instance.
186:          * @return HandlerInterface
187:          */
188:         $container->extend('phpErrorHandler', function ($handler, Container $container) use ($config) {
189:             if ($handler instanceof \Slim\Handlers\PhpError) {
190:                 $handler = new PhpError($container);
191: 
192:                 if (isset($config['handlers']['phpError'])) {
193:                     $handler->config()->merge($config['handlers']['phpError']);
194:                 }
195: 
196:                 $handler->init();
197:             }
198: 
199:             return $handler;
200:         });
201: 
202:         /**
203:          * HTTP 500 (Error) handler.
204:          *
205:          * @param  object|HandlerInterface $handler   An error handler instance.
206:          * @param  Container               $container A container instance.
207:          * @return HandlerInterface
208:          */
209:         $container->extend('errorHandler', function ($handler, Container $container) use ($config) {
210:             if ($handler instanceof \Slim\Handlers\Error) {
211:                 $handler = new Error($container);
212: 
213:                 if (isset($config['handlers']['error'])) {
214:                     $handler->config()->merge($config['handlers']['error']);
215:                 }
216: 
217:                 $handler->init();
218:             }
219: 
220:             return $handler;
221:         });
222: 
223:         if (!isset($container['shutdownHandler'])) {
224:             /**
225:              * HTTP 503 (Service Unavailable) handler.
226:              *
227:              * This handler is not part of Slim.
228:              *
229:              * @param  Container $container A container instance.
230:              * @return HandlerInterface
231:              */
232:             $container['shutdownHandler'] = function (Container $container) {
233:                 $config  = $container['config'];
234:                 $handler = new Shutdown($container);
235: 
236:                 if (isset($config['handlers']['shutdown'])) {
237:                     $handler->config()->merge($config['handlers']['shutdown']);
238:                 }
239: 
240:                 return $handler->init();
241:             };
242:         }
243:     }
244: 
245:     /**
246:      * @param Container $container The DI container.
247:      * @return void
248:      */
249:     protected function registerRouteServices(Container $container)
250:     {
251:         /** @var string The default route controller for actions. */
252:         $container['route/controller/action/class'] = ActionRoute::class;
253: 
254:         /** @var string The default route controller for scripts. */
255:         $container['route/controller/script/class'] = ScriptRoute::class;
256: 
257:         /** @var string The default route controller for templates. */
258:         $container['route/controller/template/class'] = TemplateRoute::class;
259: 
260:         /**
261:          * The Route Factory service is used to instanciate new routes.
262:          *
263:          * @param Container $container A container instance.
264:          * @return \Charcoal\Factory\FactoryInterface
265:          */
266:         $container['route/factory'] = function (Container $container) {
267:             return new Factory([
268:                 'base_class'       => RouteInterface::class,
269:                 'resolver_options' => [
270:                     'suffix' => 'Route'
271:                 ],
272:                 'arguments'  => [[
273:                     'logger' => $container['logger']
274:                 ]]
275:             ]);
276:         };
277:     }
278: 
279:     /**
280:      * @param Container $container The DI container.
281:      * @return void
282:      */
283:     protected function registerRequestControllerServices(Container $container)
284:     {
285:         /**
286:          * The Action Factory service is used to instanciate new actions.
287:          *
288:          * - Actions are `ActionInterface` and must be suffixed with `Action`.
289:          * - The container is passed to the created action constructor, which will call `setDependencies()`.
290:          *
291:          * @param Container $container A container instance.
292:          * @return \Charcoal\Factory\FactoryInterface
293:          */
294:         $container['action/factory'] = function (Container $container) {
295:             return new Factory([
296:                 'base_class'       => ActionInterface::class,
297:                 'resolver_options' => [
298:                     'suffix' => 'Action'
299:                 ],
300:                 'arguments' => [[
301:                     'container' => $container,
302:                     'logger'    => $container['logger'],
303: 
304:                 ]]
305:             ]);
306:         };
307: 
308:         /**
309:          * The Script Factory service is used to instanciate new scripts.
310:          *
311:          * - Scripts are `ScriptInterface` and must be suffixed with `Script`.
312:          * - The container is passed to the created script constructor, which will call `setDependencies()`.
313:          *
314:          * @param Container $container A container instance.
315:          * @return \Charcoal\Factory\FactoryInterface
316:          */
317:         $container['script/factory'] = function (Container $container) {
318:             return new Factory([
319:                 'base_class'       => ScriptInterface::class,
320:                 'resolver_options' => [
321:                     'suffix' => 'Script'
322:                 ],
323:                 'arguments' => [[
324:                     'container'      => $container,
325:                     'logger'         => $container['logger'],
326:                     'climate'        => $container['climate'],
327:                     'climate_reader' => $container['climate/reader']
328:                 ]]
329:             ]);
330:         };
331: 
332:         /**
333:          * The Template Factory service is used to instanciate new templates.
334:          *
335:          * - Templates are `TemplateInterface` and must be suffixed with `Template`.
336:          * - The container is passed to the created template constructor, which will call `setDependencies()`.
337:          *
338:          * @param Container $container A container instance.
339:          * @return \Charcoal\Factory\FactoryInterface
340:          */
341:         $container['template/factory'] = function (Container $container) {
342:             return new Factory([
343:                 'base_class'       => TemplateInterface::class,
344:                 'resolver_options' => [
345:                     'suffix' => 'Template'
346:                 ],
347:                 'arguments' => [[
348:                     'container' => $container,
349:                     'logger'    => $container['logger']
350:                 ]]
351:             ]);
352:         };
353: 
354:         /**
355:          * The Widget Factory service is used to instanciate new widgets.
356:          *
357:          * - Widgets are `WidgetInterface` and must be suffixed with `Widget`.
358:          * - The container is passed to the created widget constructor, which will call `setDependencies()`.
359:          *
360:          * @param Container $container A container instance.
361:          * @return \Charcoal\Factory\FactoryInterface
362:          */
363:         $container['widget/factory'] = function (Container $container) {
364:             return new Factory([
365:                 'base_class'       => WidgetInterface::class,
366:                 'resolver_options' => [
367:                     'suffix' => 'Widget'
368:                 ],
369:                 'arguments' => [[
370:                     'container' => $container,
371:                     'logger'    => $container['logger']
372:                 ]]
373:             ]);
374:         };
375:         /**
376:          * @param Container $container A container instance.
377:          * @return TemplateBuilder
378:          */
379:         $container['widget/builder'] = function (Container $container) {
380:             return new WidgetBuilder($container['widget/factory'], $container);
381:         };
382:     }
383: 
384:     /**
385:      * @param Container $container The DI container.
386:      * @return void
387:      */
388:     protected function registerModuleServices(Container $container)
389:     {
390:         /**
391:          * The Module Factory service is used to instanciate new modules.
392:          *
393:          * - Modules are `ModuleInterface` and must be suffixed with `Module`.
394:          *
395:          * @param Container $container A container instance.
396:          * @return \Charcoal\Factory\FactoryInterface
397:          */
398:         $container['module/factory'] = function (Container $container) {
399:             return new Factory([
400:                 'base_class'       => ModuleInterface::class,
401:                 'resolver_options' => [
402:                     'suffix' => 'Module'
403:                 ],
404:                 'arguments'  => [[
405:                     'logger' => $container['logger']
406:                 ]]
407:             ]);
408:         };
409:     }
410: 
411:     /**
412:      * @param Container $container A container instance.
413:      * @return void
414:      */
415:     protected function registerScriptServices(Container $container)
416:     {
417:         /**
418:          * @todo   Needs implementation
419:          * @param Container $container A container instance.
420:          * @return null|\League\CLImate\Util\Reader\ReaderInterface
421:          */
422:         $container['climate/reader'] = function (Container $container) {
423:             return null;
424:         };
425: 
426:         /**
427:          * @param Container $container A container instance.
428:          * @return CLImate
429:          */
430:         $container['climate'] = function () {
431:             $climate = new CLImate();
432:             return $climate;
433:         };
434:     }
435: 
436:     /**
437:      * @param Container $container A container instance.
438:      * @return void
439:      */
440:     protected function registerViewServices(Container $container)
441:     {
442:         if (!isset($container['view/mustache/helpers'])) {
443:             $container['view/mustache/helpers'] = function () {
444:                 return [];
445:             };
446:         }
447: 
448:         /**
449:          * Extend helpers for the Mustache Engine
450:          *
451:          * @return array
452:          */
453:         $container->extend('view/mustache/helpers', function (array $helpers, Container $container) {
454:             $baseUrl = $container['base-url'];
455:             $urls = [
456:                 /**
457:                  * Application debug mode.
458:                  *
459:                  * @return boolean
460:                  */
461:                 'debug' => ($container['config']['debug'] || $container['config']['dev_mode']),
462:                 /**
463:                  * Retrieve the base URI of the project.
464:                  *
465:                  * @return UriInterface|null
466:                  */
467:                 'siteUrl' => $baseUrl,
468:                 /**
469:                  * Alias of "siteUrl"
470:                  *
471:                  * @return UriInterface|null
472:                  */
473:                 'baseUrl' => $baseUrl,
474:                 /**
475:                  * Prepend the base URI to the given path.
476:                  *
477:                  * @param  string $uri A URI path to wrap.
478:                  * @return UriInterface|null
479:                  */
480:                 'withBaseUrl' => function ($uri, LambdaHelper $helper = null) use ($baseUrl) {
481:                     if ($helper) {
482:                         $uri = $helper->render($uri);
483:                     }
484: 
485:                     $uri = strval($uri);
486:                     if ($uri === '') {
487:                         $uri = $baseUrl->withPath('');
488:                     } else {
489:                         $parts = parse_url($uri);
490:                         if (!isset($parts['scheme'])) {
491:                             if (!in_array($uri[0], [ '/', '#', '?' ])) {
492:                                 $path  = isset($parts['path']) ? $parts['path'] : '';
493:                                 $query = isset($parts['query']) ? $parts['query'] : '';
494:                                 $hash  = isset($parts['fragment']) ? $parts['fragment'] : '';
495: 
496:                                 $uri = $baseUrl->withPath($path)
497:                                                ->withQuery($query)
498:                                                ->withFragment($hash);
499:                             }
500:                         }
501:                     }
502: 
503:                     return $uri;
504:                 }
505:             ];
506: 
507:             return array_merge($helpers, $urls);
508:         });
509:     }
510: }
511: 
API documentation generated by ApiGen