Skip to content
Commits on Source (42)
...@@ -90,6 +90,19 @@ INSTALLATION ...@@ -90,6 +90,19 @@ INSTALLATION
mv drupal-x.y.z/* drupal-x.y.z/.htaccess drupal-x.y.z/.csslintrc drupal-x.y.z/.editorconfig drupal-x.y.z/.eslintignore drupal-x.y.z/.eslintrc drupal-x.y.z/.gitattributes /path/to/your/installation mv drupal-x.y.z/* drupal-x.y.z/.htaccess drupal-x.y.z/.csslintrc drupal-x.y.z/.editorconfig drupal-x.y.z/.eslintignore drupal-x.y.z/.eslintrc drupal-x.y.z/.gitattributes /path/to/your/installation
You can also download the latest version of Drupal using Git on the command
line and set up a repository by following the instructions at
https://www.drupal.org/project/drupal/git-instructions for "Setting up
repository for the first time".
Once you have downloaded Drupal successfully, you may install Composer
globally using the instructions at
https://getcomposer.org/doc/00-intro.md#globally
With Composer installed, run the following command from the Drupal web root:
composer install
2. Create the Drupal database. 2. Create the Drupal database.
Because Drupal stores all site information in a database, the Drupal Because Drupal stores all site information in a database, the Drupal
......
...@@ -23,9 +23,10 @@ Drupal 8 ...@@ -23,9 +23,10 @@ Drupal 8
(Release Manager) (Release Manager)
- Alex Pott 'alexpott' https://www.drupal.org/u/alexpott - Alex Pott 'alexpott' https://www.drupal.org/u/alexpott
(Framework Manager) (Framework Manager)
Provisional membership:
- Scott Reeves 'Cottser' https://www.drupal.org/u/cottser - Scott Reeves 'Cottser' https://www.drupal.org/u/cottser
(Framework Manager - Frontend)
Provisional membership: None at this time.
Drupal 7 Drupal 7
- Fabian Franz 'Fabianx' https://www.drupal.org/u/fabianx - Fabian Franz 'Fabianx' https://www.drupal.org/u/fabianx
......
...@@ -2047,7 +2047,7 @@ function hook_mail_alter(&$message) { ...@@ -2047,7 +2047,7 @@ function hook_mail_alter(&$message) {
* An array of parameters supplied by the caller of * An array of parameters supplied by the caller of
* MailManagerInterface->mail(). * MailManagerInterface->mail().
* *
* @see \Drupal\Core\Mail\MailManagerInterface->mail() * @see \Drupal\Core\Mail\MailManagerInterface::mail()
*/ */
function hook_mail($key, &$message, $params) { function hook_mail($key, &$message, $params) {
$account = $params['account']; $account = $params['account'];
......
...@@ -1220,7 +1220,9 @@ function file_directory_os_temp() { ...@@ -1220,7 +1220,9 @@ function file_directory_os_temp() {
foreach ($directories as $directory) { foreach ($directories as $directory) {
if (is_dir($directory) && is_writable($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; return FALSE;
......
...@@ -596,7 +596,7 @@ function update_already_performed($module, $number) { ...@@ -596,7 +596,7 @@ function update_already_performed($module, $number) {
* An array of return values obtained by merging the results of the * An array of return values obtained by merging the results of the
* hook_update_dependencies() implementations in all installed modules. * hook_update_dependencies() implementations in all installed modules.
* *
* @see \Drupal::moduleHandler()->invokeAll() * @see \Drupal\Core\Extension\ModuleHandlerInterface::invokeAll()
* @see hook_update_dependencies() * @see hook_update_dependencies()
*/ */
function update_retrieve_dependencies() { function update_retrieve_dependencies() {
......
...@@ -81,7 +81,7 @@ class Drupal { ...@@ -81,7 +81,7 @@ class Drupal {
/** /**
* The current system version. * The current system version.
*/ */
const VERSION = '8.1.9-dev'; const VERSION = '8.1.11-dev';
/** /**
* Core API compatibility. * Core API compatibility.
......
...@@ -23,7 +23,7 @@ class Schema extends DatabaseSchema { ...@@ -23,7 +23,7 @@ class Schema extends DatabaseSchema {
* This is collected by DatabaseConnection_pgsql->queryTableInformation(), * This is collected by DatabaseConnection_pgsql->queryTableInformation(),
* by introspecting the database. * by introspecting the database.
* *
* @see DatabaseConnection_pgsql->queryTableInformation() * @see \Drupal\Core\Database\Driver\pgsql\Schema::queryTableInformation()
* @var array * @var array
*/ */
protected $tableInformation = array(); protected $tableInformation = array();
......
...@@ -297,7 +297,7 @@ protected static function matchEntityByTitle(SelectionInterface $handler, $input ...@@ -297,7 +297,7 @@ protected static function matchEntityByTitle(SelectionInterface $handler, $input
$multiples[] = $name . ' (' . $id . ')'; $multiples[] = $name . ' (' . $id . ')';
} }
$params['@id'] = $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 { else {
// Take the one and only matching entity. // Take the one and only matching entity.
......
...@@ -1543,6 +1543,7 @@ protected function readFieldItemsToPurge(FieldDefinitionInterface $field_definit ...@@ -1543,6 +1543,7 @@ protected function readFieldItemsToPurge(FieldDefinitionInterface $field_definit
$item_query = $this->database->select($table_name, 't', array('fetch' => \PDO::FETCH_ASSOC)) $item_query = $this->database->select($table_name, 't', array('fetch' => \PDO::FETCH_ASSOC))
->fields('t') ->fields('t')
->condition('entity_id', $row['entity_id']) ->condition('entity_id', $row['entity_id'])
->condition('deleted', 1)
->orderBy('delta'); ->orderBy('delta');
foreach ($item_query->execute() as $item_row) { foreach ($item_query->execute() as $item_row) {
...@@ -1581,10 +1582,12 @@ protected function purgeFieldItems(ContentEntityInterface $entity, FieldDefiniti ...@@ -1581,10 +1582,12 @@ protected function purgeFieldItems(ContentEntityInterface $entity, FieldDefiniti
$revision_id = $this->entityType->isRevisionable() ? $entity->getRevisionId() : $entity->id(); $revision_id = $this->entityType->isRevisionable() ? $entity->getRevisionId() : $entity->id();
$this->database->delete($table_name) $this->database->delete($table_name)
->condition('revision_id', $revision_id) ->condition('revision_id', $revision_id)
->condition('deleted', 1)
->execute(); ->execute();
if ($this->entityType->isRevisionable()) { if ($this->entityType->isRevisionable()) {
$this->database->delete($revision_name) $this->database->delete($revision_name)
->condition('revision_id', $revision_id) ->condition('revision_id', $revision_id)
->condition('deleted', 1)
->execute(); ->execute();
} }
} }
...@@ -1684,6 +1687,12 @@ public function countFieldData($storage_definition, $as_bool = FALSE) { ...@@ -1684,6 +1687,12 @@ public function countFieldData($storage_definition, $as_bool = FALSE) {
* Whether the field has been already deleted. * Whether the field has been already deleted.
*/ */
protected function storageDefinitionIsDeleted(FieldStorageDefinitionInterface $storage_definition) { 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)); return !array_key_exists($storage_definition->getName(), $this->entityManager->getLastInstalledFieldStorageDefinitions($this->entityTypeId));
} }
......
...@@ -1845,7 +1845,8 @@ function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\Ent ...@@ -1845,7 +1845,8 @@ function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\Ent
* *
* @param string $operation * @param string $operation
* The operation to be performed. See * The operation to be performed. See
* \Drupal\Core\Access\AccessibleInterface::access() for possible values. * \Drupal\Core\Entity\EntityAccessControlHandlerInterface::fieldAccess()
* for possible values.
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The field definition. * The field definition.
* @param \Drupal\Core\Session\AccountInterface $account * @param \Drupal\Core\Session\AccountInterface $account
...@@ -1856,6 +1857,8 @@ function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\Ent ...@@ -1856,6 +1857,8 @@ function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\Ent
* *
* @return \Drupal\Core\Access\AccessResultInterface * @return \Drupal\Core\Access\AccessResultInterface
* The access result. * The access result.
*
* @see \Drupal\Core\Entity\EntityAccessControlHandlerInterface::fieldAccess()
*/ */
function hook_entity_field_access($operation, \Drupal\Core\Field\FieldDefinitionInterface $field_definition, \Drupal\Core\Session\AccountInterface $account, \Drupal\Core\Field\FieldItemListInterface $items = NULL) { function hook_entity_field_access($operation, \Drupal\Core\Field\FieldDefinitionInterface $field_definition, \Drupal\Core\Session\AccountInterface $account, \Drupal\Core\Field\FieldItemListInterface $items = NULL) {
if ($field_definition->getName() == 'field_of_interest' && $operation == 'edit') { if ($field_definition->getName() == 'field_of_interest' && $operation == 'edit') {
......
...@@ -188,13 +188,16 @@ public function onException(GetResponseForExceptionEvent $event) { ...@@ -188,13 +188,16 @@ public function onException(GetResponseForExceptionEvent $event) {
if (!method_exists($this, $method)) { if (!method_exists($this, $method)) {
if ($exception instanceof HttpExceptionInterface) { if ($exception instanceof HttpExceptionInterface) {
$this->onFormatUnknown($event); $this->onFormatUnknown($event);
$response = $event->getResponse();
$response->headers->set('Content-Type', 'text/plain');
} }
else { else {
$this->onHtml($event); $this->onHtml($event);
} }
return;
} }
$this->$method($event); else {
$this->$method($event);
}
} }
/** /**
......
...@@ -172,7 +172,7 @@ function getProjectName(Extension $file) { ...@@ -172,7 +172,7 @@ function getProjectName(Extension $file) {
* @return * @return
* Array of .info.yml file data we need for the update manager. * 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()) { function filterProjectInfo($info, $additional_whitelist = array()) {
$whitelist = array( $whitelist = array(
......
...@@ -108,10 +108,10 @@ public function getDefaultOperations(EntityInterface $entity) { ...@@ -108,10 +108,10 @@ public function getDefaultOperations(EntityInterface $entity) {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function render() { 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(); $build['action_table'] = parent::render();
if (!$this->hasConfigurableActions) { 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'); $build['action_admin_manage_form'] = \Drupal::formBuilder()->getForm('Drupal\action\Form\ActionAdminManageForm');
return $build; 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.');
}
}
...@@ -104,9 +104,15 @@ public function getTheme() { ...@@ -104,9 +104,15 @@ public function getTheme() {
*/ */
public function postSave(EntityStorageInterface $storage, $update = TRUE) { public function postSave(EntityStorageInterface $storage, $update = TRUE) {
parent::postSave($storage, $update); parent::postSave($storage, $update);
static::invalidateBlockPluginCache();
}
// Invalidate the block cache to update custom block-based derivatives. /**
\Drupal::service('plugin.manager.block')->clearCachedDefinitions(); * {@inheritdoc}
*/
public static function postDelete(EntityStorageInterface $storage, array $entities) {
parent::postDelete($storage, $entities);
static::invalidateBlockPluginCache();
} }
/** /**
...@@ -237,4 +243,12 @@ public function setRevisionLog($revision_log) { ...@@ -237,4 +243,12 @@ public function setRevisionLog($revision_log) {
return $this; return $this;
} }
/**
* Invalidates the block plugin cache after changes and deletions.
*/
protected static function invalidateBlockPluginCache() {
// Invalidate the block cache to update custom block-based derivatives.
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
}
} }
...@@ -44,6 +44,8 @@ public static function create(ContainerInterface $container, $base_plugin_id) { ...@@ -44,6 +44,8 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
*/ */
public function getDerivativeDefinitions($base_plugin_definition) { public function getDerivativeDefinitions($base_plugin_definition) {
$block_contents = $this->blockContentStorage->loadMultiple(); $block_contents = $this->blockContentStorage->loadMultiple();
// Reset the discovered definitions.
$this->derivatives = [];
/** @var $block_content \Drupal\block_content\Entity\BlockContent */ /** @var $block_content \Drupal\block_content\Entity\BlockContent */
foreach ($block_contents as $block_content) { foreach ($block_contents as $block_content) {
$this->derivatives[$block_content->uuid()] = $base_plugin_definition; $this->derivatives[$block_content->uuid()] = $base_plugin_definition;
......
<?php
namespace Drupal\Tests\block_content\Kernel;
use Drupal\block_content\Entity\BlockContent;
use Drupal\block_content\Entity\BlockContentType;
use Drupal\Component\Plugin\PluginBase;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests that deleting a block clears the cached definitions.
*
* @group block_content
*/
class BlockContentDeletionTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
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');
}
/**
* Tests deleting a block_content updates the discovered block plugin.
*/
public function testDeletingBlockContentShouldClearPluginCache() {
// Create a block content type.
$block_content_type = BlockContentType::create([
'id' => 'spiffy',
'label' => 'Mucho spiffy',
'description' => "Provides a block type that increases your site's spiffiness by upto 11%",
]);
$block_content_type->save();
// And a block content entity.
$block_content = BlockContent::create([
'info' => 'Spiffy prototype',
'type' => 'spiffy',
]);
$block_content->save();
// Make sure the block content provides a derivative block plugin in the
// block repository.
/** @var \Drupal\Core\Block\BlockManagerInterface $block_manager */
$block_manager = $this->container->get('plugin.manager.block');
$plugin_id = 'block_content' . PluginBase::DERIVATIVE_SEPARATOR . $block_content->uuid();
$this->assertTrue($block_manager->hasDefinition($plugin_id));
// Now delete the block content entity.
$block_content->delete();
// The plugin should no longer exist.
$this->assertFalse($block_manager->hasDefinition($plugin_id));
}
}
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
namespace Drupal\comment; namespace Drupal\comment;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Field\FieldItemList; use Drupal\Core\Field\FieldItemList;
use Drupal\Core\Session\AccountInterface;
/** /**
* Defines a item list class for comment fields. * Defines a item list class for comment fields.
...@@ -37,4 +39,28 @@ public function offsetExists($offset) { ...@@ -37,4 +39,28 @@ public function offsetExists($offset) {
return parent::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() { ...@@ -384,6 +384,7 @@ function testCommentFunctionality() {
'administer entity_test fields', 'administer entity_test fields',
'view test entity', 'view test entity',
'administer entity_test content', 'administer entity_test content',
'administer comments',
)); ));
$this->drupalLogin($limited_user); $this->drupalLogin($limited_user);
$this->drupalGet('entity_test/structure/entity_test/fields/entity_test.entity_test.comment'); $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]');
}
}