/** * {@inheritdoc} */ public function resolveCurrencyLocale($language_type = LanguageInterface::TYPE_CONTENT) { if (empty($this->currencyLocales[$language_type])) { $currency_locale = NULL; $language_code = $this->languageManager->getCurrentLanguage($language_type)->getId(); // Try this request's country code. $country_code = $this->eventDispatcher->resolveCountryCode(); if ($country_code) { $currency_locale = $this->currencyLocaleStorage->load($language_code . '_' . $country_code); } // Try the site's default country code. if (!$currency_locale) { $country_code = $this->configFactory->get('system.data')->get('country.default'); if ($country_code) { $currency_locale = $this->currencyLocaleStorage->load($language_code . '_' . $country_code); } } // Try the Currency default. if (!$currency_locale) { $currency_locale = $this->currencyLocaleStorage->load($this::DEFAULT_LOCALE); } if ($currency_locale) { $this->currencyLocales[$language_type] = $currency_locale; } else { throw new \RuntimeException(sprintf('The currency locale for %s could not be loaded.', $this::DEFAULT_LOCALE)); } } return $this->currencyLocales[$language_type]; }
/** * {@inheritdoc} */ public function getAllBundleInfo() { if (empty($this->bundleInfo)) { $langcode = $this->languageManager->getCurrentLanguage()->getId(); if ($cache = $this->cacheGet("entity_bundle_info:{$langcode}")) { $this->bundleInfo = $cache->data; } else { $this->bundleInfo = $this->moduleHandler->invokeAll('entity_bundle_info'); foreach ($this->entityTypeManager->getDefinitions() as $type => $entity_type) { // First look for entity types that act as bundles for others, load them // and add them as bundles. if ($bundle_entity_type = $entity_type->getBundleEntityType()) { foreach ($this->entityTypeManager->getStorage($bundle_entity_type)->loadMultiple() as $entity) { $this->bundleInfo[$type][$entity->id()]['label'] = $entity->label(); } } elseif (!isset($this->bundleInfo[$type])) { $this->bundleInfo[$type][$type]['label'] = $entity_type->getLabel(); } } $this->moduleHandler->alter('entity_bundle_info', $this->bundleInfo); $this->cacheSet("entity_bundle_info:{$langcode}", $this->bundleInfo, Cache::PERMANENT, ['entity_types', 'entity_bundles']); } } return $this->bundleInfo; }
/** * {@inheritdoc} */ public function getTranslationFromContext(EntityInterface $entity, $langcode = NULL, $context = array()) { $translation = $entity; if ($entity instanceof TranslatableInterface && count($entity->getTranslationLanguages()) > 1) { if (empty($langcode)) { $langcode = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId(); $entity->addCacheContexts(['languages:' . LanguageInterface::TYPE_CONTENT]); } // Retrieve language fallback candidates to perform the entity language // negotiation, unless the current translation is already the desired one. if ($entity->language()->getId() != $langcode) { $context['data'] = $entity; $context += array('operation' => 'entity_view', 'langcode' => $langcode); $candidates = $this->languageManager->getFallbackCandidates($context); // Ensure the default language has the proper language code. $default_language = $entity->getUntranslated()->language(); $candidates[$default_language->getId()] = LanguageInterface::LANGCODE_DEFAULT; // Return the most fitting entity translation. foreach ($candidates as $candidate) { if ($entity->hasTranslation($candidate)) { $translation = $entity->getTranslation($candidate); break; } } } } return $translation; }
/** * Checks translation access for the entity and operation on the given route. * * @param \Symfony\Component\Routing\Route $route * The route to check against. * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The parametrized route. * @param \Drupal\Core\Session\AccountInterface $account * The currently logged in account. * @param string $source * (optional) For a create operation, the language code of the source. * @param string $target * (optional) For a create operation, the language code of the translation. * @param string $language * (optional) For an update or delete operation, the language code of the * translation being updated or deleted. * @param string $entity_type_id * (optional) The entity type ID. * * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account, $source = NULL, $target = NULL, $language = NULL, $entity_type_id = NULL) { /* @var \Drupal\Core\Entity\ContentEntityInterface $entity */ if ($entity = $route_match->getParameter($entity_type_id)) { if ($account->hasPermission('translate any entity')) { return AccessResult::allowed()->cachePerRole(); } $operation = $route->getRequirement('_access_content_translation_manage'); /* @var \Drupal\content_translation\ContentTranslationHandlerInterface $handler */ $handler = $this->entityManager->getHandler($entity->getEntityTypeId(), 'translation'); // Load translation. $translations = $entity->getTranslationLanguages(); $languages = $this->languageManager->getLanguages(); switch ($operation) { case 'create': $source_language = $this->languageManager->getLanguage($source) ?: $entity->language(); $target_language = $this->languageManager->getLanguage($target) ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT); $is_new_translation = $source_language->getId() != $target_language->getId() && isset($languages[$source_language->getId()]) && isset($languages[$target_language->getId()]) && !isset($translations[$target_language->getId()]); return AccessResult::allowedIf($is_new_translation)->cachePerRole()->cacheUntilEntityChanges($entity)->andIf($handler->getTranslationAccess($entity, $operation)); case 'update': case 'delete': $language = $this->languageManager->getLanguage($language) ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT); $has_translation = isset($languages[$language->getId()]) && $language->getId() != $entity->getUntranslated()->language()->getId() && isset($translations[$language->getId()]); return AccessResult::allowedIf($has_translation)->cachePerRole()->cacheUntilEntityChanges($entity)->andIf($handler->getTranslationAccess($entity, $operation)); } } // No opinion. return AccessResult::neutral(); }
/** * {@inheritdoc} */ public function getRuntimeContexts(array $unqualified_context_ids) { // Add a context for each language type. $language_types = $this->languageManager->getLanguageTypes(); $info = $this->languageManager->getDefinedLanguageTypesInfo(); if ($unqualified_context_ids) { foreach ($unqualified_context_ids as $unqualified_context_id) { if (array_search($unqualified_context_id, $language_types) === FALSE) { unset($language_types[$unqualified_context_id]); } } } $result = []; foreach ($language_types as $type_key) { if (isset($info[$type_key]['name'])) { $context = new Context(new ContextDefinition('language', $info[$type_key]['name'])); $context->setContextValue($this->languageManager->getCurrentLanguage($type_key)); $cacheability = new CacheableMetadata(); $cacheability->setCacheContexts(['languages:' . $type_key]); $context->addCacheableDependency($cacheability); $result[$type_key] = $context; } } return $result; }
/** * {@inheritdoc} */ public function sendMailMessages(MessageInterface $message, AccountInterface $sender) { // Clone the sender, as we make changes to mail and name properties. $sender_cloned = clone $this->userStorage->load($sender->id()); $params = array(); $current_langcode = $this->languageManager->getCurrentLanguage()->getId(); $recipient_langcode = $this->languageManager->getDefaultLanguage()->getId(); $contact_form = $message->getContactForm(); if ($sender_cloned->isAnonymous()) { // At this point, $sender contains an anonymous user, so we need to take // over the submitted form values. $sender_cloned->name = $message->getSenderName(); $sender_cloned->mail = $message->getSenderMail(); // For the email message, clarify that the sender name is not verified; it // could potentially clash with a username on this site. $sender_cloned->name = $this->t('@name (not verified)', array('@name' => $message->getSenderName())); } // Build email parameters. $params['contact_message'] = $message; $params['sender'] = $sender_cloned; if (!$message->isPersonal()) { // Send to the form recipient(s), using the site's default language. $params['contact_form'] = $contact_form; $to = implode(', ', $contact_form->getRecipients()); } elseif ($recipient = $message->getPersonalRecipient()) { // Send to the user in the user's preferred language. $to = $recipient->getEmail(); $recipient_langcode = $recipient->getPreferredLangcode(); $params['recipient'] = $recipient; } else { throw new MailHandlerException('Unable to determine message recipient'); } // Send email to the recipient(s). $key_prefix = $message->isPersonal() ? 'user' : 'page'; $this->mailManager->mail('contact', $key_prefix . '_mail', $to, $recipient_langcode, $params, $sender_cloned->getEmail()); // If requested, send a copy to the user, using the current language. if ($message->copySender()) { $this->mailManager->mail('contact', $key_prefix . '_copy', $sender_cloned->getEmail(), $current_langcode, $params, $sender_cloned->getEmail()); } // If configured, send an auto-reply, using the current language. if (!$message->isPersonal() && $contact_form->getReply()) { // User contact forms do not support an auto-reply message, so this // message always originates from the site. if (!$sender_cloned->getEmail()) { $this->logger->error('Error sending auto-reply, missing sender e-mail address in %contact_form', ['%contact_form' => $contact_form->label()]); } else { $this->mailManager->mail('contact', 'page_autoreply', $sender_cloned->getEmail(), $current_langcode, $params); } } if (!$message->isPersonal()) { $this->logger->notice('%sender-name (@sender-from) sent an email regarding %contact_form.', array('%sender-name' => $sender_cloned->getUsername(), '@sender-from' => $sender_cloned->getEmail(), '%contact_form' => $contact_form->label())); } else { $this->logger->notice('%sender-name (@sender-from) sent %recipient-name an email.', array('%sender-name' => $sender_cloned->getUsername(), '@sender-from' => $sender_cloned->getEmail(), '%recipient-name' => $message->getPersonalRecipient()->getUsername())); } }
/** * {@inheritdoc} */ public function getNumberOfPlurals($langcode = NULL) { // Ensure that the formulae are loaded. $this->loadFormulae(); // Set the langcode to use. $langcode = $langcode ?: $this->languageManager->getCurrentLanguage()->getId(); // We assume 2 plurals if there is no explicit information yet. if (!isset($this->formulae[$langcode]['plurals'])) { return 2; } return $this->formulae[$langcode]['plurals']; }
/** * {@inheritdoc} */ public function onBlockActiveContext(BlockContextEvent $event) { // Add a context for each language type. $language_types = $this->languageManager->getLanguageTypes(); $info = $this->languageManager->getDefinedLanguageTypesInfo(); foreach ($language_types as $type_key) { if (isset($info[$type_key]['name'])) { $context = new Context(new ContextDefinition('language', $info[$type_key]['name'])); $context->setContextValue($this->languageManager->getCurrentLanguage($type_key)); $event->setContext('language.' . $type_key, $context); } } }
/** * Sets the 'is-active' class on links. * * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event * The response event. */ public function onResponse(FilterResponseEvent $event) { // Only care about HTML responses. if (stripos($event->getResponse()->headers->get('Content-Type'), 'text/html') === FALSE) { return; } // For authenticated users, the 'is-active' class is set in JavaScript. // @see system_page_attachments() if ($this->currentUser->isAuthenticated()) { return; } $response = $event->getResponse(); $response->setContent(static::setLinkActiveClass($response->getContent(), ltrim($this->currentPath->getPath(), '/'), $this->pathMatcher->isFrontPage(), $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId(), $event->getRequest()->query->all())); }
/** * Enhances a page object based on a render array. * * @param \Drupal\Core\Page\HtmlPage $page * The page object to enhance. * @param array $page_array * The page array to extract onto the page object. * * @return \Drupal\Core\Page\HtmlPage * The modified page object. */ public function preparePage(HtmlPage $page, &$page_array) { $page_array['#page'] = $page; // HTML element attributes. $language_interface = $this->languageManager->getCurrentLanguage(); $html_attributes = $page->getHtmlAttributes(); $html_attributes['lang'] = $language_interface->getId(); $html_attributes['dir'] = $language_interface->getDirection(); $this->setDefaultMetaTags($page); // @todo: collect feed links from #attached rather than a static once // http://drupal.org/node/2256365 is completed. foreach (drupal_get_feeds() as $feed) { // Force the URL to be absolute, for consistency with other <link> tags // output by Drupal. $link = new FeedLinkElement($feed['title'], _url($feed['url'], array('absolute' => TRUE))); $page->addLinkElement($link); } // Add libraries and CSS used by this theme. $active_theme = \Drupal::theme()->getActiveTheme(); foreach ($active_theme->getLibraries() as $library) { $page_array['#attached']['library'][] = $library; } foreach ($active_theme->getStyleSheets() as $media => $stylesheets) { foreach ($stylesheets as $stylesheet) { $page_array['#attached']['css'][$stylesheet] = array('group' => CSS_AGGREGATE_THEME, 'every_page' => TRUE, 'media' => $media); } } return $page; }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { // This form submits to the search page, so processing happens there. $keys = $form_state->getValue('keys'); /* @var $searchApiPage \Drupal\search_api_page\SearchApiPageInterface */ $form_state->setRedirectUrl(Url::fromRoute('search_api_page.' . $this->languageManager->getCurrentLanguage()->getId() . '.' . $form_state->getValue('search_api_page'), array('keys' => $keys))); }
/** * Formats a date, using a date type or a custom date format string. * * @param int $timestamp * A UNIX timestamp to format. * @param string $type * (optional) The format to use, one of: * - One of the built-in formats: 'short', 'medium', * 'long', 'html_datetime', 'html_date', 'html_time', * 'html_yearless_date', 'html_week', 'html_month', 'html_year'. * - The name of a date type defined by a date format config entity. * - The machine name of an administrator-defined date format. * - 'custom', to use $format. * Defaults to 'medium'. * @param string $format * (optional) If $type is 'custom', a PHP date format string suitable for * input to date(). Use a backslash to escape ordinary text, so it does not * get interpreted as date format characters. * @param string|null $timezone * (optional) Time zone identifier, as described at * http://php.net/manual/timezones.php Defaults to the time zone used to * display the page. * @param string|null $langcode * (optional) Language code to translate to. NULL (default) means to use * the user interface language for the page. * * @return string * A translated date string in the requested format. Since the format may * contain user input, this value should be escaped when output. */ public function format($timestamp, $type = 'medium', $format = '', $timezone = NULL, $langcode = NULL) { if (!isset($timezone)) { $timezone = date_default_timezone_get(); } // Store DateTimeZone objects in an array rather than repeatedly // constructing identical objects over the life of a request. if (!isset($this->timezones[$timezone])) { $this->timezones[$timezone] = timezone_open($timezone); } if (empty($langcode)) { $langcode = $this->languageManager->getCurrentLanguage()->getId(); } // Create a DrupalDateTime object from the timestamp and timezone. $create_settings = array('langcode' => $langcode, 'country' => $this->country()); $date = DrupalDateTime::createFromTimestamp($timestamp, $this->timezones[$timezone], $create_settings); // If we have a non-custom date format use the provided date format pattern. if ($date_format = $this->dateFormat($type, $langcode)) { $format = $date_format->getPattern(); } // Fall back to medium if a format was not found. if (empty($format)) { $format = $this->dateFormat('fallback', $langcode)->getPattern(); } // Call $date->format(). $settings = array('langcode' => $langcode); return $date->format($format, $settings); }
/** * {@inheritdoc} */ public function form(array $form, FormStateInterface $form_state) { $block = $this->entity; $account = $this->currentUser(); if ($this->operation == 'edit') { $form['#title'] = $this->t('Edit custom block %label', array('%label' => $block->label())); } // Override the default CSS class name, since the user-defined custom block // type name in 'TYPE-block-form' potentially clashes with third-party class // names. $form['#attributes']['class'][0] = drupal_html_class('block-' . $block->bundle() . '-form'); if ($this->moduleHandler->moduleExists('language')) { $language_configuration = language_get_default_configuration('block_content', $block->bundle()); // Set the correct default language. if ($block->isNew()) { $language_default = $this->languageManager->getCurrentLanguage($language_configuration['langcode']); $block->langcode->value = $language_default->getId(); } } $form['langcode'] = array('#title' => $this->t('Language'), '#type' => 'language_select', '#default_value' => $block->getUntranslated()->language()->getId(), '#languages' => LanguageInterface::STATE_ALL, '#access' => isset($language_configuration['language_show']) && $language_configuration['language_show']); $form['advanced'] = array('#type' => 'vertical_tabs', '#weight' => 99); // Add a log field if the "Create new revision" option is checked, or if the // current user has the ability to check that option. $form['revision_information'] = array('#type' => 'details', '#title' => $this->t('Revision information'), '#open' => $block->isNewRevision(), '#group' => 'advanced', '#attributes' => array('class' => array('block-content-form-revision-information')), '#attached' => array('library' => array('block_content/drupal.block_content')), '#weight' => 20, '#access' => $block->isNewRevision() || $account->hasPermission('administer blocks')); $form['revision_information']['revision'] = array('#type' => 'checkbox', '#title' => $this->t('Create new revision'), '#default_value' => $block->isNewRevision(), '#access' => $account->hasPermission('administer blocks')); // Check the revision log checkbox when the log textarea is filled in. // This must not happen if "Create new revision" is enabled by default, // since the state would auto-disable the checkbox otherwise. if (!$block->isNewRevision()) { $form['revision_information']['revision']['#states'] = array('checked' => array('textarea[name="revision_log"]' => array('empty' => FALSE))); } $form['revision_information']['revision_log'] = array('#type' => 'textarea', '#title' => $this->t('Revision log message'), '#rows' => 4, '#default_value' => $block->getRevisionLog(), '#description' => $this->t('Briefly describe the changes you have made.')); return parent::form($form, $form_state, $block); }
/** * {@inheritdoc} */ public function getJSSettings(EditorEntity $editor) { $settings = array(); // Get the settings for all enabled plugins, even the internal ones. $enabled_plugins = array_keys($this->ckeditorPluginManager->getEnabledPluginFiles($editor, TRUE)); foreach ($enabled_plugins as $plugin_id) { $plugin = $this->ckeditorPluginManager->createInstance($plugin_id); $settings += $plugin->getConfig($editor); } // Fall back on English if no matching language code was found. $display_langcode = 'en'; // Map the interface language code to a CKEditor translation. $ckeditor_langcodes = $this->getLangcodes(); $language_interface = $this->languageManager->getCurrentLanguage(); if (isset($ckeditor_langcodes[$language_interface->getId()])) { $display_langcode = $ckeditor_langcodes[$language_interface->getId()]; } // Next, set the most fundamental CKEditor settings. $external_plugin_files = $this->ckeditorPluginManager->getEnabledPluginFiles($editor); $settings += array('toolbar' => $this->buildToolbarJSSetting($editor), 'contentsCss' => $this->buildContentsCssJSSetting($editor), 'extraPlugins' => implode(',', array_keys($external_plugin_files)), 'language' => $display_langcode, 'stylesSet' => FALSE); // Finally, set Drupal-specific CKEditor settings. $settings += array('drupalExternalPlugins' => array_map('file_create_url', $external_plugin_files)); // Parse all CKEditor plugin JavaScript files for translations. if ($this->moduleHandler->moduleExists('locale')) { locale_js_translate(array_values($external_plugin_files)); } ksort($settings); return $settings; }
/** * {@inheritdoc} */ protected function doCreate(array $values) { // Set default language to current language if not provided. $values += array($this->langcodeKey => $this->languageManager->getCurrentLanguage()->getId()); $entity = new $this->entityClass($values, $this->entityTypeId); return $entity; }
/** * Constructs this ViewsData object. * * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend * The cache backend to use. * @param \Drupal\Core\Config\ConfigFactoryInterface $config * The configuration factory object to use. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler class to use for invoking hooks. * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager * The language manager. */ public function __construct(CacheBackendInterface $cache_backend, ConfigFactoryInterface $config, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager) { $this->cacheBackend = $cache_backend; $this->moduleHandler = $module_handler; $this->languageManager = $language_manager; $this->langcode = $this->languageManager->getCurrentLanguage()->getId(); $this->skipCache = $config->get('views.settings')->get('skip_cache'); }
/** * {@inheritdoc} */ public function getAliasByPath($path, $langcode = NULL) { if ($path[0] !== '/') { throw new \InvalidArgumentException(sprintf('Source path %s has to start with a slash.', $path)); } // If no language is explicitly specified we default to the current URL // language. If we used a language different from the one conveyed by the // requested URL, we might end up being unable to check if there is a path // alias matching the URL path. $langcode = $langcode ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId(); // Check the path whitelist, if the top-level part before the first / // is not in the list, then there is no need to do anything further, // it is not in the database. if ($path === '/' || !$this->whitelist->get(strtok(trim($path, '/'), '/'))) { return $path; } // During the first call to this method per language, load the expected // paths for the page from cache. if (empty($this->langcodePreloaded[$langcode])) { $this->langcodePreloaded[$langcode] = TRUE; $this->lookupMap[$langcode] = array(); // Load the cached paths that should be used for preloading. This only // happens if a cache key has been set. if ($this->preloadedPathLookups === FALSE) { $this->preloadedPathLookups = array(); if ($this->cacheKey) { if ($cached = $this->cache->get($this->cacheKey)) { $this->preloadedPathLookups = $cached->data; } else { $this->cacheNeedsWriting = TRUE; } } } // Load paths from cache. if (!empty($this->preloadedPathLookups[$langcode])) { $this->lookupMap[$langcode] = $this->storage->preloadPathAlias($this->preloadedPathLookups[$langcode], $langcode); // Keep a record of paths with no alias to avoid querying twice. $this->noAlias[$langcode] = array_flip(array_diff_key($this->preloadedPathLookups[$langcode], array_keys($this->lookupMap[$langcode]))); } } // If we already know that there are no aliases for this path simply return. if (!empty($this->noAlias[$langcode][$path])) { return $path; } // If the alias has already been loaded, return it from static cache. if (isset($this->lookupMap[$langcode][$path])) { return $this->lookupMap[$langcode][$path]; } // Try to load alias from storage. if ($alias = $this->storage->lookupPathAlias($path, $langcode)) { $this->lookupMap[$langcode][$path] = $alias; return $alias; } // We can't record anything into $this->lookupMap because we didn't find any // aliases for this path. Thus cache to $this->noAlias. $this->noAlias[$langcode][$path] = TRUE; return $path; }
/** * Sets extra headers on successful responses. * * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event * The event to process. */ public function onRespond(FilterResponseEvent $event) { if (!$event->isMasterRequest()) { return; } $request = $event->getRequest(); $response = $event->getResponse(); // Set the X-UA-Compatible HTTP header to force IE to use the most recent // rendering engine. $response->headers->set('X-UA-Compatible', 'IE=edge', FALSE); // Set the Content-language header. $response->headers->set('Content-language', $this->languageManager->getCurrentLanguage()->getId()); // Prevent browsers from sniffing a response and picking a MIME type // different from the declared content-type, since that can lead to // XSS and other vulnerabilities. // https://www.owasp.org/index.php/List_of_useful_HTTP_headers $response->headers->set('X-Content-Type-Options', 'nosniff', FALSE); $response->headers->set('X-Frame-Options', 'SAMEORIGIN', FALSE); // If the current response isn't an implementation of the // CacheableResponseInterface, we assume that a Response is either // explicitly not cacheable or that caching headers are already set in // another place. if (!$response instanceof CacheableResponseInterface) { if (!$this->isCacheControlCustomized($response)) { $this->setResponseNotCacheable($response, $request); } // HTTP/1.0 proxies do not support the Vary header, so prevent any caching // by sending an Expires date in the past. HTTP/1.1 clients ignore the // Expires header if a Cache-Control: max-age directive is specified (see // RFC 2616, section 14.9.3). if (!$response->headers->has('Expires')) { $this->setExpiresNoCache($response); } return; } if ($this->debugCacheabilityHeaders) { // Expose the cache contexts and cache tags associated with this page in a // X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags header respectively. $response_cacheability = $response->getCacheableMetadata(); $response->headers->set('X-Drupal-Cache-Tags', implode(' ', $response_cacheability->getCacheTags())); $response->headers->set('X-Drupal-Cache-Contexts', implode(' ', $this->cacheContextsManager->optimizeTokens($response_cacheability->getCacheContexts()))); } $is_cacheable = $this->requestPolicy->check($request) === RequestPolicyInterface::ALLOW && $this->responsePolicy->check($response, $request) !== ResponsePolicyInterface::DENY; // Add headers necessary to specify whether the response should be cached by // proxies and/or the browser. if ($is_cacheable && $this->config->get('cache.page.max_age') > 0) { if (!$this->isCacheControlCustomized($response)) { // Only add the default Cache-Control header if the controller did not // specify one on the response. $this->setResponseCacheable($response, $request); } } else { // If either the policy forbids caching or the sites configuration does // not allow to add a max-age directive, then enforce a Cache-Control // header declaring the response as not cacheable. $this->setResponseNotCacheable($response, $request); } }
/** * Helper function to handle multilingual paths. * * @param string $path_info * Path that might contain language prefix. * * @return string $path info * Path without language prefix. */ protected function getPath($path_info) { $language_prefix = '/' . $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId() . '/'; if (substr($path_info, 0, strlen($language_prefix)) == $language_prefix) { $path_info = '/' . substr($path_info, strlen($language_prefix)); } return $path_info; }
/** * Sets extra headers on successful responses. * * @param Symfony\Component\HttpKernel\Event\FilterResponseEvent $event * The event to process. */ public function onRespond(FilterResponseEvent $event) { if (!$event->isMasterRequest()) { return; } $request = $event->getRequest(); $response = $event->getResponse(); // Set the X-UA-Compatible HTTP header to force IE to use the most recent // rendering engine. $response->headers->set('X-UA-Compatible', 'IE=edge', FALSE); // Set the Content-language header. $response->headers->set('Content-language', $this->languageManager->getCurrentLanguage()->getId()); // Prevent browsers from sniffing a response and picking a MIME type // different from the declared content-type, since that can lead to // XSS and other vulnerabilities. // https://www.owasp.org/index.php/List_of_useful_HTTP_headers $response->headers->set('X-Content-Type-Options', 'nosniff', FALSE); // Attach globally-declared headers to the response object so that Symfony // can send them for us correctly. // @todo Remove this once drupal_process_attached() no longer calls // _drupal_add_http_header(), which has its own static. Instead, // _drupal_process_attached() should use // \Symfony\Component\HttpFoundation\Response->headers->set(), which is // already documented on the (deprecated) _drupal_process_attached() to // become the final, intended mechanism. $headers = drupal_get_http_header(); foreach ($headers as $name => $value) { // Symfony special-cases the 'Status' header. if ($name === 'status') { $response->setStatusCode($value); } $response->headers->set($name, $value, FALSE); } // Expose the cache contexts and cache tags associated with this page in a // X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags header respectively. if ($response instanceof CacheableResponseInterface) { $response_cacheability = $response->getCacheableMetadata(); $response->headers->set('X-Drupal-Cache-Tags', implode(' ', $response_cacheability->getCacheTags())); $response->headers->set('X-Drupal-Cache-Contexts', implode(' ', $this->cacheContextsManager->optimizeTokens($response_cacheability->getCacheContexts()))); } $is_cacheable = $this->requestPolicy->check($request) === RequestPolicyInterface::ALLOW && $this->responsePolicy->check($response, $request) !== ResponsePolicyInterface::DENY; // Add headers necessary to specify whether the response should be cached by // proxies and/or the browser. if ($is_cacheable && $this->config->get('cache.page.max_age') > 0) { if (!$this->isCacheControlCustomized($response)) { // Only add the default Cache-Control header if the controller did not // specify one on the response. $this->setResponseCacheable($response, $request); } } else { // If either the policy forbids caching or the sites configuration does // not allow to add a max-age directive, then enforce a Cache-Control // header declaring the response as not cacheable. $this->setResponseNotCacheable($response, $request); } }
/** * Checks translation access for the entity and operation on the given route. * * @param \Symfony\Component\Routing\Route $route * The route to check against. * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The parametrized route. * @param \Drupal\Core\Session\AccountInterface $account * The currently logged in account. * @param string $source * (optional) For a create operation, the language code of the source. * @param string $target * (optional) For a create operation, the language code of the translation. * @param string $language * (optional) For an update or delete operation, the language code of the * translation being updated or deleted. * @param string $entity_type_id * (optional) The entity type ID. * * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account, $source = NULL, $target = NULL, $language = NULL, $entity_type_id = NULL) { /* @var \Drupal\Core\Entity\ContentEntityInterface $entity */ if ($entity = $route_match->getParameter($entity_type_id)) { $operation = $route->getRequirement('_access_content_translation_manage'); $language = $this->languageManager->getLanguage($language) ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT); $entity_type = $this->entityManager->getDefinition($entity_type_id); if (in_array($operation, ['update', 'delete'])) { // Translation operations cannot be performed on the default // translation. if ($language->getId() == $entity->getUntranslated()->language()->getId()) { return AccessResult::forbidden()->addCacheableDependency($entity); } // Editors have no access to the translation operations, as entity // access already grants them an equal or greater access level. $templates = ['update' => 'edit-form', 'delete' => 'delete-form']; if ($entity->access($operation) && $entity_type->hasLinkTemplate($templates[$operation])) { return AccessResult::forbidden()->cachePerPermissions(); } } if ($account->hasPermission('translate any entity')) { return AccessResult::allowed()->cachePerPermissions(); } /* @var \Drupal\content_translation\ContentTranslationHandlerInterface $handler */ $handler = $this->entityManager->getHandler($entity->getEntityTypeId(), 'translation'); // Load translation. $translations = $entity->getTranslationLanguages(); $languages = $this->languageManager->getLanguages(); switch ($operation) { case 'create': $source_language = $this->languageManager->getLanguage($source) ?: $entity->language(); $target_language = $this->languageManager->getLanguage($target) ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT); $is_new_translation = $source_language->getId() != $target_language->getId() && isset($languages[$source_language->getId()]) && isset($languages[$target_language->getId()]) && !isset($translations[$target_language->getId()]); return AccessResult::allowedIf($is_new_translation)->cachePerPermissions()->addCacheableDependency($entity)->andIf($handler->getTranslationAccess($entity, $operation)); case 'delete': case 'update': $has_translation = isset($languages[$language->getId()]) && $language->getId() != $entity->getUntranslated()->language()->getId() && isset($translations[$language->getId()]); return AccessResult::allowedIf($has_translation)->cachePerPermissions()->addCacheableDependency($entity)->andIf($handler->getTranslationAccess($entity, $operation)); } } // No opinion. return AccessResult::neutral(); }
/** * Sets extra headers on successful responses. * * @param Symfony\Component\HttpKernel\Event\FilterResponseEvent $event * The event to process. */ public function onRespond(FilterResponseEvent $event) { if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST) { return; } $request = $event->getRequest(); $response = $event->getResponse(); // Set the X-UA-Compatible HTTP header to force IE to use the most recent // rendering engine or use Chrome's frame rendering engine if available. $response->headers->set('X-UA-Compatible', 'IE=edge,chrome=1', FALSE); // Set the Content-language header. $response->headers->set('Content-language', $this->languageManager->getCurrentLanguage()->getId()); // Attach globally-declared headers to the response object so that Symfony // can send them for us correctly. // @todo Remove this once drupal_process_attached() no longer calls // _drupal_add_http_header(), which has its own static. Instead, // _drupal_process_attached() should use // \Symfony\Component\HttpFoundation\Response->headers->set(), which is // already documented on the (deprecated) _drupal_process_attached() to // become the final, intended mechanism. $headers = drupal_get_http_header(); foreach ($headers as $name => $value) { // Symfony special-cases the 'Status' header. if ($name === 'status') { $response->setStatusCode($value); } $response->headers->set($name, $value, FALSE); } $is_cacheable = $this->requestPolicy->check($request) === RequestPolicyInterface::ALLOW && $this->responsePolicy->check($response, $request) !== ResponsePolicyInterface::DENY; // Add headers necessary to specify whether the response should be cached by // proxies and/or the browser. if ($is_cacheable && $this->config->get('cache.page.max_age') > 0) { if (!$this->isCacheControlCustomized($response)) { // Only add the default Cache-Control header if the controller did not // specify one on the response. $this->setResponseCacheable($response, $request); } } else { // If either the policy forbids caching or the sites configuration does // not allow to add a max-age directive, then enforce a Cache-Control // header declaring the response as not cacheable. $this->setResponseNotCacheable($response, $request); } // Currently it is not possible to cache some types of responses. Therefore // exclude binary file responses (generated files, e.g. images with image // styles) and streamed responses (files directly read from the disk). // see: https://github.com/symfony/symfony/issues/9128#issuecomment-25088678 if ($is_cacheable && $this->config->get('cache.page.use_internal') && !$response instanceof BinaryFileResponse && !$response instanceof StreamedResponse) { // Store the response in the internal page cache. drupal_page_set_cache($response, $request); $response->headers->set('X-Drupal-Cache', 'MISS'); drupal_serve_page_from_cache($response, $request); } }
/** * Sets domain and language contexts for the request. * * We wait to do this in order to avoid circular dependencies * with the locale module. */ protected function initiateContext() { // @TODO: Is this cacheable? // Get the language context. Note that injecting the language manager // into the service created a circular dependency error, so we load from // the core service manager. $this->languageManager = \Drupal::languageManager(); $this->language = $this->languageManager->getCurrentLanguage(); // Get the domain context. $this->domain = $this->domainNegotiator->getActiveDomain(); }
/** * {@inheritdoc} */ protected function init(FormStateInterface $form_state) { $message = $this->entity; // Make the message inherit the current content language unless specifically // set. if ($message->isNew() && !$message->langcode->value) { $language_content = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT); $message->langcode->value = $language_content->getId(); } parent::init($form_state); }
/** * {@inheritdoc} */ protected function setUp() { parent::setUp(); $this->moduleHandler = $this->prophesize(ModuleHandlerInterface::class); $this->moduleHandler->getImplementations('entity_type_build')->willReturn([]); $this->moduleHandler->alter('entity_type', Argument::type('array'))->willReturn(NULL); $this->cacheBackend = $this->prophesize(CacheBackendInterface::class); $this->entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class); $this->cacheTagsInvalidator = $this->prophesize(CacheTagsInvalidatorInterface::class); $language = new Language(['id' => 'en']); $this->languageManager = $this->prophesize(LanguageManagerInterface::class); $this->languageManager->getCurrentLanguage()->willReturn($language); $this->languageManager->getLanguages()->willReturn(['en' => (object) ['id' => 'en']]); $this->typedDataManager = $this->prophesize(TypedDataManagerInterface::class); $this->cacheBackend = $this->prophesize(CacheBackendInterface::class); $container = $this->prophesize(ContainerInterface::class); $container->get('cache_tags.invalidator')->willReturn($this->cacheTagsInvalidator->reveal()); //$container->get('typed_data_manager')->willReturn($this->typedDataManager->reveal()); \Drupal::setContainer($container->reveal()); $this->entityTypeBundleInfo = new EntityTypeBundleInfo($this->entityTypeManager->reveal(), $this->languageManager->reveal(), $this->moduleHandler->reveal(), $this->typedDataManager->reveal(), $this->cacheBackend->reveal()); }
/** * Constructs a ConfigMapperManager. * * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend * The cache backend. * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager * The language manager. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager * The typed config manager. * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler * The theme handler. */ public function __construct(CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, ModuleHandlerInterface $module_handler, TypedConfigManagerInterface $typed_config_manager, ThemeHandlerInterface $theme_handler) { $this->typedConfigManager = $typed_config_manager; $this->factory = new ContainerFactory($this, '\\Drupal\\config_translation\\ConfigMapperInterface'); // Let others alter definitions with hook_config_translation_info_alter(). $this->moduleHandler = $module_handler; $this->themeHandler = $theme_handler; $this->alterInfo('config_translation_info'); // Config translation only uses an info hook discovery, cache by language. $cache_key = 'config_translation_info_plugins' . ':' . $language_manager->getCurrentLanguage()->getId(); $this->setCacheBackend($cache_backend, $cache_key, array('config_translation_info_plugins')); }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $langcode = $this->languageManager->getCurrentLanguage()->getId(); $account = $form_state->getValue('account'); // Mail one time login URL and instructions using current language. $mail = _user_mail_notify('password_reset', $account, $langcode); if (!empty($mail)) { $this->logger('user')->notice('Password reset instructions mailed to %name at %email.', array('%name' => $account->getUsername(), '%email' => $account->getEmail())); drupal_set_message($this->t('Further instructions have been sent to your email address.')); } $form_state->setRedirect('user.page'); }
/** * 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 setUp() { parent::setup(); require_once $this->root . '/core/includes/entity.inc'; $this->namespaces['Drupal\\Core\\Entity'] = $this->root . '/core/lib/Drupal/Core/Entity'; $language = $this->prophesize(LanguageInterface::class); $language->getId()->willReturn('en'); $this->languageManager = $this->prophesize(LanguageManagerInterface::class); $this->languageManager->getCurrentLanguage()->willReturn($language->reveal()); $this->languageManager->getLanguages()->willReturn([$language->reveal()]); // We need to support multiple entity types, including a test type: $type_info = ['test' => ['id' => 'test', 'label' => 'Test', 'entity_keys' => ['bundle' => 'bundle']], 'user' => ['id' => 'user', 'label' => 'Test User', 'entity_keys' => ['bundle' => 'user']], 'node' => ['id' => 'node', 'label' => 'Test Node', 'entity_keys' => ['bundle' => 'dummy']]]; $type_array = []; foreach ($type_info as $type => $info) { $entity_type = new ContentEntityType($info); $type_array[$type] = $entity_type; $this->entityTypeManager->getDefinition($type)->willReturn($entity_type); $this->entityManager->getDefinition($type)->willReturn($entity_type); } // We need a user_role mock as well. $role_entity_info = ['id' => 'user_role', 'label' => 'Test Role']; $role_type = new ConfigEntityType($role_entity_info); $type_array['user_role'] = $role_type; $this->entityTypeManager->getDefinitions()->willReturn($type_array); $this->entityManager->getDefinitions()->willReturn($type_array); $this->entityAccess = $this->prophesize(EntityAccessControlHandlerInterface::class); $this->entityTypeManager->getAccessControlHandler(Argument::any())->willReturn($this->entityAccess->reveal()); // The base field definitions for our test entity aren't used, and would // require additional mocking. It doesn't appear that any of our tests rely // on this for any other entity type that we are mocking. $this->entityFieldManager->getBaseFieldDefinitions(Argument::any())->willReturn([]); $this->entityManager->getBaseFieldDefinitions(Argument::any())->willReturn([]); // Return some dummy bundle information for now, so that the entity manager // does not call out to the config entity system to get bundle information. $this->entityTypeBundleInfo->getBundleInfo(Argument::any())->willReturn(['test' => ['label' => 'Test']]); $this->entityManager->getBundleInfo(Argument::any())->willReturn(['test' => ['label' => 'Test']]); $this->moduleHandler->getImplementations('entity_type_build')->willReturn([]); $this->fieldTypeManager = new FieldTypePluginManager($this->namespaces, $this->cacheBackend, $this->moduleHandler->reveal(), $this->typedDataManager); $this->container->set('plugin.manager.field.field_type', $this->fieldTypeManager); }
/** * {@inheritdoc} */ public function setUp() { parent::setup(); require_once $this->root . '/core/includes/entity.inc'; $this->namespaces['Drupal\\Core\\Entity'] = $this->root . '/core/lib/Drupal/Core/Entity'; $language = $this->prophesize(LanguageInterface::class); $language->getId()->willReturn('en'); $this->languageManager = $this->prophesize(LanguageManagerInterface::class); $this->languageManager->getCurrentLanguage()->willReturn($language->reveal()); $this->languageManager->getLanguages()->willReturn([$language->reveal()]); $entityType = new ContentEntityType(['id' => 'test', 'label' => 'Test', 'entity_keys' => ['bundle' => 'bundle']]); $this->entityManager->getDefinitions()->willReturn(['test' => $entityType]); $this->entityAccess = $this->prophesize(EntityAccessControlHandlerInterface::class); $this->entityManager->getAccessControlHandler(Argument::any())->willReturn($this->entityAccess->reveal()); // The base field definitions for our test entity aren't used, and would // require additional mocking. $this->entityManager->getBaseFieldDefinitions('test')->willReturn([]); // Return some dummy bundle information for now, so that the entity manager // does not call out to the config entity system to get bundle information. $this->entityManager->getBundleInfo(Argument::any())->willReturn(['test' => ['label' => 'Test']]); $this->moduleHandler->getImplementations('entity_type_build')->willReturn([]); }