Same filename and directory in other branches
  1. 8.x-2.x src/Controller/ExifSettingsController.php 1 comment

Namespace

Drupal\exif\Controller

File

src/Controller/ExifSettingsController.php

View source
<?php

namespace Drupal\exif\Controller;

use Drupal;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Field\FieldException;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\exif\ExifFactory;
use Drupal\taxonomy\Entity\Vocabulary;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;

/**
 * Class ExifSettingsController manage action of settings pages.
 *
 * @package Drupal\exif\Controller
 */
class ExifSettingsController extends ControllerBase {
    
    /**
     * The entity display repository.
     *
     * @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
     */
    protected $entityDisplayRepository;
    
    /**
     * Constructs a ExifSettingsController object.
     *
     * @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
     *   The entity display repository.
     */
    public function __construct(EntityDisplayRepositoryInterface $entity_display_repository) {
        $this->entityDisplayRepository = $entity_display_repository;
    }
    
    /**
     * {@inheritdoc}
     */
    public static function create(ContainerInterface $container) {
        return new static($container->get('entity_display.repository'));
    }
    
    /**
     * Button to go to help page.
     *
     * Use by routing.yml.
     */
    public function showGuide() {
        return [
            '#message' => "",
            '#taxonomy' => 'http://drupal.org/handbook/modules/taxonomy/',
            '#theme' => 'exif_helper_page',
            '#attached' => [
                'library' => [
                    'exif/exif-admin',
                ],
            ],
        ];
    }
    
    /**
     * Create a vocabulary "photographies'metadata".
     *
     * Use by routing.yml.
     */
    public function createPhotographyVocabulary() {
        $values = [
            "name" => "photographs metadata",
            "vid" => "photographs_metadata",
            "description" => "information related to photographs",
        ];
        $voc = Vocabulary::load("photographs_metadata");
        if (!$voc) {
            Vocabulary::create($values)->save();
            $message = $this->t('The  vocabulary photography has been created');
        }
        else {
            $message = $this->t('The  vocabulary photography is already created. nothing to do');
        }
        $this->messenger()
            ->addStatus($message);
        $response = new RedirectResponse('/admin/config/media/exif/helper');
        $response->send();
        exit;
    }
    
    /**
     * Create an Photography node type with default exif fields.
     *
     * Default files are title, model, keywords.
     *
     * Default behavior but 'promoted to front'.
     *
     * Use by routing.yml
     *
     * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
     * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
     * @throws \Drupal\Core\Entity\EntityStorageException
     */
    public function createPhotographyNodeType() {
        $typeName = 'Photography';
        $entity_type = 'node';
        $machineName = strtolower($typeName);
        try {
            $storage = $this->entityTypeManager()
                ->getStorage('node_type');
            $type_definition = $storage->load($machineName);
            if (!$type_definition) {
                $type_definition = $storage->create([
                    'name' => $typeName,
                    'type' => $machineName,
                    'description' => 'Use Photography for content where the photo is the main content. You still can have some other information related to the photo itself.',
                ]);
                $type_definition->save();
            }
            // Add default display.
            $values = [
                'targetEntityType' => $entity_type,
                'bundle' => $machineName,
                'mode' => 'default',
                'status' => TRUE,
            ];
            $this->entityTypeManager()
                ->getStorage('entity_view_display')
                ->create($values);
            // Add default form display.
            $values = [
                'targetEntityType' => $entity_type,
                'bundle' => $machineName,
                'mode' => 'default',
                'status' => TRUE,
            ];
            $this->entityTypeManager()
                ->getStorage('entity_form_display')
                ->create($values);
            // Then add fields.
            $this->addFields($entity_type, $type_definition);
            $message = $this->t('The %entitytype type %type has been fully created', [
                '%entitytype' => $entity_type,
                '%type' => $typeName,
            ]);
        } catch (FieldException $fe) {
            $message = $this->t('An unexpected error was thrown during creation : ') . $fe->getMessage();
        }
        $this->messenger()
            ->addStatus($message);
        $response = new RedirectResponse('/admin/config/media/exif/helper');
        $response->send();
        exit;
    }
    
