Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Similarity #35

Merged
merged 6 commits into from
Sep 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,6 @@ script:

- 'if [[ $PHPCS_TEST ]]; then vendor/bin/phpcs --standard=ruleset.xml --extensions=php --tab-width=4 -sp src tests ; fi'
- 'if [[ $LINT_CHECK ]]; then vendor/bin/parallel-lint src/ tests/ ; fi'
- 'if [[ $PHPSTAN_TEST ]]; then vendor/bin/phpstan analyse --level=6 -c tests/phpstan.neon src/ ; fi'
- 'if [[ $PHPSTAN_TEST ]]; then vendor/bin/phpstan analyse --level=8 -c tests/phpstan.neon src/ ; fi'
after_script:
- 'if [[ $PHPUNIT_COVERAGE_TEST ]]; then bash <(curl -s https://codecov.io/bash) -f coverage.xml; fi'
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"checkcs": "vendor/bin/phpcs --standard=ruleset.xml --extensions=php --tab-width=4 -sp src tests",
"fixcs": "vendor/bin/phpcbf --standard=ruleset.xml --extensions=php --tab-width=4 -sp src tests",
"lint": "vendor/bin/parallel-lint src/ tests/",
"phpstan": "vendor/bin/phpstan analyse --memory-limit=2G --level=6 -c tests/phpstan.neon src/",
"phpstan": "vendor/bin/phpstan analyse --memory-limit=2G --level=8 -c tests/phpstan.neon src/",
"test": "vendor/bin/phpunit tests"
}
}
76 changes: 0 additions & 76 deletions src/Base/IndexCreator.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

namespace Suilven\FreeTextSearch\Base;

use SilverStripe\ORM\DataObjectSchema;
use Suilven\FreeTextSearch\Indexes;

abstract class IndexCreator implements \Suilven\FreeTextSearch\Interfaces\IndexCreator
Expand All @@ -22,53 +21,6 @@ abstract class IndexCreator implements \Suilven\FreeTextSearch\Interfaces\IndexC
abstract public function createIndex(string $indexName): void;


/**
* Helper method to get get field specs for a DataObject relevant to it's index definition
*
* @param string $indexName the name of the index
* @return array<string,string>
*/
protected function getFieldSpecs(string $indexName): array
{
$indexes = new Indexes();
$index = $indexes->getIndex($indexName);
$singleton = \singleton($index->getClass());

$fields = $this->getFields($indexName);

/** @var \SilverStripe\ORM\DataObjectSchema $schema */
$schema = $singleton->getSchema();
$specs = $schema->fieldSpecs($index->getClass(), DataObjectSchema::INCLUDE_CLASS);

/** @var array<string,string> $filteredSpecs the DB specs for fields related to the index */
$filteredSpecs = [];

foreach ($fields as $field) {
if ($field === 'Link') {
continue;
}
$fieldType = $specs[$field];

// fix likes of varchar(255)
$fieldType = \explode('(', $fieldType)[0];

// remove the class name
$fieldType = \explode('.', $fieldType)[1];

$filteredSpecs[$field] = $fieldType;
}

// if Link undefined in the original index specs, add it if the method exists on the singleton dataobject
if (!isset($filteredSpecs['Link'])) {
if (\method_exists($singleton, 'Link')) {
$filteredSpecs['Link'] = 'Varchar';
}
}

return $filteredSpecs;
}


/** @return array<string> */
protected function getStoredFields(string $indexName): array
{
Expand All @@ -77,32 +29,4 @@ protected function getStoredFields(string $indexName): array

return $index->getStoredFields();
}


/** @return array<string> */
protected function getFields(string $indexName): array
{
$indexes = new Indexes();
$index = $indexes->getIndex($indexName);

$fields = [];

foreach ($index->getFields() as $field) {
$fields[] = $field;
}

foreach ($index->getTokens() as $token) {
$fields[] = $token;
}

foreach ($index->getStoredFields() as $storedField) {
$fields[] = $storedField;
}

if (!\in_array('Link', $fields, true)) {
$fields[] = 'Link';
}

return $fields;
}
}
12 changes: 10 additions & 2 deletions src/Base/Indexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ public function setIndexName(string $newIndexName): void
}


