1608 lines
57 KiB
Diff
1608 lines
57 KiB
Diff
From a3b983a44de65ceb4f0c0347136cca29b3f03349 Mon Sep 17 00:00:00 2001
|
|
From: Dieter Holvoet <dieter.holvoet@gmail.com>
|
|
Date: Mon, 9 Sep 2024 11:26:03 +0200
|
|
Subject: [PATCH 1/4] Rewrite module to use default field storage
|
|
|
|
---
|
|
image_field_caption.info.yml | 3 +-
|
|
image_field_caption.install | 376 +++++++++-------
|
|
image_field_caption.module | 307 +++----------
|
|
image_field_caption.services.yml | 7 -
|
|
src/ImageCaptionItem.php | 104 ++++-
|
|
src/ImageCaptionStorage.php | 425 ------------------
|
|
.../FieldFormatter/ImageCaptionFormatter.php | 2 +
|
|
7 files changed, 355 insertions(+), 869 deletions(-)
|
|
delete mode 100644 image_field_caption.services.yml
|
|
delete mode 100644 src/ImageCaptionStorage.php
|
|
|
|
diff --git a/image_field_caption.info.yml b/image_field_caption.info.yml
|
|
index 17d7bf9..e04a8e9 100644
|
|
--- a/image_field_caption.info.yml
|
|
+++ b/image_field_caption.info.yml
|
|
@@ -2,4 +2,5 @@ name: Image Field Caption
|
|
description: 'Provides a caption textarea for image fields.'
|
|
package: Other
|
|
type: module
|
|
-core_version_requirement: ^9 || ^10
|
|
+core_version_requirement: ^9.2 || ^10
|
|
+php: 7.1
|
|
diff --git a/image_field_caption.install b/image_field_caption.install
|
|
index 92e9220..63a974b 100644
|
|
--- a/image_field_caption.install
|
|
+++ b/image_field_caption.install
|
|
@@ -1,172 +1,222 @@
|
|
<?php
|
|
|
|
+use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
|
|
+use Drupal\Core\Entity\Sql\SqlContentEntityStorageException;
|
|
+
|
|
/**
|
|
- * @file
|
|
- * Install, update and uninstall functions for the image caption module.
|
|
+ * Implements hook_install().
|
|
*/
|
|
+function image_field_caption_install(): void {
|
|
+ _image_field_caption_field_type_schema_column_add_helper('image', ['caption', 'caption_format']);
|
|
+}
|
|
|
|
/**
|
|
- * Implements hook_schema().
|
|
+ * Implements hook_uninstall().
|
|
*/
|
|
-function image_field_caption_schema() {
|
|
- // Image Field Caption table.
|
|
- $schema['image_field_caption'] = [
|
|
- 'description' => 'The base table for the image_field_caption module.',
|
|
- 'fields' => [
|
|
- 'entity_type' => [
|
|
- 'description' => 'The entity type attached to this caption',
|
|
- 'type' => 'varchar',
|
|
- 'length' => 128,
|
|
- 'not null' => TRUE,
|
|
- 'default' => '',
|
|
- ],
|
|
- 'bundle' => [
|
|
- 'description' => 'The bundle attached to this caption',
|
|
- 'type' => 'varchar',
|
|
- 'length' => 128,
|
|
- 'not null' => TRUE,
|
|
- 'default' => '',
|
|
- ],
|
|
- 'field_name' => [
|
|
- 'description' => 'The field name attached to this caption',
|
|
- 'type' => 'varchar',
|
|
- 'length' => 32,
|
|
- 'not null' => TRUE,
|
|
- 'default' => '',
|
|
- ],
|
|
- 'entity_id' => [
|
|
- 'description' => 'The entity id attached to this caption',
|
|
- 'type' => 'int',
|
|
- 'unsigned' => TRUE,
|
|
- 'not null' => TRUE,
|
|
- ],
|
|
- 'revision_id' => [
|
|
- 'description' => 'The entity id attached to this caption, or NULL if the entity type is not versioned',
|
|
- 'type' => 'int',
|
|
- 'unsigned' => TRUE,
|
|
- 'not null' => FALSE,
|
|
- ],
|
|
- 'language' => [
|
|
- 'description' => 'The language attached to this caption',
|
|
- 'type' => 'varchar',
|
|
- 'length' => 32,
|
|
- 'not null' => TRUE,
|
|
- 'default' => '',
|
|
- ],
|
|
- 'delta' => [
|
|
- 'description' => 'The sequence number for this caption, used for multi-value fields',
|
|
- 'type' => 'int',
|
|
- 'unsigned' => TRUE,
|
|
- 'not null' => TRUE,
|
|
- ],
|
|
- 'caption' => [
|
|
- 'description' => 'The caption text.',
|
|
- 'type' => 'text',
|
|
- 'not null' => FALSE,
|
|
- ],
|
|
- 'caption_format' => [
|
|
- 'description' => 'The caption format.',
|
|
- 'type' => 'varchar',
|
|
- 'length' => 255,
|
|
- 'not null' => FALSE,
|
|
- ],
|
|
- ],
|
|
- 'indexes' => [
|
|
- 'entity_type' => ['entity_type'],
|
|
- 'bundle' => ['bundle'],
|
|
- 'entity_id' => ['entity_id'],
|
|
- 'revision_id' => ['revision_id'],
|
|
- 'language' => ['language'],
|
|
- ],
|
|
- 'primary key' => [
|
|
- 'entity_type',
|
|
- 'field_name',
|
|
- 'entity_id',
|
|
- 'language',
|
|
- 'delta',
|
|
- ],
|
|
- ];
|
|
-
|
|
- // Image Field Caption revision table.
|
|
- $schema['image_field_caption_revision'] = [
|
|
- 'description' => 'The revision table for the image_field_caption module.',
|
|
- 'fields' => [
|
|
- 'entity_type' => [
|
|
- 'description' => 'The entity type attached to this caption',
|
|
- 'type' => 'varchar',
|
|
- 'length' => 128,
|
|
- 'not null' => TRUE,
|
|
- 'default' => '',
|
|
- ],
|
|
- 'bundle' => [
|
|
- 'description' => 'The bundle attached to this caption',
|
|
- 'type' => 'varchar',
|
|
- 'length' => 128,
|
|
- 'not null' => TRUE,
|
|
- 'default' => '',
|
|
- ],
|
|
- 'field_name' => [
|
|
- 'description' => 'The field name attached to this caption',
|
|
- 'type' => 'varchar',
|
|
- 'length' => 32,
|
|
- 'not null' => TRUE,
|
|
- 'default' => '',
|
|
- ],
|
|
- 'entity_id' => [
|
|
- 'description' => 'The entity id attached to this caption',
|
|
- 'type' => 'int',
|
|
- 'unsigned' => TRUE,
|
|
- 'not null' => TRUE,
|
|
- ],
|
|
- 'revision_id' => [
|
|
- 'description' => 'The entity id attached to this caption, or NULL if the entity type is not versioned',
|
|
- 'type' => 'int',
|
|
- 'unsigned' => TRUE,
|
|
- 'not null' => TRUE,
|
|
- ],
|
|
- 'language' => [
|
|
- 'description' => 'The language attached to this caption',
|
|
- 'type' => 'varchar',
|
|
- 'length' => 32,
|
|
- 'not null' => TRUE,
|
|
- 'default' => '',
|
|
- ],
|
|
- 'delta' => [
|
|
- 'description' => 'The sequence number for this caption, used for multi-value fields',
|
|
- 'type' => 'int',
|
|
- 'unsigned' => TRUE,
|
|
- 'not null' => TRUE,
|
|
- ],
|
|
- 'caption' => [
|
|
- 'description' => 'The caption text.',
|
|
- 'type' => 'text',
|
|
- 'not null' => FALSE,
|
|
- ],
|
|
- 'caption_format' => [
|
|
- 'description' => 'The caption format.',
|
|
- 'type' => 'varchar',
|
|
- 'length' => 255,
|
|
- 'not null' => FALSE,
|
|
- ],
|
|
- ],
|
|
- 'indexes' => [
|
|
- 'entity_type' => ['entity_type'],
|
|
- 'bundle' => ['bundle'],
|
|
- 'entity_id' => ['entity_id'],
|
|
- 'revision_id' => ['revision_id'],
|
|
- 'language' => ['language'],
|
|
- ],
|
|
- 'primary key' => [
|
|
- 'entity_type',
|
|
- 'field_name',
|
|
- 'entity_id',
|
|
- 'revision_id',
|
|
- 'language',
|
|
- 'delta',
|
|
- ],
|
|
- ];
|
|
-
|
|
- return $schema;
|
|
+function image_field_caption_uninstall(): void {
|
|
+ _image_field_caption_field_type_schema_column_remove_helper('image', ['caption', 'caption_format']);
|
|
}
|
|
|
|
-/* @todo Programmatically set the default formatter for all fields that uses this field formatter using image_field_caption_uninstall(). */
|
|
+/**
|
|
+ * Helper function to add new columns to a field type.
|
|
+ *
|
|
+ * @param $field_type
|
|
+ * The field type id.
|
|
+ * @param array $columns_to_add
|
|
+ * array of the column names from schema() function.
|
|
+ *
|
|
+ * @see https://gist.github.com/JPustkuchen/ce53d40303a51ca5f17ce7f48c363b9b
|
|
+ * @see https://www.drupal.org/project/drupal/issues/937442
|
|
+ */
|
|
+function _image_field_caption_field_type_schema_column_add_helper(string $field_type, array $columns_to_add = []): void {
|
|
+ $processed_fields = [];
|
|
+ $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
|
|
+ $field_definition = $field_type_manager->getDefinition($field_type);
|
|
+ $field_item_class = $field_definition['class'];
|
|
+
|
|
+ $schema = \Drupal::database()->schema();
|
|
+ $entity_type_manager = \Drupal::entityTypeManager();
|
|
+ $entity_field_manager = \Drupal::service('entity_field.manager');
|
|
+ $entity_field_map = $entity_field_manager->getFieldMapByFieldType($field_type);
|
|
+ // The key-value collection for tracking installed storage schema.
|
|
+ $entity_storage_schema_sql = \Drupal::keyValue('entity.storage_schema.sql');
|
|
+ $entity_definitions_installed = \Drupal::keyValue('entity.definitions.installed');
|
|
+
|
|
+ foreach ($entity_field_map as $entity_type_id => $field_map) {
|
|
+ $entity_storage = $entity_type_manager->getStorage($entity_type_id);
|
|
+
|
|
+ // Only SQL storage based entities are supported / throw known exception.
|
|
+ if (!($entity_storage instanceof SqlContentEntityStorage)) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ $entity_type = $entity_type_manager->getDefinition($entity_type_id);
|
|
+ $field_storage_definitions = $entity_field_manager->getFieldStorageDefinitions($entity_type_id);
|
|
+ /** @var Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
|
|
+ $table_mapping = $entity_storage->getTableMapping($field_storage_definitions);
|
|
+ // Only need field storage definitions of our field type:
|
|
+ /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface $field_storage_definition */
|
|
+ foreach (array_intersect_key($field_storage_definitions, $field_map) as $field_storage_definition) {
|
|
+ $field_name = $field_storage_definition->getName();
|
|
+ try {
|
|
+ $table = $table_mapping->getFieldTableName($field_name);
|
|
+ } catch (SqlContentEntityStorageException $e) {
|
|
+ // Custom storage? Broken site? No matter what, if there is no table
|
|
+ // or column, there's little we can do.
|
|
+ continue;
|
|
+ }
|
|
+ // See if the field has a revision table.
|
|
+ $revision_table = NULL;
|
|
+ if ($entity_type->isRevisionable() && $field_storage_definition->isRevisionable()) {
|
|
+ if ($table_mapping->requiresDedicatedTableStorage($field_storage_definition)) {
|
|
+ $revision_table = $table_mapping->getDedicatedRevisionTableName($field_storage_definition);
|
|
+ }
|
|
+ elseif ($table_mapping->allowsSharedTableStorage($field_storage_definition)) {
|
|
+ $revision_table = $entity_type->getRevisionDataTable() ?: $entity_type->getRevisionTable();
|
|
+ }
|
|
+ }
|
|
+ // Load the installed field schema so that it can be updated.
|
|
+ $schema_key = "$entity_type_id.field_schema_data.$field_name";
|
|
+ $field_schema_data = $entity_storage_schema_sql->get($schema_key);
|
|
+
|
|
+ $processed_fields[] = [$entity_type_id, $field_name];
|
|
+ // Loop over each new column and add it as a schema column change.
|
|
+ foreach ($columns_to_add as $column_id) {
|
|
+ $column = $table_mapping->getFieldColumnName($field_storage_definition, $column_id);
|
|
+ // Add `initial_from_field` to the new spec, as this will copy over
|
|
+ // the entire data.
|
|
+ $field_schema = $field_item_class::schema($field_storage_definition);
|
|
+ $spec = $field_schema['columns'][$column_id];
|
|
+
|
|
+ // Add the new column.
|
|
+ $schema->addField($table, $column, $spec);
|
|
+ if ($revision_table) {
|
|
+ $schema->addField($revision_table, $column, $spec);
|
|
+ }
|
|
+
|
|
+ // Add the new column to the installed field schema.
|
|
+ if (!empty($field_schema_data)) {
|
|
+ $field_schema_data[$table]['fields'][$column] = $field_schema['columns'][$column_id];
|
|
+ $field_schema_data[$table]['fields'][$column]['not null'] = FALSE;
|
|
+ if ($revision_table) {
|
|
+ $field_schema_data[$revision_table]['fields'][$column] = $field_schema['columns'][$column_id];
|
|
+ $field_schema_data[$revision_table]['fields'][$column]['not null'] = FALSE;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Save changes to the installed field schema.
|
|
+ if (!empty($field_schema_data)) {
|
|
+ $entity_storage_schema_sql->set($schema_key, $field_schema_data);
|
|
+ }
|
|
+ if ($table_mapping->allowsSharedTableStorage($field_storage_definition)) {
|
|
+ $key = "$entity_type_id.field_storage_definitions";
|
|
+ if ($definitions = $entity_definitions_installed->get($key)) {
|
|
+ $definitions[$field_name] = $field_storage_definition;
|
|
+ $entity_definitions_installed->set($key, $definitions);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Helper function to remove columns from a field type.
|
|
+ *
|
|
+ * @param $field_type
|
|
+ * The field type id.
|
|
+ * @param array $columns_to_remove
|
|
+ * array of the column names from schema() function.
|
|
+ *
|
|
+ * @see https://gist.github.com/JPustkuchen/ce53d40303a51ca5f17ce7f48c363b9b
|
|
+ * @see https://www.drupal.org/project/drupal/issues/937442
|
|
+ */
|
|
+function _image_field_caption_field_type_schema_column_remove_helper(string $field_type, array $columns_to_remove = []): void {
|
|
+ $processed_fields = [];
|
|
+ $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
|
|
+ $field_definition = $field_type_manager->getDefinition($field_type);
|
|
+ $field_item_class = $field_definition['class'];
|
|
+
|
|
+ $schema = \Drupal::database()->schema();
|
|
+ $entity_type_manager = \Drupal::entityTypeManager();
|
|
+ $entity_field_manager = \Drupal::service('entity_field.manager');
|
|
+ $entity_field_map = $entity_field_manager->getFieldMapByFieldType($field_type);
|
|
+ // The key-value collection for tracking installed storage schema.
|
|
+ $entity_storage_schema_sql = \Drupal::keyValue('entity.storage_schema.sql');
|
|
+ $entity_definitions_installed = \Drupal::keyValue('entity.definitions.installed');
|
|
+
|
|
+ foreach ($entity_field_map as $entity_type_id => $field_map) {
|
|
+ $entity_storage = $entity_type_manager->getStorage($entity_type_id);
|
|
+
|
|
+ // Only SQL storage based entities are supported / throw known exception.
|
|
+ if (!($entity_storage instanceof SqlContentEntityStorage)) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ $entity_type = $entity_type_manager->getDefinition($entity_type_id);
|
|
+ $field_storage_definitions = $entity_field_manager->getFieldStorageDefinitions($entity_type_id);
|
|
+ /** @var Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
|
|
+ $table_mapping = $entity_storage->getTableMapping($field_storage_definitions);
|
|
+ // Only need field storage definitions of our field type:
|
|
+ /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface $field_storage_definition */
|
|
+ foreach (array_intersect_key($field_storage_definitions, $field_map) as $field_storage_definition) {
|
|
+ $field_name = $field_storage_definition->getName();
|
|
+ try {
|
|
+ $table = $table_mapping->getFieldTableName($field_name);
|
|
+ } catch (SqlContentEntityStorageException $e) {
|
|
+ // Custom storage? Broken site? No matter what, if there is no table
|
|
+ // or column, there's little we can do.
|
|
+ continue;
|
|
+ }
|
|
+ // See if the field has a revision table.
|
|
+ $revision_table = NULL;
|
|
+ if ($entity_type->isRevisionable() && $field_storage_definition->isRevisionable()) {
|
|
+ if ($table_mapping->requiresDedicatedTableStorage($field_storage_definition)) {
|
|
+ $revision_table = $table_mapping->getDedicatedRevisionTableName($field_storage_definition);
|
|
+ }
|
|
+ elseif ($table_mapping->allowsSharedTableStorage($field_storage_definition)) {
|
|
+ $revision_table = $entity_type->getRevisionDataTable() ?: $entity_type->getRevisionTable();
|
|
+ }
|
|
+ }
|
|
+ // Load the installed field schema so that it can be updated.
|
|
+ $schema_key = "$entity_type_id.field_schema_data.$field_name";
|
|
+ $field_schema_data = $entity_storage_schema_sql->get($schema_key);
|
|
+
|
|
+ $processed_fields[] = [$entity_type_id, $field_name];
|
|
+ // Loop over each new column and add it as a schema column change.
|
|
+ foreach ($columns_to_remove as $column_id) {
|
|
+ $column = $table_mapping->getFieldColumnName($field_storage_definition, $column_id);
|
|
+ // Add `initial_from_field` to the new spec, as this will copy over
|
|
+ // the entire data.
|
|
+ $field_schema = $field_item_class::schema($field_storage_definition);
|
|
+ $spec = $field_schema['columns'][$column_id];
|
|
+
|
|
+ // Add the new column.
|
|
+ $schema->dropField($table, $column);
|
|
+ if ($revision_table) {
|
|
+ $schema->dropField($revision_table, $column);
|
|
+ }
|
|
+
|
|
+ // Remove the column from the installed field schema.
|
|
+ if (!empty($field_schema_data)) {
|
|
+ unset($field_schema_data[$table]['fields'][$column]);
|
|
+ if ($revision_table) {
|
|
+ unset($field_schema_data[$revision_table]['fields'][$column]);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Save changes to the installed field schema.
|
|
+ if (!empty($field_schema_data)) {
|
|
+ $entity_storage_schema_sql->set($schema_key, $field_schema_data);
|
|
+ }
|
|
+ if ($table_mapping->allowsSharedTableStorage($field_storage_definition)) {
|
|
+ $key = "$entity_type_id.field_storage_definitions";
|
|
+ if ($definitions = $entity_definitions_installed->get($key)) {
|
|
+ $definitions[$field_name] = $field_storage_definition;
|
|
+ $entity_definitions_installed->set($key, $definitions);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/image_field_caption.module b/image_field_caption.module
|
|
index d49aa67..63f8999 100644
|
|
--- a/image_field_caption.module
|
|
+++ b/image_field_caption.module
|
|
@@ -5,112 +5,72 @@
|
|
* Provides a caption textarea for image fields.
|
|
*/
|
|
|
|
-use Drupal\Core\Entity\EntityInterface;
|
|
-use Drupal\Core\Entity\FieldableEntityInterface;
|
|
use Drupal\Core\Field\FieldDefinitionInterface;
|
|
use Drupal\Core\Form\FormStateInterface;
|
|
-use Drupal\Component\Utility\NestedArray;
|
|
-
|
|
-/**
|
|
- * List to do.
|
|
- *
|
|
- * Support for Views, maybe built in in D8?
|
|
- * Support the revision management.
|
|
- * */
|
|
+use Drupal\image\Plugin\Field\FieldWidget\ImageWidget;
|
|
+use Drupal\image_field_caption\ImageCaptionItem;
|
|
|
|
/**
|
|
* Implements hook_field_info_alter().
|
|
*/
|
|
-function image_field_caption_field_info_alter(&$info) {
|
|
- // Set a new class for the image fields.
|
|
- $info['image']['class'] = '\Drupal\image_field_caption\ImageCaptionItem';
|
|
+function image_field_caption_field_info_alter(array &$info): void {
|
|
+ // Override the image field type class
|
|
+ $info['image']['class'] = ImageCaptionItem::class;
|
|
+
|
|
+ // Enable translation for the caption property
|
|
+ $info['image']['column_groups']['caption'] = [
|
|
+ 'label' => t('Caption'),
|
|
+ 'translatable' => TRUE,
|
|
+ ];
|
|
}
|
|
|
|
/**
|
|
* Implements hook_field_widget_single_element_form_alter().
|
|
*/
|
|
-function image_field_caption_field_widget_single_element_form_alter(&$element, FormStateInterface $form_state, $context) {
|
|
- /** @var \Drupal\field\Entity\FieldConfig $field */
|
|
+function image_field_caption_field_widget_single_element_form_alter(array &$element, FormStateInterface $form_state, $context): void {
|
|
$field = $context['items']->getFieldDefinition();
|
|
- // If the current field is an image field.
|
|
- if ($field->getType() == 'image') {
|
|
- // Get the current field settings.
|
|
- $settings = $field->getSettings();
|
|
- // Check if the current field has the caption.
|
|
- if (!empty($settings['caption_field'])) {
|
|
- $element['#caption_field_required'] = $settings['caption_field_required'];
|
|
- $element['#process'][] = '_image_field_caption_widget_process';
|
|
- }
|
|
+ assert($field instanceof FieldDefinitionInterface);
|
|
+
|
|
+ if ($field->getType() !== 'image') {
|
|
+ return;
|
|
}
|
|
+
|
|
+ $settings = $field->getSettings();
|
|
+ $element['#caption_field'] = $settings['caption_field'];
|
|
+ $element['#caption_field_required'] = $settings['caption_field_required'];
|
|
+ $element['#process'][] = '_image_field_caption_widget_process';
|
|
}
|
|
|
|
/**
|
|
* Custom callback function for the #process of an image field type.
|
|
*/
|
|
-function _image_field_caption_widget_process($element, &$form_state, $form) {
|
|
- // Get the entity.
|
|
- // $entity = $form_state->getFormObject()->getEntity();
|
|
- // // Get the fields definitions.
|
|
- // $field_definitions = $entity->getFieldDefinitions();
|
|
- // // Get the current field definition.
|
|
- // if (!empty($field_definitions[$element['#field_name']])) {
|
|
- // $field_definition = $field_definitions[$element['#field_name']];
|
|
- // }
|
|
- // elseif (!empty($field_definitions[$element['#field_parents'][0]])) {
|
|
- // $field_definition = $field_definitions[$element['#field_parents'][0]];
|
|
- // }
|
|
- // else {
|
|
- // $field_definition = NULL;
|
|
- // }.
|
|
- // Get the current field values (form state).
|
|
- $field_values = $form_state->getValues();
|
|
- // If the field has parents (ex: paragraphs) then get the nested values.
|
|
- if (!empty($element['#field_parents'])) {
|
|
- $field_values = NestedArray::getValue($field_values, $element['#field_parents']);
|
|
- }
|
|
- $field_value = (isset($field_values[$element['#field_name']][$element['#delta']]['image_field_caption'])) ? $field_values[$element['#field_name']][$element['#delta']]['image_field_caption'] : [];
|
|
+function _image_field_caption_widget_process(array $element, FormStateInterface $form_state, array $form): array {
|
|
+ $item = $element['#value'];
|
|
+ $item['fids'] = $element['fids']['#value'];
|
|
|
|
- // Add the additional caption fields.
|
|
- $element['image_field_caption'] = [
|
|
+ // TODO: Make #allowed_formats configurable.
|
|
+
|
|
+ $element['caption'] = [
|
|
'#title' => t('Caption'),
|
|
'#type' => 'text_format',
|
|
- '#value' => (!empty($field_value['value'])) ? $field_value['value'] : ((!empty($element['#value']['caption'])) ? $element['#value']['caption'] : []),
|
|
- '#default_value' => (!empty($element['#value']['caption'])) ? $element['#value']['caption'] : (!empty($element['#value']['image_field_caption']) ? $element['#value']['image_field_caption']['value'] : ''),
|
|
- '#access' => (bool) $element['#value']['fids'],
|
|
- '#format' => (!empty($field_value['format'])) ? $field_value['format'] : ((!empty($element['#value']['caption_format'])) ? $element['#value']['caption_format'] : 'plain_text'),
|
|
+ '#default_value' => $item['caption'] ?? '',
|
|
+ '#access' => $item['fids'] && $element['#caption_field'],
|
|
+ '#format' => $item['caption_format'] ?? 'plain_text',
|
|
'#required' => $element['#caption_field_required'],
|
|
- '#element_validate' => $element['#caption_field_required'] ? ['_image_field_caption_validate_required'] : [],
|
|
+ '#element_validate' => $element['#caption_field_required'] ? [[ImageWidget::class, 'validateRequiredFields']] : [],
|
|
];
|
|
|
|
return $element;
|
|
}
|
|
|
|
-/**
|
|
- * Validate callback for caption field, if the user wants them required.
|
|
- *
|
|
- * This is separated in a validate function instead of a #required flag to
|
|
- * avoid being validated on the process callback.
|
|
- */
|
|
-function _image_field_caption_validate_required($element, FormStateInterface $form_state) {
|
|
- // Only do validation if the function is triggered from other places than
|
|
- // the image process form.
|
|
- // Only do validation if the function is triggered from other places than
|
|
- // the image process form.
|
|
- $triggering_element = $form_state->getTriggeringElement();
|
|
- if (!empty($triggering_element['#submit']) && in_array('file_managed_file_submit', $triggering_element['#submit'], TRUE)) {
|
|
- $form_state->setLimitValidationErrors([]);
|
|
- }
|
|
-}
|
|
-
|
|
/**
|
|
* Implements hook_theme().
|
|
*/
|
|
-function image_field_caption_theme() {
|
|
+function image_field_caption_theme(): array {
|
|
return [
|
|
'image_caption_formatter' => [
|
|
// As we extend the default image format, the variables passed to the
|
|
- // callback function are the same than the original
|
|
- // "callback" function ("image_formatter").
|
|
+ // callback function are the same as the original (image_formatter).
|
|
'variables' => [
|
|
'item' => NULL,
|
|
'item_attributes' => NULL,
|
|
@@ -131,10 +91,11 @@ function image_field_caption_theme() {
|
|
* (template_preprocess_image_formatter()) and also:
|
|
* - caption: An optional caption text.
|
|
*/
|
|
-function template_preprocess_image_caption_formatter(&$variables) {
|
|
- Drupal::moduleHandler()->loadInclude('image', 'inc', 'image.field');
|
|
+function template_preprocess_image_caption_formatter(array &$variables): void {
|
|
// Prepare the variables array with the original function.
|
|
+ Drupal::moduleHandler()->loadInclude('image', 'inc', 'image.field');
|
|
template_preprocess_image_formatter($variables);
|
|
+
|
|
// Set the caption value.
|
|
$values = $variables['item']->getValue();
|
|
if (!empty($values['caption'])) {
|
|
@@ -147,187 +108,19 @@ function template_preprocess_image_caption_formatter(&$variables) {
|
|
}
|
|
|
|
/**
|
|
- * Implements hook_entity_storage_load().
|
|
- */
|
|
-function image_field_caption_entity_storage_load(array $entities, $entity_type_id) {
|
|
- $imageCaption = Drupal::service('image_field_caption.storage');
|
|
-
|
|
- if (in_array($entity_type_id, $imageCaption->list('entity_type'))) {
|
|
- // This means we already have some captions.
|
|
- // No need to do all kinds of checking then.
|
|
- /** @var \Drupal\Core\Entity\Entity $entity */
|
|
- foreach ($entities as $entity) {
|
|
- // Same load avoiding check.
|
|
- if (in_array($entity->bundle(), $imageCaption->list('bundle'))) {
|
|
- $needToSave = FALSE;
|
|
-
|
|
- /** @var \Drupal\Core\Field\FieldItemList $field */
|
|
- foreach ($entity->getFields() as $fieldName => $field) {
|
|
- $values = $entity->get($fieldName)->getValue();
|
|
- foreach ($values as $delta => $value) {
|
|
- // Get the caption associated to this field.
|
|
- $revision_id = (empty($entity->getRevisionId()) ? $entity->id() : $entity->getRevisionId());
|
|
- $caption = $imageCaption->getCaption(
|
|
- $entity->getEntityTypeId(),
|
|
- $entity->bundle(),
|
|
- $fieldName,
|
|
- $entity->id(),
|
|
- $revision_id,
|
|
- $entity->language()->getId(),
|
|
- $delta
|
|
- );
|
|
-
|
|
- // Set the caption value.
|
|
- if (!empty($caption)) {
|
|
- $values[$delta] = $values[$delta] + $caption;
|
|
- $needToSave = TRUE;
|
|
- }
|
|
- }
|
|
-
|
|
- if ($needToSave) {
|
|
- // Save all values.
|
|
- $entity->get($fieldName)->setValue($values);
|
|
- }
|
|
- }
|
|
-
|
|
- }
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
-/**
|
|
- * Implements hook_entity_insert().
|
|
+ * Implements hook_config_schema_info_alter().
|
|
*/
|
|
-function image_field_caption_entity_insert(EntityInterface $entity) {
|
|
- image_field_caption_entity_update($entity);
|
|
-}
|
|
-
|
|
-/**
|
|
- * Implements hook_entity_update().
|
|
- */
|
|
-function image_field_caption_entity_update(EntityInterface $entity) {
|
|
- $imageCaption = Drupal::service('image_field_caption.storage');
|
|
-
|
|
- // For a fieldable entity.
|
|
- if (($entity instanceof FieldableEntityInterface)) {
|
|
- // Get the field names of all image fields.
|
|
- $field_names = _image_field_caption_get_image_field_names($entity);
|
|
- foreach ($field_names as $field_name) {
|
|
- // Get the current field settings.
|
|
- $settings = $entity->get($field_name)->getSettings();
|
|
- // If the caption is not enabled => pass this field.
|
|
- if (empty($settings['caption_field'])) {
|
|
- continue;
|
|
- }
|
|
- // Delete the caption associated to this field.
|
|
- $imageCaption->deleteCaption($entity->getEntityTypeId(), $entity->bundle(), $field_name, $entity->id(), $entity->language()
|
|
- ->getId());
|
|
- // Delete the caption revision associated to this field.
|
|
- /*
|
|
- $imageCaption->deleteCaptionRevision(
|
|
- $entity->getEntityTypeId(), $entity->bundle(),
|
|
- $field_name, $entity->id(), $entity->getRevisionId(),
|
|
- $entity->language()->getId()); */
|
|
- // Get the current field values.
|
|
- $values = $entity->get($field_name)->getValue();
|
|
- foreach ($values as $delta => $value) {
|
|
- // If a caption text is defined.
|
|
- if (!empty($value['image_field_caption']['value'])) {
|
|
- // Insert the caption associated to this field.
|
|
- // @todo Do the insertion using a multiple query instead several queries into a foreach;
|
|
- $revision_id = (empty($entity->getRevisionId()) ? $entity->id() : $entity->getRevisionId());
|
|
- $imageCaption->insertCaption(
|
|
- $entity->getEntityTypeId(),
|
|
- $entity->bundle(),
|
|
- $field_name,
|
|
- $entity->id(),
|
|
- $revision_id,
|
|
- $entity->language()->getId(),
|
|
- $delta,
|
|
- $value['image_field_caption']['value'],
|
|
- $value['image_field_caption']['format']
|
|
- );
|
|
- // Insert the caption revision associated to this field.
|
|
- /*
|
|
- if ($entity->isNewRevision()) {
|
|
- $imageCaption->insertCaptionRevision(
|
|
- $entity->getEntityTypeId(),
|
|
- $entity->bundle(),
|
|
- $field_name,
|
|
- $entity->id(),
|
|
- $revision_id,
|
|
- $entity->language()->getId(),
|
|
- $delta,
|
|
- $value['image_field_caption']['value'],
|
|
- $value['image_field_caption']['format']
|
|
- );
|
|
- }
|
|
- */
|
|
- }
|
|
- }
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
-/**
|
|
- * Implements hook_entity_delete().
|
|
- */
|
|
-function image_field_caption_entity_delete(EntityInterface $entity) {
|
|
- $imageCaption = Drupal::service('image_field_caption.storage');
|
|
-
|
|
- // For a fieldable entity.
|
|
- if (($entity instanceof FieldableEntityInterface)) {
|
|
- // Get the field names of all image fields.
|
|
- $field_names = _image_field_caption_get_image_field_names($entity);
|
|
- foreach ($field_names as $field_name) {
|
|
- // Delete the caption associated to this field.
|
|
- $imageCaption->deleteCaption($entity->getEntityTypeId(), $entity->bundle(), $field_name, $entity->id(), $entity->language()
|
|
- ->getId());
|
|
- // Delete the caption revisions associated to this field.
|
|
- /*
|
|
- $imageCaption->deleteCaptionRevisions(
|
|
- $entity->getEntityTypeId(), $entity->bundle(),
|
|
- $field_name, $entity->id(), $entity->language()->getId()
|
|
- );*/
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
-/**
|
|
- * Implements hook_entity_revision_delete().
|
|
- */
|
|
-function image_field_caption_entity_revision_delete(EntityInterface $entity) {
|
|
- // $imageCaption = Drupal::service('image_field_caption.storage');
|
|
- /*
|
|
- // For a fieldable entity.
|
|
- if (($entity instanceof FieldableEntityInterface)) {
|
|
- // Get the field names of all image fields.
|
|
- $field_names = _image_field_caption_get_image_field_names($entity);
|
|
- if (!empty($field_names)) {
|
|
- // Delete the caption revisions associated to this specific revision.
|
|
- $imageCaption->deleteCaptionRevisionsByRevisionId($entity->getRevisionId());
|
|
- }
|
|
- }
|
|
- */
|
|
-}
|
|
-
|
|
-/**
|
|
- * Determines the image fields on an entity.
|
|
- *
|
|
- * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
|
|
- * An entity whose fields to analyze.
|
|
- *
|
|
- * @return array
|
|
- * The names of the fields on this entity that support formatted text.
|
|
- */
|
|
-function _image_field_caption_get_image_field_names(FieldableEntityInterface $entity) {
|
|
- // Check if fields definitions are available.
|
|
- $field_definitions = $entity->getFieldDefinitions();
|
|
- if (empty($field_definitions)) {
|
|
- return [];
|
|
- }
|
|
- // Only return image fields.
|
|
- return array_keys(array_filter($field_definitions, function (FieldDefinitionInterface $definition) {
|
|
- return in_array($definition->getType(), ['image'], TRUE);
|
|
- }));
|
|
+function image_field_caption_config_schema_info_alter(array &$definitions): void {
|
|
+ $definitions['field.field_settings.image']['mapping']['caption_field'] = [
|
|
+ 'type' => 'boolean',
|
|
+ 'label' => 'Enable Caption field',
|
|
+ ];
|
|
+ $definitions['field.field_settings.image']['mapping']['caption_field_required'] = [
|
|
+ 'type' => 'boolean',
|
|
+ 'label' => 'Caption field required',
|
|
+ ];
|
|
+ $definitions['field_default_image']['mapping']['caption'] = [
|
|
+ 'type' => 'label',
|
|
+ 'label' => 'Caption',
|
|
+ ];
|
|
}
|
|
diff --git a/image_field_caption.services.yml b/image_field_caption.services.yml
|
|
deleted file mode 100644
|
|
index 845c2e6..0000000
|
|
--- a/image_field_caption.services.yml
|
|
+++ /dev/null
|
|
@@ -1,7 +0,0 @@
|
|
-services:
|
|
- image_field_caption.storage:
|
|
- class: Drupal\image_field_caption\ImageCaptionStorage
|
|
- arguments:
|
|
- - '@cache.data'
|
|
- - '@cache_tags.invalidator'
|
|
- - '@database'
|
|
diff --git a/src/ImageCaptionItem.php b/src/ImageCaptionItem.php
|
|
index 1367735..02c0ada 100644
|
|
--- a/src/ImageCaptionItem.php
|
|
+++ b/src/ImageCaptionItem.php
|
|
@@ -2,46 +2,90 @@
|
|
|
|
namespace Drupal\image_field_caption;
|
|
|
|
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
|
use Drupal\Core\Form\FormStateInterface;
|
|
+use Drupal\Core\StringTranslation\TranslatableMarkup;
|
|
+use Drupal\Core\TypedData\DataDefinition;
|
|
use Drupal\image\Plugin\Field\FieldType\ImageItem;
|
|
|
|
/**
|
|
- * Class to provide functionlality for ImageCaptionItem.
|
|
+ * Class to provide functionality for ImageCaptionItem.
|
|
*/
|
|
class ImageCaptionItem extends ImageItem {
|
|
|
|
+ /**
|
|
+ * {@inheritdoc}
|
|
+ */
|
|
+ public static function defaultStorageSettings() {
|
|
+ $settings = parent::defaultStorageSettings();
|
|
+ $settings['default_image']['caption'] = '';
|
|
+
|
|
+ return $settings;
|
|
+ }
|
|
+
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public static function defaultFieldSettings() {
|
|
- return [
|
|
- 'default_image' => [
|
|
- 'caption' => '',
|
|
- ],
|
|
- 'caption_field' => FALSE,
|
|
- 'caption_field_required' => FALSE,
|
|
- ] + parent::defaultFieldSettings();
|
|
+ $settings = parent::defaultFieldSettings();
|
|
+ $settings['default_image']['caption'] = '';
|
|
+ $settings['caption_field'] = FALSE;
|
|
+ $settings['caption_field_required'] = FALSE;
|
|
+
|
|
+ return $settings;
|
|
+ }
|
|
+
|
|
+ public static function schema(FieldStorageDefinitionInterface $field_definition) {
|
|
+ $schema = parent::schema($field_definition);
|
|
+
|
|
+ $schema['columns']['caption'] = [
|
|
+ 'description' => 'The caption text.',
|
|
+ 'type' => 'text',
|
|
+ 'not null' => FALSE,
|
|
+ ];
|
|
+
|
|
+ $schema['columns']['caption_format'] = [
|
|
+ 'description' => 'The caption format.',
|
|
+ 'type' => 'varchar',
|
|
+ 'length' => 255,
|
|
+ 'not null' => FALSE,
|
|
+ ];
|
|
+
|
|
+ return $schema;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * {@inheritdoc}
|
|
+ */
|
|
+ public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
|
|
+ $properties = parent::propertyDefinitions($field_definition);
|
|
+
|
|
+ $properties['caption'] = DataDefinition::create('string')
|
|
+ ->setLabel(new TranslatableMarkup('Caption'))
|
|
+ ->setDescription(new TranslatableMarkup("Short description of the image displayed underneath the image."));
|
|
+
|
|
+ $properties['caption_format'] = DataDefinition::create('filter_format')
|
|
+ ->setLabel(new TranslatableMarkup('Text format of the caption'));
|
|
+
|
|
+ return $properties;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
|
|
- // Get base form from ImageItem.
|
|
$element = parent::fieldSettingsForm($form, $form_state);
|
|
- // Get field settings.
|
|
$settings = $this->getSettings();
|
|
- // Get the default field settings.
|
|
- $settings_default = self::defaultFieldSettings();
|
|
|
|
// Add caption option.
|
|
$element['caption_field'] = [
|
|
'#type' => 'checkbox',
|
|
'#title' => t('Enable <em>Caption</em> field'),
|
|
- '#default_value' => (!empty($settings['caption_field'])) ? $settings['caption_field'] : $settings_default['caption_field'],
|
|
- '#description' => t('Adds an extra text area for captions on image fields.'),
|
|
+ '#default_value' => $settings['caption_field'],
|
|
+ '#description' => $this->t('Short description of the image displayed underneath the image.'),
|
|
'#weight' => 13,
|
|
];
|
|
+
|
|
// Add caption (required) option.
|
|
$element['caption_field_required'] = [
|
|
'#type' => 'checkbox',
|
|
@@ -51,16 +95,44 @@ class ImageCaptionItem extends ImageItem {
|
|
'#weight' => 14,
|
|
'#states' => [
|
|
'visible' => [
|
|
- ':input[name="settings[image_caption_field]"]' => ['checked' => TRUE],
|
|
+ ':input[name="settings[caption_field]"]' => ['checked' => TRUE],
|
|
],
|
|
],
|
|
];
|
|
+
|
|
// Add default caption.
|
|
$element['default_image']['caption'] = [
|
|
'#type' => 'value',
|
|
- '#value' => (!empty($settings['default_image']['caption'])) ? $settings['default_image']['caption'] : $settings_default['default_image']['caption'],
|
|
+ '#value' => $settings['default_image']['caption'] ?? '',
|
|
];
|
|
|
|
return $element;
|
|
}
|
|
+
|
|
+ /**
|
|
+ * {@inheritdoc}
|
|
+ */
|
|
+ protected function defaultImageForm(array &$element, array $settings) {
|
|
+ parent::defaultImageForm($element, $settings);
|
|
+
|
|
+ $element['default_image']['caption'] = [
|
|
+ '#type' => 'textfield',
|
|
+ '#title' => $this->t('Caption'),
|
|
+ '#description' => $this->t('Short description of the image displayed underneath the image.'),
|
|
+ '#default_value' => $settings['default_image']['caption'] ?? '',
|
|
+ ];
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * {@inheritdoc}
|
|
+ */
|
|
+ public function setValue($values, $notify = TRUE): void {
|
|
+ if (isset($values['caption']) && is_array($values['caption'])) {
|
|
+ $values['caption_format'] = $values['caption']['format'];
|
|
+ $values['caption'] = $values['caption']['value'];
|
|
+ }
|
|
+
|
|
+ parent::setValue($values, $notify);
|
|
+ }
|
|
+
|
|
}
|
|
diff --git a/src/ImageCaptionStorage.php b/src/ImageCaptionStorage.php
|
|
deleted file mode 100644
|
|
index 9640903..0000000
|
|
--- a/src/ImageCaptionStorage.php
|
|
+++ /dev/null
|
|
@@ -1,425 +0,0 @@
|
|
-<?php
|
|
-
|
|
-namespace Drupal\image_field_caption;
|
|
-
|
|
-use Drupal\Core\Database\Connection;
|
|
-use Drupal\Core\Cache\CacheBackendInterface;
|
|
-use Drupal\Core\Cache\Cache;
|
|
-use Drupal\Core\Cache\CacheTagsInvalidator;
|
|
-
|
|
-/**
|
|
- * Storage controller class for image captions.
|
|
- *
|
|
- * @todo Use array with key/value as argument instead several arguments.
|
|
- * @todo The methods isCaption() and deleteCaption() must manage the revisions by itself, instead to have two differents methods.
|
|
- */
|
|
-class ImageCaptionStorage {
|
|
-
|
|
- /**
|
|
- * The Cache Backend.
|
|
- *
|
|
- * @var \Drupal\Core\Cache\CacheBackendInterface
|
|
- */
|
|
- protected $cacheBackend;
|
|
-
|
|
- /**
|
|
- * The Cache Tags Invalidator.
|
|
- *
|
|
- * @var \Drupal\Core\Cache\CacheTagsInvalidator
|
|
- */
|
|
- protected $cacheTagsInvalidator;
|
|
-
|
|
- /**
|
|
- * The database connection.
|
|
- *
|
|
- * @var \Drupal\Core\Database\Connection
|
|
- */
|
|
- protected $database;
|
|
-
|
|
- /**
|
|
- * The name of the data table.
|
|
- *
|
|
- * @var string
|
|
- */
|
|
- protected $tableData = 'image_field_caption';
|
|
-
|
|
- /**
|
|
- * The name of the revision table.
|
|
- *
|
|
- * @var string
|
|
- */
|
|
- protected $tableRevision = 'image_field_caption_revision';
|
|
-
|
|
- /**
|
|
- * AbstractService constructor.
|
|
- *
|
|
- * @param \Drupal\Core\Cache\CacheBackendInterface $cacheBackend
|
|
- * The Cache Backend.
|
|
- * @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cacheTagsInvalidator
|
|
- * The cache tags invalidator.
|
|
- * @param \Drupal\Core\Database\Connection $database
|
|
- * The Database.
|
|
- */
|
|
- public function __construct(
|
|
- CacheBackendInterface $cacheBackend,
|
|
- CacheTagsInvalidator $cacheTagsInvalidator,
|
|
- Connection $database
|
|
- ) {
|
|
- $this->cacheBackend = $cacheBackend;
|
|
- $this->cacheTagsInvalidator = $cacheTagsInvalidator;
|
|
- $this->database = $database;
|
|
- }
|
|
-
|
|
- /**
|
|
- * Check if a caption is already defined for the specified arguments.
|
|
- *
|
|
- * @param string $entity_type
|
|
- * The entity type, like 'node' or 'comment'.
|
|
- * @param string $bundle
|
|
- * The bundle, like 'article' or 'news'.
|
|
- * @param string $field_name
|
|
- * The field name of the image field,
|
|
- * like 'field_image' or 'field_article_image'.
|
|
- * @param int $entity_id
|
|
- * The entity id.
|
|
- * @param int $revision_id
|
|
- * The revision id.
|
|
- * @param string $language
|
|
- * The language key, like 'en' or 'fr'.
|
|
- * @param int $delta
|
|
- * The delta of the image field.
|
|
- *
|
|
- * @return bool
|
|
- * TRUE if a caption exists or FALSE if not.
|
|
- */
|
|
- public function isCaption($entity_type, $bundle, $field_name, $entity_id, $revision_id, $language, $delta) {
|
|
- return (!empty(self::getCaption($entity_type, $bundle, $field_name, $entity_id, $revision_id, $language, $delta))) ? TRUE : FALSE;
|
|
- }
|
|
-
|
|
- /**
|
|
- * Get a caption from the database for the specified arguments.
|
|
- *
|
|
- * @param string $entity_type
|
|
- * The entity type, like 'node' or 'comment'.
|
|
- * @param string $bundle
|
|
- * The bundle, like 'article' or 'news'.
|
|
- * @param string $field_name
|
|
- * The field name of the image field,
|
|
- * like 'field_image' or 'field_article_image'.
|
|
- * @param int $entity_id
|
|
- * The entity id.
|
|
- * @param int $revision_id
|
|
- * The revision id.
|
|
- * @param string $language
|
|
- * The language key, like 'en' or 'fr'.
|
|
- * @param int $delta
|
|
- * The delta of the image field.
|
|
- *
|
|
- * @return array
|
|
- * A caption array
|
|
- * - caption: The caption text.
|
|
- * - caption_format: The caption format.
|
|
- * or an empty array, if no value found.
|
|
- */
|
|
- public function getCaption($entity_type, $bundle, $field_name, $entity_id, $revision_id, $language, $delta) {
|
|
- $captions = &drupal_static(__FUNCTION__);
|
|
-
|
|
- $cacheKey = $this->getCacheKey($entity_type, $entity_id, $revision_id, $language, $field_name, $delta);
|
|
-
|
|
- if (isset($captions[$cacheKey])) {
|
|
- $caption = $captions[$cacheKey];
|
|
- }
|
|
- elseif ($cached = $this->cacheBackend->get($cacheKey)) {
|
|
- $caption = $cached->data;
|
|
- }
|
|
- else {
|
|
- // Query.
|
|
- $query = $this->database->select($this->tableData, 'ifc');
|
|
- $result = $query
|
|
- ->fields('ifc', ['caption', 'caption_format'])
|
|
- ->condition('entity_type', $entity_type, '=')
|
|
- ->condition('bundle', $bundle, '=')
|
|
- ->condition('field_name', $field_name, '=')
|
|
- ->condition('entity_id', $entity_id, '=')
|
|
- ->condition('revision_id', $revision_id, '=')
|
|
- ->condition('language', $language, '=')
|
|
- ->condition('delta', $delta, '=')
|
|
- ->execute()
|
|
- ->fetchAssoc();
|
|
-
|
|
- // Caption array.
|
|
- $caption = [];
|
|
- if (!empty($result)) {
|
|
- $caption = $result;
|
|
- }
|
|
-
|
|
- // Let the cache depends on the entity.
|
|
- // @todo Use getCacheTags() to get the default list.
|
|
- $this->cacheBackend->set(
|
|
- $cacheKey,
|
|
- $caption,
|
|
- Cache::PERMANENT,
|
|
- [
|
|
- $field_name,
|
|
- 'image_field_caption',
|
|
- ]
|
|
- );
|
|
- }
|
|
-
|
|
- return $caption;
|
|
- }
|
|
-
|
|
- /**
|
|
- * Insert a caption into the database for the specified arguments.
|
|
- *
|
|
- * @param string $entity_type
|
|
- * The entity type, like 'node' or 'comment'.
|
|
- * @param string $bundle
|
|
- * The bundle, like 'article' or 'news'.
|
|
- * @param string $field_name
|
|
- * The field name of the image field,
|
|
- * like 'field_image' or 'field_article_image'.
|
|
- * @param int $entity_id
|
|
- * The entity id.
|
|
- * @param int $revision_id
|
|
- * The revision id.
|
|
- * @param string $language
|
|
- * The language key, like 'en' or 'fr'.
|
|
- * @param int $delta
|
|
- * The delta of the image field.
|
|
- * @param string $caption
|
|
- * The caption text.
|
|
- * @param string $caption_format
|
|
- * The text format of the caption.
|
|
- */
|
|
- public function insertCaption($entity_type, $bundle, $field_name, $entity_id, $revision_id, $language, $delta, $caption, $caption_format) {
|
|
-
|
|
- $query = $this->database->insert($this->tableData);
|
|
- $query
|
|
- ->fields([
|
|
- 'entity_type' => $entity_type,
|
|
- 'bundle' => $bundle,
|
|
- 'field_name' => $field_name,
|
|
- 'entity_id' => $entity_id,
|
|
- 'revision_id' => $revision_id,
|
|
- 'language' => $language,
|
|
- 'delta' => $delta,
|
|
- 'caption' => $caption,
|
|
- 'caption_format' => $caption_format,
|
|
- ])
|
|
- ->execute();
|
|
- $this->clearCache($field_name);
|
|
- }
|
|
-
|
|
- /**
|
|
- * Insert a caption revision into the database for the specified arguments.
|
|
- *
|
|
- * @param string $entity_type
|
|
- * The entity type, like 'node' or 'comment'.
|
|
- * @param string $bundle
|
|
- * The bundle, like 'article' or 'news'.
|
|
- * @param string $field_name
|
|
- * The field name of the image field,
|
|
- * like 'field_image' or 'field_article_image'.
|
|
- * @param int $entity_id
|
|
- * The entity id.
|
|
- * @param int $revision_id
|
|
- * The revision id.
|
|
- * @param string $language
|
|
- * The language key, like 'en' or 'fr'.
|
|
- * @param int $delta
|
|
- * The delta of the image field.
|
|
- * @param string $caption
|
|
- * The caption text.
|
|
- * @param string $caption_format
|
|
- * The text format of the caption.
|
|
- */
|
|
- public function insertCaptionRevision($entity_type, $bundle, $field_name, $entity_id, $revision_id, $language, $delta, $caption, $caption_format) {
|
|
- $query = $this->database->insert($this->tableRevision);
|
|
- $query
|
|
- ->fields([
|
|
- 'entity_type' => $entity_type,
|
|
- 'bundle' => $bundle,
|
|
- 'field_name' => $field_name,
|
|
- 'entity_id' => $entity_id,
|
|
- 'revision_id' => $revision_id,
|
|
- 'language' => $language,
|
|
- 'delta' => $delta,
|
|
- 'caption' => $caption,
|
|
- 'caption_format' => $caption_format,
|
|
- ])
|
|
- ->execute();
|
|
- $this->clearCache($field_name);
|
|
- }
|
|
-
|
|
- /**
|
|
- * Delete a caption from the database for the specified arguments.
|
|
- *
|
|
- * @param string $entity_type
|
|
- * The entity type, like 'node' or 'comment'.
|
|
- * @param string $bundle
|
|
- * The bundle, like 'article' or 'news'.
|
|
- * @param string $field_name
|
|
- * The field name of the image field, like
|
|
- * 'field_image' or 'field_article_image'.
|
|
- * @param int $entity_id
|
|
- * The entity id.
|
|
- * @param string $language
|
|
- * The language key, like 'en' or 'fr'.
|
|
- */
|
|
- public function deleteCaption($entity_type, $bundle, $field_name, $entity_id, $language) {
|
|
- $query = $this->database->delete($this->tableData);
|
|
- $query
|
|
- ->condition('entity_type', $entity_type, '=')
|
|
- ->condition('bundle', $bundle, '=')
|
|
- ->condition('field_name', $field_name, '=')
|
|
- ->condition('entity_id', $entity_id, '=')
|
|
- ->condition('language', $language, '=')
|
|
- ->execute();
|
|
- $this->clearCache($field_name);
|
|
- // @todo Try to return the count of the affected rows.
|
|
- }
|
|
-
|
|
- /**
|
|
- * Delete a caption revision from the database for the specified arguments.
|
|
- *
|
|
- * @param string $entity_type
|
|
- * The entity type, like 'node' or 'comment'.
|
|
- * @param string $bundle
|
|
- * The bundle, like 'article' or 'news'.
|
|
- * @param string $field_name
|
|
- * The field name of the image field, like
|
|
- * 'field_image' or 'field_article_image'.
|
|
- * @param int $entity_id
|
|
- * The entity id.
|
|
- * @param int $revision_id
|
|
- * The revision id.
|
|
- * @param string $language
|
|
- * The language key, like 'en' or 'fr'.
|
|
- */
|
|
- public function deleteCaptionRevision($entity_type, $bundle, $field_name, $entity_id, $revision_id, $language) {
|
|
- $query = $this->database->delete($this->tableRevision);
|
|
- $query
|
|
- ->condition('entity_type', $entity_type, '=')
|
|
- ->condition('bundle', $bundle, '=')
|
|
- ->condition('field_name', $field_name, '=')
|
|
- ->condition('entity_id', $entity_id, '=')
|
|
- ->condition('revision_id', $revision_id, '=')
|
|
- ->condition('language', $language, '=')
|
|
- ->execute();
|
|
- $this->clearCache($field_name);
|
|
- // @todo Try to return the count of the affected rows.
|
|
- }
|
|
-
|
|
- /**
|
|
- * Delete all captions revisions for the specified arguments.
|
|
- *
|
|
- * @param string $entity_type
|
|
- * The entity type, like 'node' or 'comment'.
|
|
- * @param string $bundle
|
|
- * The bundle, like 'article' or 'news'.
|
|
- * @param string $field_name
|
|
- * The field name of the image field, like 'field_image'
|
|
- * or 'field_article_image'.
|
|
- * @param int $entity_id
|
|
- * The entity id.
|
|
- * @param string $language
|
|
- * The language key, like 'en' or 'fr'.
|
|
- */
|
|
- public function deleteCaptionRevisions($entity_type, $bundle, $field_name, $entity_id, $language) {
|
|
- $query = $this->database->delete($this->tableRevision);
|
|
- $query
|
|
- ->condition('entity_type', $entity_type, '=')
|
|
- ->condition('bundle', $bundle, '=')
|
|
- ->condition('field_name', $field_name, '=')
|
|
- ->condition('entity_id', $entity_id, '=')
|
|
- ->condition('language', $language, '=')
|
|
- ->execute();
|
|
- $this->clearCache($field_name);
|
|
- // @todo Try to return the count of the affected rows.
|
|
- }
|
|
-
|
|
- /**
|
|
- * Delete all captions revisions for a specific revision id.
|
|
- *
|
|
- * @param int $revision_id
|
|
- * The revision id.
|
|
- */
|
|
- public function deleteCaptionRevisionsByRevisionId($revision_id) {
|
|
- $query = $this->database->delete($this->tableRevision);
|
|
- $query
|
|
- ->condition('revision_id', $revision_id, '=')
|
|
- ->execute();
|
|
- }
|
|
-
|
|
- /**
|
|
- * Clears the cache for a certain field name.
|
|
- *
|
|
- * @param string $field_name
|
|
- * The field name of the image field, like 'field_image'
|
|
- * or 'field_article_image'.
|
|
- */
|
|
- public function clearCache($field_name) {
|
|
- $this->cacheTagsInvalidator->invalidateTags([
|
|
- $field_name,
|
|
- 'image_field_caption',
|
|
- ]);
|
|
- }
|
|
-
|
|
- /**
|
|
- * Constructs the cache key.
|
|
- *
|
|
- * @param string $entity_type
|
|
- * The entity type, like 'node' or 'comment'.
|
|
- * @param int $entity_id
|
|
- * The entity id.
|
|
- * @param int $revision_id
|
|
- * The revision id.
|
|
- * @param string $language
|
|
- * The language key, like 'en' or 'fr'.
|
|
- * @param string $field_name
|
|
- * The field name of the image field, like 'field_image'
|
|
- * or 'field_article_image'.
|
|
- * @param int $delta
|
|
- * The delta of the image field.
|
|
- */
|
|
- public function getCacheKey($entity_type, $entity_id, $revision_id, $language, $field_name, $delta) {
|
|
- return implode(
|
|
- ":",
|
|
- [
|
|
- 'caption',
|
|
- $entity_type,
|
|
- $entity_id,
|
|
- $revision_id,
|
|
- $language,
|
|
- $field_name,
|
|
- $delta,
|
|
- ]
|
|
- );
|
|
- }
|
|
-
|
|
- /**
|
|
- * Function to list out entity type field.
|
|
- */
|
|
- public function list($key = 'entity_type') {
|
|
- $list = &drupal_static(__FUNCTION__);
|
|
-
|
|
- if (!isset($list[$key])) {
|
|
- // Query.
|
|
- $query = $this->database->select($this->tableData, 'ifc');
|
|
- $result = $query
|
|
- ->fields('ifc', [$key])
|
|
- ->distinct()
|
|
- ->execute()
|
|
- ->fetchAll();
|
|
-
|
|
- $list[$key] = [];
|
|
- foreach ($result as $row) {
|
|
- $list[$key][] = $row->{$key};
|
|
- }
|
|
- }
|
|
-
|
|
- return $list[$key];
|
|
- }
|
|
-
|
|
-}
|
|
diff --git a/src/Plugin/Field/FieldFormatter/ImageCaptionFormatter.php b/src/Plugin/Field/FieldFormatter/ImageCaptionFormatter.php
|
|
index 7ba4c62..c761a0d 100644
|
|
--- a/src/Plugin/Field/FieldFormatter/ImageCaptionFormatter.php
|
|
+++ b/src/Plugin/Field/FieldFormatter/ImageCaptionFormatter.php
|
|
@@ -23,10 +23,12 @@ class ImageCaptionFormatter extends ImageFormatter {
|
|
*/
|
|
public function viewElements(FieldItemListInterface $items, $langcode) {
|
|
$elements = parent::viewElements($items, $langcode);
|
|
+
|
|
foreach ($elements as $delta => $element) {
|
|
// Set a new theme callback function for the image caption formatter.
|
|
$elements[$delta]['#theme'] = 'image_caption_formatter';
|
|
}
|
|
+
|
|
return $elements;
|
|
}
|
|
|
|
--
|
|
GitLab
|
|
|
|
|
|
From 0066f4a953597385e284bfb5bdee941c4dc78b66 Mon Sep 17 00:00:00 2001
|
|
From: Dieter Holvoet <dieter.holvoet@gmail.com>
|
|
Date: Mon, 9 Sep 2024 11:28:27 +0200
|
|
Subject: [PATCH 2/4] Add back image module dependency
|
|
|
|
---
|
|
image_field_caption.info.yml | 4 ++++
|
|
1 file changed, 4 insertions(+)
|
|
|
|
diff --git a/image_field_caption.info.yml b/image_field_caption.info.yml
|
|
index e04a8e9..4861584 100644
|
|
--- a/image_field_caption.info.yml
|
|
+++ b/image_field_caption.info.yml
|
|
@@ -1,6 +1,10 @@
|
|
name: Image Field Caption
|
|
description: 'Provides a caption textarea for image fields.'
|
|
package: Other
|
|
+
|
|
+dependencies:
|
|
+ - drupal:image
|
|
+
|
|
type: module
|
|
core_version_requirement: ^9.2 || ^10
|
|
php: 7.1
|
|
--
|
|
GitLab
|
|
|
|
|
|
From 2e5f7c84145f267c1ac44c37e759d48a9aea07b7 Mon Sep 17 00:00:00 2001
|
|
From: Dieter Holvoet <dieter.holvoet@gmail.com>
|
|
Date: Mon, 9 Sep 2024 11:31:50 +0200
|
|
Subject: [PATCH 3/4] Fix cs issues
|
|
|
|
---
|
|
README.md | 3 ++-
|
|
image_field_caption.install | 19 +++++++++++++------
|
|
image_field_caption.module | 7 +++----
|
|
src/ImageCaptionItem.php | 5 ++++-
|
|
4 files changed, 22 insertions(+), 12 deletions(-)
|
|
|
|
diff --git a/README.md b/README.md
|
|
index 8bc42d9..2c46688 100644
|
|
--- a/README.md
|
|
+++ b/README.md
|
|
@@ -2,7 +2,8 @@
|
|
|
|
Adds an extra text area for captions on image fields.
|
|
Similar to the alt and title text fields available with an image field,
|
|
-the caption text area can be used to enter text or html descriptions of an image.
|
|
+the caption text area can be used to enter text or html descriptions of an
|
|
+image.
|
|
|
|
For a full description of the module, visit the
|
|
[Image Field Caption](https://www.drupal.org/project/image_field_caption).
|
|
diff --git a/image_field_caption.install b/image_field_caption.install
|
|
index 63a974b..dab5ae6 100644
|
|
--- a/image_field_caption.install
|
|
+++ b/image_field_caption.install
|
|
@@ -1,5 +1,10 @@
|
|
<?php
|
|
|
|
+/**
|
|
+ * @file
|
|
+ * Install, update and uninstall functions for the Image Field Caption module.
|
|
+ */
|
|
+
|
|
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
|
|
use Drupal\Core\Entity\Sql\SqlContentEntityStorageException;
|
|
|
|
@@ -20,10 +25,10 @@ function image_field_caption_uninstall(): void {
|
|
/**
|
|
* Helper function to add new columns to a field type.
|
|
*
|
|
- * @param $field_type
|
|
+ * @param string $field_type
|
|
* The field type id.
|
|
* @param array $columns_to_add
|
|
- * array of the column names from schema() function.
|
|
+ * Array of the column names from schema() function.
|
|
*
|
|
* @see https://gist.github.com/JPustkuchen/ce53d40303a51ca5f17ce7f48c363b9b
|
|
* @see https://www.drupal.org/project/drupal/issues/937442
|
|
@@ -60,7 +65,8 @@ function _image_field_caption_field_type_schema_column_add_helper(string $field_
|
|
$field_name = $field_storage_definition->getName();
|
|
try {
|
|
$table = $table_mapping->getFieldTableName($field_name);
|
|
- } catch (SqlContentEntityStorageException $e) {
|
|
+ }
|
|
+ catch (SqlContentEntityStorageException $e) {
|
|
// Custom storage? Broken site? No matter what, if there is no table
|
|
// or column, there's little we can do.
|
|
continue;
|
|
@@ -123,10 +129,10 @@ function _image_field_caption_field_type_schema_column_add_helper(string $field_
|
|
/**
|
|
* Helper function to remove columns from a field type.
|
|
*
|
|
- * @param $field_type
|
|
+ * @param string $field_type
|
|
* The field type id.
|
|
* @param array $columns_to_remove
|
|
- * array of the column names from schema() function.
|
|
+ * Array of the column names from schema() function.
|
|
*
|
|
* @see https://gist.github.com/JPustkuchen/ce53d40303a51ca5f17ce7f48c363b9b
|
|
* @see https://www.drupal.org/project/drupal/issues/937442
|
|
@@ -163,7 +169,8 @@ function _image_field_caption_field_type_schema_column_remove_helper(string $fie
|
|
$field_name = $field_storage_definition->getName();
|
|
try {
|
|
$table = $table_mapping->getFieldTableName($field_name);
|
|
- } catch (SqlContentEntityStorageException $e) {
|
|
+ }
|
|
+ catch (SqlContentEntityStorageException $e) {
|
|
// Custom storage? Broken site? No matter what, if there is no table
|
|
// or column, there's little we can do.
|
|
continue;
|
|
diff --git a/image_field_caption.module b/image_field_caption.module
|
|
index 63f8999..8bae0a6 100644
|
|
--- a/image_field_caption.module
|
|
+++ b/image_field_caption.module
|
|
@@ -14,10 +14,10 @@ use Drupal\image_field_caption\ImageCaptionItem;
|
|
* Implements hook_field_info_alter().
|
|
*/
|
|
function image_field_caption_field_info_alter(array &$info): void {
|
|
- // Override the image field type class
|
|
+ // Override the image field type class.
|
|
$info['image']['class'] = ImageCaptionItem::class;
|
|
|
|
- // Enable translation for the caption property
|
|
+ // Enable translation for the caption property.
|
|
$info['image']['column_groups']['caption'] = [
|
|
'label' => t('Caption'),
|
|
'translatable' => TRUE,
|
|
@@ -48,8 +48,7 @@ function _image_field_caption_widget_process(array $element, FormStateInterface
|
|
$item = $element['#value'];
|
|
$item['fids'] = $element['fids']['#value'];
|
|
|
|
- // TODO: Make #allowed_formats configurable.
|
|
-
|
|
+ // @todo Make #allowed_formats configurable.
|
|
$element['caption'] = [
|
|
'#title' => t('Caption'),
|
|
'#type' => 'text_format',
|
|
diff --git a/src/ImageCaptionItem.php b/src/ImageCaptionItem.php
|
|
index 02c0ada..8fb5d92 100644
|
|
--- a/src/ImageCaptionItem.php
|
|
+++ b/src/ImageCaptionItem.php
|
|
@@ -35,6 +35,9 @@ class ImageCaptionItem extends ImageItem {
|
|
return $settings;
|
|
}
|
|
|
|
+ /**
|
|
+ * {@inheritdoc}
|
|
+ */
|
|
public static function schema(FieldStorageDefinitionInterface $field_definition) {
|
|
$schema = parent::schema($field_definition);
|
|
|
|
@@ -65,7 +68,7 @@ class ImageCaptionItem extends ImageItem {
|
|
->setDescription(new TranslatableMarkup("Short description of the image displayed underneath the image."));
|
|
|
|
$properties['caption_format'] = DataDefinition::create('filter_format')
|
|
- ->setLabel(new TranslatableMarkup('Text format of the caption'));
|
|
+ ->setLabel(new TranslatableMarkup('Text format of the caption'));
|
|
|
|
return $properties;
|
|
}
|
|
--
|
|
GitLab
|
|
|
|
|
|
From fffc01d559c45e4b43729619d5cef93916d19417 Mon Sep 17 00:00:00 2001
|
|
From: Dieter Holvoet <dieter.holvoet@gmail.com>
|
|
Date: Mon, 9 Sep 2024 11:45:46 +0200
|
|
Subject: [PATCH 4/4] Fix issue reported by phpstan
|
|
|
|
---
|
|
src/ImageCaptionItem.php | 3 ++-
|
|
1 file changed, 2 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/src/ImageCaptionItem.php b/src/ImageCaptionItem.php
|
|
index 8fb5d92..3ef0772 100644
|
|
--- a/src/ImageCaptionItem.php
|
|
+++ b/src/ImageCaptionItem.php
|
|
@@ -79,6 +79,7 @@ class ImageCaptionItem extends ImageItem {
|
|
public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
|
|
$element = parent::fieldSettingsForm($form, $form_state);
|
|
$settings = $this->getSettings();
|
|
+ $defaultSettings = self::defaultFieldSettings();
|
|
|
|
// Add caption option.
|
|
$element['caption_field'] = [
|
|
@@ -93,7 +94,7 @@ class ImageCaptionItem extends ImageItem {
|
|
$element['caption_field_required'] = [
|
|
'#type' => 'checkbox',
|
|
'#title' => t('<em>Caption</em> field required'),
|
|
- '#default_value' => (!empty($settings['caption_field_required'])) ? $settings['caption_field_required'] : $settings_default['caption_field_required'],
|
|
+ '#default_value' => (!empty($settings['caption_field_required'])) ? $settings['caption_field_required'] : $defaultSettings['caption_field_required'],
|
|
'#description' => '',
|
|
'#weight' => 14,
|
|
'#states' => [
|
|
--
|
|
GitLab
|
|
|