Files
Phraseanet/lib/Alchemy/Phrasea/Core/Configuration/Handler.php
2011-12-28 13:24:26 +01:00

219 lines
6.6 KiB
PHP

<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2010 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Configuration;
use \Symfony\Component\Yaml\Yaml;
/**
* Handle configuration mechanism
*
* @package
* @license http://opensource.org/licenses/gpl-3.0 GPLv3
* @link www.phraseanet.com
*/
class Handler
{
/**
* Configuration file specification interface
* @var ConfigurationSpecification
*/
protected $confSpecification;
/**
* A file parser interface
* @var Parser\ParserInterface
*/
protected $parser;
/**
* Tell handler the configuration specification ans which parser to use
*
* @param ConfigurationSpecification $configSpec
* @param Parser\ParserInterface $parser
*/
public function __construct(Application $configSpec, Parser $parser)
{
$this->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 $allEnvs = 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
return $this->retrieveExtendedEnvFromFile($file, $allEnvs);
}
catch (\Exception $e)
{
throw new \Exception(sprintf("filename %s not found", $file->getPathname()));
}
}
else
{
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]) //if key of searched path equal key of search array
{
array_shift($currentPath); //reduce path
if (is_array($v) && count($currentPath) !== 0) //continue to run trought search array
{
$replace(&$searchArray[$k], $currentPath, $value);
}
elseif (count($currentPath) === 0) //no more scope to looking for
{
$searchArray[$k] = $value;
break; //quit
}
else
{
continue;
}
}
}
};
$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;
}
}
}
}
//replace all other value
if(count($allEnvs) >= 1)
{
foreach($allEnvs as $extendedEnv)
$mainEnv = array_replace_recursive($mainEnv, $extendedEnv);
}
return $mainEnv;
}
}