Files
core/src/Bootstrap.php
T
Vassyli 712a89bdad Changes for configuration file approach
Packages that are either of type lotgd-crate or lotgd-module can add daenerys commands and doctrine entity directories by using a lotgd.yml configuration file in their directory root (the same one were composer.json is).

All namespaces given in lotgd.yml have to be relative to the packages namespace, without a leading backslash (\).

Root namespace is derived from composer.json, either explicitely (via extra.lotgd-namespace) or implicitely via the first psr-4 or the first psr-0 namespace.
2016-07-29 09:35:46 +02:00

234 lines
7.2 KiB
PHP

<?php
declare(strict_types=1);
namespace LotGD\Core;
use Doctrine\ORM\ {
EntityManager,
EntityManagerInterface,
Mapping\AnsiQuoteStrategy,
Tools\Setup,
Tools\SchemaTool
};
use Monolog\ {
Logger,
Handler\RotatingFileHandler
};
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Application;
use LotGD\Core\ {
ComposerManager,
BootstrapInterface,
Exceptions\InvalidConfigurationException
};
class Bootstrap
{
private $rootDir;
private $game;
private $bootConfigurationManager = [];
private $annotationDirectories = [];
/**
* Create a new Game object, with all the necessary configuration.
* @return Game The newly created Game object.
*/
public static function createGame(): Game
{
$game = new self();
return $game->getGame();
}
/**
* Starts the game kernel with the most important classes and returns the object
* @return Game
*/
public function getGame(string $rootDir = null): Game
{
$this->rootDir = $rootDir ?? getcwd();
$composer = $this->createComposerManager();
$this->bootConfigurationManager = $this->createBootConfigurationManager($composer, $this->rootDir);
$config = $this->createConfiguration();
$logger = $this->createLogger($config, "lotgd");
$pdo = $this->connectToDatabase($config);
$entityManager = $this->createEntityManager($pdo);
$eventManager = $this->createEventManager($entityManager);
$this->game = new Game($config, $logger, $entityManager, $eventManager);
return $this->game;
}
public function createBootConfigurationManager(
ComposerManager $composerManager,
string $cwd
): BootConfigurationManager {
return new BootConfigurationManager($composerManager, $cwd);
}
/**
* Connects to a database using pdo
* @param \LotGD\Core\Configuration $config
* @return \PDO
*/
protected function connectToDatabase(Configuration $config): \PDO
{
return new \PDO($config->getDatabaseDSN(), $config->getDatabaseUser(), $config->getDatabasePassword());
}
/**
* Creates and returns an instance of ComposerManager
* @param Logger $logger
* @return ComposerManager
*/
protected function createComposerManager(): ComposerManager
{
$composer = new ComposerManager();
return $composer;
}
/**
* Returns all bootstrap classes
* @param ComposerManager $composer
* @return array
* @throws \Exception
*/
protected function initPackageBootstraps(ComposerManager $composer): array
{
$packages = $composer->getPackages();
$classes = [];
foreach ($packages as $package) {
if (isset($package->getExtra()["lotgd-namespace"]) === false) {
continue;
}
$cn = $package->getExtra()["lotgd-namespace"] . "Bootstrap";
// silently ignore that class does not exist, could be one that doesn't need to bootstrap
if (class_exists($cn, true) === false) {
continue;
}
$cl = new $cn();
if ($cl instanceof BootstrapInterface) {
$classes[] = $cl;
}
else {
$name = $package->getName() . "@" . $package->getVersion();
throw new \Exception("Package {$name} does not implement BootstrapInterface in it's Bootstrap class");
}
}
return $classes;
}
/**
* Returns a configuration object reading from the file located at the path stored in LOTGD_CONFIG.
* @return \LotGD\Core\Configuration
* @throws InvalidConfigurationException
*/
protected function createConfiguration(): Configuration
{
$configFilePath = getenv('LOTGD_CONFIG') ?? "/config/lotgd.yml";
if ($configFilePath === false || strlen($configFilePath) == 0 || is_file($configFilePath) === false) {
throw new InvalidConfigurationException("Invalid or missing configuration file: {$configFilePath}.");
}
$config = new Configuration($configFilePath, $this->rootDir);
return $config;
}
/**
* Returns a logger instance
* @param type $name
* @return LoggerInterface
*/
protected function createLogger(Configuration $config, string $name): LoggerInterface
{
$logger = new Logger($name);
// Add lotgd as the prefix for the log filenames.
$logger->pushHandler(new RotatingFileHandler($config->getLogPath() . DIRECTORY_SEPARATOR . $name, 14));
$v = Game::getVersion();
$logger->info("Bootstrap constructing game (Daenerys 🐲{$v}).");
return $logger;
}
/**
* Creates and returns an instance of the EventManager
* @param EntityManagerInterface $entityManager
* @return \LotGD\Core\EventManager
*/
protected function createEventManager(EntityManagerInterface $entityManager): EventManager
{
return new EventManager($entityManager);
}
/**
* Creates the EntityManager using the pdo connection given in it's argument
* @param \PDO $pdo
* @return EntityManagerInterface
*/
protected function createEntityManager(\PDO $pdo): EntityManagerInterface
{
$this->annotationDirectories = $this->generateAnnotationDirectories();
$configuration = Setup::createAnnotationMetadataConfiguration($this->annotationDirectories, true);
// Set a quote
$configuration->setQuoteStrategy(new AnsiQuoteStrategy());
// Create entity manager
$entityManager = EntityManager::create(["pdo" => $pdo], $configuration);
// Create Schema and update database if needed
$metaData = $entityManager->getMetadataFactory()->getAllMetadata();
$schemaTool = new SchemaTool($entityManager);
$schemaTool->updateSchema($metaData);
return $entityManager;
}
/**
* Is used to get all directories used to generate annotations.
* @param array $bootstrapClasses
* @return array
*/
protected function generateAnnotationDirectories(): array
{
// Read db annotations from our own model files.
$directories = [__DIR__ . '/Models'];
// Get additional annotation directories from bootstrap classes
$packageDirectories = $this->bootConfigurationManager->getEntityDirectories();
return array_merge($directories, $packageDirectories);
}
/**
* Return all directories used for reading annotations.
* @return array<string>
*/
public function getReadAnnotationDirectories(): array
{
return $this->annotationDirectories;
}
/**
* Adds console commands to a given console application from bootstrapping packages.
* @param Application $application
*/
public function addDaenerysCommands(Application $application)
{
$this->bootConfigurationManager->addDaenerysCommands($this->game, $application);
}
}