Passed
Push — master ( cc68cc...50453a )
by Julito
09:11
created

ResourceListener::setLinks()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 29
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 20
c 0
b 0
f 0
nc 8
nop 3
dl 0
loc 29
rs 8.6666
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
namespace Chamilo\CoreBundle\Entity\Listener;
6
7
use Chamilo\CoreBundle\Entity\AbstractResource;
8
use Chamilo\CoreBundle\Entity\AccessUrl;
9
use Chamilo\CoreBundle\Entity\Course;
10
use Chamilo\CoreBundle\Entity\ResourceFile;
11
use Chamilo\CoreBundle\Entity\ResourceLink;
12
use Chamilo\CoreBundle\Entity\ResourceNode;
13
use Chamilo\CoreBundle\Entity\ResourceRight;
14
use Chamilo\CoreBundle\Entity\ResourceToRootInterface;
15
use Chamilo\CoreBundle\Entity\ResourceType;
16
use Chamilo\CoreBundle\Entity\ResourceWithUrlInterface;
17
use Chamilo\CoreBundle\Entity\Session;
18
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
19
use Chamilo\CoreBundle\ToolChain;
20
use Cocur\Slugify\SlugifyInterface;
21
use Doctrine\ORM\Event\LifecycleEventArgs;
22
use Doctrine\ORM\Event\PreUpdateEventArgs;
23
use Symfony\Component\HttpFoundation\File\File;
24
use Symfony\Component\HttpFoundation\File\UploadedFile;
25
use Symfony\Component\HttpFoundation\RequestStack;
26
use Symfony\Component\Security\Core\Security;
27
28
/**
29
 * Class ResourceListener.
30
 */
