Skip to content

Commit ffaf4da

Browse files
SearchableSubscriber re-index entity on change/deletion
1 parent 3bda6b2 commit ffaf4da

File tree

4 files changed

+202
-0
lines changed

4 files changed

+202
-0
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,22 @@
66
]
77
```
88

9+
```
10+
'events' => [
11+
'listeners' => [],
12+
'subscribers' => [
13+
LaravelDoctrine\Scout\Subscribers\SearachableSubscriber::class
14+
]
15+
],
16+
```
17+
18+
```php
19+
class Post implements LaravelDoctrine\Scout\Searchable
20+
{
21+
use LaravelDoctrine\Scout\Indexable;
22+
}
23+
```
24+
925
To index all records of a certain entity:
1026

1127
```

src/Searchable.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace LaravelDoctrine\Scout;
4+
5+
use Doctrine\ORM\Mapping\ClassMetadata;
6+
7+
interface Searchable
8+
{
9+
/**
10+
* Get primary key value
11+
* @return int
12+
*/
13+
public function getKey();
14+
15+
/**
16+
* @return string
17+
*/
18+
public function searchableAs();
19+
20+
/**
21+
* @return string
22+
*/
23+
public function toSearchableArray();
24+
25+
/**
26+
* @param ClassMetadata $classMetadata
27+
*/
28+
public function setClassMetaData(ClassMetadata $classMetadata);
29+
}

src/SearchableRepository.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,24 @@ public function makeAllSearchable()
8383
});
8484
}
8585

86+
/**
87+
* Make specific entities searchable
88+
* @param Collection $entities
89+
*/
90+
public function makeEntitiesSearchable(Collection $entities)
91+
{
92+
$this->searchableUsing()->update($entities);
93+
}
94+
95+
/**
96+
* Remove specific searchable entities
97+
* @param Collection $entities
98+
*/
99+
public function removeSearchableEntities(Collection $entities)
100+
{
101+
$this->searchableUsing()->delete($entities);
102+
}
103+
86104
/**
87105
* @param int $count
88106
* @param callable $callback
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
3+
namespace LaravelDoctrine\Scout\Subscribers;
4+
5+
use Doctrine\Common\EventSubscriber;
6+
use Doctrine\ORM\EntityManagerInterface;
7+
use Doctrine\ORM\Event\LifecycleEventArgs;
8+
use Doctrine\ORM\Event\PostFlushEventArgs;
9+
use Doctrine\ORM\Events;
10+
use Illuminate\Support\Collection;
11+
use Laravel\Scout\EngineManager;
12+
use LaravelDoctrine\Scout\Searchable;
13+
use LaravelDoctrine\Scout\SearchableRepository;
14+
15+
class SearachableSubscriber implements EventSubscriber
16+
{
17+
/**
18+
* @var array
19+
*/
20+
private $indexable = [];
21+
22+
/**
23+
* @var array
24+
*/
25+
private $deleteable = [];
26+
27+
/**
28+
* @return array
29+
*/
30+
public function getSubscribedEvents()
31+
{
32+
return [
33+
Events::postPersist,
34+
Events::postUpdate,
35+
Events::preRemove,
36+
Events::postFlush
37+
];
38+
}
39+
40+
/**
41+
* @param PostFlushEventArgs $args
42+
*/
43+
public function postFlush(PostFlushEventArgs $args)
44+
{
45+
foreach ($this->indexable as $event) {
46+
$this->indexEntity($args->getEntityManager(), $event);
47+
}
48+
49+
foreach ($this->deleteable as $event) {
50+
$this->removeEntity($args->getEntityManager(), $event);
51+
}
52+
}
53+
54+
/**
55+
* @param LifecycleEventArgs $event
56+
*/
57+
public function postPersist(LifecycleEventArgs $event)
58+
{
59+
$this->scheduleIndexing($event);
60+
}
61+
62+
/**
63+
* @param LifecycleEventArgs $event
64+
*/
65+
public function postUpdate(LifecycleEventArgs $event)
66+
{
67+
$this->scheduleIndexing($event);
68+
}
69+
70+
/**
71+
* @param LifecycleEventArgs $event
72+
*/
73+
public function preRemove(LifecycleEventArgs $event)
74+
{
75+
$object = $event->getObject();
76+
77+
if ($object instanceof Searchable) {
78+
$this->deleteable[] = clone $object;
79+
}
80+
}
81+
82+
/**
83+
* @param LifecycleEventArgs $event
84+
*/
85+
public function scheduleIndexing(LifecycleEventArgs $event)
86+
{
87+
$object = $event->getObject();
88+
89+
if ($object instanceof Searchable) {
90+
$this->indexable[] = $object;
91+
}
92+
}
93+
94+
/**
95+
* @param EntityManagerInterface $em
96+
* @param Searchable $object
97+
*/
98+
private function indexEntity(EntityManagerInterface $em, Searchable $object)
99+
{
100+
$repository = $this->getRepository($em, $object);
101+
102+
$repository->makeEntitiesSearchable(new Collection([$object]));
103+
}
104+
105+
/**
106+
* @param EntityManagerInterface $em
107+
* @param Searchable $object
108+
*/
109+
private function removeEntity(EntityManagerInterface $em, Searchable $object)
110+
{
111+
$repository = $this->getRepository($em, $object);
112+
113+
$repository->removeSearchableEntities(new Collection([$object]));
114+
}
115+
116+
/**
117+
* @param EntityManagerInterface $em
118+
* @param Searchable $object
119+
* @return SearchableRepository
120+
*/
121+
private function getRepository(EntityManagerInterface $em, Searchable $object)
122+
{
123+
$class = get_class($object);
124+
$cmd = $em->getClassMetadata($class);
125+
$repository = $em->getRepository($class);
126+
127+
if (!$repository instanceof SearchableRepository) {
128+
$repository = new SearchableRepository(
129+
$em,
130+
$cmd,
131+
app(EngineManager::class)
132+
);
133+
}
134+
135+
$object->setClassMetaData($cmd);
136+
137+
return $repository;
138+
}
139+
}

0 commit comments

Comments
 (0)