*/ class ResourceWatcher extends ConfigurableService { use OntologyAwareTrait; const SERVICE_ID = 'tao/ResourceWatcher'; /** Time in seconds for updatedAt threshold */ const OPTION_THRESHOLD = 'threshold'; /** @var array */ protected $updatedAtCache = []; public function catchCreatedResourceEvent(ResourceCreated $event): void { $resource = $event->getResource(); $property = $this->getProperty(TaoOntology::PROPERTY_UPDATED_AT); $now = microtime(true); $this->updatedAtCache = []; $this->updatedAtCache[$resource->getUri()] = $now; $resource->editPropertyValues($property, $now); $this->getLogger()->debug('triggering index update on resourceCreated event'); $taskMessage = __('Adding search index for created resource'); $this->createResourceIndexingTask($resource, $taskMessage); } /** * @throws \core_kernel_persistence_Exception */ public function catchUpdatedResourceEvent(ResourceUpdated $event): void { $resource = $event->getResource(); $updatedAt = $this->getUpdatedAt($resource); if ($updatedAt && $updatedAt instanceof \core_kernel_classes_Literal) { $updatedAt = (int) $updatedAt->literal; } $now = microtime(true); $threshold = $this->getOption(self::OPTION_THRESHOLD); if ($updatedAt === null || ($now - $updatedAt) > $threshold) { $this->getLogger()->debug('triggering index update on resourceUpdated event'); $taskMessage = __('Adding/updating search index for updated resource'); $this->createResourceIndexingTask($resource, $taskMessage); $property = $this->getProperty(TaoOntology::PROPERTY_UPDATED_AT); $this->updatedAtCache[$resource->getUri()] = $now; $resource->editPropertyValues($property, $now); } } public function catchDeletedResourceEvent(ResourceDeleted $event): void { $searchService = $this->getServiceLocator()->get(Search::SERVICE_ID); try { $searchService->remove($event->getId()); } catch (\Exception $e) { $message = $e->getMessage(); $this->getLogger()->error( sprintf("Error delete index document for %s with message %s", $event->getId(), $message) ); } } /** * @return \core_kernel_classes_Container * @throws \core_kernel_persistence_Exception */ public function getUpdatedAt(core_kernel_classes_Resource $resource) { if (isset($this->updatedAtCache[$resource->getUri()])) { $updatedAt = $this->updatedAtCache[$resource->getUri()]; } else { $property = $this->getProperty(TaoOntology::PROPERTY_UPDATED_AT); $updatedAt = $resource->getOnePropertyValue($property); if ($updatedAt && $updatedAt instanceof \core_kernel_classes_Literal) { $updatedAt = (int) $updatedAt->literal; } $this->updatedAtCache[$resource->getUri()] = $updatedAt; } return $updatedAt; } /** * Creates a task in the task queue to index/re-index created/updated resource */ private function createResourceIndexingTask(core_kernel_classes_Resource $resource, string $message): void { if ($this->getServiceLocator()->get(AdvancedSearchChecker::class)->isEnabled()) { /** @var QueueDispatcherInterface $queueDispatcher */ $queueDispatcher = $this->getServiceLocator()->get(QueueDispatcherInterface::SERVICE_ID); if ($this->hasClassSupport($resource) && !$this->ignoreEditIemClassUpdates()) { $queueDispatcher->createTask(new UpdateClassInIndex(), [$resource->getUri()], $message); return; } if ($this->hasResourceSupport($resource)) { $queueDispatcher->createTask(new UpdateResourceInIndex(), [$resource->getUri()], $message); return; } } } private function hasResourceSupport(core_kernel_classes_Resource $resource): bool { $resourceTypeIds = array_map( function (core_kernel_classes_Class $resourceType): string { return $resourceType->getUri(); }, $resource->getTypes() ); $checkedResourceTypes = [OntologyRdfs::RDFS_RESOURCE, TaoOntology::CLASS_URI_OBJECT]; $resourceTypeIds = array_diff($resourceTypeIds, [OntologyRdfs::RDFS_RESOURCE, TaoOntology::CLASS_URI_OBJECT]); while (!empty($resourceTypeIds)) { $classUri = array_pop($resourceTypeIds); $hasClassSupport = $this->getServiceLocator() ->get(IndexUpdaterInterface::SERVICE_ID) ->hasClassSupport( $classUri ); if ($hasClassSupport) { return true; } $class = $this->getClass($classUri); foreach ($class->getParentClasses() as $parent) { if (!in_array($parent->getUri(), $checkedResourceTypes)) { $resourceTypeIds[] = $parent->getUri(); } } $checkedResourceTypes[] = $class->getUri(); } return false; } private function hasClassSupport(core_kernel_classes_Resource $resource): bool { return $resource instanceof core_kernel_classes_Class; } private function ignoreEditIemClassUpdates(): bool { try { $url = parse_url(common_http_Request::currentRequest()->getUrl()); } catch (\common_exception_Error $e) { return false; } return isset($url['path']) && $url['path'] === '/taoItems/Items/editItemClass'; } }