Skip to content

Commit

Permalink
Merge pull request #1323 from creative-commoners/pulls/6.0/remove-ele…
Browse files Browse the repository at this point in the history
…mental-search

API Update search functionality to work in a SearchContext
  • Loading branch information
GuySartorelli authored Mar 5, 2025
1 parent 656057f commit 27dbf74
Show file tree
Hide file tree
Showing 11 changed files with 215 additions and 367 deletions.
8 changes: 2 additions & 6 deletions _config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ SilverStripe\CMS\Controllers\ContentController:
url_handlers:
'element/$ID!': 'handleElement'

SilverStripe\CMS\Controllers\CMSMain:
extensions:
- DNADesign\Elemental\Extensions\ElementalCMSMainExtension

SilverStripe\CMS\Model\SiteTree:
extensions:
topPageSiteTreeExtension: DNADesign\Elemental\Extensions\TopPageSiteTreeExtension
Expand All @@ -37,5 +33,5 @@ Symbiote\GridFieldExtensions\GridFieldAddNewMultiClassHandler:
- DNADesign\Elemental\Extensions\GridFieldAddNewMultiClassHandlerExtension

SilverStripe\Core\Injector\Injector:
SilverStripe\CMS\Controllers\CMSSiteTreeFilter_Search:
class: DNADesign\Elemental\Controllers\ElementSiteTreeFilterSearch
SilverStripe\CMS\Search\SiteTreeSearchContext:
class: DNADesign\Elemental\ORM\Search\ElementalSiteTreeSearchContext
8 changes: 6 additions & 2 deletions docs/en/03_searching-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,14 @@ CMS page search will include search results for pages with elements that match t
By default it uses the same method as the search indexing where it will fully render every element that is
being searched. This is an expensive operation and can cause performance issues if you have a large site with a lot of elements.

> [!WARNING]
> This functionality does not scale well - the larger your site, the worse it will perform.
> Carefully consider the size of your site and how likely it is to grow when determining what configuration to use.

To increase performance by a large amount, likely more than doubling it, you can disable the rendering of elements and instead just look at the database values of the elements directly.

```yml
DNADesign\Elemental\Controllers\ElementSiteTreeFilterSearch:
DNADesign\Elemental\ORM\Search\ElementalSiteTreeSearchContext:
render_elements: false
```

Expand All @@ -79,6 +83,6 @@ App\MyElement:
If the above is still not performant enough, searching elements for content in CMS page search can be disabled entirely:

```yml
DNADesign\Elemental\Controllers\ElementSiteTreeFilterSearch:
DNADesign\Elemental\ORM\Search\ElementalSiteTreeSearchContext:
search_for_term_in_content: false
```
150 changes: 0 additions & 150 deletions src/Controllers/ElementSiteTreeFilterSearch.php

This file was deleted.

37 changes: 0 additions & 37 deletions src/Extensions/ElementalCMSMainExtension.php

This file was deleted.

7 changes: 3 additions & 4 deletions src/Models/BaseElement.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
use SilverStripe\ORM\CMSPreviewable;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Validation\ValidationResult;
use SilverStripe\Dev\Deprecation;

/**
* Class BaseElement
Expand Down Expand Up @@ -64,8 +63,8 @@ class BaseElement extends DataObject implements CMSPreviewable
private static $class_description = 'Base element class';

/**
* List of fields to exclude from CMS SiteTree seatch
* @see ElementSiteTreeFilterSearch::applyDefaultFilters()
* List of fields to exclude from CMS SiteTree search
* @see ElementalSiteTreeSearchContext
*/
private static array $fields_excluded_from_cms_search = [
'ExtraClass',
Expand Down Expand Up @@ -533,7 +532,7 @@ public function getContentForSearchIndex(): string
}

/**
* Provides content for CMS search if ElementSiteTreeFilterSearch.render_elements is false
* Provides content for CMS search if ElementalSiteTreeSearchContext.render_elements is false
*/
public function getContentForCmsSearch(): string
{
Expand Down
84 changes: 84 additions & 0 deletions src/ORM/Search/ElementalSiteTreeSearchContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

namespace DNADesign\Elemental\ORM\Search;

use DNADesign\Elemental\Extensions\ElementalPageExtension;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\CMS\Search\SiteTreeSearchContext;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\ORM\DataQuery;
use SilverStripe\ORM\Filters\ExactMatchFilter;

class ElementalSiteTreeSearchContext extends SiteTreeSearchContext
{
use Configurable;

/**
* If false, the custom search against elemental block content will not be performed.
* Set this to false for best performance.
*/
private static bool $search_for_term_in_content = true;

/**
* Whether to render elements with templates when doing a CMS SiteTree search.
* Setting this to false will give a big boost to performance with minimal impact to the user experience.
*/
private static bool $render_elements = true;

protected function generalSearchAcrossFields(string|array $searchPhrase, DataQuery $subGroup, array $searchableFields): void
{
parent::generalSearchAcrossFields($searchPhrase, $subGroup, $searchableFields);

if (static::config()->get('search_for_term_in_content') === false) {
return;
}

if (!is_array($searchPhrase)) {
$searchPhrase = [$searchPhrase];
}

$pageIDs = [];
// The same extension can't be applied to the multiple classes in the same hierarchy
// without causing a host of problems, so we can be confident that we're not getting any double ups here.
$pageClassesWithExtension = ClassInfo::classesWithExtension(ElementalPageExtension::class, SiteTree::class, true);
// Get a list of classes that can't have elemental blocks despite having the extension to reduce the amount of
// records we're filtering through needlessly
$ignoredClasses = Config::forClass(ElementalPageExtension::class)->get('ignored_classes');
foreach ($ignoredClasses as $class) {
$ignoredClasses = array_merge($ignoredClasses, ClassInfo::subclassesFor($class, false));
}
foreach ($pageClassesWithExtension as $class) {
$list = $class::get();
if (!empty($ignoredClasses)) {
$list = $list->exclude(['ClassName' => $ignoredClasses]);
}
$idsForThisClass = $list->filterByCallback(function (SiteTree $siteTree) use ($searchPhrase) {
// Check if any of the search phrase parts is in the content
if (static::config()->get('render_elements') === true) {
$pageContent = $siteTree->getElementsForSearch();
} else {
$pageContent = $siteTree->getContentFromElementsForCmsSearch();
}
foreach ($searchPhrase as $part) {
if (stripos($pageContent ?? '', $part) !== false) {
return true;
}
}
return false;
})->column('ID');
$pageIDs = array_merge($pageIDs, $idsForThisClass);
}

if (empty($pageIDs)) {
return;
}

// Apply search filter to include these pages in the result
$filter = ExactMatchFilter::create('ID');
$filter->setModel($this->getModelClass());
$filter->setValue($pageIDs);
$this->applyFilter($filter, $subGroup, []);
}
}
1 change: 0 additions & 1 deletion tests/BaseElementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,6 @@ public function testGetContentForCmsSearch()
$this->assertSame('Hello Test|#|Element 3', $element->getContentForCmsSearch());
}


public function testGetPage()
{
$element = $this->objFromFixture(ElementContent::class, 'content1');
Expand Down
Loading

0 comments on commit 27dbf74

Please sign in to comment.