2 changed files with 175 additions and 0 deletions
@ -0,0 +1,155 @@
|
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace Drupal\islandora_inplace_media\Commands; |
||||
|
||||
use Drush\Commands\DrushCommands; |
||||
use Drupal\Core\File\FileSystemInterface; |
||||
use Drupal\file\FileRepositoryInterface; |
||||
use Drupal\Core\State\StateInterface; |
||||
use Drupal\Core\Queue\QueueFactory; |
||||
use Drupal\file\Entity\File; |
||||
use Drupal\media\Entity\Media; |
||||
use Drupal\Core\File\FileExists; |
||||
use Symfony\Component\Console\Helper\ProgressBar; |
||||
use Psr\Log\LoggerInterface; |
||||
|
||||
class IslandoraInplaceMediaCommands extends DrushCommands { |
||||
|
||||
protected FileSystemInterface $fileSystem; |
||||
protected FileRepositoryInterface $fileRepository; |
||||
protected LoggerInterface $logger; |
||||
protected StateInterface $state; |
||||
protected QueueFactory $queueFactory; |
||||
|
||||
public function __construct( |
||||
FileSystemInterface $fileSystem, |
||||
FileRepositoryInterface $fileRepository, |
||||
LoggerInterface $logger, |
||||
StateInterface $state, |
||||
QueueFactory $queueFactory, |
||||
) { |
||||
parent::__construct(); |
||||
$this->fileSystem = $fileSystem; |
||||
$this->fileRepository = $fileRepository; |
||||
$this->logger = $logger; |
||||
$this->state = $state; |
||||
$this->queueFactory = $queueFactory; |
||||
} |
||||
|
||||
/** |
||||
* Process media files (optionally queued and resumable). |
||||
* |
||||
* @command islandora:inplace-media |
||||
* @aliases iim |
||||
* |
||||
* @option source_dir |
||||
* @option destination_path |
||||
* @option media_type |
||||
* @option media_use |
||||
* @option file_type |
||||
* @option ownership |
||||
* @option queue |
||||
* Queue files instead of processing immediately. |
||||
* @option reset |
||||
* Reset saved progress. |
||||
*/ |
||||
public function inplaceMedia(array $options = [ |
||||
'source_dir' => NULL, |
||||
'destination_path' => NULL, |
||||
'media_type' => NULL, |
||||
'media_use' => NULL, |
||||
'file_type' => 'field_media_file', |
||||
'ownership' => NULL, |
||||
'queue' => FALSE, |
||||
'reset' => FALSE, |
||||
]): void { |
||||
|
||||
$files = array_diff(scandir($options['source_dir']), ['.', '..']); |
||||
|
||||
$job_id = hash('sha256', serialize($options)); |
||||
$state_key = "islandora_inplace_media.progress.$job_id"; |
||||
|
||||
if ($options['reset']) { |
||||
$this->state->delete($state_key); |
||||
$this->output()->writeln('Progress reset.'); |
||||
} |
||||
|
||||
$processed = $this->state->get($state_key, []); |
||||
$remaining = array_values(array_diff($files, $processed)); |
||||
|
||||
if (empty($remaining)) { |
||||
$this->output()->success('Nothing left to process.'); |
||||
return; |
||||
} |
||||
|
||||
if ($options['queue']) { |
||||
$this->enqueueFiles($remaining, $options); |
||||
$this->output()->success('Files queued for processing.'); |
||||
return; |
||||
} |
||||
|
||||
$progress = new ProgressBar($this->output(), count($remaining)); |
||||
$progress->start(); |
||||
|
||||
foreach ($remaining as $file_name) { |
||||
$this->processFile($file_name, $options); |
||||
$processed[] = $file_name; |
||||
$this->state->set($state_key, $processed); |
||||
$progress->advance(); |
||||
} |
||||
|
||||
$progress->finish(); |
||||
$this->output()->newLine(2); |
||||
$this->output()->success('Processing complete.'); |
||||
} |
||||
|
||||
/** |
||||
* Enqueue files for background processing. |
||||
*/ |
||||
protected function enqueueFiles(array $files, array $options): void { |
||||
$queue = $this->queueFactory->get('islandora_inplace_media'); |
||||
|
||||
foreach ($files as $file) { |
||||
$queue->createItem([ |
||||
'file' => $file, |
||||
'options' => $options, |
||||
]); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Process a single file. |
||||
*/ |
||||
protected function processFile(string $file_name, array $build_data): void { |
||||
$source = "{$build_data['source_dir']}/{$file_name}"; |
||||
$dest = "{$build_data['destination_path']}/{$file_name}"; |
||||
|
||||
if (!file_exists($source)) { |
||||
$this->logger->warning('Missing file @file', ['@file' => $source]); |
||||
return; |
||||
} |
||||
|
||||
$path = ($source === $dest) |
||||
? $dest |
||||
: $this->fileSystem->copy($source, $dest, FileExists::Rename); |
||||
|
||||
$file = $this->fileRepository->loadByUri($path) |
||||
?? File::create(['uri' => $path, 'status' => 1]); |
||||
|
||||
$file->save(); |
||||
|
||||
preg_match('/^(\d+)_/', $file_name, $m); |
||||
$nid = $m[1] ?? NULL; |
||||
|
||||
Media::create([ |
||||
'bundle' => $build_data['media_type'], |
||||
'name' => $file_name, |
||||
$build_data['file_type'] => ['target_id' => $file->id()], |
||||
'field_media_use' => ['target_id' => $build_data['media_use']], |
||||
'field_media_of' => $nid, |
||||
])->save(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,20 @@
|
||||
<?php |
||||
|
||||
namespace Drupal\islandora_inplace_media\Plugin\QueueWorker; |
||||
|
||||
use Drupal\Core\Queue\QueueWorkerBase; |
||||
|
||||
/** |
||||
* @QueueWorker( |
||||
* id = "islandora_inplace_media", |
||||
* title = @Translation("Islandora Inplace Media"), |
||||
* cron = {"time" = 60} |
||||
* ) |
||||
*/ |
||||
class InplaceMediaQueueWorker extends QueueWorkerBase { |
||||
|
||||
public function processItem($data) { |
||||
\Drupal::service('islandora_inplace_media.commands') |
||||
->processFile($data['file'], $data['options']); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue