protected function setUp()
 {
     parent::setUp();
     // Set up three memory backends to be used in the chain.
     $this->firstBackend = new MemoryBackend('foo');
     $this->secondBackend = new MemoryBackend('bar');
     $this->thirdBackend = new MemoryBackend('baz');
     // Set an initial fixed dataset for all testing. The next three data
     // collections will test two edge cases (last backend has the data, and
     // first backend has the data) and will test a normal use case (middle
     // backend has the data). We should have a complete unit test with those.
     // Note that in all cases, when the same key is set on more than one
     // backend, the values are voluntarily different, this ensures in which
     // backend we actually fetched the key when doing get calls.
     // Set a key present on all backends (for delete).
     $this->firstBackend->set('t123', 1231);
     $this->secondBackend->set('t123', 1232);
     $this->thirdBackend->set('t123', 1233);
     // Set a key present on the second and the third (for get), those two will
     // be different, this will ensure from where we get the key.
     $this->secondBackend->set('t23', 232);
     $this->thirdBackend->set('t23', 233);
     // Set a key on only the third, we will ensure propagation using this one.
     $this->thirdBackend->set('t3', 33);
     // Create the chain.
     $this->chain = new BackendChain('foobarbaz');
     $this->chain->appendBackend($this->firstBackend)->appendBackend($this->secondBackend)->appendBackend($this->thirdBackend);
 }
 /**
  * {@inheritdoc}
  *
  * Cached by role, invalidated whenever permissions change.
  */
 public function generate(AccountInterface $account)
 {
     // User 1 is the super user, and can always access all permissions. Use a
     // different, unique identifier for the hash.
     if ($account->id() == 1) {
         return $this->hash('is-super-user');
     }
     $sorted_roles = $account->getRoles();
     sort($sorted_roles);
     $role_list = implode(',', $sorted_roles);
     $cid = "user_permissions_hash:{$role_list}";
     if ($static_cache = $this->static->get($cid)) {
         return $static_cache->data;
     } else {
         $tags = Cache::buildTags('config:user.role', $sorted_roles, '.');
         if ($cache = $this->cache->get($cid)) {
             $permissions_hash = $cache->data;
         } else {
             $permissions_hash = $this->doGenerate($sorted_roles);
             $this->cache->set($cid, $permissions_hash, Cache::PERMANENT, $tags);
         }
         $this->static->set($cid, $permissions_hash, Cache::PERMANENT, $tags);
     }
     return $permissions_hash;
 }
示例#3
0
 /**
  * User object.
  *
  * @return \Drupal\moodle\Sql\User
  */
 public function user()
 {
     // Static cache of already retrieved user data.
     $data =& drupal_static(__METHOD__, array());
     $user_cid = "moodle-user:{$this->user->id()}";
     // If we do not have this user id in the static cache, check {cache_data}.
     if (!isset($data[$user_cid])) {
         $cache = $this->cacheBackend->get($user_cid);
         if ($cache && $cache->data && isset($cache->data[$user_cid])) {
             $data[$user_cid] = $cache->data[$user_cid];
         }
     }
     // If nothing in the cache then retrieve it from the database.
     if (!isset($data[$user_cid])) {
         $user = new User();
         $this->query();
         $this->addFields();
         $statement = $this->query->execute();
         $statement->setFetchMode(\PDO::FETCH_INTO, $user);
         $data[$user_cid] = $statement->fetch();
         // Store the results for a day.
         $this->cacheBackend->set($user_cid, $data, REQUEST_TIME + 86400);
     }
     return $data[$user_cid];
 }
示例#4
0
 /**
  * {@inheritdoc}
  *
  * Cached by role, invalidated whenever permissions change.
  */
 public function generate(AccountInterface $account)
 {
     $sorted_roles = $account->getRoles();
     sort($sorted_roles);
     $role_list = implode(',', $sorted_roles);
     if ($cache = $this->cache->get("user_permissions_hash:{$role_list}")) {
         $permissions_hash = $cache->data;
     } else {
         $permissions_hash = $this->doGenerate($sorted_roles);
         $this->cache->set("user_permissions_hash:{$role_list}", $permissions_hash, Cache::PERMANENT, array('user_role' => $sorted_roles));
     }
     return $permissions_hash;
 }
 /**
  * Loads the base country definitions.
  *
  * @return array
  */
 protected function loadBaseDefinitions()
 {
     if (!empty($this->baseDefinitions)) {
         return $this->baseDefinitions;
     }
     $cache_key = 'address.countries.base';
     if ($cached = $this->cache->get($cache_key)) {
         $this->baseDefinitions = $cached->data;
     } else {
         $this->baseDefinitions = json_decode(file_get_contents($this->definitionPath . 'base.json'), TRUE);
         $this->cache->set($cache_key, $this->baseDefinitions, CacheBackendInterface::CACHE_PERMANENT, ['countries']);
     }
     return $this->baseDefinitions;
 }
 /**
  * {@inheritdoc}
  *
  * Cached by role, invalidated whenever permissions change.
  */
 public function generate(AccountInterface $account)
 {
     $sorted_roles = $account->getRoles();
     sort($sorted_roles);
     $role_list = implode(',', $sorted_roles);
     if ($cache = $this->cache->get("user_permissions_hash:{$role_list}")) {
         $permissions_hash = $cache->data;
     } else {
         $permissions_hash = $this->doGenerate($sorted_roles);
         $tags = Cache::buildTags('config:user.role', $sorted_roles, '.');
         $this->cache->set("user_permissions_hash:{$role_list}", $permissions_hash, Cache::PERMANENT, $tags);
     }
     return $permissions_hash;
 }
 /**
  * Sets a cache of plugin definitions for the decorated discovery class.
  *
  * @param array $definitions
  *   List of definitions to store in cache.
  */
 protected function setCachedDefinitions($definitions)
 {
     if ($this->cacheBackend) {
         $this->cacheBackend->set($this->cacheKey, $definitions, Cache::PERMANENT, $this->cacheTags);
     }
     $this->definitions = $definitions;
 }
