[ Index ]

PHP Cross Reference of phpBB-3.2.11-deutsch

title

Body

[close]

/phpbb/di/ -> container_builder.php (source)

   1  <?php
   2  /**
   3  *
   4  * This file is part of the phpBB Forum Software package.
   5  *
   6  * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7  * @license GNU General Public License, version 2 (GPL-2.0)
   8  *
   9  * For full copyright and license information, please see
  10  * the docs/CREDITS.txt file.
  11  *
  12  */
  13  
  14  namespace phpbb\di;
  15  
  16  use phpbb\filesystem\filesystem;
  17  use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper;
  18  use Symfony\Component\Config\ConfigCache;
  19  use Symfony\Component\Config\FileLocator;
  20  use Symfony\Component\DependencyInjection\ContainerBuilder;
  21  use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
  22  use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
  23  use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
  24  use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
  25  use Symfony\Component\Filesystem\Exception\IOException;
  26  use Symfony\Component\Finder\Finder;
  27  use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass;
  28  
  29  class container_builder
  30  {
  31      /**
  32       * @var string The environment to use.
  33       */
  34      protected $environment;
  35  
  36      /**
  37       * @var string phpBB Root Path
  38       */
  39      protected $phpbb_root_path;
  40  
  41      /**
  42       * @var string php file extension
  43       */
  44      protected $php_ext;
  45  
  46      /**
  47       * The container under construction
  48       *
  49       * @var ContainerBuilder
  50       */
  51      protected $container;
  52  
  53      /**
  54       * @var \phpbb\db\driver\driver_interface
  55       */
  56      protected $dbal_connection = null;
  57  
  58      /**
  59       * Indicates whether extensions should be used (default to true).
  60       *
  61       * @var bool
  62       */
  63      protected $use_extensions = true;
  64  
  65      /**
  66       * Defines a custom path to find the configuration of the container (default to $this->phpbb_root_path . 'config')
  67       *
  68       * @var string
  69       */
  70      protected $config_path = null;
  71  
  72      /**
  73       * Indicates whether the container should be dumped to the filesystem (default to true).
  74       *
  75       * If DEBUG_CONTAINER is set this option is ignored and a new container is build.
  76       *
  77       * @var bool
  78       */
  79      protected $use_cache = true;
  80  
  81      /**
  82       * Indicates if the container should be compiled automatically (default to true).
  83       *
  84       * @var bool
  85       */
  86      protected $compile_container = true;
  87  
  88      /**
  89       * Custom parameters to inject into the container.
  90       *
  91       * Default to:
  92       *     array(
  93       *         'core.root_path', $this->phpbb_root_path,
  94       *         'core.php_ext', $this->php_ext,
  95       * );
  96       *
  97       * @var array
  98       */
  99      protected $custom_parameters = [];
 100  
 101      /**
 102       * @var \phpbb\config_php_file
 103       */
 104      protected $config_php_file;
 105  
 106      /**
 107       * @var string
 108       */
 109      protected $cache_dir;
 110  
 111      /**
 112       * @var array
 113       */
 114      private $container_extensions;
 115  
 116      /** @var \Exception */
 117      private $build_exception;
 118  
 119      /**
 120       * Constructor
 121       *
 122       * @param string $phpbb_root_path Path to the phpbb includes directory.
 123       * @param string $php_ext php file extension
 124       */
 125  	public function __construct($phpbb_root_path, $php_ext)
 126      {
 127          $this->phpbb_root_path = $phpbb_root_path;
 128          $this->php_ext = $php_ext;
 129      }
 130  
 131      /**
 132       * Build and return a new Container respecting the current configuration
 133       *
 134       * @return \phpbb_cache_container|ContainerBuilder
 135       */
 136  	public function get_container()
 137      {
 138          try
 139          {
 140              $container_filename = $this->get_container_filename();
 141              $config_cache = new ConfigCache($container_filename, defined('DEBUG'));
 142              if ($this->use_cache && $config_cache->isFresh())
 143              {
 144                  if ($this->use_extensions)
 145                  {
 146                      $autoload_cache = new ConfigCache($this->get_autoload_filename(), defined('DEBUG'));
 147                      if (!$autoload_cache->isFresh())
 148                      {
 149                          // autoload cache should be refreshed
 150                          $this->load_extensions();
 151                      }
 152  
 153                      require($this->get_autoload_filename());
 154                  }
 155  
 156                  require($config_cache->getPath());
 157                  $this->container = new \phpbb_cache_container();
 158              }
 159              else
 160              {
 161                  $this->container_extensions = array(new extension\core($this->get_config_path()));
 162  
 163                  if ($this->use_extensions)
 164                  {
 165                      $this->load_extensions();
 166                  }
 167  
 168                  // Inject the config
 169                  if ($this->config_php_file)
 170                  {
 171                      $this->container_extensions[] = new extension\config($this->config_php_file);
 172                  }
 173  
 174                  $this->container = $this->create_container($this->container_extensions);
 175  
 176                  // Easy collections through tags
 177                  $this->container->addCompilerPass(new pass\collection_pass());
 178  
 179                  // Event listeners "phpBB style"
 180                  $this->container->addCompilerPass(new RegisterListenersPass('dispatcher', 'event.listener_listener', 'event.listener'));
 181  
 182                  // Event listeners "Symfony style"
 183                  $this->container->addCompilerPass(new RegisterListenersPass('dispatcher'));
 184  
 185                  if ($this->use_extensions)
 186                  {
 187                      $this->register_ext_compiler_pass();
 188                  }
 189  
 190                  $filesystem = new filesystem();
 191                  $loader     = new YamlFileLoader($this->container, new FileLocator($filesystem->realpath($this->get_config_path())));
 192                  $loader->load($this->container->getParameter('core.environment') . '/config.yml');
 193  
 194                  $this->inject_custom_parameters();
 195  
 196                  if ($this->compile_container)
 197                  {
 198                      $this->container->compile();
 199  
 200                      if ($this->use_cache)
 201                      {
 202                          $this->dump_container($config_cache);
 203                      }
 204                  }
 205              }
 206  
 207              if ($this->compile_container && $this->config_php_file)
 208              {
 209                  $this->container->set('config.php', $this->config_php_file);
 210              }
 211  
 212              $this->inject_dbal_driver();
 213  
 214              return $this->container;
 215          }
 216          catch (\Exception $e)
 217          {
 218              // Don't try to recover if we are in the development environment
 219              if ($this->get_environment() === 'development')
 220              {
 221                  throw $e;
 222              }
 223  
 224              if ($this->build_exception === null)
 225              {
 226                  $this->build_exception = $e;
 227  
 228                  return $this
 229                      ->without_extensions()
 230                      ->without_cache()
 231                      ->with_custom_parameters(array_merge($this->custom_parameters, [
 232                          'container_exception' => $e,
 233                      ]))
 234                      ->get_container();
 235              }
 236              else
 237              {
 238                  // Rethrow the original exception if it's still failing
 239                  throw $this->build_exception;
 240              }
 241          }
 242      }
 243  
 244      /**
 245       * Enable the extensions.
 246       *
 247       * @param string $environment The environment to use
 248       * @return $this
 249       */
 250  	public function with_environment($environment)
 251      {
 252          $this->environment = $environment;
 253  
 254          return $this;
 255      }
 256  
 257      /**
 258       * Enable the extensions.
 259       *
 260       * @return $this
 261       */
 262  	public function with_extensions()
 263      {
 264          $this->use_extensions = true;
 265  
 266          return $this;
 267      }
 268  
 269      /**
 270       * Disable the extensions.
 271       *
 272       * @return $this
 273       */
 274  	public function without_extensions()
 275      {
 276          $this->use_extensions = false;
 277  
 278          return $this;
 279      }
 280  
 281      /**
 282       * Enable the caching of the container.
 283       *
 284       * If DEBUG_CONTAINER is set this option is ignored and a new container is build.
 285       *
 286       * @return $this
 287       */
 288  	public function with_cache()
 289      {
 290          $this->use_cache = true;
 291  
 292          return $this;
 293      }
 294  
 295      /**
 296       * Disable the caching of the container.
 297       *
 298       * @return $this
 299       */
 300  	public function without_cache()
 301      {
 302          $this->use_cache = false;
 303  
 304          return $this;
 305      }
 306  
 307      /**
 308       * Set the cache directory.
 309       *
 310       * @param string $cache_dir The cache directory.
 311       * @return $this
 312       */
 313  	public function with_cache_dir($cache_dir)
 314      {
 315          $this->cache_dir = $cache_dir;
 316  
 317          return $this;
 318      }
 319  
 320      /**
 321       * Enable the compilation of the container.
 322       *
 323       * @return $this
 324       */
 325  	public function with_compiled_container()
 326      {
 327          $this->compile_container = true;
 328  
 329          return $this;
 330      }
 331  
 332      /**
 333       * Disable the compilation of the container.
 334       *
 335       * @return $this
 336       */
 337  	public function without_compiled_container()
 338      {
 339          $this->compile_container = false;
 340  
 341          return $this;
 342      }
 343  
 344      /**
 345       * Set a custom path to find the configuration of the container.
 346       *
 347       * @param string $config_path
 348       * @return $this
 349       */
 350  	public function with_config_path($config_path)
 351      {
 352          $this->config_path = $config_path;
 353  
 354          return $this;
 355      }
 356  
 357      /**
 358       * Set custom parameters to inject into the container.
 359       *
 360       * @param array $custom_parameters
 361       * @return $this
 362       */
 363  	public function with_custom_parameters($custom_parameters)
 364      {
 365          $this->custom_parameters = $custom_parameters;
 366  
 367          return $this;
 368      }
 369  
 370      /**
 371       * Set custom parameters to inject into the container.
 372       *
 373       * @param \phpbb\config_php_file $config_php_file
 374       * @return $this
 375       */
 376  	public function with_config(\phpbb\config_php_file $config_php_file)
 377      {
 378          $this->config_php_file = $config_php_file;
 379  
 380          return $this;
 381      }
 382  
 383      /**
 384       * Returns the path to the container configuration (default: root_path/config)
 385       *
 386       * @return string
 387       */
 388  	protected function get_config_path()
 389      {
 390          return $this->config_path ?: $this->phpbb_root_path . 'config';
 391      }
 392  
 393      /**
 394       * Returns the path to the cache directory (default: root_path/cache/environment).
 395       *
 396       * @return string Path to the cache directory.
 397       */
 398  	protected function get_cache_dir()
 399      {
 400          return $this->cache_dir ?: $this->phpbb_root_path . 'cache/' . $this->get_environment() . '/';
 401      }
 402  
 403      /**
 404       * Load the enabled extensions.
 405       */
 406  	protected function load_extensions()
 407      {
 408          if ($this->config_php_file !== null)
 409          {
 410              // Build an intermediate container to load the ext list from the database
 411              $container_builder = new container_builder($this->phpbb_root_path, $this->php_ext);
 412              $ext_container = $container_builder
 413                  ->without_cache()
 414                  ->without_extensions()
 415                  ->with_config($this->config_php_file)
 416                  ->with_config_path($this->get_config_path())
 417                  ->with_environment('production')
 418                  ->without_compiled_container()
 419                  ->get_container()
 420              ;
 421  
 422              $ext_container->register('cache.driver', '\\phpbb\\cache\\driver\\dummy');
 423              $ext_container->compile();
 424  
 425              $extensions = $ext_container->get('ext.manager')->all_enabled();
 426  
 427              // Load each extension found
 428              $autoloaders = '<?php
 429  /**
 430   * Loads all extensions custom auto-loaders.
 431   *
 432   * This file has been auto-generated
 433   * by phpBB while loading the extensions.
 434   */
 435  
 436  ';
 437              foreach ($extensions as $ext_name => $path)
 438              {
 439                  $extension_class = '\\' . str_replace('/', '\\', $ext_name) . '\\di\\extension';
 440  
 441                  if (!class_exists($extension_class))
 442                  {
 443                      $extension_class = '\\phpbb\\extension\\di\\extension_base';
 444                  }
 445  
 446                  $this->container_extensions[] = new $extension_class($ext_name, $path);
 447  
 448                  // Load extension autoloader
 449                  $filename = $path . 'vendor/autoload.php';
 450                  if (file_exists($filename))
 451                  {
 452                      $autoloaders .= "require('{$filename}');\n";
 453                  }
 454              }
 455  
 456              $configCache = new ConfigCache($this->get_autoload_filename(), false);
 457              $configCache->write($autoloaders);
 458  
 459              require($this->get_autoload_filename());
 460          }
 461          else
 462          {
 463              // To load the extensions we need the database credentials.
 464              // Automatically disable the extensions if we don't have them.
 465              $this->use_extensions = false;
 466          }
 467      }
 468  
 469      /**
 470       * Dump the container to the disk.
 471       *
 472       * @param ConfigCache $cache The config cache
 473       */
 474  	protected function dump_container($cache)
 475      {
 476          try
 477          {
 478              $dumper = new PhpDumper($this->container);
 479              $proxy_dumper = new ProxyDumper();
 480              $dumper->setProxyDumper($proxy_dumper);
 481  
 482              $cached_container_dump = $dumper->dump(array(
 483                  'class'      => 'phpbb_cache_container',
 484                  'base_class' => 'Symfony\\Component\\DependencyInjection\\ContainerBuilder',
 485              ));
 486  
 487              $cache->write($cached_container_dump, $this->container->getResources());
 488          }
 489          catch (IOException $e)
 490          {
 491              // Don't fail if the cache isn't writeable
 492          }
 493      }
 494  
 495      /**
 496       * Create the ContainerBuilder object
 497       *
 498       * @param array $extensions Array of Container extension objects
 499       * @return ContainerBuilder object
 500       */
 501  	protected function create_container(array $extensions)
 502      {
 503          $container = new ContainerBuilder(new ParameterBag($this->get_core_parameters()));
 504          $container->setProxyInstantiator(new proxy_instantiator($this->get_cache_dir()));
 505  
 506          $extensions_alias = array();
 507  
 508          foreach ($extensions as $extension)
 509          {
 510              $container->registerExtension($extension);
 511              $extensions_alias[] = $extension->getAlias();
 512          }
 513  
 514          $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions_alias));
 515  
 516          return $container;
 517      }
 518  
 519      /**
 520       * Inject the customs parameters into the container
 521       */
 522  	protected function inject_custom_parameters()
 523      {
 524          foreach ($this->custom_parameters as $key => $value)
 525          {
 526              $this->container->setParameter($key, $value);
 527          }
 528      }
 529  
 530      /**
 531       * Inject the dbal connection driver into container
 532       */
 533  	protected function inject_dbal_driver()
 534      {
 535          if (empty($this->config_php_file))
 536          {
 537              return;
 538          }
 539  
 540          $config_data = $this->config_php_file->get_all();
 541          if (!empty($config_data))
 542          {
 543              if ($this->dbal_connection === null)
 544              {
 545                  $dbal_driver_class = $this->config_php_file->convert_30_dbms_to_31($this->config_php_file->get('dbms'));
 546                  /** @var \phpbb\db\driver\driver_interface $dbal_connection */
 547                  $this->dbal_connection = new $dbal_driver_class();
 548                  $this->dbal_connection->sql_connect(
 549                      $this->config_php_file->get('dbhost'),
 550                      $this->config_php_file->get('dbuser'),
 551                      $this->config_php_file->get('dbpasswd'),
 552                      $this->config_php_file->get('dbname'),
 553                      $this->config_php_file->get('dbport'),
 554                      false,
 555                      defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK
 556                  );
 557              }
 558              $this->container->set('dbal.conn.driver', $this->dbal_connection);
 559          }
 560      }
 561  
 562      /**
 563       * Returns the core parameters.
 564       *
 565       * @return array An array of core parameters
 566       */
 567  	protected function get_core_parameters()
 568      {
 569          return array_merge(
 570              array(
 571                  'core.root_path'     => $this->phpbb_root_path,
 572                  'core.php_ext'       => $this->php_ext,
 573                  'core.environment'   => $this->get_environment(),
 574                  'core.debug'         => defined('DEBUG') ? DEBUG : false,
 575                  'core.cache_dir'     => $this->get_cache_dir(),
 576              ),
 577              $this->get_env_parameters()
 578          );
 579      }
 580  
 581      /**
 582       * Gets the environment parameters.
 583       *
 584       * Only the parameters starting with "PHPBB__" are considered.
 585       *
 586       * @return array An array of parameters
 587       */
 588  	protected function get_env_parameters()
 589      {
 590          $parameters = array();
 591          foreach ($_SERVER as $key => $value)
 592          {
 593              if (0 === strpos($key, 'PHPBB__'))
 594              {
 595                  $parameters[strtolower(str_replace('__', '.', substr($key, 9)))] = $value;
 596              }
 597          }
 598  
 599          return $parameters;
 600      }
 601  
 602      /**
 603       * Get the filename under which the dumped container will be stored.
 604       *
 605       * @return string Path for dumped container
 606       */
 607  	protected function get_container_filename()
 608      {
 609          $container_params = [
 610              'phpbb_root_path' => $this->phpbb_root_path,
 611              'use_extensions' => $this->use_extensions,
 612              'config_path' => $this->config_path,
 613          ];
 614  
 615          return $this->get_cache_dir() . 'container_' . md5(implode(',', $container_params)) . '.' . $this->php_ext;
 616      }
 617  
 618      /**
 619       * Get the filename under which the dumped extensions autoloader will be stored.
 620       *
 621       * @return string Path for dumped extensions autoloader
 622       */
 623  	protected function get_autoload_filename()
 624      {
 625          $container_params = [
 626              'phpbb_root_path' => $this->phpbb_root_path,
 627              'use_extensions' => $this->use_extensions,
 628              'config_path' => $this->config_path,
 629          ];
 630  
 631          return $this->get_cache_dir() . 'autoload_' . md5(implode(',', $container_params)) . '.' . $this->php_ext;
 632      }
 633  
 634      /**
 635       * Return the name of the current environment.
 636       *
 637       * @return string
 638       */
 639  	protected function get_environment()
 640      {
 641          return $this->environment ?: PHPBB_ENVIRONMENT;
 642      }
 643  
 644  	private function register_ext_compiler_pass()
 645      {
 646          $finder = new Finder();
 647          $finder
 648              ->name('*_pass.php')
 649              ->path('di/pass')
 650              ->files()
 651              ->ignoreDotFiles(true)
 652              ->ignoreUnreadableDirs(true)
 653              ->ignoreVCS(true)
 654              ->followLinks()
 655              ->in($this->phpbb_root_path . 'ext')
 656          ;
 657  
 658          /** @var \SplFileInfo $pass */
 659          foreach ($finder as $pass)
 660          {
 661              $filename = $pass->getPathname();
 662              $filename = substr($filename, 0, -strlen('.' . $pass->getExtension()));
 663              $filename = str_replace(DIRECTORY_SEPARATOR, '/', $filename);
 664              $className = preg_replace('#^.*ext/#', '', $filename);
 665              $className = '\\' . str_replace('/', '\\', $className);
 666  
 667              if (class_exists($className) && in_array('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface', class_implements($className), true))
 668              {
 669                  $this->container->addCompilerPass(new $className());
 670              }
 671          }
 672      }
 673  }


Generated: Wed Nov 11 20:33:01 2020 Cross-referenced by PHPXref 0.7.1