Completed
Push — master ( 6d6774...64f3ed )
by Jeroen
11:23 queued 05:13
created

Helper/Services/PagePartCreatorService.php (5 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\PagePartBundle\Helper\Services;
4
5
use Doctrine\ORM\EntityManager;
6
use Doctrine\ORM\EntityManagerInterface;
7
use Kunstmaan\AdminBundle\Entity\EntityInterface;
8
use Kunstmaan\NodeBundle\Entity\Node;
9
use Kunstmaan\NodeBundle\Entity\NodeTranslation;
10
use Kunstmaan\NodeBundle\Repository\NodeRepository;
11
use Kunstmaan\NodeBundle\Repository\NodeTranslationRepository;
12
use Kunstmaan\PagePartBundle\Entity\PagePartRef;
13
use Kunstmaan\PagePartBundle\Entity\PageTemplateConfiguration;
14
use Kunstmaan\PagePartBundle\Helper\HasPagePartsInterface;
15
use Kunstmaan\PagePartBundle\Helper\HasPageTemplateInterface;
16
use Kunstmaan\PagePartBundle\Helper\PagePartInterface;
17
use Kunstmaan\PagePartBundle\Repository\PagePartRefRepository;
18
use Kunstmaan\PagePartBundle\Repository\PageTemplateConfigurationRepository;
19
use Kunstmaan\UtilitiesBundle\Helper\ClassLookup;
20
21
/**
22
 * A class to facilitate the adding of PageParts to existing pages.
23
 *
24
 * NOTE: There is a similar implementation for adding pages. See the NodeBundle for more on this.
25
 */
26
class PagePartCreatorService
27
{
28
    /**
29
     * @var EntityManagerInterface|EntityManager
30
     */
31
    protected $em;
32
33
    /**
34
     * @var PagePartRefRepository
35
     */
36
    protected $pagePartRepo;
37
38
    /**
39
     * @var NodeTranslationRepository
40
     */
41
    protected $translationRepo;
42
43
    /**
44
     * @var NodeRepository
45
     */
46
    protected $nodeRepo;
47
48
    /**
49
     * Sets the EntityManager dependency.
50
     *
51
     * @param EntityManagerInterface $em
52
     */
53
    public function setEntityManager(EntityManagerInterface $em)
54
    {
55
        $this->em = $em;
56
        // Because these repositories are shared between the different functions it's
57
        // easier to make them available in the class.
58
        $this->pagePartRepo = $em->getRepository(PagePartRef::class);
59
        $this->translationRepo = $em->getRepository(NodeTranslation::class);
60
        $this->nodeRepo = $em->getRepository(Node::class);
61
    }
62
63
    /**
64
     * @return EntityManagerInterface
65
     */
66
    public function getEntityManager()
67
    {
68
        return $this->em;
69
    }
70
71
    /**
72
     * Add a single pagepart to an existing page for a specific language, in an optional position.
73
     *
74
     * @param mixed(Node|string)  $nodeOrInternalName
0 ignored issues
show
The doc-type mixed(Node|string) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
75
     *                                                A Node instance or the internal name.
76
     *                                                When the internal name is passed we'll get the node instance.
77
     *                                                Based on the language we'll locate the correct Page instance.
78
     * @param pagePartInterface   $pagePart
79
     *                                                A completely configured pagepart for this language
80
     * @param string              $language
81
     *                                                The languagecode. nl|fr|en|.. . Just one.
82
     * @param string              $context
83
     *                                                Where you want the pagepart to be
84
     * @param mixed(integer\NULL) $position
0 ignored issues
show
The doc-type mixed(integer\NULL) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
85
     *                                                Leave null if you want to append at the end.
86
     *                                                Otherwise set a position you would like and it'll inject the pagepart in that position.
87
     *                                                It won't override pageparts but it will rather inject itself in that position and
88
     *                                                push the other pageparts down.
89
     */
90
    public function addPagePartToPage($nodeOrInternalName, PagePartInterface $pagePart, $language, $context = 'main', $position = null)
91
    {
92
        // Find the correct page instance.
93
        $node = $this->getNode($nodeOrInternalName);
94
        /** @var $translation NodeTranslation */
95
        $translation = $node->getNodeTranslation($language, true);
96
        /** @var HasPagePartsInterface $page */
97
        $page = $translation->getRef($this->em);
0 ignored issues
show
It seems like $this->em can also be of type object<Doctrine\ORM\EntityManagerInterface>; however, Kunstmaan\NodeBundle\Ent...deTranslation::getRef() does only seem to accept object<Doctrine\ORM\EntityManager>, 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...
98
99
        // Find latest position.
100 View Code Duplication
        if (\is_null($position)) {
101
            $pageParts = $this->pagePartRepo->getPagePartRefs($page, $context);
102
            $position = \count($pageParts) + 1;
103
        }
104
105
        $this->em->persist($pagePart);
106
        $this->em->flush();
107
108
        $this->pagePartRepo->addPagePart($page, $pagePart, $position, $context);
109
    }
110
111
    /**
112
     * A helper function to more easily append multiple pageparts in different manners.
113
     *
114
     * @param mixed(Node|string) $nodeOrInternalName
0 ignored issues
show
The doc-type mixed(Node|string) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
115
     *                                               The node that you'd like to append the pageparts to. It's also possible to provide an internalname.
116
     * @param array              $structure
117
     *                                               The structure array is something like this:
118
     *
119
     *      array('main' => array(
120
     *          function() { return new DummyPagePart('A') }, function() { return new DummyPagePart('B') }
121
     *       ), 'banners' => array($awesomeBanner));
122
     *
123
     *      So it's an array containing the pageparts per region. Each pagepart is returned by a function.
124
     *      This is clean because we don't have to bother with variablenames which we have to remember to pass
125
     *      to the pagecreatorservice at the right time. With this method it's impossible to assign a wrong pagepart to a page.
126
     *      Unless you provide the incorrect page oviously ... .
127
     *
128
     *      You can also include variables in the pagepart arrays if you want.
129
     *
130
     *      Or optionally you can use the results of the getCreatorArgumentsForPagePartAndProperties function instead of an anonymous function.
131
     * @param string $language
132
     *                         The language of the translation you want to append to
133
     *
134
     * @throws \LogicException
135
     */
136
    public function addPagePartsToPage($nodeOrInternalName, array $structure, $language)
137
    {
138
        $node = $this->getNode($nodeOrInternalName);
139
140
        // First instantiate all PageParts. This way no PageParts will be saved if there is an issue instantiating some of them.
141
        $instantiatedPageParts = array();
142
        foreach ($structure as $context => $pageParts) {
143
            $instantiatedPageParts[$context] = array();
144
145
            foreach ($pageParts as $pagePartOrFunction) {
146
                if (\is_callable($pagePartOrFunction)) {
147
                    $pagePartOrFunction = $pagePartOrFunction();
148
149
                    if (!isset($pagePartOrFunction) || is_null($pagePartOrFunction)) {
150
                        throw new \LogicException('A function returned nothing for a pagepart. Make sure you return your instantiated pageparts in your anonymous functions.');
151
                    }
152
                }
153
                if (!$pagePartOrFunction instanceof PagePartInterface) {
154
                    throw new \LogicException('Detected a supposed pagepart that did not implement the PagePartInterface.');
155
                }
156
157
                $instantiatedPageParts[$context][] = $pagePartOrFunction;
158
            }
159
        }
160
161
        // All good. We can start saving.
162
        foreach ($instantiatedPageParts as $context => $pageParts) {
163
            foreach ($pageParts as $pagePart) {
164
                $this->addPagePartToPage($node, $pagePart, $language, $context);
165
            }
166
        }
167
    }
168
169
    /**
170
     * @param mixed(Node|string) $nodeOrInternalName
171
     * @param string             $language
172
     * @param string             $templateName
173
     */
174
    public function setPageTemplate($nodeOrInternalName, $language, $templateName)
175
    {
176
        $node = $this->getNode($nodeOrInternalName);
177
        /** @var $translation NodeTranslation */
178
        $translation = $node->getNodeTranslation($language, true);
179
        /** @var HasPageTemplateInterface|EntityInterface $page */
180
        $page = $translation->getRef($this->em);
181
182
        /** @var PageTemplateConfigurationRepository $repo */
183
        $repo = $this->em->getRepository(PageTemplateConfiguration::class);
184
        $pageTemplateConfiguration = $repo->findFor($page);
185
        if ($pageTemplateConfiguration) {
186
            $pageTemplateConfiguration->setPageTemplate($templateName);
187
        } else {
188
            $pageTemplateConfiguration = new PageTemplateConfiguration();
189
            $pageTemplateConfiguration->setPageId($page->getId());
190
            $pageTemplateConfiguration->setPageEntityName(ClassLookup::getClass($page));
191
            $pageTemplateConfiguration->setPageTemplate($templateName);
192
        }
193
194
        $this->em->persist($pageTemplateConfiguration);
195
        $this->em->flush();
196
    }
197
198
    /**
199
     * A helper function to express what pagepart you want.
200
     *
201
     * It just accepts a classname and an array of setter functions with their requested values.
202
     *
203
     * It'll return an anonymous function which instantiates the pagepart.
204
     *
205
     * @param string $pagePartClassName the full class name of the pagepart you want to instantiate
206
     * @param array  $setters           An array of setternames and their values. array('setName' => 'Kim', 'isDeveloper' => true)
207
     *
208
     * @return callable the function that will instantiate a pagepart
209
     */
210
    public function getCreatorArgumentsForPagePartAndProperties($pagePartClassName, array $setters = null)
211
    {
212
        return function () use ($pagePartClassName, $setters) {
213
            $pp = new $pagePartClassName();
214
215
            if (!\is_null($setters)) {
216
                foreach ($setters as $setter => $value) {
217
                    \call_user_func(array($pp, $setter), $value);
218
                }
219
            }
220
221
            return $pp;
222
        };
223
    }
224
225
    /**
226
     * @param mixed(string|Node) $nodeOrInternalName
0 ignored issues
show
The doc-type mixed(string|Node) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
227
     *
228
     * @return object
229
     */
230
    private function getNode($nodeOrInternalName)
231
    {
232
        if (\is_string($nodeOrInternalName)) {
233
            return $this->nodeRepo->findOneBy(array('internalName' => $nodeOrInternalName));
234
        }
235
236
        return $nodeOrInternalName;
237
    }
238
}
239