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('Initialized at @path', ['@path' => $this->storageService->getStorageRoot()]) : $this->t('Not initialized - 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.')); } } }