Skip to content

Commit

Permalink
Initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
bmcclure committed Apr 5, 2017
0 parents commit bb7a6bd
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea/
14 changes: 14 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "drupal/search_filters",
"type": "drupal-module",
"description": "Customizes taxonomy-based search filtering",
"keywords": ["Drupal"],
"license": "GPL-2.0+",
"homepage": "https://www.drupal.org/project/search_filters",
"minimum-stability": "dev",
"support": {
"issues": "https://www.drupal.org/project/issues/search_filters",
"source": "http://cgit.drupalcode.org/search_filters"
},
"require": { }
}
5 changes: 5 additions & 0 deletions search_filters.info.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: Search filters
type: module
description: Customizes taxonomy-based search filtering
core: 8.x
package: Search
5 changes: 5 additions & 0 deletions search_filters.links.menu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
search_filters.admin_settings:
route_name: search_filters.admin_settings
title: 'Search filters'
description: 'Configure search filter mappings.'
parent: system.admin_config_search
33 changes: 33 additions & 0 deletions search_filters.module
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

/**
* @file
* Contains search_filters.module.
*/

use Drupal\Core\Routing\RouteMatchInterface;

/**
* Implements hook_help().
*/
function search_filters_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help for the search_filters module.
case 'help.page.search_filters':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('Customizes taxonomy-based search filtering') . '</p>';
return $output;

default:
}
}

/**
* Implements hook_entity_presave().
*/
function search_filters_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
$mapping = new \Drupal\search_filters\SearchFiltersMapping();

$mapping->setFiltersOnEntity($entity);
}
2 changes: 2 additions & 0 deletions search_filters.permissions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'administer search filters':
title: 'Administer search filters'
7 changes: 7 additions & 0 deletions search_filters.routing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
search_filters.admin_settings:
path: /admin/config/search/search-filters
defaults:
_title: 'Search Filters'
_form: \Drupal\search_filters\Form\SettingsForm
requirements:
_permission: 'administer search filters'
68 changes: 68 additions & 0 deletions src/Form/SettingsForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace Drupal\search_filters\Form;

use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;

class SettingsForm extends ConfigFormBase {

/**
* {@inheritdoc}
*/
public function getFormId() {
return 'search_filters_admin_settings';
}

/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->config('search_filters.settings')
->set('bundle_mapping', $form_state->getValue('bundle_mapping'))
->set('vocabulary', $form_state->getValue('vocabulary'))
->set('field_name', $form_state->getValue('field_name'))
->save();

parent::submitForm($form, $form_state);
}

/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return ['search_filters.settings'];
}

public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('search_filters.settings');

$form['information'] = [
'#markup' => '<p>After saving these settings, any affected entities will need to be re-saved.</p>',
];

$form['vocabulary'] = [
'#type' => 'textfield',
'#title' => $this->t('Filters vocabulary'),
'#description' => $this->t('The taxonomy vocabulary ID to use for the search filters.'),
'#default_value' => $config->get('vocabulary'),
];

$form['field_name'] = [
'#type' => 'textfield',
'#title' => $this->t('Field name'),
'#description' => $this->t('The name of the term reference field to store the filter values in.'),
'#default_value' => $config->get('field_name'),
];

$form['bundle_mapping'] = [
'#type' => 'textarea',
'#title' => $this->t('Bundle mapping'),
'#description' => $this->t('A list of mappings in the format "entity_type:bundle:Term Name", one per line. Bundle can be * for a wildcard. Term name can also be in the format [field_name] to use a field from the entity as the term.'),
'#default_value' => $config->get('bundle_mapping'),
];

return parent::buildForm($form, $form_state);
}

}
149 changes: 149 additions & 0 deletions src/SearchFiltersMapping.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?php

namespace Drupal\search_filters;

use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\taxonomy\VocabularyInterface;

class SearchFiltersMapping {
protected $mapping = [];
protected $config;

public function __construct($mapping = NULL) {
$this->config = \Drupal::config('search_filters.settings');

if (is_null($mapping)) {
$mapping = $this->config->get('bundle_mapping');
}

$this->setMapping($mapping);
}

public function setMapping($mapping = NULL) {
$this->mapping = [];

if (is_array($mapping)) {
$this->mapping = $mapping;
} elseif (is_string($mapping)) {
$bundle_mapping = preg_split('/(\r\n|\r|\n)/', $mapping);

foreach ($bundle_mapping as $line) {
list($entity_type, $bundle, $values) = explode(':', $line, 3);

$values = explode('|', $values);

foreach ($values as $value) {
$this->mapping[$entity_type][$bundle][] = $value;
}
}
}
}

public function shouldSetFilters(EntityInterface $entity) {
if (!$entity instanceof FieldableEntityInterface) {
return FALSE;
}

$config = \Drupal::config('search_filters.settings');

if (empty($config->get('vocabulary')) || empty($config->get('field_name'))) {
return FALSE;
}

$vocabulary = Vocabulary::load($config->get('vocabulary'));

if (!$vocabulary instanceof VocabularyInterface) {
return FALSE;
}

$field_name = $config->get('field_name');

if (!$entity->hasField($field_name)) {
return FALSE;
}

if (!array_key_exists($entity->getEntityTypeId(), $this->mapping)) {
return FALSE;
}

return (array_key_exists($entity->bundle(), $this->mapping[$entity->getEntityTypeId()])
|| array_key_exists('*', $this->mapping[$entity->getEntityTypeId()]));
}

public function setFiltersOnEntity(EntityInterface $entity) {
if (!$this->shouldSetFilters($entity)) {
return;
}

/** @var FieldableEntityInterface $entity */

$this->clearFilterValues($entity);

foreach ([$entity->bundle(), '*'] as $bundle_key) {
if (array_key_exists($bundle_key, $this->mapping[$entity->getEntityTypeId()])) {
foreach ($this->mapping[$entity->getEntityTypeId()][$bundle_key] as $term_name) {
$this->setFilterOnEntity($term_name, $entity);
}
}
}
}

protected function clearFilterValues(FieldableEntityInterface $entity) {
$config = \Drupal::config('search_filters.settings');

$field_name = $config->get('field_name');

if ($entity->hasField($field_name)) {
$entity->get($field_name)->setValue([]);
}
}

protected function setFilterOnEntity($term_name, FieldableEntityInterface $entity) {
if (strpos($term_name, '[') === 0) {
$name_field = str_replace(['[', ']'], '', $term_name);

if (!$entity->hasField($name_field) || $entity->get($name_field)->isEmpty()) {
return;
}

$term_name = $entity->get($name_field)->value;
}

$config = \Drupal::config('search_filters.settings');

$properties = [
'vid' => $config->get('vocabulary'),
'name' => $term_name,
];

$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties($properties);

$term = reset($terms);

if (empty($term)) {
$term = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->create($properties);
$term->save();
}

$field_name = $config->get('field_name');

$values = $entity->get($field_name)->getValue();

$exists = FALSE;

foreach ($values as $item) {
if ($item['target_id'] == $term->id()) {
$exists = TRUE;
break;
}
}

if (!$exists) {
$values[] = ['target_id' => $term->id()];
}

$entity->get($field_name)->setValue($values);
}
}

0 comments on commit bb7a6bd

Please sign in to comment.