Browse Source

initial commit

main
astanley 3 months ago
commit
503dc04d75
  1. 7
      islandora_collection_harvest.info.yml
  2. 3
      islandora_collection_harvest.permissions.yml
  3. 14
      islandora_collection_harvest.routing.yml
  4. 117
      src/Controller/HarvestDownloadController.php
  5. 173
      src/Form/CollectionHarvestForm.php

7
islandora_collection_harvest.info.yml

@ -0,0 +1,7 @@
name: Islandora Collection Harvest
type: module
description: Provides a form to select an Islandora collection and media use, build a ZIP, and download it via streams.
core_version_requirement: ^10
package: Islandora
dependencies:
- drupal:islandora

3
islandora_collection_harvest.permissions.yml

@ -0,0 +1,3 @@
access collection harvest:
title: 'Access Collection Harvest form'
description: 'Allows a user to access the collection harvest form to download media as ZIP'

14
islandora_collection_harvest.routing.yml

@ -0,0 +1,14 @@
islandora_collection_harvest.harvest_form:
path: '/admin/islandora/collection-harvest'
defaults:
_form: '\Drupal\islandora_collection_harvest\Form\CollectionHarvestForm'
_title: 'Collection Harvest'
requirements:
_permission: 'access collection harvest'
islandora_collection_harvest.download_zip:
path: '/islandora/collection-harvest/download/{filename}'
defaults:
_controller: '\Drupal\islandora_collection_harvest\Controller\HarvestDownloadController::download'
requirements:
_permission: 'access collection harvest'

117
src/Controller/HarvestDownloadController.php

