Initial Drupal 11 with DDEV setup

This commit is contained in:
gluebox
2025-10-08 11:39:17 -04:00
commit 89ef74b305
25344 changed files with 2599172 additions and 0 deletions

View File

@ -0,0 +1,5 @@
name: 'Image access test for hidden fields'
type: module
description: 'Provides an entity field access hook implementation to set an image field as hidden.'
package: Testing
version: VERSION

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Drupal\image_access_test_hidden\Hook;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Hook\Attribute\Hook;
/**
* Hook implementations for image_access_test_hidden.
*/
class ImageAccessTestHiddenHooks {
/**
* Implements hook_entity_field_access().
*/
#[Hook('entity_field_access')]
public function entityFieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, ?FieldItemListInterface $items = NULL): AccessResultInterface {
if ($field_definition->getName() == 'field_image' && $operation == 'edit') {
return AccessResult::forbidden();
}
return AccessResult::neutral();
}
}

View File

@ -0,0 +1,5 @@
name: 'Image field property constraint validation'
type: module
description: 'Testing module with a constraint for image alt property'
package: Testing
version: VERSION

View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace Drupal\image_field_property_constraint_validation\Hook;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Hook\Attribute\Hook;
/**
* Hook implementations for image_field_property_constraint_validation.
*/
class ImagePropertyConstraintValidationHooks {
/**
* Implements hook_entity_bundle_field_info_alter().
*/
#[Hook('entity_bundle_field_info_alter')]
public function entityBundleFieldInfoAlter(&$fields, EntityTypeInterface $entity_type, $bundle): void {
if ($entity_type->id() == 'node' && !empty($fields['field_image'])) {
/** @var \Drupal\field\Entity\FieldConfig[] $fields */
$fields['field_image']->addPropertyConstraints('alt', ['AltTextContainsLlamas' => []]);
}
}
}

View File

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Drupal\image_field_property_constraint_validation\Plugin\Validation\Constraint;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Validation\Attribute\Constraint;
use Symfony\Component\Validator\Constraint as SymfonyConstraint;
/**
* Provides a Contains Llamas constraint.
*/
#[Constraint(
id: 'AltTextContainsLlamas',
label: new TranslatableMarkup('Contains Llamas', options: ['context' => 'Validation'])
)]
final class AltTextContainsLlamasConstraint extends SymfonyConstraint {
/**
* The error message.
*
* @var string
*/
public string $message = 'Alternative text must contain some llamas.';
}

View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace Drupal\image_field_property_constraint_validation\Plugin\Validation\Constraint;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* Validates the alt text contains llamas.
*/
final class AltTextContainsLlamasConstraintValidator extends ConstraintValidator {
/**
* {@inheritdoc}
*/
public function validate(mixed $value, Constraint $constraint): void {
if (is_string($value) && !str_contains(strtolower($value), 'llamas')) {
$this->context->buildViolation($constraint->message)
->setInvalidValue($value)
->addViolation();
}
}
}

View File

@ -0,0 +1,15 @@
image.effect.image_module_test_ajax:
type: mapping
label: 'Ajax test'
mapping:
test_parameter:
type: integer
label: 'Test Parameter'
image.style.*.third_party.image_module_test:
type: mapping
label: 'Schema for image_module_test module additions to image_style entity'
mapping:
foo:
type: string
label: 'Label for foo'

View File

@ -0,0 +1,5 @@
name: 'Image test'
type: module
description: 'Provides hook implementations for testing Image module functionality.'
package: Testing
version: VERSION

View File

@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace Drupal\image_module_test\Hook;
use Drupal\image\ImageStyleInterface;
use Drupal\Core\Hook\Attribute\Hook;
/**
* Hook implementations for image_module_test.
*/
class ImageModuleTestHooks {
/**
* Implements hook_image_effect_info_alter().
*/
#[Hook('image_effect_info_alter')]
public function imageEffectInfoAlter(&$effects): void {
$state = \Drupal::state();
// The 'image_module_test.counter' state variable value is set and accessed
// from the ImageEffectsTest::testImageEffectsCaching() test and used to
// signal if the image effect plugin definitions were computed or were
// retrieved from the cache.
// @see \Drupal\Tests\image\Kernel\ImageEffectsTest::testImageEffectsCaching()
$counter = $state->get('image_module_test.counter');
// Increase the test counter, signaling that image effects were processed,
// rather than being served from the cache.
$state->set('image_module_test.counter', ++$counter);
}
/**
* Implements hook_ENTITY_TYPE_presave().
*
* Used to save test third party settings in the image style entity.
*/
#[Hook('image_style_presave')]
public function imageStylePresave(ImageStyleInterface $style): void {
$style->setThirdPartySetting('image_module_test', 'foo', 'bar');
}
/**
* Implements hook_image_style_flush().
*/
#[Hook('image_style_flush')]
public function imageStyleFlush($style, $path = NULL): void {
$state = \Drupal::state();
$state->set('image_module_test_image_style_flush.called', $path);
}
/**
* Implements hook_file_download().
*/
#[Hook('file_download')]
public function fileDownload($uri): array {
$default_uri = \Drupal::keyValue('image')->get('test_file_download', FALSE);
if ($default_uri == $uri) {
return ['X-Image-Owned-By' => 'image_module_test'];
}
return [];
}
}

