Update to Drupal 8.1.8. For more information, see https://www.drupal.org/project/drupal/releases/8.1.8
This commit is contained in:
parent
e9f047ccf8
commit
f9f23cdf38
312 changed files with 6751 additions and 1546 deletions
|
@ -12,8 +12,10 @@
|
|||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"symfony/dependency-injection": "~2.8",
|
||||
"symfony/expression-language": "~2.7"
|
||||
"symfony/dependency-injection": "~2.8"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/expression-language": "For using expressions in service container configuration"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "drupal/core-fileCache",
|
||||
"name": "drupal/core-file-cache",
|
||||
"description": "FileCache.",
|
||||
"keywords": ["drupal"],
|
||||
"homepage": "https://www.drupal.org/project/drupal",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "drupal/core-httpFoundation",
|
||||
"name": "drupal/core-http-foundation",
|
||||
"description": "HttpFoundation.",
|
||||
"keywords": ["drupal"],
|
||||
"homepage": "https://www.drupal.org/project/drupal",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "drupal/core-phpStorage",
|
||||
"name": "drupal/core-php-storage",
|
||||
"description": "PhpStorage.",
|
||||
"keywords": ["drupal"],
|
||||
"homepage": "https://www.drupal.org/project/drupal",
|
||||
|
|
|
@ -123,7 +123,7 @@ class Crypt {
|
|||
* The number of random bytes to fetch and base64 encode.
|
||||
*
|
||||
* @return string
|
||||
* The base64 encoded result will have a length of up to 4 * $byte_count.
|
||||
* The base64 encoded result will have a length of up to 4 * $count.
|
||||
*
|
||||
* @see \Drupal\Component\Utility\Crypt::randomBytes()
|
||||
*/
|
||||
|
|
|
@ -36,6 +36,25 @@ class Html {
|
|||
*/
|
||||
protected static $isAjax = FALSE;
|
||||
|
||||
/**
|
||||
* All attributes that may contain URIs.
|
||||
*
|
||||
* - The attributes 'code' and 'codebase' are omitted, because they only exist
|
||||
* for the <applet> tag. The time of Java applets has passed.
|
||||
* - The attribute 'icon' is omitted, because no browser implements the
|
||||
* <command> tag anymore.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/command.
|
||||
* - The 'manifest' attribute is omitted because it only exists for the <html>
|
||||
* tag. That tag only makes sense in a HTML-served-as-HTML context, in which
|
||||
* case relative URLs are guaranteed to work.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes
|
||||
* @see https://stackoverflow.com/questions/2725156/complete-list-of-html-tag-attributes-which-have-a-url-value
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected static $uriAttributes = ['href', 'poster', 'src', 'cite', 'data', 'action', 'formaction', 'srcset', 'about'];
|
||||
|
||||
/**
|
||||
* Prepares a string for use as a valid class name.
|
||||
*
|
||||
|
@ -402,4 +421,61 @@ EOD;
|
|||
return htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all root-relative URLs to absolute URLs.
|
||||
*
|
||||
* Does not change any existing protocol-relative or absolute URLs. Does not
|
||||
* change other relative URLs because they would result in different absolute
|
||||
* URLs depending on the current path. For example: when the same content
|
||||
* containing such a relative URL (for example 'image.png'), is served from
|
||||
* its canonical URL (for example 'http://example.com/some-article') or from
|
||||
* a listing or feed (for example 'http://example.com/all-articles') their
|
||||
* "current path" differs, resulting in different absolute URLs:
|
||||
* 'http://example.com/some-article/image.png' versus
|
||||
* 'http://example.com/all-articles/image.png'. Only one can be correct.
|
||||
* Therefore relative URLs that are not root-relative cannot be safely
|
||||
* transformed and should generally be avoided.
|
||||
*
|
||||
* Necessary for HTML that is served outside of a website, for example, RSS
|
||||
* and e-mail.
|
||||
*
|
||||
* @param string $html
|
||||
* The partial (X)HTML snippet to load. Invalid markup will be corrected on
|
||||
* import.
|
||||
* @param string $scheme_and_host
|
||||
* The root URL, which has a URI scheme, host and optional port.
|
||||
*
|
||||
* @return string
|
||||
* The updated (X)HTML snippet.
|
||||
*/
|
||||
public static function transformRootRelativeUrlsToAbsolute($html, $scheme_and_host) {
|
||||
assert('empty(array_diff(array_keys(parse_url($scheme_and_host)), ["scheme", "host", "port"]))', '$scheme_and_host contains scheme, host and port at most.');
|
||||
assert('isset(parse_url($scheme_and_host)["scheme"])', '$scheme_and_host is absolute and hence has a scheme.');
|
||||
assert('isset(parse_url($scheme_and_host)["host"])', '$base_url is absolute and hence has a host.');
|
||||
|
||||
$html_dom = Html::load($html);
|
||||
$xpath = new \DOMXpath($html_dom);
|
||||
|
||||
// Update all root-relative URLs to absolute URLs in the given HTML.
|
||||
foreach (static::$uriAttributes as $attr) {
|
||||
foreach ($xpath->query("//*[starts-with(@$attr, '/') and not(starts-with(@$attr, '//'))]") as $node) {
|
||||
$node->setAttribute($attr, $scheme_and_host . $node->getAttribute($attr));
|
||||
}
|
||||
foreach ($xpath->query("//*[@srcset]") as $node) {
|
||||
// @see https://html.spec.whatwg.org/multipage/embedded-content.html#attr-img-srcset
|
||||
// @see https://html.spec.whatwg.org/multipage/embedded-content.html#image-candidate-string
|
||||
$image_candidate_strings = explode(',', $node->getAttribute('srcset'));
|
||||
$image_candidate_strings = array_map('trim', $image_candidate_strings);
|
||||
for ($i = 0; $i < count($image_candidate_strings); $i++) {
|
||||
$image_candidate_string = $image_candidate_strings[$i];
|
||||
if ($image_candidate_string[0] === '/' && $image_candidate_string[1] !== '/') {
|
||||
$image_candidate_strings[$i] = $scheme_and_host . $image_candidate_string;
|
||||
}
|
||||
}
|
||||
$node->setAttribute('srcset', implode(', ', $image_candidate_strings));
|
||||
}
|
||||
}
|
||||
return Html::serialize($html_dom);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Drupal\Component\Uuid;
|
||||
|
||||
/**
|
||||
* UUID implementation using the Windows internal GUID extension.
|
||||
* Generates a UUID using the Windows internal GUID extension.
|
||||
*
|
||||
* @see http://php.net/com_create_guid
|
||||
*/
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Drupal\Component\Uuid;
|
||||
|
||||
/**
|
||||
* UUID implementation using the PECL extension.
|
||||
* Generates a UUID using the PECL extension.
|
||||
*/
|
||||
class Pecl implements UuidInterface {
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class Uuid {
|
|||
const VALID_PATTERN = '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}';
|
||||
|
||||
/**
|
||||
* Checks that a string appears to be in the format of a UUID.
|
||||
* Checks whether a string appears to be in the format of a UUID.
|
||||
*
|
||||
* Implementations should not implement validation, since UUIDs should be in
|
||||
* a consistent format across all implementations.
|
||||
|
|
|
@ -95,7 +95,10 @@ abstract class ConfigFactoryOverrideBase implements EventSubscriberInterface {
|
|||
elseif (is_array($override_data[$key])) {
|
||||
if (is_array($original_data[$key])) {
|
||||
// Do the filtering one level deeper.
|
||||
$changed = $this->filterNestedArray($original_data[$key], $override_data[$key]);
|
||||
// Ensure that we track $changed along the way.
|
||||
if ($this->filterNestedArray($original_data[$key], $override_data[$key])) {
|
||||
$changed = TRUE;
|
||||
}
|
||||
// If no overrides are left under this level, remove the level.
|
||||
if (empty($override_data[$key])) {
|
||||
unset($override_data[$key]);
|
||||
|
|
|
@ -159,7 +159,8 @@ class Cron implements CronInterface {
|
|||
$queue_worker = $this->queueManager->createInstance($queue_name);
|
||||
$end = time() + (isset($info['cron']['time']) ? $info['cron']['time'] : 15);
|
||||
$queue = $this->queueFactory->get($queue_name);
|
||||
while (time() < $end && ($item = $queue->claimItem())) {
|
||||
$lease_time = isset($info['cron']['time']) ?: NULL;
|
||||
while (time() < $end && ($item = $queue->claimItem($lease_time))) {
|
||||
try {
|
||||
$queue_worker->processItem($item->data);
|
||||
$queue->deleteItem($item);
|
||||
|
|
|
@ -660,7 +660,7 @@ class Select extends Query implements SelectInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function range($start = NULL, $length = NULL) {
|
||||
$this->range = func_num_args() ? array('start' => $start, 'length' => $length) : array();
|
||||
$this->range = $start !== NULL ? array('start' => $start, 'length' => $length) : array();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -860,6 +860,14 @@ class Select extends Query implements SelectInterface {
|
|||
$query .= "\nHAVING " . $this->having;
|
||||
}
|
||||
|
||||
// UNION is a little odd, as the select queries to combine are passed into
|
||||
// this query, but syntactically they all end up on the same level.
|
||||
if ($this->union) {
|
||||
foreach ($this->union as $union) {
|
||||
$query .= ' ' . $union['type'] . ' ' . (string) $union['query'];
|
||||
}
|
||||
}
|
||||
|
||||
// ORDER BY
|
||||
if ($this->order) {
|
||||
$query .= "\nORDER BY ";
|
||||
|
@ -879,14 +887,6 @@ class Select extends Query implements SelectInterface {
|
|||
$query .= "\nLIMIT " . (int) $this->range['length'] . " OFFSET " . (int) $this->range['start'];
|
||||
}
|
||||
|
||||
// UNION is a little odd, as the select queries to combine are passed into
|
||||
// this query, but syntactically they all end up on the same level.
|
||||
if ($this->union) {
|
||||
foreach ($this->union as $union) {
|
||||
$query .= ' ' . $union['type'] . ' ' . (string) $union['query'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->forUpdate) {
|
||||
$query .= ' FOR UPDATE';
|
||||
}
|
||||
|
|
|
@ -1032,6 +1032,11 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C
|
|||
$this->clearTranslationCache();
|
||||
$translations = $this->translations;
|
||||
$this->translations = &$translations;
|
||||
|
||||
// Ensure the enforceIsNew property is actually cloned by overwriting the
|
||||
// original reference with one pointing to a copy of it.
|
||||
$enforce_is_new = $this->enforceIsNew;
|
||||
$this->enforceIsNew = &$enforce_is_new;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -222,7 +222,9 @@ abstract class Entity implements EntityInterface {
|
|||
->setOption('entity', $this);
|
||||
|
||||
// Display links by default based on the current language.
|
||||
if ($rel !== 'collection') {
|
||||
// Link relations that do not require an existing entity should not be
|
||||
// affected by this entity's language, however.
|
||||
if (!in_array($rel, ['collection', 'add-page', 'add-form'], TRUE)) {
|
||||
$options += ['language' => $this->language()];
|
||||
}
|
||||
|
||||
|
@ -302,10 +304,14 @@ abstract class Entity implements EntityInterface {
|
|||
protected function urlRouteParameters($rel) {
|
||||
$uri_route_parameters = [];
|
||||
|
||||
if ($rel != 'collection') {
|
||||
if (!in_array($rel, ['collection', 'add-page', 'add-form'], TRUE)) {
|
||||
// The entity ID is needed as a route parameter.
|
||||
$uri_route_parameters[$this->getEntityTypeId()] = $this->id();
|
||||
}
|
||||
if ($rel === 'add-form' && ($this->getEntityType()->hasKey('bundle'))) {
|
||||
$parameter_name = $this->getEntityType()->getBundleEntityType() ?: $this->getEntityType()->getKey('bundle');
|
||||
$uri_route_parameters[$parameter_name] = $this->bundle();
|
||||
}
|
||||
if ($rel === 'revision' && $this instanceof RevisionableInterface) {
|
||||
$uri_route_parameters[$this->getEntityTypeId() . '_revision'] = $this->getRevisionId();
|
||||
}
|
||||
|
|
|
@ -277,7 +277,7 @@ class EntityViewDisplay extends EntityDisplayBase implements EntityViewDisplayIn
|
|||
'view_mode' => $this->originalMode,
|
||||
'display' => $this,
|
||||
);
|
||||
\Drupal::moduleHandler()->alter('entity_display_build', $build_list[$key], $context);
|
||||
\Drupal::moduleHandler()->alter('entity_display_build', $build_list[$id], $context);
|
||||
}
|
||||
|
||||
return $build_list;
|
||||
|
|
|
@ -172,7 +172,7 @@ class EntityResolverManager {
|
|||
// First try to figure out whether there is already a parameter upcasting
|
||||
// the same entity type already.
|
||||
foreach ($parameter_definitions as $info) {
|
||||
if (isset($info['type'])) {
|
||||
if (isset($info['type']) && (strpos($info['type'], 'entity:') === 0)) {
|
||||
// The parameter types are in the form 'entity:$entity_type'.
|
||||
list(, $parameter_entity_type) = explode(':', $info['type'], 2);
|
||||
if ($parameter_entity_type == $entity_type) {
|
||||
|
|
|
@ -515,15 +515,29 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
|
|||
// Find revisioned fields that are not entity keys. Exclude the langcode
|
||||
// key as the base table holds only the default language.
|
||||
$base_fields = array_diff($table_mapping->getFieldNames($this->baseTable), array($this->langcodeKey));
|
||||
$fields = array_diff($table_mapping->getFieldNames($this->revisionDataTable), $base_fields);
|
||||
$revisioned_fields = array_diff($table_mapping->getFieldNames($this->revisionDataTable), $base_fields);
|
||||
|
||||
// Find fields that are not revisioned or entity keys. Data fields have
|
||||
// the same value regardless of entity revision.
|
||||
$data_fields = array_diff($table_mapping->getFieldNames($this->dataTable), $fields, $base_fields);
|
||||
$data_fields = array_diff($table_mapping->getFieldNames($this->dataTable), $revisioned_fields, $base_fields);
|
||||
// If there are no data fields then only revisioned fields are needed
|
||||
// else both data fields and revisioned fields are needed to map the
|
||||
// entity values.
|
||||
$all_fields = $revisioned_fields;
|
||||
if ($data_fields) {
|
||||
$fields = array_merge($fields, $data_fields);
|
||||
$all_fields = array_merge($revisioned_fields, $data_fields);
|
||||
$query->leftJoin($this->dataTable, 'data', "(revision.$this->idKey = data.$this->idKey)");
|
||||
$query->fields('data', $data_fields);
|
||||
$column_names = [];
|
||||
// Some fields can have more then one columns in the data table so
|
||||
// column names are needed.
|
||||
foreach ($data_fields as $data_field) {
|
||||
// \Drupal\Core\Entity\Sql\TableMappingInterface:: getColumNames()
|
||||
// returns an array keyed by property names so remove the keys
|
||||
// before array_merge() to avoid losing data with fields having the
|
||||
// same columns i.e. value.
|
||||
$column_names = array_merge($column_names, array_values($table_mapping->getColumnNames($data_field)));
|
||||
}
|
||||
$query->fields('data', $column_names);
|
||||
}
|
||||
|
||||
// Get the revision IDs.
|
||||
|
@ -534,7 +548,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
|
|||
$query->condition('revision.' . $this->revisionKey, $revision_ids, 'IN');
|
||||
}
|
||||
else {
|
||||
$fields = $table_mapping->getFieldNames($this->dataTable);
|
||||
$all_fields = $table_mapping->getFieldNames($this->dataTable);
|
||||
}
|
||||
|
||||
$result = $query->execute();
|
||||
|
@ -547,7 +561,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
|
|||
|
||||
$translations[$id][$langcode] = TRUE;
|
||||
|
||||
foreach ($fields as $field_name) {
|
||||
foreach ($all_fields as $field_name) {
|
||||
$columns = $table_mapping->getColumnNames($field_name);
|
||||
// Do not key single-column fields by property name.
|
||||
if (count($columns) == 1) {
|
||||
|
|
|
@ -45,7 +45,11 @@ interface TableMappingInterface {
|
|||
public function getAllColumns($table_name);
|
||||
|
||||
/**
|
||||
* Gets a list of names of fields stored in the specified table.
|
||||
* Gets a list of names for entity fields stored in the specified table.
|
||||
*
|
||||
* The return list is contains the entity field names, not database field
|
||||
* (i.e. column) names. To get the mapping of specific entity field to
|
||||
* database columns use ::getColumnNames().
|
||||
*
|
||||
* @param string $table_name
|
||||
* The name of the table to return the field names for.
|
||||
|
|
|
@ -717,7 +717,7 @@ function hook_entity_view_mode_info_alter(&$view_modes) {
|
|||
* - translatable: (optional) A boolean value specifying whether this bundle
|
||||
* has translation support enabled. Defaults to FALSE.
|
||||
*
|
||||
* @see entity_get_bundles()
|
||||
* @see \Drupal\Core\Entity\EntityTypeBundleInfo::getBundleInfo()
|
||||
* @see hook_entity_bundle_info_alter()
|
||||
*/
|
||||
function hook_entity_bundle_info() {
|
||||
|
@ -731,7 +731,7 @@ function hook_entity_bundle_info() {
|
|||
* @param array $bundles
|
||||
* An array of bundles, keyed first by entity type, then by bundle name.
|
||||
*
|
||||
* @see entity_get_bundles()
|
||||
* @see Drupal\Core\Entity\EntityTypeBundleInfo::getBundleInfo()
|
||||
* @see hook_entity_bundle_info()
|
||||
*/
|
||||
function hook_entity_bundle_info_alter(&$bundles) {
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Core\EventSubscriber;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Subscribes to filter RSS responses, to make relative URIs absolute.
|
||||
*/
|
||||
class RssResponseRelativeUrlFilter implements EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* Converts relative URLs to absolute URLs.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
|
||||
* The response event.
|
||||
*/
|
||||
public function onResponse(FilterResponseEvent $event) {
|
||||
// Only care about RSS responses.
|
||||
if (stripos($event->getResponse()->headers->get('Content-Type'), 'application/rss+xml') === FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$response = $event->getResponse();
|
||||
$response->setContent($this->transformRootRelativeUrlsToAbsolute($response->getContent(), $event->getRequest()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all root-relative URLs to absolute URLs in RSS markup.
|
||||
*
|
||||
* Does not change any existing protocol-relative or absolute URLs.
|
||||
*
|
||||
* @param string $rss_markup
|
||||
* The RSS markup to update.
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
*
|
||||
* @return string
|
||||
* The updated RSS markup.
|
||||
*/
|
||||
protected function transformRootRelativeUrlsToAbsolute($rss_markup, Request $request) {
|
||||
$rss_dom = new \DOMDocument();
|
||||
$rss_dom->loadXML($rss_markup);
|
||||
|
||||
// Invoke Html::transformRootRelativeUrlsToAbsolute() on all HTML content
|
||||
// embedded in this RSS feed.
|
||||
foreach ($rss_dom->getElementsByTagName('description') as $node) {
|
||||
$html_markup = $node->nodeValue;
|
||||
if (!empty($html_markup)) {
|
||||
$node->nodeValue = Html::transformRootRelativeUrlsToAbsolute($html_markup, $request->getSchemeAndHttpHost());
|
||||
}
|
||||
}
|
||||
|
||||
return $rss_dom->saveXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
// Should run after any other response subscriber that modifies the markup.
|
||||
// @see \Drupal\Core\EventSubscriber\ActiveLinkResponseFilter
|
||||
$events[KernelEvents::RESPONSE][] = ['onResponse', -512];
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
}
|
|
@ -175,7 +175,7 @@ function hook_module_preinstall($module) {
|
|||
* This function differs from hook_install() in that it gives all other modules
|
||||
* a chance to perform actions when a module is installed, whereas
|
||||
* hook_install() is only called on the module actually being installed. See
|
||||
* \Drupal\Core\Extension\ModuleHandler::install() for a detailed description of
|
||||
* \Drupal\Core\Extension\ModuleInstaller::install() for a detailed description of
|
||||
* the order in which install hooks are invoked.
|
||||
*
|
||||
* This hook should be implemented in a .module file, not in an .install file.
|
||||
|
@ -183,7 +183,7 @@ function hook_module_preinstall($module) {
|
|||
* @param $modules
|
||||
* An array of the modules that were installed.
|
||||
*
|
||||
* @see \Drupal\Core\Extension\ModuleHandler::install()
|
||||
* @see \Drupal\Core\Extension\ModuleInstaller::install()
|
||||
* @see hook_install()
|
||||
*/
|
||||
function hook_modules_installed($modules) {
|
||||
|
@ -223,7 +223,7 @@ function hook_modules_installed($modules) {
|
|||
* be removed during uninstall should be removed with hook_uninstall().
|
||||
*
|
||||
* @see hook_schema()
|
||||
* @see \Drupal\Core\Extension\ModuleHandler::install()
|
||||
* @see \Drupal\Core\Extension\ModuleInstaller::install()
|
||||
* @see hook_uninstall()
|
||||
* @see hook_modules_installed()
|
||||
*/
|
||||
|
|
|
@ -236,13 +236,15 @@ interface FieldStorageDefinitionInterface extends CacheableDependencyInterface {
|
|||
*
|
||||
* @return array[]
|
||||
* The field schema, as an array of key/value pairs in the format returned
|
||||
* by hook_field_schema():
|
||||
* by \Drupal\Core\Field\FieldItemInterface::schema():
|
||||
* - columns: An array of Schema API column specifications, keyed by column
|
||||
* name. This specifies what comprises a single value for a given field.
|
||||
* No assumptions should be made on how storage backends internally use
|
||||
* the original column name to structure their storage.
|
||||
* - indexes: An array of Schema API index definitions. Some storage
|
||||
* backends might not support indexes.
|
||||
* - unique keys: An array of Schema API unique key definitions. Some
|
||||
* storage backends might not support unique keys.
|
||||
* - foreign keys: An array of Schema API foreign key definitions. Note,
|
||||
* however, that depending on the storage backend specified for the field,
|
||||
* the field data is not necessarily stored in SQL.
|
||||
|
|
|
@ -160,48 +160,42 @@ class EntityReferenceEntityFormatter extends EntityReferenceFormatterBase implem
|
|||
$elements = array();
|
||||
|
||||
foreach ($this->getEntitiesToView($items, $langcode) as $delta => $entity) {
|
||||
if ($entity->id()) {
|
||||
// Due to render caching and delayed calls, the viewElements() method
|
||||
// will be called later in the rendering process through a '#pre_render'
|
||||
// callback, so we need to generate a counter that takes into account
|
||||
// all the relevant information about this field and the referenced
|
||||
// entity that is being rendered.
|
||||
$recursive_render_id = $items->getFieldDefinition()->getTargetEntityTypeId()
|
||||
. $items->getFieldDefinition()->getTargetBundle()
|
||||
. $items->getName()
|
||||
. $entity->id();
|
||||
// Due to render caching and delayed calls, the viewElements() method
|
||||
// will be called later in the rendering process through a '#pre_render'
|
||||
// callback, so we need to generate a counter that takes into account
|
||||
// all the relevant information about this field and the referenced
|
||||
// entity that is being rendered.
|
||||
$recursive_render_id = $items->getFieldDefinition()->getTargetEntityTypeId()
|
||||
. $items->getFieldDefinition()->getTargetBundle()
|
||||
. $items->getName()
|
||||
. $entity->id();
|
||||
|
||||
if (isset(static::$recursiveRenderDepth[$recursive_render_id])) {
|
||||
static::$recursiveRenderDepth[$recursive_render_id]++;
|
||||
}
|
||||
else {
|
||||
static::$recursiveRenderDepth[$recursive_render_id] = 1;
|
||||
}
|
||||
|
||||
// Protect ourselves from recursive rendering.
|
||||
if (static::$recursiveRenderDepth[$recursive_render_id] > static::RECURSIVE_RENDER_LIMIT) {
|
||||
$this->loggerFactory->get('entity')->error('Recursive rendering detected when rendering entity %entity_type: %entity_id, using the %field_name field on the %bundle_name bundle. Aborting rendering.', [
|
||||
'%entity_type' => $entity->getEntityTypeId(),
|
||||
'%entity_id' => $entity->id(),
|
||||
'%field_name' => $items->getName(),
|
||||
'%bundle_name' => $items->getFieldDefinition()->getTargetBundle(),
|
||||
]);
|
||||
return $elements;
|
||||
}
|
||||
|
||||
$view_builder = $this->entityTypeManager->getViewBuilder($entity->getEntityTypeId());
|
||||
$elements[$delta] = $view_builder->view($entity, $view_mode, $entity->language()->getId());
|
||||
|
||||
// Add a resource attribute to set the mapping property's value to the
|
||||
// entity's url. Since we don't know what the markup of the entity will
|
||||
// be, we shouldn't rely on it for structured data such as RDFa.
|
||||
if (!empty($items[$delta]->_attributes)) {
|
||||
$items[$delta]->_attributes += array('resource' => $entity->url());
|
||||
}
|
||||
if (isset(static::$recursiveRenderDepth[$recursive_render_id])) {
|
||||
static::$recursiveRenderDepth[$recursive_render_id]++;
|
||||
}
|
||||
else {
|
||||
// This is an "auto_create" item.
|
||||
$elements[$delta] = array('#markup' => $entity->label());
|
||||
static::$recursiveRenderDepth[$recursive_render_id] = 1;
|
||||
}
|
||||
|
||||
// Protect ourselves from recursive rendering.
|
||||
if (static::$recursiveRenderDepth[$recursive_render_id] > static::RECURSIVE_RENDER_LIMIT) {
|
||||
$this->loggerFactory->get('entity')->error('Recursive rendering detected when rendering entity %entity_type: %entity_id, using the %field_name field on the %bundle_name bundle. Aborting rendering.', [
|
||||
'%entity_type' => $entity->getEntityTypeId(),
|
||||
'%entity_id' => $entity->id(),
|
||||
'%field_name' => $items->getName(),
|
||||
'%bundle_name' => $items->getFieldDefinition()->getTargetBundle(),
|
||||
]);
|
||||
return $elements;
|
||||
}
|
||||
|
||||
$view_builder = $this->entityTypeManager->getViewBuilder($entity->getEntityTypeId());
|
||||
$elements[$delta] = $view_builder->view($entity, $view_mode, $entity->language()->getId());
|
||||
|
||||
// Add a resource attribute to set the mapping property's value to the
|
||||
// entity's url. Since we don't know what the markup of the entity will
|
||||
// be, we shouldn't rely on it for structured data such as RDFa.
|
||||
if (!empty($items[$delta]->_attributes) && !$entity->isNew() && $entity->hasLinkTemplate('canonical')) {
|
||||
$items[$delta]->_attributes += array('resource' => $entity->toUrl()->toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,8 +53,12 @@ class MimeTypeGuesser implements MimeTypeGuesserInterface {
|
|||
*/
|
||||
public function guess($path) {
|
||||
if ($wrapper = $this->streamWrapperManager->getViaUri($path)) {
|
||||
// Get the real path from the stream wrapper.
|
||||
$path = $wrapper->realpath();
|
||||
// Get the real path from the stream wrapper, if available. Files stored
|
||||
// in remote file systems will not have one.
|
||||
$real_path = $wrapper->realpath();
|
||||
if ($real_path !== FALSE) {
|
||||
$path = $real_path;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->sortedGuessers === NULL) {
|
||||
|
|
|
@ -73,7 +73,7 @@ class InstallerServiceProvider implements ServiceProviderInterface, ServiceModif
|
|||
// No service may persist when the early installer kernel is rebooted into
|
||||
// the production environment.
|
||||
// @todo The DrupalKernel reboot performed by drupal_install_system() is
|
||||
// actually not a "regular" reboot (like ModuleHandler::install()), so
|
||||
// actually not a "regular" reboot (like ModuleInstaller::install()), so
|
||||
// services are not actually persisted.
|
||||
foreach ($container->findTaggedServiceIds('persist') as $id => $tags) {
|
||||
$definition = $container->getDefinition($id);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\Core\ParamConverter;
|
||||
|
||||
use Drupal\Core\Entity\EntityRepositoryInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
|
@ -31,14 +32,24 @@ class EntityRevisionParamConverter implements ParamConverterInterface {
|
|||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The entity repository.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityRepositoryInterface
|
||||
*/
|
||||
protected $entityRepository;
|
||||
|
||||
/**
|
||||
* Creates a new EntityRevisionParamConverter instance.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
|
||||
* The entity repository.
|
||||
*/
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityRepositoryInterface $entity_repository) {
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->entityRepository = $entity_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,8 +57,8 @@ class EntityRevisionParamConverter implements ParamConverterInterface {
|
|||
*/
|
||||
public function convert($value, $definition, $name, array $defaults) {
|
||||
list (, $entity_type_id) = explode(':', $definition['type'], 2);
|
||||
$entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
|
||||
return $entity_storage->loadRevision($value);
|
||||
$entity = $this->entityTypeManager->getStorage($entity_type_id)->loadRevision($value);
|
||||
return $this->entityRepository->getTranslationFromContext($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,7 +25,7 @@ interface AttachmentsResponseProcessorInterface {
|
|||
* $build['#attached']['library'][] = [
|
||||
* 'library' => ['core/jquery']
|
||||
* ];
|
||||
* $build['#attached']['http_header'][] = [
|
||||
* $build['#attached']['http_header'] = [
|
||||
* ['Content-Type', 'application/rss+xml; charset=utf-8'],
|
||||
* ];
|
||||
* @endcode
|
||||
|
|
|
@ -636,8 +636,33 @@ class Renderer implements RendererInterface {
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
foreach (array_keys($elements['#attached']['placeholders']) as $placeholder) {
|
||||
$elements = $this->renderPlaceholder($placeholder, $elements);
|
||||
// The 'status messages' placeholder needs to be special cased, because it
|
||||
// depends on global state that can be modified when other placeholders are
|
||||
// being rendered: any code can add messages to render.
|
||||
// This violates the principle that each lazy builder must be able to render
|
||||
// itself in isolation, and therefore in any order. However, we cannot
|
||||
// change the way drupal_set_message() works in the Drupal 8 cycle. So we
|
||||
// have to accommodate its special needs.
|
||||
// Allowing placeholders to be rendered in a particular order (in this case:
|
||||
// last) would violate this isolation principle. Thus a monopoly is granted
|
||||
// to this one special case, with this hard-coded solution.
|
||||
// @see \Drupal\Core\Render\Element\StatusMessages
|
||||
// @see https://www.drupal.org/node/2712935#comment-11368923
|
||||
|
||||
// First render all placeholders except 'status messages' placeholders.
|
||||
$message_placeholders = [];
|
||||
foreach ($elements['#attached']['placeholders'] as $placeholder => $placeholder_element) {
|
||||
if (isset($placeholder_element['#lazy_builder']) && $placeholder_element['#lazy_builder'][0] === 'Drupal\Core\Render\Element\StatusMessages::renderMessages') {
|
||||
$message_placeholders[] = $placeholder;
|
||||
}
|
||||
else {
|
||||
$elements = $this->renderPlaceholder($placeholder, $elements);
|
||||
}
|
||||
}
|
||||
|
||||
// Then render 'status messages' placeholders.
|
||||
foreach ($message_placeholders as $message_placeholder) {
|
||||
$elements = $this->renderPlaceholder($message_placeholder, $elements);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
|
|
@ -788,17 +788,17 @@ function hook_render_template($template_file, $variables) {
|
|||
* A module may implement this hook in order to alter the element type defaults
|
||||
* defined by a module.
|
||||
*
|
||||
* @param array $types
|
||||
* @param array $info
|
||||
* An associative array with structure identical to that of the return value
|
||||
* of \Drupal\Core\Render\ElementInfoManagerInterface::getInfo().
|
||||
*
|
||||
* @see \Drupal\Core\Render\ElementInfoManager
|
||||
* @see \Drupal\Core\Render\Element\ElementInterface
|
||||
*/
|
||||
function hook_element_info_alter(array &$types) {
|
||||
function hook_element_info_alter(array &$info) {
|
||||
// Decrease the default size of textfields.
|
||||
if (isset($types['textfield']['#size'])) {
|
||||
$types['textfield']['#size'] = 40;
|
||||
if (isset($info['textfield']['#size'])) {
|
||||
$info['textfield']['#size'] = 40;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,13 @@ namespace Drupal\Core\StreamWrapper;
|
|||
*/
|
||||
abstract class LocalReadOnlyStream extends LocalStream {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getType() {
|
||||
return StreamWrapperInterface::READ_VISIBLE | StreamWrapperInterface::LOCAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for fopen(), file_get_contents(), etc.
|
||||
*
|
||||
|
|
Reference in a new issue