Completed
Pull Request — master (#290)
by Leny
06:14
created

ViewReferenceSubscriber::postUpdate()   C

Complexity

Conditions 8
Paths 5

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 23
rs 6.1404
cc 8
eloc 12
nc 5
nop 1
1
<?php
2
3
namespace Victoire\Bundle\ViewReferenceBundle\EventSubscriber;
4
5
use Doctrine\Common\EventSubscriber;
6
use Doctrine\ORM\EntityManager;
7
use Doctrine\ORM\Event\LifecycleEventArgs;
8
use Doctrine\ORM\Event\OnFlushEventArgs;
9
use Doctrine\ORM\Event\PostFlushEventArgs;
10
use Doctrine\ORM\Events;
11
use Doctrine\ORM\UnitOfWork;
12
use Victoire\Bundle\BusinessEntityBundle\Helper\BusinessEntityHelper;
13
use Victoire\Bundle\BusinessPageBundle\Builder\BusinessPageBuilder;
14
use Victoire\Bundle\BusinessPageBundle\Entity\BusinessPage;
15
use Victoire\Bundle\BusinessPageBundle\Entity\BusinessTemplate;
16
use Victoire\Bundle\CoreBundle\Entity\View;
17
use Victoire\Bundle\ViewReferenceBundle\Cache\Xml\ViewReferenceXmlCacheDriver;
18
use Victoire\Bundle\ViewReferenceBundle\Cache\Xml\ViewReferenceXmlCacheManager;
19
use Victoire\Bundle\ViewReferenceBundle\Helper\ViewReferenceHelper;
20
use Victoire\Bundle\ViewReferenceBundle\Provider\ViewReferenceProvider;
21
22
/**
23
 * Tracks if a slug changed and re-compute the view cache
24
 * ref: victoire_view_reference.event_subscriber.
25
 */
26
class ViewReferenceSubscriber implements EventSubscriber
27
{
28
    protected $viewCacheManager;
29
    protected $viewCacheDriver;
30
    protected $businessPageBuilder;
31
    protected $viewReferenceProvider;
32
    protected $viewReferenceHelper;
33
    protected $insertedEntities = [];
34
    protected $updatedEntities = [];
35
    protected $deletedEntities = [];
36
    protected $flushedEntities = [];
37
38
    /**
39
     * @param ViewReferenceXmlCacheManager $viewCacheManager
40
     * @param ViewReferenceXmlCacheDriver  $viewCacheDriver
41
     * @param BusinessPageBuilder          $businessPageBuilder
42
     * @param ViewReferenceProvider        $viewReferenceProvider
43
     * @param ViewReferenceHelper          $viewReferenceHelper
44
     * @param BusinessEntityHelper         $businessEntityHelper
45
     */
46
    public function __construct(ViewReferenceXmlCacheManager $viewCacheManager,
47
                                ViewReferenceXmlCacheDriver  $viewCacheDriver,
48
                                BusinessPageBuilder          $businessPageBuilder,
49
                                ViewReferenceProvider        $viewReferenceProvider,
50
                                ViewReferenceHelper          $viewReferenceHelper,
51
                                BusinessEntityHelper         $businessEntityHelper
52
    ) {
53
        $this->viewCacheManager = $viewCacheManager;
54
        $this->viewCacheDriver = $viewCacheDriver;
55
        $this->businessPageBuilder = $businessPageBuilder;
56
        $this->viewReferenceProvider = $viewReferenceProvider;
57
        $this->viewReferenceHelper = $viewReferenceHelper;
58
        $this->businessEntityHelper = $businessEntityHelper;
0 ignored issues
show
Bug introduced by
The property businessEntityHelper does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
59
    }
60
61
    /**
62
     * @return string[]
63
     */
64
    public function getSubscribedEvents()
65
    {
66
        return [
67
            Events::onFlush,
68
            Events::postFlush,
69
            Events::postUpdate,
70
        ];
71
    }
72
73
    /**
74
     * Will rebuild url if needed and update cache.
75
     *
76
     * @param PostFlushEventArgs $eventArgs
77
     */
78
    public function postUpdate(LifecycleEventArgs $eventArgs)
79
    {
80
        /** @var EntityManager $entityManager */
81
        $entityManager = $eventArgs->getEntityManager();
82
        /** @var UnitOfWork $uow */
83
        $uow = $entityManager->getUnitOfWork();
84
85
        foreach ($uow->getScheduledEntityUpdates() as $entity) {
86
            if ($entity instanceof BusinessTemplate) {
87
                if (((array_key_exists('slug', $uow->getEntityChangeSet($entity)) //the slug of the page has been modified
88
                    || array_key_exists('staticUrl', $uow->getEntityChangeSet($entity))
89
                    || array_key_exists('parent', $uow->getEntityChangeSet($entity))
90
                    || array_key_exists('template', $uow->getEntityChangeSet($entity)))
91
                )) {
92
                    // Get BusinessPages of the given BusinessTemplate
93
                    $inheritors = $entityManager->getRepository('Victoire\Bundle\BusinessPageBundle\Entity\BusinessPage')->findBy(['Template' => $entity]);
94
                    foreach ($inheritors as $instance) {
95
                        $this->updateBusinessPageUrl($instance, $entityManager, $uow);
96
                    }
97
                }
98
            }
99
        }
100
    }
101
102
    /**
103
     * @param OnFlushEventArgs $eventArgs
104
     */
105
    public function onFlush(OnFlushEventArgs $eventArgs)
106
    {
107
        $uow = $eventArgs->getEntityManager()->getUnitOfWork();
108
109 View Code Duplication
        foreach ($uow->getScheduledEntityInsertions() as $entity) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
110
            //If entity is a BusinessEntity or just a view
111
            if ($this->businessEntityHelper->findByEntityInstance($entity) || $entity instanceof View) {
112
                $this->flushedEntities[] = $entity;
113
                $this->insertedEntities[] = $entity;
114
                break;
115
            }
116
        }
117
118 View Code Duplication
        foreach ($uow->getScheduledEntityUpdates() as $entity) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
119
            //If entity is a BusinessEntity or just a view
120
            if ($this->businessEntityHelper->findByEntityInstance($entity) || $entity instanceof View) {
121
                $this->updatedEntities[] = $entity;
122
                $this->flushedEntities[] = $entity;
123
                break;
124
            }
125
        }
126
127 View Code Duplication
        foreach ($uow->getScheduledEntityDeletions() as $entity) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
128
            //If entity is a BusinessEntity or just a view
129
            if ($this->businessEntityHelper->findByEntityInstance($entity) || $entity instanceof View) {
130
                $this->deletedEntities[] = $entity;
131
                $this->flushedEntities[] = $entity;
132
                break;
133
            }
134
        }
