Update to Drupal 8.2.5. For more information, see https://www.drupal.org/project/drupal/releases/8.2.5
This commit is contained in:
parent
8544b60b39
commit
db56c09587
|
@ -123,7 +123,6 @@ Color
|
|||
- ?
|
||||
|
||||
Comment
|
||||
- Dick Olsson 'dixon_' https://www.drupal.org/u/dixon_
|
||||
- Lee Rowlands 'larowlan' https://www.drupal.org/u/larowlan
|
||||
- Andrey Postnikov 'andypost' https://www.drupal.org/u/andypost
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ function drupal_get_schema_versions($module) {
|
|||
* module is not installed.
|
||||
*/
|
||||
function drupal_get_installed_schema_version($module, $reset = FALSE, $array = FALSE) {
|
||||
static $versions = array();
|
||||
$versions = &drupal_static(__FUNCTION__, array());
|
||||
|
||||
if ($reset) {
|
||||
$versions = array();
|
||||
|
|
|
@ -81,7 +81,7 @@ class Drupal {
|
|||
/**
|
||||
* The current system version.
|
||||
*/
|
||||
const VERSION = '8.2.4';
|
||||
const VERSION = '8.2.5';
|
||||
|
||||
/**
|
||||
* Core API compatibility.
|
||||
|
@ -556,8 +556,7 @@ class Drupal {
|
|||
* Renders a link with a given link text and Url object.
|
||||
*
|
||||
* This method is a convenience wrapper for the link generator service's
|
||||
* generate() method. For detailed documentation, see
|
||||
* \Drupal\Core\Routing\LinkGeneratorInterface::generate().
|
||||
* generate() method.
|
||||
*
|
||||
* @param string $text
|
||||
* The link text for the anchor tag.
|
||||
|
|
|
@ -11,6 +11,7 @@ use Drupal\Core\Render\Element;
|
|||
* Properties:
|
||||
* - #default_value: An array with the keys: 'year', 'month', and 'day'.
|
||||
* Defaults to the current date if no value is supplied.
|
||||
* - #size: The size of the input element in characters.
|
||||
*
|
||||
* @code
|
||||
* $form['expiration'] = array(
|
||||
|
|
|
@ -10,6 +10,7 @@ use Drupal\Core\Render\Element;
|
|||
*
|
||||
* Properties:
|
||||
* - #default_value: An RFC-compliant email address.
|
||||
* - #size: The size of the input element in characters.
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
|
|
|
@ -16,6 +16,7 @@ use Drupal\Component\Utility\Number as NumberUtility;
|
|||
* - #step: Ensures that the number is an even multiple of step, offset by #min
|
||||
* if specified. A #min of 1 and a #step of 2 would allow values of 1, 3, 5,
|
||||
* etc.
|
||||
* - #size: The size of the input element in characters.
|
||||
*
|
||||
* Usage example:
|
||||
* @code
|
||||
|
|
|
@ -8,6 +8,9 @@ use Drupal\Core\Render\Element;
|
|||
/**
|
||||
* Provides a form element for entering a password, with hidden text.
|
||||
*
|
||||
* Properties:
|
||||
* - #size: The size of the input element in characters.
|
||||
*
|
||||
* Usage example:
|
||||
* @code
|
||||
* $form['pass'] = array(
|
||||
|
|
|
@ -10,6 +10,9 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
* Formats as a pair of password fields, which do not validate unless the two
|
||||
* entered passwords match.
|
||||
*
|
||||
* Properties:
|
||||
* - #size: The size of the input element in characters.
|
||||
*
|
||||
* Usage example:
|
||||
* @code
|
||||
* $form['pass'] = array(
|
||||
|
|
|
@ -14,8 +14,31 @@ use Drupal\Core\Render\Element;
|
|||
* list. If a value is an array, it will be rendered similarly, but as an
|
||||
* optgroup. The key of the sub-array will be used as the label for the
|
||||
* optgroup. Nesting optgroups is not allowed.
|
||||
* - #empty_option: The label that will be displayed to denote no selection.
|
||||
* - #empty_value: The value of the option that is used to denote no selection.
|
||||
* - #empty_option: (optional) The label to show for the first default option.
|
||||
* By default, the label is automatically set to "- Select -" for a required
|
||||
* field and "- None -" for an optional field.
|
||||
* - #empty_value: (optional) The value for the first default option, which is
|
||||
* used to determine whether the user submitted a value or not.
|
||||
* - If #required is TRUE, this defaults to '' (an empty string).
|
||||
* - If #required is not TRUE and this value isn't set, then no extra option
|
||||
* is added to the select control, leaving the control in a slightly
|
||||
* illogical state, because there's no way for the user to select nothing,
|
||||
* since all user agents automatically preselect the first available
|
||||
* option. But people are used to this being the behavior of select
|
||||
* controls.
|
||||
* @todo Address the above issue in Drupal 8.
|
||||
* - If #required is not TRUE and this value is set (most commonly to an
|
||||
* empty string), then an extra option (see #empty_option above)
|
||||
* representing a "non-selection" is added with this as its value.
|
||||
* - #multiple: (optional) Indicates whether one or more options can be
|
||||
* selected. Defaults to FALSE.
|
||||
* - #default_value: Must be NULL or not set in case there is no value for the
|
||||
* element yet, in which case a first default option is inserted by default.
|
||||
* Whether this first option is a valid option depends on whether the field
|
||||
* is #required or not.
|
||||
* - #required: (optional) Whether the user needs to select an option (TRUE)
|
||||
* or not (FALSE). Defaults to FALSE.
|
||||
* - #size: The size of the input element in characters.
|
||||
*
|
||||
* Usage example:
|
||||
* @code
|
||||
|
@ -66,31 +89,7 @@ class Select extends FormElement {
|
|||
* select lists.
|
||||
*
|
||||
* @param array $element
|
||||
* The form element to process. Properties used:
|
||||
* - #multiple: (optional) Indicates whether one or more options can be
|
||||
* selected. Defaults to FALSE.
|
||||
* - #default_value: Must be NULL or not set in case there is no value for the
|
||||
* element yet, in which case a first default option is inserted by default.
|
||||
* Whether this first option is a valid option depends on whether the field
|
||||
* is #required or not.
|
||||
* - #required: (optional) Whether the user needs to select an option (TRUE)
|
||||
* or not (FALSE). Defaults to FALSE.
|
||||
* - #empty_option: (optional) The label to show for the first default option.
|
||||
* By default, the label is automatically set to "- Select -" for a required
|
||||
* field and "- None -" for an optional field.
|
||||
* - #empty_value: (optional) The value for the first default option, which is
|
||||
* used to determine whether the user submitted a value or not.
|
||||
* - If #required is TRUE, this defaults to '' (an empty string).
|
||||
* - If #required is not TRUE and this value isn't set, then no extra option
|
||||
* is added to the select control, leaving the control in a slightly
|
||||
* illogical state, because there's no way for the user to select nothing,
|
||||
* since all user agents automatically preselect the first available
|
||||
* option. But people are used to this being the behavior of select
|
||||
* controls.
|
||||
* @todo Address the above issue in Drupal 8.
|
||||
* - If #required is not TRUE and this value is set (most commonly to an
|
||||
* empty string), then an extra option (see #empty_option above)
|
||||
* representing a "non-selection" is added with this as its value.
|
||||
* The form element to process.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
* @param array $complete_form
|
||||
|
|
|
@ -24,6 +24,7 @@ use Drupal\Component\Utility\Html as HtmlUtility;
|
|||
* providing responsive tables. Defaults to TRUE.
|
||||
* - #sticky: Indicates whether to add the drupal.tableheader library that makes
|
||||
* table headers always visible at the top of the page. Defaults to FALSE.
|
||||
* - #size: The size of the input element in characters.
|
||||
*
|
||||
* Usage example:
|
||||
* @code
|
||||
|
|
|
@ -10,6 +10,9 @@ use Drupal\Core\Render\Element;
|
|||
* Provides an HTML5 input element with type of "tel". It provides no special
|
||||
* validation.
|
||||
*
|
||||
* Properties:
|
||||
* - #size: The size of the input element in characters.
|
||||
*
|
||||
* Usage example:
|
||||
* @code
|
||||
* $form['phone'] = array(
|
||||
|
|
|
@ -11,6 +11,7 @@ use Drupal\Core\Render\Element;
|
|||
*
|
||||
* Properties:
|
||||
* - #default_value: A valid URL string.
|
||||
* - #size: The size of the input element in characters.
|
||||
*
|
||||
* Usage example:
|
||||
* @code
|
||||
|
|
|
@ -254,13 +254,13 @@
|
|||
* form array, which specifies the form elements for an HTML form; see the
|
||||
* @link form_api Form generation topic @endlink for more information on forms.
|
||||
*
|
||||
* Render arrays (at each level in the hierarchy) will usually have one of the
|
||||
* following three properties defined:
|
||||
* Render arrays (at any level of the hierarchy) will usually have one of the
|
||||
* following properties defined:
|
||||
* - #type: Specifies that the array contains data and options for a particular
|
||||
* type of "render element" (examples: 'form', for an HTML form; 'textfield',
|
||||
* 'submit', and other HTML form element types; 'table', for a table with
|
||||
* rows, columns, and headers). See @ref elements below for more on render
|
||||
* element types.
|
||||
* type of "render element" (for example, 'form', for an HTML form;
|
||||
* 'textfield', 'submit', for HTML form element types; 'table', for a table
|
||||
* with rows, columns, and headers). See @ref elements below for more on
|
||||
* render element types.
|
||||
* - #theme: Specifies that the array contains data to be themed by a particular
|
||||
* theme hook. Modules define theme hooks by implementing hook_theme(), which
|
||||
* specifies the input "variables" used to provide data and options; if a
|
||||
|
@ -277,30 +277,29 @@
|
|||
* can customize the markup. Note that the value is passed through
|
||||
* \Drupal\Component\Utility\Xss::filterAdmin(), which strips known XSS
|
||||
* vectors while allowing a permissive list of HTML tags that are not XSS
|
||||
* vectors. (I.e, <script> and <style> are not allowed.) See
|
||||
* \Drupal\Component\Utility\Xss::$adminTags for the list of tags that will
|
||||
* be allowed. If your markup needs any of the tags that are not in this
|
||||
* whitelist, then you can implement a theme hook and template file and/or
|
||||
* an asset library. Aternatively, you can use the render array key
|
||||
* #allowed_tags to alter which tags are filtered.
|
||||
* vectors. (For example, <script> and <style> are not allowed.) See
|
||||
* \Drupal\Component\Utility\Xss::$adminTags for the list of allowed tags. If
|
||||
* your markup needs any of the tags not in this whitelist, then you can
|
||||
* implement a theme hook and/or an asset library. Alternatively, you can use
|
||||
* the key #allowed_tags to alter which tags are filtered.
|
||||
* - #plain_text: Specifies that the array provides text that needs to be
|
||||
* escaped. This value takes precedence over #markup if present.
|
||||
* - #allowed_tags: If #markup is supplied this can be used to change which tags
|
||||
* are using to filter the markup. The value should be an array of tags that
|
||||
* Xss::filter() would accept. If #plain_text is set this value is ignored.
|
||||
* escaped. This value takes precedence over #markup.
|
||||
* - #allowed_tags: If #markup is supplied, this can be used to change which
|
||||
* tags are allowed in the markup. The value is an array of tags that
|
||||
* Xss::filter() would accept. If #plain_text is set, this value is ignored.
|
||||
*
|
||||
* Usage example:
|
||||
* @code
|
||||
* $output['admin_filtered_string'] = array(
|
||||
* $output['admin_filtered_string'] = [
|
||||
* '#markup' => '<em>This is filtered using the admin tag list</em>',
|
||||
* );
|
||||
* $output['filtered_string'] = array(
|
||||
* '#markup' => '<em>This is filtered</em>',
|
||||
* '#allowed_tags' => ['strong'],
|
||||
* );
|
||||
* $output['escaped_string'] = array(
|
||||
* ];
|
||||
* $output['filtered_string'] = [
|
||||
* '#markup' => '<video><source src="v.webm" type="video/webm"></video>',
|
||||
* '#allowed_tags' => ['video', 'source'],
|
||||
* ];
|
||||
* $output['escaped_string'] = [
|
||||
* '#plain_text' => '<em>This is escaped</em>',
|
||||
* );
|
||||
* ];
|
||||
* @endcode
|
||||
*
|
||||
* @see core.libraries.yml
|
||||
|
|
|
@ -138,6 +138,12 @@ interface BigPipeInterface {
|
|||
* The HTML response content to send.
|
||||
* @param array $attachments
|
||||
* The HTML response's attachments.
|
||||
*
|
||||
* @internal
|
||||
* This method should only be invoked by
|
||||
* \Drupal\big_pipe\Render\BigPipeResponse, which is itself an internal
|
||||
* class. Furthermore, the signature of this method will change in
|
||||
* https://www.drupal.org/node/2657684.
|
||||
*/
|
||||
public function sendContent($content, array $attachments);
|
||||
|
||||
|
|
|
@ -13,7 +13,10 @@ use Drupal\Core\Render\HtmlResponse;
|
|||
*
|
||||
* @see \Drupal\big_pipe\Render\BigPipeInterface
|
||||
*
|
||||
* @todo Will become obsolete with https://www.drupal.org/node/2577631
|
||||
* @internal
|
||||
* This is a temporary solution until a generic response emitter interface is
|
||||
* created in https://www.drupal.org/node/2577631. Only code internal to
|
||||
* BigPipe should instantiate or type hint to this class.
|
||||
*/
|
||||
class BigPipeResponse extends HtmlResponse {
|
||||
|
||||
|
|
14
core/modules/ckeditor/js/ckeditor.js
vendored
14
core/modules/ckeditor/js/ckeditor.js
vendored
|
@ -273,6 +273,20 @@
|
|||
}
|
||||
});
|
||||
|
||||
// Redirect on hash change when the original hash has an associated CKEditor.
|
||||
function redirectTextareaFragmentToCKEditorInstance() {
|
||||
var hash = location.hash.substr(1);
|
||||
var element = document.getElementById(hash);
|
||||
if (element) {
|
||||
var editor = CKEDITOR.dom.element.get(element).getEditor();
|
||||
if (editor) {
|
||||
var id = editor.container.getAttribute('id');
|
||||
location.replace('#' + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
$(window).on('hashchange.ckeditor', redirectTextareaFragmentToCKEditorInstance);
|
||||
|
||||
// Set the CKEditor cache-busting string to the same value as Drupal.
|
||||
CKEDITOR.timestamp = drupalSettings.ckeditor.timestamp;
|
||||
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\ckeditor\FunctionalJavascript;
|
||||
|
||||
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||
use Drupal\editor\Entity\Editor;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\filter\Entity\FilterFormat;
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
|
||||
/**
|
||||
* Tests the integration of CKEditor.
|
||||
*
|
||||
* @group ckeditor
|
||||
*/
|
||||
class CKEditorIntegrationTest extends JavascriptTestBase {
|
||||
|
||||
/**
|
||||
* The account.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $account;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['node', 'ckeditor', 'filter'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create a text format and associate CKEditor.
|
||||
$filtered_html_format = FilterFormat::create([
|
||||
'format' => 'filtered_html',
|
||||
'name' => 'Filtered HTML',
|
||||
'weight' => 0,
|
||||
]);
|
||||
$filtered_html_format->save();
|
||||
|
||||
Editor::create([
|
||||
'format' => 'filtered_html',
|
||||
'editor' => 'ckeditor',
|
||||
])->save();
|
||||
|
||||
// Create a node type for testing.
|
||||
NodeType::create(['type' => 'page', 'name' => 'page'])->save();
|
||||
|
||||
$field_storage = FieldStorageConfig::loadByName('node', 'body');
|
||||
|
||||
// Create a body field instance for the 'page' node type.
|
||||
FieldConfig::create([
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => 'page',
|
||||
'label' => 'Body',
|
||||
'settings' => ['display_summary' => TRUE],
|
||||
'required' => TRUE,
|
||||
])->save();
|
||||
|
||||
// Assign widget settings for the 'default' form mode.
|
||||
EntityFormDisplay::create([
|
||||
'targetEntityType' => 'node',
|
||||
'bundle' => 'page',
|
||||
'mode' => 'default',
|
||||
'status' => TRUE,
|
||||
])->setComponent('body', ['type' => 'text_textarea_with_summary'])
|
||||
->save();
|
||||
|
||||
$this->account = $this->drupalCreateUser([
|
||||
'administer nodes',
|
||||
'create page content',
|
||||
'use text format filtered_html',
|
||||
]);
|
||||
$this->drupalLogin($this->account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the fragment link to a textarea works with CKEditor enabled.
|
||||
*/
|
||||
public function testFragmentLink() {
|
||||
$session = $this->getSession();
|
||||
$web_assert = $this->assertSession();
|
||||
$ckeditor_id = '#cke_edit-body-0-value';
|
||||
|
||||
$this->drupalGet('node/add/page');
|
||||
|
||||
$session->getPage();
|
||||
|
||||
// Add a bottom margin to the title field to be sure the body field is not
|
||||
// visible. PhantomJS runs with a resolution of 1024x768px.
|
||||
$session->executeScript("document.getElementById('edit-title-0-value').style.marginBottom = '800px';");
|
||||
|
||||
// Check that the CKEditor-enabled body field is currently not visible in
|
||||
// the viewport.
|
||||
$web_assert->assertNotVisibleInViewport('css', $ckeditor_id, 'topLeft', 'CKEditor-enabled body field is visible.');
|
||||
|
||||
$before_url = $session->getCurrentUrl();
|
||||
|
||||
// Trigger a hash change with as target the hidden textarea.
|
||||
$session->executeScript("location.hash = '#edit-body-0-value';");
|
||||
|
||||
// Check that the CKEditor-enabled body field is visible in the viewport.
|
||||
$web_assert->assertVisibleInViewport('css', $ckeditor_id, 'topLeft', 'CKEditor-enabled body field is not visible.');
|
||||
|
||||
// Use JavaScript to go back in the history instead of
|
||||
// \Behat\Mink\Session::back() because that function doesn't work after a
|
||||
// hash change.
|
||||
$session->executeScript("history.back();");
|
||||
|
||||
$after_url = $session->getCurrentUrl();
|
||||
|
||||
// Check that going back in the history worked.
|
||||
self::assertEquals($before_url, $after_url, 'History back works.');
|
||||
}
|
||||
|
||||
}
|
|
@ -36,3 +36,4 @@ migration_dependencies:
|
|||
optional:
|
||||
- d7_node_type
|
||||
- d7_comment_type
|
||||
- d7_taxonomy_vocabulary
|
||||
|
|
|
@ -96,13 +96,9 @@ function file_requirements($phase) {
|
|||
$value = t('Not enabled');
|
||||
$description = t('Your server is not capable of displaying file upload progress. File upload progress requires PHP be run with mod_php or PHP-FPM and not as FastCGI.');
|
||||
}
|
||||
elseif (!$implementation && extension_loaded('apcu')) {
|
||||
$value = t('Not enabled');
|
||||
$description = t('Your server is capable of displaying file upload progress through APC, but it is not enabled. Add <code>apc.rfc1867 = 1</code> to your php.ini configuration. Alternatively, it is recommended to use <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress</a>, which supports more than one simultaneous upload.');
|
||||
}
|
||||
elseif (!$implementation) {
|
||||
$value = t('Not enabled');
|
||||
$description = t('Your server is capable of displaying file upload progress, but does not have the required libraries. It is recommended to install the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library</a> (preferred) or to install <a href="http://php.net/apcu">APC</a>.');
|
||||
$description = t('Your server is capable of displaying file upload progress, but does not have the required libraries. It is recommended to install the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library</a>.');
|
||||
}
|
||||
elseif ($implementation == 'apc') {
|
||||
$value = t('Enabled (<a href="http://php.net/manual/apcu.configuration.php#ini.apcu.rfc1867">APC RFC1867</a>)');
|
||||
|
|
|
@ -929,7 +929,7 @@ function file_progress_implementation() {
|
|||
if (extension_loaded('uploadprogress')) {
|
||||
$implementation = 'uploadprogress';
|
||||
}
|
||||
elseif (extension_loaded('apc') && ini_get('apc.rfc1867')) {
|
||||
elseif (version_compare(PHP_VERSION, '7', '<') && extension_loaded('apc') && ini_get('apc.rfc1867')) {
|
||||
$implementation = 'apc';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -291,6 +291,21 @@ class FileWidget extends WidgetBase implements ContainerFactoryPluginInterface {
|
|||
return $new_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function extractFormValues(FieldItemListInterface $items, array $form, FormStateInterface $form_state) {
|
||||
parent::extractFormValues($items, $form, $form_state);
|
||||
|
||||
// Update reference to 'items' stored during upload to take into account
|
||||
// changes to values like 'alt' etc.
|
||||
// @see \Drupal\file\Plugin\Field\FieldWidget\FileWidget::submit()
|
||||
$field_name = $this->fieldDefinition->getName();
|
||||
$field_state = static::getWidgetState($form['#parents'], $field_name, $form_state);
|
||||
$field_state['items'] = $items->getValue();
|
||||
static::setWidgetState($form['#parents'], $field_name, $form_state, $field_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Form API callback. Retrieves the value for the file_generic field element.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
id: d7_filter_settings
|
||||
label: Drupal 7 filter settings
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- filter_fallback_format
|
||||
process:
|
||||
fallback_format: filter_fallback_format
|
||||
destination:
|
||||
plugin: config
|
||||
config_name: filter.settings
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\filter\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests migration of Filter's settings to configuration.
|
||||
*
|
||||
* @group filter
|
||||
*/
|
||||
class MigrateFilterSettingsTest extends MigrateDrupal7TestBase {
|
||||
|
||||
public static $modules = ['filter'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installConfig(static::$modules);
|
||||
$this->executeMigration('d7_filter_settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of Filter variables to configuration.
|
||||
*/
|
||||
public function testFilterSettings() {
|
||||
$this->assertSame('plain_text', $this->config('filter.settings')->get('fallback_format'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\inline_form_errors\FunctionalJavascript;
|
||||
|
||||
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||
use Drupal\editor\Entity\Editor;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\filter\Entity\FilterFormat;
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
|
||||
/**
|
||||
* Tests the inline errors fragment link to a CKEditor-enabled textarea.
|
||||
*
|
||||
* @group ckeditor
|
||||
*/
|
||||
class FormErrorHandlerCKEditorTest extends JavascriptTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['node', 'ckeditor', 'inline_form_errors', 'filter'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create a text format and associate CKEditor.
|
||||
$filtered_html_format = FilterFormat::create([
|
||||
'format' => 'filtered_html',
|
||||
'name' => 'Filtered HTML',
|
||||
'weight' => 0,
|
||||
]);
|
||||
$filtered_html_format->save();
|
||||
|
||||
Editor::create([
|
||||
'format' => 'filtered_html',
|
||||
'editor' => 'ckeditor',
|
||||
])->save();
|
||||
|
||||
// Create a node type for testing.
|
||||
NodeType::create(['type' => 'page', 'name' => 'page'])->save();
|
||||
|
||||
$field_storage = FieldStorageConfig::loadByName('node', 'body');
|
||||
|
||||
// Create a body field instance for the 'page' node type.
|
||||
FieldConfig::create([
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => 'page',
|
||||
'label' => 'Body',
|
||||
'settings' => ['display_summary' => TRUE],
|
||||
'required' => TRUE,
|
||||
])->save();
|
||||
|
||||
// Assign widget settings for the 'default' form mode.
|
||||
EntityFormDisplay::create([
|
||||
'targetEntityType' => 'node',
|
||||
'bundle' => 'page',
|
||||
'mode' => 'default',
|
||||
'status' => TRUE,
|
||||
])->setComponent('body', ['type' => 'text_textarea_with_summary'])
|
||||
->save();
|
||||
|
||||
$account = $this->drupalCreateUser([
|
||||
'administer nodes',
|
||||
'create page content',
|
||||
'use text format filtered_html',
|
||||
]);
|
||||
$this->drupalLogin($account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the fragment link to a textarea works with CKEditor enabled.
|
||||
*/
|
||||
public function testFragmentLink() {
|
||||
$session = $this->getSession();
|
||||
$web_assert = $this->assertSession();
|
||||
$ckeditor_id = '#cke_edit-body-0-value';
|
||||
|
||||
$this->drupalGet('node/add/page');
|
||||
|
||||
$page = $this->getSession()->getPage();
|
||||
|
||||
// Only enter a title in the node add form and leave the body field empty.
|
||||
$edit = ['edit-title-0-value' => 'Test inline form error with CKEditor'];
|
||||
|
||||
$this->submitForm($edit, 'Save and publish');
|
||||
|
||||
// Add a bottom margin to the title field to be sure the body field is not
|
||||
// visible. PhantomJS runs with a resolution of 1024x768px.
|
||||
$session->executeScript("document.getElementById('edit-title-0-value').style.marginBottom = '800px';");
|
||||
|
||||
// Check that the CKEditor-enabled body field is currently not visible in
|
||||
// the viewport.
|
||||
$web_assert->assertNotVisibleInViewport('css', $ckeditor_id, 'topLeft', 'CKEditor-enabled body field is not visible.');
|
||||
|
||||
// Check if we can find the error fragment link within the errors summary
|
||||
// message.
|
||||
$errors_link = $page->find('css', '.messages--error a[href=\#edit-body-0-value]');
|
||||
$this->assertTrue($errors_link->isVisible(), 'Error fragment link is visible.');
|
||||
|
||||
$errors_link->click();
|
||||
|
||||
// Check that the CKEditor-enabled body field is visible in the viewport.
|
||||
$web_assert->assertVisibleInViewport('css', $ckeditor_id, 'topLeft', 'CKEditor-enabled body field is visible.');
|
||||
}
|
||||
|
||||
}
|
|
@ -20,7 +20,7 @@ process:
|
|||
plugin: skip_on_empty
|
||||
method: row
|
||||
'link/uri':
|
||||
plugin: d7_internal_uri
|
||||
plugin: link_uri
|
||||
source:
|
||||
- link_path
|
||||
'link/options': options
|
||||
|
|
|
@ -63,6 +63,9 @@ class LinkUri extends ProcessPluginBase implements ContainerFactoryPluginInterfa
|
|||
$path = ltrim($path, '/');
|
||||
|
||||
if (parse_url($path, PHP_URL_SCHEME) === NULL) {
|
||||
if ($path == '<front>') {
|
||||
$path = '';
|
||||
}
|
||||
$path = 'internal:/' . $path;
|
||||
|
||||
// Convert entity URIs to the entity scheme, if the path matches a route
|
||||
|
|
|
@ -2,42 +2,12 @@
|
|||
|
||||
namespace Drupal\menu_link_content\Plugin\migrate\process\d7;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\menu_link_content\Plugin\migrate\process\LinkUri;
|
||||
|
||||
/**
|
||||
* Process a path into an 'internal:' URI.
|
||||
* Processes an internal uri into an 'internal:' or 'entity:' URI.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "d7_internal_uri"
|
||||
* )
|
||||
* @deprecated in Drupal 8.2.0, will be removed before Drupal 9.0.0. Use
|
||||
* \Drupal\menu_link_content\Plugin\migrate\process\LinkUri instead.
|
||||
*/
|
||||
class InternalUri extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($path) = $value;
|
||||
$path = ltrim($path, '/');
|
||||
|
||||
if (parse_url($path, PHP_URL_SCHEME) == NULL) {
|
||||
// If $path is the node page (i.e. node/[nid]) then return entity path.
|
||||
if (preg_match('/^node\/\d+$/', $path)) {
|
||||
// "entity: URI"s enable the menu link to appear in the Menu Settings
|
||||
// section on the node edit page. Other entities (e.g. taxonomy terms,
|
||||
// users) do not have the Menu Settings section.
|
||||
return 'entity:' . $path;
|
||||
}
|
||||
elseif ($path == '<front>') {
|
||||
return 'internal:/';
|
||||
}
|
||||
else {
|
||||
return 'internal:/' . $path;
|
||||
}
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
}
|
||||
class InternalUri extends LinkUri {}
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Drupal\Tests\menu_link_content\Kernel\Migrate\d7;
|
|||
use Drupal\Core\Menu\MenuTreeParameters;
|
||||
use Drupal\menu_link_content\Entity\MenuLinkContent;
|
||||
use Drupal\menu_link_content\MenuLinkContentInterface;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
|
@ -18,7 +19,7 @@ class MigrateMenuLinkTest extends MigrateDrupal7TestBase {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = array('link', 'menu_ui', 'menu_link_content');
|
||||
public static $modules = array('link', 'menu_ui', 'menu_link_content', 'node');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -26,6 +27,13 @@ class MigrateMenuLinkTest extends MigrateDrupal7TestBase {
|
|||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('menu_link_content');
|
||||
$this->installEntitySchema('node');
|
||||
$node = Node::create([
|
||||
'nid' => 3,
|
||||
'title' => 'node link test',
|
||||
'type' => 'article',
|
||||
]);
|
||||
$node->save();
|
||||
$this->executeMigrations(['d7_menu', 'd7_menu_links']);
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
}
|
||||
|
|
|
@ -117,6 +117,10 @@ class LinkUriTest extends UnitTestCase {
|
|||
$expected = 'internal:/test';
|
||||
$tests['without_scheme'] = [$value, $expected];
|
||||
|
||||
$value = ['<front>'];
|
||||
$expected = 'internal:/';
|
||||
$tests['front'] = [$value, $expected];
|
||||
|
||||
$url = Url::fromRoute('route_name');
|
||||
$tests['with_route'] = [$value, $expected, $url];
|
||||
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\menu_link_content\Unit\Plugin\migrate\process\d7;
|
||||
|
||||
use Drupal\menu_link_content\Plugin\migrate\process\d7\InternalUri;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* Tests \Drupal\menu_link_content\Plugin\migrate\process\d7\InternalUri.
|
||||
*
|
||||
* @group menu_link_content
|
||||
*
|
||||
* @coversDefaultClass \Drupal\menu_link_content\Plugin\migrate\process\d7\InternalUri
|
||||
*/
|
||||
class InternalUriTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The 'd7_internal_uri' process plugin being tested.
|
||||
*
|
||||
* @var \Drupal\menu_link_content\Plugin\migrate\process\d7\InternalUri
|
||||
*/
|
||||
protected $processPlugin;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->processPlugin = new InternalUri([], 'd7_internal_uri', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests InternalUri::transform().
|
||||
*
|
||||
* @param array $value
|
||||
* The value to pass to InternalUri::transform().
|
||||
* @param string $expected
|
||||
* The expected return value of InternalUri::transform().
|
||||
*
|
||||
* @dataProvider providerTestTransform
|
||||
*
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransform(array $value, $expected) {
|
||||
$migrate_executable = $this->prophesize(MigrateExecutableInterface::class);
|
||||
$row = $this->prophesize(Row::class);
|
||||
|
||||
$actual = $this->processPlugin->transform($value, $migrate_executable->reveal(), $row->reveal(), 'link/uri');
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test cases for InternalUriTest::testTransform().
|
||||
*
|
||||
* @return array
|
||||
* An array of test cases, each which the following values:
|
||||
* - The value array to pass to InternalUri::transform().
|
||||
* - The expected path returned by InternalUri::transform().
|
||||
*/
|
||||
public function providerTestTransform() {
|
||||
$tests = [];
|
||||
$tests['with_scheme'] = [['http://example.com'], 'http://example.com'];
|
||||
$tests['leading_slash'] = [['/test'], 'internal:/test'];
|
||||
$tests['without_scheme'] = [['test'], 'internal:/test'];
|
||||
$tests['front'] = [['<front>'], 'internal:/'];
|
||||
$tests['node'] = [['node/27'], 'entity:node/27'];
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
|
@ -108,8 +108,13 @@ class Download extends ProcessPluginBase implements ContainerFactoryPluginInterf
|
|||
// Stream the request body directly to the final destination stream.
|
||||
$this->configuration['guzzle_options']['sink'] = $destination_stream;
|
||||
|
||||
// Make the request. Guzzle throws an exception for anything other than 200.
|
||||
$this->httpClient->get($source, $this->configuration['guzzle_options']);
|
||||
try {
|
||||
// Make the request. Guzzle throws an exception for anything but 200.
|
||||
$this->httpClient->get($source, $this->configuration['guzzle_options']);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
throw new MigrateException("{$e->getMessage()} ($source)");
|
||||
}
|
||||
|
||||
return $final_destination;
|
||||
}
|
||||
|
|
|
@ -112,20 +112,17 @@ class FileCopy extends ProcessPluginBase implements ContainerFactoryPluginInterf
|
|||
return $destination;
|
||||
}
|
||||
|
||||
$replace = $this->getOverwriteMode();
|
||||
// We attempt the copy/move first to avoid calling file_prepare_directory()
|
||||
// any more than absolutely necessary.
|
||||
$final_destination = $this->writeFile($source, $destination, $replace);
|
||||
if ($final_destination) {
|
||||
return $final_destination;
|
||||
}
|
||||
// If writeFile didn't work, make sure there's a writable directory in
|
||||
// place.
|
||||
// Check if a writable directory exists, and if not try to create it.
|
||||
$dir = $this->getDirectory($destination);
|
||||
if (!file_prepare_directory($dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
|
||||
throw new MigrateException("Could not create or write to directory '$dir'");
|
||||
// If the directory exists and is writable, avoid file_prepare_directory()
|
||||
// call and write the file to destination.
|
||||
if (!is_dir($dir) || !is_writable($dir)) {
|
||||
if (!file_prepare_directory($dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
|
||||
throw new MigrateException("Could not create or write to directory '$dir'");
|
||||
}
|
||||
}
|
||||
$final_destination = $this->writeFile($source, $destination, $replace);
|
||||
|
||||
$final_destination = $this->writeFile($source, $destination, $this->getOverwriteMode());
|
||||
if ($final_destination) {
|
||||
return $final_destination;
|
||||
}
|
||||
|
|
|
@ -22,15 +22,17 @@ class Iterator extends ProcessPluginBase {
|
|||
* Runs a process pipeline on each destination property per list item.
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
$return = array();
|
||||
foreach ($value as $key => $new_value) {
|
||||
$new_row = new Row($new_value, array());
|
||||
$migrate_executable->processRow($new_row, $this->configuration['process']);
|
||||
$destination = $new_row->getDestination();
|
||||
if (array_key_exists('key', $this->configuration)) {
|
||||
$key = $this->transformKey($key, $migrate_executable, $new_row);
|
||||
$return = [];
|
||||
if (!is_null($value)) {
|
||||
foreach ($value as $key => $new_value) {
|
||||
$new_row = new Row($new_value, []);
|
||||
$migrate_executable->processRow($new_row, $this->configuration['process']);
|
||||
$destination = $new_row->getDestination();
|
||||
if (array_key_exists('key', $this->configuration)) {
|
||||
$key = $this->transformKey($key, $migrate_executable, $new_row);
|
||||
}
|
||||
$return[$key] = $destination;
|
||||
}
|
||||
$return[$key] = $destination;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
|
|
@ -310,13 +310,13 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
while (!isset($this->currentRow) && $this->getIterator()->valid()) {
|
||||
|
||||
$row_data = $this->getIterator()->current() + $this->configuration;
|
||||
$this->getIterator()->next();
|
||||
$this->fetchNextRow();
|
||||
$row = new Row($row_data, $this->migration->getSourcePlugin()->getIds(), $this->migration->getDestinationIds());
|
||||
|
||||
// Populate the source key for this row.
|
||||
$this->currentSourceIds = $row->getSourceIdValues();
|
||||
|
||||
// Pick up the existing map row, if any, unless getNextRow() did it.
|
||||
// Pick up the existing map row, if any, unless fetchNextRow() did it.
|
||||
if (!$this->mapRowAdded && ($id_map = $this->idMap->getRowBySource($this->currentSourceIds))) {
|
||||
$row->setIdMap($id_map);
|
||||
}
|
||||
|
@ -348,7 +348,14 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks if the incoming data is newer than what we've previously imported.
|
||||
* Position the iterator to the following row.
|
||||
*/
|
||||
protected function fetchNextRow() {
|
||||
$this->getIterator()->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the incoming data is newer than what we've previously imported.
|
||||
*
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row we're importing.
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Drupal\migrate\Plugin\migrate\source;
|
|||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\State\StateInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\Plugin\migrate\id_map\Sql;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
|
@ -42,6 +43,22 @@ abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPlugi
|
|||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* The count of the number of batches run.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $batch = 0;
|
||||
|
||||
/**
|
||||
* Number of records to fetch from the database during each batch.
|
||||
*
|
||||
* A value of zero indicates no batching is to be done.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $batchSize = 0;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -160,70 +177,110 @@ abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPlugi
|
|||
* we will take advantage of the PDO-based API to optimize the query up-front.
|
||||
*/
|
||||
protected function initializeIterator() {
|
||||
$this->prepareQuery();
|
||||
// Initialize the batch size.
|
||||
if ($this->batchSize == 0 && isset($this->configuration['batch_size'])) {
|
||||
// Valid batch sizes are integers >= 0.
|
||||
if (is_int($this->configuration['batch_size']) && ($this->configuration['batch_size']) >= 0) {
|
||||
$this->batchSize = $this->configuration['batch_size'];
|
||||
}
|
||||
else {
|
||||
throw new MigrateException("batch_size must be greater than or equal to zero");
|
||||
}
|
||||
}
|
||||
|
||||
// Get the key values, for potential use in joining to the map table.
|
||||
$keys = array();
|
||||
// If a batch has run the query is already setup.
|
||||
if ($this->batch == 0) {
|
||||
$this->prepareQuery();
|
||||
|
||||
// The rules for determining what conditions to add to the query are as
|
||||
// follows (applying first applicable rule):
|
||||
// 1. If the map is joinable, join it. We will want to accept all rows
|
||||
// which are either not in the map, or marked in the map as NEEDS_UPDATE.
|
||||
// Note that if high water fields are in play, we want to accept all rows
|
||||
// above the high water mark in addition to those selected by the map
|
||||
// conditions, so we need to OR them together (but AND with any existing
|
||||
// conditions in the query). So, ultimately the SQL condition will look
|
||||
// like (original conditions) AND (map IS NULL OR map needs update
|
||||
// OR above high water).
|
||||
$conditions = $this->query->orConditionGroup();
|
||||
$condition_added = FALSE;
|
||||
if (empty($this->configuration['ignore_map']) && $this->mapJoinable()) {
|
||||
// Build the join to the map table. Because the source key could have
|
||||
// multiple fields, we need to build things up.
|
||||
$count = 1;
|
||||
$map_join = '';
|
||||
$delimiter = '';
|
||||
foreach ($this->getIds() as $field_name => $field_schema) {
|
||||
if (isset($field_schema['alias'])) {
|
||||
$field_name = $field_schema['alias'] . '.' . $this->query->escapeField($field_name);
|
||||
// Get the key values, for potential use in joining to the map table.
|
||||
$keys = array();
|
||||
|
||||
// The rules for determining what conditions to add to the query are as
|
||||
// follows (applying first applicable rule):
|
||||
// 1. If the map is joinable, join it. We will want to accept all rows
|
||||
// which are either not in the map, or marked in the map as NEEDS_UPDATE.
|
||||
// Note that if high water fields are in play, we want to accept all rows
|
||||
// above the high water mark in addition to those selected by the map
|
||||
// conditions, so we need to OR them together (but AND with any existing
|
||||
// conditions in the query). So, ultimately the SQL condition will look
|
||||
// like (original conditions) AND (map IS NULL OR map needs update
|
||||
// OR above high water).
|
||||
$conditions = $this->query->orConditionGroup();
|
||||
$condition_added = FALSE;
|
||||
if (empty($this->configuration['ignore_map']) && $this->mapJoinable()) {
|
||||
// Build the join to the map table. Because the source key could have
|
||||
// multiple fields, we need to build things up.
|
||||
$count = 1;
|
||||
$map_join = '';
|
||||
$delimiter = '';
|
||||
foreach ($this->getIds() as $field_name => $field_schema) {
|
||||
if (isset($field_schema['alias'])) {
|
||||
$field_name = $field_schema['alias'] . '.' . $this->query->escapeField($field_name);
|
||||
}
|
||||
$map_join .= "$delimiter$field_name = map.sourceid" . $count++;
|
||||
$delimiter = ' AND ';
|
||||
}
|
||||
$map_join .= "$delimiter$field_name = map.sourceid" . $count++;
|
||||
$delimiter = ' AND ';
|
||||
}
|
||||
|
||||
$alias = $this->query->leftJoin($this->migration->getIdMap()->getQualifiedMapTableName(), 'map', $map_join);
|
||||
$conditions->isNull($alias . '.sourceid1');
|
||||
$conditions->condition($alias . '.source_row_status', MigrateIdMapInterface::STATUS_NEEDS_UPDATE);
|
||||
$condition_added = TRUE;
|
||||
$alias = $this->query->leftJoin($this->migration->getIdMap()
|
||||
->getQualifiedMapTableName(), 'map', $map_join);
|
||||
$conditions->isNull($alias . '.sourceid1');
|
||||
$conditions->condition($alias . '.source_row_status', MigrateIdMapInterface::STATUS_NEEDS_UPDATE);
|
||||
$condition_added = TRUE;
|
||||
|
||||
// And as long as we have the map table, add its data to the row.
|
||||
$n = count($this->getIds());
|
||||
for ($count = 1; $count <= $n; $count++) {
|
||||
$map_key = 'sourceid' . $count;
|
||||
$this->query->addField($alias, $map_key, "migrate_map_$map_key");
|
||||
}
|
||||
if ($n = count($this->migration->getDestinationIds())) {
|
||||
// And as long as we have the map table, add its data to the row.
|
||||
$n = count($this->getIds());
|
||||
for ($count = 1; $count <= $n; $count++) {
|
||||
$map_key = 'destid' . $count++;
|
||||
$map_key = 'sourceid' . $count;
|
||||
$this->query->addField($alias, $map_key, "migrate_map_$map_key");
|
||||
}
|
||||
if ($n = count($this->migration->getDestinationIds())) {
|
||||
for ($count = 1; $count <= $n; $count++) {
|
||||
$map_key = 'destid' . $count++;
|
||||
$this->query->addField($alias, $map_key, "migrate_map_$map_key");
|
||||
}
|
||||
}
|
||||
$this->query->addField($alias, 'source_row_status', 'migrate_map_source_row_status');
|
||||
}
|
||||
// 2. If we are using high water marks, also include rows above the mark.
|
||||
// But, include all rows if the high water mark is not set.
|
||||
if ($this->getHighWaterProperty() && ($high_water = $this->getHighWater()) !== '') {
|
||||
$high_water_field = $this->getHighWaterField();
|
||||
$conditions->condition($high_water_field, $high_water, '>');
|
||||
$this->query->orderBy($high_water_field);
|
||||
}
|
||||
if ($condition_added) {
|
||||
$this->query->condition($conditions);
|
||||
}
|
||||
$this->query->addField($alias, 'source_row_status', 'migrate_map_source_row_status');
|
||||
}
|
||||
// 2. If we are using high water marks, also include rows above the mark.
|
||||
// But, include all rows if the high water mark is not set.
|
||||
if ($this->getHighWaterProperty() && ($high_water = $this->getHighWater()) !== '') {
|
||||
$high_water_field = $this->getHighWaterField();
|
||||
$conditions->condition($high_water_field, $high_water, '>');
|
||||
$this->query->orderBy($high_water_field);
|
||||
}
|
||||
if ($condition_added) {
|
||||
$this->query->condition($conditions);
|
||||
}
|
||||
|
||||
// Download data in batches for performance.
|
||||
if (($this->batchSize > 0)) {
|
||||
$this->query->range($this->batch * $this->batchSize, $this->batchSize);
|
||||
}
|
||||
return new \IteratorIterator($this->query->execute());
|
||||
}
|
||||
|
||||
/**
|
||||
* Position the iterator to the following row.
|
||||
*/
|
||||
protected function fetchNextRow() {
|
||||
$this->getIterator()->next();
|
||||
// We might be out of data entirely, or just out of data in the current
|
||||
// batch. Attempt to fetch the next batch and see.
|
||||
if ($this->batchSize > 0 && !$this->getIterator()->valid()) {
|
||||
$this->fetchNextBatch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares query for the next set of data from the source database.
|
||||
*/
|
||||
protected function fetchNextBatch() {
|
||||
$this->batch++;
|
||||
unset($this->iterator);
|
||||
$this->getIterator()->rewind();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Drupal\Core\Database\Query\SelectInterface
|
||||
*/
|
||||
|
@ -249,6 +306,14 @@ abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPlugi
|
|||
if (!$this->getIds()) {
|
||||
return FALSE;
|
||||
}
|
||||
// With batching, we want a later batch to return the same rows that would
|
||||
// have been returned at the same point within a monolithic query. If we
|
||||
// join to the map table, the first batch is writing to the map table and
|
||||
// thus affecting the results of subsequent batches. To be safe, we avoid
|
||||
// joining to the map table when batching.
|
||||
if ($this->batchSize > 0) {
|
||||
return FALSE;
|
||||
}
|
||||
$id_map = $this->migration->getIdMap();
|
||||
if (!$id_map instanceof Sql) {
|
||||
return FALSE;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
type: module
|
||||
name: Migrate query batch Source test
|
||||
description: 'Provides a database table and records for SQL import with batch testing.'
|
||||
package: Testing
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- migrate
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate_query_batch_test\Plugin\migrate\source;
|
||||
|
||||
use Drupal\migrate\Plugin\migrate\source\SqlBase;
|
||||
|
||||
/**
|
||||
* Source plugin for migration high water tests.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "query_batch_test"
|
||||
* )
|
||||
*/
|
||||
class QueryBatchTest extends SqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
return ($this->select('query_batch_test', 'q')->fields('q'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
$fields = [
|
||||
'id' => $this->t('Id'),
|
||||
'data' => $this->t('data'),
|
||||
];
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
return [
|
||||
'id' => [
|
||||
'type' => 'integer',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\migrate\Functional\process;
|
||||
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate\MigrateMessage;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the 'download' process plugin.
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class DownloadFunctionalTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['migrate', 'file'];
|
||||
|
||||
/**
|
||||
* Tests that an exception is thrown bu migration continues with the next row.
|
||||
*/
|
||||
public function testExceptionThrow() {
|
||||
$invalid_url = "{$this->baseUrl}/not-existent-404";
|
||||
$valid_url = "{$this->baseUrl}/core/misc/favicon.ico";
|
||||
|
||||
$definition = [
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => [
|
||||
['url' => $invalid_url, 'uri' => 'public://first.txt'],
|
||||
['url' => $valid_url, 'uri' => 'public://second.ico'],
|
||||
],
|
||||
'ids' => [
|
||||
'url' => ['type' => 'string'],
|
||||
],
|
||||
],
|
||||
'process' => [
|
||||
'uri' => [
|
||||
'plugin' => 'download',
|
||||
'source' => ['url', 'uri'],
|
||||
]
|
||||
],
|
||||
'destination' => [
|
||||
'plugin' => 'entity:file',
|
||||
],
|
||||
];
|
||||
|
||||
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration($definition);
|
||||
|
||||
$executable = new MigrateExecutable($migration, new MigrateMessage());
|
||||
$result = $executable->import();
|
||||
|
||||
// Check that the migration has completed.
|
||||
$this->assertEquals($result, MigrationInterface::RESULT_COMPLETED);
|
||||
|
||||
/** @var \Drupal\migrate\Plugin\MigrateIdMapInterface $id_map_plugin */
|
||||
$id_map_plugin = $migration->getIdMap();
|
||||
|
||||
// Check that the first row was marked as failed in the id map table.
|
||||
$map_row = $id_map_plugin->getRowBySource(['url' => $invalid_url]);
|
||||
$this->assertEquals(MigrateIdMapInterface::STATUS_FAILED, $map_row['source_row_status']);
|
||||
$this->assertNull($map_row['destid1']);
|
||||
|
||||
// Check that a message with the thrown exception has been logged.
|
||||
$messages = $id_map_plugin->getMessageIterator(['url' => $invalid_url])->fetchAll();
|
||||
$this->assertCount(1, $messages);
|
||||
$message = reset($messages);
|
||||
$this->assertEquals("Cannot read from non-readable stream ($invalid_url)", $message->message);
|
||||
$this->assertEquals(MigrationInterface::MESSAGE_ERROR, $message->level);
|
||||
|
||||
// Check that the second row was migrated successfully.
|
||||
$map_row = $id_map_plugin->getRowBySource(['url' => $valid_url]);
|
||||
$this->assertEquals(MigrateIdMapInterface::STATUS_IMPORTED, $map_row['source_row_status']);
|
||||
$this->assertEquals(1, $map_row['destid1']);
|
||||
}
|
||||
|
||||
}
|
261
core/modules/migrate/tests/src/Kernel/QueryBatchTest.php
Normal file
261
core/modules/migrate/tests/src/Kernel/QueryBatchTest.php
Normal file
|
@ -0,0 +1,261 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\migrate\Kernel;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\Core\Database\Driver\sqlite\Connection;
|
||||
|
||||
/**
|
||||
* Tests query batching.
|
||||
*
|
||||
* @covers \Drupal\migrate_query_batch_test\Plugin\migrate\source\QueryBatchTest
|
||||
* @group migrate
|
||||
*/
|
||||
class QueryBatchTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* The mocked migration.
|
||||
*
|
||||
* @var MigrationInterface|\Prophecy\Prophecy\ObjectProphecy
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'migrate',
|
||||
'migrate_query_batch_test',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create a mock migration. This will be injected into the source plugin
|
||||
// under test.
|
||||
$this->migration = $this->prophesize(MigrationInterface::class);
|
||||
|
||||
$this->migration->id()->willReturn(
|
||||
$this->randomMachineName(16)
|
||||
);
|
||||
// Prophesize a useless ID map plugin and an empty set of destination IDs.
|
||||
// Calling code can override these prophecies later and set up different
|
||||
// behaviors.
|
||||
$this->migration->getIdMap()->willReturn(
|
||||
$this->prophesize(MigrateIdMapInterface::class)->reveal()
|
||||
);
|
||||
$this->migration->getDestinationIds()->willReturn([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a negative batch size throws an exception.
|
||||
*/
|
||||
public function testBatchSizeNegative() {
|
||||
$this->setExpectedException(MigrateException::class, 'batch_size must be greater than or equal to zero');
|
||||
$plugin = $this->getPlugin(['batch_size' => -1]);
|
||||
$plugin->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a non integer batch size throws an exception.
|
||||
*/
|
||||
public function testBatchSizeNonInteger() {
|
||||
$this->setExpectedException(MigrateException::class, 'batch_size must be greater than or equal to zero');
|
||||
$plugin = $this->getPlugin(['batch_size' => '1']);
|
||||
$plugin->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function queryDataProvider() {
|
||||
// Define the parameters for building the data array. The first element is
|
||||
// the number of source data rows, the second is the batch size to set on
|
||||
// the plugin configuration.
|
||||
$test_parameters = [
|
||||
// Test when batch size is 0.
|
||||
[200, 0],
|
||||
// Test when rows mod batch size is 0.
|
||||
[200, 20],
|
||||
// Test when rows mod batch size is > 0.
|
||||
[200, 30],
|
||||
// Test when batch size = row count.
|
||||
[200, 200],
|
||||
// Test when batch size > row count.
|
||||
[200, 300],
|
||||
];
|
||||
|
||||
// Build the data provider array. The provider array consists of the source
|
||||
// data rows, the expected result data, the expected count, the plugin
|
||||
// configuration, the expected batch size and the expected batch count.
|
||||
$table = 'query_batch_test';
|
||||
$tests = [];
|
||||
$data_set = 0;
|
||||
foreach ($test_parameters as $data) {
|
||||
list($num_rows, $batch_size) = $data;
|
||||
for ($i = 0; $i < $num_rows; $i++) {
|
||||
$tests[$data_set]['source_data'][$table][] = [
|
||||
'id' => $i,
|
||||
'data' => $this->randomString(),
|
||||
];
|
||||
}
|
||||
$tests[$data_set]['expected_data'] = $tests[$data_set]['source_data'][$table];
|
||||
$tests[$data_set][2] = $num_rows;
|
||||
// Plugin configuration array.
|
||||
$tests[$data_set][3] = ['batch_size' => $batch_size];
|
||||
// Expected batch size.
|
||||
$tests[$data_set][4] = $batch_size;
|
||||
// Expected batch count is 0 unless a batch size is set.
|
||||
$expected_batch_count = 0;
|
||||
if ($batch_size > 0) {
|
||||
$expected_batch_count = (int) ($num_rows / $batch_size);
|
||||
if ($num_rows % $batch_size) {
|
||||
// If there is a remainder an extra batch is needed to get the
|
||||
// remaining rows.
|
||||
$expected_batch_count++;
|
||||
}
|
||||
}
|
||||
$tests[$data_set][5] = $expected_batch_count;
|
||||
$data_set++;
|
||||
}
|
||||
return $tests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests query batch size.
|
||||
*
|
||||
* @param array $source_data
|
||||
* The source data, keyed by table name. Each table is an array containing
|
||||
* the rows in that table.
|
||||
* @param array $expected_data
|
||||
* The result rows the plugin is expected to return.
|
||||
* @param int $num_rows
|
||||
* How many rows the source plugin is expected to return.
|
||||
* @param array $configuration
|
||||
* Configuration for the source plugin specifying the batch size.
|
||||
* @param int $expected_batch_size
|
||||
* The expected batch size, will be set to zero for invalid batch sizes.
|
||||
* @param int $expected_batch_count
|
||||
* The total number of batches.
|
||||
*
|
||||
* @dataProvider queryDataProvider
|
||||
*/
|
||||
public function testQueryBatch($source_data, $expected_data, $num_rows, $configuration, $expected_batch_size, $expected_batch_count) {
|
||||
$plugin = $this->getPlugin($configuration);
|
||||
|
||||
// Since we don't yet inject the database connection, we need to use a
|
||||
// reflection hack to set it in the plugin instance.
|
||||
$reflector = new \ReflectionObject($plugin);
|
||||
$property = $reflector->getProperty('database');
|
||||
$property->setAccessible(TRUE);
|
||||
|
||||
$connection = $this->getDatabase($source_data);
|
||||
$property->setValue($plugin, $connection);
|
||||
|
||||
// Test the results.
|
||||
$i = 0;
|
||||
/** @var \Drupal\migrate\Row $row */
|
||||
foreach ($plugin as $row) {
|
||||
|
||||
$expected = $expected_data[$i++];
|
||||
$actual = $row->getSource();
|
||||
|
||||
foreach ($expected as $key => $value) {
|
||||
$this->assertArrayHasKey($key, $actual);
|
||||
$this->assertSame((string) $value, (string) $actual[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that all rows were retrieved.
|
||||
self::assertSame($num_rows, $i);
|
||||
|
||||
// Test the batch size.
|
||||
if (is_null($expected_batch_size)) {
|
||||
$expected_batch_size = $configuration['batch_size'];
|
||||
}
|
||||
$property = $reflector->getProperty('batchSize');
|
||||
$property->setAccessible(TRUE);
|
||||
self::assertSame($expected_batch_size, $property->getValue($plugin));
|
||||
|
||||
// Test the batch count.
|
||||
if (is_null($expected_batch_count)) {
|
||||
$expected_batch_count = intdiv($num_rows, $expected_batch_size);
|
||||
if ($num_rows % $configuration['batch_size']) {
|
||||
$expected_batch_count++;
|
||||
}
|
||||
}
|
||||
$property = $reflector->getProperty('batch');
|
||||
$property->setAccessible(TRUE);
|
||||
self::assertSame($expected_batch_count, $property->getValue($plugin));
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates the source plugin under test.
|
||||
*
|
||||
* @param array $configuration
|
||||
* The source plugin configuration.
|
||||
*
|
||||
* @return \Drupal\migrate\Plugin\MigrateSourceInterface|object
|
||||
* The fully configured source plugin.
|
||||
*/
|
||||
protected function getPlugin($configuration) {
|
||||
/** @var \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager */
|
||||
$plugin_manager = $this->container->get('plugin.manager.migrate.source');
|
||||
$plugin = $plugin_manager->createInstance('query_batch_test', $configuration, $this->migration->reveal());
|
||||
|
||||
$this->migration
|
||||
->getSourcePlugin()
|
||||
->willReturn($plugin);
|
||||
return $plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an in-memory SQLite database from a set of source data.
|
||||
*
|
||||
* @param array $source_data
|
||||
* The source data, keyed by table name. Each table is an array containing
|
||||
* the rows in that table.
|
||||
*
|
||||
* @return \Drupal\Core\Database\Driver\sqlite\Connection
|
||||
* The SQLite database connection.
|
||||
*/
|
||||
protected function getDatabase(array $source_data) {
|
||||
// Create an in-memory SQLite database. Plugins can interact with it like
|
||||
// any other database, and it will cease to exist when the connection is
|
||||
// closed.
|
||||
$connection_options = ['database' => ':memory:'];
|
||||
$pdo = Connection::open($connection_options);
|
||||
$connection = new Connection($pdo, $connection_options);
|
||||
|
||||
// Create the tables and fill them with data.
|
||||
foreach ($source_data as $table => $rows) {
|
||||
// Use the biggest row to build the table schema.
|
||||
$counts = array_map('count', $rows);
|
||||
asort($counts);
|
||||
end($counts);
|
||||
$pilot = $rows[key($counts)];
|
||||
|
||||
$connection->schema()
|
||||
->createTable($table, [
|
||||
// SQLite uses loose affinity typing, so it's OK for every field to
|
||||
// be a text field.
|
||||
'fields' => array_map(function () {
|
||||
return ['type' => 'text'];
|
||||
}, $pilot),
|
||||
]);
|
||||
|
||||
$fields = array_keys($pilot);
|
||||
$insert = $connection->insert($table)->fields($fields);
|
||||
array_walk($rows, [$insert, 'values']);
|
||||
$insert->execute();
|
||||
}
|
||||
return $connection;
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,7 @@ namespace Drupal\Tests\migrate\Kernel\process;
|
|||
|
||||
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
|
||||
use Drupal\KernelTests\Core\File\FileTestBase;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Plugin\migrate\process\FileCopy;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Plugin\MigrateProcessInterface;
|
||||
|
@ -12,6 +13,8 @@ use Drupal\migrate\Row;
|
|||
/**
|
||||
* Tests the file_copy process plugin.
|
||||
*
|
||||
* @coversDefaultClass \Drupal\migrate\Plugin\migrate\process\FileCopy
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class FileCopyTest extends FileTestBase {
|
||||
|
@ -120,6 +123,32 @@ class FileCopyTest extends FileTestBase {
|
|||
$this->doTransform($source, 'public://wontmatter.jpg');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that non-writable destination throw an exception.
|
||||
*
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testNonWritableDestination() {
|
||||
$source = $this->createUri('file.txt', NULL, 'temporary');
|
||||
|
||||
// Create the parent location.
|
||||
$this->createDirectory('public://dir');
|
||||
|
||||
// Copy the file under public://dir/subdir1/.
|
||||
$this->doTransform($source, 'public://dir/subdir1/file.txt');
|
||||
|
||||
// Check that 'subdir1' was created and the file was successfully migrated.
|
||||
$this->assertFileExists('public://dir/subdir1/file.txt');
|
||||
|
||||
// Remove all permissions from public://dir to trigger a failure when
|
||||
// trying to create a subdirectory 'subdir2' inside public://dir.
|
||||
$this->fileSystem->chmod('public://dir', 0);
|
||||
|
||||
// Check that the proper exception is raised.
|
||||
$this->setExpectedException(MigrateException::class, "Could not create or write to directory 'public://dir/subdir2'");
|
||||
$this->doTransform($source, 'public://dir/subdir2/file.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the 'rename' overwrite mode.
|
||||
*/
|
||||
|
|
|
@ -3828,6 +3828,15 @@ $connection->insert('field_config_instance')
|
|||
'data' => 'a:7:{s:5:"label";s:21:"Term Entity Reference";s:6:"widget";a:5:{s:6:"weight";s:2:"18";s:4:"type";s:33:"entityreference_autocomplete_tags";s:6:"module";s:15:"entityreference";s:6:"active";i:1;s:8:"settings";a:3:{s:14:"match_operator";s:8:"CONTAINS";s:4:"size";s:2:"60";s:4:"path";s:0:"";}}s:8:"settings";a:2:{s:9:"behaviors";a:1:{s:14:"taxonomy-index";a:1:{s:6:"status";b:1;}}s:18:"user_register_form";b:0;}s:7:"display";a:1:{s:7:"default";a:5:{s:5:"label";s:5:"above";s:4:"type";s:21:"entityreference_label";s:8:"settings";a:1:{s:4:"link";b:0;}s:6:"module";s:15:"entityreference";s:6:"weight";i:17;}}s:8:"required";i:0;s:11:"description";s:0:"";s:13:"default_value";N;}',
|
||||
'deleted' => '0',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '41',
|
||||
'field_id' => '20',
|
||||
'field_name' => 'field_term_reference',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'test_vocabulary',
|
||||
'data' => 'a:7:{s:5:"label";s:14:"Term Reference";s:6:"widget";a:5:{s:6:"weight";s:2:"14";s:4:"type";s:21:"taxonomy_autocomplete";s:6:"module";s:8:"taxonomy";s:6:"active";i:0;s:8:"settings";a:2:{s:4:"size";i:60;s:17:"autocomplete_path";s:21:"taxonomy/autocomplete";}}s:8:"settings";a:1:{s:18:"user_register_form";b:0;}s:7:"display";a:1:{s:7:"default";a:4:{s:5:"label";s:5:"above";s:4:"type";s:6:"hidden";s:6:"weight";s:2:"13";s:8:"settings";a:0:{}}}s:8:"required";i:0;s:11:"description";s:0:"";s:13:"default_value";N;}',
|
||||
'deleted' => '0',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->schema()->createTable('field_data_body', array(
|
||||
|
@ -4850,6 +4859,16 @@ $connection->insert('field_data_field_integer')
|
|||
'delta' => '0',
|
||||
'field_integer_value' => '99',
|
||||
))
|
||||
->values(array(
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'test_vocabulary',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '4',
|
||||
'revision_id' => '4',
|
||||
'language' => 'und',
|
||||
'delta' => '0',
|
||||
'field_integer_value' => '6',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->schema()->createTable('field_data_field_integer_list', array(
|
||||
|
@ -5649,6 +5668,16 @@ $connection->insert('field_data_field_term_reference')
|
|||
'delta' => '0',
|
||||
'field_term_reference_tid' => '4',
|
||||
))
|
||||
->values(array(
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'test_vocabulary',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '2',
|
||||
'revision_id' => '2',
|
||||
'language' => 'und',
|
||||
'delta' => '0',
|
||||
'field_term_reference_tid' => '3',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->schema()->createTable('field_data_field_text', array(
|
||||
|
@ -7023,6 +7052,16 @@ $connection->insert('field_revision_field_integer')
|
|||
'delta' => '0',
|
||||
'field_integer_value' => '99',
|
||||
))
|
||||
->values(array(
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'test_vocabulary',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '4',
|
||||
'revision_id' => '4',
|
||||
'language' => 'und',
|
||||
'delta' => '0',
|
||||
'field_integer_value' => '6',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->schema()->createTable('field_revision_field_integer_list', array(
|
||||
|
@ -7830,6 +7869,16 @@ $connection->insert('field_revision_field_term_reference')
|
|||
'delta' => '0',
|
||||
'field_term_reference_tid' => '4',
|
||||
))
|
||||
->values(array(
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'test_vocabulary',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '2',
|
||||
'revision_id' => '2',
|
||||
'language' => 'und',
|
||||
'delta' => '0',
|
||||
'field_term_reference_tid' => '3',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->schema()->createTable('field_revision_field_text', array(
|
||||
|
|
|
@ -250,6 +250,10 @@ class MigrateUpgradeForm extends ConfirmFormBase {
|
|||
'source_module' => 'filter',
|
||||
'destination_module' => 'filter',
|
||||
],
|
||||
'd7_filter_settings' => [
|
||||
'source_module' => 'filter',
|
||||
'destination_module' => 'filter',
|
||||
],
|
||||
'd6_forum_settings' => [
|
||||
'source_module' => 'forum',
|
||||
'destination_module' => 'forum',
|
||||
|
|
|
@ -43,8 +43,8 @@ class MigrateUpgrade7Test extends MigrateUpgradeTestBase {
|
|||
'configurable_language' => 4,
|
||||
'contact_form' => 3,
|
||||
'editor' => 2,
|
||||
'field_config' => 48,
|
||||
'field_storage_config' => 36,
|
||||
'field_config' => 49,
|
||||
'field_storage_config' => 37,
|
||||
'file' => 1,
|
||||
'filter_format' => 7,
|
||||
'image_style' => 6,
|
||||
|
|
|
@ -72,7 +72,7 @@ class NodePreviewForm extends FormBase {
|
|||
public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $node = NULL) {
|
||||
$view_mode = $node->preview_view_mode;
|
||||
|
||||
$query_options = $node->isNew() ? array('query' => array('uuid' => $node->uuid())) : array();
|
||||
$query_options = array('query' => array('uuid' => $node->uuid()));
|
||||
$form['backlink'] = array(
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('Back to content editing'),
|
||||
|
|
|
@ -67,31 +67,28 @@ class NodeForm extends ContentEntityForm {
|
|||
public function form(array $form, FormStateInterface $form_state) {
|
||||
// Try to restore from temp store, this must be done before calling
|
||||
// parent::form().
|
||||
$uuid = $this->entity->uuid();
|
||||
$store = $this->tempStoreFactory->get('node_preview');
|
||||
|
||||
// If the user is creating a new node, the UUID is passed in the request.
|
||||
if ($request_uuid = \Drupal::request()->query->get('uuid')) {
|
||||
$uuid = $request_uuid;
|
||||
}
|
||||
|
||||
if ($preview = $store->get($uuid)) {
|
||||
// Attempt to load from preview when the uuid is present unless we are
|
||||
// rebuilding the form.
|
||||
$request_uuid = \Drupal::request()->query->get('uuid');
|
||||
if (!$form_state->isRebuilding() && $request_uuid && $preview = $store->get($request_uuid)) {
|
||||
/** @var $preview \Drupal\Core\Form\FormStateInterface */
|
||||
|
||||
foreach ($preview->getValues() as $name => $value) {
|
||||
$form_state->setValue($name, $value);
|
||||
}
|
||||
$form_state->setStorage($preview->getStorage());
|
||||
$form_state->setUserInput($preview->getUserInput());
|
||||
|
||||
// Rebuild the form.
|
||||
$form_state->setRebuild();
|
||||
|
||||
// The combination of having user input and rebuilding the form means
|
||||
// that it will attempt to cache the form state which will fail if it is
|
||||
// a GET request.
|
||||
$form_state->setRequestMethod('POST');
|
||||
|
||||
$this->entity = $preview->getFormObject()->getEntity();
|
||||
$this->entity->in_preview = NULL;
|
||||
|
||||
// Remove the stale temp store entry for existing nodes.
|
||||
if (!$this->entity->isNew()) {
|
||||
$store->delete($uuid);
|
||||
}
|
||||
|
||||
$this->hasBeenPreviewed = TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ class PagePreviewTest extends NodeTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'taxonomy', 'comment', 'image', 'file');
|
||||
public static $modules = array('node', 'taxonomy', 'comment', 'image', 'file', 'text', 'node_test', 'menu_ui');
|
||||
|
||||
/**
|
||||
* The name of the created field.
|
||||
|
@ -41,7 +41,7 @@ class PagePreviewTest extends NodeTestBase {
|
|||
parent::setUp();
|
||||
$this->addDefaultCommentField('node', 'page');
|
||||
|
||||
$web_user = $this->drupalCreateUser(array('edit own page content', 'create page content'));
|
||||
$web_user = $this->drupalCreateUser(array('edit own page content', 'create page content', 'administer menu'));
|
||||
$this->drupalLogin($web_user);
|
||||
|
||||
// Add a vocabulary so we can test different view modes.
|
||||
|
@ -124,6 +124,34 @@ class PagePreviewTest extends NodeTestBase {
|
|||
entity_get_display('node', 'page', 'default')
|
||||
->setComponent('field_image')
|
||||
->save();
|
||||
|
||||
// Create a multi-value text field.
|
||||
$field_storage = FieldStorageConfig::create([
|
||||
'field_name' => 'field_test_multi',
|
||||
'entity_type' => 'node',
|
||||
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||
'type' => 'text',
|
||||
'settings' => [
|
||||
'max_length' => 50,
|
||||
]
|
||||
]);
|
||||
$field_storage->save();
|
||||
FieldConfig::create([
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => 'page',
|
||||
])->save();
|
||||
|
||||
entity_get_form_display('node', 'page', 'default')
|
||||
->setComponent('field_test_multi', array(
|
||||
'type' => 'text_textfield',
|
||||
))
|
||||
->save();
|
||||
|
||||
entity_get_display('node', 'page', 'default')
|
||||
->setComponent('field_test_multi', array(
|
||||
'type' => 'string',
|
||||
))
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -176,8 +204,11 @@ class PagePreviewTest extends NodeTestBase {
|
|||
$this->clickLink(t('Back to content editing'));
|
||||
$this->assertFieldByName($title_key, $edit[$title_key], 'Title field displayed.');
|
||||
$this->assertFieldByName($body_key, $edit[$body_key], 'Body field displayed.');
|
||||
$this->assertFieldByName($term_key, $edit[$term_key] . ' (' . $this->term->id() . ')', 'Term field displayed.');
|
||||
$this->assertFieldByName($term_key, $edit[$term_key], 'Term field displayed.');
|
||||
$this->assertFieldByName('field_image[0][alt]', 'Picture of llamas');
|
||||
$this->drupalPostAjaxForm(NULL, array(), array('field_test_multi_add_more' => t('Add another item')), NULL, array(), array(), 'node-page-form');
|
||||
$this->assertFieldByName('field_test_multi[0][value]');
|
||||
$this->assertFieldByName('field_test_multi[1][value]');
|
||||
|
||||
// Return to page preview to check everything is as expected.
|
||||
$this->drupalPostForm(NULL, array(), t('Preview'));
|
||||
|
@ -191,7 +222,7 @@ class PagePreviewTest extends NodeTestBase {
|
|||
$this->drupalGet('node/add/page', array('query' => array('uuid' => $uuid)));
|
||||
$this->assertFieldByName($title_key, $edit[$title_key], 'Title field displayed.');
|
||||
$this->assertFieldByName($body_key, $edit[$body_key], 'Body field displayed.');
|
||||
$this->assertFieldByName($term_key, $edit[$term_key] . ' (' . $this->term->id() . ')', 'Term field displayed.');
|
||||
$this->assertFieldByName($term_key, $edit[$term_key], 'Term field displayed.');
|
||||
|
||||
// Save the node - this is a new POST, so we need to upload the image.
|
||||
$this->drupalPostForm('node/add/page', $edit, t('Upload'));
|
||||
|
@ -260,6 +291,80 @@ class PagePreviewTest extends NodeTestBase {
|
|||
$this->drupalPostForm('node/add/page', array($title_key => 'Preview'), t('Preview'));
|
||||
$this->clickLink(t('Back to content editing'));
|
||||
$this->assertRaw('edit-submit');
|
||||
|
||||
// Assert multiple items can be added and are not lost when previewing.
|
||||
$test_image_1 = current($this->drupalGetTestFiles('image', 39325));
|
||||
$edit_image_1['files[field_image_0][]'] = drupal_realpath($test_image_1->uri);
|
||||
$test_image_2 = current($this->drupalGetTestFiles('image', 39325));
|
||||
$edit_image_2['files[field_image_1][]'] = drupal_realpath($test_image_2->uri);
|
||||
$edit['field_image[0][alt]'] = 'Alt 1';
|
||||
|
||||
$this->drupalPostForm('node/add/page', $edit_image_1, t('Upload'));
|
||||
$this->drupalPostForm(NULL, $edit, t('Preview'));
|
||||
$this->clickLink(t('Back to content editing'));
|
||||
$this->assertFieldByName('files[field_image_1][]');
|
||||
$this->drupalPostForm(NULL, $edit_image_2, t('Upload'));
|
||||
$this->assertNoFieldByName('files[field_image_1][]');
|
||||
|
||||
$title = 'node_test_title';
|
||||
$example_text_1 = 'example_text_preview_1';
|
||||
$example_text_2 = 'example_text_preview_2';
|
||||
$example_text_3 = 'example_text_preview_3';
|
||||
$this->drupalGet('node/add/page');
|
||||
$edit = [
|
||||
'title[0][value]' => $title,
|
||||
'field_test_multi[0][value]' => $example_text_1,
|
||||
];
|
||||
$this->assertRaw('Storage is not set');
|
||||
$this->drupalPostForm(NULL, $edit, t('Preview'));
|
||||
$this->clickLink(t('Back to content editing'));
|
||||
$this->assertRaw('Storage is set');
|
||||
$this->assertFieldByName('field_test_multi[0][value]');
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
$this->assertText('Basic page ' . $title . ' has been created.');
|
||||
$node = $this->drupalGetNodeByTitle($title);
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
$this->drupalPostAjaxForm(NULL, [], array('field_test_multi_add_more' => t('Add another item')));
|
||||
$this->drupalPostAjaxForm(NULL, [], array('field_test_multi_add_more' => t('Add another item')));
|
||||
$edit = [
|
||||
'field_test_multi[1][value]' => $example_text_2,
|
||||
'field_test_multi[2][value]' => $example_text_3,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Preview'));
|
||||
$this->clickLink(t('Back to content editing'));
|
||||
$this->drupalPostForm(NULL, $edit, t('Preview'));
|
||||
$this->clickLink(t('Back to content editing'));
|
||||
$this->assertFieldByName('field_test_multi[0][value]', $example_text_1);
|
||||
$this->assertFieldByName('field_test_multi[1][value]', $example_text_2);
|
||||
$this->assertFieldByName('field_test_multi[2][value]', $example_text_3);
|
||||
|
||||
// Now save the node and make sure all values got saved.
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
$this->assertText($example_text_1);
|
||||
$this->assertText($example_text_2);
|
||||
$this->assertText($example_text_3);
|
||||
|
||||
// Edit again, change the menu_ui settings and click on preview.
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
$edit = [
|
||||
'menu[enabled]' => TRUE,
|
||||
'menu[title]' => 'Changed title',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Preview'));
|
||||
$this->clickLink(t('Back to content editing'));
|
||||
$this->assertFieldChecked('edit-menu-enabled', 'Menu option is still checked');
|
||||
$this->assertFieldByName('menu[title]', 'Changed title', 'Menu link title is correct after preview');
|
||||
|
||||
// Save, change the title while saving and make sure that it is correctly
|
||||
// saved.
|
||||
$edit = [
|
||||
'menu[enabled]' => TRUE,
|
||||
'menu[title]' => 'Second title change',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
$this->assertFieldByName('menu[title]', 'Second title change', 'Menu link title is correct after saving');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,9 +10,11 @@
|
|||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\node\NodeInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_ENTITY_TYPE_view() for node entities.
|
||||
*/
|
||||
|
@ -175,3 +177,16 @@ function node_test_node_insert(NodeInterface $node) {
|
|||
$node->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_alter().
|
||||
*/
|
||||
function node_test_form_alter(&$form, FormStateInterface $form_state, $form_id) {
|
||||
if (!$form_state->get('node_test_form_alter')) {
|
||||
drupal_set_message('Storage is not set');
|
||||
$form_state->set('node_test_form_alter', TRUE);
|
||||
}
|
||||
else {
|
||||
drupal_set_message('Storage is set');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,93 +49,104 @@ class OutsideInBlockFormTest extends OutsideInJavascriptTestBase {
|
|||
|
||||
/**
|
||||
* Tests opening Offcanvas tray by click blocks and elements in the blocks.
|
||||
*
|
||||
* @dataProvider providerTestBlocks
|
||||
*/
|
||||
public function testBlocks() {
|
||||
// @todo: re-enable once https://www.drupal.org/node/2830485 is resolved.
|
||||
$this->markTestSkipped('Test skipped due to random failures in DrupalCI, see https://www.drupal.org/node/2830485');
|
||||
|
||||
public function testBlocks($block_id, $new_page_text, $element_selector, $label_selector, $button_text, $toolbar_item) {
|
||||
$web_assert = $this->assertSession();
|
||||
$page = $this->getSession()->getPage();
|
||||
$block_selector = '#' . $block_id;
|
||||
$this->drupalGet('user');
|
||||
if (isset($toolbar_item)) {
|
||||
// Check that you can open a toolbar tray and it will be closed after
|
||||
// entering edit mode.
|
||||
if ($element = $page->find('css', "#toolbar-administration a.is-active")) {
|
||||
// If a tray was open from page load close it.
|
||||
$element->click();
|
||||
$this->waitForNoElement("#toolbar-administration a.is-active");
|
||||
}
|
||||
$page->find('css', $toolbar_item)->click();
|
||||
$this->waitForElement("{$toolbar_item}.is-active");
|
||||
}
|
||||
$this->toggleEditingMode();
|
||||
if (isset($toolbar_item)) {
|
||||
$this->waitForNoElement("{$toolbar_item}.is-active");
|
||||
}
|
||||
|
||||
$this->openBlockForm($block_selector);
|
||||
|
||||
switch ($block_id) {
|
||||
case 'block-powered':
|
||||
// Fill out form, save the form.
|
||||
$page->fillField('settings[label]', $new_page_text);
|
||||
$page->checkField('settings[label_display]');
|
||||
break;
|
||||
|
||||
case 'block-branding':
|
||||
// Fill out form, save the form.
|
||||
$page->fillField('settings[site_information][site_name]', $new_page_text);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($new_page_text)) {
|
||||
$page->pressButton($button_text);
|
||||
// Make sure the changes are present.
|
||||
// @todo Use a wait method that will take into account the form submitting
|
||||
// and all JavaScript activity. https://www.drupal.org/node/2837676
|
||||
// The use \Behat\Mink\WebAssert::pageTextContains to check text.
|
||||
$this->assertJsCondition('jQuery("' . $block_selector . ' ' . $label_selector . '").html() == "' . $new_page_text . '"');
|
||||
}
|
||||
|
||||
$this->openBlockForm($block_selector);
|
||||
|
||||
$this->toggleEditingMode();
|
||||
// Canvas should close when editing module is closed.
|
||||
$this->waitForOffCanvasToClose();
|
||||
|
||||
// Go into Edit mode again.
|
||||
$this->toggleEditingMode();
|
||||
|
||||
$element_selector = "$block_selector {$element_selector}";
|
||||
// Open block form by clicking a element inside the block.
|
||||
// This confirms that default action for links and form elements is
|
||||
// suppressed.
|
||||
$this->openBlockForm($element_selector);
|
||||
|
||||
// Exit edit mode.
|
||||
$this->toggleEditingMode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dataprovider for testBlocks().
|
||||
*/
|
||||
public function providerTestBlocks() {
|
||||
$blocks = [
|
||||
[
|
||||
'block-powered' => [
|
||||
'id' => 'block-powered',
|
||||
'new_page_text' => 'Can you imagine anyone showing the label on this block?',
|
||||
'element_selector' => '.content a',
|
||||
'label_selector' => 'h2',
|
||||
'button_text' => 'Save Powered by Drupal',
|
||||
'toolbar_item' => '#toolbar-item-user',
|
||||
],
|
||||
[
|
||||
'block-branding' => [
|
||||
'id' => 'block-branding',
|
||||
'new_page_text' => 'The site that will live a very short life.',
|
||||
'element_selector' => 'a[rel="home"]:nth-child(2)',
|
||||
'label_selector' => '.site-branding__name a',
|
||||
'button_text' => 'Save Site branding',
|
||||
'toolbar_item' => '#toolbar-item-administration',
|
||||
],
|
||||
[
|
||||
'block-search' => [
|
||||
'id' => 'block-search',
|
||||
'new_page_text' => NULL,
|
||||
'element_selector' => '#edit-submit',
|
||||
'label_selector' => 'h2',
|
||||
'button_text' => 'Save Search form',
|
||||
'toolbar_item' => NULL,
|
||||
],
|
||||
];
|
||||
$page = $this->getSession()->getPage();
|
||||
foreach ($blocks as $block) {
|
||||
$block_selector = '#' . $block['id'];
|
||||
$this->drupalGet('user');
|
||||
if (isset($block['toolbar_item'])) {
|
||||
// Check that you can open a toolbar tray and it will be closed after
|
||||
// entering edit mode.
|
||||
if ($element = $page->find('css', "#toolbar-administration a.is-active")) {
|
||||
// If a tray was open from page load close it.
|
||||
$element->click();
|
||||
$this->waitForNoElement("#toolbar-administration a.is-active");
|
||||
}
|
||||
$page->find('css', $block['toolbar_item'])->click();
|
||||
$this->waitForElement("{$block['toolbar_item']}.is-active");
|
||||
}
|
||||
$this->toggleEditingMode();
|
||||
if (isset($block['toolbar_item'])) {
|
||||
$this->waitForNoElement("{$block['toolbar_item']}.is-active");
|
||||
}
|
||||
|
||||
$this->openBlockForm($block_selector);
|
||||
|
||||
switch ($block['id']) {
|
||||
case 'block-powered':
|
||||
// Fill out form, save the form.
|
||||
$page->fillField('settings[label]', $block['new_page_text']);
|
||||
$page->checkField('settings[label_display]');
|
||||
break;
|
||||
|
||||
case 'block-branding':
|
||||
// Fill out form, save the form.
|
||||
$page->fillField('settings[site_information][site_name]', $block['new_page_text']);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($block['new_page_text'])) {
|
||||
$page->pressButton($block['button_text']);
|
||||
// Make sure the changes are present.
|
||||
$this->assertSession()->assertWaitOnAjaxRequest();
|
||||
$web_assert->pageTextContains($block['new_page_text']);
|
||||
}
|
||||
|
||||
$this->openBlockForm($block_selector);
|
||||
|
||||
$this->toggleEditingMode();
|
||||
// Canvas should close when editing module is closed.
|
||||
$this->waitForOffCanvasToClose();
|
||||
|
||||
// Go into Edit mode again.
|
||||
$this->toggleEditingMode();
|
||||
|
||||
$element_selector = "$block_selector {$block['element_selector']}";
|
||||
// Open block form by clicking a element inside the block.
|
||||
// This confirms that default action for links and form elements is
|
||||
// suppressed.
|
||||
$this->openBlockForm($element_selector);
|
||||
|
||||
// Exit edit mode.
|
||||
$this->toggleEditingMode();
|
||||
}
|
||||
return $blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,6 +9,19 @@ use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
|||
*/
|
||||
abstract class OutsideInJavascriptTestBase extends JavascriptTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function drupalGet($path, array $options = array(), array $headers = array()) {
|
||||
$return = parent::drupalGet($path, $options, $headers);
|
||||
|
||||
// After the page loaded we need to additionally wait until the settings
|
||||
// tray Ajax activity is done.
|
||||
$this->assertSession()->assertWaitOnAjaxRequest();
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables a theme.
|
||||
*
|
||||
|
|
Binary file not shown.
|
@ -17,16 +17,6 @@ $connection->insert('key_value')
|
|||
'name' => 'rest',
|
||||
'value' => 'i:8000;',
|
||||
])
|
||||
->fields([
|
||||
'collection' => 'system.schema',
|
||||
'name' => 'serialization',
|
||||
'value' => 'i:8000;',
|
||||
])
|
||||
->fields([
|
||||
'collection' => 'system.schema',
|
||||
'name' => 'basic_auth',
|
||||
'value' => 'i:8000;',
|
||||
])
|
||||
->execute();
|
||||
|
||||
// Update core.extension.
|
||||
|
@ -37,9 +27,9 @@ $extensions = $connection->select('config')
|
|||
->execute()
|
||||
->fetchField();
|
||||
$extensions = unserialize($extensions);
|
||||
$extensions['module']['basic_auth'] = 8000;
|
||||
$extensions['module']['rest'] = 8000;
|
||||
$extensions['module']['serialization'] = 8000;
|
||||
$extensions['module']['basic_auth'] = 0;
|
||||
$extensions['module']['rest'] = 0;
|
||||
$extensions['module']['serialization'] = 0;
|
||||
$connection->update('config')
|
||||
->fields([
|
||||
'data' => serialize($extensions),
|
||||
|
@ -58,7 +48,7 @@ $config = [
|
|||
],
|
||||
],
|
||||
],
|
||||
'link_domain' => '~',
|
||||
'link_domain' => NULL,
|
||||
];
|
||||
$data = $connection->insert('config')
|
||||
->fields([
|
||||
|
|
|
@ -17,11 +17,6 @@ $connection->insert('key_value')
|
|||
'name' => 'rest',
|
||||
'value' => 'i:8000;',
|
||||
])
|
||||
->fields([
|
||||
'collection' => 'system.schema',
|
||||
'name' => 'serialization',
|
||||
'value' => 'i:8000;',
|
||||
])
|
||||
->execute();
|
||||
|
||||
// Update core.extension.
|
||||
|
@ -32,8 +27,8 @@ $extensions = $connection->select('config')
|
|||
->execute()
|
||||
->fetchField();
|
||||
$extensions = unserialize($extensions);
|
||||
$extensions['module']['rest'] = 8000;
|
||||
$extensions['module']['serialization'] = 8000;
|
||||
$extensions['module']['rest'] = 0;
|
||||
$extensions['module']['serialization'] = 0;
|
||||
$connection->update('config')
|
||||
->fields([
|
||||
'data' => serialize($extensions),
|
||||
|
@ -52,7 +47,7 @@ $config = [
|
|||
],
|
||||
],
|
||||
],
|
||||
'link_domain' => '~',
|
||||
'link_domain' => NULL,
|
||||
];
|
||||
$data = $connection->insert('config')
|
||||
->fields([
|
||||
|
|
|
@ -18,16 +18,6 @@ $connection->insert('key_value')
|
|||
'name' => 'rest',
|
||||
'value' => 'i:8000;',
|
||||
])
|
||||
->fields([
|
||||
'collection' => 'system.schema',
|
||||
'name' => 'serialization',
|
||||
'value' => 'i:8000;',
|
||||
])
|
||||
->fields([
|
||||
'collection' => 'system.schema',
|
||||
'name' => 'basic_auth',
|
||||
'value' => 'i:8000;',
|
||||
])
|
||||
->execute();
|
||||
|
||||
// Update core.extension.
|
||||
|
|
|
@ -383,8 +383,11 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
$get_headers = $response->getHeaders();
|
||||
|
||||
// Verify that the GET and HEAD responses are the same. The only difference
|
||||
// is that there's no body.
|
||||
$ignored_headers = ['Date', 'Content-Length', 'X-Drupal-Cache', 'X-Drupal-Dynamic-Cache'];
|
||||
// is that there's no body. For this reason the 'Transfer-Encoding' header
|
||||
// is also added to the list of headers to ignore, as this could be added to
|
||||
// GET requests - depending on web server configuration. This would usually
|
||||
// be 'Transfer-Encoding: chunked'.
|
||||
$ignored_headers = ['Date', 'Content-Length', 'X-Drupal-Cache', 'X-Drupal-Dynamic-Cache', 'Transfer-Encoding'];
|
||||
foreach ($ignored_headers as $ignored_header) {
|
||||
unset($head_headers[$ignored_header]);
|
||||
unset($get_headers[$ignored_header]);
|
||||
|
|
|
@ -411,6 +411,7 @@ class ModulesListForm extends FormBase {
|
|||
foreach (array_keys($modules['install']) as $module) {
|
||||
if (!drupal_check_module($module)) {
|
||||
unset($modules['install'][$module]);
|
||||
unset($modules['experimental'][$module]);
|
||||
foreach (array_keys($data[$module]->required_by) as $dependent) {
|
||||
unset($modules['install'][$dependent]);
|
||||
unset($modules['dependencies'][$dependent]);
|
||||
|
|
|
@ -120,6 +120,14 @@ class ExperimentalModuleTest extends WebTestBase {
|
|||
$this->drupalPostForm(NULL, [], 'Continue');
|
||||
$this->assertText('2 modules have been enabled: Experimental Test, Experimental Dependency Test');
|
||||
|
||||
// Try to enable an experimental module that can not be due to
|
||||
// hook_requirements().
|
||||
\Drupal::state()->set('experimental_module_requirements_test_requirements', TRUE);
|
||||
$edit = [];
|
||||
$edit["modules[Core (Experimental)][experimental_module_requirements_test][enable]"] = TRUE;
|
||||
$this->drupalPostForm('admin/modules', $edit, 'Install');
|
||||
$this->assertUrl('admin/modules', [], 'If the module can not be installed we are not taken to the confirm form.');
|
||||
$this->assertText('The Experimental Test Requirements module can not be installed.');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -192,6 +192,8 @@ abstract class UpdatePathTestBase extends WebTestBase {
|
|||
$this->container = \Drupal::getContainer();
|
||||
|
||||
$this->replaceUser1();
|
||||
|
||||
require_once \Drupal::root() . '/core/includes/update.inc';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -251,6 +253,28 @@ abstract class UpdatePathTestBase extends WebTestBase {
|
|||
if ($this->checkFailedUpdates) {
|
||||
$this->assertNoRaw('<strong>' . t('Failed:') . '</strong>');
|
||||
|
||||
// Ensure that there are no pending updates.
|
||||
foreach (['update', 'post_update'] as $update_type) {
|
||||
switch ($update_type) {
|
||||
case 'update':
|
||||
$all_updates = update_get_update_list();
|
||||
break;
|
||||
case 'post_update':
|
||||
$all_updates = \Drupal::service('update.post_update_registry')->getPendingUpdateInformation();
|
||||
break;
|
||||
}
|
||||
foreach ($all_updates as $module => $updates) {
|
||||
if (!empty($updates['pending'])) {
|
||||
foreach (array_keys($updates['pending']) as $update_name) {
|
||||
$this->fail("The $update_name() update function from the $module module did not run.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reset the static cache of drupal_get_installed_schema_version() so that
|
||||
// more complex update path testing works.
|
||||
drupal_static_reset('drupal_get_installed_schema_version');
|
||||
|
||||
// The config schema can be incorrect while the update functions are being
|
||||
// executed. But once the update has been completed, it needs to be valid
|
||||
// again. Assert the schema of all configuration objects now.
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
name: 'Experimental Requirements Test'
|
||||
type: module
|
||||
description: 'Module in the experimental package to test hook_requirements() with an experimental module.'
|
||||
package: Core (Experimental)
|
||||
version: VERSION
|
||||
core: 8.x
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Experimental Test Requirements module to test hook_requirements().
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
function experimental_module_requirements_test_requirements() {
|
||||
$requirements = [];
|
||||
if (\Drupal::state()->get('experimental_module_requirements_test_requirements', FALSE)) {
|
||||
$requirements['experimental_module_requirements_test_requirements'] = [
|
||||
'severity' => REQUIREMENT_ERROR,
|
||||
'description' => t('The Experimental Test Requirements module can not be installed.'),
|
||||
];
|
||||
}
|
||||
return $requirements;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Experimental Test Requirements module to test hook_requirements().
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function experimental_module_requirements_test_help($route_name) {
|
||||
switch ($route_name) {
|
||||
case 'help.page.experimental_module_requirements_test':
|
||||
// Make the help text conform to core standards. See
|
||||
// \Drupal\system\Tests\Module\InstallUninstallTest::assertHelp().
|
||||
return t('The Experimental Requirements Test module is not done yet. It may eat your data, but you can read the <a href=":url">online documentation for the Experimental Requirements Test module</a>.', [':url' => 'http://www.example.com']);
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ label: Taxonomy terms
|
|||
migration_tags:
|
||||
- Drupal 6
|
||||
source:
|
||||
plugin: taxonomy_term
|
||||
plugin: d6_taxonomy_term
|
||||
process:
|
||||
# If you are using this file to build a custom migration consider removing
|
||||
# the tid field to allow incremental migrations.
|
||||
|
|
|
@ -2,8 +2,9 @@ id: d7_taxonomy_term
|
|||
label: Taxonomy terms
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
deriver: Drupal\taxonomy\Plugin\migrate\D7TaxonomyTermDeriver
|
||||
source:
|
||||
plugin: taxonomy_term
|
||||
plugin: d7_taxonomy_term
|
||||
process:
|
||||
# If you are using this file to build a custom migration consider removing
|
||||
# the tid field to allow incremental migrations.
|
||||
|
@ -35,3 +36,5 @@ destination:
|
|||
migration_dependencies:
|
||||
required:
|
||||
- d7_taxonomy_vocabulary
|
||||
optional:
|
||||
- d7_field_instance
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\taxonomy\Plugin\migrate;
|
||||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
|
||||
use Drupal\Core\Database\DatabaseExceptionWrapper;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\migrate\Exception\RequirementsException;
|
||||
use Drupal\migrate\Plugin\Migration;
|
||||
use Drupal\migrate\Plugin\MigrationDeriverTrait;
|
||||
use Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Deriver for Drupal 7 taxonomy term migrations based on vocabularies.
|
||||
*/
|
||||
class D7TaxonomyTermDeriver extends DeriverBase implements ContainerDeriverInterface {
|
||||
use MigrationDeriverTrait;
|
||||
|
||||
/**
|
||||
* The base plugin ID this derivative is for.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $basePluginId;
|
||||
|
||||
/**
|
||||
* Already-instantiated cckfield plugins, keyed by ID.
|
||||
*
|
||||
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldInterface[]
|
||||
*/
|
||||
protected $cckPluginCache;
|
||||
|
||||
/**
|
||||
* The CCK plugin manager.
|
||||
*
|
||||
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface
|
||||
*/
|
||||
protected $cckPluginManager;
|
||||
|
||||
/**
|
||||
* D7TaxonomyTermDeriver constructor.
|
||||
*
|
||||
* @param string $base_plugin_id
|
||||
* The base plugin ID for the plugin ID.
|
||||
* @param \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface $cck_manager
|
||||
* The CCK plugin manager.
|
||||
*/
|
||||
public function __construct($base_plugin_id, MigrateCckFieldPluginManagerInterface $cck_manager) {
|
||||
$this->basePluginId = $base_plugin_id;
|
||||
$this->cckPluginManager = $cck_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$base_plugin_id,
|
||||
$container->get('plugin.manager.migrate.cckfield')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
$fields = [];
|
||||
try {
|
||||
$source_plugin = static::getSourcePlugin('d7_field_instance');
|
||||
$source_plugin->checkRequirements();
|
||||
|
||||
// Read all field instance definitions in the source database.
|
||||
foreach ($source_plugin as $row) {
|
||||
if ($row->getSourceProperty('entity_type') == 'taxonomy_term') {
|
||||
$fields[$row->getSourceProperty('bundle')][$row->getSourceProperty('field_name')] = $row->getSource();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (RequirementsException $e) {
|
||||
// If checkRequirements() failed then the field module did not exist and
|
||||
// we do not have any fields. Therefore, $fields will be empty and below
|
||||
// we'll create a migration just for the node properties.
|
||||
}
|
||||
|
||||
try {
|
||||
foreach (static::getSourcePlugin('d7_taxonomy_vocabulary') as $row) {
|
||||
$bundle = $row->getSourceProperty('machine_name');
|
||||
$values = $base_plugin_definition;
|
||||
|
||||
$values['label'] = t('@label (@type)', [
|
||||
'@label' => $values['label'],
|
||||
'@type' => $row->getSourceProperty('name'),
|
||||
]);
|
||||
$values['source']['bundle'] = $bundle;
|
||||
$values['destination']['default_bundle'] = $bundle;
|
||||
|
||||
/** @var Migration $migration */
|
||||
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration($values);
|
||||
if (isset($fields[$bundle])) {
|
||||
foreach ($fields[$bundle] as $field_name => $info) {
|
||||
$field_type = $info['type'];
|
||||
try {
|
||||
$plugin_id = $this->cckPluginManager->getPluginIdFromFieldType($field_type, ['core' => 7], $migration);
|
||||
if (!isset($this->cckPluginCache[$field_type])) {
|
||||
$this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($plugin_id, ['core' => 7], $migration);
|
||||
}
|
||||
$this->cckPluginCache[$field_type]
|
||||
->processCckFieldValues($migration, $field_name, $info);
|
||||
}
|
||||
catch (PluginNotFoundException $ex) {
|
||||
$migration->setProcessOfProperty($field_name, $field_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->derivatives[$bundle] = $migration->getPluginDefinition();
|
||||
}
|
||||
}
|
||||
catch (DatabaseExceptionWrapper $e) {
|
||||
// Once we begin iterating the source plugin it is possible that the
|
||||
// source tables will not exist. This can happen when the
|
||||
// MigrationPluginManager gathers up the migration definitions but we do
|
||||
// not actually have a Drupal 7 source database.
|
||||
}
|
||||
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
}
|
|
@ -14,6 +14,10 @@ use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
|||
* id = "taxonomy_term",
|
||||
* source_provider = "taxonomy"
|
||||
* )
|
||||
*
|
||||
* @deprecated in Drupal 8.3.0, intended to be removed in Drupal 9.0.0.
|
||||
* Use \Drupal\taxonomy\Plugin\migrate\source\d6\Term or
|
||||
* \Drupal\taxonomy\Plugin\migrate\source\d7\Term.
|
||||
*/
|
||||
class Term extends DrupalSqlBase {
|
||||
|
||||
|
@ -50,7 +54,7 @@ class Term extends DrupalSqlBase {
|
|||
->orderBy('td.tid');
|
||||
|
||||
if (isset($this->configuration['vocabulary'])) {
|
||||
$query->condition('td.vid', $this->configuration['vocabulary'], 'IN');
|
||||
$query->condition('td.vid', (array) $this->configuration['vocabulary'], 'IN');
|
||||
}
|
||||
|
||||
return $query;
|
||||
|
|
74
core/modules/taxonomy/src/Plugin/migrate/source/d6/Term.php
Normal file
74
core/modules/taxonomy/src/Plugin/migrate/source/d6/Term.php
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\taxonomy\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* Taxonomy term source from database.
|
||||
*
|
||||
* @todo Support term_relation, term_synonym table if possible.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_taxonomy_term",
|
||||
* source_provider = "taxonomy"
|
||||
* )
|
||||
*/
|
||||
class Term extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->select('term_data', 'td')
|
||||
->fields('td')
|
||||
->distinct()
|
||||
->orderBy('td.tid');
|
||||
|
||||
if (isset($this->configuration['bundle'])) {
|
||||
$query->condition('td.vid', (array) $this->configuration['bundle'], 'IN');
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
$fields = [
|
||||
'tid' => $this->t('The term ID.'),
|
||||
'vid' => $this->t('Existing term VID'),
|
||||
'name' => $this->t('The name of the term.'),
|
||||
'description' => $this->t('The term description.'),
|
||||
'weight' => $this->t('Weight'),
|
||||
'parent' => $this->t("The Drupal term IDs of the term's parents."),
|
||||
];
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
// Find parents for this row.
|
||||
$parents = $this->select('term_hierarchy', 'th')
|
||||
->fields('th', ['parent', 'tid'])
|
||||
->condition('tid', $row->getSourceProperty('tid'))
|
||||
->execute()
|
||||
->fetchCol();
|
||||
$row->setSourceProperty('parent', $parents);
|
||||
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['tid']['type'] = 'integer';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
84
core/modules/taxonomy/src/Plugin/migrate/source/d7/Term.php
Normal file
84
core/modules/taxonomy/src/Plugin/migrate/source/d7/Term.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\taxonomy\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity;
|
||||
|
||||
/**
|
||||
* Taxonomy term source from database.
|
||||
*
|
||||
* @todo Support term_relation, term_synonym table if possible.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_taxonomy_term",
|
||||
* source_provider = "taxonomy"
|
||||
* )
|
||||
*/
|
||||
class Term extends FieldableEntity {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->select('taxonomy_term_data', 'td')
|
||||
->fields('td')
|
||||
->distinct()
|
||||
->orderBy('tid');
|
||||
$query->leftJoin('taxonomy_vocabulary', 'tv', 'td.vid = tv.vid');
|
||||
$query->addField('tv', 'machine_name');
|
||||
|
||||
if (isset($this->configuration['bundle'])) {
|
||||
$query->condition('tv.machine_name', (array) $this->configuration['bundle'], 'IN');
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
$fields = [
|
||||
'tid' => $this->t('The term ID.'),
|
||||
'vid' => $this->t('Existing term VID'),
|
||||
'machine_name' => $this->t('Vocabulary machine name'),
|
||||
'name' => $this->t('The name of the term.'),
|
||||
'description' => $this->t('The term description.'),
|
||||
'weight' => $this->t('Weight'),
|
||||
'parent' => $this->t("The Drupal term IDs of the term's parents."),
|
||||
'format' => $this->t("Format of the term description."),
|
||||
];
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
// Get Field API field values.
|
||||
foreach (array_keys($this->getFields('taxonomy_term', $row->getSourceProperty('machine_name'))) as $field) {
|
||||
$tid = $row->getSourceProperty('tid');
|
||||
$row->setSourceProperty($field, $this->getFieldValues('taxonomy_term', $field, $tid));
|
||||
}
|
||||
|
||||
// Find parents for this row.
|
||||
$parents = $this->select('taxonomy_term_hierarchy', 'th')
|
||||
->fields('th', ['parent', 'tid'])
|
||||
->condition('tid', $row->getSourceProperty('tid'))
|
||||
->execute()
|
||||
->fetchCol();
|
||||
$row->setSourceProperty('parent', $parents);
|
||||
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['tid']['type'] = 'integer';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,16 @@ use Drupal\taxonomy\TermInterface;
|
|||
*/
|
||||
class MigrateTaxonomyTermTest extends MigrateDrupal7TestBase {
|
||||
|
||||
public static $modules = array('taxonomy', 'text');
|
||||
public static $modules = [
|
||||
'comment',
|
||||
'datetime',
|
||||
'image',
|
||||
'link',
|
||||
'node',
|
||||
'taxonomy',
|
||||
'telephone',
|
||||
'text',
|
||||
];
|
||||
|
||||
/**
|
||||
* The cached taxonomy tree items, keyed by vid and tid.
|
||||
|
@ -28,7 +37,16 @@ class MigrateTaxonomyTermTest extends MigrateDrupal7TestBase {
|
|||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->executeMigrations(['d7_taxonomy_vocabulary', 'd7_taxonomy_term']);
|
||||
$this->installConfig(static::$modules);
|
||||
|
||||
$this->executeMigrations([
|
||||
'd7_node_type',
|
||||
'd7_comment_type',
|
||||
'd7_field',
|
||||
'd7_taxonomy_vocabulary',
|
||||
'd7_field_instance',
|
||||
'd7_taxonomy_term'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,8 +66,12 @@ class MigrateTaxonomyTermTest extends MigrateDrupal7TestBase {
|
|||
* The weight the migrated entity should have.
|
||||
* @param array $expected_parents
|
||||
* The parent terms the migrated entity should have.
|
||||
* @param int $expected_field_integer_value
|
||||
* The value the migrated entity field should have.
|
||||
* @param int $expected_term_reference_tid
|
||||
* The term reference id the migrated entity field should have.
|
||||
*/
|
||||
protected function assertEntity($id, $expected_label, $expected_vid, $expected_description = '', $expected_format = NULL, $expected_weight = 0, $expected_parents = []) {
|
||||
protected function assertEntity($id, $expected_label, $expected_vid, $expected_description = '', $expected_format = NULL, $expected_weight = 0, $expected_parents = [], $expected_field_integer_value = NULL, $expected_term_reference_tid = NULL) {
|
||||
/** @var \Drupal\taxonomy\TermInterface $entity */
|
||||
$entity = Term::load($id);
|
||||
$this->assertTrue($entity instanceof TermInterface);
|
||||
|
@ -60,6 +82,14 @@ class MigrateTaxonomyTermTest extends MigrateDrupal7TestBase {
|
|||
$this->assertEqual($expected_weight, $entity->getWeight());
|
||||
$this->assertIdentical($expected_parents, $this->getParentIDs($id));
|
||||
$this->assertHierarchy($expected_vid, $id, $expected_parents);
|
||||
if (!is_null($expected_field_integer_value)) {
|
||||
$this->assertTrue($entity->hasField('field_integer'));
|
||||
$this->assertEquals($expected_field_integer_value, $entity->field_integer->value);
|
||||
}
|
||||
if (!is_null($expected_term_reference_tid)) {
|
||||
$this->assertTrue($entity->hasField('field_integer'));
|
||||
$this->assertEquals($expected_term_reference_tid, $entity->field_term_reference->target_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,9 +97,9 @@ class MigrateTaxonomyTermTest extends MigrateDrupal7TestBase {
|
|||
*/
|
||||
public function testTaxonomyTerms() {
|
||||
$this->assertEntity(1, 'General discussion', 'forums', '', NULL, 2);
|
||||
$this->assertEntity(2, 'Term1', 'test_vocabulary', 'The first term.', 'filtered_html');
|
||||
$this->assertEntity(2, 'Term1', 'test_vocabulary', 'The first term.', 'filtered_html', 0, [], NULL, 3);
|
||||
$this->assertEntity(3, 'Term2', 'test_vocabulary', 'The second term.', 'filtered_html');
|
||||
$this->assertEntity(4, 'Term3', 'test_vocabulary', 'The third term.', 'full_html', 0, [3]);
|
||||
$this->assertEntity(4, 'Term3', 'test_vocabulary', 'The third term.', 'full_html', 0, [3], 6);
|
||||
$this->assertEntity(5, 'Custom Forum', 'forums', 'Where the cool kids are.', NULL, 3);
|
||||
$this->assertEntity(6, 'Games', 'forums', '', NULL, 4);
|
||||
$this->assertEntity(7, 'Minecraft', 'forums', '', NULL, 1, [6]);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source;
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
/**
|
||||
* Tests the taxonomy term source with vocabulary filter.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\Term
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d6\Term
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermSourceWithVocabularyFilterTest extends TermTest {
|
||||
|
@ -47,7 +47,7 @@ class TermSourceWithVocabularyFilterTest extends TermTest {
|
|||
|
||||
// Set up source plugin configuration.
|
||||
$tests[0]['configuration'] = [
|
||||
'vocabulary' => [5],
|
||||
'bundle' => [5],
|
||||
];
|
||||
|
||||
return $tests;
|
|
@ -1,13 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source;
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests taxonomy term source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\Term
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d6\Term
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermTest extends MigrateSqlSourceTestBase {
|
||||
|
@ -67,6 +67,13 @@ class TermTest extends MigrateSqlSourceTestBase {
|
|||
'description' => 'description value 6',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'vid' => 3,
|
||||
'name' => 'name value 7',
|
||||
'description' => 'description value 7',
|
||||
'weight' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['term_hierarchy'] = [
|
||||
[
|
||||
|
@ -97,6 +104,10 @@ class TermTest extends MigrateSqlSourceTestBase {
|
|||
'tid' => 6,
|
||||
'parent' => 2,
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'parent' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
|
@ -149,8 +160,58 @@ class TermTest extends MigrateSqlSourceTestBase {
|
|||
'weight' => 0,
|
||||
'parent' => [3, 2],
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'vid' => 3,
|
||||
'name' => 'name value 7',
|
||||
'description' => 'description value 7',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['expected_count'] = NULL;
|
||||
// Empty configuration will return terms for all vocabularies.
|
||||
$tests[0]['configuration'] = [];
|
||||
|
||||
// Change configuration to get one vocabulary, 5.
|
||||
$tests[1]['source_data'] = $tests[0]['source_data'];
|
||||
$tests[1]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4',
|
||||
'description' => 'description value 4',
|
||||
'weight' => 1,
|
||||
'parent' => [1],
|
||||
],
|
||||
];
|
||||
$tests[1]['expected_count'] = NULL;
|
||||
$tests[1]['configuration']['bundle'] = ['5'];
|
||||
|
||||
// Same as previous test, but with configuration vocabulary as a string
|
||||
// instead of an array.
|
||||
$tests[2]['source_data'] = $tests[0]['source_data'];
|
||||
$tests[2]['expected_data'] = $tests[1]['expected_data'];
|
||||
$tests[2]['expected_count'] = NULL;
|
||||
$tests[2]['configuration']['bundle'] = '5';
|
||||
|
||||
// Change configuration to get two vocabularies, 5 and 6.
|
||||
$tests[3]['source_data'] = $tests[0]['source_data'];
|
||||
$tests[3]['expected_data'] = $tests[0]['expected_data'];
|
||||
// Remove the last element because it is for vid 3.
|
||||
array_pop($tests[3]['expected_data']);
|
||||
$tests[3]['expected_count'] = NULL;
|
||||
$tests[3]['configuration']['bundle'] = ['5', '6'];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
/**
|
||||
* Tests the taxonomy term source with vocabulary filter.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d7\Term
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermSourceWithVocabularyFilterTest extends TermTest {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function providerSource() {
|
||||
// Get the source data from parent.
|
||||
$tests = parent::providerSource();
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4',
|
||||
'description' => 'description value 4',
|
||||
'weight' => 1,
|
||||
'parent' => [1],
|
||||
],
|
||||
];
|
||||
|
||||
// We know there are two rows with machine_name == 'tags'.
|
||||
$tests[0]['expected_count'] = 2;
|
||||
|
||||
// Set up source plugin configuration.
|
||||
$tests[0]['configuration'] = [
|
||||
'bundle' => ['tags'],
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,258 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests taxonomy term source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d7\Term
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['taxonomy_term_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 2',
|
||||
'description' => 'description value 2',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 3',
|
||||
'description' => 'description value 3',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4',
|
||||
'description' => 'description value 4',
|
||||
'weight' => 1,
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 5',
|
||||
'description' => 'description value 5',
|
||||
'weight' => 1,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 6',
|
||||
'description' => 'description value 6',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'vid' => 3,
|
||||
'name' => 'name value 7',
|
||||
'description' => 'description value 7',
|
||||
'weight' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['taxonomy_term_hierarchy'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'parent' => 1,
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'parent' => 2,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'parent' => 3,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'parent' => 2,
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'parent' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['taxonomy_vocabulary'] = [
|
||||
[
|
||||
'vid' => 5,
|
||||
'machine_name' => 'tags',
|
||||
],
|
||||
[
|
||||
'vid' => 6,
|
||||
'machine_name' => 'categories',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_config_instance'] = [
|
||||
[
|
||||
'field_name' => 'field_term_field',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => 0,
|
||||
],
|
||||
[
|
||||
'field_name' => 'field_term_field',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'categories',
|
||||
'deleted' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_data_field_term_field'] = [
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => 0,
|
||||
'entity_id' => 1,
|
||||
'delta' => 0,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'categories',
|
||||
'deleted' => 0,
|
||||
'entity_id' => 1,
|
||||
'delta' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 2',
|
||||
'description' => 'description value 2',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 3',
|
||||
'description' => 'description value 3',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4',
|
||||
'description' => 'description value 4',
|
||||
'weight' => 1,
|
||||
'parent' => [1],
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 5',
|
||||
'description' => 'description value 5',
|
||||
'weight' => 1,
|
||||
'parent' => [2],
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 6',
|
||||
'description' => 'description value 6',
|
||||
'weight' => 0,
|
||||
'parent' => [3, 2],
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'vid' => 3,
|
||||
'name' => 'name value 7',
|
||||
'description' => 'description value 7',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['expected_count'] = NULL;
|
||||
// Empty configuration will return terms for all vocabularies.
|
||||
$tests[0]['configuration'] = [];
|
||||
|
||||
// Change configuration to get one vocabulary, "tags".
|
||||
$tests[1]['source_data'] = $tests[0]['source_data'];
|
||||
$tests[1]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4',
|
||||
'description' => 'description value 4',
|
||||
'weight' => 1,
|
||||
'parent' => [1],
|
||||
],
|
||||
];
|
||||
$tests[1]['expected_count'] = NULL;
|
||||
$tests[1]['configuration']['bundle'] = ['tags'];
|
||||
|
||||
// Same as previous test, but with configuration vocabulary as a string
|
||||
// instead of an array.
|
||||
$tests[2]['source_data'] = $tests[0]['source_data'];
|
||||
$tests[2]['expected_data'] = $tests[1]['expected_data'];
|
||||
$tests[2]['expected_count'] = NULL;
|
||||
$tests[2]['configuration']['bundle'] = 'tags';
|
||||
|
||||
// Change configuration to get two vocabularies, "tags" and "categories".
|
||||
$tests[3]['source_data'] = $tests[0]['source_data'];
|
||||
$tests[3]['expected_data'] = $tests[0]['expected_data'];
|
||||
// Remove the last element because it is for vid 3.
|
||||
array_pop($tests[3]['expected_data']);
|
||||
$tests[3]['expected_count'] = NULL;
|
||||
$tests[3]['configuration']['bundle'] = ['tags', 'categories'];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
|
@ -3,12 +3,8 @@ label: Profile values
|
|||
class: Drupal\user\Plugin\migrate\ProfileValues
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
builder:
|
||||
plugin: d6_profile_values
|
||||
source:
|
||||
plugin: d6_profile_field_values
|
||||
load:
|
||||
plugin: drupal_entity
|
||||
process:
|
||||
uid: uid
|
||||
destination:
|
||||
|
|
|
@ -233,7 +233,7 @@ class UserAuthenticationController extends ControllerBase implements ContainerIn
|
|||
/**
|
||||
* Logs out a user.
|
||||
*
|
||||
* @return \Drupal\rest\ResourceResponse
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* The response object.
|
||||
*/
|
||||
public function logout() {
|
||||
|
|
|
@ -1172,7 +1172,7 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheableDepend
|
|||
* Moves argument options into their place.
|
||||
*
|
||||
* When configuring the default argument behavior, almost each of the radio
|
||||
* buttons has its own fieldset shown bellow it when the radio button is
|
||||
* buttons has its own fieldset shown below it when the radio button is
|
||||
* clicked. That fieldset is created through a custom form process callback.
|
||||
* Each element that has #argument_option defined and pointing to a default
|
||||
* behavior gets moved to the appropriate fieldset.
|
||||
|
|
|
@ -206,7 +206,7 @@ class InOperator extends FilterPluginBase {
|
|||
}
|
||||
|
||||
if (empty($this->options['expose']['multiple'])) {
|
||||
if (empty($this->options['expose']['required']) && (empty($default_value) || !empty($this->options['expose']['reduce']))) {
|
||||
if (empty($this->options['expose']['required']) && (empty($default_value) || !empty($this->options['expose']['reduce'])) || isset($this->options['value']['all'])) {
|
||||
$default_value = 'All';
|
||||
}
|
||||
elseif (empty($default_value)) {
|
||||
|
|
|
@ -18,19 +18,24 @@ class FilterTest extends PluginTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = array('test_filter');
|
||||
public static $testViews = array('test_filter', 'test_filter_in_operator_ui');
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('views_ui');
|
||||
public static $modules = array('views_ui', 'node');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
|
||||
$this->adminUser = $this->drupalCreateUser(array('administer views'));
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Page']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -138,4 +143,23 @@ class FilterTest extends PluginTestBase {
|
|||
$this->assertEqual(count($view->result), 5, format_string('All @count results returned', array('@count' => count($view->displayHandlers))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test no error message is displayed when all options are selected in an
|
||||
* exposed filter.
|
||||
*/
|
||||
public function testInOperatorSelectAllOptions() {
|
||||
$view = Views::getView('test_filter_in_operator_ui');
|
||||
$row['row[type]'] = 'fields';
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_filter_in_operator_ui/default/row', $row, t('Apply'));
|
||||
$field['name[node_field_data.nid]'] = TRUE;
|
||||
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_filter_in_operator_ui/default/field', $field, t('Add and configure fields'));
|
||||
$this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_in_operator_ui/default/field/nid', [], t('Apply'));
|
||||
$edit['options[value][all]'] = TRUE;
|
||||
$edit['options[value][article]'] = TRUE;
|
||||
$edit['options[value][page]'] = TRUE;
|
||||
$this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_in_operator_ui/default/filter/type', $edit, t('Apply'));
|
||||
$this->drupalPostForm('admin/structure/views/view/test_filter_in_operator_ui/edit/default', [], t('Save'));
|
||||
$this->drupalPostForm(NULL, [], t('Update preview'));
|
||||
$this->assertNoText('An illegal choice has been detected.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ class Views {
|
|||
/**
|
||||
* Returns the views data helper service.
|
||||
*
|
||||
* @return \Drupal\views\ViewsData
|
||||
* @return \Drupal\views\ViewsDataHelper
|
||||
* Returns a views data helper object.
|
||||
*/
|
||||
public static function viewsDataHelper() {
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
namespace Drupal\FunctionalJavascriptTests;
|
||||
|
||||
use Behat\Mink\Element\NodeElement;
|
||||
use Behat\Mink\Exception\ElementHtmlException;
|
||||
use Behat\Mink\Exception\ElementNotFoundException;
|
||||
use Behat\Mink\Exception\UnsupportedDriverActionException;
|
||||
use Drupal\Tests\WebAssert;
|
||||
|
||||
/**
|
||||
|
@ -39,4 +43,199 @@ class JSWebAssert extends WebAssert {
|
|||
$this->assertWaitOnAjaxRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a node, or it's specific corner, is visible in the viewport.
|
||||
*
|
||||
* Note: Always set the viewport size. This can be done with a PhantomJS
|
||||
* startup parameter or in your test with \Behat\Mink\Session->resizeWindow().
|
||||
* Drupal CI Javascript tests by default use a viewport of 1024x768px.
|
||||
*
|
||||
* @param string $selector_type
|
||||
* The element selector type (CSS, XPath).
|
||||
* @param string|array $selector
|
||||
* The element selector. Note: the first found element is used.
|
||||
* @param bool|string $corner
|
||||
* (Optional) The corner to test:
|
||||
* topLeft, topRight, bottomRight, bottomLeft.
|
||||
* Or FALSE to check the complete element (default).
|
||||
* @param string $message
|
||||
* (optional) A message for the exception.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ElementHtmlException
|
||||
* When the element doesn't exist.
|
||||
* @throws \Behat\Mink\Exception\ElementNotFoundException
|
||||
* When the element is not visible in the viewport.
|
||||
*/
|
||||
public function assertVisibleInViewport($selector_type, $selector, $corner = FALSE, $message = 'Element is not visible in the viewport.') {
|
||||
$node = $this->session->getPage()->find($selector_type, $selector);
|
||||
if ($node === NULL) {
|
||||
if (is_array($selector)) {
|
||||
$selector = implode(' ', $selector);
|
||||
}
|
||||
throw new ElementNotFoundException($this->session->getDriver(), 'element', $selector_type, $selector);
|
||||
}
|
||||
|
||||
// Check if the node is visible on the page, which is a prerequisite of
|
||||
// being visible in the viewport.
|
||||
if (!$node->isVisible()) {
|
||||
throw new ElementHtmlException($message, $this->session->getDriver(), $node);
|
||||
}
|
||||
|
||||
$result = $this->checkNodeVisibilityInViewport($node, $corner);
|
||||
|
||||
if (!$result) {
|
||||
throw new ElementHtmlException($message, $this->session->getDriver(), $node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a node, or its specific corner, is not visible in the viewport.
|
||||
*
|
||||
* Note: the node should exist in the page, otherwise this assertion fails.
|
||||
*
|
||||
* @param string $selector_type
|
||||
* The element selector type (CSS, XPath).
|
||||
* @param string|array $selector
|
||||
* The element selector. Note: the first found element is used.
|
||||
* @param bool|string $corner
|
||||
* (Optional) Corner to test: topLeft, topRight, bottomRight, bottomLeft.
|
||||
* Or FALSE to check the complete element (default).
|
||||
* @param string $message
|
||||
* (optional) A message for the exception.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ElementHtmlException
|
||||
* When the element doesn't exist.
|
||||
* @throws \Behat\Mink\Exception\ElementNotFoundException
|
||||
* When the element is not visible in the viewport.
|
||||
*
|
||||
* @see \Drupal\FunctionalJavascriptTests\JSWebAssert::assertVisibleInViewport()
|
||||
*/
|
||||
public function assertNotVisibleInViewport($selector_type, $selector, $corner = FALSE, $message = 'Element is visible in the viewport.') {
|
||||
$node = $this->session->getPage()->find($selector_type, $selector);
|
||||
if ($node === NULL) {
|
||||
if (is_array($selector)) {
|
||||
$selector = implode(' ', $selector);
|
||||
}
|
||||
throw new ElementNotFoundException($this->session->getDriver(), 'element', $selector_type, $selector);
|
||||
}
|
||||
|
||||
$result = $this->checkNodeVisibilityInViewport($node, $corner);
|
||||
|
||||
if ($result) {
|
||||
throw new ElementHtmlException($message, $this->session->getDriver(), $node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the visibility of a node, or it's specific corner.
|
||||
*
|
||||
* @param \Behat\Mink\Element\NodeElement $node
|
||||
* A valid node.
|
||||
* @param bool|string $corner
|
||||
* (Optional) Corner to test: topLeft, topRight, bottomRight, bottomLeft.
|
||||
* Or FALSE to check the complete element (default).
|
||||
*
|
||||
* @return bool
|
||||
* Returns TRUE if the node is visible in the viewport, FALSE otherwise.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\UnsupportedDriverActionException
|
||||
* When an invalid corner specification is given.
|
||||
*/
|
||||
private function checkNodeVisibilityInViewport(NodeElement $node, $corner = FALSE) {
|
||||
$xpath = $node->getXpath();
|
||||
|
||||
// Build the Javascript to test if the complete element or a specific corner
|
||||
// is in the viewport.
|
||||
switch ($corner) {
|
||||
case 'topLeft':
|
||||
$test_javascript_function = <<<JS
|
||||
function t(r, lx, ly) {
|
||||
return (
|
||||
r.top >= 0 &&
|
||||
r.top <= ly &&
|
||||
r.left >= 0 &&
|
||||
r.left <= lx
|
||||
)
|
||||
}
|
||||
JS;
|
||||
break;
|
||||
|
||||
case 'topRight':
|
||||
$test_javascript_function = <<<JS
|
||||
function t(r, lx, ly) {
|
||||
return (
|
||||
r.top >= 0 &&
|
||||
r.top <= ly &&
|
||||
r.right >= 0 &&
|
||||
r.right <= lx
|
||||
);
|
||||
}
|
||||
JS;
|
||||
break;
|
||||
|
||||
case 'bottomRight':
|
||||
$test_javascript_function = <<<JS
|
||||
function t(r, lx, ly) {
|
||||
return (
|
||||
r.bottom >= 0 &&
|
||||
r.bottom <= ly &&
|
||||
r.right >= 0 &&
|
||||
r.right <= lx
|
||||
);
|
||||
}
|
||||
JS;
|
||||
break;
|
||||
|
||||
case 'bottomLeft':
|
||||
$test_javascript_function = <<<JS
|
||||
function t(r, lx, ly) {
|
||||
return (
|
||||
r.bottom >= 0 &&
|
||||
r.bottom <= ly &&
|
||||
r.left >= 0 &&
|
||||
r.left <= lx
|
||||
);
|
||||
}
|
||||
JS;
|
||||
break;
|
||||
|
||||
case FALSE:
|
||||
$test_javascript_function = <<<JS
|
||||
function t(r, lx, ly) {
|
||||
return (
|
||||
r.top >= 0 &&
|
||||
r.left >= 0 &&
|
||||
r.bottom <= ly &&
|
||||
r.right <= lx
|
||||
);
|
||||
}
|
||||
JS;
|
||||
break;
|
||||
|
||||
// Throw an exception if an invalid corner parameter is given.
|
||||
default:
|
||||
throw new UnsupportedDriverActionException($corner, $this->session->getDriver());
|
||||
}
|
||||
|
||||
// Build the full Javascript test. The shared logic gets the corner
|
||||
// specific test logic injected.
|
||||
$full_javascript_visibility_test = <<<JS
|
||||
(function(t){
|
||||
var w = window,
|
||||
d = document,
|
||||
e = d.documentElement,
|
||||
n = d.evaluate("$xpath", d, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue,
|
||||
r = n.getBoundingClientRect(),
|
||||
lx = (w.innerWidth || e.clientWidth),
|
||||
ly = (w.innerHeight || e.clientHeight);
|
||||
|
||||
return t(r, lx, ly);
|
||||
}($test_javascript_function));
|
||||
JS;
|
||||
|
||||
// Check the visibility by injecting and executing the full Javascript test
|
||||
// script in the page.
|
||||
return $this->session->evaluateScript($full_javascript_visibility_test);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array();
|
||||
protected static $modules = array();
|
||||
|
||||
/**
|
||||
* The virtual filesystem root directory.
|
||||
|
|
|
@ -175,7 +175,7 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
*
|
||||
* @see \Drupal\Tests\BrowserTestBase::installDrupal()
|
||||
*/
|
||||
public static $modules = [];
|
||||
protected static $modules = [];
|
||||
|
||||
/**
|
||||
* An array of config object names that are excluded from schema checking.
|
||||
|
|
|
@ -762,13 +762,7 @@ if (file_exists(__DIR__ . '/settings.pantheon.php')) {
|
|||
*
|
||||
* Keep this code block at the end of this file to take full effect.
|
||||
*/
|
||||
<<<<<<< HEAD
|
||||
if (file_exists(__DIR__ . '/settings.local.php')) {
|
||||
include __DIR__ . '/settings.local.php';
|
||||
}
|
||||
=======
|
||||
#
|
||||
# if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) {
|
||||
# include $app_root . '/' . $site_path . '/settings.local.php';
|
||||
# }
|
||||
>>>>>>> b96f629ea4b63fb16b11b89c0a88fb8524e82359
|
||||
|
|
2
vendor/autoload.php
vendored
2
vendor/autoload.php
vendored
|
@ -2,6 +2,6 @@
|
|||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
require_once __DIR__ . '/composer' . '/autoload_real.php';
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInitDrupal8::getLoader();
|
||||
|
|
48
vendor/composer/ClassLoader.php
vendored
48
vendor/composer/ClassLoader.php
vendored
|
@ -53,8 +53,9 @@ class ClassLoader
|
|||
|
||||
private $useIncludePath = false;
|
||||
private $classMap = array();
|
||||
|
||||
private $classMapAuthoritative = false;
|
||||
private $missingClasses = array();
|
||||
private $apcuPrefix;
|
||||
|
||||
public function getPrefixes()
|
||||
{
|
||||
|
@ -271,6 +272,26 @@ class ClassLoader
|
|||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
|
@ -313,29 +334,34 @@ class ClassLoader
|
|||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
|
||||
if ('\\' == $class[0]) {
|
||||
$class = substr($class, 1);
|
||||
}
|
||||
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative) {
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if ($file === null && defined('HHVM_VERSION')) {
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if ($file === null) {
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
return $this->classMap[$class] = false;
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
|
@ -399,6 +425,8 @@ class ClassLoader
|
|||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
2
vendor/composer/LICENSE
vendored
2
vendor/composer/LICENSE
vendored
|
@ -1,3 +1,4 @@
|
|||
|
||||
Copyright (c) 2016 Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
@ -17,3 +18,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
|
2
vendor/composer/autoload_real.php
vendored
2
vendor/composer/autoload_real.php
vendored
|
@ -23,7 +23,7 @@ class ComposerAutoloaderInitDrupal8
|
|||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInitDrupal8', 'loadClassLoader'));
|
||||
|
||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
|
||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||
if ($useStaticLoader) {
|
||||
require_once __DIR__ . '/autoload_static.php';
|
||||
|
||||
|
|
148
vendor/composer/installed.json
vendored
148
vendor/composer/installed.json
vendored
|
@ -22,7 +22,7 @@
|
|||
"composer/composer": "1.0.*@dev",
|
||||
"phpunit/phpunit": "4.1.*"
|
||||
},
|
||||
"time": "2015-02-18 17:17:01",
|
||||
"time": "2015-02-18T17:17:01+00:00",
|
||||
"type": "composer-installer",
|
||||
"extra": {
|
||||
"class": "Composer\\Installers\\Installer",
|
||||
|
@ -121,7 +121,7 @@
|
|||
"phpunit/phpunit": "~4.8|~5.0",
|
||||
"squizlabs/php_codesniffer": "~2.1.0"
|
||||
},
|
||||
"time": "2016-03-08 17:11:37",
|
||||
"time": "2016-03-08T17:11:37+00:00",
|
||||
"type": "composer-plugin",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -165,7 +165,7 @@
|
|||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*"
|
||||
},
|
||||
"time": "2014-11-20 16:49:30",
|
||||
"time": "2014-11-20T16:49:30+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
@ -210,7 +210,7 @@
|
|||
"ircmaxell/password-compat": "~1.0",
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"time": "2016-01-20 09:13:37",
|
||||
"time": "2016-01-20T09:13:37+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -267,7 +267,7 @@
|
|||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"time": "2016-01-20 09:13:37",
|
||||
"time": "2016-01-20T09:13:37+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -330,7 +330,7 @@
|
|||
"suggest": {
|
||||
"ext-mbstring": "For best performance"
|
||||
},
|
||||
"time": "2016-01-20 09:13:37",
|
||||
"time": "2016-01-20T09:13:37+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -394,7 +394,7 @@
|
|||
"require-dev": {
|
||||
"symfony/expression-language": "~2.4|~3.0.0"
|
||||
},
|
||||
"time": "2016-03-27 12:57:53",
|
||||
"time": "2016-03-27T12:57:53+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -456,7 +456,7 @@
|
|||
"symfony/dependency-injection": "",
|
||||
"symfony/http-kernel": ""
|
||||
},
|
||||
"time": "2016-03-07 14:04:32",
|
||||
"time": "2016-03-07T14:04:32+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -504,7 +504,7 @@
|
|||
"reference": "1.0.0",
|
||||
"shasum": ""
|
||||
},
|
||||
"time": "2012-12-21 11:40:51",
|
||||
"time": "2012-12-21T11:40:51+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
@ -555,7 +555,7 @@
|
|||
"symfony/class-loader": "~2.2",
|
||||
"symfony/http-kernel": "~2.3.24|~2.5.9|~2.6,>=2.6.2"
|
||||
},
|
||||
"time": "2015-10-11 09:39:48",
|
||||
"time": "2015-10-11T09:39:48+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -636,7 +636,7 @@
|
|||
"symfony/finder": "",
|
||||
"symfony/var-dumper": ""
|
||||
},
|
||||
"time": "2016-03-25 01:40:30",
|
||||
"time": "2016-03-25T01:40:30+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -689,7 +689,7 @@
|
|||
"symfony/http-foundation": "~2.1|~3.0",
|
||||
"symfony/http-kernel": "~2.1|~3.0"
|
||||
},
|
||||
"time": "2016-08-01 12:05:04",
|
||||
"time": "2016-08-01T12:05:04+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
@ -736,7 +736,7 @@
|
|||
"phpunit/phpunit": "~4.5",
|
||||
"phpunit/phpunit-mock-objects": "~2.3"
|
||||
},
|
||||
"time": "2015-09-21 09:42:36",
|
||||
"time": "2015-09-21T09:42:36+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -795,7 +795,7 @@
|
|||
"require": {
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"time": "2014-09-09 13:34:57",
|
||||
"time": "2014-09-09T13:34:57+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -854,7 +854,7 @@
|
|||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*"
|
||||
},
|
||||
"time": "2014-12-20 21:24:13",
|
||||
"time": "2014-12-20T21:24:13+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -923,7 +923,7 @@
|
|||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"time": "2015-04-14 22:21:58",
|
||||
"time": "2015-04-14T22:21:58+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -996,7 +996,7 @@
|
|||
"predis/predis": "~1.0",
|
||||
"satooshi/php-coveralls": "~0.6"
|
||||
},
|
||||
"time": "2015-08-31 12:36:41",
|
||||
"time": "2015-08-31T12:36:41+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1065,7 +1065,7 @@
|
|||
"doctrine/cache": "1.*",
|
||||
"phpunit/phpunit": "4.*"
|
||||
},
|
||||
"time": "2015-08-31 12:32:49",
|
||||
"time": "2015-08-31T12:32:49+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1138,7 +1138,7 @@
|
|||
"require-dev": {
|
||||
"phpunit/phpunit": "~3.7"
|
||||
},
|
||||
"time": "2015-08-31 13:00:22",
|
||||
"time": "2015-08-31T13:00:22+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1215,7 +1215,7 @@
|
|||
"suggest": {
|
||||
"ml/json-ld": "~1.0"
|
||||
},
|
||||
"time": "2015-02-27 09:45:49",
|
||||
"time": "2015-02-27T09:45:49+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
@ -1274,7 +1274,7 @@
|
|||
"phpunit/phpunit": "~4.4",
|
||||
"satooshi/php-coveralls": "dev-master"
|
||||
},
|
||||
"time": "2015-06-22 21:07:51",
|
||||
"time": "2015-06-22T21:07:51+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1327,7 +1327,7 @@
|
|||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"time": "2016-05-18 16:56:05",
|
||||
"time": "2016-05-18T16:56:05+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1377,7 +1377,7 @@
|
|||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"time": "2015-05-04 20:22:00",
|
||||
"time": "2015-05-04T20:22:00+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1435,7 +1435,7 @@
|
|||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"time": "2016-06-24 23:00:38",
|
||||
"time": "2016-06-24T23:00:38+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1494,7 +1494,7 @@
|
|||
"sami/sami": "~2.0",
|
||||
"satooshi/php-coveralls": "1.0.*"
|
||||
},
|
||||
"time": "2016-05-10 14:11:45",
|
||||
"time": "2016-05-10T14:11:45+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1561,7 +1561,7 @@
|
|||
"suggest": {
|
||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
||||
},
|
||||
"time": "2015-12-01 02:52:15",
|
||||
"time": "2015-12-01T02:52:15+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
@ -1610,7 +1610,7 @@
|
|||
"require-dev": {
|
||||
"silex/silex": "~1.0"
|
||||
},
|
||||
"time": "2016-06-02 06:58:42",
|
||||
"time": "2016-06-02T06:58:42+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1676,7 +1676,7 @@
|
|||
"symfony/http-foundation": "For using a Symfony Request object",
|
||||
"symfony/yaml": "For using the YAML loader"
|
||||
},
|
||||
"time": "2016-03-23 13:11:46",
|
||||
"time": "2016-03-23T13:11:46+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1746,7 +1746,7 @@
|
|||
"suggest": {
|
||||
"symfony/event-dispatcher": "DynamicRouter can optionally trigger an event at the start of matching. Minimal version (~2.1)"
|
||||
},
|
||||
"time": "2016-03-31 09:11:39",
|
||||
"time": "2016-03-31T09:11:39+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1794,7 +1794,7 @@
|
|||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"time": "2016-03-03 16:49:40",
|
||||
"time": "2016-03-03T16:49:40+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1853,7 +1853,7 @@
|
|||
"require-dev": {
|
||||
"symfony/finder": "~2.0,>=2.0.5|~3.0.0"
|
||||
},
|
||||
"time": "2016-03-10 19:33:53",
|
||||
"time": "2016-03-10T19:33:53+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1915,7 +1915,7 @@
|
|||
"symfony/event-dispatcher": "",
|
||||
"symfony/process": ""
|
||||
},
|
||||
"time": "2016-03-17 09:19:04",
|
||||
"time": "2016-03-17T09:19:04+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1979,7 +1979,7 @@
|
|||
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
|
||||
"symfony/yaml": ""
|
||||
},
|
||||
"time": "2016-03-21 07:27:21",
|
||||
"time": "2016-03-21T07:27:21+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2033,7 +2033,7 @@
|
|||
"suggest": {
|
||||
"ext-iconv": "For best performance"
|
||||
},
|
||||
"time": "2016-02-26 11:31:02",
|
||||
"time": "2016-02-26T11:31:02+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2091,7 +2091,7 @@
|
|||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"time": "2016-03-23 13:11:46",
|
||||
"time": "2016-03-23T13:11:46+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2150,7 +2150,7 @@
|
|||
"suggest": {
|
||||
"zendframework/zend-diactoros": "To use the Zend Diactoros factory"
|
||||
},
|
||||
"time": "2015-05-29 17:57:12",
|
||||
"time": "2015-05-29T17:57:12+00:00",
|
||||
"type": "symfony-bridge",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
@ -2213,7 +2213,7 @@
|
|||
"symfony/property-access": "For using the ObjectNormalizer.",
|
||||
"symfony/yaml": "For using the default YAML mapping loader."
|
||||
},
|
||||
"time": "2016-03-07 14:04:32",
|
||||
"time": "2016-03-07T14:04:32+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2279,7 +2279,7 @@
|
|||
"symfony/config": "",
|
||||
"symfony/yaml": ""
|
||||
},
|
||||
"time": "2016-03-25 01:40:30",
|
||||
"time": "2016-03-25T01:40:30+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2353,7 +2353,7 @@
|
|||
"symfony/property-access": "For using the 2.4 Validator API",
|
||||
"symfony/yaml": ""
|
||||
},
|
||||
"time": "2016-03-27 12:57:53",
|
||||
"time": "2016-03-27T12:57:53+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2412,7 +2412,7 @@
|
|||
"phpunit/phpunit": "~4.6",
|
||||
"squizlabs/php_codesniffer": "^2.3.1"
|
||||
},
|
||||
"time": "2015-08-10 20:04:20",
|
||||
"time": "2015-08-10T20:04:20+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2474,7 +2474,7 @@
|
|||
"zendframework/zend-serializer": "Zend\\Serializer component",
|
||||
"zendframework/zend-servicemanager": "To support hydrator plugin manager usage"
|
||||
},
|
||||
"time": "2015-09-25 04:06:33",
|
||||
"time": "2015-09-25T04:06:33+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2532,7 +2532,7 @@
|
|||
"zendframework/zend-serializer": "^2.5.1, to use the SerializableStrategy",
|
||||
"zendframework/zend-servicemanager": "^2.5.1, to support hydrator plugin manager usage"
|
||||
},
|
||||
"time": "2015-09-17 14:06:43",
|
||||
"time": "2015-09-17T14:06:43+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2578,7 +2578,7 @@
|
|||
"fabpot/php-cs-fixer": "1.7.*",
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"time": "2015-06-03 14:05:37",
|
||||
"time": "2015-06-03T14:05:37+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2638,7 +2638,7 @@
|
|||
"zendframework/zend-servicemanager": "Zend\\ServiceManager component, for default/recommended ExtensionManager implementations",
|
||||
"zendframework/zend-validator": "Zend\\Validator component"
|
||||
},
|
||||
"time": "2015-08-04 21:39:18",
|
||||
"time": "2015-08-04T21:39:18+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2687,7 +2687,7 @@
|
|||
"suggest": {
|
||||
"symfony/css-selector": ""
|
||||
},
|
||||
"time": "2015-10-11 09:39:48",
|
||||
"time": "2015-10-11T09:39:48+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2735,7 +2735,7 @@
|
|||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"time": "2016-03-04 07:54:35",
|
||||
"time": "2016-03-04T07:54:35+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2798,7 +2798,7 @@
|
|||
"suggest": {
|
||||
"symfony/process": ""
|
||||
},
|
||||
"time": "2015-10-23 14:47:27",
|
||||
"time": "2015-10-23T14:47:27+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2853,7 +2853,7 @@
|
|||
"phpunit/phpunit": "^4.0",
|
||||
"psr/log": "^1.0"
|
||||
},
|
||||
"time": "2016-07-15 17:22:37",
|
||||
"time": "2016-07-15T17:22:37+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2914,7 +2914,7 @@
|
|||
"symfony/css-selector": "~2.1|~3.0",
|
||||
"symfony/dom-crawler": "~2.1|~3.0"
|
||||
},
|
||||
"time": "2015-11-05 12:58:44",
|
||||
"time": "2015-11-05T12:58:44+00:00",
|
||||
"type": "application",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -2971,7 +2971,7 @@
|
|||
"behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)",
|
||||
"behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)"
|
||||
},
|
||||
"time": "2016-03-05 08:26:18",
|
||||
"time": "2016-03-05T08:26:18+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3028,7 +3028,7 @@
|
|||
"silex/silex": "~1.2",
|
||||
"symfony/phpunit-bridge": "~2.7|~3.0"
|
||||
},
|
||||
"time": "2016-03-05 08:59:47",
|
||||
"time": "2016-03-05T08:59:47+00:00",
|
||||
"type": "mink-driver",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3085,7 +3085,7 @@
|
|||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7|~3.0"
|
||||
},
|
||||
"time": "2016-03-05 09:04:22",
|
||||
"time": "2016-03-05T09:04:22+00:00",
|
||||
"type": "mink-driver",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3140,7 +3140,7 @@
|
|||
"symfony/debug": "~2.7",
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"time": "2016-01-25 21:22:18",
|
||||
"time": "2016-01-25T21:22:18+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3206,7 +3206,7 @@
|
|||
"symfony/phpunit-bridge": "~2.7",
|
||||
"symfony/process": "~2.1"
|
||||
},
|
||||
"time": "2016-01-18 09:21:03",
|
||||
"time": "2016-01-18T09:21:03+00:00",
|
||||
"type": "phantomjs-api",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3268,7 +3268,7 @@
|
|||
"symfony/phpunit-bridge": "~2.7",
|
||||
"symfony/process": "~2.3"
|
||||
},
|
||||
"time": "2015-12-04 13:55:02",
|
||||
"time": "2015-12-04T13:55:02+00:00",
|
||||
"type": "mink-driver",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3324,7 +3324,7 @@
|
|||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.5"
|
||||
},
|
||||
"time": "2015-10-06 16:59:57",
|
||||
"time": "2015-10-06T16:59:57+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3376,7 +3376,7 @@
|
|||
"dflydev/markdown": "~1.0",
|
||||
"erusev/parsedown": "~1.0"
|
||||
},
|
||||
"time": "2015-02-03 12:10:50",
|
||||
"time": "2015-02-03T12:10:50+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3424,7 +3424,7 @@
|
|||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.2"
|
||||
},
|
||||
"time": "2015-09-15 10:49:45",
|
||||
"time": "2015-09-15T10:49:45+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3471,7 +3471,7 @@
|
|||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"time": "2016-03-04 07:54:35",
|
||||
"time": "2016-03-04T07:54:35+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3519,7 +3519,7 @@
|
|||
"reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
|
||||
"shasum": ""
|
||||
},
|
||||
"time": "2015-06-21 13:59:46",
|
||||
"time": "2015-06-21T13:59:46+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
@ -3565,7 +3565,7 @@
|
|||
"suggest": {
|
||||
"ext-uopz": "*"
|
||||
},
|
||||
"time": "2014-10-06 09:23:50",
|
||||
"time": "2014-10-06T09:23:50+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3615,7 +3615,7 @@
|
|||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"time": "2015-06-21 08:04:50",
|
||||
"time": "2015-06-21T08:04:50+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3671,7 +3671,7 @@
|
|||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"time": "2015-06-21 07:55:53",
|
||||
"time": "2015-06-21T07:55:53+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3738,7 +3738,7 @@
|
|||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"time": "2015-08-03 06:14:51",
|
||||
"time": "2015-08-03T06:14:51+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3790,7 +3790,7 @@
|
|||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.2"
|
||||
},
|
||||
"time": "2015-02-22 15:13:53",
|
||||
"time": "2015-02-22T15:13:53+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3846,7 +3846,7 @@
|
|||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"time": "2015-07-26 15:48:44",
|
||||
"time": "2015-07-26T15:48:44+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -3907,7 +3907,7 @@
|
|||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"time": "2015-06-21 13:50:34",
|
||||
"time": "2015-06-21T13:50:34+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
@ -3957,7 +3957,7 @@
|
|||
"phpunit/phpunit": "~4.0",
|
||||
"squizlabs/php_codesniffer": "~2.0"
|
||||
},
|
||||
"time": "2015-06-14 21:17:01",
|
||||
"time": "2015-06-14T21:17:01+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -4015,7 +4015,7 @@
|
|||
"suggest": {
|
||||
"ext-soap": "*"
|
||||
},
|
||||
"time": "2015-10-02 06:51:40",
|
||||
"time": "2015-10-02T06:51:40+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -4064,7 +4064,7 @@
|
|||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"time": "2015-06-21 08:01:12",
|
||||
"time": "2015-06-21T08:01:12+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
@ -4107,7 +4107,7 @@
|
|||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"time": "2015-06-21 13:08:43",
|
||||
"time": "2015-06-21T13:08:43+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -4170,7 +4170,7 @@
|
|||
"ext-xdebug": ">=2.2.1",
|
||||
"ext-xmlwriter": "*"
|
||||
},
|
||||
"time": "2015-10-06 15:47:00",
|
||||
"time": "2015-10-06T15:47:00+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -4225,7 +4225,7 @@
|
|||
"require-dev": {
|
||||
"phpspec/phpspec": "~2.0"
|
||||
},
|
||||
"time": "2015-08-13 10:07:40",
|
||||
"time": "2015-08-13T10:07:40+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -4303,7 +4303,7 @@
|
|||
"suggest": {
|
||||
"phpunit/php-invoker": "~1.1"
|
||||
},
|
||||
"time": "2016-07-21 06:48:14",
|
||||
"time": "2016-07-21T06:48:14+00:00",
|
||||
"bin": [
|
||||
"phpunit"
|
||||
],
|
||||
|
|
Reference in a new issue