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:
Pantheon Automation 2015-11-17 13:42:33 -08:00 committed by Greg Anderson
parent 4afb23bbd3
commit 7784f4c23d
929 changed files with 19798 additions and 5304 deletions

View file

@ -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'

View file

@ -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.
*

View file

@ -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);
}
};

View file

@ -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',

View file

@ -23,3 +23,4 @@ process:
uid: uid
destination:
plugin: entity:file
urlencode: true

View file

@ -23,3 +23,4 @@ process:
destination:
plugin: entity:file
source_path_property: filepath
urlencode: true

View file

@ -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;
}
}

View file

@ -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 {

View file

@ -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);
}
}
}

View file

@ -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 {
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}

View file

@ -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.

View file

@ -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.');
}
}

View 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');
}
}

View 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>

View 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']];
}
}