Update to Drupal 8.0.0 beta 14. For more information, see https://drupal.org/node/2544542

This commit is contained in:
Pantheon Automation 2015-08-27 12:03:05 -07:00 committed by Greg Anderson
parent 3b2511d96d
commit 81ccda77eb
2155 changed files with 54307 additions and 46870 deletions

View file

@ -0,0 +1,23 @@
uuid: C499B41D-035E-432E-9462-36410C43C49F
langcode: en
status: true
dependencies:
module:
- search
theme:
- bartik
id: secondtestfor2354889
theme: bartik
region: sidebar_first
weight: -6
provider: null
plugin: search_form_block
settings:
id: search_form_block
label: Search
provider: search
label_display: visible
cache:
max_age: -1
status: true
visibility: { }

View file

@ -0,0 +1,51 @@
uuid: 9d204071-a923-4707-8200-c298a540fb0c
langcode: en
status: true
dependencies:
content:
- 'block_content:basic:c1895145-893e-460b-a24e-78cd2cefbb1f'
module:
- block_content
- node
- user
theme:
- bartik
id: testfor2354889
theme: bartik
region: content
weight: -6
provider: null
plugin: 'block_content:c1895145-893e-460b-a24e-78cd2cefbb1f'
settings:
id: 'block_content:c1895145-893e-460b-a24e-78cd2cefbb1f'
label: 'Test for 2354889'
provider: block_content
label_display: visible
cache:
max_age: -1
status: true
info: ''
view_mode: full
visibility:
node_type:
id: node_type
bundles:
page: page
negate: false
context_mapping:
node: node.node
user_role:
id: user_role
roles:
authenticated: authenticated
negate: false
context_mapping:
user: user.current_user
language:
id: language
langcodes:
en: en
de: de
negate: false
context_mapping:
language: language.language_interface

View file

@ -0,0 +1,30 @@
uuid: 4558907D-2918-48FE-B56F-8A007B5FBDD5
langcode: en
status: true
dependencies:
module:
- user
theme:
- bartik
id: thirdtestfor2354889
theme: bartik
region: sidebar_first
weight: -6
provider: null
plugin: user_login_block
settings:
id: user_login_block
label: 'User login'
provider: user
label_display: visible
cache:
max_age: -1
status: true
visibility:
node_type:
id: node_type
bundles:
page: page
negate: false
context_mapping:
baloney: baloney.spam

View file

@ -0,0 +1,53 @@
<?php
/**
* @file
* Contains database additions to drupal-8.bare.standard.php.gz for testing the
* upgrade path of https://www.drupal.org/node/2354889.
*/
use Drupal\Core\Database\Database;
$connection = Database::getConnection();
// A custom block with visibility settings.
$block_configs[] = \Drupal\Component\Serialization\Yaml::decode(file_get_contents(__DIR__ . '/block.block.testfor2354889.yml'));
// A custom block without any visibility settings.
$block_configs[] = \Drupal\Component\Serialization\Yaml::decode(file_get_contents(__DIR__ . '/block.block.secondtestfor2354889.yml'));
// A custom block with visibility settings that contain a non-existing context
// mapping.
$block_configs[] = \Drupal\Component\Serialization\Yaml::decode(file_get_contents(__DIR__ . '/block.block.thirdtestfor2354889.yml'));
foreach ($block_configs as $block_config) {
$connection->insert('config')
->fields(array(
'collection',
'name',
'data',
))
->values(array(
'collection' => '',
'name' => 'block.block.' . $block_config['id'],
'data' => serialize($block_config),
))
->execute();
}
// Update the config entity query "index".
$existing_blocks = $connection->select('key_value')
->fields('key_value', ['value'])
->condition('collection', 'config.entity.key_store.block')
->condition('name', 'theme:bartik')
->execute()
->fetchField();
$existing_blocks = unserialize($existing_blocks);
$connection->update('key_value')
->fields([
'value' => serialize(array_merge($existing_blocks, ['block.block.testfor2354889', 'block.block.secondtestfor2354889', 'block.block.thirdtestfor2354889']))
])
->condition('collection', 'config.entity.key_store.block')
->condition('name', 'theme:bartik')
->execute();

View file

@ -7,7 +7,6 @@
namespace Drupal\accept_header_routing_test\Routing;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Routing\RouteFilterInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException;
@ -62,7 +61,7 @@ class AcceptHeaderMatcher implements RouteFilterInterface {
// We do not throw a
// \Symfony\Component\Routing\Exception\ResourceNotFoundException here
// because we don't want to return a 404 status code, but rather a 406.
throw new NotAcceptableHttpException(SafeMarkup::format('No route found for the specified formats @formats.', array('@formats' => implode(' ', $acceptable_mime_types))));
throw new NotAcceptableHttpException('No route found for the specified formats ' . implode(' ', $acceptable_mime_types));
}
/**

View file

@ -30,10 +30,3 @@ ajax_forms_test.lazy_load_form:
requirements:
_access: 'TRUE'
ajax_forms_test.cached_form:
path: '/ajax_forms_test_cached_form'
defaults:
_title: 'AJAX forms cached form test'
_form: '\Drupal\ajax_forms_test\Form\AjaxFormsTestCachedForm'
requirements:
_access: 'TRUE'

View file

@ -1,50 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\ajax_forms_test\Form\AjaxFormsTestCachedForm.
*/
namespace Drupal\ajax_forms_test\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
/**
* Provides an AJAX form that will be cached.
*/
class AjaxFormsTestCachedForm extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'ajax_form_cache_test_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['test1'] = [
'#type' => 'select',
'#title' => $this->t('Test 1'),
'#options' => [
'option1' => $this->t('Option 1'),
'option2' => $this->t('Option 2'),
],
'#ajax' => [
'url' => Url::fromRoute('system.ajax'),
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
}
}

View file

@ -57,7 +57,7 @@ class AjaxFormsTestSimpleForm extends FormBase {
);
// This is for testing invalid callbacks that should return a 500 error in
// \Drupal\system\FormAjaxController::content().
// \Drupal\Core\Form\FormAjaxResponseBuilderInterface::buildResponse().
$invalid_callbacks = array(
'null' => NULL,
'empty' => '',

View file

@ -0,0 +1,6 @@
cache_test.url_bubbling:
path: '/cache-test/url-bubbling'
defaults:
_controller: '\Drupal\cache_test\Controller\CacheTestController::urlBubbling'
requirements:
_access: 'TRUE'

View file

@ -0,0 +1,29 @@
<?php
/**
* @file
* Contains \Drupal\cache_test\Controller\CacheTestController.
*/
namespace Drupal\cache_test\Controller;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Render\HtmlResponse;
use Drupal\Core\Url;
/**
* Controller routines for cache_test routes.
*/
class CacheTestController {
/**
* Early renders a URL to test bubbleable metadata bubbling.
*/
public function urlBubbling() {
$url = Url::fromRoute('<current>')->setAbsolute();
return [
'#markup' => SafeMarkup::format('This URL is early-rendered: !url. Yet, its bubbleable metadata should be bubbled.', ['!url' => $url->toString()])
];
}
}

View file

@ -0,0 +1,43 @@
<?php
/**
* @file
* Contains \Drupal\condition_test\Plugin\Condition\OptionalContextCondition.
*/
namespace Drupal\condition_test\Plugin\Condition;
use Drupal\Core\Condition\ConditionPluginBase;
/**
* Provides a condition with an optional node context.
*
* The context type entity:node is used since that would allow to also use this
* for web tests with the node route context.
*
* @Condition(
* id = "condition_test_optional_context",
* label = @Translation("Optional context"),
* context = {
* "node" = @ContextDefinition("entity:node", label = @Translation("Node"), required = FALSE),
* }
* )
*/
class OptionalContextCondition extends ConditionPluginBase {
/**
* {@inheritdoc}
*/
public function evaluate() {
// Grant access if no context value is given.
return !$this->getContextValue('node');
}
/**
* {@inheritdoc}
*/
public function summary() {
return $this->t('Context with optional context.');
}
}

View file

@ -0,0 +1,74 @@
<?php
/**
* @file
* Contains \Drupal\condition_test\Tests\OptionalContextConditionTest.
*/
namespace Drupal\condition_test\Tests;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\node\Entity\Node;
use Drupal\simpletest\KernelTestBase;
/**
* Tests a condition with optional context.
*
* @group condition_test
*/
class OptionalContextConditionTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system', 'user', 'condition_test', 'node'];
/**
* Tests with both contexts mapped to the same user.
*/
protected function testContextMissing() {
/** @var \Drupal\Core\Condition\ConditionPluginBase $condition */
$condition = \Drupal::service('plugin.manager.condition')
->createInstance('condition_test_optional_context')
->setContextMapping([
'node' => 'node',
]);
\Drupal::service('context.handler')->applyContextMapping($condition, []);
$this->assertTrue($condition->execute());
}
/**
* Tests with both contexts mapped to the same user.
*/
protected function testContextNoValue() {
/** @var \Drupal\Core\Condition\ConditionPluginBase $condition */
$condition = \Drupal::service('plugin.manager.condition')
->createInstance('condition_test_optional_context')
->setContextMapping([
'node' => 'node',
]);
$definition = new ContextDefinition('entity:node');
$contexts['node'] = (new Context($definition));
\Drupal::service('context.handler')->applyContextMapping($condition, $contexts);
$this->assertTrue($condition->execute());
}
/**
* Tests with both contexts mapped to the same user.
*/
protected function testContextAvailable() {
/** @var \Drupal\Core\Condition\ConditionPluginBase $condition */
$condition = \Drupal::service('plugin.manager.condition')
->createInstance('condition_test_optional_context')
->setContextMapping([
'node' => 'node',
]);
$definition = new ContextDefinition('entity:node');
$node = Node::create(['type' => 'example']);
$contexts['node'] = (new Context($definition))->setContextValue($node);
\Drupal::service('context.handler')->applyContextMapping($condition, $contexts);
$this->assertFalse($condition->execute());
}
}

