You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

386 lines
8.6 KiB
PHP

<?php
namespace Eater\Glim;
use Eater\Glim\Helper\EasyContainer;
use Interop\Container\ContainerInterface;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Noodlehaus\Config;
use Propel\Runtime\Propel;
use Psr\Http\Message\UriInterface;
use Slim\App;
use Slim\Container;
use Slim\Http\Request;
use Slim\Http\Response;
use Symfony\Component\Yaml\Yaml;
class Core implements ContainerInterface
{
use EasyContainer;
/**
* @var string
*/
private $baseDir;
/**
* @var Config
*/
private $config;
/**
* @var array
*/
private $timers = [];
/**
* @var array
*/
private $routes;
/**
* @return \Twig_Environment
*/
public function getTwig()
{
return $this->get('twig');
}
/**
* @return Propel
*/
public function getPropel()
{
return $this->get('propel');
}
/**
* @param Propel $propel
*/
public function setPropel($propel)
{
$this->set('propel', $propel);
}
public function boot($baseDir)
{
$this->startTimer(["boot", "load"]);
$this->setBaseDir($baseDir);
$this->loadConfig();
$this->bootContainer();
$this->bootLogger();
$this->bootPropel();
$this->loadRoutes();
$this->loadContainer();
$this->loadServices();
$this->endTimer(["load"]);
$this->startTimer(["process"]);
$this->processRoutes();
$this->endTimer(["boot", "process"]);
}
public function startTimer($timers)
{
$time = microtime(true);
foreach ($timers as $timer) {
$this->timers[$timer] = [$time, false];
}
}
public function loadConfig()
{
$basePath = '?' . $this->getBaseDir() . '/config/app.';
$configs = ['yml', 'json', 'xml', 'ini'];
$configPaths = array_map(function ($ext) use ($basePath) {
return $basePath . $ext;
}, $configs);
$this->setConfig(new Config($configPaths));
}
/**
* @return string
*/
public function getBaseDir()
{
return $this->baseDir;
}
/**
* @param string $baseDir
*/
public function setBaseDir($baseDir)
{
$this->baseDir = $baseDir;
}
public function bootContainer()
{
$this->setContainer(new Container());
$this->set('core', $this);
}
public function bootLogger()
{
$config = $this->getConfig();
$logger = new Logger('default');
$logger->pushHandler(
new StreamHandler(
$config->get('core.log.path', $this->getBaseDir() . '/logs/core.log'),
$config->get('core.log.level', Logger::INFO)
)
);
$this->setLogger($logger);
}
/**
* @return Config
*/
public function getConfig()
{
return $this->config;
}
/**
* @param Config $config
*/
public function setConfig($config)
{
$this->config = $config;
}
/**
* @param Logger $logger
*/
public function setLogger($logger)
{
$this->set('logger', $logger);
}
public function bootPropel()
{
include $this->getBaseDir() . '/config/propel/config.php';
Propel::getServiceContainer()->setLogger('defaultLogger', $this->getLogger());
}
public function loadRoutes()
{
$this->startTimer(["load/routes"]);
$path = $this->getBaseDir() . '/config/routes.yml';
$routesFile = file_get_contents($path);
$routes = Yaml::parse($routesFile);
$this->setRoutes($routes);
$this->endTimer(["load/routes"]);
}
public function endTimer($timers)
{
$logger = $this->getLogger();
$time = microtime(true);
foreach ($timers as $timer) {
$this->timers[$timer][1] = $time;
$elapsed = round(($this->timers[$timer][1] - $this->timers[$timer][0]) * 1000);
$logger->addDebug("[CORE] {$timer} took {$elapsed}ms");
}
}
/**
* @return Logger
*/
public function getLogger()
{
return $this->get('logger');
}
public function loadContainer()
{
$this->startTimer(["load/container"]);
$container = $this->getContainer();
$containerSettings = $this->getConfig()->get('core.container', []);
$container->offsetSet("baseDir", $this->getBaseDir());
foreach ($containerSettings as $name => $value) {
$container->offsetSet($name, $value);
}
$this->endTimer(["load/container"]);
}
public function loadServices()
{
$this->startTimer(['load/services']);
$services = $this->getConfig()->get('core.services', []);
$container = $this->getContainer();
foreach ($services as $name => $class) {
$container->offsetSet($name, function ($container) use ($class, $name) {
/** @var Core $core */
$core = $container->get('core');
$core->startTimer(['load/service/' . $name]);
$item = $class::init($container, $name);
$core->endTimer(['load/service/' . $name]);
return $item;
});
}
$this->endTimer(['load/services']);
}
public function processRoutes()
{
$this->startTimer(["process/routes"]);
$routesConfig = $this->getRoutes();
$prefix = $routesConfig["prefix"];
$routes = $routesConfig["routes"];
$this->processRoute("", $routes, $prefix);
$this->endTimer(["process/routes"]);
}
/**
* @return array
*/
public function getRoutes()
{
return $this->routes;
}
/**
* @param array $routes
*/
public function setRoutes($routes)
{
$this->routes = $routes;
}
/**
* @param string $path
* @param array $routes
* @param string $prefix
*/
public function processRoute($path, $routes, $prefix)
{
$slim = $this->getSlim();
$core = $this;
$handler = function ($fullRoute) use ($core) {
return function (Request $request, Response $response) use ($fullRoute, $core) {
return $core->handle($fullRoute, $request, $response, $this);
};
};
foreach ($routes as $child => $route) {
if ($child[0] !== '/') {
$slim->map([strtoupper($child)], $path, $handler($prefix . $route));
continue;
}
$fullPath = $path . $child;
if (is_string($route)) {
$slim->get($fullPath, $handler($prefix . $route));
continue;
} else {
$this->processRoute($fullPath, $route, $prefix);
}
}
}
/**
* @return App
*/
public function getSlim()
{
return $this->get('slim');
}
/**
* @param UriInterface $uri
* @return string
*/
private function getBaseUrlFromUri(UriInterface $uri) {
$baseUrl = $uri->getScheme() . '://' . $uri->getHost();
if (($uri->getScheme() === 'http' && $uri->getPort() != 80) ||
($uri->getScheme() === 'https' && $uri->getPort() != 443)) {
$baseUrl .= ':' . $uri->getPort();
}
return $baseUrl;
}
/**
* @param string $class
* @param Request $request
* @param Response $response
* @param ContainerInterface $containerInterface
* @return Response
*/
public function handle($class, Request $request, Response $response, ContainerInterface $containerInterface)
{
$this->startTimer(['response']);
/** set host */
$this->set('base-url', $this->getBaseUrlFromUri($request->getUri()));
/** @var Handler\Main $handler */
$handler = new $class($this, $request, $response, $containerInterface);
$this->startTimer(['response/before-handle']);
$result = $handler->beforeHandle();
if ($result instanceof Response) {
$this->endTimer(['response']);
return $result;
}
$this->startTimer(['response/handle']);
$response = $handler->handle();
$this->endTimer(['response/handle']);
$this->endTimer(['response']);
return $response;
}
/**
* @param App $slim
*/
public function setSlim($slim)
{
$this->set('slim', $slim);
}
/**
* @param \Twig_Environment $twig
*/
public function setTwig($twig)
{
$this->set('twig', $twig);
}
public function run()
{
$this->getSlim()->run();
}
}