示例#8
0
 /**
  * {@inheritdoc}
  */
 public function getLineItemTypeId($product_type_id)
 {
     if (!isset($this->map)) {
         if ($cached_map = $this->cache->get('commerce_product.line_item_type_map')) {
             $this->map = $cached_map->data;
         } else {
             $this->map = $this->buildMap();
             $this->cache->set('commerce_product.line_item_type_map', $this->map);
         }
     }
     // A valid product type ID should always have a matching line item type ID.
     if (empty($this->map[$product_type_id])) {
         throw new \InvalidArgumentException(sprintf('No line item type found for the "%s" product type.', $product_type_id));
     }
     return $this->map[$product_type_id];
 }
示例#9
0
 /**
  * Responds after a request has finished, but before it is sent to the client.
  *
  * @param \Guzzle\Common\Event $event
  *   The Guzzle event object.
  */
 public function onRequestSent(Event $event)
 {
     $request = $event['request'];
     $response = $event['response'];
     // Handle permanent redirects by setting the redirected URL so that the
     // client can grab it quickly.
     $redirect = FALSE;
     $url = $old_url = $request->getUrl();
     if ($previous_response = $response->getPreviousResponse()) {
         if ($previous_response->getStatusCode() == 301 && ($location = $previous_response->getLocation())) {
             $response->getParams()->set('feeds.redirect', $location);
             $redirect = TRUE;
             $url = $request->getUrl();
         }
     }
     $cache_hit = $response->getStatusCode() == 304;
     if ($redirect) {
         // Delete the old cache entry.
         $this->cacheBackend->delete($this->getCacheKey($old_url));
         // Not sure if the repeated requests are smart enough to find the
         // redirect, so cache the old URL with the new response.
         static::$downloadCache[$old_url] = $response;
     }
     if ($redirect || !$cache_hit) {
         $cache = new \stdClass();
         $cache->headers = array_change_key_case($response->getHeaders()->toArray());
         // @todo We should only cache for certain status codes.
         $cache->code = $response->getStatusCode();
         $this->cacheBackend->set($this->getCacheKey($url), $cache);
     }
     // Set in-page download cache.
     static::$downloadCache[$url] = $response;
 }
 /**
  * Tests the getAllBundleInfo() method.
  *
  * @covers ::getAllBundleInfo
  */
 public function testGetAllBundleInfo()
 {
     $this->moduleHandler->invokeAll('entity_bundle_info')->willReturn([]);
     $this->moduleHandler->alter('entity_bundle_info', Argument::type('array'))->willReturn(NULL);
     $apple = $this->prophesize(EntityTypeInterface::class);
     $apple->getLabel()->willReturn('Apple');
     $apple->getBundleOf()->willReturn(NULL);
     $banana = $this->prophesize(EntityTypeInterface::class);
     $banana->getLabel()->willReturn('Banana');
     $banana->getBundleOf()->willReturn(NULL);
     $this->setUpEntityTypeDefinitions(['apple' => $apple, 'banana' => $banana]);
     $this->cacheBackend->get('entity_bundle_info:en')->willReturn(FALSE);
     $this->cacheBackend->set('entity_bundle_info:en', Argument::any(), Cache::PERMANENT, ['entity_types', 'entity_bundles'])->will(function () {
         $this->get('entity_bundle_info:en')->willReturn((object) ['data' => 'cached data'])->shouldBeCalled();
     })->shouldBeCalled();
     $this->cacheTagsInvalidator->invalidateTags(['entity_bundles'])->shouldBeCalled();
     $this->typedDataManager->clearCachedDefinitions()->shouldBeCalled();
     $expected = ['apple' => ['apple' => ['label' => 'Apple']], 'banana' => ['banana' => ['label' => 'Banana']]];
     $bundle_info = $this->entityTypeBundleInfo->getAllBundleInfo();
     $this->assertSame($expected, $bundle_info);
     $bundle_info = $this->entityTypeBundleInfo->getAllBundleInfo();
     $this->assertSame($expected, $bundle_info);
     $this->entityTypeBundleInfo->clearCachedBundles();
     $bundle_info = $this->entityTypeBundleInfo->getAllBundleInfo();
     $this->assertSame('cached data', $bundle_info);
 }
示例#11
0
 /**
  * {@inheritdoc}
  */
 public function write($key, $content)
 {
     $this->storage()->save($key, $content);
     // Save the last mtime.
     $cid = 'twig:' . $key;
     $this->cache->set($cid, REQUEST_TIME);
 }
