Files
core/src/Bootstrap.php
T

198 lines
6.1 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
};
/**
* The entry point for constructing a properly configured LotGD Game object.
*/
class Bootstrap
{
private $logger;
private $game;
private $libraryConfigurationManager = [];
private $annotationDirectories = [];
/**
* Create a new Game object, with all the necessary configuration.
* @param string $cwd
* @return Game The newly created Game object.
*/
public static function createGame(string $cwd = null): Game
{
$game = new self();
$cwd = $cwd ?? getcwd();
return $game->getGame($cwd);
}
/**
* Starts the game kernel with the most important classes and returns the object
* @param string $cwd
* @return Game
*/
public function getGame(string $cwd): Game
{
$config = $this->createConfiguration($cwd);
$this->logger = $this->createLogger($config, "lotgd");
$v = Game::getVersion();
$this->logger->info("Bootstrap (Daenerys 🐲{$v}).");
$composer = $this->createComposerManager($cwd);
$this->libraryConfigurationManager = $this->createLibraryConfigurationManager($composer, $cwd);
list($dsn, $user, $password) = $config->getDatabaseConnectionDetails($cwd);
$pdo = $this->connectToDatabase($dsn, $user, $password);
$entityManager = $this->createEntityManager($pdo);
$this->game = new Game($config, $this->logger, $entityManager, $cwd);
return $this->game;
}
/**
* Creates a library configuration manager
* @param ComposerManager $composerManager
* @param string $cwd
* @return \LotGD\Core\LibraryConfigurationManager
*/
protected function createLibraryConfigurationManager(
ComposerManager $composerManager,
string $cwd
): LibraryConfigurationManager {
return new LibraryConfigurationManager($composerManager, $cwd);
}
/**
* Connects to a database using pdo
* @param \LotGD\Core\Configuration $config
* @return \PDO
*/
protected function connectToDatabase(string $dsn, string $user, string $password): \PDO
{
return new \PDO($dsn, $user, $password);
}
/**
* Creates and returns an instance of ComposerManager
* @param string $cwd
* @return ComposerManager
*/
protected function createComposerManager(string $cwd): ComposerManager
{
$composer = new ComposerManager($cwd);
return $composer;
}
/**
* Returns a configuration object reading from the file located at the path stored in $cwd/config/lotgd.yml.
* @param string $cwd
* @return \LotGD\Core\Configuration
* @throws InvalidConfigurationException
*/
protected function createConfiguration(string $cwd): Configuration
{
if (empty($configFilePath)) {
$configFilePath = implode(DIRECTORY_SEPARATOR, [$cwd, "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);
return $config;
}
/**
* Returns a logger instance
* @param Configuration $config
* @param string $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));
return $logger;
}
/**
* 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();
$this->logger->addDebug("Adding annotation directories:");
foreach ($this->annotationDirectories as $d) {
$this->logger->addDebug(" {$d}");
}
$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.
* @return array
*/
protected function generateAnnotationDirectories(): array
{
// Read db annotations from our own model files.
$directories = [__DIR__ . DIRECTORY_SEPARATOR . 'Models'];
// Get additional annotation directories from library configs.
$libraryDirectories = $this->libraryConfigurationManager->getEntityDirectories();
return array_merge($directories, $libraryDirectories);
}
/**
* Adds Symfony/Console commands to the provided application from configured libraries.
* @param Application $application
*/
public function addDaenerysCommands(Application $application)
{
foreach ($this->libraryConfigurationManager->getConfigurations() as $config) {
$commands = $config->getDaenerysCommands();
foreach ($commands as $command) {
$application->add(new $command($this->game));
}
}
}
}