cid = $cid; $this->cache = $cache; $this->lock = $lock; $this->tags = $tags; $this->persistable = $modules_loaded && \Drupal::hasRequest() && \Drupal::request()->isMethod('GET'); // @todo: Implement lazyload. $this->cacheLoaded = TRUE; if ($this->persistable && $cached = $this->cache->get($this->cid)) { $this->storage = $cached->data; } else { // If there is no runtime cache stored, fetch the full theme registry, // but then initialize each value to NULL. This allows offsetExists() // to function correctly on non-registered theme hooks without triggering // a call to resolveCacheMiss(). $this->storage = $this->initializeRegistry(); foreach (array_keys($this->storage) as $key) { $this->persist($key); } // RegistryTest::testRaceCondition() ensures that the cache entry is // written on the initial construction of the theme registry. $this->updateCache(); } } /** * Initializes the full theme registry. * * @return * An array with the keys of the full theme registry, but the values * initialized to NULL. */ public function initializeRegistry() { // @todo DIC this. $this->completeRegistry = \Drupal::service('theme.registry')->get(); return array_fill_keys(array_keys($this->completeRegistry), NULL); } /** * {@inheritdoc} */ public function has($key) { // Since the theme registry allows for theme hooks to be requested that // are not registered, just check the existence of the key in the registry. // Use array_key_exists() here since a NULL value indicates that the theme // hook exists but has not yet been requested. return array_key_exists($key, $this->storage); } /** * {@inheritdoc} */ public function get($key) { // If the offset is set but empty, it is a registered theme hook that has // not yet been requested. Offsets that do not exist at all were not // registered in hook_theme(). if (isset($this->storage[$key])) { return $this->storage[$key]; } elseif (array_key_exists($key, $this->storage)) { return $this->resolveCacheMiss($key); } } /** * {@inheritdoc} */ public function resolveCacheMiss($key) { if (!isset($this->completeRegistry)) { $this->completeRegistry = \Drupal::service('theme.registry')->get(); } $this->storage[$key] = $this->completeRegistry[$key]; if ($this->persistable) { $this->persist($key); } return $this->storage[$key]; } /** * {@inheritdoc} */ protected function updateCache($lock = TRUE) { if (!$this->persistable) { return; } // @todo: Is the custom implementation necessary? $data = []; foreach ($this->keysToPersist as $offset => $persist) { if ($persist) { $data[$offset] = $this->storage[$offset]; } } if (empty($data)) { return; } $lock_name = $this->cid . ':' . __CLASS__; if (!$lock || $this->lock->acquire($lock_name)) { if ($cached = $this->cache->get($this->cid)) { // Use array merge instead of union so that filled in values in $data // overwrite empty values in the current cache. $data = array_merge($cached->data, $data); } else { $registry = $this->initializeRegistry(); $data = array_merge($registry, $data); } $this->cache->set($this->cid, $data, Cache::PERMANENT, $this->tags); if ($lock) { $this->lock->release($lock_name); } } } }