    /**
     * Create a Photography node type with default exif field.
     *
     * Default values are title, model, keywords.
     * Default behavior but 'promoted to front'.
     *
     * used by routing.yml
     *
     * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
     * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
     * @throws \Drupal\Core\Entity\EntityStorageException
     */
    public function createPhotographyMediaType() {
        $typeName = 'Photography';
        $entity_type = 'media';
        $machineName = strtolower($typeName);
        try {
            if (Drupal::moduleHandler()->moduleExists("media_entity")) {
                $storage = $this->entityTypeManager()
                    ->getStorage($entity_type);
                $type_definition = $storage->load($machineName);
                if (!$type_definition) {
                    $type_definition = $storage->create([
                        'name' => $typeName,
                        'type' => $machineName,
                        'description' => 'Use Photography for content where the photo is the main content. You still can have some other information related to the photo itself.',
                    ]);
                    $type_definition->save();
                }
                // Add default display.
                $values = [
                    'targetEntityType' => $entity_type,
                    'bundle' => $machineName,
                    'mode' => 'default',
                    'status' => TRUE,
                ];
                $this->entityTypeManager()
                    ->getStorage('entity_view_display')
                    ->create($values);
                // Add default form display.
                $values = [
                    'targetEntityType' => $entity_type,
                    'bundle' => $machineName,
                    'mode' => 'default',
                    'status' => TRUE,
                ];
                $this->entityTypeManager()
                    ->getStorage('entity_form_display')
                    ->create($values);
                // Then add fields.
                $this->addFields($entity_type, $type_definition);
                $message = $this->t('The %entitytype type %type has been fully created', [
                    '%entitytype' => $entity_type,
                    '%type' => $typeName,
                ]);
            }
            else {
                $message = 'Nothing done. Media modules not present.';
            }
        } catch (FieldException $fe) {
            $message = $this->t('An unexpected error was thrown during creation : ') . $fe->getMessage();
        }
        $this->messenger()
            ->addStatus($message);
        $response = new RedirectResponse('/admin/config/media/exif/helper');
        $response->send();
        exit;
    }
    
    /**
     * Create a sample HTML Fragment.
     *
     * @return array
     *   HTML Fragment with a sample image and metadata.
     */
    public function showSample() {
        $sampleImageFilePath = drupal_get_path('module', 'exif') . '/sample.jpg';
        $exif = ExifFactory::getExifInterface();
        $fullmetadata = $exif->readMetadataTags($sampleImageFilePath);
        $html = '<table class="metadata-table"><tbody>';
        foreach ($fullmetadata as $currentSection => $currentValues) {
            $html .= '<tr class="metadata-section"><td colspan="2">' . $currentSection . '</td></tr>';
            foreach ($currentValues as $currentKey => $currentValue) {
                $exif_value = $this->sanitizeValue($currentValue);
                $html .= '<tr class="metadata-row ' . $currentKey . '"><td class="metadata-key">' . $currentKey . '</td><td class="metadata-value">' . $exif_value . '</td></tr>';
            }
        }
        $html .= '</tbody><tfoot></tfoot></table>';
        return [
            '#metadata' => $html,
            '#image_path' => '/' . $sampleImageFilePath,
            '#taxo' => '',
            '#permissionLink' => '',
            '#taxonomyFragment' => '',
            '#theme' => 'exif_sample',
            '#attached' => [
                'library' => [
                    'exif/exif-sample',
                ],
            ],
        ];
    }
    