示例#12
0
 /**
  * Builds the "format_tags" configuration part of the CKEditor JS settings.
  *
  * @see getConfig()
  *
  * @param \Drupal\editor\Entity\Editor $editor
  *   A configured text editor object.
  *
  * @return array
  *   An array containing the "format_tags" configuration.
  */
 protected function generateFormatTagsSetting(Editor $editor)
 {
     // When no text format is associated yet, assume no tag is allowed.
     // @see \Drupal\Editor\EditorInterface::hasAssociatedFilterFormat()
     if (!$editor->hasAssociatedFilterFormat()) {
         return array();
     }
     $format = $editor->getFilterFormat();
     $cid = 'ckeditor_internal_format_tags:' . $format->id();
     if ($cached = $this->cache->get($cid)) {
         $format_tags = $cached->data;
     } else {
         // The <p> tag is always allowed — HTML without <p> tags is nonsensical.
         $format_tags = ['p'];
         // Given the list of possible format tags, automatically determine whether
         // the current text format allows this tag, and thus whether it should show
         // up in the "Format" dropdown.
         $possible_format_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre'];
         foreach ($possible_format_tags as $tag) {
             $input = '<' . $tag . '>TEST</' . $tag . '>';
             $output = trim(check_markup($input, $editor->id()));
             if ($input == $output) {
                 $format_tags[] = $tag;
             }
         }
         $format_tags = implode(';', $format_tags);
         // Cache the "format_tags" configuration. This cache item is infinitely
         // valid; it only changes whenever the text format is changed, hence it's
         // tagged with the text format's cache tag.
         $this->cache->set($cid, $format_tags, Cache::PERMANENT, $format->getCacheTags());
     }
     return $format_tags;
 }
示例#13
0
 /**
  * {@inheritdoc}
  */
 public function loadTreeData($menu_name, MenuTreeParameters $parameters)
 {
     // Build the cache ID; sort 'expanded' and 'conditions' to prevent duplicate
     // cache items.
     sort($parameters->expandedParents);
     asort($parameters->conditions);
     $tree_cid = "tree-data:{$menu_name}:" . serialize($parameters);
     $cache = $this->menuCacheBackend->get($tree_cid);
     if ($cache && isset($cache->data)) {
         $data = $cache->data;
         // Cache the definitions in memory so they don't need to be loaded again.
         $this->definitions += $data['definitions'];
         unset($data['definitions']);
     } else {
         $links = $this->loadLinks($menu_name, $parameters);
         $data['tree'] = $this->doBuildTreeData($links, $parameters->activeTrail, $parameters->minDepth);
         $data['definitions'] = array();
         $data['route_names'] = $this->collectRoutesAndDefinitions($data['tree'], $data['definitions']);
         $this->menuCacheBackend->set($tree_cid, $data, Cache::PERMANENT, ['config:system.menu.' . $menu_name]);
         // The definitions were already added to $this->definitions in
         // $this->doBuildTreeData()
         unset($data['definitions']);
     }
     return $data;
 }
示例#14
0
 /**
  * Discovers all available tests in all extensions.
  *
  * @param string $extension
  *   (optional) The name of an extension to limit discovery to; e.g., 'node'.
  *
  * @return array
  *   An array of tests keyed by the first @group specified in each test's
  *   PHPDoc comment block, and then keyed by class names. For example:
  *   @code
  *     $groups['block'] => array(
  *       'Drupal\block\Tests\BlockTest' => array(
  *         'name' => 'Drupal\block\Tests\BlockTest',
  *         'description' => 'Tests block UI CRUD functionality.',
  *         'group' => 'block',
  *       ),
  *     );
  *   @endcode
  *
  * @throws \ReflectionException
  *   If a discovered test class does not match the expected class name.
  *
  * @todo Remove singular grouping; retain list of groups in 'group' key.
  * @see https://www.drupal.org/node/2296615
  * @todo Add base class groups 'Kernel' + 'Web', complementing 'PHPUnit'.
  */
 public function getTestClasses($extension = NULL)
 {
     if (!isset($extension)) {
         if ($this->cacheBackend && ($cache = $this->cacheBackend->get('simpletest:discovery:classes'))) {
             return $cache->data;
         }
     }
     $list = array();
     $classmap = $this->findAllClassFiles($extension);
     // Prevent expensive class loader lookups for each reflected test class by
     // registering the complete classmap of test classes to the class loader.
     // This also ensures that test classes are loaded from the discovered
     // pathnames; a namespace/classname mismatch will throw an exception.
     $this->classLoader->addClassMap($classmap);
     foreach ($classmap as $classname => $pathname) {
         try {
             $class = new \ReflectionClass($classname);
         } catch (\ReflectionException $e) {
             // Re-throw with expected pathname.
             $message = $e->getMessage() . " in expected {$pathname}";
             throw new \ReflectionException($message, $e->getCode(), $e);
         }
         // Skip interfaces, abstract classes, and traits.
         if (!$class->isInstantiable()) {
             continue;
         }
         // Skip non-test classes.
         if (!$class->isSubclassOf('Drupal\\simpletest\\TestBase') && !$class->isSubclassOf('PHPUnit_Framework_TestCase')) {
             continue;
         }
         $info = static::getTestInfo($class);
         // Skip this test class if it requires unavailable modules.
         // @todo PHPUnit skips tests with unmet requirements when executing a test
         //   (instead of excluding them upfront). Refactor test runner to follow
         //   that approach.
         // @see https://www.drupal.org/node/1273478
         if (!empty($info['requires']['module'])) {
             if (array_diff($info['requires']['module'], $this->availableExtensions['module'])) {
                 continue;
             }
         }
         $list[$info['group']][$classname] = $info;
     }
     // Sort the groups and tests within the groups by name.
     uksort($list, 'strnatcasecmp');
     foreach ($list as &$tests) {
         uksort($tests, 'strnatcasecmp');
     }
     // Allow modules extending core tests to disable originals.
     \Drupal::moduleHandler()->alter('simpletest', $list);
     if (!isset($extension)) {
         if ($this->cacheBackend) {
             $this->cacheBackend->set('simpletest:discovery:classes', $list);
         }
     }
     return $list;
 }
 /**
  * Compile the source and write the compiled template to disk.
  */
 public function updateCompiledTemplate($cache_filename, $name)
 {
     $source = $this->loader->getSource($name);
     $compiled_source = $this->compileSource($source, $name);
     $this->storage()->save($cache_filename, $compiled_source);
     // Save the last modification time
     $cid = 'twig:' . $cache_filename;
     $this->cache_object->set($cid, REQUEST_TIME);
 }
