Skip to content
Commits on Source (26)
......@@ -2047,7 +2047,7 @@ function hook_mail_alter(&$message) {
* An array of parameters supplied by the caller of
* MailManagerInterface->mail().
*
* @see \Drupal\Core\Mail\MailManagerInterface->mail()
* @see \Drupal\Core\Mail\MailManagerInterface::mail()
*/
function hook_mail($key, &$message, $params) {
$account = $params['account'];
......
......@@ -1220,7 +1220,9 @@ function file_directory_os_temp() {
foreach ($directories as $directory) {
if (is_dir($directory) && is_writable($directory)) {
return $directory;
// Both sys_get_temp_dir() and ini_get('upload_tmp_dir') can return paths
// with a trailing directory separator.
return rtrim($directory, DIRECTORY_SEPARATOR);
}
}
return FALSE;
......
......@@ -596,7 +596,7 @@ function update_already_performed($module, $number) {
* An array of return values obtained by merging the results of the
* hook_update_dependencies() implementations in all installed modules.
*
* @see \Drupal::moduleHandler()->invokeAll()
* @see \Drupal\Core\Extension\ModuleHandlerInterface::invokeAll()
* @see hook_update_dependencies()
*/
function update_retrieve_dependencies() {
......
......@@ -81,7 +81,7 @@ class Drupal {
/**
* The current system version.
*/
const VERSION = '8.1.9-dev';
const VERSION = '8.1.11-dev';
/**
* Core API compatibility.
......
......@@ -23,7 +23,7 @@ class Schema extends DatabaseSchema {
* This is collected by DatabaseConnection_pgsql->queryTableInformation(),
* by introspecting the database.
*
* @see DatabaseConnection_pgsql->queryTableInformation()
* @see \Drupal\Core\Database\Driver\pgsql\Schema::queryTableInformation()
* @var array
*/
protected $tableInformation = array();
......
......@@ -297,7 +297,7 @@ protected static function matchEntityByTitle(SelectionInterface $handler, $input
$multiples[] = $name . ' (' . $id . ')';
}
$params['@id'] = $id;
$form_state->setError($element, t('Multiple entities match this reference; "%multiple". Specify the one you want by appending the id in parentheses, like "@value (@id)".', array('%multiple' => implode('", "', $multiples))));
$form_state->setError($element, t('Multiple entities match this reference; "%multiple". Specify the one you want by appending the id in parentheses, like "@value (@id)".', array('%multiple' => implode('", "', $multiples)) + $params));
}
else {
// Take the one and only matching entity.
......
......@@ -1543,6 +1543,7 @@ protected function readFieldItemsToPurge(FieldDefinitionInterface $field_definit
$item_query = $this->database->select($table_name, 't', array('fetch' => \PDO::FETCH_ASSOC))
->fields('t')
->condition('entity_id', $row['entity_id'])
->condition('deleted', 1)
->orderBy('delta');
foreach ($item_query->execute() as $item_row) {
......@@ -1581,10 +1582,12 @@ protected function purgeFieldItems(ContentEntityInterface $entity, FieldDefiniti
$revision_id = $this->entityType->isRevisionable() ? $entity->getRevisionId() : $entity->id();
$this->database->delete($table_name)
->condition('revision_id', $revision_id)
->condition('deleted', 1)
->execute();
if ($this->entityType->isRevisionable()) {
$this->database->delete($revision_name)
->condition('revision_id', $revision_id)
->condition('deleted', 1)
->execute();
}
}
......@@ -1684,6 +1687,12 @@ public function countFieldData($storage_definition, $as_bool = FALSE) {
* Whether the field has been already deleted.
*/
protected function storageDefinitionIsDeleted(FieldStorageDefinitionInterface $storage_definition) {
// Configurable fields are marked for deletion.
if ($storage_definition instanceOf FieldStorageConfigInterface) {
return $storage_definition->isDeleted();
}
// For non configurable fields check whether they are still in the last
// installed schema repository.
return !array_key_exists($storage_definition->getName(), $this->entityManager->getLastInstalledFieldStorageDefinitions($this->entityTypeId));
}
......
......@@ -188,13 +188,16 @@ public function onException(GetResponseForExceptionEvent $event) {
if (!method_exists($this, $method)) {
if ($exception instanceof HttpExceptionInterface) {
$this->onFormatUnknown($event);
$response = $event->getResponse();
$response->headers->set('Content-Type', 'text/plain');
}
else {
$this->onHtml($event);
}
return;
}
$this->$method($event);
else {
$this->$method($event);
}
}
/**
......
......@@ -172,7 +172,7 @@ function getProjectName(Extension $file) {
* @return
* Array of .info.yml file data we need for the update manager.
*
* @see \Drupal\Core\Utility\ProjectInfo->processInfoList()
* @see \Drupal\Core\Utility\ProjectInfo::processInfoList()
*/
function filterProjectInfo($info, $additional_whitelist = array()) {
$whitelist = array(
......
......@@ -108,10 +108,10 @@ public function getDefaultOperations(EntityInterface $entity) {
* {@inheritdoc}
*/
public function render() {
$build['action_header']['#markup'] = '<h3>' . t('Available actions:') . '</h3>';
$build['action_header']['#markup'] = '<h3>' . $this->t('Available actions:') . '</h3>';
$build['action_table'] = parent::render();
if (!$this->hasConfigurableActions) {
unset($build['action_table']['#header']['operations']);
unset($build['action_table']['table']['#header']['operations']);
}
$build['action_admin_manage_form'] = \Drupal::formBuilder()->getForm('Drupal\action\Form\ActionAdminManageForm');
return $build;
......
<?php
namespace Drupal\action\Tests;
use Drupal\simpletest\WebTestBase;
/**
* Test behaviors when visiting the action listing page.
*
* @group action
*/
class ActionListTest extends WebTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = array('action');
/**
* Tests the behavior when there are no actions to list in the admin page.
*/
public function testEmptyActionList() {
// Create a user with permission to view the actions administration pages.
$this->drupalLogin($this->drupalCreateUser(['administer actions']));
// Ensure the empty text appears on the action list page.
/** @var $storage \Drupal\Core\Entity\EntityStorageInterface */
$storage = $this->container->get('entity.manager')->getStorage('action');
$actions = $storage->loadMultiple();
$storage->delete($actions);
$this->drupalGet('/admin/config/system/actions');
$this->assertRaw('There is no Action yet.');
}
}
......@@ -17,13 +17,15 @@ class BlockContentDeletionTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['block', 'block_content'];
public static $modules = ['block', 'block_content', 'system', 'user'];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->installSchema('system', ['sequence']);
$this->installEntitySchema('user');
$this->installEntitySchema('block_content');
}
......
......@@ -2,7 +2,9 @@
namespace Drupal\comment;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Field\FieldItemList;
use Drupal\Core\Session\AccountInterface;
/**
* Defines a item list class for comment fields.
......@@ -37,4 +39,28 @@ public function offsetExists($offset) {
return parent::offsetExists($offset);
}
/**
* {@inheritdoc}
*/
public function access($operation = 'view', AccountInterface $account = NULL, $return_as_object = FALSE) {
if ($operation === 'edit') {
// Only users with administer comments permission can edit the comment
// status field.
$result = AccessResult::allowedIfHasPermission($account ?: \Drupal::currentUser(), 'administer comments');
return $return_as_object ? $result : $result->isAllowed();
}
if ($operation === 'view') {
// Only users with either post comments or access comments permisison can
// view the field value. The formatter,
// Drupal\comment\Plugin\Field\FieldFormatter\CommentDefaultFormatter,
// takes care of showing the thread and form based on individual
// permissions, so if a user only has ‘post comments’ access, only the
// form will be shown and not the comments.
$result = AccessResult::allowedIfHasPermission($account ?: \Drupal::currentUser(), 'access comments')
->orIf(AccessResult::allowedIfHasPermission($account ?: \Drupal::currentUser(), 'post comments'));
return $return_as_object ? $result : $result->isAllowed();
}
return parent::access($operation, $account, $return_as_object);
}
}
......@@ -384,6 +384,7 @@ function testCommentFunctionality() {
'administer entity_test fields',
'view test entity',
'administer entity_test content',
'administer comments',
));
$this->drupalLogin($limited_user);
$this->drupalGet('entity_test/structure/entity_test/fields/entity_test.entity_test.comment');
......
<?php
namespace Drupal\Tests\comment\Functional;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\BrowserTestBase;
/**
* Tests comment status field access.
*
* @group comment
*/
class CommentStatusFieldAccessTest extends BrowserTestBase {
use CommentTestTrait;
/**
* {@inheritdoc}
*/
public $profile = 'testing';
/**
* Comment admin.
*
* @var \Drupal\user\UserInterface
*/
protected $commentAdmin;
/**
* Node author.
*
* @var \Drupal\user\UserInterface
*/
protected $nodeAuthor;
/**
* {@inheritdoc}
*/
public static $modules = [
'node',
'comment',
'user',
'system',
'text',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$node_type = NodeType::create([
'type' => 'article',
'name' => t('Article'),
]);
$node_type->save();
$this->nodeAuthor = $this->drupalCreateUser([
'create article content',
'skip comment approval',
'post comments',
'edit own comments',
'access comments',
'administer nodes',
]);
$this->commentAdmin = $this->drupalCreateUser([
'administer comments',
'create article content',
'edit own comments',
'skip comment approval',
'post comments',
'access comments',
'administer nodes',
]);
$this->addDefaultCommentField('node', 'article');
}
/**
* Tests comment status field access.
*/
public function testCommentStatusFieldAccessStatus() {
$this->drupalLogin($this->nodeAuthor);
$this->drupalGet('node/add/article');
$assert = $this->assertSession();
$assert->fieldNotExists('comment[0][status]');
$this->submitForm([
'title[0][value]' => 'Node 1',
], t('Save and publish'));
$assert->fieldExists('subject[0][value]');
$this->drupalLogin($this->commentAdmin);
$this->drupalGet('node/add/article');
$assert->fieldExists('comment[0][status]');
$this->submitForm([
'title[0][value]' => 'Node 2',
], t('Save and publish'));
$assert->fieldExists('subject[0][value]');
}
}
......@@ -65,14 +65,17 @@ function config_file_download($uri) {
$scheme = file_uri_scheme($uri);
$target = file_uri_target($uri);
if ($scheme == 'temporary' && $target == 'config.tar.gz') {
$request = \Drupal::request();
$date = DateTime::createFromFormat('U', $request->server->get('REQUEST_TIME'));
$date_string = $date->format('Y-m-d-H-i');
$hostname = str_replace('.', '-', $request->getHttpHost());
$filename = 'config' . '-' . $hostname . '-' . $date_string . '.tar.gz';
$disposition = 'attachment; filename="' . $filename . '"';
return array(
'Content-disposition' => $disposition,
);
if (\Drupal::currentUser()->hasPermission('export configuration')) {
$request = \Drupal::request();
$date = DateTime::createFromFormat('U', $request->server->get('REQUEST_TIME'));
$date_string = $date->format('Y-m-d-H-i');
$hostname = str_replace('.', '-', $request->getHttpHost());
$filename = 'config' . '-' . $hostname . '-' . $date_string . '.tar.gz';
$disposition = 'attachment; filename="' . $filename . '"';
return array(
'Content-disposition' => $disposition,
);
}
return -1;
}
}
......@@ -88,6 +88,12 @@ function testExport() {
// Check the single export form doesn't have "form-required" elements.
$this->drupalGet('admin/config/development/configuration/single/export');
$this->assertNoRaw('js-form-required form-required', 'No form required fields are found.');
// Ensure the temporary file is not available to users without the
// permission.
$this->drupalLogout();
$this->drupalGet('system/temporary', ['query' => ['file' => 'config.tar.gz']]);
$this->assertResponse(403);
}
}
......@@ -3,12 +3,12 @@
namespace Drupal\field\Plugin\migrate\process;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Plugin\migrate\process\StaticMap;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -21,7 +21,7 @@ class FieldType extends StaticMap implements ContainerFactoryPluginInterface {
/**
* The cckfield plugin manager.
*
* @var \Drupal\Component\Plugin\PluginManagerInterface
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface
*/
protected $cckPluginManager;
......@@ -41,12 +41,12 @@ class FieldType extends StaticMap implements ContainerFactoryPluginInterface {
* The plugin ID.
* @param mixed $plugin_definition
* The plugin definition.
* @param \Drupal\Component\Plugin\PluginManagerInterface $cck_plugin_manager
* @param \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface $cck_plugin_manager
* The cckfield plugin manager.
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The migration being run.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, PluginManagerInterface $cck_plugin_manager, MigrationInterface $migration = NULL) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrateCckFieldPluginManagerInterface $cck_plugin_manager, MigrationInterface $migration = NULL) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->cckPluginManager = $cck_plugin_manager;
$this->migration = $migration;
......@@ -72,7 +72,8 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
$field_type = is_array($value) ? $value[0] : $value;
try {
return $this->cckPluginManager->createInstance($field_type, [], $this->migration)->getFieldType($row);
$plugin_id = $this->cckPluginManager->getPluginIdFromFieldType($field_type, [], $this->migration);
return $this->cckPluginManager->createInstance($plugin_id, [], $this->migration)->getFieldType($row);
}
catch (PluginNotFoundException $e) {
return parent::transform($value, $migrate_executable, $row, $destination_property);
......
......@@ -208,6 +208,7 @@ public function testFieldAdminHandler() {
'id' => 'node_test_view',
'label' => 'Node Test View',
'show[wizard_key]' => 'node',
'show[sort]' => 'none',
'page[create]' => 1,
'page[title]' => 'Test Node View',
'page[path]' => 'test/node/view',
......@@ -221,6 +222,14 @@ public function testFieldAdminHandler() {
'style_options[search_fields][title]' => 'title',
);
$this->drupalPostForm(NULL, $edit, t('Apply'));
// Set sort to NID ascending.
$edit = [
'name[node_field_data.nid]' => 1,
];
$this->drupalPostForm('admin/structure/views/nojs/add-handler/node_test_view/entity_reference_1/sort', $edit, t('Add and configure sort criteria'));
$this->drupalPostForm(NULL, NULL, t('Apply'));
$this->drupalPostForm('admin/structure/views/view/node_test_view/edit/entity_reference_1', array(), t('Save'));
$this->clickLink(t('Settings'));
......@@ -301,6 +310,7 @@ public function testFieldAdminHandler() {
$this->assertText(t('Multiple entities match this reference;'));
$this->assertText(t("@node1", ['@node1' => $node1->getTitle() . ' (' . $node1->id() . ')']));
$this->assertText(t("@node2", ['@node2' => $node2->getTitle() . ' (' . $node2->id() . ')']));
$this->assertText(t('Specify the one you want by appending the id in parentheses, like "@example".', ['@example' => $node2->getTitle() . ' (' . $node2->id() . ')']));
$edit = array(
'title[0][value]' => 'Test',
......
......@@ -210,6 +210,98 @@ function testDeleteField() {
$this->assertFalse(array_diff($found, array_keys($this->entities)));
}
/**
* Tests that recreating a field with the name as a deleted field works.
*/
public function testPurgeWithDeletedAndActiveField() {
$bundle = reset($this->bundles);
// Create another field storage.
$field_name = 'bf_3';
$deleted_field_storage = FieldStorageConfig::create(array(
'field_name' => $field_name,
'entity_type' => $this->entityTypeId,
'type' => 'test_field',
'cardinality' => 1
));
$deleted_field_storage->save();
// Create the field.
FieldConfig::create([
'field_storage' => $deleted_field_storage,
'bundle' => $bundle,
])->save();
for ($i = 0; $i < 20; $i++) {
$entity = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId)
->create(array('type' => $bundle));
$entity->{$field_name}->setValue($this->_generateTestFieldValues(1));
$entity->save();
}
// Delete the field.
$deleted_field = FieldConfig::loadByName($this->entityTypeId, $bundle, $field_name);
$deleted_field->delete();
$deleted_field_uuid = $deleted_field->uuid();
// Reload the field storage.
$field_storages = entity_load_multiple_by_properties('field_storage_config', array('uuid' => $deleted_field_storage->uuid(), 'include_deleted' => TRUE));
$deleted_field_storage = reset($field_storages);
// Create the field again.
$field_storage = FieldStorageConfig::create(array(
'field_name' => $field_name,
'entity_type' => $this->entityTypeId,
'type' => 'test_field',
'cardinality' => 1
));
$field_storage->save();
FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => $bundle,
])->save();
// The field still exists, deleted, with the same field name.
$fields = entity_load_multiple_by_properties('field_config', array('uuid' => $deleted_field_uuid, 'include_deleted' => TRUE));
$this->assertTrue(isset($fields[$deleted_field_uuid]) && $fields[$deleted_field_uuid]->isDeleted(), 'The field exists and is deleted');
$this->assertTrue(isset($fields[$deleted_field_uuid]) && $fields[$deleted_field_uuid]->getName() == $field_name);
for ($i = 0; $i < 10; $i++) {
$entity = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId)
->create(array('type' => $bundle));
$entity->{$field_name}->setValue($this->_generateTestFieldValues(1));
$entity->save();
}
// Check that the two field storages have different tables.
$storage = \Drupal::entityManager()->getStorage($this->entityTypeId);
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $storage->getTableMapping();
$deleted_table_name = $table_mapping->getDedicatedDataTableName($deleted_field_storage, TRUE);
$active_table_name = $table_mapping->getDedicatedDataTableName($field_storage);
field_purge_batch(50);
// Ensure the new field still has its table and the deleted one has been
// removed.
$this->assertTrue(\Drupal::database()->schema()->tableExists($active_table_name));
$this->assertFalse(\Drupal::database()->schema()->tableExists($deleted_table_name));
// The field has been removed from the system.
$fields = entity_load_multiple_by_properties('field_config', array('field_storage_uuid' => $deleted_field_storage->uuid(), 'deleted' => TRUE, 'include_deleted' => TRUE));
$this->assertEqual(count($fields), 0, 'The field is gone');
// Verify there are still 10 entries in the main table.
$count = \Drupal::database()
->select('entity_test__' . $field_name, 'f')
->fields('f', array('entity_id'))
->condition('bundle', $bundle)
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 10);
}
/**
* Verify that field data items and fields are purged when a field storage is
* deleted.
......