Skip to content
Commits on Source (126)
This diff is collapsed.
Drupal 8.2.8, 2017-04-19
------------------------
- Fixed security issues. See SA-CORE-2017-002.
Drupal 8.2.7, 2017-03-15
------------------------
- Fixed security issues. See SA-CORE-2017-001.
Drupal 8.2.3, 2016-11-16
------------------------
- Fixed security issues. See SA-CORE-2016-005.
......
......@@ -123,7 +123,6 @@ Color
- ?
Comment
- Dick Olsson 'dixon_' https://www.drupal.org/u/dixon_
- Lee Rowlands 'larowlan' https://www.drupal.org/u/larowlan
- Andrey Postnikov 'andypost' https://www.drupal.org/u/andypost
......
......@@ -40,7 +40,7 @@
"jcalderonzumba/gastonjs": "~1.0.2",
"jcalderonzumba/mink-phantomjs-driver": "~0.3.1",
"mikey179/vfsStream": "~1.2",
"phpunit/phpunit": "~4.8",
"phpunit/phpunit": ">=4.8.28 <5",
"symfony/css-selector": "~2.8"
},
"replace": {
......
......@@ -1073,8 +1073,9 @@
* yourmodule/tests/src/Unit directory, according to the PSR-4 standard.
* - Your test class needs a phpDoc comment block with a description and
* a @group annotation, which gives information about the test.
* - Methods in your test class whose names start with 'test' are the actual
* test cases. Each one should test a logical subset of the functionality.
* - Add test cases by adding method names that start with 'test' and have no
* arguments, for example testYourTestCase(). Each one should test a logical
* subset of the functionality.
* For more details, see:
* - https://www.drupal.org/phpunit for full documentation on how to write
* PHPUnit tests for Drupal.
......@@ -1110,9 +1111,9 @@
* set up content types and similar procedures.
* - In some cases, you may need to write a test module to support your test;
* put such modules under the yourmodule/tests/modules directory.
* - Methods in your test class whose names start with 'test', and which have
* no arguments, are the actual test cases. Each one should test a logical
* subset of the functionality, and each one runs in a new, isolated test
* - Add test cases by adding method names that start with 'test' and have no
* arguments, for example testYourTestCase(). Each one should test a logical
* subset of the functionality. Each method runs in a new, isolated test
* environment, so it can only rely on the setUp() method, not what has
* been set up by other test methods.
* For more details, see:
......@@ -1121,6 +1122,52 @@
* - @link oo_conventions Object-oriented programming topic @endlink for more
* on PSR-4, namespaces, and where to place classes.
*
* @section write_functional_phpunit Write functional PHP tests (phpunit)
* Functional tests extend the BrowserTestBase base class, and use PHPUnit as
* their underlying framework. They use a simulated browser, in which the test
* can click links, visit URLs, post to forms, etc. To write a functional test:
* - Extend \Drupal\Tests\BrowserTestBase.
* - Place the test in the yourmodule/tests/src/Functional/ directory and use
* the \Drupal\Tests\yourmodule\Functional namespace.
* - Add a @group annotation. For example, if the test is for a Drupal 6
* migration process, the group core uses is migrate_drupal_6. Use yourmodule
* as the group name if the test does not belong to another larger group.
* - You may also override the default setUp() method, which can be used to set
* up content types and similar procedures. Don't forget to call the parent
* method.
* - In some cases, you may need to write a test module to support your test;
* put such modules under the yourmodule/tests/modules directory.
* - Add test cases by adding method names that start with 'test' and have no
* arguments, for example testYourTestCase(). Each one should test a logical
* subset of the functionality. Each method runs in a new, isolated test
* environment, so it can only rely on the setUp() method, not what has
* been set up by other test methods.
* For more details, see:
* - https://www.drupal.org/docs/8/phpunit/phpunit-browser-test-tutorial for
* a full tutorial on how to write functional PHPUnit tests for Drupal.
* - https://www.drupal.org/phpunit for the full documentation on how to write
* PHPUnit tests for Drupal.
*
* @section write_jsfunctional_phpunit Write functional JavaScript tests (phpunit)
* To write a functional test that relies on JavaScript:
* - Extend \Drupal\FunctionalJavaScriptTests\JavascriptTestBase.
* - Place the test into the yourmodule/tests/src/FunctionalJavascript/
* directory and use the \Drupal\Tests\yourmodule\FunctionalJavascript
* namespace.
* - Add a @group annotation. Use yourmodule as the group name if the test does
* not belong to another larger group.
* - Set up PhantomJS; see http://phantomjs.org/download.html.
* - To run tests, see core/tests/README.md.
* - When clicking a link/button with Ajax behavior attached, keep in mind that
* the underlying browser might take time to deliver changes to the HTML. Use
* $this->assertSession()->assertWaitOnAjaxRequest() to wait for the Ajax
* request to finish.
* For more details, see:
* - https://www.drupal.org/docs/8/phpunit/phpunit-javascript-testing-tutorial
* for a full tutorial on how to write PHPUnit JavaScript tests for Drupal.
* - https://www.drupal.org/phpunit for the full documentation on how to write
* PHPUnit tests for Drupal.
*
* @section running Running tests
* You can run both Simpletest and PHPUnit tests by enabling the core Testing
* module (core/modules/simpletest). Once that module is enabled, tests can be
......
......@@ -20,6 +20,7 @@
use Drupal\Core\Site\Settings;
use Drupal\Core\StringTranslation\Translator\FileTranslation;
use Drupal\Core\StackMiddleware\ReverseProxyMiddleware;
use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Url;
......@@ -1036,6 +1037,21 @@ function install_base_system(&$install_state) {
// Install system.module.
drupal_install_system($install_state);
// Prevent the installer from using the system temporary directory after the
// system module has been installed.
if (drupal_valid_test_ua()) {
// While the temporary directory could be preset/enforced in settings.php
// like the public files directory, some tests expect it to be configurable
// in the UI. If declared in settings.php, they would no longer be
// configurable. The temporary directory needs to match what is set in each
// test types ::prepareEnvironment() step.
$temporary_directory = dirname(PublicStream::basePath()) . '/temp';
file_prepare_directory($temporary_directory, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY);
\Drupal::configFactory()->getEditable('system.file')
->set('path.temporary', $temporary_directory)
->save();
}
// Call file_ensure_htaccess() to ensure that all of Drupal's standard
// directories (e.g., the public files directory and config directory) have
// appropriate .htaccess files. These directories will have already been
......
......@@ -1044,10 +1044,11 @@ function drupal_check_module($module) {
*
* Example of .info.yml file:
* @code
* name = Minimal
* description = Start fresh, with only a few modules enabled.
* dependencies[] = block
* dependencies[] = dblog
* name: Minimal
* description: Start fresh, with only a few modules enabled.
* dependencies:
* - block
* - dblog
* @endcode
*
* @param $profile
......
......@@ -74,7 +74,7 @@ function drupal_get_schema_versions($module) {
* module is not installed.
*/
function drupal_get_installed_schema_version($module, $reset = FALSE, $array = FALSE) {
static $versions = array();
$versions = &drupal_static(__FUNCTION__, array());
if ($reset) {
$versions = array();
......
......@@ -81,7 +81,7 @@ class Drupal {
/**
* The current system version.
*/
const VERSION = '8.2.4-dev';
const VERSION = '8.2.8-dev';
/**
* Core API compatibility.
......@@ -556,8 +556,7 @@ public static function linkGenerator() {
* Renders a link with a given link text and Url object.
*
* This method is a convenience wrapper for the link generator service's
* generate() method. For detailed documentation, see
* \Drupal\Core\Routing\LinkGeneratorInterface::generate().
* generate() method.
*
* @param string $text
* The link text for the anchor tag.
......
......@@ -147,7 +147,7 @@ public function jsonSerialize() {
* A call like:
* @code
* $string = "%output_text";
* $arguments = ['output_text' => 'text output here.'];
* $arguments = ['%output_text' => 'text output here.'];
* $this->placeholderFormat($string, $arguments);
* @endcode
* makes the following HTML code:
......
......@@ -297,7 +297,7 @@ public function getConfigEntitiesToChangeOnDependencyRemoval($type, array $names
$dependency_manager = $this->getConfigDependencyManager();
$dependents = $this->findConfigEntityDependentsAsEntities($type, $names, $dependency_manager);
$original_dependencies = $dependents;
$delete_uuids = $update_uuids = [];
$delete_uuids = [];
$return = [
'update' => [],
......@@ -305,6 +305,13 @@ public function getConfigEntitiesToChangeOnDependencyRemoval($type, array $names
'unchanged' => [],
];
// Create a map of UUIDs to $original_dependencies key so that we can remove
// fixed dependencies.
$uuid_map = [];
foreach ($original_dependencies as $key => $entity) {
$uuid_map[$entity->uuid()] = $key;
}
// Try to fix any dependencies and find out what will happen to the
// dependency graph. Entities are processed in the order of most dependent
// first. For example, this ensures that Menu UI third party dependencies on
......@@ -340,8 +347,9 @@ public function getConfigEntitiesToChangeOnDependencyRemoval($type, array $names
}
}
if ($fixed) {
// Remove the fixed dependency from the list of original dependencies.
unset($original_dependencies[$uuid_map[$dependent->uuid()]]);
$return['update'][] = $dependent;
$update_uuids[] = $dependent->uuid();
}
}
// If the entity cannot be fixed then it has to be deleted.
......@@ -354,8 +362,8 @@ public function getConfigEntitiesToChangeOnDependencyRemoval($type, array $names
}
// Use the lists of UUIDs to filter the original list to work out which
// configuration entities are unchanged.
$return['unchanged'] = array_filter($original_dependencies, function ($dependent) use ($delete_uuids, $update_uuids) {
return !(in_array($dependent->uuid(), $delete_uuids) || in_array($dependent->uuid(), $update_uuids));
$return['unchanged'] = array_filter($original_dependencies, function ($dependent) use ($delete_uuids) {
return !(in_array($dependent->uuid(), $delete_uuids));
});
return $return;
......
......@@ -34,6 +34,11 @@ abstract class DraggableListBuilder extends ConfigEntityListBuilder implements F
*/
protected $weightKey = FALSE;
/**
* {@inheritdoc}
*/
protected $limit = FALSE;
/**
* The form builder.
*
......
......@@ -1031,8 +1031,17 @@ protected function initializeSettings(Request $request) {
$prefix = Settings::getApcuPrefix('class_loader', $this->root);
$apc_loader = new ApcClassLoader($prefix, $this->classLoader);
$this->classLoader->unregister();
$apc_loader->register();
// The optimized classloader might be persistent and store cache misses.
// For example, once a cache miss is stored in APCu clearing it on a
// specific web-head will not clear any other web-heads. Therefore
// fallback to the composer class loader that only statically caches
// misses.
$old_loader = $this->classLoader;
$this->classLoader = $apc_loader;
// Our class loaders are preprended to ensure they come first like the
// class loader they are replacing.
$old_loader->register(TRUE);
$apc_loader->register(TRUE);
}
}
......
......@@ -348,13 +348,10 @@ public static function getEntityLabels(array $entities) {
public static function extractEntityIdFromAutocompleteInput($input) {
$match = NULL;
// Take "label (entity id)', match the ID from parenthesis when it's a
// number.
if (preg_match("/.+\s\((\d+)\)/", $input, $matches)) {
$match = $matches[1];
}
// Match the ID when it's a string (e.g. for config entity types).
elseif (preg_match("/.+\s\(([\w.]+)\)/", $input, $matches)) {
// Take "label (entity id)', match the ID from inside the parentheses.
// @todo Add support for entities containing parentheses in their ID.
// @see https://www.drupal.org/node/2520416
if (preg_match("/.+\s\(([^\)]+)\)/", $input, $matches)) {
$match = $matches[1];
}
......
......@@ -303,6 +303,19 @@ public function fieldAccess($operation, FieldDefinitionInterface $field_definiti
// Get the default access restriction that lives within this field.
$default = $items ? $items->defaultAccess($operation, $account) : AccessResult::allowed();
// Explicitly disallow changing the entity ID and entity UUID.
if ($operation === 'edit') {
if ($field_definition->getName() === $this->entityType->getKey('id')) {
return $return_as_object ? AccessResult::forbidden('The entity ID cannot be changed') : FALSE;
}
elseif ($field_definition->getName() === $this->entityType->getKey('uuid')) {
// UUIDs can be set when creating an entity.
if ($items && ($entity = $items->getEntity()) && !$entity->isNew()) {
return $return_as_object ? AccessResult::forbidden('The entity UUID cannot be changed')->addCacheableDependency($entity) : FALSE;
}
}
}
// Get the default access restriction as specified by the access control
// handler.
$entity_default = $this->checkFieldAccess($operation, $field_definition, $account, $items);
......
......@@ -9,6 +9,7 @@
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Theme\Registry;
use Drupal\Core\TypedData\TranslatableInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -54,6 +55,13 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf
*/
protected $languageManager;
/**
* The theme registry.
*
* @var \Drupal\Core\Theme\Registry
*/
protected $themeRegistry;
/**
* The EntityViewDisplay objects created for individual field rendering.
*
......@@ -72,12 +80,15 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf
* The entity manager service.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Theme\Registry $theme_registry
* The theme registry.
*/
public function __construct(EntityTypeInterface $entity_type, EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager) {
public function __construct(EntityTypeInterface $entity_type, EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager, Registry $theme_registry = NULL) {
$this->entityTypeId = $entity_type->id();
$this->entityType = $entity_type;
$this->entityManager = $entity_manager;
$this->languageManager = $language_manager;
$this->themeRegistry = $theme_registry ?: \Drupal::service('theme.registry');
}
/**
......@@ -87,7 +98,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
return new static(
$entity_type,
$container->get('entity.manager'),
$container->get('language_manager')
$container->get('language_manager'),
$container->get('theme.registry')
);
}
......@@ -148,7 +160,6 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode) {
$this->moduleHandler()->alter('entity_view_mode', $view_mode, $entity, $context);
$build = array(
'#theme' => $this->entityTypeId,
"#{$this->entityTypeId}" => $entity,
'#view_mode' => $view_mode,
// Collect cache defaults for this entity.
......@@ -159,6 +170,11 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode) {
),
);
// Add the default #theme key if a template exists for it.
if ($this->themeRegistry->getRuntime()->has($this->entityTypeId)) {
$build['#theme'] = $this->entityTypeId;
}
// Cache the rendered output if permitted by the view mode and global entity
// type configuration.
if ($this->isViewModeCacheable($view_mode) && !$entity->isNew() && $entity->isDefaultRevision() && $this->entityType->isRenderCacheable()) {
......
......@@ -1257,7 +1257,11 @@ protected function saveToDedicatedTables(ContentEntityInterface $entity, $update
foreach ($storage_definition->getColumns() as $column => $attributes) {
$column_name = $table_mapping->getFieldColumnName($storage_definition, $column);
// Serialize the value if specified in the column schema.
$record[$column_name] = !empty($attributes['serialize']) ? serialize($item->$column) : $item->$column;
$value = $item->$column;
if (!empty($attributes['serialize'])) {
$value = serialize($value);
}
$record[$column_name] = drupal_schema_get_field_value($attributes, $value);
}
$query->values($record);
if ($this->entityType->isRevisionable()) {
......
......@@ -44,7 +44,16 @@ public function onResponse(FilterResponseEvent $event) {
*/
protected function transformRootRelativeUrlsToAbsolute($rss_markup, Request $request) {
$rss_dom = new \DOMDocument();
// Load the RSS, if there are parsing errors, abort and return the unchanged
// markup.
$previous_value = libxml_use_internal_errors(TRUE);
$rss_dom->loadXML($rss_markup);
$errors = libxml_get_errors();
libxml_use_internal_errors($previous_value);
if ($errors) {
return $rss_markup;
}
// Invoke Html::transformRootRelativeUrlsToAbsolute() on all HTML content
// embedded in this RSS feed.
......
......@@ -21,8 +21,12 @@ abstract class FieldConfigStorageBase extends ConfigEntityStorage {
* {@inheritdoc}
*/
protected function mapFromStorageRecords(array $records) {
foreach ($records as &$record) {
foreach ($records as $id => &$record) {
$class = $this->fieldTypeManager->getPluginClass($record['field_type']);
if (empty($class)) {
$config_id = $this->getPrefix() . $id;
throw new \RuntimeException("Unable to determine class for field type '{$record['field_type']}' found in the '$config_id' configuration");
}
$record['settings'] = $class::fieldSettingsFromConfigData($record['settings']);
}
return parent::mapFromStorageRecords($records);
......
......@@ -26,7 +26,7 @@
* file is not controlled by the current module, the return value should be
* NULL.
*
* @see file_download()
* @see \Drupal\system\FileDownloadController::download()
*/
function hook_file_download($uri) {
// Check to see if this is a config download.
......