diff --git a/lib/Alchemy/Phrasea/Core.php b/lib/Alchemy/Phrasea/Core.php index afb1555b3d..670a6b6806 100644 --- a/lib/Alchemy/Phrasea/Core.php +++ b/lib/Alchemy/Phrasea/Core.php @@ -58,7 +58,7 @@ class Core extends \Pimple $conf = $this->conf; $this['EM'] = $this->share(function() use ($conf) { - $doctrine = new Core\Service\Doctrine($conf->getDoctrineConf()); + $doctrine = new Core\Service\Doctrine($conf->getDoctrine()); return $doctrine->getEntityManager(); }); diff --git a/lib/Alchemy/Phrasea/Core/Configuration.php b/lib/Alchemy/Phrasea/Core/Configuration.php index 2d2ad729bc..b5019f4ae4 100644 --- a/lib/Alchemy/Phrasea/Core/Configuration.php +++ b/lib/Alchemy/Phrasea/Core/Configuration.php @@ -11,6 +11,9 @@ namespace Alchemy\Phrasea\Core; +use Alchemy\Phrasea\Core\Configuration\Application; +use Alchemy\Phrasea\Core\Configuration\Parser as ConfigurationParser; + /** * Handle configuration file mechanism of phraseanet * @@ -20,25 +23,43 @@ namespace Alchemy\Phrasea\Core; */ class Configuration { - const MAIN_ENV_NAME = "main"; - + /** * The environnment name * @var string */ protected $environnement; - + /** - * The configuration + * The finale configuration values as an array * @var Array */ - protected $configuration; - + protected $configuration = array(); + /** * Tell if appli is currently installed * @var boolean */ - protected $installed; + protected $installed = false; + + /** + * Class that take care of configuration process + * @var Configuration\Handler + */ + private $configurationHandler; + + /** + * Class that take care of configuration specification + * like filepath, extends keywords etc .. + * @var Configuration\Specification + */ + private $configurationSpecification; + + /** + * Class that take care of parsing configuration file + * @var Configuration\Parser + */ + private $configurationParser; /** * @@ -46,28 +67,61 @@ class Configuration */ public function __construct($envName) { - //check whether the main configuration file is present on disk - try - { - $specifications = new Configuration\PhraseaConfiguration(); - - $parser = new Configuration\Parser\Yaml(); - - $specifications->getConfFileFromEnvName(self::MAIN_ENV_NAME); - - $this->installed = true; - - $this->environnement = $envName; - - $confHandler = new Configuration\EnvironnementHandler($specifications, $parser); - - $this->configuration = $confHandler->handle($envName); - } - catch(\Exception $e) - { - $this->installed = false; - } - + $this->init($envName); + } + + /** + * Getter + * @return Configuration\Handler + */ + public function getConfigurationHandler() + { + return $this->configurationHandler; + } + + /** + * Setter + * @param Configuration\Handler $configurationHandler + */ + public function setConfigurationHandler(Configuration\Handler $configurationHandler) + { + $this->configurationHandler = $configurationHandler; + } + + /** + * Getter + * @return Configuration\Specification + */ + public function getConfigurationSpecification() + { + return $this->configurationSpecification; + } + + /** + * Setter + * @param Configuration\Specification $configurationSpecification + */ + public function setConfigurationSpecification(Configuration\Specification $configurationSpecification) + { + $this->configurationSpecification = $configurationSpecification; + } + + /** + * Getter + * @return Configuration\Parser + */ + public function getConfigurationParser() + { + return $this->configurationParser; + } + + /** + * Setter + * @param type $configurationParser + */ + public function setConfigurationParser($configurationParser) + { + $this->configurationParser = $configurationParser; } /** @@ -85,9 +139,52 @@ class Configuration * * @return Array */ - public function getDbalConf() + public function getDoctrine() { - return (array) $this->configuration['doctrine']['dbal'] ?: null; + $doctrine = $this->get('doctrine'); //get doctrine scope + + if (null !== $doctrine) + { + $doctrine["debug"] = $this->isDebug(); //set debug + + if (!!$doctrine["log"]['enable']) + { + $logger = $doctrine["log"]["type"]; + + if (!in_array($doctrine["log"]["type"], $this->getAvailableLogger())) + { + throw new \Exception(sprintf('Unknow logger %s', $logger)); + } + + $doctrineLogger = $this->get($logger); //set logger + + $doctrine["logger"] = $doctrineLogger; + } + } + + return null === $doctrine ? array() : $doctrine; + } + + /** + * Check if current environnement is on debug mode + * Default to false + * @return boolean + */ + public function isDebug() + { + $phraseanet = $this->getPhraseanet(); + return isset($phraseanet["debug"]) ? !!$phraseanet["debug"] : false; + } + + /** + * Return the phraseanet scope configurations values + * + * @return Array|null + */ + public function getPhraseanet() + { + $phraseanet = $this->get('phraseanet'); + return null === $phraseanet ? array() : $phraseanet; } /** @@ -100,13 +197,21 @@ class Configuration return $this->installed; } - public function get($key) + /** + * Check if key exist in final configuration if yes it returns the value else + * it returns null + * + * @param type $key + * @return Array|null + */ + private function get($key) { - return isset($this->configuration[$key]) ? $this->configuration[$key]: null; + return isset($this->configuration[$key]) ? $this->configuration[$key] : null; } - + /** * Return the configuration + * * @return Array|null */ public function getConfiguration() @@ -114,5 +219,61 @@ class Configuration return $this->configuration; } + /** + * Return Available logger + * + * @return Array + */ + private function getAvailableLogger() + { + return array('echo', 'monolog'); + } + + /** + * Return configurationFilePAth + * @return string + */ + public function getConfigurationFilePath() + { + return __DIR__ . '/../../../../config'; + } + + /** + * Return configurationFileName + * @return string + */ + public function getConfigurationFileName() + { + return 'config.yml'; + } + + /** + * Init object + * Called in constructor + */ + private function init($envName) + { + $filePath = $this->getConfigurationFilePath(); + $fileName = $this->getConfigurationFileName(); + + try + { + new \SplFileObject(sprintf("%s/%s", $filePath, $fileName)); + + $this->installed = true; + } + catch (\Exception $e) + { + + } + + $this->environnement = $envName; + + if ($this->installed) + { + $confHandler = new Configuration\Handler(new Application(), new ConfigurationParser\Yaml()); + $this->configuration = $confHandler->handle($envName); + } + } } \ No newline at end of file diff --git a/lib/Alchemy/Phrasea/Core/Configuration/PhraseaConfiguration.php b/lib/Alchemy/Phrasea/Core/Configuration/Application.php similarity index 80% rename from lib/Alchemy/Phrasea/Core/Configuration/PhraseaConfiguration.php rename to lib/Alchemy/Phrasea/Core/Configuration/Application.php index 204d6547cd..5625552aea 100644 --- a/lib/Alchemy/Phrasea/Core/Configuration/PhraseaConfiguration.php +++ b/lib/Alchemy/Phrasea/Core/Configuration/Application.php @@ -18,7 +18,7 @@ namespace Alchemy\Phrasea\Core\Configuration; * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ -class PhraseaConfiguration implements ConfigurationSpecification +class Application implements Specification { /** @@ -38,7 +38,12 @@ class PhraseaConfiguration implements ConfigurationSpecification */ public function getConfFileFromEnvName($name) { - return new \SplFileObject(sprintf("/%s/config_%s.%s" + if($name === self::EXTENDED_MAIN_KEYWORD) + { + return $this->getMainFile(); + } + + return new \SplFileObject(sprintf("%s/config_%s.%s" , $this->getConfigurationFilePath() , $name , $this->getConfFileExtension()) @@ -53,6 +58,12 @@ class PhraseaConfiguration implements ConfigurationSpecification { return __DIR__ . '/../../../../../config'; } + + public function getMainFile() + { + $path = __DIR__ . '/../../../../../config/config.yml'; + return new \SplFileObject($path); + } /** * diff --git a/lib/Alchemy/Phrasea/Core/Configuration/EnvironnementHandler.php b/lib/Alchemy/Phrasea/Core/Configuration/Handler.php similarity index 96% rename from lib/Alchemy/Phrasea/Core/Configuration/EnvironnementHandler.php rename to lib/Alchemy/Phrasea/Core/Configuration/Handler.php index 3bee323db5..6ca9182a86 100644 --- a/lib/Alchemy/Phrasea/Core/Configuration/EnvironnementHandler.php +++ b/lib/Alchemy/Phrasea/Core/Configuration/Handler.php @@ -20,7 +20,7 @@ use \Symfony\Component\Yaml\Yaml; * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ -class EnvironnementHandler +class Handler { /** * Configuration file specification interface @@ -40,7 +40,7 @@ class EnvironnementHandler * @param ConfigurationSpecification $configSpec * @param Parser\ParserInterface $parser */ - public function __construct(ConfigurationSpecification $configSpec, Parser\ParserInterface $parser) + public function __construct(Application $configSpec, Parser $parser) { $this->confSpecification = $configSpec; $this->parser = $parser; @@ -74,7 +74,7 @@ class EnvironnementHandler } catch (\Exception $e) { - throw \Exception(sprintf("filename %s not found", $file->getPathname())); + throw new \Exception(sprintf("filename %s not found", $file->getPathname())); } } else diff --git a/lib/Alchemy/Phrasea/Core/Configuration/Parser/ParserInterface.php b/lib/Alchemy/Phrasea/Core/Configuration/Parser.php similarity index 87% rename from lib/Alchemy/Phrasea/Core/Configuration/Parser/ParserInterface.php rename to lib/Alchemy/Phrasea/Core/Configuration/Parser.php index 441c51c885..f55c69131c 100644 --- a/lib/Alchemy/Phrasea/Core/Configuration/Parser/ParserInterface.php +++ b/lib/Alchemy/Phrasea/Core/Configuration/Parser.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Alchemy\Phrasea\Core\Configuration\Parser; +namespace Alchemy\Phrasea\Core\Configuration; /** * A interface to parse configuration file @@ -18,7 +18,7 @@ namespace Alchemy\Phrasea\Core\Configuration\Parser; * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ -interface ParserInterface +interface Parser { /** * Parse the configuration file $file to an array diff --git a/lib/Alchemy/Phrasea/Core/Configuration/Parser/Yaml.php b/lib/Alchemy/Phrasea/Core/Configuration/Parser/Yaml.php index 4d3feb0958..d461022d50 100644 --- a/lib/Alchemy/Phrasea/Core/Configuration/Parser/Yaml.php +++ b/lib/Alchemy/Phrasea/Core/Configuration/Parser/Yaml.php @@ -19,7 +19,7 @@ use Symfony\Component\Yaml\Yaml as SfYaml; * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ -class Yaml implements ParserInterface +class Yaml implements \Alchemy\Phrasea\Core\Configuration\Parser { /** * diff --git a/lib/Alchemy/Phrasea/Core/Configuration/ConfigurationSpecification.php b/lib/Alchemy/Phrasea/Core/Configuration/Specification.php similarity index 94% rename from lib/Alchemy/Phrasea/Core/Configuration/ConfigurationSpecification.php rename to lib/Alchemy/Phrasea/Core/Configuration/Specification.php index ab25fa1f34..7f241a7893 100644 --- a/lib/Alchemy/Phrasea/Core/Configuration/ConfigurationSpecification.php +++ b/lib/Alchemy/Phrasea/Core/Configuration/Specification.php @@ -18,12 +18,16 @@ namespace Alchemy\Phrasea\Core\Configuration; * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ -interface ConfigurationSpecification +interface Specification { /** * Keywords to detect extended file */ const EXTENDED_KEYWORD = 'extends'; + /** + * Keywords to detect main file + */ + const EXTENDED_MAIN_KEYWORD = 'main'; /** * Return an array of paths that CAN'T be extended by ONLY one or more of their value diff --git a/lib/Alchemy/Phrasea/Core/Service/Doctrine.php b/lib/Alchemy/Phrasea/Core/Service/Doctrine.php index 425f9dc874..af0e432c1c 100644 --- a/lib/Alchemy/Phrasea/Core/Service/Doctrine.php +++ b/lib/Alchemy/Phrasea/Core/Service/Doctrine.php @@ -9,7 +9,6 @@ * file that was distributed with this source code. */ - namespace Alchemy\Phrasea\Core\Service; use Doctrine\DBAL\Types\Type; @@ -22,19 +21,135 @@ use Doctrine\DBAL\Types\Type; */ class Doctrine { + const MEMCACHED = 'memcached'; + const ARRAYCACHE = 'array'; + const APC = 'apc'; protected $entityManager; - public function __construct() + public function __construct(Array $doctrineConfiguration) { - require_once __DIR__ . '/../../../../vendor/doctrine2-orm/lib/vendor/doctrine-common/lib/Doctrine/Common/ClassLoader.php'; static::loadClasses(); $config = new \Doctrine\ORM\Configuration(); - $config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache); + //debug mode + $debug = isset($doctrineConfiguration["debug"]) ? : false; + //doctrine cache + $cache = !isset($doctrineConfiguration["orm"]["cache"]) ? : $doctrineConfiguration["orm"]["cache"]; + //doctrine log configuration + $log = isset($doctrineConfiguration["log"]) ? !!$doctrineConfiguration["log"] : false; + $logEnable = isset($log["enable"]) ? : !!$log["enable"]; + //service logger configuration + $logger = !isset($doctrineConfiguration['logger']) ? : $doctrineConfiguration['logger']; + + //default query cache & meta chache + $metaCache = $this->getCache(); + $queryCache = $this->getCache(); + + //handle cache + if ($cache && !$debug) + { + //define query cache + $cacheName = isset($cache["query"]) ? $cache["query"] : self::ARRAYCACHE; + $queryCache = $this->getCache($cacheName); + + //define metadatas cache + $cacheName = isset($cache["metadata"]) ? $cache["metadata"] : self::ARRAYCACHE; + $metaCache = $this->getCache($cacheName); + } + + //Handle logs + if ($logEnable) + { + $loggerService = isset($log["type"]) ? $log["type"] : ''; + + switch ($loggerService) + { + case 'monolog': + //defaut to main handler + $doctrineHandler = isset($log["handler"]) ? $log["handler"] : 'main'; + + if(!isset($logger["handlers"])) + { + throw new \Exception("You must specify at least on monolog handler"); + } + + if (!array_key_exists($doctrineHandler, $logger["handlers"])) + { + throw new \Exception(sprintf('Unknow monolog handler %s'), $handlerType); + } + + $handlerName = ucfirst($logger["handlers"][$doctrineHandler]["type"]); + + $handlerClassName = sprintf('\Monolog\Handler\%sHandler', $handlerName); + + if (!class_exists($handlerClassName)) + { + throw new \Exception(sprintf('Unknow monolog handler class %s', $handlerClassName)); + } + + if (!isset($log["filename"])) + { + throw new \Exception('you must specify a file to write "filename: my_filename"'); + } + + $logPath = __DIR__ . '/../../../../../logs'; + $file = sprintf('%s/%s', $logPath, $log["filename"]); + + if ($doctrineHandler == 'rotate') + { + $maxDay = isset($log["max_day"]) ? (int) $log["max_day"] : (int) $logger["max_day"]; + + $handlerInstance = new $handlerClassName($file, $maxDay); + } + else + { + $handlerInstance = new $handlerClassName($file); + } + + $monologLogger = new \Monolog\Logger('query-logger'); + $monologLogger->pushHandler($handlerInstance); + + if (isset($log["output"])) + { + $output = $log["output"]; + } + elseif (isset($logger["output"])) + { + $output = $logger["output"]; + } + else + { + $output = null; + } + + if (null === $output) + { + $sqlLogger = new \Doctrine\Logger\MonologSQLLogger($monologLogger); + } + else + { + $sqlLogger = new \Doctrine\Logger\MonologSQLLogger($monologLogger, $output); + } + + $config->setSQLLogger($sqlLogger); + break; + case 'echo': + default: + $config->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + break; + } + } + + //set caches + $config->setMetadataCacheImpl($metaCache); + $config->setQueryCacheImpl($queryCache); + + //define autoregeneration of proxies base on debug mode + $config->setAutoGenerateProxyClasses($debug); $chainDriverImpl = new \Doctrine\ORM\Mapping\Driver\DriverChain(); @@ -52,24 +167,31 @@ class Doctrine $config->setProxyNamespace('Proxies'); - require __DIR__ . '/../../../../../config/connexion.inc'; + $dbalConf = isset($doctrineConfiguration["dbal"]) ? $doctrineConfiguration["dbal"] : false; - $connectionOptions = array( - 'dbname' => $dbname, - 'user' => $user, - 'password' => $password, - 'host' => $hostname, - 'driver' => 'pdo_mysql', - ); + if (!$dbalConf) + { +// throw new Exception("Unable to read dbal configuration"); + + require __DIR__ . '/../../../../../config/connexion.inc'; + + $dbalConf = array( + 'dbname' => $dbname, + 'user' => $user, + 'password' => $password, + 'host' => $hostname, + 'driver' => 'pdo_mysql', + ); + } $evm = new \Doctrine\Common\EventManager(); $evm->addEventSubscriber(new \Gedmo\Timestampable\TimestampableListener()); - $this->entityManager = \Doctrine\ORM\EntityManager::create($connectionOptions, $config, $evm); - + $this->entityManager = \Doctrine\ORM\EntityManager::create($dbalConf, $config, $evm); + $this->addTypes(); - + return $this; } @@ -77,7 +199,7 @@ class Doctrine { return $this->entityManager; } - + public function getVersion() { return \Doctrine\Common\Version::VERSION; @@ -98,6 +220,18 @@ class Doctrine ); $classLoader->register(); + $classLoader = new \Doctrine\Common\ClassLoader( + 'Doctrine\Common\DataFixtures' + , realpath(__DIR__ . '/../../../../vendor/data-fixtures/lib') + ); + $classLoader->register(); + + $classLoader = new \Doctrine\Common\ClassLoader( + 'PhraseaFixture' + , realpath(__DIR__ . '/../../../../conf.d/') + ); + $classLoader->register(); + $classLoader = new \Doctrine\Common\ClassLoader( 'Doctrine\Common' , realpath(__DIR__ . '/../../../../vendor/doctrine2-orm/lib/vendor/doctrine-common/lib') @@ -121,19 +255,33 @@ class Doctrine , realpath(__DIR__ . '/../../../../Doctrine') ); $classLoader->register(); - + $classLoader = new \Doctrine\Common\ClassLoader( 'Symfony' , realpath(__DIR__ . '/../../../../vendor/doctrine2-orm/lib/vendor') - ); - + ); + $classLoader->register(); - + + $classLoader = new \Doctrine\Common\ClassLoader( + 'Doctrine\Logger' + , realpath(__DIR__ . '/../../../../') + ); + + $classLoader->register(); + + $classLoader = new \Doctrine\Common\ClassLoader( + 'Monolog' + , realpath(__DIR__ . '/../../../../vendor/Silex/vendor/monolog/src') + ); + + $classLoader->register(); + $classLoader = new \Doctrine\Common\ClassLoader( 'Types' , realpath(__DIR__ . '/../../../../Doctrine') - ); - + ); + $classLoader->register(); $classLoader = new \Doctrine\Common\ClassLoader( @@ -145,23 +293,47 @@ class Doctrine return; } - + protected function addTypes() { - + $platform = $this->entityManager->getConnection()->getDatabasePlatform(); - + Type::addType('blob', 'Types\Blob'); Type::addType('enum', 'Types\Enum'); Type::addType('longblob', 'Types\LongBlob'); Type::addType('varbinary', 'Types\VarBinary'); - + $platform->registerDoctrineTypeMapping('enum', 'enum'); $platform->registerDoctrineTypeMapping('blob', 'blob'); $platform->registerDoctrineTypeMapping('longblob', 'longblob'); $platform->registerDoctrineTypeMapping('varbinary', 'varbinary'); - + return; } + /** + * Return a cache object according to the $name + * + * @param type $cacheName + */ + private function getCache($cacheName = self::ARRAYCACHE) + { + switch ($cacheName) + { + case self::MEMCACHED: + $cache = new \Doctrine\Common\Cache\MemcacheCache(); + break; + case self::APC: + $cache = new \Doctrine\Common\Cache\ApcCache(); + break; + case self::ARRAYCACHE: + default: + $cache = new \Doctrine\Common\Cache\ArrayCache(); + break; + } + + return $cache; + } + } \ No newline at end of file