示例#16
0
 /**
  * Discovers all available tests in all extensions.
  *
  * @param string $extension
  *   (optional) The name of an extension to limit discovery to; e.g., 'node'.
  *
  * @return array
  *   An array of tests keyed by the first @group specified in each test's
  *   PHPDoc comment block, and then keyed by class names. For example:
  *   @code
  *     $groups['block'] => array(
  *       'Drupal\block\Tests\BlockTest' => array(
  *         'name' => 'Drupal\block\Tests\BlockTest',
  *         'description' => 'Tests block UI CRUD functionality.',
  *         'group' => 'block',
  *       ),
  *     );
  *   @endcode
  *
  * @throws \ReflectionException
  *   If a discovered test class does not match the expected class name.
  *
  * @todo Remove singular grouping; retain list of groups in 'group' key.
  * @see https://www.drupal.org/node/2296615
  * @todo Add base class groups 'Kernel' + 'Web', complementing 'PHPUnit'.
  */
 public function getTestClasses($extension = NULL)
 {
     $reader = new SimpleAnnotationReader();
     $reader->addNamespace('Drupal\\simpletest\\Annotation');
     if (!isset($extension)) {
         if ($this->cacheBackend && ($cache = $this->cacheBackend->get('simpletest:discovery:classes'))) {
             return $cache->data;
         }
     }
     $list = array();
     $classmap = $this->findAllClassFiles($extension);
     // Prevent expensive class loader lookups for each reflected test class by
     // registering the complete classmap of test classes to the class loader.
     // This also ensures that test classes are loaded from the discovered
     // pathnames; a namespace/classname mismatch will throw an exception.
     $this->classLoader->addClassMap($classmap);
     foreach ($classmap as $classname => $pathname) {
         $finder = MockFileFinder::create($pathname);
         $parser = new StaticReflectionParser($classname, $finder, TRUE);
         try {
             $info = static::getTestInfo($classname, $parser->getDocComment());
         } catch (MissingGroupException $e) {
             // If the class name ends in Test and is not a migrate table dump.
             if (preg_match('/Test$/', $classname) && strpos($classname, 'migrate_drupal\\Tests\\Table') === FALSE) {
                 throw $e;
             }
             // If the class is @group annotation just skip it. Most likely it is an
             // abstract class, trait or test fixture.
             continue;
         }
         // Skip this test class if it requires unavailable modules.
         // @todo PHPUnit skips tests with unmet requirements when executing a test
         //   (instead of excluding them upfront). Refactor test runner to follow
         //   that approach.
         // @see https://www.drupal.org/node/1273478
         if (!empty($info['requires']['module'])) {
             if (array_diff($info['requires']['module'], $this->availableExtensions['module'])) {
                 continue;
             }
         }
         $list[$info['group']][$classname] = $info;
     }
     // Sort the groups and tests within the groups by name.
     uksort($list, 'strnatcasecmp');
     foreach ($list as &$tests) {
         uksort($tests, 'strnatcasecmp');
     }
     // Allow modules extending core tests to disable originals.
     \Drupal::moduleHandler()->alter('simpletest', $list);
     if (!isset($extension)) {
         if ($this->cacheBackend) {
             $this->cacheBackend->set('simpletest:discovery:classes', $list);
         }
     }
     return $list;
 }
