Update Composer, update everything
This commit is contained in:
parent
ea3e94409f
commit
dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions
|
@ -11,6 +11,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
|
||||
|
||||
|
@ -79,6 +80,8 @@ class ImageStyleDownloadController extends FileDownloadController {
|
|||
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse|\Symfony\Component\HttpFoundation\Response
|
||||
* The transferred file as response or some error response.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||
* Thrown when the file request is invalid.
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
* Thrown when the user does not have access to the file.
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException
|
||||
|
@ -104,7 +107,11 @@ class ImageStyleDownloadController extends FileDownloadController {
|
|||
$valid &= $request->query->get(IMAGE_DERIVATIVE_TOKEN) === $image_style->getPathToken($image_uri);
|
||||
}
|
||||
if (!$valid) {
|
||||
throw new AccessDeniedHttpException();
|
||||
// Return a 404 (Page Not Found) rather than a 403 (Access Denied) as the
|
||||
// image token is for DDoS protection rather than access checking. 404s
|
||||
// are more likely to be cached (e.g. at a proxy) which enhances
|
||||
// protection from DDoS.
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
$derivative_uri = $image_style->buildUri($image_uri);
|
||||
|
|
|
@ -10,7 +10,7 @@ use Drupal\Core\Image\ImageFactory;
|
|||
use Drupal\Core\Render\Element\StatusMessages;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\image\Plugin\Field\FieldType\ImageItem;
|
||||
use Drupal\user\PrivateTempStoreFactory;
|
||||
use Drupal\Core\TempStore\PrivateTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
|
@ -23,7 +23,7 @@ class QuickEditImageController extends ControllerBase {
|
|||
/**
|
||||
* Stores The Quick Edit tempstore.
|
||||
*
|
||||
* @var \Drupal\user\PrivateTempStore
|
||||
* @var \Drupal\Core\TempStore\PrivateTempStore
|
||||
*/
|
||||
protected $tempStore;
|
||||
|
||||
|
@ -48,7 +48,7 @@ class QuickEditImageController extends ControllerBase {
|
|||
* The renderer.
|
||||
* @param \Drupal\Core\Image\ImageFactory $image_factory
|
||||
* The image factory.
|
||||
* @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
|
||||
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $temp_store_factory
|
||||
* The tempstore factory.
|
||||
*/
|
||||
public function __construct(RendererInterface $renderer, ImageFactory $image_factory, PrivateTempStoreFactory $temp_store_factory) {
|
||||
|
@ -64,7 +64,7 @@ class QuickEditImageController extends ControllerBase {
|
|||
return new static(
|
||||
$container->get('renderer'),
|
||||
$container->get('image.factory'),
|
||||
$container->get('user.private_tempstore')
|
||||
$container->get('tempstore.private')
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,12 +17,20 @@ use Drupal\Component\Utility\UrlHelper;
|
|||
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
||||
|
||||
/**
|
||||
* Defines an image style configuration entity.
|
||||
*
|
||||
* @ConfigEntityType(
|
||||
* id = "image_style",
|
||||
* label = @Translation("Image style"),
|
||||
* label_collection = @Translation("Image styles"),
|
||||
* label_singular = @Translation("image style"),
|
||||
* label_plural = @Translation("image styles"),
|
||||
* label_count = @PluralTranslation(
|
||||
* singular = "@count image style",
|
||||
* plural = "@count image styles",
|
||||
* ),
|
||||
* handlers = {
|
||||
* "form" = {
|
||||
* "add" = "Drupal\image\Form\ImageStyleAddForm",
|
||||
|
@ -274,9 +282,8 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface, Entity
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function createDerivative($original_uri, $derivative_uri) {
|
||||
|
||||
// If the source file doesn't exist, return FALSE without creating folders.
|
||||
$image = \Drupal::service('image.factory')->get($original_uri);
|
||||
$image = $this->getImageFactory()->get($original_uri);
|
||||
if (!$image->isValid()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -340,6 +347,18 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface, Entity
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsUri($uri) {
|
||||
// Only support the URI if its extension is supported by the current image
|
||||
// toolkit.
|
||||
return in_array(
|
||||
mb_strtolower(pathinfo($uri, PATHINFO_EXTENSION)),
|
||||
$this->getImageFactory()->getSupportedExtensions()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -408,6 +427,16 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface, Entity
|
|||
return \Drupal::service('plugin.manager.image.effect');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image factory.
|
||||
*
|
||||
* @return \Drupal\Core\Image\ImageFactory
|
||||
* The image factory.
|
||||
*/
|
||||
protected function getImageFactory() {
|
||||
return \Drupal::service('image.factory');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Drupal private key.
|
||||
*
|
||||
|
|
|
@ -9,6 +9,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
|
||||
/**
|
||||
* Provides an add form for image effects.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ImageEffectAddForm extends ImageEffectFormBase {
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ use Drupal\image\ImageStyleInterface;
|
|||
|
||||
/**
|
||||
* Form for deleting an image effect.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ImageEffectDeleteForm extends ConfirmFormBase {
|
||||
|
||||
|
@ -68,7 +70,7 @@ class ImageEffectDeleteForm extends ConfirmFormBase {
|
|||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->imageStyle->deleteImageEffect($this->imageEffect);
|
||||
drupal_set_message($this->t('The image effect %name has been deleted.', ['%name' => $this->imageEffect->label()]));
|
||||
$this->messenger()->addStatus($this->t('The image effect %name has been deleted.', ['%name' => $this->imageEffect->label()]));
|
||||
$form_state->setRedirectUrl($this->imageStyle->urlInfo('edit-form'));
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ use Drupal\image\ImageStyleInterface;
|
|||
|
||||
/**
|
||||
* Provides an edit form for image effects.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ImageEffectEditForm extends ImageEffectFormBase {
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ abstract class ImageEffectFormBase extends FormBase {
|
|||
}
|
||||
$this->imageStyle->save();
|
||||
|
||||
drupal_set_message($this->t('The image effect was successfully applied.'));
|
||||
$this->messenger()->addStatus($this->t('The image effect was successfully applied.'));
|
||||
$form_state->setRedirectUrl($this->imageStyle->urlInfo('edit-form'));
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
|
||||
/**
|
||||
* Controller for image style addition forms.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ImageStyleAddForm extends ImageStyleFormBase {
|
||||
|
||||
|
@ -14,7 +16,7 @@ class ImageStyleAddForm extends ImageStyleFormBase {
|
|||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::submitForm($form, $form_state);
|
||||
drupal_set_message($this->t('Style %name was created.', ['%name' => $this->entity->label()]));
|
||||
$this->messenger()->addStatus($this->t('Style %name was created.', ['%name' => $this->entity->label()]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,8 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
|
||||
/**
|
||||
* Creates a form to delete an image style.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ImageStyleDeleteForm extends EntityDeleteForm {
|
||||
|
||||
|
@ -23,6 +25,7 @@ class ImageStyleDeleteForm extends EntityDeleteForm {
|
|||
public function getQuestion() {
|
||||
return $this->t('Optionally select a style before deleting %style', ['%style' => $this->entity->label()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\image\Form;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
|
@ -11,6 +12,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
|
||||
/**
|
||||
* Controller for image style edit form.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ImageStyleEditForm extends ImageStyleFormBase {
|
||||
|
||||
|
@ -58,7 +61,7 @@ class ImageStyleEditForm extends ImageStyleFormBase {
|
|||
$form['preview'] = [
|
||||
'#type' => 'item',
|
||||
'#title' => $this->t('Preview'),
|
||||
'#markup' => drupal_render($preview_arguments),
|
||||
'#markup' => \Drupal::service('renderer')->render($preview_arguments),
|
||||
// Render preview above parent elements.
|
||||
'#weight' => -5,
|
||||
];
|
||||
|
@ -143,7 +146,7 @@ class ImageStyleEditForm extends ImageStyleFormBase {
|
|||
$new_effect_options = [];
|
||||
$effects = $this->imageEffectManager->getDefinitions();
|
||||
uasort($effects, function ($a, $b) {
|
||||
return strcasecmp($a['id'], $b['id']);
|
||||
return Unicode::strcasecmp($a['label'], $b['label']);
|
||||
});
|
||||
foreach ($effects as $effect => $definition) {
|
||||
$new_effect_options[$effect] = $definition['label'];
|
||||
|
@ -228,7 +231,7 @@ class ImageStyleEditForm extends ImageStyleFormBase {
|
|||
$effect_id = $this->entity->addImageEffect($effect);
|
||||
$this->entity->save();
|
||||
if (!empty($effect_id)) {
|
||||
drupal_set_message($this->t('The image effect was successfully applied.'));
|
||||
$this->messenger()->addStatus($this->t('The image effect was successfully applied.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -251,17 +254,7 @@ class ImageStyleEditForm extends ImageStyleFormBase {
|
|||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
parent::save($form, $form_state);
|
||||
drupal_set_message($this->t('Changes to the style have been saved.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function actions(array $form, FormStateInterface $form_state) {
|
||||
$actions = parent::actions($form, $form_state);
|
||||
$actions['submit']['#value'] = $this->t('Update style');
|
||||
|
||||
return $actions;
|
||||
$this->messenger()->addStatus($this->t('Changes to the style have been saved.'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,8 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
|
||||
/**
|
||||
* Form controller for image style flush.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ImageStyleFlushForm extends EntityConfirmFormBase {
|
||||
|
||||
|
@ -43,7 +45,7 @@ class ImageStyleFlushForm extends EntityConfirmFormBase {
|
|||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->entity->flush();
|
||||
drupal_set_message($this->t('The image style %name has been flushed.', ['%name' => $this->entity->label()]));
|
||||
$this->messenger()->addStatus($this->t('The image style %name has been flushed.', ['%name' => $this->entity->label()]));
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
}
|
||||
|
||||
|
|
|
@ -50,8 +50,7 @@ interface ImageEffectInterface extends PluginInspectionInterface, ConfigurablePl
|
|||
public function transformDimensions(array &$dimensions, $uri);
|
||||
|
||||
/**
|
||||
* Returns the extension the derivative would have have after applying this
|
||||
* image effect.
|
||||
* Returns the extension of the derivative after applying this image effect.
|
||||
*
|
||||
* @param string $extension
|
||||
* The file extension the derivative has before applying.
|
||||
|
|
|
@ -42,7 +42,6 @@ interface ImageStyleInterface extends ConfigEntityInterface {
|
|||
*/
|
||||
public function setName($name);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the URI of this image when using this style.
|
||||
*
|
||||
|
@ -194,4 +193,15 @@ interface ImageStyleInterface extends ConfigEntityInterface {
|
|||
*/
|
||||
public function deleteImageEffect(ImageEffectInterface $effect);
|
||||
|
||||
/**
|
||||
* Determines if this style can be applied to a given image.
|
||||
*
|
||||
* @param string $uri
|
||||
* The URI of the image.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the image is supported, FALSE otherwise.
|
||||
*/
|
||||
public function supportsUri($uri);
|
||||
|
||||
}
|
||||
|
|
|
@ -39,9 +39,17 @@ class ImageStyleListBuilder extends ConfigEntityListBuilder {
|
|||
'url' => $entity->urlInfo('flush-form'),
|
||||
];
|
||||
|
||||
return parent::getDefaultOperations($entity) + [
|
||||
$operations = parent::getDefaultOperations($entity) + [
|
||||
'flush' => $flush,
|
||||
];
|
||||
|
||||
// Remove destination URL from the edit link to allow editing image
|
||||
// effects.
|
||||
if (isset($operations['edit'])) {
|
||||
$operations['edit']['url'] = $entity->toUrl('edit-form');
|
||||
}
|
||||
|
||||
return $operations;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -48,8 +48,11 @@ class PathProcessorImageStyles implements InboundPathProcessorInterface {
|
|||
if (strpos($path, '/' . $directory_path . '/styles/') === 0) {
|
||||
$path_prefix = '/' . $directory_path . '/styles/';
|
||||
}
|
||||
elseif (strpos($path, '/system/files/styles/') === 0) {
|
||||
// Check if the string '/system/files/styles/' exists inside the path,
|
||||
// that means we have a case of private file's image style.
|
||||
elseif (strpos($path, '/system/files/styles/') !== FALSE) {
|
||||
$path_prefix = '/system/files/styles/';
|
||||
$path = substr($path, strpos($path, $path_prefix), strlen($path));
|
||||
}
|
||||
else {
|
||||
return $path;
|
||||
|
|
|
@ -115,7 +115,7 @@ class ImageFormatter extends ImageFormatterBase implements ContainerFactoryPlugi
|
|||
'#empty_option' => t('None (original image)'),
|
||||
'#options' => $image_styles,
|
||||
'#description' => $description_link->toRenderable() + [
|
||||
'#access' => $this->currentUser->hasPermission('administer image styles')
|
||||
'#access' => $this->currentUser->hasPermission('administer image styles'),
|
||||
],
|
||||
];
|
||||
$link_types = [
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\image\Plugin\Field\FieldType;
|
||||
|
||||
use Drupal\Component\Utility\Random;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
@ -262,7 +263,7 @@ class ImageItem extends FileItem {
|
|||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable <em>Alt</em> field'),
|
||||
'#default_value' => $settings['alt_field'],
|
||||
'#description' => t('The alt attribute may be used by search engines, screen readers, and when the image cannot be loaded. Enabling this field is recommended.'),
|
||||
'#description' => t('Short description of the image used by screen readers and displayed when the image is not loaded. Enabling this field is recommended.'),
|
||||
'#weight' => 9,
|
||||
];
|
||||
$element['alt_field_required'] = [
|
||||
|
@ -313,13 +314,18 @@ class ImageItem extends FileItem {
|
|||
$height = $this->height;
|
||||
|
||||
// Determine the dimensions if necessary.
|
||||
if (empty($width) || empty($height)) {
|
||||
$image = \Drupal::service('image.factory')->get($this->entity->getFileUri());
|
||||
if ($image->isValid()) {
|
||||
$this->width = $image->getWidth();
|
||||
$this->height = $image->getHeight();
|
||||
if ($this->entity && $this->entity instanceof EntityInterface) {
|
||||
if (empty($width) || empty($height)) {
|
||||
$image = \Drupal::service('image.factory')->get($this->entity->getFileUri());
|
||||
if ($image->isValid()) {
|
||||
$this->width = $image->getWidth();
|
||||
$this->height = $image->getHeight();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
trigger_error(sprintf("Missing file with ID %s.", $this->target_id), E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -338,8 +344,8 @@ class ImageItem extends FileItem {
|
|||
if (!isset($images[$extension][$min_resolution][$max_resolution]) || count($images[$extension][$min_resolution][$max_resolution]) <= 5) {
|
||||
$tmp_file = drupal_tempnam('temporary://', 'generateImage_');
|
||||
$destination = $tmp_file . '.' . $extension;
|
||||
file_unmanaged_move($tmp_file, $destination, FILE_CREATE_DIRECTORY);
|
||||
if ($path = $random->image(drupal_realpath($destination), $min_resolution, $max_resolution)) {
|
||||
file_unmanaged_move($tmp_file, $destination);
|
||||
if ($path = $random->image(\Drupal::service('file_system')->realpath($destination), $min_resolution, $max_resolution)) {
|
||||
$image = File::create();
|
||||
$image->setFileUri($path);
|
||||
$image->setOwnerId(\Drupal::currentUser()->id());
|
||||
|
@ -348,7 +354,7 @@ class ImageItem extends FileItem {
|
|||
$destination_dir = static::doGetUploadLocation($settings);
|
||||
file_prepare_directory($destination_dir, FILE_CREATE_DIRECTORY);
|
||||
$destination = $destination_dir . '/' . basename($path);
|
||||
$file = file_move($image, $destination, FILE_CREATE_DIRECTORY);
|
||||
$file = file_move($image, $destination);
|
||||
$images[$extension][$min_resolution][$max_resolution][$file->id()] = $file;
|
||||
}
|
||||
else {
|
||||
|
@ -427,7 +433,7 @@ class ImageItem extends FileItem {
|
|||
$element['default_image']['alt'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Alternative text'),
|
||||
'#description' => t('This text will be used by screen readers, search engines, and when the image cannot be loaded.'),
|
||||
'#description' => t('Short description of the image used by screen readers and displayed when the image is not loaded. This is important for accessibility.'),
|
||||
'#default_value' => $settings['default_image']['alt'],
|
||||
'#maxlength' => 512,
|
||||
];
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
namespace Drupal\image\Plugin\Field\FieldWidget;
|
||||
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Image\ImageFactory;
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\ElementInfoManagerInterface;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\file\Plugin\Field\FieldWidget\FileWidget;
|
||||
use Drupal\image\Entity\ImageStyle;
|
||||
|
@ -22,6 +25,36 @@ use Drupal\image\Entity\ImageStyle;
|
|||
*/
|
||||
class ImageWidget extends FileWidget {
|
||||
|
||||
/**
|
||||
* The image factory service.
|
||||
*
|
||||
* @var \Drupal\Core\Image\ImageFactory
|
||||
*/
|
||||
protected $imageFactory;
|
||||
|
||||
/**
|
||||
* Constructs an ImageWidget object.
|
||||
*
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the widget.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The definition of the field to which the widget is associated.
|
||||
* @param array $settings
|
||||
* The widget settings.
|
||||
* @param array $third_party_settings
|
||||
* Any third party settings.
|
||||
* @param \Drupal\Core\Render\ElementInfoManagerInterface $element_info
|
||||
* The element info manager service.
|
||||
* @param \Drupal\Core\Image\ImageFactory $image_factory
|
||||
* The image factory service.
|
||||
*/
|
||||
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, ElementInfoManagerInterface $element_info, ImageFactory $image_factory = NULL) {
|
||||
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings, $element_info);
|
||||
$this->imageFactory = $image_factory ?: \Drupal::service('image.factory');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -112,15 +145,21 @@ class ImageWidget extends FileWidget {
|
|||
|
||||
$field_settings = $this->getFieldSettings();
|
||||
|
||||
// Add image validation.
|
||||
$element['#upload_validators']['file_validate_is_image'] = [];
|
||||
|
||||
// Add upload resolution validation.
|
||||
if ($field_settings['max_resolution'] || $field_settings['min_resolution']) {
|
||||
$element['#upload_validators']['file_validate_image_resolution'] = [$field_settings['max_resolution'], $field_settings['min_resolution']];
|
||||
}
|
||||
|
||||
// If not using custom extension validation, ensure this is an image.
|
||||
$supported_extensions = ['png', 'gif', 'jpg', 'jpeg'];
|
||||
$extensions = isset($element['#upload_validators']['file_validate_extensions'][0]) ? $element['#upload_validators']['file_validate_extensions'][0] : implode(' ', $supported_extensions);
|
||||
$extensions = array_intersect(explode(' ', $extensions), $supported_extensions);
|
||||
$extensions = $field_settings['file_extensions'];
|
||||
$supported_extensions = $this->imageFactory->getSupportedExtensions();
|
||||
|
||||
// If using custom extension validation, ensure that the extensions are
|
||||
// supported by the current image toolkit. Otherwise, validate against all
|
||||
// toolkit supported extensions.
|
||||
$extensions = !empty($extensions) ? array_intersect(explode(' ', $extensions), $supported_extensions) : $supported_extensions;
|
||||
$element['#upload_validators']['file_validate_extensions'][0] = implode(' ', $extensions);
|
||||
|
||||
// Add mobile device image capture acceptance.
|
||||
|
@ -224,7 +263,7 @@ class ImageWidget extends FileWidget {
|
|||
'#title' => t('Alternative text'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => isset($item['alt']) ? $item['alt'] : '',
|
||||
'#description' => t('This text will be used by screen readers, search engines, or when the image cannot be loaded.'),
|
||||
'#description' => t('Short description of the image used by screen readers and displayed when the image is not loaded. This is important for accessibility.'),
|
||||
// @see https://www.drupal.org/node/465106#alt-text
|
||||
'#maxlength' => 512,
|
||||
'#weight' => -12,
|
||||
|
@ -256,7 +295,8 @@ class ImageWidget extends FileWidget {
|
|||
public static function validateRequiredFields($element, FormStateInterface $form_state) {
|
||||
// Only do validation if the function is triggered from other places than
|
||||
// the image process form.
|
||||
if (!in_array('file_managed_file_submit', $form_state->getTriggeringElement()['#submit'])) {
|
||||
$triggering_element = $form_state->getTriggeringElement();
|
||||
if (empty($triggering_element['#submit']) || !in_array('file_managed_file_submit', $triggering_element['#submit'])) {
|
||||
// If the image is not there, we do not check for empty values.
|
||||
$parents = $element['#parents'];
|
||||
$field = array_pop($parents);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Drupal\image\Plugin\ImageEffect;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Image\ImageInterface;
|
||||
use Drupal\image\ConfigurableImageEffectBase;
|
||||
|
@ -41,7 +40,7 @@ class ConvertImageEffect extends ConfigurableImageEffectBase {
|
|||
*/
|
||||
public function getSummary() {
|
||||
$summary = [
|
||||
'#markup' => Unicode::strtoupper($this->configuration['extension']),
|
||||
'#markup' => mb_strtoupper($this->configuration['extension']),
|
||||
];
|
||||
$summary += parent::getSummary();
|
||||
|
||||
|
@ -64,7 +63,7 @@ class ConvertImageEffect extends ConfigurableImageEffectBase {
|
|||
$extensions = \Drupal::service('image.toolkit.manager')->getDefaultToolkit()->getSupportedExtensions();
|
||||
$options = array_combine(
|
||||
$extensions,
|
||||
array_map(['\Drupal\Component\Utility\Unicode', 'strtoupper'], $extensions)
|
||||
array_map('mb_strtoupper', $extensions)
|
||||
);
|
||||
$form['extension'] = [
|
||||
'#type' => 'select',
|
||||
|
|
|
@ -13,17 +13,38 @@ use Drupal\Core\Image\ImageInterface;
|
|||
* description = @Translation("Scale and crop will maintain the aspect-ratio of the original image, then crop the larger dimension. This is most useful for creating perfectly square thumbnails without stretching the image.")
|
||||
* )
|
||||
*/
|
||||
class ScaleAndCropImageEffect extends ResizeImageEffect {
|
||||
class ScaleAndCropImageEffect extends CropImageEffect {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applyEffect(ImageInterface $image) {
|
||||
if (!$image->scaleAndCrop($this->configuration['width'], $this->configuration['height'])) {
|
||||
$width = $this->configuration['width'];
|
||||
$height = $this->configuration['height'];
|
||||
$scale = max($width / $image->getWidth(), $height / $image->getHeight());
|
||||
|
||||
list($x, $y) = explode('-', $this->configuration['anchor']);
|
||||
$x = image_filter_keyword($x, $image->getWidth() * $scale, $width);
|
||||
$y = image_filter_keyword($y, $image->getHeight() * $scale, $height);
|
||||
|
||||
if (!$image->apply('scale_and_crop', ['x' => $x, 'y' => $y, 'width' => $width, 'height' => $height])) {
|
||||
$this->logger->error('Image scale and crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', ['%toolkit' => $image->getToolkitId(), '%path' => $image->getSource(), '%mimetype' => $image->getMimeType(), '%dimensions' => $image->getWidth() . 'x' . $image->getHeight()]);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSummary() {
|
||||
$summary = [
|
||||
'#theme' => 'image_scale_and_crop_summary',
|
||||
'#data' => $this->configuration,
|
||||
];
|
||||
$summary += parent::getSummary();
|
||||
|
||||
return $summary;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Plugin\migrate\cckfield\d7;
|
||||
|
||||
@trigger_error('ImageField is deprecated in Drupal 8.5.x and will be removed before Drupal 9.0.x. Use \Drupal\image\Plugin\migrate\field\d7\ImageField instead.', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
|
||||
|
||||
/**
|
||||
* @MigrateCckField(
|
||||
* id = "image",
|
||||
* core = {7},
|
||||
* source_module = "image",
|
||||
* destination_module = "file"
|
||||
* )
|
||||
*
|
||||
* @deprecated in Drupal 8.5.x, to be removed before Drupal 9.0.x. Use
|
||||
* \Drupal\image\Plugin\migrate\field\d7\ImageField instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2751897
|
||||
*/
|
||||
class ImageField extends CckFieldPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function processCckFieldValues(MigrationInterface $migration, $field_name, $data) {
|
||||
$process = [
|
||||
'plugin' => 'sub_process',
|
||||
'source' => $field_name,
|
||||
'process' => [
|
||||
'target_id' => 'fid',
|
||||
'alt' => 'alt',
|
||||
'title' => 'title',
|
||||
'width' => 'width',
|
||||
'height' => 'height',
|
||||
],
|
||||
];
|
||||
$migration->mergeProcessOfProperty($field_name, $process);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Plugin\migrate\field\d6;
|
||||
|
||||
use Drupal\file\Plugin\migrate\field\d6\FileField;
|
||||
|
||||
/**
|
||||
* @MigrateField(
|
||||
* id = "imagefield",
|
||||
* core = {6},
|
||||
* source_module = "imagefield",
|
||||
* destination_module = "image"
|
||||
* )
|
||||
*/
|
||||
class ImageField extends FileField {}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Plugin\migrate\field\d7;
|
||||
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\field\FieldPluginBase;
|
||||
|
||||
/**
|
||||
* @MigrateField(
|
||||
* id = "image",
|
||||
* core = {7},
|
||||
* source_module = "image",
|
||||
* destination_module = "image"
|
||||
* )
|
||||
*/
|
||||
class ImageField extends FieldPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defineValueProcessPipeline(MigrationInterface $migration, $field_name, $data) {
|
||||
$process = [
|
||||
'plugin' => 'sub_process',
|
||||
'source' => $field_name,
|
||||
'process' => [
|
||||
'target_id' => 'fid',
|
||||
'alt' => 'alt',
|
||||
'title' => 'title',
|
||||
'width' => 'width',
|
||||
'height' => 'height',
|
||||
],
|
||||
];
|
||||
$migration->mergeProcessOfProperty($field_name, $process);
|
||||
}
|
||||
|
||||
}
|
|
@ -10,7 +10,7 @@ use Drupal\migrate\Row;
|
|||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_imagecache_presets",
|
||||
* source_provider = "imagecache"
|
||||
* source_module = "imagecache"
|
||||
* )
|
||||
*/
|
||||
class ImageCachePreset extends DrupalSqlBase {
|
||||
|
|
|
@ -10,7 +10,7 @@ use Drupal\migrate\Row;
|
|||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_image_styles",
|
||||
* source_provider = "image"
|
||||
* source_module = "image"
|
||||
* )
|
||||
*/
|
||||
class ImageStyles extends DrupalSqlBase {
|
||||
|
|
|
@ -20,7 +20,7 @@ class ImageStyleRoutes implements ContainerInjectionInterface {
|
|||
protected $streamWrapperManager;
|
||||
|
||||
/**
|
||||
* Constructs a new PathProcessorImageStyles object.
|
||||
* Constructs a new ImageStyleRoutes object.
|
||||
*
|
||||
* @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager
|
||||
* The stream wrapper manager service.
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Tests;
|
||||
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\image\Entity\ImageStyle;
|
||||
|
||||
/**
|
||||
* Tests the file move function for images and image styles.
|
||||
*
|
||||
* @group image
|
||||
*/
|
||||
class FileMoveTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['image'];
|
||||
|
||||
/**
|
||||
* Tests moving a randomly generated image.
|
||||
*/
|
||||
public function testNormal() {
|
||||
// Pick a file for testing.
|
||||
$file = File::create((array) current($this->drupalGetTestFiles('image')));
|
||||
|
||||
// Create derivative image.
|
||||
$styles = ImageStyle::loadMultiple();
|
||||
$style = reset($styles);
|
||||
$original_uri = $file->getFileUri();
|
||||
$derivative_uri = $style->buildUri($original_uri);
|
||||
$style->createDerivative($original_uri, $derivative_uri);
|
||||
|
||||
// Check if derivative image exists.
|
||||
$this->assertTrue(file_exists($derivative_uri), 'Make sure derivative image is generated successfully.');
|
||||
|
||||
// Clone the object so we don't have to worry about the function changing
|
||||
// our reference copy.
|
||||
$desired_filepath = 'public://' . $this->randomMachineName();
|
||||
$result = file_move(clone $file, $desired_filepath, FILE_EXISTS_ERROR);
|
||||
|
||||
// Check if image has been moved.
|
||||
$this->assertTrue(file_exists($result->getFileUri()), 'Make sure image is moved successfully.');
|
||||
|
||||
// Check if derivative image has been flushed.
|
||||
$this->assertFalse(file_exists($derivative_uri), 'Make sure derivative image has been flushed.');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,526 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Tests;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
||||
use Drupal\image\Entity\ImageStyle;
|
||||
use Drupal\image\ImageStyleInterface;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\file\Entity\File;
|
||||
|
||||
/**
|
||||
* Tests creation, deletion, and editing of image styles and effects.
|
||||
*
|
||||
* @group image
|
||||
*/
|
||||
class ImageAdminStylesTest extends ImageFieldTestBase {
|
||||
|
||||
/**
|
||||
* Given an image style, generate an image.
|
||||
*/
|
||||
public function createSampleImage(ImageStyleInterface $style) {
|
||||
static $file_path;
|
||||
|
||||
// First, we need to make sure we have an image in our testing
|
||||
// file directory. Copy over an image on the first run.
|
||||
if (!isset($file_path)) {
|
||||
$files = $this->drupalGetTestFiles('image');
|
||||
$file = reset($files);
|
||||
$file_path = file_unmanaged_copy($file->uri);
|
||||
}
|
||||
|
||||
return $style->buildUrl($file_path) ? $file_path : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of images currently create for a style.
|
||||
*/
|
||||
public function getImageCount(ImageStyleInterface $style) {
|
||||
return count(file_scan_directory('public://styles/' . $style->id(), '/.*/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creating an image style with a numeric name and ensuring it can be
|
||||
* applied to an image.
|
||||
*/
|
||||
public function testNumericStyleName() {
|
||||
$style_name = rand();
|
||||
$style_label = $this->randomString();
|
||||
$edit = [
|
||||
'name' => $style_name,
|
||||
'label' => $style_label,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/media/image-styles/add', $edit, t('Create new style'));
|
||||
$this->assertRaw(t('Style %name was created.', ['%name' => $style_label]));
|
||||
$options = image_style_options();
|
||||
$this->assertTrue(array_key_exists($style_name, $options), format_string('Array key %key exists.', ['%key' => $style_name]));
|
||||
}
|
||||
|
||||
/**
|
||||
* General test to add a style, add/remove/edit effects to it, then delete it.
|
||||
*/
|
||||
public function testStyle() {
|
||||
$admin_path = 'admin/config/media/image-styles';
|
||||
|
||||
// Setup a style to be created and effects to add to it.
|
||||
$style_name = strtolower($this->randomMachineName(10));
|
||||
$style_label = $this->randomString();
|
||||
$style_path = $admin_path . '/manage/' . $style_name;
|
||||
$effect_edits = [
|
||||
'image_resize' => [
|
||||
'width' => 100,
|
||||
'height' => 101,
|
||||
],
|
||||
'image_scale' => [
|
||||
'width' => 110,
|
||||
'height' => 111,
|
||||
'upscale' => 1,
|
||||
],
|
||||
'image_scale_and_crop' => [
|
||||
'width' => 120,
|
||||
'height' => 121,
|
||||
],
|
||||
'image_crop' => [
|
||||
'width' => 130,
|
||||
'height' => 131,
|
||||
'anchor' => 'left-top',
|
||||
],
|
||||
'image_desaturate' => [
|
||||
// No options for desaturate.
|
||||
],
|
||||
'image_rotate' => [
|
||||
'degrees' => 5,
|
||||
'random' => 1,
|
||||
'bgcolor' => '#FFFF00',
|
||||
],
|
||||
];
|
||||
|
||||
// Add style form.
|
||||
|
||||
$edit = [
|
||||
'name' => $style_name,
|
||||
'label' => $style_label,
|
||||
];
|
||||
$this->drupalPostForm($admin_path . '/add', $edit, t('Create new style'));
|
||||
$this->assertRaw(t('Style %name was created.', ['%name' => $style_label]));
|
||||
|
||||
// Ensure that the expected entity operations are there.
|
||||
$this->drupalGet($admin_path);
|
||||
$this->assertLinkByHref($style_path);
|
||||
$this->assertLinkByHref($style_path . '/flush');
|
||||
$this->assertLinkByHref($style_path . '/delete');
|
||||
|
||||
// Add effect form.
|
||||
|
||||
// Add each sample effect to the style.
|
||||
foreach ($effect_edits as $effect => $edit) {
|
||||
$edit_data = [];
|
||||
foreach ($edit as $field => $value) {
|
||||
$edit_data['data[' . $field . ']'] = $value;
|
||||
}
|
||||
// Add the effect.
|
||||
$this->drupalPostForm($style_path, ['new' => $effect], t('Add'));
|
||||
if (!empty($edit)) {
|
||||
$this->drupalPostForm(NULL, $edit_data, t('Add effect'));
|
||||
}
|
||||
}
|
||||
|
||||
// Load the saved image style.
|
||||
$style = ImageStyle::load($style_name);
|
||||
|
||||
// Ensure that third party settings were added to the config entity.
|
||||
// These are added by a hook_image_style_presave() implemented in
|
||||
// image_module_test module.
|
||||
$this->assertEqual('bar', $style->getThirdPartySetting('image_module_test', 'foo'), 'Third party settings were added to the image style.');
|
||||
|
||||
// Ensure that the image style URI matches our expected path.
|
||||
$style_uri_path = $style->url();
|
||||
$this->assertTrue(strpos($style_uri_path, $style_path) !== FALSE, 'The image style URI is correct.');
|
||||
|
||||
// Confirm that all effects on the image style have settings that match
|
||||
// what was saved.
|
||||
$uuids = [];
|
||||
foreach ($style->getEffects() as $uuid => $effect) {
|
||||
// Store the uuid for later use.
|
||||
$uuids[$effect->getPluginId()] = $uuid;
|
||||
$effect_configuration = $effect->getConfiguration();
|
||||
foreach ($effect_edits[$effect->getPluginId()] as $field => $value) {
|
||||
$this->assertEqual($value, $effect_configuration['data'][$field], SafeMarkup::format('The %field field in the %effect effect has the correct value of %value.', ['%field' => $field, '%effect' => $effect->getPluginId(), '%value' => $value]));
|
||||
}
|
||||
}
|
||||
|
||||
// Assert that every effect was saved.
|
||||
foreach (array_keys($effect_edits) as $effect_name) {
|
||||
$this->assertTrue(isset($uuids[$effect_name]), format_string(
|
||||
'A %effect_name effect was saved with ID %uuid',
|
||||
[
|
||||
'%effect_name' => $effect_name,
|
||||
'%uuid' => $uuids[$effect_name],
|
||||
]));
|
||||
}
|
||||
|
||||
// Image style overview form (ordering and renaming).
|
||||
|
||||
// Confirm the order of effects is maintained according to the order we
|
||||
// added the fields.
|
||||
$effect_edits_order = array_keys($effect_edits);
|
||||
$order_correct = TRUE;
|
||||
$index = 0;
|
||||
foreach ($style->getEffects() as $effect) {
|
||||
if ($effect_edits_order[$index] != $effect->getPluginId()) {
|
||||
$order_correct = FALSE;
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
$this->assertTrue($order_correct, 'The order of the effects is correctly set by default.');
|
||||
|
||||
// Test the style overview form.
|
||||
// Change the name of the style and adjust the weights of effects.
|
||||
$style_name = strtolower($this->randomMachineName(10));
|
||||
$style_label = $this->randomMachineName();
|
||||
$weight = count($effect_edits);
|
||||
$edit = [
|
||||
'name' => $style_name,
|
||||
'label' => $style_label,
|
||||
];
|
||||
foreach ($style->getEffects() as $uuid => $effect) {
|
||||
$edit['effects[' . $uuid . '][weight]'] = $weight;
|
||||
$weight--;
|
||||
}
|
||||
|
||||
// Create an image to make sure it gets flushed after saving.
|
||||
$image_path = $this->createSampleImage($style);
|
||||
$this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', ['%style' => $style->label(), '%file' => $image_path]));
|
||||
|
||||
$this->drupalPostForm($style_path, $edit, t('Update style'));
|
||||
|
||||
// Note that after changing the style name, the style path is changed.
|
||||
$style_path = 'admin/config/media/image-styles/manage/' . $style_name;
|
||||
|
||||
// Check that the URL was updated.
|
||||
$this->drupalGet($style_path);
|
||||
$this->assertTitle(t('Edit style @name | Drupal', ['@name' => $style_label]));
|
||||
$this->assertResponse(200, format_string('Image style %original renamed to %new', ['%original' => $style->id(), '%new' => $style_name]));
|
||||
|
||||
// Check that the image was flushed after updating the style.
|
||||
// This is especially important when renaming the style. Make sure that
|
||||
// the old image directory has been deleted.
|
||||
$this->assertEqual($this->getImageCount($style), 0, format_string('Image style %style was flushed after renaming the style and updating the order of effects.', ['%style' => $style->label()]));
|
||||
|
||||
// Load the style by the new name with the new weights.
|
||||
$style = ImageStyle::load($style_name);
|
||||
|
||||
// Confirm the new style order was saved.
|
||||
$effect_edits_order = array_reverse($effect_edits_order);
|
||||
$order_correct = TRUE;
|
||||
$index = 0;
|
||||
foreach ($style->getEffects() as $effect) {
|
||||
if ($effect_edits_order[$index] != $effect->getPluginId()) {
|
||||
$order_correct = FALSE;
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
$this->assertTrue($order_correct, 'The order of the effects is correctly set by default.');
|
||||
|
||||
// Image effect deletion form.
|
||||
|
||||
// Create an image to make sure it gets flushed after deleting an effect.
|
||||
$image_path = $this->createSampleImage($style);
|
||||
$this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', ['%style' => $style->label(), '%file' => $image_path]));
|
||||
|
||||
// Delete the 'image_crop' effect from the style.
|
||||
$this->drupalPostForm($style_path . '/effects/' . $uuids['image_crop'] . '/delete', [], t('Delete'));
|
||||
// Confirm that the form submission was successful.
|
||||
$this->assertResponse(200);
|
||||
$image_crop_effect = $style->getEffect($uuids['image_crop']);
|
||||
$this->assertRaw(t('The image effect %name has been deleted.', ['%name' => $image_crop_effect->label()]));
|
||||
// Confirm that there is no longer a link to the effect.
|
||||
$this->assertNoLinkByHref($style_path . '/effects/' . $uuids['image_crop'] . '/delete');
|
||||
// Refresh the image style information and verify that the effect was
|
||||
// actually deleted.
|
||||
$entity_type_manager = $this->container->get('entity_type.manager');
|
||||
$style = $entity_type_manager->getStorage('image_style')->loadUnchanged($style->id());
|
||||
$this->assertFalse($style->getEffects()->has($uuids['image_crop']), format_string(
|
||||
'Effect with ID %uuid no longer found on image style %style',
|
||||
[
|
||||
'%uuid' => $uuids['image_crop'],
|
||||
'%style' => $style->label(),
|
||||
]));
|
||||
|
||||
// Additional test on Rotate effect, for transparent background.
|
||||
$edit = [
|
||||
'data[degrees]' => 5,
|
||||
'data[random]' => 0,
|
||||
'data[bgcolor]' => '',
|
||||
];
|
||||
$this->drupalPostForm($style_path, ['new' => 'image_rotate'], t('Add'));
|
||||
$this->drupalPostForm(NULL, $edit, t('Add effect'));
|
||||
$entity_type_manager = $this->container->get('entity_type.manager');
|
||||
$style = $entity_type_manager->getStorage('image_style')->loadUnchanged($style_name);
|
||||
$this->assertEqual(count($style->getEffects()), 6, 'Rotate effect with transparent background was added.');
|
||||
|
||||
// Style deletion form.
|
||||
|
||||
// Delete the style.
|
||||
$this->drupalPostForm($style_path . '/delete', [], t('Delete'));
|
||||
|
||||
// Confirm the style directory has been removed.
|
||||
$directory = file_default_scheme() . '://styles/' . $style_name;
|
||||
$this->assertFalse(is_dir($directory), format_string('Image style %style directory removed on style deletion.', ['%style' => $style->label()]));
|
||||
|
||||
$this->assertFalse(ImageStyle::load($style_name), format_string('Image style %style successfully deleted.', ['%style' => $style->label()]));
|
||||
|
||||
// Test empty text when there are no image styles.
|
||||
|
||||
// Delete all image styles.
|
||||
foreach (ImageStyle::loadMultiple() as $image_style) {
|
||||
$image_style->delete();
|
||||
}
|
||||
|
||||
// Confirm that the empty text is correct on the image styles page.
|
||||
$this->drupalGet($admin_path);
|
||||
$this->assertRaw(t('There are currently no styles. <a href=":url">Add a new one</a>.', [
|
||||
':url' => \Drupal::url('image.style_add'),
|
||||
]));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests editing Ajax-enabled image effect forms.
|
||||
*/
|
||||
public function testAjaxEnabledEffectForm() {
|
||||
$admin_path = 'admin/config/media/image-styles';
|
||||
|
||||
// Setup a style to be created and effects to add to it.
|
||||
$style_name = strtolower($this->randomMachineName(10));
|
||||
$style_label = $this->randomString();
|
||||
$style_path = $admin_path . '/manage/' . $style_name;
|
||||
$effect_edit = [
|
||||
'data[test_parameter]' => 100,
|
||||
];
|
||||
|
||||
// Add style form.
|
||||
$edit = [
|
||||
'name' => $style_name,
|
||||
'label' => $style_label,
|
||||
];
|
||||
$this->drupalPostForm($admin_path . '/add', $edit, t('Create new style'));
|
||||
$this->assertRaw(t('Style %name was created.', ['%name' => $style_label]));
|
||||
|
||||
// Add two Ajax-enabled test effects.
|
||||
$this->drupalPostForm($style_path, ['new' => 'image_module_test_ajax'], t('Add'));
|
||||
$this->drupalPostForm(NULL, $effect_edit, t('Add effect'));
|
||||
$this->drupalPostForm($style_path, ['new' => 'image_module_test_ajax'], t('Add'));
|
||||
$this->drupalPostForm(NULL, $effect_edit, t('Add effect'));
|
||||
|
||||
// Load the saved image style.
|
||||
$style = ImageStyle::load($style_name);
|
||||
|
||||
// Edit back the effects.
|
||||
foreach ($style->getEffects() as $uuid => $effect) {
|
||||
$effect_path = $admin_path . '/manage/' . $style_name . '/effects/' . $uuid;
|
||||
$this->drupalGet($effect_path);
|
||||
$this->drupalPostAjaxForm(NULL, $effect_edit, ['op' => t('Ajax refresh')]);
|
||||
$this->drupalPostForm(NULL, $effect_edit, t('Update effect'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test deleting a style and choosing a replacement style.
|
||||
*/
|
||||
public function testStyleReplacement() {
|
||||
// Create a new style.
|
||||
$style_name = strtolower($this->randomMachineName(10));
|
||||
$style_label = $this->randomString();
|
||||
$style = ImageStyle::create(['name' => $style_name, 'label' => $style_label]);
|
||||
$style->save();
|
||||
$style_path = 'admin/config/media/image-styles/manage/';
|
||||
|
||||
// Create an image field that uses the new style.
|
||||
$field_name = strtolower($this->randomMachineName(10));
|
||||
$this->createImageField($field_name, 'article');
|
||||
entity_get_display('node', 'article', 'default')
|
||||
->setComponent($field_name, [
|
||||
'type' => 'image',
|
||||
'settings' => ['image_style' => $style_name],
|
||||
])
|
||||
->save();
|
||||
|
||||
// Create a new node with an image attached.
|
||||
$test_image = current($this->drupalGetTestFiles('image'));
|
||||
$nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName());
|
||||
$node = Node::load($nid);
|
||||
|
||||
// Get node field original image URI.
|
||||
$fid = $node->get($field_name)->target_id;
|
||||
$original_uri = File::load($fid)->getFileUri();
|
||||
|
||||
// Test that image is displayed using newly created style.
|
||||
$this->drupalGet('node/' . $nid);
|
||||
$this->assertRaw(file_url_transform_relative($style->buildUrl($original_uri)), format_string('Image displayed using style @style.', ['@style' => $style_name]));
|
||||
|
||||
// Rename the style and make sure the image field is updated.
|
||||
$new_style_name = strtolower($this->randomMachineName(10));
|
||||
$new_style_label = $this->randomString();
|
||||
$edit = [
|
||||
'name' => $new_style_name,
|
||||
'label' => $new_style_label,
|
||||
];
|
||||
$this->drupalPostForm($style_path . $style_name, $edit, t('Update style'));
|
||||
$this->assertText(t('Changes to the style have been saved.'), format_string('Style %name was renamed to %new_name.', ['%name' => $style_name, '%new_name' => $new_style_name]));
|
||||
$this->drupalGet('node/' . $nid);
|
||||
|
||||
// Reload the image style using the new name.
|
||||
$style = ImageStyle::load($new_style_name);
|
||||
$this->assertRaw(file_url_transform_relative($style->buildUrl($original_uri)), 'Image displayed using style replacement style.');
|
||||
|
||||
// Delete the style and choose a replacement style.
|
||||
$edit = [
|
||||
'replacement' => 'thumbnail',
|
||||
];
|
||||
$this->drupalPostForm($style_path . $new_style_name . '/delete', $edit, t('Delete'));
|
||||
$message = t('The image style %name has been deleted.', ['%name' => $new_style_label]);
|
||||
$this->assertRaw($message);
|
||||
|
||||
$replacement_style = ImageStyle::load('thumbnail');
|
||||
$this->drupalGet('node/' . $nid);
|
||||
$this->assertRaw(file_url_transform_relative($replacement_style->buildUrl($original_uri)), 'Image displayed using style replacement style.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that editing an image effect does not cause it to be duplicated.
|
||||
*/
|
||||
public function testEditEffect() {
|
||||
// Add a scale effect.
|
||||
$style_name = 'test_style_effect_edit';
|
||||
$this->drupalGet('admin/config/media/image-styles/add');
|
||||
$this->drupalPostForm(NULL, ['label' => 'Test style effect edit', 'name' => $style_name], t('Create new style'));
|
||||
$this->drupalPostForm(NULL, ['new' => 'image_scale_and_crop'], t('Add'));
|
||||
$this->drupalPostForm(NULL, ['data[width]' => '300', 'data[height]' => '200'], t('Add effect'));
|
||||
$this->assertText(t('Scale and crop 300×200'));
|
||||
|
||||
// There should normally be only one edit link on this page initially.
|
||||
$this->clickLink(t('Edit'));
|
||||
$this->drupalPostForm(NULL, ['data[width]' => '360', 'data[height]' => '240'], t('Update effect'));
|
||||
$this->assertText(t('Scale and crop 360×240'));
|
||||
|
||||
// Check that the previous effect is replaced.
|
||||
$this->assertNoText(t('Scale and crop 300×200'));
|
||||
|
||||
// Add another scale effect.
|
||||
$this->drupalGet('admin/config/media/image-styles/add');
|
||||
$this->drupalPostForm(NULL, ['label' => 'Test style scale edit scale', 'name' => 'test_style_scale_edit_scale'], t('Create new style'));
|
||||
$this->drupalPostForm(NULL, ['new' => 'image_scale'], t('Add'));
|
||||
$this->drupalPostForm(NULL, ['data[width]' => '12', 'data[height]' => '19'], t('Add effect'));
|
||||
|
||||
// Edit the scale effect that was just added.
|
||||
$this->clickLink(t('Edit'));
|
||||
$this->drupalPostForm(NULL, ['data[width]' => '24', 'data[height]' => '19'], t('Update effect'));
|
||||
$this->drupalPostForm(NULL, ['new' => 'image_scale'], t('Add'));
|
||||
|
||||
// Add another scale effect and make sure both exist.
|
||||
$this->drupalPostForm(NULL, ['data[width]' => '12', 'data[height]' => '19'], t('Add effect'));
|
||||
$this->assertText(t('Scale 24×19'));
|
||||
$this->assertText(t('Scale 12×19'));
|
||||
|
||||
// Try to edit a nonexistent effect.
|
||||
$uuid = $this->container->get('uuid');
|
||||
$this->drupalGet('admin/config/media/image-styles/manage/' . $style_name . '/effects/' . $uuid->generate());
|
||||
$this->assertResponse(404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test flush user interface.
|
||||
*/
|
||||
public function testFlushUserInterface() {
|
||||
$admin_path = 'admin/config/media/image-styles';
|
||||
|
||||
// Create a new style.
|
||||
$style_name = strtolower($this->randomMachineName(10));
|
||||
$style = ImageStyle::create(['name' => $style_name, 'label' => $this->randomString()]);
|
||||
$style->save();
|
||||
|
||||
// Create an image to make sure it gets flushed.
|
||||
$files = $this->drupalGetTestFiles('image');
|
||||
$image_uri = $files[0]->uri;
|
||||
$derivative_uri = $style->buildUri($image_uri);
|
||||
$this->assertTrue($style->createDerivative($image_uri, $derivative_uri));
|
||||
$this->assertEqual($this->getImageCount($style), 1);
|
||||
|
||||
// Go to image styles list page and check if the flush operation link
|
||||
// exists.
|
||||
$this->drupalGet($admin_path);
|
||||
$flush_path = $admin_path . '/manage/' . $style_name . '/flush';
|
||||
$this->assertLinkByHref($flush_path);
|
||||
|
||||
// Flush the image style derivatives using the user interface.
|
||||
$this->drupalPostForm($flush_path, [], t('Flush'));
|
||||
|
||||
// The derivative image file should have been deleted.
|
||||
$this->assertEqual($this->getImageCount($style), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests image style configuration import that does a delete.
|
||||
*/
|
||||
public function testConfigImport() {
|
||||
// Create a new style.
|
||||
$style_name = strtolower($this->randomMachineName(10));
|
||||
$style_label = $this->randomString();
|
||||
$style = ImageStyle::create(['name' => $style_name, 'label' => $style_label]);
|
||||
$style->save();
|
||||
|
||||
// Create an image field that uses the new style.
|
||||
$field_name = strtolower($this->randomMachineName(10));
|
||||
$this->createImageField($field_name, 'article');
|
||||
entity_get_display('node', 'article', 'default')
|
||||
->setComponent($field_name, [
|
||||
'type' => 'image',
|
||||
'settings' => ['image_style' => $style_name],
|
||||
])
|
||||
->save();
|
||||
|
||||
// Create a new node with an image attached.
|
||||
$test_image = current($this->drupalGetTestFiles('image'));
|
||||
$nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName());
|
||||
$node = Node::load($nid);
|
||||
|
||||
// Get node field original image URI.
|
||||
$fid = $node->get($field_name)->target_id;
|
||||
$original_uri = File::load($fid)->getFileUri();
|
||||
|
||||
// Test that image is displayed using newly created style.
|
||||
$this->drupalGet('node/' . $nid);
|
||||
$this->assertRaw(file_url_transform_relative($style->buildUrl($original_uri)), format_string('Image displayed using style @style.', ['@style' => $style_name]));
|
||||
|
||||
// Copy config to sync, and delete the image style.
|
||||
$sync = $this->container->get('config.storage.sync');
|
||||
$active = $this->container->get('config.storage');
|
||||
// Remove the image field from the display, to avoid a dependency error
|
||||
// during import.
|
||||
EntityViewDisplay::load('node.article.default')
|
||||
->removeComponent($field_name)
|
||||
->save();
|
||||
$this->copyConfig($active, $sync);
|
||||
$sync->delete('image.style.' . $style_name);
|
||||
$this->configImporter()->import();
|
||||
|
||||
$this->assertFalse(ImageStyle::load($style_name), 'Style deleted after config import.');
|
||||
$this->assertEqual($this->getImageCount($style), 0, 'Image style was flushed after being deleted by config import.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests access for the image style listing.
|
||||
*/
|
||||
public function testImageStyleAccess() {
|
||||
$style = ImageStyle::create(['name' => 'style_foo', 'label' => $this->randomString()]);
|
||||
$style->save();
|
||||
|
||||
$this->drupalGet('admin/config/media/image-styles');
|
||||
$this->clickLink(t('Edit'));
|
||||
$this->assertRaw(t('Select a new effect'));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,290 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Tests;
|
||||
|
||||
use Drupal\image\Entity\ImageStyle;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests that images have correct dimensions when styled.
|
||||
*
|
||||
* @group image
|
||||
*/
|
||||
class ImageDimensionsTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['image', 'image_module_test'];
|
||||
|
||||
protected $profile = 'testing';
|
||||
|
||||
/**
|
||||
* Test styled image dimensions cumulatively.
|
||||
*/
|
||||
public function testImageDimensions() {
|
||||
$image_factory = $this->container->get('image.factory');
|
||||
// Create a working copy of the file.
|
||||
$files = $this->drupalGetTestFiles('image');
|
||||
$file = reset($files);
|
||||
$original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME);
|
||||
|
||||
// Create a style.
|
||||
/** @var $style \Drupal\image\ImageStyleInterface */
|
||||
$style = ImageStyle::create(['name' => 'test', 'label' => 'Test']);
|
||||
$style->save();
|
||||
$generated_uri = 'public://styles/test/public/' . \Drupal::service('file_system')->basename($original_uri);
|
||||
$url = file_url_transform_relative($style->buildUrl($original_uri));
|
||||
|
||||
$variables = [
|
||||
'#theme' => 'image_style',
|
||||
'#style_name' => 'test',
|
||||
'#uri' => $original_uri,
|
||||
'#width' => 40,
|
||||
'#height' => 20,
|
||||
];
|
||||
// Verify that the original image matches the hard-coded values.
|
||||
$image_file = $image_factory->get($original_uri);
|
||||
$this->assertEqual($image_file->getWidth(), $variables['#width']);
|
||||
$this->assertEqual($image_file->getHeight(), $variables['#height']);
|
||||
|
||||
// Scale an image that is wider than it is high.
|
||||
$effect = [
|
||||
'id' => 'image_scale',
|
||||
'data' => [
|
||||
'width' => 120,
|
||||
'height' => 90,
|
||||
'upscale' => TRUE,
|
||||
],
|
||||
'weight' => 0,
|
||||
];
|
||||
|
||||
$style->addImageEffect($effect);
|
||||
$style->save();
|
||||
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="120" height="60" alt="" class="image-style-test" />');
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$this->drupalGet($this->getAbsoluteUrl($url));
|
||||
$this->assertResponse(200, 'Image was generated at the URL.');
|
||||
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
|
||||
$image_file = $image_factory->get($generated_uri);
|
||||
$this->assertEqual($image_file->getWidth(), 120);
|
||||
$this->assertEqual($image_file->getHeight(), 60);
|
||||
|
||||
// Rotate 90 degrees anticlockwise.
|
||||
$effect = [
|
||||
'id' => 'image_rotate',
|
||||
'data' => [
|
||||
'degrees' => -90,
|
||||
'random' => FALSE,
|
||||
],
|
||||
'weight' => 1,
|
||||
];
|
||||
|
||||
$style->addImageEffect($effect);
|
||||
$style->save();
|
||||
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="60" height="120" alt="" class="image-style-test" />');
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$this->drupalGet($this->getAbsoluteUrl($url));
|
||||
$this->assertResponse(200, 'Image was generated at the URL.');
|
||||
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
|
||||
$image_file = $image_factory->get($generated_uri);
|
||||
$this->assertEqual($image_file->getWidth(), 60);
|
||||
$this->assertEqual($image_file->getHeight(), 120);
|
||||
|
||||
// Scale an image that is higher than it is wide (rotated by previous effect).
|
||||
$effect = [
|
||||
'id' => 'image_scale',
|
||||
'data' => [
|
||||
'width' => 120,
|
||||
'height' => 90,
|
||||
'upscale' => TRUE,
|
||||
],
|
||||
'weight' => 2,
|
||||
];
|
||||
|
||||
$style->addImageEffect($effect);
|
||||
$style->save();
|
||||
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="45" height="90" alt="" class="image-style-test" />');
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$this->drupalGet($this->getAbsoluteUrl($url));
|
||||
$this->assertResponse(200, 'Image was generated at the URL.');
|
||||
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
|
||||
$image_file = $image_factory->get($generated_uri);
|
||||
$this->assertEqual($image_file->getWidth(), 45);
|
||||
$this->assertEqual($image_file->getHeight(), 90);
|
||||
|
||||
// Test upscale disabled.
|
||||
$effect = [
|
||||
'id' => 'image_scale',
|
||||
'data' => [
|
||||
'width' => 400,
|
||||
'height' => 200,
|
||||
'upscale' => FALSE,
|
||||
],
|
||||
'weight' => 3,
|
||||
];
|
||||
|
||||
$style->addImageEffect($effect);
|
||||
$style->save();
|
||||
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="45" height="90" alt="" class="image-style-test" />');
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$this->drupalGet($this->getAbsoluteUrl($url));
|
||||
$this->assertResponse(200, 'Image was generated at the URL.');
|
||||
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
|
||||
$image_file = $image_factory->get($generated_uri);
|
||||
$this->assertEqual($image_file->getWidth(), 45);
|
||||
$this->assertEqual($image_file->getHeight(), 90);
|
||||
|
||||
// Add a desaturate effect.
|
||||
$effect = [
|
||||
'id' => 'image_desaturate',
|
||||
'data' => [],
|
||||
'weight' => 4,
|
||||
];
|
||||
|
||||
$style->addImageEffect($effect);
|
||||
$style->save();
|
||||
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="45" height="90" alt="" class="image-style-test" />');
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$this->drupalGet($this->getAbsoluteUrl($url));
|
||||
$this->assertResponse(200, 'Image was generated at the URL.');
|
||||
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
|
||||
$image_file = $image_factory->get($generated_uri);
|
||||
$this->assertEqual($image_file->getWidth(), 45);
|
||||
$this->assertEqual($image_file->getHeight(), 90);
|
||||
|
||||
// Add a random rotate effect.
|
||||
$effect = [
|
||||
'id' => 'image_rotate',
|
||||
'data' => [
|
||||
'degrees' => 180,
|
||||
'random' => TRUE,
|
||||
],
|
||||
'weight' => 5,
|
||||
];
|
||||
|
||||
$style->addImageEffect($effect);
|
||||
$style->save();
|
||||
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" alt="" class="image-style-test" />');
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$this->drupalGet($this->getAbsoluteUrl($url));
|
||||
$this->assertResponse(200, 'Image was generated at the URL.');
|
||||
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
|
||||
|
||||
|
||||
// Add a crop effect.
|
||||
$effect = [
|
||||
'id' => 'image_crop',
|
||||
'data' => [
|
||||
'width' => 30,
|
||||
'height' => 30,
|
||||
'anchor' => 'center-center',
|
||||
],
|
||||
'weight' => 6,
|
||||
];
|
||||
|
||||
$style->addImageEffect($effect);
|
||||
$style->save();
|
||||
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="30" height="30" alt="" class="image-style-test" />');
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$this->drupalGet($this->getAbsoluteUrl($url));
|
||||
$this->assertResponse(200, 'Image was generated at the URL.');
|
||||
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
|
||||
$image_file = $image_factory->get($generated_uri);
|
||||
$this->assertEqual($image_file->getWidth(), 30);
|
||||
$this->assertEqual($image_file->getHeight(), 30);
|
||||
|
||||
// Rotate to a non-multiple of 90 degrees.
|
||||
$effect = [
|
||||
'id' => 'image_rotate',
|
||||
'data' => [
|
||||
'degrees' => 57,
|
||||
'random' => FALSE,
|
||||
],
|
||||
'weight' => 7,
|
||||
];
|
||||
|
||||
$effect_id = $style->addImageEffect($effect);
|
||||
$style->save();
|
||||
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="41" height="41" alt="" class="image-style-test" />');
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$this->drupalGet($this->getAbsoluteUrl($url));
|
||||
$this->assertResponse(200, 'Image was generated at the URL.');
|
||||
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
|
||||
$image_file = $image_factory->get($generated_uri);
|
||||
$this->assertEqual($image_file->getWidth(), 41);
|
||||
$this->assertEqual($image_file->getHeight(), 41);
|
||||
|
||||
$effect_plugin = $style->getEffect($effect_id);
|
||||
$style->deleteImageEffect($effect_plugin);
|
||||
|
||||
// Ensure that an effect can unset dimensions.
|
||||
$effect = [
|
||||
'id' => 'image_module_test_null',
|
||||
'data' => [],
|
||||
'weight' => 8,
|
||||
];
|
||||
|
||||
$style->addImageEffect($effect);
|
||||
$style->save();
|
||||
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" alt="" class="image-style-test" />');
|
||||
|
||||
// Test URI dependent image effect.
|
||||
$style = ImageStyle::create(['name' => 'test_uri', 'label' => 'Test URI']);
|
||||
$effect = [
|
||||
'id' => 'image_module_test_uri_dependent',
|
||||
'data' => [],
|
||||
'weight' => 0,
|
||||
];
|
||||
$style->addImageEffect($effect);
|
||||
$style->save();
|
||||
$variables = [
|
||||
'#theme' => 'image_style',
|
||||
'#style_name' => 'test_uri',
|
||||
'#uri' => $original_uri,
|
||||
'#width' => 40,
|
||||
'#height' => 20,
|
||||
];
|
||||
// PNG original image. Should be resized to 100x100.
|
||||
$generated_uri = 'public://styles/test_uri/public/' . \Drupal::service('file_system')->basename($original_uri);
|
||||
$url = file_url_transform_relative($style->buildUrl($original_uri));
|
||||
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="100" height="100" alt="" class="image-style-test-uri" />');
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$this->drupalGet($this->getAbsoluteUrl($url));
|
||||
$this->assertResponse(200, 'Image was generated at the URL.');
|
||||
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
|
||||
$image_file = $image_factory->get($generated_uri);
|
||||
$this->assertEqual($image_file->getWidth(), 100);
|
||||
$this->assertEqual($image_file->getHeight(), 100);
|
||||
// GIF original image. Should be resized to 50x50.
|
||||
$file = $files[1];
|
||||
$original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME);
|
||||
$generated_uri = 'public://styles/test_uri/public/' . \Drupal::service('file_system')->basename($original_uri);
|
||||
$url = file_url_transform_relative($style->buildUrl($original_uri));
|
||||
$variables['#uri'] = $original_uri;
|
||||
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="50" height="50" alt="" class="image-style-test-uri" />');
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$this->drupalGet($this->getAbsoluteUrl($url));
|
||||
$this->assertResponse(200, 'Image was generated at the URL.');
|
||||
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
|
||||
$image_file = $image_factory->get($generated_uri);
|
||||
$this->assertEqual($image_file->getWidth(), 50);
|
||||
$this->assertEqual($image_file->getHeight(), 50);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an image style element.
|
||||
*
|
||||
* drupal_render() alters the passed $variables array by adding a new key
|
||||
* '#printed' => TRUE. This prevents next call to re-render the element. We
|
||||
* wrap drupal_render() in a helper protected method and pass each time a
|
||||
* fresh array so that $variables won't get altered and the element is
|
||||
* re-rendered each time.
|
||||
*/
|
||||
protected function getImageTag($variables) {
|
||||
return str_replace("\n", NULL, \Drupal::service('renderer')->renderRoot($variables));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,350 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Tests;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests setting up default images both to the field and field field.
|
||||
*
|
||||
* @group image
|
||||
*/
|
||||
class ImageFieldDefaultImagesTest extends ImageFieldTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['field_ui'];
|
||||
|
||||
/**
|
||||
* Tests CRUD for fields and fields fields with default images.
|
||||
*/
|
||||
public function testDefaultImages() {
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
// Create files to use as the default images.
|
||||
$files = $this->drupalGetTestFiles('image');
|
||||
// Create 10 files so the default image fids are not a single value.
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
$filename = $this->randomMachineName() . "$i";
|
||||
$desired_filepath = 'public://' . $filename;
|
||||
file_unmanaged_copy($files[0]->uri, $desired_filepath, FILE_EXISTS_ERROR);
|
||||
$file = File::create(['uri' => $desired_filepath, 'filename' => $filename, 'name' => $filename]);
|
||||
$file->save();
|
||||
}
|
||||
$default_images = [];
|
||||
foreach (['field', 'field', 'field2', 'field_new', 'field_new'] as $image_target) {
|
||||
$file = File::create((array) array_pop($files));
|
||||
$file->save();
|
||||
$default_images[$image_target] = $file;
|
||||
}
|
||||
|
||||
// Create an image field and add an field to the article content type.
|
||||
$field_name = strtolower($this->randomMachineName());
|
||||
$storage_settings['default_image'] = [
|
||||
'uuid' => $default_images['field']->uuid(),
|
||||
'alt' => '',
|
||||
'title' => '',
|
||||
'width' => 0,
|
||||
'height' => 0,
|
||||
];
|
||||
$field_settings['default_image'] = [
|
||||
'uuid' => $default_images['field']->uuid(),
|
||||
'alt' => '',
|
||||
'title' => '',
|
||||
'width' => 0,
|
||||
'height' => 0,
|
||||
];
|
||||
$widget_settings = [
|
||||
'preview_image_style' => 'medium',
|
||||
];
|
||||
$field = $this->createImageField($field_name, 'article', $storage_settings, $field_settings, $widget_settings);
|
||||
|
||||
// The field default image id should be 2.
|
||||
$this->assertEqual($field->getSetting('default_image')['uuid'], $default_images['field']->uuid());
|
||||
|
||||
// Also test \Drupal\field\Entity\FieldConfig::getSettings().
|
||||
$this->assertEqual($field->getSettings()['default_image']['uuid'], $default_images['field']->uuid());
|
||||
|
||||
$field_storage = $field->getFieldStorageDefinition();
|
||||
|
||||
// The field default image id should be 1.
|
||||
$this->assertEqual($field_storage->getSetting('default_image')['uuid'], $default_images['field']->uuid());
|
||||
|
||||
// Also test \Drupal\field\Entity\FieldStorageConfig::getSettings().
|
||||
$this->assertEqual($field_storage->getSettings()['default_image']['uuid'], $default_images['field']->uuid());
|
||||
|
||||
// Add another field with another default image to the page content type.
|
||||
$field2 = FieldConfig::create([
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => 'page',
|
||||
'label' => $field->label(),
|
||||
'required' => $field->isRequired(),
|
||||
'settings' => [
|
||||
'default_image' => [
|
||||
'uuid' => $default_images['field2']->uuid(),
|
||||
'alt' => '',
|
||||
'title' => '',
|
||||
'width' => 0,
|
||||
'height' => 0,
|
||||
],
|
||||
],
|
||||
]);
|
||||
$field2->save();
|
||||
|
||||
$widget_settings = entity_get_form_display('node', $field->getTargetBundle(), 'default')->getComponent($field_name);
|
||||
entity_get_form_display('node', 'page', 'default')
|
||||
->setComponent($field_name, $widget_settings)
|
||||
->save();
|
||||
entity_get_display('node', 'page', 'default')
|
||||
->setComponent($field_name)
|
||||
->save();
|
||||
|
||||
// Confirm the defaults are present on the article field settings form.
|
||||
$field_id = $field->id();
|
||||
$this->drupalGet("admin/structure/types/manage/article/fields/$field_id/storage");
|
||||
$this->assertFieldByXpath(
|
||||
'//input[@name="settings[default_image][uuid][fids]"]',
|
||||
$default_images['field']->id(),
|
||||
format_string(
|
||||
'Article image field default equals expected file ID of @fid.',
|
||||
['@fid' => $default_images['field']->id()]
|
||||
)
|
||||
);
|
||||
// Confirm the defaults are present on the article field edit form.
|
||||
$this->drupalGet("admin/structure/types/manage/article/fields/$field_id");
|
||||
$this->assertFieldByXpath(
|
||||
'//input[@name="settings[default_image][uuid][fids]"]',
|
||||
$default_images['field']->id(),
|
||||
format_string(
|
||||
'Article image field field default equals expected file ID of @fid.',
|
||||
['@fid' => $default_images['field']->id()]
|
||||
)
|
||||
);
|
||||
|
||||
// Confirm the defaults are present on the page field settings form.
|
||||
$this->drupalGet("admin/structure/types/manage/page/fields/$field_id/storage");
|
||||
$this->assertFieldByXpath(
|
||||
'//input[@name="settings[default_image][uuid][fids]"]',
|
||||
$default_images['field']->id(),
|
||||
format_string(
|
||||
'Page image field default equals expected file ID of @fid.',
|
||||
['@fid' => $default_images['field']->id()]
|
||||
)
|
||||
);
|
||||
// Confirm the defaults are present on the page field edit form.
|
||||
$field2_id = $field2->id();
|
||||
$this->drupalGet("admin/structure/types/manage/page/fields/$field2_id");
|
||||
$this->assertFieldByXpath(
|
||||
'//input[@name="settings[default_image][uuid][fids]"]',
|
||||
$default_images['field2']->id(),
|
||||
format_string(
|
||||
'Page image field field default equals expected file ID of @fid.',
|
||||
['@fid' => $default_images['field2']->id()]
|
||||
)
|
||||
);
|
||||
|
||||
// Confirm that the image default is shown for a new article node.
|
||||
$article = $this->drupalCreateNode(['type' => 'article']);
|
||||
$article_built = $this->drupalBuildEntityView($article);
|
||||
$this->assertEqual(
|
||||
$article_built[$field_name][0]['#item']->target_id,
|
||||
$default_images['field']->id(),
|
||||
format_string(
|
||||
'A new article node without an image has the expected default image file ID of @fid.',
|
||||
['@fid' => $default_images['field']->id()]
|
||||
)
|
||||
);
|
||||
|
||||
// Also check that the field renders without warnings when the label is
|
||||
// hidden.
|
||||
EntityViewDisplay::load('node.article.default')
|
||||
->setComponent($field_name, ['label' => 'hidden', 'type' => 'image'])
|
||||
->save();
|
||||
$this->drupalGet('node/' . $article->id());
|
||||
|
||||
// Confirm that the image default is shown for a new page node.
|
||||
$page = $this->drupalCreateNode(['type' => 'page']);
|
||||
$page_built = $this->drupalBuildEntityView($page);
|
||||
$this->assertEqual(
|
||||
$page_built[$field_name][0]['#item']->target_id,
|
||||
$default_images['field2']->id(),
|
||||
format_string(
|
||||
'A new page node without an image has the expected default image file ID of @fid.',
|
||||
['@fid' => $default_images['field2']->id()]
|
||||
)
|
||||
);
|
||||
|
||||
// Upload a new default for the field storage.
|
||||
$default_image_settings = $field_storage->getSetting('default_image');
|
||||
$default_image_settings['uuid'] = $default_images['field_new']->uuid();
|
||||
$field_storage->setSetting('default_image', $default_image_settings);
|
||||
$field_storage->save();
|
||||
|
||||
// Confirm that the new default is used on the article field settings form.
|
||||
$this->drupalGet("admin/structure/types/manage/article/fields/$field_id/storage");
|
||||
$this->assertFieldByXpath(
|
||||
'//input[@name="settings[default_image][uuid][fids]"]',
|
||||
$default_images['field_new']->id(),
|
||||
format_string(
|
||||
'Updated image field default equals expected file ID of @fid.',
|
||||
['@fid' => $default_images['field_new']->id()]
|
||||
)
|
||||
);
|
||||
|
||||
// Reload the nodes and confirm the field field defaults are used.
|
||||
$node_storage->resetCache([$article->id(), $page->id()]);
|
||||
$article_built = $this->drupalBuildEntityView($article = $node_storage->load($article->id()));
|
||||
$page_built = $this->drupalBuildEntityView($page = $node_storage->load($page->id()));
|
||||
$this->assertEqual(
|
||||
$article_built[$field_name][0]['#item']->target_id,
|
||||
$default_images['field']->id(),
|
||||
format_string(
|
||||
'An existing article node without an image has the expected default image file ID of @fid.',
|
||||
['@fid' => $default_images['field']->id()]
|
||||
)
|
||||
);
|
||||
$this->assertEqual(
|
||||
$page_built[$field_name][0]['#item']->target_id,
|
||||
$default_images['field2']->id(),
|
||||
format_string(
|
||||
'An existing page node without an image has the expected default image file ID of @fid.',
|
||||
['@fid' => $default_images['field2']->id()]
|
||||
)
|
||||
);
|
||||
|
||||
// Upload a new default for the article's field field.
|
||||
$default_image_settings = $field->getSetting('default_image');
|
||||
$default_image_settings['uuid'] = $default_images['field_new']->uuid();
|
||||
$field->setSetting('default_image', $default_image_settings);
|
||||
$field->save();
|
||||
|
||||
// Confirm the new field field default is used on the article field
|
||||
// admin form.
|
||||
$this->drupalGet("admin/structure/types/manage/article/fields/$field_id");
|
||||
$this->assertFieldByXpath(
|
||||
'//input[@name="settings[default_image][uuid][fids]"]',
|
||||
$default_images['field_new']->id(),
|
||||
format_string(
|
||||
'Updated article image field field default equals expected file ID of @fid.',
|
||||
['@fid' => $default_images['field_new']->id()]
|
||||
)
|
||||
);
|
||||
|
||||
// Reload the nodes.
|
||||
$node_storage->resetCache([$article->id(), $page->id()]);
|
||||
$article_built = $this->drupalBuildEntityView($article = $node_storage->load($article->id()));
|
||||
$page_built = $this->drupalBuildEntityView($page = $node_storage->load($page->id()));
|
||||
|
||||
// Confirm the article uses the new default.
|
||||
$this->assertEqual(
|
||||
$article_built[$field_name][0]['#item']->target_id,
|
||||
$default_images['field_new']->id(),
|
||||
format_string(
|
||||
'An existing article node without an image has the expected default image file ID of @fid.',
|
||||
['@fid' => $default_images['field_new']->id()]
|
||||
)
|
||||
);
|
||||
// Confirm the page remains unchanged.
|
||||
$this->assertEqual(
|
||||
$page_built[$field_name][0]['#item']->target_id,
|
||||
$default_images['field2']->id(),
|
||||
format_string(
|
||||
'An existing page node without an image has the expected default image file ID of @fid.',
|
||||
['@fid' => $default_images['field2']->id()]
|
||||
)
|
||||
);
|
||||
|
||||
// Confirm the default image is shown on the node form.
|
||||
$file = File::load($default_images['field_new']->id());
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->assertRaw($file->getFilename());
|
||||
|
||||
// Remove the instance default from articles.
|
||||
$default_image_settings = $field->getSetting('default_image');
|
||||
$default_image_settings['uuid'] = 0;
|
||||
$field->setSetting('default_image', $default_image_settings);
|
||||
$field->save();
|
||||
|
||||
// Confirm the article field field default has been removed.
|
||||
$this->drupalGet("admin/structure/types/manage/article/fields/$field_id");
|
||||
$this->assertFieldByXpath(
|
||||
'//input[@name="settings[default_image][uuid][fids]"]',
|
||||
'',
|
||||
'Updated article image field field default has been successfully removed.'
|
||||
);
|
||||
|
||||
// Reload the nodes.
|
||||
$node_storage->resetCache([$article->id(), $page->id()]);
|
||||
$article_built = $this->drupalBuildEntityView($article = $node_storage->load($article->id()));
|
||||
$page_built = $this->drupalBuildEntityView($page = $node_storage->load($page->id()));
|
||||
// Confirm the article uses the new field (not field) default.
|
||||
$this->assertEqual(
|
||||
$article_built[$field_name][0]['#item']->target_id,
|
||||
$default_images['field_new']->id(),
|
||||
format_string(
|
||||
'An existing article node without an image has the expected default image file ID of @fid.',
|
||||
['@fid' => $default_images['field_new']->id()]
|
||||
)
|
||||
);
|
||||
// Confirm the page remains unchanged.
|
||||
$this->assertEqual(
|
||||
$page_built[$field_name][0]['#item']->target_id,
|
||||
$default_images['field2']->id(),
|
||||
format_string(
|
||||
'An existing page node without an image has the expected default image file ID of @fid.',
|
||||
['@fid' => $default_images['field2']->id()]
|
||||
)
|
||||
);
|
||||
|
||||
$non_image = $this->drupalGetTestFiles('text');
|
||||
$this->drupalPostForm(NULL, ['files[settings_default_image_uuid]' => drupal_realpath($non_image[0]->uri)], t("Upload"));
|
||||
$this->assertText('The specified file text-0.txt could not be uploaded.');
|
||||
$this->assertText('Only files with the following extensions are allowed: png gif jpg jpeg.');
|
||||
|
||||
// Confirm the default image is shown on the node form.
|
||||
$file = File::load($default_images['field_new']->id());
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->assertRaw($file->getFilename());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests image field and field having an invalid default image.
|
||||
*/
|
||||
public function testInvalidDefaultImage() {
|
||||
$field_storage = FieldStorageConfig::create([
|
||||
'field_name' => Unicode::strtolower($this->randomMachineName()),
|
||||
'entity_type' => 'node',
|
||||
'type' => 'image',
|
||||
'settings' => [
|
||||
'default_image' => [
|
||||
'uuid' => 100000,
|
||||
]
|
||||
],
|
||||
]);
|
||||
$field_storage->save();
|
||||
$settings = $field_storage->getSettings();
|
||||
// The non-existent default image should not be saved.
|
||||
$this->assertNull($settings['default_image']['uuid']);
|
||||
|
||||
$field = FieldConfig::create([
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => 'page',
|
||||
'label' => $this->randomMachineName(),
|
||||
'settings' => [
|
||||
'default_image' => [
|
||||
'uuid' => 100000,
|
||||
]
|
||||
],
|
||||
]);
|
||||
$field->save();
|
||||
$settings = $field->getSettings();
|
||||
// The non-existent default image should not be saved.
|
||||
$this->assertNull($settings['default_image']['uuid']);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,461 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Tests;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\user\RoleInterface;
|
||||
use Drupal\image\Entity\ImageStyle;
|
||||
|
||||
/**
|
||||
* Tests the display of image fields.
|
||||
*
|
||||
* @group image
|
||||
*/
|
||||
class ImageFieldDisplayTest extends ImageFieldTestBase {
|
||||
|
||||
protected $dumpHeaders = TRUE;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['field_ui'];
|
||||
|
||||
/**
|
||||
* Test image formatters on node display for public files.
|
||||
*/
|
||||
public function testImageFieldFormattersPublic() {
|
||||
$this->_testImageFieldFormatters('public');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test image formatters on node display for private files.
|
||||
*/
|
||||
public function testImageFieldFormattersPrivate() {
|
||||
// Remove access content permission from anonymous users.
|
||||
user_role_change_permissions(RoleInterface::ANONYMOUS_ID, ['access content' => FALSE]);
|
||||
$this->_testImageFieldFormatters('private');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test image formatters on node display.
|
||||
*/
|
||||
public function _testImageFieldFormatters($scheme) {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$field_name = strtolower($this->randomMachineName());
|
||||
$field_settings = ['alt_field_required' => 0];
|
||||
$instance = $this->createImageField($field_name, 'article', ['uri_scheme' => $scheme], $field_settings);
|
||||
|
||||
// Go to manage display page.
|
||||
$this->drupalGet("admin/structure/types/manage/article/display");
|
||||
|
||||
// Test for existence of link to image styles configuration.
|
||||
$this->drupalPostAjaxForm(NULL, [], "{$field_name}_settings_edit");
|
||||
$this->assertLinkByHref(\Drupal::url('entity.image_style.collection'), 0, 'Link to image styles configuration is found');
|
||||
|
||||
// Remove 'administer image styles' permission from testing admin user.
|
||||
$admin_user_roles = $this->adminUser->getRoles(TRUE);
|
||||
user_role_change_permissions(reset($admin_user_roles), ['administer image styles' => FALSE]);
|
||||
|
||||
// Go to manage display page again.
|
||||
$this->drupalGet("admin/structure/types/manage/article/display");
|
||||
|
||||
// Test for absence of link to image styles configuration.
|
||||
$this->drupalPostAjaxForm(NULL, [], "{$field_name}_settings_edit");
|
||||
$this->assertNoLinkByHref(\Drupal::url('entity.image_style.collection'), 'Link to image styles configuration is absent when permissions are insufficient');
|
||||
|
||||
// Restore 'administer image styles' permission to testing admin user
|
||||
user_role_change_permissions(reset($admin_user_roles), ['administer image styles' => TRUE]);
|
||||
|
||||
// Create a new node with an image attached.
|
||||
$test_image = current($this->drupalGetTestFiles('image'));
|
||||
|
||||
// Ensure that preview works.
|
||||
$this->previewNodeImage($test_image, $field_name, 'article');
|
||||
|
||||
// After previewing, make the alt field required. It cannot be required
|
||||
// during preview because the form validation will fail.
|
||||
$instance->setSetting('alt_field_required', 1);
|
||||
$instance->save();
|
||||
|
||||
// Create alt text for the image.
|
||||
$alt = $this->randomMachineName();
|
||||
|
||||
// Save node.
|
||||
$nid = $this->uploadNodeImage($test_image, $field_name, 'article', $alt);
|
||||
$node_storage->resetCache([$nid]);
|
||||
$node = $node_storage->load($nid);
|
||||
|
||||
// Test that the default formatter is being used.
|
||||
$file = $node->{$field_name}->entity;
|
||||
$image_uri = $file->getFileUri();
|
||||
$image = [
|
||||
'#theme' => 'image',
|
||||
'#uri' => $image_uri,
|
||||
'#width' => 40,
|
||||
'#height' => 20,
|
||||
'#alt' => $alt,
|
||||
];
|
||||
$default_output = str_replace("\n", NULL, $renderer->renderRoot($image));
|
||||
$this->assertRaw($default_output, 'Default formatter displaying correctly on full node view.');
|
||||
|
||||
// Test the image linked to file formatter.
|
||||
$display_options = [
|
||||
'type' => 'image',
|
||||
'settings' => ['image_link' => 'file'],
|
||||
];
|
||||
$display = entity_get_display('node', $node->getType(), 'default');
|
||||
$display->setComponent($field_name, $display_options)
|
||||
->save();
|
||||
|
||||
$image = [
|
||||
'#theme' => 'image',
|
||||
'#uri' => $image_uri,
|
||||
'#width' => 40,
|
||||
'#height' => 20,
|
||||
'#alt' => $alt,
|
||||
];
|
||||
$default_output = '<a href="' . file_create_url($image_uri) . '">' . $renderer->renderRoot($image) . '</a>';
|
||||
$this->drupalGet('node/' . $nid);
|
||||
$this->assertCacheTag($file->getCacheTags()[0]);
|
||||
// @todo Remove in https://www.drupal.org/node/2646744.
|
||||
$this->assertCacheContext('url.site');
|
||||
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
|
||||
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
|
||||
$this->assertRaw($default_output, 'Image linked to file formatter displaying correctly on full node view.');
|
||||
// Verify that the image can be downloaded.
|
||||
$this->assertEqual(file_get_contents($test_image->uri), $this->drupalGet(file_create_url($image_uri)), 'File was downloaded successfully.');
|
||||
if ($scheme == 'private') {
|
||||
// Only verify HTTP headers when using private scheme and the headers are
|
||||
// sent by Drupal.
|
||||
$this->assertEqual($this->drupalGetHeader('Content-Type'), 'image/png', 'Content-Type header was sent.');
|
||||
$this->assertTrue(strstr($this->drupalGetHeader('Cache-Control'), 'private') !== FALSE, 'Cache-Control header was sent.');
|
||||
|
||||
// Log out and try to access the file.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet(file_create_url($image_uri));
|
||||
$this->assertResponse('403', 'Access denied to original image as anonymous user.');
|
||||
|
||||
// Log in again.
|
||||
$this->drupalLogin($this->adminUser);
|
||||
}
|
||||
|
||||
// Test the image linked to content formatter.
|
||||
$display_options['settings']['image_link'] = 'content';
|
||||
$display->setComponent($field_name, $display_options)
|
||||
->save();
|
||||
$image = [
|
||||
'#theme' => 'image',
|
||||
'#uri' => $image_uri,
|
||||
'#width' => 40,
|
||||
'#height' => 20,
|
||||
];
|
||||
$this->drupalGet('node/' . $nid);
|
||||
$this->assertCacheTag($file->getCacheTags()[0]);
|
||||
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
|
||||
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
|
||||
$elements = $this->xpath(
|
||||
'//a[@href=:path]/img[@src=:url and @alt=:alt and @width=:width and @height=:height]',
|
||||
[
|
||||
':path' => $node->url(),
|
||||
':url' => file_url_transform_relative(file_create_url($image['#uri'])),
|
||||
':width' => $image['#width'],
|
||||
':height' => $image['#height'],
|
||||
':alt' => $alt,
|
||||
]
|
||||
);
|
||||
$this->assertEqual(count($elements), 1, 'Image linked to content formatter displaying correctly on full node view.');
|
||||
|
||||
// Test the image style 'thumbnail' formatter.
|
||||
$display_options['settings']['image_link'] = '';
|
||||
$display_options['settings']['image_style'] = 'thumbnail';
|
||||
$display->setComponent($field_name, $display_options)
|
||||
->save();
|
||||
|
||||
// Ensure the derivative image is generated so we do not have to deal with
|
||||
// image style callback paths.
|
||||
$this->drupalGet(ImageStyle::load('thumbnail')->buildUrl($image_uri));
|
||||
$image_style = [
|
||||
'#theme' => 'image_style',
|
||||
'#uri' => $image_uri,
|
||||
'#width' => 40,
|
||||
'#height' => 20,
|
||||
'#style_name' => 'thumbnail',
|
||||
'#alt' => $alt,
|
||||
];
|
||||
$default_output = $renderer->renderRoot($image_style);
|
||||
$this->drupalGet('node/' . $nid);
|
||||
$image_style = ImageStyle::load('thumbnail');
|
||||
$this->assertCacheTag($image_style->getCacheTags()[0]);
|
||||
$this->assertRaw($default_output, 'Image style thumbnail formatter displaying correctly on full node view.');
|
||||
|
||||
if ($scheme == 'private') {
|
||||
// Log out and try to access the file.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet(ImageStyle::load('thumbnail')->buildUrl($image_uri));
|
||||
$this->assertResponse('403', 'Access denied to image style thumbnail as anonymous user.');
|
||||
}
|
||||
|
||||
// Test the image URL formatter without an image style.
|
||||
$display_options = [
|
||||
'type' => 'image_url',
|
||||
'settings' => ['image_style' => ''],
|
||||
];
|
||||
$expected_url = file_url_transform_relative(file_create_url($image_uri));
|
||||
$this->assertEqual($expected_url, $node->{$field_name}->view($display_options)[0]['#markup']);
|
||||
|
||||
// Test the image URL formatter with an image style.
|
||||
$display_options['settings']['image_style'] = 'thumbnail';
|
||||
$expected_url = file_url_transform_relative(ImageStyle::load('thumbnail')->buildUrl($image_uri));
|
||||
$this->assertEqual($expected_url, $node->{$field_name}->view($display_options)[0]['#markup']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for image field settings.
|
||||
*/
|
||||
public function testImageFieldSettings() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$test_image = current($this->drupalGetTestFiles('image'));
|
||||
list(, $test_image_extension) = explode('.', $test_image->filename);
|
||||
$field_name = strtolower($this->randomMachineName());
|
||||
$field_settings = [
|
||||
'alt_field' => 1,
|
||||
'file_extensions' => $test_image_extension,
|
||||
'max_filesize' => '50 KB',
|
||||
'max_resolution' => '100x100',
|
||||
'min_resolution' => '10x10',
|
||||
'title_field' => 1,
|
||||
];
|
||||
$widget_settings = [
|
||||
'preview_image_style' => 'medium',
|
||||
];
|
||||
$field = $this->createImageField($field_name, 'article', [], $field_settings, $widget_settings);
|
||||
|
||||
// Verify that the min/max resolution set on the field are properly
|
||||
// extracted, and displayed, on the image field's configuration form.
|
||||
$this->drupalGet('admin/structure/types/manage/article/fields/' . $field->id());
|
||||
$this->assertFieldByName('settings[max_resolution][x]', '100', 'Expected max resolution X value of 100.');
|
||||
$this->assertFieldByName('settings[max_resolution][y]', '100', 'Expected max resolution Y value of 100.');
|
||||
$this->assertFieldByName('settings[min_resolution][x]', '10', 'Expected min resolution X value of 10.');
|
||||
$this->assertFieldByName('settings[min_resolution][y]', '10', 'Expected min resolution Y value of 10.');
|
||||
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->assertText(t('50 KB limit.'), 'Image widget max file size is displayed on article form.');
|
||||
$this->assertText(t('Allowed types: @extensions.', ['@extensions' => $test_image_extension]), 'Image widget allowed file types displayed on article form.');
|
||||
$this->assertText(t('Images must be larger than 10x10 pixels. Images larger than 100x100 pixels will be resized.'), 'Image widget allowed resolution displayed on article form.');
|
||||
|
||||
// We have to create the article first and then edit it because the alt
|
||||
// and title fields do not display until the image has been attached.
|
||||
|
||||
// Create alt text for the image.
|
||||
$alt = $this->randomMachineName();
|
||||
|
||||
$nid = $this->uploadNodeImage($test_image, $field_name, 'article', $alt);
|
||||
$this->drupalGet('node/' . $nid . '/edit');
|
||||
$this->assertFieldByName($field_name . '[0][alt]', '', 'Alt field displayed on article form.');
|
||||
$this->assertFieldByName($field_name . '[0][title]', '', 'Title field displayed on article form.');
|
||||
// Verify that the attached image is being previewed using the 'medium'
|
||||
// style.
|
||||
$node_storage->resetCache([$nid]);
|
||||
$node = $node_storage->load($nid);
|
||||
$file = $node->{$field_name}->entity;
|
||||
|
||||
$url = file_url_transform_relative(file_create_url(ImageStyle::load('medium')->buildUrl($file->getFileUri())));
|
||||
$this->assertTrue($this->cssSelect('img[width=40][height=20][class=image-style-medium][src="' . $url . '"]'));
|
||||
|
||||
// Add alt/title fields to the image and verify that they are displayed.
|
||||
$image = [
|
||||
'#theme' => 'image',
|
||||
'#uri' => $file->getFileUri(),
|
||||
'#alt' => $alt,
|
||||
'#title' => $this->randomMachineName(),
|
||||
'#width' => 40,
|
||||
'#height' => 20,
|
||||
];
|
||||
$edit = [
|
||||
$field_name . '[0][alt]' => $image['#alt'],
|
||||
$field_name . '[0][title]' => $image['#title'],
|
||||
];
|
||||
$this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save and keep published'));
|
||||
$default_output = str_replace("\n", NULL, $renderer->renderRoot($image));
|
||||
$this->assertRaw($default_output, 'Image displayed using user supplied alt and title attributes.');
|
||||
|
||||
// Verify that alt/title longer than allowed results in a validation error.
|
||||
$test_size = 2000;
|
||||
$edit = [
|
||||
$field_name . '[0][alt]' => $this->randomMachineName($test_size),
|
||||
$field_name . '[0][title]' => $this->randomMachineName($test_size),
|
||||
];
|
||||
$this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save and keep published'));
|
||||
$schema = $field->getFieldStorageDefinition()->getSchema();
|
||||
$this->assertRaw(t('Alternative text cannot be longer than %max characters but is currently %length characters long.', [
|
||||
'%max' => $schema['columns']['alt']['length'],
|
||||
'%length' => $test_size,
|
||||
]));
|
||||
$this->assertRaw(t('Title cannot be longer than %max characters but is currently %length characters long.', [
|
||||
'%max' => $schema['columns']['title']['length'],
|
||||
'%length' => $test_size,
|
||||
]));
|
||||
|
||||
// Set cardinality to unlimited and add upload a second image.
|
||||
// The image widget is extending on the file widget, but the image field
|
||||
// type does not have the 'display_field' setting which is expected by
|
||||
// the file widget. This resulted in notices before when cardinality is not
|
||||
// 1, so we need to make sure the file widget prevents these notices by
|
||||
// providing all settings, even if they are not used.
|
||||
// @see FileWidget::formMultipleElements().
|
||||
$this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.' . $field_name . '/storage', ['cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED], t('Save field settings'));
|
||||
$edit = [
|
||||
'files[' . $field_name . '_1][]' => drupal_realpath($test_image->uri),
|
||||
];
|
||||
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published'));
|
||||
// Add the required alt text.
|
||||
$this->drupalPostForm(NULL, [$field_name . '[1][alt]' => $alt], t('Save and keep published'));
|
||||
$this->assertText(format_string('Article @title has been updated.', ['@title' => $node->getTitle()]));
|
||||
|
||||
// Assert ImageWidget::process() calls FieldWidget::process().
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
$edit = [
|
||||
'files[' . $field_name . '_2][]' => drupal_realpath($test_image->uri),
|
||||
];
|
||||
$this->drupalPostAjaxForm(NULL, $edit, $field_name . '_2_upload_button');
|
||||
$this->assertNoRaw('<input multiple type="file" id="edit-' . strtr($field_name, '_', '-') . '-2-upload" name="files[' . $field_name . '_2][]" size="22" class="js-form-file form-file">');
|
||||
$this->assertRaw('<input multiple type="file" id="edit-' . strtr($field_name, '_', '-') . '-3-upload" name="files[' . $field_name . '_3][]" size="22" class="js-form-file form-file">');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test use of a default image with an image field.
|
||||
*/
|
||||
public function testImageFieldDefaultImage() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
// Create a new image field.
|
||||
$field_name = strtolower($this->randomMachineName());
|
||||
$this->createImageField($field_name, 'article');
|
||||
|
||||
// Create a new node, with no images and verify that no images are
|
||||
// displayed.
|
||||
$node = $this->drupalCreateNode(['type' => 'article']);
|
||||
$this->drupalGet('node/' . $node->id());
|
||||
// Verify that no image is displayed on the page by checking for the class
|
||||
// that would be used on the image field.
|
||||
$this->assertNoPattern('<div class="(.*?)field--name-' . strtr($field_name, '_', '-') . '(.*?)">', 'No image displayed when no image is attached and no default image specified.');
|
||||
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
|
||||
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
|
||||
|
||||
// Add a default image to the public image field.
|
||||
$images = $this->drupalGetTestFiles('image');
|
||||
$alt = $this->randomString(512);
|
||||
$title = $this->randomString(1024);
|
||||
$edit = [
|
||||
// Get the path of the 'image-test.png' file.
|
||||
'files[settings_default_image_uuid]' => drupal_realpath($images[0]->uri),
|
||||
'settings[default_image][alt]' => $alt,
|
||||
'settings[default_image][title]' => $title,
|
||||
];
|
||||
$this->drupalPostForm("admin/structure/types/manage/article/fields/node.article.$field_name/storage", $edit, t('Save field settings'));
|
||||
// Clear field definition cache so the new default image is detected.
|
||||
\Drupal::entityManager()->clearCachedFieldDefinitions();
|
||||
$field_storage = FieldStorageConfig::loadByName('node', $field_name);
|
||||
$default_image = $field_storage->getSetting('default_image');
|
||||
$file = \Drupal::entityManager()->loadEntityByUuid('file', $default_image['uuid']);
|
||||
$this->assertTrue($file->isPermanent(), 'The default image status is permanent.');
|
||||
$image = [
|
||||
'#theme' => 'image',
|
||||
'#uri' => $file->getFileUri(),
|
||||
'#alt' => $alt,
|
||||
'#title' => $title,
|
||||
'#width' => 40,
|
||||
'#height' => 20,
|
||||
];
|
||||
$default_output = str_replace("\n", NULL, $renderer->renderRoot($image));
|
||||
$this->drupalGet('node/' . $node->id());
|
||||
$this->assertCacheTag($file->getCacheTags()[0]);
|
||||
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
|
||||
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
|
||||
$this->assertRaw($default_output, 'Default image displayed when no user supplied image is present.');
|
||||
|
||||
// Create a node with an image attached and ensure that the default image
|
||||
// is not displayed.
|
||||
|
||||
// Create alt text for the image.
|
||||
$alt = $this->randomMachineName();
|
||||
|
||||
// Upload the 'image-test.gif' file.
|
||||
$nid = $this->uploadNodeImage($images[2], $field_name, 'article', $alt);
|
||||
$node_storage->resetCache([$nid]);
|
||||
$node = $node_storage->load($nid);
|
||||
$file = $node->{$field_name}->entity;
|
||||
$image = [
|
||||
'#theme' => 'image',
|
||||
'#uri' => $file->getFileUri(),
|
||||
'#width' => 40,
|
||||
'#height' => 20,
|
||||
'#alt' => $alt,
|
||||
];
|
||||
$image_output = str_replace("\n", NULL, $renderer->renderRoot($image));
|
||||
$this->drupalGet('node/' . $nid);
|
||||
$this->assertCacheTag($file->getCacheTags()[0]);
|
||||
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
|
||||
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
|
||||
$this->assertNoRaw($default_output, 'Default image is not displayed when user supplied image is present.');
|
||||
$this->assertRaw($image_output, 'User supplied image is displayed.');
|
||||
|
||||
// Remove default image from the field and make sure it is no longer used.
|
||||
$edit = [
|
||||
'settings[default_image][uuid][fids]' => 0,
|
||||
];
|
||||
$this->drupalPostForm("admin/structure/types/manage/article/fields/node.article.$field_name/storage", $edit, t('Save field settings'));
|
||||
// Clear field definition cache so the new default image is detected.
|
||||
\Drupal::entityManager()->clearCachedFieldDefinitions();
|
||||
$field_storage = FieldStorageConfig::loadByName('node', $field_name);
|
||||
$default_image = $field_storage->getSetting('default_image');
|
||||
$this->assertFalse($default_image['uuid'], 'Default image removed from field.');
|
||||
// Create an image field that uses the private:// scheme and test that the
|
||||
// default image works as expected.
|
||||
$private_field_name = strtolower($this->randomMachineName());
|
||||
$this->createImageField($private_field_name, 'article', ['uri_scheme' => 'private']);
|
||||
// Add a default image to the new field.
|
||||
$edit = [
|
||||
// Get the path of the 'image-test.gif' file.
|
||||
'files[settings_default_image_uuid]' => drupal_realpath($images[2]->uri),
|
||||
'settings[default_image][alt]' => $alt,
|
||||
'settings[default_image][title]' => $title,
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.' . $private_field_name . '/storage', $edit, t('Save field settings'));
|
||||
// Clear field definition cache so the new default image is detected.
|
||||
\Drupal::entityManager()->clearCachedFieldDefinitions();
|
||||
|
||||
$private_field_storage = FieldStorageConfig::loadByName('node', $private_field_name);
|
||||
$default_image = $private_field_storage->getSetting('default_image');
|
||||
$file = \Drupal::entityManager()->loadEntityByUuid('file', $default_image['uuid']);
|
||||
$this->assertEqual('private', file_uri_scheme($file->getFileUri()), 'Default image uses private:// scheme.');
|
||||
$this->assertTrue($file->isPermanent(), 'The default image status is permanent.');
|
||||
// Create a new node with no image attached and ensure that default private
|
||||
// image is displayed.
|
||||
$node = $this->drupalCreateNode(['type' => 'article']);
|
||||
$image = [
|
||||
'#theme' => 'image',
|
||||
'#uri' => $file->getFileUri(),
|
||||
'#alt' => $alt,
|
||||
'#title' => $title,
|
||||
'#width' => 40,
|
||||
'#height' => 20,
|
||||
];
|
||||
$default_output = str_replace("\n", NULL, $renderer->renderRoot($image));
|
||||
$this->drupalGet('node/' . $node->id());
|
||||
$this->assertCacheTag($file->getCacheTags()[0]);
|
||||
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
|
||||
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
|
||||
$this->assertRaw($default_output, 'Default private image displayed when no user supplied image is present.');
|
||||
}
|
||||
|
||||
}
|
|
@ -2,17 +2,20 @@
|
|||
|
||||
namespace Drupal\image\Tests;
|
||||
|
||||
@trigger_error('The ' . __NAMESPACE__ . '\ImageFieldTestBase class is deprecated in Drupal 8.5.x and will be removed before Drupal 9.0.0. Use \Drupal\Tests\image\Functional\ImageFieldTestBase instead. See https://www.drupal.org/node/2863626.', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\Tests\image\Kernel\ImageFieldCreationTrait;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* TODO: Test the following functions.
|
||||
*
|
||||
* image.effects.inc:
|
||||
* In file:
|
||||
* - image.effects.inc:
|
||||
* image_style_generate()
|
||||
* \Drupal\image\ImageStyleInterface::createDerivative()
|
||||
*
|
||||
* image.module:
|
||||
* - image.module:
|
||||
* image_style_options()
|
||||
* \Drupal\image\ImageStyleInterface::flush()
|
||||
* image_filter_keyword()
|
||||
|
@ -69,7 +72,7 @@ abstract class ImageFieldTestBase extends WebTestBase {
|
|||
$edit = [
|
||||
'title[0][value]' => $this->randomMachineName(),
|
||||
];
|
||||
$edit['files[' . $field_name . '_0]'] = drupal_realpath($image->uri);
|
||||
$edit['files[' . $field_name . '_0]'] = \Drupal::service('file_system')->realpath($image->uri);
|
||||
$this->drupalPostForm('node/add/' . $type, $edit, t('Preview'));
|
||||
}
|
||||
|
||||
|
@ -89,11 +92,11 @@ abstract class ImageFieldTestBase extends WebTestBase {
|
|||
$edit = [
|
||||
'title[0][value]' => $this->randomMachineName(),
|
||||
];
|
||||
$edit['files[' . $field_name . '_0]'] = drupal_realpath($image->uri);
|
||||
$this->drupalPostForm('node/add/' . $type, $edit, t('Save and publish'));
|
||||
$edit['files[' . $field_name . '_0]'] = \Drupal::service('file_system')->realpath($image->uri);
|
||||
$this->drupalPostForm('node/add/' . $type, $edit, t('Save'));
|
||||
if ($alt) {
|
||||
// Add alt text.
|
||||
$this->drupalPostForm(NULL, [$field_name . '[0][alt]' => $alt], t('Save and publish'));
|
||||
$this->drupalPostForm(NULL, [$field_name . '[0][alt]' => $alt], t('Save'));
|
||||
}
|
||||
|
||||
// Retrieve ID of the newly created node from the current URL.
|
||||
|
|
|
@ -1,159 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Tests;
|
||||
|
||||
/**
|
||||
* Tests validation functions such as min/max resolution.
|
||||
*
|
||||
* @group image
|
||||
*/
|
||||
class ImageFieldValidateTest extends ImageFieldTestBase {
|
||||
/**
|
||||
* Test min/max resolution settings.
|
||||
*/
|
||||
public function testResolution() {
|
||||
$field_names = [
|
||||
0 => strtolower($this->randomMachineName()),
|
||||
1 => strtolower($this->randomMachineName()),
|
||||
2 => strtolower($this->randomMachineName()),
|
||||
];
|
||||
$min_resolution = [
|
||||
'width' => 50,
|
||||
'height' => 50
|
||||
];
|
||||
$max_resolution = [
|
||||
'width' => 100,
|
||||
'height' => 100
|
||||
];
|
||||
$no_height_min_resolution = [
|
||||
'width' => 50,
|
||||
'height' => NULL
|
||||
];
|
||||
$no_height_max_resolution = [
|
||||
'width' => 100,
|
||||
'height' => NULL
|
||||
];
|
||||
$no_width_min_resolution = [
|
||||
'width' => NULL,
|
||||
'height' => 50
|
||||
];
|
||||
$no_width_max_resolution = [
|
||||
'width' => NULL,
|
||||
'height' => 100
|
||||
];
|
||||
$field_settings = [
|
||||
0 => $this->getFieldSettings($min_resolution, $max_resolution),
|
||||
1 => $this->getFieldSettings($no_height_min_resolution, $no_height_max_resolution),
|
||||
2 => $this->getFieldSettings($no_width_min_resolution, $no_width_max_resolution),
|
||||
];
|
||||
$this->createImageField($field_names[0], 'article', [], $field_settings[0]);
|
||||
$this->createImageField($field_names[1], 'article', [], $field_settings[1]);
|
||||
$this->createImageField($field_names[2], 'article', [], $field_settings[2]);
|
||||
|
||||
// We want a test image that is too small, and a test image that is too
|
||||
// big, so cycle through test image files until we have what we need.
|
||||
$image_that_is_too_big = FALSE;
|
||||
$image_that_is_too_small = FALSE;
|
||||
$image_factory = $this->container->get('image.factory');
|
||||
foreach ($this->drupalGetTestFiles('image') as $image) {
|
||||
$image_file = $image_factory->get($image->uri);
|
||||
if ($image_file->getWidth() > $max_resolution['width']) {
|
||||
$image_that_is_too_big = $image;
|
||||
}
|
||||
if ($image_file->getWidth() < $min_resolution['width']) {
|
||||
$image_that_is_too_small = $image;
|
||||
}
|
||||
if ($image_that_is_too_small && $image_that_is_too_big) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->uploadNodeImage($image_that_is_too_small, $field_names[0], 'article');
|
||||
$this->assertRaw(t('The specified file %name could not be uploaded.', ['%name' => $image_that_is_too_small->filename]));
|
||||
$this->assertRaw(t('The image is too small; the minimum dimensions are %dimensions pixels.', ['%dimensions' => '50x50']));
|
||||
$this->uploadNodeImage($image_that_is_too_big, $field_names[0], 'article');
|
||||
$this->assertText(t('The image was resized to fit within the maximum allowed dimensions of 100x100 pixels.'));
|
||||
$this->uploadNodeImage($image_that_is_too_small, $field_names[1], 'article');
|
||||
$this->assertRaw(t('The specified file %name could not be uploaded.', ['%name' => $image_that_is_too_small->filename]));
|
||||
$this->uploadNodeImage($image_that_is_too_big, $field_names[1], 'article');
|
||||
$this->assertText(t('The image was resized to fit within the maximum allowed width of 100 pixels.'));
|
||||
$this->uploadNodeImage($image_that_is_too_small, $field_names[2], 'article');
|
||||
$this->assertRaw(t('The specified file %name could not be uploaded.', ['%name' => $image_that_is_too_small->filename]));
|
||||
$this->uploadNodeImage($image_that_is_too_big, $field_names[2], 'article');
|
||||
$this->assertText(t('The image was resized to fit within the maximum allowed height of 100 pixels.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that required alt/title fields gets validated right.
|
||||
*/
|
||||
public function testRequiredAttributes() {
|
||||
$field_name = strtolower($this->randomMachineName());
|
||||
$field_settings = [
|
||||
'alt_field' => 1,
|
||||
'alt_field_required' => 1,
|
||||
'title_field' => 1,
|
||||
'title_field_required' => 1,
|
||||
'required' => 1,
|
||||
];
|
||||
$instance = $this->createImageField($field_name, 'article', [], $field_settings);
|
||||
$images = $this->drupalGetTestFiles('image');
|
||||
// Let's just use the first image.
|
||||
$image = $images[0];
|
||||
$this->uploadNodeImage($image, $field_name, 'article');
|
||||
|
||||
// Look for form-required for the alt text.
|
||||
$elements = $this->xpath('//label[@for="edit-' . $field_name . '-0-alt" and @class="js-form-required form-required"]/following-sibling::input[@id="edit-' . $field_name . '-0-alt"]');
|
||||
|
||||
$this->assertTrue(isset($elements[0]), 'Required marker is shown for the required alt text.');
|
||||
|
||||
$elements = $this->xpath('//label[@for="edit-' . $field_name . '-0-title" and @class="js-form-required form-required"]/following-sibling::input[@id="edit-' . $field_name . '-0-title"]');
|
||||
|
||||
$this->assertTrue(isset($elements[0]), 'Required marker is shown for the required title text.');
|
||||
|
||||
$this->assertText(t('Alternative text field is required.'));
|
||||
$this->assertText(t('Title field is required.'));
|
||||
|
||||
$instance->setSetting('alt_field_required', 0);
|
||||
$instance->setSetting('title_field_required', 0);
|
||||
$instance->save();
|
||||
|
||||
$edit = [
|
||||
'title[0][value]' => $this->randomMachineName(),
|
||||
];
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save and publish'));
|
||||
|
||||
$this->assertNoText(t('Alternative text field is required.'));
|
||||
$this->assertNoText(t('Title field is required.'));
|
||||
|
||||
$instance->setSetting('required', 0);
|
||||
$instance->setSetting('alt_field_required', 1);
|
||||
$instance->setSetting('title_field_required', 1);
|
||||
$instance->save();
|
||||
|
||||
$edit = [
|
||||
'title[0][value]' => $this->randomMachineName(),
|
||||
];
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save and publish'));
|
||||
|
||||
$this->assertNoText(t('Alternative text field is required.'));
|
||||
$this->assertNoText(t('Title field is required.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns field settings.
|
||||
*
|
||||
* @param int[] $min_resolution
|
||||
* The minimum width and height resolution setting.
|
||||
* @param int[] $max_resolution
|
||||
* The maximum width and height resolution setting.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getFieldSettings($min_resolution, $max_resolution) {
|
||||
return [
|
||||
'max_resolution' => $max_resolution['width'] . 'x' . $max_resolution['height'],
|
||||
'min_resolution' => $min_resolution['width'] . 'x' . $min_resolution['height'],
|
||||
'alt_field' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -1,225 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Tests;
|
||||
|
||||
use Drupal\file\Entity\File;
|
||||
|
||||
/**
|
||||
* Uploads images to translated nodes.
|
||||
*
|
||||
* @group image
|
||||
*/
|
||||
class ImageOnTranslatedEntityTest extends ImageFieldTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['language', 'content_translation', 'field_ui'];
|
||||
|
||||
/**
|
||||
* The name of the image field used in the test.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create the "Basic page" node type.
|
||||
// @todo Remove the disabling of new revision creation in
|
||||
// https://www.drupal.org/node/1239558.
|
||||
$this->drupalCreateContentType(['type' => 'basicpage', 'name' => 'Basic page', 'new_revision' => FALSE]);
|
||||
|
||||
// Create a image field on the "Basic page" node type.
|
||||
$this->fieldName = strtolower($this->randomMachineName());
|
||||
$this->createImageField($this->fieldName, 'basicpage', [], ['title_field' => 1]);
|
||||
|
||||
// Create and log in user.
|
||||
$permissions = [
|
||||
'access administration pages',
|
||||
'administer content translation',
|
||||
'administer content types',
|
||||
'administer languages',
|
||||
'administer node fields',
|
||||
'create content translations',
|
||||
'create basicpage content',
|
||||
'edit any basicpage content',
|
||||
'translate any entity',
|
||||
'delete any basicpage content',
|
||||
];
|
||||
$admin_user = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Add a second and third language.
|
||||
$edit = [];
|
||||
$edit['predefined_langcode'] = 'fr';
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
|
||||
$edit = [];
|
||||
$edit['predefined_langcode'] = 'nl';
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests synced file fields on translated nodes.
|
||||
*/
|
||||
public function testSyncedImages() {
|
||||
// Enable translation for "Basic page" nodes.
|
||||
$edit = [
|
||||
'entity_types[node]' => 1,
|
||||
'settings[node][basicpage][translatable]' => 1,
|
||||
"settings[node][basicpage][fields][$this->fieldName]" => 1,
|
||||
"settings[node][basicpage][columns][$this->fieldName][file]" => 1,
|
||||
// Explicitly disable alt and title since the javascript disables the
|
||||
// checkboxes on the form.
|
||||
"settings[node][basicpage][columns][$this->fieldName][alt]" => FALSE,
|
||||
"settings[node][basicpage][columns][$this->fieldName][title]" => FALSE,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/content-language', $edit, 'Save configuration');
|
||||
|
||||
// Verify that the image field on the "Basic basic" node type is
|
||||
// translatable.
|
||||
$definitions = \Drupal::entityManager()->getFieldDefinitions('node', 'basicpage');
|
||||
$this->assertTrue($definitions[$this->fieldName]->isTranslatable(), 'Node image field is translatable.');
|
||||
|
||||
// Create a default language node.
|
||||
$default_language_node = $this->drupalCreateNode(['type' => 'basicpage', 'title' => 'Lost in translation']);
|
||||
|
||||
// Edit the node to upload a file.
|
||||
$edit = [];
|
||||
$name = 'files[' . $this->fieldName . '_0]';
|
||||
$edit[$name] = drupal_realpath($this->drupalGetTestFiles('image')[0]->uri);
|
||||
$this->drupalPostForm('node/' . $default_language_node->id() . '/edit', $edit, t('Save'));
|
||||
$edit = [$this->fieldName . '[0][alt]' => 'Lost in translation image', $this->fieldName . '[0][title]' => 'Lost in translation image title'];
|
||||
$this->drupalPostForm(NULL, $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', [], t('Remove'));
|
||||
|
||||
// Upload a different file.
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = 'Scarlett Johansson';
|
||||
$name = 'files[' . $this->fieldName . '_0]';
|
||||
$edit[$name] = drupal_realpath($this->drupalGetTestFiles('image')[1]->uri);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
$edit = [$this->fieldName . '[0][alt]' => 'Scarlett Johansson image', $this->fieldName . '[0][title]' => 'Scarlett Johansson image title'];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
// This inspects the HTML after the post of the translation, the image
|
||||
// should be displayed on the original node.
|
||||
$this->assertRaw('alt="Lost in translation image"');
|
||||
$this->assertRaw('title="Lost in translation image title"');
|
||||
$second_fid = $this->getLastFileId();
|
||||
// View the translated node.
|
||||
$this->drupalGet('fr/node/' . $default_language_node->id());
|
||||
$this->assertRaw('alt="Scarlett Johansson image"');
|
||||
|
||||
\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', [], t('Remove'));
|
||||
|
||||
// Upload a different file.
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = 'Akiko Takeshita';
|
||||
$name = 'files[' . $this->fieldName . '_0]';
|
||||
$edit[$name] = drupal_realpath($this->drupalGetTestFiles('image')[2]->uri);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
$edit = [$this->fieldName . '[0][alt]' => 'Akiko Takeshita image', $this->fieldName . '[0][title]' => 'Akiko Takeshita image title'];
|
||||
$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 image
|
||||
// should be displayed on the original node.
|
||||
$this->assertRaw('alt="Lost in translation image"');
|
||||
$this->assertRaw('title="Lost in translation image title"');
|
||||
// View the translated node.
|
||||
$this->drupalGet('nl/node/' . $default_language_node->id());
|
||||
$this->assertRaw('alt="Akiko Takeshita image"');
|
||||
$this->assertRaw('title="Akiko Takeshita image title"');
|
||||
|
||||
// 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', [], t('Remove'));
|
||||
|
||||
// Upload a different file.
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = 'Giovanni Ribisi';
|
||||
$name = 'files[' . $this->fieldName . '_0]';
|
||||
$edit[$name] = drupal_realpath($this->drupalGetTestFiles('image')[3]->uri);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
$name = $this->fieldName . '[0][alt]';
|
||||
|
||||
$edit = [$name => 'Giovanni Ribisi image'];
|
||||
$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());
|
||||
|
||||
// Delete the third translation.
|
||||
$this->drupalPostForm('nl/node/' . $default_language_node->id() . '/delete', [], 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', [], 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());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Tests;
|
||||
|
||||
use Drupal\image\Entity\ImageStyle;
|
||||
|
||||
/**
|
||||
* Tests flushing of image styles.
|
||||
*
|
||||
* @group image
|
||||
*/
|
||||
class ImageStyleFlushTest extends ImageFieldTestBase {
|
||||
|
||||
/**
|
||||
* Given an image style and a wrapper, generate an image.
|
||||
*/
|
||||
public function createSampleImage($style, $wrapper) {
|
||||
static $file;
|
||||
|
||||
if (!isset($file)) {
|
||||
$files = $this->drupalGetTestFiles('image');
|
||||
$file = reset($files);
|
||||
}
|
||||
|
||||
// Make sure we have an image in our wrapper testing file directory.
|
||||
$source_uri = file_unmanaged_copy($file->uri, $wrapper . '://');
|
||||
// Build the derivative image.
|
||||
$derivative_uri = $style->buildUri($source_uri);
|
||||
$derivative = $style->createDerivative($source_uri, $derivative_uri);
|
||||
|
||||
return $derivative ? $derivative_uri : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of images currently created for a style in a wrapper.
|
||||
*/
|
||||
public function getImageCount($style, $wrapper) {
|
||||
return count(file_scan_directory($wrapper . '://styles/' . $style->id(), '/.*/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* General test to flush a style.
|
||||
*/
|
||||
public function testFlush() {
|
||||
|
||||
// Setup a style to be created and effects to add to it.
|
||||
$style_name = strtolower($this->randomMachineName(10));
|
||||
$style_label = $this->randomString();
|
||||
$style_path = 'admin/config/media/image-styles/manage/' . $style_name;
|
||||
$effect_edits = [
|
||||
'image_resize' => [
|
||||
'data[width]' => 100,
|
||||
'data[height]' => 101,
|
||||
],
|
||||
'image_scale' => [
|
||||
'data[width]' => 110,
|
||||
'data[height]' => 111,
|
||||
'data[upscale]' => 1,
|
||||
],
|
||||
];
|
||||
|
||||
// Add style form.
|
||||
$edit = [
|
||||
'name' => $style_name,
|
||||
'label' => $style_label,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/media/image-styles/add', $edit, t('Create new style'));
|
||||
|
||||
// Add each sample effect to the style.
|
||||
foreach ($effect_edits as $effect => $edit) {
|
||||
// Add the effect.
|
||||
$this->drupalPostForm($style_path, ['new' => $effect], t('Add'));
|
||||
if (!empty($edit)) {
|
||||
$this->drupalPostForm(NULL, $edit, t('Add effect'));
|
||||
}
|
||||
}
|
||||
|
||||
// Load the saved image style.
|
||||
$style = ImageStyle::load($style_name);
|
||||
|
||||
// Create an image for the 'public' wrapper.
|
||||
$image_path = $this->createSampleImage($style, 'public');
|
||||
// Expecting to find 2 images, one is the sample.png image shown in
|
||||
// image style preview.
|
||||
$this->assertEqual($this->getImageCount($style, 'public'), 2, format_string('Image style %style image %file successfully generated.', ['%style' => $style->label(), '%file' => $image_path]));
|
||||
|
||||
// Create an image for the 'private' wrapper.
|
||||
$image_path = $this->createSampleImage($style, 'private');
|
||||
$this->assertEqual($this->getImageCount($style, 'private'), 1, format_string('Image style %style image %file successfully generated.', ['%style' => $style->label(), '%file' => $image_path]));
|
||||
|
||||
// Remove the 'image_scale' effect and updates the style, which in turn
|
||||
// forces an image style flush.
|
||||
$style_path = 'admin/config/media/image-styles/manage/' . $style->id();
|
||||
$uuids = [];
|
||||
foreach ($style->getEffects() as $uuid => $effect) {
|
||||
$uuids[$effect->getPluginId()] = $uuid;
|
||||
}
|
||||
$this->drupalPostForm($style_path . '/effects/' . $uuids['image_scale'] . '/delete', [], t('Delete'));
|
||||
$this->assertResponse(200);
|
||||
$this->drupalPostForm($style_path, [], t('Update style'));
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Post flush, expected 1 image in the 'public' wrapper (sample.png).
|
||||
$this->assertEqual($this->getImageCount($style, 'public'), 1, format_string('Image style %style flushed correctly for %wrapper wrapper.', ['%style' => $style->label(), '%wrapper' => 'public']));
|
||||
|
||||
// Post flush, expected no image in the 'private' wrapper.
|
||||
$this->assertEqual($this->getImageCount($style, 'private'), 0, format_string('Image style %style flushed correctly for %wrapper wrapper.', ['%style' => $style->label(), '%wrapper' => 'private']));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,268 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Tests;
|
||||
|
||||
use Drupal\image\Entity\ImageStyle;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests the functions for generating paths and URLs for image styles.
|
||||
*
|
||||
* @group image
|
||||
*/
|
||||
class ImageStylesPathAndUrlTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['image', 'image_module_test'];
|
||||
|
||||
/**
|
||||
* @var \Drupal\image\ImageStyleInterface
|
||||
*/
|
||||
protected $style;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->style = ImageStyle::create(['name' => 'style_foo', 'label' => $this->randomString()]);
|
||||
$this->style->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests \Drupal\image\ImageStyleInterface::buildUri().
|
||||
*/
|
||||
public function testImageStylePath() {
|
||||
$scheme = 'public';
|
||||
$actual = $this->style->buildUri("$scheme://foo/bar.gif");
|
||||
$expected = "$scheme://styles/" . $this->style->id() . "/$scheme/foo/bar.gif";
|
||||
$this->assertEqual($actual, $expected, 'Got the path for a file URI.');
|
||||
|
||||
$actual = $this->style->buildUri('foo/bar.gif');
|
||||
$expected = "$scheme://styles/" . $this->style->id() . "/$scheme/foo/bar.gif";
|
||||
$this->assertEqual($actual, $expected, 'Got the path for a relative file path.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests an image style URL using the "public://" scheme.
|
||||
*/
|
||||
public function testImageStyleUrlAndPathPublic() {
|
||||
$this->doImageStyleUrlAndPathTests('public');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests an image style URL using the "private://" scheme.
|
||||
*/
|
||||
public function testImageStyleUrlAndPathPrivate() {
|
||||
$this->doImageStyleUrlAndPathTests('private');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests an image style URL with the "public://" scheme and unclean URLs.
|
||||
*/
|
||||
public function testImageStyleUrlAndPathPublicUnclean() {
|
||||
$this->doImageStyleUrlAndPathTests('public', FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests an image style URL with the "private://" schema and unclean URLs.
|
||||
*/
|
||||
public function testImageStyleUrlAndPathPrivateUnclean() {
|
||||
$this->doImageStyleUrlAndPathTests('private', FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests an image style URL with a file URL that has an extra slash in it.
|
||||
*/
|
||||
public function testImageStyleUrlExtraSlash() {
|
||||
$this->doImageStyleUrlAndPathTests('public', TRUE, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an invalid source image returns a 404.
|
||||
*/
|
||||
public function testImageStyleUrlForMissingSourceImage() {
|
||||
$non_existent_uri = 'public://foo.png';
|
||||
$generated_url = $this->style->buildUrl($non_existent_uri);
|
||||
$this->drupalGet($generated_url);
|
||||
$this->assertResponse(404, 'Accessing an image style URL with a source image that does not exist provides a 404 error response.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests building an image style URL.
|
||||
*/
|
||||
public function doImageStyleUrlAndPathTests($scheme, $clean_url = TRUE, $extra_slash = FALSE) {
|
||||
$this->prepareRequestForGenerator($clean_url);
|
||||
|
||||
// Make the default scheme neither "public" nor "private" to verify the
|
||||
// functions work for other than the default scheme.
|
||||
$this->config('system.file')->set('default_scheme', 'temporary')->save();
|
||||
|
||||
// Create the directories for the styles.
|
||||
$directory = $scheme . '://styles/' . $this->style->id();
|
||||
$status = file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
|
||||
$this->assertNotIdentical(FALSE, $status, 'Created the directory for the generated images for the test style.');
|
||||
|
||||
// Create a working copy of the file.
|
||||
$files = $this->drupalGetTestFiles('image');
|
||||
$file = array_shift($files);
|
||||
$original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
|
||||
// Let the image_module_test module know about this file, so it can claim
|
||||
// ownership in hook_file_download().
|
||||
\Drupal::state()->set('image.test_file_download', $original_uri);
|
||||
$this->assertNotIdentical(FALSE, $original_uri, 'Created the generated image file.');
|
||||
|
||||
// Get the URL of a file that has not been generated and try to create it.
|
||||
$generated_uri = $this->style->buildUri($original_uri);
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$generate_url = $this->style->buildUrl($original_uri, $clean_url);
|
||||
|
||||
// Ensure that the tests still pass when the file is generated by accessing
|
||||
// a poorly constructed (but still valid) file URL that has an extra slash
|
||||
// in it.
|
||||
if ($extra_slash) {
|
||||
$modified_uri = str_replace('://', ':///', $original_uri);
|
||||
$this->assertNotEqual($original_uri, $modified_uri, 'An extra slash was added to the generated file URI.');
|
||||
$generate_url = $this->style->buildUrl($modified_uri, $clean_url);
|
||||
}
|
||||
if (!$clean_url) {
|
||||
$this->assertTrue(strpos($generate_url, 'index.php/') !== FALSE, 'When using non-clean URLS, the system path contains the script name.');
|
||||
}
|
||||
// Add some extra chars to the token.
|
||||
$this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', IMAGE_DERIVATIVE_TOKEN . '=Zo', $generate_url));
|
||||
$this->assertResponse(403, 'Image was inaccessible at the URL with an invalid token.');
|
||||
// Change the parameter name so the token is missing.
|
||||
$this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', 'wrongparam=', $generate_url));
|
||||
$this->assertResponse(403, 'Image was inaccessible at the URL with a missing token.');
|
||||
|
||||
// Check that the generated URL is the same when we pass in a relative path
|
||||
// rather than a URI. We need to temporarily switch the default scheme to
|
||||
// match the desired scheme before testing this, then switch it back to the
|
||||
// "temporary" scheme used throughout this test afterwards.
|
||||
$this->config('system.file')->set('default_scheme', $scheme)->save();
|
||||
$relative_path = file_uri_target($original_uri);
|
||||
$generate_url_from_relative_path = $this->style->buildUrl($relative_path, $clean_url);
|
||||
$this->assertEqual($generate_url, $generate_url_from_relative_path);
|
||||
$this->config('system.file')->set('default_scheme', 'temporary')->save();
|
||||
|
||||
// Fetch the URL that generates the file.
|
||||
$this->drupalGet($generate_url);
|
||||
$this->assertResponse(200, 'Image was generated at the URL.');
|
||||
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
|
||||
$this->assertRaw(file_get_contents($generated_uri), 'URL returns expected file.');
|
||||
$image = $this->container->get('image.factory')->get($generated_uri);
|
||||
$this->assertEqual($this->drupalGetHeader('Content-Type'), $image->getMimeType(), 'Expected Content-Type was reported.');
|
||||
$this->assertEqual($this->drupalGetHeader('Content-Length'), $image->getFileSize(), 'Expected Content-Length was reported.');
|
||||
|
||||
// Check that we did not download the original file.
|
||||
$original_image = $this->container->get('image.factory')->get($original_uri);
|
||||
$this->assertNotEqual($this->drupalGetHeader('Content-Length'), $original_image->getFileSize());
|
||||
|
||||
if ($scheme == 'private') {
|
||||
$this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
|
||||
$this->assertNotEqual(strpos($this->drupalGetHeader('Cache-Control'), 'no-cache'), FALSE, 'Cache-Control header contains \'no-cache\' to prevent caching.');
|
||||
$this->assertEqual($this->drupalGetHeader('X-Image-Owned-By'), 'image_module_test', 'Expected custom header has been added.');
|
||||
|
||||
// Make sure that a second request to the already existing derivative
|
||||
// works too.
|
||||
$this->drupalGet($generate_url);
|
||||
$this->assertResponse(200, 'Image was generated at the URL.');
|
||||
|
||||
// Check that the second request also returned the generated image.
|
||||
$this->assertEqual($this->drupalGetHeader('Content-Length'), $image->getFileSize());
|
||||
|
||||
// Check that we did not download the original file.
|
||||
$this->assertNotEqual($this->drupalGetHeader('Content-Length'), $original_image->getFileSize());
|
||||
|
||||
// Make sure that access is denied for existing style files if we do not
|
||||
// have access.
|
||||
\Drupal::state()->delete('image.test_file_download');
|
||||
$this->drupalGet($generate_url);
|
||||
$this->assertResponse(403, 'Confirmed that access is denied for the private image style.');
|
||||
|
||||
// Repeat this with a different file that we do not have access to and
|
||||
// make sure that access is denied.
|
||||
$file_noaccess = array_shift($files);
|
||||
$original_uri_noaccess = file_unmanaged_copy($file_noaccess->uri, $scheme . '://', FILE_EXISTS_RENAME);
|
||||
$generated_uri_noaccess = $scheme . '://styles/' . $this->style->id() . '/' . $scheme . '/' . drupal_basename($original_uri_noaccess);
|
||||
$this->assertFalse(file_exists($generated_uri_noaccess), 'Generated file does not exist.');
|
||||
$generate_url_noaccess = $this->style->buildUrl($original_uri_noaccess);
|
||||
|
||||
$this->drupalGet($generate_url_noaccess);
|
||||
$this->assertResponse(403, 'Confirmed that access is denied for the private image style.');
|
||||
// Verify that images are not appended to the response. Currently this test only uses PNG images.
|
||||
if (strpos($generate_url, '.png') === FALSE ) {
|
||||
$this->fail('Confirming that private image styles are not appended require PNG file.');
|
||||
}
|
||||
else {
|
||||
// Check for PNG-Signature (cf. http://www.libpng.org/pub/png/book/chapter08.html#png.ch08.div.2) in the
|
||||
// response body.
|
||||
$this->assertNoRaw( chr(137) . chr(80) . chr(78) . chr(71) . chr(13) . chr(10) . chr(26) . chr(10), 'No PNG signature found in the response body.');
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
|
||||
$this->assertEqual(strpos($this->drupalGetHeader('Cache-Control'), 'no-cache'), FALSE, 'Cache-Control header contains \'no-cache\' to prevent caching.');
|
||||
|
||||
if ($clean_url) {
|
||||
// Add some extra chars to the token.
|
||||
$this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', IMAGE_DERIVATIVE_TOKEN . '=Zo', $generate_url));
|
||||
$this->assertResponse(200, 'Existing image was accessible at the URL with an invalid token.');
|
||||
}
|
||||
}
|
||||
|
||||
// Allow insecure image derivatives to be created for the remainder of this
|
||||
// test.
|
||||
$this->config('image.settings')->set('allow_insecure_derivatives', TRUE)->save();
|
||||
|
||||
// Create another working copy of the file.
|
||||
$files = $this->drupalGetTestFiles('image');
|
||||
$file = array_shift($files);
|
||||
$original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
|
||||
// Let the image_module_test module know about this file, so it can claim
|
||||
// ownership in hook_file_download().
|
||||
\Drupal::state()->set('image.test_file_download', $original_uri);
|
||||
|
||||
// Suppress the security token in the URL, then get the URL of a file that
|
||||
// has not been created and try to create it. Check that the security token
|
||||
// is not present in the URL but that the image is still accessible.
|
||||
$this->config('image.settings')->set('suppress_itok_output', TRUE)->save();
|
||||
$generated_uri = $this->style->buildUri($original_uri);
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$generate_url = $this->style->buildUrl($original_uri, $clean_url);
|
||||
$this->assertIdentical(strpos($generate_url, IMAGE_DERIVATIVE_TOKEN . '='), FALSE, 'The security token does not appear in the image style URL.');
|
||||
$this->drupalGet($generate_url);
|
||||
$this->assertResponse(200, 'Image was accessible at the URL with a missing token.');
|
||||
|
||||
// Stop supressing the security token in the URL.
|
||||
$this->config('image.settings')->set('suppress_itok_output', FALSE)->save();
|
||||
// Ensure allow_insecure_derivatives is enabled.
|
||||
$this->assertEqual($this->config('image.settings')->get('allow_insecure_derivatives'), TRUE);
|
||||
// Check that a security token is still required when generating a second
|
||||
// image derivative using the first one as a source.
|
||||
$nested_url = $this->style->buildUrl($generated_uri, $clean_url);
|
||||
$matches_expected_url_format = (boolean) preg_match('/styles\/' . $this->style->id() . '\/' . $scheme . '\/styles\/' . $this->style->id() . '\/' . $scheme . '/', $nested_url);
|
||||
$this->assertTrue($matches_expected_url_format, "URL for a derivative of an image style matches expected format.");
|
||||
$nested_url_with_wrong_token = str_replace(IMAGE_DERIVATIVE_TOKEN . '=', 'wrongparam=', $nested_url);
|
||||
$this->drupalGet($nested_url_with_wrong_token);
|
||||
$this->assertResponse(403, 'Image generated from an earlier derivative was inaccessible at the URL with a missing token.');
|
||||
// Check that this restriction cannot be bypassed by adding extra slashes
|
||||
// to the URL.
|
||||
$this->drupalGet(substr_replace($nested_url_with_wrong_token, '//styles/', strrpos($nested_url_with_wrong_token, '/styles/'), strlen('/styles/')));
|
||||
$this->assertResponse(403, 'Image generated from an earlier derivative was inaccessible at the URL with a missing token, even with an extra forward slash in the URL.');
|
||||
$this->drupalGet(substr_replace($nested_url_with_wrong_token, '////styles/', strrpos($nested_url_with_wrong_token, '/styles/'), strlen('/styles/')));
|
||||
$this->assertResponse(403, 'Image generated from an earlier derivative was inaccessible at the URL with a missing token, even with multiple forward slashes in the URL.');
|
||||
// Make sure the image can still be generated if a correct token is used.
|
||||
$this->drupalGet($nested_url);
|
||||
$this->assertResponse(200, 'Image was accessible when a correct token was provided in the URL.');
|
||||
|
||||
// Check that requesting a nonexistent image does not create any new
|
||||
// directories in the file system.
|
||||
$directory = $scheme . '://styles/' . $this->style->id() . '/' . $scheme . '/' . $this->randomMachineName();
|
||||
$this->drupalGet(file_create_url($directory . '/' . $this->randomString()));
|
||||
$this->assertFalse(file_exists($directory), 'New directory was not created in the filesystem when requesting an unauthorized image.');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,221 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Tests;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\image\Entity\ImageStyle;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests image theme functions.
|
||||
*
|
||||
* @group image
|
||||
*/
|
||||
class ImageThemeFunctionTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['image', 'entity_test'];
|
||||
|
||||
/**
|
||||
* Created file entity.
|
||||
*
|
||||
* @var \Drupal\file\Entity\File
|
||||
*/
|
||||
protected $image;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Image\ImageFactory
|
||||
*/
|
||||
protected $imageFactory;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
FieldStorageConfig::create([
|
||||
'entity_type' => 'entity_test',
|
||||
'field_name' => 'image_test',
|
||||
'type' => 'image',
|
||||
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||
])->save();
|
||||
FieldConfig::create([
|
||||
'entity_type' => 'entity_test',
|
||||
'field_name' => 'image_test',
|
||||
'bundle' => 'entity_test',
|
||||
])->save();
|
||||
file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', 'public://example.jpg');
|
||||
$this->image = File::create([
|
||||
'uri' => 'public://example.jpg',
|
||||
]);
|
||||
$this->image->save();
|
||||
$this->imageFactory = $this->container->get('image.factory');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests usage of the image field formatters.
|
||||
*/
|
||||
public function testImageFormatterTheme() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
|
||||
// Create an image.
|
||||
$files = $this->drupalGetTestFiles('image');
|
||||
$file = reset($files);
|
||||
$original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME);
|
||||
|
||||
// Create a style.
|
||||
$style = ImageStyle::create(['name' => 'test', 'label' => 'Test']);
|
||||
$style->save();
|
||||
$url = file_url_transform_relative($style->buildUrl($original_uri));
|
||||
|
||||
// Create a test entity with the image field set.
|
||||
$entity = EntityTest::create();
|
||||
$entity->image_test->target_id = $this->image->id();
|
||||
$entity->image_test->alt = NULL;
|
||||
$entity->image_test->uri = $original_uri;
|
||||
$image = $this->imageFactory->get('public://example.jpg');
|
||||
$entity->save();
|
||||
|
||||
// Create the base element that we'll use in the tests below.
|
||||
$path = $this->randomMachineName();
|
||||
$base_element = [
|
||||
'#theme' => 'image_formatter',
|
||||
'#image_style' => 'test',
|
||||
'#item' => $entity->image_test,
|
||||
'#url' => Url::fromUri('base:' . $path),
|
||||
];
|
||||
|
||||
// Test using theme_image_formatter() with a NULL value for the alt option.
|
||||
$element = $base_element;
|
||||
$this->setRawContent($renderer->renderRoot($element));
|
||||
$elements = $this->xpath('//a[@href=:path]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height]', [':path' => base_path() . $path, ':url' => $url, ':width' => $image->getWidth(), ':height' => $image->getHeight()]);
|
||||
$this->assertEqual(count($elements), 1, 'theme_image_formatter() correctly renders with a NULL value for the alt option.');
|
||||
|
||||
// Test using theme_image_formatter() without an image title, alt text, or
|
||||
// link options.
|
||||
$element = $base_element;
|
||||
$element['#item']->alt = '';
|
||||
$this->setRawContent($renderer->renderRoot($element));
|
||||
$elements = $this->xpath('//a[@href=:path]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height and @alt=""]', [':path' => base_path() . $path, ':url' => $url, ':width' => $image->getWidth(), ':height' => $image->getHeight()]);
|
||||
$this->assertEqual(count($elements), 1, 'theme_image_formatter() correctly renders without title, alt, or path options.');
|
||||
|
||||
// Link the image to a fragment on the page, and not a full URL.
|
||||
$fragment = $this->randomMachineName();
|
||||
$element = $base_element;
|
||||
$element['#url'] = Url::fromRoute('<none>', [], ['fragment' => $fragment]);
|
||||
$this->setRawContent($renderer->renderRoot($element));
|
||||
$elements = $this->xpath('//a[@href=:fragment]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height and @alt=""]', [
|
||||
':fragment' => '#' . $fragment,
|
||||
':url' => $url,
|
||||
':width' => $image->getWidth(),
|
||||
':height' => $image->getHeight()
|
||||
]);
|
||||
$this->assertEqual(count($elements), 1, 'theme_image_formatter() correctly renders a link fragment.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests usage of the image style theme function.
|
||||
*/
|
||||
public function testImageStyleTheme() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
|
||||
// Create an image.
|
||||
$files = $this->drupalGetTestFiles('image');
|
||||
$file = reset($files);
|
||||
$original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME);
|
||||
|
||||
// Create a style.
|
||||
$style = ImageStyle::create(['name' => 'image_test', 'label' => 'Test']);
|
||||
$style->save();
|
||||
$url = file_url_transform_relative($style->buildUrl($original_uri));
|
||||
|
||||
// Create the base element that we'll use in the tests below.
|
||||
$base_element = [
|
||||
'#theme' => 'image_style',
|
||||
'#style_name' => 'image_test',
|
||||
'#uri' => $original_uri,
|
||||
];
|
||||
|
||||
$element = $base_element;
|
||||
$this->setRawContent($renderer->renderRoot($element));
|
||||
$elements = $this->xpath('//img[@class="image-style-image-test" and @src=:url and @alt=""]', [':url' => $url]);
|
||||
$this->assertEqual(count($elements), 1, 'theme_image_style() renders an image correctly.');
|
||||
|
||||
// Test using theme_image_style() with a NULL value for the alt option.
|
||||
$element = $base_element;
|
||||
$element['#alt'] = NULL;
|
||||
$this->setRawContent($renderer->renderRoot($element));
|
||||
$elements = $this->xpath('//img[@class="image-style-image-test" and @src=:url]', [':url' => $url]);
|
||||
$this->assertEqual(count($elements), 1, 'theme_image_style() renders an image correctly with a NULL value for the alt option.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests image alt attribute functionality.
|
||||
*/
|
||||
public function testImageAltFunctionality() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
|
||||
// Test using alt directly with alt attribute.
|
||||
$image_with_alt_property = [
|
||||
'#theme' => 'image',
|
||||
'#uri' => '/core/themes/bartik/logo.svg',
|
||||
'#alt' => 'Regular alt',
|
||||
'#title' => 'Test title',
|
||||
'#width' => '50%',
|
||||
'#height' => '50%',
|
||||
'#attributes' => ['class' => 'image-with-regular-alt', 'id' => 'my-img'],
|
||||
];
|
||||
|
||||
$this->setRawContent($renderer->renderRoot($image_with_alt_property));
|
||||
$elements = $this->xpath('//img[contains(@class, class) and contains(@alt, :alt)]', [":class" => "image-with-regular-alt", ":alt" => "Regular alt"]);
|
||||
$this->assertEqual(count($elements), 1, 'Regular alt displays correctly');
|
||||
|
||||
// Test using alt attribute inside attributes.
|
||||
$image_with_alt_attribute_alt_attribute = [
|
||||
'#theme' => 'image',
|
||||
'#uri' => '/core/themes/bartik/logo.svg',
|
||||
'#width' => '50%',
|
||||
'#height' => '50%',
|
||||
'#attributes' => [
|
||||
'class' => 'image-with-attribute-alt',
|
||||
'id' => 'my-img',
|
||||
'title' => 'New test title',
|
||||
'alt' => 'Attribute alt',
|
||||
],
|
||||
];
|
||||
|
||||
$this->setRawContent($renderer->renderRoot($image_with_alt_attribute_alt_attribute));
|
||||
$elements = $this->xpath('//img[contains(@class, class) and contains(@alt, :alt)]', [":class" => "image-with-attribute-alt", ":alt" => "Attribute alt"]);
|
||||
$this->assertEqual(count($elements), 1, 'Attribute alt displays correctly');
|
||||
|
||||
// Test using alt attribute as property and inside attributes.
|
||||
$image_with_alt_attribute_both = [
|
||||
'#theme' => 'image',
|
||||
'#uri' => '/core/themes/bartik/logo.svg',
|
||||
'#width' => '50%',
|
||||
'#height' => '50%',
|
||||
'#alt' => 'Kitten sustainable',
|
||||
'#attributes' => [
|
||||
'class' => 'image-with-attribute-alt',
|
||||
'id' => 'my-img',
|
||||
'title' => 'New test title',
|
||||
'alt' => 'Attribute alt',
|
||||
],
|
||||
];
|
||||
|
||||
$this->setRawContent($renderer->renderRoot($image_with_alt_attribute_both));
|
||||
$elements = $this->xpath('//img[contains(@class, class) and contains(@alt, :alt)]', [":class" => "image-with-attribute-alt", ":alt" => "Attribute alt"]);
|
||||
$this->assertEqual(count($elements), 1, 'Attribute alt overrides alt property if both set.');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,186 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Tests;
|
||||
|
||||
use Drupal\Tests\image\Kernel\ImageFieldCreationTrait;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests the endpoints used by the "image" in-place editor.
|
||||
*
|
||||
* @group image
|
||||
*/
|
||||
class QuickEditImageControllerTest extends WebTestBase {
|
||||
|
||||
use ImageFieldCreationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['node', 'image', 'quickedit'];
|
||||
|
||||
/**
|
||||
* The machine name of our image field.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
* A user with permissions to edit articles and use Quick Edit.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $contentAuthorUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create the Article node type.
|
||||
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
|
||||
|
||||
// Log in as a content author who can use Quick Edit and edit Articles.
|
||||
$this->contentAuthorUser = $this->drupalCreateUser([
|
||||
'access contextual links',
|
||||
'access in-place editing',
|
||||
'access content',
|
||||
'create article content',
|
||||
'edit any article content',
|
||||
'delete any article content',
|
||||
]);
|
||||
$this->drupalLogin($this->contentAuthorUser);
|
||||
|
||||
// Create a field with basic resolution validators.
|
||||
$this->fieldName = strtolower($this->randomMachineName());
|
||||
$field_settings = [
|
||||
'max_resolution' => '100x',
|
||||
'min_resolution' => '50x',
|
||||
];
|
||||
$this->createImageField($this->fieldName, 'article', [], $field_settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that routes restrict access for un-privileged users.
|
||||
*/
|
||||
public function testAccess() {
|
||||
// Create an anonymous user.
|
||||
$user = $this->createUser();
|
||||
$this->drupalLogin($user);
|
||||
|
||||
// Create a test Node.
|
||||
$node = $this->drupalCreateNode([
|
||||
'type' => 'article',
|
||||
'title' => t('Test Node'),
|
||||
]);
|
||||
$this->drupalGet('quickedit/image/info/node/' . $node->id() . '/' . $this->fieldName . '/' . $node->language()->getId() . '/default');
|
||||
$this->assertResponse('403');
|
||||
$this->drupalPost('quickedit/image/upload/node/' . $node->id() . '/' . $this->fieldName . '/' . $node->language()->getId() . '/default', 'application/json', []);
|
||||
$this->assertResponse('403');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the field info route returns expected data.
|
||||
*/
|
||||
public function testFieldInfo() {
|
||||
// Create a test Node.
|
||||
$node = $this->drupalCreateNode([
|
||||
'type' => 'article',
|
||||
'title' => t('Test Node'),
|
||||
]);
|
||||
$info = $this->drupalGetJSON('quickedit/image/info/node/' . $node->id() . '/' . $this->fieldName . '/' . $node->language()->getId() . '/default');
|
||||
// Assert that the default settings for our field are respected by our JSON
|
||||
// endpoint.
|
||||
$this->assertTrue($info['alt_field']);
|
||||
$this->assertFalse($info['title_field']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that uploading a valid image works.
|
||||
*/
|
||||
public function testValidImageUpload() {
|
||||
// Create a test Node.
|
||||
$node = $this->drupalCreateNode([
|
||||
'type' => 'article',
|
||||
'title' => t('Test Node'),
|
||||
]);
|
||||
|
||||
// We want a test image that is a valid size.
|
||||
$valid_image = FALSE;
|
||||
$image_factory = $this->container->get('image.factory');
|
||||
foreach ($this->drupalGetTestFiles('image') as $image) {
|
||||
$image_file = $image_factory->get($image->uri);
|
||||
if ($image_file->getWidth() > 50 && $image_file->getWidth() < 100) {
|
||||
$valid_image = $image;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->assertTrue($valid_image);
|
||||
$this->uploadImage($valid_image, $node->id(), $this->fieldName, $node->language()->getId());
|
||||
$this->assertText('fid', t('Valid upload completed successfully.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that uploading a invalid image does not work.
|
||||
*/
|
||||
public function testInvalidUpload() {
|
||||
// Create a test Node.
|
||||
$node = $this->drupalCreateNode([
|
||||
'type' => 'article',
|
||||
'title' => t('Test Node'),
|
||||
]);
|
||||
|
||||
// We want a test image that will fail validation.
|
||||
$invalid_image = FALSE;
|
||||
/** @var \Drupal\Core\Image\ImageFactory $image_factory */
|
||||
$image_factory = $this->container->get('image.factory');
|
||||
foreach ($this->drupalGetTestFiles('image') as $image) {
|
||||
/** @var \Drupal\Core\Image\ImageInterface $image_file */
|
||||
$image_file = $image_factory->get($image->uri);
|
||||
if ($image_file->getWidth() < 50 || $image_file->getWidth() > 100 ) {
|
||||
$invalid_image = $image;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->assertTrue($invalid_image);
|
||||
$this->uploadImage($invalid_image, $node->id(), $this->fieldName, $node->language()->getId());
|
||||
$this->assertText('main_error', t('Invalid upload returned errors.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads an image using the image module's Quick Edit route.
|
||||
*
|
||||
* @param object $image
|
||||
* The image to upload.
|
||||
* @param int $nid
|
||||
* The target node ID.
|
||||
* @param string $field_name
|
||||
* The target field machine name.
|
||||
* @param string $langcode
|
||||
* The langcode to use when setting the field's value.
|
||||
*
|
||||
* @return mixed
|
||||
* The content returned from the call to $this->curlExec().
|
||||
*/
|
||||
public function uploadImage($image, $nid, $field_name, $langcode) {
|
||||
$filepath = $this->container->get('file_system')->realpath($image->uri);
|
||||
$data = [
|
||||
'files[image]' => curl_file_create($filepath),
|
||||
];
|
||||
$path = 'quickedit/image/upload/node/' . $nid . '/' . $field_name . '/' . $langcode . '/default';
|
||||
// We assemble the curl request ourselves as drupalPost cannot process file
|
||||
// uploads, and drupalPostForm only works with typical Drupal forms.
|
||||
return $this->curlExec([
|
||||
CURLOPT_URL => $this->buildUrl($path, []),
|
||||
CURLOPT_POST => TRUE,
|
||||
CURLOPT_POSTFIELDS => $data,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Accept: application/json',
|
||||
'Content-Type: multipart/form-data',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Tests\Update;
|
||||
|
||||
use Drupal\system\Tests\Update\UpdatePathTestBase;
|
||||
|
||||
/**
|
||||
* Tests Image update path.
|
||||
*
|
||||
* @group image
|
||||
*/
|
||||
class ImageUpdateTest extends UpdatePathTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setDatabaseDumpFiles() {
|
||||
$this->databaseDumpFiles = [
|
||||
__DIR__ . '/../../../../system/tests/fixtures/update/drupal-8-rc1.bare.standard.php.gz',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests image_post_update_image_style_dependencies().
|
||||
*
|
||||
* @see image_post_update_image_style_dependencies()
|
||||
*/
|
||||
public function testPostUpdateImageStylesDependencies() {
|
||||
$view = 'core.entity_view_display.node.article.default';
|
||||
$form = 'core.entity_form_display.node.article.default';
|
||||
|
||||
// Check that view display 'node.article.default' doesn't depend on image
|
||||
// style 'image.style.large'.
|
||||
$dependencies = $this->config($view)->get('dependencies.config');
|
||||
$this->assertFalse(in_array('image.style.large', $dependencies));
|
||||
// Check that form display 'node.article.default' doesn't depend on image
|
||||
// style 'image.style.thumbnail'.
|
||||
$dependencies = $this->config($form)->get('dependencies.config');
|
||||
$this->assertFalse(in_array('image.style.thumbnail', $dependencies));
|
||||
|
||||
// Run updates.
|
||||
$this->runUpdates();
|
||||
|
||||
// Check that view display 'node.article.default' depend on image style
|
||||
// 'image.style.large'.
|
||||
$dependencies = $this->config($view)->get('dependencies.config');
|
||||
$this->assertTrue(in_array('image.style.large', $dependencies));
|
||||
// Check that form display 'node.article.default' depend on image style
|
||||
// 'image.style.thumbnail'.
|
||||
$dependencies = $this->config($view)->get('dependencies.config');
|
||||
$this->assertTrue(in_array('image.style.large', $dependencies));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\image\Tests\Views;
|
||||
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\views\Tests\ViewTestBase;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests image on user relationship handler.
|
||||
*
|
||||
* @group image
|
||||
*/
|
||||
class RelationshipUserImageDataTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['image', 'image_test_views', 'user'];
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_image_user_image_data'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create the user profile field and instance.
|
||||
FieldStorageConfig::create([
|
||||
'entity_type' => 'user',
|
||||
'field_name' => 'user_picture',
|
||||
'type' => 'image',
|
||||
'translatable' => '0',
|
||||
])->save();
|
||||
FieldConfig::create([
|
||||
'label' => 'User Picture',
|
||||
'description' => '',
|
||||
'field_name' => 'user_picture',
|
||||
'entity_type' => 'user',
|
||||
'bundle' => 'user',
|
||||
'required' => 0,
|
||||
])->save();
|
||||
|
||||
ViewTestData::createTestViews(get_class($this), ['image_test_views']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests using the views image relationship.
|
||||
*/
|
||||
public function testViewsHandlerRelationshipUserImageData() {
|
||||
$file = File::create([
|
||||
'fid' => 2,
|
||||
'uid' => 2,
|
||||
'filename' => 'image-test.jpg',
|
||||
'uri' => "public://image-test.jpg",
|
||||
'filemime' => 'image/jpeg',
|
||||
'created' => 1,
|
||||
'changed' => 1,
|
||||
'status' => FILE_STATUS_PERMANENT,
|
||||
]);
|
||||
$file->enforceIsNew();
|
||||
file_put_contents($file->getFileUri(), file_get_contents('core/modules/simpletest/files/image-1.png'));
|
||||
$file->save();
|
||||
|
||||
$account = $this->drupalCreateUser();
|
||||
$account->user_picture->target_id = 2;
|
||||
$account->save();
|
||||
|
||||
$view = Views::getView('test_image_user_image_data');
|
||||
// Tests \Drupal\taxonomy\Plugin\views\relationship\NodeTermData::calculateDependencies().
|
||||
$expected = [
|
||||
'module' => [
|
||||
'file',
|
||||
'user',
|
||||
],
|
||||
];
|
||||
$this->assertIdentical($expected, $view->getDependencies());
|
||||
$this->executeView($view);
|
||||
$expected_result = [
|
||||
[
|
||||
'file_managed_user__user_picture_fid' => '2',
|
||||
],
|
||||
];
|
||||
$column_map = ['file_managed_user__user_picture_fid' => 'file_managed_user__user_picture_fid'];
|
||||
$this->assertIdenticalResultset($view, $expected_result, $column_map);
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue