. */ namespace App\Traits; use App\Contracts\Searchable; use App\Jobs\UpdateSearchIndexForEntity; use Elasticsearch; use Elasticsearch\Common\Exceptions\Missing404Exception; use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Support\Facades\Config; /** * Class IndexedInElasticsearch. * * Classes using this trait must declare the `$elasticsearchType` property and * implement the `Searchable` interface. */ trait IndexedInElasticsearchTrait { use DispatchesJobs; // These two functions are from the Searchable interface. They're included // here, without being implemented, to assist IDE's when editing this trait. abstract public function toElasticsearch():array; abstract public function shouldBeIndexed():bool; // Laravel automatically runs this method based on the trait's name. #magic public static function bootIndexedInElasticsearchTrait() { static::saved(function (Searchable $entity) { $entity->updateElasticsearchEntry(); }); static::deleted(function (Searchable $entity) { $entity->updateElasticsearchEntry(); }); } /** * @param bool $includeBody set to false when deleting documents * @return array */ private function getElasticsearchParameters(bool $includeBody = true) { $parameters = [ 'index' => config('ponyfm.elasticsearch_index'), 'type' => $this->elasticsearchType, 'id' => $this->id, ]; if ($includeBody) { $parameters['body'] = $this->toElasticsearch(); } return $parameters; } private function createOrUpdateElasticsearchEntry() { Elasticsearch::connection()->index($this->getElasticsearchParameters()); } private function deleteElasticsearchEntry() { try { Elasticsearch::connection()->delete($this->getElasticsearchParameters(false)); } catch (Missing404Exception $e) { // If the entity we're trying to delete isn't indexed in Elasticsearch, // that's fine. } } /** * Asynchronously updates the Elasticsearch entry. * When in doubt, this is the method to use. */ public function updateElasticsearchEntry() { $job = (new UpdateSearchIndexForEntity($this))->onQueue(config('ponyfm.indexing_queue')); $this->dispatch($job); } /** * Synchronously updates the Elasticsearch entry. This should only be * called from the UpdateSearchIndexForEntity job. */ public function updateElasticsearchEntrySynchronously() { if ($this->shouldBeIndexed()) { $this->createOrUpdateElasticsearchEntry(); } else { $this->deleteElasticsearchEntry(); } } }