diff options
Diffstat (limited to 'phpBB/phpbb/di')
-rw-r--r-- | phpBB/phpbb/di/container_builder.php | 704 | ||||
-rw-r--r-- | phpBB/phpbb/di/extension/container_configuration.php | 52 | ||||
-rw-r--r-- | phpBB/phpbb/di/extension/core.php | 107 | ||||
-rw-r--r-- | phpBB/phpbb/di/extension/ext.php | 67 | ||||
-rw-r--r-- | phpBB/phpbb/di/ordered_service_collection.php | 117 | ||||
-rw-r--r-- | phpBB/phpbb/di/pass/collection_pass.php | 22 | ||||
-rw-r--r-- | phpBB/phpbb/di/proxy_instantiator.php | 77 | ||||
-rw-r--r-- | phpBB/phpbb/di/service_collection.php | 27 | ||||
-rw-r--r-- | phpBB/phpbb/di/service_collection_iterator.php | 2 |
9 files changed, 841 insertions, 334 deletions
diff --git a/phpBB/phpbb/di/container_builder.php b/phpBB/phpbb/di/container_builder.php index a214356ac3..4d5f189f12 100644 --- a/phpBB/phpbb/di/container_builder.php +++ b/phpBB/phpbb/di/container_builder.php @@ -13,392 +13,616 @@ 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\HttpKernel\DependencyInjection\RegisterListenersPass; +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 phpBB Root Path */ - protected $phpbb_root_path; - - /** @var string php file extension */ - protected $php_ext; - /** - * The container under construction - * - * @var ContainerBuilder - */ - protected $container; + * @var string The environment to use. + */ + protected $environment; /** - * @var \phpbb\db\driver\driver_interface - */ - protected $dbal_connection = null; + * @var string phpBB Root Path + */ + protected $phpbb_root_path; /** - * @var array the installed extensions - */ - protected $installed_exts = null; + * @var string php file extension + */ + protected $php_ext; /** - * Indicates whether the php config file should be injected into the container (default to true). - * - * @var bool - */ - protected $inject_config = true; + * The container under construction + * + * @var ContainerBuilder + */ + protected $container; /** - * Indicates whether extensions should be used (default to true). - * - * @var bool - */ + * 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 - */ + * 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 phpBB compile pass should be used (default to true). - * - * @var bool - */ - protected $use_custom_pass = true; + * 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 whether the kernel compile pass should be used (default to true). - * - * @var bool - */ - protected $use_kernel_pass = true; + * Indicates if the container should be compiled automatically (default to true). + * + * @var bool + */ + protected $compile_container = true; /** - * 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 $dump_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 = []; /** - * Indicates if the container should be compiled automatically (default to true). - * - * @var bool - */ - protected $compile_container = true; + * @var \phpbb\config_php_file + */ + protected $config_php_file; /** - * Custom parameters to inject into the container. - * - * Default to true: - * array( - * 'core.root_path', $this->phpbb_root_path, - * 'core.php_ext', $this->php_ext, - * ); - * - * @var array - */ - protected $custom_parameters = null; + * @var string + */ + protected $cache_dir; /** - * @var \phpbb\config_php_file - */ - protected $config_php_file; + * @var array + */ + private $container_extensions; + + /** @var \Exception */ + private $build_exception; /** - * Constructor - * - * @param \phpbb\config_php_file $config_php_file - * @param string $phpbb_root_path Path to the phpbb includes directory. - * @param string $php_ext php file extension - */ - function __construct(\phpbb\config_php_file $config_php_file, $phpbb_root_path, $php_ext) + * 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->config_php_file = $config_php_file; $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 - */ + * Build and return a new Container respecting the current configuration + * + * @return \phpbb_cache_container|ContainerBuilder + */ public function get_container() { - $container_filename = $this->get_container_filename(); - if (!defined('DEBUG_CONTAINER') && $this->dump_container && file_exists($container_filename)) + try { - require($container_filename); - $this->container = new \phpbb_cache_container(); - } - else - { - if ($this->config_path === null) + $container_filename = $this->get_container_filename(); + $config_cache = new ConfigCache($container_filename, defined('DEBUG')); + if ($this->use_cache && $config_cache->isFresh()) { - $this->config_path = $this->phpbb_root_path . 'config'; - } - $container_extensions = array(new \phpbb\di\extension\core($this->config_path)); + if ($this->use_extensions) + { + require($this->get_autoload_filename()); + } - if ($this->use_extensions) - { - $installed_exts = $this->get_installed_extensions(); - $container_extensions[] = new \phpbb\di\extension\ext($installed_exts); + require($config_cache->getPath()); + $this->container = new \phpbb_cache_container(); } - - if ($this->inject_config) + else { - $container_extensions[] = new \phpbb\di\extension\config($this->config_php_file); - } + $this->container_extensions = array(new extension\core($this->get_config_path())); - $this->container = $this->create_container($container_extensions); + if ($this->use_extensions) + { + $this->load_extensions(); + } - if ($this->use_custom_pass) - { - // Symfony Kernel Listeners - $this->container->addCompilerPass(new \phpbb\di\pass\collection_pass()); + // 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')); - if ($this->use_kernel_pass) + // 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->addCompilerPass(new RegisterListenersPass('dispatcher')); + $this->container->compile(); + + if ($this->use_cache) + { + $this->dump_container($config_cache); + } } } - $this->inject_custom_parameters(); + if ($this->compile_container && $this->config_php_file) + { + $this->container->set('config.php', $this->config_php_file); + } - if ($this->compile_container) + return $this->container; + } + catch (\Exception $e) + { + // Don't try to recover if we are in the development environment + if ($this->get_environment() === 'development') { - $this->container->compile(); + throw $e; } - if ($this->dump_container && !defined('DEBUG_CONTAINER')) + 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 { - $this->dump_container($container_filename); + // Rethrow the original exception if it's still failing + throw $this->build_exception; } } + } - $this->container->set('config.php', $this->config_php_file); + /** + * Enable the extensions. + * + * @param string $environment The environment to use + * @return $this + */ + public function with_environment($environment) + { + $this->environment = $environment; - if ($this->compile_container) - { - $this->inject_dbal(); - } + return $this; + } + + /** + * Enable the extensions. + * + * @return $this + */ + public function with_extensions() + { + $this->use_extensions = true; - return $this->container; + return $this; } /** - * Set if the extensions should be used. - * - * @param bool $use_extensions - */ - public function set_use_extensions($use_extensions) + * Disable the extensions. + * + * @return $this + */ + public function without_extensions() { - $this->use_extensions = $use_extensions; + $this->use_extensions = false; + + return $this; } /** - * Set if the phpBB compile pass have to be used. - * - * @param bool $use_custom_pass - */ - public function set_use_custom_pass($use_custom_pass) + * 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_custom_pass = $use_custom_pass; + $this->use_cache = true; + + return $this; } /** - * Set if the kernel compile pass have to be used. - * - * @param bool $use_kernel_pass - */ - public function set_use_kernel_pass($use_kernel_pass) + * Disable the caching of the container. + * + * @return $this + */ + public function without_cache() { - $this->use_kernel_pass = $use_kernel_pass; + $this->use_cache = false; + + return $this; } /** - * Set if the php config file should be injecting into the container. - * - * @param bool $inject_config - */ - public function set_inject_config($inject_config) + * Set the cache directory. + * + * @param string $cache_dir The cache directory. + * @return $this + */ + public function with_cache_dir($cache_dir) { - $this->inject_config = $inject_config; + $this->cache_dir = $cache_dir; + + return $this; } /** - * Set if a dump container should be used. - * - * If DEBUG_CONTAINER is set this option is ignored and a new container is build. - * - * @var bool $dump_container - */ - public function set_dump_container($dump_container) + * Enable the compilation of the container. + * + * @return $this + */ + public function with_compiled_container() { - $this->dump_container = $dump_container; + $this->compile_container = true; + + return $this; } /** - * Set if the container should be compiled automatically (default to true). - * - * @var bool $dump_container - */ - public function set_compile_container($compile_container) + * Disable the compilation of the container. + * + * @return $this + */ + public function without_compiled_container() { - $this->compile_container = $compile_container; + $this->compile_container = false; + + return $this; } /** - * Set a custom path to find the configuration of the container - * - * @param string $config_path - */ - public function set_config_path($config_path) + * 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 - */ - public function set_custom_parameters($custom_parameters) + * 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; } /** - * Dump the container to the disk. - * - * @param string $container_filename The name of the file. - */ - protected function dump_container($container_filename) + * 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) { - $dumper = new PhpDumper($this->container); - $cached_container_dump = $dumper->dump(array( - 'class' => 'phpbb_cache_container', - 'base_class' => 'Symfony\\Component\\DependencyInjection\\ContainerBuilder', - )); + $this->config_php_file = $config_php_file; - file_put_contents($container_filename, $cached_container_dump); + return $this; } /** - * Inject the connection into the container if one was opened. - */ - protected function inject_dbal() + * Returns the path to the container configuration (default: root_path/config) + * + * @return string + */ + protected function get_config_path() { - if ($this->dbal_connection !== null) - { - $this->container->get('dbal.conn')->set_driver($this->dbal_connection); - } + return $this->config_path ?: $this->phpbb_root_path . 'config'; } /** - * Get DB connection. - * - * @return \phpbb\db\driver\driver_interface - */ - protected function get_dbal_connection() + * Returns the path to the cache directory (default: root_path/cache/environment). + * + * @return string Path to the cache directory. + */ + protected function get_cache_dir() { - if ($this->dbal_connection === null) - { - $dbal_driver_class = $this->config_php_file->convert_30_dbms_to_31($this->config_php_file->get('dbms')); - $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'), - defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK - ); - } - - return $this->dbal_connection; + return $this->cache_dir ?: $this->phpbb_root_path . 'cache/' . $this->get_environment() . '/'; } /** - * Get enabled extensions. - * - * @return array enabled extensions - */ - protected function get_installed_extensions() + * Load the enabled extensions. + */ + protected function load_extensions() { - $db = $this->get_dbal_connection(); - $extension_table = $this->config_php_file->get('table_prefix') . 'ext'; + 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'; - $sql = 'SELECT * - FROM ' . $extension_table . ' - WHERE ext_active = 1'; + 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"; + } + } - $result = $db->sql_query($sql); - $rows = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); + $configCache = new ConfigCache($this->get_autoload_filename(), false); + $configCache->write($autoloaders); - $exts = array(); - foreach ($rows as $row) + require($this->get_autoload_filename()); + } + else { - $exts[$row['ext_name']] = $this->phpbb_root_path . 'ext/' . $row['ext_name'] . '/'; + // 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); - return $exts; + $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 - */ + * Create the ContainerBuilder object + * + * @param array $extensions Array of Container extension objects + * @return ContainerBuilder object + */ protected function create_container(array $extensions) { - $container = new ContainerBuilder(); + $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); - $container->loadFromExtension($extension->getAlias()); + $extensions_alias[] = $extension->getAlias(); } + $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions_alias)); + return $container; } /** - * Inject the customs parameters into the container - */ + * Inject the customs parameters into the container + */ protected function inject_custom_parameters() { - if ($this->custom_parameters === null) + foreach ($this->custom_parameters as $key => $value) { - $this->custom_parameters = array( - 'core.root_path' => $this->phpbb_root_path, - 'core.php_ext' => $this->php_ext, - ); + $this->container->setParameter($key, $value); } - foreach ($this->custom_parameters as $key => $value) + } + + /** + * 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) { - $this->container->setParameter($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 - */ + * Get the filename under which the dumped container will be stored. + * + * @return string Path for dumped container + */ protected function get_container_filename() { - return $this->phpbb_root_path . 'cache/container_' . md5($this->phpbb_root_path) . '.' . $this->php_ext; + $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()); + } + } } } diff --git a/phpBB/phpbb/di/extension/container_configuration.php b/phpBB/phpbb/di/extension/container_configuration.php new file mode 100644 index 0000000000..4585d6509e --- /dev/null +++ b/phpBB/phpbb/di/extension/container_configuration.php @@ -0,0 +1,52 @@ +<?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\extension; + +use Symfony\Component\Config\Definition\Builder\TreeBuilder; +use Symfony\Component\Config\Definition\ConfigurationInterface; + +class container_configuration implements ConfigurationInterface +{ + + /** + * Generates the configuration tree builder. + * + * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder + */ + public function getConfigTreeBuilder() + { + $treeBuilder = new TreeBuilder(); + $rootNode = $treeBuilder->root('core'); + $rootNode + ->children() + ->booleanNode('require_dev_dependencies')->defaultValue(false)->end() + ->arrayNode('debug') + ->addDefaultsIfNotSet() + ->children() + ->booleanNode('exceptions')->defaultValue(false)->end() + ->end() + ->end() + ->arrayNode('twig') + ->addDefaultsIfNotSet() + ->children() + ->booleanNode('debug')->defaultValue(null)->end() + ->booleanNode('auto_reload')->defaultValue(null)->end() + ->booleanNode('enable_debug_extension')->defaultValue(false)->end() + ->end() + ->end() + ->end() + ; + return $treeBuilder; + } +} diff --git a/phpBB/phpbb/di/extension/core.php b/phpBB/phpbb/di/extension/core.php index ca4fa5c082..29c0b0e44e 100644 --- a/phpBB/phpbb/di/extension/core.php +++ b/phpBB/phpbb/di/extension/core.php @@ -13,53 +13,110 @@ namespace phpbb\di\extension; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; -use Symfony\Component\Config\FileLocator; +use Symfony\Component\HttpKernel\DependencyInjection\Extension; /** * Container core extension */ class core extends Extension { + const TWIG_OPTIONS_POSITION = 6; + /** - * Config path - * @var string - */ + * Config path + * @var string + */ protected $config_path; /** - * Constructor - * - * @param string $config_path Config path - */ + * Constructor + * + * @param string $config_path Config path + */ public function __construct($config_path) { $this->config_path = $config_path; } /** - * Loads a specific configuration. - * - * @param array $config An array of configuration values - * @param ContainerBuilder $container A ContainerBuilder instance - * - * @throws \InvalidArgumentException When provided tag is not defined in this extension - */ - public function load(array $config, ContainerBuilder $container) + * Loads a specific configuration. + * + * @param array $configs An array of configuration values + * @param ContainerBuilder $container A ContainerBuilder instance + * + * @throws \InvalidArgumentException When provided tag is not defined in this extension + */ + public function load(array $configs, ContainerBuilder $container) + { + $filesystem = new \phpbb\filesystem\filesystem(); + $loader = new YamlFileLoader($container, new FileLocator($filesystem->realpath($this->config_path))); + $loader->load($container->getParameter('core.environment') . '/container/environment.yml'); + + $config = $this->getConfiguration($configs, $container); + $config = $this->processConfiguration($config, $configs); + + if ($config['require_dev_dependencies']) + { + if (!class_exists('Goutte\Client', true)) + { + trigger_error( + 'Composer development dependencies have not been set up for the ' . $container->getParameter('core.environment') . ' environment yet, run ' . + "'php ../composer.phar install --dev' from the phpBB directory to do so.", + E_USER_ERROR + ); + } + } + + // Set the Twig options if defined in the environment + $definition = $container->getDefinition('template.twig.environment'); + $twig_environment_options = $definition->getArgument(static::TWIG_OPTIONS_POSITION); + if ($config['twig']['debug']) + { + $twig_environment_options['debug'] = true; + } + if ($config['twig']['auto_reload']) + { + $twig_environment_options['auto_reload'] = true; + } + + // Replace the 7th argument, the options passed to the environment + $definition->replaceArgument(static::TWIG_OPTIONS_POSITION, $twig_environment_options); + + if ($config['twig']['enable_debug_extension']) + { + $definition = $container->getDefinition('template.twig.extensions.debug'); + $definition->addTag('twig.extension'); + } + + // Set the debug options + foreach ($config['debug'] as $name => $value) + { + $container->setParameter('debug.' . $name, $value); + } + } + + /** + * {@inheritdoc} + */ + public function getConfiguration(array $config, ContainerBuilder $container) { - $loader = new YamlFileLoader($container, new FileLocator(phpbb_realpath($this->config_path))); - $loader->load('services.yml'); + $r = new \ReflectionClass('\phpbb\di\extension\container_configuration'); + $container->addResource(new FileResource($r->getFileName())); + + return new container_configuration(); } /** - * Returns the recommended alias to use in XML. - * - * This alias is also the mandatory prefix to use when using YAML. - * - * @return string The alias - */ + * Returns the recommended alias to use in XML. + * + * This alias is also the mandatory prefix to use when using YAML. + * + * @return string The alias + */ public function getAlias() { return 'core'; diff --git a/phpBB/phpbb/di/extension/ext.php b/phpBB/phpbb/di/extension/ext.php deleted file mode 100644 index 718c992d2e..0000000000 --- a/phpBB/phpbb/di/extension/ext.php +++ /dev/null @@ -1,67 +0,0 @@ -<?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\extension; - -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\HttpKernel\DependencyInjection\Extension; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; -use Symfony\Component\Config\FileLocator; - -/** -* Container ext extension -*/ -class ext extends Extension -{ - protected $paths = array(); - - public function __construct($enabled_extensions) - { - foreach ($enabled_extensions as $ext => $path) - { - $this->paths[] = $path; - } - } - - /** - * Loads a specific configuration. - * - * @param array $config An array of configuration values - * @param ContainerBuilder $container A ContainerBuilder instance - * - * @throws \InvalidArgumentException When provided tag is not defined in this extension - */ - public function load(array $config, ContainerBuilder $container) - { - foreach ($this->paths as $path) - { - if (file_exists($path . '/config/services.yml')) - { - $loader = new YamlFileLoader($container, new FileLocator(phpbb_realpath($path . '/config'))); - $loader->load('services.yml'); - } - } - } - - /** - * Returns the recommended alias to use in XML. - * - * This alias is also the mandatory prefix to use when using YAML. - * - * @return string The alias - */ - public function getAlias() - { - return 'ext'; - } -} diff --git a/phpBB/phpbb/di/ordered_service_collection.php b/phpBB/phpbb/di/ordered_service_collection.php new file mode 100644 index 0000000000..046012ae5b --- /dev/null +++ b/phpBB/phpbb/di/ordered_service_collection.php @@ -0,0 +1,117 @@ +<?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 Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Collection of services in a specified order + */ +class ordered_service_collection extends service_collection +{ + /** + * @var bool + */ + protected $is_ordered; + + /** + * @var array + */ + protected $service_ids; + + /** + * Constructor + * + * @param ContainerInterface $container Container object + */ + public function __construct(ContainerInterface $container) + { + $this->is_ordered = false; + $this->service_ids = array(); + + parent::__construct($container); + } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + if (!$this->is_ordered) + { + $this->sort_services(); + } + + return new service_collection_iterator($this); + } + + /** + * {@inheritdoc} + */ + public function offsetExists($index) + { + if (!$this->is_ordered) + { + $this->sort_services(); + } + + return parent::offsetExists($index); + } + + /** + * {@inheritdoc} + */ + public function offsetGet($index) + { + if (!$this->is_ordered) + { + $this->sort_services(); + } + + return parent::offsetGet($index); + } + + /** + * Adds a service ID to the collection + * + * @param string $service_id + * @param int $order + */ + public function add($service_id, $order = 0) + { + $order = (int) $order; + $this->service_ids[$order][] = $service_id; + $this->is_ordered = false; + } + + protected function sort_services() + { + if ($this->is_ordered) + { + return; + } + + $this->exchangeArray(array()); + ksort($this->service_ids); + foreach ($this->service_ids as $service_order_group) + { + foreach ($service_order_group as $service_id) + { + $this->offsetSet($service_id, null); + } + } + + $this->is_ordered = true; + } +} diff --git a/phpBB/phpbb/di/pass/collection_pass.php b/phpBB/phpbb/di/pass/collection_pass.php index a5c054674e..341f88518d 100644 --- a/phpBB/phpbb/di/pass/collection_pass.php +++ b/phpBB/phpbb/di/pass/collection_pass.php @@ -34,10 +34,30 @@ class collection_pass implements CompilerPassInterface foreach ($container->findTaggedServiceIds('service_collection') as $id => $data) { $definition = $container->getDefinition($id); + $is_ordered_collection = (substr($definition->getClass(), -strlen('ordered_service_collection')) === 'ordered_service_collection'); + $is_class_name_aware = (isset($data[0]['class_name_aware']) && $data[0]['class_name_aware']); foreach ($container->findTaggedServiceIds($data[0]['tag']) as $service_id => $service_data) { - $definition->addMethodCall('add', array($service_id)); + if ($is_ordered_collection) + { + $arguments = array($service_id, $service_data[0]['order']); + } + else + { + $arguments = array($service_id); + } + + if ($is_class_name_aware) + { + $service_definition = $container->getDefinition($service_id); + $definition->addMethodCall('add_service_class', array( + $service_id, + $service_definition->getClass() + )); + } + + $definition->addMethodCall('add', $arguments); } } } diff --git a/phpBB/phpbb/di/proxy_instantiator.php b/phpBB/phpbb/di/proxy_instantiator.php new file mode 100644 index 0000000000..a388e82c0e --- /dev/null +++ b/phpBB/phpbb/di/proxy_instantiator.php @@ -0,0 +1,77 @@ +<?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 bantu\IniGetWrapper\IniGetWrapper; +use phpbb\filesystem\filesystem; +use ProxyManager\Configuration; +use ProxyManager\Factory\LazyLoadingValueHolderFactory; +use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface; + +/** + * Runtime lazy loading proxy generator extended for allowing use while using + * open_basedir restrictions + * + * Original author: Marco Pivetta <ocramius@gmail.com> + */ +class proxy_instantiator implements InstantiatorInterface +{ + /** + * @var LazyLoadingValueHolderFactory + */ + private $factory; + + /** + * proxy_instantiator constructor + * @param string $cache_dir Cache dir for fall back when using open_basedir + */ + public function __construct($cache_dir) + { + $config = new Configuration(); + + // Prevent trying to write to system temp dir in case of open_basedir + // restrictions being in effect + $ini_wrapper = new IniGetWrapper(); + $filesystem = new filesystem(); + $tmp_dir = (function_exists('sys_get_temp_dir')) ? sys_get_temp_dir() : ''; + if (empty($tmp_dir) || $ini_wrapper->getString('open_basedir') && + (!$filesystem->exists($tmp_dir) || !$filesystem->is_writable($tmp_dir))) + { + $config->setProxiesTargetDir($cache_dir); + } + $config->setGeneratorStrategy(new EvaluatingGeneratorStrategy()); + + $this->factory = new LazyLoadingValueHolderFactory($config); + } + + /** + * {@inheritdoc} + */ + public function instantiateProxy(ContainerInterface $container, Definition $definition, $id, $realInstantiator) + { + return $this->factory->createProxy( + $definition->getClass(), + function (&$wrappedInstance, \ProxyManager\Proxy\LazyLoadingInterface $proxy) use ($realInstantiator) { + $wrappedInstance = call_user_func($realInstantiator); + + $proxy->setProxyInitializer(null); + + return true; + } + ); + } +} diff --git a/phpBB/phpbb/di/service_collection.php b/phpBB/phpbb/di/service_collection.php index 82ca9bf679..8e9175e204 100644 --- a/phpBB/phpbb/di/service_collection.php +++ b/phpBB/phpbb/di/service_collection.php @@ -26,6 +26,11 @@ class service_collection extends \ArrayObject protected $container; /** + * @var array + */ + protected $service_classes; + + /** * Constructor * * @param ContainerInterface $container Container object @@ -33,6 +38,7 @@ class service_collection extends \ArrayObject public function __construct(ContainerInterface $container) { $this->container = $container; + $this->service_classes = array(); } /** @@ -76,4 +82,25 @@ class service_collection extends \ArrayObject { $this->offsetSet($name, null); } + + /** + * Add a service's class to the collection + * + * @param string $service_id + * @param string $class + */ + public function add_service_class($service_id, $class) + { + $this->service_classes[$service_id] = $class; + } + + /** + * Get services' classes + * + * @return array + */ + public function get_service_classes() + { + return $this->service_classes; + } } diff --git a/phpBB/phpbb/di/service_collection_iterator.php b/phpBB/phpbb/di/service_collection_iterator.php index 0d031ab52d..31bc156e99 100644 --- a/phpBB/phpbb/di/service_collection_iterator.php +++ b/phpBB/phpbb/di/service_collection_iterator.php @@ -32,7 +32,7 @@ class service_collection_iterator extends \ArrayIterator */ public function __construct(service_collection $collection, $flags = 0) { - parent::__construct($collection, $flags); + parent::__construct($collection->getArrayCopy(), $flags); $this->collection = $collection; } |