Update to Drupal 8.2.2. For more information, see https://www.drupal.org/project/drupal/releases/8.2.2

This commit is contained in:
Pantheon Automation 2016-11-02 11:43:31 -07:00 committed by Greg Anderson
parent 23ffed3665
commit 507b45a0ed
378 changed files with 11434 additions and 5542 deletions

View file

@ -81,7 +81,7 @@ class Drupal {
/**
* The current system version.
*/
const VERSION = '8.2.1';
const VERSION = '8.2.2';
/**
* Core API compatibility.

View file

@ -288,7 +288,6 @@ class Random {
// Make a perfect circle in the image middle.
$color = imagecolorallocate($im, rand(0, 255), rand(0, 255), rand(0, 255));
$smaller_dimension = min($width, $height);
$smaller_dimension = ($smaller_dimension % 2) ? $smaller_dimension : $smaller_dimension;
imageellipse($im, $width / 2, $height / 2, $smaller_dimension, $smaller_dimension, $color);
$save_function = 'image' . ($extension == 'jpg' ? 'jpeg' : $extension);

View file

@ -97,12 +97,15 @@ class CsrfRequestHeaderAccessCheck implements AccessCheckInterface {
&& $account->isAuthenticated()
&& $this->sessionConfiguration->hasSession($request)
) {
if (!$request->headers->has('X-CSRF-Token')) {
return AccessResult::forbidden()->setReason('X-CSRF-Token request header is missing')->setCacheMaxAge(0);
}
$csrf_token = $request->headers->get('X-CSRF-Token');
// @todo Remove validate call using 'rest' in 8.3.
// Kept here for sessions active during update.
if (!$this->csrfToken->validate($csrf_token, self::TOKEN_KEY)
&& !$this->csrfToken->validate($csrf_token, 'rest')) {
return AccessResult::forbidden()->setReason('X-CSRF-Token request header is missing')->setCacheMaxAge(0);
return AccessResult::forbidden()->setReason('X-CSRF-Token request header is invalid')->setCacheMaxAge(0);
}
}
// Let other access checkers decide if the request is legit.

View file

@ -2,6 +2,8 @@
namespace Drupal\Core\Ajax;
use Drupal\Component\Render\PlainTextOutput;
/**
* Defines an AJAX command to open certain content in a dialog.
*
@ -69,6 +71,7 @@ class OpenDialogCommand implements CommandInterface, CommandWithAttachedAssetsIn
* populated automatically from the current request.
*/
public function __construct($selector, $title, $content, array $dialog_options = array(), $settings = NULL) {
$title = PlainTextOutput::renderFromHtml($title);
$dialog_options += array('title' => $title);
$this->selector = $selector;
$this->content = $content;

View file

@ -214,7 +214,7 @@ class AssetResolver implements AssetResolverInterface {
// hook_library_info_alter(). Additionally add the current language to
// support translation of JavaScript files via hook_js_alter().
$libraries_to_load = $this->getLibrariesToLoad($assets);
$cid = 'js:' . $theme_info->getName() . ':' . $this->languageManager->getCurrentLanguage()->getId() . ':' . Crypt::hashBase64(serialize($libraries_to_load) . serialize($assets->getLibraries())) . (int) (count($assets->getSettings()) > 0) . (int) $optimize;
$cid = 'js:' . $theme_info->getName() . ':' . $this->languageManager->getCurrentLanguage()->getId() . ':' . Crypt::hashBase64(serialize($libraries_to_load)) . (int) (count($assets->getSettings()) > 0) . (int) $optimize;
if ($cached = $this->cache->get($cid)) {
list($js_assets_header, $js_assets_footer, $settings, $settings_in_header) = $cached->data;

View file

@ -2,6 +2,8 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Component\Utility\Crypt;
/**
* Defines the SessionCacheContext service, for "per session" caching.
*
@ -20,7 +22,8 @@ class SessionCacheContext extends RequestStackCacheContextBase {
* {@inheritdoc}
*/
public function getContext() {
return $this->requestStack->getCurrentRequest()->getSession()->getId();
$sid = $this->requestStack->getCurrentRequest()->getSession()->getId();
return Crypt::hashBase64($sid);
}
}

View file

@ -120,7 +120,7 @@ class Schema extends DatabaseSchema {
// By default, MySQL uses the default collation for new tables, which is
// 'utf8mb4_general_ci' for utf8mb4. If an alternate collation has been
// set, it needs to be explicitly specified.
// @see DatabaseConnection_mysql
// @see \Drupal\Core\Database\Driver\mysql\Schema
if (!empty($info['collation'])) {
$sql .= ' COLLATE ' . $info['collation'];
}

View file

@ -20,8 +20,8 @@ class Schema extends DatabaseSchema {
/**
* A cache of information about blob columns and sequences of tables.
*
* This is collected by DatabaseConnection_pgsql->queryTableInformation(),
* by introspecting the database.
* This is collected by Schema::queryTableInformation(), by introspecting the
* database.
*
* @see \Drupal\Core\Database\Driver\pgsql\Schema::queryTableInformation()
* @var array

View file

@ -306,7 +306,7 @@ class StatementPrefetch implements \Iterator, StatementInterface {
return $this->fetchOptions['object'];
case \PDO::FETCH_COLUMN:
if (isset($this->columnNames[$this->fetchOptions['column']])) {
return $this->currentRow[$k][$this->columnNames[$this->fetchOptions['column']]];
return $this->currentRow[$this->columnNames[$this->fetchOptions['column']]];
}
else {
return;

View file

@ -301,7 +301,7 @@ class EntityController implements ContainerInjectionInterface {
* @param array $bundles
* An array of bundle information.
* @param \Drupal\Core\Entity\EntityTypeInterface $bundle_entity_type
* The ID of the bundle entity type.
* The bundle entity type definition.
*
* @return array
* The expanded array of bundle information.

View file

@ -236,7 +236,7 @@ class EntityFormDisplay extends EntityDisplayBase implements EntityFormDisplayIn
// Flag entity level violations.
foreach ($violations->getEntityViolations() as $violation) {
/** @var \Symfony\Component\Validator\ConstraintViolationInterface $violation */
$form_state->setErrorByName('', $violation->getMessage());
$form_state->setError($form, $violation->getMessage());
}
$this->flagWidgetsErrorsFromViolations($violations, $form, $form_state);

View file

@ -166,7 +166,10 @@ class EntityResolverManager {
list($entity_type) = explode('.', $entity_form, 2);
}
if (isset($entity_type) && isset($this->getEntityTypes()[$entity_type])) {
// Do not add parameter information if the route does not declare a
// parameter in the first place. This is the case for add forms, for
// example.
if (isset($entity_type) && isset($this->getEntityTypes()[$entity_type]) && (strpos($route->getPath(), '{' . $entity_type . '}') !== FALSE)) {
$parameter_definitions = $route->getOption('parameters') ?: array();
// First try to figure out whether there is already a parameter upcasting

View file

@ -358,11 +358,18 @@ use Drupal\node\Entity\NodeType;
* \Drupal\Core\Entity\EntityType.
*
* @section sec_routes Entity routes
* Entity routes, like other routes, are defined in *.routing.yml files; see
* the @link routing Routing API @endlink topic for more information. Entities
* may alternatively use an auto route provider class; there is an example of
* this at the end of this section. If providing routes directly, here is a
* typical entry, for the block configure form:
* Entity routes can be defined in *.routing.yml files, like any other route:
* see the @link routing Routing API @endlink topic for more information.
* Another option for entity routes is to use a route provider class, and
* reference it in the annotations on the entity class: see the end of this
* section for an example.
*
* It's possible to use both a YAML file and a provider class for entity
* routes, at the same time. Avoid duplicating route names between the two:
* if a duplicate route name is found in both locations, the one in the YAML
* file takes precedence; regardless, such duplication can be confusing.
*
* Here's an example YAML route specification, for the block configure form:
* @code
* entity.block.edit_form:
* path: '/admin/structure/block/manage/{block}'
@ -372,7 +379,7 @@ use Drupal\node\Entity\NodeType;
* requirements:
* _entity_access: 'block.update'
* @endcode
* Some notes:
* Some notes on this example:
* - path: The {block} in the path is a placeholder, which (for an entity) must
* always take the form of {machine_name_of_entity_type}. In the URL, the
* placeholder value will be the ID of an entity item. When the route is used,
@ -389,19 +396,21 @@ use Drupal\node\Entity\NodeType;
* "form" = {
* "default" = "Drupal\block\BlockForm",
* @endcode
* - Instead of putting the routes for your entity in a *.routing.yml file, you
* can instead use a route provider class.
* \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider provides canonical,
* edit-form, and delete-form routes;
* \Drupal\Core\Entity\Routing\AdminHtmlRouteProvider provides the same
* If instead of YAML you want to use a route provider class:
* - \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider provides canonical,
* edit-form, and delete-form routes.
* - \Drupal\Core\Entity\Routing\AdminHtmlRouteProvider provides the same
* routes, set up to use the administrative theme for edit and delete pages.
* You can also create your own class. To use a route provider class, add
* lines like the following to your entity annotation:
* @code
* handlers = {
* "route_provider" = {
* "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
* @endcode
* - You can also create your own class, extending one of these two classes if
* you only want to modify their behaviour slightly.
*
* To register any route provider class, add lines like the following to your
* entity class annotation:
* @code
* handlers = {
* "route_provider" = {
* "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
* @endcode
*
* @section bundle Defining a content entity bundle
* For entity types that use bundles, such as Node (bundles are content types)

View file

@ -20,7 +20,7 @@ class PathRootsSubscriber implements EventSubscriberInterface {
*
* @var array
*/
protected $pathRoots;
protected $pathRoots = [];
/**
* The state key value store.
@ -58,7 +58,7 @@ class PathRootsSubscriber implements EventSubscriberInterface {
*/
public function onRouteFinished() {
$this->state->set('router.path_roots', array_keys($this->pathRoots));
unset($this->pathRoots);
$this->pathRoots = [];
}
/**

View file

@ -22,6 +22,8 @@ use Drupal\Core\TypedData\ListInterface;
*
* When implementing this interface which extends Traversable, make sure to list
* IteratorAggregate or Iterator before this interface in the implements clause.
*
* @see \Drupal\Core\Field\FieldItemInterface
*/
interface FieldItemListInterface extends ListInterface, AccessibleInterface {

View file

@ -268,7 +268,26 @@ class EntityReferenceItem extends FieldItemBase implements OptionsProviderInterf
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$manager = \Drupal::service('plugin.manager.entity_reference_selection');
if ($referenceable = $manager->getSelectionHandler($field_definition)->getReferenceableEntities()) {
// Instead of calling $manager->getSelectionHandler($field_definition)
// replicate the behavior to be able to override the sorting settings.
$options = array(
'target_type' => $field_definition->getFieldStorageDefinition()->getSetting('target_type'),
'handler' => $field_definition->getSetting('handler'),
'handler_settings' => $field_definition->getSetting('handler_settings') ?: array(),
'entity' => NULL,
);
$entity_type = \Drupal::entityManager()->getDefinition($options['target_type']);
$options['handler_settings']['sort'] = [
'field' => $entity_type->getKey('id'),
'direction' => 'DESC',
];
$selection_handler = $manager->getInstance($options);
// Select a random number of references between the last 50 referenceable
// entities created.
if ($referenceable = $selection_handler->getReferenceableEntities(NULL, 'CONTAINS', 50)) {
$group = array_rand($referenceable);
$values['target_id'] = array_rand($referenceable[$group]);
return $values;

View file

@ -87,11 +87,14 @@ class EntityReferenceAutocompleteWidget extends WidgetBase {
$entity = $items->getEntity();
$referenced_entities = $items->referencedEntities();
// Append the match operation to the selection settings.
$selection_settings = $this->getFieldSetting('handler_settings') + ['match_operator' => $this->getSetting('match_operator')];
$element += array(
'#type' => 'entity_autocomplete',
'#target_type' => $this->getFieldSetting('target_type'),
'#selection_handler' => $this->getFieldSetting('handler'),
'#selection_settings' => $this->getFieldSetting('handler_settings'),
'#selection_settings' => $selection_settings,
// Entity reference field items are handling validation themselves via
// the 'ValidReference' constraint.
'#validate_reference' => FALSE,

View file

@ -181,8 +181,10 @@ class FileSystem implements FileSystemInterface {
// If recursive, create each missing component of the parent directory
// individually and set the mode explicitly to override the umask.
if ($recursive) {
// Ensure the path is using DIRECTORY_SEPARATOR.
$uri = str_replace('/', DIRECTORY_SEPARATOR, $uri);
// Ensure the path is using DIRECTORY_SEPARATOR, and trim off any trailing
// slashes because they can throw off the loop when creating the parent
// directories.
$uri = rtrim(str_replace('/', DIRECTORY_SEPARATOR, $uri), DIRECTORY_SEPARATOR);
// Determine the components of the path.
$components = explode(DIRECTORY_SEPARATOR, $uri);
// If the filepath is absolute the first component will be empty as there

View file

@ -152,7 +152,7 @@ class ExtensionMimeTypeGuesser implements MimeTypeGuesserInterface {
129 => 'application/x-iphone',
130 => 'application/x-iso9660-image',
131 => 'application/x-java-jnlp-file',
132 => 'application/x-javascript',
132 => 'application/javascript',
133 => 'application/x-jmol',
134 => 'application/x-kchart',
135 => 'application/x-killustrator',

View file

@ -316,7 +316,7 @@ class FormBuilder implements FormBuilderInterface, FormValidatorInterface, FormS
// In case the post request exceeds the configured allowed size
// (post_max_size), the post request is potentially broken. Add some
// protection against that and at the same time have a nice error message.
if ($ajax_form_request && !isset($form_state->getUserInput()['form_id'])) {
if ($ajax_form_request && !$request->request->has('form_id')) {
throw new BrokenPostRequestException($this->getFileUploadMaxSize());
}
@ -327,7 +327,9 @@ class FormBuilder implements FormBuilderInterface, FormValidatorInterface, FormS
// then passed through
// \Drupal\Core\Form\FormAjaxResponseBuilderInterface::buildResponse() to
// build a proper AJAX response.
if ($ajax_form_request && $form_state->isProcessingInput()) {
// Only do this when the form ID matches, since there is no guarantee from
// $ajax_form_request that it's an AJAX request for this particular form.
if ($ajax_form_request && $form_state->isProcessingInput() && $request->request->get('form_id') == $form_id) {
throw new FormAjaxException($form, $form_state);
}

View file

@ -92,7 +92,7 @@ class Link extends RenderElement {
/** @var \Drupal\Core\Utility\LinkGenerator $link_generator */
$link_generator = \Drupal::service('link_generator');
$generated_link = $link_generator->generate($element['#title'], $element['#url']->setOptions($options));
$element['#markup'] = $generated_link->getGeneratedLink();
$element['#markup'] = $generated_link;
$generated_link->merge(BubbleableMetadata::createFromRenderArray($element))
->applyTo($element);
}

View file

@ -33,7 +33,8 @@ use Drupal\Component\Utility\Html as HtmlUtility;
* '#header' => array($this->t('Name'), $this->t('Phone')),
* );
*
* for ($i=1; $i<=4; $i++) {
* for ($i = 1; $i <= 4; $i++) {
* $form['contacts'][$i]['#attributes'] = array('class' => array('foo', 'baz'));
* $form['contacts'][$i]['name'] = array(
* '#type' => 'textfield',
* '#title' => $this->t('Name'),
@ -46,6 +47,11 @@ use Drupal\Component\Utility\Html as HtmlUtility;
* '#title_display' => 'invisible',
* );
* }
*
* $form['contacts'][]['colspan_example'] = array(
* '#plain_text' => 'Colspan Example',
* '#wrapper_attributes' => array('colspan' => 2, 'class' => array('foo', 'bar')),
* );
* @endcode
* @see \Drupal\Core\Render\Element\Tableselect
*

View file

@ -42,7 +42,12 @@ class ContentTypeHeaderMatcher implements RouteFilterInterface {
// We do not throw a
// \Symfony\Component\Routing\Exception\ResourceNotFoundException here
// because we don't want to return a 404 status code, but rather a 415.
throw new UnsupportedMediaTypeHttpException('No route found that matches "Content-Type: ' . $request->headers->get('Content-Type') . '"');
if (!$request->headers->has('Content-Type')) {
throw new UnsupportedMediaTypeHttpException('No "Content-Type" request header specified');
}
else {
throw new UnsupportedMediaTypeHttpException('No route found that matches "Content-Type: ' . $request->headers->get('Content-Type') . '"');
}
}
/**

View file

@ -257,7 +257,8 @@ class SessionManager extends NativeSessionStorage implements SessionManagerInter
// Unset the session cookies.
$session_name = $this->getName();
$cookies = $this->requestStack->getCurrentRequest()->cookies;
if ($cookies->has($session_name)) {
// setcookie() can only be called when headers are not yet sent.
if ($cookies->has($session_name) && !headers_sent()) {
$params = session_get_cookie_params();
setcookie($session_name, '', REQUEST_TIME - 3600, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
$cookies->remove($session_name);

View file

@ -8,6 +8,7 @@ use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Render\AttachmentsInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Render\Markup;
use Drupal\Core\Render\RenderableInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Routing\UrlGeneratorInterface;
@ -273,6 +274,11 @@ class TwigExtension extends \Twig_Extension {
}
$url->setOption('attributes', $attributes);
}
// The text has been processed by twig already, convert it to a safe object
// for the render system.
if ($text instanceof \Twig_Markup) {
$text = Markup::create($text);
}
$build = [
'#type' => 'link',
'#title' => $text,

View file

@ -0,0 +1,63 @@
<?php
namespace Drupal\Core\Test;
/**
* Consolidates test result status information.
*
* For our test runners, a $status of 0 = passed test, 1 = failed test,
* 2 = exception, >2 indicates segfault timeout, or other type of system
* failure.
*/
class TestStatus {
/**
* Signify that the test result was a passed test.
*/
const PASS = 0;
/**
* Signify that the test result was a failed test.
*/
const FAIL = 1;
/**
* Signify that the test result was an exception or code error.
*
* This means that the test runner was able to exit and report an error.
*/
const EXCEPTION = 2;
/**
* Signify a system error where the test runner was unable to complete.
*
* Note that SYSTEM actually represents the lowest value of system errors, and
* the returned value could be as high as 127. Since that's the case, this
* constant should be used for range comparisons, and not just for equality.
*
* @see http://php.net/manual/en/pcntl.constants.php
*/
const SYSTEM = 3;
/**
* Turns a status code into a human-readable string.
*
* @param int $status
* A test runner return code.
*
* @return string
* The human-readable version of the status code.
*/
public static function label($status) {
$statusMap = [
static::PASS => 'pass',
static::FAIL => 'fail',
static::EXCEPTION => 'exception',
static::SYSTEM => 'error',
];
// For status 3 and higher, we want 'error.'
$label = $statusMap[$status > static::SYSTEM ? static::SYSTEM : $status];
return $label;
}
}

View file

@ -31,7 +31,7 @@ interface LinkGeneratorInterface {
* This keeps the context of the link title ('settings' in the example) for
* translators.
*
* @param string|array $text
* @param string|array|\Drupal\Component\Render\MarkupInterface $text
* The link text for the anchor tag as a translated string or render array.
* Strings will be sanitized automatically. If you need to output HTML in
* the link text, use a render array or an already sanitized string such as