diff --git a/_config/extensions.yml b/_config/extensions.yml index a453b3e..ff399e8 100644 --- a/_config/extensions.yml +++ b/_config/extensions.yml @@ -28,3 +28,12 @@ SilverStripe\CMS\Model\SiteTree: extensions: SearchServiceExtension: SilverStripe\SearchService\Extensions\SearchServiceExtension SiteTreeHierarchyExtension: SilverStripe\SearchService\Extensions\SiteTreeHierarchyExtension +--- +Name: search-service-form-extension +--- +SilverStripe\AssetAdmin\Forms\FileFormFactory: + extensions: + - SilverStripe\SearchService\Extensions\SearchFormFactoryExtension +SilverStripe\SearchService\Extensions\SearchFormFactoryExtension: + exclude_classes: + - SilverStripe\Assets\Image diff --git a/docs/en/configuration.md b/docs/en/configuration.md index 9b1f0a0..c3a67ee 100644 --- a/docs/en/configuration.md +++ b/docs/en/configuration.md @@ -254,6 +254,29 @@ __Additional note__: This is handled via `SubsiteIndexConfigurationExtension` - this logic could be replicated for other scenarios like languages if required. +## Configuring search exclusion for files + +By default, `SilverStripe\Assets\Image` is excluded from the search. To change this default +setting, use the code snippet below. + +```yaml +--- +After: search-service-form-extension +--- +SilverStripe\SearchService\Extensions\SearchFormFactoryExtension: + exclude_classes: null +``` + +If you want to exclude certain file extensions from being added to the search index, add +the following configuration to your code base: + +```yaml +SilverStripe\SearchService\Extensions\SearchFormFactoryExtension: + exclude_file_extensions: + - svg + - mp4 +``` + ## More information * [Usage](usage.md) diff --git a/src/Extensions/SearchFormFactoryExtension.php b/src/Extensions/SearchFormFactoryExtension.php new file mode 100644 index 0000000..32e9913 --- /dev/null +++ b/src/Extensions/SearchFormFactoryExtension.php @@ -0,0 +1,63 @@ +Fields()->findOrMakeTab('Editor.Details'); + $file = $context['Record'] ?? null; + + $excludedClasses = Config::inst()->get(self::class, 'exclude_classes') ?? []; + $excludeFileTypes = Config::inst()->get(self::class, 'exclude_file_extensions') ?? []; + + if (!$fields || !$file) { + return; + } + + if (in_array($file->ClassName, $excludedClasses) || in_array($file->getExtension(), $excludeFileTypes)) { + if ($file->ShowInSearch) { + $file->ShowInSearch = false; + $file->write(); + } + + return; + } + + $fields->push( + CheckboxField::create( + 'ShowInSearch', + _t( + 'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.SHOWINSEARRCH', + 'Show in search?' + ) + ) + ); + + $fields->push( + DatetimeField::create( + 'SearchIndexed', + _t( + 'SilverStripe\\SearchService\\Extensions\\SearchServiceExtension.LastIndexed', + 'Last indexed in search' + ) + ) + ->setReadonly(true) + ); + } + +} diff --git a/src/Extensions/SearchServiceExtension.php b/src/Extensions/SearchServiceExtension.php index e7d148c..06291c8 100644 --- a/src/Extensions/SearchServiceExtension.php +++ b/src/Extensions/SearchServiceExtension.php @@ -3,8 +3,10 @@ namespace SilverStripe\SearchService\Extensions; use Exception; +use SilverStripe\CMS\Model\SiteTree; use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\Injector\Injectable; +use SilverStripe\Forms\CheckboxField; use SilverStripe\Forms\FieldList; use SilverStripe\Forms\ReadonlyField; use SilverStripe\ORM\DataExtension; @@ -36,9 +38,14 @@ class SearchServiceExtension extends DataExtension use BatchProcessorAware; private static array $db = [ + 'ShowInSearch' => 'Boolean', 'SearchIndexed' => 'Datetime', ]; + private static array $defaults = [ + 'ShowInSearch' => true, + ]; + private bool $hasConfigured = false; public function __construct( @@ -53,19 +60,49 @@ public function __construct( $this->setBatchProcessor($batchProcessor); } + /** + * General DataObject Search settings + * + * @param FieldList $fields + * @return void + */ public function updateCMSFields(FieldList $fields): void { - if (!$this->getConfiguration()->isEnabled()) { + if ($this->owner instanceof SiteTree || !$this->getConfiguration()->isEnabled()) { return; } - $field = ReadonlyField::create('SearchIndexed', _t(self::class.'.LastIndexed', 'Last indexed in search')); + $showInSearchField = CheckboxField::create( + 'ShowInSearch', + _t(self::class . '.ShowInSearch', 'Show in search?') + ); + $searchIndexedField = ReadonlyField::create( + 'SearchIndexed', + _t(self::class . '.LastIndexed', 'Last indexed in search') + ); + + $fields->push($showInSearchField); + $fields->push($searchIndexedField); + } - if ($fields->hasTabSet()) { - $fields->addFieldToTab('Root.Main', $field); - } else { - $fields->push($field); + /** + * Specific settings for SiteTree + * + * @param FieldList $fields + * @return void + */ + public function updateSettingsFields(FieldList $fields): void + { + if (!$this->owner instanceof SiteTree || !$this->getConfiguration()->isEnabled()) { + return; } + + $searchIndexedField = ReadonlyField::create( + 'SearchIndexed', + _t(self::class . '.LastIndexed', 'Last indexed in search') + ); + + $fields->insertAfter('ShowInSearch', $searchIndexedField); } /** diff --git a/tests/DataObject/DataObjectDocumentTest.php b/tests/DataObject/DataObjectDocumentTest.php index e2b87b7..1419017 100644 --- a/tests/DataObject/DataObjectDocumentTest.php +++ b/tests/DataObject/DataObjectDocumentTest.php @@ -758,4 +758,32 @@ public function testIndexDataObjectDocument(): void }); } + public function testIndexDataObjectDocumentShowInSearch(): void + { + $dataObject = $this->objFromFixture(DataObjectFakeVersioned::class, 'two'); + $doc = DataObjectDocument::create($dataObject); + + $config = $this->mockConfig(); + $config->set( + 'getIndexesForDocument', + [ + $doc->getIdentifier() => [ + 'index' => 'data', + ], + ] + ); + + // Should not index as ShowInSearch is false for this DataObject + $dataObject->publishRecursive(); + $this->assertFalse($doc->shouldIndex()); + + // Should index as ShowInSearch is now set to true + $dataObject->ShowInSearch = true; + $dataObject->publishRecursive(); + + $doc = DataObjectDocument::create($dataObject); + + $this->assertTrue($doc->shouldIndex()); + } + } diff --git a/tests/Extensions/SearchFormFactoryExtensionTest.php b/tests/Extensions/SearchFormFactoryExtensionTest.php new file mode 100644 index 0000000..ffd1288 --- /dev/null +++ b/tests/Extensions/SearchFormFactoryExtensionTest.php @@ -0,0 +1,68 @@ +get(SearchFormFactoryExtension::class, 'exclude_classes'); + $this->assertEquals($expected, $actual); + } + + public function testImageAndFileInclusionInShowInSearch(): void + { + $form = Form::create(); + $fields = new FieldList(new TabSet('Editor')); + $form->setFields($fields); + + $image = $this->objFromFixture(Image::class, 'image'); + // Every file has default ShowInSearch value of 1 + // (https://github.com/silverstripe/silverstripe-assets/blob/2/src/File.php#L163) + $this->assertEquals(1, $image->ShowInSearch); + + $searchFormFactoryExtension = new SearchFormFactoryExtension(); + $searchFormFactoryExtension->updateForm($form, null, 'Form', ['Record' => $image]); + // By default, `SilverStripe\Assets\Image` is excluded from the search - see `_config/extensions.yml` + $this->assertEquals(0, $image->ShowInSearch); + + $file = $this->objFromFixture(File::class, 'pdf-file'); + $searchFormFactoryExtension->updateForm($form, null, 'Form', ['Record' => $file]); + $this->assertEquals(1, $file->ShowInSearch); + } + + public function testExcludedFileExtensionShowInSearch(): void + { + // Modify config to exclude pdf files from search + Config::modify()->set(SearchFormFactoryExtension::class, 'exclude_file_extensions', ['pdf']); + + $file = $this->objFromFixture(File::class, 'pdf-file'); + // Default ShowInSearch value of 1 + $this->assertEquals(1, $file->ShowInSearch); + + $form = Form::create(); + $fields = new FieldList(new TabSet('Editor')); + $form->setFields($fields); + + $searchFormFactoryExtension = new SearchFormFactoryExtension(); + $searchFormFactoryExtension->updateForm($form, null, 'Form', ['Record' => $file]); + $this->assertEquals(0, $file->ShowInSearch); + } + +} diff --git a/tests/Fake/DataObjectFake.php b/tests/Fake/DataObjectFake.php index ea6164c..333231e 100644 --- a/tests/Fake/DataObjectFake.php +++ b/tests/Fake/DataObjectFake.php @@ -19,7 +19,6 @@ class DataObjectFake extends DataObject implements TestOnly private static array $db = [ 'Title' => 'Varchar', - 'ShowInSearch' => 'Boolean', 'Sort' => 'Int', ]; diff --git a/tests/fixtures.yml b/tests/fixtures.yml index 4ee023f..5356b8f 100644 --- a/tests/fixtures.yml +++ b/tests/fixtures.yml @@ -64,3 +64,16 @@ SilverStripe\Subsites\Model\Subsite: Title: 'Subsite 1' subsite2: Title: 'Subsite 2' + + +SilverStripe\Assets\Image: + image: + Name: 'Image' + Filename: silverstripe-logo.png + PopulateFileFrom: tests/silverstripe-logo.png + +SilverStripe\Assets\File: + pdf-file: + Title: Test File + Filename: test-file.pdf + PopulateFileFrom: tests/test-file.pdf diff --git a/tests/silverstripe-logo.png b/tests/silverstripe-logo.png new file mode 100644 index 0000000..c70ca44 Binary files /dev/null and b/tests/silverstripe-logo.png differ diff --git a/tests/test-file.pdf b/tests/test-file.pdf new file mode 100644 index 0000000..a9ecd2b Binary files /dev/null and b/tests/test-file.pdf differ