    /**
     * Add a field to a entity type.
     *
     * @param string $entity_type
     *   The entity type name to be modified.
     * @param \Drupal\Core\Entity\EntityInterface $type_definition
     *   The definition of type.
     *
     * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
     * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
     * @throws \Drupal\Core\Entity\EntityStorageException
     */
    protected function addFields($entity_type, EntityInterface $type_definition) {
        // First, add image field.
        $this->addFieldToEntityType($entity_type, $type_definition, 'Photo', 'image', 'image', 'exif_readonly');
        $widget_settings = [
            'image_field' => 'field_image',
            'exif_field' => 'naming_convention',
        ];
        // Then add all extra fields (metadata)
        // Date type.
        $this->addFieldToEntityType($entity_type, $type_definition, 'Creation date', 'exif_datetime', 'datetime', 'exif_readonly', $widget_settings);
        // Text type.
        $this->addFieldToEntityType($entity_type, $type_definition, 'Photo Comment', 'exif_comments', 'text', 'exif_readonly', $widget_settings);
        $this->addFieldToEntityType($entity_type, $type_definition, 'Photo Description', 'exif_imagedescription', 'text', 'exif_readonly', $widget_settings);
        $this->addFieldToEntityType($entity_type, $type_definition, 'Photo Title', 'exif_title', 'text', 'exif_readonly', $widget_settings);
        $this->addFieldToEntityType($entity_type, $type_definition, 'Make', 'exif_make', 'text', 'exif_readonly', $widget_settings);
        $this->addFieldToEntityType($entity_type, $type_definition, 'Aperture', 'exif_aperturefnumber', 'text', 'exif_readonly', $widget_settings);
        $this->addFieldToEntityType($entity_type, $type_definition, 'Exposure', 'exif_exposuretime', 'text', 'exif_readonly', $widget_settings);
        $this->addFieldToEntityType($entity_type, $type_definition, 'ISO', 'exif_isospeedratings', 'text', 'exif_readonly', $widget_settings);
        $this->addFieldToEntityType($entity_type, $type_definition, 'Focal', 'exif_focallength', 'text', 'exif_readonly', $widget_settings);
        $this->addFieldToEntityType($entity_type, $type_definition, 'Flash', 'exif_flash', 'text', 'exif_readonly', $widget_settings);
        $this->addFieldToEntityType($entity_type, $type_definition, 'Exposure Program', 'exif_exposureprogram', 'text', 'exif_readonly', $widget_settings);
        $this->addFieldToEntityType($entity_type, $type_definition, 'Exposure Mode', 'exif_exposuremode', 'text', 'exif_readonly', $widget_settings);
        $this->addFieldToEntityType($entity_type, $type_definition, 'White Balance Mode', 'exif_whitebalance', 'text', 'exif_readonly', $widget_settings);
        $this->addFieldToEntityType($entity_type, $type_definition, 'scene Mode', 'exif_scenecapturetype', 'text', 'exif_readonly', $widget_settings);
        $this->addFieldToEntityType($entity_type, $type_definition, 'orientation', 'exif_orientation', 'text', 'exif_readonly', $widget_settings);
        // Terms Type (taxonomy).
        $this->addReferenceToEntityType($entity_type, $type_definition, 'Photographer', 'exif_author', 'taxonomy_term', 'photographs_metadata', 'exif_readonly', $widget_settings);
        $this->addReferenceToEntityType($entity_type, $type_definition, 'Camera', 'exif_model', 'taxonomy_term', 'photographs_metadata', 'exif_readonly', $widget_settings);
        $this->addReferenceToEntityType($entity_type, $type_definition, 'ISO', 'exif_isospeedratings', 'taxonomy_term', 'photographs_metadata', 'exif_readonly', $widget_settings);
        $widget_settings_for_tags = [
            'image_field' => 'field_image',
            'exif_field' => 'naming_convention',
            'exif_field_separator' => ';',
        ];
        $this->addReferenceToEntityType($entity_type, $type_definition, 'Tags', 'exif_keywords', 'taxonomy_term', 'photographs_metadata', 'exif_readonly', $widget_settings_for_tags);
    }
    
    /**
     * Add a Field to an Entity Type.
     *
     * @param string $entity_type
     *   The entity type name to be modified.
     * @param \Drupal\Core\Entity\EntityInterface $type
     *   The definition of type.
     * @param string $fieldLabel
     *   Field description (what is show in forms).
     * @param string $fieldName
     *   Field name (the real one used internally).
     * @param string $fieldType
     *   Name of the field type to be added.
     * @param string $fieldWidget
     *   Name of the widget to use.
     * @param array $widgetSettings
     *   Settings to set for the widget.
     * @param array $settings
     *   Specific setting for the field (optional).
     *
     * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
     * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
     * @throws \Drupal\Core\Entity\EntityStorageException
     */
    protected function addFieldToEntityType($entity_type, EntityInterface $type, $fieldLabel, $fieldName, $fieldType, $fieldWidget, array $widgetSettings = [], array $settings = []) {
        $realFieldName = 'field_' . $fieldName;
        $storage = $this->getFieldStorageConfig();
        $field_storage = $storage->load($entity_type . '.' . $realFieldName);
        if (empty($field_storage)) {
            $field_storage_values = [
                'field_name' => $realFieldName,
                'field_label' => $fieldLabel,
                'entity_type' => $entity_type,
                'bundle' => $type->id(),
                'type' => $fieldType,
                'translatable' => FALSE,
            ];
            $storage->create($field_storage_values)
                ->save();
        }
        $fieldSettings = [
            'display_summary' => TRUE,
        ];
        $this->entityAddExtraField($entity_type, $type, $realFieldName, $fieldLabel, $fieldSettings, $fieldWidget, $widgetSettings);
    }
    
