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.
239 lines
6.2 KiB
PHP
239 lines
6.2 KiB
PHP
<?php
|
|
|
|
namespace BitCommunism\Marx;
|
|
|
|
use DI\Container;
|
|
use DI\ContainerBuilder;
|
|
use function DI\value;
|
|
use Doctrine\ORM\Tools\Console\ConsoleRunner;
|
|
use FastRoute\Dispatcher;
|
|
use FastRoute\RouteCollector;
|
|
use function FastRoute\simpleDispatcher;
|
|
use function GuzzleHttp\Psr7\copy_to_stream;
|
|
use GuzzleHttp\Psr7\Response;
|
|
use GuzzleHttp\Psr7\ServerRequest;
|
|
use function GuzzleHttp\Psr7\stream_for;
|
|
use Psr\Http\Message\ResponseInterface;
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
|
|
class Instance
|
|
{
|
|
const CONFIG_PATH = '%s/config/%s.php';
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected $directory;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected $environment;
|
|
|
|
/**
|
|
* @var Container
|
|
*/
|
|
protected $container;
|
|
|
|
/**
|
|
* @var string[]
|
|
*/
|
|
protected $modules = [];
|
|
|
|
/**
|
|
* @var Dispatcher
|
|
*/
|
|
protected $router;
|
|
|
|
/**
|
|
* @var \Closure[]
|
|
*/
|
|
protected $calls = [];
|
|
|
|
protected $knownCalls = [
|
|
'doctrine' => 'doctrine',
|
|
'cli' => 'cli',
|
|
'http' => 'http',
|
|
];
|
|
|
|
public static function create($directory, $environment = 'development', $overrideConfig = []): Instance
|
|
{
|
|
$realDir = realpath($directory);
|
|
|
|
if (file_exists($realDir . '/vendor/autoload.php')) {
|
|
include_once $directory . '/vendor/autoload.php';
|
|
}
|
|
|
|
if ($environment === 'dev') {
|
|
$environment = 'development';
|
|
}
|
|
|
|
if ($environment === 'prod') {
|
|
$environment = 'production';
|
|
}
|
|
|
|
$instance = new Instance(realpath($realDir), $environment);
|
|
$instance->load($overrideConfig);
|
|
|
|
return $instance;
|
|
}
|
|
|
|
public function __construct($directory, $environment = 'development')
|
|
{
|
|
$this->directory = $directory;
|
|
$this->environment = $environment;
|
|
}
|
|
|
|
public function load($overrideConfig = [])
|
|
{
|
|
$container = $this->buildTemporaryContainer($overrideConfig);
|
|
$this->buildContainer($container->get('modules'), $overrideConfig);
|
|
|
|
$this->registerCalls();
|
|
$this->runLoaders();
|
|
}
|
|
|
|
protected function registerCalls() {
|
|
$calls = $this->container->get('marx.calls');
|
|
|
|
foreach ($calls as $name => $call) {
|
|
$this->register($name, function (...$arguments) use ($call) {
|
|
return $this->container->call($call, [
|
|
'arguments' => $arguments
|
|
]);
|
|
});
|
|
}
|
|
}
|
|
|
|
protected function runLoaders() {
|
|
$loaders = $this->container->get('marx.loaders');
|
|
|
|
foreach ($loaders as $loader) {
|
|
$this->container->call($loader);
|
|
}
|
|
}
|
|
|
|
protected function loadModules($modules, ContainerBuilder $builder) {
|
|
$directories = [];
|
|
|
|
$loadedModules = [];
|
|
|
|
foreach ($modules as $module) {
|
|
if (strpos($module, '/') === false) {
|
|
$module = 'bitcommunism/' . $module;
|
|
}
|
|
|
|
$directory = $this->directory;
|
|
$modulePath = $directory . '/vendor/' . $module;
|
|
|
|
if (!is_dir($modulePath)) {
|
|
$stderr = fopen('php://stderr', 'w+');
|
|
fwrite($stderr, "Warning: Module '{$module}' doesn't exist, did you install it? e.g.:\n\n\tcomposer require {$module}\n\n");
|
|
// fclose($stderr);
|
|
}
|
|
|
|
$directories[] = $modulePath;
|
|
$loadedModules[$module] = true;
|
|
}
|
|
|
|
$builder->addDefinitions($loadedModules);
|
|
|
|
$this->loadDefinitions($builder, $directories);
|
|
}
|
|
|
|
public function register($name, $callback) {
|
|
$this->calls[$name] = $callback;
|
|
}
|
|
|
|
public function __call($name, $arguments)
|
|
{
|
|
if (!isset($this->calls[$name])) {
|
|
if (isset($this->knownCalls[$name])) {
|
|
throw new \Exception("No call {$name} found, did you install and enable the {$this->knownCalls[$name]} module?");
|
|
}
|
|
|
|
throw new \Exception("No call {$name} found. are you missing a module?");
|
|
}
|
|
|
|
return $this->calls[$name](...$arguments);
|
|
}
|
|
|
|
|
|
private function buildTemporaryContainer($overrideConfig = []) {
|
|
$builder = new ContainerBuilder();
|
|
|
|
$builder->addDefinitions([
|
|
'basedir' => $this->directory,
|
|
]);
|
|
|
|
$this->loadDefinitions($builder, [__DIR__ . '/..', $this->directory]);
|
|
|
|
$builder->addDefinitions($overrideConfig);
|
|
|
|
return $builder->build();
|
|
}
|
|
|
|
private function loadDefinitions(ContainerBuilder $builder, $directories = []) {
|
|
$configTypes = ['default', 'routes', $this->environment];
|
|
|
|
foreach ($directories as $directory) {
|
|
foreach ($configTypes as $configType) {
|
|
$configPath = sprintf(self::CONFIG_PATH, $directory, $configType);
|
|
if (!file_exists($configPath)) {
|
|
continue;
|
|
}
|
|
try {
|
|
$config = include($configPath);
|
|
} catch (\Throwable $e) {
|
|
// Failed loading config
|
|
|
|
continue;
|
|
}
|
|
|
|
if ($configType === 'routes') {
|
|
// Routes needs to be put in 'routes'
|
|
$config = [
|
|
'routes' => $config,
|
|
];
|
|
}
|
|
|
|
if (!is_array($config)) {
|
|
continue;
|
|
}
|
|
|
|
$builder->addDefinitions($config);
|
|
}
|
|
}
|
|
}
|
|
|
|
private function buildContainer($modules, $overrideConfig = [])
|
|
{
|
|
$builder = new ContainerBuilder();
|
|
|
|
$builder->addDefinitions([
|
|
'basedir' => $this->directory,
|
|
'marx.instance' => value($this),
|
|
self::class => $this,
|
|
]);
|
|
|
|
$this->loadDefinitions($builder, [__DIR__ . '/..']);
|
|
$this->loadModules($modules, $builder);
|
|
$this->loadDefinitions($builder, [$this->directory]);
|
|
|
|
$builder->addDefinitions($overrideConfig);
|
|
|
|
$this->container = $builder->build();
|
|
}
|
|
|
|
public function has(string $key): bool {
|
|
return $this->container->has($key);
|
|
}
|
|
|
|
public function get(string $key, $default = null) {
|
|
if (!$this->container->has($key)) {
|
|
return $default;
|
|
}
|
|
|
|
return $this->container->get($key);
|
|
}
|
|
} |