View File

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace Drupal\image_module_test\Plugin\Field\FieldFormatter;
use Drupal\Core\Field\Attribute\FieldFormatter;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Empty renderer for a dummy field with an AJAX handler.
*/
#[FieldFormatter(
id: 'image_module_test_dummy_ajax_formatter',
label: new TranslatableMarkup('Dummy AJAX'),
field_types: [
'image_module_test_dummy_ajax',
],
)]
class DummyAjaxFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$summary = [];
$summary[] = $this->t('Renders nothing');
return $summary;
}
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$element = [];
return $element;
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Drupal\image_module_test\Plugin\Field\FieldFormatter;
use Drupal\Core\Field\Attribute\FieldFormatter;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Plugin implementation of the Dummy image formatter.
*/
#[FieldFormatter(
id: 'dummy_image_formatter',
label: new TranslatableMarkup('Dummy image'),
field_types: [
'image',
],
)]
class DummyImageFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
return [
['#markup' => 'Dummy'],
];
}
}

View File

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace Drupal\image_module_test\Plugin\Field\FieldType;
use Drupal\Core\Field\Attribute\FieldType;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\TypedData\DataDefinition;
/**
* Defines a dummy field containing an AJAX handler.
*/
#[FieldType(
id: "image_module_test_dummy_ajax",
label: new TranslatableMarkup("Dummy AJAX"),
description: new TranslatableMarkup("A field containing an AJAX handler."),
default_widget: "image_module_test_dummy_ajax_widget",
default_formatter: "image_module_test_dummy_ajax_formatter"
)]
class DummyAjaxItem extends FieldItemBase {
/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition) {
return [
'columns' => [
'value' => [
'type' => 'varchar',
'length' => 255,
],
],
];
}
/**
* {@inheritdoc}
*/
public function isEmpty() {
return empty($this->get('value')->getValue());
}
/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
$properties['value'] = DataDefinition::create('string')
->setLabel(new TranslatableMarkup('Dummy string value'));
return $properties;
}
}

View File

@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace Drupal\image_module_test\Plugin\Field\FieldWidget;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Field\Attribute\FieldWidget;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Default widget for Dummy AJAX test.
*/
#[FieldWidget(
id: 'image_module_test_dummy_ajax_widget',
label: new TranslatableMarkup('Dummy AJAX widget'),
field_types: ['image_module_test_dummy_ajax'],
multiple_values: TRUE,
)]
class DummyAjaxWidget extends WidgetBase {
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$element['select_widget'] = [
'#type' => 'select',
'#title' => $this->t('Dummy select'),
'#options' => ['pow' => 'Pow!', 'bam' => 'Bam!'],
'#required' => TRUE,
'#ajax' => [
'callback' => static::class . '::dummyAjaxCallback',
'effect' => 'fade',
],
];
return $element;
}
/**
* Ajax callback for Dummy AJAX test.
*
* @param array $form
* The build form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*
* @return \Drupal\Core\Ajax\AjaxResponse
* Ajax response.
*/
public static function dummyAjaxCallback(array &$form, FormStateInterface $form_state) {
return new AjaxResponse();
}
}

View File

