Compare commits

..

No commits in common. "3" and "3.9.0-beta1" have entirely different histories.

60 changed files with 407 additions and 544 deletions

View File

@ -1,15 +0,0 @@
name: CI
on:
push:
pull_request:
workflow_dispatch:
jobs:
ci:
name: CI
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v1
with:
extra_jobs: |
- name_suffix: subsites
composer_require_extra: silverstripe/subsites:^2

View File

@ -1,16 +0,0 @@
name: Dispatch CI
on:
# At 2:10 PM UTC, only on Wednesday and Thursday
schedule:
- cron: '10 14 * * 3,4'
jobs:
dispatch-ci:
name: Dispatch CI
# Only run cron on the silverstripe account
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
runs-on: ubuntu-latest
steps:
- name: Dispatch CI
uses: silverstripe/gha-dispatch-ci@v1

View File

@ -1,17 +0,0 @@
name: Keepalive
on:
workflow_dispatch:
# The 4th of every month at 10:50am UTC
schedule:
- cron: '50 10 4 * *'
jobs:
keepalive:
name: Keepalive
# Only run cron on the silverstripe account
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
runs-on: ubuntu-latest
steps:
- name: Keepalive
uses: silverstripe/gha-keepalive@v1

15
.scrutinizer.yml Normal file
View File

