2012-08-23 17:49:32 +02:00
|
|
|
<?php
|
2017-04-21 02:23:27 +02:00
|
|
|
|
2017-11-14 21:48:52 +01:00
|
|
|
namespace SilverStripe\FullTextSearch\Tests;
|
|
|
|
|
2020-04-08 23:04:01 +02:00
|
|
|
use Apache_Solr_Document;
|
|
|
|
use Page;
|
2021-11-02 02:48:12 +01:00
|
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
2020-04-08 23:04:01 +02:00
|
|
|
use SilverStripe\Assets\File;
|
|
|
|
use SilverStripe\CMS\Model\SiteTree;
|
2017-11-14 21:48:52 +01:00
|
|
|
use SilverStripe\Core\Config\Config;
|
2017-11-29 22:40:25 +01:00
|
|
|
use SilverStripe\Core\Environment;
|
2017-11-14 05:05:30 +01:00
|
|
|
use SilverStripe\Core\Injector\Injector;
|
|
|
|
use SilverStripe\Core\Kernel;
|
2017-04-21 02:23:27 +02:00
|
|
|
use SilverStripe\Dev\SapphireTest;
|
2020-04-08 23:04:01 +02:00
|
|
|
use SilverStripe\FullTextSearch\Search\FullTextSearch;
|
2017-12-04 21:11:51 +01:00
|
|
|
use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
|
2020-06-10 07:22:20 +02:00
|
|
|
use SilverStripe\FullTextSearch\Search\Services\SearchableService;
|
2020-04-08 23:04:01 +02:00
|
|
|
use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater;
|
2017-12-04 21:11:51 +01:00
|
|
|
use SilverStripe\FullTextSearch\Search\Variants\SearchVariantSubsites;
|
|
|
|
use SilverStripe\FullTextSearch\Solr\Services\Solr3Service;
|
2020-04-08 23:04:01 +02:00
|
|
|
use SilverStripe\FullTextSearch\Solr\Services\Solr4Service;
|
2017-04-26 12:52:20 +02:00
|
|
|
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container;
|
|
|
|
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasOne;
|
|
|
|
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasMany;
|
|
|
|
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_ManyMany;
|
2017-11-14 04:31:16 +01:00
|
|
|
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_OtherContainer;
|
2017-12-04 21:11:51 +01:00
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_AmbiguousRelationIndex;
|
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_AmbiguousRelationInheritedIndex;
|
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_BoostedIndex;
|
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex;
|
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex2;
|
2020-04-08 23:04:01 +02:00
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_ShowInSearchIndex;
|
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_MyPage;
|
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_MyDataObjectOne;
|
|
|
|
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_MyDataObjectTwo;
|
2017-12-04 21:11:51 +01:00
|
|
|
use SilverStripe\Subsites\Model\Subsite;
|
2020-04-08 23:04:01 +02:00
|
|
|
use SilverStripe\Versioned\Versioned;
|
2017-04-21 03:18:37 +02:00
|
|
|
|
2015-11-21 07:19:20 +01:00
|
|
|
class SolrIndexTest extends SapphireTest
|
|
|
|
{
|
2020-04-08 23:04:01 +02:00
|
|
|
|
|
|
|
protected $usesDatabase = true;
|
|
|
|
|
|
|
|
protected static $extra_dataobjects = [
|
|
|
|
SolrIndexTest_MyPage::class,
|
|
|
|
SolrIndexTest_MyDataObjectOne::class,
|
|
|
|
SolrIndexTest_MyDataObjectTwo::class,
|
|
|
|
];
|
|
|
|
|
2015-11-21 07:19:20 +01:00
|
|
|
public function testFieldDataHasOne()
|
|
|
|
{
|
|
|
|
$index = new SolrIndexTest_FakeIndex();
|
|
|
|
$data = $index->fieldData('HasOneObject.Field1');
|
|
|
|
|
2017-04-26 12:52:20 +02:00
|
|
|
$data = $data[SearchUpdaterTest_Container::class . '_HasOneObject_Field1'];
|
|
|
|
|
|
|
|
$this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_Container::class, $data['base']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_HasOne::class, $data['class']);
|
2015-11-21 07:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testFieldDataHasMany()
|
|
|
|
{
|
|
|
|
$index = new SolrIndexTest_FakeIndex();
|
|
|
|
$data = $index->fieldData('HasManyObjects.Field1');
|
2017-04-26 12:52:20 +02:00
|
|
|
$data = $data[SearchUpdaterTest_Container::class . '_HasManyObjects_Field1'];
|
2015-11-21 07:19:20 +01:00
|
|
|
|
2017-04-26 12:52:20 +02:00
|
|
|
$this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_Container::class, $data['base']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_HasMany::class, $data['class']);
|
2015-11-21 07:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testFieldDataManyMany()
|
|
|
|
{
|
|
|
|
$index = new SolrIndexTest_FakeIndex();
|
|
|
|
$data = $index->fieldData('ManyManyObjects.Field1');
|
2017-04-26 12:52:20 +02:00
|
|
|
$data = $data[SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1'];
|
2015-11-21 07:19:20 +01:00
|
|
|
|
2017-04-26 12:52:20 +02:00
|
|
|
$this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_Container::class, $data['base']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_ManyMany::class, $data['class']);
|
2015-11-21 07:19:20 +01:00
|
|
|
}
|
|
|
|
|
2017-06-19 00:50:11 +02:00
|
|
|
public function testFieldDataAmbiguousHasMany()
|
|
|
|
{
|
|
|
|
$index = new SolrIndexTest_AmbiguousRelationIndex();
|
|
|
|
$data = $index->fieldData('HasManyObjects.Field1');
|
|
|
|
|
2017-11-14 05:05:30 +01:00
|
|
|
$this->assertArrayHasKey(SearchUpdaterTest_Container::class . '_HasManyObjects_Field1', $data);
|
|
|
|
$this->assertArrayHasKey(SearchUpdaterTest_OtherContainer::class . '_HasManyObjects_Field1', $data);
|
2017-06-19 00:50:11 +02:00
|
|
|
|
2017-11-14 05:05:30 +01:00
|
|
|
$dataContainer = $data[SearchUpdaterTest_Container::class . '_HasManyObjects_Field1'];
|
2017-11-14 04:31:16 +01:00
|
|
|
$this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['origin']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['base']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_HasMany::class, $dataContainer['class']);
|
2017-06-19 00:50:11 +02:00
|
|
|
|
2017-11-14 05:05:30 +01:00
|
|
|
$dataOtherContainer = $data[SearchUpdaterTest_OtherContainer::class . '_HasManyObjects_Field1'];
|
2017-11-14 04:31:16 +01:00
|
|
|
$this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['origin']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['base']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_HasMany::class, $dataOtherContainer['class']);
|
2017-06-19 00:50:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testFieldDataAmbiguousManyMany()
|
|
|
|
{
|
|
|
|
$index = new SolrIndexTest_AmbiguousRelationIndex();
|
|
|
|
$data = $index->fieldData('ManyManyObjects.Field1');
|
|
|
|
|
2017-11-14 05:05:30 +01:00
|
|
|
$this->assertArrayHasKey(SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1', $data);
|
|
|
|
$this->assertArrayHasKey(SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1', $data);
|
2017-06-19 00:50:11 +02:00
|
|
|
|
2017-11-14 05:05:30 +01:00
|
|
|
$dataContainer = $data[SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1'];
|
2017-11-14 04:31:16 +01:00
|
|
|
$this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['origin']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['base']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataContainer['class']);
|
2017-06-19 00:50:11 +02:00
|
|
|
|
2017-11-14 05:05:30 +01:00
|
|
|
$dataOtherContainer = $data[SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1'];
|
2017-11-14 04:31:16 +01:00
|
|
|
$this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['origin']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['base']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataOtherContainer['class']);
|
2017-06-19 00:50:11 +02:00
|
|
|
}
|
|
|
|
|
2017-06-15 23:39:37 +02:00
|
|
|
public function testFieldDataAmbiguousManyManyInherited()
|
|
|
|
{
|
|
|
|
$index = new SolrIndexTest_AmbiguousRelationInheritedIndex();
|
|
|
|
$data = $index->fieldData('ManyManyObjects.Field1');
|
|
|
|
|
2017-11-14 05:05:30 +01:00
|
|
|
$this->assertArrayHasKey(SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1', $data);
|
|
|
|
$this->assertArrayHasKey(SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1', $data);
|
|
|
|
$this->assertArrayNotHasKey(SearchUpdaterTest_ExtendedContainer::class . '_ManyManyObjects_Field1', $data);
|
2017-06-15 23:39:37 +02:00
|
|
|
|
2017-11-14 05:05:30 +01:00
|
|
|
$dataContainer = $data[SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1'];
|
2017-11-14 04:31:16 +01:00
|
|
|
$this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['origin']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['base']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataContainer['class']);
|
2017-06-15 23:39:37 +02:00
|
|
|
|
2017-11-14 05:05:30 +01:00
|
|
|
$dataOtherContainer = $data[SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1'];
|
2017-11-14 04:31:16 +01:00
|
|
|
$this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['origin']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['base']);
|
|
|
|
$this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataOtherContainer['class']);
|
2017-06-15 23:39:37 +02:00
|
|
|
}
|
|
|
|
|
2015-11-21 07:19:20 +01:00
|
|
|
/**
|
|
|
|
* Test boosting on SearchQuery
|
|
|
|
*/
|
|
|
|
public function testBoostedQuery()
|
|
|
|
{
|
2021-11-02 02:48:12 +01:00
|
|
|
/** @var Solr3Service|MockObject $serviceMock */
|
2017-04-26 12:52:20 +02:00
|
|
|
$serviceMock = $this->getMockBuilder(Solr3Service::class)
|
|
|
|
->setMethods(['search'])
|
|
|
|
->getMock();
|
|
|
|
|
|
|
|
$serviceMock->expects($this->once())
|
|
|
|
->method('search')
|
2017-11-14 04:31:16 +01:00
|
|
|
->with(
|
|
|
|
$this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'),
|
2017-04-26 12:52:20 +02:00
|
|
|
$this->anything(),
|
|
|
|
$this->anything(),
|
|
|
|
$this->anything(),
|
|
|
|
$this->anything()
|
|
|
|
)->willReturn($this->getFakeRawSolrResponse());
|
2015-11-21 07:19:20 +01:00
|
|
|
|
|
|
|
$index = new SolrIndexTest_FakeIndex();
|
|
|
|
$index->setService($serviceMock);
|
|
|
|
|
|
|
|
$query = new SearchQuery();
|
2018-05-14 18:04:40 +02:00
|
|
|
$query->addSearchTerm(
|
2015-11-21 07:19:20 +01:00
|
|
|
'term',
|
|
|
|
null,
|
|
|
|
array('Field1' => 1.5, 'HasOneObject_Field1' => 3)
|
|
|
|
);
|
|
|
|
$index->search($query);
|
|
|
|
}
|
2016-04-15 05:46:19 +02:00
|
|
|
|
2015-11-21 07:19:20 +01:00
|
|
|
/**
|
|
|
|
* Test boosting on field schema (via queried fields parameter)
|
|
|
|
*/
|
|
|
|
public function testBoostedField()
|
|
|
|
{
|
2017-12-04 21:11:51 +01:00
|
|
|
if (class_exists(Subsite::class)) {
|
|
|
|
Config::modify()->set(SearchVariantSubsites::class, 'enabled', false);
|
|
|
|
}
|
|
|
|
|
2021-11-02 02:48:12 +01:00
|
|
|
/** @var Solr3Service|MockObject $serviceMock */
|
2017-04-26 12:52:20 +02:00
|
|
|
$serviceMock = $this->getMockBuilder(Solr3Service::class)
|
|
|
|
->setMethods(['search'])
|
|
|
|
->getMock();
|
|
|
|
|
|
|
|
$serviceMock->expects($this->once())
|
|
|
|
->method('search')
|
2017-11-14 04:31:16 +01:00
|
|
|
->with(
|
|
|
|
$this->equalTo('+term'),
|
2017-04-26 12:52:20 +02:00
|
|
|
$this->anything(),
|
|
|
|
$this->anything(),
|
2017-12-04 21:11:51 +01:00
|
|
|
$this->equalTo([
|
|
|
|
'qf' => SearchUpdaterTest_Container::class . '_Field1^1.5 '
|
|
|
|
. SearchUpdaterTest_Container::class . '_Field2^2.1 _text',
|
2018-02-23 04:42:35 +01:00
|
|
|
'fq' => '',
|
2017-12-04 21:11:51 +01:00
|
|
|
]),
|
2017-04-26 12:52:20 +02:00
|
|
|
$this->anything()
|
|
|
|
)->willReturn($this->getFakeRawSolrResponse());
|
2015-11-21 07:19:20 +01:00
|
|
|
|
|
|
|
$index = new SolrIndexTest_BoostedIndex();
|
|
|
|
$index->setService($serviceMock);
|
|
|
|
|
|
|
|
$query = new SearchQuery();
|
2018-05-14 18:04:40 +02:00
|
|
|
$query->addSearchTerm('term');
|
2015-11-21 07:19:20 +01:00
|
|
|
$index->search($query);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testHighlightQueryOnBoost()
|
|
|
|
{
|
2017-04-26 12:52:20 +02:00
|
|
|
/** @var SilverStripe\FullTextSearch\Solr\Services\Solr3Service|ObjectProphecy $serviceMock */
|
|
|
|
$serviceMock = $this->getMockBuilder(Solr3Service::class)
|
|
|
|
->setMethods(['search'])
|
|
|
|
->getMock();
|
|
|
|
|
|
|
|
$serviceMock->expects($this->exactly(2))
|
|
|
|
->method('search')
|
2017-11-14 21:48:52 +01:00
|
|
|
->withConsecutive(
|
|
|
|
[
|
2017-04-26 12:52:20 +02:00
|
|
|
$this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'),
|
|
|
|
$this->anything(),
|
|
|
|
$this->anything(),
|
|
|
|
$this->logicalNot(
|
|
|
|
$this->arrayHasKey('hl.q')
|
|
|
|
),
|
|
|
|
$this->anything()
|
|
|
|
],
|
|
|
|
[
|
|
|
|
$this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'),
|
|
|
|
$this->anything(),
|
|
|
|
$this->anything(),
|
|
|
|
$this->arrayHasKey('hl.q'),
|
|
|
|
$this->anything()
|
|
|
|
]
|
|
|
|
)->willReturn($this->getFakeRawSolrResponse());
|
2015-11-21 07:19:20 +01:00
|
|
|
|
|
|
|
$index = new SolrIndexTest_FakeIndex();
|
|
|
|
$index->setService($serviceMock);
|
|
|
|
|
|
|
|
// Search without highlighting
|
|
|
|
$query = new SearchQuery();
|
2018-05-14 18:04:40 +02:00
|
|
|
$query->addSearchTerm(
|
2015-11-21 07:19:20 +01:00
|
|
|
'term',
|
|
|
|
null,
|
|
|
|
array('Field1' => 1.5, 'HasOneObject_Field1' => 3)
|
|
|
|
);
|
|
|
|
$index->search($query);
|
|
|
|
|
|
|
|
// Search with highlighting
|
|
|
|
$query = new SearchQuery();
|
2018-05-14 18:04:40 +02:00
|
|
|
$query->addSearchTerm(
|
2015-11-21 07:19:20 +01:00
|
|
|
'term',
|
|
|
|
null,
|
|
|
|
array('Field1' => 1.5, 'HasOneObject_Field1' => 3)
|
|
|
|
);
|
|
|
|
$index->search($query, -1, -1, array('hl' => true));
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testIndexExcludesNullValues()
|
|
|
|
{
|
2017-04-26 12:52:20 +02:00
|
|
|
/** @var Solr3Service|ObjectProphecy $serviceMock */
|
|
|
|
$serviceMock = $this->createMock(Solr3Service::class);
|
2015-11-21 07:19:20 +01:00
|
|
|
$index = new SolrIndexTest_FakeIndex();
|
|
|
|
$index->setService($serviceMock);
|
2017-04-26 12:52:20 +02:00
|
|
|
$obj = new SearchUpdaterTest_Container();
|
2015-11-21 07:19:20 +01:00
|
|
|
|
|
|
|
$obj->Field1 = 'Field1 val';
|
|
|
|
$obj->Field2 = null;
|
|
|
|
$obj->MyDate = null;
|
|
|
|
$docs = $index->add($obj);
|
2017-04-26 12:52:20 +02:00
|
|
|
$value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_Field1');
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->assertEquals('Field1 val', $value['value'], 'Writes non-NULL string fields');
|
2017-04-26 12:52:20 +02:00
|
|
|
$value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_Field2');
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->assertFalse($value, 'Ignores string fields if they are NULL');
|
2017-04-26 12:52:20 +02:00
|
|
|
$value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_MyDate');
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->assertFalse($value, 'Ignores date fields if they are NULL');
|
|
|
|
|
|
|
|
$obj->MyDate = '2010-12-30';
|
|
|
|
$docs = $index->add($obj);
|
2017-04-26 12:52:20 +02:00
|
|
|
$value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_MyDate');
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->assertEquals('2010-12-30T00:00:00Z', $value['value'], 'Writes non-NULL dates');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testAddFieldExtraOptions()
|
|
|
|
{
|
2017-11-14 05:05:30 +01:00
|
|
|
Injector::inst()->get(Kernel::class)->setEnvironment('live');
|
2015-11-21 07:19:20 +01:00
|
|
|
|
|
|
|
$index = new SolrIndexTest_FakeIndex();
|
|
|
|
|
|
|
|
$defs = simplexml_load_string('<fields>' . $index->getFieldDefinitions() . '</fields>');
|
2017-04-26 12:52:20 +02:00
|
|
|
$defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]');
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->assertEquals((string)$defField1[0]['stored'], 'false');
|
|
|
|
|
|
|
|
$index->addFilterField('Field1', null, array('stored' => 'true'));
|
|
|
|
$defs = simplexml_load_string('<fields>' . $index->getFieldDefinitions() . '</fields>');
|
2017-04-26 12:52:20 +02:00
|
|
|
$defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]');
|
2015-11-21 07:19:20 +01:00
|
|
|
$this->assertEquals((string)$defField1[0]['stored'], 'true');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testAddAnalyzer()
|
|
|
|
{
|
|
|
|
$index = new SolrIndexTest_FakeIndex();
|
|
|
|
|
|
|
|
$defs = simplexml_load_string('<fields>' . $index->getFieldDefinitions() . '</fields>');
|
2017-04-26 12:52:20 +02:00
|
|
|
$defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]');
|
2015-11-21 07:19:20 +01:00
|
|
|
$analyzers = $defField1[0]->analyzer;
|
|
|
|
$this->assertFalse((bool)$analyzers);
|
|
|
|
|
|
|
|
$index->addAnalyzer('Field1', 'charFilter', array('class' => 'solr.HTMLStripCharFilterFactory'));
|
|
|
|
$defs = simplexml_load_string('<fields>' . $index->getFieldDefinitions() . '</fields>');
|
2017-04-26 12:52:20 +02:00
|
|
|
$defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]');
|
2015-11-21 07:19:20 +01:00
|
|
|
$analyzers = $defField1[0]->analyzer;
|
|
|
|
$this->assertTrue((bool)$analyzers);
|
|
|
|
$this->assertEquals('solr.HTMLStripCharFilterFactory', $analyzers[0]->charFilter[0]['class']);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testAddCopyField()
|
|
|
|
{
|
|
|
|
$index = new SolrIndexTest_FakeIndex();
|
|
|
|
$index->addCopyField('sourceField', 'destField');
|
|
|
|
|
|
|
|
$defs = simplexml_load_string('<fields>' . $index->getCopyFieldDefinitions() . '</fields>');
|
|
|
|
$copyField = $defs->xpath('copyField');
|
|
|
|
|
|
|
|
$this->assertEquals('sourceField', $copyField[0]['source']);
|
|
|
|
$this->assertEquals('destField', $copyField[0]['dest']);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tests the setting of the 'stored' flag
|
|
|
|
*/
|
|
|
|
public function testStoredFields()
|
|
|
|
{
|
|
|
|
// Test two fields
|
|
|
|
$index = new SolrIndexTest_FakeIndex2();
|
|
|
|
$index->addStoredField('Field1');
|
|
|
|
$index->addFulltextField('Field2');
|
|
|
|
$schema = $index->getFieldDefinitions();
|
2021-11-02 02:48:12 +01:00
|
|
|
$this->assertStringContainsString(
|
2017-04-26 12:52:20 +02:00
|
|
|
"<field name='" . SearchUpdaterTest_Container::class . "_Field1' type='text' indexed='true' stored='true'",
|
2015-11-21 07:19:20 +01:00
|
|
|
$schema
|
|
|
|
);
|
2021-11-02 02:48:12 +01:00
|
|
|
$this->assertStringContainsString(
|
2017-04-26 12:52:20 +02:00
|
|
|
"<field name='" . SearchUpdaterTest_Container::class . "_Field2' type='text' indexed='true' stored='false'",
|
2015-11-21 07:19:20 +01:00
|
|
|
$schema
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test with addAllFulltextFields
|
|
|
|
$index2 = new SolrIndexTest_FakeIndex2();
|
|
|
|
$index2->addAllFulltextFields();
|
|
|
|
$index2->addStoredField('Field2');
|
|
|
|
$schema2 = $index2->getFieldDefinitions();
|
2021-11-02 02:48:12 +01:00
|
|
|
$this->assertStringContainsString(
|
2017-04-26 12:52:20 +02:00
|
|
|
"<field name='" . SearchUpdaterTest_Container::class . "_Field1' type='text' indexed='true' stored='false'",
|
2015-11-21 07:19:20 +01:00
|
|
|
$schema2
|
|
|
|
);
|
2021-11-02 02:48:12 +01:00
|
|
|
$this->assertStringContainsString(
|
2017-04-26 12:52:20 +02:00
|
|
|
"<field name='" . SearchUpdaterTest_Container::class . "_Field2' type='text' indexed='true' stored='true'",
|
2015-11-21 07:19:20 +01:00
|
|
|
$schema2
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-11-16 01:59:15 +01:00
|
|
|
public function testSanitiseClassName()
|
|
|
|
{
|
|
|
|
$index = new SolrIndexTest_FakeIndex2;
|
2017-12-05 22:17:18 +01:00
|
|
|
|
2017-11-16 01:59:15 +01:00
|
|
|
$this->assertSame(
|
|
|
|
'SilverStripe\\\\FullTextSearch\\\\Tests\\\\SolrIndexTest',
|
|
|
|
$index->sanitiseClassName(static::class)
|
|
|
|
);
|
2017-12-05 22:17:18 +01:00
|
|
|
|
|
|
|
$this->assertSame(
|
|
|
|
'SilverStripe-FullTextSearch-Tests-SolrIndexTest',
|
|
|
|
$index->sanitiseClassName(static::class, '-')
|
|
|
|
);
|
2017-11-16 01:59:15 +01:00
|
|
|
}
|
|
|
|
|
2017-11-29 22:40:25 +01:00
|
|
|
public function testGetIndexName()
|
|
|
|
{
|
|
|
|
$index = new SolrIndexTest_FakeIndex2;
|
2017-12-05 22:17:18 +01:00
|
|
|
$this->assertSame(
|
|
|
|
'SilverStripe-FullTextSearch-Tests-SolrIndexTest-SolrIndexTest_FakeIndex2',
|
|
|
|
$index->getIndexName()
|
|
|
|
);
|
2017-11-29 22:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testGetIndexNameWithPrefixAndSuffixFromEnvironment()
|
|
|
|
{
|
|
|
|
$index = new SolrIndexTest_FakeIndex2;
|
|
|
|
|
|
|
|
Environment::putEnv('SS_SOLR_INDEX_PREFIX="foo_"');
|
|
|
|
Environment::putEnv('SS_SOLR_INDEX_SUFFIX="_bar"');
|
|
|
|
|
2017-12-05 22:17:18 +01:00
|
|
|
$this->assertSame(
|
|
|
|
'foo_SilverStripe-FullTextSearch-Tests-SolrIndexTest-SolrIndexTest_FakeIndex2_bar',
|
|
|
|
$index->getIndexName()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-04-08 23:04:01 +02:00
|
|
|
/**
|
|
|
|
* Test that ShowInSearch and getShowInSearch() exclude DataObjects from being added to the index
|
|
|
|
*
|
|
|
|
* Note: this code path that really being tested here is SearchUpdateProcessor->prepareIndexes()
|
|
|
|
* This code path is used for 'inlet' filtering on CMS->save()
|
|
|
|
* The results of this will show-up in SolrIndex->_addAs()
|
|
|
|
*/
|
|
|
|
public function testShowInSearch()
|
|
|
|
{
|
2020-06-10 07:22:20 +02:00
|
|
|
// allow anonymous users to assess draft-only content to pass canView() check (will auto-reset for next test)
|
|
|
|
Versioned::set_draft_site_secured(false);
|
2020-04-08 23:04:01 +02:00
|
|
|
Versioned::set_reading_mode('Stage.' . Versioned::DRAFT);
|
2020-06-10 07:22:20 +02:00
|
|
|
Config::modify()->set(SearchableService::class, 'variant_state_draft_excluded', false);
|
2020-04-08 23:04:01 +02:00
|
|
|
|
|
|
|
$serviceMock = $this->getMockBuilder(Solr4Service::class)
|
|
|
|
->setMethods(['addDocument', 'deleteById'])
|
|
|
|
->getMock();
|
|
|
|
|
|
|
|
$index = new SolrIndexTest_ShowInSearchIndex();
|
|
|
|
$index->setService($serviceMock);
|
|
|
|
FullTextSearch::force_index_list($index);
|
|
|
|
|
|
|
|
// will get added
|
|
|
|
$pageA = new Page();
|
|
|
|
$pageA->Title = 'Test Page true';
|
|
|
|
$pageA->ShowInSearch = true;
|
|
|
|
$pageA->write();
|
|
|
|
|
|
|
|
// will get filtered out
|
|
|
|
$page = new Page();
|
|
|
|
$page->Title = 'Test Page false';
|
|
|
|
$page->ShowInSearch = false;
|
|
|
|
$page->write();
|
|
|
|
|
|
|
|
// will get added
|
|
|
|
$fileA = new File();
|
|
|
|
$fileA->Title = 'Test File true';
|
|
|
|
$fileA->ShowInSearch = true;
|
|
|
|
$fileA->write();
|
|
|
|
|
|
|
|
// will get filtered out
|
|
|
|
$file = new File();
|
|
|
|
$file->Title = 'Test File false';
|
|
|
|
$file->ShowInSearch = false;
|
|
|
|
$file->write();
|
|
|
|
|
|
|
|
// will get added
|
|
|
|
$objOneA = new SolrIndexTest_MyDataObjectOne();
|
|
|
|
$objOneA->Title = 'Test MyDataObjectOne true';
|
|
|
|
$objOneA->ShowInSearch = true;
|
|
|
|
$objOneA->write();
|
|
|
|
|
|
|
|
// will get filtered out
|
|
|
|
$objOne = new SolrIndexTest_MyDataObjectOne();
|
|
|
|
$objOne->Title = 'Test MyDataObjectOne false';
|
|
|
|
$objOne->ShowInSearch = false;
|
|
|
|
$objOne->write();
|
|
|
|
|
|
|
|
// will get added
|
|
|
|
// this class has a getShowInSearch() == true, which will override $mypage->ShowInSearch = false
|
|
|
|
$objTwoA = new SolrIndexTest_MyDataObjectTwo();
|
|
|
|
$objTwoA->Title = 'Test MyDataObjectTwo false';
|
|
|
|
$objTwoA->ShowInSearch = false;
|
|
|
|
$objTwoA->write();
|
|
|
|
|
|
|
|
// will get added
|
|
|
|
// this class has a getShowInSearch() == true, which will override $mypage->ShowInSearch = false
|
|
|
|
$myPageA = new SolrIndexTest_MyPage();
|
|
|
|
$myPageA->Title = 'Test MyPage false';
|
|
|
|
$myPageA->ShowInSearch = false;
|
|
|
|
$myPageA->write();
|
|
|
|
|
|
|
|
$callback = function (Apache_Solr_Document $doc) use ($pageA, $myPageA, $fileA, $objOneA, $objTwoA): bool {
|
|
|
|
$validKeys = [
|
|
|
|
Page::class . $pageA->ID,
|
|
|
|
SolrIndexTest_MyPage::class . $myPageA->ID,
|
|
|
|
File::class . $fileA->ID,
|
|
|
|
SolrIndexTest_MyDataObjectOne::class . $objOneA->ID,
|
|
|
|
SolrIndexTest_MyDataObjectTwo::class . $objTwoA->ID
|
|
|
|
];
|
2022-04-13 01:24:03 +02:00
|
|
|
return in_array($this->createSolrDocKey($doc), $validKeys ?? []);
|
2020-04-08 23:04:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
$serviceMock
|
|
|
|
->expects($this->exactly(5))
|
|
|
|
->method('addDocument')
|
|
|
|
->withConsecutive(
|
|
|
|
[$this->callback($callback)],
|
|
|
|
[$this->callback($callback)],
|
|
|
|
[$this->callback($callback)],
|
|
|
|
[$this->callback($callback)],
|
|
|
|
[$this->callback($callback)]
|
|
|
|
);
|
|
|
|
|
|
|
|
// This is what actually triggers all the solr stuff
|
|
|
|
SearchUpdater::flush_dirty_indexes();
|
|
|
|
|
|
|
|
// delete a solr doc by setting ShowInSearch to false
|
|
|
|
$pageA->ShowInSearch = false;
|
|
|
|
$pageA->write();
|
|
|
|
|
|
|
|
$serviceMock
|
|
|
|
->expects($this->exactly(1))
|
|
|
|
->method('deleteById')
|
|
|
|
->withConsecutive(
|
|
|
|
[$this->callback(function (string $docID) use ($pageA): bool {
|
2022-04-13 01:24:03 +02:00
|
|
|
return strpos($docID ?? '', $pageA->ID . '-' . SiteTree::class) !== false;
|
2020-04-08 23:04:01 +02:00
|
|
|
})]
|
|
|
|
);
|
|
|
|
|
2020-06-10 07:22:20 +02:00
|
|
|
SearchableService::singleton()->clearCache();
|
2020-04-08 23:04:01 +02:00
|
|
|
SearchUpdater::flush_dirty_indexes();
|
2020-06-10 07:22:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test that canView() check is used to exclude DataObjects from being added to the index
|
|
|
|
*
|
|
|
|
* Note: this code path that really being tested here is SearchUpdateProcessor->prepareIndexes()
|
|
|
|
* This code path is used for 'inlet' filtering on CMS->save()
|
|
|
|
* The results of this will show-up in SolrIndex->_addAs()
|
|
|
|
*/
|
|
|
|
public function testCanView()
|
|
|
|
{
|
|
|
|
// allow anonymous users to assess draft-only content to pass canView() check (will auto-reset for next test)
|
|
|
|
Versioned::set_draft_site_secured(false);
|
|
|
|
Versioned::set_reading_mode('Stage.' . Versioned::DRAFT);
|
|
|
|
Config::modify()->set(SearchableService::class, 'variant_state_draft_excluded', false);
|
2020-04-08 23:04:01 +02:00
|
|
|
|
2020-06-10 07:22:20 +02:00
|
|
|
$serviceMock = $this->getMockBuilder(Solr4Service::class)
|
|
|
|
->setMethods(['addDocument', 'deleteById'])
|
|
|
|
->getMock();
|
|
|
|
|
|
|
|
$index = new SolrIndexTest_ShowInSearchIndex();
|
|
|
|
$index->setService($serviceMock);
|
|
|
|
FullTextSearch::force_index_list($index);
|
|
|
|
|
|
|
|
// will get added
|
|
|
|
$pageA = new Page();
|
|
|
|
$pageA->Title = 'Test Page Anyone';
|
|
|
|
$pageA->CanViewType = 'Anyone';
|
|
|
|
$pageA->write();
|
|
|
|
|
|
|
|
// will get filtered out
|
|
|
|
$page = new Page();
|
|
|
|
$page->Title = 'Test Page LoggedInUsers';
|
|
|
|
$page->CanViewType = 'LoggedInUsers';
|
|
|
|
$page->write();
|
|
|
|
|
|
|
|
// will get added
|
|
|
|
$fileA = new File();
|
|
|
|
$fileA->Title = 'Test File Anyone';
|
|
|
|
$fileA->CanViewType = 'Anyone';
|
|
|
|
$fileA->write();
|
|
|
|
|
|
|
|
// will get filtered out
|
|
|
|
$file = new File();
|
|
|
|
$file->Title = 'Test File LoggedInUsers';
|
|
|
|
$file->CanViewType = 'LoggedInUsers';
|
|
|
|
$file->write();
|
|
|
|
|
|
|
|
// will get added
|
|
|
|
$objOneA = new SolrIndexTest_MyDataObjectOne();
|
|
|
|
$objOneA->Title = 'Test MyDataObjectOne true';
|
|
|
|
$objOneA->ShowInSearch = true;
|
|
|
|
$objOneA->CanViewValue = true;
|
|
|
|
$objOneA->write();
|
|
|
|
|
|
|
|
// will get filtered out
|
|
|
|
$objOne = new SolrIndexTest_MyDataObjectOne();
|
|
|
|
$objOne->Title = 'Test MyDataObjectOne false';
|
|
|
|
$objOne->ShowInSearch = true;
|
|
|
|
$objOne->CanViewValue = false;
|
|
|
|
$objOne->write();
|
|
|
|
|
|
|
|
$callback = function (Apache_Solr_Document $doc) use ($pageA, $fileA, $objOneA): bool {
|
|
|
|
$validKeys = [
|
|
|
|
Page::class . $pageA->ID,
|
|
|
|
File::class . $fileA->ID,
|
|
|
|
SolrIndexTest_MyDataObjectOne::class . $objOneA->ID
|
|
|
|
];
|
2022-04-13 01:24:03 +02:00
|
|
|
return in_array($this->createSolrDocKey($doc), $validKeys ?? []);
|
2020-06-10 07:22:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
$serviceMock
|
|
|
|
->expects($this->exactly(3))
|
|
|
|
->method('addDocument')
|
|
|
|
->withConsecutive(
|
|
|
|
[$this->callback($callback)],
|
|
|
|
[$this->callback($callback)],
|
|
|
|
[$this->callback($callback)]
|
|
|
|
);
|
|
|
|
|
|
|
|
// This is what actually triggers all the solr stuff
|
|
|
|
SearchUpdater::flush_dirty_indexes();
|
|
|
|
|
|
|
|
// delete a solr doc by setting ShowInSearch to false
|
|
|
|
$pageA->ShowInSearch = false;
|
|
|
|
$pageA->write();
|
|
|
|
|
|
|
|
$serviceMock
|
|
|
|
->expects($this->exactly(1))
|
|
|
|
->method('deleteById')
|
|
|
|
->withConsecutive(
|
|
|
|
[$this->callback(function (string $docID) use ($pageA): bool {
|
2022-04-13 01:24:03 +02:00
|
|
|
return strpos($docID ?? '', $pageA->ID . '-' . SiteTree::class) !== false;
|
2020-06-10 07:22:20 +02:00
|
|
|
})]
|
|
|
|
);
|
|
|
|
|
|
|
|
SearchableService::singleton()->clearCache();
|
|
|
|
SearchUpdater::flush_dirty_indexes();
|
2020-04-08 23:04:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function createSolrDocKey(Apache_Solr_Document $doc)
|
|
|
|
{
|
|
|
|
return $doc->getField('ClassName')['value'] . $doc->getField('ID')['value'];
|
|
|
|
}
|
|
|
|
|
2015-11-21 07:19:20 +01:00
|
|
|
protected function getFakeRawSolrResponse()
|
|
|
|
{
|
2017-04-26 12:52:20 +02:00
|
|
|
return new \Apache_Solr_Response(
|
|
|
|
new \Apache_Solr_HttpTransport_Response(
|
2015-11-21 07:19:20 +01:00
|
|
|
null,
|
|
|
|
null,
|
|
|
|
'{}'
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2012-08-23 17:49:32 +02:00
|
|
|
}
|