2011-03-22 10:00:53 +01:00
|
|
|
<?php
|
2016-06-16 06:57:19 +02:00
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
use SilverStripe\Assets\File;
|
2017-03-12 23:11:56 +01:00
|
|
|
use SilverStripe\CMS\Controllers\ModelAsController;
|
2017-03-09 06:17:31 +01:00
|
|
|
use SilverStripe\CMS\Model\SiteTree;
|
2017-03-12 23:11:56 +01:00
|
|
|
use SilverStripe\Control\HTTPRequest;
|
|
|
|
use SilverStripe\Core\Config\Config;
|
2016-06-16 06:57:19 +02:00
|
|
|
use SilverStripe\ORM\DB;
|
2017-03-21 05:26:46 +01:00
|
|
|
use SilverStripe\Versioned\Versioned;
|
2016-06-23 01:51:20 +02:00
|
|
|
use SilverStripe\MSSQL\MSSQLDatabase;
|
|
|
|
use SilverStripe\PostgreSQL\PostgreSQLDatabase;
|
2016-07-22 01:32:32 +02:00
|
|
|
use SilverStripe\CMS\Controllers\ContentController;
|
|
|
|
use SilverStripe\CMS\Search\SearchForm;
|
2016-08-23 04:36:06 +02:00
|
|
|
use SilverStripe\ORM\Search\FulltextSearchable;
|
|
|
|
use SilverStripe\Dev\FunctionalTest;
|
2017-03-09 06:17:31 +01:00
|
|
|
use SilverStripe\Security\Member;
|
2016-08-23 04:36:06 +02:00
|
|
|
|
2011-03-22 10:00:53 +01:00
|
|
|
/**
|
2011-03-22 10:47:26 +01:00
|
|
|
* @package cms
|
2011-03-22 10:00:53 +01:00
|
|
|
* @subpackage testing
|
2016-01-06 00:42:07 +01:00
|
|
|
*
|
2011-03-22 10:00:53 +01:00
|
|
|
* @todo Fix unpublished pages check in testPublishedPagesMatchedByTitle()
|
|
|
|
* @todo All tests run on unpublished pages at the moment, due to the searchform not distinguishing between them
|
2016-01-06 00:42:07 +01:00
|
|
|
*
|
2011-11-07 23:27:25 +01:00
|
|
|
* Because this manipulates the test database in severe ways, I've renamed the test to force it to run last...
|
2011-03-22 10:00:53 +01:00
|
|
|
*/
|
2017-01-25 21:59:25 +01:00
|
|
|
class ZZZSearchFormTest extends FunctionalTest
|
|
|
|
{
|
|
|
|
|
|
|
|
protected static $fixture_file = 'SearchFormTest.yml';
|
|
|
|
|
|
|
|
protected $illegalExtensions = array(
|
2017-03-09 06:17:31 +01:00
|
|
|
SiteTree::class => array('SiteTreeSubsites', 'Translatable')
|
2017-01-25 21:59:25 +01:00
|
|
|
);
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
/**
|
|
|
|
* @var ContentController
|
|
|
|
*/
|
2017-01-25 21:59:25 +01:00
|
|
|
protected $mockController;
|
|
|
|
|
|
|
|
public function waitUntilIndexingFinished()
|
|
|
|
{
|
|
|
|
$schema = DB::get_schema();
|
|
|
|
if (method_exists($schema, 'waitUntilIndexingFinished')) {
|
|
|
|
$schema->waitUntilIndexingFinished();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setUpOnce()
|
|
|
|
{
|
|
|
|
// HACK Postgres doesn't refresh TSearch indexes when the schema changes after CREATE TABLE
|
|
|
|
// MySQL will need a different table type
|
|
|
|
self::kill_temp_db();
|
2017-03-12 23:11:56 +01:00
|
|
|
Config::modify();
|
2017-01-25 21:59:25 +01:00
|
|
|
FulltextSearchable::enable();
|
|
|
|
self::create_temp_db();
|
|
|
|
$this->resetDBSchema(true);
|
|
|
|
parent::setUpOnce();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setUp()
|
|
|
|
{
|
|
|
|
parent::setUp();
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
/** @var Page $holderPage */
|
2017-03-09 06:17:31 +01:00
|
|
|
$holderPage = $this->objFromFixture(SiteTree::class, 'searchformholder');
|
2017-03-12 23:11:56 +01:00
|
|
|
$this->mockController = ModelAsController::controller_for($holderPage);
|
2017-01-25 21:59:25 +01:00
|
|
|
|
|
|
|
$this->waitUntilIndexingFinished();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return Boolean
|
|
|
|
*/
|
|
|
|
protected function checkFulltextSupport()
|
|
|
|
{
|
|
|
|
$conn = DB::get_conn();
|
2017-03-09 06:17:31 +01:00
|
|
|
if (class_exists(MSSQLDatabase::class) && $conn instanceof MSSQLDatabase) {
|
2017-01-25 21:59:25 +01:00
|
|
|
$supports = $conn->fullTextEnabled();
|
|
|
|
} else {
|
|
|
|
$supports = true;
|
|
|
|
}
|
|
|
|
if (!$supports) {
|
|
|
|
$this->markTestSkipped('Fulltext not supported by DB driver or setup');
|
|
|
|
}
|
|
|
|
return $supports;
|
|
|
|
}
|
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
/**
|
|
|
|
* @skipUpgrade
|
|
|
|
*/
|
2017-01-25 21:59:25 +01:00
|
|
|
public function testSearchFormTemplateCanBeChanged()
|
|
|
|
{
|
|
|
|
if (!$this->checkFulltextSupport()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$sf = new SearchForm($this->mockController);
|
2017-01-25 21:59:25 +01:00
|
|
|
|
|
|
|
$sf->setTemplate('BlankPage');
|
|
|
|
|
|
|
|
$this->assertContains(
|
2017-03-09 06:17:31 +01:00
|
|
|
'<body class="SearchForm Form BlankPage">',
|
2017-01-25 21:59:25 +01:00
|
|
|
$sf->forTemplate()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
/**
|
|
|
|
* @skipUpgrade
|
|
|
|
*/
|
2017-01-25 21:59:25 +01:00
|
|
|
public function testPublishedPagesMatchedByTitle()
|
|
|
|
{
|
|
|
|
if (!$this->checkFulltextSupport()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
$request = new HTTPRequest('GET', 'search', ['Search'=>'publicPublishedPage']);
|
|
|
|
$this->mockController->setRequest($request);
|
2017-03-09 06:17:31 +01:00
|
|
|
$sf = new SearchForm($this->mockController);
|
2017-01-25 21:59:25 +01:00
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$publishedPage = $this->objFromFixture(SiteTree::class, 'publicPublishedPage');
|
2017-01-25 21:59:25 +01:00
|
|
|
$publishedPage->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
|
|
|
|
|
|
|
|
$this->waitUntilIndexingFinished();
|
2017-03-12 23:11:56 +01:00
|
|
|
|
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertContains(
|
|
|
|
$publishedPage->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'Published pages are found by searchform'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
/**
|
|
|
|
* @skipUpgrade
|
|
|
|
*/
|
2017-01-25 21:59:25 +01:00
|
|
|
public function testDoubleQuotesPublishedPagesMatchedByTitle()
|
|
|
|
{
|
|
|
|
if (!$this->checkFulltextSupport()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
$request = new HTTPRequest('GET', 'search', ['Search'=>'"finding butterflies"']);
|
|
|
|
$this->mockController->setRequest($request);
|
2017-03-09 06:17:31 +01:00
|
|
|
$sf = new SearchForm($this->mockController);
|
2017-01-25 21:59:25 +01:00
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$publishedPage = $this->objFromFixture(SiteTree::class, 'publicPublishedPage');
|
2017-01-25 21:59:25 +01:00
|
|
|
$publishedPage->Title = "finding butterflies";
|
|
|
|
$publishedPage->write();
|
|
|
|
$publishedPage->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
|
|
|
|
|
|
|
|
$this->waitUntilIndexingFinished();
|
2017-03-12 23:11:56 +01:00
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertContains(
|
|
|
|
$publishedPage->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'Published pages are found by searchform'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
/**
|
|
|
|
* @skipUpgrade
|
|
|
|
*/
|
2017-01-25 21:59:25 +01:00
|
|
|
public function testUnpublishedPagesNotIncluded()
|
|
|
|
{
|
|
|
|
if (!$this->checkFulltextSupport()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
$request = new HTTPRequest('GET', 'search', ['Search'=>'publicUnpublishedPage']);
|
|
|
|
$this->mockController->setRequest($request);
|
2017-03-09 06:17:31 +01:00
|
|
|
$sf = new SearchForm($this->mockController);
|
2017-01-25 21:59:25 +01:00
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
$results = $sf->getResults();
|
2017-03-09 06:17:31 +01:00
|
|
|
$unpublishedPage = $this->objFromFixture(SiteTree::class, 'publicUnpublishedPage');
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertNotContains(
|
|
|
|
$unpublishedPage->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'Unpublished pages are not found by searchform'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testPagesRestrictedToLoggedinUsersNotIncluded()
|
|
|
|
{
|
|
|
|
if (!$this->checkFulltextSupport()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
$request = new HTTPRequest('GET', 'search', ['Search'=>'restrictedViewLoggedInUsers']);
|
|
|
|
$this->mockController->setRequest($request);
|
2017-03-09 06:17:31 +01:00
|
|
|
$sf = new SearchForm($this->mockController);
|
2017-01-25 21:59:25 +01:00
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$page = $this->objFromFixture(SiteTree::class, 'restrictedViewLoggedInUsers');
|
2017-01-25 21:59:25 +01:00
|
|
|
$page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
|
2017-03-12 23:11:56 +01:00
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertNotContains(
|
|
|
|
$page->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'Page with "Restrict to logged in users" doesnt show without valid login'
|
|
|
|
);
|
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$member = $this->objFromFixture(Member::class, 'randomuser');
|
2017-01-25 21:59:25 +01:00
|
|
|
$member->logIn();
|
2017-03-12 23:11:56 +01:00
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertContains(
|
|
|
|
$page->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'Page with "Restrict to logged in users" shows if login is present'
|
|
|
|
);
|
|
|
|
$member->logOut();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testPagesRestrictedToSpecificGroupNotIncluded()
|
|
|
|
{
|
|
|
|
if (!$this->checkFulltextSupport()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
$request = new HTTPRequest('GET', 'search', ['Search'=>'restrictedViewOnlyWebsiteUsers']);
|
|
|
|
$this->mockController->setRequest($request);
|
2017-03-09 06:17:31 +01:00
|
|
|
$sf = new SearchForm($this->mockController);
|
2017-01-25 21:59:25 +01:00
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$page = $this->objFromFixture(SiteTree::class, 'restrictedViewOnlyWebsiteUsers');
|
2017-01-25 21:59:25 +01:00
|
|
|
$page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
|
2017-03-12 23:11:56 +01:00
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertNotContains(
|
|
|
|
$page->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'Page with "Restrict to these users" doesnt show without valid login'
|
|
|
|
);
|
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$member = $this->objFromFixture(Member::class, 'randomuser');
|
2017-01-25 21:59:25 +01:00
|
|
|
$member->logIn();
|
2017-03-12 23:11:56 +01:00
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertNotContains(
|
|
|
|
$page->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'Page with "Restrict to these users" doesnt show if logged in user is not in the right group'
|
|
|
|
);
|
|
|
|
$member->logOut();
|
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$member = $this->objFromFixture(Member::class, 'websiteuser');
|
2017-01-25 21:59:25 +01:00
|
|
|
$member->logIn();
|
2017-03-12 23:11:56 +01:00
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertContains(
|
|
|
|
$page->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'Page with "Restrict to these users" shows if user in this group is logged in'
|
|
|
|
);
|
|
|
|
$member->logOut();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testInheritedRestrictedPagesNotIncluded()
|
|
|
|
{
|
2017-03-12 23:11:56 +01:00
|
|
|
$request = new HTTPRequest('GET', 'search', ['Search'=>'inheritRestrictedView']);
|
|
|
|
$this->mockController->setRequest($request);
|
2017-03-09 06:17:31 +01:00
|
|
|
$sf = new SearchForm($this->mockController);
|
2017-01-25 21:59:25 +01:00
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$parent = $this->objFromFixture(SiteTree::class, 'restrictedViewLoggedInUsers');
|
2017-01-25 21:59:25 +01:00
|
|
|
$parent->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
|
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$page = $this->objFromFixture(SiteTree::class, 'inheritRestrictedView');
|
2017-01-25 21:59:25 +01:00
|
|
|
$page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
|
2017-03-12 23:11:56 +01:00
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertNotContains(
|
|
|
|
$page->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'Page inheriting "Restrict to loggedin users" doesnt show without valid login'
|
|
|
|
);
|
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$member = $this->objFromFixture(Member::class, 'websiteuser');
|
2017-01-25 21:59:25 +01:00
|
|
|
$member->logIn();
|
2017-03-12 23:11:56 +01:00
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertContains(
|
|
|
|
$page->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'Page inheriting "Restrict to loggedin users" shows if user in this group is logged in'
|
|
|
|
);
|
|
|
|
$member->logOut();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testDisabledShowInSearchFlagNotIncludedForSiteTree()
|
|
|
|
{
|
|
|
|
if (!$this->checkFulltextSupport()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
$request = new HTTPRequest('GET', 'search', ['Search'=>'dontShowInSearchPage']);
|
|
|
|
$this->mockController->setRequest($request);
|
2017-03-09 06:17:31 +01:00
|
|
|
$sf = new SearchForm($this->mockController);
|
2017-01-25 21:59:25 +01:00
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$page = $this->objFromFixture(SiteTree::class, 'dontShowInSearchPage');
|
2017-03-12 23:11:56 +01:00
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertNotContains(
|
|
|
|
$page->ID,
|
|
|
|
$results->column('ID'),
|
2017-03-12 23:11:56 +01:00
|
|
|
'Page with "Show in Search" disabled does not show'
|
2017-01-25 21:59:25 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testDisabledShowInSearchFlagNotIncludedForFiles()
|
|
|
|
{
|
|
|
|
if (!$this->checkFulltextSupport()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
$request = new HTTPRequest('GET', 'search', ['Search'=>'dontShowInSearchFile']);
|
|
|
|
$this->mockController->setRequest($request);
|
2017-03-09 06:17:31 +01:00
|
|
|
$sf = new SearchForm($this->mockController);
|
2017-01-25 21:59:25 +01:00
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$dontShowInSearchFile = $this->objFromFixture(File::class, 'dontShowInSearchFile');
|
2017-01-25 21:59:25 +01:00
|
|
|
$dontShowInSearchFile->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
|
2017-03-09 06:17:31 +01:00
|
|
|
$showInSearchFile = $this->objFromFixture(File::class, 'showInSearchFile');
|
2017-01-25 21:59:25 +01:00
|
|
|
$showInSearchFile->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertNotContains(
|
|
|
|
$dontShowInSearchFile->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'File with "Show in Search" disabled doesnt show'
|
|
|
|
);
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
// Check ShowInSearch=1 can be found
|
|
|
|
$request = new HTTPRequest('GET', 'search', ['Search'=>'showInSearchFile']);
|
|
|
|
$this->mockController->setRequest($request);
|
|
|
|
$sf = new SearchForm($this->mockController);
|
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertContains(
|
|
|
|
$showInSearchFile->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'File with "Show in Search" enabled can be found'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testSearchTitleAndContentWithSpecialCharacters()
|
|
|
|
{
|
|
|
|
if (!$this->checkFulltextSupport()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
if (class_exists(PostgreSQLDatabase::class) && DB::get_conn() instanceof PostgreSQLDatabase) {
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->markTestSkipped("PostgreSQLDatabase doesn't support entity-encoded searches");
|
|
|
|
}
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
$request = new HTTPRequest('GET', 'search', ['Search'=>'Brötchen']);
|
|
|
|
$this->mockController->setRequest($request);
|
2017-03-09 06:17:31 +01:00
|
|
|
$sf = new SearchForm($this->mockController);
|
2017-01-25 21:59:25 +01:00
|
|
|
|
2017-03-09 06:17:31 +01:00
|
|
|
$pageWithSpecialChars = $this->objFromFixture(SiteTree::class, 'pageWithSpecialChars');
|
2017-01-25 21:59:25 +01:00
|
|
|
$pageWithSpecialChars->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertContains(
|
|
|
|
$pageWithSpecialChars->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'Published pages with umlauts in title are found'
|
|
|
|
);
|
|
|
|
|
2017-03-12 23:11:56 +01:00
|
|
|
// Check another word
|
|
|
|
$request = new HTTPRequest('GET', 'search', ['Search'=>'Bäcker']);
|
|
|
|
$this->mockController->setRequest($request);
|
|
|
|
$sf = new SearchForm($this->mockController);
|
|
|
|
$results = $sf->getResults();
|
2017-01-25 21:59:25 +01:00
|
|
|
$this->assertContains(
|
|
|
|
$pageWithSpecialChars->ID,
|
|
|
|
$results->column('ID'),
|
|
|
|
'Published pages with htmlencoded umlauts in content are found'
|
|
|
|
);
|
|
|
|
}
|
2011-03-22 10:00:53 +01:00
|
|
|
}
|