Completed
Push — master ( aba493...5356ed )
by Ruud
315:38 queued 305:00
created

Kunstmaan/FixturesBundle/Builder/PageBuilder.php (1 issue)

Upgrade to new PHP Analysis Engine

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 Kunstmaan\FixturesBundle\Builder;
4
5
use Doctrine\ORM\EntityManager;
6
use Kunstmaan\FixturesBundle\Loader\Fixture;
7
use Kunstmaan\FixturesBundle\Populator\Populator;
8
use Kunstmaan\NodeBundle\Entity\HasNodeInterface;
9
use Kunstmaan\NodeBundle\Entity\Node;
10
use Kunstmaan\NodeBundle\Entity\NodeTranslation;
11
use Kunstmaan\NodeBundle\Entity\NodeVersion;
12
use Kunstmaan\NodeBundle\Entity\StructureNode;
13
use Kunstmaan\NodeBundle\Helper\PagesConfiguration;
14
use Kunstmaan\NodeBundle\Helper\Services\ACLPermissionCreatorService;
15
use Kunstmaan\PagePartBundle\Entity\PageTemplateConfiguration;
16
use Kunstmaan\UtilitiesBundle\Helper\ClassLookup;
17
use Kunstmaan\UtilitiesBundle\Helper\Slugifier;
18
19
class PageBuilder implements BuilderInterface
20
{
21
    private $manager;
22
23
    private $userRepo;
24
25
    private $nodeRepo;
26
27
    private $nodeTranslationRepo;
28
29
    private $aclPermissionCreatorService;
30
31
    private $populator;
32
33
    private $slugifier;
34
35
    /**
36
     * @var PagesConfiguration
37
     */
38
    private $pagesConfiguration;
39
40
    public function __construct(
41
        EntityManager $em,
0 ignored issues
show
You have injected the EntityManager via parameter $em. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
42
        ACLPermissionCreatorService $aclPermissionCreatorService,
43
        Populator $populator,
44
        Slugifier $slugifier,
45
        PagesConfiguration $pagesConfiguration
46
    ) {
47
        $this->manager = $em;
48
        $this->nodeRepo = $em->getRepository('KunstmaanNodeBundle:Node');
49
        $this->nodeTranslationRepo = $em->getRepository('KunstmaanNodeBundle:NodeTranslation');
50
        $this->userRepo = $em->getRepository('KunstmaanAdminBundle:User');
51
        $this->aclPermissionCreatorService = $aclPermissionCreatorService;
52
        $this->populator = $populator;
53
        $this->slugifier = $slugifier;
54
        $this->pagesConfiguration = $pagesConfiguration;
55
    }
56
57
    public function canBuild(Fixture $fixture)
58
    {
59
        if ($fixture->getEntity() instanceof HasNodeInterface) {
60
            return true;
61
        }
62
63
        return false;
64
    }
65
66
    public function preBuild(Fixture $fixture)
67
    {
68
        return;
69
    }
70
71
    public function postBuild(Fixture $fixture)
72
    {
73
        $entity = $fixture->getEntity();
74
        $fixtureParams = $fixture->getParameters();
75
        $translations = $fixture->getTranslations();
76 View Code Duplication
        if (empty($translations)) {
77
            throw new \Exception('No translations detected for page fixture ' . $fixture->getName() . ' (' . $fixture->getClass() . ')');
78
        }
79
80
        $internalName = array_key_exists('page_internal_name', $fixtureParams) ?
81
            $fixtureParams['page_internal_name'] : null;
82
83
        $rootNode = null;
84
        foreach ($fixture->getTranslations() as $language => $data) {
85
            if ($rootNode === null) {
86
                $page = $entity;
87
                $rootNode = $this->createRootNode($page, $language, $internalName, $fixtureParams);
88
                $this->manager->persist($rootNode);
89
            } else {
90
                $cloned = clone $entity;
91
                $page = $cloned;
92
                $this->manager->persist($page);
93
            }
94
95
            // Create the translationNode.
96
            $translationNode = $this->createTranslationNode($rootNode, $language, $page);
97
            if (!$page instanceof StructureNode) {
98
                $translationNode->setOnline(isset($fixtureParams['set_online']) ? $fixtureParams['set_online'] : true);
99
            }
100
101
            $fixture->addAdditional($fixture->getName() . '_' . $language, $page);
102
            $fixture->addAdditional('translationNode_' . $language, $translationNode);
103
            $fixture->addAdditional('nodeVersion_' . $language, $translationNode->getPublicNodeVersion());
104
            $fixture->addAdditional('rootNode', $rootNode);
105
106
            $this->populator->populate($translationNode, $data);
107
            $this->populator->populate($page, $data);
108 View Code Duplication
            if ($translationNode->getSlug() === null && $rootNode->getParent() !== null) {
109
                $translationNode->setSlug($this->slugifier->slugify($translationNode->getTitle()));
110
            }
111
            $this->ensureUniqueUrl($translationNode, $page);
112
113
            $this->manager->persist($translationNode);
114
            $rootNode->addNodeTranslation($translationNode);
115
        }
116
117
        $this->manager->flush();
118
        $this->aclPermissionCreatorService->createPermission($rootNode);
119
    }
120
121
    public function postFlushBuild(Fixture $fixture)
122
    {
123
        $entities = $fixture->getAdditionalEntities();
124
        $fixtureParams = $fixture->getParameters();
125
126
        foreach ($fixture->getTranslations() as $language => $data) {
127
            /** @var HasNodeInterface $page */
128
            $page = $entities[$fixture->getName() . '_' . $language];
129
            /** @var NodeTranslation $translationNode */
130
            $translationNode = $entities['translationNode_' . $language];
131
132
            $pagecreator = array_key_exists('creator', $fixtureParams) ? $fixtureParams['creator'] : 'pagecreator';
133
            $creator = $this->userRepo->findOneBy(array('username' => $pagecreator));
134
135
            $nodeVersion = new NodeVersion();
136
            $nodeVersion->setNodeTranslation($translationNode);
137
            $nodeVersion->setType('public');
138
            $nodeVersion->setOwner($creator);
139
            $nodeVersion->setRef($page);
140
141
            $translationNode->setPublicNodeVersion($nodeVersion);
142
143
            if (isset($fixtureParams['template'])) {
144
                $pageTemplateConfiguration = new PageTemplateConfiguration();
145
                $pageTemplateConfiguration->setPageId($page->getId());
146
                $pageTemplateConfiguration->setPageEntityName(ClassLookup::getClass($page));
147
                $pageTemplateConfiguration->setPageTemplate($fixtureParams['template']);
148
                $this->manager->persist($pageTemplateConfiguration);
149
            }
150
151
            $this->manager->persist($nodeVersion);
152
            $this->manager->persist($translationNode);
153
        }
154
        $this->manager->flush();
155
    }
156
157
    private function getParentNode($params, $language)
158
    {
159
        if (!isset($params['parent'])) {
160
            return;
161
        }
162
163
        $parent = $params['parent'];
164
        if ($parent instanceof Fixture) {
165
            $additionals = $parent->getAdditionalEntities();
166
            $parent = $additionals['rootNode'];
167
        } elseif (is_string($parent)) {
168
            $nodes = $this->nodeRepo->getNodesByInternalName($parent, $language, false, true);
169
            if (count($nodes) > 0) {
170
                $parent = $nodes[0];
171
            }
172
        }
173
174
        return $parent;
175
    }
176
177
    private function createRootNode($page, $language, $internalName, $fixtureParams)
178
    {
179
        $rootNode = new Node();
180
        $rootNode->setRef($page);
181
        $rootNode->setDeleted(false);
182
        $rootNode->setInternalName($internalName);
183
        $rootNode->setHiddenFromNav(
184
            isset($fixtureParams['hidden_from_nav']) ? $fixtureParams['hidden_from_nav'] : false
185
        );
186
        $parent = $this->getParentNode($fixtureParams, $language);
187
188
        if ($parent instanceof Node) {
189
            $rootNode->setParent($parent);
190
191
            if (!$this->canHaveChild($parent->getRefEntityName(), get_class($page))) {
192
                throw new \Exception(
193
                    sprintf('A %s can\'t have a %s as child. Forgot to add in allowed_children or getPossibleChildTypes?', $parent->getRefEntityName(), get_class($page))
194
                );
195
            }
196
        }
197
198
        return $rootNode;
199
    }
200
201
    private function createTranslationNode(Node $rootNode, $language, HasNodeInterface $page)
202
    {
203
        $translationNode = new NodeTranslation();
204
        $translationNode
205
            ->setNode($rootNode)
206
            ->setLang($language)
207
            ->setTitle($page->getTitle())
208
            ->setOnline(false)
209
            ->setWeight(0);
210
211
        return $translationNode;
212
    }
213
214
    private function ensureUniqueUrl(NodeTranslation $translation, HasNodeInterface $page)
215
    {
216
        if ($page instanceof StructureNode) {
217
            $translation->setSlug('');
218
            $translation->setUrl($translation->getFullSlug());
219
220
            return $translation;
221
        }
222
223
        $translation->setUrl($translation->getFullSlug());
224
225
        // Find all translations with this new URL, whose nodes are not deleted.
226
        $translationWithSameUrl = $this->nodeTranslationRepo->getNodeTranslationForUrl($translation->getUrl(), $translation->getLang(), false, $translation);
227
228
        if ($translationWithSameUrl instanceof NodeTranslation) {
229
            $translation->setSlug($this->slugifier->slugify($this->incrementString($translation->getSlug())));
230
            $this->ensureUniqueUrl($translation, $page);
231
        }
232
233
        return $translation;
234
    }
235
236 View Code Duplication
    private function incrementString($string, $append = '-v')
237
    {
238
        $finalDigitGrabberRegex = '/\d+$/';
239
        $matches = array();
240
241
        preg_match($finalDigitGrabberRegex, $string, $matches);
242
243
        if (count($matches) > 0) {
244
            $digit = (int) $matches[0];
245
            ++$digit;
246
247
            // Replace the integer with the new digit.
248
            return preg_replace($finalDigitGrabberRegex, $digit, $string);
249
        } else {
250
            return $string . $append . '1';
251
        }
252
    }
253
254
    /**
255
     * @param string $parentPageClass
256
     * @param string $childPageClass
257
     *
258
     * @return bool
259
     */
260
    private function canHaveChild($parentPageClass, $childPageClass)
261
    {
262
        $childTypes = $this->pagesConfiguration->getPossibleChildTypes($parentPageClass);
263
264
        foreach ($childTypes as $childType) {
265
            if ($childType['class'] == $childPageClass) {
266
                return true;
267
            }
268
        }
269
270
        return false;
271
    }
272
}
273