1 | <?php |
||||||
2 | |||||||
3 | namespace Beelab\TagBundle\Listener; |
||||||
4 | |||||||
5 | use Beelab\TagBundle\Tag\TaggableInterface; |
||||||
6 | use Beelab\TagBundle\Tag\TagInterface; |
||||||
7 | use Doctrine\Common\EventSubscriber; |
||||||
8 | use Doctrine\Common\Persistence\Mapping\MappingException as LegacyMappingException; |
||||||
0 ignored issues
–
show
|
|||||||
9 | use Doctrine\ORM\Event\OnFlushEventArgs; |
||||||
10 | use Doctrine\Persistence\Mapping\MappingException; |
||||||
11 | |||||||
12 | /** |
||||||
13 | * Add tags to entities that implements TaggableInterface. |
||||||
14 | */ |
||||||
15 | final class TagSubscriber implements EventSubscriber |
||||||
16 | { |
||||||
17 | /** |
||||||
18 | * @var \Doctrine\ORM\EntityManager |
||||||
19 | */ |
||||||
20 | private $manager; |
||||||
21 | |||||||
22 | /** |
||||||
23 | * @var \Doctrine\ORM\UnitOfWork |
||||||
24 | */ |
||||||
25 | private $uow; |
||||||
26 | |||||||
27 | /** |
||||||
28 | * @var TagInterface |
||||||
29 | */ |
||||||
30 | private $tag; |
||||||
31 | |||||||
32 | /** |
||||||
33 | * @var bool |
||||||
34 | */ |
||||||
35 | private $purge; |
||||||
36 | |||||||
37 | /** |
||||||
38 | * @param bool $purge whether to delete tags when entity is deleted |
||||||
39 | * |
||||||
40 | * @throws MappingException |
||||||
41 | * @throws \InvalidArgumentException |
||||||
42 | */ |
||||||
43 | public function __construct(string $tagClassName, bool $purge = false) |
||||||
44 | { |
||||||
45 | if (!\class_exists($tagClassName)) { |
||||||
46 | if (\class_exists('Doctrine\Common\Persistence\Mapping\MappingException')) { |
||||||
47 | throw LegacyMappingException::nonExistingClass($tagClassName); |
||||||
48 | } |
||||||
49 | throw MappingException::nonExistingClass($tagClassName); |
||||||
50 | } |
||||||
51 | $this->tag = new $tagClassName(); |
||||||
52 | if (!$this->tag instanceof TagInterface) { |
||||||
53 | throw new \InvalidArgumentException(\sprintf('Class "%s" must implement TagInterface.', $tagClassName)); |
||||||
54 | } |
||||||
55 | $this->purge = $purge; |
||||||
56 | } |
||||||
57 | |||||||
58 | public function getSubscribedEvents(): array |
||||||
59 | { |
||||||
60 | return ['onFlush']; |
||||||
61 | } |
||||||
62 | |||||||
63 | /** |
||||||
64 | * Main method: call setTags() on entities scheduled to be inserted or updated, and |
||||||
65 | * possibly call purgeTags() on entities scheduled to be deleted. |
||||||
66 | */ |
||||||
67 | public function onFlush(OnFlushEventArgs $args): void |
||||||
68 | { |
||||||
69 | $this->manager = $args->getEntityManager(); |
||||||
70 | $this->uow = $this->manager->getUnitOfWork(); |
||||||
71 | foreach ($this->uow->getScheduledEntityInsertions() as $key => $entity) { |
||||||
72 | if ($entity instanceof TaggableInterface) { |
||||||
73 | $this->setTags($entity, false); |
||||||
74 | } |
||||||
75 | } |
||||||
76 | foreach ($this->uow->getScheduledEntityUpdates() as $key => $entity) { |
||||||
77 | if ($entity instanceof TaggableInterface) { |
||||||
78 | $this->setTags($entity, true); |
||||||
79 | } |
||||||
80 | } |
||||||
81 | if ($this->purge) { |
||||||
82 | foreach ($this->uow->getScheduledEntityDeletions() as $key => $entity) { |
||||||
83 | if ($entity instanceof TaggableInterface) { |
||||||
84 | $this->purgeTags($entity); |
||||||
85 | } |
||||||
86 | } |
||||||
87 | } |
||||||
88 | } |
||||||
89 | |||||||
90 | /** |
||||||
91 | * Do the stuff. |
||||||
92 | * |
||||||
93 | * @param bool $update true if entity is being updated, false otherwise |
||||||
94 | */ |
||||||
95 | private function setTags(TaggableInterface $entity, bool $update = false): void |
||||||
96 | { |
||||||
97 | $tagNames = $entity->getTagNames(); |
||||||
98 | if (empty($tagNames) && !$update) { |
||||||
99 | return; |
||||||
100 | } |
||||||
101 | // need to clone here, to avoid getting new tags |
||||||
102 | $oldTags = \is_object($entityTags = $entity->getTags()) ? clone $entityTags : $entityTags; |
||||||
103 | $tagClassMetadata = $this->manager->getClassMetadata(\get_class($this->tag)); |
||||||
104 | $repository = $this->manager->getRepository(\get_class($this->tag)); |
||||||
105 | foreach ($tagNames as $tagName) { |
||||||
106 | $tag = $repository->findOneByName($tagName); |
||||||
0 ignored issues
–
show
The method
findOneByName() does not exist on Doctrine\Persistence\ObjectRepository . Did you maybe mean findOneBy() ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed.
Loading history...
|
|||||||
107 | if (empty($tag)) { |
||||||
108 | // if tag doesn't exist, create it |
||||||
109 | $tag = clone $this->tag; |
||||||
110 | $tag->setName($tagName); |
||||||
111 | $this->manager->persist($tag); |
||||||
112 | // see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#onflush |
||||||
113 | $this->uow->computeChangeSet($tagClassMetadata, $tag); |
||||||
114 | } |
||||||
115 | if (!$entity->hasTag($tag)) { |
||||||
116 | // add tag only if not already added |
||||||
117 | $entity->addTag($tag); |
||||||
118 | } |
||||||
119 | } |
||||||
120 | // if updating, need to check if some tags were removed |
||||||
121 | if ($update) { |
||||||
122 | foreach ($oldTags as $oldTag) { |
||||||
123 | if (!\in_array($oldTag->getName(), $tagNames)) { |
||||||
124 | $entity->removeTag($oldTag); |
||||||
125 | } |
||||||
126 | } |
||||||
127 | } |
||||||
128 | // see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#onflush |
||||||
129 | $entityClassMetadata = $this->manager->getClassMetadata(\get_class($entity)); |
||||||
130 | $this->uow->computeChangeSets($entityClassMetadata, $entity); |
||||||
131 | } |
||||||
132 | |||||||
133 | /** |
||||||
134 | * Purge oprhan tags |
||||||
135 | * Warning: DO NOT purge tags if you have more than one entity |
||||||
136 | * with tags, since this could lead to costraint violations. |
||||||
137 | */ |
||||||
138 | private function purgeTags(TaggableInterface $entity): void |
||||||
139 | { |
||||||
140 | foreach ($entity->getTags() as $oldTag) { |
||||||
141 | $this->manager->remove($oldTag); |
||||||
142 | } |
||||||
143 | } |
||||||
144 | } |
||||||
145 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths