4 * Contains \Drupal\bootstrap\Utility\Storage.
7 namespace Drupal\bootstrap\Utility;
9 use Drupal\bootstrap\Bootstrap;
10 use Drupal\Core\Cache\Cache;
11 use Drupal\Core\KeyValueStore\MemoryStorage;
16 * A hybrid storage solution that utilizes the cache system for complex and
17 * expensive operations performed by a [base] theme.
19 * Instead of using multiple cache identifiers, which increases the number of
20 * database calls, this storage only executes a single cache call and stores
21 * individual entries in memory as an associative array.
23 * It also tracks when the data has been modified so it can be saved back to
24 * cache before the system fully shuts down.
26 * This storage object can be used in `foreach` loops.
30 * @see \Drupal\bootstrap\Utility\StorageItem
32 class Storage extends MemoryStorage implements \Iterator {
35 * The bin (table) data should be stored in (not prefixed with "cache_").
42 * Flag determining whether or not the cache should be saved to the database.
49 * The cache identifier.
56 * Indicates when the cache should expire.
63 * Flag determining whether or not object has been initialized yet.
67 protected $initialized = FALSE;
70 * Tags to associate with the cached data so it can be properly invalidated.
79 public function __construct($cid, $bin = 'default', $expire = Cache::PERMANENT, $tags = [Bootstrap::CACHE_TAG]) {
80 $this->cid = "theme_registry:storage:$cid";
82 $this->changed = FALSE;
83 $this->expire = $expire;
86 // Register the cache object to save, if it's needed, on shutdown.
87 drupal_register_shutdown_function([$this, 'save']);
89 // Retrieve the cached data.
90 $data = ($cached = \Drupal::cache($bin)->get($this->cid)) && !empty($cached->data) ? $cached->data : [];
93 $this->setMultiple($data);
95 // Cache has been initialized.
96 $this->initialized = TRUE;
100 * Notifies the object that data has changed.
102 public function changed() {
103 if ($this->initialized) {
104 $this->changed = TRUE;
111 public function current() {
112 return current($this->data);
118 public function delete($key) {
119 parent::delete($key);
126 public function deleteAll() {
134 public function deleteMultiple(array $keys) {
135 parent::deleteMultiple($keys);
142 public function getAll($arrays = TRUE) {
145 foreach ($data as $key => $value) {
146 if ($value instanceof StorageItem) {
147 $data[$key] = $value->getAll();
155 * Determines if the cache is empty.
160 public function isEmpty() {
161 return empty($this->data);
167 public function key() {
168 return key($this->data);
174 public function next() {
175 return next($this->data);
181 public function rename($key, $new_key) {
182 parent::rename($key, $new_key);
189 public function rewind() {
190 return reset($this->data);
194 * Saves the data back to the database, if necessary, on shutdown.
196 * This method is automatically invoked during PHP shutdown.
200 * @see \Drupal\bootstrap\Utility\Storage::__construct
202 public function save() {
203 if ($this->changed) {
204 \Drupal::cache($this->bin)->set($this->cid, $this->getAll(), $this->expire, $this->tags);
211 public function set($key, $value) {
212 if (is_array($value)) {
213 $value = new StorageItem($value, $this);
215 parent::set($key, $value);
222 public function setIfNotExists($key, $value) {
223 if (!isset($this->data[$key])) {
224 if (is_array($value)) {
225 $value = new StorageItem($value, $this);
227 $this->data[$key] = $value;
237 public function setMultiple(array $data) {
238 foreach ($data as $key => $value) {
239 if (is_array($value)) {
240 $data[$key] = new StorageItem($value, $this);
243 parent::setMultiple($data);
250 public function valid() {
251 return key($this->data) !== NULL;