135
    }
136
137
    /**
138
     * @param PostFlushEventArgs $eventArgs
139
     */
140
    public function postFlush(PostFlushEventArgs $eventArgs)
141
    {
142
        if (count($this->flushedEntities)) {
143
            $this->rebuildViewsReferenceCache($eventArgs);
144
        }
145
    }
146
147
    /**
148
     * Manage urls.
149
     *
150
     * @param View $page
151
     *
152
     * @return void
153
     */
154
    protected function updateBusinessPageUrl(BusinessPage $page, EntityManager $em, UnitOfWork $uow)
155
    {
156
        $oldSlug = $page->getSlug();
157
        $staticUrl = $page->getStaticUrl();
158
        $computedPage = $this->businessPageBuilder->generateEntityPageFromTemplate($page->getTemplate(), $page->getBusinessEntity(), $em);
0 ignored issues
show
Documentation introduced by
$page->getTemplate() is of type string, but the function expects a object<Victoire\Bundle\B...ntity\BusinessTemplate>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
159
        $newSlug = $computedPage->getSlug();
160
161 View Code Duplication
        if ($staticUrl) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
162
            $staticUrl = preg_replace('/'.$oldSlug.'/', $newSlug, $staticUrl);
163
            $page->setStaticUrl($staticUrl);
0 ignored issues
show
Bug introduced by
It seems like $staticUrl defined by preg_replace('/' . $oldS..., $newSlug, $staticUrl) on line 162 can also be of type array<integer,string>; however, Victoire\Bundle\Business...essPage::setStaticUrl() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
164
        }
165
        $page->setSlug($newSlug);
166
        $meta = $em->getClassMetadata(get_class($page));
167
        $em->persist($page);
168
        $uow->computeChangeSet($meta, $page);
169
    }
170
171
    /**
172
     * @param PostFlushEventArgs $eventArgs
173
     */
174
    protected function rebuildViewsReferenceCache(PostFlushEventArgs $eventArgs)
175
    {
176
        //Rebuild viewsReferences xml cache
177
        /** @var EntityManager $entityManager */
178
        $entityManager = $eventArgs->getEntityManager();
179
        $viewRepository = $entityManager->getRepository('VictoireCoreBundle:View');
180
        $tree = $viewRepository->getRootNodes();
181
182
        $insertFunc = function ($views, $toInsert) use (&$insertFunc) {
183
            foreach ($views as $_view) {
184
                if ($toInsert->getParent() === $_view) {
185
                    $_view->addChild($toInsert);
186
                    break;
187
                }
188
                $insertFunc($_view->getChildren(), $toInsert);
189
            }
190
        };
191
192
        foreach ($this->insertedEntities as $_insertedEntity) {
193
            if ($_insertedEntity instanceof View) {
194
                $insertFunc($tree, $_insertedEntity);
195
            }
196
        }
197
198
        $views = $this->viewReferenceProvider->getReferencableViews($tree, $entityManager);
199
        $this->viewReferenceHelper->buildViewReferenceRecursively($views, $entityManager);
200
201
        $this->viewCacheDriver->writeFile(
202
            $this->viewCacheManager->generateXml($views)
203
        );
204
        //End of viewsReferences xml cache rebuild
205
    }
206
}
207