View file

@ -1,6 +1,6 @@
name: Content negotiation test
type: module
description: 'Support testing content negotiation variations.'
package: Core
package: Testing
version: VERSION
core: 8.x

View file

@ -274,5 +274,21 @@ function database_test_schema() {
'primary key' => array('name', 'age'),
);
$schema['test_special_columns'] = array(
'description' => 'A simple test table with special column names.',
'fields' => array(
'id' => array(
'description' => 'Simple unique ID.',
'type' => 'int',
'not null' => TRUE,
),
'offset' => array(
'description' => 'A column with preserved name.',
'type' => 'text',
),
),
'primary key' => array('id'),
);
return $schema;
}

View file

@ -0,0 +1,6 @@
name: 'Display variant tests'
type: module
description: 'Support module for testing display variants.'
package: Testing
version: VERSION
core: 8.x

View file

@ -0,0 +1,5 @@
services:
display_variant_test.page_display_variant_subscriber:
class: Drupal\display_variant_test\EventSubscriber\TestPageDisplayVariantSubscriber
tags:
- { name: 'event_subscriber', priority: 1000 }

View file

@ -0,0 +1,38 @@
<?php
/**
* @file
* Contains \Drupal\display_variant_test\EventSubscriber\TestPageDisplayVariantSubscriber.
*/
namespace Drupal\display_variant_test\EventSubscriber;
use Drupal\Core\Render\PageDisplayVariantSelectionEvent;
use Drupal\Core\Render\RenderEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Selects the test page display variant.
*/
class TestPageDisplayVariantSubscriber implements EventSubscriberInterface {
/**
* Selects the page display variant.
*
* @param \Drupal\Core\Render\PageDisplayVariantSelectionEvent $event
* The event to process.
*/
public function onSelectPageDisplayVariant(PageDisplayVariantSelectionEvent $event) {
$event->setPluginId('display_variant_test');
$event->setPluginConfiguration(['required_configuration' => 'A very important, required value.']);
}
/**
* {@inheritdoc}
*/
static function getSubscribedEvents() {
$events[RenderEvents::SELECT_PAGE_DISPLAY_VARIANT][] = array('onSelectPageDisplayVariant');
return $events;
}
}

View file

@ -0,0 +1,54 @@
<?php
/**
* @file
* Contains \Drupal\display_variant_test\Plugin\DisplayVariant\TestDisplayVariant.
*/
namespace Drupal\display_variant_test\Plugin\DisplayVariant;
use Drupal\Core\Display\VariantBase;
use Drupal\Core\Display\PageVariantInterface;
/**
* Provides a display variant that requires configuration.
*
* @DisplayVariant(
* id = "display_variant_test",
* admin_label = @Translation("Test display variant")
* )
*/
class TestDisplayVariant extends VariantBase implements PageVariantInterface {
/**
* The render array representing the main page content.
*
* @var array
*/
protected $mainContent = [];
/**
* {@inheritdoc}
*/
public function setMainContent(array $main_content) {
$this->mainContent = $main_content;
return $this;
}
/**
* {@inheritdoc}
*/
public function build() {
$config = $this->getConfiguration();
if (empty($config['required_configuration'])) {
throw new \Exception('Required configuration is missing!');
}
$build = [];
$build['content']['default'] = [
'#markup' => $config['required_configuration'],
];
return $build;
}
}

View file

@ -0,0 +1,6 @@
name: 'Early rendering controller test'
type: module
description: 'Support module for EarlyRenderingControllerTest.'
package: Testing
version: VERSION
core: 8.x

View file

@ -0,0 +1,111 @@
# Controller returning a render array.
early_rendering_controller_test.render_array:
path: '/early-rendering-controller-test/render-array'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::renderArray'
requirements:
_access: 'TRUE'
early_rendering_controller_test.render_array.early:
path: '/early-rendering-controller-test/render-array/early'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::renderArrayEarly'
requirements:
_access: 'TRUE'
# Controller returning an AjaxResponse.
early_rendering_controller_test.ajax_response:
path: '/early-rendering-controller-test/ajax-response'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::ajaxResponse'
requirements:
_access: 'TRUE'
early_rendering_controller_test.ajax_response.early:
path: '/early-rendering-controller-test/ajax-response/early'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::ajaxResponseEarly'
requirements:
_access: 'TRUE'
# Controller returning a basic Response object.
early_rendering_controller_test.response:
path: '/early-rendering-controller-test/response'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::response'
requirements:
_access: 'TRUE'
early_rendering_controller_test.response.early:
path: '/early-rendering-controller-test/response/early'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::responseEarly'
requirements:
_access: 'TRUE'
# Controller returning a Response object with attachments.
early_rendering_controller_test.response-with-attachments:
path: '/early-rendering-controller-test/response-with-attachments'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::responseWithAttachments'
requirements:
_access: 'TRUE'
early_rendering_controller_test.response-with-attachments.early:
path: '/early-rendering-controller-test/response-with-attachments/early'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::responseWithAttachmentsEarly'
requirements:
_access: 'TRUE'
# Controller returning a cacheable Response object.
early_rendering_controller_test.cacheable-response:
path: '/early-rendering-controller-test/cacheable-response'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::cacheableResponse'
requirements:
_access: 'TRUE'
early_rendering_controller_test.cacheable-response.early:
path: '/early-rendering-controller-test/cacheable-response/early'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::cacheableResponseEarly'
requirements:
_access: 'TRUE'
# Controller returning a basic domain object.
early_rendering_controller_test.domain-object:
path: '/early-rendering-controller-test/domain-object'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::domainObject'
requirements:
_access: 'TRUE'
early_rendering_controller_test.domain-object.early:
path: '/early-rendering-controller-test/domain-object/early'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::domainObjectEarly'
requirements:
_access: 'TRUE'
# Controller returning a domain object with attachments.
early_rendering_controller_test.domain-object-with-attachments:
path: '/early-rendering-controller-test/domain-object-with-attachments'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::domainObjectWithAttachments'
requirements:
_access: 'TRUE'
early_rendering_controller_test.domain-object-with-attachments.early:
path: '/early-rendering-controller-test/domain-object-with-attachments/early'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::domainObjectWithAttachmentsEarly'
requirements:
_access: 'TRUE'
# Controller returning a cacheable domain object.
early_rendering_controller_test.cacheable-domain-object:
path: '/early-rendering-controller-test/cacheable-domain-object'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::cacheableDomainObject'
requirements:
_access: 'TRUE'
early_rendering_controller_test.cacheable-domain-object.early:
path: '/early-rendering-controller-test/cacheable-domain-object/early'
defaults:
_controller: '\Drupal\early_rendering_controller_test\EarlyRenderingTestController::cacheableDomainObjectEarly'
requirements:
_access: 'TRUE'

View file

@ -0,0 +1,5 @@
services:
test_domain_object.view_subscriber:
class: Drupal\early_rendering_controller_test\TestDomainObjectViewSubscriber
tags:
- { name: event_subscriber }

View file

@ -0,0 +1,17 @@
<?php
/**
* @file
* Contains \Drupal\early_rendering_controller_test\AttachmentsTestDomainObject.
*/
namespace Drupal\early_rendering_controller_test;
use Drupal\Core\Render\AttachmentsInterface;
use Drupal\Core\Render\AttachmentsTrait;
class AttachmentsTestDomainObject extends TestDomainObject implements AttachmentsInterface {
use AttachmentsTrait;
}

View file

@ -0,0 +1,18 @@
<?php
/**
* @file
* Contains \Drupal\early_rendering_controller_test\AttachmentsTestResponse.
*/
namespace Drupal\early_rendering_controller_test;
use Drupal\Core\Render\AttachmentsInterface;
use Drupal\Core\Render\AttachmentsTrait;
use Symfony\Component\HttpFoundation\Response;
class AttachmentsTestResponse extends Response implements AttachmentsInterface {
use AttachmentsTrait;
}

View file

@ -0,0 +1,35 @@
<?php
/**
* @file
* Contains \Drupal\early_rendering_controller_test\AttachmentsTestDomainObject.
*/
namespace Drupal\early_rendering_controller_test;
use Drupal\Core\Cache\CacheableDependencyInterface;
class CacheableTestDomainObject extends TestDomainObject implements CacheableDependencyInterface {
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return [];
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
return [];
}
/**
* {@inheritdoc}
*/
public function getCacheMaxAge() {
return 0;
}
}

View file

@ -0,0 +1,18 @@
<?php
/**
* @file
* Contains \Drupal\early_rendering_controller_test\CacheableTestResponse.
*/
namespace Drupal\early_rendering_controller_test;
use Drupal\Core\Cache\CacheableResponseInterface;
use Drupal\Core\Cache\CacheableResponseTrait;
use Symfony\Component\HttpFoundation\Response;
class CacheableTestResponse extends Response implements CacheableResponseInterface {
use CacheableResponseTrait;
}

View file

@ -0,0 +1,150 @@
<?php
/**
* @file
* Contains \Drupal\early_rendering_controller_test\EarlyRenderingTestController.
*/
namespace Drupal\early_rendering_controller_test;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\InsertCommand;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Render\RendererInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Response;
/**
* Controller routines for early_rendering_test routes.
*
* The methods on this controller each correspond to a route for this module,
* each of which exist solely for test cases in EarlyRenderingControllerTest;
* see that test for documentation.
*
* @see core/modules/early_rendering_controller_test/early_rendering_controller_test.routing.yml
* @see \Drupal\system\Tests\Common\EarlyRenderingControllerTest::testEarlyRendering()
*/
class EarlyRenderingTestController extends ControllerBase {
/**
* The renderer.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* Constructs a EarlyRenderingTestController.
*
* @param \Drupal\Core\Render\RendererInterface $renderer
*/
public function __construct(RendererInterface $renderer) {
$this->renderer = $renderer;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('renderer')
);
}
protected function earlyRenderContent() {
return [
'#markup' => 'Hello world!',
'#cache' => [
'tags' => [
'foo',
],
],
];
}
public function renderArray() {
return [
'#pre_render' => [function () {
$elements = $this->earlyRenderContent();
return $elements;
}],
];
}
public function renderArrayEarly() {
$render_array = $this->earlyRenderContent();
return [
'#markup' => $this->renderer->render($render_array),
];
}
public function ajaxResponse() {
$response = new AjaxResponse();
$response->addCommand(new InsertCommand(NULL, $this->renderArray()));
return $response;
}
public function ajaxResponseEarly() {
$response = new AjaxResponse();
$response->addCommand(new InsertCommand(NULL, $this->renderArrayEarly()));
return $response;
}
public function response() {
return new Response('Hello world!');
}
public function responseEarly() {
$render_array = $this->earlyRenderContent();
return new Response($this->renderer->render($render_array));
}
public function responseWithAttachments() {
return new AttachmentsTestResponse('Hello world!');
}
public function responseWithAttachmentsEarly() {
$render_array = $this->earlyRenderContent();
return new AttachmentsTestResponse($this->renderer->render($render_array));
}
public function cacheableResponse() {
return new CacheableTestResponse('Hello world!');
}
public function cacheableResponseEarly() {
$render_array = $this->earlyRenderContent();
return new CacheableTestResponse($this->renderer->render($render_array));
}
public function domainObject() {
return new TestDomainObject();
}
public function domainObjectEarly() {
$render_array = $this->earlyRenderContent();
$this->renderer->render($render_array);
return new TestDomainObject();
}
public function domainObjectWithAttachments() {
return new AttachmentsTestDomainObject();
}
public function domainObjectWithAttachmentsEarly() {
$render_array = $this->earlyRenderContent();
$this->renderer->render($render_array);
return new AttachmentsTestDomainObject();
}
public function cacheableDomainObject() {
return new CacheableTestDomainObject();
}
public function cacheableDomainObjectEarly() {
$render_array = $this->earlyRenderContent();
$this->renderer->render($render_array);
return new CacheableTestDomainObject();
}
}

View file

@ -0,0 +1,10 @@
<?php
/**
* @file
* Contains \Drupal\early_rendering_controller_test\TestDomainObject.
*/
namespace Drupal\early_rendering_controller_test;
class TestDomainObject { }

View file

@ -0,0 +1,51 @@
<?php
/**
* @file
* Contains \Drupal\early_rendering_controller_test\TestDomainObjectViewSubscriber.
*/
namespace Drupal\early_rendering_controller_test;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* View subscriber for turning TestDomainObject objects into Response objects.
*/
class TestDomainObjectViewSubscriber implements EventSubscriberInterface {
/**
* Sets a response given a TestDomainObject instance.
*
* @param \Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent $event
* The event to process.
*/
public function onViewTestDomainObject(GetResponseForControllerResultEvent $event) {
$result = $event->getControllerResult();
if ($result instanceof TestDomainObject) {
if ($result instanceof AttachmentsTestDomainObject) {
$event->setResponse(new AttachmentsTestResponse('AttachmentsTestDomainObject'));
}
elseif ($result instanceof CacheableTestDomainObject) {
$event->setResponse(new CacheableTestResponse('CacheableTestDomainObject'));
}
else {
$event->setResponse(new Response('TestDomainObject'));
}
}
}
/**
* {@inheritdoc}
*/
static function getSubscribedEvents() {
$events[KernelEvents::VIEW][] = ['onViewTestDomainObject'];
return $events;
}
}

View file

@ -9,6 +9,7 @@ use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
@ -97,6 +98,23 @@ function entity_test_entity_type_alter(array &$entity_types) {
}
}
/**
* Implements hook_entity_base_field_info().
*/
function entity_test_entity_base_field_info(EntityTypeInterface $entity_type) {
$fields = [];
if ($entity_type->id() == 'entity_test_mulrev' && \Drupal::state()->get('entity_test.field_test_item')) {
$fields['field_test_item'] = BaseFieldDefinition::create('field_test')
->setLabel(t('Field test'))
->setDescription(t('A field test.'))
->setRevisionable(TRUE)
->setTranslatable(TRUE);
}
return $fields;
}
/**
* Implements hook_entity_base_field_info_alter().
*/
@ -257,6 +275,37 @@ function entity_test_entity_extra_field_info() {
return $extra;
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*/
function entity_test_form_entity_test_form_alter(&$form) {
switch (\Drupal::state()->get('entity_test.form.validate.test')) {
case 'form-level':
$form['#validate'][] = 'entity_test_form_entity_test_form_validate';
$form['#validate'][] = 'entity_test_form_entity_test_form_validate_check';
break;
case 'button-level':
$form['actions']['submit']['#validate'][] = 'entity_test_form_entity_test_form_validate';
}
}
/**
* Validation handler for the entity_test entity form.
*/
function entity_test_form_entity_test_form_validate(array &$form, FormStateInterface $form_state) {
$form['#entity_test_form_validate'] = TRUE;
}
/**
* Validation handler for the entity_test entity form.
*/
function entity_test_form_entity_test_form_validate_check(array &$form, FormStateInterface $form_state) {
if (!empty($form['#entity_test_form_validate'])) {
\Drupal::state()->set('entity_test.form.validate.result', TRUE);
}
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*/

View file

@ -76,5 +76,12 @@ entity.user_role.test_operation:
requirements:
_access: 'TRUE'
entity.entity_test_view_builder.canonical:
path: '/entity_test_view_builder/{entity_test_view_builder}'
defaults:
_entity_view: 'entity_test_view_builder'
requirements:
_access: 'TRUE'
route_callbacks:
- '\Drupal\entity_test\Routing\EntityTestRoutes::routes'

View file

@ -7,11 +7,14 @@
namespace Drupal\entity_test\Cache;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\Context\CacheContextInterface;
/**
* Defines the entity_test view grants cache context service.
*
* Cache context ID: 'entity_test_view_grants'.
*
* @see \Drupal\node\Cache\NodeAccessViewGrantsCacheContext
*/
class EntityTestViewGrantsCacheContext implements CacheContextInterface {
@ -32,4 +35,11 @@ class EntityTestViewGrantsCacheContext implements CacheContextInterface {
return '299792458';
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
return new CacheableMetadata();
}
}

View file

@ -0,0 +1,31 @@
<?php
/**
* @file
* Contains \Drupal\entity_test\Entity\EntityTestViewBuilder.
*/
namespace Drupal\entity_test\Entity;
/**
* Test entity class for testing a view builder.
*
* @ContentEntityType(
* id = "entity_test_view_builder",
* label = @Translation("Entity Test view builder"),
* handlers = {
* "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
* "view_builder" = "Drupal\entity_test\EntityTestViewBuilderOverriddenView",
* },
* base_table = "entity_test",
* render_cache = FALSE,
* entity_keys = {
* "id" = "id",
* "label" = "name",
* "bundle" = "type"
* }
* )
*/
class EntityTestViewBuilder extends EntityTest {
}

View file

@ -51,35 +51,40 @@ class EntityTestForm extends ContentEntityForm {
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
$entity = $this->entity;
try {
$entity = $this->entity;
// Save as a new revision if requested to do so.
if (!$form_state->isValueEmpty('revision')) {
$entity->setNewRevision();
}
// Save as a new revision if requested to do so.
if (!$form_state->isValueEmpty('revision')) {
$entity->setNewRevision();
}
$is_new = $entity->isNew();
$entity->save();
$is_new = $entity->isNew();
$entity->save();
if ($is_new) {
$message = t('%entity_type @id has been created.', array('@id' => $entity->id(), '%entity_type' => $entity->getEntityTypeId()));
}
else {
$message = t('%entity_type @id has been updated.', array('@id' => $entity->id(), '%entity_type' => $entity->getEntityTypeId()));
}
drupal_set_message($message);
if ($is_new) {
$message = t('%entity_type @id has been created.', array('@id' => $entity->id(), '%entity_type' => $entity->getEntityTypeId()));
}
else {
$message = t('%entity_type @id has been updated.', array('@id' => $entity->id(), '%entity_type' => $entity->getEntityTypeId()));
}
drupal_set_message($message);
if ($entity->id()) {
$entity_type = $entity->getEntityTypeId();
$form_state->setRedirect(
"entity.$entity_type.edit_form",
array($entity_type => $entity->id())
);
if ($entity->id()) {
$entity_type = $entity->getEntityTypeId();
$form_state->setRedirect(
"entity.$entity_type.edit_form",
array($entity_type => $entity->id())
);
}
else {
// Error on save.
drupal_set_message(t('The entity could not be saved.'), 'error');
$form_state->setRebuild();
}
}
else {
// Error on save.
drupal_set_message(t('The entity could not be saved.'), 'error');
$form_state->setRebuild();
catch (\Exception $e) {
\Drupal::state()->set('entity_test.form.save.exception', get_class($e) . ': ' . $e->getMessage());
}
}

View file

@ -0,0 +1,38 @@
<?php
/**
* @file
* Contains \Drupal\entity_test\EntityTestViewBuilderOverriddenView.
*/
namespace Drupal\entity_test;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Entity\EntityInterface;
/**
* Provides a view builder that overrides ::view() and ::viewMultiple().
*/
class EntityTestViewBuilderOverriddenView extends EntityTestViewBuilder {
/**
* {@inheritdoc}
*/
public function view(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) {
$build = [];
$build[$entity->id()]['#markup'] = SafeMarkup::checkPlain($entity->label());
return $build;
}
/**
* {@inheritdoc}
*/
public function viewMultiple(array $entities = [], $view_mode = 'full', $langcode = NULL) {
$build = [];
foreach ($entities as $key => $entity) {
$build[$key] = $this->view($entity, $view_mode, $langcode);
}
return $build;
}
}

View file

@ -0,0 +1,118 @@
<?php
/**
* @file
* Contains \Drupal\entity_test\Plugin\Field\FieldType\FieldTestItem.
*/
namespace Drupal\entity_test\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\StringTranslation\TranslationWrapper;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\TypedData\DataDefinitionInterface;
use Drupal\Core\TypedData\TypedDataInterface;
/**
* Defines the 'field_test' entity field type.
*
* @FieldType(
* id = "field_test",
* label = @Translation("Test field item"),
* description = @Translation("A field containing a plain string value."),
* category = @Translation("Field"),
* )
*/
class FieldTestItem extends FieldItemBase {
/**
* Counts how many times all items of this type are saved.
*
* @var int
*/
protected static $counter = [];
/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
// This is called very early by the user entity roles field. Prevent
// early t() calls by using the TranslationWrapper.
$properties['value'] = DataDefinition::create('string')
->setLabel(new TranslationWrapper('Test value'))
->setRequired(TRUE);
return $properties;
}
/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition) {
return array(
'columns' => array(
'value' => array(
'type' => 'varchar',
'length' => 255,
),
),
);
}
/**
* {@inheritdoc}
*/
public function __construct(DataDefinitionInterface $definition, $name = NULL, TypedDataInterface $parent = NULL) {
parent::__construct($definition, $name, $parent);
$name = $this->getFieldDefinition()->getName();
static::$counter[$name] = 0;
}
/**
* {@inheritdoc}
*/
public function preSave() {
$name = $this->getFieldDefinition()->getName();
static::$counter[$name]++;
// Overwrite the field value unless it is going to be overridden, in which
// case its final value will already be different from the current one.
if (!$this->getEntity()->isNew() && !$this->mustResave()) {
$this->setValue('overwritten');
}
}
/**
* {@inheritdoc}
*/
public function postSave($update) {
// Determine whether the field value should be rewritten to the storage. We
// always rewrite on create as we need to store a value including the entity
// id.
$resave = !$update || $this->mustResave();
if ($resave) {
$entity = $this->getEntity();
$definition = $this->getFieldDefinition();
$name = $definition->getName();
$value = 'field_test:' . $name . ':' . $entity->id() . ':' . static::$counter[$name];
$this->setValue($value);
}
return $resave;
}
/**
* Checks whether the field item value should be resaved.
*
* @return bool
* TRUE if the item should be resaved, FALSE otherwise.
*/
protected function mustResave() {
return $this->getValue()['value'] == 'resave';
}
}

View file

@ -0,0 +1,6 @@
name: 'Entity Operation Test'
type: module
description: 'Provides a test operation to entities.'
package: Testing
version: VERSION
core: 8.x

View file

@ -0,0 +1,21 @@
<?php
/**
* @file
* Contains hook implementations for Entity Operation Test Module.
*/
use Drupal\Core\Url;
/**
* Implements hook_entity_operation().
*/
function entity_test_operation_entity_operation(\Drupal\Core\Entity\EntityInterface $entity) {
return [
'test' => [
'title' => t('Front page'),
'url' => Url::fromRoute('<front>'),
'weight' => 0,
],
];
}

View file

@ -0,0 +1,6 @@
name: 'Error service test'
type: module
description: 'Support module for causing bedlam in container rebuilds.'
package: Testing
version: VERSION
core: 8.x

View file

@ -0,0 +1,6 @@
error_service_test.broken_class:
path: broken-service-class
defaults:
_controller: \Drupal\error_service_test\Controller\LonelyMonkeyController::testBrokenClass
requirements:
_access: 'TRUE'

View file

@ -0,0 +1,8 @@
services:
http_middleware.monkeys:
class: Drupal\error_service_test\MonkeysInTheControlRoom
tags:
- { name: http_middleware, priority: 400 }
# Set up a service with a missing class dependency.
broken_class_with_missing_dependency:
class: Drupal\error_service_test\LonelyMonkeyClass

View file

@ -0,0 +1,37 @@
<?php
/**
* @file
* Contains \Drupal\error_service_test\Controller\LonelyMonkeyController.
*/
namespace Drupal\error_service_test\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\error_service_test\LonelyMonkeyClass;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a controller which calls out to a service with missing dependencies.
*/
class LonelyMonkeyController extends ControllerBase implements ContainerInjectionInterface {
public function __construct(LonelyMonkeyClass $class) {
$this->class = $class;
}
public function testBrokenClass() {
return [
'#markup' => $this->t('This should be broken.'),
];
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container->get('broken_class_with_missing_dependency'));
}
}

View file

@ -0,0 +1,28 @@
<?php
/**
* @file
* Contains \Drupal\error_service_test\ErrorServiceTestServiceProvider.
*/
namespace Drupal\error_service_test;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
class ErrorServiceTestServiceProvider implements ServiceModifierInterface {
/**
* The in-situ container builder.
*
* @var \Drupal\Core\DependencyInjection\ContainerBuilder
*/
public static $containerBuilder;
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container) {
static::$containerBuilder = $container;
}
}

View file

@ -0,0 +1,21 @@
<?php
/**
* @file
* Contains \Drupal\error_service_test\LonelyMonkeyClass.
*/
namespace Drupal\error_service_test;
use Drupal\Core\Database\Connection;
/**
* A class with a single dependency.
*/
class LonelyMonkeyClass {
public function __construct(Connection $connection) {
$this->connection = $connection;
}
}

View file

@ -0,0 +1,63 @@
<?php
/**
* @file
* Contains \Drupal\error_service_test\MonkeysInTheControlRoom.
*/
namespace Drupal\error_service_test;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* A http middleware designed to cause bedlam.
*
* @see error_service_test.services.yml
*/
class MonkeysInTheControlRoom implements HttpKernelInterface {
/**
* The app kernel.
*
* @var \Symfony\Component\HttpKernel\HttpKernelInterface
*/
protected $app;
/**
* MonkeysInTheControlRoom constructor.
*
* @param \Symfony\Component\HttpKernel\HttpKernelInterface $app
* The wrapper HTTP kernel.
*/
public function __construct(HttpKernelInterface $app) {
$this->app = $app;
}
/**
* {@inheritdoc}
*/
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
if (\Drupal::state()->get('error_service_test.break_bare_html_renderer')) {
// Let the bedlam begin.
// 1) Force a container rebuild.
/** @var \Drupal\Core\DrupalKernelInterface $kernel */
$kernel = \Drupal::service('kernel');
$kernel->rebuildContainer();
// 2) Fetch the in-situ container builder.
$container = ErrorServiceTestServiceProvider::$containerBuilder;
// Ensure the compiler pass worked.
if (!$container) {
throw new \Exception('Oh oh, monkeys stole the ServiceProvider.');
}
// Stop the theme manager from being found - and triggering error
// maintenance mode.
$container->removeDefinition('theme.manager');
// Mash. Mash. Mash.
\Drupal::setContainer($container);
throw new \Exception('Oh oh, bananas in the instruments.');
}
return $this->app->handle($request, $type, $catch);
}
}