@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
namespace Drupal\image_module_test\Plugin\ImageEffect;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Image\ImageInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\image\Attribute\ImageEffect;
use Drupal\image\ConfigurableImageEffectBase;
/**
* Provides a test effect using Ajax in the configuration form.
*/
#[ImageEffect(
id: "image_module_test_ajax",
label: new TranslatableMarkup("Ajax test")
)]
class AjaxTestImageEffect extends ConfigurableImageEffectBase {
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return [
'test_parameter' => 0,
];
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form['test_parameter'] = [
'#type' => 'number',
'#title' => $this->t('Test parameter'),
'#default_value' => $this->configuration['test_parameter'],
'#min' => 0,
];
$form['ajax_refresh'] = [
'#type' => 'button',
'#value' => $this->t('Ajax refresh'),
'#ajax' => ['callback' => [$this, 'ajaxCallback']],
];
$form['ajax_value'] = [
'#id' => 'ajax-value',
'#type' => 'item',
'#title' => $this->t('Ajax value'),
'#markup' => 'bar',
];
return $form;
}
/**
* AJAX callback.
*/
public function ajaxCallback($form, FormStateInterface $form_state) {
$item = [
'#type' => 'item',
'#title' => $this->t('Ajax value'),
'#markup' => microtime(),
];
$response = new AjaxResponse();
$response->addCommand(new HtmlCommand('#ajax-value', $item));
return $response;
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
$this->configuration['test_parameter'] = $form_state->getValue('test_parameter');
}
/**
* {@inheritdoc}
*/
public function applyEffect(ImageInterface $image) {
return TRUE;
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Drupal\image_module_test\Plugin\ImageEffect;
use Drupal\Core\Image\ImageInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\image\Attribute\ImageEffect;
use Drupal\image\ImageEffectBase;
/**
* Performs no operation on an image resource.
*/
#[ImageEffect(
id: "image_module_test_null",
label: new TranslatableMarkup("Image module test")
)]
class NullTestImageEffect extends ImageEffectBase {
/**
* {@inheritdoc}
*/
public function transformDimensions(array &$dimensions, $uri) {
// Unset image dimensions.
$dimensions['width'] = $dimensions['height'] = NULL;
}
/**
* {@inheritdoc}
*/
public function applyEffect(ImageInterface $image) {
return TRUE;
}
}

View File

@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace Drupal\image_module_test\Plugin\ImageEffect;
use Drupal\Core\Image\ImageInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\image\Attribute\ImageEffect;
use Drupal\image\ImageEffectBase;
/**
* Performs an image operation that depends on the URI of the original image.
*/
#[ImageEffect(
id: "image_module_test_uri_dependent",
label: new TranslatableMarkup("URI dependent test image effect")
)]
class UriDependentTestImageEffect extends ImageEffectBase {
/**
* {@inheritdoc}
*/
public function transformDimensions(array &$dimensions, $uri) {
$dimensions = $this->getUriDependentDimensions($uri);
}
/**
* {@inheritdoc}
*/
public function applyEffect(ImageInterface $image) {
$dimensions = $this->getUriDependentDimensions($image->getSource());
return $image->resize($dimensions['width'], $dimensions['height']);
}
/**
* Make the image dimensions dependent on the image file extension.
*
* @param string $uri
* Original image file URI.
*
* @return array
* Associative array.
* - width: Integer with the derivative image width.
* - height: Integer with the derivative image height.
*/
protected function getUriDependentDimensions($uri) {
$dimensions = [];
$extension = pathinfo($uri, PATHINFO_EXTENSION);
switch (strtolower($extension)) {
case 'png':
$dimensions['width'] = $dimensions['height'] = 100;
break;
case 'gif':
$dimensions['width'] = $dimensions['height'] = 50;
break;
default:
$dimensions['width'] = $dimensions['height'] = 20;
break;
}
return $dimensions;
}
}

View File

@ -0,0 +1,8 @@
name: 'Image test views'
type: module
description: 'Provides default views for views image tests.'
package: Testing
version: VERSION
dependencies:
- drupal:image
- drupal:views

View File

@ -0,0 +1,77 @@
langcode: en
status: true
dependencies:
module:
- file
- user
id: test_image_user_image_data
label: test_image_user_image_data
module: views
description: ''
tag: ''
base_table: users_field_data
base_field: uid
display:
default:
display_plugin: default
id: default
display_title: Default
position: 0
display_options:
access:
type: perm
options:
perm: 'access user profiles'
cache:
type: tag
style:
type: table
options:
grouping: { }
class: ''
row_class: ''
default_row_class: true
override: true
sticky: false
caption: ''
summary: ''
description: ''
columns:
name: name
fid: fid
info:
name:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
fid:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
default: '-1'
empty_table: false
row:
type: fields
options:
inline: { }
separator: ''
hide_empty: false
default_field_elements: true
relationships:
user_picture_target_id:
id: user_picture_target_id
table: user__user_picture
field: user_picture_target_id
relationship: none
group_type: group
admin_label: 'image from user_picture'
required: true
plugin_id: standard
arguments: { }
display_extenders: { }