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