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

Kunstmaan/FixturesBundle/Builder/PageBuilder.php (3 issues)

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')
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
This method seems to be duplicated in 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...
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