create OCFL node.json files for each node and associated media/files.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

261 lines
9.1 KiB

<?php
declare(strict_types=1);
namespace Drupal\ocfl_export\Form;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\ocfl_export\OcflStorageService;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Configuration form for OCFL Export settings.
*/
class OcflSettingsForm extends ConfigFormBase {
public function __construct(
ConfigFactoryInterface $config_factory,
protected EntityTypeManagerInterface $entityTypeManager,
protected OcflStorageService $storageService,
) {
parent::__construct($config_factory);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container): static {
return new static(
$container->get('config.factory'),
$container->get('entity_type.manager'),
$container->get('ocfl_export.storage'),
);
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames(): array {
return ['ocfl_export.settings'];
}
/**
* {@inheritdoc}
*/
public function getFormId(): string {
return 'ocfl_export_settings_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state): array {
$config = $this->config('ocfl_export.settings');
// Storage status.
$form['status'] = [
'#type' => 'details',
'#title' => $this->t('Storage Status'),
'#open' => TRUE,
];
$initialized = $this->storageService->isInitialized();
$form['status']['storage_status'] = [
'#type' => 'item',
'#title' => $this->t('OCFL Storage'),
'#markup' => $initialized
? $this->t('<span style="color: green;">Initialized</span> at @path', ['@path' => $this->storageService->getStorageRoot()])
: $this->t('<span style="color: orange;">Not initialized</span> - will be created on first export'),
];
// Storage settings.
$form['storage'] = [
'#type' => 'details',
'#title' => $this->t('Storage Settings'),
'#open' => TRUE,
];
$form['storage']['storage_root'] = [
'#type' => 'textfield',
'#title' => $this->t('Storage Root Path'),
'#description' => $this->t('The filesystem path where OCFL objects will be stored. Use stream wrappers like private:// or public://, or an absolute path.'),
'#default_value' => $config->get('storage_root'),
'#required' => TRUE,
];
$form['storage']['ocfl_version'] = [
'#type' => 'select',
'#title' => $this->t('OCFL Version'),
'#options' => [
'1.1' => '1.1',
'1.0' => '1.0',
],
'#default_value' => $config->get('ocfl_version') ?: '1.1',
'#description' => $this->t('The OCFL specification version to use.'),
];
// Export settings.
$form['export'] = [
'#type' => 'details',
'#title' => $this->t('Export Settings'),
'#open' => TRUE,
];
$form['export']['auto_export_enabled'] = [
'#type' => 'checkbox',
'#title' => $this->t('Enable automatic export on node save'),
'#description' => $this->t('When enabled, nodes will be automatically exported to OCFL when saved.'),
'#default_value' => $config->get('auto_export_enabled'),
];
// Get all content types.
$contentTypes = $this->entityTypeManager->getStorage('node_type')->loadMultiple();
$options = [];
foreach ($contentTypes as $type) {
$options[$type->id()] = $type->label();
}
$form['export']['content_types'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Content Types to Export'),
'#description' => $this->t('Select which content types should be exported. Leave empty to export all content types.'),
'#options' => $options,
'#default_value' => $config->get('content_types') ?: [],
];
// Media export settings.
$form['media_export'] = [
'#type' => 'details',
'#title' => $this->t('Media Export Settings'),
'#open' => TRUE,
];
$form['media_export']['auto_export_media_enabled'] = [
'#type' => 'checkbox',
'#title' => $this->t('Enable automatic export on media save'),
'#description' => $this->t('When enabled, media entities will be automatically exported to OCFL when saved.'),
'#default_value' => $config->get('auto_export_media_enabled'),
];
// Get all media types.
$mediaTypes = $this->entityTypeManager->getStorage('media_type')->loadMultiple();
$mediaOptions = [];
foreach ($mediaTypes as $type) {
$mediaOptions[$type->id()] = $type->label();
}
$form['media_export']['media_types'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Media Types to Export'),
'#description' => $this->t('Select which media types should be exported. Leave empty to export all media types.'),
'#options' => $mediaOptions,
'#default_value' => $config->get('media_types') ?: [],
];
// Files and relationships.
$form['content'] = [
'#type' => 'details',
'#title' => $this->t('Files and Relationships'),
'#open' => TRUE,
];
$form['content']['include_files'] = [
'#type' => 'checkbox',
'#title' => $this->t('Copy files into OCFL objects'),
'#description' => $this->t('Copy the binaries of associated media and of file/image fields into each object. Unchanged files are not copied again in later versions. When unchecked, only metadata is exported.'),
'#default_value' => $config->get('include_files') ?? TRUE,
];
$form['content']['media_of_field'] = [
'#type' => 'textfield',
'#title' => $this->t('"Media of" field'),
'#description' => $this->t('Media field that references the node the media belongs to (Islandora: field_media_of). Media found through it are included in the OCFL object of that node. Leave empty to disable.'),
'#default_value' => $config->get('media_of_field'),
];
$form['content']['member_of_field'] = [
'#type' => 'textfield',
'#title' => $this->t('"Member of" field'),
'#description' => $this->t('Node field that references parent nodes (Islandora: field_member_of). Used to record direct parents and the full collection hierarchy. Leave empty to disable.'),
'#default_value' => $config->get('member_of_field'),
];
$form['content']['model_field'] = [
'#type' => 'textfield',
'#title' => $this->t('Model field'),
'#description' => $this->t('Node field that references the model term (Islandora: field_model). Leave empty to disable.'),
'#default_value' => $config->get('model_field'),
];
// Initialize button.
$form['actions']['initialize'] = [
'#type' => 'submit',
'#value' => $this->t('Initialize Storage'),
'#submit' => ['::initializeStorage'],
'#weight' => 10,
];
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state): void {
parent::validateForm($form, $form_state);
$storagePath = $form_state->getValue('storage_root');
// Check if path uses a valid stream wrapper or is an absolute path.
if (!str_contains($storagePath, '://') && !str_starts_with($storagePath, '/')) {
$form_state->setErrorByName('storage_root', $this->t('Storage path must be an absolute path or use a stream wrapper (e.g., private://).'));
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state): void {
// Filter out unchecked content types.
$contentTypes = array_filter($form_state->getValue('content_types'));
// Filter out unchecked media types.
$mediaTypes = array_filter($form_state->getValue('media_types'));
$this->config('ocfl_export.settings')
->set('storage_root', $form_state->getValue('storage_root'))
->set('auto_export_enabled', (bool) $form_state->getValue('auto_export_enabled'))
->set('content_types', array_values($contentTypes))
->set('auto_export_media_enabled', (bool) $form_state->getValue('auto_export_media_enabled'))
->set('media_types', array_values($mediaTypes))
->set('ocfl_version', $form_state->getValue('ocfl_version'))
->set('include_files', (bool) $form_state->getValue('include_files'))
->set('media_of_field', trim((string) $form_state->getValue('media_of_field')))
->set('member_of_field', trim((string) $form_state->getValue('member_of_field')))
->set('model_field', trim((string) $form_state->getValue('model_field')))
->save();
parent::submitForm($form, $form_state);
}
/**
* Submit handler to initialize storage.
*/
public function initializeStorage(array &$form, FormStateInterface $form_state): void {
// Save config first.
$this->submitForm($form, $form_state);
// Initialize storage.
if ($this->storageService->initializeStorageRoot()) {
$this->messenger()->addStatus($this->t('OCFL storage has been initialized at @path.', [
'@path' => $this->storageService->getStorageRoot(),
]));
}
else {
$this->messenger()->addError($this->t('Failed to initialize OCFL storage. Check the logs for details.'));
}
}
}