31
class ResourceListener
32
{
33
    protected $slugify;
34
    protected $request;
35
    protected $accessUrl;
36
37
    /**
38
     * ResourceListener constructor.
39
     */
40
    public function __construct(
41
        SlugifyInterface $slugify,
42
        ToolChain $toolChain,
43
        RequestStack $request,
44
        Security $security
45
    ) {
46
        $this->slugify = $slugify;
47
        $this->security = $security;
48
        $this->toolChain = $toolChain;
49
        $this->request = $request;
50
        $this->accessUrl = null;
51
    }
52
53
    public function getAccessUrl($em)
54
    {
55
        if (null === $this->accessUrl) {
56
            $request = $this->request->getCurrentRequest();
57
            if (null === $request) {
58
                throw new \Exception('An Request is needed');
59
            }
60
            $sessionRequest = $request->getSession();
61
62
            if (null === $sessionRequest) {
63
                throw new \Exception('An Session request is needed');
64
            }
65
66
            $id = $sessionRequest->get('access_url_id');
67
            $url = $em->getRepository('ChamiloCoreBundle:AccessUrl')->find($id);
68
69
            if ($url) {
70
                $this->accessUrl = $url;
71
72
                return $url;
73
            }
74
        }
75
76
        if (null === $this->accessUrl) {
77
            throw new \Exception('An AccessUrl is needed');
78
        }
79
80
        return $this->accessUrl;
81
    }
82
83
    public function prePersist(AbstractResource $resource, LifecycleEventArgs $event)
84
    {
85
        error_log('resource listener prePersist for obj: '.get_class($resource));
86
        $em = $event->getEntityManager();
87
        $request = $this->request;
88
89
        $url = null;
90
        if ($resource instanceof ResourceWithUrlInterface) {
91
            $url = $this->getAccessUrl($em);
92
            $resource->addUrl($url);
93
        }
94
95
        if ($resource->hasResourceNode()) {
96
            // This will attach the resource to the main resource node root (For example a Course).
97
            if ($resource instanceof ResourceToRootInterface) {
98
                $url = $this->getAccessUrl($em);
99
                $resource->getResourceNode()->setParent($url->getResourceNode());
100
            }
101
            error_log('resource has already a resource node. Do nothing');
102
            // Do not override resource node, it's already added.
103
            return true;
104
        }
105
106
        // Add resource node
107
        $creator = $this->security->getUser();
108
109
        if (null === $creator) {
110
            throw new \InvalidArgumentException('User creator not found');
111
        }
112
113
        $resourceNode = new ResourceNode();
114
        $resource->setResourceNode($resourceNode);
115
        $this->updateResourceName($resource);
116
        $resourceName = $resource->getResourceName();
117
118
        // @todo use static table instead of Doctrine
119
        $repo = $em->getRepository(ResourceType::class);
120
        $class = str_replace('Entity', 'Repository', get_class($event->getEntity()));
121
        $class .= 'Repository';
122
        $name = $this->toolChain->getResourceTypeNameFromRepository($class);
123
        $resourceType = $repo->findOneBy(['name' => $name]);
124
125
        if (null === $resourceType) {
126
            throw new \InvalidArgumentException('ResourceType not found');
127
        }
128
129
        $resourceNode
130
            ->setCreator($creator)
131
            ->setResourceType($resourceType)
132
        ;
133
134
        // Add resource directly to the resource node root (Example: for a course resource).
135
        if ($resource instanceof ResourceToRootInterface) {
136
            $url = $this->getAccessUrl($em);
137
            $resourceNode->setParent($url->getResourceNode());
138
        }
139
140
        if ($resource->hasParentResourceNode()) {
141
            $nodeRepo = $em->getRepository(ResourceNode::class);
142
            $parent = $nodeRepo->find($resource->getParentResourceNode());
143
            $resourceNode->setParent($parent);
144
        }
145
146
        if ($resource->hasUploadFile()) {
147
            // @todo check CreateResourceNodeFileAction
148
            /** @var File $uploadedFile */
149
            $uploadedFile = $request->getCurrentRequest()->files->get('uploadFile');
150
151
            if (empty($uploadedFile)) {
152
                $content = $request->getCurrentRequest()->get('contentFile');
153
                $title = $resourceName.'.html';
154
                $handle = tmpfile();
155
                fwrite($handle, $content);
156
                $meta = stream_get_meta_data($handle);
157
                $uploadedFile = new UploadedFile($meta['uri'], $title, 'text/html', null, true);
158
            }
159
160
            // File upload
161
            if ($uploadedFile instanceof UploadedFile) {
162
                $resourceFile = new ResourceFile();
163
                $resourceFile->setName($uploadedFile->getFilename());
164
                $resourceFile->setOriginalName($uploadedFile->getFilename());
165
                $resourceFile->setFile($uploadedFile);
166
                $em->persist($resourceFile);
167
                $resourceNode->setResourceFile($resourceFile);
168
            }
169
        }
170
171
        // Use by api platform
172
        $links = $resource->getResourceLinkArray();
173
174
        if ($links) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $links of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
175
            $courseRepo = $em->getRepository(Course::class);
176
            $sessionRepo = $em->getRepository(Session::class);
177
178
            foreach ($links as $link) {
179
                $resourceLink = new ResourceLink();
180
                if (isset($link['c_id']) && !empty($link['c_id'])) {
181
                    $course = $courseRepo->find($link['c_id']);
182
                    if ($course) {
183
                        $resourceLink->setCourse($course);
184
                    } else {
185
                        throw new \InvalidArgumentException(sprintf('Course #%s does not exists', $link['c_id']));
186
                    }
187
                }
188
189
                if (isset($link['session_id']) && !empty($link['session_id'])) {
190
                    $session = $sessionRepo->find($link['session_id']);
191
                    if ($session) {
192
                        $resourceLink->setSession($session);
193
                    } else {
194
                        throw new \InvalidArgumentException(sprintf('Session #%s does not exists', $link['session_id']));
195
                    }
196
                }
197
198
                if (isset($link['visibility'])) {
199
                    $resourceLink->setVisibility((int) $link['visibility']);
200
                } else {
201
                    throw new \InvalidArgumentException('Link needs a visibility key');
202
                }
203
204
                $resourceLink->setResourceNode($resourceNode);
205
                $em->persist($resourceLink);
206
            }
207
        }
208
209
        // Use by Chamilo.
210
        $this->setLinks($resourceNode, $resource, $em);
211
212
        if (null !== $resource->getParent()) {
213
            $resourceNode->setParent($resource->getParent()->getResourceNode());
214
        }
215
216
        error_log('Listener end, adding resource node');
217
        $resource->setResourceNode($resourceNode);
218
219
        // All resources should have a parent, except AccessUrl.
220
        if (!($resource instanceof AccessUrl)) {
221
            if (null == $resourceNode->getParent()) {
222
                throw new \InvalidArgumentException('Resource Node should have a parent');
223
            }
224
        }
225
226
        return $resourceNode;
227
    }