/** @return array<string, array<string,string|int|float|bool>> */
/**
* index name -> field name -> list of values
*
* @return array<string, array<string, array|bool|float|int|string>>
*/
public function getIndexablePayload(\SilverStripe\ORM\DataObject $dataObject): array
{
$helper = new IndexingHelper();
Expand All @@ -44,11 +48,15 @@ public function getIndexablePayload(\SilverStripe\ORM\DataObject $dataObject): a
// populate MVA columns
$mvaColumns = $index->getHasManyFields();


/** @var string $mvaColumnName */
foreach (\array_keys($mvaColumns) as $mvaColumnName) {
$relationship = $mvaColumns[$mvaColumnName]['relationship'];

/** @phpstan-ignore-next-line */
// @phpstan-ignore-next-line
$relationshipDOs = $dataObject->$relationship();

/** @var array $values */
$values = [];
foreach ($relationshipDOs as $mvaDO) {
$values[] = $mvaDO->ID;
Expand Down
4 changes: 2 additions & 2 deletions src/Base/Searcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

abstract class Searcher implements \Suilven\FreeTextSearch\Interfaces\Searcher
{
/** @var array<string,string|int|float> $filters */
/** @var array<string,string|int|float|bool> $filters */
protected $filters;

/** @var int */
Expand All @@ -35,7 +35,7 @@ abstract class Searcher implements \Suilven\FreeTextSearch\Interfaces\Searcher
abstract public function search(?string $q): SearchResults;


/** @param array<string,string|int|float> $filters */
/** @param array<string,string|int|float|bool> $filters */
public function setFilters(array $filters): void
{
$this->filters = $filters;
Expand Down
5 changes: 5 additions & 0 deletions src/Extension/IndexingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public function onBeforeWrite(): void
return;
}

// @phpstan-ignore-next-line
$this->getOwner()->IsDirtyFreeTextSearch = true;
}

Expand All @@ -61,6 +62,8 @@ public function onAfterWrite(): void

// a dataobject could belong to multiple indexes. Update them all
$helper = new IndexingHelper();

// @phpstan-ignore-next-line
$indexNames = $helper->getIndexes($this->getOwner());

// @phpstan-ignore-next-line
Expand All @@ -80,6 +83,8 @@ public function onAfterWrite(): void
$indexer = $factory->getIndexer();
foreach ($indexNames as $indexName) {
$indexer->setIndexName($indexName);

// @phpstan-ignore-next-line
$indexer->index($this->getOwner());
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/Helper/BulkIndexingHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ public function bulkIndex(string $indexName, bool $dirty = false, ?CLImate $clim
$climate->blue(' per second ');
}

// assert this as a string, as it can initially be null
/** @var string $clazz */
$clazz = $index->getClass();
$table = Config::inst()->get($clazz, 'table_name');

Expand Down
28 changes: 28 additions & 0 deletions src/Helper/IndexingHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,32 @@ public function getFieldsToIndex(DataObject $dataObject): array

return $payload;
}


/** @return array<string> */
public function getFields(string $indexName): array
{
$indexes = new Indexes();
$index = $indexes->getIndex($indexName);

$fields = [];

foreach ($index->getFields() as $field) {
$fields[] = $field;
}

foreach ($index->getTokens() as $token) {
$fields[] = $token;
}

foreach ($index->getStoredFields() as $storedField) {
$fields[] = $storedField;
}

if (!\in_array('Link', $fields, true)) {
$fields[] = 'Link';
}

return $fields;
}
}
54 changes: 54 additions & 0 deletions src/Helper/SearchHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php declare(strict_types = 1);

/**
* Created by PhpStorm.
* User: gordon
* Date: 25/3/2561
* Time: 17:01 น.
*/

namespace Suilven\FreeTextSearch\Helper;

use SilverStripe\ORM\DataObject;

class SearchHelper
{
/**
* @param \SilverStripe\ORM\DataObject $dataObject the dataobject to extra text from
* @return array<string,array<string,string>>
*/
public function getTextFieldPayload(DataObject $dataObject): array
{
$helper = new IndexingHelper();
$fullPayload = $helper->getFieldsToIndex($dataObject);

$textPayload = [];

$keys = \array_keys($fullPayload);
$specsHelper = new SpecsHelper();

foreach ($keys as $key) {
if ($fullPayload[$key] === []) {
continue;
}

$textPayload[$key] = [];
$specs = $specsHelper->getFieldSpecs($key);

foreach (\array_keys($specs) as $field) {
// skip link field
if ($field === 'Link') {
continue;
}
$type = $specs[$field];
if (!\in_array($type, ['Varchar', 'HTMLText'], true)) {
continue;
}

$textPayload[$key][$field] = (string) $fullPayload[$key][$field];
}
}

return $textPayload;
}
}
63 changes: 63 additions & 0 deletions src/Helper/SpecsHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php declare(strict_types = 1);

/**
* Created by PhpStorm.
* User: gordon
* Date: 25/3/2561
* Time: 17:01 น.
*/

namespace Suilven\FreeTextSearch\Helper;

use SilverStripe\ORM\DataObjectSchema;
use Suilven\FreeTextSearch\Indexes;

class SpecsHelper
{
/**
* Helper method to get get field specs for a DataObject relevant to it's index definition
*
* @param string $indexName the name of the index
* @return array<string,string>
*/
public function getFieldSpecs(string $indexName): array
{
$indexes = new Indexes();
$index = $indexes->getIndex($indexName);
$singleton = \singleton((string)($index->getClass()));

$helper = new IndexingHelper();
$fields = $helper->getFields($indexName);

/** @var \SilverStripe\ORM\DataObjectSchema $schema */
$schema = $singleton->getSchema();
$specs = $schema->fieldSpecs((string) $index->getClass(), DataObjectSchema::INCLUDE_CLASS);

/** @var array<string,string> $filteredSpecs the DB specs for fields related to the index */
$filteredSpecs = [];

foreach ($fields as $field) {
if ($field === 'Link') {
continue;
}
$fieldType = $specs[$field];

// fix likes of varchar(255)
$fieldType = \explode('(', $fieldType)[0];

// remove the class name
$fieldType = \explode('.', $fieldType)[1];

$filteredSpecs[$field] = $fieldType;
}

// if Link undefined in the original index specs, add it if the method exists on the singleton dataobject
if (!isset($filteredSpecs['Link'])) {
if (\method_exists($singleton, 'Link')) {
$filteredSpecs['Link'] = 'Varchar';
}
}

return $filteredSpecs;
}
}
8 changes: 4 additions & 4 deletions src/Indexes.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
*/
class Indexes
{
/** @var array<string, \Suilven\FreeTextSearch\Index>|null */
private $indexesByName;
/** @var array<string, \Suilven\FreeTextSearch\Index> */
private $indexesByName = [];


/**
* Get an Index object by name from the config
*/
public function getIndex(string $name): Index
{
if (\is_null($this->indexesByName)) {
if ($this->indexesByName === []) {
$this->getIndexes();
}

Expand Down Expand Up @@ -107,7 +107,7 @@ public function getIndexes(): array

$this->indexesByName[$index->getName()] = $index;
}

return $this->indexesByName;
}

Expand Down
3 changes: 2 additions & 1 deletion src/Interfaces/Indexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use SilverStripe\ORM\DataObject;

// @phpcs:disable SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification
interface Indexer
{

Expand All @@ -24,6 +25,6 @@ public function index(DataObject $dataObject): void;
public function setIndexName(string $newIndexName): void;

// this is provided by the base indexer
/** @return array<string, array<string,string|int|float|bool|null>> */
/* @return array<string, array<string, array|bool|float|int|string>> */
public function getIndexablePayload(\SilverStripe\ORM\DataObject $dataObject): array;
}
Loading