Update to Drupal 8.0.0 beta 14. For more information, see https://drupal.org/node/2544542
This commit is contained in:
parent
3b2511d96d
commit
81ccda77eb
2155 changed files with 54307 additions and 46870 deletions
|
@ -1,2 +1,3 @@
|
|||
administer actions:
|
||||
title: 'Administer actions'
|
||||
restrict access: true
|
||||
|
|
|
@ -11,7 +11,3 @@ process:
|
|||
destination:
|
||||
plugin: config
|
||||
config_name: action.settings
|
||||
dependencies:
|
||||
module:
|
||||
- action
|
||||
- migrate_drupal
|
|
@ -123,8 +123,8 @@ abstract class ActionFormBase extends EntityForm {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate(array $form, FormStateInterface $form_state) {
|
||||
parent::validate($form, $form_state);
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::validateForm($form, $form_state);
|
||||
|
||||
if ($this->plugin instanceof PluginFormInterface) {
|
||||
$this->plugin->validateConfigurationForm($form, $form_state);
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Plugin\migrate\source\d6\Action.
|
||||
* Contains \Drupal\action\Plugin\migrate\source\d6\Action.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Plugin\migrate\source\d6;
|
||||
namespace Drupal\action\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
|
@ -2,19 +2,18 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Tests\d6\MigrateActionConfigsTest.
|
||||
* Contains \Drupal\action\Tests\Migrate\d6\MigrateActionConfigsTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Tests\d6;
|
||||
namespace Drupal\action\Tests\Migrate\d6;
|
||||
|
||||
use Drupal\config\Tests\SchemaCheckTestTrait;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Upgrade variables to action.settings.yml.
|
||||
*
|
||||
* @group migrate_drupal
|
||||
* @group action
|
||||
*/
|
||||
class MigrateActionConfigsTest extends MigrateDrupal6TestBase {
|
||||
|
||||
|
@ -32,13 +31,8 @@ class MigrateActionConfigsTest extends MigrateDrupal6TestBase {
|
|||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$migration = entity_load('migration', 'd6_action_settings');
|
||||
$dumps = array(
|
||||
$this->getDumpDirectory() . '/Variable.php',
|
||||
);
|
||||
$this->prepare($migration, $dumps);
|
||||
$executable = new MigrateExecutable($migration, $this);
|
||||
$executable->import();
|
||||
$this->loadDumps(['Variable.php']);
|
||||
$this->executeMigration('d6_action_settings');
|
||||
}
|
||||
|
||||
/**
|
|
@ -2,23 +2,23 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\migrate_drupal\Unit\source\d6\ActionTest.
|
||||
* Contains \Drupal\Tests\action\Unit\Plugin\migrate\source\d6\ActionTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\migrate_drupal\Unit\source\d6;
|
||||
namespace Drupal\Tests\action\Unit\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
|
||||
|
||||
/**
|
||||
* Tests D6 actions source plugin.
|
||||
*
|
||||
* @group migrate_drupal
|
||||
* @group action
|
||||
*/
|
||||
class ActionTest extends MigrateSqlSourceTestCase {
|
||||
|
||||
// The plugin system is not working during unit testing so the source plugin
|
||||
// class needs to be manually specified.
|
||||
const PLUGIN_CLASS = 'Drupal\migrate_drupal\Plugin\migrate\source\d6\Action';
|
||||
const PLUGIN_CLASS = 'Drupal\action\Plugin\migrate\source\d6\Action';
|
||||
|
||||
// The fake Migration configuration entity.
|
||||
protected $migrationConfiguration = array(
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
use Drupal\aggregator\Entity\Feed;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
|
||||
/**
|
||||
|
@ -166,7 +166,7 @@ function aggregator_cron() {
|
|||
* The filtered content.
|
||||
*/
|
||||
function aggregator_filter_xss($value) {
|
||||
return Xss::filter($value, preg_split('/\s+|<|>/', \Drupal::config('aggregator.settings')->get('items.allowed_html'), -1, PREG_SPLIT_NO_EMPTY));
|
||||
return SafeMarkup::xssFilter($value, preg_split('/\s+|<|>/', \Drupal::config('aggregator.settings')->get('items.allowed_html'), -1, PREG_SPLIT_NO_EMPTY));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,6 @@ migration_tags:
|
|||
- Drupal 6
|
||||
source:
|
||||
plugin: d6_aggregator_feed
|
||||
|
||||
process:
|
||||
fid: fid
|
||||
title: title
|
||||
|
@ -16,10 +15,5 @@ process:
|
|||
image: image
|
||||
etag: etag
|
||||
modified: modified
|
||||
|
||||
destination:
|
||||
plugin: entity:aggregator_feed
|
||||
dependencies:
|
||||
module:
|
||||
- aggregator
|
||||
- migrate_drupal
|
|
@ -22,9 +22,3 @@ destination:
|
|||
migration_dependencies:
|
||||
required:
|
||||
- d6_aggregator_feed
|
||||
dependencies:
|
||||
config:
|
||||
- migrate.migration.d6_aggregator_feed
|
||||
module:
|
||||
- aggregator
|
||||
- migrate_drupal
|
|
@ -23,7 +23,3 @@ process:
|
|||
destination:
|
||||
plugin: config
|
||||
config_name: aggregator.settings
|
||||
dependencies:
|
||||
module:
|
||||
- aggregator
|
||||
- migrate_drupal
|
|
@ -0,0 +1,25 @@
|
|||
id: d7_aggregator_settings
|
||||
label: Drupal 7 aggregator configuration
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- aggregator_fetcher
|
||||
- aggregator_parser
|
||||
- aggregator_processors
|
||||
- aggregator_allowed_html_tags
|
||||
- aggregator_teaser_length
|
||||
- aggregator_clear
|
||||
- aggregator_summary_items
|
||||
process:
|
||||
fetcher: aggregator_fetcher
|
||||
parser: aggregator_parser
|
||||
processors: aggregator_processors
|
||||
'items/allowed_html': aggregator_allowed_html_tags
|
||||
'items/teaser_length': aggregator_teaser_length
|
||||
'items/expire': aggregator_clear
|
||||
'source/list_max': aggregator_summary_items
|
||||
destination:
|
||||
plugin: config
|
||||
config_name: aggregator.settings
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\aggregator\Controller;
|
||||
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\aggregator\FeedInterface;
|
||||
|
@ -187,7 +187,7 @@ class AggregatorController extends ControllerBase {
|
|||
* The feed label.
|
||||
*/
|
||||
public function feedTitle(FeedInterface $aggregator_feed) {
|
||||
return Xss::filter($aggregator_feed->label());
|
||||
return SafeMarkup::xssFilter($aggregator_feed->label());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -225,13 +225,15 @@ class Item extends ContentEntityBase implements ItemInterface {
|
|||
// handles the regular cases. The Item entity has one special case: a newly
|
||||
// created Item is *also* associated with a Feed, so we must invalidate the
|
||||
// associated Feed's cache tag.
|
||||
Cache::invalidateTags($this->getCacheTags());
|
||||
if (!$update) {
|
||||
Cache::invalidateTags($this->getCacheTagsToInvalidate());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
public function getCacheTagsToInvalidate() {
|
||||
return Feed::load($this->getFeedId())->getCacheTags();
|
||||
}
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ class OpmlFeedAdd extends FormBase {
|
|||
// @todo Move this to a fetcher implementation.
|
||||
try {
|
||||
$response = $this->httpClient->get($form_state->getValue('remote'));
|
||||
$data = $response->getBody(TRUE);
|
||||
$data = (string) $response->getBody();
|
||||
}
|
||||
catch (RequestException $e) {
|
||||
$this->logger('aggregator')->warning('Failed to download OPML file due to "%error".', array('%error' => $e->getMessage()));
|
||||
|
|
|
@ -154,32 +154,27 @@ class AggregatorFeedBlock extends BlockBase implements ContainerFactoryPluginInt
|
|||
->sort('iid', 'DESC')
|
||||
->execute();
|
||||
|
||||
$items = $this->itemStorage->loadMultiple($result);
|
||||
if ($result) {
|
||||
// Only display the block if there are items to show.
|
||||
$items = $this->itemStorage->loadMultiple($result);
|
||||
|
||||
$more_link = array(
|
||||
'#type' => 'more_link',
|
||||
'#url' => $feed->urlInfo(),
|
||||
'#attributes' => array('title' => $this->t("View this feed's recent news.")),
|
||||
);
|
||||
$read_more = drupal_render($more_link);
|
||||
$rendered_items = array();
|
||||
foreach ($items as $item) {
|
||||
$aggregator_block_item = array(
|
||||
'#type' => 'link',
|
||||
'#url' => $item->urlInfo(),
|
||||
'#title' => $item->label(),
|
||||
);
|
||||
$rendered_items[] = drupal_render($aggregator_block_item);
|
||||
}
|
||||
// Only display the block if there are items to show.
|
||||
if (count($rendered_items) > 0) {
|
||||
$item_list = array(
|
||||
$build['list'] = [
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $rendered_items,
|
||||
);
|
||||
return array(
|
||||
'#children' => drupal_render($item_list) . $read_more,
|
||||
);
|
||||
'#items' => [],
|
||||
];
|
||||
foreach ($items as $item) {
|
||||
$build['list']['#items'][$item->id()] = [
|
||||
'#type' => 'link',
|
||||
'#url' => $item->urlInfo(),
|
||||
'#title' => $item->label(),
|
||||
];
|
||||
}
|
||||
$build['more_link'] = [
|
||||
'#type' => 'more_link',
|
||||
'#url' => $feed->urlInfo(),
|
||||
'#attributes' => ['title' => $this->t("View this feed's recent news.")],
|
||||
];
|
||||
return $build;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,13 @@ namespace Drupal\aggregator\Plugin\aggregator\fetcher;
|
|||
use Drupal\aggregator\Plugin\FetcherInterface;
|
||||
use Drupal\aggregator\FeedInterface;
|
||||
use Drupal\Component\Datetime\DateTimePlus;
|
||||
use Drupal\Core\Http\ClientFactory;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
|
@ -32,9 +36,9 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
|
|||
/**
|
||||
* The HTTP client to fetch the feed data with.
|
||||
*
|
||||
* @var \GuzzleHttp\ClientInterface
|
||||
* @var \Drupal\Core\Http\ClientFactory
|
||||
*/
|
||||
protected $httpClient;
|
||||
protected $httpClientFactory;
|
||||
|
||||
/**
|
||||
* A logger instance.
|
||||
|
@ -46,13 +50,13 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
|
|||
/**
|
||||
* Constructs a DefaultFetcher object.
|
||||
*
|
||||
* @param \GuzzleHttp\ClientInterface $http_client
|
||||
* @param \Drupal\Core\Http\ClientFactory $http_client_factory
|
||||
* A Guzzle client object.
|
||||
* @param \Psr\Log\LoggerInterface $logger
|
||||
* A logger instance.
|
||||
*/
|
||||
public function __construct(ClientInterface $http_client, LoggerInterface $logger) {
|
||||
$this->httpClient = $http_client;
|
||||
public function __construct(ClientFactory $http_client_factory, LoggerInterface $logger) {
|
||||
$this->httpClientFactory = $http_client_factory;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
|
@ -61,7 +65,7 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
|
|||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$container->get('http_client'),
|
||||
$container->get('http_client_factory'),
|
||||
$container->get('logger.factory')->get('aggregator')
|
||||
);
|
||||
}
|
||||
|
@ -70,19 +74,26 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function fetch(FeedInterface $feed) {
|
||||
$request = $this->httpClient->createRequest('GET', $feed->getUrl());
|
||||
$request = new Request('GET', $feed->getUrl());
|
||||
$feed->source_string = FALSE;
|
||||
|
||||
// Generate conditional GET headers.
|
||||
if ($feed->getEtag()) {
|
||||
$request->addHeader('If-None-Match', $feed->getEtag());
|
||||
$request = $request->withAddedHeader('If-None-Match', $feed->getEtag());
|
||||
}
|
||||
if ($feed->getLastModified()) {
|
||||
$request->addHeader('If-Modified-Since', gmdate(DateTimePlus::RFC7231, $feed->getLastModified()));
|
||||
$request = $request->withAddedHeader('If-Modified-Since', gmdate(DateTimePlus::RFC7231, $feed->getLastModified()));
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->send($request);
|
||||
|
||||
/** @var \Psr\Http\Message\UriInterface $actual_uri */
|
||||
$actual_uri = NULL;
|
||||
$response = $this->httpClientFactory->fromOptions(['allow_redirects' => [
|
||||
'on_redirect' => function(RequestInterface $request, ResponseInterface $response, UriInterface $uri) use (&$actual_uri) {
|
||||
$actual_uri = (string) $uri;
|
||||
}
|
||||
]])->send($request);
|
||||
|
||||
// In case of a 304 Not Modified, there is no new content, so return
|
||||
// FALSE.
|
||||
|
@ -91,13 +102,17 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
|
|||
}
|
||||
|
||||
$feed->source_string = (string) $response->getBody();
|
||||
$feed->setEtag($response->getHeader('ETag'));
|
||||
$feed->setLastModified(strtotime($response->getHeader('Last-Modified')));
|
||||
if ($response->hasHeader('ETag')) {
|
||||
$feed->setEtag($response->getHeaderLine('ETag'));
|
||||
}
|
||||
if ($response->hasHeader('Last-Modified')) {
|
||||
$feed->setLastModified(strtotime($response->getHeaderLine('Last-Modified')));
|
||||
}
|
||||
$feed->http_headers = $response->getHeaders();
|
||||
|
||||
// Update the feed URL in case of a 301 redirect.
|
||||
if ($response->getEffectiveUrl() != $feed->getUrl()) {
|
||||
$feed->setUrl($response->getEffectiveUrl());
|
||||
if ($actual_uri && $actual_uri !== $feed->getUrl()) {
|
||||
$feed->setUrl($actual_uri);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Plugin\migrate\source\d6\AggregatorFeed.
|
||||
* Contains \Drupal\aggregator\Plugin\migrate\source\d6\AggregatorFeed.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Plugin\migrate\source\d6;
|
||||
namespace Drupal\aggregator\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Plugin\migrate\source\d6\AggregatorItem.
|
||||
* Contains \Drupal\aggregator\Plugin\migrate\source\d6\AggregatorItem.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Plugin\migrate\source\d6;
|
||||
namespace Drupal\aggregator\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
|
@ -26,11 +26,6 @@ class FeedParserTest extends AggregatorTestBase {
|
|||
// feeds have hardcoded dates in them (which may be expired when this test
|
||||
// is run).
|
||||
$this->config('aggregator.settings')->set('items.expire', AGGREGATOR_CLEAR_NEVER)->save();
|
||||
// Reset any reader cache between tests.
|
||||
Reader::reset();
|
||||
// Set our bridge extension manager to Zend Feed.
|
||||
$bridge = $this->container->get('feed.bridge.reader');
|
||||
Reader::setExtensionManager($bridge);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,6 +63,15 @@ class FeedParserTest extends AggregatorTestBase {
|
|||
$this->assertLinkByHref('http://example.org/2003/12/13/atom03');
|
||||
$this->assertText('Some text.');
|
||||
$this->assertEqual('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', db_query('SELECT guid FROM {aggregator_item} WHERE link = :link', array(':link' => 'http://example.org/2003/12/13/atom03'))->fetchField(), 'Atom entry id element is parsed correctly.');
|
||||
|
||||
// Check for second feed entry.
|
||||
$this->assertText('We tried to stop them, but we failed.');
|
||||
$this->assertLinkByHref('http://example.org/2003/12/14/atom03');
|
||||
$this->assertText('Some other text.');
|
||||
$db_guid = db_query('SELECT guid FROM {aggregator_item} WHERE link = :link', array(
|
||||
':link' => 'http://example.org/2003/12/14/atom03',
|
||||
))->fetchField();
|
||||
$this->assertEqual('urn:uuid:1225c695-cfb8-4ebb-bbbb-80da344efa6a', $db_guid, 'Atom entry id element is parsed correctly.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,19 +2,18 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Tests\d6\MigrateAggregatorConfigsTest.
|
||||
* Contains \Drupal\aggregator\Tests\Migrate\d6\MigrateAggregatorConfigsTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Tests\d6;
|
||||
namespace Drupal\aggregator\Tests\Migrate\d6;
|
||||
|
||||
use Drupal\config\Tests\SchemaCheckTestTrait;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Upgrade variables to aggregator.settings.yml.
|
||||
*
|
||||
* @group migrate_drupal
|
||||
* @group aggregator
|
||||
*/
|
||||
class MigrateAggregatorConfigsTest extends MigrateDrupal6TestBase {
|
||||
|
||||
|
@ -32,13 +31,8 @@ class MigrateAggregatorConfigsTest extends MigrateDrupal6TestBase {
|
|||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$migration = entity_load('migration', 'd6_aggregator_settings');
|
||||
$dumps = array(
|
||||
$this->getDumpDirectory() . '/Variable.php',
|
||||
);
|
||||
$this->prepare($migration, $dumps);
|
||||
$executable = new MigrateExecutable($migration, $this);
|
||||
$executable->import();
|
||||
$this->loadDumps(['Variable.php']);
|
||||
$this->executeMigration('d6_aggregator_settings');
|
||||
}
|
||||
|
||||
/**
|
|
@ -2,19 +2,18 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Tests\d6\MigrateAggregatorFeedTest.
|
||||
* Contains \Drupal\aggregator\Tests\Migrate\d6\MigrateAggregatorFeedTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Tests\d6;
|
||||
namespace Drupal\aggregator\Tests\Migrate\d6;
|
||||
|
||||
use Drupal\aggregator\Entity\Feed;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Upgrade variables to aggregator_feed entities.
|
||||
*
|
||||
* @group migrate_drupal
|
||||
* @group aggregator
|
||||
*/
|
||||
class MigrateAggregatorFeedTest extends MigrateDrupal6TestBase {
|
||||
|
||||
|
@ -26,14 +25,8 @@ class MigrateAggregatorFeedTest extends MigrateDrupal6TestBase {
|
|||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('aggregator_feed');
|
||||
|
||||
$migration = entity_load('migration', 'd6_aggregator_feed');
|
||||
$dumps = array(
|
||||
$this->getDumpDirectory() . '/AggregatorFeed.php',
|
||||
);
|
||||
$this->prepare($migration, $dumps);
|
||||
$executable = new MigrateExecutable($migration, $this);
|
||||
$executable->import();
|
||||
$this->loadDumps(['AggregatorFeed.php']);
|
||||
$this->executeMigration('d6_aggregator_feed');
|
||||
}
|
||||
|
||||
/**
|
|
@ -2,20 +2,18 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Tests\d6\MigrateAggregatorItemTest.
|
||||
* Contains \Drupal\aggregator\Tests\Migrate\d6\MigrateAggregatorItemTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Tests\d6;
|
||||
namespace Drupal\aggregator\Tests\Migrate\d6;
|
||||
|
||||
use Drupal\aggregator\Entity\Item;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Upgrade aggregator items.
|
||||
*
|
||||
* @group migrate_drupal
|
||||
* @group aggregator
|
||||
*/
|
||||
class MigrateAggregatorItemTest extends MigrateDrupal6TestBase {
|
||||
|
||||
|
@ -47,14 +45,8 @@ class MigrateAggregatorItemTest extends MigrateDrupal6TestBase {
|
|||
));
|
||||
$entity->enforceIsNew();
|
||||
$entity->save();
|
||||
/** @var \Drupal\migrate\entity\Migration $migration */
|
||||
$migration = entity_load('migration', 'd6_aggregator_item');
|
||||
$dumps = array(
|
||||
$this->getDumpDirectory() . '/AggregatorItem.php',
|
||||
);
|
||||
$this->prepare($migration, $dumps);
|
||||
$executable = new MigrateExecutable($migration, $this);
|
||||
$executable->import();
|
||||
$this->loadDumps(['AggregatorItem.php']);
|
||||
$this->executeMigration('d6_aggregator_item');
|
||||
}
|
||||
|
||||
/**
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\aggregator\Tests\Migrate\d7\MigrateAggregatorSettingsTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\aggregator\Tests\Migrate\d7;
|
||||
|
||||
use Drupal\migrate_drupal\Tests\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests migration of Aggregator's variables to configuration.
|
||||
*
|
||||
* @group aggregator
|
||||
*/
|
||||
class MigrateAggregatorSettingsTest extends MigrateDrupal7TestBase {
|
||||
|
||||
public static $modules = ['aggregator'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installConfig(static::$modules);
|
||||
$this->loadDumps(['Variable.php']);
|
||||
$this->executeMigration('d7_aggregator_settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of Aggregator variables to configuration.
|
||||
*/
|
||||
public function testMigration() {
|
||||
$config = \Drupal::config('aggregator.settings')->get();
|
||||
$this->assertIdentical('aggregator', $config['fetcher']);
|
||||
$this->assertIdentical('aggregator', $config['parser']);
|
||||
$this->assertIdentical(['aggregator'], $config['processors']);
|
||||
$this->assertIdentical('<p> <div> <a>', $config['items']['allowed_html']);
|
||||
$this->assertIdentical(500, $config['items']['teaser_length']);
|
||||
$this->assertIdentical(86400, $config['items']['expire']);
|
||||
$this->assertIdentical(6, $config['source']['list_max']);
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\aggregator\Tests\Views;
|
||||
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
|
@ -66,6 +67,9 @@ class IntegrationTest extends ViewUnitTestBase {
|
|||
* Tests basic aggregator_item view.
|
||||
*/
|
||||
public function testAggregatorItemView() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$feed = $this->feedStorage->create(array(
|
||||
'title' => $this->randomMachineName(),
|
||||
'url' => 'https://www.drupal.org/',
|
||||
|
@ -112,13 +116,22 @@ class IntegrationTest extends ViewUnitTestBase {
|
|||
foreach ($view->result as $row) {
|
||||
$iid = $view->field['iid']->getValue($row);
|
||||
$expected_link = \Drupal::l($items[$iid]->getTitle(), Url::fromUri($items[$iid]->getLink(), ['absolute' => TRUE]));
|
||||
$this->assertEqual($view->field['title']->advancedRender($row), $expected_link, 'Ensure the right link is generated');
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $row) {
|
||||
return $view->field['title']->advancedRender($row);
|
||||
});
|
||||
$this->assertEqual($output, $expected_link, 'Ensure the right link is generated');
|
||||
|
||||
$expected_author = aggregator_filter_xss($items[$iid]->getAuthor());
|
||||
$this->assertEqual($view->field['author']->advancedRender($row), $expected_author, 'Ensure the author got filtered');
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $row) {
|
||||
return $view->field['author']->advancedRender($row);
|
||||
});
|
||||
$this->assertEqual($output, $expected_author, 'Ensure the author got filtered');
|
||||
|
||||
$expected_description = aggregator_filter_xss($items[$iid]->getDescription());
|
||||
$this->assertEqual($view->field['description']->advancedRender($row), $expected_description, 'Ensure the author got filtered');
|
||||
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $row) {
|
||||
return $view->field['description']->advancedRender($row);
|
||||
});
|
||||
$this->assertEqual($output, $expected_description, 'Ensure the author got filtered');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,4 +17,12 @@
|
|||
<summary>Some text.</summary>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<title>We tried to stop them, but we failed.</title>
|
||||
<link href="http://example.org/2003/12/14/atom03" />
|
||||
<id>urn:uuid:1225c695-cfb8-4ebb-bbbb-80da344efa6a</id>
|
||||
<updated>2003-12-14T16:30:02Z</updated>
|
||||
<summary>Some other text.</summary>
|
||||
</entry>
|
||||
|
||||
</feed>
|
||||
|
|
|
@ -2,21 +2,21 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\migrate_drupal\Unit\source\d6\AggregatorFeedTest.
|
||||
* Contains \Drupal\Tests\aggregator\Unit\Plugin\migrate\source\d6\AggregatorFeedTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\migrate_drupal\Unit\source\d6;
|
||||
namespace Drupal\Tests\aggregator\Unit\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
|
||||
|
||||
/**
|
||||
* Tests D6 aggregator feed source plugin.
|
||||
*
|
||||
* @group migrate_drupal
|
||||
* @group aggregator
|
||||
*/
|
||||
class AggregatorFeedTest extends MigrateSqlSourceTestCase {
|
||||
|
||||
const PLUGIN_CLASS = 'Drupal\migrate_drupal\Plugin\migrate\source\d6\AggregatorFeed';
|
||||
const PLUGIN_CLASS = 'Drupal\aggregator\Plugin\migrate\source\d6\AggregatorFeed';
|
||||
|
||||
protected $migrationConfiguration = array(
|
||||
'id' => 'test',
|
|
@ -2,21 +2,21 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\migrate_drupal\Unit\source\d6\AggregatorItemTest.
|
||||
* Contains \Drupal\Tests\aggregator\Unit\Plugin\migrate\source\d6\AggregatorItemTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\migrate_drupal\Unit\source\d6;
|
||||
namespace Drupal\Tests\aggregator\Unit\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
|
||||
|
||||
/**
|
||||
* Tests D6 aggregator item source plugin.
|
||||
*
|
||||
* @group migrate_drupal
|
||||
* @group aggregator
|
||||
*/
|
||||
class AggregatorItemTest extends MigrateSqlSourceTestCase {
|
||||
|
||||
const PLUGIN_CLASS = 'Drupal\migrate_drupal\Plugin\migrate\source\d6\AggregatorItem';
|
||||
const PLUGIN_CLASS = 'Drupal\aggregator\Plugin\migrate\source\d6\AggregatorItem';
|
||||
|
||||
// The fake Migration configuration entity.
|
||||
protected $migrationConfiguration = array(
|
146
core/modules/block/block.install
Normal file
146
core/modules/block/block.install
Normal file
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains install and update functions for Block.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function block_install() {
|
||||
// Because the Block module upon installation unconditionally overrides all
|
||||
// HTML output by selecting a different page display variant, we must
|
||||
// invalidate all cached HTML output.
|
||||
Cache::invalidateTags(['rendered']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @addtogroup updates-8.0.0-beta
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Update block visibility context mapping.
|
||||
*/
|
||||
function block_update_8001() {
|
||||
// This update function updates blocks for the change from
|
||||
// https://www.drupal.org/node/2354889.
|
||||
|
||||
// Core visibility context plugins are updated automatically; blocks with
|
||||
// unknown plugins are disabled and their previous visibility settings are
|
||||
// saved in key value storage; see change record
|
||||
// https://www.drupal.org/node/2527840 for more explanation.
|
||||
|
||||
// These are all the contexts that Drupal core provides.
|
||||
$context_service_id_map = [
|
||||
'node.node' => '@node.node_route_context:node',
|
||||
'user.current_user' => '@user.current_user_context:current_user',
|
||||
];
|
||||
|
||||
foreach (array_keys(\Drupal::languageManager()->getDefinedLanguageTypesInfo()) as $language_type_id) {
|
||||
$context_service_id_map['language.' . $language_type_id] = '@language.current_language_context:' . $language_type_id;
|
||||
}
|
||||
|
||||
// Contributed modules should leverage hook_update_dependencies() in order to
|
||||
// be executed before block_update_8002(), so they can update their context
|
||||
// mappings, if wanted.
|
||||
$config_factory = \Drupal::configFactory();
|
||||
$backup_values = $update_backup = [];
|
||||
|
||||
foreach ($config_factory->listAll('block.block.') as $block_config_name) {
|
||||
$block = $config_factory->getEditable($block_config_name);
|
||||
if ($visibility = $block->get('visibility')) {
|
||||
foreach ($visibility as $condition_plugin_id => &$condition) {
|
||||
foreach ($condition['context_mapping'] as $key => $context) {
|
||||
if (!isset($context_service_id_map[$context])) {
|
||||
// Remove the visibility condition for unknown context mapping
|
||||
// entries, so the update process itself runs through and users can
|
||||
// fix their block placements manually OR alternatively contributed
|
||||
// modules can run their own update functions to update mappings
|
||||
// that they provide.
|
||||
$backup_values[$context][] = $condition_plugin_id;
|
||||
unset($visibility[$condition_plugin_id]);
|
||||
continue;
|
||||
}
|
||||
// Replace the context ID based on the defined mapping.
|
||||
$condition['context_mapping'][$key] = $context_service_id_map[$context];
|
||||
}
|
||||
}
|
||||
$block->set('visibility', $visibility);
|
||||
|
||||
if ($backup_values) {
|
||||
// We not only store the missing context mappings but also the previous
|
||||
// block status, in order to allow contributed and custom modules to do
|
||||
// their own updates.
|
||||
$update_backup[$block->get('id')] = [
|
||||
'missing_context_ids' => $backup_values,
|
||||
'status' => $block->get('status')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the resulting configuration as trusted data. This avoids issues with
|
||||
// future schema changes.
|
||||
$block->save(TRUE);
|
||||
}
|
||||
|
||||
if ($update_backup) {
|
||||
\Drupal::keyValue('update_backup')->set('block_update_8001', $update_backup);
|
||||
}
|
||||
|
||||
return t('Block context IDs updated.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable all blocks with missing context IDs in block_update_8001().
|
||||
*/
|
||||
function block_update_8002() {
|
||||
$block_update_8001 = \Drupal::keyValue('update_backup')->get('block_update_8001', []);
|
||||
|
||||
$block_ids = array_keys($block_update_8001);
|
||||
$config_factory = \Drupal::configFactory();
|
||||
/** @var \Drupal\Core\Config\Config[] $blocks */
|
||||
$blocks = [];
|
||||
foreach ($block_ids as $block_id) {
|
||||
$blocks[$block_id] = $block = $config_factory->getEditable('block.block.' . $block_id);
|
||||
// This block will have an invalid context mapping service and must be
|
||||
// disabled in order to prevent information disclosure.
|
||||
|
||||
// Disable currently enabled blocks.
|
||||
if ($block_update_8001[$block_id]['status']) {
|
||||
$block->set('status', FALSE);
|
||||
$block->save(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
// Provides a list of plugin labels, keyed by plugin ID.
|
||||
$condition_plugin_id_label_map = array_column(\Drupal::service('plugin.manager.condition')->getDefinitions(), 'label', 'id');
|
||||
|
||||
// Override with the UI labels we are aware of. Sadly they are not machine
|
||||
// accessible, see
|
||||
// \Drupal\node\Plugin\Condition\NodeType::buildConfigurationForm().
|
||||
$condition_plugin_id_label_map['node_type'] = t('Content types');
|
||||
$condition_plugin_id_label_map['request_path'] = t('Pages');
|
||||
$condition_plugin_id_label_map['user_role'] = t('Roles');
|
||||
|
||||
if (count($block_ids) > 0) {
|
||||
$message = t('Encountered an unknown context mapping key coming probably from a contributed or custom module: One or more mappings could not be updated. Please manually review your visibility settings for the following blocks, which are disabled now:');
|
||||
$message .= '<ul>';
|
||||
foreach ($blocks as $disabled_block_id => $disabled_block) {
|
||||
$message .= '<li>' . t('@label (Visibility: @plugin_ids)', array(
|
||||
'@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']))))
|
||||
)) . '</li>';
|
||||
}
|
||||
$message .= '</ul>';
|
||||
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup updates-8.0.0-beta".
|
||||
*/
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
use Drupal\block\BlockInterface;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\language\ConfigurableLanguageInterface;
|
||||
|
@ -58,9 +57,6 @@ function block_theme() {
|
|||
'block' => array(
|
||||
'render element' => 'elements',
|
||||
),
|
||||
'block_list' => array(
|
||||
'render element' => 'form',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -85,45 +81,6 @@ function block_page_top(array &$page_top) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of block class instances by theme.
|
||||
*
|
||||
* @param $theme
|
||||
* The theme to rehash blocks for. If not provided, defaults to the currently
|
||||
* used theme.
|
||||
*
|
||||
* @return
|
||||
* Blocks currently exported by modules.
|
||||
*/
|
||||
function _block_rehash($theme = NULL) {
|
||||
$theme = $theme ? $theme : \Drupal::config('system.theme')->get('default');
|
||||
$regions = system_region_list($theme);
|
||||
$blocks = entity_load_multiple_by_properties('block', array('theme' => $theme));
|
||||
foreach ($blocks as $block_id => $block) {
|
||||
// Remove any invalid block from the list.
|
||||
// @todo Remove this check as part of https://www.drupal.org/node/1776830.
|
||||
if (!$block->getPlugin()) {
|
||||
unset($blocks[$block_id]);
|
||||
continue;
|
||||
}
|
||||
$region = $block->getRegion();
|
||||
$status = $block->status();
|
||||
// Disable blocks in invalid regions.
|
||||
if (!empty($region) && $region != BlockInterface::BLOCK_REGION_NONE && !isset($regions[$region]) && $status) {
|
||||
drupal_set_message(t('The block %info was assigned to the invalid region %region and has been disabled.', array('%info' => $block_id, '%region' => $region)), 'warning');
|
||||
// Disabled blocks are moved into the BlockInterface::BLOCK_REGION_NONE
|
||||
// later so no need to move the block to another region.
|
||||
$block->disable()->save();
|
||||
}
|
||||
// Set region to none if not enabled.
|
||||
if (!$status && $region != BlockInterface::BLOCK_REGION_NONE) {
|
||||
$block->setRegion(BlockInterface::BLOCK_REGION_NONE);
|
||||
$block->save();
|
||||
}
|
||||
}
|
||||
return $blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes blocks for installed themes.
|
||||
*
|
||||
|
@ -177,9 +134,26 @@ function block_theme_initialize($theme) {
|
|||
* Implements hook_rebuild().
|
||||
*/
|
||||
function block_rebuild() {
|
||||
foreach (\Drupal::service('theme_handler')->listInfo() as $name => $data) {
|
||||
foreach (\Drupal::service('theme_handler')->listInfo() as $theme => $data) {
|
||||
if ($data->status) {
|
||||
_block_rehash($name);
|
||||
$regions = system_region_list($theme);
|
||||
/** @var \Drupal\block\BlockInterface[] $blocks */
|
||||
$blocks = entity_load_multiple_by_properties('block', ['theme' => $theme]);
|
||||
foreach ($blocks as $block_id => $block) {
|
||||
// Disable blocks in invalid regions.
|
||||
$region = $block->getRegion();
|
||||
if ($region !== BlockInterface::BLOCK_REGION_NONE) {
|
||||
if (!empty($region) && !isset($regions[$region]) && $block->status()) {
|
||||
drupal_set_message(t('The block %info was assigned to the invalid region %region and has been disabled.', ['%info' => $block_id, '%region' => $region]), 'warning');
|
||||
$block->disable();
|
||||
}
|
||||
// Set region to none if not enabled.
|
||||
if (!$block->status()) {
|
||||
$block->setRegion(BlockInterface::BLOCK_REGION_NONE);
|
||||
$block->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -307,13 +281,3 @@ function block_configurable_language_delete(ConfigurableLanguageInterface $langu
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function block_install() {
|
||||
// Because the Block module upon installation unconditionally overrides all
|
||||
// HTML output by selecting a different page display variant, we must
|
||||
// invalidate all cached HTML output.
|
||||
Cache::invalidateTags(['rendered']);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,15 @@ block.admin_display_theme:
|
|||
_access_theme: 'TRUE'
|
||||
_permission: 'administer blocks'
|
||||
|
||||
block.admin_library:
|
||||
path: 'admin/structure/block/library/{theme}'
|
||||
defaults:
|
||||
_controller: '\Drupal\block\Controller\BlockLibraryController::listBlocks'
|
||||
_title: 'Place block'
|
||||
requirements:
|
||||
_access_theme: 'TRUE'
|
||||
_permission: 'administer blocks'
|
||||
|
||||
block.admin_add:
|
||||
path: '/admin/structure/block/add/{plugin_id}/{theme}'
|
||||
defaults:
|
||||
|
|
|
@ -7,21 +7,6 @@ services:
|
|||
class: Drupal\block\EventSubscriber\BlockPageDisplayVariantSubscriber
|
||||
tags:
|
||||
- { name: event_subscriber }
|
||||
block.current_user_context:
|
||||
class: Drupal\block\EventSubscriber\CurrentUserContext
|
||||
arguments: ['@current_user', '@entity.manager']
|
||||
tags:
|
||||
- { name: 'event_subscriber' }
|
||||
block.current_language_context:
|
||||
class: Drupal\block\EventSubscriber\CurrentLanguageContext
|
||||
arguments: ['@language_manager']
|
||||
tags:
|
||||
- { name: 'event_subscriber' }
|
||||
block.node_route_context:
|
||||
class: Drupal\block\EventSubscriber\NodeRouteContext
|
||||
arguments: ['@current_route_match']
|
||||
tags:
|
||||
- { name: 'event_subscriber' }
|
||||
block.repository:
|
||||
class: Drupal\block\BlockRepository
|
||||
arguments: ['@entity.manager', '@theme.manager', '@context.handler']
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
/* Block listing page */
|
||||
.region-title .button {
|
||||
margin-left: 1em; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .region-title .button {
|
||||
margin-left: 0;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
/* Block demo mode */
|
||||
.block-region {
|
||||
background-color: #ff6;
|
||||
margin-top: 4px;
|
||||
|
@ -22,87 +32,10 @@ a.block-demo-backlink:hover {
|
|||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.layout-region {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.block-list-secondary {
|
||||
border: 1px solid #bfbfbf;
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
.block-list {
|
||||
padding: 0 0.75em;
|
||||
margin: 0;
|
||||
}
|
||||
.block-list li {
|
||||
list-style: none;
|
||||
padding: 0.1em 0;
|
||||
}
|
||||
.block-list a:before {
|
||||
content: '+ ';
|
||||
}
|
||||
.block-list-secondary .form-type-search {
|
||||
padding: 0 1em;
|
||||
}
|
||||
/* Configure block form - Block description */
|
||||
.block-form .form-item-settings-admin-label label {
|
||||
display: inline;
|
||||
}
|
||||
.block-form .form-item-settings-admin-label label:after {
|
||||
content: ':';
|
||||
}
|
||||
|
||||
/* Wide screens */
|
||||
@media
|
||||
screen and (min-width: 780px),
|
||||
(orientation: landscape) and (min-device-height: 780px) {
|
||||
|
||||
.block-list-primary {
|
||||
float: left; /* LTR */
|
||||
width: 75%;
|
||||
padding-right: 2em;
|
||||
}
|
||||
[dir="rtl"] .block-list-primary {
|
||||
float: right;
|
||||
padding-left: 2em;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.block-list-secondary {
|
||||
float: right; /* LTR */
|
||||
width: 25%;
|
||||
}
|
||||
[dir="rtl"] .block-list-secondary {
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* @todo File an issue to add a standard class to all text-like inputs */
|
||||
.block-list-secondary .form-autocomplete,
|
||||
.block-list-secondary .form-text,
|
||||
.block-list-secondary .form-tel,
|
||||
.block-list-secondary .form-email,
|
||||
.block-list-secondary .form-url,
|
||||
.block-list-secondary .form-search,
|
||||
.block-list-secondary .form-number,
|
||||
.block-list-secondary .form-color,
|
||||
.block-list-secondary textarea {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The vertical toolbar mode gets triggered for narrow screens, which throws off
|
||||
* the intent of media queries written for the viewport width. When the vertical
|
||||
* toolbar is on, we need to suppress layout for the original media width + the
|
||||
* toolbar width (240px). In this case, 240px + 780px.
|
||||
*/
|
||||
@media
|
||||
screen and (max-width: 1020px) {
|
||||
|
||||
.toolbar-vertical.toolbar-tray-open .block-list-primary,
|
||||
.toolbar-vertical.toolbar-tray-open .block-list-secondary {
|
||||
float: none;
|
||||
width: auto;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,66 +19,38 @@
|
|||
Drupal.behaviors.blockFilterByText = {
|
||||
attach: function (context, settings) {
|
||||
var $input = $('input.block-filter-text').once('block-filter-text');
|
||||
var $element = $($input.attr('data-element'));
|
||||
var $blocks;
|
||||
var $details;
|
||||
var $table = $($input.attr('data-element'));
|
||||
var $filter_rows;
|
||||
|
||||
/**
|
||||
* Hides the `<details>` element for a category if it has no visible blocks.
|
||||
*
|
||||
* @param {number} index
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
function hideCategoryDetails(index, element) {
|
||||
var $catDetails = $(element);
|
||||
$catDetails.toggle($catDetails.find('li:visible').length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the block list.
|
||||
*
|
||||
* @param {jQuery.Event} e
|
||||
*/
|
||||
function filterBlockList(e) {
|
||||
var query = $(e.target).val().toLowerCase();
|
||||
|
||||
/**
|
||||
* Shows or hides the block entry based on the query.
|
||||
*
|
||||
* @param {number} index
|
||||
* @param {HTMLElement} block
|
||||
* @param {number} index The index of the block.
|
||||
* @param {HTMLElement} label The label of the block.
|
||||
*/
|
||||
function showBlockEntry(index, block) {
|
||||
var $block = $(block);
|
||||
var $sources = $block.find('.block-filter-text-source');
|
||||
var textMatch = $sources.text().toLowerCase().indexOf(query) !== -1;
|
||||
$block.toggle(textMatch);
|
||||
function toggleBlockEntry(index, label) {
|
||||
var $label = $(label);
|
||||
var $row = $label.parent().parent();
|
||||
var textMatch = $label.text().toLowerCase().indexOf(query) !== -1;
|
||||
$row.toggle(textMatch);
|
||||
}
|
||||
|
||||
// Filter if the length of the query is at least 2 characters.
|
||||
if (query.length >= 2) {
|
||||
$blocks.each(showBlockEntry);
|
||||
|
||||
// Note that we first open all <details> to be able to use ':visible'.
|
||||
// Mark the <details> elements that were closed before filtering, so
|
||||
// they can be reclosed when filtering is removed.
|
||||
$details.not('[open]').attr('data-drupal-block-state', 'forced-open');
|
||||
// Hide the category <details> if they don't have any visible rows.
|
||||
$details.attr('open', 'open').each(hideCategoryDetails);
|
||||
$filter_rows.each(toggleBlockEntry);
|
||||
}
|
||||
else {
|
||||
$blocks.show();
|
||||
$details.show();
|
||||
// Return <details> elements that had been closed before filtering
|
||||
// to a closed state.
|
||||
$details.filter('[data-drupal-block-state="forced-open"]').removeAttr('open data-drupal-block-state');
|
||||
$filter_rows.each(function (index) {
|
||||
$(this).parent().parent().show();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ($element.length) {
|
||||
$details = $element.find('details');
|
||||
$blocks = $details.find('li');
|
||||
|
||||
if ($table.length) {
|
||||
$filter_rows = $table.find('div.block-filter-text-source');
|
||||
$input.on('keyup', filterBlockList);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
var $checkboxes = $(context).find('input[type="checkbox"]:checked + label');
|
||||
var il = $checkboxes.length;
|
||||
for (var i = 0; i < il; i++) {
|
||||
vals.push($($checkboxes[i]).text());
|
||||
vals.push($($checkboxes[i]).html());
|
||||
}
|
||||
if (!vals.length) {
|
||||
vals.push(Drupal.t('Not restricted'));
|
||||
|
|
|
@ -92,11 +92,3 @@ migration_dependencies:
|
|||
- d6_menu
|
||||
- d6_custom_block
|
||||
- d6_user_role
|
||||
dependencies:
|
||||
config:
|
||||
- migrate.migration.d6_custom_block
|
||||
- migrate.migration.d6_menu
|
||||
- migrate.migration.d6_user_role
|
||||
module:
|
||||
- block
|
||||
- migrate_drupal
|
|
@ -9,6 +9,8 @@ namespace Drupal\block;
|
|||
|
||||
use Drupal\Component\Plugin\Exception\ContextException;
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Condition\ConditionAccessResolverTrait;
|
||||
use Drupal\Core\Entity\EntityAccessControlHandler;
|
||||
use Drupal\Core\Entity\EntityHandlerInterface;
|
||||
|
@ -16,6 +18,7 @@ use Drupal\Core\Entity\EntityInterface;
|
|||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Executable\ExecutableManagerInterface;
|
||||
use Drupal\Core\Plugin\Context\ContextHandlerInterface;
|
||||
use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
@ -43,6 +46,13 @@ class BlockAccessControlHandler extends EntityAccessControlHandler implements En
|
|||
*/
|
||||
protected $contextHandler;
|
||||
|
||||
/**
|
||||
* The context manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface
|
||||
*/
|
||||
protected $contextRepository;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -50,7 +60,8 @@ class BlockAccessControlHandler extends EntityAccessControlHandler implements En
|
|||
return new static(
|
||||
$entity_type,
|
||||
$container->get('plugin.manager.condition'),
|
||||
$container->get('context.handler')
|
||||
$container->get('context.handler'),
|
||||
$container->get('context.repository')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -63,11 +74,14 @@ class BlockAccessControlHandler extends EntityAccessControlHandler implements En
|
|||
* The ConditionManager for checking visibility of blocks.
|
||||
* @param \Drupal\Core\Plugin\Context\ContextHandlerInterface $context_handler
|
||||
* The ContextHandler for applying contexts to conditions properly.
|
||||
* @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository
|
||||
* The lazy context repository service.
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type, ExecutableManagerInterface $manager, ContextHandlerInterface $context_handler) {
|
||||
public function __construct(EntityTypeInterface $entity_type, ExecutableManagerInterface $manager, ContextHandlerInterface $context_handler, ContextRepositoryInterface $context_repository ) {
|
||||
parent::__construct($entity_type);
|
||||
$this->manager = $manager;
|
||||
$this->contextHandler = $context_handler;
|
||||
$this->contextRepository = $context_repository;
|
||||
}
|
||||
|
||||
|
||||
|
@ -85,33 +99,62 @@ class BlockAccessControlHandler extends EntityAccessControlHandler implements En
|
|||
return AccessResult::forbidden()->cacheUntilEntityChanges($entity);
|
||||
}
|
||||
else {
|
||||
$contexts = $entity->getContexts();
|
||||
$conditions = [];
|
||||
$missing_context = 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 (ContextException $e) {
|
||||
return AccessResult::forbidden()->setCacheMaxAge(0);
|
||||
$missing_context = TRUE;
|
||||
}
|
||||
}
|
||||
$conditions[$condition_id] = $condition;
|
||||
}
|
||||
if ($this->resolveConditions($conditions, 'and') !== FALSE) {
|
||||
|
||||
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.
|
||||
$access = AccessResult::forbidden()->setCacheMaxAge(0);
|
||||
}
|
||||
elseif ($this->resolveConditions($conditions, 'and') !== FALSE) {
|
||||
// Delegate to the plugin.
|
||||
$access = $entity->getPlugin()->access($account, TRUE);
|
||||
}
|
||||
else {
|
||||
$access = AccessResult::forbidden();
|
||||
}
|
||||
// This should not be hardcoded to an uncacheable access check result, but
|
||||
// in order to fix that, we need condition plugins to return cache contexts,
|
||||
// otherwise it will be impossible to determine by which cache contexts the
|
||||
// result should be varied.
|
||||
// @todo Change this to use $access->cacheUntilEntityChanges($entity) once
|
||||
// https://www.drupal.org/node/2375695 is resolved.
|
||||
return $access->setCacheMaxAge(0);
|
||||
|
||||
$this->mergeCacheabilityFromConditions($access, $conditions);
|
||||
|
||||
// Ensure that access is evaluated again when the block changes.
|
||||
return $access->cacheUntilEntityChanges($entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges cacheable metadata from conditions onto the access result object.
|
||||
*
|
||||
* @param \Drupal\Core\Access\AccessResult $access
|
||||
* The access result object.
|
||||
* @param \Drupal\Core\Condition\ConditionInterface[] $conditions
|
||||
* List of visibility conditions.
|
||||
*/
|
||||
protected function mergeCacheabilityFromConditions(AccessResult $access, array $conditions) {
|
||||
foreach ($conditions as $condition) {
|
||||
if ($condition instanceof CacheableDependencyInterface) {
|
||||
$access->addCacheTags($condition->getCacheTags());
|
||||
$access->addCacheContexts($condition->getCacheContexts());
|
||||
$access->setCacheMaxAge(Cache::mergeMaxAges($access->getCacheMaxAge(), $condition->getCacheMaxAge()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
namespace Drupal\block;
|
||||
|
||||
use Drupal\block\Event\BlockContextEvent;
|
||||
use Drupal\block\Event\BlockEvents;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Entity\EntityForm;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
|
@ -18,8 +16,8 @@ use Drupal\Core\Form\FormState;
|
|||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginInterface;
|
||||
use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* Provides form for block instance forms.
|
||||
|
@ -68,6 +66,13 @@ class BlockForm extends EntityForm {
|
|||
*/
|
||||
protected $themeHandler;
|
||||
|
||||
/**
|
||||
* The context repository service.
|
||||
*
|
||||
* @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface
|
||||
*/
|
||||
protected $contextRepository;
|
||||
|
||||
/**
|
||||
* Constructs a BlockForm object.
|
||||
*
|
||||
|
@ -75,17 +80,17 @@ class BlockForm extends EntityForm {
|
|||
* The entity manager.
|
||||
* @param \Drupal\Core\Executable\ExecutableManagerInterface $manager
|
||||
* The ConditionManager for building the visibility UI.
|
||||
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
|
||||
* The EventDispatcher for gathering administrative contexts.
|
||||
* @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository
|
||||
* The lazy context repository service.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language
|
||||
* The language manager.
|
||||
* @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
|
||||
* The theme handler.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager, ExecutableManagerInterface $manager, EventDispatcherInterface $dispatcher, LanguageManagerInterface $language, ThemeHandlerInterface $theme_handler) {
|
||||
public function __construct(EntityManagerInterface $entity_manager, ExecutableManagerInterface $manager, ContextRepositoryInterface $context_repository, LanguageManagerInterface $language, ThemeHandlerInterface $theme_handler) {
|
||||
$this->storage = $entity_manager->getStorage('block');
|
||||
$this->manager = $manager;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->contextRepository = $context_repository;
|
||||
$this->language = $language;
|
||||
$this->themeHandler = $theme_handler;
|
||||
}
|
||||
|
@ -97,7 +102,7 @@ class BlockForm extends EntityForm {
|
|||
return new static(
|
||||
$container->get('entity.manager'),
|
||||
$container->get('plugin.manager.condition'),
|
||||
$container->get('event_dispatcher'),
|
||||
$container->get('context.repository'),
|
||||
$container->get('language_manager'),
|
||||
$container->get('theme_handler')
|
||||
);
|
||||
|
@ -117,7 +122,7 @@ class BlockForm extends EntityForm {
|
|||
|
||||
// Store the gathered contexts in the form state for other objects to use
|
||||
// during form building.
|
||||
$form_state->setTemporaryValue('gathered_contexts', $this->dispatcher->dispatch(BlockEvents::ADMINISTRATIVE_CONTEXT, new BlockContextEvent())->getContexts());
|
||||
$form_state->setTemporaryValue('gathered_contexts', $this->contextRepository->getAvailableContexts());
|
||||
|
||||
$form['#tree'] = TRUE;
|
||||
$form['settings'] = $entity->getPlugin()->buildConfigurationForm(array(), $form_state);
|
||||
|
@ -165,11 +170,13 @@ class BlockForm extends EntityForm {
|
|||
}
|
||||
|
||||
// Region settings.
|
||||
$entity_region = $entity->getRegion();
|
||||
$region = $entity->isNew() ? $this->getRequest()->query->get('region', $entity_region) : $entity_region;
|
||||
$form['region'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Region'),
|
||||
'#description' => $this->t('Select the region where this block should be displayed.'),
|
||||
'#default_value' => $entity->getRegion(),
|
||||
'#default_value' => $region,
|
||||
'#empty_value' => BlockInterface::BLOCK_REGION_NONE,
|
||||
'#options' => system_region_list($theme, REGIONS_VISIBLE),
|
||||
'#prefix' => '<div id="edit-block-region-wrapper">',
|
||||
|
@ -273,8 +280,8 @@ class BlockForm extends EntityForm {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate(array $form, FormStateInterface $form_state) {
|
||||
parent::validate($form, $form_state);
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::validateForm($form, $form_state);
|
||||
|
||||
// The Block Entity form puts all block plugin form elements in the
|
||||
// settings form element, so just pass that to the block for validation.
|
||||
|
|
|
@ -95,24 +95,6 @@ interface BlockInterface extends ConfigEntityInterface {
|
|||
*/
|
||||
public function setVisibilityConfig($instance_id, array $configuration);
|
||||
|
||||
/**
|
||||
* Get all available contexts.
|
||||
*
|
||||
* @return \Drupal\Component\Plugin\Context\ContextInterface[]
|
||||
* An array of set contexts, keyed by context name.
|
||||
*/
|
||||
public function getContexts();
|
||||
|
||||
/**
|
||||
* Set the contexts that are available for use within the block entity.
|
||||
*
|
||||
* @param \Drupal\Component\Plugin\Context\ContextInterface[] $contexts
|
||||
* An array of contexts to set on the block.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setContexts(array $contexts);
|
||||
|
||||
/**
|
||||
* Returns the weight of this block (used for sorting).
|
||||
*
|
||||
|
|
|
@ -8,15 +8,16 @@
|
|||
namespace Drupal\block;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Block\BlockManagerInterface;
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Form\FormInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Theme\ThemeManagerInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
@ -28,13 +29,6 @@ use Symfony\Component\HttpFoundation\Request;
|
|||
*/
|
||||
class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface {
|
||||
|
||||
/**
|
||||
* The regions containing the blocks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $regions;
|
||||
|
||||
/**
|
||||
* The theme containing the blocks.
|
||||
*
|
||||
|
@ -50,11 +44,23 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
|
|||
protected $request;
|
||||
|
||||
/**
|
||||
* The block manager.
|
||||
* The theme manager.
|
||||
*
|
||||
* @var \Drupal\Core\Block\BlockManagerInterface
|
||||
* @var \Drupal\Core\Theme\ThemeManagerInterface
|
||||
*/
|
||||
protected $blockManager;
|
||||
protected $themeManager;
|
||||
|
||||
/**
|
||||
* The form builder.
|
||||
*
|
||||
* @var \Drupal\Core\Form\FormBuilderInterface
|
||||
*/
|
||||
protected $formBuilder;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $limit = FALSE;
|
||||
|
||||
/**
|
||||
* Constructs a new BlockListBuilder object.
|
||||
|
@ -63,13 +69,16 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
|
|||
* The entity type definition.
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
|
||||
* The entity storage class.
|
||||
* @param \Drupal\Core\Block\BlockManagerInterface $block_manager
|
||||
* The block manager.
|
||||
* @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
|
||||
* The theme manager.
|
||||
* @param \Drupal\Core\Form\FormBuilderInterface $form_builder
|
||||
* The form builder.
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, BlockManagerInterface $block_manager) {
|
||||
public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, ThemeManagerInterface $theme_manager, FormBuilderInterface $form_builder) {
|
||||
parent::__construct($entity_type, $storage);
|
||||
|
||||
$this->blockManager = $block_manager;
|
||||
$this->themeManager = $theme_manager;
|
||||
$this->formBuilder = $form_builder;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,31 +88,11 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
|
|||
return new static(
|
||||
$entity_type,
|
||||
$container->get('entity.manager')->getStorage($entity_type->id()),
|
||||
$container->get('plugin.manager.block')
|
||||
$container->get('theme.manager'),
|
||||
$container->get('form_builder')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load() {
|
||||
// If no theme was specified, use the current theme.
|
||||
if (!$this->theme) {
|
||||
$this->theme = \Drupal::theme()->getActiveTheme()->getName();
|
||||
}
|
||||
|
||||
// Store the region list.
|
||||
$this->regions = system_region_list($this->theme, REGIONS_VISIBLE);
|
||||
|
||||
// Load only blocks for this theme, and sort them.
|
||||
// @todo Move the functionality of _block_rehash() out of the listing page.
|
||||
$entities = _block_rehash($this->theme);
|
||||
|
||||
// Sort the blocks using \Drupal\block\Entity\Block::sort().
|
||||
uasort($entities, array($this->entityType->getClass(), 'sort'));
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
|
@ -118,10 +107,9 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
|
|||
*/
|
||||
public function render($theme = NULL, Request $request = NULL) {
|
||||
$this->request = $request;
|
||||
// If no theme was specified, use the current theme.
|
||||
$this->theme = $theme ?: \Drupal::theme()->getActiveTheme()->getName();
|
||||
$this->theme = $theme;
|
||||
|
||||
return \Drupal::formBuilder()->getForm($this);
|
||||
return $this->formBuilder->getForm($this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,55 +120,40 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Form\FormInterface::buildForm().
|
||||
*
|
||||
* Form constructor for the main block administration form.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$placement = FALSE;
|
||||
if ($this->request->query->has('block-placement')) {
|
||||
$placement = $this->request->query->get('block-placement');
|
||||
$form['#attached']['drupalSettings']['blockPlacement'] = $placement;
|
||||
}
|
||||
$entities = $this->load();
|
||||
$form['#theme'] = array('block_list');
|
||||
$form['#attached']['library'][] = 'core/drupal.tableheader';
|
||||
$form['#attached']['library'][] = 'block/drupal.block';
|
||||
$form['#attached']['library'][] = 'block/drupal.block.admin';
|
||||
$form['#attributes']['class'][] = 'clearfix';
|
||||
|
||||
// Add a last region for disabled blocks.
|
||||
$block_regions_with_disabled = $this->regions + array(BlockInterface::BLOCK_REGION_NONE => BlockInterface::BLOCK_REGION_NONE);
|
||||
$form['block_regions'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $block_regions_with_disabled,
|
||||
);
|
||||
|
||||
// Weights range from -delta to +delta, so delta should be at least half
|
||||
// of the amount of blocks present. This makes sure all blocks in the same
|
||||
// region get an unique weight.
|
||||
$weight_delta = round(count($entities) / 2);
|
||||
|
||||
// Build the form tree.
|
||||
$form['edited_theme'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $this->theme,
|
||||
$form['blocks'] = $this->buildBlocksForm();
|
||||
|
||||
$form['actions'] = array(
|
||||
'#tree' => FALSE,
|
||||
'#type' => 'actions',
|
||||
);
|
||||
$form['blocks'] = array(
|
||||
'#type' => 'table',
|
||||
'#header' => array(
|
||||
t('Block'),
|
||||
t('Category'),
|
||||
t('Region'),
|
||||
t('Weight'),
|
||||
t('Operations'),
|
||||
),
|
||||
'#attributes' => array(
|
||||
'id' => 'blocks',
|
||||
),
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save blocks'),
|
||||
'#button_type' => 'primary',
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the main "Blocks" portion of the form.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function buildBlocksForm() {
|
||||
// Build blocks first for each region.
|
||||
$blocks = [];
|
||||
$entities = $this->load();
|
||||
/** @var \Drupal\block\BlockInterface[] $entities */
|
||||
foreach ($entities as $entity_id => $entity) {
|
||||
$definition = $entity->getPlugin()->getPluginDefinition();
|
||||
$blocks[$entity->getRegion()][$entity_id] = array(
|
||||
|
@ -192,36 +165,73 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
|
|||
);
|
||||
}
|
||||
|
||||
$form = array(
|
||||
'#type' => 'table',
|
||||
'#header' => array(
|
||||
$this->t('Block'),
|
||||
$this->t('Category'),
|
||||
$this->t('Region'),
|
||||
$this->t('Weight'),
|
||||
$this->t('Operations'),
|
||||
),
|
||||
'#attributes' => array(
|
||||
'id' => 'blocks',
|
||||
),
|
||||
);
|
||||
|
||||
// Weights range from -delta to +delta, so delta should be at least half
|
||||
// of the amount of blocks present. This makes sure all blocks in the same
|
||||
// region get an unique weight.
|
||||
$weight_delta = round(count($entities) / 2);
|
||||
|
||||
$placement = FALSE;
|
||||
if ($this->request->query->has('block-placement')) {
|
||||
$placement = $this->request->query->get('block-placement');
|
||||
$form['#attached']['drupalSettings']['blockPlacement'] = $placement;
|
||||
}
|
||||
|
||||
// Loop over each region and build blocks.
|
||||
$regions = $this->systemRegionList($this->getThemeName(), REGIONS_VISIBLE);
|
||||
$block_regions_with_disabled = $regions + array(BlockInterface::BLOCK_REGION_NONE => $this->t('Disabled', array(), array('context' => 'Plural')));
|
||||
foreach ($block_regions_with_disabled as $region => $title) {
|
||||
$form['blocks']['#tabledrag'][] = array(
|
||||
$form['#tabledrag'][] = array(
|
||||
'action' => 'match',
|
||||
'relationship' => 'sibling',
|
||||
'group' => 'block-region-select',
|
||||
'subgroup' => 'block-region-' . $region,
|
||||
'hidden' => FALSE,
|
||||
);
|
||||
$form['blocks']['#tabledrag'][] = array(
|
||||
$form['#tabledrag'][] = array(
|
||||
'action' => 'order',
|
||||
'relationship' => 'sibling',
|
||||
'group' => 'block-weight',
|
||||
'subgroup' => 'block-weight-' . $region,
|
||||
);
|
||||
|
||||
$form['blocks'][$region] = array(
|
||||
$form['region-' . $region] = array(
|
||||
'#attributes' => array(
|
||||
'class' => array('region-title', 'region-title-' . $region),
|
||||
'no_striping' => TRUE,
|
||||
),
|
||||
);
|
||||
$form['blocks'][$region]['title'] = array(
|
||||
'#markup' => $region != BlockInterface::BLOCK_REGION_NONE ? $title : t('Disabled', array(), array('context' => 'Plural')),
|
||||
$form['region-' . $region]['title'] = array(
|
||||
'#prefix' => $region != BlockInterface::BLOCK_REGION_NONE ? $title : $block_regions_with_disabled[$region],
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('Place block <span class="visually-hidden">in the %region region</span>', ['%region' => $block_regions_with_disabled[$region]]),
|
||||
'#url' => Url::fromRoute('block.admin_library', ['theme' => $this->getThemeName()], ['query' => ['region' => $region]]),
|
||||
'#wrapper_attributes' => array(
|
||||
'colspan' => 5,
|
||||
),
|
||||
'#attributes' => [
|
||||
'class' => ['use-ajax', 'button', 'button--small'],
|
||||
'data-dialog-type' => 'modal',
|
||||
'data-dialog-options' => Json::encode([
|
||||
'width' => 700,
|
||||
]),
|
||||
],
|
||||
);
|
||||
|
||||
$form['blocks'][$region . '-message'] = array(
|
||||
$form['region-' . $region . '-message'] = array(
|
||||
'#attributes' => array(
|
||||
'class' => array(
|
||||
'region-message',
|
||||
|
@ -230,8 +240,8 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
|
|||
),
|
||||
),
|
||||
);
|
||||
$form['blocks'][$region . '-message']['message'] = array(
|
||||
'#markup' => '<em>' . t('No blocks in this region') . '</em>',
|
||||
$form['region-' . $region . '-message']['message'] = array(
|
||||
'#markup' => '<em>' . $this->t('No blocks in this region') . '</em>',
|
||||
'#wrapper_attributes' => array(
|
||||
'colspan' => 5,
|
||||
),
|
||||
|
@ -241,137 +251,87 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
|
|||
foreach ($blocks[$region] as $info) {
|
||||
$entity_id = $info['entity_id'];
|
||||
|
||||
$form['blocks'][$entity_id] = array(
|
||||
$form[$entity_id] = array(
|
||||
'#attributes' => array(
|
||||
'class' => array('draggable'),
|
||||
),
|
||||
);
|
||||
if ($placement && $placement == Html::getClass($entity_id)) {
|
||||
$form['blocks'][$entity_id]['#attributes']['class'][] = 'color-warning';
|
||||
$form['blocks'][$entity_id]['#attributes']['class'][] = 'js-block-placed';
|
||||
$form[$entity_id]['#attributes']['class'][] = 'color-warning';
|
||||
$form[$entity_id]['#attributes']['class'][] = 'js-block-placed';
|
||||
}
|
||||
$form['blocks'][$entity_id]['info'] = array(
|
||||
$form[$entity_id]['info'] = array(
|
||||
'#markup' => SafeMarkup::checkPlain($info['label']),
|
||||
'#wrapper_attributes' => array(
|
||||
'class' => array('block'),
|
||||
),
|
||||
);
|
||||
$form['blocks'][$entity_id]['type'] = array(
|
||||
$form[$entity_id]['type'] = array(
|
||||
'#markup' => $info['category'],
|
||||
);
|
||||
$form['blocks'][$entity_id]['region-theme']['region'] = array(
|
||||
$form[$entity_id]['region-theme']['region'] = array(
|
||||
'#type' => 'select',
|
||||
'#default_value' => $region,
|
||||
'#empty_value' => BlockInterface::BLOCK_REGION_NONE,
|
||||
'#title' => t('Region for @block block', array('@block' => $info['label'])),
|
||||
'#title' => $this->t('Region for @block block', array('@block' => $info['label'])),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => $this->regions,
|
||||
'#options' => $regions,
|
||||
'#attributes' => array(
|
||||
'class' => array('block-region-select', 'block-region-' . $region),
|
||||
),
|
||||
'#parents' => array('blocks', $entity_id, 'region'),
|
||||
);
|
||||
$form['blocks'][$entity_id]['region-theme']['theme'] = array(
|
||||
$form[$entity_id]['region-theme']['theme'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $this->theme,
|
||||
'#value' => $this->getThemeName(),
|
||||
'#parents' => array('blocks', $entity_id, 'theme'),
|
||||
);
|
||||
$form['blocks'][$entity_id]['weight'] = array(
|
||||
$form[$entity_id]['weight'] = array(
|
||||
'#type' => 'weight',
|
||||
'#default_value' => $info['weight'],
|
||||
'#delta' => $weight_delta,
|
||||
'#title' => t('Weight for @block block', array('@block' => $info['label'])),
|
||||
'#title' => $this->t('Weight for @block block', array('@block' => $info['label'])),
|
||||
'#title_display' => 'invisible',
|
||||
'#attributes' => array(
|
||||
'class' => array('block-weight', 'block-weight-' . $region),
|
||||
),
|
||||
);
|
||||
$form['blocks'][$entity_id]['operations'] = $this->buildOperations($info['entity']);
|
||||
$form[$entity_id]['operations'] = $this->buildOperations($info['entity']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do not allow disabling the main system content block when it is present.
|
||||
if (isset($form['blocks']['system_main']['region'])) {
|
||||
$form['blocks']['system_main']['region']['#required'] = TRUE;
|
||||
}
|
||||
|
||||
$form['actions'] = array(
|
||||
'#tree' => FALSE,
|
||||
'#type' => 'actions',
|
||||
);
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Save blocks'),
|
||||
'#button_type' => 'primary',
|
||||
);
|
||||
|
||||
$form['place_blocks']['title'] = array(
|
||||
'#type' => 'container',
|
||||
'#markup' => '<h3>' . t('Place blocks') . '</h3>',
|
||||
'#attributes' => array(
|
||||
'class' => array(
|
||||
'entity-meta__header',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$form['place_blocks']['filter'] = array(
|
||||
'#type' => 'search',
|
||||
'#title' => t('Filter'),
|
||||
'#title_display' => 'invisible',
|
||||
'#size' => 30,
|
||||
'#placeholder' => t('Filter by block name'),
|
||||
'#attributes' => array(
|
||||
'class' => array('block-filter-text'),
|
||||
'data-element' => '.entity-meta',
|
||||
'title' => t('Enter a part of the block name to filter by.'),
|
||||
),
|
||||
);
|
||||
|
||||
$form['place_blocks']['list']['#type'] = 'container';
|
||||
$form['place_blocks']['list']['#attributes']['class'][] = 'entity-meta';
|
||||
|
||||
// Only add blocks which work without any available context.
|
||||
$definitions = $this->blockManager->getDefinitionsForContexts();
|
||||
$sorted_definitions = $this->blockManager->getSortedDefinitions($definitions);
|
||||
foreach ($sorted_definitions as $plugin_id => $plugin_definition) {
|
||||
$category = SafeMarkup::checkPlain($plugin_definition['category']);
|
||||
$category_key = 'category-' . $category;
|
||||
if (!isset($form['place_blocks']['list'][$category_key])) {
|
||||
$form['place_blocks']['list'][$category_key] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $category,
|
||||
'#open' => TRUE,
|
||||
'content' => array(
|
||||
'#theme' => 'links',
|
||||
'#links' => array(),
|
||||
'#attributes' => array(
|
||||
'class' => array(
|
||||
'block-list',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
$form['place_blocks']['list'][$category_key]['content']['#links'][$plugin_id] = array(
|
||||
'title' => $plugin_definition['admin_label'],
|
||||
'url' => Url::fromRoute('block.admin_add', [
|
||||
'plugin_id' => $plugin_id,
|
||||
'theme' => $this->theme
|
||||
]),
|
||||
'attributes' => array(
|
||||
'class' => array('use-ajax', 'block-filter-text-source'),
|
||||
'data-dialog-type' => 'modal',
|
||||
'data-dialog-options' => Json::encode(array(
|
||||
'width' => 700,
|
||||
)),
|
||||
),
|
||||
);
|
||||
if (isset($form['system_main']['region'])) {
|
||||
$form['system_main']['region']['#required'] = TRUE;
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the theme used for this block listing.
|
||||
*
|
||||
* @return string
|
||||
* The name of the theme.
|
||||
*/
|
||||
protected function getThemeName() {
|
||||
// If no theme was specified, use the current theme.
|
||||
if (!$this->theme) {
|
||||
$this->theme = $this->themeManager->getActiveTheme()->getName();
|
||||
}
|
||||
return $this->theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntityIds() {
|
||||
return $this->getStorage()->getQuery()
|
||||
->condition('theme', $this->getThemeName())
|
||||
->sort($this->entityType->getKey('id'))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -379,26 +339,25 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
|
|||
$operations = parent::getDefaultOperations($entity);
|
||||
|
||||
if (isset($operations['edit'])) {
|
||||
$operations['edit']['title'] = t('Configure');
|
||||
$operations['edit']['title'] = $this->t('Configure');
|
||||
}
|
||||
|
||||
return $operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Form\FormInterface::validateForm().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
// No validation.
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Form\FormInterface::submitForm().
|
||||
*
|
||||
* Form submission handler for the main block administration form.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$entities = $this->storage->loadMultiple(array_keys($form_state->getValue('blocks')));
|
||||
/** @var \Drupal\block\BlockInterface[] $entities */
|
||||
foreach ($entities as $entity_id => $entity) {
|
||||
$entity_values = $form_state->getValue(array('blocks', $entity_id));
|
||||
$entity->setWeight($entity_values['weight']);
|
||||
|
@ -417,4 +376,11 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
|
|||
$this->request->query->remove('block-placement');
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps system_region_list().
|
||||
*/
|
||||
protected function systemRegionList($theme, $show = REGIONS_ALL) {
|
||||
return system_region_list($theme, $show);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ namespace Drupal\block;
|
|||
|
||||
use Drupal\Component\Plugin\Exception\PluginException;
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection;
|
||||
|
||||
/**
|
||||
|
@ -56,7 +55,7 @@ class BlockPluginCollection extends DefaultSingleLazyPluginCollection {
|
|||
*/
|
||||
protected function initializePlugin($instance_id) {
|
||||
if (!$instance_id) {
|
||||
throw new PluginException(SafeMarkup::format("The block '@block' did not specify a plugin.", array('@block' => $this->blockId)));
|
||||
throw new PluginException("The block '{$this->blockId}' did not specify a plugin.");
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\block;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Plugin\Context\ContextHandlerInterface;
|
||||
use Drupal\Core\Theme\ThemeManagerInterface;
|
||||
|
@ -49,7 +50,7 @@ class BlockRepository implements BlockRepositoryInterface {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVisibleBlocksPerRegion(array $contexts) {
|
||||
public function getVisibleBlocksPerRegion(array &$cacheable_metadata = []) {
|
||||
$active_theme = $this->themeManager->getActiveTheme();
|
||||
// Build an array of the region names in the right order.
|
||||
$empty = array_fill_keys($active_theme->getRegions(), array());
|
||||
|
@ -57,9 +58,18 @@ class BlockRepository implements BlockRepositoryInterface {
|
|||
$full = array();
|
||||
foreach ($this->blockStorage->loadByProperties(array('theme' => $active_theme->getName())) as $block_id => $block) {
|
||||
/** @var \Drupal\block\BlockInterface $block */
|
||||
$access = $block->access('view', NULL, TRUE);
|
||||
$region = $block->getRegion();
|
||||
if (!isset($cacheable_metadata[$region])) {
|
||||
$cacheable_metadata[$region] = CacheableMetadata::createFromObject($access);
|
||||
}
|
||||
else {
|
||||
$cacheable_metadata[$region] = $cacheable_metadata[$region]->merge(CacheableMetadata::createFromObject($access));
|
||||
}
|
||||
|
||||
// Set the contexts on the block before checking access.
|
||||
if ($block->setContexts($contexts)->access('view')) {
|
||||
$full[$block->getRegion()][$block_id] = $block;
|
||||
if ($access->isAllowed()) {
|
||||
$full[$region][$block_id] = $block;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,13 +12,14 @@ interface BlockRepositoryInterface {
|
|||
/**
|
||||
* Returns an array of regions and their block entities.
|
||||
*
|
||||
* @param \Drupal\Component\Plugin\Context\ContextInterface[] $contexts
|
||||
* An array of contexts to set on the blocks.
|
||||
* @param \Drupal\Core\Cache\CacheableMetadata[] $cacheable_metadata
|
||||
* (optional) List of CacheableMetadata objects, keyed by region. This is
|
||||
* by reference and is used to pass this information back to the caller.
|
||||
*
|
||||
* @return array
|
||||
* The array is first keyed by region machine name, with the values
|
||||
* containing an array keyed by block ID, with block entities as the values.
|
||||
*/
|
||||
public function getVisibleBlocksPerRegion(array $contexts);
|
||||
public function getVisibleBlocksPerRegion(array &$cacheable_metadata = []);
|
||||
|
||||
}
|
||||
|
|
|
@ -48,6 +48,9 @@ class BlockViewBuilder extends EntityViewBuilder {
|
|||
$derivative_id = $plugin->getDerivativeId();
|
||||
$configuration = $plugin->getConfiguration();
|
||||
|
||||
$cache_tags = Cache::mergeTags($this->getCacheTags(), $entity->getCacheTags());
|
||||
$cache_tags = Cache::mergeTags($cache_tags, $plugin->getCacheTags());
|
||||
|
||||
// Create the render array for the block as a whole.
|
||||
// @see template_preprocess_block().
|
||||
$build[$entity_id] = array(
|
||||
|
@ -67,12 +70,11 @@ class BlockViewBuilder extends EntityViewBuilder {
|
|||
'#id' => $entity->id(),
|
||||
'#cache' => [
|
||||
'keys' => ['entity_view', 'block', $entity->id()],
|
||||
'contexts' => $plugin->getCacheContexts(),
|
||||
'tags' => Cache::mergeTags(
|
||||
$this->getCacheTags(), // Block view builder cache tag.
|
||||
$entity->getCacheTags(), // Block entity cache tag.
|
||||
$plugin->getCacheTags() // Block plugin cache tags.
|
||||
'contexts' => Cache::mergeContexts(
|
||||
$entity->getCacheContexts(),
|
||||
$plugin->getCacheContexts()
|
||||
),
|
||||
'tags' => $cache_tags,
|
||||
'max-age' => $plugin->getCacheMaxAge(),
|
||||
],
|
||||
'#pre_render' => [
|
||||
|
|
179
core/modules/block/src/Controller/BlockLibraryController.php
Normal file
179
core/modules/block/src/Controller/BlockLibraryController.php
Normal file
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\block\Controller\BlockLibraryController.
|
||||
*/
|
||||
|
||||
namespace Drupal\block\Controller;
|
||||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Block\BlockManagerInterface;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||
use Drupal\Core\Menu\LocalActionManagerInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Provides a list of block plugins to be added to the layout.
|
||||
*/
|
||||
class BlockLibraryController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* The block manager.
|
||||
*
|
||||
* @var \Drupal\Core\Block\BlockManagerInterface
|
||||
*/
|
||||
protected $blockManager;
|
||||
|
||||
/**
|
||||
* The route match.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteMatchInterface
|
||||
*/
|
||||
protected $routeMatch;
|
||||
|
||||
/**
|
||||
* The local action manager.
|
||||
*
|
||||
* @var \Drupal\Core\Menu\LocalActionManagerInterface
|
||||
*/
|
||||
protected $localActionManager;
|
||||
|
||||
/**
|
||||
* Constructs a BlockLibraryController object.
|
||||
*
|
||||
* @param \Drupal\Core\Block\BlockManagerInterface $block_manager
|
||||
* The block manager.
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The current route match.
|
||||
* @param \Drupal\Core\Menu\LocalActionManagerInterface $local_action_manager
|
||||
* The local action manager.
|
||||
*/
|
||||
public function __construct(BlockManagerInterface $block_manager, RouteMatchInterface $route_match, LocalActionManagerInterface $local_action_manager) {
|
||||
$this->blockManager = $block_manager;
|
||||
$this->routeMatch = $route_match;
|
||||
$this->localActionManager = $local_action_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('plugin.manager.block'),
|
||||
$container->get('current_route_match'),
|
||||
$container->get('plugin.manager.menu.local_action')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a list of blocks that can be added to a theme's layout.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
* @param string $theme
|
||||
* Theme key of the block list.
|
||||
*
|
||||
* @return array
|
||||
* A render array as expected by the renderer.
|
||||
*/
|
||||
public function listBlocks(Request $request, $theme) {
|
||||
// Since modals do not render any other part of the page, we need to render
|
||||
// them manually as part of this listing.
|
||||
if ($request->query->get(MainContentViewSubscriber::WRAPPER_FORMAT) === 'drupal_modal') {
|
||||
$build['local_actions'] = $this->buildLocalActions();
|
||||
}
|
||||
|
||||
$headers = [
|
||||
['data' => $this->t('Block')],
|
||||
['data' => $this->t('Category')],
|
||||
['data' => $this->t('Operations')],
|
||||
];
|
||||
|
||||
// Only add blocks which work without any available context.
|
||||
$definitions = $this->blockManager->getDefinitionsForContexts();
|
||||
// Order by category, and then by admin label.
|
||||
$definitions = $this->blockManager->getSortedDefinitions($definitions);
|
||||
|
||||
$region = $request->query->get('region');
|
||||
$rows = [];
|
||||
foreach ($definitions as $plugin_id => $plugin_definition) {
|
||||
$row = [];
|
||||
$row['title']['data'] = [
|
||||
'#markup' => $plugin_definition['admin_label'],
|
||||
'#prefix' => '<div class="block-filter-text-source">',
|
||||
'#suffix' => '</div>',
|
||||
];
|
||||
$row['category']['data'] = SafeMarkup::checkPlain($plugin_definition['category']);
|
||||
$links['add'] = [
|
||||
'title' => $this->t('Place block'),
|
||||
'url' => Url::fromRoute('block.admin_add', ['plugin_id' => $plugin_id, 'theme' => $theme]),
|
||||
'attributes' => [
|
||||
'class' => ['use-ajax'],
|
||||
'data-dialog-type' => 'modal',
|
||||
'data-dialog-options' => Json::encode([
|
||||
'width' => 700,
|
||||
]),
|
||||
],
|
||||
];
|
||||
if ($region) {
|
||||
$links['add']['query']['region'] = $region;
|
||||
}
|
||||
$row['operations']['data'] = [
|
||||
'#type' => 'operations',
|
||||
'#links' => $links,
|
||||
];
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
$build['#attached']['library'][] = 'block/drupal.block.admin';
|
||||
|
||||
$build['filter'] = [
|
||||
'#type' => 'search',
|
||||
'#title' => $this->t('Filter'),
|
||||
'#title_display' => 'invisible',
|
||||
'#size' => 30,
|
||||
'#placeholder' => $this->t('Filter by block name'),
|
||||
'#attributes' => [
|
||||
'class' => ['block-filter-text'],
|
||||
'data-element' => '.block-add-table',
|
||||
'title' => $this->t('Enter a part of the block name to filter by.'),
|
||||
],
|
||||
];
|
||||
|
||||
$build['blocks'] = [
|
||||
'#type' => 'table',
|
||||
'#header' => $headers,
|
||||
'#rows' => $rows,
|
||||
'#empty' => $this->t('No blocks available.'),
|
||||
'#attributes' => [
|
||||
'class' => ['block-add-table'],
|
||||
],
|
||||
];
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the local actions for this listing.
|
||||
*
|
||||
* @return array
|
||||
* An array of local actions for this listing.
|
||||
*/
|
||||
protected function buildLocalActions() {
|
||||
$build = $this->localActionManager->getActionsForRoute($this->routeMatch->getRouteName());
|
||||
// Without this workaround, the action links will be rendered as <li> with
|
||||
// no wrapping <ul> element.
|
||||
if (!empty($build)) {
|
||||
$build['#prefix'] = '<ul class="action-links">';
|
||||
$build['#suffix'] = '</ul>';
|
||||
}
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
|
@ -246,25 +246,10 @@ class Block extends ConfigEntityBase implements BlockInterface, EntityWithPlugin
|
|||
// so we must invalidate the associated block's cache tag (which includes
|
||||
// the theme cache tag).
|
||||
if (!$update) {
|
||||
Cache::invalidateTags($this->getCacheTags());
|
||||
Cache::invalidateTags($this->getCacheTagsToInvalidate());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setContexts(array $contexts) {
|
||||
$this->contexts = $contexts;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContexts() {
|
||||
return $this->contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\block\Event\BlockContextEvent.
|
||||
*/
|
||||
|
||||
namespace Drupal\block\Event;
|
||||
|
||||
use Drupal\Core\Plugin\Context\ContextInterface;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event subscribers can add context to be used by the block and its conditions.
|
||||
*
|
||||
* @see \Drupal\block\Event\BlockEvents::ACTIVE_CONTEXT
|
||||
* @see \Drupal\block\Event\BlockEvents::ADMINISTRATIVE_CONTEXT
|
||||
*/
|
||||
class BlockContextEvent extends Event {
|
||||
|
||||
/**
|
||||
* The array of available contexts for blocks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $contexts = [];
|
||||
|
||||
/**
|
||||
* Sets the context object for a given name.
|
||||
*
|
||||
* @param string $name
|
||||
* The name to store the context object under.
|
||||
* @param \Drupal\Core\Plugin\Context\ContextInterface $context
|
||||
* The context object to set.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setContext($name, ContextInterface $context) {
|
||||
$this->contexts[$name] = $context;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context objects.
|
||||
*
|
||||
* @return \Drupal\Component\Plugin\Context\ContextInterface[]
|
||||
* An array of contexts that have been provided.
|
||||
*/
|
||||
public function getContexts() {
|
||||
return $this->contexts;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\block\Event\BlockEvents.
|
||||
*/
|
||||
|
||||
namespace Drupal\block\Event;
|
||||
|
||||
/**
|
||||
* Defines events for the Block module.
|
||||
*/
|
||||
final class BlockEvents {
|
||||
|
||||
/**
|
||||
* Name of the event when gathering condition context for a block plugin.
|
||||
*
|
||||
* This event allows you to provide additional context that can be used by
|
||||
* a condition plugin in order to determine the visibility of a block. The
|
||||
* event listener method receives a \Drupal\block\Event\BlockContextEvent
|
||||
* instance. Generally any new context is paired with a new condition plugin
|
||||
* that interprets the provided context and allows the block system to
|
||||
* determine whether or not the block should be displayed.
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\Core\Block\BlockBase::getConditionContexts()
|
||||
* @see \Drupal\block\Event\BlockContextEvent
|
||||
* @see \Drupal\block\EventSubscriber\NodeRouteContext::onBlockActiveContext()
|
||||
* @see \Drupal\Core\Condition\ConditionInterface
|
||||
*/
|
||||
const ACTIVE_CONTEXT = 'block.active_context';
|
||||
|
||||
/**
|
||||
* Name of the event when gathering contexts for plugin configuration.
|
||||
*
|
||||
* This event allows you to provide information about your context to the
|
||||
* administration UI without having to provide a value for the context. For
|
||||
* example, during configuration there is no specific node to pass as context.
|
||||
* However, we still need to inform the system that a context named 'node' is
|
||||
* available and provide a definition so that blocks can be configured to use
|
||||
* it.
|
||||
*
|
||||
* The event listener method receives a \Drupal\block\Event\BlockContextEvent
|
||||
* instance.
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\block\BlockForm::form()
|
||||
* @see \Drupal\block\Event\BlockContextEvent
|
||||
* @see \Drupal\block\EventSubscriber\NodeRouteContext::onBlockAdministrativeContext()
|
||||
*/
|
||||
const ADMINISTRATIVE_CONTEXT = 'block.administrative_context';
|
||||
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\block\EventSubscriber\BlockContextSubscriberBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\block\EventSubscriber;
|
||||
|
||||
use Drupal\block\Event\BlockContextEvent;
|
||||
use Drupal\block\Event\BlockEvents;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
/**
|
||||
* Provides a base class for block context subscribers.
|
||||
*/
|
||||
abstract class BlockContextSubscriberBase implements EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
$events[BlockEvents::ACTIVE_CONTEXT][] = 'onBlockActiveContext';
|
||||
$events[BlockEvents::ADMINISTRATIVE_CONTEXT][] = 'onBlockAdministrativeContext';
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the available run-time contexts.
|
||||
*
|
||||
* For blocks to render correctly, all of the contexts that they require
|
||||
* must be populated with values. So this method must set a value for each
|
||||
* context that it adds. For example:
|
||||
* @code
|
||||
* // Determine a specific node to pass as context to blocks.
|
||||
* $node = ...
|
||||
*
|
||||
* // Set that specific node as the value of the 'node' context.
|
||||
* $context = new Context(new ContextDefinition('entity:node'));
|
||||
* $context->setContextValue($node);
|
||||
* $event->setContext('node.node', $context);
|
||||
* @endcode
|
||||
*
|
||||
* @param \Drupal\block\Event\BlockContextEvent $event
|
||||
* The Event to which to register available contexts.
|
||||
*/
|
||||
abstract public function onBlockActiveContext(BlockContextEvent $event);
|
||||
|
||||
/**
|
||||
* Determines the available configuration-time contexts.
|
||||
*
|
||||
* When a block is being configured, the configuration UI must know which
|
||||
* named contexts are potentially available, but does not care about the
|
||||
* value, since the value can be different for each request, and might not
|
||||
* be available at all during the configuration UI's request.
|
||||
*
|
||||
* For example:
|
||||
* @code
|
||||
* // During configuration, there is no specific node to pass as context.
|
||||
* // However, inform the system that a context named 'node.node' is
|
||||
* // available, and provide its definition, so that blocks can be
|
||||
* // configured to use it. When the block is rendered, the value of this
|
||||
* // context will be supplied by onBlockActiveContext().
|
||||
* $context = new Context(new ContextDefinition('entity:node'));
|
||||
* $event->setContext('node.node', $context);
|
||||
* @endcode
|
||||
*
|
||||
* @param \Drupal\block\Event\BlockContextEvent $event
|
||||
* The Event to which to register available contexts.
|
||||
*
|
||||
* @see static::onBlockActiveContext()
|
||||
*/
|
||||
abstract public function onBlockAdministrativeContext(BlockContextEvent $event);
|
||||
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\block\EventSubscriber\CurrentLanguageContext.
|
||||
*/
|
||||
|
||||
namespace Drupal\block\EventSubscriber;
|
||||
|
||||
use Drupal\block\Event\BlockContextEvent;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\Core\Plugin\Context\Context;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Sets the current language as a context.
|
||||
*/
|
||||
class CurrentLanguageContext extends BlockContextSubscriberBase {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The language manager.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* Constructs a new CurrentLanguageContext.
|
||||
*
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface
|
||||
* The language manager.
|
||||
*/
|
||||
public function __construct(LanguageManagerInterface $language_manager) {
|
||||
$this->languageManager = $language_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onBlockActiveContext(BlockContextEvent $event) {
|
||||
// Add a context for each language type.
|
||||
$language_types = $this->languageManager->getLanguageTypes();
|
||||
$info = $this->languageManager->getDefinedLanguageTypesInfo();
|
||||
foreach ($language_types as $type_key) {
|
||||
if (isset($info[$type_key]['name'])) {
|
||||
$context = new Context(new ContextDefinition('language', $info[$type_key]['name']));
|
||||
$context->setContextValue($this->languageManager->getCurrentLanguage($type_key));
|
||||
$event->setContext('language.' . $type_key, $context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onBlockAdministrativeContext(BlockContextEvent $event) {
|
||||
$this->onBlockActiveContext($event);
|
||||
}
|
||||
|
||||
}
|
|
@ -69,7 +69,7 @@ class ThemeLocalTask extends DeriverBase implements ContainerDeriverInterface {
|
|||
}
|
||||
// Default task!
|
||||
if ($default_theme == $theme_name) {
|
||||
$this->derivatives[$theme_name]['route_name'] = 'block.admin_display';
|
||||
$this->derivatives[$theme_name]['route_name'] = $base_plugin_definition['parent_id'];
|
||||
// Emulate default logic because without the base plugin id we can't
|
||||
// change the base_route.
|
||||
$this->derivatives[$theme_name]['weight'] = -10;
|
||||
|
|
|
@ -8,17 +8,14 @@
|
|||
namespace Drupal\block\Plugin\DisplayVariant;
|
||||
|
||||
use Drupal\block\BlockRepositoryInterface;
|
||||
use Drupal\block\Event\BlockContextEvent;
|
||||
use Drupal\block\Event\BlockEvents;
|
||||
use Drupal\Core\Block\MainContentBlockPluginInterface;
|
||||
use Drupal\Core\Block\MessagesBlockPluginInterface;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Display\PageVariantInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityViewBuilderInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Display\VariantBase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* Provides a page display variant that decorates the main content with blocks.
|
||||
|
@ -79,16 +76,13 @@ class BlockPageVariant extends VariantBase implements PageVariantInterface, Cont
|
|||
* The block repository.
|
||||
* @param \Drupal\Core\Entity\EntityViewBuilderInterface $block_view_builder
|
||||
* The block view builder.
|
||||
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
|
||||
* The event dispatcher.
|
||||
* @param string[] $block_list_cache_tags
|
||||
* The Block entity type list cache tags.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, BlockRepositoryInterface $block_repository, EntityViewBuilderInterface $block_view_builder, EventDispatcherInterface $dispatcher, array $block_list_cache_tags) {
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, BlockRepositoryInterface $block_repository, EntityViewBuilderInterface $block_view_builder, array $block_list_cache_tags) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->blockRepository = $block_repository;
|
||||
$this->blockViewBuilder = $block_view_builder;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->blockListCacheTags = $block_list_cache_tags;
|
||||
}
|
||||
|
||||
|
@ -102,7 +96,6 @@ class BlockPageVariant extends VariantBase implements PageVariantInterface, Cont
|
|||
$plugin_definition,
|
||||
$container->get('block.repository'),
|
||||
$container->get('entity.manager')->getViewBuilder('block'),
|
||||
$container->get('event_dispatcher'),
|
||||
$container->get('entity.manager')->getDefinition('block')->getListCacheTags()
|
||||
);
|
||||
}
|
||||
|
@ -128,9 +121,9 @@ class BlockPageVariant extends VariantBase implements PageVariantInterface, Cont
|
|||
'tags' => $this->blockListCacheTags,
|
||||
],
|
||||
];
|
||||
$contexts = $this->getActiveBlockContexts();
|
||||
// Load all region content assigned via blocks.
|
||||
foreach ($this->blockRepository->getVisibleBlocksPerRegion($contexts) as $region => $blocks) {
|
||||
$cacheable_metadata_list = [];
|
||||
foreach ($this->blockRepository->getVisibleBlocksPerRegion($cacheable_metadata_list) as $region => $blocks) {
|
||||
/** @var $blocks \Drupal\block\BlockInterface[] */
|
||||
foreach ($blocks as $key => $block) {
|
||||
$block_plugin = $block->getPlugin();
|
||||
|
@ -172,17 +165,18 @@ class BlockPageVariant extends VariantBase implements PageVariantInterface, Cont
|
|||
];
|
||||
}
|
||||
|
||||
// The access results' cacheability is currently added to the top level of the
|
||||
// render array. This is done to prevent issues with empty regions being
|
||||
// displayed.
|
||||
// This would need to be changed to allow caching of block regions, as each
|
||||
// region must then have the relevant cacheable metadata.
|
||||
$merged_cacheable_metadata = CacheableMetadata::createFromRenderArray($build);
|
||||
foreach ($cacheable_metadata_list as $cacheable_metadata) {
|
||||
$merged_cacheable_metadata = $merged_cacheable_metadata->merge($cacheable_metadata);
|
||||
}
|
||||
$merged_cacheable_metadata->applyTo($build);
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of context objects to set on the blocks.
|
||||
*
|
||||
* @return \Drupal\Component\Plugin\Context\ContextInterface[]
|
||||
* An array of contexts to set on the blocks.
|
||||
*/
|
||||
protected function getActiveBlockContexts() {
|
||||
return $this->dispatcher->dispatch(BlockEvents::ACTIVE_CONTEXT, new BlockContextEvent())->getContexts();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Plugin\migrate\process\d6\BlockPluginId.
|
||||
* Contains \Drupal\block\Plugin\migrate\process\d6\BlockPluginId.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Plugin\migrate\process\d6;
|
||||
namespace Drupal\block\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
|
@ -1,12 +1,12 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Plugin\migrate\process\d6\BlockRegion.
|
||||
* Contains \Drupal\block\Plugin\migrate\process\d6\BlockRegion.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Plugin\migrate\process\d6;
|
||||
namespace Drupal\block\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Plugin\migrate\process\d6\BlockSettings.
|
||||
* Contains \Drupal\block\Plugin\migrate\process\d6\BlockSettings.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Plugin\migrate\process\d6;
|
||||
namespace Drupal\block\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
|
@ -1,10 +1,11 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Plugin\migrate\process\d6\BlockTheme.
|
||||
* Contains \Drupal\block\Plugin\migrate\process\d6\BlockTheme.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Plugin\migrate\process\d6;
|
||||
namespace Drupal\block\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Plugin\migrate\process\d6\BlockVisibility.
|
||||
* Contains \Drupal\block\Plugin\migrate\process\d6\BlockVisibility.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Plugin\migrate\process\d6;
|
||||
namespace Drupal\block\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Plugin\migrate\source\d6\Block.
|
||||
* Contains \Drupal\block\Plugin\migrate\source\d6\Block.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Plugin\migrate\source\d6;
|
||||
namespace Drupal\block\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
|
@ -119,9 +119,11 @@ class BlockCacheTest extends WebTestBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Test a cacheable block without any cache context.
|
||||
* Test a cacheable block without any additional cache context.
|
||||
*/
|
||||
function testCacheGlobal() {
|
||||
function testCachePermissions() {
|
||||
// user.permissions is a required context, so a user with different
|
||||
// permissions will see a different version of the block.
|
||||
\Drupal::state()->set('block_test.cache_contexts', []);
|
||||
|
||||
$current_content = $this->randomMachineName();
|
||||
|
@ -134,9 +136,12 @@ class BlockCacheTest extends WebTestBase {
|
|||
$current_content = $this->randomMachineName();
|
||||
\Drupal::state()->set('block_test.content', $current_content);
|
||||
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('user');
|
||||
$this->assertText($old_content, 'Block content served from cache.');
|
||||
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('user');
|
||||
$this->assertText($current_content, 'Block content not served from cache.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -62,6 +62,7 @@ class BlockLanguageCacheTest extends WebTestBase {
|
|||
// Create the block cache for all languages.
|
||||
foreach ($this->langcodes as $langcode) {
|
||||
$this->drupalGet('admin/structure/block', array('language' => $langcode));
|
||||
$this->clickLinkPartialName('Place block');
|
||||
}
|
||||
|
||||
// Create a menu in the default language.
|
||||
|
@ -73,6 +74,7 @@ class BlockLanguageCacheTest extends WebTestBase {
|
|||
// Check that the block is listed for all languages.
|
||||
foreach ($this->langcodes as $langcode) {
|
||||
$this->drupalGet('admin/structure/block', array('language' => $langcode));
|
||||
$this->clickLinkPartialName('Place block');
|
||||
$this->assertText($edit['label']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,7 @@ class BlockLanguageTest extends WebTestBase {
|
|||
'langcodes' => array(
|
||||
'fr' => 'fr',
|
||||
),
|
||||
'context_mapping' => ['language' => '@language.current_language_context:language_interface'],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -141,7 +142,7 @@ class BlockLanguageTest extends WebTestBase {
|
|||
// Enable a standard block and set visibility to French only.
|
||||
$block_id = strtolower($this->randomMachineName(8));
|
||||
$edit = [
|
||||
'visibility[language][context_mapping][language]' => 'language.language_interface',
|
||||
'visibility[language][context_mapping][language]' => '@language.current_language_context:language_interface',
|
||||
'visibility[language][langcodes][fr]' => TRUE,
|
||||
'id' => $block_id,
|
||||
'region' => 'sidebar_first',
|
||||
|
@ -167,7 +168,7 @@ class BlockLanguageTest extends WebTestBase {
|
|||
|
||||
// Change visibility to now depend on content language for this block.
|
||||
$edit = [
|
||||
'visibility[language][context_mapping][language]' => 'language.language_content'
|
||||
'visibility[language][context_mapping][language]' => '@language.current_language_context:language_content'
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/block/manage/' . $block_id, $edit, t('Save block'));
|
||||
|
||||
|
|
|
@ -53,6 +53,14 @@ class BlockSystemBrandingTest extends BlockTestBase {
|
|||
$this->assertTrue(!empty($site_slogan_element), 'The branding block slogan was found.');
|
||||
$this->assertCacheTag('config:system.site');
|
||||
|
||||
// Be sure the slogan is XSS-filtered.
|
||||
$this->config('system.site')
|
||||
->set('slogan', '<script>alert("Community carpentry");</script>')
|
||||
->save();
|
||||
$this->drupalGet('');
|
||||
$site_slogan_element = $this->xpath($site_slogan_xpath);
|
||||
$this->assertEqual($site_slogan_element[0], 'alert("Community carpentry");', 'The site slogan was XSS-filtered.');
|
||||
|
||||
// Turn just the logo off.
|
||||
$this->config('block.block.site-branding')
|
||||
->set('settings.use_site_logo', 0)
|
||||
|
|
|
@ -334,11 +334,13 @@ class BlockTest extends BlockTestBase {
|
|||
'config:block_list',
|
||||
'block_view',
|
||||
'config:block.block.powered',
|
||||
'config:user.role.anonymous',
|
||||
'rendered',
|
||||
);
|
||||
sort($expected_cache_tags);
|
||||
$keys = \Drupal::service('cache_contexts_manager')->convertTokensToKeys(['languages:language_interface', 'theme', 'user.permissions'])->getKeys();
|
||||
$this->assertIdentical($cache_entry->tags, $expected_cache_tags);
|
||||
$cache_entry = \Drupal::cache('render')->get('entity_view:block:powered:en:classy');
|
||||
$cache_entry = \Drupal::cache('render')->get('entity_view:block:powered:' . implode(':', $keys));
|
||||
$expected_cache_tags = array(
|
||||
'block_view',
|
||||
'config:block.block.powered',
|
||||
|
@ -373,6 +375,7 @@ class BlockTest extends BlockTestBase {
|
|||
'block_view',
|
||||
'config:block.block.powered',
|
||||
'config:block.block.powered-2',
|
||||
'config:user.role.anonymous',
|
||||
'rendered',
|
||||
);
|
||||
sort($expected_cache_tags);
|
||||
|
@ -383,7 +386,8 @@ class BlockTest extends BlockTestBase {
|
|||
'rendered',
|
||||
);
|
||||
sort($expected_cache_tags);
|
||||
$cache_entry = \Drupal::cache('render')->get('entity_view:block:powered:en:classy');
|
||||
$keys = \Drupal::service('cache_contexts_manager')->convertTokensToKeys(['languages:language_interface', 'theme', 'user.permissions'])->getKeys();
|
||||
$cache_entry = \Drupal::cache('render')->get('entity_view:block:powered:' . implode(':', $keys));
|
||||
$this->assertIdentical($cache_entry->tags, $expected_cache_tags);
|
||||
$expected_cache_tags = array(
|
||||
'block_view',
|
||||
|
@ -391,7 +395,8 @@ class BlockTest extends BlockTestBase {
|
|||
'rendered',
|
||||
);
|
||||
sort($expected_cache_tags);
|
||||
$cache_entry = \Drupal::cache('render')->get('entity_view:block:powered-2:en:classy');
|
||||
$keys = \Drupal::service('cache_contexts_manager')->convertTokensToKeys(['languages:language_interface', 'theme', 'user.permissions'])->getKeys();
|
||||
$cache_entry = \Drupal::cache('render')->get('entity_view:block:powered-2:' . implode(':', $keys));
|
||||
$this->assertIdentical($cache_entry->tags, $expected_cache_tags);
|
||||
|
||||
// Now we should have a cache hit again.
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\block\Tests\BlockTitleXSSTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\block\Tests;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests block XSS in title.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockTitleXSSTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('block', 'block_test');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('test_xss_title', array('label' => '<script>alert("XSS label");</script>'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test XSS in title.
|
||||
*/
|
||||
function testXSSInTitle() {
|
||||
\Drupal::state()->set('block_test.content', $this->randomMachineName());
|
||||
$this->drupalGet('');
|
||||
$this->assertNoRaw('<script>alert("XSS label");</script>', 'The block title was properly sanitized when rendered.');
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser(array('administer blocks', 'access administration pages')));
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
$this->drupalGet('admin/structure/block/list/' . $default_theme);
|
||||
$this->assertNoRaw("<script>alert('XSS subject');</script>", 'The block title was properly sanitized in Block Plugin UI Admin page.');
|
||||
}
|
||||
|
||||
}
|
|
@ -126,6 +126,12 @@ class BlockUiTest extends WebTestBase {
|
|||
'The block "' . $label . '" has the correct weight assignment (' . $values['test_weight'] . ').'
|
||||
);
|
||||
}
|
||||
|
||||
// Add a block with a machine name the same as a region name.
|
||||
$this->drupalPlaceBlock('system_powered_by_block', ['region' => 'header', 'id' => 'header']);
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$element = $this->xpath('//tr[contains(@class, :class)]', [':class' => 'region-title-header']);
|
||||
$this->assertTrue(!empty($element));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,14 +139,15 @@ class BlockUiTest extends WebTestBase {
|
|||
*/
|
||||
public function testCandidateBlockList() {
|
||||
$arguments = array(
|
||||
':ul_class' => 'block-list',
|
||||
':li_class' => 'test-block-instantiation',
|
||||
':title' => 'Display message',
|
||||
':category' => 'Block test',
|
||||
':href' => 'admin/structure/block/add/test_block_instantiation/classy',
|
||||
':text' => 'Display message',
|
||||
);
|
||||
$pattern = '//tr[.//td/div[text()=:title] and .//td[text()=:category] and .//td//a[contains(@href, :href)]]';
|
||||
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$elements = $this->xpath('//details[@id="edit-category-block-test"]//ul[contains(@class, :ul_class)]/li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
|
||||
$this->clickLinkPartialName('Place block');
|
||||
$elements = $this->xpath($pattern, $arguments);
|
||||
$this->assertTrue(!empty($elements), 'The test block appears in the category for its module.');
|
||||
|
||||
// Trigger the custom category addition in block_test_block_alter().
|
||||
|
@ -148,7 +155,9 @@ class BlockUiTest extends WebTestBase {
|
|||
$this->container->get('plugin.manager.block')->clearCachedDefinitions();
|
||||
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$elements = $this->xpath('//details[@id="edit-category-custom-category"]//ul[contains(@class, :ul_class)]/li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
|
||||
$this->clickLinkPartialName('Place block');
|
||||
$arguments[':category'] = 'Custom category';
|
||||
$elements = $this->xpath($pattern, $arguments);
|
||||
$this->assertTrue(!empty($elements), 'The test block appears in a custom category controlled by block_test_block_alter().');
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace Drupal\block\Tests;
|
|||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\Context\UrlCacheContext;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\simpletest\KernelTestBase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
@ -27,7 +27,7 @@ class BlockViewBuilderTest extends KernelTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('block', 'block_test', 'system');
|
||||
public static $modules = array('block', 'block_test', 'system', 'user');
|
||||
|
||||
/**
|
||||
* The block being tested.
|
||||
|
@ -160,7 +160,7 @@ class BlockViewBuilderTest extends KernelTestBase {
|
|||
|
||||
// Test that a cache entry is created.
|
||||
$build = $this->getBlockRenderArray();
|
||||
$cid = 'entity_view:block:test_block:en:core';
|
||||
$cid = 'entity_view:block:test_block:' . implode(':', \Drupal::service('cache_contexts_manager')->convertTokensToKeys(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'])->getKeys());
|
||||
$this->renderer->renderRoot($build);
|
||||
$this->assertTrue($this->container->get('cache.render')->get($cid), 'The block render element has been cached.');
|
||||
|
||||
|
@ -190,14 +190,14 @@ class BlockViewBuilderTest extends KernelTestBase {
|
|||
public function testBlockViewBuilderAlter() {
|
||||
// Establish baseline.
|
||||
$build = $this->getBlockRenderArray();
|
||||
$this->assertIdentical($this->renderer->renderRoot($build), 'Llamas > unicorns!');
|
||||
$this->assertIdentical((string) $this->renderer->renderRoot($build), 'Llamas > unicorns!');
|
||||
|
||||
// Enable the block view alter hook that adds a suffix, for basic testing.
|
||||
\Drupal::state()->set('block_test_view_alter_suffix', TRUE);
|
||||
Cache::invalidateTags($this->block->getCacheTags());
|
||||
Cache::invalidateTags($this->block->getCacheTagsToInvalidate());
|
||||
$build = $this->getBlockRenderArray();
|
||||
$this->assertTrue(isset($build['#suffix']) && $build['#suffix'] === '<br>Goodbye!', 'A block with content is altered.');
|
||||
$this->assertIdentical($this->renderer->renderRoot($build), 'Llamas > unicorns!<br>Goodbye!');
|
||||
$this->assertIdentical((string) $this->renderer->renderRoot($build), 'Llamas > unicorns!<br>Goodbye!');
|
||||
\Drupal::state()->set('block_test_view_alter_suffix', FALSE);
|
||||
|
||||
// Force a request via GET so we can test the render cache.
|
||||
|
@ -206,7 +206,7 @@ class BlockViewBuilderTest extends KernelTestBase {
|
|||
$request->setMethod('GET');
|
||||
|
||||
\Drupal::state()->set('block_test.content', NULL);
|
||||
Cache::invalidateTags($this->block->getCacheTags());
|
||||
Cache::invalidateTags($this->block->getCacheTagsToInvalidate());
|
||||
|
||||
$default_keys = array('entity_view', 'block', 'test_block');
|
||||
$default_tags = array('block_view', 'config:block.block.test_block');
|
||||
|
@ -214,11 +214,11 @@ class BlockViewBuilderTest extends KernelTestBase {
|
|||
// Advanced: cached block, but an alter hook adds an additional cache key.
|
||||
$alter_add_key = $this->randomMachineName();
|
||||
\Drupal::state()->set('block_test_view_alter_cache_key', $alter_add_key);
|
||||
$cid = 'entity_view:block:test_block:' . $alter_add_key . ':en:core';
|
||||
$cid = 'entity_view:block:test_block:' . $alter_add_key . ':' . implode(':', \Drupal::service('cache_contexts_manager')->convertTokensToKeys(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'])->getKeys());
|
||||
$expected_keys = array_merge($default_keys, array($alter_add_key));
|
||||
$build = $this->getBlockRenderArray();
|
||||
$this->assertIdentical($expected_keys, $build['#cache']['keys'], 'An altered cacheable block has the expected cache keys.');
|
||||
$this->assertIdentical($this->renderer->renderRoot($build), '');
|
||||
$this->assertIdentical((string) $this->renderer->renderRoot($build), '');
|
||||
$cache_entry = $this->container->get('cache.render')->get($cid);
|
||||
$this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
|
||||
$expected_tags = array_merge($default_tags, ['rendered']);
|
||||
|
@ -233,7 +233,7 @@ class BlockViewBuilderTest extends KernelTestBase {
|
|||
$build = $this->getBlockRenderArray();
|
||||
sort($build['#cache']['tags']);
|
||||
$this->assertIdentical($expected_tags, $build['#cache']['tags'], 'An altered cacheable block has the expected cache tags.');
|
||||
$this->assertIdentical($this->renderer->renderRoot($build), '');
|
||||
$this->assertIdentical((string) $this->renderer->renderRoot($build), '');
|
||||
$cache_entry = $this->container->get('cache.render')->get($cid);
|
||||
$this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
|
||||
$expected_tags = array_merge($default_tags, [$alter_add_tag, 'rendered']);
|
||||
|
@ -246,7 +246,7 @@ class BlockViewBuilderTest extends KernelTestBase {
|
|||
\Drupal::state()->set('block_test_view_alter_append_pre_render_prefix', TRUE);
|
||||
$build = $this->getBlockRenderArray();
|
||||
$this->assertFalse(isset($build['#prefix']), 'The appended #pre_render callback has not yet run before rendering.');
|
||||
$this->assertIdentical($this->renderer->renderRoot($build), 'Hiya!<br>');
|
||||
$this->assertIdentical((string) $this->renderer->renderRoot($build), 'Hiya!<br>');
|
||||
$this->assertTrue(isset($build['#prefix']) && $build['#prefix'] === 'Hiya!<br>', 'A cached block without content is altered.');
|
||||
|
||||
// Restore the previous request method.
|
||||
|
|
|
@ -26,7 +26,34 @@ class BlockXssTest extends WebTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['block', 'block_content', 'menu_ui', 'views'];
|
||||
public static $modules = ['block', 'block_content', 'block_test', 'menu_ui', 'views'];
|
||||
|
||||
/**
|
||||
* Test XSS in title.
|
||||
*/
|
||||
public function testXssInTitle() {
|
||||
$this->drupalPlaceBlock('test_xss_title', ['label' => '<script>alert("XSS label");</script>']);
|
||||
|
||||
\Drupal::state()->set('block_test.content', $this->randomMachineName());
|
||||
$this->drupalGet('');
|
||||
$this->assertNoRaw('<script>alert("XSS label");</script>', 'The block title was properly sanitized when rendered.');
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer blocks', 'access administration pages']));
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
$this->drupalGet('admin/structure/block/list/' . $default_theme);
|
||||
$this->assertNoRaw("<script>alert('XSS subject');</script>", 'The block title was properly sanitized in Block Plugin UI Admin page.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests XSS in category.
|
||||
*/
|
||||
public function testXssInCategory() {
|
||||
$this->drupalPlaceBlock('test_xss_title');
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer blocks', 'access administration pages']));
|
||||
$this->drupalGet(Url::fromRoute('block.admin_display'));
|
||||
$this->clickLinkPartialName('Place block');
|
||||
$this->assertNoRaw("<script>alert('XSS category');</script>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests various modules that provide blocks for XSS.
|
||||
|
@ -51,8 +78,9 @@ class BlockXssTest extends WebTestBase {
|
|||
$view->save();
|
||||
|
||||
$this->drupalGet(Url::fromRoute('block.admin_display'));
|
||||
$this->clickLink('<script>alert("view");</script>');
|
||||
$this->assertRaw('<script>alert("view");</script>');
|
||||
$this->clickLinkPartialName('Place block');
|
||||
// The block admin label is automatically XSS admin filtered.
|
||||
$this->assertRaw('alert("view");');
|
||||
$this->assertNoRaw('<script>alert("view");</script>');
|
||||
}
|
||||
|
||||
|
@ -66,8 +94,9 @@ class BlockXssTest extends WebTestBase {
|
|||
])->save();
|
||||
|
||||
$this->drupalGet(Url::fromRoute('block.admin_display'));
|
||||
$this->clickLink('<script>alert("menu");</script>');
|
||||
$this->assertRaw('<script>alert("menu");</script>');
|
||||
$this->clickLinkPartialName('Place block');
|
||||
// The block admin label is automatically XSS admin filtered.
|
||||
$this->assertRaw('alert("menu");');
|
||||
$this->assertNoRaw('<script>alert("menu");</script>');
|
||||
}
|
||||
|
||||
|
@ -86,8 +115,9 @@ class BlockXssTest extends WebTestBase {
|
|||
])->save();
|
||||
|
||||
$this->drupalGet(Url::fromRoute('block.admin_display'));
|
||||
$this->clickLink('<script>alert("block_content");</script>');
|
||||
$this->assertRaw('<script>alert("block_content");</script>');
|
||||
$this->clickLinkPartialName('Place block');
|
||||
// The block admin label is automatically XSS admin filtered.
|
||||
$this->assertRaw('alert("block_content");');
|
||||
$this->assertNoRaw('<script>alert("block_content");</script>');
|
||||
}
|
||||
|
||||
|
|
|
@ -2,19 +2,18 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Tests\d6\MigrateBlockTest.
|
||||
* Contains \Drupal\block\Tests\Migrate\d6\MigrateBlockTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Tests\d6;
|
||||
namespace Drupal\block\Tests\Migrate\d6;
|
||||
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Upgrade block settings to block.block.*.yml.
|
||||
*
|
||||
* @group migrate_drupal
|
||||
* @group block
|
||||
*/
|
||||
class MigrateBlockTest extends MigrateDrupal6TestBase {
|
||||
|
||||
|
@ -72,16 +71,8 @@ class MigrateBlockTest extends MigrateDrupal6TestBase {
|
|||
// Install one of D8's test themes.
|
||||
\Drupal::service('theme_handler')->install(array('test_theme'));
|
||||
|
||||
/** @var \Drupal\migrate\entity\Migration $migration */
|
||||
$migration = entity_load('migration', 'd6_block');
|
||||
$dumps = array(
|
||||
$this->getDumpDirectory() . '/Blocks.php',
|
||||
$this->getDumpDirectory() . '/BlocksRoles.php',
|
||||
$this->getDumpDirectory() . '/AggregatorFeed.php',
|
||||
);
|
||||
$this->prepare($migration, $dumps);
|
||||
$executable = new MigrateExecutable($migration, $this);
|
||||
$executable->import();
|
||||
$this->loadDumps(['Blocks.php', 'BlocksRoles.php', 'AggregatorFeed.php']);
|
||||
$this->executeMigration('d6_block');
|
||||
}
|
||||
|
||||
/**
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\block\Tests\Update\BlockContextMappingUpdateTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\block\Tests\Update;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\system\Tests\Update\UpdatePathTestBase;
|
||||
|
||||
/**
|
||||
* Tests the upgrade path for block context mapping renames.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2354889
|
||||
*
|
||||
* @group Update
|
||||
*/
|
||||
class BlockContextMappingUpdateTest extends UpdatePathTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block_test', 'language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->databaseDumpFiles = [
|
||||
__DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
|
||||
__DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.block-context-manager-2354889.php',
|
||||
];
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that block context mapping is updated properly.
|
||||
*/
|
||||
public function testUpdateHookN() {
|
||||
$this->runUpdates();
|
||||
$this->assertRaw('Encountered an unknown context mapping key coming probably from a contributed or custom module: One or more mappings could not be updated. Please manually review your visibility settings for the following blocks, which are disabled now:<ul><li>User login (Visibility: Baloney spam)</li></ul>');
|
||||
|
||||
// Disable maintenance mode.
|
||||
\Drupal::state()->set('system.maintenance_mode', FALSE);
|
||||
|
||||
// We finished updating so we can login the user now.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
// The block that we are testing has the following visibility rules:
|
||||
// - only visible on node pages
|
||||
// - only visible to authenticated users.
|
||||
$block_title = 'Test for 2354889';
|
||||
|
||||
// Create two nodes, a page and an article.
|
||||
$page = Node::create([
|
||||
'type' => 'page',
|
||||
'title' => 'Page node',
|
||||
]);
|
||||
$page->save();
|
||||
|
||||
$article = Node::create([
|
||||
'type' => 'article',
|
||||
'title' => 'Article node',
|
||||
]);
|
||||
$article->save();
|
||||
|
||||
// Check that the block appears only on Page nodes for authenticated users.
|
||||
$this->drupalGet('node/' . $page->id());
|
||||
$this->assertRaw($block_title, 'Test block is visible on a Page node as an authenticated user.');
|
||||
|
||||
$this->drupalGet('node/' . $article->id());
|
||||
$this->assertNoRaw($block_title, 'Test block is not visible on a Article node as an authenticated user.');
|
||||
|
||||
$this->drupalLogout();
|
||||
|
||||
// Check that the block does not appear on any page for anonymous users.
|
||||
$this->drupalGet('node/' . $page->id());
|
||||
$this->assertNoRaw($block_title, 'Test block is not visible on a Page node as an anonymous user.');
|
||||
|
||||
$this->drupalGet('node/' . $article->id());
|
||||
$this->assertNoRaw($block_title, 'Test block is not visible on a Article node as an anonymous user.');
|
||||
|
||||
// Ensure that all the context mappings got updated properly.
|
||||
$block = Block::load('testfor2354889');
|
||||
$visibility = $block->get('visibility');
|
||||
$this->assertEqual('@node.node_route_context:node', $visibility['node_type']['context_mapping']['node']);
|
||||
$this->assertEqual('@user.current_user_context:current_user', $visibility['user_role']['context_mapping']['user']);
|
||||
$this->assertEqual('@language.current_language_context:language_interface', $visibility['language']['context_mapping']['language']);
|
||||
|
||||
// Check that a block with invalid context is being disabled and that it can
|
||||
// still be edited afterward.
|
||||
$disabled_block = Block::load('thirdtestfor2354889');
|
||||
$this->assertFalse($disabled_block->status(), 'Block with invalid context is disabled');
|
||||
|
||||
$this->assertEqual(['thirdtestfor2354889' => ['missing_context_ids' => ['baloney.spam' => ['node_type']], 'status' => TRUE]], \Drupal::keyValue('update_backup')->get('block_update_8001'));
|
||||
|
||||
$disabled_block_visibility = $disabled_block->get('visibility');
|
||||
$this->assertTrue(!isset($disabled_block_visibility['node_type']), 'The problematic visibility condition has been removed.');
|
||||
|
||||
$admin_user = $this->drupalCreateUser(['administer blocks']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
$this->drupalGet('admin/structure/block/manage/thirdtestfor2354889');
|
||||
$this->assertResponse('200');
|
||||
}
|
||||
|
||||
}
|
|
@ -8,8 +8,6 @@
|
|||
namespace Drupal\block\Tests\Views;
|
||||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\views\Tests\ViewTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
|
@ -60,19 +58,20 @@ class DisplayBlockTest extends ViewTestBase {
|
|||
$edit['block[style][row_plugin]'] = 'fields';
|
||||
$this->drupalPostForm('admin/structure/views/add', $edit, t('Save and edit'));
|
||||
|
||||
$pattern = '//tr[.//td[text()=:category] and .//td//a[contains(@href, :href)]]';
|
||||
|
||||
// Test that the block was given a default category corresponding to its
|
||||
// base table.
|
||||
$arguments = array(
|
||||
':id' => 'edit-category-lists-views',
|
||||
':li_class' => 'views-block' . Html::getClass($edit['id']) . '-block-1',
|
||||
':href' => \Drupal::Url('block.admin_add', array(
|
||||
'plugin_id' => 'views_block:' . $edit['id'] . '-block_1',
|
||||
'theme' => 'classy',
|
||||
)),
|
||||
':text' => $edit['label'],
|
||||
':category' => t('Lists (Views)'),
|
||||
);
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$elements = $this->xpath('//details[@id=:id]//li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
|
||||
$this->clickLinkPartialName('Place block');
|
||||
$elements = $this->xpath($pattern, $arguments);
|
||||
$this->assertTrue(!empty($elements), 'The test block appears in the category for its base table.');
|
||||
|
||||
// Duplicate the block before changing the category.
|
||||
|
@ -81,10 +80,9 @@ class DisplayBlockTest extends ViewTestBase {
|
|||
|
||||
// Change the block category to a random string.
|
||||
$this->drupalGet('admin/structure/views/view/' . $edit['id'] . '/edit/block_1');
|
||||
$label = t('Lists (Views)');
|
||||
$link = $this->xpath('//a[@id="views-block-1-block-category" and normalize-space(text())=:label]', array(':label' => $label));
|
||||
$link = $this->xpath('//a[@id="views-block-1-block-category" and normalize-space(text())=:category]', $arguments);
|
||||
$this->assertTrue(!empty($link));
|
||||
$this->clickLink($label);
|
||||
$this->clickLink(t('Lists (Views)'));
|
||||
$category = $this->randomString();
|
||||
$this->drupalPostForm(NULL, array('block_category' => $category), t('Apply'));
|
||||
|
||||
|
@ -95,34 +93,30 @@ class DisplayBlockTest extends ViewTestBase {
|
|||
$this->drupalPostForm(NULL, array(), t('Save'));
|
||||
|
||||
// Test that the blocks are listed under the correct categories.
|
||||
$category_id = Html::getUniqueId('edit-category-' . SafeMarkup::checkPlain($category));
|
||||
$arguments[':id'] = $category_id;
|
||||
$arguments[':category'] = $category;
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$elements = $this->xpath('//details[@id=:id]//li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
|
||||
$this->clickLinkPartialName('Place block');
|
||||
$elements = $this->xpath($pattern, $arguments);
|
||||
$this->assertTrue(!empty($elements), 'The test block appears in the custom category.');
|
||||
|
||||
$arguments = array(
|
||||
':id' => 'edit-category-lists-views',
|
||||
':li_class' => 'views-block' . Html::getClass($edit['id']) . '-block-2',
|
||||
':href' => \Drupal::Url('block.admin_add', array(
|
||||
'plugin_id' => 'views_block:' . $edit['id'] . '-block_2',
|
||||
'theme' => 'classy',
|
||||
)),
|
||||
':text' => $edit['label'],
|
||||
':category' => t('Lists (Views)'),
|
||||
);
|
||||
$elements = $this->xpath('//details[@id=:id]//li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
|
||||
$elements = $this->xpath($pattern, $arguments);
|
||||
$this->assertTrue(!empty($elements), 'The first duplicated test block remains in the original category.');
|
||||
|
||||
$arguments = array(
|
||||
':id' => $category_id,
|
||||
':li_class' => 'views-block' . Html::getClass($edit['id']) . '-block-3',
|
||||
':href' => \Drupal::Url('block.admin_add', array(
|
||||
'plugin_id' => 'views_block:' . $edit['id'] . '-block_3',
|
||||
'theme' => 'classy',
|
||||
)),
|
||||
':text' => $edit['label'],
|
||||
':category' => $category,
|
||||
);
|
||||
$elements = $this->xpath('//details[@id=:id]//li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
|
||||
$elements = $this->xpath($pattern, $arguments);
|
||||
$this->assertTrue(!empty($elements), 'The second duplicated test block appears in the custom category.');
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\block_test\Plugin\Condition\BaloneySpam.
|
||||
*/
|
||||
|
||||
namespace Drupal\block_test\Plugin\Condition;
|
||||
|
||||
use Drupal\Core\Condition\ConditionPluginBase;
|
||||
|
||||
/**
|
||||
* Provides a 'baloney.spam' condition.
|
||||
*
|
||||
* @Condition(
|
||||
* id = "baloney.spam",
|
||||
* label = @Translation("Baloney spam"),
|
||||
* )
|
||||
*
|
||||
*/
|
||||
class BaloneySpam extends ConditionPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function evaluate() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function summary() {
|
||||
return 'Summary';
|
||||
}
|
||||
|
||||
}
|
|
@ -30,13 +30,6 @@ class BlockFormTest extends UnitTestCase {
|
|||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* The event dispatcher service.
|
||||
*
|
||||
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
/**
|
||||
* The language manager service.
|
||||
*
|
||||
|
@ -59,6 +52,13 @@ class BlockFormTest extends UnitTestCase {
|
|||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The mocked context repository.
|
||||
*
|
||||
* @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $contextRepository;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -67,7 +67,7 @@ class BlockFormTest extends UnitTestCase {
|
|||
|
||||
$this->conditionManager = $this->getMock('Drupal\Core\Executable\ExecutableManagerInterface');
|
||||
$this->language = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
|
||||
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||
$this->contextRepository = $this->getMock('Drupal\Core\Plugin\Context\ContextRepositoryInterface');
|
||||
|
||||
$this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
|
||||
$this->storage = $this->getMock('Drupal\Core\Config\Entity\ConfigEntityStorageInterface');
|
||||
|
@ -104,7 +104,7 @@ class BlockFormTest extends UnitTestCase {
|
|||
->method('getQuery')
|
||||
->will($this->returnValue($query));
|
||||
|
||||
$block_form_controller = new BlockForm($this->entityManager, $this->conditionManager, $this->dispatcher, $this->language, $this->themeHandler);
|
||||
$block_form_controller = new BlockForm($this->entityManager, $this->conditionManager, $this->contextRepository, $this->language, $this->themeHandler);
|
||||
|
||||
// Ensure that the block with just one other instance gets the next available
|
||||
// name suggestion.
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace Drupal\Tests\block\Unit;
|
||||
|
||||
use Drupal\block\BlockRepository;
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Block\BlockPluginInterface;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
@ -59,7 +60,7 @@ class BlockRepositoryTest extends UnitTestCase {
|
|||
]);
|
||||
|
||||
$theme_manager = $this->getMock('Drupal\Core\Theme\ThemeManagerInterface');
|
||||
$theme_manager->expects($this->once())
|
||||
$theme_manager->expects($this->atLeastOnce())
|
||||
->method('getActiveTheme')
|
||||
->will($this->returnValue($active_theme));
|
||||
|
||||
|
@ -84,15 +85,18 @@ class BlockRepositoryTest extends UnitTestCase {
|
|||
$blocks = [];
|
||||
foreach ($blocks_config as $block_id => $block_config) {
|
||||
$block = $this->getMock('Drupal\block\BlockInterface');
|
||||
$block->expects($this->once())
|
||||
->method('setContexts')
|
||||
->willReturnSelf();
|
||||
$block->expects($this->once())
|
||||
->method('access')
|
||||
->will($this->returnValue($block_config[0]));
|
||||
$block->expects($block_config[0] ? $this->atLeastOnce() : $this->never())
|
||||
->method('getRegion')
|
||||
->willReturn($block_config[1]);
|
||||
$block->expects($this->any())
|
||||
->method('label')
|
||||
->willReturn($block_id);
|
||||
$block->expects($this->any())
|
||||
->method('getWeight')
|
||||
->willReturn($block_config[2]);
|
||||
$blocks[$block_id] = $block;
|
||||
}
|
||||
|
||||
|
@ -101,30 +105,34 @@ class BlockRepositoryTest extends UnitTestCase {
|
|||
->with(['theme' => $this->theme])
|
||||
->willReturn($blocks);
|
||||
$result = [];
|
||||
foreach ($this->blockRepository->getVisibleBlocksPerRegion([]) as $region => $resulting_blocks) {
|
||||
$cacheable_metadata = [];
|
||||
foreach ($this->blockRepository->getVisibleBlocksPerRegion($cacheable_metadata) as $region => $resulting_blocks) {
|
||||
$result[$region] = [];
|
||||
foreach ($resulting_blocks as $plugin_id => $block) {
|
||||
$result[$region][] = $plugin_id;
|
||||
}
|
||||
}
|
||||
$this->assertSame($result, $expected_blocks);
|
||||
$this->assertEquals($expected_blocks, $result);
|
||||
}
|
||||
|
||||
public function providerBlocksConfig() {
|
||||
$blocks_config = array(
|
||||
'block1' => array(
|
||||
TRUE, 'top', 0
|
||||
AccessResult::allowed(), 'top', 0
|
||||
),
|
||||
// Test a block without access.
|
||||
'block2' => array(
|
||||
FALSE, 'bottom', 0
|
||||
),
|
||||
// Test two blocks in the same region with specific weight.
|
||||
'block3' => array(
|
||||
TRUE, 'bottom', 5
|
||||
AccessResult::forbidden(), 'bottom', 0
|
||||
),
|
||||
// Test some blocks in the same region with specific weight.
|
||||
'block4' => array(
|
||||
TRUE, 'bottom', -5
|
||||
AccessResult::allowed(), 'bottom', 5
|
||||
),
|
||||
'block3' => array(
|
||||
AccessResult::allowed(), 'bottom', 5
|
||||
),
|
||||
'block5' => array(
|
||||
AccessResult::allowed(), 'bottom', -5
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -133,7 +141,7 @@ class BlockRepositoryTest extends UnitTestCase {
|
|||
[
|
||||
'top' => ['block1'],
|
||||
'center' => [],
|
||||
'bottom' => ['block4', 'block3'],
|
||||
'bottom' => ['block5', 'block3', 'block4'],
|
||||
]
|
||||
];
|
||||
return $test_cases;
|
||||
|
@ -146,24 +154,21 @@ class BlockRepositoryTest extends UnitTestCase {
|
|||
*/
|
||||
public function testGetVisibleBlocksPerRegionWithContext() {
|
||||
$block = $this->getMock('Drupal\block\BlockInterface');
|
||||
$block->expects($this->once())
|
||||
->method('setContexts')
|
||||
->willReturnSelf();
|
||||
$block->expects($this->once())
|
||||
->method('access')
|
||||
->willReturn(TRUE);
|
||||
->willReturn(AccessResult::allowed()->addCacheTags(['config:block.block.block_id']));
|
||||
$block->expects($this->once())
|
||||
->method('getRegion')
|
||||
->willReturn('top');
|
||||
$blocks['block_id'] = $block;
|
||||
|
||||
$contexts = [];
|
||||
$this->blockStorage->expects($this->once())
|
||||
->method('loadByProperties')
|
||||
->with(['theme' => $this->theme])
|
||||
->willReturn($blocks);
|
||||
$result = [];
|
||||
foreach ($this->blockRepository->getVisibleBlocksPerRegion($contexts) as $region => $resulting_blocks) {
|
||||
$cacheable_metadata = [];
|
||||
foreach ($this->blockRepository->getVisibleBlocksPerRegion($cacheable_metadata) as $region => $resulting_blocks) {
|
||||
$result[$region] = [];
|
||||
foreach ($resulting_blocks as $plugin_id => $block) {
|
||||
$result[$region][] = $plugin_id;
|
||||
|
@ -177,6 +182,10 @@ class BlockRepositoryTest extends UnitTestCase {
|
|||
'bottom' => [],
|
||||
];
|
||||
$this->assertSame($expected, $result);
|
||||
|
||||
// Assert that the cacheable metadata from the block access results was
|
||||
// collected.
|
||||
$this->assertEquals(['config:block.block.block_id'], $cacheable_metadata['top']->getCacheTags());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
namespace Drupal\Tests\block\Unit\Plugin\DisplayVariant;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\DependencyInjection\Container;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
|
@ -29,13 +31,6 @@ class BlockPageVariantTest extends UnitTestCase {
|
|||
*/
|
||||
protected $blockViewBuilder;
|
||||
|
||||
/**
|
||||
* The event dispatcher.
|
||||
*
|
||||
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
/**
|
||||
* The plugin context handler.
|
||||
*
|
||||
|
@ -55,14 +50,23 @@ class BlockPageVariantTest extends UnitTestCase {
|
|||
* A mocked display variant plugin.
|
||||
*/
|
||||
public function setUpDisplayVariant($configuration = array(), $definition = array()) {
|
||||
|
||||
$container = new Container();
|
||||
$cache_context_manager = $this->getMockBuilder('Drupal\Core\Cache\CacheContextsManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$container->set('cache_contexts_manager', $cache_context_manager);
|
||||
$cache_context_manager->expects($this->any())
|
||||
->method('validateTokens')
|
||||
->with([])
|
||||
->willReturn([]);
|
||||
\Drupal::setContainer($container);
|
||||
|
||||
$this->blockRepository = $this->getMock('Drupal\block\BlockRepositoryInterface');
|
||||
$this->blockViewBuilder = $this->getMock('Drupal\Core\Entity\EntityViewBuilderInterface');
|
||||
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||
$this->dispatcher->expects($this->any())
|
||||
->method('dispatch')
|
||||
->willReturnArgument(1);
|
||||
|
||||
return $this->getMockBuilder('Drupal\block\Plugin\DisplayVariant\BlockPageVariant')
|
||||
->setConstructorArgs(array($configuration, 'test', $definition, $this->blockRepository, $this->blockViewBuilder, $this->dispatcher, ['config:block_list']))
|
||||
->setConstructorArgs(array($configuration, 'test', $definition, $this->blockRepository, $this->blockViewBuilder, ['config:block_list']))
|
||||
->setMethods(array('getRegionNames'))
|
||||
->getMock();
|
||||
}
|
||||
|
@ -96,7 +100,10 @@ class BlockPageVariantTest extends UnitTestCase {
|
|||
'#cache' => [
|
||||
'tags' => [
|
||||
'config:block_list',
|
||||
'route',
|
||||
],
|
||||
'contexts' => [],
|
||||
'max-age' => -1,
|
||||
],
|
||||
'top' => [
|
||||
'block1' => [],
|
||||
|
@ -121,7 +128,10 @@ class BlockPageVariantTest extends UnitTestCase {
|
|||
'#cache' => [
|
||||
'tags' => [
|
||||
'config:block_list',
|
||||
'route',
|
||||
],
|
||||
'contexts' => [],
|
||||
'max-age' => -1,
|
||||
],
|
||||
'top' => [
|
||||
'block1' => [],
|
||||
|
@ -152,7 +162,10 @@ class BlockPageVariantTest extends UnitTestCase {
|
|||
'#cache' => [
|
||||
'tags' => [
|
||||
'config:block_list',
|
||||
'route',
|
||||
],
|
||||
'contexts' => [],
|
||||
'max-age' => -1,
|
||||
],
|
||||
'top' => [
|
||||
'block1' => [],
|
||||
|
@ -194,20 +207,26 @@ class BlockPageVariantTest extends UnitTestCase {
|
|||
$messages_block_plugin = $this->getMock('Drupal\Core\Block\MessagesBlockPluginInterface');
|
||||
foreach ($blocks_config as $block_id => $block_config) {
|
||||
$block = $this->getMock('Drupal\block\BlockInterface');
|
||||
$block->expects($this->any())
|
||||
->method('getContexts')
|
||||
->willReturn([]);
|
||||
$block->expects($this->atLeastOnce())
|
||||
->method('getPlugin')
|
||||
->willReturn($block_config[1] ? $main_content_block_plugin : ($block_config[2] ? $messages_block_plugin : $block_plugin));
|
||||
$blocks[$block_config[0]][$block_id] = $block;
|
||||
}
|
||||
|
||||
$this->blockViewBuilder->expects($this->exactly($visible_block_count))
|
||||
->method('view')
|
||||
->will($this->returnValue(array()));
|
||||
$this->blockRepository->expects($this->once())
|
||||
->method('getVisibleBlocksPerRegion')
|
||||
->will($this->returnValue($blocks));
|
||||
->willReturnCallback(function (&$cacheable_metadata) use ($blocks) {
|
||||
$cacheable_metadata['top'] = (new CacheableMetadata())->addCacheTags(['route']);
|
||||
return $blocks;
|
||||
});
|
||||
|
||||
$this->assertSame($expected_render_array, $display_variant->build());
|
||||
$value = $display_variant->build();
|
||||
$this->assertSame($expected_render_array, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,6 +245,8 @@ class BlockPageVariantTest extends UnitTestCase {
|
|||
'tags' => [
|
||||
'config:block_list',
|
||||
],
|
||||
'contexts' => [],
|
||||
'max-age' => -1,
|
||||
],
|
||||
'content' => [
|
||||
'system_main' => [],
|
||||
|
|
|
@ -2,23 +2,24 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\migrate_drupal\Unit\source\d6\BlockTest.
|
||||
* Contains \Drupal\Tests\block\Unit\Plugin\migrate\source\d6\BlockTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\migrate_drupal\Unit\source\d6;
|
||||
namespace Drupal\Tests\block\Unit\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
|
||||
|
||||
/**
|
||||
* Tests D6 block source plugin.
|
||||
*
|
||||
* @group migrate_drupal
|
||||
* @coversDefaultClass \Drupal\block\Plugin\migrate\source\d6\Block
|
||||
* @group block
|
||||
*/
|
||||
class BlockTest extends MigrateSqlSourceTestCase {
|
||||
|
||||
// The plugin system is not working during unit testing so the source plugin
|
||||
// class needs to be manually specified.
|
||||
const PLUGIN_CLASS = 'Drupal\migrate_drupal\Plugin\migrate\source\d6\Block';
|
||||
const PLUGIN_CLASS = 'Drupal\block\Plugin\migrate\source\d6\Block';
|
||||
|
||||
// The fake Migration configuration entity.
|
||||
protected $migrationConfiguration = array(
|
|
@ -8,7 +8,6 @@ block_content_add_action:
|
|||
route_name: block_content.add_page
|
||||
title: 'Add custom block'
|
||||
appears_on:
|
||||
- block.admin_display
|
||||
- block.admin_display_theme
|
||||
- block.admin_library
|
||||
- entity.block_content.collection
|
||||
class: \Drupal\block_content\Plugin\Menu\LocalAction\BlockContentAddLocalAction
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* Provides page callbacks for custom blocks.
|
||||
*/
|
||||
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\block_content\Entity\BlockContentType;
|
||||
use Drupal\block_content\Entity\BlockContent;
|
||||
|
@ -28,7 +27,9 @@ function template_preprocess_block_content_add_list(&$variables) {
|
|||
foreach ($variables['content'] as $type) {
|
||||
$variables['types'][$type->id()] = array(
|
||||
'link' => \Drupal::l($type->label(), new Url('block_content.add_form', array('block_content_type' => $type->id()), array('query' => $query))),
|
||||
'description' => Xss::filterAdmin($type->getDescription()),
|
||||
'description' => array(
|
||||
'#markup' => $type->getDescription(),
|
||||
),
|
||||
'title' => $type->label(),
|
||||
'localized_options' => array(
|
||||
'query' => $query,
|
||||
|
|
|
@ -16,3 +16,15 @@ block_content.type.*:
|
|||
description:
|
||||
type: text
|
||||
label: 'Description'
|
||||
|
||||
migrate.source.d6_box:
|
||||
type: migrate_source_sql
|
||||
label: 'Drupal 6 box'
|
||||
mapping:
|
||||
constants:
|
||||
type: mapping
|
||||
label: 'Constants'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Type'
|
||||
|
|
|
@ -23,10 +23,3 @@ destination:
|
|||
migration_dependencies:
|
||||
required:
|
||||
- d6_block_content_type
|
||||
dependencies:
|
||||
config:
|
||||
- migrate.migration.d6_block_content_type
|
||||
module:
|
||||
- block_content
|
||||
- field
|
||||
- migrate_drupal
|
|
@ -14,7 +14,3 @@ process:
|
|||
label: 'constants/label'
|
||||
destination:
|
||||
plugin: entity:block_content_type
|
||||
dependencies:
|
||||
module:
|
||||
- block_content
|
||||
- migrate_drupal
|
|
@ -22,10 +22,3 @@ migration_dependencies:
|
|||
required:
|
||||
- d6_filter_format
|
||||
- d6_block_content_body_field
|
||||
dependencies:
|
||||
config:
|
||||
- migrate.migration.d6_block_content_body_field
|
||||
- migrate.migration.d6_filter_format
|
||||
module:
|
||||
- block_content
|
||||
- migrate_drupal
|
|
@ -224,7 +224,8 @@ class BlockContentForm extends ContentEntityForm {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
if ($this->entity->isNew()) {
|
||||
$entity = parent::validateForm($form, $form_state);
|
||||
if ($entity->isNew()) {
|
||||
$exists = $this->blockContentStorage->loadByProperties(array('info' => $form_state->getValue(['info', 0, 'value'])));
|
||||
if (!empty($exists)) {
|
||||
$form_state->setErrorByName('info', $this->t('A block with description %name already exists.', array(
|
||||
|
@ -232,6 +233,7 @@ class BlockContentForm extends ContentEntityForm {
|
|||
)));
|
||||
}
|
||||
}
|
||||
return $entity;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\block_content;
|
||||
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
|
||||
|
@ -45,7 +44,7 @@ class BlockContentTypeListBuilder extends ConfigEntityListBuilder {
|
|||
*/
|
||||
public function buildRow(EntityInterface $entity) {
|
||||
$row['type'] = $entity->link();
|
||||
$row['description'] = Xss::filterAdmin($entity->getDescription());
|
||||
$row['description']['data']['#markup'] = $entity->getDescription();
|
||||
return $row + parent::buildRow($entity);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Plugin\migrate\source\d6\Box.
|
||||
* Contains \Drupal\block_content\Plugin\migrate\source\d6\Box.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Plugin\migrate\source\d6;
|
||||
namespace Drupal\block_content\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
|
@ -90,13 +90,15 @@ class BlockContentCacheTagsTest extends EntityCacheTagsTestBase {
|
|||
// Expected keys, contexts, and tags for the block.
|
||||
// @see \Drupal\block\BlockViewBuilder::viewMultiple()
|
||||
$expected_block_cache_keys = ['entity_view', 'block', $block->id()];
|
||||
$expected_block_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme'];
|
||||
$expected_block_cache_tags = Cache::mergeTags(['block_view', 'rendered'], $block->getCacheTags(), $block->getPlugin()->getCacheTags());
|
||||
$expected_block_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'];
|
||||
$expected_block_cache_tags = Cache::mergeTags(['block_view', 'rendered'], $block->getCacheTags());
|
||||
$expected_block_cache_tags = Cache::mergeTags($expected_block_cache_tags, $block->getPlugin()->getCacheTags());
|
||||
|
||||
// Expected contexts and tags for the BlockContent entity.
|
||||
// @see \Drupal\Core\Entity\EntityViewBuilder::getBuildDefaults().
|
||||
$expected_entity_cache_contexts = ['theme'];
|
||||
$expected_entity_cache_tags = Cache::mergeTags(['block_content_view'], $this->entity->getCacheTags(), $this->getAdditionalCacheTagsForEntity($this->entity));
|
||||
$expected_entity_cache_tags = Cache::mergeTags(['block_content_view'], $this->entity->getCacheTags());
|
||||
$expected_entity_cache_tags = Cache::mergeTags($expected_entity_cache_tags, $this->getAdditionalCacheTagsForEntity($this->entity));
|
||||
|
||||
// Verify that what was render cached matches the above expectations.
|
||||
$cid = $this->createCacheId($expected_block_cache_keys, $expected_block_cache_contexts);
|
||||
|
|
|
@ -189,6 +189,7 @@ class BlockContentTypeTest extends BlockContentTestBase {
|
|||
// block configure form.
|
||||
$path = $theme == $default_theme ? 'admin/structure/block' : "admin/structure/block/list/$theme";
|
||||
$this->drupalGet($path);
|
||||
$this->clickLinkPartialName('Place block');
|
||||
$this->clickLink(t('Add custom block'));
|
||||
// The seven theme has markup inside the link, we cannot use clickLink().
|
||||
if ($default_theme == 'seven') {
|
||||
|
|
|
@ -2,22 +2,18 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Tests\d6\MigrateBlockContentTest.
|
||||
* Contains \Drupal\block_content\Tests\Migrate\d6\MigrateBlockContentTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Tests\d6;
|
||||
namespace Drupal\block_content\Tests\Migrate\d6;
|
||||
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\block_content\Entity\BlockContent;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Upgrade custom blocks.
|
||||
*
|
||||
* @group migrate_drupal
|
||||
* @group block_content
|
||||
*/
|
||||
class MigrateBlockContentTest extends MigrateDrupal6TestBase {
|
||||
|
||||
|
@ -31,26 +27,16 @@ class MigrateBlockContentTest extends MigrateDrupal6TestBase {
|
|||
$this->installConfig(array('block_content'));
|
||||
$this->installEntitySchema('block_content');
|
||||
|
||||
$migration = entity_load('migration', 'd6_block_content_type');
|
||||
$executable = new MigrateExecutable($migration, $this);
|
||||
$executable->import();
|
||||
$migration = entity_load('migration', 'd6_block_content_body_field');
|
||||
$executable = new MigrateExecutable($migration, $this);
|
||||
$executable->import();
|
||||
$this->executeMigration('d6_block_content_type');
|
||||
$this->executeMigration('d6_block_content_body_field');
|
||||
|
||||
$this->prepareMigrations(array(
|
||||
'd6_filter_format' => array(
|
||||
array(array(2), array('full_html'))
|
||||
)
|
||||
));
|
||||
/** @var \Drupal\migrate\entity\Migration $migration */
|
||||
$migration = entity_load('migration', 'd6_custom_block');
|
||||
$dumps = array(
|
||||
$this->getDumpDirectory() . '/Boxes.php',
|
||||
);
|
||||
$this->prepare($migration, $dumps);
|
||||
$executable = new MigrateExecutable($migration, $this);
|
||||
$executable->import();
|
||||
$this->loadDumps(['Boxes.php']);
|
||||
$this->executeMigration('d6_custom_block');
|
||||
}
|
||||
|
||||
/**
|
|
@ -60,6 +60,7 @@ function block_content_test_block_content_insert(BlockContent $block_content) {
|
|||
// Set the block_content title to the block_content ID and save.
|
||||
if ($block_content->label() == 'new') {
|
||||
$block_content->setInfo('BlockContent ' . $block_content->id());
|
||||
$block_content->setNewRevision(FALSE);
|
||||
$block_content->save();
|
||||
}
|
||||
if ($block_content->label() == 'fail_creation') {
|
||||
|
|
|
@ -2,23 +2,23 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\migrate_drupal\Unit\source\d6\BoxTest.
|
||||
* Contains \Drupal\Tests\block_content\Unit\Plugin\migrate\source\d6\BoxTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\migrate_drupal\Unit\source\d6;
|
||||
namespace Drupal\Tests\block_content\Unit\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
|
||||
|
||||
/**
|
||||
* Tests D6 block boxes source plugin.
|
||||
*
|
||||
* @group migrate_drupal
|
||||
* @group block_content
|
||||
*/
|
||||
class BoxTest extends MigrateSqlSourceTestCase {
|
||||
|
||||
// The plugin system is not working during unit testing so the source plugin
|
||||
// class needs to be manually specified.
|
||||
const PLUGIN_CLASS = 'Drupal\migrate_drupal\Plugin\migrate\source\d6\Box';
|
||||
const PLUGIN_CLASS = 'Drupal\block_content\Plugin\migrate\source\d6\Box';
|
||||
|
||||
// The fake Migration configuration entity.
|
||||
protected $migrationConfiguration = array(
|
|
@ -21,10 +21,3 @@ destination:
|
|||
migration_dependencies:
|
||||
required:
|
||||
- d6_node
|
||||
dependencies:
|
||||
config:
|
||||
- migrate.migration.d6_node
|
||||
module:
|
||||
- book
|
||||
- migrate_drupal
|
||||
- node
|
|
@ -15,7 +15,3 @@ process:
|
|||
destination:
|
||||
plugin: config
|
||||
config_name: book.settings
|
||||
dependencies:
|
||||
module:
|
||||
- book
|
||||
- migrate_drupal
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\book\Cache;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Cache\Context\CacheContextInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerAware;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
@ -14,6 +15,8 @@ use Symfony\Component\HttpFoundation\RequestStack;
|
|||
/**
|
||||
* Defines the book navigation cache context service.
|
||||
*
|
||||
* Cache context ID: 'route.book_navigation'.
|
||||
*
|
||||
* This allows for book navigation location-aware caching. It depends on:
|
||||
* - whether the current route represents a book node at all
|
||||
* - and if so, where in the book hierarchy we are
|
||||
|
@ -65,7 +68,27 @@ class BookNavigationCacheContext extends ContainerAware implements CacheContextI
|
|||
// If we're looking at a book node, get the trail for that node.
|
||||
$active_trail = $this->container->get('book.manager')
|
||||
->getActiveTrailIds($node->book['bid'], $node->book);
|
||||
return 'book.' . implode('|', $active_trail);
|
||||
return implode('|', $active_trail);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata() {
|
||||
// The book active trail depends on the node and data attached to it.
|
||||
// That information is however not stored as part of the node.
|
||||
$cacheable_metadata = new CacheableMetadata();
|
||||
if ($node = $this->requestStack->getCurrentRequest()->get('node')) {
|
||||
// If the node is part of a book then we can use the cache tag for that
|
||||
// book. If not, then it can't be optimized away.
|
||||
if (!empty($node->book['bid'])) {
|
||||
$cacheable_metadata->addCacheTags(['bid:' . $node->book['bid']]);
|
||||
}
|
||||
else {
|
||||
$cacheable_metadata->setCacheMaxAge(0);
|
||||
}
|
||||
}
|
||||
return $cacheable_metadata;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\Book.
|
||||
* Contains \Drupal\book\Plugin\migrate\destination\Book.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
namespace Drupal\book\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\migrate\Plugin\migrate\destination\EntityContentBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Plugin\migrate\source\d6\Book.
|
||||
* Contains \Drupal\book\Plugin\migrate\source\d6\Book.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Plugin\migrate\source\d6;
|
||||
namespace Drupal\book\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
92
core/modules/book/src/ProxyClass/BookUninstallValidator.php
Normal file
92
core/modules/book/src/ProxyClass/BookUninstallValidator.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains Drupal\book\ProxyClass\BookUninstallValidator.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file was generated via php core/scripts/generate-proxy-class.php 'Drupal\book\BookUninstallValidator' "core/modules/book/src".
|
||||
*/
|
||||
|
||||
namespace Drupal\book\ProxyClass {
|
||||
|
||||
/**
|
||||
* Provides a proxy class for \Drupal\book\BookUninstallValidator.
|
||||
*
|
||||
* @see \Drupal\Component\ProxyBuilder
|
||||
*/
|
||||
class BookUninstallValidator implements \Drupal\Core\Extension\ModuleUninstallValidatorInterface
|
||||
{
|
||||
|
||||
use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
|
||||
|
||||
/**
|
||||
* The id of the original proxied service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $drupalProxyOriginalServiceId;
|
||||
|
||||
/**
|
||||
* The real proxied service, after it was lazy loaded.
|
||||
*
|
||||
* @var \Drupal\book\BookUninstallValidator
|
||||
*/
|
||||
protected $service;
|
||||
|
||||
/**
|
||||
* The service container.
|
||||
*
|
||||
* @var \Symfony\Component\DependencyInjection\ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* Constructs a ProxyClass Drupal proxy object.
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
|
||||
* The container.
|
||||
* @param string $drupal_proxy_original_service_id
|
||||
* The service ID of the original service.
|
||||
*/
|
||||
public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy loads the real service from the container.
|
||||
*
|
||||
* @return object
|
||||
* Returns the constructed real service.
|
||||
*/
|
||||
protected function lazyLoadItself()
|
||||
{
|
||||
if (!isset($this->service)) {
|
||||
$this->service = $this->container->get($this->drupalProxyOriginalServiceId);
|
||||
}
|
||||
|
||||
return $this->service;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($module)
|
||||
{
|
||||
return $this->lazyLoadItself()->validate($module);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setStringTranslation(\Drupal\Core\StringTranslation\TranslationInterface $translation)
|
||||
{
|
||||
return $this->lazyLoadItself()->setStringTranslation($translation);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -2,20 +2,18 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Tests\d6\MigrateBookConfigsTest.
|
||||
* Contains \Drupal\book\Tests\Migrate\d6\MigrateBookConfigsTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Tests\d6;
|
||||
namespace Drupal\book\Tests\Migrate\d6;
|
||||
|
||||
use Drupal\config\Tests\SchemaCheckTestTrait;
|
||||
use Drupal\migrate\MigrateMessage;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Upgrade variables to book.settings.yml.
|
||||
*
|
||||
* @group migrate_drupal
|
||||
* @group book
|
||||
*/
|
||||
class MigrateBookConfigsTest extends MigrateDrupal6TestBase {
|
||||
|
||||
|
@ -33,14 +31,8 @@ class MigrateBookConfigsTest extends MigrateDrupal6TestBase {
|
|||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$migration = entity_load('migration', 'd6_book_settings');
|
||||
$dumps = array(
|
||||
$this->getDumpDirectory() . '/Variable.php',
|
||||
);
|
||||
$this->prepare($migration, $dumps);
|
||||
$executable = new MigrateExecutable($migration, new MigrateMessage());
|
||||
$executable->import();
|
||||
$this->loadDumps(['Variable.php']);
|
||||
$this->executeMigration('d6_book_settings');
|
||||
}
|
||||
|
||||
/**
|
|
@ -2,19 +2,18 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_drupal\Tests\d6\MigrateBookTest.
|
||||
* Contains \Drupal\book\Tests\Migrate\d6\MigrateBookTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_drupal\Tests\d6;
|
||||
namespace Drupal\book\Tests\Migrate\d6;
|
||||
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
|
||||
use Drupal\node\Entity\Node;
|
||||
|
||||
/**
|
||||
* Upgrade book structure.
|
||||
*
|
||||
* @group migrate_drupal
|
||||
* @group book
|
||||
*/
|
||||
class MigrateBookTest extends MigrateDrupal6TestBase {
|
||||
|
||||
|
@ -44,15 +43,8 @@ class MigrateBookTest extends MigrateDrupal6TestBase {
|
|||
}
|
||||
$this->prepareMigrations($id_mappings);
|
||||
// Load database dumps to provide source data.
|
||||
$dumps = array(
|
||||
$this->getDumpDirectory() . '/Book.php',
|
||||
$this->getDumpDirectory() . '/MenuLinks.php',
|
||||
);
|
||||
$this->loadDumps($dumps);
|
||||
// Migrate books..
|
||||
$migration = entity_load('migration', 'd6_book');
|
||||
$executable = new MigrateExecutable($migration, $this);
|
||||
$executable->import();
|
||||
$this->loadDumps(['Book.php', 'MenuLinks.php']);
|
||||
$this->executeMigration('d6_book');
|
||||
}
|
||||
|
||||
/**
|
|
@ -169,6 +169,7 @@ class BreakpointManager extends DefaultPluginManager implements BreakpointManage
|
|||
$this->breakpointsByGroup[$group] = $breakpoints;
|
||||
}
|
||||
}
|
||||
|
||||
$instances = array();
|
||||
foreach ($this->breakpointsByGroup[$group] as $plugin_id => $definition) {
|
||||
if (!isset($this->instances[$plugin_id])) {
|
||||
|
|
|
@ -34,34 +34,22 @@ class BreakpointDiscoveryTest extends KernelTestBase {
|
|||
public function testThemeBreakpoints() {
|
||||
// Verify the breakpoint group for breakpoint_theme_test was created.
|
||||
$expected_breakpoints = array(
|
||||
'breakpoint_theme_test.tv' => array(
|
||||
'label' => 'tv',
|
||||
'mediaQuery' => 'only screen and (min-width: 1220px)',
|
||||
'breakpoint_theme_test.mobile' => array(
|
||||
'label' => 'mobile',
|
||||
'mediaQuery' => '(min-width: 0px)',
|
||||
'weight' => 0,
|
||||
'multipliers' => array(
|
||||
'1x',
|
||||
),
|
||||
'provider' => 'breakpoint_theme_test',
|
||||
'id' => 'breakpoint_theme_test.tv',
|
||||
'group' => 'breakpoint_theme_test',
|
||||
'class' => 'Drupal\\breakpoint\\Breakpoint',
|
||||
),
|
||||
'breakpoint_theme_test.wide' => array(
|
||||
'label' => 'wide',
|
||||
'mediaQuery' => '(min-width: 851px)',
|
||||
'weight' => 1,
|
||||
'multipliers' => array(
|
||||
'1x',
|
||||
),
|
||||
'provider' => 'breakpoint_theme_test',
|
||||
'id' => 'breakpoint_theme_test.wide',
|
||||
'id' => 'breakpoint_theme_test.mobile',
|
||||
'group' => 'breakpoint_theme_test',
|
||||
'class' => 'Drupal\\breakpoint\\Breakpoint',
|
||||
),
|
||||
'breakpoint_theme_test.narrow' => array(
|
||||
'label' => 'narrow',
|
||||
'mediaQuery' => '(min-width: 560px)',
|
||||
'weight' => 2,
|
||||
'weight' => 1,
|
||||
'multipliers' => array(
|
||||
'1x',
|
||||
),
|
||||
|
@ -70,15 +58,27 @@ class BreakpointDiscoveryTest extends KernelTestBase {
|
|||
'group' => 'breakpoint_theme_test',
|
||||
'class' => 'Drupal\\breakpoint\\Breakpoint',
|
||||
),
|
||||
'breakpoint_theme_test.mobile' => array(
|
||||
'label' => 'mobile',
|
||||
'mediaQuery' => '(min-width: 0px)',
|
||||
'breakpoint_theme_test.wide' => array(
|
||||
'label' => 'wide',
|
||||
'mediaQuery' => '(min-width: 851px)',
|
||||
'weight' => 2,
|
||||
'multipliers' => array(
|
||||
'1x',
|
||||
),
|
||||
'provider' => 'breakpoint_theme_test',
|
||||
'id' => 'breakpoint_theme_test.wide',
|
||||
'group' => 'breakpoint_theme_test',
|
||||
'class' => 'Drupal\\breakpoint\\Breakpoint',
|
||||
),
|
||||
'breakpoint_theme_test.tv' => array(
|
||||
'label' => 'tv',
|
||||
'mediaQuery' => 'only screen and (min-width: 1220px)',
|
||||
'weight' => 3,
|
||||
'multipliers' => array(
|
||||
'1x',
|
||||
),
|
||||
'provider' => 'breakpoint_theme_test',
|
||||
'id' => 'breakpoint_theme_test.mobile',
|
||||
'id' => 'breakpoint_theme_test.tv',
|
||||
'group' => 'breakpoint_theme_test',
|
||||
'class' => 'Drupal\\breakpoint\\Breakpoint',
|
||||
),
|
||||
|
@ -102,7 +102,7 @@ class BreakpointDiscoveryTest extends KernelTestBase {
|
|||
'breakpoint_theme_test.group2.narrow' => array(
|
||||
'label' => 'narrow',
|
||||
'mediaQuery' => '(min-width: 560px)',
|
||||
'weight' => 2,
|
||||
'weight' => 0,
|
||||
'multipliers' => array(
|
||||
'1x',
|
||||
'2x',
|
||||
|
@ -128,7 +128,7 @@ class BreakpointDiscoveryTest extends KernelTestBase {
|
|||
'breakpoint_module_test.breakpoint_theme_test.group2.tv' => array(
|
||||
'label' => 'tv',
|
||||
'mediaQuery' => '(min-width: 6000px)',
|
||||
'weight' => 0,
|
||||
'weight' => 2,
|
||||
'multipliers' => array(
|
||||
'1x',
|
||||
),
|
||||
|
@ -153,7 +153,7 @@ class BreakpointDiscoveryTest extends KernelTestBase {
|
|||
'breakpoint_module_test.mobile' => array(
|
||||
'label' => 'mobile',
|
||||
'mediaQuery' => '(min-width: 0px)',
|
||||
'weight' => 1,
|
||||
'weight' => 0,
|
||||
'multipliers' => array(
|
||||
'1x',
|
||||
),
|
||||
|
@ -165,7 +165,7 @@ class BreakpointDiscoveryTest extends KernelTestBase {
|
|||
'breakpoint_module_test.standard' => array(
|
||||
'label' => 'standard',
|
||||
'mediaQuery' => '(min-width: 560px)',
|
||||
'weight' => 0,
|
||||
'weight' => 1,
|
||||
'multipliers' => array(
|
||||
'1x',
|
||||
'2x',
|
||||
|
@ -178,9 +178,7 @@ class BreakpointDiscoveryTest extends KernelTestBase {
|
|||
);
|
||||
|
||||
$breakpoints = \Drupal::service('breakpoint.manager')->getBreakpointsByGroup('breakpoint_module_test');
|
||||
foreach ($expected_breakpoints as $id => $expected_breakpoint) {
|
||||
$this->assertEqual($expected_breakpoint, $breakpoints[$id]->getPluginDefinition());
|
||||
}
|
||||
$this->assertEqual(array_keys($expected_breakpoints), array_keys($breakpoints));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
breakpoint_module_test.mobile:
|
||||
label: mobile
|
||||
mediaQuery: '(min-width: 0px)'
|
||||
weight: 1
|
||||
weight: 0
|
||||
# Don't include multipliers. A 1x multiplier this will be enforced by default.
|
||||
breakpoint_module_test.standard:
|
||||
label: standard
|
||||
mediaQuery: '(min-width: 560px)'
|
||||
weight: 0
|
||||
weight: 1
|
||||
# Don't include a 1x multiplier this will be enforced by default.
|
||||
multipliers:
|
||||
- 2x
|
||||
|
@ -15,7 +15,7 @@ breakpoint_module_test.standard:
|
|||
breakpoint_module_test.breakpoint_theme_test.group2.tv:
|
||||
label: tv
|
||||
mediaQuery: '(min-width: 6000px)'
|
||||
weight: 0
|
||||
weight: 2
|
||||
multipliers:
|
||||
- 1x
|
||||
group: breakpoint_theme_test.group2
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
breakpoint_theme_test.mobile:
|
||||
label: mobile
|
||||
mediaQuery: '(min-width: 0px)'
|
||||
weight: 3
|
||||
weight: 0
|
||||
multipliers:
|
||||
- 1x
|
||||
breakpoint_theme_test.narrow:
|
||||
label: narrow
|
||||
mediaQuery: '(min-width: 560px)'
|
||||
weight: 2
|
||||
weight: 1
|
||||
multipliers:
|
||||
- 1x
|
||||
# Out of order breakpoint to test sorting.
|
||||
breakpoint_theme_test.tv:
|
||||
label: tv
|
||||
mediaQuery: 'only screen and (min-width: 1220px)'
|
||||
weight: 0
|
||||
weight: 3
|
||||
multipliers:
|
||||
- 1x
|
||||
breakpoint_theme_test.wide:
|
||||
label: wide
|
||||
mediaQuery: '(min-width: 851px)'
|
||||
weight: 1
|
||||
weight: 2
|
||||
multipliers:
|
||||
- 1x
|
||||
breakpoint_theme_test.group2.narrow:
|
||||
label: narrow
|
||||
mediaQuery: '(min-width: 560px)'
|
||||
weight: 2
|
||||
weight: 0
|
||||
multipliers:
|
||||
- 1x
|
||||
- 2x
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue