Completed
Push — master ( d861b1...95c183 )
by Jeroen
22:16 queued 07:16
created

PageCreatorService::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 0
cts 4
cp 0
rs 9.9332
c 0
b 0
f 0
cc 2
nc 2
nop 3
crap 6
1
<?php
2
3
namespace Kunstmaan\NodeBundle\Helper\Services;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use Doctrine\ORM\ORMException;
7
use Kunstmaan\AdminBundle\Repository\UserRepository;
8
use Kunstmaan\NodeBundle\Entity\HasNodeInterface;
9
use Kunstmaan\NodeBundle\Entity\Node;
10
use Kunstmaan\NodeBundle\Entity\NodeTranslation;
11
use Kunstmaan\NodeBundle\Repository\NodeRepository;
12
use Kunstmaan\PagePartBundle\Helper\HasPagePartsInterface;
13
use Kunstmaan\SeoBundle\Entity\Seo;
14
use Kunstmaan\SeoBundle\Repository\SeoRepository;
15
use Symfony\Component\DependencyInjection\ContainerInterface;
16
17
/**
18
 * Service to create new pages.
19
 */
20
class PageCreatorService
21
{
22
    /** @var EntityManagerInterface */
23
    protected $entityManager;
24
25
    /** @var ACLPermissionCreatorService */
26
    protected $aclPermissionCreatorService;
27
28
    /** @var string */
29
    protected $userEntityClass;
30
31
    public function __construct(EntityManagerInterface $em = null, ACLPermissionCreatorService $aclPermissionCreatorService = null, string $userEntityClass = null)
32
    {
33
        if (null === $em) {
34
            @trigger_error(sprintf('Not injecting the required dependencies in the constructor of "%s" is deprecated since KunstmaanNodeBundle 5.7 and will be required in KunstmaanNodeBundle 6.0.', __CLASS__), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
35
        }
36
37
        $this->entityManager = $em;
38
        $this->aclPermissionCreatorService = $aclPermissionCreatorService;
39
        $this->userEntityClass = $userEntityClass;
40
    }
41
42
    /**
43
     * @deprecated since KunstmaanNodeBundle 5.7 and will be removed in KunstmaanNodeBundle 6.0. Inject the required dependencies in the constructor instead.
44
     */
45
    public function setEntityManager($entityManager)
46
    {
47
        @trigger_error(sprintf('Using the "%s" method is deprecated since KunstmaanNodeBundle 5.7 and will be removed in KunstmaanNodeBundle 6.0. Inject the required dependencies in the constructor instead.', __METHOD__), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
48
49
        $this->entityManager = $entityManager;
50
    }
51
52
    /**
53
     * @deprecated since KunstmaanNodeBundle 5.7 and will be removed in KunstmaanNodeBundle 6.0. Inject the required dependencies in the constructor instead.
54
     */
55
    public function setACLPermissionCreatorService($aclPermissionCreatorService)
56
    {
57
        @trigger_error(sprintf('Using the "%s" method is deprecated since KunstmaanNodeBundle 5.7 and will be removed in KunstmaanNodeBundle 6.0. Inject the required dependencies in the constructor instead.', __METHOD__), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
58
59
        $this->aclPermissionCreatorService = $aclPermissionCreatorService;
60
    }
61
62
    /**
63
     * @deprecated since KunstmaanNodeBundle 5.7 and will be removed in KunstmaanNodeBundle 6.0. Inject the required dependencies in the constructor instead.
64
     */
65
    public function setUserEntityClass($userEntityClass)
66
    {
67
        @trigger_error(sprintf('Using the "%s" method is deprecated since KunstmaanNodeBundle 5.7 and will be removed in KunstmaanNodeBundle 6.0. Inject the required dependencies in the constructor instead.', __METHOD__), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
68
69
        $this->userEntityClass = $userEntityClass;
70
    }
71
72
    /**
73
     * Sets the Container. This is still here for backwards compatibility.
74
     *
75
     * The ContainerAwareInterface has been removed so the container won't be injected automatically.
76
     * This function is just there for code that calls it manually.
77
     *
78
     * @param ContainerInterface $container a ContainerInterface instance
0 ignored issues
show
Documentation introduced by
Should the type for parameter $container not be null|ContainerInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
79
     *
80
     * @deprecated since KunstmaanNodeBundle 5.7 and will be removed in KunstmaanNodeBundle 6.0. Inject the required dependencies in the constructor instead.
81
     *
82
     * @api
83
     */
84
    public function setContainer(ContainerInterface $container = null)
85
    {
86
        @trigger_error(sprintf('Using the "%s" method is deprecated since KunstmaanNodeBundle 5.7 and will be removed in KunstmaanNodeBundle 6.0. Inject the required dependencies in the constructor instead.', __METHOD__), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
87
88
        $this->setEntityManager($container->get('doctrine.orm.entity_manager'));
0 ignored issues
show
Bug introduced by
It seems like $container is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
Deprecated Code introduced by
The method Kunstmaan\NodeBundle\Hel...ice::setEntityManager() has been deprecated with message: since KunstmaanNodeBundle 5.7 and will be removed in KunstmaanNodeBundle 6.0. Inject the required dependencies in the constructor instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
89
        $this->setACLPermissionCreatorService($container->get('kunstmaan_node.acl_permission_creator_service'));
0 ignored issues
show
Deprecated Code introduced by
The method Kunstmaan\NodeBundle\Hel...missionCreatorService() has been deprecated with message: since KunstmaanNodeBundle 5.7 and will be removed in KunstmaanNodeBundle 6.0. Inject the required dependencies in the constructor instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
90
        $this->setUserEntityClass($container->getParameter('fos_user.model.user.class'));
0 ignored issues
show
Deprecated Code introduced by
The method Kunstmaan\NodeBundle\Hel...e::setUserEntityClass() has been deprecated with message: since KunstmaanNodeBundle 5.7 and will be removed in KunstmaanNodeBundle 6.0. Inject the required dependencies in the constructor instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
91
    }
92
93
    /**
94
     * @param HasNodeInterface $pageTypeInstance the page
95
     * @param array            $translations     Containing arrays. Sample:
96
     *                                           [
97
     *                                           [   "language" => "nl",
98
     *                                           "callback" => function($page, $translation) {
99
     *                                           $translation->setTitle('NL titel');
100
     *                                           }
101
     *                                           ],
102
     *                                           [   "language" => "fr",
103
     *                                           "callback" => function($page, $translation) {
104
     *                                           $translation->setTitle('FR titel');
105
     *                                           }
106
     *                                           ]
107
     *                                           ]
108
     *                                           Perhaps it's cleaner when you create one array and append another array for each language.
109
     * @param array            $options          Possible options:
110
     *                                           parent: type node, nodetransation or page.
111
     *                                           page_internal_name: string. name the page will have in the database.
112
     *                                           set_online: bool. if true the page will be set as online after creation.
113
     *                                           hidden_from_nav: bool. if true the page will not be show in the navigation
114
     *                                           creator: username
115
     *
116
     * Automatically calls the ACL + sets the slugs to empty when the page is an Abstract node.
117
     *
118
     * @return Node the new node for the page
0 ignored issues
show
Documentation introduced by
Should the return type not be Node|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
119
     *
120
     * @throws \InvalidArgumentException
121
     */
122
    public function createPage(HasNodeInterface $pageTypeInstance, array $translations, array $options = array())
123
    {
124
        if (\is_null($options)) {
125
            $options = array();
126
        }
127
128
        if (\is_null($translations) || (\count($translations) == 0)) {
129
            throw new \InvalidArgumentException('There has to be at least 1 translation in the translations array');
130
        }
131
132
        $em = $this->entityManager;
133
134
        /** @var NodeRepository $nodeRepo */
135
        $nodeRepo = $em->getRepository(Node::class);
136
        /** @var UserRepository $userRepo */
137
        $userRepo = $em->getRepository($this->userEntityClass);
138
        /* @var SeoRepository $seoRepo */
139
        try {
140
            $seoRepo = $em->getRepository(Seo::class);
141
        } catch (ORMException $e) {
142
            $seoRepo = null;
143
        }
144
145
        $pagecreator = \array_key_exists('creator', $options) ? $options['creator'] : 'pagecreator';
146
147
        if ($pagecreator instanceof $this->userEntityClass) {
148
            $creator = $pagecreator;
149
        } else {
150
            $creator = $userRepo->findOneBy(array('username' => $pagecreator));
151
        }
152
153
        $parent = isset($options['parent']) ? $options['parent'] : null;
154
155
        $pageInternalName = isset($options['page_internal_name']) ? $options['page_internal_name'] : null;
156
157
        $setOnline = isset($options['set_online']) ? $options['set_online'] : false;
158
159
        // We need to get the language of the first translation so we can create the rootnode.
160
        // This will also create a translationnode for that language attached to the rootnode.
161
        $first = true;
162
        $rootNode = null;
163
164
        /* @var \Kunstmaan\NodeBundle\Repository\NodeTranslationRepository $nodeTranslationRepo*/
165
        $nodeTranslationRepo = $em->getRepository(NodeTranslation::class);
166
167
        foreach ($translations as $translation) {
168
            $language = $translation['language'];
169
            $callback = $translation['callback'];
170
171
            $translationNode = null;
0 ignored issues
show
Unused Code introduced by
$translationNode is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
172
            if ($first) {
173
                $first = false;
174
175
                $em->persist($pageTypeInstance);
176
                $em->flush($pageTypeInstance);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $pageTypeInstance.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
177
178
                // Fetch the translation instead of creating it.
179
                // This returns the rootnode.
180
                $rootNode = $nodeRepo->createNodeFor($pageTypeInstance, $language, $creator, $pageInternalName);
181
182
                if (\array_key_exists('hidden_from_nav', $options)) {
183
                    $rootNode->setHiddenFromNav($options['hidden_from_nav']);
184
                }
185
186
                if (!\is_null($parent)) {
187
                    if ($parent instanceof HasPagePartsInterface) {
188
                        $parent = $nodeRepo->getNodeFor($parent);
0 ignored issues
show
Documentation introduced by
$parent is of type object<Kunstmaan\PagePar...\HasPagePartsInterface>, but the function expects a object<Kunstmaan\NodeBun...ntity\HasNodeInterface>.

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...
189
                    }
190
                    $rootNode->setParent($parent);
191
                }
192
193
                $em->persist($rootNode);
194
                $em->flush($rootNode);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $rootNode.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
195
196
                $translationNode = $rootNode->getNodeTranslation($language, true);
197
            } else {
198
                // Clone the $pageTypeInstance.
199
                $pageTypeInstance = clone $pageTypeInstance;
200
201
                $em->persist($pageTypeInstance);
202
                $em->flush($pageTypeInstance);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $pageTypeInstance.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
203
204
                // Create the translationnode.
205
                $translationNode = $nodeTranslationRepo->createNodeTranslationFor($pageTypeInstance, $language, $rootNode, $creator);
206
            }
207
208
            // Make SEO.
209
            $seo = null;
210
211
            if (!\is_null($seoRepo)) {
212
                $seo = $seoRepo->findOrCreateFor($pageTypeInstance);
213
            }
214
215
            $callback($pageTypeInstance, $translationNode, $seo);
216
217
            // Overwrite the page title with the translated title
218
            $pageTypeInstance->setTitle($translationNode->getTitle());
219
            $em->persist($pageTypeInstance);
220
            $em->persist($translationNode);
221
            $em->flush($pageTypeInstance);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $pageTypeInstance.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
222
            $em->flush($translationNode);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $translationNode.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
223
224
            $translationNode->setOnline($setOnline);
225
226
            if (!\is_null($seo)) {
227
                $em->persist($seo);
228
                $em->flush($seo);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $seo.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
229
            }
230
231
            $em->persist($translationNode);
232
            $em->flush($translationNode);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $translationNode.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
233
        }
234
235
        // ACL
236
        $this->aclPermissionCreatorService->createPermission($rootNode);
0 ignored issues
show
Bug introduced by
It seems like $rootNode defined by null on line 162 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...
237
238
        return $rootNode;
239
    }
240
}
241