示例#17
0
 /**
  * Loads all non-admin routes right before the actual page is rendered.
  *
  * @param \Symfony\Component\HttpKernel\Event\KernelEvent $event
  *   The event to process.
  */
 public function onRequest(KernelEvent $event)
 {
     // Only preload on normal HTML pages, as they will display menu links.
     if ($this->routeProvider instanceof PreloadableRouteProviderInterface && $event->getRequest()->getRequestFormat() == 'html') {
         // Ensure that the state query is cached to skip the database query, if
         // possible.
         $key = 'routing.non_admin_routes';
         if ($cache = $this->cache->get($key)) {
             $routes = $cache->data;
         } else {
             $routes = $this->state->get($key, []);
             $this->cache->set($key, $routes, Cache::PERMANENT, ['routes']);
         }
         if ($routes) {
             // Preload all the non-admin routes at once.
             $this->routeProvider->preLoadRoutes($routes);
         }
     }
 }
 /**
  * Stores entities in the persistent cache backend.
  *
  * @param \Drupal\Core\Entity\ContentEntityInterface[] $entities
  *   Entities to store in the cache.
  */
 protected function setPersistentCache($entities)
 {
     if (!$this->entityType->isPersistentlyCacheable()) {
         return;
     }
     $cache_tags = array($this->entityTypeId . '_values', 'entity_field_info');
     foreach ($entities as $id => $entity) {
         $this->cacheBackend->set($this->buildCacheId($id), $entity, CacheBackendInterface::CACHE_PERMANENT, $cache_tags);
     }
 }
示例#19
0
 /**
  * {@inheritdoc}
  */
 public function write($name, array $data)
 {
     if ($this->storage->write($name, $data)) {
         // While not all written data is read back, setting the cache instead of
         // just deleting it avoids cache rebuild stampedes.
         $this->cache->set($this->getCacheKey($name), $data);
         $this->findByPrefixCache = array();
         return TRUE;
     }
     return FALSE;
 }
示例#20
0
 /**
  * Marks the fast cache bin as outdated because of a write.
  */
 protected function markAsOutdated()
 {
     // Clocks on a single server can drift. Multiple servers may have slightly
     // differing opinions about the current time. Given that, do not assume
     // 'now' on this server is always later than our stored timestamp.
     $now = microtime(TRUE);
     if ($now > $this->getLastWriteTimestamp()) {
         $this->lastWriteTimestamp = $now;
         $this->consistentBackend->set(self::LAST_WRITE_TIMESTAMP_PREFIX . $this->bin, $this->lastWriteTimestamp);
     }
 }
 /**
  * {@inheritdoc}
  */
 protected function loadDefinitions($countryCode, $parentId = NULL)
 {
     $lookup_id = $parentId ?: $countryCode;
     if (isset($this->definitions[$lookup_id])) {
         return $this->definitions[$lookup_id];
     }
     // If there are predefined subdivisions at this level, try to load them.
     $this->definitions[$lookup_id] = [];
     if ($this->hasData($countryCode, $parentId)) {
         $cache_key = 'address.subdivisions.' . $lookup_id;
         $filename = $this->definitionPath . $lookup_id . '.json';
         if ($cached = $this->cache->get($cache_key)) {
             $this->definitions[$lookup_id] = $cached->data;
         } elseif ($raw_definition = @file_get_contents($filename)) {
             $this->definitions[$lookup_id] = json_decode($raw_definition, TRUE);
             $this->cache->set($cache_key, $this->definitions[$lookup_id], CacheBackendInterface::CACHE_PERMANENT, ['subdivisions']);
         }
     }
     return $this->definitions[$lookup_id];
 }
示例#22
0
 /**
  * Builds a menu tree.
  *
  * This function may be used build the data for a menu tree only, for example
  * to further massage the data manually before further processing happens.
  * MenuTree::checkAccess() needs to be invoked afterwards.
  *
  * @param string $menu_name
  *   The name of the menu.
  * @param array $parameters
  *   The parameters passed into static::buildTree()
  *
  * @see static::buildTree()
  */
 protected function doBuildTree($menu_name, array $parameters = array())
 {
     $language_interface = $this->languageManager->getCurrentLanguage();
     // Build the cache id; sort parents to prevent duplicate storage and remove
     // default parameter values.
     if (isset($parameters['expanded'])) {
         sort($parameters['expanded']);
     }
     $tree_cid = 'links:' . $menu_name . ':tree-data:' . $language_interface->id . ':' . hash('sha256', serialize($parameters));
     // If we do not have this tree in the static cache, check {cache_menu}.
     if (!isset($this->menuTree[$tree_cid])) {
         $cache = $this->cache->get($tree_cid);
         if ($cache && $cache->data) {
             $this->menuTree[$tree_cid] = $cache->data;
         }
     }
     if (!isset($this->menuTree[$tree_cid])) {
         $query = $this->queryFactory->get('menu_link');
         for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) {
             $query->sort('p' . $i, 'ASC');
         }
         $query->condition('menu_name', $menu_name);
         if (!empty($parameters['expanded'])) {
             $query->condition('plid', $parameters['expanded'], 'IN');
         } elseif (!empty($parameters['only_active_trail'])) {
             $query->condition('mlid', $parameters['active_trail'], 'IN');
         }
         $min_depth = isset($parameters['min_depth']) ? $parameters['min_depth'] : 1;
         if ($min_depth != 1) {
             $query->condition('depth', $min_depth, '>=');
         }
         if (isset($parameters['max_depth'])) {
             $query->condition('depth', $parameters['max_depth'], '<=');
         }
         // Add custom query conditions, if any were passed.
         if (isset($parameters['conditions'])) {
             foreach ($parameters['conditions'] as $column => $value) {
                 $query->condition($column, $value);
             }
         }
         // Build an ordered array of links using the query result object.
         $links = array();
         if ($result = $query->execute()) {
             $links = $this->menuLinkStorage->loadMultiple($result);
         }
         $active_trail = isset($parameters['active_trail']) ? $parameters['active_trail'] : array();
         $tree = $this->doBuildTreeData($links, $active_trail, $min_depth);
         // Cache the data, if it is not already in the cache.
         $this->cache->set($tree_cid, $tree, Cache::PERMANENT, array('menu' => $menu_name));
         $this->menuTree[$tree_cid] = $tree;
     }
     return $this->menuTree[$tree_cid];
 }
 /**
  * {@inheritdoc}
  */
 public function get($locale, $fallback_locale = null)
 {
     $locale = $this->resolveLocale($locale, $fallback_locale);
     if (isset($this->numberFormats[$locale])) {
         return $this->numberFormats[$locale];
     }
     // Load the definition.
     $cache_key = 'commerce_price.number_format.' . $locale;
     if ($cached = $this->cache->get($cache_key)) {
         $definition = $cached->data;
     } else {
         $filename = $this->definitionPath . $locale . '.json';
         $definition = json_decode(file_get_contents($filename), true);
         $this->cache->set($cache_key, $definition, CacheBackendInterface::CACHE_PERMANENT, ['number_formats']);
     }
     // Instantiate and alter the number format.
     $number_format = $this->createNumberFormatFromDefinition($definition, $locale);
     $event = new NumberFormatEvent($number_format);
     $this->eventDispatcher->dispatch(PriceEvents::NUMBER_FORMAT_LOAD, $event);
     $this->numberFormats[$locale] = $number_format;
     return $this->numberFormats[$locale];
 }
