diff --git a/_config/config.yml b/_config/config.yml index ade179a..cbe3b96 100644 --- a/_config/config.yml +++ b/_config/config.yml @@ -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 diff --git a/src/Extensions/SubsitesVirtualPageExtension.php b/src/Extensions/SubsitesVirtualPageExtension.php new file mode 100644 index 0000000..fc86f40 --- /dev/null +++ b/src/Extensions/SubsitesVirtualPageExtension.php @@ -0,0 +1,48 @@ + $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; + } +} diff --git a/src/Extensions/VirtualPageExtension.php b/src/Extensions/VirtualPageExtension.php new file mode 100644 index 0000000..ede322c --- /dev/null +++ b/src/Extensions/VirtualPageExtension.php @@ -0,0 +1,43 @@ + $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; + } +} diff --git a/src/Service/AlgoliaIndexer.php b/src/Service/AlgoliaIndexer.php index 0399dcb..6ea2e0a 100644 --- a/src/Service/AlgoliaIndexer.php +++ b/src/Service/AlgoliaIndexer.php @@ -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; @@ -39,7 +40,11 @@ class AlgoliaIndexer * @config */ private static $attributes_blacklisted = [ - 'ID', 'Title', 'ClassName', 'LastEdited', 'Created' + 'ID', + 'Title', + 'ClassName', + 'LastEdited', + 'Created' ]; /** @@ -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(); @@ -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; }