From 0ae027d4a5d30436289c3c541c87d9d85c182457 Mon Sep 17 00:00:00 2001 From: ajstanley <astanley@upei.ca> Date: Fri, 28 Feb 2025 14:40:32 +0000 Subject: [PATCH] working --- config/schema/roblib_alter_solr.schema.yml | 8 + css/styles.css | 34 ++++ js/help_modal.js | 43 ++++ js/roblib_alter_solr.js | 31 +++ roblib_alter_solr.libraries.yml | 13 ++ roblib_alter_solr.links.menu.yml | 6 + roblib_alter_solr.routing.yml | 7 + roblib_alter_solr.services.yml | 6 + .../RoblibAlterSolrSubscriber.php | 79 ++++++++ src/Form/RoblibAlterSolrSettingsForm.php | 183 ++++++++++++++++++ 10 files changed, 410 insertions(+) create mode 100644 config/schema/roblib_alter_solr.schema.yml create mode 100644 css/styles.css create mode 100644 js/help_modal.js create mode 100644 js/roblib_alter_solr.js create mode 100644 roblib_alter_solr.libraries.yml create mode 100644 roblib_alter_solr.links.menu.yml create mode 100644 roblib_alter_solr.routing.yml create mode 100644 roblib_alter_solr.services.yml create mode 100644 src/EventSubscriber/RoblibAlterSolrSubscriber.php create mode 100644 src/Form/RoblibAlterSolrSettingsForm.php diff --git a/config/schema/roblib_alter_solr.schema.yml b/config/schema/roblib_alter_solr.schema.yml new file mode 100644 index 0000000..1b11736 --- /dev/null +++ b/config/schema/roblib_alter_solr.schema.yml @@ -0,0 +1,8 @@ +# Schema for the configuration files of the Roblib Alter Solr module. +roblib_alter_solr.settings: + type: config_object + label: 'Roblib Alter Solr settings' + mapping: + example: + type: string + label: 'Example' diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 0000000..fa6a270 --- /dev/null +++ b/css/styles.css @@ -0,0 +1,34 @@ +/* Modal styles */ +.modal { + display: none; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0, 0, 0, 0.4); +} + +.modal-content { + background-color: #fff; + margin: 15% auto; + padding: 20px; + border: 1px solid #888; + width: 80%; +} + +.close-button { + color: #aaa; + font-size: 28px; + font-weight: bold; + float: right; +} + +.close-button:hover, +.close-button:focus { + color: black; + text-decoration: none; + cursor: pointer; +} diff --git a/js/help_modal.js b/js/help_modal.js new file mode 100644 index 0000000..ecb6259 --- /dev/null +++ b/js/help_modal.js @@ -0,0 +1,43 @@ +(function ($, Drupal) { + Drupal.behaviors.robib_solr_alterlBehavior = { + attach: function (context, settings) { + // Attach event to the modal link without using once() + $('#open-modal-link', context).click(function (e) { + e.preventDefault(); + // Create the modal content + var modalContent = '<div id="help-modal" class="modal">' + + '<div class="modal-content">' + + '<span class="close-button">×</span>' + + '<h2>Roblib Solr Alter</h2>' + + '<p>The form allows you two or more existing Solr fields to a new multivalues field.</p>' + + '<p>Select existing fields from the dropdowns on the left, and pair them with a new field</ br> '+ + 'in the column on the right. Your new field name comply with your Solr installion\'s schema.</p>' + + '</div>' + + '</div>'; + + // Append the modal to the body + $('body').append(modalContent); + + + // Show the modal + $('#help-modal').fadeIn(); + + // Close the modal when clicking the close button + $('#help-modal .close-button').click(function () { + $('#help-modal').fadeOut(function () { + $('#help-modal').remove(); // Remove modal from DOM after closing + }); + }); + + // Close the modal when clicking outside the modal content + $(window).click(function(event) { + if ($(event.target).is('#help-modal')) { + $('#help-modal').fadeOut(function () { + $('#help-modal').remove(); // Remove modal from DOM + }); + } + }); + }); + } + }; +})(jQuery, Drupal); diff --git a/js/roblib_alter_solr.js b/js/roblib_alter_solr.js new file mode 100644 index 0000000..d4e6073 --- /dev/null +++ b/js/roblib_alter_solr.js @@ -0,0 +1,31 @@ +(function ($, Drupal, once) { + Drupal.behaviors.addRowVisibility = { + attach: function (context, settings) { + function toggleButton() { + var sourceField = $('.source-field', context); + var destinationField = $('.destination-field', context); + + // Ensure source and destination fields exist before checking values + if (sourceField.length > 0 && destinationField.length > 0) { + var sourceFilled = sourceField.find('option:selected').length > 0; + var destinationFilled = destinationField.val().trim().length > 0; + // Show/hide button based on whether both fields are filled + if (sourceFilled && destinationFilled) { + $('.form-submit[value="Add Row"]', context).show(); + } else { + $('.form-submit[value="Add Row"]', context).hide(); + } + } else { + console.error('Source or destination field is missing'); + } + } + + once('toggleButton', '.source-field, .destination-field', context).forEach(function (element) { + $(element).on('change keyup', toggleButton); + }); + + toggleButton(); // Run initially to set the correct state + + } + }; +})(jQuery, Drupal, once); diff --git a/roblib_alter_solr.libraries.yml b/roblib_alter_solr.libraries.yml new file mode 100644 index 0000000..00d0952 --- /dev/null +++ b/roblib_alter_solr.libraries.yml @@ -0,0 +1,13 @@ +roblib_alter_solr: + version: 1.x + js: + js/roblib_alter_solr.js: {} + js/help_modal.js: {} + dependencies: + - core/drupal + - core/jquery + - core/drupal.once + - core/drupalSettings + css: + theme: + css/styles.css: {} \ No newline at end of file diff --git a/roblib_alter_solr.links.menu.yml b/roblib_alter_solr.links.menu.yml new file mode 100644 index 0000000..88e1db4 --- /dev/null +++ b/roblib_alter_solr.links.menu.yml @@ -0,0 +1,6 @@ +roblib_alter_solr.roblib_alter_solr_settings: + title: Roblib alter solr settings + description: Configure Solr overrides + parent: system.admin_config_system + route_name: roblib_alter_solr.roblib_alter_solr_settings + weight: 10 diff --git a/roblib_alter_solr.routing.yml b/roblib_alter_solr.routing.yml new file mode 100644 index 0000000..3ec34c7 --- /dev/null +++ b/roblib_alter_solr.routing.yml @@ -0,0 +1,7 @@ +roblib_alter_solr.roblib_alter_solr_settings: + path: '/admin/config/system/roblib-alter-solr-settings' + defaults: + _title: 'Roblib alter solr settings' + _form: 'Drupal\roblib_alter_solr\Form\RoblibAlterSolrSettingsForm' + requirements: + _permission: 'administer site configuration' diff --git a/roblib_alter_solr.services.yml b/roblib_alter_solr.services.yml new file mode 100644 index 0000000..c4cafdd --- /dev/null +++ b/roblib_alter_solr.services.yml @@ -0,0 +1,6 @@ +services: + roblib_alter_solr.event_subscriber: + class: Drupal\roblib_alter_solr\EventSubscriber\RoblibAlterSolrSubscriber + arguments: ['@logger.factory', '@config.factory'] + tags: + - { name: event_subscriber } diff --git a/src/EventSubscriber/RoblibAlterSolrSubscriber.php b/src/EventSubscriber/RoblibAlterSolrSubscriber.php new file mode 100644 index 0000000..94af3e1 --- /dev/null +++ b/src/EventSubscriber/RoblibAlterSolrSubscriber.php @@ -0,0 +1,79 @@ +<?php + +namespace Drupal\roblib_alter_solr\EventSubscriber; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Drupal\Core\Logger\LoggerChannelFactoryInterface; +use Drupal\search_api_solr\Event\SearchApiSolrEvents; +use Drupal\search_api_solr\Event\PostCreateIndexDocumentEvent; +use Drupal\Core\Config\ConfigFactory; + +/** + * Allows users to combine Solr fields dynamically. + */ +final class RoblibAlterSolrSubscriber implements EventSubscriberInterface { + + /** + * The logger service. + * + * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface + */ + protected $logger; + + /** + * The Config factory. + * + * @var \Drupal\Core\Config\ConfigFactory + */ + protected $config; + + /** + * Constructs a new RoblibAlterSolrSubscriber. + * + * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory + * The logger factory service. + * @param \Drupal\Core\Config\ConfigFactory $config + * The config factory service. + */ + public function __construct(LoggerChannelFactoryInterface $logger_factory, ConfigFactory $config) { + $this->logger = $logger_factory->get('roblib_alter_solr'); + $this->config = $config->get('roblib_alter_solr.settings'); + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents(): array { + return [ + SearchApiSolrEvents::POST_CREATE_INDEX_DOCUMENT => 'onAlterSolrDocument', + ]; + } + + /** + * Alters the Solr document before indexing. + * + * @param \Drupal\search_api_solr\Event\PostCreateIndexDocumentEvent $event + * The Solr document alter event. + */ + public function onAlterSolrDocument(PostCreateIndexDocumentEvent $event) { + $solrDocument = $event->getSolariumDocument(); + $item = $event->getSearchApiItem(); + $pairs = $this->config->get('pairs'); + foreach ($pairs as $index => $values) { + $fields = array_values($values['source']); + $consolidated_values = []; + foreach ($fields as $field) { + $field_value = $item->getField($field); + if ($field_value && $field_value->getValues()) { + $all_values = $field_value->getValues(); + $consolidated_values[] = $all_values[0]; + } + } + if ($consolidated_values) { + $field_name = "sm_{$values['destination']}"; + $solrDocument->setField($field_name, $consolidated_values); + } + } + } + +} diff --git a/src/Form/RoblibAlterSolrSettingsForm.php b/src/Form/RoblibAlterSolrSettingsForm.php new file mode 100644 index 0000000..4f458de --- /dev/null +++ b/src/Form/RoblibAlterSolrSettingsForm.php @@ -0,0 +1,183 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\roblib_alter_solr\Form; + +use Drupal\Core\Form\ConfigFormBase; +use Drupal\Core\Form\FormStateInterface; + +/** + * Configure Roblib Alter Solr settings for this site. + */ +final class RoblibAlterSolrSettingsForm extends ConfigFormBase { + + /** + * {@inheritdoc} + */ + public function getFormId(): string { + return 'roblib_alter_solr_roblib_alter_solr_settings'; + } + + /** + * {@inheritdoc} + */ + protected function getEditableConfigNames(): array { + return ['roblib_alter_solr.settings']; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + $config = $this->config('roblib_alter_solr.settings'); + $solr_config = $this->config('search_api.index.default_solr_index'); + $solr_fields = $solr_config->get('field_settings'); + $fields_options = []; + foreach ($solr_fields as $name => $field) { + $fields_options[$name] = $field['label']; + } + // Use getStorage() to persist state across AJAX calls. + $pairs = $form_state->getStorage()['pairs'] ?? $form_state->get('pairs') ?? $config->get('pairs') ?? []; + $form_state->setStorage(['pairs' => $pairs]); + $form['open_modal'] = [ + '#type' => 'markup', + '#markup' => '<a href="#" id="open-modal-link">' . $this->t('How to use this form') . '</a>', + '#prefix' => '<div id="open_link-wrapper">', + '#suffix' => '</div>', + ]; + + $form['pairs'] = [ + '#type' => 'table', + '#header' => [ + $this->t('Source'), + $this->t('Destination'), + $this->t('Operations'), + ], + '#prefix' => '<div id="pairs-wrapper">', + '#suffix' => '</div>', + ]; + $added = FALSE; + + foreach ($pairs as $index => $pair) { + $form['pairs'][$index]['source'] = [ + '#type' => 'select', + '#multiple' => TRUE, + '#options' => $fields_options, + '#default_value' => $pair['source'] ?? '', + ]; + + $form['pairs'][$index]['destination'] = [ + '#type' => 'textfield', + '#default_value' => $pair['destination'] ?? '', + ]; + if ($pair['source'] && $pair['destination']) { + $form['pairs'][$index]['remove'] = [ + '#type' => 'submit', + '#value' => $this->t('Remove'), + '#submit' => ['::removeCallback'], + '#ajax' => [ + 'callback' => '::ajaxCallback', + 'wrapper' => 'pairs-wrapper', + ], + '#name' => 'remove_' . $index, + '#limit_validation_errors' => [], + ]; + } + else { + $form['pairs'][$index]['add'] = [ + '#type' => 'submit', + '#value' => $this->t('Add Row'), + '#submit' => ['::addCallback'], + '#ajax' => [ + 'callback' => '::ajaxCallback', + 'wrapper' => 'pairs-wrapper', + ], + ]; + $form['pairs'][$index]['source']['#attributes'] = ['class' => ['source-field']]; + $form['pairs'][$index]['destination']['#attributes'] = ['class' => ['destination-field']]; + $added = TRUE; + } + + } + if (!$added) { + $unique_id = uniqid(); + $pairs[$unique_id] = ['source' => '', 'destination' => '']; + $form['pairs'][$unique_id]['source'] = [ + '#type' => 'select', + '#multiple' => TRUE, + '#options' => $fields_options, + '#default_value' => '', + '#attributes' => ['class' => ['source-field']], + ]; + + $form['pairs'][$unique_id]['destination'] = [ + '#type' => 'textfield', + '#default_value' => '', + '#attributes' => ['class' => ['destination-field']], + ]; + $form['add'] = [ + '#type' => 'submit', + '#value' => $this->t('Add Row'), + '#submit' => ['::addCallback'], + '#ajax' => [ + 'callback' => '::ajaxCallback', + 'wrapper' => 'pairs-wrapper', + ], + ]; + + } + $form['#attached']['library'][] = 'roblib_alter_solr/roblib_alter_solr'; + + return parent::buildForm($form, $form_state); + } + + /** + * Callback function to add a new row. + */ + public function addCallback(array &$form, FormStateInterface $form_state) { + $user_input = $form_state->getUserInput(); + $unique_id = uniqid(); + $pairs = $user_input['pairs'] ?? []; + $pairs[$unique_id] = ['source' => '', 'destination' => '']; + $form_state->set('pairs', $pairs); + $form_state->setRebuild(); + } + + /** + * Callback function to remove a row. + */ + public function removeCallback(array &$form, FormStateInterface $form_state) { + $trigger = $form_state->getTriggeringElement(); + $index = str_replace('remove_', '', $trigger['#name']); + $pairs = $form_state->get('pairs') ?? []; + + if (isset($pairs[$index])) { + unset($pairs[$index]); + $form_state->set('pairs', $pairs); + } + + $form_state->setRebuild(); + } + + /** + * AJAX callback to update the form. + */ + public function ajaxCallback(array &$form, FormStateInterface $form_state) { + return $form['pairs']; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $pairs = $form_state->getValue('pairs'); + $config = $this->config('roblib_alter_solr.settings'); + $config->set('pairs', $pairs)->save(); + + $this->messenger()->addStatus($this->t('Configuration saved successfully.')); + } + + + +}