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