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

Kunstmaan/FixturesBundle/Builder/PageBuilder.php (4 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,
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)) {
0 ignored issues
show
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...
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);
0 ignored issues
show
It seems like $rootNode defined by null on line 83 can be null; however, Kunstmaan\NodeBundle\Hel...ice::createPermission() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
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);
0 ignored issues
show
$creator is of type object|null, but the function expects a string.

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...
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)
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...
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