upgrades core to 8.4.2

This commit is contained in:
Bachir Soussi Chiadmi
2017-11-14 16:09:54 +01:00
parent bd60eff9b3
commit c2b4e25be4
3504 changed files with 140306 additions and 38684 deletions
@@ -3,4 +3,4 @@ description:
length: 128
icon:
directory: 'core/modules/file/icons'
make_unused_managed_files_temporary: false
@@ -565,7 +565,7 @@ display:
decimal: .
separator: ','
format_plural: true
format_plural_string: "1 place\x03@count places"
format_plural_string: !!binary MSBwbGFjZQNAY291bnQgcGxhY2Vz
prefix: ''
suffix: ''
plugin_id: numeric
@@ -1007,7 +1007,7 @@ display:
decimal: .
separator: ','
format_plural: false
format_plural_string: "1\x03@count"
format_plural_string: !!binary MQNAY291bnQ=
prefix: ''
suffix: ''
plugin_id: numeric
@@ -21,6 +21,9 @@ file.settings:
directory:
type: path
label: 'Directory'
make_unused_managed_files_temporary:
type: boolean
label: 'Controls if unused files should be marked temporary'
field.storage_settings.file:
type: base_entity_reference_field_settings
@@ -48,7 +51,7 @@ base_file_field_field_settings:
label: 'Reference method'
handler_settings:
type: entity_reference_selection.[%parent.handler]
label: 'Entity reference selection settings'
label: 'File selection handler settings'
file_directory:
type: string
label: 'File directory'
+253
View File
@@ -0,0 +1,253 @@
/**
* @file
* Provides JavaScript additions to the managed file field type.
*
* This file provides progress bar support (if available), popup windows for
* file previews, and disabling of other file fields during Ajax uploads (which
* prevents separate file fields from accidentally uploading files).
*/
(function ($, Drupal) {
/**
* Attach behaviors to the file fields passed in the settings.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches validation for file extensions.
* @prop {Drupal~behaviorDetach} detach
* Detaches validation for file extensions.
*/
Drupal.behaviors.fileValidateAutoAttach = {
attach(context, settings) {
const $context = $(context);
let elements;
function initFileValidation(selector) {
$context.find(selector)
.once('fileValidate')
.on('change.fileValidate', { extensions: elements[selector] }, Drupal.file.validateExtension);
}
if (settings.file && settings.file.elements) {
elements = settings.file.elements;
Object.keys(elements).forEach(initFileValidation);
}
},
detach(context, settings, trigger) {
const $context = $(context);
let elements;
function removeFileValidation(selector) {
$context.find(selector)
.removeOnce('fileValidate')
.off('change.fileValidate', Drupal.file.validateExtension);
}
if (trigger === 'unload' && settings.file && settings.file.elements) {
elements = settings.file.elements;
Object.keys(elements).forEach(removeFileValidation);
}
},
};
/**
* Attach behaviors to file element auto upload.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches triggers for the upload button.
* @prop {Drupal~behaviorDetach} detach
* Detaches auto file upload trigger.
*/
Drupal.behaviors.fileAutoUpload = {
attach(context) {
$(context).find('input[type="file"]').once('auto-file-upload').on('change.autoFileUpload', Drupal.file.triggerUploadButton);
},
detach(context, setting, trigger) {
if (trigger === 'unload') {
$(context).find('input[type="file"]').removeOnce('auto-file-upload').off('.autoFileUpload');
}
},
};
/**
* Attach behaviors to the file upload and remove buttons.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches form submit events.
* @prop {Drupal~behaviorDetach} detach
* Detaches form submit events.
*/
Drupal.behaviors.fileButtons = {
attach(context) {
const $context = $(context);
$context.find('.js-form-submit').on('mousedown', Drupal.file.disableFields);
$context.find('.js-form-managed-file .js-form-submit').on('mousedown', Drupal.file.progressBar);
},
detach(context) {
const $context = $(context);
$context.find('.js-form-submit').off('mousedown', Drupal.file.disableFields);
$context.find('.js-form-managed-file .js-form-submit').off('mousedown', Drupal.file.progressBar);
},
};
/**
* Attach behaviors to links within managed file elements for preview windows.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches triggers.
* @prop {Drupal~behaviorDetach} detach
* Detaches triggers.
*/
Drupal.behaviors.filePreviewLinks = {
attach(context) {
$(context).find('div.js-form-managed-file .file a').on('click', Drupal.file.openInNewWindow);
},
detach(context) {
$(context).find('div.js-form-managed-file .file a').off('click', Drupal.file.openInNewWindow);
},
};
/**
* File upload utility functions.
*
* @namespace
*/
Drupal.file = Drupal.file || {
/**
* Client-side file input validation of file extensions.
*
* @name Drupal.file.validateExtension
*
* @param {jQuery.Event} event
* The event triggered. For example `change.fileValidate`.
*/
validateExtension(event) {
event.preventDefault();
// Remove any previous errors.
$('.file-upload-js-error').remove();
// Add client side validation for the input[type=file].
const extensionPattern = event.data.extensions.replace(/,\s*/g, '|');
if (extensionPattern.length > 1 && this.value.length > 0) {
const acceptableMatch = new RegExp(`\\.(${extensionPattern})$`, 'gi');
if (!acceptableMatch.test(this.value)) {
const error = Drupal.t('The selected file %filename cannot be uploaded. Only files with the following extensions are allowed: %extensions.', {
// According to the specifications of HTML5, a file upload control
// should not reveal the real local path to the file that a user
// has selected. Some web browsers implement this restriction by
// replacing the local path with "C:\fakepath\", which can cause
// confusion by leaving the user thinking perhaps Drupal could not
// find the file because it messed up the file path. To avoid this
// confusion, therefore, we strip out the bogus fakepath string.
'%filename': this.value.replace('C:\\fakepath\\', ''),
'%extensions': extensionPattern.replace(/\|/g, ', '),
});
$(this).closest('div.js-form-managed-file').prepend(`<div class="messages messages--error file-upload-js-error" aria-live="polite">${error}</div>`);
this.value = '';
// Cancel all other change event handlers.
event.stopImmediatePropagation();
}
}
},
/**
* Trigger the upload_button mouse event to auto-upload as a managed file.
*
* @name Drupal.file.triggerUploadButton
*
* @param {jQuery.Event} event
* The event triggered. For example `change.autoFileUpload`.
*/
triggerUploadButton(event) {
$(event.target).closest('.js-form-managed-file').find('.js-form-submit').trigger('mousedown');
},
/**
* Prevent file uploads when using buttons not intended to upload.
*
* @name Drupal.file.disableFields
*
* @param {jQuery.Event} event
* The event triggered, most likely a `mousedown` event.
*/
disableFields(event) {
const $clickedButton = $(this).findOnce('ajax');
// Only disable upload fields for Ajax buttons.
if (!$clickedButton.length) {
return;
}
// Check if we're working with an "Upload" button.
let $enabledFields = [];
if ($clickedButton.closest('div.js-form-managed-file').length > 0) {
$enabledFields = $clickedButton.closest('div.js-form-managed-file').find('input.js-form-file');
}
// Temporarily disable upload fields other than the one we're currently
// working with. Filter out fields that are already disabled so that they
// do not get enabled when we re-enable these fields at the end of
// behavior processing. Re-enable in a setTimeout set to a relatively
// short amount of time (1 second). All the other mousedown handlers
// (like Drupal's Ajax behaviors) are executed before any timeout
// functions are called, so we don't have to worry about the fields being
// re-enabled too soon. @todo If the previous sentence is true, why not
// set the timeout to 0?
const $fieldsToTemporarilyDisable = $('div.js-form-managed-file input.js-form-file').not($enabledFields).not(':disabled');
$fieldsToTemporarilyDisable.prop('disabled', true);
setTimeout(() => {
$fieldsToTemporarilyDisable.prop('disabled', false);
}, 1000);
},
/**
* Add progress bar support if possible.
*
* @name Drupal.file.progressBar
*
* @param {jQuery.Event} event
* The event triggered, most likely a `mousedown` event.
*/
progressBar(event) {
const $clickedButton = $(this);
const $progressId = $clickedButton.closest('div.js-form-managed-file').find('input.file-progress');
if ($progressId.length) {
const originalName = $progressId.attr('name');
// Replace the name with the required identifier.
$progressId.attr('name', originalName.match(/APC_UPLOAD_PROGRESS|UPLOAD_IDENTIFIER/)[0]);
// Restore the original name after the upload begins.
setTimeout(() => {
$progressId.attr('name', originalName);
}, 1000);
}
// Show the progress bar if the upload takes longer than half a second.
setTimeout(() => {
$clickedButton.closest('div.js-form-managed-file').find('div.ajax-progress-bar').slideDown();
}, 500);
},
/**
* Open links to files within forms in a new window.
*
* @name Drupal.file.openInNewWindow
*
* @param {jQuery.Event} event
* The event triggered, most likely a `click` event.
*/
openInNewWindow(event) {
event.preventDefault();
$(this).attr('target', '_blank');
window.open(this.href, 'filePreview', 'toolbar=0,scrollbars=1,location=1,statusbar=1,menubar=0,resizable=1,width=500,height=550');
},
};
}(jQuery, Drupal));
+1 -1
View File
@@ -73,7 +73,7 @@ function template_preprocess_file_widget_multiple(&$variables) {
// Render everything else together in a column, without the normal wrappers.
$widget['#theme_wrappers'] = [];
$information = drupal_render($widget);
$information = \Drupal::service('renderer')->render($widget);
$display = '';
if ($element['#display_field']) {
unset($widget['display']['#title']);
+3 -3
View File
@@ -7,8 +7,8 @@ package: Field types
dependencies:
- field
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
+12
View File
@@ -116,3 +116,15 @@ function file_requirements($phase) {
return $requirements;
}
/**
* Prevent unused files from being deleted.
*/
function file_update_8300() {
// Disable deletion of unused permanent files.
\Drupal::configFactory()->getEditable('file.settings')
->set('make_unused_managed_files_temporary', FALSE)
->save();
return t('Files that have no remaining usages are no longer deleted by default.');
}
+26 -147
View File
@@ -1,35 +1,18 @@
/**
* @file
* Provides JavaScript additions to the managed file field type.
*
* This file provides progress bar support (if available), popup windows for
* file previews, and disabling of other file fields during Ajax uploads (which
* prevents separate file fields from accidentally uploading files).
*/
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/2815083
* @preserve
**/
(function ($, Drupal) {
'use strict';
/**
* Attach behaviors to the file fields passed in the settings.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches validation for file extensions.
* @prop {Drupal~behaviorDetach} detach
* Detaches validation for file extensions.
*/
Drupal.behaviors.fileValidateAutoAttach = {
attach: function (context, settings) {
attach: function attach(context, settings) {
var $context = $(context);
var elements;
var elements = void 0;
function initFileValidation(selector) {
$context.find(selector)
.once('fileValidate')
.on('change.fileValidate', {extensions: elements[selector]}, Drupal.file.validateExtension);
$context.find(selector).once('fileValidate').on('change.fileValidate', { extensions: elements[selector] }, Drupal.file.validateExtension);
}
if (settings.file && settings.file.elements) {
@@ -37,14 +20,12 @@
Object.keys(elements).forEach(initFileValidation);
}
},
detach: function (context, settings, trigger) {
detach: function detach(context, settings, trigger) {
var $context = $(context);
var elements;
var elements = void 0;
function removeFileValidation(selector) {
$context.find(selector)
.removeOnce('fileValidate')
.off('change.fileValidate', Drupal.file.validateExtension);
$context.find(selector).removeOnce('fileValidate').off('change.fileValidate', Drupal.file.validateExtension);
}
if (trigger === 'unload' && settings.file && settings.file.elements) {
@@ -54,204 +35,102 @@
}
};
/**
* Attach behaviors to file element auto upload.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches triggers for the upload button.
* @prop {Drupal~behaviorDetach} detach
* Detaches auto file upload trigger.
*/
Drupal.behaviors.fileAutoUpload = {
attach: function (context) {
attach: function attach(context) {
$(context).find('input[type="file"]').once('auto-file-upload').on('change.autoFileUpload', Drupal.file.triggerUploadButton);
},
detach: function (context, setting, trigger) {
detach: function detach(context, setting, trigger) {
if (trigger === 'unload') {
$(context).find('input[type="file"]').removeOnce('auto-file-upload').off('.autoFileUpload');
}
}
};
/**
* Attach behaviors to the file upload and remove buttons.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches form submit events.
* @prop {Drupal~behaviorDetach} detach
* Detaches form submit events.
*/
Drupal.behaviors.fileButtons = {
attach: function (context) {
attach: function attach(context) {
var $context = $(context);
$context.find('.js-form-submit').on('mousedown', Drupal.file.disableFields);
$context.find('.js-form-managed-file .js-form-submit').on('mousedown', Drupal.file.progressBar);
},
detach: function (context) {
detach: function detach(context) {
var $context = $(context);
$context.find('.js-form-submit').off('mousedown', Drupal.file.disableFields);
$context.find('.js-form-managed-file .js-form-submit').off('mousedown', Drupal.file.progressBar);
}
};
/**
* Attach behaviors to links within managed file elements for preview windows.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches triggers.
* @prop {Drupal~behaviorDetach} detach
* Detaches triggers.
*/
Drupal.behaviors.filePreviewLinks = {
attach: function (context) {
attach: function attach(context) {
$(context).find('div.js-form-managed-file .file a').on('click', Drupal.file.openInNewWindow);
},
detach: function (context) {
detach: function detach(context) {
$(context).find('div.js-form-managed-file .file a').off('click', Drupal.file.openInNewWindow);
}
};
/**
* File upload utility functions.
*
* @namespace
*/
Drupal.file = Drupal.file || {
/**
* Client-side file input validation of file extensions.
*
* @name Drupal.file.validateExtension
*
* @param {jQuery.Event} event
* The event triggered. For example `change.fileValidate`.
*/
validateExtension: function (event) {
validateExtension: function validateExtension(event) {
event.preventDefault();
// Remove any previous errors.
$('.file-upload-js-error').remove();
// Add client side validation for the input[type=file].
var extensionPattern = event.data.extensions.replace(/,\s*/g, '|');
if (extensionPattern.length > 1 && this.value.length > 0) {
var acceptableMatch = new RegExp('\\.(' + extensionPattern + ')$', 'gi');
if (!acceptableMatch.test(this.value)) {
var error = Drupal.t('The selected file %filename cannot be uploaded. Only files with the following extensions are allowed: %extensions.', {
// According to the specifications of HTML5, a file upload control
// should not reveal the real local path to the file that a user
// has selected. Some web browsers implement this restriction by
// replacing the local path with "C:\fakepath\", which can cause
// confusion by leaving the user thinking perhaps Drupal could not
// find the file because it messed up the file path. To avoid this
// confusion, therefore, we strip out the bogus fakepath string.
'%filename': this.value.replace('C:\\fakepath\\', ''),
'%extensions': extensionPattern.replace(/\|/g, ', ')
});
$(this).closest('div.js-form-managed-file').prepend('<div class="messages messages--error file-upload-js-error" aria-live="polite">' + error + '</div>');
this.value = '';
// Cancel all other change event handlers.
event.stopImmediatePropagation();
}
}
},
/**
* Trigger the upload_button mouse event to auto-upload as a managed file.
*
* @name Drupal.file.triggerUploadButton
*
* @param {jQuery.Event} event
* The event triggered. For example `change.autoFileUpload`.
*/
triggerUploadButton: function (event) {
triggerUploadButton: function triggerUploadButton(event) {
$(event.target).closest('.js-form-managed-file').find('.js-form-submit').trigger('mousedown');
},
/**
* Prevent file uploads when using buttons not intended to upload.
*
* @name Drupal.file.disableFields
*
* @param {jQuery.Event} event
* The event triggered, most likely a `mousedown` event.
*/
disableFields: function (event) {
disableFields: function disableFields(event) {
var $clickedButton = $(this).findOnce('ajax');
// Only disable upload fields for Ajax buttons.
if (!$clickedButton.length) {
return;
}
// Check if we're working with an "Upload" button.
var $enabledFields = [];
if ($clickedButton.closest('div.js-form-managed-file').length > 0) {
$enabledFields = $clickedButton.closest('div.js-form-managed-file').find('input.js-form-file');
}
// Temporarily disable upload fields other than the one we're currently
// working with. Filter out fields that are already disabled so that they
// do not get enabled when we re-enable these fields at the end of
// behavior processing. Re-enable in a setTimeout set to a relatively
// short amount of time (1 second). All the other mousedown handlers
// (like Drupal's Ajax behaviors) are executed before any timeout
// functions are called, so we don't have to worry about the fields being
// re-enabled too soon. @todo If the previous sentence is true, why not
// set the timeout to 0?
var $fieldsToTemporarilyDisable = $('div.js-form-managed-file input.js-form-file').not($enabledFields).not(':disabled');
$fieldsToTemporarilyDisable.prop('disabled', true);
setTimeout(function () {
$fieldsToTemporarilyDisable.prop('disabled', false);
}, 1000);
},
/**
* Add progress bar support if possible.
*
* @name Drupal.file.progressBar
*
* @param {jQuery.Event} event
* The event triggered, most likely a `mousedown` event.
*/
progressBar: function (event) {
progressBar: function progressBar(event) {
var $clickedButton = $(this);
var $progressId = $clickedButton.closest('div.js-form-managed-file').find('input.file-progress');
if ($progressId.length) {
var originalName = $progressId.attr('name');
// Replace the name with the required identifier.
$progressId.attr('name', originalName.match(/APC_UPLOAD_PROGRESS|UPLOAD_IDENTIFIER/)[0]);
// Restore the original name after the upload begins.
setTimeout(function () {
$progressId.attr('name', originalName);
}, 1000);
}
// Show the progress bar if the upload takes longer than half a second.
setTimeout(function () {
$clickedButton.closest('div.js-form-managed-file').find('div.ajax-progress-bar').slideDown();
}, 500);
},
/**
* Open links to files within forms in a new window.
*
* @name Drupal.file.openInNewWindow
*
* @param {jQuery.Event} event
* The event triggered, most likely a `click` event.
*/
openInNewWindow: function (event) {
openInNewWindow: function openInNewWindow(event) {
event.preventDefault();
$(this).attr('target', '_blank');
window.open(this.href, 'filePreview', 'toolbar=0,scrollbars=1,location=1,statusbar=1,menubar=0,resizable=1,width=500,height=550');
}
};
})(jQuery, Drupal);
})(jQuery, Drupal);
+3 -1
View File
@@ -1208,7 +1208,9 @@ function file_managed_file_save_upload($element, FormStateInterface $form_state)
// Value callback expects FIDs to be keys.
$files = array_filter($files);
$fids = array_map(function($file) { return $file->id(); }, $files);
$fids = array_map(function ($file) {
return $file->id();
}, $files);
return empty($files) ? [] : array_combine($fids, $files);
}
+1 -1
View File
@@ -1,6 +1,6 @@
services:
file.usage:
class: Drupal\file\FileUsage\DatabaseFileUsageBackend
arguments: ['@database']
arguments: ['@database', 'file_usage', '@config.factory']
tags:
- { name: backend_overridable }
@@ -1,7 +1,7 @@
# Every migration that references a file by Drupal 6 fid should specify this
# migration as an optional dependency.
id: d6_file
label: Files
label: Public files
migration_tags:
- Drupal 6
source:
@@ -9,7 +9,7 @@ process:
vid: vid
type: type
upload:
plugin: iterator
plugin: sub_process
source: upload
process:
target_id:
@@ -6,7 +6,7 @@ source:
# We do an empty source and a proper destination to have an idmap for
# migration_dependencies.
plugin: md_empty
provider: upload
source_module: upload
constants:
entity_type: node
type: file
@@ -1,7 +1,7 @@
# Every migration that references a file by Drupal 7 fid should specify this
# migration as an optional dependency.
id: d7_file
label: Files
label: Public files
migration_tags:
- Drupal 7
source:
@@ -1,5 +1,5 @@
id: d7_file_private
label: Files
label: Private files
migration_tags:
- Drupal 7
source:
@@ -9,6 +9,7 @@ source:
- file_description_type
- file_description_length
- file_icon_directory
source_module: system
process:
'description/type': file_description_type
'description/length': file_description_length
+12 -4
View File
@@ -398,15 +398,23 @@ class ManagedFile extends FormElement {
* Render API callback: Validates the managed_file element.
*/
public static function validateManagedFile(&$element, FormStateInterface $form_state, &$complete_form) {
// If referencing an existing file, only allow if there are existing
// references. This prevents unmanaged files from being deleted if this
// item were to be deleted.
$clicked_button = end($form_state->getTriggeringElement()['#parents']);
if ($clicked_button != 'remove_button' && !empty($element['fids']['#value'])) {
$fids = $element['fids']['#value'];
foreach ($fids as $fid) {
if ($file = File::load($fid)) {
if ($file->isPermanent()) {
// If referencing an existing file, only allow if there are existing
// references. This prevents unmanaged files from being deleted if
// this item were to be deleted. When files that are no longer in use
// are automatically marked as temporary (now disabled by default),
// it is not safe to reference a permanent file without usage. Adding
// a usage and then later on removing it again would delete the file,
// but it is unknown if and where it is currently referenced. However,
// when files are not marked temporary (and then removed)
// automatically, it is safe to add and remove usages, as it would
// simply return to the current state.
// @see https://www.drupal.org/node/2891902
if ($file->isPermanent() && \Drupal::config('file.settings')->get('make_unused_managed_files_temporary')) {
$references = static::fileUsage()->listUsage($file);
if (empty($references)) {
// We expect the field name placeholder value to be wrapped in t()
+4 -1
View File
@@ -190,7 +190,10 @@ class File extends ContentEntityBase implements FileInterface {
// The file itself might not exist or be available right now.
$uri = $this->getFileUri();
if ($size = @filesize($uri)) {
$size = @filesize($uri);
// Set size unless there was an error.
if ($size !== FALSE) {
$this->setSize($size);
}
}
@@ -22,4 +22,4 @@ use Drupal\Core\Entity\EntityAccessControlHandlerInterface;
*
* @see \Drupal\file\Plugin\Field\FieldFormatter\FileFormatterBase::needsAccessCheck()
*/
interface FileAccessFormatterControlHandlerInterface extends EntityAccessControlHandlerInterface { }
interface FileAccessFormatterControlHandlerInterface extends EntityAccessControlHandlerInterface {}
@@ -2,6 +2,7 @@
namespace Drupal\file\FileUsage;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\Connection;
use Drupal\file\FileInterface;
@@ -32,8 +33,11 @@ class DatabaseFileUsageBackend extends FileUsageBase {
* information.
* @param string $table
* (optional) The table to store file usage info. Defaults to 'file_usage'.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* (optional) The config factory.
*/
public function __construct(Connection $connection, $table = 'file_usage') {
public function __construct(Connection $connection, $table = 'file_usage', ConfigFactoryInterface $config_factory = NULL) {
parent::__construct($config_factory);
$this->connection = $connection;
$this->tableName = $table;
@@ -2,6 +2,7 @@
namespace Drupal\file\FileUsage;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\file\FileInterface;
/**
@@ -9,6 +10,27 @@ use Drupal\file\FileInterface;
*/
abstract class FileUsageBase implements FileUsageInterface {
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* Creates a FileUsageBase object.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* (optional) The config factory. Defaults to NULL and will use
* \Drupal::configFactory() instead.
*
* @deprecated The $config_factory parameter will become required in Drupal
* 9.0.0.
*/
public function __construct(ConfigFactoryInterface $config_factory = NULL) {
$this->configFactory = $config_factory ?: \Drupal::configFactory();
}
/**
* {@inheritdoc}
*/
@@ -24,6 +46,10 @@ abstract class FileUsageBase implements FileUsageInterface {
* {@inheritdoc}
*/
public function delete(FileInterface $file, $module, $type = NULL, $id = NULL, $count = 1) {
// Do not actually mark files as temporary when the behavior is disabled.
if (!$this->configFactory->get('file.settings')->get('make_unused_managed_files_temporary')) {
return;
}
// If there are no more remaining usages of this file, mark it as temporary,
// which result in a delete through system_cron().
$usage = \Drupal::service('file.usage')->listUsage($file);
@@ -13,7 +13,7 @@ class FileFieldItemList extends EntityReferenceFieldItemList {
/**
* {@inheritdoc}
*/
public function defaultValuesForm(array &$form, FormStateInterface $form_state) { }
public function defaultValuesForm(array &$form, FormStateInterface $form_state) {}
/**
* {@inheritdoc}
@@ -333,7 +333,7 @@ class FileItem extends EntityReferenceItem {
$file = file_save_data($data, $destination, FILE_EXISTS_ERROR);
$values = [
'target_id' => $file->id(),
'display' => (int)$settings['display_default'],
'display' => (int) $settings['display_default'],
'description' => $random->sentences(10),
];
return $values;
@@ -2,6 +2,8 @@
namespace Drupal\file\Plugin\migrate\cckfield\d6;
@trigger_error('FileField is deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.x. Use \Drupal\file\Plugin\migrate\field\d6\FileField instead.', E_USER_DEPRECATED);
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
@@ -11,6 +13,11 @@ use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
* id = "filefield",
* core = {6}
* )
*
* @deprecated in Drupal 8.3.x, to be removed before Drupal 9.0.x. Use
* \Drupal\file\Plugin\migrate\field\d6\FileField instead.
*
* @see https://www.drupal.org/node/2751897
*/
class FileField extends CckFieldPluginBase {
@@ -2,6 +2,8 @@
namespace Drupal\file\Plugin\migrate\cckfield\d7;
@trigger_error('FileField is deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.x. Use \Drupal\file\Plugin\migrate\field\d7\FileField instead.', E_USER_DEPRECATED);
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
@@ -11,6 +13,11 @@ use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
* id = "file",
* core = {7}
* )
*
* @deprecated in Drupal 8.3.x, to be removed before Drupal 9.0.x. Use
* \Drupal\file\Plugin\migrate\field\d7\FileField instead.
*
* @see https://www.drupal.org/node/2751897
*/
class FileField extends CckFieldPluginBase {
@@ -2,6 +2,8 @@
namespace Drupal\file\Plugin\migrate\cckfield\d7;
@trigger_error('ImageField is deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.x. Use \Drupal\file\Plugin\migrate\field\d7\ImageField instead.', E_USER_DEPRECATED);
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
@@ -10,16 +12,14 @@ use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
* id = "image",
* core = {7}
* )
*
* @deprecated in Drupal 8.3.x, to be removed before Drupal 9.0.x. Use
* \Drupal\file\Plugin\migrate\field\d7\ImageField instead.
*
* @see https://www.drupal.org/node/2751897
*/
class ImageField extends CckFieldPluginBase {
/**
* {@inheritdoc}
*/
public function getFieldFormatterMap() {
return [];
}
/**
* {@inheritdoc}
*/
@@ -0,0 +1,58 @@
<?php
namespace Drupal\file\Plugin\migrate\field\d6;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\field\FieldPluginBase;
/**
* @MigrateField(
* id = "filefield",
* core = {6}
* )
*/
class FileField extends FieldPluginBase {
/**
* {@inheritdoc}
*/
public function getFieldWidgetMap() {
return [
'filefield_widget' => 'file_generic',
];
}
/**
* {@inheritdoc}
*/
public function getFieldFormatterMap() {
return [
'default' => 'file_default',
'url_plain' => 'file_url_plain',
'path_plain' => 'file_url_plain',
'image_plain' => 'image',
'image_nodelink' => 'image',
'image_imagelink' => 'image',
];
}
/**
* {@inheritdoc}
*/
public function processFieldValues(MigrationInterface $migration, $field_name, $data) {
$process = [
'plugin' => 'd6_field_file',
'source' => $field_name,
];
$migration->mergeProcessOfProperty($field_name, $process);
}
/**
* {@inheritdoc}
*/
public function getFieldType(Row $row) {
return $row->getSourceProperty('widget_type') == 'imagefield_widget' ? 'image' : 'file';
}
}
@@ -0,0 +1,32 @@
<?php
namespace Drupal\file\Plugin\migrate\field\d7;
use Drupal\file\Plugin\migrate\field\d6\FileField as D6FileField;
use Drupal\migrate\Plugin\MigrationInterface;
/**
* @MigrateField(
* id = "file",
* core = {7}
* )
*/
class FileField extends D6FileField {
/**
* {@inheritdoc}
*/
public function processFieldValues(MigrationInterface $migration, $field_name, $data) {
$process = [
'plugin' => 'iterator',
'source' => $field_name,
'process' => [
'target_id' => 'fid',
'display' => 'display',
'description' => 'description',
],
];
$migration->mergeProcessOfProperty($field_name, $process);
}
}
@@ -0,0 +1,34 @@
<?php
namespace Drupal\file\Plugin\migrate\field\d7;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate_drupal\Plugin\migrate\field\FieldPluginBase;
/**
* @MigrateField(
* id = "image",
* core = {7}
* )
*/
class ImageField extends FieldPluginBase {
/**
* {@inheritdoc}
*/
public function processFieldValues(MigrationInterface $migration, $field_name, $data) {
$process = [
'plugin' => 'iterator',
'source' => $field_name,
'process' => [
'target_id' => 'fid',
'alt' => 'alt',
'title' => 'title',
'width' => 'width',
'height' => 'height',
],
];
$migration->mergeProcessOfProperty($field_name, $process);
}
}
@@ -2,91 +2,16 @@
namespace Drupal\file\Plugin\migrate\process\d6;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Plugin\MigrateProcessInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface;
@trigger_error('CckFile is deprecated in Drupal 8.3.x and will be be removed before Drupal 9.0.x. Use \Drupal\file\Plugin\migrate\process\d6\FieldFile instead.', E_USER_DEPRECATED);
/**
* @MigrateProcessPlugin(
* id = "d6_cck_file"
* )
*
* @deprecated in Drupal 8.3.x, to be removed before Drupal 9.0.x. Use
* \Drupal\file\Plugin\migrate\process\d6\FieldFile instead.
*
* @see https://www.drupal.org/node/2751897
*/
class CckFile extends ProcessPluginBase implements ContainerFactoryPluginInterface {
/**
* The migration process plugin, configured for lookups in d6_file.
*
* @var \Drupal\migrate\Plugin\MigrateProcessInterface
*/
protected $migrationPlugin;
/**
* Constructs a CckFile plugin instance.
*
* @param array $configuration
* The plugin configuration.
* @param string $plugin_id
* The plugin ID.
* @param mixed $plugin_definition
* The plugin definition.
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The current migration.
* @param \Drupal\migrate\Plugin\MigrateProcessInterface $migration_plugin
* An instance of the 'migration' process plugin.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, MigrateProcessInterface $migration_plugin) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->migration = $migration;
$this->migrationPlugin = $migration_plugin;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
// Configure the migration process plugin to look up migrated IDs from
// a d6 file migration.
$migration_plugin_configuration = $configuration + [
'migration' => 'd6_file',
'source' => ['fid'],
];
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$migration,
$container->get('plugin.manager.migrate.process')->createInstance('migration', $migration_plugin_configuration, $migration)
);
}
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
$options = unserialize($value['data']);
// Try to look up the ID of the migrated file. If one cannot be found, it
// means the file referenced by the current field item did not migrate for
// some reason -- file migration is notoriously brittle -- and we do NOT
// want to send invalid file references into the field system (it causes
// fatals), so return an empty item instead.
if ($fid = $this->migrationPlugin->transform($value['fid'], $migrate_executable, $row, $destination_property)) {
return [
'target_id' => $fid,
'display' => $value['list'],
'description' => isset($options['description']) ? $options['description'] : '',
'alt' => isset($options['alt']) ? $options['alt'] : '',
'title' => isset($options['title']) ? $options['title'] : '',
];
}
else {
return [];
}
}
}
class CckFile extends FieldFile {}
@@ -0,0 +1,92 @@
<?php
namespace Drupal\file\Plugin\migrate\process\d6;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Plugin\MigrateProcessInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* @MigrateProcessPlugin(
* id = "d6_field_file"
* )
*/
class FieldFile extends ProcessPluginBase implements ContainerFactoryPluginInterface {
/**
* The migration process plugin, configured for lookups in d6_file.
*
* @var \Drupal\migrate\Plugin\MigrateProcessInterface
*/
protected $migrationPlugin;
/**
* Constructs a FieldFile plugin instance.
*
* @param array $configuration
* The plugin configuration.
* @param string $plugin_id
* The plugin ID.
* @param mixed $plugin_definition
* The plugin definition.
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The current migration.
* @param \Drupal\migrate\Plugin\MigrateProcessInterface $migration_plugin
* An instance of the 'migration' process plugin.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, MigrateProcessInterface $migration_plugin) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->migration = $migration;
$this->migrationPlugin = $migration_plugin;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
// Configure the migration process plugin to look up migrated IDs from
// a d6 file migration.
$migration_plugin_configuration = $configuration + [
'migration' => 'd6_file',
'source' => ['fid'],
];
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$migration,
$container->get('plugin.manager.migrate.process')->createInstance('migration', $migration_plugin_configuration, $migration)
);
}
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
$options = unserialize($value['data']);
// Try to look up the ID of the migrated file. If one cannot be found, it
// means the file referenced by the current field item did not migrate for
// some reason -- file migration is notoriously brittle -- and we do NOT
// want to send invalid file references into the field system (it causes
// fatals), so return an empty item instead.
if ($fid = $this->migrationPlugin->transform($value['fid'], $migrate_executable, $row, $destination_property)) {
return [
'target_id' => $fid,
'display' => $value['list'],
'description' => isset($options['description']) ? $options['description'] : '',
'alt' => isset($options['alt']) ? $options['alt'] : '',
'title' => isset($options['title']) ? $options['title'] : '',
];
}
else {
return [];
}
}
}
@@ -9,7 +9,8 @@ use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
* Drupal 6 file source from database.
*
* @MigrateSource(
* id = "d6_file"
* id = "d6_file",
* source_module = "system"
* )
*/
class File extends DrupalSqlBase {
@@ -10,7 +10,7 @@ use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
*
* @MigrateSource(
* id = "d6_upload",
* source_provider = "upload"
* source_module = "upload"
* )
*/
class Upload extends DrupalSqlBase {
@@ -10,7 +10,7 @@ use Drupal\migrate\Plugin\migrate\source\DummyQueryTrait;
*
* @MigrateSource(
* id = "d6_upload_instance",
* source_provider = "upload"
* source_module = "upload"
* )
*/
class UploadInstance extends DrupalSqlBase {
@@ -25,7 +25,9 @@ class UploadInstance extends DrupalSqlBase {
->fields('nt', ['type'])
->execute()
->fetchCol();
$variables = array_map(function($type) { return 'upload_' . $type; }, $node_types);
$variables = array_map(function ($type) {
return 'upload_' . $type;
}, $node_types);
$max_filesize = $this->variableGet('upload_uploadsize_default', 1);
$max_filesize = $max_filesize ? $max_filesize . 'MB' : '';
@@ -10,7 +10,8 @@ use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
* Drupal 7 file source from database.
*
* @MigrateSource(
* id = "d7_file"
* id = "d7_file",
* source_module = "file"
* )
*/
class File extends DrupalSqlBase {
+6 -3
View File
@@ -91,9 +91,12 @@ class DownloadTest extends FileManagedTestBase {
// Tilde (~) is excluded from this test because it is encoded by
// rawurlencode() in PHP 5.2 but not in PHP 5.3, as per RFC 3986.
// @see http://php.net/manual/function.rawurlencode.php#86506
$basename = " -._!$'\"()*@[]?&+%#,;=:\n\x00" . // "Special" ASCII characters.
"%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string.
"éøïвβ中國書۞"; // Characters from various non-ASCII alphabets.
// "Special" ASCII characters.
$basename = " -._!$'\"()*@[]?&+%#,;=:\n\x00" .
// Characters that look like a percent-escaped string.
"%23%25%26%2B%2F%3F" .
// Characters from various non-ASCII alphabets.
"éøïвβ中國書۞";
$basename_encoded = '%20-._%21%24%27%22%28%29%2A%40%5B%5D%3F%26%2B%25%23%2C%3B%3D%3A__' .
'%2523%2525%2526%252B%252F%253F' .
'%C3%A9%C3%B8%C3%AF%D0%B2%CE%B2%E4%B8%AD%E5%9C%8B%E6%9B%B8%DB%9E';
@@ -138,7 +138,7 @@ class FileFieldAnonymousSubmissionTest extends FileFieldTestBase {
$label = 'Save';
}
else {
$label = 'Save and publish';
$label = 'Save';
}
$this->drupalPostForm(NULL, $edit, $label);
$this->assertResponse(200);
@@ -77,7 +77,7 @@ class FileFieldDisplayTest extends FileFieldTestBase {
// Turn the "display" option off and check that the file is no longer displayed.
$edit = [$field_name . '[0][display]' => FALSE];
$this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save and keep published'));
$this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save'));
$this->assertNoRaw($default_output, 'Field is hidden when "display" option is unchecked.');
@@ -87,7 +87,7 @@ class FileFieldDisplayTest extends FileFieldTestBase {
$field_name . '[0][description]' => $description,
$field_name . '[0][display]' => TRUE,
];
$this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save and keep published'));
$this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save'));
$this->assertText($description);
// Ensure the filename in the link's title attribute is escaped.
@@ -167,7 +167,7 @@ class FileFieldDisplayTest extends FileFieldTestBase {
'title[0][value]' => $title,
'files[field_' . $field_name . '_0]' => drupal_realpath($file->uri),
];
$this->drupalPostForm('node/add/' . $type_name, $edit, t('Save and publish'));
$this->drupalPostForm('node/add/' . $type_name, $edit, t('Save'));
$node = $this->drupalGetNodeByTitle($title);
$this->drupalGet('node/' . $node->id() . '/edit');
$this->assertText(t('The description may be used as the label of the link to the file.'));
@@ -2,7 +2,6 @@
namespace Drupal\file\Tests;
/**
* Tests file formatter access.
* @group file
@@ -22,6 +22,11 @@ class FileFieldRevisionTest extends FileFieldTestBase {
* should be deleted also.
*/
public function testRevisions() {
// This test expects unused managed files to be marked as a temporary file
// and then deleted up by file_cron().
$this->config('file.settings')
->set('make_unused_managed_files_temporary', TRUE)
->save();
$node_storage = $this->container->get('entity.manager')->getStorage('node');
$type_name = 'article';
$field_name = strtolower($this->randomMachineName());
@@ -63,7 +68,7 @@ class FileFieldRevisionTest extends FileFieldTestBase {
// Save a new version of the node without any changes.
// Check that the file is still the same as the previous revision.
$this->drupalPostForm('node/' . $nid . '/edit', ['revision' => '1'], t('Save and keep published'));
$this->drupalPostForm('node/' . $nid . '/edit', ['revision' => '1'], t('Save'));
$node_storage->resetCache([$nid]);
$node = $node_storage->load($nid);
$node_file_r3 = File::load($node->{$field_name}->target_id);
@@ -227,7 +227,7 @@ abstract class FileFieldTestBase extends WebTestBase {
$edit[$name][] = $file_path;
}
}
$this->drupalPostForm("node/$nid/edit", $edit, t('Save and keep published'));
$this->drupalPostForm("node/$nid/edit", $edit, t('Save'));
return $nid;
}
@@ -243,7 +243,7 @@ abstract class FileFieldTestBase extends WebTestBase {
];
$this->drupalPostForm('node/' . $nid . '/edit', [], t('Remove'));
$this->drupalPostForm(NULL, $edit, t('Save and keep published'));
$this->drupalPostForm(NULL, $edit, t('Save'));
}
/**
@@ -256,7 +256,7 @@ abstract class FileFieldTestBase extends WebTestBase {
];
$this->drupalPostForm('node/' . $nid . '/edit', [], t('Remove'));
$this->drupalPostForm(NULL, $edit, t('Save and keep published'));
$this->drupalPostForm(NULL, $edit, t('Save'));
}
/**
@@ -29,7 +29,7 @@ class FileFieldValidateTest extends FileFieldTestBase {
// Try to post a new node without uploading a file.
$edit = [];
$edit['title[0][value]'] = $this->randomMachineName();
$this->drupalPostForm('node/add/' . $type_name, $edit, t('Save and publish'));
$this->drupalPostForm('node/add/' . $type_name, $edit, t('Save'));
$this->assertRaw(t('@title field is required.', ['@title' => $field->getLabel()]), 'Node save failed when required file field was empty.');
// Create a new node with the uploaded file.
@@ -50,7 +50,7 @@ class FileFieldValidateTest extends FileFieldTestBase {
// Try to post a new node without uploading a file in the multivalue field.
$edit = [];
$edit['title[0][value]'] = $this->randomMachineName();
$this->drupalPostForm('node/add/' . $type_name, $edit, t('Save and publish'));
$this->drupalPostForm('node/add/' . $type_name, $edit, t('Save'));
$this->assertRaw(t('@title field is required.', ['@title' => $field->getLabel()]), 'Node save failed when required multiple value file field was empty.');
// Create a new node with the uploaded file into the multivalue field.
@@ -71,8 +71,10 @@ class FileFieldValidateTest extends FileFieldTestBase {
$field_name = strtolower($this->randomMachineName());
$this->createFileField($field_name, 'node', $type_name, [], ['required' => '1']);
$small_file = $this->getTestFile('text', 131072); // 128KB.
$large_file = $this->getTestFile('text', 1310720); // 1.2MB
// 128KB.
$small_file = $this->getTestFile('text', 131072);
// 1.2MB
$large_file = $this->getTestFile('text', 1310720);
// Test uploading both a large and small file with different increments.
$sizes = [
@@ -121,7 +121,7 @@ class FileFieldWidgetTest extends FileFieldTestBase {
$this->assertTrue(isset($label[0]), 'Label for upload found.');
// Save the node and ensure it does not have the file.
$this->drupalPostForm(NULL, [], t('Save and keep published'));
$this->drupalPostForm(NULL, [], t('Save'));
$node_storage->resetCache([$nid]);
$node = $node_storage->load($nid);
$this->assertTrue(empty($node->{$field_name}->target_id), 'File was successfully removed from the node.');
@@ -238,8 +238,7 @@ class FileFieldWidgetTest extends FileFieldTestBase {
$this->assertNoFieldByXPath('//input[@type="submit"]', t('Remove'), format_string('After removing all files, there is no "Remove" button displayed (JSMode=%type).', ['%type' => $type]));
// Save the node and ensure it does not have any files.
$this->drupalPostForm(NULL, ['title[0][value]' => $this->randomMachineName()], t('Save and publish'));
$matches = [];
$this->drupalPostForm(NULL, ['title[0][value]' => $this->randomMachineName()], t('Save'));
preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
$nid = $matches[1];
$node_storage->resetCache([$nid]);
@@ -368,7 +367,7 @@ class FileFieldWidgetTest extends FileFieldTestBase {
$edit = [
'title[0][value]' => $this->randomMachineName(),
];
$this->drupalPostForm('node/add/article', $edit, t('Save and publish'));
$this->drupalPostForm('node/add/article', $edit, t('Save'));
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
// Add a comment with a file.
@@ -402,7 +401,8 @@ class FileFieldWidgetTest extends FileFieldTestBase {
// Unpublishes node.
$this->drupalLogin($this->adminUser);
$this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save and unpublish'));
$edit = ['status[value]' => FALSE];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
// Ensures normal user can no longer download the file.
$this->drupalLogin($user);
@@ -30,6 +30,11 @@ class FileListingTest extends FileFieldTestBase {
protected function setUp() {
parent::setUp();
// This test expects unused managed files to be marked as a temporary file.
$this->config('file.settings')
->set('make_unused_managed_files_temporary', TRUE)
->save();
$this->adminUser = $this->drupalCreateUser(['access files overview', 'bypass node access']);
$this->baseUser = $this->drupalCreateUser();
$this->createFileField('file', 'node', 'article', [], ['file_extensions' => 'txt png']);
@@ -194,4 +194,55 @@ class FileManagedFileElementTest extends FileFieldTestBase {
$file->delete();
}
/**
* Verify that unused permanent files can be used.
*/
public function testUnusedPermanentFileValidation() {
// Create a permanent file without usages.
$file = $this->getTestFile('image');
$file->setPermanent();
$file->save();
// By default, unused files are no longer marked temporary, and it must be
// allowed to reference an unused file.
$this->drupalGet('file/test/1/0/1/' . $file->id());
$this->drupalPostForm(NULL, [], 'Save');
$this->assertNoText('The file used in the Managed file &amp; butter field may not be referenced.');
$this->assertText('The file ids are ' . $file->id());
// Enable marking unused files as tempory, unused permanent files must not
// be referenced now.
$this->config('file.settings')
->set('make_unused_managed_files_temporary', TRUE)
->save();
$this->drupalGet('file/test/1/0/1/' . $file->id());
$this->drupalPostForm(NULL, [], 'Save');
$this->assertText('The file used in the Managed file &amp; butter field may not be referenced.');
$this->assertNoText('The file ids are ' . $file->id());
// Make the file temporary, now using it is allowed.
$file->setTemporary();
$file->save();
$this->drupalGet('file/test/1/0/1/' . $file->id());
$this->drupalPostForm(NULL, [], 'Save');
$this->assertNoText('The file used in the Managed file &amp; butter field may not be referenced.');
$this->assertText('The file ids are ' . $file->id());
// Make the file permanent again and add a usage from itself, referencing is
// still allowed.
$file->setPermanent();
$file->save();
/** @var \Drupal\file\FileUsage\FileUsageInterface $file_usage */
$file_usage = \Drupal::service('file.usage');
$file_usage->add($file, 'file', 'file', $file->id());
$this->drupalGet('file/test/1/0/1/' . $file->id());
$this->drupalPostForm(NULL, [], 'Save');
$this->assertNoText('The file used in the Managed file &amp; butter field may not be referenced.');
$this->assertText('The file ids are ' . $file->id());
}
}
@@ -29,6 +29,11 @@ class FileOnTranslatedEntityTest extends FileFieldTestBase {
protected function setUp() {
parent::setUp();
// This test expects unused managed files to be marked as temporary a file.
$this->config('file.settings')
->set('make_unused_managed_files_temporary', TRUE)
->save();
// Create the "Basic page" node type.
// @todo Remove the disabling of new revision creation in
// https://www.drupal.org/node/1239558.
@@ -27,6 +27,10 @@ class FilePrivateTest extends FileFieldTestBase {
node_access_test_add_field(NodeType::load('article'));
node_access_rebuild();
\Drupal::state()->set('node_access_test.private', TRUE);
// This test expects unused managed files to be marked as a temporary file.
$this->config('file.settings')
->set('make_unused_managed_files_temporary', TRUE)
->save();
}
/**
@@ -73,10 +77,10 @@ class FilePrivateTest extends FileFieldTestBase {
// Attempt to reuse the file when editing a node.
$edit = [];
$edit['title[0][value]'] = $this->randomMachineName();
$this->drupalPostForm('node/add/' . $type_name, $edit, t('Save and publish'));
$this->drupalPostForm('node/add/' . $type_name, $edit, t('Save'));
$new_node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
$edit[$field_name . '[0][fids]'] = $node_file->id();
$this->drupalPostForm('node/' . $new_node->id() . '/edit', $edit, t('Save and keep published'));
$this->drupalPostForm('node/' . $new_node->id() . '/edit', $edit, t('Save'));
// Make sure the form submit failed - we stayed on the edit form.
$this->assertUrl('node/' . $new_node->id() . '/edit');
// Check that we got the expected constraint form error.
@@ -87,7 +91,7 @@ class FilePrivateTest extends FileFieldTestBase {
$edit = [];
$edit['title[0][value]'] = $this->randomMachineName();
$edit[$field_name . '[0][fids]'] = $node_file->id();
$this->drupalPostForm('node/add/' . $type_name, $edit, t('Save and publish'));
$this->drupalPostForm('node/add/' . $type_name, $edit, t('Save'));
$new_node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
$this->assertTrue(empty($new_node), 'Node was not created.');
$this->assertUrl('node/add/' . $type_name);
@@ -5,8 +5,8 @@ package: Testing
# version: VERSION
# core: 8.x
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
@@ -5,8 +5,8 @@ package: Testing
# version: VERSION
# core: 8.x
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
@@ -8,8 +8,8 @@ dependencies:
- file
- views
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
@@ -259,7 +259,7 @@ abstract class FileFieldTestBase extends BrowserTestBase {
/**
* Asserts that a file exists physically on disk.
*
* Overrides PHPUnit_Framework_Assert::assertFileExists() to also work with
* Overrides PHPUnit\Framework\Assert::assertFileExists() to also work with
* file entities.
*
* @param \Drupal\File\FileInterface|string $file
@@ -286,7 +286,7 @@ abstract class FileFieldTestBase extends BrowserTestBase {
/**
* Asserts that a file does not exist on disk.
*
* Overrides PHPUnit_Framework_Assert::assertFileExists() to also work with
* Overrides PHPUnit\Framework\Assert::assertFileExists() to also work with
* file entities.
*
* @param \Drupal\File\FileInterface|string $file
@@ -0,0 +1,42 @@
<?php
namespace Drupal\Tests\file\Functional\Update;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
/**
* Tests the upgrade path for setting the file usage deletion configuration.
*
* @see https://www.drupal.org/node/2801777
*
* @group Update
*/
class FileUsageTemporaryDeletionConfigurationUpdateTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['file'];
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
];
}
/**
* Tests that make_unused_managed_files_temporary conditions are correct.
*
* Verify that the before and after conditions for the variable are correct.
*/
public function testUpdateHookN() {
$this->assertIdentical($this->config('file.settings')->get('make_unused_managed_files_temporary'), NULL);
$this->runUpdates();
$this->assertIdentical($this->config('file.settings')->get('make_unused_managed_files_temporary'), FALSE);
$this->assertResponse('200');
}
}
@@ -28,6 +28,11 @@ class DeleteTest extends FileManagedUnitTestBase {
* Tries deleting a file that is in use.
*/
public function testInUse() {
// This test expects unused managed files to be marked as a temporary file
// and then deleted up by file_cron().
$this->config('file.settings')
->set('make_unused_managed_files_temporary', TRUE)
->save();
$file = $this->createFile();
$file_usage = $this->container->get('file.usage');
$file_usage->add($file, 'testing', 'test', 1);
@@ -1,6 +1,7 @@
<?php
namespace Drupal\Tests\file\Kernel\Migrate\d6;
use Drupal\migrate\Plugin\MigrationInterface;
/**
@@ -0,0 +1,37 @@
<?php
namespace Drupal\Tests\file\Kernel\Migrate\d7;
use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
/**
* A trait to setup the file migration.
*/
trait FileMigrationSetupTrait {
/**
* Prepare the file migration for running.
*/
protected function fileMigrationSetup() {
$this->installSchema('file', ['file_usage']);
$this->installEntitySchema('file');
$this->container->get('stream_wrapper_manager')->registerWrapper('public', PublicStream::class, StreamWrapperInterface::NORMAL);
$fs = \Drupal::service('file_system');
// The public file directory active during the test will serve as the
// root of the fictional Drupal 7 site we're migrating.
$fs->mkdir('public://sites/default/files', NULL, TRUE);
file_put_contents('public://sites/default/files/cube.jpeg', str_repeat('*', 3620));
/** @var \Drupal\migrate\Plugin\Migration $migration */
$migration = $this->getMigration('d7_file');
// Set the source plugin's source_base_path configuration value, which
// would normally be set by the user running the migration.
$source = $migration->getSourceConfiguration();
$source['constants']['source_base_path'] = $fs->realpath('public://');
$migration->set('source', $source);
$this->executeMigration($migration);
}
}
@@ -2,7 +2,6 @@
namespace Drupal\Tests\file\Kernel\Migrate\d7;
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
use Drupal\file\Entity\File;
use Drupal\file\FileInterface;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
@@ -14,6 +13,8 @@ use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
*/
class MigrateFileTest extends MigrateDrupal7TestBase {
use FileMigrationSetupTrait;
public static $modules = ['file'];
/**
@@ -22,23 +23,7 @@ class MigrateFileTest extends MigrateDrupal7TestBase {
protected function setUp() {
parent::setUp();
$this->installEntitySchema('file');
$this->container->get('stream_wrapper_manager')->registerWrapper('public', 'Drupal\Core\StreamWrapper\PublicStream', StreamWrapperInterface::NORMAL);
$fs = \Drupal::service('file_system');
// The public file directory active during the test will serve as the
// root of the fictional Drupal 7 site we're migrating.
$fs->mkdir('public://sites/default/files', NULL, TRUE);
file_put_contents('public://sites/default/files/cube.jpeg', str_repeat('*', 3620));
/** @var \Drupal\migrate\Plugin\Migration $migration */
$migration = $this->getMigration('d7_file');
// Set the source plugin's source_base_path configuration value, which
// would normally be set by the user running the migration.
$source = $migration->getSourceConfiguration();
$source['constants']['source_base_path'] = $fs->realpath('public://');
$migration->set('source', $source);
$this->executeMigration($migration);
$this->fileMigrationSetup();
}
/**
@@ -12,6 +12,7 @@ use Drupal\Tests\migrate_drupal\Kernel\MigrateDrupalTestBase;
* @coversDefaultClass \Drupal\file\Plugin\migrate\process\d6\CckFile
*
* @group file
* @group legacy
*/
class CckFileTest extends MigrateDrupalTestBase {
@@ -81,6 +81,22 @@ class SaveTest extends FileManagedUnitTestBase {
$this->assertEqual(1, count($fids));
$this->assertEqual([$uppercase_file->id() => $uppercase_file->id()], $fids);
// Save a file with zero bytes.
$file = File::create([
'uid' => 1,
'filename' => 'no-druplicon.txt',
'uri' => 'public://no-druplicon.txt',
'filemime' => 'text/plain',
'status' => FILE_STATUS_PERMANENT,
]);
file_put_contents($file->getFileUri(), '');
// Save it, inserting a new record.
$file->save();
// Check the file size was set to zero.
$this->assertSame(0, $file->getSize());
}
}
@@ -1,6 +1,7 @@
<?php
namespace Drupal\Tests\file\Kernel;
use Drupal\file\Entity\File;
/**
@@ -74,11 +74,34 @@ class UsageTest extends FileManagedUnitTestBase {
$this->assertEqual($usage[2]->count, 2, 'Correct count');
}
/**
* Tests file usage deletion when files are made temporary.
*/
public function testRemoveUsageTemporary() {
$this->config('file.settings')
->set('make_unused_managed_files_temporary', TRUE)
->save();
$file = $this->doTestRemoveUsage();
$this->assertTrue($file->isTemporary());
}
/**
* Tests file usage deletion when files are made temporary.
*/
public function testRemoveUsageNonTemporary() {
$this->config('file.settings')
->set('make_unused_managed_files_temporary', FALSE)
->save();
$file = $this->doTestRemoveUsage();
$this->assertFalse($file->isTemporary());
}
/**
* Tests \Drupal\file\FileUsage\DatabaseFileUsageBackend::delete().
*/
public function testRemoveUsage() {
public function doTestRemoveUsage() {
$file = $this->createFile();
$file->setPermanent();
$file_usage = $this->container->get('file.usage');
db_insert('file_usage')
->fields([
@@ -116,6 +139,7 @@ class UsageTest extends FileManagedUnitTestBase {
->execute()
->fetchField();
$this->assertIdentical(FALSE, $count, 'Decrementing non-exist record complete.');
return $file;
}
/**
@@ -2,7 +2,6 @@
namespace Drupal\Tests\file\Kernel;
/**
* Tests the file_validate() function.
*
@@ -0,0 +1,82 @@
<?php
namespace Drupal\Tests\file\Unit\Plugin\migrate\cckfield\d6;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Drupal\Tests\UnitTestCase;
use Drupal\file\Plugin\migrate\cckfield\d6\FileField;
use Prophecy\Argument;
/**
* @coversDefaultClass \Drupal\file\Plugin\migrate\cckfield\d6\FileField
* @group file
* @group legacy
*/
class FileCckTest extends UnitTestCase {
/**
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldInterface
*/
protected $plugin;
/**
* @var \Drupal\migrate\Plugin\MigrationInterface
*/
protected $migration;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->plugin = new FileField([], 'file', []);
$migration = $this->prophesize(MigrationInterface::class);
// The plugin's processFieldValues() method will call
// mergeProcessOfProperty() and return nothing. So, in order to examine the
// process pipeline created by the plugin, we need to ensure that
// getProcess() always returns the last input to mergeProcessOfProperty().
$migration->mergeProcessOfProperty(Argument::type('string'), Argument::type('array'))
->will(function ($arguments) use ($migration) {
$migration->getProcess()->willReturn($arguments[1]);
});
$this->migration = $migration->reveal();
}
/**
* @covers ::processCckFieldValues
*/
public function testProcessCckFieldValues() {
$this->plugin->processCckFieldValues($this->migration, 'somefieldname', []);
$expected = [
'plugin' => 'd6_cck_file',
'source' => 'somefieldname',
];
$this->assertSame($expected, $this->migration->getProcess());
}
/**
* Data provider for testGetFieldType().
*/
public function getFieldTypeProvider() {
return [
['image', 'imagefield_widget'],
['file', 'filefield_widget'],
['file', 'x_widget']
];
}
/**
* @covers ::getFieldType
* @dataProvider getFieldTypeProvider
*/
public function testGetFieldType($expected_type, $widget_type, array $settings = []) {
$row = new Row();
$row->setSourceProperty('widget_type', $widget_type);
$row->setSourceProperty('global_settings', $settings);
$this->assertSame($expected_type, $this->plugin->getFieldType($row));
}
}
@@ -0,0 +1,87 @@
<?php
namespace Drupal\Tests\file\Unit\Plugin\migrate\cckfield\d7;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Drupal\Tests\UnitTestCase;
use Drupal\file\Plugin\migrate\cckfield\d7\FileField;
use Prophecy\Argument;
/**
* @coversDefaultClass \Drupal\file\Plugin\migrate\cckfield\d7\FileField
* @group file
* @group legacy
*/
class FileCckTest extends UnitTestCase {
/**
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldInterface
*/
protected $plugin;
/**
* @var \Drupal\migrate\Plugin\MigrationInterface
*/
protected $migration;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->plugin = new FileField([], 'file', []);
$migration = $this->prophesize(MigrationInterface::class);
// The plugin's processFieldValues() method will call
// mergeProcessOfProperty() and return nothing. So, in order to examine the
// process pipeline created by the plugin, we need to ensure that
// getProcess() always returns the last input to mergeProcessOfProperty().
$migration->mergeProcessOfProperty(Argument::type('string'), Argument::type('array'))
->will(function ($arguments) use ($migration) {
$migration->getProcess()->willReturn($arguments[1]);
});
$this->migration = $migration->reveal();
}
/**
* @covers ::processCckFieldValues
*/
public function testProcessCckFieldValues() {
$this->plugin->processCckFieldValues($this->migration, 'somefieldname', []);
$expected = [
'plugin' => 'iterator',
'source' => 'somefieldname',
'process' => [
'target_id' => 'fid',
'display' => 'display',
'description' => 'description',
],
];
$this->assertSame($expected, $this->migration->getProcess());
}
/**
* Data provider for testGetFieldType().
*/
public function getFieldTypeProvider() {
return [
['image', 'imagefield_widget'],
['file', 'filefield_widget'],
['file', 'x_widget']
];
}
/**
* @covers ::getFieldType
* @dataProvider getFieldTypeProvider
*/
public function testGetFieldType($expected_type, $widget_type, array $settings = []) {
$row = new Row();
$row->setSourceProperty('widget_type', $widget_type);
$row->setSourceProperty('global_settings', $settings);
$this->assertSame($expected_type, $this->plugin->getFieldType($row));
}
}
@@ -0,0 +1,66 @@
<?php
namespace Drupal\Tests\file\Unit\Plugin\migrate\cckfield\d7;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\Tests\UnitTestCase;
use Drupal\file\Plugin\migrate\cckfield\d7\ImageField;
use Prophecy\Argument;
/**
* @coversDefaultClass \Drupal\file\Plugin\migrate\cckfield\d7\ImageField
* @group file
* @group legacy
*/
class ImageCckTest extends UnitTestCase {
/**
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldInterface
*/
protected $plugin;
/**
* @var \Drupal\migrate\Plugin\MigrationInterface
*/
protected $migration;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->plugin = new ImageField([], 'image', []);
$migration = $this->prophesize(MigrationInterface::class);
// The plugin's processFieldValues() method will call
// mergeProcessOfProperty() and return nothing. So, in order to examine the
// process pipeline created by the plugin, we need to ensure that
// getProcess() always returns the last input to mergeProcessOfProperty().
$migration->mergeProcessOfProperty(Argument::type('string'), Argument::type('array'))
->will(function ($arguments) use ($migration) {
$migration->getProcess()->willReturn($arguments[1]);
});
$this->migration = $migration->reveal();
}
/**
* @covers ::processCckFieldValues
*/
public function testProcessCckFieldValues() {
$this->plugin->processCckFieldValues($this->migration, 'somefieldname', []);
$expected = [
'plugin' => 'iterator',
'source' => 'somefieldname',
'process' => [
'target_id' => 'fid',
'alt' => 'alt',
'title' => 'title',
'width' => 'width',
'height' => 'height',
],
];
$this->assertSame($expected, $this->migration->getProcess());
}
}
@@ -0,0 +1,81 @@
<?php
namespace Drupal\Tests\file\Unit\Plugin\migrate\field\d6;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Drupal\Tests\UnitTestCase;
use Drupal\file\Plugin\migrate\field\d6\FileField;
use Prophecy\Argument;
/**
* @coversDefaultClass \Drupal\file\Plugin\migrate\field\d6\FileField
* @group file
*/
class FileFieldTest extends UnitTestCase {
/**
* @var \Drupal\migrate_drupal\Plugin\MigrateFieldInterface
*/
protected $plugin;
/**
* @var \Drupal\migrate\Plugin\MigrationInterface
*/
protected $migration;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->plugin = new FileField([], 'file', []);
$migration = $this->prophesize(MigrationInterface::class);
// The plugin's processFieldValues() method will call
// mergeProcessOfProperty() and return nothing. So, in order to examine the
// process pipeline created by the plugin, we need to ensure that
// getProcess() always returns the last input to mergeProcessOfProperty().
$migration->mergeProcessOfProperty(Argument::type('string'), Argument::type('array'))
->will(function ($arguments) use ($migration) {
$migration->getProcess()->willReturn($arguments[1]);
});
$this->migration = $migration->reveal();
}
/**
* @covers ::processFieldValues
*/
public function testProcessFieldValues() {
$this->plugin->processFieldValues($this->migration, 'somefieldname', []);
$expected = [
'plugin' => 'd6_field_file',
'source' => 'somefieldname',
];
$this->assertSame($expected, $this->migration->getProcess());
}
/**
* Data provider for testGetFieldType().
*/
public function getFieldTypeProvider() {
return [
['image', 'imagefield_widget'],
['file', 'filefield_widget'],
['file', 'x_widget']
];
}
/**
* @covers ::getFieldType
* @dataProvider getFieldTypeProvider
*/
public function testGetFieldType($expected_type, $widget_type, array $settings = []) {
$row = new Row();
$row->setSourceProperty('widget_type', $widget_type);
$row->setSourceProperty('global_settings', $settings);
$this->assertSame($expected_type, $this->plugin->getFieldType($row));
}
}
@@ -0,0 +1,86 @@
<?php
namespace Drupal\Tests\file\Unit\Plugin\migrate\field\d7;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Drupal\Tests\UnitTestCase;
use Drupal\file\Plugin\migrate\field\d7\FileField;
use Prophecy\Argument;
/**
* @coversDefaultClass \Drupal\file\Plugin\migrate\field\d7\FileField
* @group file
*/
class FileFieldTest extends UnitTestCase {
/**
* @var \Drupal\migrate_drupal\Plugin\MigrateFieldInterface
*/
protected $plugin;
/**
* @var \Drupal\migrate\Plugin\MigrationInterface
*/
protected $migration;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->plugin = new FileField([], 'file', []);
$migration = $this->prophesize(MigrationInterface::class);
// The plugin's processFieldValues() method will call
// mergeProcessOfProperty() and return nothing. So, in order to examine the
// process pipeline created by the plugin, we need to ensure that
// getProcess() always returns the last input to mergeProcessOfProperty().
$migration->mergeProcessOfProperty(Argument::type('string'), Argument::type('array'))
->will(function ($arguments) use ($migration) {
$migration->getProcess()->willReturn($arguments[1]);
});
$this->migration = $migration->reveal();
}
/**
* @covers ::processFieldValues
*/
public function testProcessFieldValues() {
$this->plugin->processFieldValues($this->migration, 'somefieldname', []);
$expected = [
'plugin' => 'iterator',
'source' => 'somefieldname',
'process' => [
'target_id' => 'fid',
'display' => 'display',
'description' => 'description',
],
];
$this->assertSame($expected, $this->migration->getProcess());
}
/**
* Data provider for testGetFieldType().
*/
public function getFieldTypeProvider() {
return [
['image', 'imagefield_widget'],
['file', 'filefield_widget'],
['file', 'x_widget']
];
}
/**
* @covers ::getFieldType
* @dataProvider getFieldTypeProvider
*/
public function testGetFieldType($expected_type, $widget_type, array $settings = []) {
$row = new Row();
$row->setSourceProperty('widget_type', $widget_type);
$row->setSourceProperty('global_settings', $settings);
$this->assertSame($expected_type, $this->plugin->getFieldType($row));
}
}
@@ -0,0 +1,65 @@
<?php
namespace Drupal\Tests\file\Unit\Plugin\migrate\field\d7;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\Tests\UnitTestCase;
use Drupal\file\Plugin\migrate\field\d7\ImageField;
use Prophecy\Argument;
/**
* @coversDefaultClass \Drupal\file\Plugin\migrate\field\d7\ImageField
* @group file
*/
class ImageFieldTest extends UnitTestCase {
/**
* @var \Drupal\migrate_drupal\Plugin\MigrateFieldInterface
*/
protected $plugin;
/**
* @var \Drupal\migrate\Plugin\MigrationInterface
*/
protected $migration;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->plugin = new ImageField([], 'image', []);
$migration = $this->prophesize(MigrationInterface::class);
// The plugin's processFieldValues() method will call
// mergeProcessOfProperty() and return nothing. So, in order to examine the
// process pipeline created by the plugin, we need to ensure that
// getProcess() always returns the last input to mergeProcessOfProperty().
$migration->mergeProcessOfProperty(Argument::type('string'), Argument::type('array'))
->will(function ($arguments) use ($migration) {
$migration->getProcess()->willReturn($arguments[1]);
});
$this->migration = $migration->reveal();
}
/**
* @covers ::processFieldValues
*/
public function testProcessFieldValues() {
$this->plugin->processFieldValues($this->migration, 'somefieldname', []);
$expected = [
'plugin' => 'iterator',
'source' => 'somefieldname',
'process' => [
'target_id' => 'fid',
'alt' => 'alt',
'title' => 'title',
'width' => 'width',
'height' => 'height',
],
];
$this->assertSame($expected, $this->migration->getProcess());
}
}
@@ -11,6 +11,7 @@ use Drupal\Tests\UnitTestCase;
/**
* @group file
* @group legacy
*/
class CckFileTest extends UnitTestCase {
@@ -0,0 +1,51 @@
<?php
namespace Drupal\Tests\file\Unit\Plugin\migrate\process\d6;
use Drupal\file\Plugin\migrate\process\d6\FieldFile;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Plugin\MigrateProcessInterface;
use Drupal\migrate\Row;
use Drupal\Tests\UnitTestCase;
/**
* @group file
*/
class FieldFileTest extends UnitTestCase {
/**
* Tests that alt and title attributes are included in transformed values.
*/
public function testTransformAltTitle() {
$executable = $this->prophesize(MigrateExecutableInterface::class)->reveal();
$row = $this->prophesize(Row::class)->reveal();
$migration = $this->prophesize(MigrationInterface::class)->reveal();
$migration_plugin = $this->prophesize(MigrateProcessInterface::class);
$migration_plugin->transform(1, $executable, $row, 'foo')->willReturn(1);
$plugin = new FieldFile([], 'd6_file', [], $migration, $migration_plugin->reveal());
$options = [
'alt' => 'Foobaz',
'title' => 'Wambooli',
];
$value = [
'fid' => 1,
'list' => TRUE,
'data' => serialize($options),
];
$transformed = $plugin->transform($value, $executable, $row, 'foo');
$expected = [
'target_id' => 1,
'display' => TRUE,
'description' => '',
'alt' => 'Foobaz',
'title' => 'Wambooli',
];
$this->assertSame($expected, $transformed);
}
}