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

Helper/Services/PagePartCreatorService.php (1 issue)

duplicate/similar code.

Duplication Informational

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\NodeTranslation;
9
use Kunstmaan\NodeBundle\Repository\NodeRepository;
10
use Kunstmaan\NodeBundle\Repository\NodeTranslationRepository;
11
use Kunstmaan\PagePartBundle\Entity\PageTemplateConfiguration;
12
use Kunstmaan\PagePartBundle\Helper\HasPagePartsInterface;
13
use Kunstmaan\PagePartBundle\Helper\HasPageTemplateInterface;
14
use Kunstmaan\PagePartBundle\Helper\PagePartInterface;
15
use Kunstmaan\PagePartBundle\Repository\PagePartRefRepository;
16
use Kunstmaan\PagePartBundle\Repository\PageTemplateConfigurationRepository;
17
use Kunstmaan\UtilitiesBundle\Helper\ClassLookup;
18
19
/**
20
 * A class to facilitate the adding of PageParts to existing pages.
21
 *
22
 * NOTE: There is a similar implementation for adding pages. See the NodeBundle for more on this.
23
 */
24
class PagePartCreatorService
25
{
26
    /**
27
     * @var EntityManagerInterface|EntityManager
28
     */
29
    protected $em;
30
31
    /**
32
     * @var PagePartRefRepository
33
     */
34
    protected $pagePartRepo;
35
36
    /**
37
     * @var NodeTranslationRepository
38
     */
39
    protected $translationRepo;
40
41
    /**
42
     * @var NodeRepository
43
     */
44
    protected $nodeRepo;
45
46
    /**
47
     * Sets the EntityManager dependency.
48
     *
49
     * @param EntityManagerInterface $em
50
     */
51
    public function setEntityManager(EntityManagerInterface $em)
52
    {
53
        $this->em = $em;
54
        // Because these repositories are shared between the different functions it's
55
        // easier to make them available in the class.
56
        $this->pagePartRepo = $em->getRepository('KunstmaanPagePartBundle:PagePartRef');
57
        $this->translationRepo = $em->getRepository('KunstmaanNodeBundle:NodeTranslation');
58
        $this->nodeRepo = $em->getRepository('KunstmaanNodeBundle:Node');
59
    }
60
61
    /**
62
     * @return EntityManagerInterface
63
     */
64
    public function getEntityManager()
65
    {
66
        return $this->em;
67
    }
68
69
    /**
70
     * Add a single pagepart to an existing page for a specific language, in an optional position.
71
     *
72
     * @param mixed(Node|string)  $nodeOrInternalName
73
     *                                                A Node instance or the internal name.
74
     *                                                When the internal name is passed we'll get the node instance.
75
     *                                                Based on the language we'll locate the correct Page instance.
76
     * @param pagePartInterface   $pagePart
77
     *                                                A completely configured pagepart for this language
78
     * @param string              $language
79
     *                                                The languagecode. nl|fr|en|.. . Just one.
80
     * @param string              $context
81
     *                                                Where you want the pagepart to be
82
     * @param mixed(integer\NULL) $position
83
     *                                                Leave null if you want to append at the end.
84
     *                                                Otherwise set a position you would like and it'll inject the pagepart in that position.
85
     *                                                It won't override pageparts but it will rather inject itself in that position and
86
     *                                                push the other pageparts down.
87
     */
88
    public function addPagePartToPage($nodeOrInternalName, PagePartInterface $pagePart, $language, $context = 'main', $position = null)
89
    {
90
        // Find the correct page instance.
91
        $node = $this->getNode($nodeOrInternalName);
92
        /** @var $translation NodeTranslation */
93
        $translation = $node->getNodeTranslation($language, true);
94
        /** @var HasPagePartsInterface $page */
95
        $page = $translation->getRef($this->em);
96
97
        // Find latest position.
98 View Code Duplication
        if (\is_null($position)) {
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...
99
            $pageParts = $this->pagePartRepo->getPagePartRefs($page, $context);
100
            $position = \count($pageParts) + 1;
101
        }
102
103
        $this->em->persist($pagePart);
104
        $this->em->flush();
105
106
        $this->pagePartRepo->addPagePart($page, $pagePart, $position, $context);
107
    }
108
109
    /**
110
     * A helper function to more easily append multiple pageparts in different manners.
111
     *
112
     * @param mixed(Node|string) $nodeOrInternalName
113
     *                                               The node that you'd like to append the pageparts to. It's also possible to provide an internalname.
114
     * @param array              $structure
115
     *                                               The structure array is something like this:
116
     *
117
     *      array('main' => array(
118
     *          function() { return new DummyPagePart('A') }, function() { return new DummyPagePart('B') }
119
     *       ), 'banners' => array($awesomeBanner));
120
     *
121
     *      So it's an array containing the pageparts per region. Each pagepart is returned by a function.
122
     *      This is clean because we don't have to bother with variablenames which we have to remember to pass
123
     *      to the pagecreatorservice at the right time. With this method it's impossible to assign a wrong pagepart to a page.
124
     *      Unless you provide the incorrect page oviously ... .
125
     *
126
     *      You can also include variables in the pagepart arrays if you want.
127
     *
128
     *      Or optionally you can use the results of the getCreatorArgumentsForPagePartAndProperties function instead of an anonymous function.
129
     * @param string $language
130
     *                         The language of the translation you want to append to
131
     *
132
     * @throws \LogicException
133
     */
134
    public function addPagePartsToPage($nodeOrInternalName, array $structure, $language)
135
    {
136
        $node = $this->getNode($nodeOrInternalName);
137
138
        // First instantiate all PageParts. This way no PageParts will be saved if there is an issue instantiating some of them.
139
        $instantiatedPageParts = array();
140
        foreach ($structure as $context => $pageParts) {
141
            $instantiatedPageParts[$context] = array();
142
143
            foreach ($pageParts as $pagePartOrFunction) {
144
                if (\is_callable($pagePartOrFunction)) {
145
                    $pagePartOrFunction = $pagePartOrFunction();
146
147
                    if (!isset($pagePartOrFunction) || is_null($pagePartOrFunction)) {
148
                        throw new \LogicException('A function returned nothing for a pagepart. Make sure you return your instantiated pageparts in your anonymous functions.');
149
                    }
150
                }
151
                if (!$pagePartOrFunction instanceof PagePartInterface) {
152
                    throw new \LogicException('Detected a supposed pagepart that did not implement the PagePartInterface.');
153
                }
154
155
                $instantiatedPageParts[$context][] = $pagePartOrFunction;
156
            }
157
        }
158
159
        // All good. We can start saving.
160
        foreach ($instantiatedPageParts as $context => $pageParts) {
161
            foreach ($pageParts as $pagePart) {
162
                $this->addPagePartToPage($node, $pagePart, $language, $context);
163
            }
164
        }
165
    }
166
167
    /**
168
     * @param mixed(Node|string) $nodeOrInternalName
169
     * @param string             $language
170
     * @param string             $templateName
171
     */
172
    public function setPageTemplate($nodeOrInternalName, $language, $templateName)
173
    {
174
        $node = $this->getNode($nodeOrInternalName);
175
        /** @var $translation NodeTranslation */
176
        $translation = $node->getNodeTranslation($language, true);
177
        /** @var HasPageTemplateInterface|EntityInterface $page */
178
        $page = $translation->getRef($this->em);
179
180
        /** @var PageTemplateConfigurationRepository $repo */
181
        $repo = $this->em->getRepository('KunstmaanPagePartBundle:PageTemplateConfiguration');
182
        $pageTemplateConfiguration = $repo->findFor($page);
183
        if ($pageTemplateConfiguration) {
184
            $pageTemplateConfiguration->setPageTemplate($templateName);
185
        } else {
186
            $pageTemplateConfiguration = new PageTemplateConfiguration();
187
            $pageTemplateConfiguration->setPageId($page->getId());
188
            $pageTemplateConfiguration->setPageEntityName(ClassLookup::getClass($page));
189
            $pageTemplateConfiguration->setPageTemplate($templateName);
190
        }
191
192
        $this->em->persist($pageTemplateConfiguration);
193
        $this->em->flush();
194
    }
195
196
    /**
197
     * A helper function to express what pagepart you want.
198
     *
199
     * It just accepts a classname and an array of setter functions with their requested values.
200
     *
201
     * It'll return an anonymous function which instantiates the pagepart.
202
     *
203
     * @param string $pagePartClassName the full class name of the pagepart you want to instantiate
204
     * @param array  $setters           An array of setternames and their values. array('setName' => 'Kim', 'isDeveloper' => true)
205
     *
206
     * @return callable the function that will instantiate a pagepart
207
     */
208
    public function getCreatorArgumentsForPagePartAndProperties($pagePartClassName, array $setters = null)
209
    {
210
        return function () use ($pagePartClassName, $setters) {
211
            $pp = new $pagePartClassName();
212
213
            if (!\is_null($setters)) {
214
                foreach ($setters as $setter => $value) {
215
                    \call_user_func(array($pp, $setter), $value);
216
                }
217
            }
218
219
            return $pp;
220
        };
221
    }
222
223
    /**
224
     * @param mixed(string|Node) $nodeOrInternalName
225
     *
226
     * @return object
227
     */
228
    private function getNode($nodeOrInternalName)
229
    {
230
        if (\is_string($nodeOrInternalName)) {
231
            return $this->nodeRepo->findOneBy(array('internalName' => $nodeOrInternalName));
232
        }
233
234
        return $nodeOrInternalName;
235
    }
236
}
237