content_sync-8.x-2.x-dev/src/Normalizer/FileEntityNormalizer.php
src/Normalizer/FileEntityNormalizer.php
<?php namespace Drupal\content_sync\Normalizer; use Drupal\content_sync\Plugin\SyncNormalizerDecoratorManager; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\EntityTypeRepositoryInterface; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\File\FileUrlGeneratorInterface; /** * Adds the file URI to embedded file entities. */ class FileEntityNormalizer extends ContentEntityNormalizer { /** * The interface or class that this Normalizer supports. * * @var string */ protected $supportedInterfaceOrClass = 'Drupal\file\FileInterface'; /** * File system service. * * @var \Drupal\Core\File\FileSystemInterface */ protected $fileSystem; /** * The file URL generator. * * @var \Drupal\Core\File\FileUrlGeneratorInterface */ protected $fileUrlGenerator; /** * FileEntityNormalizer constructor. * * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The entity type manager. * @param \Drupal\Core\Entity\EntityTypeRepositoryInterface $entity_type_repository * The entity type repository. * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager * The entity field manager. * * @param \Drupal\content_sync\Plugin\SyncNormalizerDecoratorManager $decorator_manager * * @param \Drupal\Core\File\FileSystemInterface $file_system * File system service. * @param \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator * The file URL generator. */ public function __construct( EntityTypeManagerInterface $entity_type_manager, EntityTypeRepositoryInterface $entity_type_repository, EntityFieldManagerInterface $entity_field_manager, SyncNormalizerDecoratorManager $decorator_manager, FileSystemInterface $file_system, FileUrlGeneratorInterface $file_url_generator) { parent::__construct($entity_type_manager, $entity_type_repository, $entity_field_manager, $decorator_manager); $this->fileSystem = $file_system; $this->fileUrlGenerator = $file_url_generator; } /** * {@inheritdoc} */ public function denormalize($data, $class, $format = NULL, array $serializer_context = array()): array|string|int|float|bool|\ArrayObject|NULL { $file_data = ''; // Check if the image is available as base64-encoded image. if (!empty($data['data'][0]['value'])) { $file_data = $data['data'][0]['value']; // Avoid 'data' being treated as a field. unset($data['data']); } // If a directory is set, we must to copy the file to the file system. if (!empty($serializer_context['content_sync_directory_files'])) { $scheme = \Drupal::service('stream_wrapper_manager')->getScheme($data['uri'][0]['value']); if (!empty($scheme)) { $source_path = realpath($serializer_context['content_sync_directory_files']) . '/' .$scheme . '/'; $source = str_replace($scheme . '://', $source_path, $data['uri'][0]['value']); if (file_exists($source)) { $file = $this->fileSystem->realpath($data['uri'][0]['value']); if (!file_exists($file) || (md5_file($file) !== md5_file($source))) { $dir = $this->fileSystem->dirname($data['uri'][0]['value']); $this->fileSystem->prepareDirectory($dir, FileSystemInterface::CREATE_DIRECTORY); $uri = $this->fileSystem->copy($source, $data['uri'][0]['value']); $data['uri'] = [ [ 'value' => $uri, 'url' => str_replace($GLOBALS['base_url'], '', $this->fileUrlGenerator->generateAbsoluteString($uri)) ] ]; // We just need one method to create the image. $file_data = ''; } } } } $entity = parent::denormalize($data, $class, $format, $serializer_context); // If the image was sent as base64 we must to create the physical file. if ($file_data) { // Decode and save to file. $file_contents = base64_decode($file_data); $dirname = $this->fileSystem->dirname($entity->getFileUri()); $this->fileSystem->prepareDirectory($dirname, FileSystemInterface::CREATE_DIRECTORY); if ($uri = $this->fileSystem->saveData($file_contents, $entity->getFileUri())) { $entity->setFileUri($uri); } else { throw new \RuntimeException(new FormattableMarkup('Failed to write @filename.', ['@filename' => $entity->getFilename()])); } } // If the image was sent as URL we must to create the physical file. /*if ($file_data) { // Decode and save to file. $file_contents = base64_decode($file_data); $dirname = $this->fileSystem->dirname($entity->getFileUri()); file_prepare_directory($dirname, FILE_CREATE_DIRECTORY); if ($uri = file_unmanaged_save_data($file_contents, $entity->getFileUri())) { $entity->setFileUri($uri); } else { throw new \RuntimeException(SafeMarkup::format('Failed to write @filename.', array('@filename' => $entity->getFilename()))); } }*/ return $entity; } /** * {@inheritdoc} */ public function normalize($object, $format = NULL, array $serializer_context = array()): array|\ArrayObject|bool|float|int|NULL|string { $data = parent::normalize($object, $format, $serializer_context); // The image will be saved in the export directory. if (!empty($serializer_context['content_sync_directory_files'])) { $uri = $object->getFileUri(); $scheme = \Drupal::service('stream_wrapper_manager')->getScheme($uri); $destination = "{$serializer_context['content_sync_directory_files']}/{$scheme}/"; $destination = str_replace($scheme . '://', $destination, $uri); $prep_dir = $this->fileSystem->dirname($destination); $this->fileSystem->prepareDirectory($prep_dir, FileSystemInterface::CREATE_DIRECTORY); // Exception for when the file doesn't exist // TODO: add a notice/log about it. if (file_exists($uri)) { $this->fileSystem->copy($uri, $destination, FileSystemInterface::EXISTS_REPLACE); } } // Set base64-encoded file contents to the "data" property. if (!empty($serializer_context['content_sync_file_base_64'])) { $file_data = base64_encode(file_get_contents($object->getFileUri())); $data['data'] = [['value' => $file_data]]; } return $data; } }