diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 77458a1..8e5418f 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -1,5 +1,7 @@ exists('container.early')) { + $storage->delete('container.early'); + } } + if (isset($new_container)) { $container = $new_container; } - if (!isset($container)) { - // Return a ContainerBuilder instance with the bare essentials needed for any - // full bootstrap regardless of whether there will be a DrupalKernel involved. - // This will get merged with the full Kernel-built Container on normal page - // requests. - $container = new ContainerBuilder(); - - // Register active configuration storage. - $container - ->register('config.cachedstorage.storage', 'Drupal\Core\Config\FileStorage') - ->addArgument(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY)); - // @todo Replace this with a cache.factory service plus 'config' argument. - $container - ->register('cache.config') - ->setFactoryClass('Drupal\Core\Cache\CacheFactory') - ->setFactoryMethod('get') - ->addArgument('config'); - - $container - ->register('config.storage', 'Drupal\Core\Config\CachedStorage') - ->addArgument(new Reference('config.cachedstorage.storage')) - ->addArgument(new Reference('cache.config')); - - // Register configuration object factory. - $container->register('config.subscriber.globalconf', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber'); - $container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher') - ->addMethodCall('addSubscriber', array(new Reference('config.subscriber.globalconf'))); - $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') - ->addArgument(new Reference('config.storage')) - ->addArgument(new Reference('dispatcher')); - - // Register staging configuration storage. - $container - ->register('config.storage.staging', 'Drupal\Core\Config\FileStorage') - ->addArgument(config_get_config_directory(CONFIG_STAGING_DIRECTORY)); - $container - ->register('state.storage', 'Drupal\Core\KeyValueStore\DatabaseStorage') - ->addArgument('state'); + else if (!isset($container)) { + + $storage = drupal_php_storage(); + + // Load the container from compiled code if necessary. + /* + if ($storage->load('container.early')) { + $container = new DrupalCoreEarlyContainer(); + } + else { + */ + // Return a ContainerBuilder instance with the bare essentials needed for any + // full bootstrap regardless of whether there will be a DrupalKernel involved. + // This will get merged with the full Kernel-built Container on normal page + // requests. + $container = new ContainerBuilder(); + + $container + ->register('database', 'Drupal\Core\Database\Connection') + ->setFactoryClass('Drupal\Core\Database\Database') + ->setFactoryMethod('getConnection') + ->addArgument('default'); + + $container + ->register('database.slave', 'Drupal\Core\Database\Connection') + ->setFactoryClass('Drupal\Core\Database\Database') + ->setFactoryMethod('getConnection') + ->addArgument('slave'); + + $container + ->register('module.manager', 'Drupal\Core\Module\ModuleManager') + ->addArgument(new Reference('database')); + + $container->setParameter('system.module.list', $container->get('module.manager')->getEnabledModuleList()); + + /* + $dumper = new PhpDumper($container); + $storage->save('container.early', $dumper->dump(array('class' => 'DrupalCoreEarlyContainer'))); + } + */ } + return $container; } diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index dfb41f5..2aa96c4 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -4,6 +4,7 @@ use Drupal\Core\Database\Database; use Drupal\Core\Database\Install\TaskException; use Drupal\Core\Language\Language; +use Drupal\Core\MaintainanceKernel; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; @@ -286,6 +287,10 @@ function install_begin_request(&$install_state) { include_once DRUPAL_ROOT . '/core/includes/session.inc'; require_once DRUPAL_ROOT . '/core/includes/entity.inc'; + // Create the container using the maintainance kernel. + $kernel = new MaintainanceKernel('prod', false); + $kernel->boot(); + // Determine whether the configuration system is ready to operate. $install_state['config_verified'] = install_verify_config_directory(CONFIG_ACTIVE_DIRECTORY) && install_verify_config_directory(CONFIG_STAGING_DIRECTORY); @@ -312,20 +317,8 @@ function install_begin_request(&$install_state) { // This override is reverted as soon as the config directory has been set up // successfully. // @see drupal_install_config_directories() - if (!$install_state['config_verified']) { - // @todo Move into a proper Drupal\Core\DependencyInjection\InstallContainerBuilder. - $container = new ContainerBuilder(); - - $container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher'); - - $container->register('config.storage', 'Drupal\Core\Config\InstallStorage'); - $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') - ->addArgument(new Reference('config.storage')) - ->addArgument(new Reference('dispatcher')); - $container - ->register('state.storage', 'Drupal\Core\KeyValueStore\DatabaseStorage') - ->addArgument('state'); - drupal_container($container); + if ($install_state['config_verified']) { + $container = $kernel->getContainer()->enterScope('config-ready'); } // Set up $language, so t() caller functions will still work. @@ -1105,15 +1098,30 @@ function install_settings_form_submit($form, &$form_state) { 'required' => TRUE, ); - drupal_rewrite_settings($settings); - // Add the config directories to settings.php. - drupal_install_config_directories(); + $settings += drupal_install_config_directories(); + + // First ensure they exist. + foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $config_type) { + // This should never fail, since if the config directory was specified in + // settings.php it will have already been created and verified earlier, and + // if it wasn't specified in settings.php, it is created here inside the + // public files directory, which has already been verified to be writable + // itself. But if it somehow fails anyway, the installation cannot proceed. + // Bail out using a similar error message as in system_requirements(). + if (!install_ensure_config_directory($config_type)) { + throw new Exception(st('The directory %directory could not be created or could not be made writable. To proceed with the installation, either create the directory and modify its permissions manually or ensure that the installer has the permissions to create it automatically. For more information, see the online handbook.', array( + '%directory' => config_get_config_directory($config_type), + '@handbook_url' => 'http://drupal.org/server-permissions', + ))); + } + } + + // Rewrite settings.php with both database and config settings options. + drupal_rewrite_settings($settings); - // We have valid configuration directories in settings.php. - // Reset the service container, so the config.storage service will use the - // actual active storage for installing configuration. - drupal_container(NULL, TRUE); + // Now everything is able to use the config API. + drupal_container()->enterScope('config-ready'); // Indicate that the settings file has been verified, and check the database // for the last completed task, now that we have a valid connection. This diff --git a/core/includes/install.inc b/core/includes/install.inc index 3c30c89..d8467ac 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -261,39 +261,27 @@ function drupal_rewrite_settings($settings = array()) { function drupal_install_config_directories() { global $config_directories; + $settings = array(); + // Add a randomized config directory name to settings.php, unless it was // manually defined in the existing already. if (empty($config_directories)) { - $settings['config_directories'] = array( - 'value' => array( - CONFIG_ACTIVE_DIRECTORY => array( - 'path' => 'config/active_' . drupal_hash_base64(drupal_random_bytes(55)), - ), - CONFIG_STAGING_DIRECTORY => array( - 'path' => 'config/staging_' . drupal_hash_base64(drupal_random_bytes(55)), - ), + $config_directories = array( + CONFIG_ACTIVE_DIRECTORY => array( + 'path' => 'config/active_' . drupal_hash_base64(drupal_random_bytes(55)), ), - 'required' => TRUE, + CONFIG_STAGING_DIRECTORY => array( + 'path' => 'config/staging_' . drupal_hash_base64(drupal_random_bytes(55)), + ) ); - // Rewrite settings.php, which also sets the value as global variable. - drupal_rewrite_settings($settings); - } - - // Ensure the config directories exist or can be created, and are writable. - foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $config_type) { - // This should never fail, since if the config directory was specified in - // settings.php it will have already been created and verified earlier, and - // if it wasn't specified in settings.php, it is created here inside the - // public files directory, which has already been verified to be writable - // itself. But if it somehow fails anyway, the installation cannot proceed. - // Bail out using a similar error message as in system_requirements(). - if (!install_ensure_config_directory($config_type)) { - throw new Exception(st('The directory %directory could not be created or could not be made writable. To proceed with the installation, either create the directory and modify its permissions manually or ensure that the installer has the permissions to create it automatically. For more information, see the online handbook.', array( - '%directory' => config_get_config_directory($config_type), - '@handbook_url' => 'http://drupal.org/server-permissions', - ))); - } } + + $settings['config_directories'] = array( + 'value' => $config_directories, + 'required' => TRUE, + ); + + return $settings; } /** diff --git a/core/includes/update.inc b/core/includes/update.inc index 5d80188..69030bc 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -173,7 +173,17 @@ function update_prepare_d8_bootstrap() { // them. If the directories have not been specified in settings.php and // created manually already, and either directory cannot be created by the // web server, an exception will be thrown, halting the update. - drupal_install_config_directories(); + $settings = drupal_install_config_directories(); + foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $config_type) { + if (!install_ensure_config_directory($config_type)) { + // @see install_settings_form_submit() for details. + throw new Exception(st('The directory %directory could not be created or could not be made writable. To proceed with the installation, either create the directory and modify its permissions manually or ensure that the installer has the permissions to create it automatically. For more information, see the online handbook.', array( + '%directory' => config_get_config_directory($config_type), + '@handbook_url' => 'http://drupal.org/server-permissions', + ))); + } + } + drupal_rewrite_settings($settings); // Change language column to langcode in url_alias. if (db_table_exists('url_alias') && db_field_exists('url_alias', 'language')) { diff --git a/core/lib/Drupal/Component/PhpStorage/MTimeProtectedFastFileStorage.php b/core/lib/Drupal/Component/PhpStorage/MTimeProtectedFastFileStorage.php index 4e2aec5..c343c37 100644 --- a/core/lib/Drupal/Component/PhpStorage/MTimeProtectedFastFileStorage.php +++ b/core/lib/Drupal/Component/PhpStorage/MTimeProtectedFastFileStorage.php @@ -144,7 +144,7 @@ protected function ensureDirectory() { mkdir($this->directory, 0700, TRUE); } chmod($this->directory, 0700); - file_save_htaccess($this->directory); + //file_save_htaccess($this->directory); } /** diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index ed15dd5..74fbaf4 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -28,6 +28,38 @@ class CoreBundle extends Bundle { public function build(ContainerBuilder $container) { + // Register active configuration storage. + $container + ->register('config.cachedstorage.storage', 'Drupal\Core\Config\FileStorage') + ->addArgument(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY)); + // @todo Replace this with a cache.factory service plus 'config' argument. + $container + ->register('cache.config') + ->setFactoryClass('Drupal\Core\Cache\CacheFactory') + ->setFactoryMethod('get') + ->addArgument('config'); + + $container + ->register('config.storage', 'Drupal\Core\Config\CachedStorage') + ->addArgument(new Reference('config.cachedstorage.storage')) + ->addArgument(new Reference('cache.config')); + + // Register configuration object factory. + $container->register('config.subscriber.globalconf', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber'); + $container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher') + ->addMethodCall('addSubscriber', array(new Reference('config.subscriber.globalconf'))); + $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') + ->addArgument(new Reference('config.storage')) + ->addArgument(new Reference('dispatcher')); + + // Register staging configuration storage. + $container + ->register('config.storage.staging', 'Drupal\Core\Config\FileStorage') + ->addArgument(config_get_config_directory(CONFIG_STAGING_DIRECTORY)); + $container + ->register('state.storage', 'Drupal\Core\KeyValueStore\DatabaseStorage') + ->addArgument('state'); + // The 'request' scope and service enable services to depend on the Request // object and get reconstructed when the request object changes (e.g., // during a subrequest). @@ -46,14 +78,6 @@ public function build(ContainerBuilder $container) { $container->register('language_manager', 'Drupal\Core\Language\LanguageManager') ->addArgument(new Reference('request')) ->setScope('request'); - $container->register('database', 'Drupal\Core\Database\Connection') - ->setFactoryClass('Drupal\Core\Database\Database') - ->setFactoryMethod('getConnection') - ->addArgument('default'); - $container->register('database.slave', 'Drupal\Core\Database\Connection') - ->setFactoryClass('Drupal\Core\Database\Database') - ->setFactoryMethod('getConnection') - ->addArgument('slave'); $container->register('typed_data', 'Drupal\Core\TypedData\TypedDataManager'); // Add the user's storage for temporary, non-cache data. $container->register('lock', 'Drupal\Core\Lock\DatabaseLockBackend'); diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index 869d4ee..3caf394 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -43,10 +43,10 @@ public function registerBundles() { new CoreBundle(), ); - // @todo Remove the necessity of calling system_list() to find out which - // bundles exist. See http://drupal.org/node/1331486 - $modules = array_keys(system_list('module_enabled')); - foreach ($modules as $module) { + $modules = drupal_container()->getParameter('system.module.list'); + $modules = array_keys($modules); + + foreach ($modules as $module => $path) { $camelized = ContainerBuilder::camelize($module); $class = "Drupal\\{$module}\\{$camelized}Bundle"; if (class_exists($class)) { diff --git a/core/lib/Drupal/Core/MaintainanceBundle.php b/core/lib/Drupal/Core/MaintainanceBundle.php new file mode 100644 index 0000000..122170a 100644 --- /dev/null +++ b/core/lib/Drupal/Core/MaintainanceBundle.php @@ -0,0 +1,96 @@ +register('config.storage', 'Drupal\Core\Config\InstallStorage'); + $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') + ->addArgument(new Reference('config.storage')) + ->addArgument(new Reference('dispatcher')); + $container + ->register('state.storage', 'Drupal\Core\KeyValueStore\DatabaseStorage') + ->addArgument('state'); + + $container->addScope(new Scope('config-ready')); + + // Ensure config directories exists. Do not write them, and let the later + // install step do it properly when settings.php will be written. This only + // populates the global variables. + drupal_install_config_directories(); + + // Register active configuration storage. + $container + ->register('config.cachedstorage.storage', 'Drupal\Core\Config\FileStorage') + ->addArgument(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY)); + + // @todo Replace this with a cache.factory service plus 'config' argument. + $container + ->register('cache.config') + ->setFactoryClass('Drupal\Core\Cache\CacheFactory') + ->setFactoryMethod('get') + ->addArgument('config'); + + $container + ->register('config.storage', 'Drupal\Core\Config\CachedStorage') + ->addArgument(new Reference('config.cachedstorage.storage')) + ->addArgument(new Reference('cache.config')); + + // Register configuration object factory. + $container->register('config.subscriber.globalconf', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber'); + $container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher') + ->addMethodCall('addSubscriber', array(new Reference('config.subscriber.globalconf'))); + $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') + ->addArgument(new Reference('config.storage')) + ->addArgument(new Reference('dispatcher')); + + // Register staging configuration storage. + $container + ->register('config.storage.staging', 'Drupal\Core\Config\FileStorage') + ->addArgument(config_get_config_directory(CONFIG_STAGING_DIRECTORY)); + $container + ->register('state.storage', 'Drupal\Core\KeyValueStore\DatabaseStorage') + ->addArgument('state'); + + // The 'request' scope and service enable services to depend on the Request + // object and get reconstructed when the request object changes (e.g., + // during a subrequest). + $container->addScope(new Scope('request')); + $container->register('request', 'Symfony\Component\HttpFoundation\Request') + ->setSynthetic(TRUE); + + $container->register('dispatcher', 'Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher') + ->addArgument(new Reference('service_container')); + $container->register('resolver', 'Drupal\Core\ControllerResolver') + ->addArgument(new Reference('service_container')); + $container->register('http_kernel', 'Drupal\Core\HttpKernel') + ->addArgument(new Reference('dispatcher')) + ->addArgument(new Reference('service_container')) + ->addArgument(new Reference('resolver')); + $container->register('language_manager', 'Drupal\Core\Language\LanguageManager') + ->addArgument(new Reference('request')) + ->setScope('request'); + $container->register('typed_data', 'Drupal\Core\TypedData\TypedDataManager'); + // Add the user's storage for temporary, non-cache data. + $container->register('lock', 'Drupal\Core\Lock\DatabaseLockBackend'); + $container->register('user.tempstore', 'Drupal\user\TempStoreFactory') + ->addArgument(new Reference('database')) + ->addArgument(new Reference('lock')); + } +} diff --git a/core/lib/Drupal/Core/MaintainanceKernel.php b/core/lib/Drupal/Core/MaintainanceKernel.php new file mode 100644 index 0000000..763e404 100644 --- /dev/null +++ b/core/lib/Drupal/Core/MaintainanceKernel.php @@ -0,0 +1,41 @@ +container = $this->buildContainer(); + $this->container->set('kernel', $this); + drupal_container($this->container); + } + +} diff --git a/core/lib/Drupal/Core/Module/ModuleManager.php b/core/lib/Drupal/Core/Module/ModuleManager.php new file mode 100644 index 0000000..ef23d34 100644 --- /dev/null +++ b/core/lib/Drupal/Core/Module/ModuleManager.php @@ -0,0 +1,63 @@ +databaseConnection = $databaseConnection; + } + + /** + * Get enabled module list. + * + * @return array + * Key values pairs where keys are module names and values are associated + * module path. + */ + public function getEnabledModuleList() { + if (!isset($this->enabledModuleList)) { + $this->enabledModuleList = $this + ->databaseConnection + ->select('system', 's') + ->fields('s', array('name', 'filename')) + ->condition('status', 1) + ->condition('type', 'module') + ->execute() + ->fetchAllKeyed(); + } + return $this->enabledModuleList; + } + +} diff --git a/index.php b/index.php index 38177ab..bad9dc9 100644 --- a/index.php +++ b/index.php @@ -25,11 +25,17 @@ // @see Drupal\Core\EventSubscriber\PathSubscriber; // @see Drupal\Core\EventSubscriber\LegacyRequestSubscriber; require_once DRUPAL_ROOT . '/core/includes/bootstrap.inc'; -drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE); +drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION); // @todo Figure out how best to handle the Kernel constructor parameters. $kernel = new DrupalKernel('prod', FALSE); +// Explicitely boot the kernel in order to have a fully working container +// before anything else. +$kernel->boot(); + +drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE); + // Create a request object from the HTTPFoundation. $request = Request::createFromGlobals(); $response = $kernel->handle($request)->prepare($request)->send();