Browse Source

working drush

drush
ajstanley 2 days ago
parent
commit
c949672072
  1. 7
      drush.services.yml
  2. 4
      islandora_inplace_media.info.yml
  3. 15
      islandora_inplace_media.services.yml
  4. 140
      src/Commands/IslandoraInplaceMediaCommands.php
  5. 3
      src/Plugin/QueueWorker/InplaceMediaQueueWorker.php
  6. 50
      src/Service/InplaceMediaProcessor.php

7
drush.services.yml

@ -0,0 +1,7 @@
services:
islandora_inplace_media.commands:
class: Drupal\islandora_inplace_media\Commands\IslandoraInplaceMediaCommands
arguments:
- '@islandora_inplace_media.processor'
tags:
- { name: drush.command }

4
islandora_inplace_media.info.yml

@ -1,7 +1,7 @@
name: 'Islandora Inplace Media' name: 'Islandora Inplace Media'
type: module type: module
description: 'Allows Uploaded files to be attched to exisitng nodes as media' description: 'Allows Uploaded files to be attached to existing nodes as media'
package: Custom package: Islandora
core_version_requirement: ^10 || ^11 core_version_requirement: ^10 || ^11
dependencies: dependencies:
- islandora:islandora - islandora:islandora

15
islandora_inplace_media.services.yml

@ -1,4 +1,13 @@
services: services:
islandora_inplace_media.utils:
class: Drupal\islandora_inplace_media\Utils logger.channel.islandora_inplace_media:
arguments: ['@entity_type.manager', '@file_system', '@logger.factory', '@entity_field.manager'] class: Drupal\Core\Logger\LoggerChannel
factory: logger.factory:get
arguments: ['islandora_inplace_media']
islandora_inplace_media.processor:
class: Drupal\islandora_inplace_media\Service\InplaceMediaProcessor
arguments:
- '@file_system'
- '@file.repository'
- '@logger.channel.islandora_inplace_media'

140
src/Commands/IslandoraInplaceMediaCommands.php

@ -1,155 +1,77 @@
<?php <?php
declare(strict_types=1);
namespace Drupal\islandora_inplace_media\Commands; namespace Drupal\islandora_inplace_media\Commands;
use Drush\Commands\DrushCommands; use Drush\Commands\DrushCommands;
use Drupal\Core\File\FileSystemInterface; use Drupal\islandora_inplace_media\Service\InplaceMediaProcessor;
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 Symfony\Component\Console\Helper\ProgressBar;
use Psr\Log\LoggerInterface;
class IslandoraInplaceMediaCommands extends DrushCommands { class IslandoraInplaceMediaCommands extends DrushCommands {
protected FileSystemInterface $fileSystem;
protected FileRepositoryInterface $fileRepository;
protected LoggerInterface $logger;
protected StateInterface $state;
protected QueueFactory $queueFactory;
public function __construct( public function __construct(
FileSystemInterface $fileSystem, protected InplaceMediaProcessor $processor
FileRepositoryInterface $fileRepository,
LoggerInterface $logger,
StateInterface $state,
QueueFactory $queueFactory,
) { ) {
parent::__construct(); parent::__construct();
$this->fileSystem = $fileSystem;
$this->fileRepository = $fileRepository;
$this->logger = $logger;
$this->state = $state;
$this->queueFactory = $queueFactory;
} }
/** /**
* Process media files (optionally queued and resumable). * Create Islandora media from files.
* *
* @command islandora:inplace-media * @command islandora:inplace-media
* @aliases iim * @aliases iim
* *
* @option source_dir * @option source_dir
* Source directory containing files.
* @option destination_path * @option destination_path
* Destination directory (public://, private://, or absolute).
* @option media_type * @option media_type
* Media bundle machine name.
* @option media_use * @option media_use
* Taxonomy term ID for field_media_use.
* @option file_type * @option file_type
* @option ownership * Media file field name.
* @option limit
* Maximum number of files to process.
* @option offset
* Number of files to skip before processing.
* @option queue * @option queue
* Queue files instead of processing immediately. * Queue files instead of processing immediately.
* @option reset
* Reset saved progress.
*/ */
public function inplaceMedia(array $options = [ public function run(array $options = [
'source_dir' => NULL, 'source_dir' => NULL,
'destination_path' => NULL, 'destination_path' => NULL,
'media_type' => NULL, 'media_type' => NULL,
'media_use' => NULL, 'media_use' => NULL,
'file_type' => 'field_media_file', 'file_type' => 'field_media_file',
'ownership' => NULL, 'limit' => NULL,
'offset' => 0,
'queue' => FALSE, 'queue' => FALSE,
'reset' => FALSE, ]) {
]): void { $files = array_values(array_diff(scandir($options['source_dir']), ['.', '..']));
$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)) { if ($options['offset']) {
$this->output()->success('Nothing left to process.'); $files = array_slice($files, (int) $options['offset']);
return;
} }
if ($options['limit']) {
if ($options['queue']) { $files = array_slice($files, 0, (int) $options['limit']);
$this->enqueueFiles($remaining, $options);
$this->output()->success('Files queued for processing.');
return;
} }
$progress = new ProgressBar($this->output(), count($remaining)); $progress = new ProgressBar($this->output(), count($files));
$progress->start(); $progress->start();
foreach ($remaining as $file_name) { foreach ($files as $file) {
$this->processFile($file_name, $options); if ($options['queue']) {
$processed[] = $file_name; \Drupal::queue('islandora_inplace_media')
$this->state->set($state_key, $processed); ->createItem(['file' => $file, 'options' => $options]);
}
else {
$this->processor->processFile($file, $options);
}
$progress->advance(); $progress->advance();
} }
$progress->finish(); $progress->finish();
$this->output()->newLine(2); $this->output()->writeln('');
$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();
} }
} }

