Update to Drupal 8.1.5. For more information, see https://www.drupal.org/project/drupal/releases/8.1.5

This commit is contained in:
Pantheon Automation 2016-07-07 09:44:38 -07:00 committed by Greg Anderson
parent 13b6ca7cc2
commit 38ba7c357d
342 changed files with 7814 additions and 1534 deletions

View file

@ -1,8 +1,8 @@
<?php
namespace Drupal\action\Tests;
namespace Drupal\Tests\action\Functional;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
/**
* Tests that uninstalling actions does not remove other module's actions.
@ -10,7 +10,7 @@ use Drupal\simpletest\WebTestBase;
* @group action
* @see \Drupal\action\Plugin\views\field\BulkForm
*/
class ActionUninstallTest extends WebTestBase {
class ActionUninstallTest extends BrowserTestBase {
/**
* Modules to install.

View file

@ -1,8 +1,8 @@
<?php
namespace Drupal\action\Tests;
namespace Drupal\Tests\action\Functional;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
use Drupal\views\Views;
/**
@ -11,7 +11,7 @@ use Drupal\views\Views;
* @group action
* @see \Drupal\action\Plugin\views\field\BulkForm
*/
class BulkFormTest extends WebTestBase {
class BulkFormTest extends BrowserTestBase {
/**
* Modules to install.
@ -123,7 +123,7 @@ class BulkFormTest extends WebTestBase {
// Check the default title.
$this->drupalGet('test_bulk_form');
$result = $this->xpath('//label[@for="edit-action"]');
$this->assertEqual('With selection', (string) $result[0]);
$this->assertEqual('With selection', $result[0]->getText());
// Setup up a different bulk form title.
$view = Views::getView('test_bulk_form');
@ -133,7 +133,7 @@ class BulkFormTest extends WebTestBase {
$this->drupalGet('test_bulk_form');
$result = $this->xpath('//label[@for="edit-action"]');
$this->assertEqual('Test title', (string) $result[0]);
$this->assertEqual('Test title', $result[0]->getText());
$this->drupalGet('test_bulk_form');
// Call the node delete action.

View file

@ -1,9 +1,9 @@
<?php
namespace Drupal\action\Tests;
namespace Drupal\Tests\action\Functional;
use Drupal\Component\Utility\Crypt;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
/**
* Tests complex actions configuration by adding, editing, and deleting a
@ -11,7 +11,7 @@ use Drupal\simpletest\WebTestBase;
*
* @group action
*/
class ConfigurationTest extends WebTestBase {
class ConfigurationTest extends BrowserTestBase {
/**
* Modules to install.

View file

@ -20,7 +20,7 @@ class AggregatorItem extends DrupalSqlBase {
public function query() {
return $this->select('aggregator_item', 'ai')
->fields('ai')
->orderBy('iid');
->orderBy('ai.iid');
}
/**

View file

@ -1,15 +1,15 @@
<?php
namespace Drupal\ban\Tests;
namespace Drupal\Tests\ban\Functional;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
/**
* Tests IP address banning.
*
* @group ban
*/
class IpAddressBlockingTest extends WebTestBase {
class IpAddressBlockingTest extends BrowserTestBase {
/**
* Modules to install.
@ -61,7 +61,7 @@ class IpAddressBlockingTest extends WebTestBase {
// Pass an IP address as a URL parameter and submit it.
$submit_ip = '1.2.3.4';
$this->drupalPostForm('admin/config/people/ban/' . $submit_ip, NULL, t('Add'));
$this->drupalPostForm('admin/config/people/ban/' . $submit_ip, array(), t('Add'));
$ip = db_query("SELECT iid from {ban_ip} WHERE ip = :ip", array(':ip' => $submit_ip))->fetchField();
$this->assertTrue($ip, 'IP address found in database');
$this->assertRaw(t('The IP address %ip has been banned.', array('%ip' => $submit_ip)), 'IP address was banned.');

View file

@ -226,6 +226,13 @@ class BigPipe implements BigPipeInterface {
$preg_placeholder_strings = array_map($prepare_for_preg_split, array_keys($no_js_placeholders));
$fragments = preg_split('/' . implode('|', $preg_placeholder_strings) . '/', $html, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
// Determine how many occurrences there are of each no-JS placeholder.
$placeholder_occurrences = array_count_values(array_intersect($fragments, array_keys($no_js_placeholders)));
// Set up a variable to store the content of placeholders that have multiple
// occurrences.
$multi_occurrence_placeholders_content = [];
foreach ($fragments as $fragment) {
// If the fragment isn't one of the no-JS placeholders, it is the HTML in
// between placeholders and it must be printed & flushed immediately. The
@ -236,6 +243,15 @@ class BigPipe implements BigPipeInterface {
continue;
}
// If there are multiple occurrences of this particular placeholder, and
// this is the second occurrence, we can skip all calculations and just
// send the same content.
if ($placeholder_occurrences[$fragment] > 1 && isset($multi_occurrence_placeholders_content[$fragment])) {
print $multi_occurrence_placeholders_content[$fragment];
flush();
continue;
}
$placeholder = $fragment;
assert('isset($no_js_placeholders[$placeholder])');
$token = Crypt::randomBytesBase64(55);
@ -310,6 +326,13 @@ class BigPipe implements BigPipeInterface {
// they can be sent in ::sendPreBody().
$cumulative_assets->setAlreadyLoadedLibraries(array_merge($cumulative_assets->getAlreadyLoadedLibraries(), $html_response->getAttachments()['library']));
$cumulative_assets->setSettings($html_response->getAttachments()['drupalSettings']);
// If there are multiple occurrences of this particular placeholder, track
// the content that was sent, so we can skip all calculations for the next
// occurrence.
if ($placeholder_occurrences[$fragment] > 1) {
$multi_occurrence_placeholders_content[$fragment] = $html_response->getContent();
}
}
}
@ -508,7 +531,9 @@ EOF;
*
* @return array
* Indexed array; the order in which the BigPipe placeholders must be sent.
* Values are the BigPipe placeholder IDs.
* Values are the BigPipe placeholder IDs. Note that only unique
* placeholders are kept: if the same placeholder occurs multiple times, we
* only keep the first occurrence.
*/
protected function getPlaceholderOrder($html) {
$fragments = explode('<div data-big-pipe-placeholder-id="', $html);
@ -521,7 +546,7 @@ EOF;
$order[] = $placeholder;
}
return $order;
return array_unique($order);
}
}

View file

@ -269,6 +269,42 @@ class BigPipeTest extends WebTestBase {
unlink(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
}
/**
* Tests BigPipe with a multi-occurrence placeholder.
*/
public function testBigPipeMultiOccurrencePlaceholders() {
$this->drupalLogin($this->rootUser);
$this->assertSessionCookieExists(TRUE);
$this->assertBigPipeNoJsCookieExists(FALSE);
// By not calling performMetaRefresh() here, we simulate JavaScript being
// enabled, because as far as the BigPipe module is concerned, JavaScript is
// enabled in the browser as long as the BigPipe no-JS cookie is *not* set.
// @see setUp()
// @see performMetaRefresh()
$this->drupalGet(Url::fromRoute('big_pipe_test_multi_occurrence'));
$big_pipe_placeholder_id = 'callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&amp;args[0]&amp;token=a8c34b5e';
$expected_placeholder_replacement = '<script type="application/vnd.drupal-ajax" data-big-pipe-replacement-for-placeholder-with-id="' . $big_pipe_placeholder_id . '">';
$this->assertRaw('The count is 1.');
$this->assertNoRaw('The count is 2.');
$this->assertNoRaw('The count is 3.');
$raw_content = $this->getRawContent();
$this->assertTrue(substr_count($raw_content, $expected_placeholder_replacement) == 1, 'Only one placeholder replacement was found for the duplicate #lazy_builder arrays.');
// By calling performMetaRefresh() here, we simulate JavaScript being
// disabled, because as far as the BigPipe module is concerned, it is
// enabled in the browser when the BigPipe no-JS cookie is set.
// @see setUp()
// @see performMetaRefresh()
$this->performMetaRefresh();
$this->assertBigPipeNoJsCookieExists(TRUE);
$this->drupalGet(Url::fromRoute('big_pipe_test_multi_occurrence'));
$this->assertRaw('The count is 1.');
$this->assertNoRaw('The count is 2.');
$this->assertNoRaw('The count is 3.');
}
protected function assertBigPipeResponseHeadersPresent() {
$this->pass('Verifying BigPipe response headers…', 'Debug');
$this->assertTrue(FALSE !== strpos($this->drupalGetHeader('Cache-Control'), 'private'), 'Cache-Control header set to "private".');

View file

@ -15,3 +15,12 @@ no_big_pipe:
_no_big_pipe: TRUE
requirements:
_access: 'TRUE'
big_pipe_test_multi_occurrence:
path: '/big_pipe_test_multi_occurrence'
defaults:
_controller: '\Drupal\big_pipe_test\BigPipeTestController::multiOccurrence'
_title: 'BigPipe test multiple occurrences of the same placeholder'
requirements:
_access: 'TRUE'

View file

@ -52,6 +52,30 @@ class BigPipeTestController {
return ['#markup' => '<p>Nope.</p>'];
}
/**
* A page with multiple occurrences of the same placeholder.
*
* @see \Drupal\big_pipe\Tests\BigPipeTest::testBigPipeMultipleOccurrencePlaceholders()
*
* @return array
*/
public function multiOccurrence() {
return [
'item1' => [
'#lazy_builder' => [static::class . '::counter', []],
'#create_placeholder' => TRUE,
],
'item2' => [
'#lazy_builder' => [static::class . '::counter', []],
'#create_placeholder' => TRUE,
],
'item3' => [
'#lazy_builder' => [static::class . '::counter', []],
'#create_placeholder' => TRUE,
],
];
}
/**
* #lazy_builder callback; builds <time> markup with current time.
*
@ -98,4 +122,31 @@ class BigPipeTestController {
return ['#plain_text' => BigPipeTestSubscriber::CONTENT_TRIGGER_EXCEPTION];
}
/**
* #lazy_builder callback; returns the current count.
*
* @see \Drupal\big_pipe\Tests\BigPipeTest::testBigPipeMultipleOccurrencePlaceholders()
*
* @return array
* The render array.
*/
public static function counter() {
// Lazy builders are not allowed to build their own state like this function
// does, but in this case we're intentionally doing that for testing
// purposes: so we can ensure that each lazy builder is only ever called
// once with the same parameters.
static $count;
if (!isset($count)) {
$count = 0;
}
$count++;
return [
'#markup' => BigPipeMarkup::create("<p>The count is $count.</p>"),
'#cache' => ['max-age' => 0],
];
}
}

View file

@ -0,0 +1,117 @@
<?php
namespace Drupal\Tests\big_pipe\FunctionalJavascript;
use Drupal\comment\CommentInterface;
use Drupal\comment\Entity\Comment;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\editor\Entity\Editor;
use Drupal\filter\Entity\FilterFormat;
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
use Drupal\simpletest\ContentTypeCreationTrait;
use Drupal\simpletest\NodeCreationTrait;
/**
* BigPipe regression tests.
*
* @group big_pipe
*/
class BigPipeRegressionTest extends JavascriptTestBase {
use CommentTestTrait;
use ContentTypeCreationTrait;
use NodeCreationTrait;
/**
* {@inheritdoc}
*/
public static $modules = [
'node',
'comment',
'big_pipe',
'history',
'editor',
'ckeditor',
'filter',
];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
// Use the big_pipe_test_theme theme.
$this->container->get('theme_installer')->install(['big_pipe_test_theme']);
$this->container->get('config.factory')->getEditable('system.theme')->set('default', 'big_pipe_test_theme')->save();
}
/**
* Ensure comment form works with history and big_pipe modules.
*
* @see https://www.drupal.org/node/2698811
*/
public function testCommentForm_2698811() {
// Ensure an `article` node type exists.
$this->createContentType(['type' => 'article']);
$this->addDefaultCommentField('node', 'article');
// Enable CKEditor.
$format = $this->randomMachineName();
FilterFormat::create([
'format' => $format,
'name' => $this->randomString(),
'weight' => 1,
'filters' => [],
])->save();
$settings['toolbar']['rows'] = [
[
[
'name' => 'Links',
'items' => [
'DrupalLink',
'DrupalUnlink',
],
],
],
];
$editor = Editor::create([
'format' => $format,
'editor' => 'ckeditor',
]);
$editor->setSettings($settings);
$editor->save();
$admin_user = $this->drupalCreateUser([
'access comments',
'post comments',
'use text format ' . $format,
]);
$this->drupalLogin($admin_user);
$node = $this->createNode([
'type' => 'article',
'comment' => CommentItemInterface::OPEN,
]);
// Create some comments.
foreach (range(1, 5) as $i) {
$comment = Comment::create([
'status' => CommentInterface::PUBLISHED,
'field_name' => 'comment',
'entity_type' => 'node',
'entity_id' => $node->id(),
]);
$comment->save();
}
$this->drupalGet($node->toUrl()->toString());
// Confirm that CKEditor loaded.
$javascript = <<<JS
(function(){
return Object.keys(CKEDITOR.instances).length > 0;
}());
JS;
$this->assertJsCondition($javascript);
}
}

View file

@ -0,0 +1,5 @@
name: 'BigPipe test theme'
type: theme
description: 'Theme for testing BigPipe edge cases.'
version: VERSION
core: 8.x

View file

@ -0,0 +1,13 @@
{#
/**
* @file
* Test that comments still work with the form above instead of below.
*
* @see \Drupal\Tests\big_pipe\FunctionalJavascript\BigPipeRegressionTest::testCommentForm_2698811()
*/
#}
<section{{ attributes }}>
{{ comment_form }}
{{ comments }}
</section>

View file

@ -19,6 +19,9 @@ process:
- module
- delta
delimiter: _
-
plugin: machine_name
field: id
plugin:
-
plugin: static_map

View file

@ -291,7 +291,6 @@ class Block extends ConfigEntityBase implements BlockInterface, EntityWithPlugin
* The condition plugin manager.
*/
protected function conditionPluginManager() {
$this->conditionPluginManager;
if (!isset($this->conditionPluginManager)) {
$this->conditionPluginManager = \Drupal::service('plugin.manager.condition');
}

View file

@ -43,6 +43,13 @@ class Block extends DrupalSqlBase {
*/
protected $blockRoleTable;
/**
* Table listing user roles.
*
* @var string
*/
protected $userRoleTable;
/**
* {@inheritdoc}
*/
@ -55,6 +62,9 @@ class Block extends DrupalSqlBase {
$this->blockTable = 'blocks';
$this->blockRoleTable = 'blocks_roles';
}
// Drupal 6 & 7 both use the same name for the user roles table.
$this->userRoleTable = 'role';
return $this->select($this->blockTable, 'b')->fields('b');
}
@ -106,11 +116,12 @@ class Block extends DrupalSqlBase {
$module = $row->getSourceProperty('module');
$delta = $row->getSourceProperty('delta');
$roles = $this->select($this->blockRoleTable, 'br')
$query = $this->select($this->blockRoleTable, 'br')
->fields('br', array('rid'))
->condition('module', $module)
->condition('delta', $delta)
->execute()
->condition('delta', $delta);
$query->join($this->userRoleTable, 'ur', 'br.rid = ur.rid');
$roles = $query->execute()
->fetchCol();
$row->setSourceProperty('roles', $roles);

View file

@ -108,7 +108,7 @@ class MigrateBlockTest extends MigrateDrupal7TestBase {
$this->assertEntity('bartik_system_main', 'system_main_block', [], '', 'content', 'bartik', 0, '', '0');
$this->assertEntity('bartik_search_form', 'search_form_block', [], '', 'sidebar_first', 'bartik', -1, '', '0');
$this->assertEntity('bartik_user_login', 'user_login_block', [], '', 'sidebar_first', 'bartik', 0, '', '0');
$this->assertEntity('bartik_system_powered-by', 'system_powered_by_block', [], '', 'footer', 'bartik', 10, '', '0');
$this->assertEntity('bartik_system_powered_by', 'system_powered_by_block', [], '', 'footer', 'bartik', 10, '', '0');
$this->assertEntity('seven_system_main', 'system_main_block', [], '', 'content', 'seven', 0, '', '0');
$this->assertEntity('seven_user_login', 'user_login_block', [], '', 'content', 'seven', 10, '', '0');

View file

@ -25,6 +25,39 @@ class BlockTest extends MigrateSqlSourceTestCase {
* Sample block instance query results from the source.
*/
protected $expectedResults = array(
array(
'bid' => 1,
'module' => 'block',
'delta' => '1',
'theme' => 'garland',
'status' => 1,
'weight' => 0,
'region' => 'left',
'visibility' => 0,
'pages' => '',
'title' => 'Test Title 01',
'cache' => -1,
'roles' => [2]
),
array(
'bid' => 2,
'module' => 'block',
'delta' => '2',
'theme' => 'garland',
'status' => 1,
'weight' => 5,
'region' => 'right',
'visibility' => 0,
'pages' => '<front>',
'title' => 'Test Title 02',
'cache' => -1,
'roles' => [2]
),
);
/**
* Sample block table.
*/
protected $expectedBlocks = array(
array(
'bid' => 1,
'module' => 'block',
@ -62,14 +95,35 @@ class BlockTest extends MigrateSqlSourceTestCase {
'delta' => 1,
'rid' => 2,
),
array(
'module' => 'block',
'delta' => 2,
'rid' => 2,
),
array(
'module' => 'block',
'delta' => 2,
'rid' => 100,
),
);
/**
* Sample role table.
*/
protected $expectedRole = array(
array(
'rid' => 2,
'name' => 'authenticated user',
),
);
/**
* Prepopulate database contents.
*/
protected function setUp() {
$this->databaseContents['blocks'] = $this->expectedResults;
$this->databaseContents['blocks'] = $this->expectedBlocks;
$this->databaseContents['blocks_roles'] = $this->expectedBlocksRoles;
$this->databaseContents['role'] = $this->expectedRole;
$this->databaseContents['system'] = array(
array(
'filename' => 'modules/system/system.module',

View file

@ -392,7 +392,7 @@ display:
plugin_id: string
type:
id: type
table: block_content
table: block_content_field_data
field: type
relationship: none
group_type: group

View file

@ -4,11 +4,8 @@ migration_tags:
- Drupal 6
source:
plugin: d6_box
constants:
type: basic
process:
id: bid
type: 'constants/type'
info: info
'body/format':
plugin: migration
@ -17,6 +14,7 @@ process:
'body/value': body
destination:
plugin: entity:block_content
default_bundle: basic
no_stub: true
migration_dependencies:
required:

View file

@ -4,11 +4,8 @@ migration_tags:
- Drupal 7
source:
plugin: d7_block_custom
constants:
type: basic
process:
id: bid
type: 'constants/type'
info: info
'body/format':
plugin: migration
@ -17,6 +14,7 @@ process:
'body/value': body
destination:
plugin: entity:block_content
default_bundle: basic
no_stub: true
migration_dependencies:
required:

View file

@ -19,7 +19,7 @@ class Box extends DrupalSqlBase {
public function query() {
$query = $this->select('boxes', 'b')
->fields('b', array('bid', 'body', 'info', 'format'));
$query->orderBy('bid');
$query->orderBy('b.bid');
return $query;
}

View file

@ -28,6 +28,10 @@ class BlockContentListViewsTest extends BlockContentTestBase {
// Test for the page title.
$this->assertTitle(t('Custom block library') . ' | Drupal');
// Test for the exposed filters.
$this->assertFieldByName('info');
$this->assertFieldByName('type');
// Test for the table.
$element = $this->xpath('//div[@class="layout-content"]//table');
$this->assertTrue($element, 'Views table found.');

View file

@ -18,6 +18,8 @@ interface BookManagerInterface {
* Since this can be the full tree including hidden items, the data returned
* may be used for generating an an admin interface or a select.
*
* Note: based on menu_tree_all_data().
*
* @param int $bid
* The Book ID to find links for.
* @param array|null $link
@ -31,8 +33,6 @@ interface BookManagerInterface {
*
* @return array
* An tree of menu links in an array, in the order they should be rendered.
*
* Note: based on menu_tree_all_data().
*/
public function bookTreeAllData($bid, $link = NULL, $max_depth = NULL);

View file

@ -23,7 +23,7 @@ class Book extends DrupalSqlBase {
for ($i = 1; $i <= 9; $i++) {
$field = "p$i";
$ml_fields[] = $field;
$query->orderBy($field);
$query->orderBy('ml.' . $field);
}
$query->fields('ml', $ml_fields);
return $query;

View file

@ -30,7 +30,7 @@ class CommentType extends DrupalSqlBase {
return $this->select('field_config_instance', 'fci')
->distinct()
->fields('fci', array('bundle'))
->condition('entity_type', 'comment');
->condition('fci.entity_type', 'comment');
}
/**

View file

@ -0,0 +1,14 @@
id: d6_i18n_system_maintenance
label: Maintenance page configuration
migration_tags:
- Drupal 6
source:
plugin: i18n_variable
variables:
- site_offline_message
process:
langcode: language
message: site_offline_message
destination:
plugin: config
config_name: system.maintenance

View file

@ -0,0 +1,38 @@
id: d6_i18n_system_site
label: Site configuration
migration_tags:
- Drupal 6
source:
plugin: i18n_variable
constants:
slash: '/'
variables:
- site_name
- site_mail
- site_slogan
- site_frontpage
- site_403
- site_404
process:
langcode: language
name: site_name
mail: site_mail
slogan: site_slogan
'page/front':
plugin: concat
source:
- constants/slash
- site_frontpage
'page/403':
plugin: concat
source:
- constants/slash
- site_403
'page/404':
plugin: concat
source:
- constants/slash
- site_404
destination:
plugin: config
config_name: system.site

View file

@ -0,0 +1,68 @@
id: d6_i18n_user_mail
label: User mail configuration
migration_tags:
- Drupal 6
source:
plugin: i18n_variable
variables:
- user_mail_status_activated_subject
- user_mail_status_activated_body
- user_mail_password_reset_subject
- user_mail_password_reset_body
- user_mail_status_deleted_subject
- user_mail_status_deleted_body
- user_mail_register_admin_created_subject
- user_mail_register_admin_created_body
- user_mail_register_no_approval_required_subject
- user_mail_register_no_approval_required_body
- user_mail_register_pending_approval_subject
- user_mail_register_pending_approval_body
- user_mail_status_blocked_subject
- user_mail_status_blocked_body
process:
langcode: language
'status_activated/subject':
plugin: convert_tokens
source: user_mail_status_activated_subject
'status_activated/body':
plugin: convert_tokens
source: user_mail_status_activated_body
'password_reset/subject':
plugin: convert_tokens
source: user_mail_password_reset_subject
'password_reset/body':
plugin: convert_tokens
source: user_mail_password_reset_body
'cancel_confirm/subject':
plugin: convert_tokens
source: user_mail_status_deleted_subject
'cancel_confirm/body':
plugin: convert_tokens
source: user_mail_status_deleted_body
'register_admin_created/subject':
plugin: convert_tokens
source: user_mail_register_admin_created_subject
'register_admin_created/body':
plugin: convert_tokens
source: user_mail_register_admin_created_body
'register_no_approval_required/subject':
plugin: convert_tokens
source: user_mail_register_no_approval_required_subject
'register_no_approval_required/body':
plugin: convert_tokens
source: user_mail_register_no_approval_required_body
'register_pending_approval/subject':
plugin: convert_tokens
source: user_mail_register_pending_approval_subject
'register_pending_approval/body':
plugin: convert_tokens
source: user_mail_register_pending_approval_body
'status_blocked/subject':
plugin: convert_tokens
source: user_mail_status_blocked_subject
'status_blocked/body':
plugin: convert_tokens
source: user_mail_status_blocked_body
destination:
plugin: config
config_name: user.mail

View file

@ -0,0 +1,29 @@
id: d6_i18n_user_settings
label: User configuration
migration_tags:
- Drupal 6
source:
plugin: i18n_variable
variables:
- user_mail_status_blocked_notify
- user_mail_status_activated_notify
- user_email_verification
- user_register
- anonymous
process:
langcode: language
'notify/status_blocked': user_mail_status_blocked_notify
'notify/status_activated': user_mail_status_activated_notify
verify_mail: user_email_verification
register:
plugin: static_map
source: user_register
default_value: visitors_admin_approval
map:
2: visitors_admin_approval
1: visitors
0: admin_only
anonymous: anonymous
destination:
plugin: config
config_name: user.settings

View file

@ -0,0 +1,32 @@
<?php
namespace Drupal\Tests\config_translation\Kernel\Migrate\d6;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade i18n maintenance variables to system.*.yml.
*
* @group migrate_drupal_6
*/
class MigrateI18nSystemMaintenanceTest extends MigrateDrupal6TestBase {
public static $modules = ['language', 'config_translation'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('d6_i18n_system_maintenance');
}
/**
* Tests migration of system (maintenance) variables to system.maintenance.yml.
*/
public function testSystemMaintenance() {
$config = \Drupal::service('language_manager')->getLanguageConfigOverride('fr', 'system.maintenance');
$this->assertIdentical('fr - Drupal is currently under maintenance. We should be back shortly. Thank you for your patience.', $config->get('message'));
}
}

View file

@ -0,0 +1,47 @@
<?php
namespace Drupal\Tests\config_translation\Kernel\Migrate\d6;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade i18n_strings site variables to system.*.yml.
*
* @group migrate_drupal_6
*/
class MigrateI18nSystemSiteTest extends MigrateDrupal6TestBase {
public static $modules = ['language', 'config_translation'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('d6_i18n_system_site');
}
/**
* Tests migration of system (site) variables to system.site.yml.
*/
public function testSystemSite() {
$config_translation = \Drupal::service('language_manager')->getLanguageConfigOverride('fr', 'system.site');
$this->assertIdentical('fr site name', $config_translation->get('name'));
$this->assertIdentical('fr_site_mail@example.com', $config_translation->get('mail'));
$this->assertIdentical('fr Migrate rocks', $config_translation->get('slogan'));
$this->assertIdentical('/fr-user', $config_translation->get('page.403'));
$this->assertIdentical('/fr-page-not-found', $config_translation->get('page.404'));
$this->assertIdentical('/node', $config_translation->get('page.front'));
$this->assertIdentical(NULL, $config_translation->get('admin_compact_mode'));
$config_translation = \Drupal::service('language_manager')->getLanguageConfigOverride('zu', 'system.site');
$this->assertIdentical('zu - site_name', $config_translation->get('name'));
$this->assertIdentical('site_mail@example.com', $config_translation->get('mail'));
$this->assertIdentical('Migrate rocks', $config_translation->get('slogan'));
$this->assertIdentical('/zu-user', $config_translation->get('page.403'));
$this->assertIdentical('/zu-page-not-found', $config_translation->get('page.404'));
$this->assertIdentical('/node', $config_translation->get('page.front'));
$this->assertIdentical(NULL, $config_translation->get('admin_compact_mode'));
}
}

View file

@ -0,0 +1,74 @@
<?php
namespace Drupal\Tests\config_translation\Kernel\Migrate\d6;
use Drupal\config\Tests\SchemaCheckTestTrait;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade i18n variables to user.*.yml.
*
* @group migrate_drupal_6
*/
class MigrateI18nUserConfigsTest extends MigrateDrupal6TestBase {
use SchemaCheckTestTrait;
public static $modules = ['language', 'locale', 'config_translation'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installSchema('locale',
['locales_source', 'locales_target', 'locales_location']);
$this->executeMigrations(['d6_i18n_user_mail', 'd6_i18n_user_settings']);
}
/**
* Tests migration of i18n user variables to user.mail.yml.
*/
public function testUserMail() {
$config = \Drupal::service('language_manager')->getLanguageConfigOverride('fr', 'user.mail');
$this->assertIdentical('fr - Account details for [user:name] at [site:name] (approved)', $config->get('status_activated.subject'));
$this->assertIdentical("fr - [user:name],\r\n\r\nYour account at [site:name] has been activated.\r\n\r\nYou may now log in by clicking on this link or copying and pasting it in your browser:\r\n\r\n[user:one-time-login-url]\r\n\r\nThis is a one-time login, so it can be used only once.\r\n\r\nAfter logging in, you will be redirected to [user:edit-url] so you can change your password.\r\n\r\nOnce you have set your own password, you will be able to log in to [site:login-url] in the future using:\r\n\r\nusername: [user:name]\r\n", $config->get('status_activated.body'));
$this->assertIdentical('fr - Replacement login information for [user:name] at [site:name]', $config->get('password_reset.subject'));
$this->assertIdentical("fr - [user:name],\r\n\r\nA request to reset the password for your account has been made at [site:name].\r\n\r\nYou may now log in to [site:url-brief] by clicking on this link or copying and pasting it in your browser:\r\n\r\n[user:one-time-login-url]\r\n\r\nThis is a one-time login, so it can be used only once. It expires after one day and nothing will happen if it's not used.\r\n\r\nAfter logging in, you will be redirected to [user:edit-url] so you can change your password.", $config->get('password_reset.body'));
$this->assertIdentical('fr - Account details for [user:name] at [site:name] (deleted)', $config->get('cancel_confirm.subject'));
$this->assertIdentical("fr - [user:name],\r\n\r\nYour account on [site:name] has been deleted.", $config->get('cancel_confirm.body'));
$this->assertIdentical('fr - An administrator created an account for you at [site:name]', $config->get('register_admin_created.subject'));
$this->assertIdentical("fr - [user:name],\r\n\r\nA site administrator at [site:name] has created an account for you. You may now log in to [site:login-url] using the following username and password:\r\n\r\nusername: [user:name]\r\npassword: \r\n\r\nYou may also log in by clicking on this link or copying and pasting it in your browser:\r\n\r\n[user:one-time-login-url]\r\n\r\nThis is a one-time login, so it can be used only once.\r\n\r\nAfter logging in, you will be redirected to [user:edit-url] so you can change your password.\r\n\r\n\r\n-- [site:name] team", $config->get('register_admin_created.body'));
$this->assertIdentical('fr - Account details for [user:name] at [site:name]', $config->get('register_no_approval_required.subject'));
$this->assertIdentical("fr - [user:name],\r\n\r\nThank you for registering at [site:name]. You may now log in to [site:login-url] using the following username and password:\r\n\r\nusername: [user:name]\r\npassword: \r\n\r\nYou may also log in by clicking on this link or copying and pasting it in your browser:\r\n\r\n[user:one-time-login-url]\r\n\r\nThis is a one-time login, so it can be used only once.\r\n\r\nAfter logging in, you will be redirected to [user:edit-url] so you can change your password.\r\n\r\n\r\n-- [site:name] team", $config->get('register_no_approval_required.body'));
$this->assertIdentical('fr - Account details for [user:name] at [site:name] (pending admin approval)', $config->get('register_pending_approval.subject'));
$this->assertIdentical("fr - [user:name],\r\n\r\nThank you for registering at [site:name]. Your application for an account is currently pending approval. Once it has been approved, you will receive another email containing information about how to log in, set your password, and other details.\r\n\r\n\r\n-- [site:name] team", $config->get('register_pending_approval.body'));
$this->assertIdentical('fr - Account details for [user:name] at [site:name] (blocked)', $config->get('status_blocked.subject'));
$this->assertIdentical("fr - [user:name],\r\n\r\nYour account on [site:name] has been blocked.", $config->get('status_blocked.body'));
$this->assertConfigSchema(\Drupal::service('config.typed'), 'user.mail', $config->get());
$config = \Drupal::service('language_manager')->getLanguageConfigOverride('zu', 'user.mail');
$this->assertIdentical('zu - An administrator created an account for you at [site:name]', $config->get('register_admin_created.subject'));
$this->assertIdentical("zu - [user:name],\r\n\r\nA site administrator at [site:name] has created an account for you. You may now log in to [site:login-url] using the following username and password:\r\n\r\nusername: [user:name]\r\npassword: \r\n\r\nYou may also log in by clicking on this link or copying and pasting it in your browser:\r\n\r\n[user:one-time-login-url]\r\n\r\nThis is a one-time login, so it can be used only once.\r\n\r\nAfter logging in, you will be redirected to [user:edit-url] so you can change your password.\r\n\r\n\r\n-- [site:name] team", $config->get('register_admin_created.body'));
}
/**
* Tests migration of i18n user variables to user.settings.yml.
*/
public function testUserSettings() {
$config = \Drupal::service('language_manager')->getLanguageConfigOverride('fr', 'user.settings');
$this->assertIdentical(1, $config->get('notify.status_blocked'));
$this->assertIdentical(0, $config->get('notify.status_activated'));
$this->assertIdentical(0, $config->get('verify_mail'));
$this->assertIdentical('admin_only', $config->get('register'));
$this->assertIdentical('fr Guest', $config->get('anonymous'));
$config = \Drupal::service('language_manager')->getLanguageConfigOverride('zu', 'user.settings');
$this->assertIdentical(1, $config->get('notify.status_blocked'));
$this->assertIdentical(0, $config->get('notify.status_activated'));
$this->assertIdentical(0, $config->get('verify_mail'));
$this->assertIdentical('admin_only', $config->get('register'));
$this->assertIdentical('Guest', $config->get('anonymous'));
}
}

View file

@ -21,7 +21,7 @@ interface ContactFormInterface extends ConfigEntityInterface {
* Returns an auto-reply message to send to the message author.
*
* @return string
* An auto-reply message
* An auto-reply message
*/
public function getReply();

View file

@ -29,7 +29,7 @@ class ContactCategory extends DrupalSqlBase {
'selected',
)
);
$query->orderBy('cid');
$query->orderBy('c.cid');
return $query;
}

View file

@ -18,7 +18,7 @@ class ContactSettings extends Variable {
protected function initializeIterator() {
$default_category = $this->select('contact', 'c')
->fields('c', ['cid'])
->condition('selected', 1)
->condition('c.selected', 1)
->execute()
->fetchField();
return new \ArrayIterator([$this->values() + ['default_category' => $default_category]]);

View file

@ -77,8 +77,8 @@ class ContentTranslationController extends ControllerBase {
* The route match.
* @param string $entity_type_id
* (optional) The entity type ID.
* @return array Array of page elements to render.
* Array of page elements to render.
* @return array
* Array of page elements to render.
*/
public function overview(RouteMatchInterface $route_match, $entity_type_id = NULL) {
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */

View file

@ -446,17 +446,23 @@ class DateTimeFieldTest extends WebTestBase {
$this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-year\"]", NULL, 'Year element found.');
$this->assertOptionSelected("edit-$field_name-0-value-year", '', 'No year selected.');
$this->assertOptionByText("edit-$field_name-0-value-year", t('Year'));
$this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-month\"]", NULL, 'Month element found.');
$this->assertOptionSelected("edit-$field_name-0-value-month", '', 'No month selected.');
$this->assertOptionByText("edit-$field_name-0-value-month", t('Month'));
$this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-day\"]", NULL, 'Day element found.');
$this->assertOptionSelected("edit-$field_name-0-value-day", '', 'No day selected.');
$this->assertOptionByText("edit-$field_name-0-value-day", t('Day'));
$this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-hour\"]", NULL, 'Hour element found.');
$this->assertOptionSelected("edit-$field_name-0-value-hour", '', 'No hour selected.');
$this->assertOptionByText("edit-$field_name-0-value-hour", t('Hour'));
$this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-minute\"]", NULL, 'Minute element found.');
$this->assertOptionSelected("edit-$field_name-0-value-minute", '', 'No minute selected.');
$this->assertOptionByText("edit-$field_name-0-value-minute", t('Minute'));
$this->assertNoFieldByXPath("//*[@id=\"edit-$field_name-0-value-second\"]", NULL, 'Second element not found.');
$this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-ampm\"]", NULL, 'AMPM element found.');
$this->assertOptionSelected("edit-$field_name-0-value-ampm", '', 'No ampm selected.');
$this->assertOptionByText("edit-$field_name-0-value-ampm", t('AM/PM'));
// Submit a valid date and ensure it is accepted.
$date_value = array('year' => 2012, 'month' => 12, 'day' => 31, 'hour' => 5, 'minute' => 15);

View file

@ -173,13 +173,13 @@ class DynamicPageCacheSubscriber implements EventSubscriberInterface {
// Don't cache the response if Dynamic Page Cache's request subscriber did
// not fire, because that means it is impossible to have a Dynamic Page
// Cache hit. (This can happen when the master request is for example a 403
// Cache hit. This can happen when the master request is for example a 403
// or 404, in which case a subrequest is performed by the router. In that
// case, it is the subrequest's response that is cached by Dynamic Page
// Cache, because the routing happens in a request subscriber earlier than
// Dynamic Page Cache's and immediately sets a response, i.e. the one
// returned by the subrequest, and thus causes Dynamic Page Cache's request
// subscriber to not fire for the master request.)
// subscriber to not fire for the master request.
// @see \Drupal\Core\Routing\AccessAwareRouter::checkAccess()
// @see \Drupal\Core\EventSubscriber\DefaultExceptionHtmlSubscriber::on403()
$request = $event->getRequest();
@ -218,7 +218,7 @@ class DynamicPageCacheSubscriber implements EventSubscriberInterface {
* is automatically placeholdered, and consequently the cacheability metadata
* of the placeholdered content does not bubble up to the response level.
*
* @param \Drupal\Core\Cache\CacheableResponseInterface
* @param \Drupal\Core\Cache\CacheableResponseInterface $response
* The response whose cacheability to analyze.
*
* @return bool

View file

@ -2,6 +2,8 @@ id: d7_field
label: Field configuration
migration_tags:
- Drupal 7
class: Drupal\migrate_drupal\Plugin\migrate\CckMigration
cck_plugin_method: processField
source:
plugin: d7_field
constants:
@ -13,7 +15,7 @@ process:
langcode: 'constants/langcode'
field_name: field_name
type:
plugin: static_map
plugin: field_type
source: type
map:
date: datetime
@ -30,8 +32,6 @@ process:
number_decimal: decimal
number_float: float
phone: telephone
taxonomy_term_reference: entity_reference
text: text
text_long: text_long
text_with_summary: text_with_summary
translatable: translatable

View file

@ -2,6 +2,8 @@ id: d7_field_formatter_settings
label: Field formatter configuration
migration_tags:
- Drupal 7
class: Drupal\migrate_drupal\Plugin\migrate\CckMigration
cck_plugin_method: processFieldFormatter
source:
plugin: d7_field_instance_per_view_mode
constants:

View file

@ -2,6 +2,8 @@ id: d7_field_instance
label: Field instance configuration
migration_tags:
- Drupal 7
class: Drupal\migrate_drupal\Plugin\migrate\CckMigration
cck_plugin_method: processFieldInstance
source:
plugin: d7_field_instance
constants:

View file

@ -2,6 +2,8 @@ id: d7_field_instance_widget_settings
label: Field instance widget configuration
migration_tags:
- Drupal 7
class: Drupal\migrate_drupal\Plugin\migrate\CckMigration
cck_plugin_method: processFieldWidget
source:
plugin: d7_field_instance_per_form_display
constants:

View file

@ -1,11 +1,12 @@
<?php
namespace Drupal\field\Plugin\migrate\process\d6;
namespace Drupal\field\Plugin\migrate\process;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Plugin\migrate\process\StaticMap;
use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -24,6 +25,13 @@ class FieldType extends StaticMap implements ContainerFactoryPluginInterface {
*/
protected $cckPluginManager;
/**
* The migration object.
*
* @var \Drupal\migrate\Plugin\MigrationInterface
*/
protected $migration;
/**
* Constructs a FieldType plugin.
*
@ -35,21 +43,25 @@ class FieldType extends StaticMap implements ContainerFactoryPluginInterface {
* The plugin definition.
* @param \Drupal\Component\Plugin\PluginManagerInterface $cck_plugin_manager
* The cckfield plugin manager.
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The migration being run.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, PluginManagerInterface $cck_plugin_manager) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, PluginManagerInterface $cck_plugin_manager, MigrationInterface $migration = NULL) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->cckPluginManager = $cck_plugin_manager;
$this->migration = $migration;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('plugin.manager.migrate.cckfield')
$container->get('plugin.manager.migrate.cckfield'),
$migration
);
}
@ -57,11 +69,10 @@ class FieldType extends StaticMap implements ContainerFactoryPluginInterface {
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
list ($field_type, $widget_type) = $value;
$field_type = is_array($value) ? $value[0] : $value;
try {
return $this->cckPluginManager->createInstance($field_type)
->getFieldType($row);
return $this->cckPluginManager->createInstance($field_type, [], $this->migration)->getFieldType($row);
}
catch (PluginNotFoundException $e) {
return parent::transform($value, $migrate_executable, $row, $destination_property);

View file

@ -62,7 +62,7 @@ class FieldInstancePerFormDisplay extends DrupalSqlBase {
'module',
));
$query->join('content_node_field', 'cnf', 'cnfi.field_name = cnf.field_name');
$query->orderBy('weight');
$query->orderBy('cnfi.weight');
return $query;
}

View file

@ -65,7 +65,7 @@ class FieldInstancePerViewMode extends ViewModeBase {
'module',
));
$query->join('content_node_field', 'cnf', 'cnfi.field_name = cnf.field_name');
$query->orderBy('weight');
$query->orderBy('cnfi.weight');
return $query;
}

View file

@ -31,10 +31,10 @@ class FieldInstance extends DrupalSqlBase {
// Optionally filter by entity type and bundle.
if (isset($this->configuration['entity_type'])) {
$query->condition('entity_type', $this->configuration['entity_type']);
$query->condition('fci.entity_type', $this->configuration['entity_type']);
if (isset($this->configuration['bundle'])) {
$query->condition('bundle', $this->configuration['bundle']);
$query->condition('fci.bundle', $this->configuration['bundle']);
}
}

View file

@ -17,7 +17,7 @@ abstract class FieldTestBase extends WebTestBase {
* @param $cardinality
* Number of values to generate.
* @return
* An array of random values, in the format expected for field values.
* An array of random values, in the format expected for field values.
*/
function _generateTestFieldValues($cardinality) {
$values = array();

View file

@ -142,8 +142,6 @@ abstract class FieldUnitTestBase extends KernelTestBase {
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to save.
*
* @return void
*/
protected function entityValidateAndSave(EntityInterface $entity) {
$violations = $entity->validate();
@ -161,7 +159,7 @@ abstract class FieldUnitTestBase extends KernelTestBase {
* @param $cardinality
* Number of values to generate.
* @return
* An array of random values, in the format expected for field values.
* An array of random values, in the format expected for field values.
*/
protected function _generateTestFieldValues($cardinality) {
$values = array();

View file

@ -81,6 +81,16 @@ class FieldUITest extends FieldTestBase {
$this->assertEqual($view->field['field_name_0']->options['type'], 'text_trimmed');
$this->assertEqual($view->field['field_name_0']->options['settings']['trim_length'], $random_number);
// Now change the formatter back to 'default' which doesn't have any
// settings. We want to ensure that the settings are empty then.
$edit['options[type]'] = 'text_default';
$this->drupalPostForm('admin/structure/views/nojs/handler/test_view_fieldapi/default/field/field_name_0', $edit, t('Apply'));
$this->drupalPostForm('admin/structure/views/view/test_view_fieldapi', [], t('Save'));
$view = Views::getView('test_view_fieldapi');
$view->initHandlers();
$this->assertEqual($view->field['field_name_0']->options['type'], 'text_default');
$this->assertEqual($view->field['field_name_0']->options['settings'], []);
// Ensure that the view depends on the field storage.
$dependencies = \Drupal::service('config.manager')->findConfigEntityDependents('config', [$this->fieldStorages[0]->getConfigDependencyName()]);
$this->assertTrue(isset($dependencies['views.view.test_view_fieldapi']), 'The view is dependent on the field storage.');

View file

@ -139,8 +139,6 @@ abstract class FieldKernelTestBase extends KernelTestBase {
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to save.
*
* @return void
*/
protected function entityValidateAndSave(EntityInterface $entity) {
$violations = $entity->validate();
@ -158,7 +156,7 @@ abstract class FieldKernelTestBase extends KernelTestBase {
* @param $cardinality
* Number of values to generate.
* @return
* An array of random values, in the format expected for field values.
* An array of random values, in the format expected for field values.
*/
protected function _generateTestFieldValues($cardinality) {
$values = array();

View file

@ -27,7 +27,13 @@ class FieldInstanceTest extends MigrateSqlSourceTestCase {
'bundle' => 'page',
'label' => 'Body',
'widget_settings' => array(
'module' => 'text',
'settings' => array(
'rows' => 20,
'summary_rows' => 5,
),
'type' => 'text_textarea_with_summary',
'weight' => -4,
),
'display_settings' => array(
),

View file

@ -26,8 +26,28 @@ class FieldTest extends MigrateSqlSourceTestCase {
'type' => 'file',
'global_settings' => '',
'storage' => array(
'type' => 'field_sql_storage',
'active' => 1,
'details' => array(
'sql' => array(
'FIELD_LOAD_CURRENT' => array(
'field_data_field_file' => array(
'description' => 'field_file_description',
'display' => 'field_file_display',
'fid' => 'field_file_fid',
),
),
'FIELD_LOAD_REVISION' => array(
'field_revision_field_file' => array(
'description' => 'field_file_description',
'display' => 'field_file_display',
'fid' => 'field_file_fid',
),
),
),
),
'module' => 'field_sql_storage',
'settings' => array(),
'type' => 'field_sql_storage',
),
'module' => 'file',
'db_columns' => '',
@ -39,8 +59,28 @@ class FieldTest extends MigrateSqlSourceTestCase {
'type' => 'file',
'global_settings' => '',
'storage' => array(
'type' => 'field_sql_storage',
'active' => 1,
'details' => array(
'sql' => array(
'FIELD_LOAD_CURRENT' => array(
'field_data_field_file' => array(
'description' => 'field_file_description',
'display' => 'field_file_display',
'fid' => 'field_file_fid',
),
),
'FIELD_LOAD_REVISION' => array(
'field_revision_field_file' => array(
'description' => 'field_file_description',
'display' => 'field_file_display',
'fid' => 'field_file_fid',
),
),
),
),
'module' => 'field_sql_storage',
'settings' => array(),
'type' => 'field_sql_storage',
),
'module' => 'file',
'db_columns' => '',

View file

@ -148,10 +148,27 @@ class FieldStorageConfigEditForm extends EntityForm {
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
$field_storage_definitions = \Drupal::service('entity_field.manager')->getFieldStorageDefinitions($this->entity->getTargetEntityTypeId());
// Validate field cardinality.
if ($form_state->getValue('cardinality') === 'number' && !$form_state->getValue('cardinality_number')) {
$form_state->setErrorByName('cardinality_number', $this->t('Number of values is required.'));
}
// If a specific cardinality is used, validate that there are no entities
// with a higher delta.
elseif (!$this->entity->isNew() && isset($field_storage_definitions[$this->entity->getName()]) && $form_state->getValue('cardinality') != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
// Get a count of entities that have a value in a delta higher than the
// one selected. Deltas start with 0, so the selected value does not
// need to be incremented.
$entities_with_higher_delta = \Drupal::entityQuery($this->entity->getTargetEntityTypeId())
->condition($this->entity->getName() . '.%delta', $form_state->getValue('cardinality'))
->count()
->execute();
if ($entities_with_higher_delta) {
$form_state->setErrorByName('cardinality_number', $this->formatPlural($entities_with_higher_delta, 'There is @count entity with @delta or more values in this field.', 'There are @count entities with @delta or more values in this field.', ['@delta' => $form_state->getValue('cardinality') + 1]));
}
}
}
/**

View file

@ -267,6 +267,23 @@ class ManageFieldsTest extends WebTestBase {
$this->assertLink(t('Field settings'));
$this->assertLinkByHref($field_edit_path);
// Add two entries in the body.
$edit = ['title[0][value]' => 'Cardinality', 'body[0][value]' => 'Body 1', 'body[1][value]' => 'Body 2'];
$this->drupalPostForm('node/add/article', $edit, 'Save');
// Assert that you can't set the cardinality to a lower number than the
// highest delta of this field.
$edit = [
'cardinality' => 'number',
'cardinality_number' => 1,
];
$this->drupalPostForm($field_edit_path, $edit, t('Save field settings'));
$this->assertRaw(t('There is @count entity with @delta or more values in this field.', ['@count' => 1, '@delta' => 2]), 'Correctly failed to set cardinality lower than highest delta.');
// Create a second entity with three values.
$edit = ['title[0][value]' => 'Cardinality 3', 'body[0][value]' => 'Body 1', 'body[1][value]' => 'Body 2', 'body[2][value]' => 'Body 3'];
$this->drupalPostForm('node/add/article', $edit, 'Save');
// Set to unlimited.
$edit = array(
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
@ -276,6 +293,28 @@ class ManageFieldsTest extends WebTestBase {
$this->drupalGet($field_edit_path);
$this->assertFieldByXPath("//select[@name='cardinality']", FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
$this->assertFieldByXPath("//input[@name='cardinality_number']", 1);
// Assert that you can't set the cardinality to a lower number then the
// highest delta of this field but can set it to the same.
$edit = [
'cardinality' => 'number',
'cardinality_number' => 1,
];
$this->drupalPostForm($field_edit_path, $edit, t('Save field settings'));
$this->assertRaw(t('There are @count entities with @delta or more values in this field.', ['@count' => 2, '@delta' => 2]), 'Correctly failed to set cardinality lower than highest delta.');
$edit = [
'cardinality' => 'number',
'cardinality_number' => 2,
];
$this->drupalPostForm($field_edit_path, $edit, t('Save field settings'));
$this->assertRaw(t('There is @count entity with @delta or more values in this field.', ['@count' => 1, '@delta' => 3]), 'Correctly failed to set cardinality lower than highest delta.');
$edit = [
'cardinality' => 'number',
'cardinality_number' => 3,
];
$this->drupalPostForm($field_edit_path, $edit, t('Save field settings'));
}
/**

View file

@ -185,8 +185,6 @@ function file_copy(FileInterface $source, $destination = NULL, $replace = FILE_E
/**
* Moves a file to a new location and update the file's database entry.
*
* Moving a file is performed by copying the file to the new location and then
* deleting the original.
* - Checks if $source and $destination are valid and readable/writable.
* - Performs a file move if $source is not equal to $destination.
* - If file already exists in $destination either the call will error out,
@ -1177,7 +1175,7 @@ function file_managed_file_save_upload($element, FormStateInterface $form_state)
$destination = isset($element['#upload_location']) ? $element['#upload_location'] : NULL;
if (isset($destination) && !file_prepare_directory($destination, FILE_CREATE_DIRECTORY)) {
\Drupal::logger('file')->notice('The upload directory %directory for the file field !name could not be created or is not accessible. A newly uploaded file could not be saved in this directory as a consequence, and the upload was canceled.', array('%directory' => $destination, '!name' => $element['#field_name']));
\Drupal::logger('file')->notice('The upload directory %directory for the file field %name could not be created or is not accessible. A newly uploaded file could not be saved in this directory as a consequence, and the upload was canceled.', array('%directory' => $destination, '%name' => $element['#field_name']));
$form_state->setError($element, t('The file could not be uploaded.'));
return FALSE;
}

View file

@ -8,7 +8,8 @@ use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
/**
* @MigrateCckField(
* id = "filefield"
* id = "filefield",
* core = {6}
* )
*/
class FileField extends CckFieldPluginBase {

View file

@ -9,6 +9,7 @@ use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
/**
* @MigrateCckField(
* id = "file",
* core = {7}
* )
*/
class FileField extends CckFieldPluginBase {

View file

@ -7,7 +7,8 @@ use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
/**
* @MigrateCckField(
* id = "image"
* id = "image",
* core = {7}
* )
*/
class ImageField extends CckFieldPluginBase {

View file

@ -147,7 +147,7 @@ class EntityFile extends EntityContentBase {
* (optional) FILE_EXISTS_REPLACE (default) or FILE_EXISTS_RENAME.
*
* @return bool
* TRUE on success, FALSE on failure.
* TRUE on success, FALSE on failure.
*/
protected function writeFile($source, $destination, $replace = FILE_EXISTS_REPLACE) {
if ($this->configuration['move']) {
@ -190,8 +190,8 @@ class EntityFile extends EntityContentBase {
* The URI or path.
*
* @return string|false
* The directory component of the path or URI, or FALSE if it could not
* be determined.
* The directory component of the path or URI, or FALSE if it could not
* be determined.
*/
protected function getDirectory($uri) {
$dir = $this->fileSystem->dirname($uri);
@ -213,8 +213,8 @@ class EntityFile extends EntityContentBase {
* The destination URI.
*
* @return bool
* TRUE if the source and destination URIs refer to the same physical path,
* otherwise FALSE.
* TRUE if the source and destination URIs refer to the same physical path,
* otherwise FALSE.
*/
protected function isLocationUnchanged($source, $destination) {
if ($this->isLocalUri($source) && $this->isLocalUri($destination)) {

View file

@ -45,7 +45,7 @@ class File extends DrupalSqlBase {
// If two or more files have the same timestamp, they'll end up in a
// non-deterministic order. Ordering by fid (or any other unique field)
// will prevent this.
->orderBy('fid');
->orderBy('f.fid');
}
/**

View file

@ -33,7 +33,7 @@ class UploadInstance extends DrupalSqlBase {
$return = array();
$values = $this->select('variable', 'v')
->fields('v', ['name', 'value'])
->condition('name', $variables, 'IN')
->condition('v.name', $variables, 'IN')
->execute()
->fetchAllKeyed();
foreach ($node_types as $node_type) {

View file

@ -42,7 +42,7 @@ class File extends DrupalSqlBase {
public function query() {
$query = $this->select('file_managed', 'f')
->fields('f')
->orderBy('timestamp');
->orderBy('f.timestamp');
// Filter by scheme(s), if configured.
if (isset($this->configuration['scheme'])) {

View file

@ -4,6 +4,7 @@ namespace Drupal\file\Tests;
use Drupal\node\Entity\Node;
use Drupal\file\Entity\File;
use Drupal\entity_test\Entity\EntityTestConstraints;
/**
* Tests file listing page functionality.
@ -17,7 +18,7 @@ class FileListingTest extends FileFieldTestBase {
*
* @var array
*/
public static $modules = array('views', 'file', 'image');
public static $modules = array('views', 'file', 'image', 'entity_test');
/**
* An authenticated user.
@ -144,11 +145,60 @@ class FileListingTest extends FileFieldTestBase {
}
}
/**
* Tests file listing usage page for entities with no canonical link template.
*/
function testFileListingUsageNoLink() {
// Login with user with right permissions and test listing.
$this->drupalLogin($this->adminUser);
// Create a bundle and attach a File field to the bundle.
$bundle = $this->randomMachineName();
entity_test_create_bundle($bundle, NULL, 'entity_test_constraints');
$this->createFileField('field_test_file', 'entity_test_constraints', $bundle, array(), array('file_extensions' => 'txt png'));
// Create file to attach to entity.
$file = File::create([
'filename' => 'druplicon.txt',
'uri' => 'public://druplicon.txt',
'filemime' => 'text/plain',
]);
$file->setPermanent();
file_put_contents($file->getFileUri(), 'hello world');
$file->save();
// Create entity and attach the created file.
$entity_name = $this->randomMachineName();
$entity = EntityTestConstraints::create(array(
'uid' => 1,
'name' => $entity_name,
'type' => $bundle,
'field_test_file' => array(
'target_id' => $file->id(),
),
));
$entity->save();
// Create node entity and attach the created file.
$node = $this->drupalCreateNode(array('type' => 'article', 'file' => $file));
$node->save();
// Load the file usage page for the created and attached file.
$this->drupalGet('admin/content/files/usage/' . $file->id());
$this->assertResponse(200);
// Entity name should be displayed, but not linked if Entity::toUrl
// throws an exception
$this->assertText($entity_name, 'Entity name is added to file usage listing.');
$this->assertNoLink($entity_name, 'Linked entity name not added to file usage listing.');
$this->assertLink($node->getTitle());
}
/**
* Creates and saves a test file.
*
* @return \Drupal\Core\Entity\EntityInterface
* A file entity.
* A file entity.
*/
protected function createFile() {
// Create a new file entity.

View file

@ -8,6 +8,7 @@ process:
format: format
name: name
cache: cache
weight: weight
filters:
plugin: iterator
source: filters
@ -25,5 +26,6 @@ process:
status:
plugin: default_value
default_value: true
weight: weight
destination:
plugin: entity:filter_format

View file

@ -35,25 +35,31 @@ class MigrateFilterFormatTest extends MigrateDrupal7TestBase {
* @param string $label
* The expected label of the format.
* @param array $enabled_filters
* The expected filters in the format, keyed by ID.
* The expected filters in the format, keyed by ID with weight as values.
* @param int $weight
* The weight of the filter.
*/
protected function assertEntity($id, $label, array $enabled_filters) {
protected function assertEntity($id, $label, array $enabled_filters, $weight) {
/** @var \Drupal\filter\FilterFormatInterface $entity */
$entity = FilterFormat::load($id);
$this->assertTrue($entity instanceof FilterFormatInterface);
$this->assertIdentical($label, $entity->label());
// get('filters') will return enabled filters only, not all of them.
$this->assertIdentical($enabled_filters, array_keys($entity->get('filters')));
$this->assertIdentical(array_keys($enabled_filters), array_keys($entity->get('filters')));
$this->assertIdentical($weight, $entity->get('weight'));
foreach ($entity->get('filters') as $filter_id => $filter) {
$this->assertIdentical($filter['weight'], $enabled_filters[$filter_id]);
}
}
/**
* Tests the Drupal 7 filter format to Drupal 8 migration.
*/
public function testFilterFormat() {
$this->assertEntity('custom_text_format', 'Custom Text format', ['filter_autop', 'filter_html']);
$this->assertEntity('filtered_html', 'Filtered HTML', ['filter_autop', 'filter_html', 'filter_htmlcorrector', 'filter_url']);
$this->assertEntity('full_html', 'Full HTML', ['filter_autop', 'filter_htmlcorrector', 'filter_url']);
$this->assertEntity('plain_text', 'Plain text', ['filter_html_escape', 'filter_url', 'filter_autop']);
$this->assertEntity('custom_text_format', 'Custom Text format', ['filter_autop' => 0, 'filter_html' => -10], 0);
$this->assertEntity('filtered_html', 'Filtered HTML', ['filter_autop' => 2, 'filter_html' => 1, 'filter_htmlcorrector' => 10, 'filter_url' => 0], 0);
$this->assertEntity('full_html', 'Full HTML', ['filter_autop' => 1, 'filter_htmlcorrector' => 10, 'filter_url' => 0], 1);
$this->assertEntity('plain_text', 'Plain text', ['filter_html_escape' => 0, 'filter_url' => 1, 'filter_autop' => 2], 10);
// This assertion covers issue #2555089. Drupal 7 formats are identified
// by machine names, so migrated formats should be merged into existing
// ones.

View file

@ -32,16 +32,19 @@ class FilterFormatTest extends MigrateSqlSourceTestCase {
'module' => 'filter',
'delta' => 2,
'weight' => 0,
'settings' => array(),
),
array(
'module' => 'filter',
'delta' => 0,
'weight' => 1,
'settings' => array(),
),
array(
'module' => 'filter',
'delta' => 1,
'weight' => 2,
'settings' => array(),
),
),
),
@ -55,16 +58,19 @@ class FilterFormatTest extends MigrateSqlSourceTestCase {
'module' => 'filter',
'delta' => 2,
'weight' => 0,
'settings' => array(),
),
array(
'module' => 'filter',
'delta' => 1,
'weight' => 1,
'settings' => array(),
),
array(
'module' => 'filter',
'delta' => 3,
'weight' => 10,
'settings' => array(),
),
),
),
@ -79,6 +85,7 @@ class FilterFormatTest extends MigrateSqlSourceTestCase {
'module' => 'markdown',
'delta' => 1,
'weight' => 10,
'settings' => array(),
),
),
),
@ -89,9 +96,11 @@ class FilterFormatTest extends MigrateSqlSourceTestCase {
*/
protected function setUp() {
$fid = 1;
$empty_array = serialize(array());
foreach ($this->expectedResults as $k => $row) {
$row['roles'] = ',' . implode(',', $row['roles']) . ',';
foreach ($row['filters'] as $filter) {
$filter['settings'] = $empty_array;
$this->databaseContents['filters'][$fid] = $filter;
$this->databaseContents['filters'][$fid]['format'] = $row['format'];
$this->databaseContents['filters'][$fid]['fid'] = $fid;

View file

@ -29,6 +29,7 @@ class FilterFormatTest extends MigrateSqlSourceTestCase {
'weight' => 0,
'filters' => array(
'filter_autop' => array(
'format' => 'custom_text_format',
'module' => 'filter',
'name' => 'filter_autop',
'weight' => 0,
@ -36,6 +37,7 @@ class FilterFormatTest extends MigrateSqlSourceTestCase {
'settings' => array(),
),
'filter_html' => array(
'format' => 'custom_text_format',
'module' => 'filter',
'name' => 'filter_html',
'weight' => 1,
@ -52,6 +54,7 @@ class FilterFormatTest extends MigrateSqlSourceTestCase {
'weight' => 1,
'filters' => array(
'filter_url' => array(
'format' => 'full_html',
'module' => 'filter',
'name' => 'filter_url',
'weight' => 0,

View file

@ -2,6 +2,7 @@ langcode: en
status: true
dependencies:
config:
- field.field.taxonomy_term.forums.forum_container
- taxonomy.vocabulary.forums
module:
- text

View file

@ -2,6 +2,7 @@ langcode: en
status: true
dependencies:
config:
- field.field.taxonomy_term.forums.forum_container
- taxonomy.vocabulary.forums
module:
- text

View file

@ -1,15 +1,15 @@
<?php
namespace Drupal\help\Tests;
namespace Drupal\Tests\help\Functional;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
/**
* Verifies help for experimental modules.
*
* @group help
*/
class ExperimentalHelpTest extends WebTestBase {
class ExperimentalHelpTest extends BrowserTestBase {
/**
* Modules to enable.

View file

@ -1,15 +1,15 @@
<?php
namespace Drupal\help\Tests;
namespace Drupal\Tests\help\Functional;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
/**
* Tests display of help block.
*
* @group help
*/
class HelpBlockTest extends WebTestBase {
class HelpBlockTest extends BrowserTestBase {
/**
* {@inheritdoc}

View file

@ -1,15 +1,15 @@
<?php
namespace Drupal\help\Tests;
namespace Drupal\Tests\help\Functional;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
/**
* Verify help display and user access to help based on permissions.
*
* @group help
*/
class HelpTest extends WebTestBase {
class HelpTest extends BrowserTestBase {
/**
* Modules to enable.
@ -40,8 +40,6 @@ class HelpTest extends WebTestBase {
protected function setUp() {
parent::setUp();
$this->getModuleList();
// Create users.
$this->adminUser = $this->drupalCreateUser(array('access administration pages', 'view the administration theme', 'administer permissions'));
$this->anyUser = $this->drupalCreateUser(array());
@ -122,7 +120,7 @@ class HelpTest extends WebTestBase {
$this->assertResponse($response);
if ($response == 200) {
$this->assertTitle($name . ' | Drupal', format_string('%module title was displayed', array('%module' => $module)));
$this->assertEqual($this->cssSelect('h1.page-title')[0], t($name), format_string('%module heading was displayed', array('%module' => $module)));
$this->assertEquals($name, $this->cssSelect('h1.page-title')[0]->getText(), "$module heading was displayed");
$admin_tasks = system_get_module_admin_tasks($module, system_get_info('module', $module));
if (!empty($admin_tasks)) {
$this->assertText(t('@module administration pages', array('@module' => $name)));

View file

@ -1,15 +1,15 @@
<?php
namespace Drupal\help\Tests;
namespace Drupal\Tests\help\Functional;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
/**
* Verify no help is displayed for modules not providing any help.
*
* @group help
*/
class NoHelpTest extends WebTestBase {
class NoHelpTest extends BrowserTestBase {
/**
* Modules to enable.

View file

@ -188,14 +188,14 @@ class ImageFormatter extends ImageFormatterBase implements ContainerFactoryPlugi
$image_style_setting = $this->getSetting('image_style');
// Collect cache tags to be added for each item in the field.
$cache_tags = array();
$base_cache_tags = [];
if (!empty($image_style_setting)) {
$image_style = $this->imageStyleStorage->load($image_style_setting);
$cache_tags = $image_style->getCacheTags();
$base_cache_tags = $image_style->getCacheTags();
}
foreach ($files as $delta => $file) {
$cache_contexts = array();
$cache_contexts = [];
if (isset($link_file)) {
$image_uri = $file->getFileUri();
// @todo Wrap in file_url_transform_relative(). This is currently
@ -206,7 +206,7 @@ class ImageFormatter extends ImageFormatterBase implements ContainerFactoryPlugi
$url = Url::fromUri(file_create_url($image_uri));
$cache_contexts[] = 'url.site';
}
$cache_tags = Cache::mergeTags($cache_tags, $file->getCacheTags());
$cache_tags = Cache::mergeTags($base_cache_tags, $file->getCacheTags());
// Extract field item attributes for the theme function, and unset them
// from the $item so that the field template does not re-render them.

View file

@ -343,7 +343,7 @@ class ImageItem extends FileItem {
$image = File::create();
$image->setFileUri($path);
$image->setOwnerId(\Drupal::currentUser()->id());
$image->setMimeType('image/' . pathinfo($path, PATHINFO_EXTENSION));
$image->setMimeType(\Drupal::service('file.mime_type.guesser')->guess($path));
$image->setFileName(drupal_basename($path));
$destination_dir = static::doGetUploadLocation($settings);
file_prepare_directory($destination_dir, FILE_CREATE_DIRECTORY);

View file

@ -0,0 +1,102 @@
<?php
namespace Drupal\Tests\image\Kernel;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Tests\field\Kernel\FieldKernelTestBase;
/**
* Tests the image field rendering using entity fields of the image field type.
*
* @group image
*/
class ImageFormatterTest extends FieldKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file', 'image');
/**
* @var string
*/
protected $entityType;
/**
* @var string
*/
protected $bundle;
/**
* @var string
*/
protected $fieldName;
/**
* @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface
*/
protected $display;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installConfig(['field']);
$this->installEntitySchema('entity_test');
$this->installEntitySchema('file');
$this->installSchema('file', array('file_usage'));
$this->entityType = 'entity_test';
$this->bundle = $this->entityType;
$this->fieldName = Unicode::strtolower($this->randomMachineName());
FieldStorageConfig::create(array(
'entity_type' => $this->entityType,
'field_name' => $this->fieldName,
'type' => 'image',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
))->save();
FieldConfig::create([
'entity_type' => $this->entityType,
'field_name' => $this->fieldName,
'bundle' => $this->bundle,
'settings' => [
'file_extensions' => 'jpg',
],
])->save();
$this->display = entity_get_display($this->entityType, $this->bundle, 'default')
->setComponent($this->fieldName, [
'type' => 'image',
'label' => 'hidden',
]);
$this->display->save();
}
/**
* Tests the cache tags from image formatters.
*/
function testImageFormatterCacheTags() {
// Create a test entity with the image field set.
$entity = EntityTest::create([
'name' => $this->randomMachineName(),
]);
$entity->{$this->fieldName}->generateSampleItems(2);
$entity->save();
// Generate the render array to verify if the cache tags are as expected.
$build = $this->display->build($entity);
$this->assertEquals($entity->{$this->fieldName}[0]->entity->getCacheTags(), $build[$this->fieldName][0]['#cache']['tags'], 'First image cache tags is as expected');
$this->assertEquals($entity->{$this->fieldName}[1]->entity->getCacheTags(), $build[$this->fieldName][1]['#cache']['tags'], 'Second image cache tags is as expected');
}
}

View file

@ -53,6 +53,9 @@ class ImageItemTest extends FieldKernelTestBase {
'entity_type' => 'entity_test',
'field_name' => 'image_test',
'bundle' => 'entity_test',
'settings' => [
'file_extensions' => 'jpg',
],
])->save();
file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', 'public://example.jpg');
$this->image = File::create([
@ -123,6 +126,7 @@ class ImageItemTest extends FieldKernelTestBase {
$entity = EntityTest::create();
$entity->image_test->generateSampleItems();
$this->entityValidateAndSave($entity);
$this->assertEqual($entity->image_test->entity->get('filemime')->value, 'image/jpeg');
}
}

View file

@ -41,7 +41,7 @@ class ImageStyleTest extends UnitTestCase {
* @param \Drupal\image\ImageEffectInterface|\PHPUnit_Framework_MockObject_MockObject $image_effect
* The image effect used for testing.
*
* @return \Drupal\image\ImageStyleInterface|\Drupal\image\ImageStyleInterface
* @return \Drupal\image\ImageStyleInterface
* The mocked image style.
*/
protected function getImageStyleMock($image_effect_id, $image_effect, $stubs = array()) {

View file

@ -0,0 +1,44 @@
id: d6_language_content_settings
label: Drupal 6 language content settings
migration_tags:
- Drupal 6
source:
plugin: d6_language_content_settings
constants:
target_type: 'node'
process:
# Ignore i18n_node_options_[node_type] options not available in Drupal 8,
# i18n_required_node and i18n_newnode_current
target_bundle: type
target_entity_type_id: 'constants/target_type'
default_langcode:
-
plugin: static_map
source: language_content_type
map:
0: NULL
1: 'current_interface'
2: 'current_interface'
-
plugin: skip_on_empty
method: row
language_alterable:
plugin: static_map
source: i18n_lock_node
map:
0: true
1: false
'third_party_settings/content_translation/enabled':
plugin: static_map
source: language_content_type
map:
# In the case of being 0, it will be skipped. We are not actually setting
# a null value.
0: NULL
1: false
2: true
destination:
plugin: entity:language_content_settings
migration_dependencies:
required:
- d6_node_type

View file

@ -0,0 +1,44 @@
id: d7_language_content_settings
label: Drupal 7 language content settings
migration_tags:
- Drupal 7
source:
plugin: d7_language_content_settings
constants:
target_type: 'node'
process:
# Ignore i18n_node_options_[node_type] options not available in Drupal 8,
# i18n_required_node and i18n_newnode_current
target_bundle: type
target_entity_type_id: 'constants/target_type'
default_langcode:
-
plugin: static_map
source: language_content_type
map:
0: NULL
1: 'current_interface'
2: 'current_interface'
-
plugin: skip_on_empty
method: row
language_alterable:
plugin: static_map
source: i18n_lock_node
map:
0: true
1: false
'third_party_settings/content_translation/enabled':
plugin: static_map
source: language_content_type
map:
# In the case of being 0, it will be skipped. We are not actually setting
# a null value.
0: NULL
1: false
2: true
destination:
plugin: entity:language_content_settings
migration_dependencies:
required:
- d7_node_type

View file

@ -40,7 +40,7 @@ class DefaultLanguageItem extends LanguageItem {
* The entity whose language code to be loaded.
*
* @return string
* A string language code.
* A string language code.
*/
public function getDefaultLangcode(EntityInterface $entity) {
return language_get_default_langcode($entity->getEntityTypeId(), $entity->bundle());

View file

@ -0,0 +1,57 @@
<?php
namespace Drupal\language\Plugin\migrate\source\d6;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
/**
* Drupal multilingual node settings from database.
*
* @MigrateSource(
* id = "d6_language_content_settings",
* )
*/
class LanguageContentSettings extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function query() {
return $this->select('node_type', 't')
->fields('t', array(
'type',
));
}
/**
* {@inheritdoc}
*/
public function fields() {
$fields = array(
'type' => $this->t('Type'),
'language_content_type' => $this->t('Multilingual support.'),
'i18n_lock_node' => $this->t('Lock language.'),
);
return $fields;
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
$type = $row->getSourceProperty('type');
$row->setSourceProperty('language_content_type', $this->variableGet('language_content_type_' . $type, NULL));
$row->setSourceProperty('i18n_lock_node', $this->variableGet('i18n_lock_node_' . $type, 0));
return parent::prepareRow($row);
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['type']['type'] = 'string';
return $ids;
}
}

View file

@ -0,0 +1,63 @@
<?php
namespace Drupal\language\Plugin\migrate\source\d7;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
/**
* Drupal multilingual node settings from database.
*
* @MigrateSource(
* id = "d7_language_content_settings",
* )
*/
class LanguageContentSettings extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function query() {
return $this->select('node_type', 't')
->fields('t', array(
'type',
));
}
/**
* {@inheritdoc}
*/
public function fields() {
$fields = array(
'type' => $this->t('Type'),
'language_content_type' => $this->t('Multilingual support.'),
'i18n_lock_node' => $this->t('Lock language.'),
);
return $fields;
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
$type = $row->getSourceProperty('type');
$row->setSourceProperty('language_content_type', $this->variableGet('language_content_type_' . $type, NULL));
$i18n_node_options = $this->variableGet('i18n_node_options_' . $type, NULL);
if ($i18n_node_options && in_array('lock', $i18n_node_options)) {
$row->setSourceProperty('i18n_lock_node', 1);
}
else {
$row->setSourceProperty('i18n_lock_node', 0);
}
return parent::prepareRow($row);
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['type']['type'] = 'string';
return $ids;
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace Drupal\Tests\language\Kernel\Migrate\d6;
use Drupal\language\Entity\ContentLanguageSettings;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Tests migration of language content setting variables,
* language_content_type_$type, i18n_node_options_* and i18n_lock_node_*.
*
* @group migrate_drupal_6
*/
class MigrateLanguageContentSettingsTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['node', 'text', 'language', 'content_translation'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installConfig(['node']);
$this->executeMigrations(['d6_node_type', 'd6_language_content_settings']);
}
/**
* Tests migration of content language settings.
*/
public function testLanguageContent() {
// Assert that a translatable content is still translatable.
$config = $this->config('language.content_settings.node.article');
$this->assertSame($config->get('target_entity_type_id'), 'node');
$this->assertSame($config->get('target_bundle'), 'article');
$this->assertSame($config->get('default_langcode'), 'current_interface');
$this->assertTrue($config->get('third_party_settings.content_translation.enabled'));
// Assert that a non-translatable content is not translatable.
$config = ContentLanguageSettings::loadByEntityTypeBundle('node', 'company');
$this->assertTrue($config->isDefaultConfiguration());
$this->assertFalse($config->isLanguageAlterable());
$this->assertSame($config->getDefaultLangcode(), 'site_default');
}
/**
* Tests migration of content language settings when there is no language lock.
*/
public function testLanguageContentWithNoLanguageLock() {
// Assert that a we can assign a language.
$config = ContentLanguageSettings::loadByEntityTypeBundle('node', 'employee');
$this->assertSame($config->getDefaultLangcode(), 'current_interface');
$this->assertTrue($config->isLanguageAlterable());
}
}

View file

@ -0,0 +1,50 @@
<?php
namespace Drupal\Tests\language\Kernel\Migrate\d7;
use Drupal\language\Entity\ContentLanguageSettings;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
/**
* Tests migration of language content setting variables,
* language_content_type_$type, i18n_node_options_* and i18n_lock_node_*.
*
* @group migrate_drupal_7
*/
class MigrateLanguageContentSettingsTest extends MigrateDrupal7TestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['node', 'text', 'language', 'content_translation'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installConfig(['node']);
$this->executeMigrations(['d7_node_type', 'd7_language_content_settings']);
}
/**
* Tests migration of content language settings.
*/
public function testLanguageContent() {
// Assert that a translatable content is still translatable.
$config = $this->config('language.content_settings.node.blog');
$this->assertIdentical($config->get('target_entity_type_id'), 'node');
$this->assertIdentical($config->get('target_bundle'), 'blog');
$this->assertIdentical($config->get('default_langcode'), 'current_interface');
$this->assertFalse($config->get('language_alterable'));
$this->assertTrue($config->get('third_party_settings.content_translation.enabled'));
// Assert that a non-translatable content is not translatable.
$config = ContentLanguageSettings::loadByEntityTypeBundle('node', 'page');
$this->assertTrue($config->isDefaultConfiguration());
$this->assertFalse($config->isLanguageAlterable());
$this->assertSame($config->getDefaultLangcode(), 'site_default');
}
}

View file

@ -7,7 +7,11 @@ use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
/**
* @MigrateCckField(
* id = "link"
* id = "link",
* core = {6},
* type_map = {
* "link_field" = "link"
* }
* )
*/
class LinkField extends CckFieldPluginBase {

View file

@ -36,6 +36,32 @@ class CckLink extends ProcessPluginBase implements ContainerFactoryPluginInterfa
);
}
/**
* Turn a Drupal 6 URI into a Drupal 8-compatible format.
*
* @param string $uri
* The 'url' value from Drupal 6.
*
* @return string
* The Drupal 8-compatible URI.
*
* @see \Drupal\link\Plugin\Field\FieldWidget\LinkWidget::getUserEnteredStringAsUri()
*/
protected function canonicalizeUri($uri) {
// If we already have a scheme, we're fine.
if (empty($uri) || !is_null(parse_url($uri, PHP_URL_SCHEME))) {
return $uri;
}
// Remove the <front> component of the URL.
if (strpos($uri, '<front>') === 0) {
$uri = substr($uri, strlen('<front>'));
}
// Add the internal: scheme and ensure a leading slash.
return 'internal:/' . ltrim($uri, '/');
}
/**
* {@inheritdoc}
*/
@ -51,7 +77,7 @@ class CckLink extends ProcessPluginBase implements ContainerFactoryPluginInterfa
}
// Massage the values into the correct form for the link.
$route['uri'] = $value['url'];
$route['uri'] = $this->canonicalizeUri($value['url']);
$route['options']['attributes'] = $attributes;
$route['title'] = $value['title'];
return $route;

View file

@ -0,0 +1,56 @@
<?php
namespace Drupal\Tests\link\Unit\Plugin\migrate\process\d6;
use Drupal\link\Plugin\migrate\process\d6\CckLink;
use Drupal\Tests\UnitTestCase;
/**
* @group Link
*/
class CckLinkTest extends UnitTestCase {
/**
* Test the url transformations in the CckLink process plugin.
*
* @dataProvider canonicalizeUriDataProvider
*/
public function testCanonicalizeUri($url, $expected) {
$link_plugin = new CckLink([], '', [], $this->getMock('\Drupal\migrate\Plugin\MigrationInterface'));
$transformed = $link_plugin->transform([
'url' => $url,
'title' => '',
'attributes' => serialize([]),
], $this->getMock('\Drupal\migrate\MigrateExecutableInterface'), $this->getMockBuilder('\Drupal\migrate\Row')->disableOriginalConstructor()->getMock(), NULL);
$this->assertEquals($expected, $transformed['uri']);
}
/**
* Data provider for testCanonicalizeUri.
*/
public function canonicalizeUriDataProvider() {
return [
'Simple front-page' => [
'<front>',
'internal:/',
],
'Front page with query' => [
'<front>?query=1',
'internal:/?query=1',
],
'No leading forward slash' => [
'node/10',
'internal:/node/10',
],
'Leading forward slash' => [
'/node/10',
'internal:/node/10',
],
'Existing scheme' => [
'scheme:test',
'scheme:test',
],
];
}
}

View file

@ -5,11 +5,8 @@ migration_tags:
- Drupal 7
source:
plugin: menu_link
constants:
bundle: menu_link_content
process:
id: mlid
bundle: 'constants/bundle'
title: link_title
description: description
menu_name:
@ -49,6 +46,7 @@ process:
changed: updated
destination:
plugin: entity:menu_link_content
default_bundle: menu_link_content
no_stub: true
migration_dependencies:
required:

View file

@ -17,33 +17,30 @@ use Drupal\migrate\Row;
* @section overview Overview of migration
* Migration is an
* @link http://wikipedia.org/wiki/Extract,_transform,_load Extract, Transform, Load @endlink
* (ETL) process. For historical reasons, in the Drupal migration tool the
* extract phase is called "source", the transform phase is called "process",
* and the load phase is called "destination".
* (ETL) process. In the Drupal migration API the extract phase is called
* "source", the transform phase is called "process", and the load phase is
* called "destination". It is important to understand that the "load" in ETL
* means to load data into storage, while traditionally Drupal uses "load" to
* mean load data from storage into memory.
*
* Source, process, and destination phases are each provided by plugins. Source
* plugins extract data from a data source in "rows", containing "properties".
* Each row is handed off to one or more series of process plugins, where each
* series operates to transform the row data into one result property. After all
* the properties are processed, the resulting row is handed off to a
* destination plugin, which saves the data.
* Source, process, and destination phases are each provided by plugins.
* Source plugins extract data from a data source in "rows", containing
* "properties". Each row is handed off to one or more process plugins which
* transform the row's properties. After all the properties are processed, the
* resulting row is handed off to a destination plugin, which saves the data.
*
* The Migrate module provides process plugins for common operations (setting
* default values, mapping values, etc.), and destination plugins for Drupal
* core objects (configuration, entity, URL alias, etc.). The Migrate Drupal
* module provides source plugins to extract data from various versions of
* Drupal. Custom and contributed modules can provide additional plugins; see
* the @link plugin_api Plugin API topic @endlink for generic information about
* providing plugins, and sections below for details about the plugin types.
* A source plugin, one or more process plugins, and a destination plugin are
* brought together to extract, transform, and load (in the ETL sense) a specific
* type of data by a migration plugin.
*
* The configuration of migrations is stored in configuration entities, which
* list the IDs and configurations of the plugins that are involved. See
* @ref sec_entity below for details. To migrate an entire site, you'll need to
* create a migration manifest; see @ref sec_manifest for details.
*
* https://www.drupal.org/node/2127611 has more complete information on the
* Migration API, including information on load plugins, which are only used
* in Drupal 6 migration.
* @section sec_migrations Migration plugins
* Migration plugin definitions are stored in a module's 'migrations' directory.
* For backwards compatibility we also scan the 'migration_templates' directory.
* Examples of migration plugin definitions can be found in
* 'core/modules/action/migration_templates'. The plugin class is
* \Drupal\migrate\Plugin\Migration, with interface
* \Drupal\migrate\Plugin\MigrationInterface. Migration plugins are managed by
* the \Drupal\migrate\Plugin\MigrationPluginManager class.
*
* @section sec_source Source plugins
* Migration source plugins implement
@ -61,7 +58,9 @@ use Drupal\migrate\Row;
* with \Drupal\migrate\Annotation\MigrateProcessPlugin annotation, and must be
* in namespace subdirectory Plugin\migrate\process under the namespace of the
* module that defines them. Migration process plugins are managed by the
* \Drupal\migrate\Plugin\MigratePluginManager class.
* \Drupal\migrate\Plugin\MigratePluginManager class. The Migrate module
* provides process plugins for common operations (setting default values,
* mapping values, etc.).
*
* @section sec_destination Destination plugins
* Migration destination plugins implement
@ -70,34 +69,12 @@ use Drupal\migrate\Row;
* annotated with \Drupal\migrate\Annotation\MigrateDestination annotation, and
* must be in namespace subdirectory Plugin\migrate\destination under the
* namespace of the module that defines them. Migration destination plugins
* are managed by the
* \Drupal\migrate\Plugin\MigrateDestinationPluginManager class.
* are managed by the \Drupal\migrate\Plugin\MigrateDestinationPluginManager
* class. The Migrate module provides destination plugins for Drupal core
* objects (configuration and entity).
*
* @section sec_entity Migration configuration entities
* The definition of how to migrate each type of data is stored in configuration
* entities. The migration configuration entity class is
* \Drupal\migrate\Entity\Migration, with interface
* \Drupal\migrate\Entity\MigrationInterface; the configuration schema can be
* found in the migrate.schema.yml file. Migration configuration consists of IDs
* and configuration for the source, process, and destination plugins, as well
* as information on dependencies. Process configuration consists of sections,
* each of which defines the series of process plugins needed for one
* destination property. You can find examples of migration configuration files
* in the core/modules/migrate_drupal/config/install directory.
*
* @section sec_manifest Migration manifests
* You can run a migration with the "drush migrate-manifest" command, providing
* a migration manifest file. This file lists the configuration names of the
* migrations you want to execute, as well as any dependencies they have (you
* can find these in the "migration_dependencies" sections of the individual
* configuration files). For example, to migrate blocks from a Drupal 6 site,
* you would list:
* @code
* # Migrate blocks from Drupal 6 to 8
* - d6_filter_format
* - d6_custom_block
* - d6_block
* @endcode
* @section sec_more_info More information
* @link https://www.drupal.org/node/2127611 Migration API documentation. @endlink
*
* @see update_api
* @}

View file

@ -662,7 +662,7 @@ class Migration extends PluginBase implements MigrationInterface, RequirementsIn
* {@inheritdoc}
*/
public function getMigrationDependencies() {
return $this->migration_dependencies + ['required' => [], 'optional' => []];
return ($this->migration_dependencies ?: []) + ['required' => [], 'optional' => []];
}
/**
@ -703,14 +703,14 @@ class Migration extends PluginBase implements MigrationInterface, RequirementsIn
* {@inheritdoc}
*/
public function getTrackLastImported() {
$this->trackLastImported;
return $this->trackLastImported;
}
/**
* {@inheritdoc}
*/
public function getDestinationIds() {
$this->destinationIds;
return $this->destinationIds;
}
}

View file

@ -88,6 +88,21 @@ abstract class Entity extends DestinationBase implements ContainerFactoryPluginI
return substr($plugin_id, 7);
}
/**
* Gets the bundle for the row taking into account the default.
*
* @param \Drupal\migrate\Row $row
* The current row we're importing.
*
* @return string
* The bundle for this row.
*/
public function getBundle(Row $row) {
$default_bundle = isset($this->configuration['default_bundle']) ? $this->configuration['default_bundle'] : '';
$bundle_key = $this->getKey('bundle');
return $row->getDestinationProperty($bundle_key) ?: $default_bundle;
}
/**
* {@inheritdoc}
*/
@ -112,6 +127,11 @@ abstract class Entity extends DestinationBase implements ContainerFactoryPluginI
$this->updateEntity($entity, $row);
}
else {
// Attempt to ensure we always have a bundle.
if ($bundle = $this->getBundle($row)) {
$row->setDestinationProperty($this->getKey('bundle'), $bundle);
}
// Stubs might need some required fields filled in.
if ($row->isStub()) {
$this->processStubRow($row);

View file

@ -143,7 +143,7 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
// Set up some defaults based on the source configuration.
$this->cacheCounts = !empty($configuration['cache_counts']);
$this->skipCount = !empty($configuration['skip_count']);
$this->cacheKey = !empty($configuration['cache_key']) ? !empty($configuration['cache_key']) : NULL;
$this->cacheKey = !empty($configuration['cache_key']) ? $configuration['cache_key'] : NULL;
$this->trackChanges = !empty($configuration['track_changes']) ? $configuration['track_changes'] : FALSE;
$this->idMap = $this->migration->getIdMap();

View file

@ -1,10 +0,0 @@
id: node_template
label: Template test - node
migration_tags:
- Template Test
source:
plugin: empty
process:
src: barfoo
destination:
plugin: entity:node

View file

@ -1,10 +0,0 @@
id: other_template
label: Template with a different tag
migration_tags:
- Different Template Test
source:
plugin: empty
process:
src: raboof
destination:
plugin: entity:user

View file

@ -1,10 +0,0 @@
id: url_template
label: Template test - URL
migration_tags:
- Template Test
source:
plugin: empty
process:
src: foobar
destination:
plugin: url_alias

View file

@ -1,5 +0,0 @@
name: 'Migration template test'
type: module
package: Testing
version: VERSION
core: 8.x

View file

@ -0,0 +1,155 @@
<?php
namespace Drupal\Tests\migrate\Kernel;
use Drupal\migrate\MigrateExecutable;
use Drupal\taxonomy\Entity\Term;
use Drupal\taxonomy\Entity\Vocabulary;
/**
* Tests setting of bundles on content entity migrations.
*
* @group migrate
*/
class MigrateBundleTest extends MigrateTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['taxonomy', 'text'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('taxonomy_vocabulary');
$this->installEntitySchema('taxonomy_term');
$this->installConfig(['taxonomy']);
// Set up two vocabularies (taxonomy bundles).
Vocabulary::create(['vid' => 'tags', 'name' => 'Tags']);
Vocabulary::create(['vid' => 'categories', 'name' => 'Categories']);
}
/**
* Tests setting the bundle in the destination.
*/
public function testDestinationBundle() {
$term_data_rows = [
['id' => 1, 'name' => 'Category 1'],
];
$ids = ['id' => ['type' => 'integer']];
$definition = [
'id' => 'terms',
'migration_tags' => ['Bundle test'],
'source' => [
'plugin' => 'embedded_data',
'data_rows' => $term_data_rows,
'ids' => $ids,
],
'process' => [
'tid' => 'id',
'name' => 'name',
],
'destination' => [
'plugin' => 'entity:taxonomy_term',
'default_bundle' => 'categories',
],
'migration_dependencies' => [],
];
$term_migration = \Drupal::service('plugin.manager.migration')->createStubMigration($definition);
// Import and validate the term entity was created with the correct bundle.
$term_executable = new MigrateExecutable($term_migration, $this);
$term_executable->import();
/** @var Term $term */
$term = Term::load(1);
$this->assertEquals($term->bundle(), 'categories');
}
/**
* Tests setting the bundle in the process pipeline.
*/
public function testProcessBundle() {
$term_data_rows = [
['id' => 1, 'vocab' => 'categories', 'name' => 'Category 1'],
['id' => 2, 'vocab' => 'tags', 'name' => 'Tag 1'],
];
$ids = ['id' => ['type' => 'integer']];
$definition = [
'id' => 'terms',
'migration_tags' => ['Bundle test'],
'source' => [
'plugin' => 'embedded_data',
'data_rows' => $term_data_rows,
'ids' => $ids,
],
'process' => [
'tid' => 'id',
'vid' => 'vocab',
'name' => 'name',
],
'destination' => [
'plugin' => 'entity:taxonomy_term',
],
'migration_dependencies' => [],
];
$term_migration = \Drupal::service('plugin.manager.migration')->createStubMigration($definition);
// Import and validate the term entities were created with the correct bundle.
$term_executable = new MigrateExecutable($term_migration, $this);
$term_executable->import();
/** @var Term $term */
$term = Term::load(1);
$this->assertEquals($term->bundle(), 'categories');
$term = Term::load(2);
$this->assertEquals($term->bundle(), 'tags');
}
/**
* Tests setting bundles both in process and destination.
*/
public function testMixedBundles() {
$term_data_rows = [
['id' => 1, 'vocab' => 'categories', 'name' => 'Category 1'],
['id' => 2, 'name' => 'Tag 1'],
];
$ids = ['id' => ['type' => 'integer']];
$definition = [
'id' => 'terms',
'migration_tags' => ['Bundle test'],
'source' => [
'plugin' => 'embedded_data',
'data_rows' => $term_data_rows,
'ids' => $ids,
],
'process' => [
'tid' => 'id',
'vid' => 'vocab',
'name' => 'name',
],
'destination' => [
'plugin' => 'entity:taxonomy_term',
// When no vocab is provided, the destination bundle is applied.
'default_bundle' => 'tags',
],
'migration_dependencies' => [],
];
$term_migration = \Drupal::service('plugin.manager.migration')->createStubMigration($definition);
// Import and validate the term entities were created with the correct bundle.
$term_executable = new MigrateExecutable($term_migration, $this);
$term_executable->import();
/** @var Term $term */
$term = Term::load(1);
$this->assertEquals($term->bundle(), 'categories');
$term = Term::load(2);
$this->assertEquals($term->bundle(), 'tags');
}
}

View file

@ -27,4 +27,41 @@ class MigrationTest extends KernelTestBase {
$this->assertEquals([], $migration->getProcessPlugins([]));
}
/**
* Tests Migration::getMigrationDependencies()
*
* @covers ::getMigrationDependencies
*/
public function testGetMigrationDependencies() {
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration([
'migration_dependencies' => NULL
]);
$this->assertNotEmpty($migration->getMigrationDependencies(), 'Migration dependencies is not empty');
}
/**
* Tests Migration::getDestinationIds()
*
* @covers ::getDestinationIds
*/
public function testGetDestinationIds() {
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration(['destinationIds' => ['foo' => 'bar']]);
$destination_ids = $migration->getDestinationIds();
$this->assertNotEmpty($destination_ids, 'Destination ids are not empty');
$this->assertEquals(['foo' => 'bar'], $destination_ids, 'Destination ids match the expected values.');
}
/**
* Tests Migration::getTrackLastImported()
*
* @covers ::getTrackLastImported
* @covers ::isTrackLastImported
*/
public function testGetTrackLastImported() {
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration([]);
$migration->setTrackLastImported(TRUE);
$this->assertEquals(TRUE, $migration->getTrackLastImported());
$this->assertEquals(TRUE, $migration->isTrackLastImported());
}
}

View file

@ -170,6 +170,25 @@ class MigrateSourceTest extends MigrateTestCase {
$this->assertEquals(-1, $source->count());
}
/**
* Test that the key can be set for the count cache.
*
* @covers ::count
*/
public function testCountCacheKey() {
// Mock the cache to validate set() receives appropriate arguments.
$container = new ContainerBuilder();
$cache = $this->getMock(CacheBackendInterface::class);
$cache->expects($this->any())->method('set')
->with('test_key', $this->isType('int'), $this->isType('int'));
$container->set('cache.migrate', $cache);
\Drupal::setContainer($container);
// Test caching the count with a configured key works.
$source = $this->getSource(['cache_counts' => TRUE, 'cache_key' => 'test_key']);
$this->assertEquals(1, $source->count());
}
/**
* Test that we don't get a row if prepareRow() is false.
*/

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