View file

@ -75,19 +75,6 @@ function _form_test_tableselect_get_data() {
return array($header, $options);
}
/**
* Implements hook_form_FORM_ID_alter().
*
* @see form_test_state_persist()
*/
function form_test_form_form_test_state_persist_alter(&$form, FormStateInterface $form_state) {
// Simulate a form alter implementation inserting form elements that enable
// caching of the form, e.g. elements having #ajax.
if (\Drupal::request()->get('cache')) {
$form_state->setCached();
}
}
/**
* Implements hook_form_FORM_ID_alter() for the registration form.
*/

View file

@ -82,17 +82,33 @@ class FormTestStorageForm extends FormBase {
'#value' => 'Save',
);
if (\Drupal::request()->get('cache')) {
// @todo Remove this in https://www.drupal.org/node/2524408, because form
// cache immutability is no longer necessary, because we no longer cache
// forms during safe HTTP methods. In the meantime, because
// Drupal\system\Tests\Form still has test coverage for a poisoned form
// cache following a GET request, trick $form_state into caching the form
// to keep that test working until we either remove it or change it in
// that issue.
if ($this->getRequest()->get('immutable')) {
$form_state->addBuildInfo('immutable', TRUE);
if ($this->getRequest()->get('cache') && $this->getRequest()->isMethodSafe()) {
$form_state->setRequestMethod('FAKE');
$form_state->setCached();
}
}
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
if ($this->getRequest()->get('cache')) {
// Manually activate caching, so we can test that the storage keeps working
// when it's enabled.
$form_state->setCached();
}
if ($this->getRequest()->get('immutable')) {
$form_state->addBuildInfo('immutable', TRUE);
}
return $form;
}
/**
@ -105,7 +121,7 @@ class FormTestStorageForm extends FormBase {
// This presumes that another submitted form value triggers a validation error
// elsewhere in the form. Form API should still update the cached form storage
// though.
if (\Drupal::request()->get('cache') && $form_state->getValue('value') == 'change_title') {
if ($this->getRequest()->get('cache') && $form_state->getValue('value') == 'change_title') {
$form_state->set(['thing', 'changed'], TRUE);
}
}

View file

@ -48,7 +48,6 @@ class FormTestStoragePageCacheForm extends FormBase {
);
$form['#after_build'] = array(array($this, 'form_test_storage_page_cache_old_build_id'));
$form_state->setCached();
return $form;
}
@ -70,6 +69,17 @@ class FormTestStoragePageCacheForm extends FormBase {
$form_state->setRebuild();
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
// Test using form cache when re-displaying a form due to validation
// errors.
if ($form_state->hasAnyErrors()) {
$form_state->setCached();
}
}
/**
* {@inheritdoc}
*/

View file

@ -49,10 +49,6 @@ class FormTestValidateForm extends FormBase {
'#value' => 'Save',
);
// To simplify this test, enable form caching and use form storage to
// remember our alteration.
$form_state->setCached();
return $form;
}
@ -70,6 +66,10 @@ class FormTestValidateForm extends FormBase {
// Trigger a form validation error to see our changes.
$form_state->setErrorByName('');
// To simplify this test, enable form caching and use form storage to
// remember our alteration.
$form_state->setCached();
}
}

View file

@ -26,6 +26,22 @@ menu_test.local_action4:
appears_on:
- menu_test.local_action1
menu_test.local_action_derivative:
route_name: menu_test.local_action4
weight: -20
deriver: Drupal\menu_test\Plugin\Derivative\LocalActionTest
class: Drupal\Core\Menu\LocalActionDefault
appears_on:
- menu_test.local_action1
menu_test.local_action6:
route_name: menu_test.local_action4
title: 'Dynamic local action with user input'
weight: -15
class: '\Drupal\menu_test\Plugin\Menu\LocalAction\TestLocalAction5'
appears_on:
- menu_test.local_action1
menu_test.hidden_menu_add:
route_name: menu_test.hidden_menu_add
title: 'Add menu'

View file

@ -1,12 +1,13 @@
menu_test.hidden_manage:
title: 'List links'
menu_test.contextual_hidden_manage:
title: 'List links - contextual'
group: menu_test_menu
route_name: menu_test.hidden_manage
route_name: menu_test.contextual_hidden_manage
class: '\Drupal\menu_test\Plugin\Menu\ContextualLink\TestContextualLink'
menu_test.hidden_manage_edit:
title: 'Edit menu'
menu_test.contextual_hidden_manage_edit:
title: 'Edit menu - contextual'
group: menu_test_menu
route_name: menu_test.hidden_manage_edit
route_name: menu_test.contextual_hidden_manage_edit
menu_test.hidden_block_configure:
title: 'Configure block'

View file

@ -79,3 +79,7 @@ menu_test.child:
title: 'Test menu_name child'
route_name: menu_test.menu_name_test
parent: menu_test.parent
menu_test.unsafe:
route_name: menu_test.menu_name_test
deriver: '\Drupal\menu_test\Plugin\Derivative\MenuLinkTestWithUnsafeTitle'

View file

@ -10,6 +10,10 @@ menu_test.local_task_test_tasks_settings:
route_name: menu_test.local_task_test_tasks_settings
title: Settings
base_route: menu_test.local_task_test_tasks_view
menu_test.local_task_test_tasks_settings_dynamic:
route_name: menu_test.local_task_test_tasks_settings_dynamic
base_route: menu_test.local_task_test_tasks_view
class: \Drupal\menu_test\Plugin\Menu\LocalTask\TestTaskWithUserInput
menu_test.local_task_test_tasks_settings_sub1:
route_name: menu_test.local_task_test_tasks_settings_sub1
title: sub1
@ -53,6 +57,11 @@ menu_test.tasks_default_tab:
route_name: menu_test.tasks_default
title: 'View'
base_route: menu_test.tasks_default
menu_test.tasks_default_derived:
route_name: menu_test.router_test1
title: 'Derived'
base_route: menu_test.tasks_default
deriver: '\Drupal\menu_test\Plugin\Derivative\LocalTaskTestWithUnsafeTitle'
menu_test.tasks_tasks_tab:
route_name: menu_test.tasks_tasks
@ -82,3 +91,8 @@ menu_test.router_test3:
route_name: menu_test.router_test3
title: 'Local task C'
base_route: menu_test.router_test1
menu_test.router_test4:
route_name: menu_test.router_test4
base_route: menu_test.router_test1
class: \Drupal\menu_test\Plugin\Menu\LocalTask\TestTaskWithUserInput

View file

@ -5,6 +5,8 @@
* Module that implements various hooks for menu tests.
*/
use Drupal\Core\Url;
/**
* Implements hook_menu_links_discovered_alter().
*/
@ -26,20 +28,14 @@ function menu_test_menu_links_discovered_alter(&$links) {
/**
* Implements hook_menu_local_tasks().
*
* If the menu_test.settings configuration 'tasks.add' has been set, adds
* several local tasks to menu-test/tasks.
*/
function menu_test_menu_local_tasks(&$data, $route_name) {
if (!\Drupal::config('menu_test.settings')->get('tasks.add')) {
return;
}
if (in_array($route_name, array('menu_test.tasks_default', 'menu_test.tasks_empty', 'menu_test.tasks_tasks'))) {
if (in_array($route_name, array('menu_test.tasks_default'))) {
$data['tabs'][0]['foo'] = array(
'#theme' => 'menu_local_task',
'#link' => array(
'title' => 'Task 1',
'href' => 'task/foo',
'title' => "Task 1 <script>alert('Welcome to the jungle!')</script>",
'url' => Url::fromRoute('menu_test.router_test1', array('bar' => '1')),
),
'#weight' => 10,
);
@ -47,7 +43,7 @@ function menu_test_menu_local_tasks(&$data, $route_name) {
'#theme' => 'menu_local_task',
'#link' => array(
'title' => 'Task 2',
'href' => 'task/bar',
'url' => Url::fromRoute('menu_test.router_test2', array('bar' => '2')),
),
'#weight' => 20,
);

View file

@ -67,6 +67,13 @@ menu_test.router_test3:
requirements:
_access: 'FALSE'
menu_test.router_test4:
path: '/foo/{bar}/d'
defaults:
_controller: '\Drupal\menu_test\TestControllers::test2'
requirements:
_access: 'TRUE'
menu_test.local_action1:
path: '/menu-test-local-action'
defaults:
@ -102,6 +109,27 @@ menu_test.local_action5:
requirements:
_access: 'TRUE'
menu_test.contextual_test:
path: '/menu-test-contextual/default'
defaults:
_controller: '\Drupal\menu_test\TestControllers::testContextual'
requirements:
_access: 'TRUE'
menu_test.contextual_hidden_manage:
path: '/menu-test-contextual/{bar}'
defaults:
_controller: '\Drupal\menu_test\TestControllers::test1'
requirements:
_access: 'TRUE'
menu_test.contextual_hidden_manage_edit:
path: '/menu-test-contextual/{bar}/edit'
defaults:
_controller: '\Drupal\menu_test\TestControllers::test2'
requirements:
_access: 'TRUE'
menu_test.local_task_test_tasks:
path: '/menu-local-task-test/tasks'
defaults:
@ -109,6 +137,13 @@ menu_test.local_task_test_tasks:
requirements:
_access: 'TRUE'
menu_test.tasks_default:
path: '/menu-local-task-test/default'
defaults:
_controller: '\Drupal\menu_test\TestControllers::test1'
requirements:
_access: 'TRUE'
menu_test.local_task_test_tasks_tasks:
path: '/menu-local-task-test/tasks/tasks'
defaults:
@ -137,6 +172,13 @@ menu_test.local_task_test_tasks_settings:
requirements:
_access: 'TRUE'
menu_test.local_task_test_tasks_settings_dynamic:
path: '/menu-local-task-test/tasks/settings-dynamic'
defaults:
_controller: '\Drupal\menu_test\TestControllers::test1'
requirements:
_access: 'TRUE'
menu_test.local_task_test_tasks_settings_sub1:
path: '/menu-local-task-test/tasks/settings/sub1'
defaults:

View file

@ -0,0 +1,30 @@
<?php
/**
* @file
* Contains \Drupal\menu_test\Plugin\Derivative\LocalActionTest.
*/
namespace Drupal\menu_test\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DeriverBase;
/**
* Test derivative to check local action title escaping.
*
* @see \Drupal\system\Tests\Menu\LocalActionTest
*/
class LocalActionTest extends DeriverBase {
/**
* @inheritDoc
*/
public function getDerivativeDefinitions($base_plugin_definition) {
$this->derivatives['example'] = $base_plugin_definition + [
'title' => "<script>alert('Welcome to the derived jungle!')</script>",
];
return $this->derivatives;
}
}

View file

@ -0,0 +1,31 @@
<?php
/**
* @file
* Contains \Drupal\menu_test\Plugin\Derivative\LocalTaskTestWithUnsafeTitle.
*/
namespace Drupal\menu_test\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DeriverBase;
/**
* Test derivative to check local task title escaping.
*
* @see \Drupal\system\Tests\Menu\LocalTasksTest
*/
class LocalTaskTestWithUnsafeTitle extends DeriverBase {
/**
* @inheritDoc
*/
public function getDerivativeDefinitions($base_plugin_definition) {
$this->derivatives['unsafe'] = [
'title' => "<script>alert('Welcome to the derived jungle!')</script>",
'route_parameters' => ['bar' => 'unsafe'],
] + $base_plugin_definition;
return $this->derivatives;
}
}

View file

@ -0,0 +1,29 @@
<?php
/**
* @file
* Contains \Drupal\menu_test\Plugin\Derivative\MenuLinkTestWithUnsafeTitle.
*/
namespace Drupal\menu_test\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DeriverBase;
/**
* Test derivative with an unsafe string.
*/
class MenuLinkTestWithUnsafeTitle extends DeriverBase {
/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions($base_plugin_definition) {
$this->derivatives['unsafe'] = [
'title' => '<script>alert("Even more wild animals")</script>',
'menu_name' => 'tools',
] + $base_plugin_definition;
return $this->derivatives;
}
}

View file

@ -0,0 +1,24 @@
<?php
/**
* @file
* Contains \Drupal\menu_test\Plugin\Menu\ContextualLink\TestContextualLink.
*/
namespace Drupal\menu_test\Plugin\Menu\ContextualLink;
use Drupal\Core\Menu\ContextualLinkDefault;
/**
* Defines a contextual link plugin with a dynamic title from user input.
*/
class TestContextualLink extends ContextualLinkDefault {
/**
* {@inheritdoc}
*/
public function getTitle() {
return "<script>alert('Welcome to the jungle!')</script>";
}
}

View file

@ -8,12 +8,15 @@
namespace Drupal\menu_test\Plugin\Menu\LocalAction;
use Drupal\Core\Menu\LocalActionDefault;
use Drupal\Core\StringTranslation\StringTranslationTrait;
/**
* Defines a local action plugin with a dynamic title.
*/
class TestLocalAction4 extends LocalActionDefault {
use StringTranslationTrait;
/**
* {@inheritdoc}
*/

View file

@ -0,0 +1,24 @@
<?php
/**
* @file
* Contains \Drupal\menu_test\Plugin\Menu\LocalAction\TestLocalAction5.
*/
namespace Drupal\menu_test\Plugin\Menu\LocalAction;
use Drupal\Core\Menu\LocalActionDefault;
/**
* Defines a local action plugin with a dynamic title from user input.
*/
class TestLocalAction5 extends LocalActionDefault {
/**
* {@inheritdoc}
*/
public function getTitle() {
return "<script>alert('Welcome to the jungle!')</script>";
}
}

View file

@ -0,0 +1,22 @@
<?php
/**
* @file
* Contains \Drupal\menu_test\Plugin\Menu\LocalTask\TestTaskWithUserInput.
*/
namespace Drupal\menu_test\Plugin\Menu\LocalTask;
use Drupal\Core\Menu\LocalTaskDefault;
use Symfony\Component\HttpFoundation\Request;
class TestTaskWithUserInput extends LocalTaskDefault {
/**
* @inheritDoc
*/
public function getTitle(Request $request = NULL) {
return "<script>alert('Welcome to the jungle!')</script>";
}
}

View file

@ -8,9 +8,12 @@
namespace Drupal\menu_test\Plugin\Menu\LocalTask;
use Drupal\Core\Menu\LocalTaskDefault;
use Drupal\Core\StringTranslation\StringTranslationTrait;
class TestTasksSettingsSub1 extends LocalTaskDefault {
use StringTranslationTrait;
/**
* {@inheritdoc}
*/

View file

@ -61,4 +61,20 @@ class TestControllers {
}
}
/**
* Prints out test data with contextual links.
*/
public function testContextual() {
return [
'#markup' => 'testContextual',
'stuff' => [
'#type' => 'contextual_links',
'#contextual_links' => [
'menu_test_menu' => [
'route_parameters' => ['bar' => 1],
]
]
]
];
}
}

View file

@ -0,0 +1,3 @@
# This entity is intentionally missing an 'id' key. During installation, an
# EntityMalformedException should be thrown about the missing key.
name: 'This entity does not have an ID'

View file

@ -0,0 +1,10 @@
module_installer_config_test.type.*:
type: config_entity
label: 'Test entity type'
mapping:
id:
type: string
name:
type: label
label: 'Name'

View file

@ -0,0 +1,7 @@
name: 'Module installer config test'
description: 'Support module for tests that require a failed module install.'
type: module
package: Testing
core: 8.x
version: VERSION

View file

@ -0,0 +1,30 @@
<?php
/**
* @file
* Contains \Drupal\module_installer_config_test\Entity\TestConfigType.
*/
namespace Drupal\module_installer_config_test\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
/**
* Defines a configuration-based entity type used for testing.
*
* @ConfigEntityType(
* id = "test_config_type",
* label = @Translation("Test entity type"),
* handlers = {
* "list_builder" = "Drupal\Core\Entity\EntityListBuilder"
* },
* admin_permission = "administer modules",
* config_prefix = "type",
* entity_keys = {
* "id" = "id",
* "label" = "name"
* }
* )
*/
class TestConfigType extends ConfigEntityBase {
}

View file

@ -69,7 +69,7 @@ class PagerTestController extends ControllerBase {
* #pre_render callback for #type => pager that shows the pager cache context.
*/
public static function showPagerCacheContext(array $pager) {
drupal_set_message(\Drupal::service('cache_contexts_manager')->convertTokensToKeys(['url.query_args.pagers:' . $pager['#element']])[0]);
drupal_set_message(\Drupal::service('cache_contexts_manager')->convertTokensToKeys(['url.query_args.pagers:' . $pager['#element']])->getKeys()[0]);
return $pager;
}

View file

@ -141,6 +141,20 @@ router_test.22:
requirements:
_role: 'anonymous'
router_test.23:
path: '/router_test/test23'
defaults:
_controller: '\Drupal\router_test\TestControllers::test23'
requirements:
_access: 'TRUE'
router_test.24:
path: '/router_test/test24'
defaults:
_controller: '\Drupal\router_test\TestControllers::test24'
requirements:
_access: 'TRUE'
router_test.hierarchy_parent:
path: '/menu-test/parent'
defaults:

View file

@ -12,6 +12,8 @@ use Drupal\Core\ParamConverter\ParamNotConvertedException;
use Drupal\user\UserInterface;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\Response;
use Zend\Diactoros\Response\HtmlResponse;
/**
* Controller routines for testing the routing system.
@ -74,14 +76,7 @@ class TestControllers {
* This can be used to test if the generated backtrace is properly escaped.
*/
public function test10() {
// Remove the exception logger from the event dispatcher. We are going to
// throw an exception to check if it is properly escaped when rendered as a
// backtrace. The exception logger does a call to error_log() which is not
// handled by the Simpletest error handler and would cause a test failure.
$event_dispatcher = \Drupal::service('event_dispatcher');
$exception_logger = \Drupal::service('exception.logger');
$event_dispatcher->removeSubscriber($exception_logger);
$this->removeExceptionLogger();
$this->throwException('<script>alert(\'xss\')</script>');
}
@ -102,6 +97,15 @@ class TestControllers {
return new CacheableResponse('test21');
}
public function test23() {
return new HtmlResponse('test23');
}
public function test24() {
$this->removeExceptionLogger();
throw new \Exception('Escaped content: <p> <br> <h3>');
}
/**
* Throws an exception.
*
@ -115,4 +119,14 @@ class TestControllers {
throw new \Exception($message);
}
protected function removeExceptionLogger() {
// Remove the exception logger from the event dispatcher. We are going to
// throw an exception to check if it is properly escaped when rendered as a
// backtrace. The exception logger does a call to error_log() which is not
// handled by the Simpletest error handler and would cause a test failure.
$event_dispatcher = \Drupal::service('event_dispatcher');
$exception_logger = \Drupal::service('exception.logger');
$event_dispatcher->removeSubscriber($exception_logger);
}
}

View file

@ -26,5 +26,9 @@ class ServiceProviderTestServiceProvider implements ServiceModifierInterface {
if ($indicator = Settings::get('deployment_identifier')) {
$container->setParameter('container_rebuild_indicator', $indicator);
}
if ($parameter = Settings::get('container_rebuild_test_parameter')) {
$container->setParameter('container_rebuild_test_parameter', $parameter);
}
}
}

View file

@ -51,6 +51,9 @@ class TestClass implements EventSubscriberInterface, DestructableInterface, Cont
if ($this->container->hasParameter('container_rebuild_indicator')) {
$event->getResponse()->headers->set('container_rebuild_indicator', $this->container->getParameter('container_rebuild_indicator'));
}
if ($this->container->hasParameter('container_rebuild_test_parameter')) {
$event->getResponse()->headers->set('container_rebuild_test_parameter', $this->container->getParameter('container_rebuild_test_parameter'));
}
}
/**

View file

@ -3,6 +3,8 @@ session_test.get:
defaults:
_title: 'Session value'
_controller: '\Drupal\session_test\Controller\SessionTestController::get'
options:
no_cache: TRUE
requirements:
_access: 'TRUE'
session_test.get_from_session_object:
@ -10,6 +12,8 @@ session_test.get_from_session_object:
defaults:
_title: 'Session value'
_controller: '\Drupal\session_test\Controller\SessionTestController::getFromSessionObject'
options:
no_cache: TRUE
requirements:
_access: 'TRUE'
session_test.id:
@ -17,6 +21,8 @@ session_test.id:
defaults:
_title: 'Session ID'
_controller: '\Drupal\session_test\Controller\SessionTestController::getId'
options:
no_cache: TRUE
requirements:
_access: 'TRUE'
@ -34,6 +40,7 @@ session_test.set:
_title: 'Set session value'
_controller: '\Drupal\session_test\Controller\SessionTestController::set'
options:
no_cache: TRUE
converters:
test_value: '\s+'
requirements:
@ -45,6 +52,7 @@ session_test.no_set:
_title: 'Set session value but do not save session'
_controller: '\Drupal\session_test\Controller\SessionTestController::noSet'
options:
no_cache: TRUE
converters:
test_value: '\s+'
requirements:
@ -96,6 +104,7 @@ session_test.get_session_basic_auth:
_title: 'Get session information using basic authentication'
_controller: '\Drupal\session_test\Controller\SessionTestController::getSession'
options:
no_cache: TRUE
_auth: ['basic_auth']
requirements:
_permission: 'administer site configuration'
@ -105,6 +114,8 @@ session_test.get_session_no_auth:
defaults:
_title: 'Get session information'
_controller: '\Drupal\session_test\Controller\SessionTestController::getSession'
options:
no_cache: TRUE
requirements:
_access: 'TRUE'
@ -114,6 +125,7 @@ session_test.set_session:
_title: 'Set a session value using basic authentication'
_controller: '\Drupal\session_test\Controller\SessionTestController::setSession'
options:
no_cache: TRUE
_auth: ['basic_auth']
converters:
test_value: '\s+'

View file

@ -75,7 +75,7 @@ class SessionTestController extends ControllerBase {
* A notification message with session ID.
*/
public function getIdFromCookie(Request $request) {
return ['#markup' => 'session_id:' . $request->cookies->get(session_name()) . "\n"];
return ['#markup' => 'session_id:' . $request->cookies->get(session_name()) . "\n", '#cache' => ['contexts' => ['cookies:' . session_name()]]];
}
/**

View file

@ -1,3 +0,0 @@
pet llamas:
title: 'Pet llamas'
description: 'Petting of llamas.'

View file

@ -1,6 +1,20 @@
<?php
use Drupal\Core\Extension\Extension;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function system_test_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.system_test':
$output = '';
$output .= '<h3>' . t('Test Help Page') . '</h3>';
$output .= '<p>' . t('This is a test help page for the system_test module for the purpose of testing if the "Help" link displays properly.') . '</p>';
return $output;
}
}
/**
* Implements hook_modules_installed().

View file

@ -0,0 +1,2 @@
system test:
title: 'Administer system test'

View file

@ -7,6 +7,8 @@
namespace Drupal\test_page_test\Controller;
use Drupal\Component\Utility\SafeMarkup;
/**
* Defines a test controller for page titles.
*/
@ -49,6 +51,26 @@ class Test {
return 'Dynamic title';
}
/**
* Defines a controller with a cached render array.
*
* @param bool $mark_safe
* Whether or not to mark the title as safe use SafeMarkup::checkPlain.
*
* @return array
* A render array
*/
public function controllerWithCache($mark_safe = FALSE) {
$build = [];
$build['#title'] = '<span>Cached title</span>';
if ($mark_safe) {
$build['#title'] = SafeMarkup::checkPlain($build['#title']);
}
$build['#cache']['keys'] = ['test_controller', 'with_title', $mark_safe];
return $build;
}
/**
* Returns a generic page render array for title tests.
*

View file

@ -21,6 +21,21 @@ test_page_test.static_title:
requirements:
_access: 'TRUE'
test_page_test.cached_controller:
path: '/test-page-cached-controller'
defaults:
_controller: '\Drupal\test_page_test\Controller\Test::controllerWithCache'
requirements:
_access: 'TRUE'
test_page_test.cached_controller.safe:
path: '/test-page-cached-controller-safe'
defaults:
_controller: '\Drupal\test_page_test\Controller\Test::controllerWithCache'
mark_safe: true
requirements:
_access: 'TRUE'
test_page_test.dynamic_title:
path: '/test-page-dynamic-title'
defaults:

View file

@ -0,0 +1,86 @@
<?php
/**
* @file
* Contains \Drupal\token_test\Controller\TestController.
*/
namespace Drupal\token_test\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Utility\Token;
use Drupal\node\NodeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a test controller for token replacement.
*/
class TestController extends ControllerBase {
/**
* The token replacement system.
*
* @var \Drupal\Core\Utility\Token
*/
protected $token;
/**
* Constructs a new TestController instance.
*
* @param \Drupal\Core\Utility\Token $token
* The token replacement system.
*/
public function __construct(Token $token) {
$this->token = $token;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container->get('token'));
}
/**
* Provides a token replacement with a node as well as the current user.
*
* This controller passes an explicit bubbleable metadata object to
* $this->token->replace(), and applies the collected metadata to the render
* array being built.
*
* @param \Drupal\node\NodeInterface $node
* The node.
*
* @return array
* The render array.
*/
public function tokenReplace(NodeInterface $node) {
$bubbleable_metadata = new BubbleableMetadata();
$build['#markup'] = $this->token->replace('Tokens: [node:nid] [current-user:uid]', ['node' => $node], [], $bubbleable_metadata);
$bubbleable_metadata->applyTo($build);
return $build;
}
/**
* Provides a token replacement with a node as well as the current user.
*
* This controller is for testing the token service's fallback behavior of
* applying collected metadata to the currently active render context when an
* explicit bubbleable metadata object isn't passed in.
*
* @param \Drupal\node\NodeInterface $node
* The node.
*
* @return array
* The render array.
*/
public function tokenReplaceWithoutPassedBubbleableMetadata(NodeInterface $node) {
$build['#markup'] = $this->token->replace('Tokens: [node:nid] [current-user:uid]', ['node' => $node], []);
return $build;
}
}

View file

@ -0,0 +1,8 @@
name: Token test
type: module
core: 8.x
package: Testing
version: VERSION
dependencies:
- user
- node

View file

@ -0,0 +1,12 @@
token_test.test:
path: token-test/{node}
defaults:
_controller: Drupal\token_test\Controller\TestController::tokenReplace
requirements:
_access: 'TRUE'
token_test.test_without_bubbleable_metadata:
path: token-test-without-bubleable-metadata/{node}
defaults:
_controller: Drupal\token_test\Controller\TestController::tokenReplaceWithoutPassedBubbleableMetadata
requirements:
_access: 'TRUE'

View file

@ -7,6 +7,7 @@
namespace Drupal\twig_theme_test;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Url;
/**
@ -53,11 +54,14 @@ class TwigThemeTestController {
* Renders for testing link_generator functions in a Twig template.
*/
public function linkGeneratorRender() {
return array(
return [
'#theme' => 'twig_theme_test_link_generator',
'#test_url' => new Url('user.register', [], ['absolute' => TRUE]),
'#test_url_attribute' => new Url('user.register', [], ['attributes' => ['foo' => 'bar']]),
);
// Explicitly creating an Attribute object to avoid false positives when
// testing Attribute object merging with the twig link() function.
'#attributes' => new Attribute(['class' => ['llama', 'kitten', 'panda']]),
];
}
/**

View file

@ -2,3 +2,4 @@
<div>link via the linkgenerator: {{ link('register', test_url, {'foo': 'bar'}) }}</div>
<div>link via the linkgenerator: {{ link('register', test_url_attribute, {'id': 'kitten'}) }}</div>
<div>link via the linkgenerator: {{ link('register', 'route:user.register', {'id': 'kitten'}) }}</div>
<div>link via the linkgenerator: {{ link('register', 'route:user.register', attributes) }}</div>

View file

@ -43,7 +43,11 @@ function twig_theme_test_theme($existing, $type, $theme, $path) {
'template' => 'twig_theme_test.url_generator',
);
$items['twig_theme_test_link_generator'] = array(
'variables' => array('test_url' => NULL, 'test_url_attribute' => NULL),
'variables' => [
'test_url' => NULL,
'test_url_attribute' => NULL,
'attributes' => [],
],
'template' => 'twig_theme_test.link_generator',
);
$items['twig_theme_test_url_to_string'] = array(

View file

@ -0,0 +1,6 @@
name: 'Update order test'
type: module
description: 'Support module for update testing.'
package: Testing
version: VERSION
core: 8.x

View file

@ -0,0 +1,53 @@
<?php
/**
* @file
* Update hooks for the update_order_test module.
*/
use Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface;
/**
* Only declare the update hooks once the test is running.
*
* @see \Drupal\system\Tests\Entity\Update\SqlContentEntityStorageSchemaIndexTest
*/
if (\Drupal::state()->get('update_order_test', FALSE)) {
/**
* Runs before entity schema updates.
*/
function update_order_test_update_8001() {
// Store whether the node__default_langcode index exists when this hook is
// invoked.
\Drupal::state()->set('update_order_test_update_8001', db_index_exists('node_field_data', 'node__default_langcode'));
}
/**
* Runs before entity schema updates.
*/
function update_order_test_update_8002() {
// Check and store whether the update_order_test field exists when this
// hook is first invoked.
\Drupal::state()->set('update_order_test_update_8002_update_order_test_before', db_field_exists('node_field_data', 'update_order_test'));
// Attempt to apply the update for the update_order_test field and then
// check and store again whether it exists.
if (\Drupal::service('entity.definition_update_manager')->applyFieldUpdate(EntityDefinitionUpdateManagerInterface::DEFINITION_CREATED, 'node', 'update_order_test')) {
\Drupal::state()->set('update_order_test_update_8002_update_order_test_after', db_field_exists('node_field_data', 'update_order_test'));
}
// Attempt to apply all node entity type updates.
if (\Drupal::service('entity.definition_update_manager')->applyEntityUpdate(EntityDefinitionUpdateManagerInterface::DEFINITION_UPDATED, 'node')) {
// Node updates have now run. Check and store whether the updated node
// indices now exist.
\Drupal::state()->set('update_order_test_update_8002_node__default_langcode', db_index_exists('node_field_data', 'node__default_langcode'));
\Drupal::state()->set('update_order_test_update_8002_node__id__default_langcode__langcode', db_index_exists('node_field_data', 'node__id__default_langcode__langcode'));
// User updates have not yet run. Check and store whether the updated
// user indices now exist.
\Drupal::state()->set('update_order_test_update_8002_user__id__default_langcode__langcode', db_index_exists('users_field_data', 'user__id__default_langcode__langcode'));
}
}
}

View file

@ -0,0 +1,27 @@
<?php
/**
* @file
* Hooks for the update_order_test module.
*/
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
/**
* Only declare the new entity base field once the test is running.
*/
if (\Drupal::state()->get('update_order_test', FALSE)) {
/**
* Implements hook_entity_base_field_info().
*/
function update_order_test_entity_base_field_info(EntityTypeInterface $entity_type) {
if ($entity_type->id() === 'node') {
$fields['update_order_test'] = BaseFieldDefinition::create('integer')
->setLabel(t('Update order test'));
return $fields;
}
}
}

View file

@ -7,9 +7,9 @@
namespace Drupal\url_alter_test;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Symfony\Component\HttpFoundation\Request;
use Drupal\user\Entity\User;
@ -44,14 +44,14 @@ class PathProcessorTest implements InboundPathProcessorInterface, OutboundPathPr
/**
* Implements Drupal\Core\PathProcessor\OutboundPathProcessorInterface::processOutbound().
*/
public function processOutbound($path, &$options = array(), Request $request = NULL, CacheableMetadata $cacheable_metadata = NULL) {
public function processOutbound($path, &$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
// Rewrite user/uid to user/username.
if (preg_match('!^/user/([0-9]+)(/.*)?!', $path, $matches)) {
if ($account = User::load($matches[1])) {
$matches += array(2 => '');
$path = '/user/' . $account->getUsername() . $matches[2];
if ($cacheable_metadata) {
$cacheable_metadata->addCacheTags($account->getCacheTags());
if ($bubbleable_metadata) {
$bubbleable_metadata->addCacheTags($account->getCacheTags());
}
}
}

View file

@ -0,0 +1,62 @@
<?php
/**
* @file
* Contains \Drupal\Tests\system\Unit\Migrate\source\d6\MenuTest.
*/
namespace Drupal\Tests\system\Unit\Migrate\source\d6;
use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
/**
* Tests D6 menu source plugin.
*
* @group system
*/
class MenuTest 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\system\Plugin\migrate\source\d6\Menu';
// The fake Migration configuration entity.
protected $migrationConfiguration = array(
// The ID of the entity, can be any string.
'id' => 'test',
// Leave it empty for now.
'idlist' => array(),
// This needs to be the identifier of the actual key: cid for comment, nid
// for node and so on.
'source' => array(
'plugin' => 'd6_menu',
),
);
// We need to set up the database contents; it's easier to do that below.
protected $expectedResults = array(
array(
'menu_name' => 'menu-name-1',
'title' => 'menu custom value 1',
'description' => 'menu custom description value 1',
),
array(
'menu_name' => 'menu-name-2',
'title' => 'menu custom value 2',
'description' => 'menu custom description value 2',
),
);
/**
* {@inheritdoc}
*/
protected function setUp() {
// This array stores the database.
foreach ($this->expectedResults as $k => $row) {
$this->databaseContents['menu_custom'][$k] = $row;
}
parent::setUp();
}
}

View file

@ -50,6 +50,13 @@ class MachineNameControllerTest extends UnitTestCase {
array(array('text' => 'Bob', 'langcode' => 'en', 'replace' => 'Alice', 'replace_pattern' => 'Tom'), '"Bob"'),
array(array('text' => 'Äwesome', 'langcode' => 'en', 'lowercase' => TRUE), '"awesome"'),
array(array('text' => 'Äwesome', 'langcode' => 'de', 'lowercase' => TRUE), '"aewesome"'),
// Tests special characters replacement in the input text.
array(array('text' => 'B?!"@\/-ob@e', 'langcode' => 'en', 'lowercase' => TRUE, 'replace' => '_', 'replace_pattern' => '[^a-z0-9_.]+'), '"b_ob_e"'),
// Tests @ character in the replace_pattern regex.
array(array('text' => 'Bob@e\0', 'langcode' => 'en', 'lowercase' => TRUE, 'replace' => '_', 'replace_pattern' => '[^a-z0-9_.@]+'), '"bob@e_0"'),
// Tests null byte in the replace_pattern regex.
array(array('text' => 'Bob', 'langcode' => 'en', 'lowercase' => TRUE, 'replace' => 'fail()', 'replace_pattern' => ".*@e\0"), '"bob"'),
array(array('text' => 'Bob@e', 'langcode' => 'en', 'lowercase' => TRUE, 'replace' => 'fail()', 'replace_pattern' => ".*@e\0"), '"fail()"'),
);
}

View file

@ -0,0 +1,5 @@
name: 'Theme test with invalid core version'
type: theme
description: 'Test theme which has an invalid core version.'
version: VERSION
core: 7.x

View file

@ -0,0 +1,8 @@
name: 'Theme test with missing content region'
type: theme
description: 'Test theme which has a non-existent content region.'
version: VERSION
core: 8.x
regions:
- foo: Foo