diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 956bcb4..2cf982e 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -1687,9 +1687,7 @@ function watchdog($type, $message, array $variables = array(), $severity = WATCH // It is possible that the error handling will itself trigger an error. In that case, we could // end up in an infinite loop. To avoid that, we implement a simple static semaphore. - // During early bootstrap of the installer, module_implements() might be - // loaded already, but the module system might be initialized yet. - if (!$in_error_state && function_exists('module_implements') && module_load_all(NULL)) { + if (!$in_error_state && function_exists('module_implements')) { $in_error_state = TRUE; // The user object may not exist in all conditions, so 0 is substituted if needed. @@ -2410,8 +2408,8 @@ function drupal_get_bootstrap_phase() { * A new container instance to replace the current. * @param bool $reset * (optional) Internal use only. Whether to enforce a reset of the statically - * cached container. Pass NULL for $new_container to recreate a new Container - * from scratch in a subsequent call to this function. Used by tests. + * cached container. Pass NULL for $new_container to create a fresh Container + * in a subsequent call to this function. Used by tests. * * @return Symfony\Component\DependencyInjection\Container * The instance of the Container used to set up and maintain object @@ -2432,12 +2430,12 @@ function drupal_container(Container $new_container = NULL, $reset = FALSE) { // requests. $container = new ContainerBuilder(); - // Register configuration storage class and options. + // Register active configuration storage. // @todo The active store and its options need to be configurable. // Use either global $conf (recursion warning) or global $config, or a // bootstrap configuration *file* to allow to set/override this very // lowest of low level configuration. - $container->setParameter('config.storage.options', array( + $container->setParameter('config.storage.active.options', array( 'Drupal\Core\Config\FileStorage' => array( 'directory' => config_get_config_directory(CONFIG_ACTIVE_DIRECTORY), ), @@ -2446,8 +2444,8 @@ function drupal_container(Container $new_container = NULL, $reset = FALSE) { 'bin' => 'config', ), )); - $container->register('config.storage', 'Drupal\Core\Config\CachedFileStorage') - ->addArgument('%config.storage.options%'); + $container->register('config.storage.active', 'Drupal\Core\Config\CachedFileStorage') + ->addArgument('%config.storage.active.options%'); $container->register('config.subscriber.globalconf', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber'); $container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher') @@ -2455,15 +2453,15 @@ function drupal_container(Container $new_container = NULL, $reset = FALSE) { // Register configuration object factory. $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') - ->addArgument(new Reference('config.storage')) + ->addArgument(new Reference('config.storage.active')) ->addArgument(new Reference('dispatcher')); - // Register configuration state. - $container->setParameter('config.state.options', array( + // Register staging configuration storage. + $container->setParameter('config.storage.staging.options', array( 'directory' => config_get_config_directory(CONFIG_STAGING_DIRECTORY), )); - $container->register('config.state', 'Drupal\Core\Config\FileStorage') - ->addArgument('%config.state.options%'); + $container->register('config.storage.staging', 'Drupal\Core\Config\FileStorage') + ->addArgument('%config.storage.staging.options%'); } return $container; } diff --git a/core/includes/config.inc b/core/includes/config.inc index 9eae96a..2bc77c0 100644 --- a/core/includes/config.inc +++ b/core/includes/config.inc @@ -22,7 +22,7 @@ function config_install_default_config($type, $name) { $config_dir = drupal_get_path($type, $name) . '/config'; if (is_dir($config_dir)) { $source_storage = new FileStorage(array('directory' => $config_dir)); - $target_storage = drupal_container()->get('config.storage'); + $target_storage = drupal_container()->get('config.storage.active'); $null_storage = new NullStorage(); // Upon installation, only new config objects need to be created. @@ -45,7 +45,7 @@ function config_install_default_config($type, $name) { * @see Drupal\Core\Config\StorageInterface::listAll() */ function config_get_storage_names_with_prefix($prefix = '') { - return drupal_container()->get('config.storage')->listAll($prefix); + return drupal_container()->get('config.storage.active')->listAll($prefix); } /** @@ -136,8 +136,8 @@ function config_sync_changes(array $config_changes, StorageInterface $source_sto */ function config_import() { // Retrieve a list of differences between staging and the active store. - $source_storage = drupal_container()->get('config.state'); - $target_storage = drupal_container()->get('config.storage'); + $source_storage = drupal_container()->get('config.storage.staging'); + $target_storage = drupal_container()->get('config.storage.active'); $config_changes = config_sync_get_changes($source_storage, $target_storage); if (empty($config_changes)) { @@ -214,13 +214,11 @@ function config_import_invoke_owner(array $config_changes, StorageInterface $sou /** * Exports configuration from the active store to staging. - * - * @todo config_export() is a misnomer now. Rename to config_state_update(). */ function config_export() { // Retrieve a list of differences between the active store and staging. - $source_storage = drupal_container()->get('config.storage'); - $target_storage = drupal_container()->get('config.state'); + $source_storage = drupal_container()->get('config.storage.active'); + $target_storage = drupal_container()->get('config.storage.staging'); $config_changes = config_sync_get_changes($source_storage, $target_storage); if (empty($config_changes)) { diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 6f9effc..039f007 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -288,11 +288,11 @@ function install_begin_request(&$install_state) { // configuration yet, and because the configuration system does not have a // notion of default values at runtime, data is missing in many places. The // lack of data does not trigger errors, but results in a broken user - // interface (e.g., missing titles, etc). + // interface (e.g., missing page title, etc). // - The actual configuration data to read during installation is essentially // the default configuration provided by the installation profile and // modules (most notably System module). The InstallStorage therefore reads - // from the default configuration directories. + // from the default configuration directories of extensions. // This override is reverted as soon as the config directory has been set up // successfully. // @see drupal_install_config_directory() @@ -302,9 +302,9 @@ function install_begin_request(&$install_state) { $container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher'); - $container->register('config.storage', 'Drupal\Core\Config\InstallStorage'); + $container->register('config.storage.active', 'Drupal\Core\Config\InstallStorage'); $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') - ->addArgument(new Reference('config.storage')) + ->addArgument(new Reference('config.storage.active')) ->addArgument(new Reference('dispatcher')); drupal_container($container); @@ -1091,9 +1091,9 @@ function install_settings_form_submit($form, &$form_state) { // Add the config directories to settings.php. drupal_install_config_directories(); - // We have a valid configuration directory in settings.php. - // Reset the service container, so the config.storage service will use the - // regular configuration storage for the remainder of the installation. + // We have valid configuration directories in settings.php. + // Reset the service container, so the config.storage.active service will use + // the actual active storage for installing configuration. drupal_container(NULL, TRUE); // Indicate that the settings file has been verified, and check the database diff --git a/core/includes/install.inc b/core/includes/install.inc index 193f909..3ae0144 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -7,6 +7,7 @@ use Drupal\Core\Database\Database; use Drupal\locale\Gettext; +use Exception; /** * Indicates that a module has not been installed yet. @@ -313,13 +314,16 @@ function install_verify_config_directory($type) { if (!isset($config_directories[$type])) { return FALSE; } + // config_get_config_directory() throws an exception when there is a prepared + // settings.php that defines $config_directories already and the directories + // do not exist yet. try { $config_directory = config_get_config_directory($type); if (is_dir($config_directory) && is_writable($config_directory)) { return TRUE; } } - catch (\Exception $e) { + catch (Exception $e) { } return FALSE; } diff --git a/core/includes/module.inc b/core/includes/module.inc index 0d0decf..c3399c0 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -618,7 +618,7 @@ function module_uninstall($module_list = array(), $uninstall_dependents = TRUE) } $source_storage = new NullStorage(); - $target_storage = drupal_container()->get('config.storage'); + $target_storage = drupal_container()->get('config.storage.active'); foreach ($module_list as $module) { // Remove all configuration belonging to the module. $config_changes = $target_storage->listAll($module . '.'); diff --git a/core/lib/Drupal/Core/Config/DatabaseStorage.php b/core/lib/Drupal/Core/Config/DatabaseStorage.php index a7b16a3..e4a1934 100644 --- a/core/lib/Drupal/Core/Config/DatabaseStorage.php +++ b/core/lib/Drupal/Core/Config/DatabaseStorage.php @@ -65,8 +65,6 @@ public function read($name) { // read without actually having the database available. In this case, // catch the exception and just return an empty array so the caller can // handle it if need be. - // @todo Remove this and use appropriate config.storage service definition - // in the installer instead. try { $raw = $this->getConnection()->query('SELECT data FROM {config} WHERE name = :name', array(':name' => $name), $this->options)->fetchField(); if ($raw !== FALSE) { diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php index 9a6ce66..cbad07f 100644 --- a/core/lib/Drupal/Core/Config/FileStorage.php +++ b/core/lib/Drupal/Core/Config/FileStorage.php @@ -28,7 +28,7 @@ class FileStorage implements StorageInterface { */ public function __construct(array $options = array()) { if (!isset($options['directory'])) { - $options['directory'] = config_get_config_directory(); + $options['directory'] = config_get_config_directory(CONFIG_ACTIVE_DIRECTORY); } $this->options = $options; } diff --git a/core/lib/Drupal/Core/Config/InstallStorage.php b/core/lib/Drupal/Core/Config/InstallStorage.php index 740d583..b2ee894 100644 --- a/core/lib/Drupal/Core/Config/InstallStorage.php +++ b/core/lib/Drupal/Core/Config/InstallStorage.php @@ -2,13 +2,15 @@ /** * @file - * Definition of Drupal\Core\Config\InstallStorage. + * Contains Drupal\Core\Config\InstallStorage. */ namespace Drupal\Core\Config; /** * Storage controller used by the Drupal installer. + * + * @see install_begin_request() */ class InstallStorage extends FileStorage { @@ -33,15 +35,17 @@ public function __construct(array $options = array()) { * * Returns the path to the configuration file. * - * This essentially attempts to determine the owner and path to the default - * configuration file of a requested config object name located in the - * installation profile, a module, or a theme. + * Determines the owner and path to the default configuration file of a + * requested config object name located in the installation profile, a module, + * or a theme (in this order). * * @return string * The path to the configuration file. * * @todo Improve this when figuring out how we want to handle configuration in - * installation profiles. + * installation profiles. E.g., a config object actually has to be searched + * in the profile first (whereas the profile is never the owner), only + * afterwards check for a corresponding module or theme. */ public function getFilePath($name) { // Extract the owner. @@ -50,10 +54,17 @@ public function getFilePath($name) { $path = FALSE; foreach (array('profile', 'module', 'theme') as $type) { if ($path = drupal_get_path($type, $owner)) { - break; + $file = $path . '/config/' . $name . '.' . self::getFileExtension(); + if (file_exists($file)) { + return $file; + } } } - return $path . '/config/' . $name . '.' . self::getFileExtension(); + // If any code in the early installer requests a configuration object that + // does not exist anywhere as default config, then that must be mistake. + throw new StorageException(format_string('Missing configuration file: @name', array( + '@name' => $name, + ))); } /** diff --git a/core/modules/config/config.admin.inc b/core/modules/config/config.admin.inc index eefa104..e41dcb8 100644 --- a/core/modules/config/config.admin.inc +++ b/core/modules/config/config.admin.inc @@ -55,8 +55,8 @@ function config_admin_sync_form(array &$form, array &$form_state, StorageInterfa */ function config_admin_import_form($form, &$form_state) { // Retrieve a list of differences between last known state and active store. - $source_storage = drupal_container()->get('config.state'); - $target_storage = drupal_container()->get('config.storage'); + $source_storage = drupal_container()->get('config.storage.staging'); + $target_storage = drupal_container()->get('config.storage.active'); // Prevent users from deleting all configuration. // If the source storage is empty, that signals the unique condition of not @@ -105,12 +105,12 @@ function config_admin_import_form_submit($form, &$form_state) { * @see config_admin_export_form_submit() * @see config_export() * - * @todo "export" is a misnomer with config.state. + * @todo "export" is a misnomer with config.storage.staging. */ function config_admin_export_form($form, &$form_state) { // Retrieve a list of differences between active store and last known state. - $source_storage = drupal_container()->get('config.storage'); - $target_storage = drupal_container()->get('config.state'); + $source_storage = drupal_container()->get('config.storage.active'); + $target_storage = drupal_container()->get('config.storage.staging'); config_admin_sync_form($form, $form_state, $source_storage, $target_storage); diff --git a/core/modules/config/lib/Drupal/config/ConfigStorageController.php b/core/modules/config/lib/Drupal/config/ConfigStorageController.php index f53cbb7..840c8fb 100644 --- a/core/modules/config/lib/Drupal/config/ConfigStorageController.php +++ b/core/modules/config/lib/Drupal/config/ConfigStorageController.php @@ -151,7 +151,7 @@ protected function buildQuery($ids, $revision_id = FALSE) { // Load all of the configurables. if ($ids === NULL) { - $names = drupal_container()->get('config.storage')->listAll($prefix); + $names = drupal_container()->get('config.storage.active')->listAll($prefix); $result = array(); foreach ($names as $name) { $config = config($name); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php index 9eea495..3a66d57 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php @@ -25,7 +25,7 @@ public static function getInfo() { * Tests CRUD operations. */ function testCRUD() { - $storage = $this->container->get('config.storage'); + $storage = $this->container->get('config.storage.active'); $name = 'config_test.crud'; $config = config($name); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigFileContentTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigFileContentTest.php index 7fadf31..4a82d0b 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigFileContentTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigFileContentTest.php @@ -26,7 +26,7 @@ public static function getInfo() { * Tests setting, writing, and reading of a configuration setting. */ function testReadWriteConfig() { - $storage = $this->container->get('config.storage'); + $storage = $this->container->get('config.storage.active'); $name = 'foo.bar'; $key = 'foo'; diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php index 601fb8d..8ad26f0 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php @@ -62,8 +62,8 @@ function testNoImport() { function testDeleted() { $name = 'config_test.system'; $dynamic_name = 'config_test.dynamic.default'; - $storage = $this->container->get('config.storage'); - $state = $this->container->get('config.state'); + $storage = $this->container->get('config.storage.active'); + $staging = $this->container->get('config.storage.staging'); // Verify the default configuration values exist. $config = config($name); @@ -75,8 +75,8 @@ function testDeleted() { config_export(); // Delete the configuration objects from the staging directory. - $state->delete($name); - $state->delete($dynamic_name); + $staging->delete($name); + $staging->delete($dynamic_name); // Import. config_import(); @@ -99,7 +99,7 @@ function testDeleted() { $this->assertTrue(isset($GLOBALS['hook_config_test']['delete'])); // Verify that there is nothing more to import. - $this->assertFalse(config_sync_get_changes($state, $storage)); + $this->assertFalse(config_sync_get_changes($staging, $storage)); } /** @@ -108,8 +108,8 @@ function testDeleted() { function testNew() { $name = 'config_test.new'; $dynamic_name = 'config_test.dynamic.new'; - $storage = $this->container->get('config.storage'); - $state = $this->container->get('config.state'); + $storage = $this->container->get('config.storage.active'); + $staging = $this->container->get('config.storage.staging'); // Export. config_export(); @@ -118,14 +118,14 @@ function testNew() { $this->assertIdentical($storage->exists($name), FALSE, $name . ' not found.'); $this->assertIdentical($storage->exists($dynamic_name), FALSE, $dynamic_name . ' not found.'); - $this->assertIdentical($state->exists($name), FALSE, $name . ' not found.'); - $this->assertIdentical($state->exists($dynamic_name), FALSE, $dynamic_name . ' not found.'); + $this->assertIdentical($staging->exists($name), FALSE, $name . ' not found.'); + $this->assertIdentical($staging->exists($dynamic_name), FALSE, $dynamic_name . ' not found.'); // Create new configuration objects in the staging directory. $original_name_data = array( 'add_me' => 'new value', ); - $state->write($name, $original_name_data); + $staging->write($name, $original_name_data); $original_dynamic_data = array( 'id' => 'new', 'label' => 'New', @@ -133,9 +133,9 @@ function testNew() { 'style' => '', 'uuid' => '30df59bd-7b03-4cf7-bb35-d42fc49f0651', ); - $state->write($dynamic_name, $original_dynamic_data); - $this->assertIdentical($state->exists($name), TRUE, $name . ' found.'); - $this->assertIdentical($state->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); + $staging->write($dynamic_name, $original_dynamic_data); + $this->assertIdentical($staging->exists($name), TRUE, $name . ' found.'); + $this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); // Import. config_import(); @@ -155,7 +155,7 @@ function testNew() { $this->assertFalse(isset($GLOBALS['hook_config_test']['delete'])); // Verify that there is nothing more to import. - $this->assertFalse(config_sync_get_changes($state, $storage)); + $this->assertFalse(config_sync_get_changes($staging, $storage)); } /** @@ -164,8 +164,8 @@ function testNew() { function testUpdated() { $name = 'config_test.system'; $dynamic_name = 'config_test.dynamic.default'; - $storage = $this->container->get('config.storage'); - $state = $this->container->get('config.state'); + $storage = $this->container->get('config.storage.active'); + $staging = $this->container->get('config.storage.staging'); // Export. config_export(); @@ -174,18 +174,18 @@ function testUpdated() { $this->assertIdentical($storage->exists($name), TRUE, $name . ' found.'); $this->assertIdentical($storage->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); - $this->assertIdentical($state->exists($name), TRUE, $name . ' found.'); - $this->assertIdentical($state->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); + $this->assertIdentical($staging->exists($name), TRUE, $name . ' found.'); + $this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); // Replace the file content of the existing configuration objects in the // staging directory. $original_name_data = array( 'foo' => 'beer', ); - $state->write($name, $original_name_data); - $original_dynamic_data = $state->read($dynamic_name); + $staging->write($name, $original_name_data); + $original_dynamic_data = $staging->read($dynamic_name); $original_dynamic_data['label'] = 'Updated'; - $state->write($dynamic_name, $original_dynamic_data); + $staging->write($dynamic_name, $original_dynamic_data); // Verify the active store still returns the default values. $config = config($name); @@ -203,8 +203,8 @@ function testUpdated() { $this->assertIdentical($config->get('label'), 'Updated'); // Verify that the original file content is still the same. - $this->assertIdentical($state->read($name), $original_name_data); - $this->assertIdentical($state->read($dynamic_name), $original_dynamic_data); + $this->assertIdentical($staging->read($name), $original_name_data); + $this->assertIdentical($staging->read($dynamic_name), $original_dynamic_data); // Verify that appropriate module API hooks have been invoked. $this->assertTrue(isset($GLOBALS['hook_config_test']['load'])); @@ -215,7 +215,7 @@ function testUpdated() { $this->assertFalse(isset($GLOBALS['hook_config_test']['delete'])); // Verify that there is nothing more to import. - $this->assertFalse(config_sync_get_changes($state, $storage)); + $this->assertFalse(config_sync_get_changes($staging, $storage)); } } diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php index ea20651..8779734 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php @@ -69,14 +69,14 @@ function testExport() { function testImport() { $name = 'config_test.new'; $dynamic_name = 'config_test.dynamic.new'; - $storage = $this->container->get('config.storage'); - $state = $this->container->get('config.state'); + $storage = $this->container->get('config.storage.active'); + $staging = $this->container->get('config.storage.staging'); // Verify the configuration to create does not exist yet. $this->assertIdentical($storage->exists($name), FALSE, $name . ' not found.'); $this->assertIdentical($storage->exists($dynamic_name), FALSE, $dynamic_name . ' not found.'); - $this->assertIdentical($state->exists($name), FALSE, $name . ' not found.'); - $this->assertIdentical($state->exists($dynamic_name), FALSE, $dynamic_name . ' not found.'); + $this->assertIdentical($staging->exists($name), FALSE, $name . ' not found.'); + $this->assertIdentical($staging->exists($dynamic_name), FALSE, $dynamic_name . ' not found.'); // Verify that the import UI does not allow to import without exported // configuration. @@ -91,7 +91,7 @@ function testImport() { $original_name_data = array( 'add_me' => 'new value', ); - $state->write($name, $original_name_data); + $staging->write($name, $original_name_data); $original_dynamic_data = array( 'id' => 'new', 'label' => 'New', @@ -99,9 +99,9 @@ function testImport() { 'style' => '', 'uuid' => '30df59bd-7b03-4cf7-bb35-d42fc49f0651', ); - $state->write($dynamic_name, $original_dynamic_data); - $this->assertIdentical($state->exists($name), TRUE, $name . ' found.'); - $this->assertIdentical($state->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); + $staging->write($dynamic_name, $original_dynamic_data); + $this->assertIdentical($staging->exists($name), TRUE, $name . ' found.'); + $this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); // Verify that both appear as new. $this->drupalGet('admin/config/development/sync'); @@ -127,10 +127,10 @@ function testImport() { */ function testImportLock() { $name = 'config_test.new'; - $state = $this->container->get('config.state'); + $staging = $this->container->get('config.storage.staging'); // Write a configuration object to import. - $state->write($name, array( + $staging->write($name, array( 'add_me' => 'new value', )); diff --git a/core/modules/system/system.install b/core/modules/system/system.install index a9151d3..dc8821f 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -1547,34 +1547,9 @@ function system_update_8002() { } /** - * Adds {config} table for new Configuration system. + * Creates {cache_config} cache table for the new configuration system. */ function system_update_8003() { - // @todo Temporary. - if (db_table_exists('config')) { - db_drop_table('config'); - } - db_create_table('config', array( - 'description' => 'Default active store for the configuration system.', - 'fields' => array( - 'name' => array( - 'description' => 'The identifier for the configuration entry, such as module.example (the name of the file, minus the file extension).', - 'type' => 'varchar', - 'length' => 255, - 'not null' => TRUE, - 'default' => '', - ), - 'data' => array( - 'description' => 'The raw data for this configuration entry.', - 'type' => 'blob', - 'not null' => TRUE, - 'size' => 'big', - 'translatable' => TRUE, - ), - ), - 'primary key' => array('name'), - )); - $schema['cache'] = array( 'description' => 'Generic cache table for caching things not separated out into their own tables. Contributed modules may also use this to store cached items.', 'fields' => array(