3
src/Plugin/QueueWorker/InplaceMediaQueueWorker.php

@ -14,7 +14,8 @@ use Drupal\Core\Queue\QueueWorkerBase;
class InplaceMediaQueueWorker extends QueueWorkerBase { class InplaceMediaQueueWorker extends QueueWorkerBase {
public function processItem($data) { public function processItem($data) {
\Drupal::service('islandora_inplace_media.commands') \Drupal::service('islandora_inplace_media.processor')
->processFile($data['file'], $data['options']); ->processFile($data['file'], $data['options']);
} }
} }

50
src/Service/InplaceMediaProcessor.php

@ -0,0 +1,50 @@
<?php
namespace Drupal\islandora_inplace_media\Service;
use Drupal\Core\File\FileSystemInterface;
use Drupal\file\FileRepositoryInterface;
use Drupal\Core\File\FileExists;
use Drupal\file\Entity\File;
use Drupal\media\Entity\Media;
use Psr\Log\LoggerInterface;
class InplaceMediaProcessor {
public function __construct(
protected FileSystemInterface $fileSystem,
protected FileRepositoryInterface $fileRepository,
protected LoggerInterface $logger,
) {}
public function processFile(string $file, array $opts): void {
$source = "{$opts['source_dir']}/{$file}";
$dest = "{$opts['destination_path']}/{$file}";
if (!file_exists($source)) {
$this->logger->warning('Missing file @file', ['@file' => $source]);
return;
}
$uri = ($source === $dest)
? $dest
: $this->fileSystem->copy($source, $dest, FileExists::Rename);
$fileEntity = $this->fileRepository->loadByUri($uri)
?? File::create(['uri' => $uri, 'status' => 1]);
$fileEntity->save();
preg_match('/^(\d+)_/', $file, $m);
$nid = $m[1] ?? NULL;
Media::create([
'bundle' => $opts['media_type'],
'name' => $file,
$opts['file_type'] => ['target_id' => $fileEntity->id()],
'field_media_use' => ['target_id' => $opts['media_use']],
'field_media_of' => $nid,
])->save();
}
}
Loading…
Cancel
Save