@ -0,0 +1,15 @@
inherit: true
build:
nodes:
analysis:
tests:
override: [php-scrutinizer-run]
checks:
php:
code_rating: true
duplication: true
filter:
paths: [src/*, tests/*]

18
.travis.yml Normal file
View File

@ -0,0 +1,18 @@
version: ~> 1.0
import:
- silverstripe/silverstripe-travis-shared:config/provision/standard-jobs-range.yml
env:
global:
- COMPOSER_ROOT_VERSION="3.x-dev"
- REQUIRE_EXTRA="symbiote/silverstripe-queuedjobs:^4.0"
jobs:
include:
- php: 7.3
env:
- DB=MYSQL
- REQUIRE_INSTALLER=4.x-dev
- PHPUNIT_TEST=1
- REQUIRE_EXTRA="symbiote/silverstripe-queuedjobs:^4 silverstripe/subsites:^2"

View File

@ -1,8 +0,0 @@
[main]
host = https://www.transifex.com
[o:silverstripe:p:silverstripe-fulltextsearch:r:master]
file_filter = lang/<lang>.yml
source_file = lang/en.yml
source_lang = en
type = YML

View File

@ -1,8 +1,11 @@
# FullTextSearch module # FullTextSearch module
[![CI](https://github.com/silverstripe/silverstripe-fulltextsearch/actions/workflows/ci.yml/badge.svg)](https://github.com/silverstripe/silverstripe-fulltextsearch/actions/workflows/ci.yml) [![Build Status](https://api.travis-ci.com/silverstripe/silverstripe-fulltextsearch.svg?branch=3)](https://travis-ci.com/silverstripe/silverstripe-fulltextsearch)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/silverstripe/silverstripe-fulltextsearch/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/silverstripe/silverstripe-fulltextsearch/?branch=master)
[![codecov](https://codecov.io/gh/silverstripe/silverstripe-fulltextsearch/branch/master/graph/badge.svg)](https://codecov.io/gh/silverstripe/silverstripe-fulltextsearch)
[![SilverStripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
Adds support for fulltext search engines like Sphinx and Solr to Silverstripe CMS. Adds support for fulltext search engines like Sphinx and Solr to SilverStripe CMS.
Compatible with PHP 7.2 Compatible with PHP 7.2
## Important notes when upgrading to fulltextsearch 3.7.0+ ## Important notes when upgrading to fulltextsearch 3.7.0+
@ -83,9 +86,9 @@ it's recommended you update your implementation to call `SearchableService::isVi
## Requirements ## Requirements
* Silverstripe 4.0+ * SilverStripe 4.0+
**Note:** For Silverstripe 3.x, please use the [2.x release line](https://github.com/silverstripe/silverstripe-fulltextsearch/tree/2). **Note:** For SilverStripe 3.x, please use the [2.x release line](https://github.com/silverstripe/silverstripe-fulltextsearch/tree/2).
## Documentation ## Documentation

5
_config.php Normal file
View File

@ -0,0 +1,5 @@
<?php
use SilverStripe\Dev\Deprecation;
Deprecation::notification_version('3.0', 'silverstripe/fulltextsearch');

View File

@ -21,19 +21,17 @@
} }
], ],
"require": { "require": {
"php": "^7.4 || ^8.0", "php": "^7.3 || ^8.0",
"silverstripe/framework": "^4.10", "silverstripe/framework": "^4.10",
"monolog/monolog": "~1.15", "monolog/monolog": "~1.15",
"silverstripe/solr-php-client": "^1.0", "ptcinc/solr-php-client": "^1.0",
"symfony/process": "^3.4 || ^4", "symfony/process": "^3.2",
"tractorcow/silverstripe-proxy-db": "^1", "tractorcow/silverstripe-proxy-db": "~0.1"
"ext-curl": "*"
}, },
"require-dev": { "require-dev": {
"silverstripe/cms": "^4.0", "silverstripe/cms": "^4.0",
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "^3.0", "squizlabs/php_codesniffer": "^3.0"
"symbiote/silverstripe-queuedjobs": "^4.9"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

View File

@ -379,7 +379,7 @@
--> -->
<autoSoftCommit> <autoSoftCommit>
<maxTime>${solr.autoSoftCommit.maxTime:60000}</maxTime> <maxTime>${solr.autoSoftCommit.maxTime:-1}</maxTime>
</autoSoftCommit> </autoSoftCommit>
<!-- Update Related Event Listeners <!-- Update Related Event Listeners

View File

@ -1,26 +1,13 @@
# Troubleshooting # Troubleshooting
## Newly indexed content only shows in searches after a delay
First, check how you're running index operations.
In many cases where the `queuedjobs` module is installed,
saving or publishing a record will create a new index job which needs to complete first.
Solr also distinguishes between adding documents to the indexing,
committing them, and making them available to new searches.
In most cases this happens within a few seconds, but
in sometimes it can take up to a minute due to the
`autoSoftCommit` configuration setting defaults in your `solrconfig.xml`.
To find out more detail, read about
[soft vs. hard commits](https://lucidworks.com/post/understanding-transaction-logs-softcommit-and-commit-in-sorlcloud/).
## Common gotchas ## Common gotchas
* By default number-letter boundaries are treated as a word boundary. For example, `A1` is two words - `a` and `1` - when Solr parses the search term. * By default number-letter boundaries are treated as a word boundary. For example, `A1` is two words - `a` and `1` - when Solr parses the search term.
* Special characters and operators are not correctly escaped * Special characters and operators are not correctly escaped
* Multi-word synonym issues * Multi-word synonym issues
* When Solr indexes are reconfigured and reindexed, their content is trashed and rebuilt * When Dolr indexes are reconfigured and reindexed, their content is trashed and rebuilt
## CWP-specific ### CWP-specific
* `solrconfig.xml` customisations fail silently * `solrconfig.xml` customisations fail silently
* Developers arent able to test raw queries or see output via the * Developers arent able to test raw queries or see output via the

View File

@ -2,13 +2,3 @@ en:
SilverStripe\FullTextSearch\Solr\Forms\SearchForm: SilverStripe\FullTextSearch\Solr\Forms\SearchForm:
GO: Go GO: Go
SEARCH: Search SEARCH: Search
SolrResultsPage:
DidYouMean: 'Did you mean'
NoResults: 'Sorry, your search query did not return any results.'
Page: Page
ReadMore: 'Read more about'
SearchQuery: 'You searched for'
ViewNextPage: 'View the next page'
ViewPageNumber: 'View page number'
ViewPreviousPage: 'View the previous page'
of: of

View File

@ -1,14 +0,0 @@
eo:
SilverStripe\FullTextSearch\Solr\Forms\SearchForm:
GO: Iri
SEARCH: Serĉi
SolrResultsPage:
DidYouMean: 'Ĉu vi intencis'
NoResults: 'Bedaŭrinde via serĉpeto ne liveris rezultojn.'
Page: Paĝo
ReadMore: 'Legi pli pri'
SearchQuery: 'Vi serĉis por'
ViewNextPage: 'Vidi la sekvan paĝon'
ViewPageNumber: 'Vidi paĝnumeron'
ViewPreviousPage: 'Vidi la antaŭan paĝon'
of: de

View File

@ -3,12 +3,12 @@ fi:
GO: Hae GO: Hae
SEARCH: Haku SEARCH: Haku
SolrResultsPage: SolrResultsPage:
DidYouMean: Tarkoititko
NoResults: 'Pahoittelut, mutta hakusi ei tuottanut yhtään osumaa.'
Page: Sivu
ReadMore: 'Lue lisää'
SearchQuery: 'Hakusanasi oli' SearchQuery: 'Hakusanasi oli'
'View page number': 'Siirry sivulle' DidYouMean: 'Tarkoititko'
ViewNextPage: 'Katso seuraava sivu' ReadMore: 'Lue lisää'
NoResults: 'Pahoittelut, mutta hakusi ei tuottanut yhtään osumaa.'
Page: 'Sivu'
of: '/'
ViewPreviousPage: 'Katso edellinen sivu' ViewPreviousPage: 'Katso edellinen sivu'
of: / View page number: 'Siirry sivulle'
ViewNextPage: 'Katso seuraava sivu'

View File

@ -1,14 +0,0 @@
nl:
SilverStripe\FullTextSearch\Solr\Forms\SearchForm:
GO: Zoek
SEARCH: Zoeken
SolrResultsPage:
DidYouMean: 'Bedoelde je'
NoResults: 'Helaas, deze zoekterm heeft geen resultaten opgeleverd.'
Page: Pagina
ReadMore: 'Lees meer over'
SearchQuery: 'Er is gezocht op'
ViewNextPage: 'Bekijk volgende pagina'
ViewPageNumber: 'Bekijk pagina'
ViewPreviousPage: 'Bekijk volgende pagina'
of: van

View File

@ -1,14 +0,0 @@
sl:
SilverStripe\FullTextSearch\Solr\Forms\SearchForm:
GO: Išči
SEARCH: Iskanje
SolrResultsPage:
DidYouMean: 'Ste morda mislili'
NoResults: 'Fraze, ki ste jo iskali, nismo našli.'
Page: Stran
ReadMore: 'Več o'
SearchQuery: 'Iskali ste'
ViewNextPage: Naslednja
ViewPageNumber: 'Skoči na stran'
ViewPreviousPage: Prejšnja
of: od

View File

@ -1,14 +0,0 @@
sv:
SilverStripe\FullTextSearch\Solr\Forms\SearchForm:
GO:
SEARCH: Sök
SolrResultsPage:
DidYouMean: 'Menade du'
NoResults: 'Förlåt, din sökfråga gav inga resultat.'
Page: Sida
ReadMore: 'Läs mera om'
SearchQuery: 'Du sökte efter'
ViewNextPage: 'Visa nästa sida'
ViewPageNumber: 'Visa sidnummer'
ViewPreviousPage: 'Visa föregående sida'
of: av

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/silverstripe/cms/tests/bootstrap.php" colors="true"> <phpunit bootstrap="vendor/silverstripe/cms/tests/bootstrap.php" colors="true">
<testsuites> <testsuites>
<testsuite name="Default"> <testsuite name="Default">

View File

@ -2,12 +2,11 @@
namespace SilverStripe\FullTextSearch\Search\Captures; namespace SilverStripe\FullTextSearch\Search\Captures;
use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\Connect\MySQLDatabase; use SilverStripe\ORM\Connect\MySQLDatabase;
use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater; use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater;
/** /**
* @deprecated 3.1.0 Use tractorcow/silverstripe-proxy-db to proxy the database connector instead * @deprecated 3.1...4.0 Please use tractorcow/silverstripe-proxy-db to proxy the database connector instead
*/ */
class SearchManipulateCapture_MySQLDatabase extends MySQLDatabase class SearchManipulateCapture_MySQLDatabase extends MySQLDatabase
@ -15,11 +14,6 @@ class SearchManipulateCapture_MySQLDatabase extends MySQLDatabase
public $isManipulationCapture = true; public $isManipulationCapture = true;
public function __construct()
{
Deprecation::notice('3.1.0', 'Use tractorcow/silverstripe-proxy-db to proxy the database connector instead', Deprecation::SCOPE_CLASS);
}
public function manipulate($manipulation) public function manipulate($manipulation)
{ {
$res = parent::manipulate($manipulation); $res = parent::manipulate($manipulation);

View File

@ -2,7 +2,6 @@
namespace SilverStripe\FullTextSearch\Search\Captures; namespace SilverStripe\FullTextSearch\Search\Captures;
use SilverStripe\Dev\Deprecation;
use SilverStripe\PostgreSQL\PostgreSQLDatabase; use SilverStripe\PostgreSQL\PostgreSQLDatabase;
use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater; use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater;
@ -11,17 +10,13 @@ if (!class_exists(PostgreSQLDatabase::class)) {
} }
/** /**
* @deprecated 3.1.0 Use tractorcow/silverstripe-proxy-db to proxy the database connector instead * @deprecated 3.1...4.0 Please use tractorcow/silverstripe-proxy-db to proxy the database connector instead
*/ */
class SearchManipulateCapture_PostgreSQLDatabase extends PostgreSQLDatabase class SearchManipulateCapture_PostgreSQLDatabase extends PostgreSQLDatabase
{ {
public $isManipulationCapture = true; public $isManipulationCapture = true;
public function __construct()
{
Deprecation::notice('3.1.0', 'Use tractorcow/silverstripe-proxy-db to proxy the database connector instead', Deprecation::SCOPE_CLASS);
}
public function manipulate($manipulation) public function manipulate($manipulation)
{ {
$res = parent::manipulate($manipulation); $res = parent::manipulate($manipulation);

View File

@ -2,7 +2,6 @@
namespace SilverStripe\FullTextSearch\Search\Captures; namespace SilverStripe\FullTextSearch\Search\Captures;
use SilverStripe\Dev\Deprecation;
use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater; use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater;
use SilverStripe\SQLite\SQLite3Database; use SilverStripe\SQLite\SQLite3Database;
@ -11,7 +10,7 @@ if (!class_exists(SQLite3Database::class)) {
} }
/** /**
* @deprecated 3.1.0 Use tractorcow/silverstripe-proxy-db to proxy the database connector instead * @deprecated 3.1...4.0 Please use tractorcow/silverstripe-proxy-db to proxy the database connector instead
*/ */
class SearchManipulateCapture_SQLite3Database extends SQLite3Database class SearchManipulateCapture_SQLite3Database extends SQLite3Database
@ -19,11 +18,6 @@ class SearchManipulateCapture_SQLite3Database extends SQLite3Database
public $isManipulationCapture = true; public $isManipulationCapture = true;
public function __construct()
{
Deprecation::notice('3.1.0', 'Use tractorcow/silverstripe-proxy-db to proxy the database connector instead', Deprecation::SCOPE_CLASS);
}
public function manipulate($manipulation) public function manipulate($manipulation)
{ {
$res = parent::manipulate($manipulation); $res = parent::manipulate($manipulation);

View File

@ -222,7 +222,7 @@ class SearchCriteria implements SearchCriteriaInterface
protected function getConjunction($key) protected function getConjunction($key)
{ {
$conjunctions = $this->getConjunctions(); $conjunctions = $this->getConjunctions();
if (!array_key_exists($key, $conjunctions ?? [])) { if (!array_key_exists($key, $conjunctions)) {
return null; return null;
} }

View File

@ -67,7 +67,7 @@ class FullTextSearch
} }
if ($hidden) { if ($hidden) {
$candidates = array_diff($candidates ?? [], $hidden); $candidates = array_diff($candidates, $hidden);
} }
// Create all indexes // Create all indexes
@ -86,7 +86,7 @@ class FullTextSearch
$valid = array(); $valid = array();
foreach ($all as $indexclass => $instance) { foreach ($all as $indexclass => $instance) {
if (is_subclass_of($indexclass, $class ?? '')) { if (is_subclass_of($indexclass, $class)) {
$valid[$indexclass] = $instance; $valid[$indexclass] = $instance;
} }
} }

View File

@ -70,7 +70,7 @@ abstract class SearchIndex extends ViewableData
*/ */
protected function getSourceName($source) protected function getSourceName($source)
{ {
$source = explode(self::config()->get('class_delimiter') ?? '', $source ?? ''); $source = explode(self::config()->get('class_delimiter'), $source);
return $source[0]; return $source[0];
} }
@ -102,7 +102,7 @@ abstract class SearchIndex extends ViewableData
*/ */
public function fieldData($field, $forceType = null, $extraOptions = []) public function fieldData($field, $forceType = null, $extraOptions = [])
{ {
$fullfield = str_replace(".", "_", $field ?? ''); $fullfield = str_replace(".", "_", $field);
$sources = $this->getClasses(); $sources = $this->getClasses();
foreach ($sources as $source => $options) { foreach ($sources as $source => $options) {
@ -112,8 +112,8 @@ abstract class SearchIndex extends ViewableData
$found = []; $found = [];
if (strpos($field ?? '', '.') !== false) { if (strpos($field, '.') !== false) {
$lookups = explode(".", $field ?? ''); $lookups = explode(".", $field);
$field = array_pop($lookups); $field = array_pop($lookups);
foreach ($lookups as $lookup) { foreach ($lookups as $lookup) {
@ -133,7 +133,7 @@ abstract class SearchIndex extends ViewableData
// we only want to include base class for relation, omit classes that inherited the relation // we only want to include base class for relation, omit classes that inherited the relation
$relationList = Config::inst()->get($dataclass, 'has_one', Config::UNINHERITED); $relationList = Config::inst()->get($dataclass, 'has_one', Config::UNINHERITED);
$relationList = (!is_null($relationList)) ? $relationList : []; $relationList = (!is_null($relationList)) ? $relationList : [];
if (!array_key_exists($lookup, $relationList ?? [])) { if (!array_key_exists($lookup, $relationList)) {
continue; continue;
} }
@ -146,7 +146,7 @@ abstract class SearchIndex extends ViewableData
// we only want to include base class for relation, omit classes that inherited the relation // we only want to include base class for relation, omit classes that inherited the relation
$relationList = Config::inst()->get($dataclass, 'has_many', Config::UNINHERITED); $relationList = Config::inst()->get($dataclass, 'has_many', Config::UNINHERITED);
$relationList = (!is_null($relationList)) ? $relationList : []; $relationList = (!is_null($relationList)) ? $relationList : [];
if (!array_key_exists($lookup, $relationList ?? [])) { if (!array_key_exists($lookup, $relationList)) {
continue; continue;
} }
@ -160,7 +160,7 @@ abstract class SearchIndex extends ViewableData
// we only want to include base class for relation, omit classes that inherited the relation // we only want to include base class for relation, omit classes that inherited the relation
$relationList = Config::inst()->get($dataclass, 'many_many', Config::UNINHERITED); $relationList = Config::inst()->get($dataclass, 'many_many', Config::UNINHERITED);
$relationList = (!is_null($relationList)) ? $relationList : []; $relationList = (!is_null($relationList)) ? $relationList : [];
if (!array_key_exists($lookup, $relationList ?? [])) { if (!array_key_exists($lookup, $relationList)) {
continue; continue;
} }
@ -199,7 +199,7 @@ abstract class SearchIndex extends ViewableData
$class = $this->getSourceName($class); $class = $this->getSourceName($class);
$dataclasses = SearchIntrospection::hierarchy($class, $options['include_children']); $dataclasses = SearchIntrospection::hierarchy($class, $options['include_children']);
while (count($dataclasses ?? [])) { while (count($dataclasses)) {
$dataclass = array_shift($dataclasses); $dataclass = array_shift($dataclasses);
$type = null; $type = null;
$fieldoptions = $options; $fieldoptions = $options;
@ -228,9 +228,9 @@ abstract class SearchIndex extends ViewableData
if ($type) { if ($type) {
// Don't search through child classes of a class we matched on. TODO: Should we? // Don't search through child classes of a class we matched on. TODO: Should we?
$dataclasses = array_diff($dataclasses ?? [], array_values(ClassInfo::subclassesFor($dataclass) ?? [])); $dataclasses = array_diff($dataclasses, array_values(ClassInfo::subclassesFor($dataclass)));
// Trim arguments off the type string // Trim arguments off the type string
if (preg_match('/^(\w+)\(/', $type ?? '', $match)) { if (preg_match('/^(\w+)\(/', $type, $match)) {
$type = $match[1]; $type = $match[1];
} }
// Get the origin // Get the origin
@ -412,7 +412,7 @@ abstract class SearchIndex extends ViewableData
public function buildDependancyList() public function buildDependancyList()
{ {
$this->dependancyList = array_keys($this->getClasses() ?? []); $this->dependancyList = array_keys($this->getClasses());
foreach ($this->getFieldsIterator() as $name => $field) { foreach ($this->getFieldsIterator() as $name => $field) {
if (!isset($field['class'])) { if (!isset($field['class'])) {
@ -434,7 +434,7 @@ abstract class SearchIndex extends ViewableData
$this->derivedFields = array(); $this->derivedFields = array();
foreach ($this->getFieldsIterator() as $name => $field) { foreach ($this->getFieldsIterator() as $name => $field) {
if (count($field['lookup_chain'] ?? []) < 2) { if (count($field['lookup_chain']) < 2) {
continue; continue;
} }
@ -445,7 +445,7 @@ abstract class SearchIndex extends ViewableData
$this->derivedFields[$key]['fields'][$fieldname] = $fieldname; $this->derivedFields[$key]['fields'][$fieldname] = $fieldname;
SearchIntrospection::add_unique_by_ancestor($this->derivedFields['classes'], $field['class']); SearchIntrospection::add_unique_by_ancestor($this->derivedFields['classes'], $field['class']);
} else { } else {
$chain = array_reverse($field['lookup_chain'] ?? []); $chain = array_reverse($field['lookup_chain']);
array_shift($chain); array_shift($chain);
$this->derivedFields[$key] = array( $this->derivedFields[$key] = array(
@ -473,7 +473,7 @@ abstract class SearchIndex extends ViewableData
{ {
ksort($state); ksort($state);
$parts = array('id' => $id, 'base' => $base, 'state' => json_encode($state)); $parts = array('id' => $id, 'base' => $base, 'state' => json_encode($state));
return implode('-', array_values($parts ?? [])); return implode('-', array_values($parts));
} }
/** /**
@ -501,7 +501,7 @@ abstract class SearchIndex extends ViewableData
$errorHandler = function ($no, $str) { $errorHandler = function ($no, $str) {
throw new Exception('HTML Parse Error: ' . $str); throw new Exception('HTML Parse Error: ' . $str);
}; };
set_error_handler($errorHandler, E_ALL & ~(E_DEPRECATED | E_USER_DEPRECATED)); set_error_handler($errorHandler, E_ALL);
try { try {
foreach ($field['lookup_chain'] as $step) { foreach ($field['lookup_chain'] as $step) {
@ -586,7 +586,7 @@ abstract class SearchIndex extends ViewableData
// First, if this object is directly contained in the index, add it // First, if this object is directly contained in the index, add it
foreach ($this->classes as $searchclass => $options) { foreach ($this->classes as $searchclass => $options) {
if ($searchclass == $class || ($options['include_children'] && is_subclass_of($class, $searchclass ?? ''))) { if ($searchclass == $class || ($options['include_children'] && is_subclass_of($class, $searchclass))) {
$base = DataObject::getSchema()->baseDataClass($searchclass); $base = DataObject::getSchema()->baseDataClass($searchclass);
$dirty[$base] = array(); $dirty[$base] = array();
foreach ($statefulids as $statefulid) { foreach ($statefulids as $statefulid) {
@ -605,7 +605,7 @@ abstract class SearchIndex extends ViewableData
if (!SearchIntrospection::is_subclass_of($class, $derivation['classes'])) { if (!SearchIntrospection::is_subclass_of($class, $derivation['classes'])) {
continue; continue;
} }
if (!array_intersect_key($fields ?? [], $derivation['fields'])) { if (!array_intersect_key($fields, $derivation['fields'])) {
continue; continue;
} }

View File

@ -89,7 +89,7 @@ abstract class SearchUpdateBatchedProcessor extends SearchUpdateProcessor
} }
// Don't re-process completed queue // Don't re-process completed queue
if ($this->currentBatch >= count($this->batches ?? [])) { if ($this->currentBatch >= count($this->batches)) {
return true; return true;
} }
@ -138,14 +138,14 @@ abstract class SearchUpdateBatchedProcessor extends SearchUpdateProcessor
while ($ids) { while ($ids) {
// Estimate maximum number of items to take for this iteration, allowing for the soft cap // Estimate maximum number of items to take for this iteration, allowing for the soft cap
$take = $batchSize - $currentSize; $take = $batchSize - $currentSize;
if (count($ids ?? []) <= $take + $softCap) { if (count($ids) <= $take + $softCap) {
$take += $softCap; $take += $softCap;
} }
$items = array_slice($ids ?? [], 0, $take, true); $items = array_slice($ids, 0, $take, true);
$ids = array_slice($ids ?? [], count($items ?? []), null, true); $ids = array_slice($ids, count($items), null, true);
// Update batch // Update batch
$currentSize += count($items ?? []); $currentSize += count($items);
$merge = array( $merge = array(
$base => array( $base => array(
$stateKey => array( $stateKey => array(

View File

@ -97,7 +97,7 @@ class SearchUpdateCommitJobProcessor implements QueuedJob
if ($dirty) { if ($dirty) {
$indexes = FullTextSearch::get_indexes(); $indexes = FullTextSearch::get_indexes();
static::$dirty_indexes = array_keys($indexes ?? []); static::$dirty_indexes = array_keys($indexes);
} }
return $id; return $id;
} }
@ -126,7 +126,7 @@ class SearchUpdateCommitJobProcessor implements QueuedJob
{ {
if (empty($this->indexes)) { if (empty($this->indexes)) {
$indexes = FullTextSearch::get_indexes(); $indexes = FullTextSearch::get_indexes();
$this->indexes = array_keys($indexes ?? []); $this->indexes = array_keys($indexes);
} }
return $this->indexes; return $this->indexes;
} }
@ -135,7 +135,7 @@ class SearchUpdateCommitJobProcessor implements QueuedJob
{ {
// If we've indexed exactly as many as we would like, we are done // If we've indexed exactly as many as we would like, we are done
return $this->skipped return $this->skipped
|| (count($this->getAllIndexes() ?? []) <= count($this->completed ?? [])); || (count($this->getAllIndexes()) <= count($this->completed));
} }
public function prepareForRestart() public function prepareForRestart()
@ -213,7 +213,7 @@ class SearchUpdateCommitJobProcessor implements QueuedJob
{ {
// Skip index if this is already complete // Skip index if this is already complete
$name = get_class($index); $name = get_class($index);
if (in_array($name, $this->completed ?? [])) { if (in_array($name, $this->completed)) {
$this->addMessage("Skipping already comitted index {$name}"); $this->addMessage("Skipping already comitted index {$name}");
return; return;
} }
@ -240,8 +240,8 @@ class SearchUpdateCommitJobProcessor implements QueuedJob
public function getJobData() public function getJobData()
{ {
$data = new stdClass(); $data = new stdClass();
$data->totalSteps = count($this->getAllIndexes() ?? []); $data->totalSteps = count($this->getAllIndexes());
$data->currentStep = count($this->completed ?? []); $data->currentStep = count($this->completed);
$data->isComplete = $this->jobFinished(); $data->isComplete = $this->jobFinished();
$data->messages = $this->messages; $data->messages = $this->messages;
@ -265,7 +265,7 @@ class SearchUpdateCommitJobProcessor implements QueuedJob
public function addMessage($message, $severity = 'INFO') public function addMessage($message, $severity = 'INFO')
{ {
$severity = strtoupper($severity ?? ''); $severity = strtoupper($severity);
$this->messages[] = '[' . date('Y-m-d H:i:s') . "][$severity] $message"; $this->messages[] = '[' . date('Y-m-d H:i:s') . "][$severity] $message";
} }

View File

@ -5,7 +5,6 @@ namespace SilverStripe\FullTextSearch\Search\Processors;
use SilverStripe\FullTextSearch\Search\Services\SearchableService; use SilverStripe\FullTextSearch\Search\Services\SearchableService;
use SilverStripe\FullTextSearch\Search\Variants\SearchVariantVersioned; use SilverStripe\FullTextSearch\Search\Variants\SearchVariantVersioned;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB;
use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; use SilverStripe\FullTextSearch\Search\Variants\SearchVariant;
use SilverStripe\FullTextSearch\Search\FullTextSearch; use SilverStripe\FullTextSearch\Search\FullTextSearch;
use SilverStripe\Versioned\Versioned; use SilverStripe\Versioned\Versioned;
@ -55,7 +54,7 @@ abstract class SearchUpdateProcessor
$forclass[$statekey] = array('state' => $state, 'ids' => array($id => array($index))); $forclass[$statekey] = array('state' => $state, 'ids' => array($id => array($index)));
} elseif (!isset($forclass[$statekey]['ids'][$id])) { } elseif (!isset($forclass[$statekey]['ids'][$id])) {
$forclass[$statekey]['ids'][$id] = array($index); $forclass[$statekey]['ids'][$id] = array($index);
} elseif (array_search($index, $forclass[$statekey]['ids'][$id] ?? []) === false) { } elseif (array_search($index, $forclass[$statekey]['ids'][$id]) === false) {
$forclass[$statekey]['ids'][$id][] = $index; $forclass[$statekey]['ids'][$id][] = $index;
// dirty count stays the same // dirty count stays the same
} }
@ -89,7 +88,7 @@ abstract class SearchUpdateProcessor
SearchVariant::activate_state($state); SearchVariant::activate_state($state);
// Ensure that indexes for all new / updated objects are included // Ensure that indexes for all new / updated objects are included
$objs = DataObject::get($base)->byIDs(array_keys($ids ?? [])); $objs = DataObject::get($base)->byIDs(array_keys($ids));
/** @var DataObject $obj */ /** @var DataObject $obj */
foreach ($objs as $obj) { foreach ($objs as $obj) {
@ -155,9 +154,6 @@ abstract class SearchUpdateProcessor
*/ */
public function process() public function process()
{ {
if (!DB::is_active()) {
return false;
}
// Generate and commit all instances // Generate and commit all instances
$indexes = $this->prepareIndexes(); $indexes = $this->prepareIndexes();
foreach ($indexes as $index) { foreach ($indexes as $index) {

View File

@ -45,7 +45,7 @@ class SearchUpdateQueuedJobProcessor extends SearchUpdateBatchedProcessor implem
public function jobFinished() public function jobFinished()
{ {
return $this->currentBatch >= count($this->batches ?? []); return $this->currentBatch >= count($this->batches);
} }
public function setup() public function setup()
@ -68,7 +68,7 @@ class SearchUpdateQueuedJobProcessor extends SearchUpdateBatchedProcessor implem
public function getJobData() public function getJobData()
{ {
$data = new stdClass(); $data = new stdClass();
$data->totalSteps = count($this->batches ?? []); $data->totalSteps = count($this->batches);
$data->currentStep = $this->currentBatch; $data->currentStep = $this->currentBatch;
$data->isComplete = $this->jobFinished(); $data->isComplete = $this->jobFinished();
$data->messages = $this->messages; $data->messages = $this->messages;
@ -91,7 +91,7 @@ class SearchUpdateQueuedJobProcessor extends SearchUpdateBatchedProcessor implem
public function addMessage($message, $severity = 'INFO') public function addMessage($message, $severity = 'INFO')
{ {
$severity = strtoupper($severity ?? ''); $severity = strtoupper($severity);
$this->messages[] = '[' . date('Y-m-d H:i:s') . "][$severity] $message"; $this->messages[] = '[' . date('Y-m-d H:i:s') . "][$severity] $message";
} }

View File

@ -284,81 +284,81 @@ class SearchQuery extends ViewableData
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @deprecated 4.0.0 Use addSearchTerm() instead * @deprecated
*/ */
public function search($text, $fields = null, $boost = []) public function search($text, $fields = null, $boost = [])
{ {
Deprecation::notice('4.0.0', 'Use addSearchTerm() instead'); Deprecation::notice('4.0', 'Use addSearchTerm() instead');
return $this->addSearchTerm($text, $fields, $boost); return $this->addSearchTerm($text, $fields, $boost);
} }
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @deprecated 4.0.0 Use addFuzzySearchTerm() instead * @deprecated
*/ */
public function fuzzysearch($text, $fields = null, $boost = []) public function fuzzysearch($text, $fields = null, $boost = [])
{ {
Deprecation::notice('4.0.0', 'Use addFuzzySearchTerm() instead'); Deprecation::notice('4.0', 'Use addFuzzySearchTerm() instead');
return $this->addFuzzySearchTerm($text, $fields, $boost); return $this->addFuzzySearchTerm($text, $fields, $boost);
} }
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @deprecated 4.0.0 Use addClassFilter() instead * @deprecated
*/ */
public function inClass($class, $includeSubclasses = true) public function inClass($class, $includeSubclasses = true)
{ {
Deprecation::notice('4.0.0', 'Use addClassFilter() instead'); Deprecation::notice('4.0', 'Use addClassFilter() instead');
return $this->addClassFilter($class, $includeSubclasses); return $this->addClassFilter($class, $includeSubclasses);
} }
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @deprecated 4.0.0 Use addFilter() instead * @deprecated
*/ */
public function filter($field, $values) public function filter($field, $values)
{ {
Deprecation::notice('4.0.0', 'Use addFilter() instead'); Deprecation::notice('4.0', 'Use addFilter() instead');
return $this->addFilter($field, $values); return $this->addFilter($field, $values);
} }
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @deprecated 4.0.0 Use addExclude() instead * @deprecated
*/ */
public function exclude($field, $values) public function exclude($field, $values)
{ {
Deprecation::notice('4.0.0', 'Use addExclude() instead'); Deprecation::notice('4.0', 'Use addExclude() instead');
return $this->addExclude($field, $values); return $this->addExclude($field, $values);
} }
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @deprecated 4.0.0 Use setStart() instead * @deprecated
*/ */
public function start($start) public function start($start)
{ {
Deprecation::notice('4.0.0', 'Use setStart() instead'); Deprecation::notice('4.0', 'Use setStart() instead');
return $this->setStart($start); return $this->setStart($start);
} }
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @deprecated 4.0.0 Use setLimit() instead * @deprecated
*/ */
public function limit($limit) public function limit($limit)
{ {
Deprecation::notice('4.0.0', 'Use setLimit() instead'); Deprecation::notice('4.0', 'Use setLimit() instead');
return $this->setLimit($limit); return $this->setLimit($limit);
} }
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @deprecated 4.0.0 Use setPageSize() instead * @deprecated
*/ */
public function page($page) public function page($page)
{ {
Deprecation::notice('4.0.0', 'Use setPageSize() instead'); Deprecation::notice('4.0', 'Use setPageSize() instead');
return $this->setPageSize($page); return $this->setPageSize($page);
} }

View File

@ -40,22 +40,22 @@ class SearchQuery_Range
} }
/** /**
* @deprecated 4.0.0 Use setStart() instead * @deprecated
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public function start($start) public function start($start)
{ {
Deprecation::notice('4.0.0', 'Use setStart() instead'); Deprecation::notice('4.0', 'Use setStart() instead');
return $this->setStart($start); return $this->setStart($start);
} }
/** /**
* @deprecated 4.0.0 Use setEnd() instead * @deprecated
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public function end($end) public function end($end)
{ {
Deprecation::notice('4.0.0', 'Use setEnd() instead'); Deprecation::notice('4.0', 'Use setEnd() instead');
return $this->setEnd($end); return $this->setEnd($end);
} }
} }

View File

@ -21,7 +21,7 @@ class SearchIntrospection
public static function is_subclass_of($class, $of) public static function is_subclass_of($class, $of)
{ {
$ancestry = isset(self::$ancestry[$class]) ? self::$ancestry[$class] : (self::$ancestry[$class] = ClassInfo::ancestry($class)); $ancestry = isset(self::$ancestry[$class]) ? self::$ancestry[$class] : (self::$ancestry[$class] = ClassInfo::ancestry($class));
return is_array($of) ? (bool)array_intersect($of, $ancestry) : array_key_exists($of, $ancestry ?? []); return is_array($of) ? (bool)array_intersect($of, $ancestry) : array_key_exists($of, $ancestry);
} }
protected static $hierarchy = array(); protected static $hierarchy = array();
@ -40,12 +40,12 @@ class SearchIntrospection
$key = "$class!" . ($includeSubclasses ? 'sc' : 'an') . '!' . ($dataOnly ? 'do' : 'al'); $key = "$class!" . ($includeSubclasses ? 'sc' : 'an') . '!' . ($dataOnly ? 'do' : 'al');
if (!isset(self::$hierarchy[$key])) { if (!isset(self::$hierarchy[$key])) {
$classes = array_values(ClassInfo::ancestry($class) ?? []); $classes = array_values(ClassInfo::ancestry($class));
if ($includeSubclasses) { if ($includeSubclasses) {
$classes = array_unique(array_merge($classes, array_values(ClassInfo::subclassesFor($class) ?? []))); $classes = array_unique(array_merge($classes, array_values(ClassInfo::subclassesFor($class))));
} }
$idx = array_search(DataObject::class, $classes ?? []); $idx = array_search(DataObject::class, $classes);
if ($idx !== false) { if ($idx !== false) {
array_splice($classes, 0, $idx+1); array_splice($classes, 0, $idx+1);
} }
@ -76,7 +76,7 @@ class SearchIntrospection
// Strip out any subclasses of $class already in the list // Strip out any subclasses of $class already in the list
$children = ClassInfo::subclassesFor($class); $children = ClassInfo::subclassesFor($class);
$list = array_diff($list ?? [], $children); $list = array_diff($list, $children);
// Then add the class in // Then add the class in
$list[] = $class; $list[] = $class;

View File

@ -151,12 +151,12 @@ class SearchableService
// Anonymous member canView() for indexing // Anonymous member canView() for indexing
if (!$this->classSkipsCanViewCheck($objClass)) { if (!$this->classSkipsCanViewCheck($objClass)) {
$value = Member::actAs(null, function () use ($obj) { $value = Member::actAs(null, function () use ($obj) {
return (bool) $obj->canView(); return $obj->canView();
}); });
} }
} else { } else {
// Current member canView() check for retrieving search results // Current member canView() check for retrieving search results
$value = (bool) $obj->canView(); $value = $obj->canView();
} }
} }
$this->extend('updateIsSearchable', $obj, $indexing, $value); $this->extend('updateIsSearchable', $obj, $indexing, $value);
@ -199,11 +199,11 @@ class SearchableService
if (empty($skipClasses)) { if (empty($skipClasses)) {
return false; return false;
} }
if (in_array($class, $skipClasses ?? [])) { if (in_array($class, $skipClasses)) {
return true; return true;
} }
foreach ($skipClasses as $skipClass) { foreach ($skipClasses as $skipClass) {
if (in_array($skipClass, class_parents($class) ?? [])) { if (in_array($skipClass, class_parents($class))) {
return true; return true;
} }
} }

View File

@ -106,7 +106,7 @@ class SearchUpdater
'command' => $command, 'command' => $command,
'fields' => array() 'fields' => array()
); );
} elseif (is_subclass_of($class, $writes[$key]['class'] ?? '')) { } elseif (is_subclass_of($class, $writes[$key]['class'])) {
// Otherwise update the class label if it's more specific than the currently recorded one // Otherwise update the class label if it's more specific than the currently recorded one
$writes[$key]['class'] = $class; $writes[$key]['class'] = $class;
} }
@ -118,7 +118,7 @@ class SearchUpdater
} }
// Trim non-delete records without fields // Trim non-delete records without fields
foreach (array_keys($writes ?? []) as $key) { foreach (array_keys($writes) as $key) {
if ($writes[$key]['command'] !== 'delete' && empty($writes[$key]['fields'])) { if ($writes[$key]['command'] !== 'delete' && empty($writes[$key]['fields'])) {
unset($writes[$key]); unset($writes[$key]);
} }

View File

@ -105,9 +105,6 @@ abstract class SearchVariant
$ref = new ReflectionClass($variantclass); $ref = new ReflectionClass($variantclass);
if ($ref->isInstantiable()) { if ($ref->isInstantiable()) {
$variant = singleton($variantclass); $variant = singleton($variantclass);
// reassign actual class since Injector could be involved when creating the singleton
$variantclass = get_class($variant);
if ($variant->appliesToEnvironment()) { if ($variant->appliesToEnvironment()) {
$concrete[$variantclass] = $variant; $concrete[$variantclass] = $variant;
} }
@ -205,7 +202,7 @@ abstract class SearchVariant
// Merge the variants applicable to the current class into the list of common variants, using // Merge the variants applicable to the current class into the list of common variants, using
// the variant instance to replace any previous versions for the same class name (should be singleton // the variant instance to replace any previous versions for the same class name (should be singleton
// anyway). // anyway).
$commonVariants = array_replace($commonVariants ?? [], $variantsForClass); $commonVariants = array_replace($commonVariants, $variantsForClass);
} }
// Cache for future calls // Cache for future calls
@ -325,7 +322,7 @@ abstract class SearchVariant
$merged = array_values(array_unique(array_merge($left, $right))); $merged = array_values(array_unique(array_merge($left, $right)));
// If there is only one item, return it as a single string // If there is only one item, return it as a single string
if (count($merged ?? []) === 1) { if (count($merged) === 1) {
return reset($merged); return reset($merged);
} }
return $merged; return $merged;

View File

@ -65,7 +65,7 @@ class SearchVariantVersioned extends SearchVariant
$class = $details['class']; $class = $details['class'];
$stage = Versioned::DRAFT; $stage = Versioned::DRAFT;
if (preg_match('/^(.*)_' . Versioned::LIVE . '$/', $table ?? '', $matches)) { if (preg_match('/^(.*)_' . Versioned::LIVE . '$/', $table, $matches)) {
$class = DataObject::getSchema()->tableClass($matches[1]); $class = DataObject::getSchema()->tableClass($matches[1]);
$stage = Versioned::LIVE; $stage = Versioned::LIVE;
} }

View File

@ -19,7 +19,7 @@ class SearchVariant_Caller
$values = array(); $values = array();
foreach ($this->variants as $variant) { foreach ($this->variants as $variant) {
if (method_exists($variant, $method ?? '')) { if (method_exists($variant, $method)) {
$value = $variant->$method(...$args); $value = $variant->$method(...$args);
if ($value !== null) { if ($value !== null) {
$values[] = $value; $values[] = $value;

View File

@ -81,9 +81,9 @@ abstract class SolrReindexBase implements SolrReindexHandler
// Apply filter // Apply filter
if (!is_array($filterClasses)) { if (!is_array($filterClasses)) {
$filterClasses = explode(',', $filterClasses ?? ''); $filterClasses = explode(',', $filterClasses);
} }
return array_intersect_key($classes ?? [], array_combine($filterClasses ?? [], $filterClasses ?? [])); return array_intersect_key($classes, array_combine($filterClasses, $filterClasses));
} }
/** /**

View File

@ -77,26 +77,27 @@ class SolrReindexImmediateHandler extends SolrReindexBase
$indexClass = get_class($indexInstance); $indexClass = get_class($indexInstance);
// Build script parameters // Build script parameters
$indexClassEscaped = $indexClass;
$statevar = json_encode($state); $statevar = json_encode($state);
if (strpos(PHP_OS, "WIN") !== false) {
$statevar = '"' . str_replace('"', '\\"', $statevar) . '"';
} else {
$statevar = "'" . $statevar . "'";
$class = addslashes($class);
$indexClassEscaped = addslashes($indexClass);
}
$php = Environment::getEnv('SS_PHP_BIN') ?: Config::inst()->get(static::class, 'php_bin'); $php = Environment::getEnv('SS_PHP_BIN') ?: Config::inst()->get(static::class, 'php_bin');
// Build script line // Build script line
$frameworkPath = ModuleLoader::getModule('silverstripe/framework')->getPath(); $frameworkPath = ModuleLoader::getModule('silverstripe/framework')->getPath();
$scriptPath = sprintf("%s%scli-script.php", $frameworkPath, DIRECTORY_SEPARATOR); $scriptPath = sprintf("%s%scli-script.php", $frameworkPath, DIRECTORY_SEPARATOR);
$scriptTask = "{$php} {$scriptPath} dev/tasks/{$taskName}";
$cmd = [ $cmd = "{$scriptTask} index={$indexClassEscaped} class={$class} group={$group} groups={$groups} variantstate={$statevar}";
$php, $cmd .= " verbose=1";
$scriptPath, $logger->info("Running '$cmd'");
"dev/tasks/{$taskName}",
"index={$indexClass}",
"class={$class}",
"group={$group}",
"groups={$groups}",
"variantstate={$statevar}",
"verbose=1"
];
$logger->info('Running ' . implode(' ', $cmd));
// Execute script via shell // Execute script via shell
$process = new Process($cmd); $process = new Process($cmd);
@ -109,7 +110,7 @@ class SolrReindexImmediateHandler extends SolrReindexBase
$res = $process->getOutput(); $res = $process->getOutput();
if ($logger) { if ($logger) {
$logger->info(preg_replace('/\r\n|\n/', '$0 ', $res ?? '')); $logger->info(preg_replace('/\r\n|\n/', '$0 ', $res));
} }
// If we're in dev mode, commit more often for fun and profit // If we're in dev mode, commit more often for fun and profit

View File

@ -24,7 +24,7 @@ class SolrService extends SolrService_Core
*/ */
protected function coreCommand($command, $core, $params = array()) protected function coreCommand($command, $core, $params = array())
{ {
$command = strtoupper($command ?? ''); $command = strtoupper($command);
$params = array_merge($params, array('action' => $command, 'wt' => 'json')); $params = array_merge($params, array('action' => $command, 'wt' => 'json'));
$params[$command === 'CREATE' ? 'name' : 'core'] = $core; $params[$command === 'CREATE' ? 'name' : 'core'] = $core;

View File

@ -94,7 +94,7 @@ class Solr
$module = ModuleLoader::getModule('silverstripe/fulltextsearch'); $module = ModuleLoader::getModule('silverstripe/fulltextsearch');
$modulePath = $module->getPath(); $modulePath = $module->getPath();
if (version_compare($version ?? '', '4', '>=')) { if (version_compare($version, '4', '>=')) {
$versionDefaults = [ $versionDefaults = [
'service' => Solr4Service::class, 'service' => Solr4Service::class,
'extraspath' => $modulePath . '/conf/solr/4/extras/', 'extraspath' => $modulePath . '/conf/solr/4/extras/',

View File

@ -89,7 +89,7 @@ abstract class SolrIndex extends SearchIndex
{ {
$globalOptions = Solr::solr_options(); $globalOptions = Solr::solr_options();
$path = $this->templatesPath ? $this->templatesPath : $globalOptions['templatespath']; $path = $this->templatesPath ? $this->templatesPath : $globalOptions['templatespath'];
return rtrim($path ?? '', '/'); return rtrim($path, '/');
} }
/** /**
@ -127,7 +127,7 @@ abstract class SolrIndex extends SearchIndex
$indexParts[] = $indexSuffix; $indexParts[] = $indexSuffix;
} }
return implode($indexParts ?? ''); return implode($indexParts);
} }
public function getTypes() public function getTypes()
@ -256,11 +256,11 @@ abstract class SolrIndex extends SearchIndex
*/ */
protected function getNiceSuggestion($collation = '') protected function getNiceSuggestion($collation = '')
{ {
$collationParts = explode(' ', $collation ?? ''); $collationParts = explode(' ', $collation);
// Remove advanced query params from the beginning of each collation part. // Remove advanced query params from the beginning of each collation part.
foreach ($collationParts as $key => &$part) { foreach ($collationParts as $key => &$part) {
$part = ltrim($part ?? '', '+'); $part = ltrim($part, '+');
} }
return implode(' ', $collationParts); return implode(' ', $collationParts);
@ -275,7 +275,7 @@ abstract class SolrIndex extends SearchIndex
*/ */
protected function getSuggestionQueryString($collation = '') protected function getSuggestionQueryString($collation = '')
{ {
return str_replace(' ', '+', $this->getNiceSuggestion($collation) ?? ''); return str_replace(' ', '+', $this->getNiceSuggestion($collation));
} }
/** /**
@ -312,7 +312,7 @@ abstract class SolrIndex extends SearchIndex
{ {
// Ensure that 'boost' is recorded here without being captured by solr // Ensure that 'boost' is recorded here without being captured by solr
$boost = null; $boost = null;
if (array_key_exists('boost', $extraOptions ?? [])) { if (array_key_exists('boost', $extraOptions)) {
$boost = $extraOptions['boost']; $boost = $extraOptions['boost'];
unset($extraOptions['boost']); unset($extraOptions['boost']);
} }
@ -515,7 +515,7 @@ abstract class SolrIndex extends SearchIndex
} }
// Check single origin // Check single origin
return $class === $base || is_subclass_of($class, $base ?? ''); return $class === $base || is_subclass_of($class, $base);
} }
protected function _addField($doc, $object, $field) protected function _addField($doc, $object, $field)
@ -536,7 +536,7 @@ abstract class SolrIndex extends SearchIndex
if (!$sub) { if (!$sub) {
continue; continue;
} }
$sub = gmdate('Y-m-d\TH:i:s\Z', strtotime($sub ?? '')); $sub = gmdate('Y-m-d\TH:i:s\Z', strtotime($sub));
} }
/* Solr requires numbers to be valid if presented, not just empty */ /* Solr requires numbers to be valid if presented, not just empty */
@ -552,7 +552,7 @@ abstract class SolrIndex extends SearchIndex
if (!$value) { if (!$value) {
return; return;
} }
$value = gmdate('Y-m-d\TH:i:s\Z', strtotime($value ?? '')); $value = gmdate('Y-m-d\TH:i:s\Z', strtotime($value));
} }
/* Solr requires numbers to be valid if presented, not just empty */ /* Solr requires numbers to be valid if presented, not just empty */
@ -586,7 +586,7 @@ abstract class SolrIndex extends SearchIndex
// Add the user-specified fields // Add the user-specified fields
foreach ($this->getFieldsIterator() as $name => $field) { foreach ($this->getFieldsIterator() as $name => $field) {
if ($field['base'] === $base || (is_array($field['base']) && in_array($base, $field['base'] ?? []))) { if ($field['base'] === $base || (is_array($field['base']) && in_array($base, $field['base']))) {
$this->_addField($doc, $object, $field); $this->_addField($doc, $object, $field);
} }
} }
@ -607,7 +607,7 @@ abstract class SolrIndex extends SearchIndex
$docs = array(); $docs = array();
foreach ($this->getClasses() as $searchclass => $options) { foreach ($this->getClasses() as $searchclass => $options) {
if ($searchclass == $class || ($options['include_children'] && is_subclass_of($class, $searchclass ?? ''))) { if ($searchclass == $class || ($options['include_children'] && is_subclass_of($class, $searchclass))) {
$base = DataObject::getSchema()->baseDataClass($searchclass); $base = DataObject::getSchema()->baseDataClass($searchclass);
$docs[] = $this->_addAs($object, $base, $options); $docs[] = $this->_addAs($object, $base, $options);
} }
@ -619,7 +619,7 @@ abstract class SolrIndex extends SearchIndex
public function canAdd($class) public function canAdd($class)
{ {
foreach ($this->classes as $searchclass => $options) { foreach ($this->classes as $searchclass => $options) {
if ($searchclass == $class || ($options['include_children'] && is_subclass_of($class, $searchclass ?? ''))) { if ($searchclass == $class || ($options['include_children'] && is_subclass_of($class, $searchclass))) {
return true; return true;
} }
} }
@ -713,7 +713,7 @@ abstract class SolrIndex extends SearchIndex
// If using boosting, set the clean term separately for highlighting. // If using boosting, set the clean term separately for highlighting.
// See https://issues.apache.org/jira/browse/SOLR-2632 // See https://issues.apache.org/jira/browse/SOLR-2632
if (array_key_exists('hl', $params ?? []) && !array_key_exists('hl.q', $params ?? [])) { if (array_key_exists('hl', $params) && !array_key_exists('hl.q', $params)) {
$params['hl.q'] = implode(' ', $hlq); $params['hl.q'] = implode(' ', $hlq);
} }
@ -870,7 +870,7 @@ abstract class SolrIndex extends SearchIndex
*/ */
protected function applySearchVariants(SearchQuery $query) protected function applySearchVariants(SearchQuery $query)
{ {
$classes = count($query->classes ?? []) ? $query->classes : $this->getClasses(); $classes = count($query->classes) ? $query->classes : $this->getClasses();
/** @var SearchVariant_Caller $variantCaller */ /** @var SearchVariant_Caller $variantCaller */
$variantCaller = SearchVariant::withCommon($classes); $variantCaller = SearchVariant::withCommon($classes);
@ -886,7 +886,7 @@ abstract class SolrIndex extends SearchIndex
*/ */
public function sanitiseClassName($className, $replaceWith = '\\\\') public function sanitiseClassName($className, $replaceWith = '\\\\')
{ {
return str_replace('\\', $replaceWith ?? '', $className ?? ''); return str_replace('\\', $replaceWith, $className);
} }
/** /**
@ -901,14 +901,14 @@ abstract class SolrIndex extends SearchIndex
$q = array(); $q = array();
foreach ($searchQuery->search as $search) { foreach ($searchQuery->search as $search) {
$text = $search['text']; $text = $search['text'];
preg_match_all('/"[^"]*"|\S+/', $text ?? '', $parts); preg_match_all('/"[^"]*"|\S+/', $text, $parts);
$fuzzy = $search['fuzzy'] ? '~' : ''; $fuzzy = $search['fuzzy'] ? '~' : '';
foreach ($parts[0] as $part) { foreach ($parts[0] as $part) {
$fields = (isset($search['fields'])) ? $search['fields'] : array(); $fields = (isset($search['fields'])) ? $search['fields'] : array();
if (isset($search['boost'])) { if (isset($search['boost'])) {
$fields = array_merge($fields, array_keys($search['boost'] ?? [])); $fields = array_merge($fields, array_keys($search['boost']));
} }
if ($fields) { if ($fields) {
$searchq = array(); $searchq = array();
@ -1014,7 +1014,7 @@ abstract class SolrIndex extends SearchIndex
*/ */
protected function getCriteriaComponent(SearchQuery $searchQuery) protected function getCriteriaComponent(SearchQuery $searchQuery)
{ {
if (count($searchQuery->getCriteria() ?? []) === 0) { if (count($searchQuery->getCriteria()) === 0) {
return null; return null;
} }
@ -1095,7 +1095,7 @@ abstract class SolrIndex extends SearchIndex
// Upload additional files // Upload additional files
foreach (glob($this->getExtrasPath() . '/*') as $file) { foreach (glob($this->getExtrasPath() . '/*') as $file) {
if (is_file($file ?? '')) { if (is_file($file)) {
$store->uploadFile($this->getIndexName(), $file); $store->uploadFile($this->getIndexName(), $file);
} }
} }

View File

@ -20,8 +20,8 @@ class SolrConfigStore_File implements SolrConfigStore
{ {
$targetDir = "{$this->local}/{$index}/conf"; $targetDir = "{$this->local}/{$index}/conf";
if (!is_dir($targetDir ?? '')) { if (!is_dir($targetDir)) {
$worked = @mkdir($targetDir ?? '', 0770, true); $worked = @mkdir($targetDir, 0770, true);
if (!$worked) { if (!$worked) {
throw new \RuntimeException( throw new \RuntimeException(
@ -36,7 +36,7 @@ class SolrConfigStore_File implements SolrConfigStore
public function uploadFile($index, $file) public function uploadFile($index, $file)
{ {
$targetDir = $this->getTargetDir($index); $targetDir = $this->getTargetDir($index);
copy($file ?? '', $targetDir . '/' . basename($file ?? '')); copy($file, $targetDir . '/' . basename($file));
} }
public function uploadString($index, $filename, $string) public function uploadString($index, $filename, $string)

View File

@ -43,7 +43,7 @@ class SolrConfigStore_Post implements SolrConfigStore
*/ */
public function uploadFile($index, $file) public function uploadFile($index, $file)
{ {
$this->uploadString($index, basename($file ?? ''), file_get_contents($file ?? '')); $this->uploadString($index, basename($file), file_get_contents($file));
} }
/** /**

View File

@ -46,7 +46,7 @@ class SolrConfigStore_WebDAV implements SolrConfigStore
public function uploadFile($index, $file) public function uploadFile($index, $file)
{ {
$targetDir = $this->getTargetDir($index); $targetDir = $this->getTargetDir($index);
WebDAV::upload_from_file($file, $targetDir . '/' . basename($file ?? '')); WebDAV::upload_from_file($file, $targetDir . '/' . basename($file));
} }
public function uploadString($index, $filename, $string) public function uploadString($index, $filename, $string)

View File

@ -86,7 +86,7 @@ class Solr_Reindex extends Solr_BuildTask
continue; continue;
} }
//check the indexname matches the index passed to the request //check the indexname matches the index passed to the request
if (!strcasecmp(singleton($solrIndexClass)->getIndexName() ?? '', $index ?? '')) { if (!strcasecmp(singleton($solrIndexClass)->getIndexName(), $index)) {
//if we match, set the correct index name and move on //if we match, set the correct index name and move on
$index = $solrIndexClass; $index = $solrIndexClass;
break; break;
@ -104,7 +104,7 @@ class Solr_Reindex extends Solr_BuildTask
// Run grouped batches (id % groups = group) // Run grouped batches (id % groups = group)
$group = $request->getVar('group'); $group = $request->getVar('group');
$indexInstance = singleton($index); $indexInstance = singleton($index);
$state = json_decode($request->getVar('variantstate') ?? '', true); $state = json_decode($request->getVar('variantstate'), true);
$handler->runGroup($this->getLogger(), $indexInstance, $state, $class, $groups, $group); $handler->runGroup($this->getLogger(), $indexInstance, $state, $class, $groups, $group);
return; return;

View File

@ -20,7 +20,7 @@ class SolrSearchQueryWriterBasic extends AbstractSearchQueryWriter
return sprintf( return sprintf(
'%s(%s%s%s)', '%s(%s%s%s)',
$this->getComparisonPolarity($searchCriterion->getComparison()), $this->getComparisonPolarity($searchCriterion->getComparison()),
addslashes($searchCriterion->getTarget() ?? ''), addslashes($searchCriterion->getTarget()),
$this->getComparisonConjunction(), $this->getComparisonConjunction(),
$searchCriterion->getQuoteValue($searchCriterion->getValue()) $searchCriterion->getQuoteValue($searchCriterion->getValue())
); );

View File

@ -62,7 +62,7 @@ class SolrSearchQueryWriterIn extends AbstractSearchQueryWriter
$conditions[] = sprintf( $conditions[] = sprintf(
'%s%s%s', '%s%s%s',
addslashes($searchCriterion->getTarget() ?? ''), addslashes($searchCriterion->getTarget()),
$this->getComparisonConjunction(), $this->getComparisonConjunction(),
$value $value
); );

View File

@ -21,7 +21,7 @@ class SolrSearchQueryWriterRange extends AbstractSearchQueryWriter
return sprintf( return sprintf(
'%s(%s:%s%s%s%s%s)', '%s(%s:%s%s%s%s%s)',
$this->getComparisonPolarity($searchCriterion->getComparison()), $this->getComparisonPolarity($searchCriterion->getComparison()),
addslashes($searchCriterion->getTarget() ?? ''), addslashes($searchCriterion->getTarget()),
$this->getOpenComparisonContainer($searchCriterion->getComparison()), $this->getOpenComparisonContainer($searchCriterion->getComparison()),
$this->getLeftComparison($searchCriterion), $this->getLeftComparison($searchCriterion),
$this->getComparisonConjunction(), $this->getComparisonConjunction(),

View File

@ -18,21 +18,20 @@ class CombinationsArrayIterator implements Iterator
$this->arrays = array(); $this->arrays = array();
$this->keys = array(); $this->keys = array();
$keys = array_keys($args ?? []); $keys = array_keys($args);
$values = array_values($args ?? []); $values = array_values($args);
foreach ($values as $i => $arg) { foreach ($values as $i => $arg) {
if (is_array($arg) && count($arg ?? [])) { if (is_array($arg) && count($arg)) {
$this->arrays[] = $arg; $this->arrays[] = $arg;
$this->keys[] = $keys[$i]; $this->keys[] = $keys[$i];
} }
} }
$this->numArrays = count($this->arrays ?? []); $this->numArrays = count($this->arrays);
$this->rewind(); $this->rewind();
} }
#[\ReturnTypeWillChange]
public function rewind() public function rewind()
{ {
if (!$this->numArrays) { if (!$this->numArrays) {
@ -47,13 +46,11 @@ class CombinationsArrayIterator implements Iterator
} }
} }
#[\ReturnTypeWillChange]
public function valid() public function valid()
{ {
return $this->isValid; return $this->isValid;
} }
#[\ReturnTypeWillChange]
public function next() public function next()
{ {
$this->k++; $this->k++;
@ -71,17 +68,15 @@ class CombinationsArrayIterator implements Iterator
} }
} }
#[\ReturnTypeWillChange]
public function current() public function current()
{ {
$res = array(); $res = array();
for ($i = 0; $i < $this->numArrays; $i++) { for ($i = 0; $i < $this->numArrays; $i++) {
$res[$this->keys[$i]] = current($this->arrays[$i] ?? []); $res[$this->keys[$i]] = current($this->arrays[$i]);
} }
return $res; return $res;
} }
#[\ReturnTypeWillChange]
public function key() public function key()
{ {
return $this->k; return $this->k;

View File

@ -90,7 +90,7 @@ class MonologFactory implements SearchLogFactory
{ {
return Injector::inst()->createWithArgs( return Injector::inst()->createWithArgs(
Logger::class, Logger::class,
array(strtolower($name ?? '')) array(strtolower($name))
); );
} }

View File

@ -14,7 +14,7 @@ class MultipleArrayIterator implements Iterator
$this->arrays = array(); $this->arrays = array();
foreach ($args as $arg) { foreach ($args as $arg) {
if (is_array($arg) && count($arg ?? [])) { if (is_array($arg) && count($arg)) {
$this->arrays[] = $arg; $this->arrays[] = $arg;
} }
} }
@ -22,7 +22,6 @@ class MultipleArrayIterator implements Iterator
$this->rewind(); $this->rewind();
} }
#[\ReturnTypeWillChange]
public function rewind() public function rewind()
{ {
$this->active = $this->arrays; $this->active = $this->arrays;
@ -31,19 +30,16 @@ class MultipleArrayIterator implements Iterator
} }
} }
#[\ReturnTypeWillChange]
public function current() public function current()
{ {
return $this->active ? current($this->active[0]) : false; return $this->active ? current($this->active[0]) : false;
} }
#[\ReturnTypeWillChange]
public function key() public function key()
{ {
return $this->active ? key($this->active[0]) : false; return $this->active ? key($this->active[0]) : false;
} }
#[\ReturnTypeWillChange]
public function next() public function next()
{ {
if (!$this->active) { if (!$this->active) {
@ -58,9 +54,8 @@ class MultipleArrayIterator implements Iterator
} }
} }
#[\ReturnTypeWillChange]
public function valid() public function valid()
{ {
return $this->active && (current($this->active[0] ?? []) !== false); return $this->active && (current($this->active[0]) !== false);
} }
} }

View File

@ -17,19 +17,15 @@ class WebDAV
public static function exists($url) public static function exists($url)
{ {
// WebDAV expects that checking a directory exists has a trailing slash // WebDAV expects that checking a directory exists has a trailing slash
if (substr($url ?? '', -1) != '/') { if (substr($url, -1) != '/') {
$url .= '/'; $url .= '/';
} }
$ch = self::curl_init($url, 'PROPFIND'); $ch = self::curl_init($url, 'PROPFIND');
curl_exec($ch); $res = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$err = curl_error($ch);
curl_close($ch);
if ($code == 404) { if ($code == 404) {
return false; return false;
} }
@ -37,16 +33,15 @@ class WebDAV
return true; return true;
} }
user_error("Got error from webdav server - " . $err, E_USER_ERROR); user_error("Got error from webdav server - " . $code, E_USER_ERROR);
} }
public static function mkdir($url) public static function mkdir($url)
{ {
$ch = self::curl_init(rtrim($url ?? '', '/') . '/', 'MKCOL'); $ch = self::curl_init(rtrim($url, '/') . '/', 'MKCOL');
curl_exec($ch); $res = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $code == 201; return $code == 201;
} }
@ -61,24 +56,22 @@ class WebDAV
curl_setopt($ch, CURLOPT_INFILE, $handle); curl_setopt($ch, CURLOPT_INFILE, $handle);
curl_exec($ch); $res = curl_exec($ch);
fclose($handle); fclose($handle);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $code; return curl_getinfo($ch, CURLINFO_HTTP_CODE);
} }
public static function upload_from_string($string, $url) public static function upload_from_string($string, $url)
{ {
$fh = tmpfile(); $fh = tmpfile();
fwrite($fh, $string ?? ''); fwrite($fh, $string);
fseek($fh, 0); fseek($fh, 0);
return self::put($fh, $url); return self::put($fh, $url);
} }
public static function upload_from_file($string, $url) public static function upload_from_file($string, $url)
{ {
return self::put(fopen($string ?? '', 'rb'), $url); return self::put(fopen($string, 'rb'), $url);
} }
} }

View File

@ -106,7 +106,7 @@ class BatchedProcessorTest extends SapphireTest
$processor->addDirtyIDs( $processor->addDirtyIDs(
BatchedProcessorTest_Object::class, BatchedProcessorTest_Object::class,
array(array( array(array(
'id' => $object->ID, 'id' => $id,
'state' => array(SearchVariantVersioned::class => 'Stage') 'state' => array(SearchVariantVersioned::class => 'Stage')
)), )),
BatchedProcessorTest_Index::class BatchedProcessorTest_Index::class
@ -133,28 +133,28 @@ class BatchedProcessorTest extends SapphireTest
$this->assertEquals(9, $data->totalSteps); $this->assertEquals(9, $data->totalSteps);
$this->assertEquals(0, $data->currentStep); $this->assertEquals(0, $data->currentStep);
$this->assertEmpty($data->isComplete); $this->assertEmpty($data->isComplete);
$this->assertEquals(0, count($index->getAdded() ?? [])); $this->assertEquals(0, count($index->getAdded()));
// Advance state // Advance state
for ($pass = 1; $pass <= 8; $pass++) { for ($pass = 1; $pass <= 8; $pass++) {
$processor->process(); $processor->process();
$data = $processor->getJobData(); $data = $processor->getJobData();
$this->assertEquals($pass, $data->currentStep); $this->assertEquals($pass, $data->currentStep);
$this->assertEquals($pass * 5, count($index->getAdded() ?? [])); $this->assertEquals($pass * 5, count($index->getAdded()));
} }
// Last run should have two hanging items // Last run should have two hanging items
$processor->process(); $processor->process();
$data = $processor->getJobData(); $data = $processor->getJobData();
$this->assertEquals(9, $data->currentStep); $this->assertEquals(9, $data->currentStep);
$this->assertEquals(42, count($index->getAdded() ?? [])); $this->assertEquals(42, count($index->getAdded()));
$this->assertTrue($data->isComplete); $this->assertTrue($data->isComplete);
// Check any additional queued jobs // Check any additional queued jobs
$processor->afterComplete(); $processor->afterComplete();
$service = singleton(QueuedJobService::class); $service = singleton(QueuedJobService::class);
$jobs = $service->getJobs(); $jobs = $service->getJobs();
$this->assertEquals(1, count($jobs ?? [])); $this->assertEquals(1, count($jobs));
$this->assertInstanceOf(SearchUpdateCommitJobProcessor::class, $jobs[0]['job']); $this->assertInstanceOf(SearchUpdateCommitJobProcessor::class, $jobs[0]['job']);
} }
@ -242,7 +242,7 @@ class BatchedProcessorTest extends SapphireTest
} }
$data = $processor->getJobData(); $data = $processor->getJobData();
$this->assertEquals(8, $data->currentStep); $this->assertEquals(8, $data->currentStep);
$this->assertEquals(42, count($index->getAdded() ?? [])); $this->assertEquals(42, count($index->getAdded()));
$this->assertTrue($data->isComplete); $this->assertTrue($data->isComplete);
} }
} }

View File

@ -31,7 +31,7 @@ class SearchVariantSubsiteTest extends SapphireTest
self::$index = singleton(static::class); self::$index = singleton(static::class);
} }
Config::inst()->merge(Injector::class, SearchUpdateProcessor::class, [ Config::inst()->update(Injector::class, SearchUpdateProcessor::class, [
'class' => SearchUpdateImmediateProcessor::class 'class' => SearchUpdateImmediateProcessor::class
]); ]);

View File

@ -223,7 +223,7 @@ class SolrIndexSubsitesTest extends SapphireTest
$subsiteIDs = ['0'] + $this->allFixtureIDs(Subsite::class); $subsiteIDs = ['0'] + $this->allFixtureIDs(Subsite::class);
$subsiteIDs = array_map(function ($v) { $subsiteIDs = array_map(function ($v) {
return (string) $v; return (string) $v;
}, $subsiteIDs ?? []); }, $subsiteIDs);
$mockWrites = [ $mockWrites = [
'35910:File:a:0:{}' => [ '35910:File:a:0:{}' => [
'base' => File::class, 'base' => File::class,
@ -253,7 +253,7 @@ class SolrIndexSubsitesTest extends SapphireTest
$tmpMockWrites = $mockWrites; $tmpMockWrites = $mockWrites;
$variant->extractManipulationWriteState($tmpMockWrites); $variant->extractManipulationWriteState($tmpMockWrites);
foreach ($tmpMockWrites as $mockWrite) { foreach ($tmpMockWrites as $mockWrite) {
$this->assertCount(count($subsiteIDs ?? []), $mockWrite['statefulids']); $this->assertCount(count($subsiteIDs), $mockWrite['statefulids']);
foreach ($mockWrite['statefulids'] as $statefulIDs) { foreach ($mockWrite['statefulids'] as $statefulIDs) {
$this->assertContains( $this->assertContains(
(string) $statefulIDs['state'][SearchVariantSubsites::class], (string) $statefulIDs['state'][SearchVariantSubsites::class],

View File

@ -478,7 +478,7 @@ class SolrIndexTest extends SapphireTest
SolrIndexTest_MyDataObjectOne::class . $objOneA->ID, SolrIndexTest_MyDataObjectOne::class . $objOneA->ID,
SolrIndexTest_MyDataObjectTwo::class . $objTwoA->ID SolrIndexTest_MyDataObjectTwo::class . $objTwoA->ID
]; ];
return in_array($this->createSolrDocKey($doc), $validKeys ?? []); return in_array($this->createSolrDocKey($doc), $validKeys);
}; };
$serviceMock $serviceMock
@ -504,7 +504,7 @@ class SolrIndexTest extends SapphireTest
->method('deleteById') ->method('deleteById')
->withConsecutive( ->withConsecutive(
[$this->callback(function (string $docID) use ($pageA): bool { [$this->callback(function (string $docID) use ($pageA): bool {
return strpos($docID ?? '', $pageA->ID . '-' . SiteTree::class) !== false; return strpos($docID, $pageA->ID . '-' . SiteTree::class) !== false;
})] })]
); );
@ -578,7 +578,7 @@ class SolrIndexTest extends SapphireTest
File::class . $fileA->ID, File::class . $fileA->ID,
SolrIndexTest_MyDataObjectOne::class . $objOneA->ID SolrIndexTest_MyDataObjectOne::class . $objOneA->ID
]; ];
return in_array($this->createSolrDocKey($doc), $validKeys ?? []); return in_array($this->createSolrDocKey($doc), $validKeys);
}; };
$serviceMock $serviceMock
@ -602,7 +602,7 @@ class SolrIndexTest extends SapphireTest
->method('deleteById') ->method('deleteById')
->withConsecutive( ->withConsecutive(
[$this->callback(function (string $docID) use ($pageA): bool { [$this->callback(function (string $docID) use ($pageA): bool {
return strpos($docID ?? '', $pageA->ID . '-' . SiteTree::class) !== false; return strpos($docID, $pageA->ID . '-' . SiteTree::class) !== false;
})] })]
); );

View File

@ -233,9 +233,9 @@ class SolrReindexQueuedTest extends SapphireTest
// Check IDs // Check IDs
$idMessage = $logger->filterMessages('Updated '); $idMessage = $logger->filterMessages('Updated ');
$this->assertNotEmpty(preg_match('/^Updated (?<ids>[,\d]+)/i', $idMessage[0] ?? '', $matches)); $this->assertNotEmpty(preg_match('/^Updated (?<ids>[,\d]+)/i', $idMessage[0], $matches));
$ids = array_unique(explode(',', $matches['ids'] ?? '')); $ids = array_unique(explode(',', $matches['ids']));
$this->assertEquals(6, count($ids ?? [])); $this->assertEquals(6, count($ids));
foreach ($ids as $id) { foreach ($ids as $id) {
// Each id should be % 3 == 0 // Each id should be % 3 == 0
$this->assertEquals(0, $id % 3, "ID $id Should match pattern ID % 3 = 0"); $this->assertEquals(0, $id % 3, "ID $id Should match pattern ID % 3 = 0");

View File

@ -250,8 +250,8 @@ class SolrReindexTest extends SapphireTest
$state = array(SolrReindexTest_Variant::class => '1'); $state = array(SolrReindexTest_Variant::class => '1');
$this->getHandler()->runGroup($logger, $this->index, $state, SolrReindexTest_Item::class, 6, 2); $this->getHandler()->runGroup($logger, $this->index, $state, SolrReindexTest_Item::class, 6, 2);
$idMessage = $logger->filterMessages('Updated '); $idMessage = $logger->filterMessages('Updated ');
$this->assertNotEmpty(preg_match('/^Updated (?<ids>[,\d]+)/i', $idMessage[0] ?? '', $matches)); $this->assertNotEmpty(preg_match('/^Updated (?<ids>[,\d]+)/i', $idMessage[0], $matches));
$ids = array_unique(explode(',', $matches['ids'] ?? '')); $ids = array_unique(explode(',', $matches['ids']));
// Test successful // Test successful
$this->assertNotEmpty($logger->getMessages('Adding ' . SolrReindexTest_Item::class)); $this->assertNotEmpty($logger->getMessages('Adding ' . SolrReindexTest_Item::class));
@ -259,7 +259,7 @@ class SolrReindexTest extends SapphireTest
// Test that items in this variant / group are re-indexed // Test that items in this variant / group are re-indexed
// 120 divided into 6 groups should be 20 at least (max 21) // 120 divided into 6 groups should be 20 at least (max 21)
$c = count($ids ?? []); $c = count($ids);
$this->assertTrue($c === 20 || $c === 21, 'Group size is about 20'); $this->assertTrue($c === 20 || $c === 21, 'Group size is about 20');
foreach ($ids as $id) { foreach ($ids as $id) {
// Each id should be % 6 == 2 // Each id should be % 6 == 2
@ -301,12 +301,12 @@ class SolrReindexTest extends SapphireTest
// Count all ids updated // Count all ids updated
$ids = array(); $ids = array();
foreach ($logger->filterMessages('Updated ') as $message) { foreach ($logger->filterMessages('Updated ') as $message) {
$this->assertNotEmpty(preg_match('/^Updated (?<ids>[,\d]+)/', $message ?? '', $matches)); $this->assertNotEmpty(preg_match('/^Updated (?<ids>[,\d]+)/', $message, $matches));
$ids = array_unique(array_merge($ids, explode(',', $matches['ids'] ?? ''))); $ids = array_unique(array_merge($ids, explode(',', $matches['ids'])));
} }
// Check ids // Check ids
$this->assertEquals(120, count($ids ?? [])); $this->assertEquals(120, count($ids));
} }
/** /**
@ -385,7 +385,7 @@ class SolrReindexTest extends SapphireTest
SolrIndexTest_MyDataObjectOne::class . $objOneA->ID, SolrIndexTest_MyDataObjectOne::class . $objOneA->ID,
SolrIndexTest_MyDataObjectTwo::class . $objTwoA->ID SolrIndexTest_MyDataObjectTwo::class . $objTwoA->ID
]; ];
return in_array($this->createSolrDocKey($doc), $validKeys ?? []); return in_array($this->createSolrDocKey($doc), $validKeys);
}; };
$serviceMock $serviceMock
@ -470,7 +470,7 @@ class SolrReindexTest extends SapphireTest
SolrIndexTest_MyDataObjectOne::class . $objOneA->ID, SolrIndexTest_MyDataObjectOne::class . $objOneA->ID,
]; ];
$solrDocKey = $this->createSolrDocKey($doc); $solrDocKey = $this->createSolrDocKey($doc);
return in_array($this->createSolrDocKey($doc), $validKeys ?? []); return in_array($this->createSolrDocKey($doc), $validKeys);
}; };
$serviceMock $serviceMock

View File

@ -49,9 +49,9 @@ class SolrReindexTest_RecordingLogger extends Logger implements TestOnly
public function filterMessages($containing) public function filterMessages($containing)
{ {
return array_values(array_filter( return array_values(array_filter(
$this->getMessages() ?? [], $this->getMessages(),
function ($content) use ($containing) { function ($content) use ($containing) {
return stripos($content ?? '', $containing ?? '') !== false; return stripos($content, $containing) !== false;
} }
)); ));
} }
@ -69,6 +69,6 @@ class SolrReindexTest_RecordingLogger extends Logger implements TestOnly
} else { } else {
$messages = $this->getMessages(); $messages = $this->getMessages();
} }
return count($messages ?? []); return count($messages);
} }
} }

View File

@ -185,7 +185,7 @@ class SolrWritersTest extends SapphireTest
$index = new SolrIndexTest_FakeIndex(); $index = new SolrIndexTest_FakeIndex();
$this->assertTrue(in_array($expected, $index->getFiltersComponent($query) ?? [])); $this->assertTrue(in_array($expected, $index->getFiltersComponent($query)));
} }
/** /**
@ -235,6 +235,6 @@ class SolrWritersTest extends SapphireTest
$index = new SolrIndexTest_FakeIndex(); $index = new SolrIndexTest_FakeIndex();
$this->assertTrue(in_array($expected, $index->getFiltersComponent($query) ?? [])); $this->assertTrue(in_array($expected, $index->getFiltersComponent($query)));
} }
} }