diff --git a/lib/Alchemy/Phrasea/Core.php b/lib/Alchemy/Phrasea/Core.php index 77ca90737c..a35fe63540 100644 --- a/lib/Alchemy/Phrasea/Core.php +++ b/lib/Alchemy/Phrasea/Core.php @@ -24,7 +24,13 @@ require_once __DIR__ . '/../../vendor/Silex/vendor/pimple/lib/Pimple.php'; class Core extends \Pimple { - public function __construct($isDev = false) + /** + * + * @var Core\Configuration + */ + private $conf; + + public function __construct($env) { /** @@ -32,14 +38,18 @@ class Core extends \Pimple */ static::initAutoloads(); + + $this->conf = new Core\Configuration($env); + $this['Version'] = $this->share(function() { return new Core\Version(); }); - - $this['EM'] = $this->share(function() + + $conf = $this->conf; + $this['EM'] = $this->share(function() use ($conf) { - $doctrine = new Core\Service\Doctrine(); + $doctrine = new Core\Service\Doctrine($conf->getDoctrineConf()); return $doctrine->getEntityManager(); }); @@ -91,6 +101,20 @@ class Core extends \Pimple return; } + private function init() + { + if ($this->conf->debug) + { + ini_set('display_errors', 1); + error_reporting(E_ALL); + \Symfony\Component\HttpKernel\Debug\ErrorHandler::register(); + } + else + { + ini_set('display_errors', 0); + } + } + /** * * @return Request @@ -291,4 +315,14 @@ class Core extends \Pimple return; } + + public function getEnv() + { + return $this->env; + } + + public function isDebug() + { + return $this->conf->debug; + } } diff --git a/lib/Alchemy/Phrasea/Core/Configuration.php b/lib/Alchemy/Phrasea/Core/Configuration.php new file mode 100644 index 0000000000..c4e9150cdc --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Configuration.php @@ -0,0 +1,203 @@ +handle($envName); + + var_dump($configuration); + + exit; + } + + public function getMainConfigFileName() + { + return 'config'; + } + + /** + * + * @return \SplFileObject + */ + public function getMainConfigFile() + { + return $this->mainConfigFile; + } + + public function getDoctrineConf() + { + return (array) $this->dbConf; + } + + public function isInstalled() + { + return $this->installed; + } + + private function loadEnvironnments($env) + { + $filename = $this->loadFileName($env); + + if (!is_file($filename)) + throw new \InvalidArgumentException(sprintf('Config file %s do not exist', $filename)); + + $envConf = \Symfony\Component\Yaml\Yaml::parse($filename); + + $this->envsConf[] = $envConf; + + if (isset($envConf["extends"])) + { + $this->loadEnvironnments($envConf["extends"]); + } + else + { + return; + } + } + + private function substituteEnvConfToMainConf(Array $mainConf) + { + foreach (array_reverse($this->envsConf) as $env) + { + $this->conf = array_replace_recursive($this->conf, $env); + } + + $this->conf = array_replace_recursive($mainConf, $this->conf); + } + + private function loadFileName($env = 'main') + { + if ('main' === $env) + { + return sprintf('%s/%s.yml', $this->configFilePath, $this->getMainConfigFileName()); + } + else + { + return sprintf('%s/%s_%s.yml', $this->configFilePath, $this->getMainConfigFileName(), $env); + } + } + + private function getNoneReplacedPath() + { + return array( + array('doctrine', 'dbal') + ); + } + + private function process($env) + { + $mainConf = \Symfony\Component\Yaml\Yaml::parse($this->loadFileName()); + + $this->loadEnvironnments($env); + + $this->substituteEnvConfToMainConf($mainConf); + + $path = array(); + + $excludedPath = $pathToProcess = $this->getNoneReplacedPath(); + + $confToChange = $this->conf; + + foreach (array_reverse($this->envsConf) as $conf) + { + foreach ($pathToProcess as $key => $thePath) + { + $replaceValue = $this->getDataPath($conf, $thePath); + + if (null !== $replaceValue) + { + $map = function($item, $key) use (&$confToChange, $replaceValue, &$map, &$path, $thePath) + { + if (count(array_diff($path, $thePath) === 0)) + { + + $path[] = $key; + $replace = function(&$searchArray, $path, $value, $depth = 0) use (&$replace) + { + foreach ($searchArray as $k => $v) + { + if ($k === $path[$depth]) + { + array_shift($path); + if (is_array($v) && count($path) !== 0) + { + $replace(&$searchArray[$k], $path, $value, $depth++); + } + else + { + $searchArray[$k] = $value; + } + } + } + }; + $replace($confToChange, $path, $replaceValue); + } + elseif (is_array($item)) + { + $path[] = $key; + array_walk($item, $map); + } + }; + + array_walk($this->conf, $map); + unset($pathToProcess[$key]); + } + } + } + } + + public function getDataPath(Array $data, Array $path) + { + $found = true; + + for ($x = 0; ($x < count($path) && $found); $x++) + { + $key = $path[$x]; + + if (isset($data[$key])) + { + $data = $data[$key]; + } + else + { + $found = false; + } + } + + if ($found) + return $data; + else + return null; + } + +} \ No newline at end of file diff --git a/lib/Alchemy/Phrasea/Core/Configuration/ConfigurationSpecification.php b/lib/Alchemy/Phrasea/Core/Configuration/ConfigurationSpecification.php new file mode 100644 index 0000000000..e921894e97 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Configuration/ConfigurationSpecification.php @@ -0,0 +1,79 @@ +confSpecification = $configSpec; + $this->parser = $parser; + } + + /** + * Stacks all envrironnement in $env that extends the loaded configuration file + * + * @param SplFileObject $file File of the current loaded config file + * @param array $envs A stack of conf environnments + * @return array + */ + private function retrieveExtendedEnvFromFile(\SplFileObject $file, Array $envs = array()) + { + $env = $this->parser->parse($file); + + //stack current env to allEnvs + $allEnvs[] = $env; + + //check if the loaded environnement extends another configuration file + if ($this->confSpecification->isExtended($env)) + { + try + { + //get extended environnement name + $envName = $this->confSpecification->getExtendedEnvName($env); + //get extended configuration file + $file = $this->confSpecification->getConfFileFromEnvName($envName); + //recurse + $this->retrieveExtendedEnvFromFile($file, $allEnvs); + } + catch (\Exception $e) + { + throw \Exception(sprintf("filename %s not found", $file->getPathname())); + } + } + + return $allEnvs; + } + + /** + * Get the value of a specified data path + * + * @param array $data The array where the data are stored + * @param array $path The Path as an array example : array('path', 'to', 'my', 'value') + * @return mixed + */ + private function getDataPath(Array $data, Array $path) + { + $found = true; + + for ($x = 0; ($x < count($path) && $found); $x++) + { + $key = $path[$x]; + + if (isset($data[$key])) + { + $data = $data[$key]; + } + else + { + $found = false; + } + } + + return $found ? $data : null; + } + + /** + * Handle the configuration process and return the final configuration + * + * @param strinig $name the name of the loaded environnement + * @return Array + */ + public function handle($name) + { + + //get the corresepondant file + $file = $this->confSpecification->getConfFileFromEnvName($name); + + //get all extended configuration from current env + $allEnvs = $this->retrieveExtendedEnvFromFile($file); + + //Last env is the main one + $mainEnv = array_pop($allEnvs); + + $excludedPath = $pathToprocess = $this->confSpecification->getNonExtendablePath(); + + //at least 2 envs and one path to process + if (count($allEnvs) >= 1 && count($excludedPath) >= 1) + { + foreach ($allEnvs as $currentEnv) // run trought environnements + { + foreach ($pathToprocess as $kpath => $processedPath) //run throught path + { + $valueToReplace = $this->getDataPath($currentEnv, $processedPath); //retrive the value to replace + + if (null !== $valueToReplace) + { + + // reset current path + $currentPath = array(); + + //callback to iterate over the main conf environnement and replace value from extended file + $map = function($item, $key) use (&$mainEnv, $valueToReplace, &$map, &$currentPath, $processedPath) + { + if (count(array_diff($processedPath, $currentPath)) === 0) // current path and processed path match + { + /** + * Replace current value of the $currentpath in $searchArray by $value + */ + $replace = function(&$searchArray, $currentPath, $value) use (&$replace) + { + foreach ($searchArray as $k => $v) + { + if ($k === $currentPath[0]) + { + array_shift($currentPath); + + if (is_array($v) && count($currentPath) !== 0) + { + $replace(&$searchArray[$k], $currentPath, $value); + } + elseif (count($currentPath) === 0) + { + $searchArray[$k] = $value; + } + } + } + }; + + $replace($mainEnv, $currentPath, $valueToReplace); + } + elseif (is_array($item)) // if current item is an array + { + $currentPath[] = $key; // add item's key to current path + + array_walk($item, $map); // and dig into the current item + } + else //wrong path + { + $currentPath = array(); //reset + } + }; + + //run trough the main conf environnement + array_walk($mainEnv, $map); + + //once done + //reduce the paths to process + unset($pathToprocess[$kpath]); + + break; + } + } + } + } + + if(count($allEnvs) >= 1) + { + foreach($allEnvs as $extendedEnv) + $mainEnv = array_replace_recursive($mainEnv, $extendedEnv); + } + + return $mainEnv; + } + +} diff --git a/lib/Alchemy/Phrasea/Core/Configuration/Parser/ParserInterface.php b/lib/Alchemy/Phrasea/Core/Configuration/Parser/ParserInterface.php new file mode 100644 index 0000000000..60d61cf808 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Configuration/Parser/ParserInterface.php @@ -0,0 +1,30 @@ +getPathname()); + } + catch(\Exception $e) + { + throw new \Exception(sprintf('Failed to parse the configuration file %s', $e->getMessage())); + } + } + +} \ No newline at end of file diff --git a/lib/Alchemy/Phrasea/Core/Configuration/PhraseaConfiguration.php b/lib/Alchemy/Phrasea/Core/Configuration/PhraseaConfiguration.php new file mode 100644 index 0000000000..b88df26ff2 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Configuration/PhraseaConfiguration.php @@ -0,0 +1,81 @@ +getConfigurationFilePath() + , $name + , $this->getConfFileExtension()) + ); + } + + /** + * + * @Override + */ + public function getConfigurationFilePath() + { + return __DIR__ . '/../../../../../config'; + } + + /** + * + * @Override + */ + public function getConfFileExtension() + { + return 'yml'; + } + + /** + * + * @Override + */ + public function isExtended(Array $env) + { + return isset($env[self::EXTENDED_KEYWORD]); + } + + /** + * + * @Override + */ + public function getExtendedEnvName(Array $env) + { + return $this->isExtended($env) ? $env[self::EXTENDED_KEYWORD] : null; + } + +}