Skip to content

Commit

Permalink
Merge pull request #267 from andrewmenich/feature/support-multi-eleme…
Browse files Browse the repository at this point in the history
…nttypes

Feature - Add support for multiple Element Types per Index
  • Loading branch information
janhenckens authored Apr 12, 2024
2 parents 16f1363 + 266fd56 commit 11662f8
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 47 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,20 @@ This function accepts an `ElementQuery` and should also return an `ElementQuery`
});
```

#### `->getElements(callable $queries)`
This function can be used to query multiple different Element types. It should return an array of ElementQuery objects.

```php
->getElements(function () {
return [
Entry::find()->section('blog'),
Category::find()->group('blogCategories'),
];
});
```

*Note:* When `->getElements()` is used, `->criteria()` and `->elementType()` are ignored.

#### `->transformer(callable|string|array|TransformerAbstract $transformer)`
The [transformer](http://fractal.thephpleague.com/transformers/) that should be used to define the data that should be sent to Algolia for each element. If you don’t set this, the default transformer will be used, which includes all of the element’s direct attribute values, but no custom field values.

Expand Down
33 changes: 32 additions & 1 deletion src/ScoutIndex.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ class ScoutIndex

/** @var IndexSettings */
public $indexSettings;

/** @var bool */
public $enforceElementType = true;

/** @var string */
public $elementType = Entry::class;

/** @var ElementQuery */
/** @var ElementQuery|ElementQuery[] */
public $criteria;

/** @var callable|string|array|\League\Fractal\TransformerAbstract */
Expand Down Expand Up @@ -67,6 +70,34 @@ public function criteria(callable $criteria): self

return $this;
}

/**
* @throws Exception
*/
public function getElements(callable $getElements): self
{
$elementQueries = $getElements();

if ($elementQueries instanceof ElementQuery) {
$elementQueries = [$elementQueries];
}

// loop through $elementQueries and check that they are all ElementQuery objects
foreach ($elementQueries as $elementQuery) {
if (!$elementQuery instanceof ElementQuery) {
throw new Exception('You must return a valid ElementQuery or array of ElementQuery objects from the getElements function.');
}

if (is_null($elementQuery->siteId)) {
$elementQuery->siteId = Craft::$app->getSites()->getPrimarySite()->id;
}
}

$this->enforceElementType = false;
$this->criteria = $elementQueries;

return $this;
}

/*
* @param $transformer callable|string|array|TransformerAbstract
Expand Down
33 changes: 26 additions & 7 deletions src/behaviors/SearchableBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,23 @@ class SearchableBehavior extends Behavior

public function validatesCriteria(ScoutIndex $scoutIndex): bool
{
$criteria = clone $scoutIndex->criteria;

return $criteria
->id($this->owner->id)
->exists();
if (is_array($scoutIndex->criteria)) {
foreach($scoutIndex->criteria as $query) {
$criteria = clone $query;

if (!$criteria->id($this->owner->id)->exists()) {
return false;
}
}
return true;

} else {
$criteria = clone $scoutIndex->criteria;

return $criteria
->id($this->owner->id)
->exists();
}
}

public function getIndices(): Collection
Expand All @@ -52,12 +64,19 @@ public function getIndices(): Collection
->getSettings()
->getIndices()
->filter(function (ScoutIndex $scoutIndex) {
if(is_array($scoutIndex->criteria)){
$criteriaSiteIds = collect($scoutIndex->criteria)->map(function($criteria){
return Arr::wrap($criteria->siteId);
})->flatten()->unique()->values()->toArray();
} else {
$criteriaSiteIds = Arr::wrap($scoutIndex->criteria->siteId);
}
$siteIds = array_map(function ($siteId) {
return (int) $siteId;
}, Arr::wrap($scoutIndex->criteria->siteId));
}, $criteriaSiteIds);

return $scoutIndex->elementType === get_class($this->owner)
&& ($scoutIndex->criteria->siteId === '*'
&& ($criteriaSiteIds[0] === '*'
|| in_array((int) $this->owner->siteId, $siteIds));
});
}
Expand Down
45 changes: 34 additions & 11 deletions src/console/controllers/scout/IndexController.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,40 @@ public function actionImport($index = '')
]));
$this->stdout("Added ImportIndex job for '{$engine->scoutIndex->indexName}' to the queue".PHP_EOL, Console::FG_GREEN);
} else {
$totalElements = $engine->scoutIndex->criteria->count();
$elementsUpdated = 0;
$batch = $engine->scoutIndex->criteria->batch(
Scout::$plugin->getSettings()->batch_size
);

foreach ($batch as $elements) {
$engine->update($elements);
$elementsUpdated += count($elements);
$this->stdout("Updated {$elementsUpdated}/{$totalElements} element(s) in {$engine->scoutIndex->indexName}\n", Console::FG_GREEN);
}
// check if $engine->scoutIndex->criteria is iterable
if (is_array($engine->scoutIndex->criteria)) {
// use array_reduce to get the count of elements
$totalElements = array_reduce($engine->scoutIndex->criteria, function ($carry, $query) {
return $carry + $query->count();
}, 0);

foreach($engine->scoutIndex->criteria as $query) {
$elementsUpdated = 0;
$batch = $query->batch(
Scout::$plugin->getSettings()->batch_size
);

foreach ($batch as $elements) {
$engine->update($elements);
$elementsUpdated += count($elements);
$this->stdout("Updated {$elementsUpdated}/{$totalElements} element(s) in {$engine->scoutIndex->indexName} via " . get_class($query) . "\n", Console::FG_GREEN);
}
}

} else {
$totalElements = $engine->scoutIndex->criteria->count();

$elementsUpdated = 0;
$batch = $engine->scoutIndex->criteria->batch(
Scout::$plugin->getSettings()->batch_size
);

foreach ($batch as $elements) {
$engine->update($elements);
$elementsUpdated += count($elements);
$this->stdout("Updated {$elementsUpdated}/{$totalElements} element(s) in {$engine->scoutIndex->indexName}\n", Console::FG_GREEN);
}
}
}
});

Expand Down
39 changes: 31 additions & 8 deletions src/controllers/IndexController.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,37 @@ public function actionImport()

return $this->redirect(UrlHelper::url('utilities/'.ScoutUtility::id()));
}

$elementsCount = $engine->scoutIndex->criteria->count();
$batch = $engine->scoutIndex->criteria->batch(
Scout::$plugin->getSettings()->batch_size
);

foreach ($batch as $elements) {
$engine->update($elements);

// check if $engine->scoutIndex->criteria is iterable
if (is_array($engine->scoutIndex->criteria)) {
// use array_reduce to get the count of elements
$elementsCount = array_reduce($engine->scoutIndex->criteria, function ($carry, $query) {
return $carry + $query->count();
}, 0);

$elementsUpdated = 0;

foreach($engine->scoutIndex->criteria as $query) {
$batch = $query->batch(
Scout::$plugin->getSettings()->batch_size
);

foreach ($batch as $elements) {
$engine->update($elements);
}
}

} else {
$elementsCount = $engine->scoutIndex->criteria->count();

$elementsUpdated = 0;
$batch = $engine->scoutIndex->criteria->batch(
Scout::$plugin->getSettings()->batch_size
);

foreach ($batch as $elements) {
$engine->update($elements);
}
}

Craft::$app->getSession()->setNotice("Updated {$elementsCount} element(s) in {$engine->scoutIndex->indexName}");
Expand Down
10 changes: 6 additions & 4 deletions src/engines/AlgoliaEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ public function __construct(ScoutIndex $scoutIndex, Algolia $algolia)
public function update($elements)
{
$elements = new Collection(Arr::wrap($elements));

$elements = $elements->filter(function (Element $element) {
return get_class($element) === $this->scoutIndex->elementType;
});

if($this->scoutIndex->enforceElementType) {
$elements = $elements->filter(function (Element $element) {
return get_class($element) === $this->scoutIndex->elementType;
});
}

if ($elements->isEmpty()) {
return;
Expand Down
46 changes: 35 additions & 11 deletions src/jobs/ImportIndex.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,41 @@ public function execute($queue): void
if (!$engine) {
return;
}

$elementsCount = $engine->scoutIndex->criteria->count();
$elementsUpdated = 0;
$batch = $engine->scoutIndex->criteria->batch(
Scout::$plugin->getSettings()->batch_size
);

foreach ($batch as $elements) {
$engine->update($elements);
$elementsUpdated += count($elements);
$this->setProgress($queue, $elementsUpdated / $elementsCount);

// check if $engine->scoutIndex->criteria is iterable
if (is_array($engine->scoutIndex->criteria)) {
// use array_reduce to get the count of elements
$elementsCount = array_reduce($engine->scoutIndex->criteria, function ($carry, $query) {
return $carry + $query->count();
}, 0);

$elementsUpdated = 0;

foreach($engine->scoutIndex->criteria as $query) {
$batch = $query->batch(
Scout::$plugin->getSettings()->batch_size
);

foreach ($batch as $elements) {
$engine->update($elements);
$elementsUpdated += count($elements);
$this->setProgress($queue, $elementsUpdated / $elementsCount);
}
}

} else {
$elementsCount = $engine->scoutIndex->criteria->count();

$elementsUpdated = 0;
$batch = $engine->scoutIndex->criteria->batch(
Scout::$plugin->getSettings()->batch_size
);

foreach ($batch as $elements) {
$engine->update($elements);
$elementsUpdated += count($elements);
$this->setProgress($queue, $elementsUpdated / $elementsCount);
}
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/templates/utility.twig
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
{% for index in stats %}
<h2 style="width: 100%;">
{{ index.name }}
{% if index.site == "all" %}
{% if index.sites == "all" %}
<span class="light">&ndash; {{ "All sites"|t('scout') }}</span>&nbsp;
{% else %}
<span class="light">&ndash; {{ index.site.name }}</span>&nbsp;
{% for site in index.sites %}
<span class="light">&ndash; {{ site.name }}</span>&nbsp;
{% endfor %}
{% endif %}
<span class="light">&ndash; </span><small class="light">{{ index.elementType }}</small>
</h2>
Expand Down
28 changes: 25 additions & 3 deletions src/utilities/ScoutUtility.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Craft;
use craft\base\Utility;
use Illuminate\Support\Arr;
use rias\scout\engines\Engine;
use rias\scout\Scout;

Expand Down Expand Up @@ -31,12 +32,33 @@ public static function contentHtml(): string
$engines = Scout::$plugin->getSettings()->getEngines();

$stats = $engines->map(function (Engine $engine) {
// loop through criteria to get siteId from each criteria
$engineCriteria = collect(Arr::wrap($engine->scoutIndex->criteria));

$criteriaSites = $engineCriteria->map(function($criteria){
return $criteria->siteId;
})->flatten()->unique()->values()->toArray();

if (count($criteriaSites) === 1 && $criteriaSites[0] === '*') {
$sites = 'all';
} else {
$sites = collect($criteriaSites)->map(function($siteId){
return Craft::$app->getSites()->getSiteById($siteId);
})->implode('name', ', ');
}

$totalElements = $engineCriteria->reduce(function($carry, $criteria){
return $carry + $criteria->count();
}, 0);

$elementType = $engine->scoutIndex->enforceElementType ? $engine->scoutIndex->elementType : 'Mixed Element Types';

return [
'name' => $engine->scoutIndex->indexName,
'elementType' => $engine->scoutIndex->elementType,
'site' => $engine->scoutIndex->criteria->siteId === '*' ? 'all' : Craft::$app->getSites()->getSiteById($engine->scoutIndex->criteria->siteId),
'elementType' => $elementType,
'sites' => $sites,
'indexed' => $engine->getTotalRecords(),
'elements' => $engine->scoutIndex->criteria->count(),
'elements' => $totalElements,
'hasSettings' => $engine->scoutIndex->indexSettings ?? null,
];
});
Expand Down

0 comments on commit 11662f8

Please sign in to comment.