OpenXE/classes/Core/Installer/Installer.php
2021-05-21 08:49:41 +02:00

237 lines
6.1 KiB
PHP

<?php
namespace Xentral\Core\Installer;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RegexIterator;
use RuntimeException;
use Xentral\Components\SchemaCreator\Collection\SchemaCollection;
final class Installer
{
/** @var ClassMapGenerator $classMapGenerator */
private $classMapGenerator;
/** @var Psr4ClassNameResolver $classNameResolver */
private $classNameResolver;
/** @var array $classMap */
private $classMap = [];
/** @var array $bootstrapClasses */
private $bootstrapClasses = [];
/** @var array */
private $services = [];
/** @var array $javascript */
private $javascript = [];
/** @var string $classDir */
private $classDir;
/**
* @param ClassMapGenerator $generator
*/
public function __construct(ClassMapGenerator $generator, Psr4ClassNameResolver $resolver)
{
$this->classMapGenerator = $generator;
$this->classNameResolver = $resolver;
$this->classDir = dirname(dirname(__DIR__));
}
/**
* @return array
*/
public function getClassMap()
{
if (!empty($this->classMap)) {
return $this->classMap;
}
$this->classMap = $this->classMapGenerator->generate($this->classDir);
return $this->classMap;
}
/**
* @return array
*/
public function getServices()
{
if (!empty($this->services)) {
return $this->services;
}
$classNames = $this->getBootstrapClassNames();
foreach ($classNames as $className) {
if (empty($className)) {
continue;
}
if (!class_exists($className, true)) {
$this->loadClass($className);
}
if (!method_exists($className, 'registerServices')) {
continue;
}
$services = forward_static_call([$className, 'registerServices']);
foreach ($services as $serviceName => $factoryMethod) {
$this->addServiceDefinition($serviceName, $className, $factoryMethod);
}
}
return $this->services;
}
/**
* @throws RuntimeException
*
* @return SchemaCollection
*/
public function getTableSchemas(): SchemaCollection
{
$schemaCollection = new SchemaCollection();
$classNames = $this->getBootstrapClassNames();
foreach ($classNames as $className) {
if (empty($className)) {
continue;
}
if (!class_exists($className, true)) {
$this->loadClass($className);
}
if (!method_exists($className, 'registerTableSchemas')) {
continue;
}
forward_static_call([$className, 'registerTableSchemas'], $schemaCollection);
}
return $schemaCollection;
}
/**
* @return array
*/
public function getJavascriptFiles()
{
$classNames = $this->getBootstrapClassNames();
foreach ($classNames as $className) {
if (!class_exists($className, true)) {
continue;
}
if (!method_exists($className, 'registerJavascript')) {
continue;
}
$javascript = forward_static_call([$className, 'registerJavascript']);
foreach ($javascript as $cacheName => $jsFiles) {
$this->addJavascriptDefinition($cacheName, $jsFiles);
}
}
return $this->javascript;
}
/**
* @return array Absolute paths to all bootstrap files
*/
private function getBootstrapFiles()
{
$directory = new RecursiveDirectoryIterator($this->classDir);
$iterator = new RecursiveIteratorIterator($directory);
$bootstraps = new RegexIterator($iterator, '/^.+Bootstrap\.php$/', RegexIterator::MATCH);
$files = [];
/** @var \SplFileInfo $bootstrap */
foreach ($bootstraps as $bootstrap) {
$files[] = $bootstrap->getRealPath();
}
return $files;
}
/**
* @return array FQCN of all bootstrap classes
*/
private function getBootstrapClassNames()
{
if (!empty($this->bootstrapClasses)) {
return $this->bootstrapClasses;
}
$files = $this->getBootstrapFiles();
foreach ($files as $file) {
$className = $this->classNameResolver->resolveClassName($file);
if ($className === null) {
continue;
}
$this->bootstrapClasses[] = $className;
}
return $this->bootstrapClasses;
}
/**
* @param string $serviceName
* @param string $bootstrapClass
* @param string $factoryMethod
*
* @return void
*/
private function addServiceDefinition($serviceName, $bootstrapClass, $factoryMethod)
{
if (isset($this->services[$serviceName])) {
$registeredCallString = $this->services[$serviceName][0] . '::' . $this->services[$serviceName][1];
$failedCallString = $bootstrapClass . '::' . $factoryMethod;
throw new RuntimeException(sprintf(
'Service "%s" can not be registered. Name is already taken. Registered "%s" - Failed "%s"',
$serviceName, $registeredCallString, $failedCallString
));
}
$this->services[$serviceName] = [$bootstrapClass, $factoryMethod];
}
/**
* @param $cacheName
* @param $files
*
* @return void
*/
private function addJavascriptDefinition($cacheName, $files)
{
$this->javascript[$cacheName] = $files;
}
/**
* @param string $className
*
* @throws RuntimeException
*
* @return void
*/
private function loadClass($className)
{
if (empty($className)) {
return;
}
if (empty($this->classMap)) {
$this->getClassMap();
}
if (!isset($this->classMap[$className])) {
throw new RuntimeException(sprintf(
'Could not load class "%s"', $className
));
}
include $this->classMap[$className];
}
}