Skip to content

EWPP-593: Ajax fixes on the list page config subform entity type and bundle selection. #57

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 87 additions & 52 deletions src/Form/ListPageConfigurationSubForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\SubformState;
use Drupal\Core\Render\Element\Checkboxes;
use Drupal\Core\Render\Element\Select;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\oe_list_pages\ListPageConfiguration;
Expand Down Expand Up @@ -109,9 +108,9 @@ public function getConfiguration(): ListPageConfiguration {
* {@inheritdoc}
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
public function buildForm(array $form, FormStateInterface $form_state): array {
$input = $form_state->getUserInput();
$entity_type_options = $this->getEntityTypeOptions();
$entity_type_id = $this->configuration->getEntityType();
$entity_type_bundle = $this->configuration->getBundle();
Expand All @@ -125,8 +124,11 @@ public function buildForm(array $form, FormStateInterface $form_state): array {
],
];

$selected_entity_type = NestedArray::getValue($input, array_merge($form['#parents'], ['wrapper', 'entity_type'])) ?? $entity_type_id;
$selected_bundle = NestedArray::getValue($input, array_merge($form['#parents'], ['wrapper', 'bundle'])) ?? $entity_type_bundle;
$selected_entity_type = $form_state->has('entity_type') ? $form_state->get('entity_type') : $entity_type_id;
$selected_bundle = $form_state->has('bundle') ? $form_state->get('bundle') : $entity_type_bundle;
if (!$form_state->has('entity_type')) {
$form_state->set('entity_type', $selected_entity_type);
}

$form['wrapper']['entity_type'] = [
'#type' => 'select',
Expand All @@ -140,9 +142,17 @@ public function buildForm(array $form, FormStateInterface $form_state): array {
'#required' => TRUE,
'#op' => 'entity-type',
'#ajax' => [
'callback' => [get_class($this), 'updateEntityBundles'],
'callback' => [get_class($this), 'entityTypeSelectAjax'],
'wrapper' => $ajax_wrapper_id,
],
'#executes_submit_callback' => TRUE,
'#submit' => [[$this, 'entityTypeSelectSubmit']],
'#limit_validation_errors' => [
array_merge($form['#parents'], [
'wrapper',
'entity_type',
]),
],
];

if (!empty($selected_entity_type)) {
Expand All @@ -157,9 +167,17 @@ public function buildForm(array $form, FormStateInterface $form_state): array {
'#op' => 'bundle',
'#required' => TRUE,
'#ajax' => [
'callback' => [$this, 'updateExposedFilters'],
'callback' => [$this, 'bundleSelectAjax'],
'wrapper' => $ajax_wrapper_id,
],
'#executes_submit_callback' => TRUE,
'#submit' => [[$this, 'bundleSelectSubmit']],
'#limit_validation_errors' => [
array_merge($form['#parents'], [
'wrapper',
'bundle',
]),
],
'#process' => [
[Select::class, 'processSelect'],
[Select::class, 'processAjaxForm'],
Expand Down Expand Up @@ -202,10 +220,6 @@ public function buildForm(array $form, FormStateInterface $form_state): array {
'#title' => $this->t('Exposed filters'),
'#default_value' => $exposed_filters,
'#options' => $available_filters,
'#process' => [
[Checkboxes::class, 'processCheckboxes'],
[$this, 'processExposedFilters'],
],
'#states' => [
'visible' => [
':input[name="' . $name . '"]' => ['checked' => TRUE],
Expand All @@ -229,6 +243,58 @@ public function buildForm(array $form, FormStateInterface $form_state): array {
return $form;
}

/**
* Submit callback when changing the entity type.
*
* @param array $form
* The form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*/
public function entityTypeSelectSubmit(array &$form, FormStateInterface $form_state): void {
$triggering_element = $form_state->getTriggeringElement();
$form_state->set('entity_type', $triggering_element['#value']);
$form_state->set('bundle', NULL);

// In this form we embed the default filters form as well so if we change
// entity types, we need to reset any filter selection.
$form_state->set('facet_id', NULL);
$form_state->set('filter_id', NULL);
$form_state->setRebuild(TRUE);
}

/**
* Submit callback when changing the bundle.
*
* @param array $form
* The form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*/
public function bundleSelectSubmit(array &$form, FormStateInterface $form_state): void {
$triggering_element = $form_state->getTriggeringElement();
$form_state->set('bundle', $triggering_element['#value']);
$form_state->setRebuild(TRUE);

// In this form we embed the default filters form as well so if we change
// entity types, we need to reset any filter selection.
$form_state->set('facet_id', NULL);
$form_state->set('filter_id', NULL);

// When we change the bundle, we want to set the default exposed filter
// values to the user input so that the checkboxes can be checked when the
// user changes the bundle.
$parents = array_merge(array_slice($triggering_element['#parents'], 0, -1), ['exposed_filters']);
$entity_type = $form_state->get('entity_type');
$list_source = $this->listSourceFactory->get($entity_type, $triggering_element['#value']);
if ($list_source instanceof ListSourceInterface) {
$default_exposed_filters = $this->getBundleDefaultExposedFilters($list_source);
$input = $form_state->getUserInput();
NestedArray::setValue($input, $parents, $default_exposed_filters);
$form_state->setUserInput($input);
}
}

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -280,42 +346,6 @@ public function processBundle(array &$element, FormStateInterface $form_state, a
return $element;
}

/**
* Process callback for the exposed filters selection element.
*
* @param array $element
* The element.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
* @param array $complete_form
* The complete form.
*
* @return array
* The processed element.
*/
public function processExposedFilters(array &$element, FormStateInterface $form_state, array &$complete_form): array {
$triggering_element = $form_state->getTriggeringElement();
// If we change the value of the entity type or bundle, we want to reset
// the value of the submitted exposed filters checkbox. Moreover, we want
// to set the default exposed filter values to the user input so that the
// checkboxes can be checked when the user changes the bundle.
if ($triggering_element && isset($triggering_element['#op']) && in_array($triggering_element['#op'], ['entity-type', 'bundle'])) {
$values = $entity_type = $form_state->getValue(array_slice($element['#parents'], 0, -1));
$entity_type = $values['entity_type'];
$bundle = $values['bundle'];
if ($entity_type && $bundle) {
$list_source = $this->listSourceFactory->get($entity_type, $bundle);
$default_exposed_filters = $this->getBundleDefaultExposedFilters($list_source);
$input = $form_state->getUserInput();
NestedArray::setValue($input, $element['#parents'], $default_exposed_filters);
$form_state->setUserInput($input);
}

$element['#value'] = [];
}
return $element;
}

/**
* Ajax request handler for updating the entity bundles.
*
Expand All @@ -327,14 +357,14 @@ public function processExposedFilters(array &$element, FormStateInterface $form_
* @return array
* The form element.
*/
public static function updateEntityBundles(array &$form, FormStateInterface $form_state): array {
public static function entityTypeSelectAjax(array &$form, FormStateInterface $form_state): array {
$triggering_element = $form_state->getTriggeringElement();
$element = NestedArray::getValue($form, array_slice($triggering_element['#array_parents'], 0, -2));
return $element['wrapper'];
}

/**
* Ajax request handler for updating the exposed filters.
* Ajax callback for when the bundle is selected.
*
* @param array $form
* The form.
Expand All @@ -344,7 +374,7 @@ public static function updateEntityBundles(array &$form, FormStateInterface $for
* @return array
* The form element.
*/
public function updateExposedFilters(array &$form, FormStateInterface $form_state): array {
public function bundleSelectAjax(array &$form, FormStateInterface $form_state): array {
$triggering_element = $form_state->getTriggeringElement();
$element = NestedArray::getValue($form, array_slice($triggering_element['#array_parents'], 0, -2));
// We have to clear #value and #checked manually after processing of
Expand Down Expand Up @@ -414,11 +444,11 @@ protected function areExposedFiltersOverridden(ListSourceInterface $list_source)
protected function getEntityTypeOptions(): array {
$entity_type_options = [];
$entity_types = $this->entityTypeManager->getDefinitions();
foreach ($entity_types as $entity_type_key => $entity_type) {
if (!$entity_type instanceof ContentEntityTypeInterface) {
foreach ($entity_types as $entity_type_id => $entity_type) {
if (!$entity_type instanceof ContentEntityTypeInterface || !$this->listSourceFactory->isEntityTypeSourced($entity_type_id)) {
continue;
}
$entity_type_options[$entity_type_key] = $entity_type->getLabel();
$entity_type_options[$entity_type_id] = $entity_type->getLabel();
}

$event = new ListPageSourceAlterEvent(array_keys($entity_type_options));
Expand All @@ -439,6 +469,11 @@ protected function getBundleOptions(string $selected_entity_type): array {
$bundle_options = [];
$bundles = $this->entityTypeBundleInfo->getBundleInfo($selected_entity_type);
foreach ($bundles as $bundle_key => $bundle) {
$list_source = $this->listSourceFactory->get($selected_entity_type, $bundle_key);
if (!$list_source instanceof ListSourceInterface) {
continue;
}

$bundle_options[$bundle_key] = $bundle['label'];
}

Expand Down
1 change: 1 addition & 0 deletions src/ListPageConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ public function toArray(): array {
'exposed_filters_overridden' => $this->isExposedFiltersOverridden(),
'exposed_filters' => $this->getExposedFilters(),
'default_filter_values' => $this->getDefaultFiltersValues(),
'limit' => $this->getLimit(),
];
}

Expand Down
56 changes: 52 additions & 4 deletions src/ListSourceFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\PluginBase;
use Drupal\facets\FacetManager\DefaultFacetManager;
use Drupal\search_api\Datasource\DatasourceInterface;
use Drupal\search_api\IndexInterface;

/**
Expand All @@ -31,7 +32,7 @@ class ListSourceFactory implements ListSourceFactoryInterface {
/**
* The list sources.
*
* @var array
* @var \Drupal\oe_list_pages\ListSourceInterface[]
*/
protected $listsSources;

Expand All @@ -52,7 +53,6 @@ public function __construct(DefaultFacetManager $facetsManager, EntityTypeManage
* {@inheritdoc}
*/
public function get(string $entity_type, string $bundle): ?ListSourceInterface {

if (empty($this->listsSources)) {
$this->instantiateLists();
}
Expand All @@ -61,6 +61,23 @@ public function get(string $entity_type, string $bundle): ?ListSourceInterface {
return !empty($this->listsSources[$id]) ? $this->listsSources[$id] : NULL;
}

/**
* {@inheritdoc}
*/
public function isEntityTypeSourced(string $entity_type): bool {
if (empty($this->listsSources)) {
$this->instantiateLists();
}

foreach ($this->listsSources as $lists_source) {
if ($lists_source->getEntityType() === $entity_type) {
return TRUE;
}
}

return FALSE;
}

/**
* {@inheritdoc}
*/
Expand All @@ -72,7 +89,6 @@ public static function generateFacetSourcePluginId(string $entity_type, string $
* Instantiate the list sources from the indexed content bundles.
*/
protected function instantiateLists(): void {

if (!empty($this->listsSources)) {
return;
}
Expand All @@ -93,7 +109,7 @@ protected function instantiateLists(): void {
$bundles = $datasource->getBundles();
foreach ($bundles as $bundle => $label) {
// In case not all bundles are indexed.
if (!empty($datasource->getConfiguration()['bundles']['selected']) && !in_array($bundle, $datasource->getConfiguration()['bundles']['selected'])) {
if (!$this->isBundleIndexed($datasource, $bundle)) {
continue;
}

Expand Down Expand Up @@ -138,4 +154,36 @@ protected function create(string $entity_type, string $bundle, IndexInterface $i
return new ListSource($id, $entity_type, $bundle, $bundle_field_id, $index, $filters);
}

/**
* Checks if a given bundle is indexed on a data source.
*
* @param \Drupal\search_api\Datasource\DatasourceInterface $datasource
* The datasource.
* @param string $bundle
* The bundle.
*
* @return bool
* Whether the bundle is indexed.
*/
protected function isBundleIndexed(DatasourceInterface $datasource, string $bundle): bool {
$configuration = $datasource->getConfiguration();
$selected = $configuration['bundles']['selected'];
if ($configuration['bundles']['default'] === TRUE && empty($selected)) {
// All bundles are indexed.
return TRUE;
}

if ($configuration['bundles']['default'] === TRUE && !empty($selected) && !in_array($bundle, $selected)) {
// All bundles are indexed, except a few that are selected.
return TRUE;
}

if ($configuration['bundles']['default'] === FALSE && in_array($bundle, $selected)) {
// Only specific bundles are indexed.
return TRUE;
}

return FALSE;
}

}
11 changes: 11 additions & 0 deletions src/ListSourceFactoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,15 @@ public static function generateFacetSourcePluginId(string $entity_type, string $
*/
public function get(string $entity_type, string $bundle): ?ListSourceInterface;

/**
* Checks whether a given entity type has a list source.
*
* @param string $entity_type
* The entity type ID.
*
* @return bool
* Whether the entity type is used in any list sources.
*/
public function isEntityTypeSourced(string $entity_type): bool;

}
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,10 @@ field_settings:
datasource_settings:
'entity:node':
bundles:
default: true
selected: { }
default: false
selected:
- content_type_one
- content_type_two
languages:
default: true
selected: { }
Expand Down
Loading