updated core to 8.6.1 via composer

This commit is contained in:
2018-09-12 13:58:26 +02:00
parent a9a219f2ed
commit ea56b9fba3
4443 changed files with 112098 additions and 40708 deletions
+2 -1
View File
@@ -29,8 +29,9 @@ function action_help($route_name, RouteMatchInterface $route_match) {
$output = '<p>' . t('There are two types of actions: simple and advanced. Simple actions do not require any additional configuration and are listed here automatically. Advanced actions need to be created and configured before they can be used because they have options that need to be specified; for example, sending an email to a specified address or unpublishing content containing certain words. To create an advanced action, select the action from the drop-down list in the advanced action section below and click the <em>Create</em> button.') . '</p>';
return $output;
case 'action.admin_add':
case 'entity.action.edit_form':
return t('An advanced action offers additional configuration options which may be filled out below. Changing the <em>Description</em> field is recommended in order to better identify the precise action taking place.');
return t('An advanced action offers additional configuration options which may be filled out below. Changing the <em>Label</em> field is recommended in order to better identify the precise action taking place.');
}
}
-1
View File
@@ -29,4 +29,3 @@ entity.action.delete_form:
_title: 'Delete'
requirements:
_permission: 'administer actions'
+1 -1
View File
@@ -132,7 +132,7 @@ abstract class ActionFormBase extends EntityForm {
*/
public function save(array $form, FormStateInterface $form_state) {
$this->entity->save();
drupal_set_message($this->t('The action has been successfully saved.'));
$this->messenger()->addStatus($this->t('The action has been successfully saved.'));
$form_state->setRedirect('entity.action.collection');
}
@@ -72,7 +72,7 @@ class ActionAdminManageForm extends FormBase {
'#empty_option' => $this->t('- Select -'),
];
$form['parent']['actions'] = [
'#type' => 'actions'
'#type' => 'actions',
];
$form['parent']['actions']['submit'] = [
'#type' => 'submit',
@@ -139,12 +139,11 @@ class EmailAction extends ConfigurableActionBase implements ContainerFactoryPlug
}
$params = ['context' => $this->configuration];
if ($this->mailManager->mail('system', 'action_send_email', $recipient, $langcode, $params)) {
$message = $this->mailManager->mail('system', 'action_send_email', $recipient, $langcode, $params);
// Error logging is handled by \Drupal\Core\Mail\MailManager::mail().
if ($message['result']) {
$this->logger->notice('Sent email to %recipient', ['%recipient' => $recipient]);
}
else {
$this->logger->error('Unable to send email to %recipient', ['%recipient' => $recipient]);
}
}
/**
@@ -5,6 +5,7 @@ namespace Drupal\action\Plugin\Action;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Action\ConfigurableActionBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Session\AccountInterface;
@@ -36,6 +37,13 @@ class MessageAction extends ConfigurableActionBase implements ContainerFactoryPl
*/
protected $renderer;
/**
* The messenger.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* Constructs a MessageAction object.
*
@@ -49,19 +57,22 @@ class MessageAction extends ConfigurableActionBase implements ContainerFactoryPl
* The token service.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, Token $token, RendererInterface $renderer) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, Token $token, RendererInterface $renderer, MessengerInterface $messenger) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->token = $token;
$this->renderer = $renderer;
$this->messenger = $messenger;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container->get('token'), $container->get('renderer'));
return new static($configuration, $plugin_id, $plugin_definition, $container->get('token'), $container->get('renderer'), $container->get('messenger'));
}
/**
@@ -77,7 +88,7 @@ class MessageAction extends ConfigurableActionBase implements ContainerFactoryPl
];
// @todo Fix in https://www.drupal.org/node/2577827
drupal_set_message($this->renderer->renderPlain($build));
$this->messenger->addStatus($this->renderer->renderPlain($build));
}
/**
@@ -5,6 +5,6 @@ package: Testing
version: VERSION
core: 8.x
dependencies:
- action
- views
- node
- drupal:action
- drupal:views
- drupal:node
@@ -28,10 +28,10 @@ class ActionListTest extends BrowserTestBase {
// 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();
$actions = $storage->loadMultiple();
$storage->delete($actions);
$this->drupalGet('/admin/config/system/actions');
$this->assertRaw('There is no Action yet.');
$this->assertRaw('There are no actions yet.');
}
}
@@ -148,7 +148,7 @@ class BulkFormTest extends BrowserTestBase {
$errors = $this->xpath('//div[contains(@class, "messages--status")]');
$this->assertFalse($errors, 'No action message shown.');
$this->drupalPostForm(NULL, [], t('Delete'));
$this->assertText(t('Deleted 5 posts.'));
$this->assertText(t('Deleted 5 content items.'));
// Check if we got redirected to the original page.
$this->assertUrl('test_bulk_form');
}
@@ -3,7 +3,7 @@
namespace Drupal\Tests\action\FunctionalJavascript;
use Drupal\Core\Url;
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\system\Entity\Action;
/**
@@ -11,7 +11,7 @@ use Drupal\system\Entity\Action;
*
* @group action
*/
class ActionFormAjaxTest extends JavascriptTestBase {
class ActionFormAjaxTest extends WebDriverTestBase {
/**
* {@inheritdoc}
@@ -33,16 +33,15 @@ class ActionFormAjaxTest extends JavascriptTestBase {
public function testActionConfigurationWithAjax() {
$url = Url::fromRoute('action.admin_add', ['action_id' => 'action_form_ajax_test']);
$this->drupalGet($url);
$this->assertSession()->statusCodeEquals(200);
$page = $this->getSession()->getPage();
$id = 'test_plugin';
$page->find('css', '[name="id"]')
->setValue($id);
$this->assertSession()->waitForElementVisible('named', ['button', 'Edit'])->press();
$this->assertSession()->waitForElementVisible('css', '[name="id"]')->setValue($id);
$page->find('css', '[name="having_a_party"]')
->check();
$this->assertSession()->waitForElement('css', '[name="party_time"]');
$this->assertSession()->waitForElementVisible('css', '[name="party_time"]');
$party_time = 'Evening';
$page->find('css', '[name="party_time"]')
@@ -54,7 +53,6 @@ class ActionFormAjaxTest extends JavascriptTestBase {
$url = Url::fromRoute('entity.action.collection');
$this->assertSession()->pageTextContains('The action has been successfully saved.');
$this->assertSession()->addressEquals($url);
$this->assertSession()->statusCodeEquals(200);
// Check storage.
$instance = Action::load($id);
@@ -40,7 +40,7 @@ class MigrateActionsTest extends MigrateDrupal6TestBase {
$this->assertEntity('send_e_mail', 'Send e-mail', 'system', [
"recipient" => "test@example.com",
"subject" => "Drupal migration test",
"message" => "Drupal migration test"
"message" => "Drupal migration test",
]);
$this->assertEntity('redirect_to_url', 'Redirect to URL', 'system', ["url" => "https://www.drupal.org"]);
@@ -40,7 +40,7 @@ class MigrateActionsTest extends MigrateDrupal7TestBase {
$this->assertEntity('send_e_mail', 'Send e-mail', 'system', [
"recipient" => "test@example.com",
"subject" => "Drupal migration test",
"message" => "Drupal migration test"
"message" => "Drupal migration test",
]);
$this->assertEntity('redirect_to_url', 'Redirect to URL', 'system', ["url" => "https://www.drupal.org"]);
@@ -0,0 +1,65 @@
<?php
namespace Drupal\Tests\action\Kernel\Plugin\Action;
use Drupal\Core\Test\AssertMailTrait;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests for the EmailAction plugin.
*
* @group action
*/
class EmailActionTest extends KernelTestBase {
use AssertMailTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['system', 'user', 'action', 'dblog'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('user');
$this->installSchema('dblog', ['watchdog']);
}
/**
* Test the email action plugin.
*/
public function testEmailAction() {
/** @var \Drupal\Core\Action\ActionManager $plugin_manager */
$plugin_manager = $this->container->get('plugin.manager.action');
$configuration = [
'recipient' => 'test@example.com',
'subject' => 'Test subject',
'message' => 'Test message',
];
$plugin_manager
->createInstance('action_send_email_action', $configuration)
->execute();
$mails = $this->getMails();
$this->assertCount(1, $this->getMails());
$this->assertEquals('test@example.com', $mails[0]['to']);
$this->assertEquals('Test subject', $mails[0]['subject']);
$this->assertEquals("Test message\n", $mails[0]['body']);
// Ensure that the email sending is logged.
$log = \Drupal::database()
->select('watchdog', 'w')
->fields('w', ['message', 'variables'])
->orderBy('wid', 'DESC')
->range(0, 1)
->execute()
->fetch();
$this->assertEquals($log->message, 'Sent email to %recipient');
$variables = unserialize($log->variables);
$this->assertEquals($variables['%recipient'], 'test@example.com');
}
}
+2 -2
View File
@@ -6,5 +6,5 @@ version: VERSION
core: 8.x
configure: aggregator.admin_settings
dependencies:
- file
- options
- drupal:file
- drupal:options
@@ -44,7 +44,8 @@ class AggregatorController extends ControllerBase {
* Presents the aggregator feed creation form.
*
* @return array
* A form array as expected by drupal_render().
* A form array as expected by
* \Drupal\Core\Render\RendererInterface::render().
*/
public function feedAdd() {
$feed = $this->entityManager()->getStorage('aggregator_feed')->create();
@@ -101,7 +102,8 @@ class AggregatorController extends ControllerBase {
* Displays the aggregator administration page.
*
* @return array
* A render array as expected by drupal_render().
* A render array as expected by
* \Drupal\Core\Render\RendererInterface::render().
*/
public function adminOverview() {
$entity_manager = $this->entityManager();
@@ -14,6 +14,13 @@ use Drupal\aggregator\FeedInterface;
* @ContentEntityType(
* id = "aggregator_feed",
* label = @Translation("Aggregator feed"),
* label_collection = @Translation("Aggregator feeds"),
* label_singular = @Translation("aggregator feed"),
* label_plural = @Translation("aggregator feeds"),
* label_count = @PluralTranslation(
* singular = "@count aggregator feed",
* plural = "@count aggregator feeds",
* ),
* handlers = {
* "storage" = "Drupal\aggregator\FeedStorage",
* "storage_schema" = "Drupal\aggregator\FeedStorageSchema",
+7 -1
View File
@@ -16,6 +16,13 @@ use Drupal\Core\Url;
* @ContentEntityType(
* id = "aggregator_item",
* label = @Translation("Aggregator feed item"),
* label_collection = @Translation("Aggregator feed items"),
* label_singular = @Translation("aggregator feed item"),
* label_plural = @Translation("aggregator feed items"),
* label_count = @PluralTranslation(
* singular = "@count aggregator feed item",
* plural = "@count aggregator feed items",
* ),
* handlers = {
* "storage" = "Drupal\aggregator\ItemStorage",
* "storage_schema" = "Drupal\aggregator\ItemStorageSchema",
@@ -232,7 +239,6 @@ class Item extends ContentEntityBase implements ItemInterface {
return Feed::load($this->getFeedId())->getCacheTags();
}
/**
* Entity URI callback.
*/
+2 -2
View File
@@ -22,12 +22,12 @@ class FeedForm extends ContentEntityForm {
$label = $feed->label();
$view_link = $feed->link($label, 'canonical');
if ($status == SAVED_UPDATED) {
drupal_set_message($this->t('The feed %feed has been updated.', ['%feed' => $view_link]));
$this->messenger()->addStatus($this->t('The feed %feed has been updated.', ['%feed' => $view_link]));
$form_state->setRedirectUrl($feed->urlInfo('canonical'));
}
else {
$this->logger('aggregator')->notice('Feed %feed added.', ['%feed' => $feed->label(), 'link' => $this->l($this->t('View'), new Url('aggregator.admin_overview'))]);
drupal_set_message($this->t('The feed %feed has been added.', ['%feed' => $view_link]));
$this->messenger()->addStatus($this->t('The feed %feed has been added.', ['%feed' => $view_link]));
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ class FeedStorage extends SqlContentEntityStorage implements FeedStorageInterfac
* {@inheritdoc}
*/
public function getFeedIdsToRefresh() {
return $this->database->query('SELECT fid FROM {aggregator_feed} WHERE queued = 0 AND checked + refresh < :time AND refresh <> :never', [
return $this->database->query('SELECT fid FROM {' . $this->getBaseTable() . '} WHERE queued = 0 AND checked + refresh < :time AND refresh <> :never', [
':time' => REQUEST_TIME,
':never' => AGGREGATOR_CLEAR_NEVER,
])->fetchCol();
@@ -17,7 +17,7 @@ class FeedStorageSchema extends SqlContentEntityStorageSchema {
$schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping);
$field_name = $storage_definition->getName();
if ($table_name == 'aggregator_feed') {
if ($table_name == $this->storage->getBaseTable()) {
switch ($field_name) {
case 'url':
$this->addSharedTableFieldIndex($storage_definition, $schema, TRUE, 255);
@@ -123,14 +123,14 @@ class OpmlFeedAdd extends FormBase {
}
catch (RequestException $e) {
$this->logger('aggregator')->warning('Failed to download OPML file due to "%error".', ['%error' => $e->getMessage()]);
drupal_set_message($this->t('Failed to download OPML file due to "%error".', ['%error' => $e->getMessage()]));
$this->messenger()->addStatus($this->t('Failed to download OPML file due to "%error".', ['%error' => $e->getMessage()]));
return;
}
}
$feeds = $this->parseOpml($data);
if (empty($feeds)) {
drupal_set_message($this->t('No new feed has been added.'));
$this->messenger()->addStatus($this->t('No new feed has been added.'));
return;
}
@@ -138,7 +138,7 @@ class OpmlFeedAdd extends FormBase {
foreach ($feeds as $feed) {
// Ensure URL is valid.
if (!UrlHelper::isValid($feed['url'], TRUE)) {
drupal_set_message($this->t('The URL %url is invalid.', ['%url' => $feed['url']]), 'warning');
$this->messenger()->addWarning($this->t('The URL %url is invalid.', ['%url' => $feed['url']]));
continue;
}
@@ -153,11 +153,11 @@ class OpmlFeedAdd extends FormBase {
$result = $this->feedStorage->loadMultiple($ids);
foreach ($result as $old) {
if (strcasecmp($old->label(), $feed['title']) == 0) {
drupal_set_message($this->t('A feed named %title already exists.', ['%title' => $old->label()]), 'warning');
$this->messenger()->addWarning($this->t('A feed named %title already exists.', ['%title' => $old->label()]));
continue 2;
}
if (strcasecmp($old->getUrl(), $feed['url']) == 0) {
drupal_set_message($this->t('A feed with the URL %url already exists.', ['%url' => $old->getUrl()]), 'warning');
$this->messenger()->addWarning($this->t('A feed with the URL %url already exists.', ['%url' => $old->getUrl()]));
continue 2;
}
}
@@ -3,7 +3,7 @@
namespace Drupal\aggregator\Form;
use Drupal\aggregator\Plugin\AggregatorPluginManager;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\PluginFormInterface;
@@ -68,7 +68,7 @@ class SettingsForm extends ConfigFormBase {
// Get all available fetcher, parser and processor definitions.
foreach (['fetcher', 'parser', 'processor'] as $type) {
foreach ($this->managers[$type]->getDefinitions() as $id => $definition) {
$this->definitions[$type][$id] = SafeMarkup::format('@title <span class="description">@description</span>', ['@title' => $definition['title'], '@description' => $definition['description']]);
$this->definitions[$type][$id] = new FormattableMarkup('@title <span class="description">@description</span>', ['@title' => $definition['title'], '@description' => $definition['description']]);
}
}
}
@@ -17,7 +17,7 @@ class ItemStorageSchema extends SqlContentEntityStorageSchema {
$schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping);
$field_name = $storage_definition->getName();
if ($table_name == 'aggregator_item') {
if ($table_name == $this->storage->getBaseTable()) {
switch ($field_name) {
case 'timestamp':
$this->addSharedTableFieldIndex($storage_definition, $schema, TRUE);
@@ -57,7 +57,6 @@ class AggregatorFeedBlock extends BlockBase implements ContainerFactoryPluginInt
$this->itemStorage = $item_storage;
}
/**
* {@inheritdoc}
*/
@@ -71,7 +70,6 @@ class AggregatorFeedBlock extends BlockBase implements ContainerFactoryPluginInt
);
}
/**
* {@inheritdoc}
*/
@@ -21,6 +21,7 @@ use Drupal\Core\Url;
* )
*/
class AggregatorTitleFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
@@ -6,6 +6,7 @@ use Drupal\aggregator\Plugin\FetcherInterface;
use Drupal\aggregator\FeedInterface;
use Drupal\Component\Datetime\DateTimePlus;
use Drupal\Core\Http\ClientFactory;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Request;
@@ -42,6 +43,13 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
*/
protected $logger;
/**
* The messenger.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* Constructs a DefaultFetcher object.
*
@@ -49,10 +57,13 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
* A Guzzle client object.
* @param \Psr\Log\LoggerInterface $logger
* A logger instance.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger.
*/
public function __construct(ClientFactory $http_client_factory, LoggerInterface $logger) {
public function __construct(ClientFactory $http_client_factory, LoggerInterface $logger, MessengerInterface $messenger) {
$this->httpClientFactory = $http_client_factory;
$this->logger = $logger;
$this->messenger = $messenger;
}
/**
@@ -61,7 +72,8 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$container->get('http_client_factory'),
$container->get('logger.factory')->get('aggregator')
$container->get('logger.factory')->get('aggregator'),
$container->get('messenger')
);
}
@@ -88,7 +100,7 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
'allow_redirects' => [
'on_redirect' => function (RequestInterface $request, ResponseInterface $response, UriInterface $uri) use (&$actual_uri) {
$actual_uri = (string) $uri;
}
},
],
])->send($request);
@@ -115,7 +127,7 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
}
catch (RequestException $e) {
$this->logger->warning('The feed from %site seems to be broken because of error "%error".', ['%site' => $feed->label(), '%error' => $e->getMessage()]);
drupal_set_message(t('The feed from %site seems to be broken because of error "%error".', ['%site' => $feed->label(), '%error' => $e->getMessage()]), 'warning');
$this->messenger->addWarning(t('The feed from %site seems to be broken because of error "%error".', ['%site' => $feed->label(), '%error' => $e->getMessage()]));
return FALSE;
}
}
@@ -4,6 +4,7 @@ namespace Drupal\aggregator\Plugin\aggregator\parser;
use Drupal\aggregator\Plugin\ParserInterface;
use Drupal\aggregator\FeedInterface;
use Drupal\Core\Messenger\MessengerTrait;
use Zend\Feed\Reader\Reader;
use Zend\Feed\Reader\Exception\ExceptionInterface;
@@ -20,6 +21,8 @@ use Zend\Feed\Reader\Exception\ExceptionInterface;
*/
class DefaultParser implements ParserInterface {
use MessengerTrait;
/**
* {@inheritdoc}
*/
@@ -31,7 +34,7 @@ class DefaultParser implements ParserInterface {
}
catch (ExceptionInterface $e) {
watchdog_exception('aggregator', $e);
drupal_set_message(t('The feed from %site seems to be broken because of error "%error".', ['%site' => $feed->label(), '%error' => $e->getMessage()]), 'error');
$this->messenger()->addError(t('The feed from %site seems to be broken because of error "%error".', ['%site' => $feed->label(), '%error' => $e->getMessage()]));
return FALSE;
}
@@ -3,15 +3,16 @@
namespace Drupal\aggregator\Plugin\aggregator\processor;
use Drupal\aggregator\Entity\Item;
use Drupal\aggregator\FeedInterface;
use Drupal\aggregator\ItemStorageInterface;
use Drupal\aggregator\Plugin\AggregatorPluginSettingsBase;
use Drupal\aggregator\Plugin\ProcessorInterface;
use Drupal\aggregator\FeedInterface;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Form\ConfigFormBaseTrait;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Routing\UrlGeneratorTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -28,6 +29,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
* )
*/
class DefaultProcessor extends AggregatorPluginSettingsBase implements ProcessorInterface, ContainerFactoryPluginInterface {
use ConfigFormBaseTrait;
use UrlGeneratorTrait;
@@ -52,6 +54,13 @@ class DefaultProcessor extends AggregatorPluginSettingsBase implements Processor
*/
protected $dateFormatter;
/**
* The messenger.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* Constructs a DefaultProcessor object.
*
@@ -67,11 +76,14 @@ class DefaultProcessor extends AggregatorPluginSettingsBase implements Processor
* The entity storage for feed items.
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
* The date formatter service.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config, ItemStorageInterface $item_storage, DateFormatterInterface $date_formatter) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config, ItemStorageInterface $item_storage, DateFormatterInterface $date_formatter, MessengerInterface $messenger) {
$this->configFactory = $config;
$this->itemStorage = $item_storage;
$this->dateFormatter = $date_formatter;
$this->messenger = $messenger;
// @todo Refactor aggregator plugins to ConfigEntity so merging
// the configuration here is not needed.
parent::__construct($configuration + $this->getConfiguration(), $plugin_id, $plugin_definition);
@@ -87,7 +99,8 @@ class DefaultProcessor extends AggregatorPluginSettingsBase implements Processor
$plugin_definition,
$container->get('config.factory'),
$container->get('entity_type.manager')->getStorage('aggregator_item'),
$container->get('date.formatter')
$container->get('date.formatter'),
$container->get('messenger')
);
}
@@ -231,7 +244,7 @@ class DefaultProcessor extends AggregatorPluginSettingsBase implements Processor
$this->itemStorage->delete($items);
}
// @todo This should be moved out to caller with a different message maybe.
drupal_set_message(t('The news items from %site have been deleted.', ['%site' => $feed->label()]));
$this->messenger->addStatus(t('The news items from %site have been deleted.', ['%site' => $feed->label()]));
}
/**
@@ -23,7 +23,7 @@ class Fid extends NumericArgument {
protected $entityManager;
/**
* Constructs a Drupal\Component\Plugin\PluginBase object.
* Constructs a \Drupal\aggregator\Plugin\views\argument\Fid object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
@@ -23,7 +23,7 @@ class Iid extends NumericArgument {
protected $entityManager;
/**
* Constructs a Drupal\Component\Plugin\PluginBase object.
* Constructs a \Drupal\aggregator\Plugin\views\argument\Iid object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
@@ -5,5 +5,5 @@ package: Testing
version: VERSION
core: 8.x
dependencies:
- aggregator
- views
- drupal:aggregator
- drupal:views
@@ -60,7 +60,7 @@ class AddFeedTest extends AggregatorTestBase {
$this->assertNoRaw('Test feed title <script>alert(123);</script>');
// Ensure the feed icon title is escaped.
$this->assertTrue(strpos(str_replace(["\n", "\r"], '', $this->getRawContent()), 'class="feed-icon"> Subscribe to Test feed title &lt;script&gt;alert(123);&lt;/script&gt; feed</a>') !== FALSE);
$this->assertTrue(strpos(str_replace(["\n", "\r"], '', $this->getSession()->getPage()->getContent()), 'class="feed-icon"> Subscribe to Test feed title &lt;script&gt;alert(123);&lt;/script&gt; feed</a>') !== FALSE);
}
/**
@@ -2,7 +2,7 @@
namespace Drupal\Tests\aggregator\Functional;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\views\Entity\View;
/**
@@ -114,7 +114,7 @@ class AggregatorRenderingTest extends AggregatorTestBase {
// Find the expected read_more link on the sources page.
$href = $feed->url();
$links = $this->xpath('//a[@href = :href]', [':href' => $href]);
$this->assertTrue(isset($links[0]), SafeMarkup::format('Link to href %href found.', ['%href' => $href]));
$this->assertTrue(isset($links[0]), new FormattableMarkup('Link to href %href found.', ['%href' => $href]));
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
$cache_tags = explode(' ', $cache_tags_header);
$this->assertTrue(in_array('aggregator_feed:' . $feed->id(), $cache_tags));
@@ -8,6 +8,7 @@ namespace Drupal\Tests\aggregator\Functional;
* @group aggregator
*/
class DeleteFeedItemTest extends AggregatorTestBase {
/**
* Tests running "delete items" from 'admin/config/services/aggregator' page.
*/
@@ -40,7 +40,7 @@ class DeleteFeedTest extends AggregatorTestBase {
// Check feed source.
$this->drupalGet('aggregator/sources/' . $feed1->id());
$this->assertResponse(404, 'Deleted feed source does not exists.');
$this->assertResponse(404, 'Deleted feed source does not exist.');
// Check database for feed.
$result = db_query("SELECT COUNT(*) FROM {aggregator_feed} WHERE title = :title AND url = :url", [':title' => $feed1->label(), ':url' => $feed1->getUrl()])->fetchField();
@@ -3,7 +3,7 @@
namespace Drupal\Tests\aggregator\Functional;
use Drupal\aggregator\Entity\Feed;
use Drupal\system\Tests\Entity\EntityWithUriCacheTagsTestBase;
use Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\hal\Functional\EntityResource\Feed;
namespace Drupal\Tests\aggregator\Functional\Hal;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\hal\Functional\EntityResource\Feed;
namespace Drupal\Tests\aggregator\Functional\Hal;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\hal\Functional\EntityResource\Feed;
namespace Drupal\Tests\aggregator\Functional\Hal;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
@@ -1,18 +1,13 @@
<?php
namespace Drupal\Tests\hal\Functional\EntityResource\Term;
namespace Drupal\Tests\aggregator\Functional\Hal;
use Drupal\Tests\aggregator\Functional\Rest\FeedResourceTestBase;
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\Term\TermResourceTestBase;
/**
* @group hal
*/
class TermHalJsonAnonTest extends TermResourceTestBase {
abstract class FeedHalJsonTestBase extends FeedResourceTestBase {
use HalEntityNormalizationTrait;
use AnonResourceTestTrait;
/**
* {@inheritdoc}
@@ -40,10 +35,10 @@ class TermHalJsonAnonTest extends TermResourceTestBase {
return $normalization + [
'_links' => [
'self' => [
'href' => $this->baseUrl . '/llama?_format=hal_json',
'href' => $this->baseUrl . '/aggregator/sources/1?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
'href' => $this->baseUrl . '/rest/type/aggregator_feed/aggregator_feed',
],
],
];
@@ -56,7 +51,7 @@ class TermHalJsonAnonTest extends TermResourceTestBase {
return parent::getNormalizedPostEntity() + [
'_links' => [
'type' => [
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
'href' => $this->baseUrl . '/rest/type/aggregator_feed/aggregator_feed',
],
],
];
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\hal\Functional\EntityResource\Item;
namespace Drupal\Tests\aggregator\Functional\Hal;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\hal\Functional\EntityResource\Item;
namespace Drupal\Tests\aggregator\Functional\Hal;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\hal\Functional\EntityResource\Item;
namespace Drupal\Tests\aggregator\Functional\Hal;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
@@ -0,0 +1,100 @@
<?php
namespace Drupal\Tests\aggregator\Functional\Hal;
use Drupal\aggregator\Entity\Feed;
use Drupal\Tests\aggregator\Functional\Rest\ItemResourceTestBase;
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* ResourceTestBase for Item entity.
*/
abstract class ItemHalJsonTestBase extends ItemResourceTestBase {
use HalEntityNormalizationTrait;
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
$default_normalization = parent::getExpectedNormalizedEntity();
$normalization = $this->applyHalFieldNormalization($default_normalization);
$feed = Feed::load($this->entity->getFeedId());
return $normalization + [
'_embedded' => [
$this->baseUrl . '/rest/relation/aggregator_item/aggregator_item/fid' => [
[
'_links' => [
'self' => [
'href' => $this->baseUrl . '/aggregator/sources/1?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/aggregator_feed/aggregator_feed',
],
],
'uuid' => [
[
'value' => $feed->uuid(),
],
],
],
],
],
'_links' => [
'self' => [
'href' => '',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/aggregator_item/aggregator_item',
],
$this->baseUrl . '/rest/relation/aggregator_item/aggregator_item/fid' => [
[
'href' => $this->baseUrl . '/aggregator/sources/' . $feed->id() . '?_format=hal_json',
],
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return parent::getNormalizedPostEntity() + [
'_links' => [
'type' => [
'href' => $this->baseUrl . '/rest/type/aggregator_item/aggregator_item',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedCacheContexts() {
return [
'url.site',
'user.permissions',
];
}
}
@@ -5,7 +5,7 @@ namespace Drupal\Tests\aggregator\Functional;
use Drupal\aggregator\Entity\Feed;
use Drupal\aggregator\Entity\Item;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\system\Tests\Entity\EntityCacheTagsTestBase;
use Drupal\Tests\system\Functional\Entity\EntityCacheTagsTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Feed;
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Feed;
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Feed;
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
@@ -0,0 +1,192 @@
<?php
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
use Drupal\aggregator\Entity\Feed;
abstract class FeedResourceTestBase extends EntityResourceTestBase {
use BcTimestampNormalizerUnixTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['aggregator'];
/**
* {@inheritdoc}
*/
public static $entityTypeId = 'aggregator_feed';
/**
* {@inheritdoc}
*/
protected static $patchProtectedFieldNames = [];
/**
* {@inheritdoc}
*/
protected static $uniqueFieldNames = ['url'];
/**
* {@inheritdoc}
*/
protected function setUpAuthorization($method) {
switch ($method) {
case 'GET':
$this->grantPermissionsToTestedRole(['access news feeds']);
break;
case 'POST':
case 'PATCH':
case 'DELETE':
$this->grantPermissionsToTestedRole(['administer news feeds']);
break;
}
}
/**
* {@inheritdoc}
*/
public function createEntity() {
$feed = Feed::create();
$feed->set('fid', 1)
->set('uuid', 'abcdefg')
->setTitle('Feed')
->setUrl('http://example.com/rss.xml')
->setDescription('Feed Resource Test 1')
->setRefreshRate(900)
->setLastCheckedTime(123456789)
->setQueuedTime(123456789)
->setWebsiteUrl('http://example.com')
->setImage('http://example.com/feed_logo')
->setHash('abcdefg')
->setEtag('hijklmn')
->setLastModified(123456789)
->save();
return $feed;
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
return [
'uuid' => [
[
'value' => 'abcdefg',
],
],
'fid' => [
[
'value' => 1,
],
],
'langcode' => [
[
'value' => 'en',
],
],
'url' => [
[
'value' => 'http://example.com/rss.xml',
],
],
'title' => [
[
'value' => 'Feed',
],
],
'refresh' => [
[
'value' => 900,
],
],
'checked' => [
$this->formatExpectedTimestampItemValues(123456789),
],
'queued' => [
$this->formatExpectedTimestampItemValues(123456789),
],
'link' => [
[
'value' => 'http://example.com',
],
],
'description' => [
[
'value' => 'Feed Resource Test 1',
],
],
'image' => [
[
'value' => 'http://example.com/feed_logo',
],
],
'hash' => [
[
'value' => 'abcdefg',
],
],
'etag' => [
[
'value' => 'hijklmn',
],
],
'modified' => [
$this->formatExpectedTimestampItemValues(123456789),
],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return [
'title' => [
[
'value' => 'Feed Resource Post Test',
],
],
'url' => [
[
'value' => 'http://example.com/feed',
],
],
'refresh' => [
[
'value' => 900,
],
],
'description' => [
[
'value' => 'Feed Resource Post Test Description',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessMessage($method) {
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
return parent::getExpectedUnauthorizedAccessMessage($method);
}
switch ($method) {
case 'GET':
return "The 'access news feeds' permission is required.";
case 'POST':
case 'PATCH':
case 'DELETE':
return "The 'administer news feeds' permission is required.";
default:
return parent::getExpectedUnauthorizedAccessMessage($method);
}
}
}
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Feed;
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Feed;
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Feed;
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Item;
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Item;
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Item;
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
@@ -0,0 +1,192 @@
<?php
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\aggregator\Entity\Feed;
use Drupal\aggregator\Entity\Item;
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
/**
* ResourceTestBase for Item entity.
*/
abstract class ItemResourceTestBase extends EntityResourceTestBase {
use BcTimestampNormalizerUnixTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['aggregator'];
/**
* {@inheritdoc}
*/
protected static $entityTypeId = 'aggregator_item';
/**
* {@inheritdoc}
*/
protected static $patchProtectedFieldNames = [];
/**
* The Item entity.
*
* @var \Drupal\aggregator\ItemInterface
*/
protected $entity;
/**
* {@inheritdoc}
*/
protected function setUpAuthorization($method) {
switch ($method) {
case 'GET':
$this->grantPermissionsToTestedRole(['access news feeds']);
break;
case 'POST':
case 'PATCH':
case 'DELETE':
$this->grantPermissionsToTestedRole(['administer news feeds']);
break;
}
}
/**
* {@inheritdoc}
*/
protected function createEntity() {
// Create a "Camelids" feed.
$feed = Feed::create([
'title' => 'Camelids',
'url' => 'https://groups.drupal.org/not_used/167169',
'refresh' => 900,
'checked' => 1389919932,
'description' => 'Drupal Core Group feed',
]);
$feed->save();
// Create a "Llama" item.
$item = Item::create();
$item->setTitle('Llama')
->setFeedId($feed->id())
->setLink('https://www.drupal.org/')
->setPostedTime(123456789)
->save();
return $item;
}
/**
* {@inheritdoc}
*/
protected function createAnotherEntity() {
$entity = $this->entity->createDuplicate();
$entity->setLink('https://www.example.org/');
$label_key = $entity->getEntityType()->getKey('label');
if ($label_key) {
$entity->set($label_key, $entity->label() . '_dupe');
}
$entity->save();
return $entity;
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
$feed = Feed::load($this->entity->getFeedId());
return [
'iid' => [
[
'value' => 1,
],
],
'langcode' => [
[
'value' => 'en',
],
],
'fid' => [
[
'target_id' => 1,
'target_type' => 'aggregator_feed',
'target_uuid' => $feed->uuid(),
'url' => base_path() . 'aggregator/sources/1',
],
],
'title' => [
[
'value' => 'Llama',
],
],
'link' => [
[
'value' => 'https://www.drupal.org/',
],
],
'author' => [],
'description' => [],
'timestamp' => [
$this->formatExpectedTimestampItemValues(123456789),
],
'guid' => [],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return [
'fid' => [
[
'target_id' => 1,
],
],
'title' => [
[
'value' => 'Llama',
],
],
'link' => [
[
'value' => 'https://www.drupal.org/',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedCacheContexts() {
// @see ::createEntity()
return ['user.permissions'];
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessMessage($method) {
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
return parent::getExpectedUnauthorizedAccessMessage($method);
}
switch ($method) {
case 'GET':
return "The 'access news feeds' permission is required.";
case 'POST':
case 'PATCH':
case 'DELETE':
return "The 'administer news feeds' permission is required.";
default:
return parent::getExpectedUnauthorizedAccessMessage($method);
}
}
}
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Item;
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Item;
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
@@ -1,6 +1,6 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Item;
namespace Drupal\Tests\aggregator\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
@@ -8,6 +8,7 @@ use Drupal\FunctionalTests\Update\UpdatePathTestBase;
* Tests that node settings are properly updated during database updates.
*
* @group aggregator
* @group legacy
*/
class AggregatorUpdateTest extends UpdatePathTestBase {
@@ -10,6 +10,7 @@ use Drupal\aggregator\Entity\Feed;
* @group aggregator
*/
class UpdateFeedItemTest extends AggregatorTestBase {
/**
* Tests running "update items" from 'admin/config/services/aggregator' page.
*/
@@ -8,6 +8,7 @@ namespace Drupal\Tests\aggregator\Functional;
* @group aggregator
*/
class UpdateFeedTest extends AggregatorTestBase {
/**
* Creates a feed and attempts to update it.
*/
@@ -4,6 +4,7 @@ namespace Drupal\Tests\aggregator\Unit\Plugin;
use Drupal\aggregator\Form\SettingsForm;
use Drupal\Core\Form\FormState;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Tests\UnitTestCase;
/**
@@ -55,6 +56,10 @@ class AggregatorPluginSettingsBaseTest extends UnitTestCase {
->will($this->returnValue(['aggregator_test' => ['title' => '', 'description' => '']]));
}
/** @var \Drupal\Core\Messenger\MessengerInterface|\PHPUnit_Framework_MockObject_MockBuilder $messenger */
$messenger = $this->createMock(MessengerInterface::class);
$messenger->expects($this->any())->method('addMessage');
$this->settingsForm = new SettingsForm(
$this->configFactory,
$this->managers['fetcher'],
@@ -62,6 +67,7 @@ class AggregatorPluginSettingsBaseTest extends UnitTestCase {
$this->managers['processor'],
$this->getStringTranslationStub()
);
$this->settingsForm->setMessenger($messenger);
}
/**
@@ -104,11 +110,3 @@ class AggregatorPluginSettingsBaseTest extends UnitTestCase {
}
}
// @todo Delete after https://www.drupal.org/node/2278383 is in.
namespace Drupal\Core\Form;
if (!function_exists('drupal_set_message')) {
function drupal_set_message() {
}
}
@@ -31,7 +31,7 @@ class AutomatedCron implements EventSubscriberInterface {
/**
* The state key value store.
*
* @var \Drupal\Core\State\StateInterface;
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
+2 -2
View File
@@ -2,7 +2,7 @@
namespace Drupal\ban;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
@@ -45,7 +45,7 @@ class BanMiddleware implements HttpKernelInterface {
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
$ip = $request->getClientIp();
if ($this->banIpManager->isBanned($ip)) {
return new Response(SafeMarkup::format('@ip has been banned', ['@ip' => $ip]), 403);
return new Response(new FormattableMarkup('@ip has been banned', ['@ip' => $ip]), 403);
}
return $this->httpKernel->handle($request, $type, $catch);
}
+1 -1
View File
@@ -120,7 +120,7 @@ class BanAdmin extends FormBase {
public function submitForm(array &$form, FormStateInterface $form_state) {
$ip = trim($form_state->getValue('ip'));
$this->ipManager->banIp($ip);
drupal_set_message($this->t('The IP address %ip has been banned.', ['%ip' => $ip]));
$this->messenger()->addStatus($this->t('The IP address %ip has been banned.', ['%ip' => $ip]));
$form_state->setRedirect('ban.admin_page');
}
+1 -1
View File
@@ -96,7 +96,7 @@ class BanDelete extends ConfirmFormBase {
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->ipManager->unbanIp($this->banIp);
$this->logger('user')->notice('Deleted %ip', ['%ip' => $this->banIp]);
drupal_set_message($this->t('The IP address %ip was deleted.', ['%ip' => $this->banIp]));
$this->messenger()->addStatus($this->t('The IP address %ip was deleted.', ['%ip' => $this->banIp]));
$form_state->setRedirectUrl($this->getCancelUrl());
}
@@ -27,7 +27,7 @@ class BlockedIpsTest extends MigrateSqlSourceTestBase {
[
'iid' => 1,
'ip' => '127.0.0.1',
]
],
];
$tests[0]['expected_data'] = [
[
+1 -1
View File
@@ -5,4 +5,4 @@ package: Web services
version: VERSION
core: 8.x
dependencies:
- user
- drupal:user
@@ -2,7 +2,7 @@
namespace Drupal\basic_auth\Authentication\Provider;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Authentication\AuthenticationProviderInterface;
use Drupal\Core\Authentication\AuthenticationProviderChallengeInterface;
use Drupal\Core\Cache\CacheableMetadata;
@@ -129,7 +129,7 @@ class BasicAuth implements AuthenticationProviderInterface, AuthenticationProvid
public function challengeException(Request $request, \Exception $previous) {
$site_config = $this->configFactory->get('system.site');
$site_name = $site_config->get('name');
$challenge = SafeMarkup::format('Basic realm="@realm"', [
$challenge = new FormattableMarkup('Basic realm="@realm"', [
'@realm' => !empty($site_name) ? $site_name : 'Access restricted',
]);
@@ -2,7 +2,7 @@
namespace Drupal\Tests\basic_auth\Functional;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Url;
use Drupal\Tests\basic_auth\Traits\BasicAuthTestTrait;
use Drupal\language\Entity\ConfigurableLanguage;
@@ -50,7 +50,7 @@ class BasicAuthTest extends BrowserTestBase {
$this->mink->resetSessions();
$this->drupalGet($url);
$this->assertEqual($this->drupalGetHeader('WWW-Authenticate'), SafeMarkup::format('Basic realm="@realm"', ['@realm' => \Drupal::config('system.site')->get('name')]));
$this->assertEqual($this->drupalGetHeader('WWW-Authenticate'), new FormattableMarkup('Basic realm="@realm"', ['@realm' => \Drupal::config('system.site')->get('name')]));
$this->assertResponse('401', 'Not authenticated on the route that allows only basic_auth. Prompt to authenticate received.');
$this->drupalGet('admin');
+58 -54
View File
@@ -3,49 +3,7 @@
* Renders BigPipe placeholders using Drupal's Ajax system.
*/
(function ($, Drupal, drupalSettings) {
/**
* Executes Ajax commands in <script type="application/vnd.drupal-ajax"> tag.
*
* These Ajax commands replace placeholders with HTML and load missing CSS/JS.
*
* @param {number} index
* Current index.
* @param {HTMLScriptElement} placeholderReplacement
* Script tag created by BigPipe.
*/
function bigPipeProcessPlaceholderReplacement(index, placeholderReplacement) {
const placeholderId = placeholderReplacement.getAttribute('data-big-pipe-replacement-for-placeholder-with-id');
const content = this.textContent.trim();
// Ignore any placeholders that are not in the known placeholder list. Used
// to avoid someone trying to XSS the site via the placeholdering mechanism.
if (typeof drupalSettings.bigPipePlaceholderIds[placeholderId] !== 'undefined') {
const response = mapTextContentToAjaxResponse(content);
// If we try to parse the content too early (when the JSON containing Ajax
// commands is still arriving), textContent will be empty or incomplete.
if (response === false) {
/**
* Mark as unprocessed so this will be retried later.
* @see bigPipeProcessDocument()
*/
$(this).removeOnce('big-pipe');
}
else {
// Create a Drupal.Ajax object without associating an element, a
// progress indicator or a URL.
const ajaxObject = Drupal.ajax({
url: '',
base: false,
element: false,
progress: false,
});
// Then, simulate an AJAX response having arrived, and let the Ajax
// system handle it.
ajaxObject.success(response, 'success');
}
}
}
(function($, Drupal, drupalSettings) {
/**
* Maps textContent of <script type="application/vnd.drupal-ajax"> to an AJAX response.
*
@@ -62,12 +20,64 @@
try {
return JSON.parse(content);
}
catch (e) {
} catch (e) {
return false;
}
}
/**
* Executes Ajax commands in <script type="application/vnd.drupal-ajax"> tag.
*
* These Ajax commands replace placeholders with HTML and load missing CSS/JS.
*
* @param {number} index
* Current index.
* @param {HTMLScriptElement} placeholderReplacement
* Script tag created by BigPipe.
*/
function bigPipeProcessPlaceholderReplacement(index, placeholderReplacement) {
const placeholderId = placeholderReplacement.getAttribute(
'data-big-pipe-replacement-for-placeholder-with-id',
);
const content = this.textContent.trim();
// Ignore any placeholders that are not in the known placeholder list. Used
// to avoid someone trying to XSS the site via the placeholdering mechanism.
if (
typeof drupalSettings.bigPipePlaceholderIds[placeholderId] !== 'undefined'
) {
const response = mapTextContentToAjaxResponse(content);
// If we try to parse the content too early (when the JSON containing Ajax
// commands is still arriving), textContent will be empty or incomplete.
if (response === false) {
/**
* Mark as unprocessed so this will be retried later.
* @see bigPipeProcessDocument()
*/
$(this).removeOnce('big-pipe');
} else {
// Create a Drupal.Ajax object without associating an element, a
// progress indicator or a URL.
const ajaxObject = Drupal.ajax({
url: '',
base: false,
element: false,
progress: false,
});
// Then, simulate an AJAX response having arrived, and let the Ajax
// system handle it.
ajaxObject.success(response, 'success');
}
}
}
// The frequency with which to check for newly arrived BigPipe placeholders.
// Hence 50 ms means we check 20 times per second. Setting this to 100 ms or
// more would cause the user to see content appear noticeably slower.
const interval = drupalSettings.bigPipeInterval || 50;
// The internal ID to contain the watcher service.
let timeoutID;
/**
* Processes a streamed HTML document receiving placeholder replacements.
*
@@ -85,7 +95,8 @@
return false;
}
$(context).find('script[data-big-pipe-replacement-for-placeholder-with-id]')
$(context)
.find('script[data-big-pipe-replacement-for-placeholder-with-id]')
.once('big-pipe')
.each(bigPipeProcessPlaceholderReplacement);
@@ -109,13 +120,6 @@
}, interval);
}
// The frequency with which to check for newly arrived BigPipe placeholders.
// Hence 50 ms means we check 20 times per second. Setting this to 100 ms or
// more would cause the user to see content appear noticeably slower.
const interval = drupalSettings.bigPipeInterval || 50;
// The internal ID to contain the watcher service.
let timeoutID;
bigPipeProcess();
// If something goes wrong, make sure everything is cleaned up and has had a
@@ -126,4 +130,4 @@
}
bigPipeProcessDocument(document);
});
}(jQuery, Drupal, drupalSettings));
})(jQuery, Drupal, drupalSettings);
+14 -14
View File
@@ -6,6 +6,18 @@
**/
(function ($, Drupal, drupalSettings) {
function mapTextContentToAjaxResponse(content) {
if (content === '') {
return false;
}
try {
return JSON.parse(content);
} catch (e) {
return false;
}
}
function bigPipeProcessPlaceholderReplacement(index, placeholderReplacement) {
var placeholderId = placeholderReplacement.getAttribute('data-big-pipe-replacement-for-placeholder-with-id');
var content = this.textContent.trim();
@@ -28,17 +40,9 @@
}
}
function mapTextContentToAjaxResponse(content) {
if (content === '') {
return false;
}
var interval = drupalSettings.bigPipeInterval || 50;
try {
return JSON.parse(content);
} catch (e) {
return false;
}
}
var timeoutID = void 0;
function bigPipeProcessDocument(context) {
if (!context.querySelector('script[data-big-pipe-event="start"]')) {
@@ -65,10 +69,6 @@
}, interval);
}
var interval = drupalSettings.bigPipeInterval || 50;
var timeoutID = void 0;
bigPipeProcess();
$(window).on('load', function () {
+2 -2
View File
@@ -730,8 +730,8 @@ EOF;
// 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.
// change the way \Drupal\Core\Messenger\MessengerInterface::addMessage()
// 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.
@@ -39,7 +39,7 @@ class BigPipeRegressionTestController {
public static function currentTime() {
return [
'#markup' => '<time datetime="' . date('Y-m-d', time()) . '"></time>',
'#cache' => ['max-age' => 0]
'#cache' => ['max-age' => 0],
];
}
@@ -23,4 +23,3 @@ big_pipe_test_multi_occurrence:
_title: 'BigPipe test multiple occurrences of the same placeholder'
requirements:
_access: 'TRUE'
@@ -52,7 +52,7 @@ class BigPipePlaceholderTestCases {
[
'#lazy_builder' => [
'Drupal\Core\Render\Element\StatusMessages::renderMessages',
[NULL]
[NULL],
],
]
);
@@ -129,7 +129,7 @@ class BigPipePlaceholderTestCases {
[
'#lazy_builder' => [
'route_processor_csrf:renderPlaceholderCsrfToken',
['admin/config/user-interface/shortcut/manage/default/add-link-inline']
['admin/config/user-interface/shortcut/manage/default/add-link-inline'],
],
]
);
@@ -155,14 +155,14 @@ class BigPipePlaceholderTestCases {
'#attached' => [
'placeholders' => [
'<hello' => ['#lazy_builder' => ['\Drupal\big_pipe_test\BigPipeTestController::helloOrYarhar', []]],
]
],
],
],
'<hello',
[
'#lazy_builder' => [
'hello_or_yarhar',
[]
[],
],
]
);
@@ -188,9 +188,9 @@ class BigPipePlaceholderTestCases {
'#pre_render' => [
'\Drupal\big_pipe_test\BigPipeTestController::currentTime',
],
]
]
]
],
],
],
],
'<time>CURRENT TIME</time>',
[
@@ -24,7 +24,7 @@ class BigPipeTestController {
if ($has_session) {
// Only set a message if a session already exists, otherwise we always
// trigger a session, which means we can't test no-session requests.
drupal_set_message('Hello from BigPipe!');
\Drupal::messenger()->addStatus('Hello from BigPipe!');
}
$build['html'] = $cases['html']->renderArray;
@@ -91,7 +91,7 @@ class BigPipeTestController {
public static function currentTime() {
return [
'#markup' => '<time datetime="' . date('Y-m-d', 668948400) . '"></time>',
'#cache' => ['max-age' => 0]
'#cache' => ['max-age' => 0],
];
}
@@ -156,7 +156,7 @@ class BigPipeTest extends BrowserTestBase {
$this->drupalGet(Url::fromRoute('big_pipe_test'));
$this->assertBigPipeResponseHeadersPresent();
$this->assertNoCacheTag('cache_tag_set_in_lazy_builder');
$this->assertSession()->responseHeaderNotContains('X-Drupal-Cache-Tags', 'cache_tag_set_in_lazy_builder');
$this->setCsrfTokenSeedInTestEnvironment();
$cases = $this->getTestCases();
@@ -205,7 +205,7 @@ class BigPipeTest extends BrowserTestBase {
$this->assertNoRaw(BigPipe::STOP_SIGNAL, 'BigPipe stop signal absent: error occurred before then.');
$this->assertNoRaw('</body>', 'Closing body tag absent: error occurred before then.');
// The exception is expected. Do not interpret it as a test failure.
unlink(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
unlink($this->root . '/' . $this->siteDirectory . '/error.log');
}
/**
@@ -236,7 +236,7 @@ class BigPipeTest extends BrowserTestBase {
$this->drupalGet(Url::fromRoute('big_pipe_test'));
$this->assertBigPipeResponseHeadersPresent();
$this->assertNoCacheTag('cache_tag_set_in_lazy_builder');
$this->assertSession()->responseHeaderNotContains('X-Drupal-Cache-Tags', 'cache_tag_set_in_lazy_builder');
$this->setCsrfTokenSeedInTestEnvironment();
$cases = $this->getTestCases();
@@ -273,7 +273,7 @@ class BigPipeTest extends BrowserTestBase {
$this->assertRaw('You are not allowed to say llamas are not cool!');
$this->assertNoRaw('</body>', 'Closing body tag absent: error occurred before then.');
// The exception is expected. Do not interpret it as a test failure.
unlink(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
unlink($this->root . '/' . $this->siteDirectory . '/error.log');
}
/**
@@ -296,7 +296,7 @@ class BigPipeTest extends BrowserTestBase {
$this->assertRaw('The count is 1.');
$this->assertNoRaw('The count is 2.');
$this->assertNoRaw('The count is 3.');
$raw_content = $this->getRawContent();
$raw_content = $this->getSession()->getPage()->getContent();
$this->assertTrue(substr_count($raw_content, $expected_placeholder_replacement) == 1, 'Only one placeholder replacement was found for the duplicate #lazy_builder arrays.');
// By calling performMetaRefresh() here, we simulate JavaScript being
@@ -357,7 +357,7 @@ class BigPipeTest extends BrowserTestBase {
// Verify expected placeholder.
$expected_placeholder_html = '<span data-big-pipe-placeholder-id="' . $big_pipe_placeholder_id . '"></span>';
$this->assertRaw($expected_placeholder_html, 'BigPipe placeholder for placeholder ID "' . $big_pipe_placeholder_id . '" found.');
$pos = strpos($this->getRawContent(), $expected_placeholder_html);
$pos = strpos($this->getSession()->getPage()->getContent(), $expected_placeholder_html);
$placeholder_positions[$pos] = $big_pipe_placeholder_id;
// Verify expected placeholder replacement.
$expected_placeholder_replacement = '<script type="application/vnd.drupal-ajax" data-big-pipe-replacement-for-placeholder-with-id="' . $big_pipe_placeholder_id . '">';
@@ -369,7 +369,7 @@ class BigPipeTest extends BrowserTestBase {
}
$this->assertEqual($expected_ajax_response, trim($result[0]->getText()));
$this->assertRaw($expected_placeholder_replacement);
$pos = strpos($this->getRawContent(), $expected_placeholder_replacement);
$pos = strpos($this->getSession()->getPage()->getContent(), $expected_placeholder_replacement);
$placeholder_replacement_positions[$pos] = $big_pipe_placeholder_id;
}
ksort($placeholder_positions, SORT_NUMERIC);
@@ -384,13 +384,13 @@ class BigPipeTest extends BrowserTestBase {
}
$this->assertEqual($expected_big_pipe_placeholders_with_replacements, array_filter($expected_big_pipe_placeholders));
$this->assertSetsEqual(array_keys($expected_big_pipe_placeholders_with_replacements), array_values($placeholder_replacement_positions));
$this->assertEqual(count($expected_big_pipe_placeholders_with_replacements), preg_match_all('/' . preg_quote('<script type="application/vnd.drupal-ajax" data-big-pipe-replacement-for-placeholder-with-id="', '/') . '/', $this->getRawContent()));
$this->assertEqual(count($expected_big_pipe_placeholders_with_replacements), preg_match_all('/' . preg_quote('<script type="application/vnd.drupal-ajax" data-big-pipe-replacement-for-placeholder-with-id="', '/') . '/', $this->getSession()->getPage()->getContent()));
$this->pass('Verifying BigPipe start/stop signals…', 'Debug');
$this->assertRaw(BigPipe::START_SIGNAL, 'BigPipe start signal present.');
$this->assertRaw(BigPipe::STOP_SIGNAL, 'BigPipe stop signal present.');
$start_signal_position = strpos($this->getRawContent(), BigPipe::START_SIGNAL);
$stop_signal_position = strpos($this->getRawContent(), BigPipe::STOP_SIGNAL);
$start_signal_position = strpos($this->getSession()->getPage()->getContent(), BigPipe::START_SIGNAL);
$stop_signal_position = strpos($this->getSession()->getPage()->getContent(), BigPipe::STOP_SIGNAL);
$this->assertTrue($start_signal_position < $stop_signal_position, 'BigPipe start signal appears before stop signal.');
$this->pass('Verifying BigPipe placeholder replacements and start/stop signals were streamed in the correct order…', 'Debug');
@@ -11,7 +11,7 @@ use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Core\Url;
use Drupal\editor\Entity\Editor;
use Drupal\filter\Entity\FilterFormat;
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\simpletest\ContentTypeCreationTrait;
use Drupal\simpletest\NodeCreationTrait;
@@ -20,7 +20,7 @@ use Drupal\simpletest\NodeCreationTrait;
*
* @group big_pipe
*/
class BigPipeRegressionTest extends JavascriptTestBase {
class BigPipeRegressionTest extends WebDriverTestBase {
use CommentTestTrait;
use ContentTypeCreationTrait;
+1 -1
View File
@@ -150,7 +150,7 @@ function hook_block_view_BASE_BLOCK_ID_alter(array &$build, \Drupal\Core\Block\B
*/
function hook_block_build_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block) {
// Add the 'user' cache context to some blocks.
if ($some_condition) {
if ($block->label() === 'some condition') {
$build['#cache']['contexts'][] = 'user';
}
}
+1 -1
View File
@@ -73,7 +73,7 @@ function block_update_8001() {
// their own updates.
$update_backup[$block->get('id')] = [
'missing_context_ids' => $backup_values,
'status' => $block->get('status')
'status' => $block->get('status'),
];
}
}
+5 -1
View File
@@ -145,7 +145,11 @@ function block_rebuild() {
// Disable blocks in invalid regions.
if (!isset($regions[$block->getRegion()])) {
if ($block->status()) {
drupal_set_message(t('The block %info was assigned to the invalid region %region and has been disabled.', ['%info' => $block_id, '%region' => $block->getRegion()]), 'warning');
\Drupal::messenger()
->addWarning(t('The block %info was assigned to the invalid region %region and has been disabled.', [
'%info' => $block_id,
'%region' => $block->getRegion(),
]));
}
$block
->setRegion(system_default_region($theme))
+1 -1
View File
@@ -60,7 +60,7 @@ function block_post_update_disable_blocks_with_missing_contexts() {
foreach ($blocks as $disabled_block_id => $disabled_block) {
$message .= '<li>' . t('@label (Visibility: @plugin_ids)', [
'@label' => $disabled_block->get('settings')['label'],
'@plugin_ids' => implode(', ', array_intersect_key($condition_plugin_id_label_map, array_flip(array_keys($block_update_8001[$disabled_block_id]['missing_context_ids']))))
'@plugin_ids' => implode(', ', array_intersect_key($condition_plugin_id_label_map, array_flip(array_keys($block_update_8001[$disabled_block_id]['missing_context_ids'])))),
]) . '</li>';
}
$message .= '</ul>';
+33 -16
View File
@@ -3,7 +3,7 @@
* Block admin behaviors.
*/
(function ($, Drupal, debounce) {
(function($, Drupal, debounce) {
/**
* Filters the block list by a text input search string.
*
@@ -33,7 +33,9 @@
* The jQuery event for the keyup event that triggered the filter.
*/
function filterBlockList(e) {
const query = $(e.target).val().toLowerCase();
const query = $(e.target)
.val()
.toLowerCase();
/**
* Shows or hides the block entry based on the query.
@@ -46,7 +48,11 @@
function toggleBlockEntry(index, label) {
const $label = $(label);
const $row = $label.parent().parent();
const textMatch = $label.text().toLowerCase().indexOf(query) !== -1;
const textMatch =
$label
.text()
.toLowerCase()
.indexOf(query) !== -1;
$row.toggle(textMatch);
}
@@ -60,10 +66,12 @@
'@count blocks are available in the modified list.',
),
);
}
else {
$filterRows.each(function (index) {
$(this).parent().parent().show();
} else {
$filterRows.each(function(index) {
$(this)
.parent()
.parent()
.show();
});
}
}
@@ -86,15 +94,24 @@
Drupal.behaviors.blockHighlightPlacement = {
attach(context, settings) {
if (settings.blockPlacement) {
$(context).find('[data-drupal-selector="edit-blocks"]').once('block-highlight').each(function () {
const $container = $(this);
// Just scrolling the document.body will not work in Firefox. The html
// element is needed as well.
$('html, body').animate({
scrollTop: ($('.js-block-placed').offset().top - $container.offset().top) + $container.scrollTop(),
}, 500);
});
$(context)
.find('[data-drupal-selector="edit-blocks"]')
.once('block-highlight')
.each(function() {
const $container = $(this);
// Just scrolling the document.body will not work in Firefox. The html
// element is needed as well.
$('html, body').animate(
{
scrollTop:
$('.js-block-placed').offset().top -
$container.offset().top +
$container.scrollTop(),
},
500,
);
});
}
},
};
}(jQuery, Drupal, Drupal.debounce));
})(jQuery, Drupal, Drupal.debounce);
+64 -24
View File
@@ -3,7 +3,7 @@
* Block behaviors.
*/
(function ($, window, Drupal) {
(function($, window, Drupal) {
/**
* Provide the summary information for the block settings vertical tabs.
*
@@ -32,7 +32,9 @@
*/
function checkboxesSummary(context) {
const vals = [];
const $checkboxes = $(context).find('input[type="checkbox"]:checked + label');
const $checkboxes = $(context).find(
'input[type="checkbox"]:checked + label',
);
const il = $checkboxes.length;
for (let i = 0; i < il; i++) {
vals.push($($checkboxes[i]).html());
@@ -43,10 +45,16 @@
return vals.join(', ');
}
$('[data-drupal-selector="edit-visibility-node-type"], [data-drupal-selector="edit-visibility-language"], [data-drupal-selector="edit-visibility-user-role"]').drupalSetSummary(checkboxesSummary);
$(
'[data-drupal-selector="edit-visibility-node-type"], [data-drupal-selector="edit-visibility-language"], [data-drupal-selector="edit-visibility-user-role"]',
).drupalSetSummary(checkboxesSummary);
$('[data-drupal-selector="edit-visibility-request-path"]').drupalSetSummary((context) => {
const $pages = $(context).find('textarea[name="visibility[request_path][pages]"]');
$(
'[data-drupal-selector="edit-visibility-request-path"]',
).drupalSetSummary(context => {
const $pages = $(context).find(
'textarea[name="visibility[request_path][pages]"]',
);
if (!$pages.val()) {
return Drupal.t('Not restricted');
}
@@ -70,7 +78,10 @@
Drupal.behaviors.blockDrag = {
attach(context, settings) {
// tableDrag is required and we should be on the blocks admin page.
if (typeof Drupal.tableDrag === 'undefined' || typeof Drupal.tableDrag.blocks === 'undefined') {
if (
typeof Drupal.tableDrag === 'undefined' ||
typeof Drupal.tableDrag.blocks === 'undefined'
) {
return;
}
@@ -83,19 +94,25 @@
* The jQuery object representing the table row.
*/
function checkEmptyRegions(table, rowObject) {
table.find('tr.region-message').each(function () {
table.find('tr.region-message').each(function() {
const $this = $(this);
// If the dragged row is in this region, but above the message row,
// swap it down one space.
if ($this.prev('tr').get(0) === rowObject.element) {
// Prevent a recursion problem when using the keyboard to move rows
// up.
if ((rowObject.method !== 'keyboard' || rowObject.direction === 'down')) {
if (
rowObject.method !== 'keyboard' ||
rowObject.direction === 'down'
) {
rowObject.swap('after', this);
}
}
// This region has become empty.
if ($this.next('tr').is(':not(.draggable)') || $this.next('tr').length === 0) {
if (
$this.next('tr').is(':not(.draggable)') ||
$this.next('tr').length === 0
) {
$this.removeClass('region-populated').addClass('region-empty');
}
// This region has become populated.
@@ -136,33 +153,40 @@
// Calculate minimum weight.
let weight = -Math.round(table.find('.draggable').length / 2);
// Update the block weights.
table.find(`.region-${region}-message`).nextUntil('.region-title')
.find('select.block-weight').val(() =>
table
.find(`.region-${region}-message`)
.nextUntil('.region-title')
.find('select.block-weight')
.val(
// Increment the weight before assigning it to prevent using the
// absolute minimum available weight. This way we always have an
// unused upper and lower bound, which makes manually setting the
// weights easier for users who prefer to do it that way.
++weight);
() => ++weight,
);
}
const table = $('#blocks');
// Get the blocks tableDrag object.
const tableDrag = Drupal.tableDrag.blocks;
// Add a handler for when a row is swapped, update empty regions.
tableDrag.row.prototype.onSwap = function (swappedRow) {
tableDrag.row.prototype.onSwap = function(swappedRow) {
checkEmptyRegions(table, this);
updateLastPlaced(table, this);
};
// Add a handler so when a row is dropped, update fields dropped into
// new regions.
tableDrag.onDrop = function () {
tableDrag.onDrop = function() {
const dragObject = this;
const $rowElement = $(dragObject.rowObject.element);
// Use "region-message" row instead of "region" row because
// "region-{region_name}-message" is less prone to regexp match errors.
const regionRow = $rowElement.prevAll('tr.region-message').get(0);
const regionName = regionRow.className.replace(/([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/, '$2');
const regionName = regionRow.className.replace(
/([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/,
'$2',
);
const regionField = $rowElement.find('select.block-region-select');
// Check whether the newly picked region is available for this block.
if (regionField.find(`option[value=${regionName}]`).length === 0) {
@@ -177,9 +201,16 @@
// Update region and weight fields if the region has been changed.
if (!regionField.is(`.block-region-${regionName}`)) {
const weightField = $rowElement.find('select.block-weight');
const oldRegionName = weightField[0].className.replace(/([^ ]+[ ]+)*block-weight-([^ ]+)([ ]+[^ ]+)*/, '$2');
regionField.removeClass(`block-region-${oldRegionName}`).addClass(`block-region-${regionName}`);
weightField.removeClass(`block-weight-${oldRegionName}`).addClass(`block-weight-${regionName}`);
const oldRegionName = weightField[0].className.replace(
/([^ ]+[ ]+)*block-weight-([^ ]+)([ ]+[^ ]+)*/,
'$2',
);
regionField
.removeClass(`block-region-${oldRegionName}`)
.addClass(`block-region-${regionName}`);
weightField
.removeClass(`block-weight-${oldRegionName}`)
.addClass(`block-weight-${regionName}`);
regionField.val(regionName);
}
@@ -187,16 +218,22 @@
};
// Add the behavior to each region select list.
$(context).find('select.block-region-select').once('block-region-select')
.on('change', function (event) {
$(context)
.find('select.block-region-select')
.once('block-region-select')
.on('change', function(event) {
// Make our new row and select field.
const row = $(this).closest('tr');
const select = $(this);
// Find the correct region and insert the row as the last in the
// region.
tableDrag.rowObject = new tableDrag.row(row[0]);
const regionMessage = table.find(`.region-${select[0].value}-message`);
const regionItems = regionMessage.nextUntil('.region-message, .region-title');
const regionMessage = table.find(
`.region-${select[0].value}-message`,
);
const regionItems = regionMessage.nextUntil(
'.region-message, .region-title',
);
if (regionItems.length) {
regionItems.last().after(row);
}
@@ -211,7 +248,10 @@
updateLastPlaced(table, row);
// Show unsaved changes warning.
if (!tableDrag.changed) {
$(Drupal.theme('tableDragChangedWarning')).insertBefore(tableDrag.table).hide().fadeIn('slow');
$(Drupal.theme('tableDragChangedWarning'))
.insertBefore(tableDrag.table)
.hide()
.fadeIn('slow');
tableDrag.changed = true;
}
// Remove focus from selectbox.
@@ -219,4 +259,4 @@
});
},
};
}(jQuery, window, Drupal));
})(jQuery, window, Drupal);
@@ -3,6 +3,7 @@
namespace Drupal\block;
use Drupal\Component\Plugin\Exception\ContextException;
use Drupal\Component\Plugin\Exception\MissingValueContextException;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableDependencyInterface;
@@ -67,7 +68,6 @@ class BlockAccessControlHandler extends EntityAccessControlHandler implements En
$this->contextRepository = $context_repository;
}
/**
* {@inheritdoc}
*/
@@ -84,12 +84,16 @@ class BlockAccessControlHandler extends EntityAccessControlHandler implements En
else {
$conditions = [];
$missing_context = FALSE;
$missing_value = FALSE;
foreach ($entity->getVisibilityConditions() as $condition_id => $condition) {
if ($condition instanceof ContextAwarePluginInterface) {
try {
$contexts = $this->contextRepository->getRuntimeContexts(array_values($condition->getContextMapping()));
$this->contextHandler->applyContextMapping($condition, $contexts);
}
catch (MissingValueContextException $e) {
$missing_value = TRUE;
}
catch (ContextException $e) {
$missing_context = TRUE;
}
@@ -100,14 +104,15 @@ class BlockAccessControlHandler extends EntityAccessControlHandler implements En
if ($missing_context) {
// If any context is missing then we might be missing cacheable
// metadata, and don't know based on what conditions the block is
// accessible or not. For example, blocks that have a node type
// condition will have a missing context on any non-node route like the
// frontpage.
// @todo Avoid setting max-age 0 for some or all cases, for example by
// treating available contexts without value differently in
// https://www.drupal.org/node/2521956.
// accessible or not. Make sure the result cannot be cached.
$access = AccessResult::forbidden()->setCacheMaxAge(0);
}
elseif ($missing_value) {
// The contexts exist but have no value. Deny access without
// disabling caching. For example the node type condition will have a
// missing context on any non-node route like the frontpage.
$access = AccessResult::forbidden();
}
elseif ($this->resolveConditions($conditions, 'and') !== FALSE) {
// Delegate to the plugin.
$block_plugin = $entity->getPlugin();
@@ -118,12 +123,15 @@ class BlockAccessControlHandler extends EntityAccessControlHandler implements En
}
$access = $block_plugin->access($account, TRUE);
}
catch (MissingValueContextException $e) {
// The contexts exist but have no value. Deny access without
// disabling caching.
$access = AccessResult::forbidden();
}
catch (ContextException $e) {
// Setting access to forbidden if any context is missing for the same
// reasons as with conditions (described in the comment above).
// @todo Avoid setting max-age 0 for some or all cases, for example by
// treating available contexts without value differently in
// https://www.drupal.org/node/2521956.
// If any context is missing then we might be missing cacheable
// metadata, and don't know based on what conditions the block is
// accessible or not. Make sure the result cannot be cached.
$access = AccessResult::forbidden()->setCacheMaxAge(0);
}
}
+3 -2
View File
@@ -239,7 +239,8 @@ class BlockForm extends EntityForm {
// @todo Allow list of conditions to be configured in
// https://www.drupal.org/node/2284687.
$visibility = $this->entity->getVisibility();
foreach ($this->manager->getDefinitionsForContexts($form_state->getTemporaryValue('gathered_contexts')) as $condition_id => $definition) {
$definitions = $this->manager->getFilteredDefinitions('block_ui', $form_state->getTemporaryValue('gathered_contexts'), ['block' => $this->entity]);
foreach ($definitions as $condition_id => $definition) {
// Don't display the current theme condition.
if ($condition_id == 'current_theme') {
continue;
@@ -359,7 +360,7 @@ class BlockForm extends EntityForm {
// Save the settings of the plugin.
$entity->save();
drupal_set_message($this->t('The block configuration has been saved.'));
$this->messenger()->addStatus($this->t('The block configuration has been saved.'));
$form_state->setRedirect(
'block.admin_display_theme',
[
+14 -4
View File
@@ -11,6 +11,7 @@ use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -56,6 +57,13 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
*/
protected $limit = FALSE;
/**
* The messenger.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* Constructs a new BlockListBuilder object.
*
@@ -68,11 +76,12 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
* @param \Drupal\Core\Form\FormBuilderInterface $form_builder
* The form builder.
*/
public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, ThemeManagerInterface $theme_manager, FormBuilderInterface $form_builder) {
public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, ThemeManagerInterface $theme_manager, FormBuilderInterface $form_builder, MessengerInterface $messenger) {
parent::__construct($entity_type, $storage);
$this->themeManager = $theme_manager;
$this->formBuilder = $form_builder;
$this->messenger = $messenger;
}
/**
@@ -83,7 +92,8 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
$entity_type,
$container->get('entity.manager')->getStorage($entity_type->id()),
$container->get('theme.manager'),
$container->get('form_builder')
$container->get('form_builder'),
$container->get('messenger')
);
}
@@ -212,7 +222,7 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
'#theme_wrappers' => [
'container' => [
'#attributes' => ['class' => 'region-title__action'],
]
],
],
'#prefix' => $title,
'#type' => 'link',
@@ -367,7 +377,7 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
$entity->setRegion($entity_values['region']);
$entity->save();
}
drupal_set_message(t('The block settings have been updated.'));
$this->messenger->addStatus($this->t('The block settings have been updated.'));
// Remove any previously set block placement.
$this->request->query->remove('block-placement');
@@ -53,7 +53,7 @@ class BlockController extends ControllerBase {
*/
public function performOperation(BlockInterface $block, $op) {
$block->$op()->save();
drupal_set_message($this->t('The block settings have been updated.'));
$this->messenger()->addStatus($this->t('The block settings have been updated.'));
return $this->redirect('block.admin_display');
}
@@ -101,8 +101,14 @@ class BlockLibraryController extends ControllerBase {
['data' => $this->t('Operations')],
];
$region = $request->query->get('region');
$weight = $request->query->get('weight');
// Only add blocks which work without any available context.
$definitions = $this->blockManager->getDefinitionsForContexts($this->contextRepository->getAvailableContexts());
$definitions = $this->blockManager->getFilteredDefinitions('block_ui', $this->contextRepository->getAvailableContexts(), [
'theme' => $theme,
'region' => $region,
]);
// Order by category, and then by admin label.
$definitions = $this->blockManager->getSortedDefinitions($definitions);
// Filter out definitions that are not intended to be placed by the UI.
@@ -110,8 +116,6 @@ class BlockLibraryController extends ControllerBase {
return empty($definition['_block_ui_hidden']);
});
$region = $request->query->get('region');
$weight = $request->query->get('weight');
$rows = [];
foreach ($definitions as $plugin_id => $plugin_definition) {
$row = [];
@@ -48,7 +48,8 @@ class BlockListController extends EntityListController {
* The current request.
*
* @return array
* A render array as expected by drupal_render().
* A render array as expected by
* \Drupal\Core\Render\RendererInterface::render().
*/
public function listing($theme = NULL, Request $request = NULL) {
$theme = $theme ?: $this->config('system.theme')->get('default');
+7
View File
@@ -17,6 +17,13 @@ use Drupal\Core\Entity\EntityStorageInterface;
* @ConfigEntityType(
* id = "block",
* label = @Translation("Block"),
* label_collection = @Translation("Blocks"),
* label_singular = @Translation("block"),
* label_plural = @Translation("blocks"),
* label_count = @PluralTranslation(
* singular = "@count block",
* plural = "@count blocks",
* ),
* handlers = {
* "access" = "Drupal\block\BlockAccessControlHandler",
* "view_builder" = "Drupal\block\BlockViewBuilder",
@@ -115,7 +115,7 @@ class BlockVisibility extends ProcessPluginBase implements ContainerFactoryPlugi
// anything else -- the block will simply have no PHP or request_path
// visibility configuration.
elseif ($this->skipPHP) {
throw new MigrateSkipRowException();
throw new MigrateSkipRowException(sprintf("The block with bid '%d' from module '%s' will have no PHP or request_path visibility configuration.", $row->getSourceProperty('bid'), $row->getSourceProperty('module'), $destination_property));
}
}
else {
@@ -0,0 +1,71 @@
<?php
namespace Drupal\block\Plugin\migrate\source\d6;
use Drupal\block\Plugin\migrate\source\Block;
use Drupal\migrate\Plugin\migrate\source\SourcePluginBase;
use Drupal\migrate\Row;
/**
* Gets i18n block data from source database.
*
* @MigrateSource(
* id = "d6_block_translation",
* source_module = "i18nblocks"
* )
*/
class BlockTranslation extends Block {
/**
* {@inheritdoc}
*/
public function query() {
// Let the parent set the block table to use, but do not use the parent
// query. Instead build a query so can use an inner join to the selected
// block table.
parent::query();
$query = $this->select('i18n_blocks', 'i18n')
->fields('i18n')
->fields('b', ['bid', 'module', 'delta', 'theme', 'title']);
$query->innerJoin($this->blockTable, 'b', ('b.module = i18n.module AND b.delta = i18n.delta'));
return $query;
}
/**
* {@inheritdoc}
*/
public function fields() {
return [
'bid' => $this->t('The block numeric identifier.'),
'ibid' => $this->t('The i18n_blocks block numeric identifier.'),
'module' => $this->t('The module providing the block.'),
'delta' => $this->t("The block's delta."),
'type' => $this->t('Block type'),
'language' => $this->t('Language for this field.'),
'theme' => $this->t('Which theme the block is placed in.'),
'default_theme' => $this->t('The default theme.'),
'title' => $this->t('Block title.'),
];
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
$row->setSourceProperty('default_theme', $this->defaultTheme);
return SourcePluginBase::prepareRow($row);
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids = parent::getIds();
$ids['module']['alias'] = 'b';
$ids['delta']['alias'] = 'b';
$ids['theme']['alias'] = 'b';
$ids['language']['type'] = 'string';
return $ids;
}
}
@@ -5,4 +5,4 @@ package: Testing
version: VERSION
core: 8.x
dependencies:
- block
- drupal:block
@@ -4,9 +4,8 @@ namespace Drupal\block_test\ContextProvider;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\Plugin\Context\ContextProviderInterface;
use Drupal\Core\Plugin\Context\EntityContext;
use Drupal\Core\Session\AccountInterface;
/**
@@ -47,9 +46,8 @@ class MultipleStaticContext implements ContextProviderInterface {
public function getRuntimeContexts(array $unqualified_context_ids) {
$current_user = $this->userStorage->load($this->account->id());
$context1 = new Context(new ContextDefinition('entity:user', 'User A'), $current_user);
$context2 = new Context(new ContextDefinition('entity:user', 'User B'), $current_user);
$context1 = EntityContext::fromEntity($current_user, 'User A');
$context2 = EntityContext::fromEntity($current_user, 'User B');
$cacheability = new CacheableMetadata();
$cacheability->setCacheContexts(['user']);
@@ -17,7 +17,8 @@ class TestMultipleFormController extends ControllerBase {
'form2' => $this->formBuilder()->buildForm('\Drupal\block_test\Form\FavoriteAnimalTestForm', $form_state),
];
// Output all attached placeholders trough drupal_set_message(), so we can
// Output all attached placeholders trough
// \Drupal\Core\Messenger\MessengerInterface::addMessage(), so we can
// see if there's only one in the tests.
$post_render_callable = function ($elements) {
$matches = [];
@@ -26,7 +27,7 @@ class TestMultipleFormController extends ControllerBase {
$action_values = $matches[2];
foreach ($action_values as $action_value) {
drupal_set_message('Form action: ' . $action_value);
$this->messenger()->addStatus('Form action: ' . $action_value);
}
return $elements;
};
@@ -25,7 +25,7 @@ class FavoriteAnimalTestForm extends FormBase {
public function buildForm(array $form, FormStateInterface $form_state) {
$form['favorite_animal'] = [
'#type' => 'textfield',
'#title' => $this->t('Your favorite animal.')
'#title' => $this->t('Your favorite animal.'),
];
$form['submit_animal'] = [
@@ -40,7 +40,7 @@ class FavoriteAnimalTestForm extends FormBase {
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
drupal_set_message($this->t('Your favorite animal is: @favorite_animal', ['@favorite_animal' => $form['favorite_animal']['#value']]));
$this->messenger()->addStatus($this->t('Your favorite animal is: @favorite_animal', ['@favorite_animal' => $form['favorite_animal']['#value']]));
}
}
@@ -25,7 +25,7 @@ class TestForm extends FormBase {
public function buildForm(array $form, FormStateInterface $form_state) {
$form['email'] = [
'#type' => 'email',
'#title' => $this->t('Your .com email address.')
'#title' => $this->t('Your .com email address.'),
];
$form['show'] = [
@@ -49,7 +49,7 @@ class TestForm extends FormBase {
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
drupal_set_message($this->t('Your email address is @email', ['@email' => $form['email']['#value']]));
$this->messenger()->addStatus($this->t('Your email address is @email', ['@email' => $form['email']['#value']]));
}
}

Some files were not shown because too many files have changed in this diff Show More