示例#24
0
 /**
  * Builds the theme registry cache.
  *
  * Theme hook definitions are collected in the following order:
  * - Modules
  * - Base theme engines
  * - Base themes
  * - Theme engine
  * - Theme
  *
  * All theme hook definitions are essentially just collated and merged in the
  * above order. However, various extension-specific default values and
  * customizations are required; e.g., to record the effective file path for
  * theme template. Therefore, this method first collects all extensions per
  * type, and then dispatches the processing for each extension to
  * processExtension().
  *
  * After completing the collection, modules are allowed to alter it. Lastly,
  * any derived and incomplete theme hook definitions that are hook suggestions
  * for base hooks (e.g., 'block__node' for the base hook 'block') need to be
  * determined based on the full registry and classified as 'base hook'.
  *
  * See the @link themeable Default theme implementations topic @endlink for
  * details.
  *
  * @return \Drupal\Core\Utility\ThemeRegistry
  *   The build theme registry.
  *
  * @see hook_theme_registry_alter()
  */
 protected function build()
 {
     $cache = array();
     // First, preprocess the theme hooks advertised by modules. This will
     // serve as the basic registry. Since the list of enabled modules is the
     // same regardless of the theme used, this is cached in its own entry to
     // save building it for every theme.
     if ($cached = $this->cache->get('theme_registry:build:modules')) {
         $cache = $cached->data;
     } else {
         foreach ($this->moduleHandler->getImplementations('theme') as $module) {
             $this->processExtension($cache, $module, 'module', $module, $this->getPath($module));
         }
         // Only cache this registry if all modules are loaded.
         if ($this->moduleHandler->isLoaded()) {
             $this->cache->set("theme_registry:build:modules", $cache, Cache::PERMANENT, array('theme_registry'));
         }
     }
     // Process each base theme.
     // Ensure that we start with the root of the parents, so that both CSS files
     // and preprocess functions comes first.
     foreach (array_reverse($this->theme->getBaseThemes()) as $base) {
         // If the base theme uses a theme engine, process its hooks.
         $base_path = $base->getPath();
         if ($this->theme->getEngine()) {
             $this->processExtension($cache, $this->theme->getEngine(), 'base_theme_engine', $base->getName(), $base_path);
         }
         $this->processExtension($cache, $base->getName(), 'base_theme', $base->getName(), $base_path);
     }
     // And then the same thing, but for the theme.
     if ($this->theme->getEngine()) {
         $this->processExtension($cache, $this->theme->getEngine(), 'theme_engine', $this->theme->getName(), $this->theme->getPath());
     }
     // Hooks provided by the theme itself.
     $this->processExtension($cache, $this->theme->getName(), 'theme', $this->theme->getName(), $this->theme->getPath());
     // Discover and add all preprocess functions for theme hook suggestions.
     $this->postProcessExtension($cache, $this->theme);
     // Let modules and themes alter the registry.
     $this->moduleHandler->alter('theme_registry', $cache);
     $this->themeManager->alterForTheme($this->theme, 'theme_registry', $cache);
     // @todo Implement more reduction of the theme registry entry.
     // Optimize the registry to not have empty arrays for functions.
     foreach ($cache as $hook => $info) {
         if (empty($info['preprocess functions'])) {
             unset($cache[$hook]['preprocess functions']);
         }
     }
     $this->registry = $cache;
     return $this->registry;
 }
