methods do not contain too many execution paths.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Beelab\TagBundle\Listener; |
||
4 | |||
5 | use Beelab\TagBundle\Tag\TagInterface; |
||
6 | use Beelab\TagBundle\Tag\TaggableInterface; |
||
7 | use Doctrine\Common\EventSubscriber; |
||
8 | use Doctrine\Common\Persistence\Mapping\MappingException; |
||
9 | use Doctrine\ORM\Event\OnFlushEventArgs; |
||
10 | |||
11 | /** |
||
12 | * Add tags to entities that implements TaggableInterface. |
||
13 | */ |
||
14 | class TagSubscriber implements EventSubscriber |
||
15 | { |
||
16 | /** |
||
17 | * @var \Doctrine\ORM\EntityManager |
||
18 | */ |
||
19 | protected $manager; |
||
20 | |||
21 | /** |
||
22 | * @var \Doctrine\ORM\UnitOfWork |
||
23 | */ |
||
24 | protected $uow; |
||
25 | |||
26 | /** |
||
27 | * @var TagInterface |
||
28 | */ |
||
29 | protected $tag; |
||
30 | |||
31 | /** |
||
32 | * @var bool |
||
33 | */ |
||
34 | protected $purge; |
||
35 | |||
36 | /** |
||
37 | * Constructor. |
||
38 | * |
||
39 | * @param string $tagClassName |
||
40 | * @param bool $purge whether to delete tags when entity is deleted |
||
41 | */ |
||
42 | public function __construct(string $tagClassName, $purge = false) |
||
43 | { |
||
44 | if (!class_exists($tagClassName)) { |
||
45 | throw MappingException::nonExistingClass($tagClassName); |
||
46 | } |
||
47 | $this->tag = new $tagClassName(); |
||
48 | if (!$this->tag instanceof TagInterface) { |
||
49 | throw new \InvalidArgumentException(sprintf('Class "%s" must implement TagInterface.', $tagClassName)); |
||
50 | } |
||
51 | $this->purge = $purge; |
||
52 | } |
||
53 | |||
54 | /** |
||
55 | * {@inheritdoc} |
||
56 | */ |
||
57 | public function getSubscribedEvents() |
||
58 | { |
||
59 | return ['onFlush']; |
||
60 | } |
||
61 | |||
62 | /** |
||
63 | * Main method: call setTags() on entities scheduled to be inserted or updated, and |
||
64 | * possibly call purgeTags() on entities scheduled to be deleted. |
||
65 | * |
||
66 | * @param OnFlushEventArgs $args |
||
67 | */ |
||
68 | public function onFlush(OnFlushEventArgs $args) |
||
69 | { |
||
70 | $this->manager = $args->getEntityManager(); |
||
71 | $this->uow = $this->manager->getUnitOfWork(); |
||
72 | foreach ($this->uow->getScheduledEntityInsertions() as $key => $entity) { |
||
73 | if ($entity instanceof TaggableInterface) { |
||
74 | $this->setTags($entity, false); |
||
75 | } |
||
76 | } |
||
77 | foreach ($this->uow->getScheduledEntityUpdates() as $key => $entity) { |
||
78 | if ($entity instanceof TaggableInterface) { |
||
79 | $this->setTags($entity, true); |
||
80 | } |
||
81 | } |
||
82 | if ($this->purge) { |
||
83 | foreach ($this->uow->getScheduledEntityDeletions() as $key => $entity) { |
||
84 | if ($entity instanceof TaggableInterface) { |
||
85 | $this->purgeTags($entity); |
||
86 | } |
||
87 | } |
||
88 | } |
||
89 | } |
||
90 | |||
91 | /** |
||
92 | * Do the stuff. |
||
93 | * |
||
94 | * @param TaggableInterface $entity |
||
95 | * @param bool $update true if entity is being updated, false otherwise |
||
96 | */ |
||
97 | protected function setTags(TaggableInterface $entity, bool $update = false) |
||
0 ignored issues
–
show
|
|||
98 | { |
||
99 | $tagNames = $entity->getTagNames(); |
||
100 | if (empty($tagNames) && !$update) { |
||
101 | return; |
||
102 | } |
||
103 | // need to clone here, to avoid getting new tags |
||
104 | $oldTags = is_object($entityTags = $entity->getTags()) ? clone $entityTags : $entityTags; |
||
105 | $tagClassMetadata = $this->manager->getClassMetadata(get_class($this->tag)); |
||
106 | $repository = $this->manager->getRepository(get_class($this->tag)); |
||
107 | foreach ($tagNames as $tagName) { |
||
108 | $tag = $repository->findOneByName($tagName); |
||
109 | if (empty($tag)) { |
||
110 | // if tag doesn't exist, create it |
||
111 | $tag = clone $this->tag; |
||
112 | $tag->setName($tagName); |
||
113 | $this->manager->persist($tag); |
||
114 | // see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#onflush |
||
115 | $this->uow->computeChangeSet($tagClassMetadata, $tag); |
||
116 | } |
||
117 | if (!$entity->hasTag($tag)) { |
||
118 | // add tag only if not already added |
||
119 | $entity->addTag($tag); |
||
120 | } |
||
121 | } |
||
122 | // if updating, need to check if some tags were removed |
||
123 | if ($update) { |
||
124 | foreach ($oldTags as $oldTag) { |
||
125 | if (!in_array($oldTag->getName(), $tagNames)) { |
||
126 | $entity->removeTag($oldTag); |
||
127 | } |
||
128 | } |
||
129 | } |
||
130 | // see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#onflush |
||
131 | $entityClassMetadata = $this->manager->getClassMetadata(get_class($entity)); |
||
132 | $this->uow->computeChangeSets($entityClassMetadata, $entity); |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * Purge oprhan tags |
||
137 | * Warning: DO NOT purge tags if you have more than one entity |
||
138 | * with tags, since this could lead to costraint violations. |
||
139 | * |
||
140 | * @param TaggableInterface $entity |
||
141 | */ |
||
142 | protected function purgeTags(TaggableInterface $entity) |
||
143 | { |
||
144 | foreach ($entity->getTags() as $oldTag) { |
||
145 | $this->manager->remove($oldTag); |
||
146 | } |
||
147 | } |
||
148 | } |
||
149 |
A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.
You can also find more information in the “Code” section of your repository.