    /**
     * Get storage for fields configuration.
     *
     * @return \Drupal\Core\Entity\EntityStorageInterface
     *   The entity storage.
     *
     * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
     * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
     */
    protected function getFieldStorageConfig() {
        return $this->entityTypeManager()
            ->getStorage('field_storage_config');
    }
    
    /**
     * Get EntityStorage for Fields Configuration.
     *
     * @return \Drupal\Core\Entity\EntityStorageInterface
     *   storage of fields configuration.
     *
     * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
     * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
     */
    protected function getFieldConfig() {
        return $this->entityTypeManager()
            ->getStorage('field_config');
    }
    
    /**
     * Add a new field to the entity type.
     *
     * @param string $entity_type
     *   The entity type name to be modified.
     * @param \Drupal\Core\Entity\EntityInterface $type
     *   The definition of type.
     * @param string $fieldName
     *   Field name (the real one used internally).
     * @param string $fieldLabel
     *   Field description (what is show in forms).
     * @param array $fieldSettings
     *   Settings for the field.
     * @param string $fieldWidget
     *   Name of the widget to use.
     * @param array $widgetSettings
     *   Settings to set for the widget.
     *
     * @return \Drupal\Core\Entity\EntityInterface
     *   The Field Entity.
     *
     * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
     * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
     * @throws \Drupal\Core\Entity\EntityStorageException
     */
    protected function entityAddExtraField($entity_type, EntityInterface $type, $fieldName, $fieldLabel, array $fieldSettings, $fieldWidget, array $widgetSettings) {
        $machineName = strtolower($fieldName);
        // Add or remove the body field, as needed.
        $storage = $this->getFieldStorageConfig();
        $field_storage = $storage->load($entity_type . '.' . $machineName);
        $field_config = $this->getFieldConfig();
        $field = $field_config->load($entity_type . '.' . $type->id() . '.' . $machineName);
        if (empty($field)) {
            $field = $field_config->create([
                'field_storage' => $field_storage,
                'bundle' => $type->id(),
                'label' => $fieldLabel,
                'settings' => $fieldSettings,
            ]);
            $field->save();
        }
        // Assign widget settings for the 'default' form mode.
        $this->entity_get_form_display($entity_type, $type->id(), 'default')
            ->setComponent($machineName, [
            'type' => $fieldWidget,
            'settings' => $widgetSettings,
        ])
            ->save();
        // Assign display settings for the 'default' and 'teaser' view modes.
        $this->entity_get_display($entity_type, $type->id(), 'default')
            ->setComponent($machineName, [
            'label' => 'hidden',
            'type' => 'text_default',
        ])
            ->save();
        // The teaser view mode is created by the Standard profile and therefore
        // might not exist.
        $view_modes = $this->entityDisplayRepository
            ->getViewModes($entity_type);
        if (isset($view_modes['teaser'])) {
            $this->entity_get_display($entity_type, $type->id(), 'teaser')
                ->setComponent($machineName, [
                'label' => 'hidden',
                'type' => 'text_summary_or_trimmed',
            ])
                ->save();
        }
        return $field;
    }
    
    /**
     * Add a field that reference a vocabulary.
     *
     * @param string $entity_type
     *   The entity type name to be modified.
     * @param \Drupal\Core\Entity\EntityInterface $type
     *   The definition of type.
     * @param string $fieldLabel
     *   Field description (what is show in forms).
     * @param string $fieldName
     *   Field name (the real one used internally).
     * @param string $fieldType
     *   Name of the field type to be added.
     * @param string $fieldTypeBundle
     *   Name of the bundle to be used.
     * @param string $fieldWidget
     *   Name of the widget to use.
     * @param array $widgetSettings
     *   Settings to set for the widget.
     * @param array $settings
     *   Specific setting for the field (optional).
     *
     * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
     * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
     * @throws \Drupal\Core\Entity\EntityStorageException
     */
    protected function addReferenceToEntityType($entity_type, EntityInterface $type, $fieldLabel, $fieldName, $fieldType, $fieldTypeBundle, $fieldWidget, array $widgetSettings = [], array $settings = []) {
        $realFieldName = 'field_' . $fieldName;
        $storage = $this->getFieldStorageConfig();
        $field_storage = $storage->load($entity_type . '.' . $realFieldName);
        if (empty($field_storage)) {
            $field_storage_values = [
                'field_name' => $realFieldName,
                'field_label' => $fieldLabel,
                'entity_type' => $entity_type,
                'bundle' => $type->id(),
                'type' => 'entity_reference',
                'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
                'translatable' => FALSE,
                'settings' => [
                    'target_type' => $fieldType,
                ],
            ];
            $temp = $storage->create($field_storage_values);
            $temp->save();
        }
        $fieldSettings = [
            'handler' => 'default:' . $fieldType,
            'handler_settings' => [
                'target_bundles' => [
                    $fieldTypeBundle => $fieldTypeBundle,
                ],
            ],
            'sort' => [
                'field' => '_none',
            ],
            'auto_create' => FALSE,
            'auto_create_bundle' => '',
        ];
        $this->entityAddExtraField($entity_type, $type, $realFieldName, $fieldLabel, $fieldSettings, $fieldWidget, $widgetSettings);
    }
    