示例#25
0
 /**
  * Finds configuration object names starting with a given prefix.
  *
  * Given the following configuration objects:
  * - node.type.article
  * - node.type.page
  *
  * Passing the prefix 'node.type.' will return an array containing the above
  * names.
  *
  * @param string $prefix
  *   The prefix to search for
  *
  * @return array
  *   An array containing matching configuration object names.
  */
 protected function findByPrefix($prefix)
 {
     if (!isset($this->findByPrefixCache[$prefix])) {
         // The : character is not allowed in config file names, so this can not
         // conflict.
         if ($cache = $this->cache->get('find:' . $prefix)) {
             $this->findByPrefixCache[$prefix] = $cache->data;
         } else {
             $this->findByPrefixCache[$prefix] = $this->storage->listAll($prefix);
             $this->cache->set('find:' . $prefix, $this->findByPrefixCache[$prefix], Cache::PERMANENT, array($this::FIND_BY_PREFIX_CACHE_TAG => TRUE));
         }
     }
     return $this->findByPrefixCache[$prefix];
 }
示例#26
0
 /**
  * {@inheritdoc}
  */
 public function getPunctuationCharacters()
 {
     if (empty($this->punctuationCharacters)) {
         $langcode = $this->languageManager->getCurrentLanguage()->getId();
         $cid = 'pathauto:punctuation:' . $langcode;
         if ($cache = $this->cacheBackend->get($cid)) {
             $this->punctuationCharacters = $cache->data;
         } else {
             $punctuation = array();
             $punctuation['double_quotes'] = array('value' => '"', 'name' => t('Double quotation marks'));
             $punctuation['quotes'] = array('value' => '\'', 'name' => t("Single quotation marks (apostrophe)"));
             $punctuation['backtick'] = array('value' => '`', 'name' => t('Back tick'));
             $punctuation['comma'] = array('value' => ',', 'name' => t('Comma'));
             $punctuation['period'] = array('value' => '.', 'name' => t('Period'));
             $punctuation['hyphen'] = array('value' => '-', 'name' => t('Hyphen'));
             $punctuation['underscore'] = array('value' => '_', 'name' => t('Underscore'));
             $punctuation['colon'] = array('value' => ':', 'name' => t('Colon'));
             $punctuation['semicolon'] = array('value' => ';', 'name' => t('Semicolon'));
             $punctuation['pipe'] = array('value' => '|', 'name' => t('Vertical bar (pipe)'));
             $punctuation['left_curly'] = array('value' => '{', 'name' => t('Left curly bracket'));
             $punctuation['left_square'] = array('value' => '[', 'name' => t('Left square bracket'));
             $punctuation['right_curly'] = array('value' => '}', 'name' => t('Right curly bracket'));
             $punctuation['right_square'] = array('value' => ']', 'name' => t('Right square bracket'));
             $punctuation['plus'] = array('value' => '+', 'name' => t('Plus sign'));
             $punctuation['equal'] = array('value' => '=', 'name' => t('Equal sign'));
             $punctuation['asterisk'] = array('value' => '*', 'name' => t('Asterisk'));
             $punctuation['ampersand'] = array('value' => '&', 'name' => t('Ampersand'));
             $punctuation['percent'] = array('value' => '%', 'name' => t('Percent sign'));
             $punctuation['caret'] = array('value' => '^', 'name' => t('Caret'));
             $punctuation['dollar'] = array('value' => '$', 'name' => t('Dollar sign'));
             $punctuation['hash'] = array('value' => '#', 'name' => t('Number sign (pound sign, hash)'));
             $punctuation['at'] = array('value' => '@', 'name' => t('At sign'));
             $punctuation['exclamation'] = array('value' => '!', 'name' => t('Exclamation mark'));
             $punctuation['tilde'] = array('value' => '~', 'name' => t('Tilde'));
             $punctuation['left_parenthesis'] = array('value' => '(', 'name' => t('Left parenthesis'));
             $punctuation['right_parenthesis'] = array('value' => ')', 'name' => t('Right parenthesis'));
             $punctuation['question_mark'] = array('value' => '?', 'name' => t('Question mark'));
             $punctuation['less_than'] = array('value' => '<', 'name' => t('Less-than sign'));
             $punctuation['greater_than'] = array('value' => '>', 'name' => t('Greater-than sign'));
             $punctuation['slash'] = array('value' => '/', 'name' => t('Slash'));
             $punctuation['back_slash'] = array('value' => '\\', 'name' => t('Backslash'));
             // Allow modules to alter the punctuation list and cache the result.
             $this->moduleHandler->alter('pathauto_punctuation_chars', $punctuation);
             $this->cacheBackend->set($cid, $punctuation);
             $this->punctuationCharacters = $punctuation;
         }
     }
     return $this->punctuationCharacters;
 }
示例#27
0
 /**
  * Returns metadata describing supported tokens.
  *
  * The metadata array contains token type, name, and description data as well
  * as an optional pointer indicating that the token chains to another set of
  * tokens.
  *
  * @return array
  *   An associative array of token information, grouped by token type. The
  *   array structure is identical to that of hook_token_info().
  *
  * @see hook_token_info()
  */
 public function getInfo()
 {
     if (is_null($this->tokenInfo)) {
         $cache_id = 'token_info:' . $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
         $cache = $this->cache->get($cache_id);
         if ($cache) {
             $this->tokenInfo = $cache->data;
         } else {
             $this->tokenInfo = $this->moduleHandler->invokeAll('token_info');
             $this->moduleHandler->alter('token_info', $this->tokenInfo);
             $this->cache->set($cache_id, $this->tokenInfo, CacheBackendInterface::CACHE_PERMANENT, array(static::TOKEN_INFO_CACHE_TAG));
         }
     }
     return $this->tokenInfo;
 }
