2020-02-24 12:34:31 +00:00
< ? php
2020-06-12 08:09:02 +00:00
namespace Benzine ;
2020-02-24 12:34:31 +00:00
2020-06-16 10:47:20 +00:00
use Benzine\ORM\Connection\Databases ;
2020-06-12 13:57:36 +00:00
use Benzine\ORM\Laminator ;
2020-06-24 13:11:05 +00:00
use Benzine\Redis\Redis ;
2020-07-27 01:31:04 +00:00
use Benzine\Router\Router ;
2020-06-12 08:09:02 +00:00
use Benzine\Services\ConfigurationService ;
2020-06-12 13:57:36 +00:00
use Benzine\Services\EnvironmentService ;
use Benzine\Services\SessionService ;
use Benzine\Twig\Extensions ;
2020-02-24 12:34:31 +00:00
use Cache\Adapter\Apc\ApcCachePool ;
use Cache\Adapter\Apcu\ApcuCachePool ;
use Cache\Adapter\Chain\CachePoolChain ;
use Cache\Adapter\PHPArray\ArrayCachePool ;
2020-06-12 13:57:36 +00:00
use Cache\Adapter\Redis\RedisCachePool ;
2021-05-06 20:15:01 +00:00
use Cocur\Slugify\Slugify ;
2020-02-24 12:34:31 +00:00
use DebugBar\Bridge\MonologCollector ;
2020-07-27 02:44:36 +00:00
use DebugBar\DataCollector\ExceptionsCollector ;
use DebugBar\DataCollector\MemoryCollector ;
use DebugBar\DataCollector\MessagesCollector ;
use DebugBar\DataCollector\PhpInfoCollector ;
use DebugBar\DataCollector\RequestDataCollector ;
use DebugBar\DataCollector\TimeDataCollector ;
2020-02-24 12:34:31 +00:00
use DebugBar\DebugBar ;
2020-06-12 13:57:36 +00:00
use DI\Container ;
use DI\ContainerBuilder ;
2020-02-24 12:34:31 +00:00
use Faker\Factory as FakerFactory ;
use Faker\Provider ;
2020-07-27 00:10:21 +00:00
use Middlewares\TrailingSlash ;
2020-06-12 13:57:36 +00:00
use Monolog\Formatter\LineFormatter ;
use Monolog\Handler\ErrorLogHandler ;
2020-12-15 11:08:04 +00:00
use Monolog\Handler\StreamHandler ;
2020-06-12 13:57:36 +00:00
use Monolog\Logger ;
2020-02-24 21:34:42 +00:00
use Monolog\Processor\PsrLogMessageProcessor ;
2020-06-12 13:57:36 +00:00
use Psr\Container\ContainerInterface ;
2020-09-07 22:28:46 +00:00
use Psr\Http\Message\ServerRequestInterface ;
2020-02-24 12:34:31 +00:00
use Slim ;
2020-06-12 13:57:36 +00:00
use Slim\Factory\AppFactory ;
2020-09-07 22:28:46 +00:00
use Slim\Factory\ServerRequestCreatorFactory ;
2020-07-21 17:26:52 +00:00
use Symfony\Bridge\Twig\Extension as SymfonyTwigExtensions ;
2020-09-01 16:52:53 +00:00
use Symfony\Component\Filesystem\Exception\IOException ;
2020-09-01 16:41:34 +00:00
use Symfony\Component\Filesystem\Filesystem ;
2020-07-21 17:26:52 +00:00
use Symfony\Component\Translation ;
2020-11-13 09:49:18 +00:00
use Tuupola\Middleware\ServerTimingMiddleware ;
2020-06-12 13:57:36 +00:00
use Twig ;
use Twig\Loader\FilesystemLoader ;
2020-06-12 08:09:02 +00:00
class App
2020-02-24 12:34:31 +00:00
{
public const DEFAULT_TIMEZONE = 'Europe/London' ;
2020-06-12 13:57:36 +00:00
public static App $instance ;
2020-02-24 12:34:31 +00:00
2020-06-12 13:57:36 +00:00
protected EnvironmentService $environmentService ;
protected ConfigurationService $configurationService ;
protected \Slim\App $app ;
protected Logger $logger ;
2020-07-27 02:44:36 +00:00
protected DebugBar $debugBar ;
2020-07-27 01:31:04 +00:00
protected Router $router ;
2020-06-12 13:57:36 +00:00
protected bool $isSessionsEnabled = true ;
protected bool $interrogateControllersComplete = false ;
2021-01-22 04:20:21 +00:00
protected ? CachePoolChain $cachePoolChain = null ;
2020-07-21 19:39:19 +00:00
private array $viewPaths = [];
2020-11-13 09:52:44 +00:00
private string $cachePath = APP_ROOT . '/cache' ;
2021-01-22 04:20:21 +00:00
private string $logPath = APP_ROOT . '/logs' ;
2020-07-21 19:39:19 +00:00
private array $supportedLanguages = [ 'en_US' ];
2021-01-22 04:19:38 +00:00
private bool $debugMode = false ;
2020-02-24 12:34:31 +00:00
2020-06-18 17:24:31 +00:00
private static bool $isInitialised = false ;
2020-06-12 13:57:36 +00:00
public function __construct ()
2020-02-24 12:34:31 +00:00
{
2020-08-06 17:48:55 +00:00
if ( ! ini_get ( 'auto_detect_line_endings' )) {
ini_set ( 'auto_detect_line_endings' , '1' );
}
2020-06-12 13:57:36 +00:00
// Configure Dependency Injector
$container = $this -> setupContainer ();
2020-07-27 02:44:36 +00:00
$this -> logger = $container -> get ( Logger :: class );
$this -> debugBar = $container -> get ( DebugBar :: class );
2020-06-12 13:57:36 +00:00
AppFactory :: setContainer ( $container );
2020-02-24 12:34:31 +00:00
2020-09-01 16:41:34 +00:00
// If we're not on the CLI and Sessions ARE enabled...
2020-09-07 22:28:46 +00:00
if ( 'cli' !== php_sapi_name () && $this -> isSessionsEnabled ) {
2020-09-01 16:41:34 +00:00
// Call SessionService out of the container to force initialise it
$container -> get ( SessionService :: class );
2020-07-27 02:44:36 +00:00
}
2020-09-01 16:41:34 +00:00
// Configure default expected views paths
2020-07-27 02:44:36 +00:00
$this -> viewPaths [] = APP_ROOT . '/views/' ;
$this -> viewPaths [] = APP_ROOT . '/src/Views/' ;
2020-06-22 11:46:35 +00:00
2020-06-12 13:57:36 +00:00
// Configure Slim
$this -> app = AppFactory :: create ();
$this -> app -> add ( Slim\Views\TwigMiddleware :: createFromContainer ( $this -> app ));
$this -> app -> addRoutingMiddleware ();
2020-02-24 12:34:31 +00:00
2020-07-27 02:44:36 +00:00
$this -> setupMiddlewares ( $container );
2020-02-24 12:34:31 +00:00
2021-01-22 04:19:38 +00:00
// Determine if we're going to enable debug mode
$this -> debugMode = $this -> environmentService -> get ( 'DEBUG_MODE' , 'off' ) == 'on' ;
// Enable the slim error middleware if appropriate.
if ( $this -> debugMode ) {
$this -> app -> addErrorMiddleware ( true , true , true , $this -> logger );
}
2020-02-24 12:34:31 +00:00
2020-07-27 02:44:36 +00:00
$this -> debugBar [ 'time' ] -> startMeasure ( 'interrogateTranslations' , 'Time to interrogate translation files' );
2020-07-21 19:39:19 +00:00
$this -> interrogateTranslations ();
2020-07-27 02:44:36 +00:00
$this -> debugBar [ 'time' ] -> stopMeasure ( 'interrogateTranslations' );
2020-11-13 09:49:18 +00:00
$this -> app -> add ( new ServerTimingMiddleware ());
2020-02-24 12:34:31 +00:00
}
2020-07-09 17:47:27 +00:00
public function getCachePath () : string
{
return $this -> cachePath ;
}
public function setCachePath ( string $cachePath ) : App
{
$this -> cachePath = $cachePath ;
return $this ;
}
2021-01-22 01:58:44 +00:00
/**
* @ return array
*/
public function getViewPaths () : array
{
return $this -> viewPaths ;
}
/**
* @ param array $viewPaths
2021-01-22 04:20:21 +00:00
*
2021-01-22 01:58:44 +00:00
* @ return App
*/
public function setViewPaths ( array $viewPaths ) : App
{
$this -> viewPaths = $viewPaths ;
2021-01-22 04:20:21 +00:00
2021-01-22 01:58:44 +00:00
return $this ;
}
/**
* @ return string
*/
public function getLogPath () : string
{
return $this -> logPath ;
}
/**
* @ param string $logPath
2021-01-22 04:20:21 +00:00
*
2021-01-22 01:58:44 +00:00
* @ return App
*/
public function setLogPath ( string $logPath ) : App
{
$this -> logPath = $logPath ;
2021-01-22 04:20:21 +00:00
2021-01-22 01:58:44 +00:00
return $this ;
}
2020-06-18 17:24:31 +00:00
/**
* Get item from Dependency Injection .
*/
public function get ( string $id )
{
return $this -> getApp () -> getContainer () -> get ( $id );
}
2020-06-12 13:57:36 +00:00
public function setupContainer () : Container
2020-02-24 12:34:31 +00:00
{
2020-06-15 06:19:42 +00:00
$app = $this ;
2020-06-12 13:57:36 +00:00
$container =
( new ContainerBuilder ())
-> useAutowiring ( true )
-> useAnnotations ( true )
2020-06-18 17:24:31 +00:00
;
2020-09-01 16:52:53 +00:00
//if ((new Filesystem())->exists($this->getCachePath())) {
// $container->enableCompilation($this->getCachePath());
// $container->writeProxiesToFile(true, "{$this->getCachePath()}/injection-proxies");
//}
2020-12-15 11:08:04 +00:00
2020-06-22 19:38:55 +00:00
$container = $container -> build ();
2020-06-12 13:57:36 +00:00
2020-07-31 21:10:39 +00:00
$container -> set ( Slim\Views\Twig :: class , function (
EnvironmentService $environmentService ,
SessionService $sessionService ,
Translation\Translator $translator
) {
2020-02-24 12:34:31 +00:00
foreach ( $this -> viewPaths as $i => $viewLocation ) {
2020-09-01 16:41:34 +00:00
if ( ! ( new Filesystem ()) -> exists ( $viewLocation ) || ! is_dir ( $viewLocation )) {
2020-02-24 12:34:31 +00:00
unset ( $this -> viewPaths [ $i ]);
}
}
2020-07-09 17:47:27 +00:00
$twigCachePath = " { $this -> getCachePath () } /twig " ;
2020-07-10 03:02:39 +00:00
$twigSettings = [];
2020-07-10 06:39:04 +00:00
if ( $environmentService -> has ( 'TWIG_CACHE' ) && 'on' == strtolower ( $environmentService -> get ( 'TWIG_CACHE' ))) {
2020-07-10 03:02:39 +00:00
$twigSettings [ 'cache' ] = $twigCachePath ;
}
2020-07-09 17:47:27 +00:00
2020-09-01 16:41:34 +00:00
if ( ! ( new Filesystem ()) -> exists ( $twigCachePath )) {
2020-09-01 16:52:53 +00:00
try {
( new Filesystem ()) -> mkdir ( $twigCachePath , 0777 );
} catch ( IOException $IOException ) {
unset ( $twigSettings [ 'cache' ]);
2020-09-28 16:36:59 +00:00
if ( ! in_array ( PHP_SAPI , [ 'cli' , 'phpdbg' ], true )) {
$this -> getLogger () -> warning ( sprintf ( 'Could not create Twig cache (%s), Twig cache disabled ' , $twigCachePath ));
}
2020-09-01 16:52:53 +00:00
}
2020-07-09 17:47:27 +00:00
}
2020-06-12 13:57:36 +00:00
$loader = new FilesystemLoader ();
2020-02-24 12:34:31 +00:00
2020-06-12 13:57:36 +00:00
foreach ( $this -> viewPaths as $path ) {
2020-06-18 17:24:31 +00:00
$loader -> addPath ( $path );
2020-06-12 13:57:36 +00:00
}
2020-02-24 12:34:31 +00:00
2020-07-09 17:47:27 +00:00
$twig = new Slim\Views\Twig ( $loader , $twigSettings );
2020-02-24 12:34:31 +00:00
2020-06-12 13:57:36 +00:00
$twig -> addExtension ( new Extensions\ArrayUniqueTwigExtension ());
$twig -> addExtension ( new Extensions\FilterAlphanumericOnlyTwigExtension ());
2020-02-24 12:34:31 +00:00
// Add coding string transform filters (ie: camel_case to StudlyCaps)
2020-06-12 13:57:36 +00:00
$twig -> addExtension ( new Extensions\TransformExtension ());
2020-02-24 12:34:31 +00:00
// Add pluralisation/depluralisation support with singularize/pluralize filters
2020-06-12 13:57:36 +00:00
$twig -> addExtension ( new Extensions\InflectionExtension ());
2020-02-24 12:34:31 +00:00
// Added Twig_Extension_Debug to enable twig dump() etc.
2020-06-12 13:57:36 +00:00
$twig -> addExtension ( new Twig\Extension\DebugExtension ());
2020-07-21 19:39:19 +00:00
// Add Twig extension to integrate Kint
$twig -> addExtension ( new \Kint\Twig\TwigExtension ());
2020-08-27 01:34:52 +00:00
// Add Twig extension to check if something is an instance of a known class or entity
$twig -> addExtension ( new Extensions\InstanceOfExtension ());
2020-07-21 17:26:52 +00:00
// Add Twig Translate from symfony/twig-bridge
2020-07-21 17:59:21 +00:00
$selectedLanguage = $sessionService -> has ( 'Language' ) ? $sessionService -> get ( 'Language' ) : 'en_US' ;
2020-07-21 17:26:52 +00:00
$twig -> addExtension ( new SymfonyTwigExtensions\TranslationExtension ( $translator ));
$twig -> offsetSet ( 'language' , $translator -> trans ( $selectedLanguage ));
2020-09-09 04:00:03 +00:00
// Add Twig Intl Extension
2021-05-16 04:39:55 +00:00
$twig -> addExtension ( new Twig\Extra\Intl\IntlExtension ());
2020-09-09 04:00:03 +00:00
2020-07-21 17:26:52 +00:00
// Set some default parameters
2020-09-01 16:52:53 +00:00
$twig -> offsetSet ( 'app_name' , defined ( 'APP_NAME' ) ? APP_NAME : 'APP_NAME not set' );
2020-06-12 13:57:36 +00:00
$twig -> offsetSet ( 'year' , date ( 'Y' ));
2020-07-21 19:39:19 +00:00
$twig -> offsetSet ( 'session' , $sessionService );
2020-07-26 15:08:17 +00:00
2020-06-12 13:57:36 +00:00
return $twig ;
});
2020-07-21 17:26:52 +00:00
2020-07-21 19:39:19 +00:00
// This is required as some plugins for Slim expect there to be a twig available as "view"
2020-07-27 00:35:26 +00:00
$container -> set ( 'view' , function ( Slim\Views\Twig $twig ) {
return $twig ;
2020-06-12 13:57:36 +00:00
});
2020-02-24 12:34:31 +00:00
2020-07-27 00:35:26 +00:00
$container -> set ( Translation\Translator :: class , function ( SessionService $sessionService ) {
2020-07-21 17:59:21 +00:00
$selectedLanguage = $sessionService -> has ( 'Language' ) ? $sessionService -> get ( 'Language' ) : 'en_US' ;
2020-07-21 17:26:52 +00:00
2020-07-21 17:59:21 +00:00
$translator = new Translation\Translator ( $selectedLanguage );
2020-07-21 17:27:21 +00:00
2020-07-21 17:26:52 +00:00
// set default locale
2020-07-21 17:59:21 +00:00
$translator -> setFallbackLocales ([ 'en_US' ]);
2020-07-21 17:26:52 +00:00
// build the yaml loader
$yamlLoader = new Translation\Loader\YamlFileLoader ();
// add the loader to the translator
$translator -> addLoader ( 'yaml' , $yamlLoader );
// add some resources to the translator
2020-07-21 22:42:42 +00:00
$translator -> addResource ( 'yaml' , APP_ROOT . " /src/Strings/ { $selectedLanguage } .yaml " , $selectedLanguage );
2020-07-21 17:27:21 +00:00
2020-07-21 17:26:52 +00:00
return $translator ;
});
2020-07-27 00:35:26 +00:00
$container -> set ( ConfigurationService :: class , function ( EnvironmentService $environmentService ) use ( $app ) {
2020-06-15 06:19:42 +00:00
return new ConfigurationService (
$app ,
2020-07-27 00:35:26 +00:00
$environmentService
2020-06-15 06:19:42 +00:00
);
2020-06-12 13:57:36 +00:00
});
2020-06-15 06:19:42 +00:00
2020-07-27 00:35:26 +00:00
$container -> set ( \Faker\Generator :: class , function () {
2020-02-24 12:34:31 +00:00
$faker = FakerFactory :: create ();
$faker -> addProvider ( new Provider\Base ( $faker ));
$faker -> addProvider ( new Provider\DateTime ( $faker ));
$faker -> addProvider ( new Provider\Lorem ( $faker ));
$faker -> addProvider ( new Provider\Internet ( $faker ));
$faker -> addProvider ( new Provider\Payment ( $faker ));
$faker -> addProvider ( new Provider\en_US\Person ( $faker ));
$faker -> addProvider ( new Provider\en_US\Address ( $faker ));
$faker -> addProvider ( new Provider\en_US\PhoneNumber ( $faker ));
$faker -> addProvider ( new Provider\en_US\Company ( $faker ));
return $faker ;
2020-06-12 13:57:36 +00:00
});
2020-07-21 19:39:19 +00:00
2020-12-15 11:08:04 +00:00
$container -> set ( CachePoolChain :: class , function ( Logger $logger , Redis $redis ) {
if ( ! $this -> cachePoolChain ) {
$caches = [];
2020-02-24 12:34:31 +00:00
2020-12-15 11:08:04 +00:00
// If apc/apcu present, add it to the pool
if ( function_exists ( 'apcu_add' )) {
$caches [] = new ApcuCachePool ( true );
} elseif ( function_exists ( 'apc_add' )) {
$caches [] = new ApcCachePool ( true );
}
2020-02-24 12:34:31 +00:00
2020-12-15 11:08:04 +00:00
// If Redis is configured, add it to the pool.
if ( $redis -> isAvailable ()) {
$caches [] = new RedisCachePool ( $redis -> getUnderlyingRedis ());
}
$caches [] = new ArrayCachePool ();
$this -> cachePoolChain = new CachePoolChain ( $caches );
}
2021-01-22 04:20:21 +00:00
2020-12-15 11:08:04 +00:00
return $this -> cachePoolChain ;
2020-06-12 13:57:36 +00:00
});
2020-07-27 00:35:26 +00:00
$container -> set ( 'MonologFormatter' , function ( EnvironmentService $environmentService ) {
return new LineFormatter (
2020-02-24 12:34:31 +00:00
// the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%"
2020-07-27 00:35:26 +00:00
$environmentService -> get ( 'MONOLOG_FORMAT' , '[%datetime%] %channel%.%level_name%: %message% %context% %extra%' ) . " \n " ,
2020-02-24 12:34:31 +00:00
'Y n j, g:i a'
2020-06-12 13:57:36 +00:00
);
});
2020-02-24 12:34:31 +00:00
2021-05-06 20:15:01 +00:00
$container -> set ( Logger :: class , function ( ConfigurationService $configurationService , EnvironmentService $environmentService , Slugify $slugify ) {
2020-12-15 11:08:04 +00:00
$appName = $configurationService -> get ( ConfigurationService :: KEY_APP_NAME );
2021-01-22 04:20:21 +00:00
$logName = $environmentService -> has ( 'REQUEST_URI' ) ? sprintf ( '%s(%s)' , $appName , $environmentService -> get ( 'REQUEST_URI' )) : $appName ;
2020-12-15 11:08:04 +00:00
$monolog = new Logger ( $logName );
2021-05-06 20:15:01 +00:00
$monolog -> pushHandler ( new StreamHandler ( sprintf (
'%s/%s.%s.log' ,
$this -> getLogPath (),
$slugify -> slugify ( $appName ),
$slugify -> slugify ( PHP_SAPI )
)));
2020-06-12 13:57:36 +00:00
$monolog -> pushHandler ( new ErrorLogHandler (), Logger :: DEBUG );
2020-02-24 21:34:42 +00:00
$monolog -> pushProcessor ( new PsrLogMessageProcessor ());
return $monolog ;
2020-06-12 13:57:36 +00:00
});
2020-02-24 12:34:31 +00:00
2020-12-06 18:00:12 +00:00
$container -> set ( Redis :: class , function ( Logger $logger , EnvironmentService $environmentService ) {
2020-11-27 10:47:52 +00:00
return new Redis (
2020-12-06 18:00:12 +00:00
$logger ,
2020-06-18 17:24:31 +00:00
$environmentService -> get ( 'REDIS_HOST' , 'redis' ),
2020-11-27 10:43:02 +00:00
$environmentService -> get ( 'REDIS_PORT' , 6379 ),
2021-01-30 09:57:28 +00:00
$environmentService -> get ( 'REDIS_PASSWORD' , null ),
2020-12-06 18:00:12 +00:00
$environmentService -> get ( 'REDIS_TIMEOUT' , 1.0 )
2020-11-27 10:47:52 +00:00
);
2020-11-27 10:43:02 +00:00
});
2020-02-24 12:34:31 +00:00
2020-07-27 00:35:26 +00:00
$container -> set ( Laminator :: class , function ( ConfigurationService $configurationService , Databases $databases ) {
2020-06-18 17:24:31 +00:00
return new Laminator (
APP_ROOT ,
2020-07-27 00:35:26 +00:00
$configurationService ,
$databases
2020-06-18 17:24:31 +00:00
);
2020-06-12 13:57:36 +00:00
});
2020-02-24 12:34:31 +00:00
2020-07-27 00:14:52 +00:00
$container -> set ( TrailingSlash :: class , function () {
2020-07-27 00:10:21 +00:00
return ( new TrailingSlash ()) -> redirect ();
});
2020-07-27 02:44:36 +00:00
$container -> set ( DebugBar :: class , function ( Logger $logger ) {
return ( new DebugBar ())
-> addCollector ( new PhpInfoCollector ())
-> addCollector ( new MessagesCollector ())
//->addCollector(new RequestDataCollector())
-> addCollector ( new TimeDataCollector ())
-> addCollector ( new MemoryCollector ())
-> addCollector ( new ExceptionsCollector ())
-> addCollector ( new MonologCollector ( $logger , Logger :: DEBUG ))
;
});
$container -> set ( \Middlewares\Debugbar :: class , function ( DebugBar $debugBar ) {
return new \Middlewares\Debugbar (
$debugBar
);
});
2020-07-31 21:10:39 +00:00
$this -> environmentService = $container -> get ( Services\EnvironmentService :: class );
if ( $this -> environmentService -> has ( 'TIMEZONE' )) {
date_default_timezone_set ( $this -> environmentService -> get ( 'TIMEZONE' ));
2020-09-01 16:41:34 +00:00
} elseif (( new Filesystem ()) -> exists ( '/etc/timezone' )) {
2020-05-24 16:03:18 +00:00
date_default_timezone_set ( trim ( file_get_contents ( '/etc/timezone' )));
2020-02-24 12:34:31 +00:00
} else {
date_default_timezone_set ( self :: DEFAULT_TIMEZONE );
}
2020-07-27 01:31:04 +00:00
$this -> router = $container -> get ( Router :: class );
2020-06-12 13:57:36 +00:00
2021-01-22 04:20:21 +00:00
//!\Kint::dump($this->environmentService->all());exit;
2020-06-12 13:57:36 +00:00
return $container ;
2020-02-24 12:34:31 +00:00
}
2020-06-12 13:57:36 +00:00
public function setupMiddlewares ( ContainerInterface $container ) : void
2020-02-24 12:34:31 +00:00
{
// Middlewares
2020-06-18 17:24:31 +00:00
//$this->app->add($container->get(\Middlewares\Geolocation::class));
2020-07-27 00:10:21 +00:00
$this -> app -> add ( $container -> get ( \Middlewares\TrailingSlash :: class ));
2020-06-18 17:24:31 +00:00
//$this->app->add($container->get(\Middlewares\Whoops::class));
//$this->app->add($container->get(\Middlewares\Minifier::class));
2020-07-27 01:31:04 +00:00
//$this->app->add($container->get(\Middlewares\GzipEncoder::class));
2020-07-27 00:10:21 +00:00
$this -> app -> add ( $container -> get ( \Middlewares\ContentLength :: class ));
2020-02-24 12:34:31 +00:00
}
/**
* @ return self
*/
2020-09-01 16:41:34 +00:00
public static function Instance ()
2020-02-24 12:34:31 +00:00
{
2020-06-12 13:57:36 +00:00
if ( ! self :: $isInitialised ) {
2020-02-24 12:34:31 +00:00
$calledClass = get_called_class ();
2020-06-25 14:52:04 +00:00
/** @var App $tempApp */
2020-09-01 16:41:34 +00:00
$tempApp = new $calledClass ();
2020-06-24 15:30:27 +00:00
/** @var ConfigurationService $config */
$config = $tempApp -> get ( ConfigurationService :: class );
$configCoreClass = $config -> getCore ();
2020-06-25 14:52:04 +00:00
if ( $configCoreClass != get_called_class ()) {
2020-09-01 16:41:34 +00:00
self :: $instance = new $configCoreClass ();
2020-06-25 14:52:04 +00:00
} else {
2020-06-24 15:30:27 +00:00
self :: $instance = $tempApp ;
}
2020-02-24 12:34:31 +00:00
}
2020-06-25 14:52:04 +00:00
2020-02-24 12:34:31 +00:00
return self :: $instance ;
}
2020-07-07 16:45:26 +00:00
/**
* Convenience function to get objects out of the Dependency Injection Container .
*/
public static function DI ( string $key )
{
return self :: Instance () -> get ( $key );
}
2020-07-21 17:27:21 +00:00
public function getApp () : Slim\App
2020-02-24 12:34:31 +00:00
{
return $this -> app ;
}
public function addViewPath ( $path )
{
2020-09-01 16:41:34 +00:00
if (( new Filesystem ()) -> exists ( $path )) {
2020-02-24 12:34:31 +00:00
$this -> viewPaths [] = $path ;
}
return $this ;
}
2021-01-22 06:22:56 +00:00
public static function Log ( $message , int $level = Logger :: DEBUG )
2020-02-24 12:34:31 +00:00
{
return self :: Instance ()
2020-07-27 02:44:36 +00:00
-> getLogger ()
2020-02-24 12:34:31 +00:00
-> log ( $level , ( $message instanceof \Exception ) ? $message -> __toString () : $message )
;
}
2020-09-07 22:28:46 +00:00
public function runHttp () : void
{
$serverRequestCreator = ServerRequestCreatorFactory :: create ();
$request = $serverRequestCreator -> createServerRequestFromGlobals ();
$this -> loadAllRoutes ( $request );
$this -> debugBar [ 'time' ] -> startMeasure ( 'runHTTP' , 'HTTP runtime' );
$this -> app -> run ( $request );
if ( $this -> debugBar [ 'time' ] -> hasStartedMeasure ( 'runHTTP' )) {
$this -> debugBar [ 'time' ] -> stopMeasure ( 'runHTTP' );
}
}
2020-07-21 19:39:19 +00:00
/**
* @ return string []
*/
public function getSupportedLanguages () : array
{
return $this -> supportedLanguages ;
}
/**
* @ param string [] $supportedLanguages
*/
public function setSupportedLanguages ( array $supportedLanguages ) : self
{
$this -> supportedLanguages = $supportedLanguages ;
return $this ;
}
public function addSupportedLanguage ( string $supportedLanguage ) : self
{
$this -> supportedLanguages [] = $supportedLanguage ;
$this -> supportedLanguages = array_unique ( $this -> supportedLanguages );
return $this ;
}
public function isSupportedLanguage ( string $supportedLanguage ) : bool
{
return in_array ( $supportedLanguage , $this -> supportedLanguages , true );
}
2020-07-27 01:31:04 +00:00
/**
* @ return mixed | Router
*/
public function getRouter ()
{
return $this -> router ;
}
/**
* @ param mixed | Router $router
*
* @ return App
*/
public function setRouter ( $router )
{
$this -> router = $router ;
return $this ;
}
2020-07-27 02:44:36 +00:00
public function getLogger () : Logger
{
return $this -> logger ;
}
2020-10-19 17:12:24 +00:00
public function loadAllRoutes ( ServerRequestInterface $request ) : self
2020-09-11 14:51:16 +00:00
{
$this -> debugBar [ 'time' ] -> startMeasure ( 'interrogateControllers' , 'Time to interrogate controllers for routes' );
$this -> interrogateControllers ();
$this -> debugBar [ 'time' ] -> stopMeasure ( 'interrogateControllers' );
2020-12-15 11:08:04 +00:00
$timeToBootstrapMs = ( microtime ( true ) - $_SERVER [ 'REQUEST_TIME_FLOAT' ]) * 1000 ;
$bootstrapTooLongThresholdMs = 300 ;
2021-01-22 04:20:21 +00:00
if ( $timeToBootstrapMs >= $bootstrapTooLongThresholdMs ) {
2020-12-15 11:08:04 +00:00
$this -> logger -> warning ( sprintf ( 'Bootstrap complete in %sms which is more than the threshold of %sms' , number_format ( $timeToBootstrapMs , 2 ), $bootstrapTooLongThresholdMs ));
}
2020-09-11 14:51:16 +00:00
$this -> router -> populateRoutes ( $this -> getApp (), $request );
return $this ;
}
2020-07-21 19:39:19 +00:00
protected function interrogateTranslations () : void
{
2020-08-24 16:58:21 +00:00
$stringPath = APP_ROOT . '/src/Strings' ;
2020-09-01 16:41:34 +00:00
if ( ! ( new Filesystem ()) -> exists ( $stringPath )) {
2020-08-24 16:58:21 +00:00
return ;
}
foreach ( new \DirectoryIterator ( $stringPath ) as $translationFile ) {
2020-09-07 22:28:46 +00:00
if ( 'yaml' === $translationFile -> getExtension ()) {
2020-07-21 19:39:19 +00:00
$languageName = substr ( $translationFile -> getBasename (), 0 , - 5 );
$this -> addSupportedLanguage ( $languageName );
}
}
}
protected function interrogateControllers () : void
2020-02-24 12:34:31 +00:00
{
if ( $this -> interrogateControllersComplete ) {
return ;
}
$this -> interrogateControllersComplete = true ;
2020-08-06 17:48:55 +00:00
if ( $this -> environmentService -> has ( 'ROUTE_CACHE' )
2020-09-07 22:28:46 +00:00
&& 'on' === strtolower ( $this -> environmentService -> get ( 'ROUTE_CACHE' ))
2020-07-31 21:10:39 +00:00
&& $this -> router -> loadCache ()
) {
2020-07-27 01:31:04 +00:00
return ;
}
2020-09-07 22:28:46 +00:00
$appClass = new \ReflectionClass ( static :: class );
2020-09-07 10:10:21 +00:00
$this -> router -> loadRoutesFromAnnotations (
[
APP_ROOT . '/src/Controllers' ,
],
$appClass -> getNamespaceName ()
);
2020-02-24 12:34:31 +00:00
2020-09-07 22:28:46 +00:00
$this -> router -> cache ();
2020-08-06 17:48:55 +00:00
2020-12-15 11:08:04 +00:00
$this -> logger -> info ( 'ROUTE_CACHE miss.' );
2020-02-24 12:34:31 +00:00
}
}