@ -0,0 +1,117 @@
<?php
declare(strict_types=1);
namespace Drupal\islandora_collection_harvest\Controller;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Drupal\flysystem\FlysystemFactory;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
final class HarvestDownloadController extends ControllerBase {
protected FileSystemInterface $fileSystem;
protected PrivateTempStoreFactory $tempStoreFactory;
protected FlysystemFactory $flysystemFactory;
protected StreamWrapperManagerInterface $streamWrapperManager;
public function __construct(
FileSystemInterface $file_system,
PrivateTempStoreFactory $tempStoreFactory,
FlysystemFactory $flysystemFactory,
StreamWrapperManagerInterface $streamWrapperManager
) {
$this->fileSystem = $file_system;
$this->tempStoreFactory = $tempStoreFactory;
$this->flysystemFactory = $flysystemFactory;
$this->streamWrapperManager = $streamWrapperManager;
}
public static function create(ContainerInterface $container): self {
return new self(
$container->get('file_system'),
$container->get('tempstore.private'),
$container->get('flysystem_factory'),
$container->get('stream_wrapper_manager')
);
}
/**
* Builds and downloads archive.
*
* @param string $filename
*
* @return \Symfony\Component\HttpFoundation\StreamedResponse
*/
public function download(string $filename): StreamedResponse {
$temp_store = $this->tempStoreFactory->get('islandora_collection_harvest');
$media_entities = $temp_store->get($filename);
if (empty($media_entities)) {
throw new \Symfony\Component\HttpKernel\Exception\NotFoundHttpException('No media found.');
}
return new StreamedResponse(function() use ($media_entities) {
$zip = new \ZipArchive();
$tmpfile = tempnam(sys_get_temp_dir(), 'collection_zip_');
$zip->open($tmpfile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
foreach ($media_entities as $media) {
$source_field = $media->getSource()
->getConfiguration()['source_field'] ?? NULL;
if (!$source_field || !$media->hasField($source_field)) {
continue;
}
$file = $media->get($source_field)->entity;
if (!$file) {
continue;
}
$uri = $file->getFileUri();
$filename_in_zip = basename($uri);
$real_path = $this->fileSystem->realpath($uri);
if ($real_path && file_exists($real_path)) {
$zip->addFile($real_path, $filename_in_zip);
}
else {
// Flysystem v1 fallback
try {
$scheme = $this->streamWrapperManager->getScheme($uri);
$path = substr($uri, strlen($scheme) + 3);
$filesystem = $this->flysystemFactory->getFilesystem($scheme);
if ($filesystem && $filesystem->has($path)) {
$contents = $filesystem->read($path);
if ($contents !== FALSE) {
$tmp_fly = tempnam(sys_get_temp_dir(), 'zip_');
file_put_contents($tmp_fly, $contents);
$zip->addFile($tmp_fly, $filename_in_zip);
}
}
}
catch (\Exception $e) {
$this->logger('islandora_collection_harvest')->error(
'Error reading @uri from Flysystem: @msg',
['@uri' => $uri, '@msg' => $e->getMessage()]
);
}
}
}
$zip->close();
readfile($tmpfile);
unlink($tmpfile);
}, 200, [
'Content-Type' => 'application/zip',
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
]);
}
}

173
src/Form/CollectionHarvestForm.php

@ -0,0 +1,173 @@
<?php
declare(strict_types=1);
namespace Drupal\islandora_collection_harvest\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\flysystem\FlysystemFactory;
use Drupal\islandora\IslandoraUtils;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Form for selecting Collection and Media Use and preparing ZIP download.
*/
final class CollectionHarvestForm extends FormBase {
protected EntityTypeManagerInterface $entityTypeManager;
protected IslandoraUtils $utils;
protected FileSystemInterface $fileSystem;
protected FlysystemFactory $flysystemFactory;
protected PrivateTempStoreFactory $tempStoreFactory;
/**
* {@inheritdoc}
*/
public function __construct(
EntityTypeManagerInterface $entity_type_manager,
IslandoraUtils $utils,
FileSystemInterface $file_system,
FlysystemFactory $flysystem_factory,
PrivateTempStoreFactory $temp_store_factory
) {
$this->entityTypeManager = $entity_type_manager;
$this->utils = $utils;
$this->fileSystem = $file_system;
$this->flysystemFactory = $flysystem_factory;
$this->tempStoreFactory = $temp_store_factory;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container): self {
return new self(
$container->get('entity_type.manager'),
$container->get('islandora.utils'),
$container->get('file_system'),
$container->get('flysystem_factory'),
$container->get('tempstore.private')
);
}
/**
* {@inheritdoc}
*/
public function getFormId(): string {
return 'islandora_collection_harvest_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state): array {
$term = $this->utils->getTermForUri('http://purl.org/dc/dcmitype/Collection');
$collections = [];
if ($term) {
$query = $this->entityTypeManager->getStorage('node')->getQuery();
$query->condition('type', 'islandora_object');
$query->condition('field_model', $term->id(), 'IN');
$query->accessCheck(FALSE);
$nids = $query->execute();
$nodes = $this->entityTypeManager->getStorage('node')
->loadMultiple($nids);
foreach ($nodes as $node) {
$collections[$node->id()] = $node->label();
}
}
$vid = 'islandora_media_use';
$terms = $this->entityTypeManager->getStorage('taxonomy_term')
->loadTree($vid);
$media_use_options = [];
foreach ($terms as $term) {
$media_use_options[$term->tid] = $term->name;
}
$form['#attributes']['id'] = 'collection-harvest-form';
$form['collection'] = [
'#type' => 'select',
'#title' => $this->t('Collection'),
'#options' => $collections,
'#required' => TRUE,
];
$form['media_use'] = [
'#type' => 'select',
'#title' => $this->t('Media Use'),
'#options' => $media_use_options,
'#required' => TRUE,
];
$form['actions'] = [
'#type' => 'actions',
'submit' => [
'#type' => 'submit',
'#value' => $this->t('Build Download'),
'#button_type' => 'primary',
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state): void {
$collection_id = $form_state->getValue('collection');
$media_use_tid = $form_state->getValue('media_use');
$term = $this->entityTypeManager->getStorage('taxonomy_term')
->load($media_use_tid);
if (!$term) {
$this->messenger()->addError($this->t('Media use term not found.'));
return;
}
// Load nodes in collection
$query = $this->entityTypeManager->getStorage('node')->getQuery();
$query->condition('type', 'islandora_object');
$query->condition('field_member_of', $collection_id);
$query->accessCheck(FALSE);
$nids = $query->execute();
$media_entities = [];
foreach ($nids as $nid) {
$node = $this->entityTypeManager->getStorage('node')->load($nid);
$media = $this->utils->getMediaWithTerm($node, $term);
if ($media) {
$source_field = $media->getSource()
->getConfiguration()['source_field'] ?? NULL;
if ($source_field && $media->hasField($source_field) && !$media->get($source_field)
->isEmpty()) {
$media_entities[] = $media;
}
}
}
if (empty($media_entities)) {
$this->messenger()
->addError($this->t('No media found for this collection.'));
return;
}
// Store in tempstore
$temp_store = $this->tempStoreFactory->get('islandora_collection_harvest');
$zip_filename = 'collection_' . time() . '.zip';
$temp_store->set($zip_filename, $media_entities);
$this->messenger()
->addStatus($this->t('Your ZIP download has been initiated. Please wait for the download to start.'));
// Redirect to download route
$form_state->setRedirect('islandora_collection_harvest.download_zip', ['filename' => $zip_filename]);
}
}
Loading…
Cancel
Save