Update to Drupal 8.0-dev-2015-11-17. Commits through da81cd220, Tue Nov 17 15:53:49 2015 +0000, Issue #2617224 by Wim Leers: Move around/fix some documentation.
This commit is contained in:
parent
4afb23bbd3
commit
7784f4c23d
929 changed files with 19798 additions and 5304 deletions
|
@ -5,3 +5,6 @@ migrate.destination.entity:file:
|
|||
source_path_property:
|
||||
type: string
|
||||
label: 'Source path'
|
||||
urlencode:
|
||||
type: boolean
|
||||
label: 'Whether to urlencode incoming file paths'
|
||||
|
|
|
@ -9,27 +9,6 @@ use Drupal\Core\Field\FieldDefinitionInterface;
|
|||
use Drupal\Core\Field\FieldFilteredMarkup;
|
||||
use Drupal\Core\Render\Element;
|
||||
|
||||
/**
|
||||
* Returns HTML for an individual file upload widget.
|
||||
*
|
||||
* Default template: file-widget.html.twig.
|
||||
*
|
||||
* @param array $variables
|
||||
* An associative array containing:
|
||||
* - element: A render element representing the file.
|
||||
*/
|
||||
function template_preprocess_file_widget(&$variables) {
|
||||
$element = $variables['element'];
|
||||
if (!empty($element['fids']['#value'])) {
|
||||
// Add the file size after the file name.
|
||||
$file = reset($element['#files']);
|
||||
$element['file_' . $file->id()]['filename']['#suffix'] = ' <span class="file-size">(' . format_size($file->getSize()) . ')</span> ';
|
||||
}
|
||||
$variables['element'] = $element;
|
||||
// The "js-form-managed-file" class is required for proper Ajax functionality.
|
||||
$variables['attributes'] = array('class' => array('file-widget', 'js-form-managed-file', 'form-managed-file', 'clearfix'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares variables for multi file form widget templates.
|
||||
*
|
||||
|
|
|
@ -110,10 +110,10 @@
|
|||
*/
|
||||
Drupal.behaviors.filePreviewLinks = {
|
||||
attach: function (context) {
|
||||
$(context).find('div.js-form-managed-file .file a, .file-widget .file a').on('click', Drupal.file.openInNewWindow);
|
||||
$(context).find('div.js-form-managed-file .file a').on('click', Drupal.file.openInNewWindow);
|
||||
},
|
||||
detach: function (context) {
|
||||
$(context).find('div.js-form-managed-file .file a, .file-widget .file a').off('click', Drupal.file.openInNewWindow);
|
||||
$(context).find('div.js-form-managed-file .file a').off('click', Drupal.file.openInNewWindow);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -555,10 +555,6 @@ function file_theme() {
|
|||
),
|
||||
|
||||
// From file.field.inc.
|
||||
'file_widget' => array(
|
||||
'render element' => 'element',
|
||||
'file' => 'file.field.inc',
|
||||
),
|
||||
'file_widget_multiple' => array(
|
||||
'render element' => 'element',
|
||||
'file' => 'file.field.inc',
|
||||
|
|
|
@ -23,3 +23,4 @@ process:
|
|||
uid: uid
|
||||
destination:
|
||||
plugin: entity:file
|
||||
urlencode: true
|
||||
|
|
|
@ -23,3 +23,4 @@ process:
|
|||
destination:
|
||||
plugin: entity:file
|
||||
source_path_property: filepath
|
||||
urlencode: true
|
||||
|
|
|
@ -27,8 +27,41 @@ class FileSelection extends DefaultSelection {
|
|||
*/
|
||||
protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
|
||||
$query = parent::buildEntityQuery($match, $match_operator);
|
||||
$query->condition('status', FILE_STATUS_PERMANENT);
|
||||
// Allow referencing :
|
||||
// - files with status "permanent"
|
||||
// - or files uploaded by the current user (since newly uploaded files only
|
||||
// become "permanent" after the containing entity gets validated and
|
||||
// saved.)
|
||||
$query->condition($query->orConditionGroup()
|
||||
->condition('status', FILE_STATUS_PERMANENT)
|
||||
->condition('uid', $this->currentUser->id()));
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createNewEntity($entity_type_id, $bundle, $label, $uid) {
|
||||
$file = parent::createNewEntity($entity_type_id, $bundle, $label, $uid);
|
||||
|
||||
// In order to create a referenceable file, it needs to have a "permanent"
|
||||
// status.
|
||||
/** @var \Drupal\file\FileInterface $file */
|
||||
$file->setPermanent();
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateReferenceableNewEntities(array $entities) {
|
||||
$entities = parent::validateReferenceableNewEntities($entities);
|
||||
$entities = array_filter($entities, function ($file) {
|
||||
/** @var \Drupal\file\FileInterface $file */
|
||||
return $file->isPermanent() || $file->getOwnerId() === $this->currentUser->id();
|
||||
});
|
||||
return $entities;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ use Drupal\Core\TypedData\DataDefinition;
|
|||
* default_widget = "file_generic",
|
||||
* default_formatter = "file_default",
|
||||
* list_class = "\Drupal\file\Plugin\Field\FieldType\FileFieldItemList",
|
||||
* constraints = {"ValidReference" = {}, "ReferenceAccess" = {}}
|
||||
* constraints = {"ReferenceAccess" = {}, "FileValidation" = {}}
|
||||
* )
|
||||
*/
|
||||
class FileItem extends EntityReferenceItem {
|
||||
|
|
|
@ -18,8 +18,9 @@ use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
|||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Render\ElementInfoManagerInterface;
|
||||
use Drupal\file\Element\ManagedFile;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\file\Entity\File;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'file_generic' widget.
|
||||
|
@ -369,11 +370,6 @@ class FileWidget extends WidgetBase implements ContainerFactoryPluginInterface {
|
|||
$item = $element['#value'];
|
||||
$item['fids'] = $element['fids']['#value'];
|
||||
|
||||
// Prevent the file widget from overriding the image widget.
|
||||
if (!isset($element['#theme'])) {
|
||||
$element['#theme'] = 'file_widget';
|
||||
}
|
||||
|
||||
// Add the display field if enabled.
|
||||
if ($element['#display_field']) {
|
||||
$element['display'] = array(
|
||||
|
@ -575,4 +571,15 @@ class FileWidget extends WidgetBase implements ContainerFactoryPluginInterface {
|
|||
static::setWidgetState($parents, $field_name, $form_state, $field_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function flagErrors(FieldItemListInterface $items, ConstraintViolationListInterface $violations, array $form, FormStateInterface $form_state) {
|
||||
// Never flag validation errors for the remove button.
|
||||
$clicked_button = end($form_state->getTriggeringElement()['#parents']);
|
||||
if ($clicked_button !== 'remove_button') {
|
||||
parent::flagErrors($items, $violations, $form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\file\Plugin\Validation\Constraint\FileValidationConstraint.
|
||||
*/
|
||||
|
||||
namespace Drupal\file\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
/**
|
||||
* Validation File constraint.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "FileValidation",
|
||||
* label = @Translation("File Validation", context = "Validation")
|
||||
* )
|
||||
*/
|
||||
class FileValidationConstraint extends Constraint {
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\file\Plugin\Validation\Constraint\FileValidationConstraintValidator.
|
||||
*/
|
||||
|
||||
namespace Drupal\file\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
|
||||
/**
|
||||
* Checks that a file referenced in a file field is valid.
|
||||
*/
|
||||
class FileValidationConstraintValidator extends ConstraintValidator {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($value, Constraint $constraint) {
|
||||
// Get the file to execute validators.
|
||||
$file = $value->get('entity')->getTarget()->getValue();
|
||||
// Get the validators.
|
||||
$validators = $value->getUploadValidators();
|
||||
// Checks that a file meets the criteria specified by the validators.
|
||||
if ($errors = file_validate($file, $validators)) {
|
||||
foreach ($errors as $error) {
|
||||
$this->context->addViolation($error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -7,8 +7,11 @@
|
|||
|
||||
namespace Drupal\file\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\UriItem;
|
||||
use Drupal\Core\File\FileSystemInterface;
|
||||
use Drupal\Core\StreamWrapper\LocalStream;
|
||||
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
|
||||
|
@ -41,7 +44,7 @@ class EntityFile extends EntityContentBase {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, StreamWrapperManagerInterface $stream_wrappers, FileSystemInterface $file_system) {
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager, StreamWrapperManagerInterface $stream_wrappers, FileSystemInterface $file_system) {
|
||||
$configuration += array(
|
||||
'source_base_path' => '',
|
||||
'source_path_property' => 'filepath',
|
||||
|
@ -49,7 +52,7 @@ class EntityFile extends EntityContentBase {
|
|||
'move' => FALSE,
|
||||
'urlencode' => FALSE,
|
||||
);
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_manager);
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_manager, $field_type_manager);
|
||||
|
||||
$this->streamWrapperManager = $stream_wrappers;
|
||||
$this->fileSystem = $file_system;
|
||||
|
@ -68,6 +71,7 @@ class EntityFile extends EntityContentBase {
|
|||
$container->get('entity.manager')->getStorage($entity_type),
|
||||
array_keys($container->get('entity.manager')->getBundleInfo($entity_type)),
|
||||
$container->get('entity.manager'),
|
||||
$container->get('plugin.manager.field.field_type'),
|
||||
$container->get('stream_wrapper_manager'),
|
||||
$container->get('file_system')
|
||||
);
|
||||
|
@ -77,6 +81,12 @@ class EntityFile extends EntityContentBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntity(Row $row, array $old_destination_id_values) {
|
||||
// For stub rows, there is no real file to deal with, let the stubbing
|
||||
// process take its default path.
|
||||
if ($row->isStub()) {
|
||||
return parent::getEntity($row, $old_destination_id_values);
|
||||
}
|
||||
|
||||
$destination = $row->getDestinationProperty($this->configuration['destination_path_property']);
|
||||
$entity = $this->storage->loadByProperties(['uri' => $destination]);
|
||||
if ($entity) {
|
||||
|
@ -91,6 +101,12 @@ class EntityFile extends EntityContentBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
// For stub rows, there is no real file to deal with, let the stubbing
|
||||
// process create the stub entity.
|
||||
if ($row->isStub()) {
|
||||
return parent::import($row, $old_destination_id_values);
|
||||
}
|
||||
|
||||
$file = $row->getSourceProperty($this->configuration['source_path_property']);
|
||||
$destination = $row->getDestinationProperty($this->configuration['destination_path_property']);
|
||||
$source = $this->configuration['source_base_path'] . $file;
|
||||
|
@ -256,4 +272,30 @@ class EntityFile extends EntityContentBase {
|
|||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function processStubRow(Row $row) {
|
||||
// We stub the uri value ourselves so we can create a real stub file for it.
|
||||
if (!$row->getDestinationProperty('uri')) {
|
||||
$field_definitions = $this->entityManager
|
||||
->getFieldDefinitions($this->storage->getEntityTypeId(),
|
||||
$this->getKey('bundle'));
|
||||
$value = UriItem::generateSampleValue($field_definitions['uri']);
|
||||
if (empty($value)) {
|
||||
throw new MigrateException('Stubbing failed, unable to generate value for field uri');
|
||||
}
|
||||
// generateSampleValue() wraps the value in an array.
|
||||
$value = reset($value);
|
||||
// Make it into a proper public file uri, stripping off the existing
|
||||
// scheme if present.
|
||||
$value = 'public://' . preg_replace('|^[a-z]+://|i', '', $value);
|
||||
$value = Unicode::substr($value, 0, $field_definitions['uri']->getSetting('max_length'));
|
||||
// Create a real file, so File::preSave() can do filesize() on it.
|
||||
touch($value);
|
||||
$row->setDestinationProperty('uri', $value);
|
||||
}
|
||||
parent::processStubRow($row);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,11 @@ class FileUri extends ProcessPluginBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
// If we're stubbing a file entity, return a uri of NULL so it will get
|
||||
// stubbed by the general process.
|
||||
if ($row->isStub()) {
|
||||
return NULL;
|
||||
}
|
||||
list($filepath, $file_directory_path, $temp_directory_path, $is_public) = $value;
|
||||
|
||||
// Specific handling using $temp_directory_path for temporary files.
|
||||
|
|
|
@ -159,4 +159,35 @@ class FileFieldValidateTest extends FileFieldTestBase {
|
|||
$this->assertFileEntryExists($node_file, 'File entry exists after uploading a file with extension checking.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a file can always be removed if it does not pass validation.
|
||||
*/
|
||||
public function testFileRemoval() {
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$type_name = 'article';
|
||||
$field_name = 'file_test';
|
||||
$this->createFileField($field_name, 'node', $type_name);
|
||||
|
||||
$test_file = $this->getTestFile('image');
|
||||
|
||||
// Disable extension checking.
|
||||
$this->updateFileField($field_name, $type_name, array('file_extensions' => ''));
|
||||
|
||||
// Check that the file can be uploaded with no extension checking.
|
||||
$nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
|
||||
$node_storage->resetCache(array($nid));
|
||||
$node = $node_storage->load($nid);
|
||||
$node_file = File::load($node->{$field_name}->target_id);
|
||||
$this->assertFileExists($node_file, 'File exists after uploading a file with no extension checking.');
|
||||
$this->assertFileEntryExists($node_file, 'File entry exists after uploading a file with no extension checking.');
|
||||
|
||||
// Enable extension checking for text files.
|
||||
$this->updateFileField($field_name, $type_name, array('file_extensions' => 'txt'));
|
||||
|
||||
// Check that the file can still be removed.
|
||||
$this->removeNodeFile($nid);
|
||||
$this->assertNoText('Only files with the following extensions are allowed: txt.');
|
||||
$this->assertText('Article ' . $node->getTitle() . ' has been updated.');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
42
core/modules/file/src/Tests/Migrate/MigrateFileStubTest.php
Normal file
42
core/modules/file/src/Tests/Migrate/MigrateFileStubTest.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\file\Tests\Migrate\MigrateFileStubTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\file\Tests\Migrate;
|
||||
|
||||
use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
|
||||
use Drupal\migrate_drupal\Tests\StubTestTrait;
|
||||
|
||||
/**
|
||||
* Test stub creation for file entities.
|
||||
*
|
||||
* @group file
|
||||
*/
|
||||
class MigrateFileStubTest extends MigrateDrupalTestBase {
|
||||
|
||||
use StubTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['file'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('file');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests creation of file stubs.
|
||||
*/
|
||||
public function testStub() {
|
||||
$this->performStubTest('file');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display a file widget.
|
||||
*
|
||||
* Available variables:
|
||||
* - element: Form element for the managed file.
|
||||
* - attributes: Remaining HTML attributes for the containing element.
|
||||
*
|
||||
* @see template_preprocess_file_widget()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
<div{{ attributes }}>
|
||||
{{ element }}
|
||||
</div>
|
119
core/modules/file/tests/src/Kernel/FileItemValidationTest.php
Normal file
119
core/modules/file/tests/src/Kernel/FileItemValidationTest.php
Normal file
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\file\Kernel\FileItemValidationTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\file\Kernel;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
|
||||
/**
|
||||
* Tests that files referenced in file and image fields are always validated.
|
||||
*
|
||||
* @group file
|
||||
*/
|
||||
class FileItemValidationTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['file', 'image', 'entity_test', 'field', 'user', 'system'];
|
||||
|
||||
/**
|
||||
* A user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('user');
|
||||
$this->installEntitySchema('file');
|
||||
$this->installSchema('file', 'file_usage');
|
||||
$this->installSchema('system', 'sequences');
|
||||
|
||||
$this->user = User::create([
|
||||
'name' => 'username',
|
||||
'status' => 1,
|
||||
]);
|
||||
$this->user->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Drupal\file\Plugin\Validation\Constraint\FileValidationConstraint
|
||||
* @covers \Drupal\file\Plugin\Validation\Constraint\FileValidationConstraintValidator
|
||||
* @dataProvider getFileTypes
|
||||
*/
|
||||
public function testFileValidationConstraint($file_type) {
|
||||
$field_storage = FieldStorageConfig::create([
|
||||
'field_name' => 'field_test_file',
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => $file_type,
|
||||
]);
|
||||
$field_storage->save();
|
||||
|
||||
$field = FieldConfig::create([
|
||||
'field_name' => 'field_test_file',
|
||||
'entity_type' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'settings' => [
|
||||
'max_filesize' => '2k',
|
||||
'file_extensions' => 'jpg|png',
|
||||
],
|
||||
]);
|
||||
$field->save();
|
||||
|
||||
vfsStream::setup('drupal_root');
|
||||
vfsStream::create([
|
||||
'sites' => [
|
||||
'default' => [
|
||||
'files' => [
|
||||
'test.txt' => str_repeat('a', 3000),
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
// Test for max filesize.
|
||||
$file = File::create([
|
||||
'uri' => 'vfs://drupal_root/sites/default/files/test.txt',
|
||||
]);
|
||||
$file->setPermanent();
|
||||
$file->save();
|
||||
|
||||
$entity_test = EntityTest::create([
|
||||
'uid' => $this->user->id(),
|
||||
'field_test_file' => [
|
||||
'target_id' => $file->id(),
|
||||
]
|
||||
]);
|
||||
$result = $entity_test->validate();
|
||||
$this->assertCount(2, $result);
|
||||
|
||||
$this->assertEquals('field_test_file.0', $result->get(0)->getPropertyPath());
|
||||
$this->assertEquals('The file is <em class="placeholder">2.93 KB</em> exceeding the maximum file size of <em class="placeholder">2 KB</em>.', (string) $result->get(0)->getMessage());
|
||||
$this->assertEquals('field_test_file.0', $result->get(1)->getPropertyPath());
|
||||
$this->assertEquals('Only files with the following extensions are allowed: <em class="placeholder">jpg|png</em>.', (string) $result->get(1)->getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of file types to test.
|
||||
*/
|
||||
public function getFileTypes() {
|
||||
return [['file'], ['image']];
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue