View source
<?php
namespace Drupal\exif;
use Drupal;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Datetime\Entity\DateFormat;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldConfigInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\UriItem;
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
use Drupal\file\Plugin\Field\FieldType\FileFieldItemList;
use Drupal\taxonomy\Entity\Term;
class ExifContent {
private $localCopiesOfRemoteFiles = [];
public function checkTitle($entityType, FieldableEntityInterface $entity) {
$bundles_to_check = $this
->getBundleForExifData();
if (in_array($entity
->bundle(), $bundles_to_check)) {
$exif = ExifFactory::getExifInterface();
$ar_exif_fields = $this
->filterFieldsOnSettings($entityType, $entity);
$ar_exif_fields = $exif
->getMetadataFields($ar_exif_fields);
foreach ($ar_exif_fields as $drupal_field => $metadata_field_descriptor) {
$field_name = $drupal_field;
if ($field_name == 'title') {
$field = $entity
->get($field_name);
if ($field
->isEmpty()) {
$field
->appendItem("EXIF_FILLED");
}
break;
}
}
}
}
private function getBundleForExifData() {
$config = Drupal::config('exif.settings');
$new_types = [];
foreach ($config
->get('nodetypes', []) as $type) {
if ($type != "0") {
$new_types[] = $type;
}
}
foreach ($config
->get('mediatypes', []) as $type) {
if ($type != "0") {
$new_types[] = $type;
}
}
foreach ($config
->get('filetypes', []) as $type) {
if ($type != "0") {
$new_types[] = $type;
}
}
return $new_types;
}
private function filterFieldsOnSettings($entityType, FieldableEntityInterface $entity) {
$result = [];
foreach ($entity
->getFieldDefinitions() as $fieldName => $fieldDefinition) {
if ($fieldDefinition instanceof FieldConfigInterface || ($fieldDefinition instanceof BaseFieldDefinition and $fieldName === 'title')) {
$settings = \Drupal::entityTypeManager()
->getStorage('entity_form_display')
->load($entityType . '.' . $entity
->bundle() . '.default')
->getComponent($fieldName)['settings'];
$exifField = NULL;
$mediaField = NULL;
$imageField = NULL;
$exifFieldSeparator = NULL;
if ($settings != NULL) {
if (array_key_exists('exif_field', $settings)) {
$exifField = $settings['exif_field'];
}
if (array_key_exists('exif_field_separator', $settings)) {
$exifFieldSeparator = $settings['exif_field_separator'];
}
if (array_key_exists('image_field', $settings)) {
$imageField = $settings['image_field'];
}
if (array_key_exists('media_generic', $settings)) {
$mediaField = $settings['media_generic'];
}
}
if (isset($exifField) && (isset($imageField) || isset($mediaField))) {
$element = [];
if ($exifField == 'naming_convention') {
$name = substr($fieldName, 6);
}
else {
$name = $exifField;
}
$element['metadata_field'] = $name;
if (isset($exifFieldSeparator) && strlen($exifFieldSeparator) > 0) {
$element['metadata_field_separator'] = $exifFieldSeparator;
}
if (!isset($imageField) && isset($mediaField)) {
$element['image_field'] = $mediaField;
}
else {
$element['image_field'] = $imageField;
}
$result[$fieldName] = $element;
}
}
}
return $result;
}
public function entity_insert_update($entityType, FieldableEntityInterface $entity, $update = TRUE) {
$bundles_to_check = $this
->getBundleForExifData();
if (in_array($entity
->bundle(), $bundles_to_check)) {
$exif = ExifFactory::getExifInterface();
$ar_exif_fields = $this
->filterFieldsOnSettings($entityType, $entity);
$ar_exif_fields = $exif
->getMetadataFields($ar_exif_fields);
if (!$update && isset($entity->original)) {
$original = $entity->original;
foreach ($ar_exif_fields as $drupal_field => $metadata_field_descriptor) {
$field_name = $drupal_field;
$field = $entity
->get($field_name);
$field
->offsetSet(0, $original
->get($field_name));
}
}
else {
$image_fields = $this
->getImageFields($entity);
$metadata_images_fields = $this
->getImageFieldsMetadata($entity, $ar_exif_fields, $image_fields);
foreach ($ar_exif_fields as $drupal_field => $metadata_field_descriptor) {
$field_name = $drupal_field;
$field = $entity
->get($field_name);
$key = $metadata_field_descriptor['metadata_field']['tag'];
$section = $metadata_field_descriptor['metadata_field']['section'];
if (array_key_exists($metadata_field_descriptor['image_field'], $metadata_images_fields)) {
if ($key == "all") {
$j = 0;
foreach ($metadata_images_fields[$metadata_field_descriptor['image_field']] as $metadata_image_fields) {
$html = '<table class="metadata-table"><tbody>';
foreach ($metadata_image_fields 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-value"><td>' . $currentKey . '</td><td>' . $exif_value . '</td></tr>';
}
}
$html .= '</tbody><tfoot></tfoot></table>';
$this
->handleTextField($j, $field, $section, $key, [
"value" => $html,
'format' => 'full_html',
]);
$j++;
}
}
else {
$values = [];
foreach ($metadata_images_fields[$metadata_field_descriptor['image_field']] as $metadata_image_fields) {
if (array_key_exists($section, $metadata_image_fields) && array_key_exists($key, $metadata_image_fields[$section])) {
$value = $metadata_image_fields[$section][$key];
if (is_string($value) && isset($metadata_field_descriptor['metadata_field_separator'])) {
if (is_string($metadata_field_descriptor['metadata_field_separator'])) {
$subValues = explode($metadata_field_descriptor['metadata_field_separator'], $value);
foreach ($subValues as $index => $subValue) {
$values[] = $subValue;
}
}
else {
$values[] = $value;
}
}
else {
if (is_array($value)) {
$values = array_merge($values, $value);
}
else {
$values[] = $value;
}
}
}
}
$j = 0;
foreach ($values as $innerkey => $value) {
$this
->handleField($j, $field, $section, $key, $value);
$j++;
}
}
}
}
}
}
}
private function getImageFields(FieldableEntityInterface $entity) {
$result = [];
if ($entity
->getEntityTypeId() == 'node' or $entity
->getEntityTypeId() == 'media') {
foreach ($entity
->getFieldDefinitions() as $fieldName => $fieldDefinition) {
if ($fieldDefinition
->getType() == 'image') {
$result[$fieldName] = $fieldDefinition;
}
}
}
if ($entity
->getEntityTypeId() == 'file') {
$result['file'] = $entity;
}
return $result;
}
private function getImageFieldsMetadata(FieldableEntityInterface $entity, &$ar_exif_fields, $image_fields) {
$result = [];
if (empty($ar_exif_fields)) {
return TRUE;
}
if (empty($image_fields)) {
return FALSE;
}
foreach ($ar_exif_fields as $drupal_field => $metadata_settings) {
$field_image_name = $metadata_settings['image_field'];
if (empty($image_fields[$field_image_name])) {
$result[$field_image_name] = [];
}
else {
$images_descriptor = $this
->getFileUriAndLanguage($entity, $field_image_name);
if ($images_descriptor == FALSE) {
$fullmetadata = [];
}
else {
foreach ($images_descriptor as $index => $image_descriptor) {
$fullmetadata[$index] = $this
->getDataFromFileUri($image_descriptor['uri']);
}
}
$result[$field_image_name] = $fullmetadata;
$ar_exif_fields[$drupal_field]['language'] = $image_descriptor['language'];
}
}
return $result;
}
private function getFileUriAndLanguage(FieldableEntityInterface $entity, $field_image_name) {
$result = FALSE;
if ($entity
->getEntityTypeId() == 'node' || $entity
->getEntityTypeId() == 'media') {
$image_field_instance = $entity
->get($field_image_name);
if ($image_field_instance instanceof FileFieldItemList) {
$nbImages = count($image_field_instance
->getValue());
$result = [];
for ($i = 0; $i < $nbImages; $i++) {
$result[$i] = [];
$tmp = $image_field_instance
->get($i)->entity;
$result[$i]['uri'] = $tmp->uri[0];
$result[$i]['language'] = $tmp
->language();
}
}
}
else {
if ($entity
->getEntityTypeId() == 'file') {
$result = [];
$result[0] = [];
$result[0]['uri'] = $entity->uri;
$result[0]['language'] = $entity
->language();
}
}
return $result;
}
private function getDataFromFileUri(UriItem $file_uri) {
$uri = $file_uri
->getValue()['value'];
$file_system = \Drupal::service('file_system');
$scheme = $file_system
->uriScheme($uri);
if (!isset(\Drupal::service('stream_wrapper_manager')
->getWrappers(StreamWrapperInterface::LOCAL)[$scheme])) {
$cache_key = md5($uri);
if (empty($this->localCopiesOfRemoteFiles[$cache_key])) {
if (!($this->localCopiesOfRemoteFiles[$cache_key] = file_unmanaged_copy($uri, 'temporary://exif_' . $cache_key . '_' . basename($uri), FILE_EXISTS_REPLACE))) {
\Drupal::logger('exif')
->notice('Unable to create local temporary copy of remote file for exif extraction! File %file.', [
'%file' => $uri,
]);
return [];
}
}
$uri = $this->localCopiesOfRemoteFiles[$cache_key];
}
$exif = ExifFactory::getExifInterface();
$fullmetadata = $exif
->readMetadataTags($file_system
->realpath($uri));
return $fullmetadata;
}
private function sanitizeValue($exif_value) {
if (!Unicode::validateUtf8($exif_value)) {
$exif_value = Html::escape(utf8_encode($exif_value));
}
return $exif_value;
}
private function handleTextField($index, FieldItemListInterface &$field, $exif_section, $exif_name, $exif_sanitized_value) {
$field
->offsetSet($index, $exif_sanitized_value);
}
private function handleField($index, FieldItemListInterface &$field, $exif_section, $exif_name, $exif_value) {
$value = $this
->sanitizeValue($exif_value);
$field_typename = $field
->getFieldDefinition()
->getType();
if (in_array($field_typename, [
'text',
'text_long',
'text_with_summary',
'string',
'string_long',
])) {
$this
->handleTextField($index, $field, $exif_section, $exif_name, $value);
}
else {
if ($field_typename == 'entity_reference' && $field
->getFieldDefinition()
->getFieldStorageDefinition()
->getSetting('target_type') == 'taxonomy_term') {
$this
->handleTaxonomyField($index, $field, $exif_section, $exif_name, $value);
}
else {
if ($field_typename == 'datetime' || $field_typename == 'date') {
$this
->handleDateField($index, $field, $exif_section, $exif_name, $value);
}
}
}
}
public function handleTaxonomyField($index, FieldItemListInterface &$field, $exif_section, $exif_name, $exif_value) {
if (!Unicode::validateUtf8($exif_value)) {
$exif_value = Html::escape(utf8_encode($exif_value));
}
$config = Drupal::config('exif.settings');
$chosen_vocabulary = array_keys($field
->getSettings('vocabulary')['handler_settings']['target_bundles'])[0];
if (isset($chosen_vocabulary)) {
$terms = taxonomy_term_load_multiple_by_name($exif_value, $chosen_vocabulary);
if (is_array($terms) && count($terms) > 0) {
$term = array_shift($terms);
}
else {
$terms = taxonomy_term_load_multiple_by_name($exif_name, $chosen_vocabulary);
if (is_array($terms) && count($terms) > 0) {
$parent_term = array_shift($terms);
}
else {
$terms = taxonomy_term_load_multiple_by_name($exif_section, $chosen_vocabulary);
if (is_array($terms) && count($terms) > 0) {
$section_term = array_shift($terms);
}
else {
$section_term = $this
->createTerm($chosen_vocabulary, $exif_section);
}
$parent_term = $this
->createTerm($chosen_vocabulary, $exif_name, $section_term
->id());
}
$term = $this
->createTerm($chosen_vocabulary, $exif_value, $parent_term
->id());
}
$field
->offsetSet($index, $term
->id());
}
}
public function createTerm($vid, $name, $parent_term_id = 0) {
$values = [
'vid' => $vid,
'name' => $name,
'parent' => $parent_term_id,
];
$term = Term::create($values);
$term
->save();
return $term;
}
public function handleDateField($index, FieldItemListInterface &$field, $exif_section, $exif_name, $exif_sanitized_value) {
if ($exif_name == 'filedatetime') {
$format = 'atom';
}
else {
$format = 'exif';
}
$dateFormatStorage = Drupal::getContainer()
->get('entity.manager')
->getStorage('date_format');
if ($dateFormatStorage instanceof EntityStorageInterface) {
$dateFormat = $dateFormatStorage
->load($format);
if ($dateFormat instanceof DateFormat) {
$date_datetime = DrupalDateTime::createFromFormat($dateFormat
->getPattern(), $exif_sanitized_value);
$storage_format = $field
->getFieldDefinition()
->getSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE ? DATETIME_DATE_STORAGE_FORMAT : DATETIME_DATETIME_STORAGE_FORMAT;
$value = $date_datetime
->format($storage_format);
$field
->offsetSet($index, $value);
}
}
}
public function __destruct() {
foreach ($this->localCopiesOfRemoteFiles as $uri) {
\Drupal::service('file_system')
->unlink($uri);
}
}
}