Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
61.54% |
16 / 26 |
CRAP | |
85.14% |
189 / 222 |
| container_builder | |
0.00% |
0 / 1 |
|
61.54% |
16 / 26 |
71.82 | |
85.14% |
189 / 222 |
| __construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
| get_container | |
0.00% |
0 / 1 |
15.05 | |
93.94% |
62 / 66 |
|||
| with_environment | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| with_extensions | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| without_extensions | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| with_cache | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| without_cache | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| with_cache_dir | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| with_compiled_container | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| without_compiled_container | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| with_config_path | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| with_custom_parameters | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| with_config | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| get_config_path | |
100.00% |
1 / 1 |
2 | |
100.00% |
1 / 1 |
|||
| get_cache_dir | |
100.00% |
1 / 1 |
2 | |
100.00% |
1 / 1 |
|||
| load_extensions | |
0.00% |
0 / 1 |
5.02 | |
91.18% |
31 / 34 |
|||
| dump_container | |
100.00% |
1 / 1 |
2 | |
100.00% |
10 / 10 |
|||
| create_container | |
100.00% |
1 / 1 |
2 | |
100.00% |
9 / 9 |
|||
| inject_custom_parameters | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
| inject_dbal_driver | |
0.00% |
0 / 1 |
5.02 | |
91.30% |
21 / 23 |
|||
| get_core_parameters | |
100.00% |
1 / 1 |
2 | |
100.00% |
9 / 9 |
|||
| get_env_parameters | |
0.00% |
0 / 1 |
3.14 | |
75.00% |
6 / 8 |
|||
| get_container_filename | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
| get_autoload_filename | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 5 |
|||
| get_environment | |
100.00% |
1 / 1 |
2 | |
100.00% |
1 / 1 |
|||
| register_ext_compiler_pass | |
0.00% |
0 / 1 |
5.26 | |
57.14% |
12 / 21 |
|||
| <?php | |
| /** | |
| * | |
| * This file is part of the phpBB Forum Software package. | |
| * | |
| * @copyright (c) phpBB Limited <https://www.phpbb.com> | |
| * @license GNU General Public License, version 2 (GPL-2.0) | |
| * | |
| * For full copyright and license information, please see | |
| * the docs/CREDITS.txt file. | |
| * | |
| */ | |
| namespace phpbb\di; | |
| use phpbb\filesystem\filesystem; | |
| use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper; | |
| use Symfony\Component\Config\ConfigCache; | |
| use Symfony\Component\Config\FileLocator; | |
| use Symfony\Component\DependencyInjection\ContainerBuilder; | |
| use Symfony\Component\DependencyInjection\Dumper\PhpDumper; | |
| use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; | |
| use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; | |
| use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; | |
| use Symfony\Component\Filesystem\Exception\IOException; | |
| use Symfony\Component\Finder\Finder; | |
| use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass; | |
| class container_builder | |
| { | |
| /** | |
| * @var string The environment to use. | |
| */ | |
| protected $environment; | |
| /** | |
| * @var string phpBB Root Path | |
| */ | |
| protected $phpbb_root_path; | |
| /** | |
| * @var string php file extension | |
| */ | |
| protected $php_ext; | |
| /** | |
| * The container under construction | |
| * | |
| * @var ContainerBuilder | |
| */ | |
| protected $container; | |
| /** | |
| * @var \phpbb\db\driver\driver_interface | |
| */ | |
| protected $dbal_connection = null; | |
| /** | |
| * Indicates whether extensions should be used (default to true). | |
| * | |
| * @var bool | |
| */ | |
| protected $use_extensions = true; | |
| /** | |
| * Defines a custom path to find the configuration of the container (default to $this->phpbb_root_path . 'config') | |
| * | |
| * @var string | |
| */ | |
| protected $config_path = null; | |
| /** | |
| * Indicates whether the container should be dumped to the filesystem (default to true). | |
| * | |
| * If DEBUG_CONTAINER is set this option is ignored and a new container is build. | |
| * | |
| * @var bool | |
| */ | |
| protected $use_cache = true; | |
| /** | |
| * Indicates if the container should be compiled automatically (default to true). | |
| * | |
| * @var bool | |
| */ | |
| protected $compile_container = true; | |
| /** | |
| * Custom parameters to inject into the container. | |
| * | |
| * Default to: | |
| * array( | |
| * 'core.root_path', $this->phpbb_root_path, | |
| * 'core.php_ext', $this->php_ext, | |
| * ); | |
| * | |
| * @var array | |
| */ | |
| protected $custom_parameters = []; | |
| /** | |
| * @var \phpbb\config_php_file | |
| */ | |
| protected $config_php_file; | |
| /** | |
| * @var string | |
| */ | |
| protected $cache_dir; | |
| /** | |
| * @var array | |
| */ | |
| private $container_extensions; | |
| /** @var \Exception */ | |
| private $build_exception; | |
| /** | |
| * Constructor | |
| * | |
| * @param string $phpbb_root_path Path to the phpbb includes directory. | |
| * @param string $php_ext php file extension | |
| */ | |
| public function __construct($phpbb_root_path, $php_ext) | |
| { | |
| $this->phpbb_root_path = $phpbb_root_path; | |
| $this->php_ext = $php_ext; | |
| } | |
| /** | |
| * Build and return a new Container respecting the current configuration | |
| * | |
| * @return \phpbb_cache_container|ContainerBuilder | |
| */ | |
| public function get_container() | |
| { | |
| try | |
| { | |
| $container_filename = $this->get_container_filename(); | |
| $config_cache = new ConfigCache($container_filename, defined('DEBUG')); | |
| if ($this->use_cache && $config_cache->isFresh()) | |
| { | |
| if ($this->use_extensions) | |
| { | |
| $autoload_cache = new ConfigCache($this->get_autoload_filename(), defined('DEBUG')); | |
| if (!$autoload_cache->isFresh()) | |
| { | |
| // autoload cache should be refreshed | |
| $this->load_extensions(); | |
| } | |
| require($this->get_autoload_filename()); | |
| } | |
| require($config_cache->getPath()); | |
| $this->container = new \phpbb_cache_container(); | |
| } | |
| else | |
| { | |
| $this->container_extensions = array(new extension\core($this->get_config_path())); | |
| if ($this->use_extensions) | |
| { | |
| $this->load_extensions(); | |
| } | |
| // Inject the config | |
| if ($this->config_php_file) | |
| { | |
| $this->container_extensions[] = new extension\config($this->config_php_file); | |
| } | |
| $this->container = $this->create_container($this->container_extensions); | |
| // Easy collections through tags | |
| $this->container->addCompilerPass(new pass\collection_pass()); | |
| // Event listeners "phpBB style" | |
| $this->container->addCompilerPass(new RegisterListenersPass('dispatcher', 'event.listener_listener', 'event.listener')); | |
| // Event listeners "Symfony style" | |
| $this->container->addCompilerPass(new RegisterListenersPass('dispatcher')); | |
| if ($this->use_extensions) | |
| { | |
| $this->register_ext_compiler_pass(); | |
| } | |
| $filesystem = new filesystem(); | |
| $loader = new YamlFileLoader($this->container, new FileLocator($filesystem->realpath($this->get_config_path()))); | |
| $loader->load($this->container->getParameter('core.environment') . '/config.yml'); | |
| $this->inject_custom_parameters(); | |
| if ($this->compile_container) | |
| { | |
| $this->container->compile(); | |
| if ($this->use_cache) | |
| { | |
| $this->dump_container($config_cache); | |
| } | |
| } | |
| } | |
| if ($this->compile_container && $this->config_php_file) | |
| { | |
| $this->container->set('config.php', $this->config_php_file); | |
| } | |
| $this->inject_dbal_driver(); | |
| return $this->container; | |
| } | |
| catch (\Exception $e) | |
| { | |
| // Don't try to recover if we are in the development environment | |
| if ($this->get_environment() === 'development') | |
| { | |
| throw $e; | |
| } | |
| if ($this->build_exception === null) | |
| { | |
| $this->build_exception = $e; | |
| return $this | |
| ->without_extensions() | |
| ->without_cache() | |
| ->with_custom_parameters(array_merge($this->custom_parameters, [ | |
| 'container_exception' => $e, | |
| ])) | |
| ->get_container(); | |
| } | |
| else | |
| { | |
| // Rethrow the original exception if it's still failing | |
| throw $this->build_exception; | |
| } | |
| } | |
| } | |
| /** | |
| * Enable the extensions. | |
| * | |
| * @param string $environment The environment to use | |
| * @return $this | |
| */ | |
| public function with_environment($environment) | |
| { | |
| $this->environment = $environment; | |
| return $this; | |
| } | |
| /** | |
| * Enable the extensions. | |
| * | |
| * @return $this | |
| */ | |
| public function with_extensions() | |
| { | |
| $this->use_extensions = true; | |
| return $this; | |
| } | |
| /** | |
| * Disable the extensions. | |
| * | |
| * @return $this | |
| */ | |
| public function without_extensions() | |
| { | |
| $this->use_extensions = false; | |
| return $this; | |
| } | |
| /** | |
| * Enable the caching of the container. | |
| * | |
| * If DEBUG_CONTAINER is set this option is ignored and a new container is build. | |
| * | |
| * @return $this | |
| */ | |
| public function with_cache() | |
| { | |
| $this->use_cache = true; | |
| return $this; | |
| } | |
| /** | |
| * Disable the caching of the container. | |
| * | |
| * @return $this | |
| */ | |
| public function without_cache() | |
| { | |
| $this->use_cache = false; | |
| return $this; | |
| } | |
| /** | |
| * Set the cache directory. | |
| * | |
| * @param string $cache_dir The cache directory. | |
| * @return $this | |
| */ | |
| public function with_cache_dir($cache_dir) | |
| { | |
| $this->cache_dir = $cache_dir; | |
| return $this; | |
| } | |
| /** | |
| * Enable the compilation of the container. | |
| * | |
| * @return $this | |
| */ | |
| public function with_compiled_container() | |
| { | |
| $this->compile_container = true; | |
| return $this; | |
| } | |
| /** | |
| * Disable the compilation of the container. | |
| * | |
| * @return $this | |
| */ | |
| public function without_compiled_container() | |
| { | |
| $this->compile_container = false; | |
| return $this; | |
| } | |
| /** | |
| * Set a custom path to find the configuration of the container. | |
| * | |
| * @param string $config_path | |
| * @return $this | |
| */ | |
| public function with_config_path($config_path) | |
| { | |
| $this->config_path = $config_path; | |
| return $this; | |
| } | |
| /** | |
| * Set custom parameters to inject into the container. | |
| * | |
| * @param array $custom_parameters | |
| * @return $this | |
| */ | |
| public function with_custom_parameters($custom_parameters) | |
| { | |
| $this->custom_parameters = $custom_parameters; | |
| return $this; | |
| } | |
| /** | |
| * Set custom parameters to inject into the container. | |
| * | |
| * @param \phpbb\config_php_file $config_php_file | |
| * @return $this | |
| */ | |
| public function with_config(\phpbb\config_php_file $config_php_file) | |
| { | |
| $this->config_php_file = $config_php_file; | |
| return $this; | |
| } | |
| /** | |
| * Returns the path to the container configuration (default: root_path/config) | |
| * | |
| * @return string | |
| */ | |
| protected function get_config_path() | |
| { | |
| return $this->config_path ?: $this->phpbb_root_path . 'config'; | |
| } | |
| /** | |
| * Returns the path to the cache directory (default: root_path/cache/environment). | |
| * | |
| * @return string Path to the cache directory. | |
| */ | |
| protected function get_cache_dir() | |
| { | |
| return $this->cache_dir ?: $this->phpbb_root_path . 'cache/' . $this->get_environment() . '/'; | |
| } | |
| /** | |
| * Load the enabled extensions. | |
| */ | |
| protected function load_extensions() | |
| { | |
| if ($this->config_php_file !== null) | |
| { | |
| // Build an intermediate container to load the ext list from the database | |
| $container_builder = new container_builder($this->phpbb_root_path, $this->php_ext); | |
| $ext_container = $container_builder | |
| ->without_cache() | |
| ->without_extensions() | |
| ->with_config($this->config_php_file) | |
| ->with_config_path($this->get_config_path()) | |
| ->with_environment('production') | |
| ->without_compiled_container() | |
| ->get_container() | |
| ; | |
| $ext_container->register('cache.driver', '\\phpbb\\cache\\driver\\dummy'); | |
| $ext_container->compile(); | |
| $extensions = $ext_container->get('ext.manager')->all_enabled(); | |
| // Load each extension found | |
| $autoloaders = '<?php | |
| /** | |
| * Loads all extensions custom auto-loaders. | |
| * | |
| * This file has been auto-generated | |
| * by phpBB while loading the extensions. | |
| */ | |
| '; | |
| foreach ($extensions as $ext_name => $path) | |
| { | |
| $extension_class = '\\' . str_replace('/', '\\', $ext_name) . '\\di\\extension'; | |
| if (!class_exists($extension_class)) | |
| { | |
| $extension_class = '\\phpbb\\extension\\di\\extension_base'; | |
| } | |
| $this->container_extensions[] = new $extension_class($ext_name, $path); | |
| // Load extension autoloader | |
| $filename = $path . 'vendor/autoload.php'; | |
| if (file_exists($filename)) | |
| { | |
| $autoloaders .= "require('{$filename}');\n"; | |
| } | |
| } | |
| $configCache = new ConfigCache($this->get_autoload_filename(), false); | |
| $configCache->write($autoloaders); | |
| require($this->get_autoload_filename()); | |
| } | |
| else | |
| { | |
| // To load the extensions we need the database credentials. | |
| // Automatically disable the extensions if we don't have them. | |
| $this->use_extensions = false; | |
| } | |
| } | |
| /** | |
| * Dump the container to the disk. | |
| * | |
| * @param ConfigCache $cache The config cache | |
| */ | |
| protected function dump_container($cache) | |
| { | |
| try | |
| { | |
| $dumper = new PhpDumper($this->container); | |
| $proxy_dumper = new ProxyDumper(); | |
| $dumper->setProxyDumper($proxy_dumper); | |
| $cached_container_dump = $dumper->dump(array( | |
| 'class' => 'phpbb_cache_container', | |
| 'base_class' => 'Symfony\\Component\\DependencyInjection\\ContainerBuilder', | |
| )); | |
| $cache->write($cached_container_dump, $this->container->getResources()); | |
| } | |
| catch (IOException $e) | |
| { | |
| // Don't fail if the cache isn't writeable | |
| } | |
| } | |
| /** | |
| * Create the ContainerBuilder object | |
| * | |
| * @param array $extensions Array of Container extension objects | |
| * @return ContainerBuilder object | |
| */ | |
| protected function create_container(array $extensions) | |
| { | |
| $container = new ContainerBuilder(new ParameterBag($this->get_core_parameters())); | |
| $container->setProxyInstantiator(new proxy_instantiator($this->get_cache_dir())); | |
| $extensions_alias = array(); | |
| foreach ($extensions as $extension) | |
| { | |
| $container->registerExtension($extension); | |
| $extensions_alias[] = $extension->getAlias(); | |
| } | |
| $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions_alias)); | |
| return $container; | |
| } | |
| /** | |
| * Inject the customs parameters into the container | |
| */ | |
| protected function inject_custom_parameters() | |
| { | |
| foreach ($this->custom_parameters as $key => $value) | |
| { | |
| $this->container->setParameter($key, $value); | |
| } | |
| } | |
| /** | |
| * Inject the dbal connection driver into container | |
| */ | |
| protected function inject_dbal_driver() | |
| { | |
| if (empty($this->config_php_file)) | |
| { | |
| return; | |
| } | |
| $config_data = $this->config_php_file->get_all(); | |
| if (!empty($config_data)) | |
| { | |
| if ($this->dbal_connection === null) | |
| { | |
| $dbal_driver_class = $this->config_php_file->convert_30_dbms_to_31($this->config_php_file->get('dbms')); | |
| /** @var \phpbb\db\driver\driver_interface $dbal_connection */ | |
| $this->dbal_connection = new $dbal_driver_class(); | |
| $this->dbal_connection->sql_connect( | |
| $this->config_php_file->get('dbhost'), | |
| $this->config_php_file->get('dbuser'), | |
| $this->config_php_file->get('dbpasswd'), | |
| $this->config_php_file->get('dbname'), | |
| $this->config_php_file->get('dbport'), | |
| false, | |
| defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK | |
| ); | |
| } | |
| $this->container->set('dbal.conn.driver', $this->dbal_connection); | |
| } | |
| } | |
| /** | |
| * Returns the core parameters. | |
| * | |
| * @return array An array of core parameters | |
| */ | |
| protected function get_core_parameters() | |
| { | |
| return array_merge( | |
| array( | |
| 'core.root_path' => $this->phpbb_root_path, | |
| 'core.php_ext' => $this->php_ext, | |
| 'core.environment' => $this->get_environment(), | |
| 'core.debug' => defined('DEBUG') ? DEBUG : false, | |
| 'core.cache_dir' => $this->get_cache_dir(), | |
| ), | |
| $this->get_env_parameters() | |
| ); | |
| } | |
| /** | |
| * Gets the environment parameters. | |
| * | |
| * Only the parameters starting with "PHPBB__" are considered. | |
| * | |
| * @return array An array of parameters | |
| */ | |
| protected function get_env_parameters() | |
| { | |
| $parameters = array(); | |
| foreach ($_SERVER as $key => $value) | |
| { | |
| if (0 === strpos($key, 'PHPBB__')) | |
| { | |
| $parameters[strtolower(str_replace('__', '.', substr($key, 9)))] = $value; | |
| } | |
| } | |
| return $parameters; | |
| } | |
| /** | |
| * Get the filename under which the dumped container will be stored. | |
| * | |
| * @return string Path for dumped container | |
| */ | |
| protected function get_container_filename() | |
| { | |
| $container_params = [ | |
| 'phpbb_root_path' => $this->phpbb_root_path, | |
| 'use_extensions' => $this->use_extensions, | |
| 'config_path' => $this->config_path, | |
| ]; | |
| return $this->get_cache_dir() . 'container_' . md5(implode(',', $container_params)) . '.' . $this->php_ext; | |
| } | |
| /** | |
| * Get the filename under which the dumped extensions autoloader will be stored. | |
| * | |
| * @return string Path for dumped extensions autoloader | |
| */ | |
| protected function get_autoload_filename() | |
| { | |
| $container_params = [ | |
| 'phpbb_root_path' => $this->phpbb_root_path, | |
| 'use_extensions' => $this->use_extensions, | |
| 'config_path' => $this->config_path, | |
| ]; | |
| return $this->get_cache_dir() . 'autoload_' . md5(implode(',', $container_params)) . '.' . $this->php_ext; | |
| } | |
| /** | |
| * Return the name of the current environment. | |
| * | |
| * @return string | |
| */ | |
| protected function get_environment() | |
| { | |
| return $this->environment ?: PHPBB_ENVIRONMENT; | |
| } | |
| private function register_ext_compiler_pass() | |
| { | |
| $finder = new Finder(); | |
| $finder | |
| ->name('*_pass.php') | |
| ->path('di/pass') | |
| ->files() | |
| ->ignoreDotFiles(true) | |
| ->ignoreUnreadableDirs(true) | |
| ->ignoreVCS(true) | |
| ->followLinks() | |
| ->in($this->phpbb_root_path . 'ext') | |
| ; | |
| /** @var \SplFileInfo $pass */ | |
| foreach ($finder as $pass) | |
| { | |
| $filename = $pass->getPathname(); | |
| $filename = substr($filename, 0, -strlen('.' . $pass->getExtension())); | |
| $filename = str_replace(DIRECTORY_SEPARATOR, '/', $filename); | |
| $className = preg_replace('#^.*ext/#', '', $filename); | |
| $className = '\\' . str_replace('/', '\\', $className); | |
| if (class_exists($className) && in_array('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface', class_implements($className), true)) | |
| { | |
| $this->container->addCompilerPass(new $className()); | |
| } | |
| } | |
| } | |
| } |