示例#28
0
 /**
  * Marks the fast cache bin as outdated because of a write.
  */
 protected function markAsOutdated()
 {
     // Clocks on a single server can drift. Multiple servers may have slightly
     // differing opinions about the current time. Given that, do not assume
     // 'now' on this server is always later than our stored timestamp.
     // Also add 1 millisecond, to ensure that caches written earlier in the same
     // millisecond are invalidated. It is possible that caches will be later in
     // the same millisecond and are then incorrectly invalidated, but that only
     // costs one additional roundtrip to the persistent cache.
     $now = round(microtime(TRUE) + 0.001, 3);
     if ($now > $this->getLastWriteTimestamp()) {
         $this->lastWriteTimestamp = $now;
         $this->consistentBackend->set(self::LAST_WRITE_TIMESTAMP_PREFIX . $this->bin, $this->lastWriteTimestamp);
     }
 }
示例#29
0
 /**
  * {@inheritdoc}
  */
 public function buildTree($token_type, array $options = [])
 {
     $options += ['restricted' => FALSE, 'depth' => 4, 'data' => [], 'values' => FALSE, 'flat' => FALSE];
     // Do not allow past the maximum token information depth.
     $options['depth'] = min($options['depth'], static::MAX_DEPTH);
     // If $token_type is an entity, make sure we are using the actual token type.
     if ($entity_token_type = $this->entityMapper->getTokenTypeForEntityType($token_type)) {
         $token_type = $entity_token_type;
     }
     $langcode = $this->languageManager->getCurrentLanguage()->getId();
     $tree_cid = "token_tree:{$token_type}:{$langcode}:{$options['depth']}";
     // If we do not have this base tree in the static cache, check the cache
     // otherwise generate and store it in the cache.
     if (!isset($this->builtTrees[$tree_cid])) {
         if ($cache = $this->cacheBackend->get($tree_cid)) {
             $this->builtTrees[$tree_cid] = $cache->data;
         } else {
             $options['parents'] = [];
             $this->builtTrees[$tree_cid] = $this->getTokenData($token_type, $options);
             $this->cacheBackend->set($tree_cid, $this->builtTrees[$tree_cid], Cache::PERMANENT, [Token::TOKEN_INFO_CACHE_TAG]);
         }
     }
     $tree = $this->builtTrees[$tree_cid];
     // If the user has requested a flat tree, convert it.
     if (!empty($options['flat'])) {
         $tree = $this->flattenTree($tree);
     }
     // Fill in token values.
     if (!empty($options['values'])) {
         $token_values = [];
         foreach ($tree as $token => $token_info) {
             if (!empty($token_info['dynamic']) || !empty($token_info['restricted'])) {
                 continue;
             } elseif (!isset($token_info['value'])) {
                 $token_values[$token_info['token']] = $token;
             }
         }
         if (!empty($token_values)) {
             $token_values = $this->tokenService->generate($token_type, $token_values, $options['data'], [], new BubbleableMetadata());
             foreach ($token_values as $token => $replacement) {
                 $tree[$token]['value'] = $replacement;
             }
         }
     }
     return $tree;
 }
 /**
  * {@inheritdoc}
  */
 public function getActiveThemeByName($theme_name)
 {
     if ($cached = $this->cache->get('theme.active_theme.' . $theme_name)) {
         return $cached->data;
     }
     $themes = $this->themeHandler->listInfo();
     // If no theme could be negotiated, or if the negotiated theme is not within
     // the list of installed themes, fall back to the default theme output of
     // core and modules (like Stark, but without a theme extension at all). This
     // is possible, because loadActiveTheme() always loads the Twig theme
     // engine. This is desired, because missing or malformed theme configuration
     // should not leave the application in a broken state. By falling back to
     // default output, the user is able to reconfigure the theme through the UI.
     // Lastly, tests are expected to operate with no theme by default, so as to
     // only assert the original theme output of modules (unless a test manually
     // installs a specific theme).
     if (empty($themes) || !$theme_name || !isset($themes[$theme_name])) {
         $theme_name = 'core';
         // /core/core.info.yml does not actually exist, but is required because
         // Extension expects a pathname.
         $active_theme = $this->getActiveTheme(new Extension($this->root, 'theme', 'core/core.info.yml'));
         // Early-return and do not set state, because the initialized $theme_name
         // differs from the original $theme_name.
         return $active_theme;
     }
     // Find all our ancestor themes and put them in an array.
     $base_themes = array();
     $ancestor = $theme_name;
     while ($ancestor && isset($themes[$ancestor]->base_theme)) {
         $ancestor = $themes[$ancestor]->base_theme;
         if (!$this->themeHandler->themeExists($ancestor)) {
             if ($ancestor == 'stable') {
                 // Themes that depend on Stable will be fixed by system_update_8014().
                 // There is no harm in not adding it as an ancestor since at worst
                 // some people might experience slight visual regressions on
                 // update.php.
                 continue;
             }
             throw new MissingThemeDependencyException(sprintf('Base theme %s has not been installed.', $ancestor), $ancestor);
         }
         $base_themes[] = $themes[$ancestor];
     }
     $active_theme = $this->getActiveTheme($themes[$theme_name], $base_themes);
     $this->cache->set('theme.active_theme.' . $theme_name, $active_theme);
     return $active_theme;
 }