diff --git a/search_api.links.action.yml b/search_api.links.action.yml index 7d85b50..5b99f87 100644 --- a/search_api.links.action.yml +++ b/search_api.links.action.yml @@ -13,8 +13,3 @@ search_api.execute_tasks: title: 'Execute pending tasks' appears_on: - search_api.overview -entity.search_api_index.add_fields: - route_name: entity.search_api_index.add_fields - title: 'Add fields' - appears_on: - - entity.search_api_index.fields diff --git a/src/Form/IndexAddFieldsForm.php b/src/Form/IndexAddFieldsForm.php index 6c2d37d..a92a8f8 100644 --- a/src/Form/IndexAddFieldsForm.php +++ b/src/Form/IndexAddFieldsForm.php @@ -2,8 +2,10 @@ namespace Drupal\search_api\Form; +use Drupal\Component\Render\PlainTextOutput; use Drupal\Component\Render\FormattableMarkup; use Drupal\Component\Utility\Html; +use Drupal\Component\Utility\NestedArray; use Drupal\Core\Datetime\DateFormatter; use Drupal\Core\Entity\EntityForm; use Drupal\Core\Entity\EntityTypeManagerInterface; @@ -85,6 +87,15 @@ class IndexAddFieldsForm extends EntityForm { protected $unmappedFields = array(); /** + * REMOVE. + * + * Counter keeping track of the sequence of method invocation. + * + * @var int + */ + protected static $sequenceCounter = 0; + + /** * {@inheritdoc} */ public function getFormId() { @@ -121,6 +132,8 @@ class IndexAddFieldsForm extends EntityForm { $this->renderer = $renderer; $this->dateFormatter = $date_formatter; $this->parameters = $parameters; + // REMOVE. + $this->displayMethodInvocation('__construct'); } /** @@ -197,6 +210,9 @@ class IndexAddFieldsForm extends EntityForm { * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { + + $this->displayMethodInvocation('buildForm'); + $index = $this->entity; // Do not allow the form to be cached. See @@ -230,19 +246,60 @@ class IndexAddFieldsForm extends EntityForm { } } + // Set title. Strip html to accomodate modal title. $args['%index'] = $index->label(); - $form['#title'] = $this->t('Add fields to index %index', $args); + $form['#title'] = PlainTextOutput::renderFromHtml($this->t('Add fields to index %index', $args)); - $form['properties'] = array( - '#theme' => 'search_api_form_item_list', - ); - $datasources = array( - '' => NULL, + // Main container. + $form['index-fields'] = [ + '#type' => 'container', + '#attributes' => ['id' => 'index-fields'], + ]; + + // TEST. + $form['index-fields']['messages'] = [ + '#type' => 'container', + '#attributes' => ['id' => 'message-wrapper'], + ]; + + // We store the datasources we need to show in the form + // to accomodate the ajax magic. + // Create hidden form field to store datasources. + $form['datasources'] = array( + '#type' => 'hidden', ); - $datasources += $this->entity->getDatasources(); - foreach ($datasources as $datasource) { - $form['properties'][] = $this->getDatasourceListItem($datasource); + + // First set some defaults when nothing is set. + $form_state_datasources = $form_state->getValue('datasources'); + + dsm('form state at start of build form'); + dsm($form_state_datasources); + + if (empty($form_state_datasources)) { + dsm('leeg dus invullen'); + // Get the datasources to add. + // Start with the general fields. + $datasources = ['general' => NULL]; + // Add entity datasource. + $entity_datasources = $this->entity->getDatasources(); + // For each datasource add id to form value. + foreach ($entity_datasources as $entity_datasource) { + $datasource_id = $entity_datasource->getPluginId(); + $datasources[$datasource_id] = NULL; + } + $form['datasources']['#value'] = $datasources; + } + else { + dsm('niet leeg'); + $form['datasources']['#value'] = $form_state_datasources; } + dsm('deze datasources moeten we weergeven'); + dsm($form['datasources']['#value']); + + // Create form elementes for each of the datasources we want to show. + // This is a recursive function, allowing to show the nested elements. + $containers = $this->createFieldContainers($form['datasources']['#value']); + $form['index-fields']['properties'] = $containers; // Log any unmapped types that were encountered. if ($this->unmappedFields) { @@ -256,68 +313,201 @@ class IndexAddFieldsForm extends EntityForm { ->warning('Warning while retrieving available fields for index %index: could not find a type mapping for the following fields: @fields.', $vars); } - $form['actions'] = $this->actionsElement($form, $form_state); - return $form; } /** - * Creates a list item for one datasource. + * Create form elements for each field. * - * @param \Drupal\search_api\Datasource\DatasourceInterface|null $datasource - * The datasource, or NULL for general properties. + * @param array $fields + * A nested array which defines what fields to show. This info is + * stored in the form. * * @return array - * A render array representing the given datasource and, possibly, its - * attached properties. + * Return form elements. */ - protected function getDatasourceListItem(DatasourceInterface $datasource = NULL) { - $item = array( - '#type' => 'container', - '#attributes' => array( - 'class' => array('container-inline'), - ), - ); + protected function createFieldContainers(array $fields) { + foreach (array_keys($fields) as $datasource_id) { - $active = FALSE; - $datasource_id = $datasource ? $datasource->getPluginId() : ''; - $active_datasource = $this->getParameter('datasource'); - if (isset($active_datasource)) { - $active = $active_datasource == $datasource_id; - } + // Each element get's a container so we can add children for subelements. + $item = array( + '#type' => 'container', + '#attributes' => array( + 'class' => array('container-inline'), + '#attributes' => ['id' => '' . $datasource_id], + ), + '#field-name' => $datasource_id, + ); - $url = $this->entity->toUrl('add-fields'); - if ($active) { - $expand_link = array( - '#type' => 'link', - '#title' => '(-) ', - '#url' => $url, + $item['test'] = array( + '#markup' => 'Show ' . $datasource_id . ' in ' . 'index-field-' . $datasource_id . ' container', ); + + $active = FALSE; + + $active_datasource = $this->getParameter('datasource'); + if (isset($active_datasource)) { + $active = $active_datasource == $datasource_id; + } + + $url = $this->entity->toUrl('add-fields'); + if ($active) { + $expand_link = array( + '#type' => 'link', + '#title' => '(-) ', + '#url' => $url, + ); + } + else { + $url->setOption('query', array('datasource' => $datasource_id)); + $expand_link = array( + '#type' => 'link', + '#title' => '(+) ', + '#url' => $url, + ); + $expand_button = array( + '#type' => 'submit', + '#name' => 'expand_datasource_' . $datasource_id, + '#value' => '(+)', + '#submit' => ['::expandDatasourceFormSubmit'], + '#ajax' => [ + 'callback' => '::expandDatasourceFormAjax', + 'wrapper' => 'index-fields', + 'effect' => 'fade', + 'method' => 'replace', + ], + ); + + } + $item['expand_link'] = $expand_link; + $item['expand_button'] = $expand_button; + + //$label = $fields[$datasource_id] ? $fields[$datasource_id] : $this->t('General'); + //$item['label']['#markup'] = $label; + + if ($active) { + $properties = $this->entity->getPropertyDefinitions($datasource_id == 'general' ? NULL: $datasource_id); + if ($properties) { + $active_property_path = $this->getParameter('property_path', ''); + $base_url = clone $url; + $base_url->setOption('query', array('datasource' => $datasource_id)); + $item['properties'] = $this->getPropertiesList($properties, $active_property_path, $base_url); + } + } + $items[] = $item; + + // Add child elements. + if(is_array($fields[$datasource_id])){ + // Add new things. + $new_things = $this->createFieldContainers($fields[$datasource_id]); + foreach($new_things as $new_thing){ + $items[] = $new_thing; + } + } + + } - else { - $url->setOption('query', array('datasource' => $datasource_id)); - $expand_link = array( - '#type' => 'link', - '#title' => '(+) ', - '#url' => $url, - ); + return $items; + } + + /** + * Handles form submissions for expanding a datasource. + */ + public function expandDatasourceFormSubmit(&$form, FormStateInterface &$form_state) { + // REMOVE. + $this->displayMethodInvocation('expandDatasourceFormSubmit'); + + // Find the triggering field. + $button = $form_state->getTriggeringElement(); + // Go one level up in the form, to the widgets container. + $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -1)); + $field_name = $element['#field-name']; + + // Add new items to form state. + $datasources = $form_state->getValue('datasources'); + + $properties = $this->entity->getPropertyDefinitions($field_name == 'general' ? NULL : $field_name); + + //dsm(array_keys($properties)); + dsm('opgevraagde datasources'); + dsm($datasources); + foreach(array_keys($properties) as $property){ + $datasources[$field_name][$property] = NULL; } - $item['expand_link'] = $expand_link; - - $label = $datasource ? Html::escape($datasource->label()) : $this->t('General'); - $item['label']['#markup'] = $label; - - if ($active) { - $properties = $this->entity->getPropertyDefinitions($datasource_id ?: NULL); - if ($properties) { - $active_property_path = $this->getParameter('property_path', ''); - $base_url = clone $url; - $base_url->setOption('query', array('datasource' => $datasource_id)); - $item['properties'] = $this->getPropertiesList($properties, $active_property_path, $base_url); - } + + dsm('datasources changes uit ajax submit'); + dsm($datasources); + $form_state->setValue('datasources', $datasources); + dsm('opgeslaan in datasources?'); + dsm($form_state->getValue('datasources')); + $form_state->setRebuild(); + } + + /** + * Return new datasource structure. + */ + public function expandDatasourceFormAjax(array $form, FormStateInterface &$form_state) { + + + $this->displayMethodInvocation('expandDatasourceFormAjax'); + //dsm($form_state->getValue('datasource')); + //$form = $form_state->getCompleteForm(); + //$button = $form_state->getTriggeringElement(); + + // Go one level up in the form, to the widgets container. + //dsm('array of button parrents'); + //dsm($button['#array_parents']); + //$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -3)); + //echo 'Which element trigggered?'; + //dsm('Which element trigggered?'); + + //dsm(array_keys($element)); + //dsm($element['#type']); + //dsm($element['field-name']); + + $form['messages']['status'] = [ + '#type' => 'status_messages', + ]; +//dsm($form['datasources']['#value']); + + //$datasources = $form_state->getValue('datasources'); + //dsm($datasources); + //$form['datasources']['#value'] = $datasources; + //return $form['messages']; + //return $form['index-fields']; + //return $element; + return $form; + + /* + * $button = $form_state->getTriggeringElement(); + + + // Ensure the widget allows adding additional items. + if ($element['#cardinality'] != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) { + return; } - return $item; + // Add a DIV around the delta receiving the Ajax effect. + $delta = $element['#max_delta']; + $element[$delta]['#prefix'] = '
' . (isset($element[$delta]['#prefix']) ? $element[$delta]['#prefix'] : ''); + $element[$delta]['#suffix'] = (isset($element[$delta]['#suffix']) ? $element[$delta]['#suffix'] : '') . '
'; + + return $element; + */ + } + + /** + * Update form processing information. + * + * Display the method being called and it's sequence in the form + * processing. + * + * @param string $method_name + * The method being invoked. + */ + private function displayMethodInvocation($method_name) { + self::$sequenceCounter++; + drupal_set_message(self::$sequenceCounter . ". $method_name"); } /** @@ -340,6 +530,7 @@ class IndexAddFieldsForm extends EntityForm { * properties. */ protected function getPropertiesList(array $properties, $active_property_path, Url $base_url, $parent_path = '', $label_prefix = '') { + $list = array( '#theme' => 'search_api_form_item_list', ); @@ -352,7 +543,12 @@ class IndexAddFieldsForm extends EntityForm { $type_mapping = Utility::getFieldTypeMapping(); $query_base = $base_url->getOption('query'); + dsm('query'); + dsm($query_base); + dsm('values to get from form'); foreach ($properties as $key => $property) { + dsm('properties'); + dsm($key); $this_path = $parent_path ? $parent_path . ':' : ''; $this_path .= $key; @@ -366,6 +562,8 @@ class IndexAddFieldsForm extends EntityForm { if ($property instanceof ComplexDataDefinitionInterface) { $can_be_indexed = FALSE; $nested_properties = Utility::getNestedProperties($property); + //dsm('nested props'); + //dsm($nested_properties); $main_property = $property->getMainPropertyName(); if ($main_property && isset($nested_properties[$main_property])) { $parent_child_type = $property->getDataType() . '.'; @@ -435,6 +633,17 @@ class IndexAddFieldsForm extends EntityForm { '#title' => '(+) ', '#url' => $link_url, ); + $expand_button = array( + '#type' => 'button', + '#name' => 'widget_configure', + '#value' => '(+)', + '#limit_validation_errors' => [['widget']], + '#submit' => ['::submitAjaxWidgetConfigForm'], + '#ajax' => [ + 'callback' => '::buildAjaxWidgetConfigForm', + 'wrapper' => 'index-field-list', + ], + ); } } @@ -448,6 +657,9 @@ class IndexAddFieldsForm extends EntityForm { if ($expand_link) { $item['expand_link'] = $expand_link; } + if ($expand_button) { + $item['expand_button'] = $expand_button; + } $item['label']['#markup'] = Html::escape($label) . ' '; @@ -474,22 +686,6 @@ class IndexAddFieldsForm extends EntityForm { } /** - * {@inheritdoc} - */ - protected function actions(array $form, FormStateInterface $form_state) { - return array( - 'done' => array( - '#type' => 'link', - '#title' => $this->t('Done'), - '#url' => $this->entity->toUrl('fields'), - '#attributes' => array( - 'class' => array('button'), - ), - ), - ); - } - - /** * Form submission handler for adding a new field to the index. * * @param array $form diff --git a/src/Form/IndexFieldsForm.php b/src/Form/IndexFieldsForm.php index 81c91ba..7c1ac99 100644 --- a/src/Form/IndexFieldsForm.php +++ b/src/Form/IndexFieldsForm.php @@ -2,6 +2,7 @@ namespace Drupal\search_api\Form; +use Drupal\Component\Serialization\Json; use Drupal\Component\Utility\Html; use Drupal\Core\Datetime\DateFormatter; use Drupal\Core\Entity\EntityForm; @@ -207,6 +208,19 @@ class IndexFieldsForm extends EntityForm { $form['#title'] = $this->t('Manage fields for search index %label', array('%label' => $index->label())); $form['#tree'] = TRUE; + $form['add-field'] = [ + '#type' => 'link', + '#title' => $this->t('Add fields'), + '#url' => Url::fromRoute('entity.search_api_index.add_fields', ['search_api_index' => $index->id()]), + '#attributes' => [ + 'class' => ['use-ajax button button-action button--primary button--small'], + 'data-dialog-type' => 'modal', + 'data-dialog-options' => Json::encode([ + 'width' => 700, + ]), + ], + ]; + $form['description']['#markup'] = $this->t('

The data type of a field determines how it can be used for searching and filtering. The boost is used to give additional weight to certain fields, e.g. titles or tags.

For information about the data types available for indexing, see the data types table at the bottom of the page.

', array('@url' => '#search-api-data-types-table')); if ($index->hasValidServer()) { $arguments = array(