pdf_to_imagefield-1.0.x-dev/src/PDFToImageBatchHelper.php
src/PDFToImageBatchHelper.php
<?php
namespace Drupal\pdf_to_imagefield;
use Drupal\Component\Render\PlainTextOutput;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Utility\Token;
use Drupal\file\Entity\File;
use Drupal\file\FileInterface;
use Spatie\PdfToImage\Pdf;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\Mime\MimeTypeGuesserInterface;
/**
* Provides helper class for batch.
*/
class PDFToImageBatchHelper {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface|null
*/
protected static $entityTypeManager = NULL;
/**
* The file system service.
*
* @var \Drupal\Core\File\FileSystemInterface|null
*/
protected static $fileSystem = NULL;
/**
* The token replacement instance.
*
* @var \Drupal\Core\Utility\Token|null
*/
protected static $token = NULL;
/**
* The Drupal messenger service.
*
* @var \Drupal\Core\Messenger\MessengerInterface|null
*/
protected static $messenger = NULL;
/**
* Retrieve entity type manager.
*
* @return \Drupal\Core\Entity\EntityTypeManagerInterface
* Entity manager interface.
*/
protected static function getEntityTypeManager():EntityTypeManagerInterface {
if (!self::$entityTypeManager) {
self::$entityTypeManager = \Drupal::entityTypeManager();
}
return self::$entityTypeManager;
}
/**
* Retrieve file system service.
*
* @return \Drupal\Core\File\FileSystemInterface
* File system.
*/
protected static function getFileSystem():FileSystemInterface {
if (!self::$fileSystem) {
self::$fileSystem = \Drupal::service('file_system');
}
return self::$fileSystem;
}
/**
* Retrieve token.
*
* @return \Drupal\Core\Utility\Token
* Token
*/
protected static function getToken():Token {
if (!self::$token) {
self::$token = \Drupal::service('token');
}
return self::$token;
}
/**
* Retrieve messenger.
*
* @return \Drupal\Core\Messenger\MessengerInterface
* Message interface
*/
protected static function getMessenger():MessengerInterface {
if (!self::$messenger) {
self::$messenger = \Drupal::messenger();
}
return self::$messenger;
}
/**
* Move non PDF files.
*/
public static function moveNonPdfFiles(array $base_batch_data, array $files, &$context) {
if (!isset($context['results']['files'])) {
$context['results']['files'] = [];
}
$context['results']['params'] = $base_batch_data;
$context['results']['files'] = array_merge($context['results']['files'], $files);
}
/**
* Generate single page of PDF file.
*/
public static function generateProcessPage(array $base_batch_data, FileInterface $pdf_file, Pdf $pdf, int $start, int $end, &$context) {
if (!isset($context['results']['files'])) {
$context['results']['files'] = [];
}
$context['results']['params'] = $base_batch_data;
for ($page_number = $start; $page_number <= $end; $page_number++) {
$file = self::generatePage($base_batch_data, $pdf_file, $pdf, $page_number);
if ($file instanceof FileInterface) {
$context['results']['files'][] = $file;
}
}
}
/**
* Provides conversion logic from PDF page to the image.
*/
protected static function generatePage(array $params, FileInterface $pdf_file, Pdf $pdf, int $page_number = 1) {
/** @var \Drupal\field\FieldConfigInterface $field_definition */
$field_definition = reset($params['image']['instance']);
$settings = $field_definition->getSettings();
$destination = self::getUploadLocation($settings);
$prepared_filename = $pdf_file->id() . '-' . $page_number . '.' . $pdf->getOutputFormat();
// Create the file.
$file_uri = "{$destination}/{$prepared_filename}";
if ($destination === $settings['uri_scheme'] . '://') {
$file_uri = "{$destination}{$prepared_filename}";
}
$file_uri = self::getFileSystem()->getDestinationFilename($file_uri, FileSystemInterface::EXISTS_RENAME);
$image_temp_path = self::getFileSystem()->getTempDirectory() . '/' . $prepared_filename;
$pdf->setPage($page_number)
->saveImage($image_temp_path);
if (file_exists($image_temp_path)) {
// @todo logger about successful creation.
}
$guesser = \Drupal::service('file.mime_type.guesser');
$prepared_filename = self::getFileSystem()->basename($image_temp_path);
$current_user = \Drupal::currentUser();
$file = File::create();
$file->setOwnerId($current_user->id());
$file->setFilename($prepared_filename);
if ($guesser instanceof MimeTypeGuesserInterface) {
$file->setMimeType($guesser->guessMimeType($prepared_filename));
@trigger_error('\Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Implement \Symfony\Component\Mime\MimeTypeGuesserInterface instead. See https://www.drupal.org/node/3133341', E_USER_DEPRECATED);
}
$file->setFileUri($image_temp_path);
$file->setSize(@filesize($image_temp_path));
$file->setFileUri($file_uri);
// Move the file to the correct location after validation. Use
// FileSystemInterface::EXISTS_ERROR as the file location has already been
// determined above in FileSystem::getDestinationFilename().
try {
self::$fileSystem->move($image_temp_path, $file_uri, FileSystemInterface::EXISTS_ERROR);
}
catch (FileException $e) {
throw new HttpException(500, 'Temporary file could not be moved to file location');
}
$file->save();
return $file;
}
/**
* Batch Finished callback.
*
* @param bool $success
* Success of the operation.
* @param array $results
* Array of results for post processing.
* @param array $operations
* Array of operations.
*/
public static function generateProcessAttach(bool $success, array $results, array $operations) {
$messenger = self::getMessenger();
if ($success) {
if (empty($results)) {
$messenger->addMessage(t('No files produced from processing document'));
}
else {
$messenger->addMessage(t('@count files processed.', ['@count' => count($results['files'])]));
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = $results['params']['entity'];
/** @var \Drupal\field\FieldStorageConfigInterface $image_field */
$image_field = reset($results['params']['image']['field']);
$field_name = $image_field->getName();
$entity_type_manager = self::getEntityTypeManager();
if ($entity->id()) {
// Don't use the entity as given,
// load it again as things may have happened
// to it since the batch job began.
/** @var \Drupal\Core\Entity\ContentEntityInterface|null $entity */
$entity = $entity_type_manager->getStorage($entity->getEntityTypeId())->load($entity->id());
if ($entity) {
$entity->set($field_name, []);
ksort($results['files'], SORT_NUMERIC);
$file_ids = [];
/** @var \Drupal\file\FileInterface $file */
foreach ($results['files'] as $file) {
$file_ids[] = $file->id();
}
$entity->set($field_name, $file_ids);
$entity->save();
}
}
}
}
else {
// An error occurred.
// $operations contains the operations that remained unprocessed.
$error_operation = reset($operations);
$messenger->addMessage(
t('An error occurred while processing @operation with arguments : @args',
[
'@operation' => $error_operation[0],
'@args' => print_r($error_operation[0], TRUE),
]
)
);
}
}
/**
* Determines the URI for a file field.
*
* @param array $settings
* The array of field settings.
*
* @return string
* An un-sanitized file directory URI with tokens replaced. The result of
* the token replacement is then converted to plain text and returned.
*/
protected static function getUploadLocation(array $settings) {
$destination = trim($settings['file_directory'], '/');
// Replace tokens. As the tokens might contain HTML we convert it to plain
// text.
$destination = PlainTextOutput::renderFromHtml(self::getToken()->replace($destination, [], [], new BubbleableMetadata()));
return $settings['uri_scheme'] . '://' . $destination;
}
}
