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\Route;
|
|
|
|
|
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;
|
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;
|
|
|
|
|
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-02-24 12:34:31 +00:00
|
|
|
use Psr\Http\Message\ResponseInterface;
|
|
|
|
|
use Slim;
|
2020-06-12 13:57:36 +00:00
|
|
|
use Slim\Factory\AppFactory;
|
2020-07-21 17:26:52 +00:00
|
|
|
use Symfony\Bridge\Twig\Extension as SymfonyTwigExtensions;
|
|
|
|
|
use Symfony\Component\Translation;
|
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;
|
2020-07-21 19:39:19 +00:00
|
|
|
private array $viewPaths = [];
|
2020-07-09 17:47:27 +00:00
|
|
|
private string $cachePath = '/cache';
|
2020-07-21 19:39:19 +00:00
|
|
|
private array $supportedLanguages = ['en_US'];
|
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-07-27 02:44:36 +00:00
|
|
|
if ('cli' != php_sapi_name() && $this->isSessionsEnabled) {
|
|
|
|
|
$session = $container->get(SessionService::class);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$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
|
|
|
|
2020-07-27 02:44:36 +00:00
|
|
|
$errorMiddleware = $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-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;
|
|
|
|
|
}
|
|
|
|
|
|
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-07-09 17:47:27 +00:00
|
|
|
if (file_exists($this->getCachePath())) {
|
|
|
|
|
// $container->enableCompilation($this->getCachePath());
|
|
|
|
|
// $container->writeProxiesToFile(true, "{$this->getCachePath()}/injection-proxies");
|
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) {
|
|
|
|
|
if (!file_exists($viewLocation) || !is_dir($viewLocation)) {
|
|
|
|
|
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
|
|
|
|
|
|
|
|
if (!file_exists($twigCachePath)) {
|
2020-07-10 00:03:52 +00:00
|
|
|
@mkdir($twigCachePath, 0777, true);
|
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-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));
|
|
|
|
|
|
|
|
|
|
// Set some default parameters
|
2020-06-12 13:57:36 +00:00
|
|
|
$twig->offsetSet('app_name', APP_NAME);
|
|
|
|
|
$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-07-27 00:35:26 +00:00
|
|
|
$container->set(CachePoolChain::class, function (\Redis $redis) {
|
2020-02-24 12:34:31 +00:00
|
|
|
$caches = [];
|
|
|
|
|
|
|
|
|
|
// If apc/apcu present, add it to the pool
|
|
|
|
|
if (function_exists('apcu_add')) {
|
|
|
|
|
$caches[] = new ApcuCachePool();
|
|
|
|
|
} elseif (function_exists('apc_add')) {
|
|
|
|
|
$caches[] = new ApcCachePool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If Redis is configured, add it to the pool.
|
2020-07-27 00:35:26 +00:00
|
|
|
$caches[] = new RedisCachePool($redis);
|
2020-02-24 12:34:31 +00:00
|
|
|
$caches[] = new ArrayCachePool();
|
|
|
|
|
|
|
|
|
|
return new CachePoolChain($caches);
|
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
|
|
|
|
2020-07-27 00:35:26 +00:00
|
|
|
$container->set(Logger::class, function (ConfigurationService $configurationService) {
|
|
|
|
|
$monolog = new Logger($configurationService->get(ConfigurationService::KEY_APP_NAME));
|
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-07-27 00:35:26 +00:00
|
|
|
$container->set(\Redis::class, function (EnvironmentService $environmentService) {
|
2020-06-24 13:11:05 +00:00
|
|
|
$redis = new Redis();
|
2020-06-18 17:24:31 +00:00
|
|
|
$redis->connect(
|
|
|
|
|
$environmentService->get('REDIS_HOST', 'redis'),
|
|
|
|
|
$environmentService->get('REDIS_PORT', 6379)
|
|
|
|
|
);
|
2020-02-24 12:34:31 +00:00
|
|
|
|
2020-06-18 17:24:31 +00:00
|
|
|
return $redis;
|
2020-06-12 13:57:36 +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-05-24 16:03:18 +00:00
|
|
|
} elseif (file_exists('/etc/timezone')) {
|
|
|
|
|
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
|
|
|
|
|
|
|
|
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
|
|
|
|
|
*/
|
|
|
|
|
public static function Instance(array $options = [])
|
|
|
|
|
{
|
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-06-24 15:30:27 +00:00
|
|
|
$tempApp = new $calledClass($options);
|
|
|
|
|
/** @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-06-24 15:30:27 +00:00
|
|
|
self::$instance = new $configCoreClass($options);
|
2020-06-25 14:52:04 +00:00
|
|
|
} else {
|
2020-06-24 15:30:27 +00:00
|
|
|
self::$instance = $tempApp;
|
|
|
|
|
}
|
2020-08-06 17:48:55 +00:00
|
|
|
if (!defined('APP_CORE_NAME')) {
|
|
|
|
|
define('APP_CORE_NAME', get_class(self::$instance));
|
|
|
|
|
}
|
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)
|
|
|
|
|
{
|
|
|
|
|
if (file_exists($path)) {
|
|
|
|
|
$this->viewPaths[] = $path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static function Log(int $level = Logger::DEBUG, $message)
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function loadAllRoutes()
|
|
|
|
|
{
|
2020-08-06 17:48:55 +00:00
|
|
|
$this->debugBar['time']->startMeasure('interrogateControllers', 'Time to interrogate controllers for routes');
|
|
|
|
|
$this->interrogateControllers();
|
|
|
|
|
$this->debugBar['time']->stopMeasure('interrogateControllers');
|
|
|
|
|
|
|
|
|
|
$this->logger->debug(sprintf('Bootstrap complete in %sms', number_format((microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']) * 1000, 2)));
|
|
|
|
|
|
|
|
|
|
$this->router->populateRoutes($this->getApp());
|
2020-02-24 12:34:31 +00:00
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-12 13:57:36 +00:00
|
|
|
public function runHttp(): void
|
2020-02-24 12:34:31 +00:00
|
|
|
{
|
2020-08-06 17:48:55 +00:00
|
|
|
$this->loadAllRoutes();
|
2020-07-31 21:15:09 +00:00
|
|
|
$this->debugBar['time']->startMeasure('runHTTP', 'HTTP runtime');
|
2020-06-12 13:57:36 +00:00
|
|
|
$this->app->run();
|
2020-08-06 17:48:55 +00:00
|
|
|
|
2020-07-31 21:15:09 +00:00
|
|
|
if ($this->debugBar['time']->hasStartedMeasure('runHTTP')) {
|
2020-07-27 02:44:36 +00:00
|
|
|
$this->debugBar['time']->stopMeasure('runHTTP');
|
|
|
|
|
}
|
2020-02-24 12:34:31 +00:00
|
|
|
}
|
|
|
|
|
|
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-07-21 19:39:19 +00:00
|
|
|
protected function interrogateTranslations(): void
|
|
|
|
|
{
|
2020-07-21 22:42:42 +00:00
|
|
|
foreach (new \DirectoryIterator(APP_ROOT.'/src/Strings') as $translationFile) {
|
2020-07-21 19:39:19 +00:00
|
|
|
if ('yaml' == $translationFile->getExtension()) {
|
|
|
|
|
$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')
|
|
|
|
|
&& '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-02-24 12:34:31 +00:00
|
|
|
$controllerPaths = [
|
2020-07-27 02:44:36 +00:00
|
|
|
APP_ROOT.'/src/Controllers',
|
2020-02-24 12:34:31 +00:00
|
|
|
];
|
2020-06-12 13:57:36 +00:00
|
|
|
|
2020-02-24 12:34:31 +00:00
|
|
|
foreach ($controllerPaths as $controllerPath) {
|
|
|
|
|
if (file_exists($controllerPath)) {
|
|
|
|
|
foreach (new \DirectoryIterator($controllerPath) as $controllerFile) {
|
|
|
|
|
if (!$controllerFile->isDot() && $controllerFile->isFile() && $controllerFile->isReadable()) {
|
2020-06-12 13:57:36 +00:00
|
|
|
$appClass = new \ReflectionClass(get_called_class());
|
2020-02-24 12:34:31 +00:00
|
|
|
$expectedClasses = [
|
|
|
|
|
$appClass->getNamespaceName().'\\Controllers\\'.str_replace('.php', '', $controllerFile->getFilename()),
|
2020-07-31 21:10:39 +00:00
|
|
|
'Benzine\\Controllers\\'.str_replace('.php', '', $controllerFile->getFilename()),
|
2020-02-24 12:34:31 +00:00
|
|
|
];
|
|
|
|
|
foreach ($expectedClasses as $expectedClass) {
|
|
|
|
|
if (class_exists($expectedClass)) {
|
|
|
|
|
$rc = new \ReflectionClass($expectedClass);
|
|
|
|
|
if (!$rc->isAbstract()) {
|
|
|
|
|
foreach ($rc->getMethods() as $method) {
|
|
|
|
|
/** @var \ReflectionMethod $method */
|
2020-06-12 13:57:36 +00:00
|
|
|
if (true || ResponseInterface::class == ($method->getReturnType() instanceof \ReflectionType ? $method->getReturnType()->getName() : null)) {
|
2020-02-24 12:34:31 +00:00
|
|
|
$docBlock = $method->getDocComment();
|
2020-07-31 21:10:39 +00:00
|
|
|
$newRoute = new Route($this->logger);
|
2020-02-24 12:34:31 +00:00
|
|
|
foreach (explode("\n", $docBlock) as $docBlockRow) {
|
2020-07-31 21:10:39 +00:00
|
|
|
if (false !== stripos($docBlockRow, '@route')) {
|
|
|
|
|
$route = trim(substr(
|
|
|
|
|
$docBlockRow,
|
|
|
|
|
(stripos($docBlockRow, '@route') + strlen('@route'))
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
@list($httpMethods, $path, $extra) = explode(' ', $route, 3);
|
|
|
|
|
$httpMethods = explode(',', strtoupper($httpMethods));
|
|
|
|
|
|
|
|
|
|
$options = [];
|
|
|
|
|
$defaultOptions = [
|
|
|
|
|
'access' => Route::ACCESS_PUBLIC,
|
|
|
|
|
'weight' => 100,
|
|
|
|
|
];
|
|
|
|
|
if (isset($extra)) {
|
|
|
|
|
foreach (explode(' ', $extra) as $item) {
|
|
|
|
|
@list($extraK, $extraV) = explode('=', $item, 2);
|
|
|
|
|
if (!isset($extraV)) {
|
|
|
|
|
$extraV = true;
|
|
|
|
|
}
|
|
|
|
|
$options[$extraK] = $extraV;
|
2020-02-24 12:34:31 +00:00
|
|
|
}
|
|
|
|
|
}
|
2020-07-31 21:10:39 +00:00
|
|
|
$options = array_merge($defaultOptions, $options);
|
|
|
|
|
foreach ($httpMethods as $httpMethod) {
|
|
|
|
|
$newRoute
|
|
|
|
|
->setHttpMethod($httpMethod)
|
|
|
|
|
->setRouterPattern('/'.ltrim($path, '/'))
|
|
|
|
|
->setCallback($method->class.':'.$method->name)
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
foreach ($options as $key => $value) {
|
|
|
|
|
$keyMethod = 'set'.ucfirst($key);
|
|
|
|
|
if (method_exists($newRoute, $keyMethod)) {
|
|
|
|
|
$newRoute->{$keyMethod}($value);
|
|
|
|
|
} else {
|
|
|
|
|
$newRoute->setArgument($key, $value);
|
|
|
|
|
}
|
2020-02-24 12:34:31 +00:00
|
|
|
}
|
|
|
|
|
|
2020-07-31 21:10:39 +00:00
|
|
|
$this->router->addRoute($newRoute);
|
|
|
|
|
}
|
|
|
|
|
} elseif (false !== stripos($docBlockRow, '@domains')) {
|
|
|
|
|
$domains = explode(' ', trim(substr(
|
|
|
|
|
$docBlockRow,
|
|
|
|
|
(stripos($docBlockRow, '@domains') + strlen('@domains'))
|
|
|
|
|
)));
|
|
|
|
|
foreach ($domains as $domain) {
|
|
|
|
|
$newRoute->addValidDomain($domain);
|
|
|
|
|
}
|
|
|
|
|
$newRoute->setWeight($newRoute->getWeight() - 10);
|
2020-02-24 12:34:31 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-27 01:31:04 +00:00
|
|
|
$this->router
|
|
|
|
|
->weighRoutes()
|
2020-07-27 02:44:36 +00:00
|
|
|
->cache()
|
|
|
|
|
;
|
2020-08-06 17:48:55 +00:00
|
|
|
|
|
|
|
|
$this->logger->debug(sprintf(
|
|
|
|
|
'ROUTE_CACHE miss. Perhaps enable ROUTE_CACHE envvar.'
|
|
|
|
|
));
|
2020-02-24 12:34:31 +00:00
|
|
|
}
|
|
|
|
|
}
|