10 changed files with 410 additions and 0 deletions
@ -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' |
@ -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; |
||||||
|
} |
@ -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); |
@ -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); |
@ -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: {} |
@ -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 |
@ -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' |
@ -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 } |
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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.')); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue