Skip to content

Commit

Permalink
feat: add support for virtual pages, pulling content from the origina…
Browse files Browse the repository at this point in the history
…l source.
  • Loading branch information
wilr committed Aug 21, 2024
1 parent 8d32123 commit a4807fc
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 71 deletions.
6 changes: 6 additions & 0 deletions _config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@ Name: silverstripe-algolia
SilverStripe\CMS\Model\SiteTree:
extensions:
- Wilr\SilverStripe\Algolia\Extensions\AlgoliaObjectExtension
SilverStripe\Subsites\Pages\SubsitesVirtualPage:
extensions:
- Wilr\SilverStripe\Algolia\Extensions\SubsitesVirtualPageExtension
ilverStripe\CMS\Model\VirtualPage:
extensions:
- Wilr\SilverStripe\Algolia\Extensions\VirtualPageExtension
48 changes: 48 additions & 0 deletions src/Extensions/SubsitesVirtualPageExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace Wilr\SilverStripe\Algolia\Extensions;

use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\Map;
use SilverStripe\Subsites\Model\Subsite;
use Wilr\SilverStripe\Algolia\Service\AlgoliaIndexer;

class SubsitesVirtualPageExtension extends \SilverStripe\ORM\DataExtension
{
public function exportObjectToAlgolia($toIndex)
{
$attributes = new Map(ArrayList::create());

foreach ($toIndex as $k => $v) {
if ($k === 'objectClassName') {
continue;
}

$attributes->push($k, $v);
}

/** @var AlgoliaIndexer */
$indexer = Injector::inst()->get(AlgoliaIndexer::class);
$owner = $this->owner;

// get original object
$result = Subsite::withDisabledSubsiteFilter(function () use ($owner, $attributes, $indexer) {
$originalObject = $owner->CopyContentFrom();

if (!$originalObject) {
return $attributes;
}

$attributes->push('objectClassName', $originalObject->ClassName);
$specs = $originalObject->config()->get('algolia_index_fields');
$attributes = $indexer->addSpecsToAttributes($originalObject, $attributes, $specs);

$originalObject->invokeWithExtensions('updateAlgoliaAttributes', $attributes);

return $attributes;
});

return $result;
}
}
43 changes: 43 additions & 0 deletions src/Extensions/VirtualPageExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace Wilr\SilverStripe\Algolia\Extensions;

use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\Map;
use Wilr\SilverStripe\Algolia\Service\AlgoliaIndexer;

class VirtualPageExtension extends \SilverStripe\ORM\DataExtension
{
public function exportObjectToAlgolia($toIndex)
{
$attributes = new Map(ArrayList::create());

foreach ($toIndex as $k => $v) {
if ($k === 'objectClassName') {
continue;
}

$attributes->push($k, $v);
}

/** @var AlgoliaIndexer */
$indexer = Injector::inst()->get(AlgoliaIndexer::class);
$owner = $this->owner;

// get original object
$originalObject = $owner->CopyContentFrom();

if (!$originalObject) {
return $attributes;
}

$attributes->push('objectClassName', $originalObject->ClassName);
$specs = $originalObject->config()->get('algolia_index_fields');
$attributes = $indexer->addSpecsToAttributes($originalObject, $attributes, $specs);

$originalObject->invokeWithExtensions('updateAlgoliaAttributes', $attributes);

return $attributes;
}
}
162 changes: 91 additions & 71 deletions src/Service/AlgoliaIndexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Wilr\SilverStripe\Algolia\Service;

use Algolia\AlgoliaSearch\Exceptions\NotFoundException;
use Exception;
use LogicException;
use Psr\Log\LoggerInterface;
use SilverStripe\Core\Injector\Injector;
Expand Down Expand Up @@ -39,7 +40,11 @@ class AlgoliaIndexer
* @config
*/
private static $attributes_blacklisted = [
'ID', 'Title', 'ClassName', 'LastEdited', 'Created'
'ID',
'Title',
'ClassName',
'LastEdited',
'Created'
];

