Update to Drupal 8.0.3. For more information, see https://www.drupal.org/drupal-8.0.3-release-notes
This commit is contained in:
parent
10f9f7fbde
commit
9db4fae9a7
202 changed files with 3806 additions and 760 deletions
|
@ -977,7 +977,12 @@ function file_tokens($type, $tokens, array $data, array $options, BubbleableMeta
|
|||
break;
|
||||
|
||||
case 'url':
|
||||
// Ideally, this would use file_url_transform_relative(), but because
|
||||
// tokens are also often used in e-mails, it's better to keep absolute
|
||||
// file URLs. The 'url.site' cache context is associated to ensure the
|
||||
// correct absolute URL is used in case of a multisite setup.
|
||||
$replacements[$original] = file_create_url($file->getFileUri());
|
||||
$bubbleable_metadata->addCacheContexts(['url.site']);
|
||||
break;
|
||||
|
||||
// These tokens are default variations on the chained tokens handled below.
|
||||
|
@ -1228,7 +1233,13 @@ function template_preprocess_file_link(&$variables) {
|
|||
$options = array();
|
||||
|
||||
$file_entity = ($file instanceof File) ? $file : File::load($file->fid);
|
||||
// @todo Wrap in file_url_transform_relative(). This is currently
|
||||
// impossible. As a work-around, we currently add the 'url.site' cache context
|
||||
// to ensure different file URLs are generated for different sites in a
|
||||
// multisite setup, including HTTP and HTTPS versions of the same site.
|
||||
// Fix in https://www.drupal.org/node/2646744.
|
||||
$url = file_create_url($file_entity->getFileUri());
|
||||
$variables['#cache']['contexts'][] = 'url.site';
|
||||
|
||||
$mime_type = $file->getMimeType();
|
||||
// Set options as per anchor format described at
|
||||
|
|
|
@ -70,6 +70,8 @@ class File extends ContentEntityBase implements FileInterface {
|
|||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @see file_url_transform_relative()
|
||||
*/
|
||||
public function url($rel = 'canonical', $options = array()) {
|
||||
return file_create_url($this->getFileUri());
|
||||
|
|
|
@ -52,6 +52,8 @@ abstract class BaseFieldFileFormatterBase extends FormatterBase {
|
|||
$url = NULL;
|
||||
// Add support to link to the entity itself.
|
||||
if ($this->getSetting('link_to_file')) {
|
||||
// @todo Wrap in file_url_transform_relative(). This is currently
|
||||
// impossible. See below.
|
||||
$url = file_create_url($items->getEntity()->uri->value);
|
||||
}
|
||||
|
||||
|
@ -63,6 +65,16 @@ abstract class BaseFieldFileFormatterBase extends FormatterBase {
|
|||
'#type' => 'link',
|
||||
'#title' => $view_value,
|
||||
'#url' => Url::fromUri($url),
|
||||
// @todo Remove the 'url.site' cache context by using a relative file
|
||||
// URL (file_url_transform_relative()). This is currently impossible
|
||||
// because #type => link requires a Url object, and Url objects do not
|
||||
// support relative URLs: they require fully qualified URLs. Fix in
|
||||
// https://www.drupal.org/node/2646744.
|
||||
'#cache' => [
|
||||
'contexts' => [
|
||||
'url.site',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -55,6 +55,9 @@ class FileUriFormatter extends BaseFieldFileFormatterBase {
|
|||
protected function viewValue(FieldItemInterface $item) {
|
||||
$value = $item->value;
|
||||
if ($this->getSetting('file_download_path')) {
|
||||
// @todo Wrap in file_url_transform_relative(). This is currently
|
||||
// impossible. See BaseFieldFileFormatterBase::viewElements(). Fix in
|
||||
// https://www.drupal.org/node/2646744.
|
||||
$value = file_create_url($value);
|
||||
}
|
||||
return $value;
|
||||
|
|
|
@ -33,6 +33,9 @@ class RSSEnclosureFormatter extends FileFormatterBase {
|
|||
$entity->rss_elements[] = array(
|
||||
'key' => 'enclosure',
|
||||
'attributes' => array(
|
||||
// In RSS feeds, it is necessary to use absolute URLs. The 'url.site'
|
||||
// cache context is already associated with RSS feed responses, so it
|
||||
// does not need to be specified here.
|
||||
'url' => file_create_url($file->getFileUri()),
|
||||
'length' => $file->getSize(),
|
||||
'type' => $file->getMimeType(),
|
||||
|
|
|
@ -30,7 +30,7 @@ class UrlPlainFormatter extends FileFormatterBase {
|
|||
|
||||
foreach ($this->getEntitiesToView($items, $langcode) as $delta => $file) {
|
||||
$elements[$delta] = array(
|
||||
'#markup' => file_create_url($file->getFileUri()),
|
||||
'#markup' => file_url_transform_relative(file_create_url($file->getFileUri())),
|
||||
'#cache' => array(
|
||||
'tags' => $file->getCacheTags(),
|
||||
),
|
||||
|
|
|
@ -56,9 +56,11 @@ class FileFieldItemList extends EntityReferenceFieldItemList {
|
|||
$original_ids = array();
|
||||
$langcode = $this->getLangcode();
|
||||
$original = $entity->original;
|
||||
$original_items = $original->hasTranslation($langcode) ? $original->getTranslation($langcode)->{$field_name} : $original->{$field_name};
|
||||
foreach ($original_items as $item) {
|
||||
$original_ids[] = $item->target_id;
|
||||
if ($original->hasTranslation($langcode)) {
|
||||
$original_items = $original->getTranslation($langcode)->{$field_name};
|
||||
foreach ($original_items as $item) {
|
||||
$original_ids[] = $item->target_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Decrement file usage by 1 for files that were removed from the field.
|
||||
|
|
|
@ -186,7 +186,6 @@ class FileWidget extends WidgetBase implements ContainerFactoryPluginInterface {
|
|||
$elements['#description'] = $description;
|
||||
$elements['#field_name'] = $field_name;
|
||||
$elements['#language'] = $items->getLangcode();
|
||||
$elements['#display_field'] = (bool) $this->getFieldSetting('display_field');
|
||||
// The field settings include defaults for the field type. However, this
|
||||
// widget is a base class for other widgets (e.g., ImageWidget) that may
|
||||
// act on field types without these expected settings.
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\file\Plugin\migrate\cckfield\FileField.
|
||||
* Contains \Drupal\file\Plugin\migrate\cckfield\d6\FileField.
|
||||
*/
|
||||
|
||||
namespace Drupal\file\Plugin\migrate\cckfield;
|
||||
namespace Drupal\file\Plugin\migrate\cckfield\d6;
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\file\Plugin\migrate\cckfield\d7\FileField.
|
||||
*/
|
||||
|
||||
namespace Drupal\file\Plugin\migrate\cckfield\d7;
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
|
||||
|
||||
/**
|
||||
* @MigrateCckField(
|
||||
* id = "file",
|
||||
* )
|
||||
*/
|
||||
class FileField extends CckFieldPluginBase {
|
||||
|
||||
/**
|
||||
* {@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 processCckFieldValues(MigrationInterface $migration, $field_name, $data) {
|
||||
$process = [
|
||||
'plugin' => 'iterator',
|
||||
'source' => $field_name,
|
||||
'process' => [
|
||||
'target_id' => 'fid',
|
||||
'display' => 'display',
|
||||
'description' => 'description',
|
||||
],
|
||||
];
|
||||
$migration->mergeProcessOfProperty($field_name, $process);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFieldType(Row $row) {
|
||||
return $row->getSourceProperty('widget_type') == 'imagefield_widget' ? 'image' : 'file';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\file\Plugin\migrate\cckfield\d7\ImageField.
|
||||
*/
|
||||
|
||||
namespace Drupal\file\Plugin\migrate\cckfield\d7;
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
|
||||
|
||||
/**
|
||||
* @MigrateCckField(
|
||||
* id = "image"
|
||||
* )
|
||||
*/
|
||||
class ImageField extends CckFieldPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFieldFormatterMap() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function processCckFieldValues(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);
|
||||
}
|
||||
|
||||
}
|
|
@ -69,6 +69,12 @@ class File extends FieldPluginBase {
|
|||
protected function renderLink($data, ResultRow $values) {
|
||||
if (!empty($this->options['link_to_file']) && $data !== NULL && $data !== '') {
|
||||
$this->options['alter']['make_link'] = TRUE;
|
||||
// @todo Wrap in file_url_transform_relative(). This is currently
|
||||
// impossible. As a work-around, we could add the 'url.site' cache context
|
||||
// to ensure different file URLs are generated for different sites in a
|
||||
// multisite setup, including HTTP and HTTPS versions of the same site.
|
||||
// But unfortunately it's impossible to bubble a cache context here.
|
||||
// Fix in https://www.drupal.org/node/2646744.
|
||||
$this->options['alter']['path'] = file_create_url($this->getValue($values, 'uri'));
|
||||
}
|
||||
|
||||
|
|
208
core/modules/file/src/Tests/FileOnTranslatedEntityTest.php
Normal file
208
core/modules/file/src/Tests/FileOnTranslatedEntityTest.php
Normal file
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\file\Tests\FileOnTranslatedEntityTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\file\Tests;
|
||||
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\node\Entity\Node;
|
||||
|
||||
/**
|
||||
* Uploads files to translated nodes.
|
||||
*
|
||||
* @group file
|
||||
*/
|
||||
class FileOnTranslatedEntityTest extends FileFieldTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = array('language', 'content_translation');
|
||||
|
||||
/**
|
||||
* The name of the file field used in the test.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create the "Basic page" node type.
|
||||
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
|
||||
|
||||
// Create a file field on the "Basic page" node type.
|
||||
$this->fieldName = strtolower($this->randomMachineName());
|
||||
$this->createFileField($this->fieldName, 'node', 'page');
|
||||
|
||||
// Create and login user.
|
||||
$permissions = array(
|
||||
'access administration pages',
|
||||
'administer content translation',
|
||||
'administer content types',
|
||||
'administer languages',
|
||||
'create content translations',
|
||||
'create page content',
|
||||
'edit any page content',
|
||||
'translate any entity',
|
||||
'delete any page content',
|
||||
);
|
||||
$admin_user = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Add a second and third language.
|
||||
$edit = array();
|
||||
$edit['predefined_langcode'] = 'fr';
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
|
||||
$edit = array();
|
||||
$edit['predefined_langcode'] = 'nl';
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
|
||||
// Enable translation for "Basic page" nodes.
|
||||
$edit = array(
|
||||
'entity_types[node]' => 1,
|
||||
'settings[node][page][translatable]' => 1,
|
||||
"settings[node][page][fields][$this->fieldName]" => 1,
|
||||
);
|
||||
$this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
|
||||
\Drupal::entityManager()->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests synced file fields on translated nodes.
|
||||
*/
|
||||
public function testSyncedFiles() {
|
||||
// Verify that the file field on the "Basic page" node type is translatable.
|
||||
$definitions = \Drupal::entityManager()->getFieldDefinitions('node', 'page');
|
||||
$this->assertTrue($definitions[$this->fieldName]->isTranslatable(), 'Node file field is translatable.');
|
||||
|
||||
// Create a default language node.
|
||||
$default_language_node = $this->drupalCreateNode(array('type' => 'page', 'title' => 'Lost in translation'));
|
||||
|
||||
// Edit the node to upload a file.
|
||||
$edit = array();
|
||||
$name = 'files[' . $this->fieldName . '_0]';
|
||||
$edit[$name] = drupal_realpath($this->drupalGetTestFiles('text')[0]->uri);
|
||||
$this->drupalPostForm('node/' . $default_language_node->id() . '/edit', $edit, t('Save'));
|
||||
$first_fid = $this->getLastFileId();
|
||||
|
||||
// Translate the node into French: remove the existing file.
|
||||
$this->drupalPostForm('node/' . $default_language_node->id() . '/translations/add/en/fr', array(), t('Remove'));
|
||||
|
||||
// Upload a different file.
|
||||
$edit = array();
|
||||
$edit['title[0][value]'] = 'Bill Murray';
|
||||
$name = 'files[' . $this->fieldName . '_0]';
|
||||
$edit[$name] = drupal_realpath($this->drupalGetTestFiles('text')[1]->uri);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
// This inspects the HTML after the post of the translation, the file
|
||||
// should be displayed on the original node.
|
||||
$this->assertRaw('file--mime-text-plain');
|
||||
$second_fid = $this->getLastFileId();
|
||||
|
||||
\Drupal::entityTypeManager()->getStorage('file')->resetCache();
|
||||
|
||||
/* @var $file \Drupal\file\FileInterface */
|
||||
|
||||
// Ensure the file status of the first file permanent.
|
||||
$file = File::load($first_fid);
|
||||
$this->assertTrue($file->isPermanent());
|
||||
|
||||
// Ensure the file status of the second file is permanent.
|
||||
$file = File::load($second_fid);
|
||||
$this->assertTrue($file->isPermanent());
|
||||
|
||||
// Translate the node into dutch: remove the existing file.
|
||||
$this->drupalPostForm('node/' . $default_language_node->id() . '/translations/add/en/nl', array(), t('Remove'));
|
||||
|
||||
// Upload a different file.
|
||||
$edit = array();
|
||||
$edit['title[0][value]'] = 'Scarlett Johansson';
|
||||
$name = 'files[' . $this->fieldName . '_0]';
|
||||
$edit[$name] = drupal_realpath($this->drupalGetTestFiles('text')[2]->uri);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
$third_fid = $this->getLastFileId();
|
||||
|
||||
\Drupal::entityTypeManager()->getStorage('file')->resetCache();
|
||||
|
||||
// Ensure the first file is untouched.
|
||||
$file = File::load($first_fid);
|
||||
$this->assertTrue($file->isPermanent(), 'First file still exists and is permanent.');
|
||||
// This inspects the HTML after the post of the translation, the file
|
||||
// should be displayed on the original node.
|
||||
$this->assertRaw('file--mime-text-plain');
|
||||
|
||||
// Ensure the file status of the second file is permanent.
|
||||
$file = File::load($second_fid);
|
||||
$this->assertTrue($file->isPermanent());
|
||||
|
||||
// Ensure the file status of the third file is permanent.
|
||||
$file = File::load($third_fid);
|
||||
$this->assertTrue($file->isPermanent());
|
||||
|
||||
// Edit the second translation: remove the existing file.
|
||||
$this->drupalPostForm('fr/node/' . $default_language_node->id() . '/edit', array(), t('Remove'));
|
||||
|
||||
// Upload a different file.
|
||||
$edit = array();
|
||||
$edit['title[0][value]'] = 'David Bowie';
|
||||
$name = 'files[' . $this->fieldName . '_0]';
|
||||
$edit[$name] = drupal_realpath($this->drupalGetTestFiles('text')[3]->uri);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
$replaced_second_fid = $this->getLastFileId();
|
||||
|
||||
\Drupal::entityTypeManager()->getStorage('file')->resetCache();
|
||||
|
||||
// Ensure the first and third files are untouched.
|
||||
$file = File::load($first_fid);
|
||||
$this->assertTrue($file->isPermanent(), 'First file still exists and is permanent.');
|
||||
|
||||
$file = File::load($third_fid);
|
||||
$this->assertTrue($file->isPermanent());
|
||||
|
||||
// Ensure the file status of the replaced second file is permanent.
|
||||
$file = File::load($replaced_second_fid);
|
||||
$this->assertTrue($file->isPermanent());
|
||||
|
||||
// Ensure the file status of the old second file is now temporary.
|
||||
$file = File::load($second_fid);
|
||||
$this->assertTrue($file->isTemporary());
|
||||
|
||||
// Delete the third translation.
|
||||
$this->drupalPostForm('nl/node/' . $default_language_node->id() . '/delete', array(), t('Delete Dutch translation'));
|
||||
|
||||
\Drupal::entityTypeManager()->getStorage('file')->resetCache();
|
||||
|
||||
// Ensure the first and replaced second files are untouched.
|
||||
$file = File::load($first_fid);
|
||||
$this->assertTrue($file->isPermanent(), 'First file still exists and is permanent.');
|
||||
|
||||
$file = File::load($replaced_second_fid);
|
||||
$this->assertTrue($file->isPermanent());
|
||||
|
||||
// Ensure the file status of the third file is now temporary.
|
||||
$file = File::load($third_fid);
|
||||
$this->assertTrue($file->isTemporary());
|
||||
|
||||
// Delete the all translations.
|
||||
$this->drupalPostForm('node/' . $default_language_node->id() . '/delete', array(), t('Delete all translations'));
|
||||
|
||||
\Drupal::entityTypeManager()->getStorage('file')->resetCache();
|
||||
|
||||
// Ensure the file status of the all files are now temporary.
|
||||
$file = File::load($first_fid);
|
||||
$this->assertTrue($file->isTemporary(), 'First file still exists and is temporary.');
|
||||
|
||||
$file = File::load($replaced_second_fid);
|
||||
$this->assertTrue($file->isTemporary());
|
||||
}
|
||||
|
||||
}
|
|
@ -66,7 +66,8 @@ class FileTokenReplaceTest extends FileFieldTestBase {
|
|||
$metadata_tests['[file:path]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[file:mime]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[file:size]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[file:url]'] = $base_bubbleable_metadata;
|
||||
$bubbleable_metadata = clone $base_bubbleable_metadata;
|
||||
$metadata_tests['[file:url]'] = $bubbleable_metadata->addCacheContexts(['url.site']);
|
||||
$bubbleable_metadata = clone $base_bubbleable_metadata;
|
||||
$metadata_tests['[file:created]'] = $bubbleable_metadata->addCacheTags(['rendered']);
|
||||
$metadata_tests['[file:created:short]'] = $bubbleable_metadata;
|
||||
|
|
Reference in a new issue