228
229
    /**
230
     * When updating a Resource.
231
     */
232
    public function preUpdate(AbstractResource $resource, PreUpdateEventArgs $event)
233
    {
234
        error_log('Resource listener preUpdate');
235
        if ($resource->hasUploadFile()) {
236
            $uploadedFile = $resource->getUploadFile();
237
238
            // File upload
239
            if ($uploadedFile instanceof UploadedFile) {
240
                /*$resourceFile = new ResourceFile();
241
                $resourceFile->setName($uploadedFile->getFilename());
242
                $resourceFile->setOriginalName($uploadedFile->getFilename());
243
                $resourceFile->setFile($uploadedFile);
244
                $em->persist($resourceFile);*/
245
                //$resourceNode->setResourceFile($uploadedFile);
246
            }
247
        }
248
    }
249
250
    public function postUpdate(AbstractResource $resource, LifecycleEventArgs $event)
251
    {
252
        //error_log('resource listener postUpdate');
253
        //$em = $event->getEntityManager();
254
        //$this->updateResourceName($resource, $resource->getResourceName(), $em);
255
    }
256
257
    public function updateResourceName(AbstractResource $resource)
258
    {
259
        $resourceName = $resource->getResourceName();
260
261
        if (empty($resourceName)) {
262
            throw new \InvalidArgumentException('Resource needs a name');
263
        }
264
265
        $extension = $this->slugify->slugify(pathinfo($resourceName, PATHINFO_EXTENSION));
266
        if (empty($extension)) {
267
            //$slug = $this->slugify->slugify($resourceName);
268
        } else {
269
            /*$originalExtension = pathinfo($resourceName, PATHINFO_EXTENSION);
270
            $originalBasename = \basename($resourceName, $originalExtension);
271
            $slug = sprintf('%s.%s', $this->slugify->slugify($originalBasename), $originalExtension);*/
272
        }
273
274
        $resource->getResourceNode()->setTitle($resourceName);
275
    }
276
277
    public function setLinks($resourceNode, AbstractResource $resource, $em)
278
    {
279
        $links = $resource->getResourceLinkEntityList();
280
        if ($links) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $links of type Chamilo\CoreBundle\Entity\ResourceLink[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
281
            foreach ($links as $link) {
282
                $link->setResourceNode($resourceNode);
283
284
                $rights = [];
285
                switch ($link->getVisibility()) {
286
                    case ResourceLink::VISIBILITY_PENDING:
287
                    case ResourceLink::VISIBILITY_DRAFT:
288
                        $editorMask = ResourceNodeVoter::getEditorMask();
289
                        $resourceRight = new ResourceRight();
290
                        $resourceRight
291
                            ->setMask($editorMask)
292
                            ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
293
                        ;
294
                        $rights[] = $resourceRight;
295
296
                        break;
297
                }
298
299
                if (!empty($rights)) {
300
                    foreach ($rights as $right) {
301
                        $link->addResourceRight($right);
302
                    }
303
                }
304
                $em->persist($resourceNode);
305
                $em->persist($link);
306
            }
307
        }
308
    }
309
}
310