/**
Expand All @@ -61,7 +66,14 @@ class AlgoliaIndexer
public function indexItem($item)
{
$searchIndexes = $this->getService()->initIndexes($item);
$fields = $this->exportAttributesFromObject($item);

try {
$fields = $this->exportAttributesFromObject($item);
} catch (Exception $e) {
Injector::inst()->get(LoggerInterface::class)->error($e);

return false;
}

if (method_exists($fields, 'toArray')) {
$fields = $fields->toArray();
Expand Down Expand Up @@ -196,86 +208,94 @@ public function exportAttributesFromObject($item)
$specs = $item->config()->get('algolia_index_fields');

if ($specs) {
$maxFieldSize = $this->config()->get('max_field_size_bytes');
$attributes = $this->addSpecsToAttributes($item, $attributes, $specs);
}

foreach ($specs as $attributeName) {
if (in_array($attributeName, $this->config()->get('attributes_blacklisted'))) {
continue;
}
$item->invokeWithExtensions('updateAlgoliaAttributes', $attributes);

// fetch the db object, or fallback to the getters but prefer
// the db object
try {
$dbField = $item->relObject($attributeName);
} catch (LogicException $e) {
$dbField = $item->{$attributeName};
}
return $attributes;
}

if (!$dbField) {
continue;
}

if (is_string($dbField) || is_array($dbField)) {
$attributes->push($attributeName, $dbField);
} elseif ($dbField instanceof DBForeignKey) {
$attributes->push($attributeName, $dbField->Value);
} elseif ($dbField->exists() || $dbField instanceof DBBoolean) {
if ($dbField instanceof RelationList || $dbField instanceof DataObject) {
// has-many, many-many, has-one
$this->exportAttributesFromRelationship($item, $attributeName, $attributes);
} else {
// db-field, if it's a date then use the timestamp since we need it
$hasContent = true;

switch (get_class($dbField)) {
case DBDate::class:
case DBDatetime::class:
$value = $dbField->getTimestamp();
break;
case DBBoolean::class:
$value = $dbField->getValue();
break;
case DBHTMLText::class:
$fieldData = $dbField->Plain();
$fieldLength = mb_strlen($fieldData, '8bit');

if ($fieldLength > $maxFieldSize) {
$maxIterations = 100;
$i = 0;

while ($hasContent && $i < $maxIterations) {
$block = mb_strcut(
$fieldData,
$i * $maxFieldSize,
$maxFieldSize - 1
);

if ($block) {
$attributes->push($attributeName . '_Block' . $i, $block);
} else {
$hasContent = false;
}

$i++;
public function addSpecsToAttributes($item, $attributes, $specs)
{
$maxFieldSize = $this->config()->get('max_field_size_bytes');

foreach ($specs as $attributeName) {
if (in_array($attributeName, $this->config()->get('attributes_blacklisted'))) {
continue;
}

// fetch the db object, or fallback to the getters but prefer
// the db object
try {
$dbField = $item->relObject($attributeName);
} catch (LogicException $e) {
$dbField = $item->{$attributeName};
}

if (!$dbField) {
continue;
}

if (is_string($dbField) || is_array($dbField)) {
$attributes->push($attributeName, $dbField);
} elseif ($dbField instanceof DBForeignKey) {
$attributes->push($attributeName, $dbField->Value);
} elseif ($dbField->exists() || $dbField instanceof DBBoolean) {
if ($dbField instanceof RelationList || $dbField instanceof DataObject) {
// has-many, many-many, has-one
$this->exportAttributesFromRelationship($item, $attributeName, $attributes);
} else {
// db-field, if it's a date then use the timestamp since we need it
$hasContent = true;

switch (get_class($dbField)) {
case DBDate::class:
case DBDatetime::class:
$value = $dbField->getTimestamp();
break;
case DBBoolean::class:
$value = $dbField->getValue();
break;
case DBHTMLText::class:
$fieldData = $dbField->Plain();
$fieldLength = mb_strlen($fieldData, '8bit');

if ($fieldLength > $maxFieldSize) {
$maxIterations = 100;
$i = 0;

while ($hasContent && $i < $maxIterations) {
$block = mb_strcut(
$fieldData,
$i * $maxFieldSize,
$maxFieldSize - 1
);

if ($block) {
$attributes->push($attributeName . '_Block' . $i, $block);
} else {
$hasContent = false;
}
} else {
$value = $fieldData;

$i++;
}
break;
default:
$value = @$dbField->forTemplate();
}

if ($hasContent) {
$attributes->push($attributeName, $value);
}
} else {
$value = $fieldData;
}
break;
default:
$value = @$dbField->forTemplate();
}

if ($hasContent) {
$attributes->push($attributeName, $value);
}
}
}
}

$item->invokeWithExtensions('updateAlgoliaAttributes', $attributes);

return $attributes;
}

Expand Down

0 comments on commit a4807fc

Please sign in to comment.