    /**
     * Escape a string by using HTML entities.
     *
     * @param string $exif_value
     *   UTF8 values to be escaped.
     *
     * @return string
     *   value with HTML Entities.
     */
    protected function sanitizeValue($exif_value) {
        if (!Unicode::validateUtf8($exif_value)) {
            $exif_value = Html::escape(utf8_encode($exif_value));
        }
        return $exif_value;
    }
    
    /**
     * Ensure field is visible in default form.
     *
     * @param string $field_name
     *   Name of the field to add to the view.
     * @param int $widget_id
     *   Widget used in the form or NULL if default.
     */
    protected function configureEntityFormDisplay($field_name, $widget_id = NULL) {
        // Make sure the field is displayed in the 'default' form mode (using
        // default widget and settings). It stays hidden for other form modes
        // until it is explicitly configured.
        $options = $widget_id ? [
            'type' => $widget_id,
        ] : [];
        $this->entity_get_form_display($this->entityTypeId, $this->bundle, 'default')
            ->setComponent($field_name, $options)
            ->save();
    }
    
    /**
     * Ensure field is visible in default view.
     *
     * @param string $field_name
     *   Name of the field to add to the view.
     * @param int $formatter_id
     *   Formatter associated to this view and this field or NULL if default.
     */
    protected function configureEntityViewDisplay($field_name, $formatter_id = NULL) {
        // Make sure the field is displayed in the 'default' view mode (using
        // default formatter and settings). It stays hidden for other view
        // modes until it is explicitly configured.
        $options = $formatter_id ? [
            'type' => $formatter_id,
        ] : [];
        $this->entity_get_display($this->entityTypeId, $this->bundle, 'default')
            ->setComponent($field_name, $options)
            ->save();
    }
    
    /**
     * Implements hook_entity_get_form_display().
     */
    public function entity_get_form_display($entity_type, $bundle, $form_mode) {
        // Try loading the entity from configuration.
        $entity_form_display = EntityFormDisplay::load($entity_type . '.' . $bundle . '.' . $form_mode);
        // If not found, create a fresh entity object. We do not preemptively create
        // new entity form display configuration entries for each existing entity
        // type and bundle whenever a new form mode becomes available.
        // Instead, configuration entries are only created when an entity form
        // display is explicitly configured and saved.
        if (!$entity_form_display) {
            $entity_form_display = EntityFormDisplay::create([
                'targetEntityType' => $entity_type,
                'bundle' => $bundle,
                'mode' => $form_mode,
                'status' => TRUE,
            ]);
        }
        return $entity_form_display;
    }
    
    /**
     * Implements hook_entity_get_display().
     */
    public function entity_get_display($entity_type, $bundle, $view_mode) {
        // Try loading the display from configuration.
        $display = EntityViewDisplay::load($entity_type . '.' . $bundle . '.' . $view_mode);
        // If not found, create a fresh display object. We do not preemptively
        // create new entity_view_display configuration entries for each existing
        // entity type and bundle whenever a new view mode becomes available.
        // Instead, configuration entries are only created when a display object
        // is explicitly configured and saved.
        if (!$display) {
            $display = EntityViewDisplay::create([
                'targetEntityType' => $entity_type,
                'bundle' => $bundle,
                'mode' => $view_mode,
                'status' => TRUE,
            ]);
        }
        return $display;
    }

}

Classes

Title Deprecated Summary
ExifSettingsController Class ExifSettingsController manage action of settings pages.