1 | <?php |
||||
2 | |||||
3 | /* For licensing terms, see /license.txt */ |
||||
4 | |||||
5 | use Chamilo\CoreBundle\Component\Utils\ChamiloApi; |
||||
6 | use Chamilo\CoreBundle\Entity\Course as CourseEntity; |
||||
7 | use Chamilo\CoreBundle\Entity\ExtraField as ExtraFieldEntity; |
||||
8 | use Chamilo\CoreBundle\Entity\ExtraFieldRelTag; |
||||
9 | use Chamilo\CoreBundle\Entity\Portfolio; |
||||
10 | use Chamilo\CoreBundle\Entity\PortfolioAttachment; |
||||
11 | use Chamilo\CoreBundle\Entity\PortfolioCategory; |
||||
12 | use Chamilo\CoreBundle\Entity\PortfolioComment; |
||||
13 | use Chamilo\UserBundle\Entity\User; |
||||
14 | use Doctrine\ORM\Query\Expr\Join; |
||||
15 | use Symfony\Component\Filesystem\Filesystem; |
||||
16 | use Symfony\Component\HttpFoundation\Request as HttpRequest; |
||||
0 ignored issues
–
show
|
|||||
17 | |||||
18 | /** |
||||
19 | * Class PortfolioController. |
||||
20 | */ |
||||
21 | class PortfolioController |
||||
22 | { |
||||
23 | /** |
||||
24 | * @var string |
||||
25 | */ |
||||
26 | public $baseUrl; |
||||
27 | /** |
||||
28 | * @var CourseEntity|null |
||||
29 | */ |
||||
30 | private $course; |
||||
31 | /** |
||||
32 | * @var \Chamilo\CoreBundle\Entity\Session|null |
||||
33 | */ |
||||
34 | private $session; |
||||
35 | /** |
||||
36 | * @var \Chamilo\UserBundle\Entity\User |
||||
37 | */ |
||||
38 | private $owner; |
||||
39 | /** |
||||
40 | * @var \Doctrine\ORM\EntityManager |
||||
41 | */ |
||||
42 | private $em; |
||||
43 | |||||
44 | /** |
||||
45 | * PortfolioController constructor. |
||||
46 | */ |
||||
47 | public function __construct() |
||||
48 | { |
||||
49 | $this->em = Database::getManager(); |
||||
50 | |||||
51 | $this->owner = api_get_user_entity(api_get_user_id()); |
||||
52 | $this->course = api_get_course_entity(api_get_course_int_id()); |
||||
53 | $this->session = api_get_session_entity(api_get_session_id()); |
||||
54 | |||||
55 | $cidreq = api_get_cidreq(); |
||||
56 | $this->baseUrl = api_get_self().'?'.($cidreq ? $cidreq.'&' : ''); |
||||
57 | } |
||||
58 | |||||
59 | /** |
||||
60 | * @throws \Doctrine\ORM\ORMException |
||||
61 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
62 | */ |
||||
63 | public function addCategory() |
||||
64 | { |
||||
65 | global $interbreadcrumb; |
||||
66 | |||||
67 | Display::addFlash( |
||||
68 | Display::return_message(get_lang('PortfolioCategoryFieldHelp'), 'info') |
||||
69 | ); |
||||
70 | |||||
71 | $form = new FormValidator('add_category', 'post', "{$this->baseUrl}&action=add_category"); |
||||
72 | |||||
73 | if (api_get_configuration_value('save_titles_as_html')) { |
||||
74 | $form->addHtmlEditor('title', get_lang('Title'), true, false, ['ToolbarSet' => 'TitleAsHtml']); |
||||
75 | } else { |
||||
76 | $form->addText('title', get_lang('Title')); |
||||
77 | $form->applyFilter('title', 'trim'); |
||||
78 | } |
||||
79 | |||||
80 | $form->addHtmlEditor('description', get_lang('Description'), false, false, ['ToolbarSet' => 'Minimal']); |
||||
81 | $form->addButtonCreate(get_lang('Create')); |
||||
82 | |||||
83 | if ($form->validate()) { |
||||
84 | $values = $form->exportValues(); |
||||
85 | |||||
86 | $category = new PortfolioCategory(); |
||||
87 | $category |
||||
88 | ->setTitle($values['title']) |
||||
89 | ->setDescription($values['description']) |
||||
90 | ->setUser($this->owner); |
||||
91 | |||||
92 | $this->em->persist($category); |
||||
93 | $this->em->flush(); |
||||
94 | |||||
95 | Display::addFlash( |
||||
96 | Display::return_message(get_lang('CategoryAdded'), 'success') |
||||
97 | ); |
||||
98 | |||||
99 | header("Location: {$this->baseUrl}"); |
||||
100 | exit; |
||||
101 | } |
||||
102 | |||||
103 | $interbreadcrumb[] = [ |
||||
104 | 'name' => get_lang('Portfolio'), |
||||
105 | 'url' => $this->baseUrl, |
||||
106 | ]; |
||||
107 | |||||
108 | $actions = []; |
||||
109 | $actions[] = Display::url( |
||||
110 | Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM), |
||||
111 | $this->baseUrl |
||||
112 | ); |
||||
113 | |||||
114 | $content = $form->returnForm(); |
||||
115 | |||||
116 | $this->renderView($content, get_lang('AddCategory'), $actions); |
||||
117 | } |
||||
118 | |||||
119 | /** |
||||
120 | * @throws \Doctrine\ORM\ORMException |
||||
121 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
122 | * @throws \Exception |
||||
123 | */ |
||||
124 | public function editCategory(PortfolioCategory $category) |
||||
125 | { |
||||
126 | global $interbreadcrumb; |
||||
127 | |||||
128 | if (!$this->categoryBelongToOwner($category)) { |
||||
129 | api_not_allowed(true); |
||||
130 | } |
||||
131 | |||||
132 | Display::addFlash( |
||||
133 | Display::return_message(get_lang('PortfolioCategoryFieldHelp'), 'info') |
||||
134 | ); |
||||
135 | |||||
136 | $form = new FormValidator( |
||||
137 | 'edit_category', |
||||
138 | 'post', |
||||
139 | $this->baseUrl."action=edit_category&id={$category->getId()}" |
||||
140 | ); |
||||
141 | |||||
142 | if (api_get_configuration_value('save_titles_as_html')) { |
||||
143 | $form->addHtmlEditor('title', get_lang('Title'), true, false, ['ToolbarSet' => 'TitleAsHtml']); |
||||
144 | } else { |
||||
145 | $form->addText('title', get_lang('Title')); |
||||
146 | $form->applyFilter('title', 'trim'); |
||||
147 | } |
||||
148 | |||||
149 | $form->addHtmlEditor('description', get_lang('Description'), false, false, ['ToolbarSet' => 'Minimal']); |
||||
150 | $form->addButtonUpdate(get_lang('Update')); |
||||
151 | $form->setDefaults( |
||||
152 | [ |
||||
153 | 'title' => $category->getTitle(), |
||||
154 | 'description' => $category->getDescription(), |
||||
155 | ] |
||||
156 | ); |
||||
157 | |||||
158 | if ($form->validate()) { |
||||
159 | $values = $form->exportValues(); |
||||
160 | |||||
161 | $category |
||||
162 | ->setTitle($values['title']) |
||||
163 | ->setDescription($values['description']); |
||||
164 | |||||
165 | $this->em->persist($category); |
||||
166 | $this->em->flush(); |
||||
167 | |||||
168 | Display::addFlash( |
||||
169 | Display::return_message(get_lang('Updated'), 'success') |
||||
170 | ); |
||||
171 | |||||
172 | header("Location: $this->baseUrl"); |
||||
173 | exit; |
||||
174 | } |
||||
175 | |||||
176 | $interbreadcrumb[] = [ |
||||
177 | 'name' => get_lang('Portfolio'), |
||||
178 | 'url' => $this->baseUrl, |
||||
179 | ]; |
||||
180 | |||||
181 | $actions = []; |
||||
182 | $actions[] = Display::url( |
||||
183 | Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM), |
||||
184 | $this->baseUrl |
||||
185 | ); |
||||
186 | |||||
187 | $content = $form->returnForm(); |
||||
188 | |||||
189 | $this->renderView($content, get_lang('EditCategory'), $actions); |
||||
190 | } |
||||
191 | |||||
192 | /** |
||||
193 | * @throws \Doctrine\ORM\ORMException |
||||
194 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
195 | */ |
||||
196 | public function showHideCategory(PortfolioCategory $category) |
||||
197 | { |
||||
198 | if (!$this->categoryBelongToOwner($category)) { |
||||
199 | api_not_allowed(true); |
||||
200 | } |
||||
201 | |||||
202 | $category->setIsVisible(!$category->isVisible()); |
||||
203 | |||||
204 | $this->em->persist($category); |
||||
205 | $this->em->flush(); |
||||
206 | |||||
207 | Display::addFlash( |
||||
208 | Display::return_message(get_lang('VisibilityChanged'), 'success') |
||||
209 | ); |
||||
210 | |||||
211 | header("Location: $this->baseUrl"); |
||||
212 | exit; |
||||
213 | } |
||||
214 | |||||
215 | /** |
||||
216 | * @throws \Doctrine\ORM\ORMException |
||||
217 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
218 | */ |
||||
219 | public function deleteCategory(PortfolioCategory $category) |
||||
220 | { |
||||
221 | if (!$this->categoryBelongToOwner($category)) { |
||||
222 | api_not_allowed(true); |
||||
223 | } |
||||
224 | |||||
225 | $this->em->remove($category); |
||||
226 | $this->em->flush(); |
||||
227 | |||||
228 | Display::addFlash( |
||||
229 | Display::return_message(get_lang('CategoryDeleted'), 'success') |
||||
230 | ); |
||||
231 | |||||
232 | header("Location: $this->baseUrl"); |
||||
233 | exit; |
||||
234 | } |
||||
235 | |||||
236 | /** |
||||
237 | * @throws \Doctrine\ORM\ORMException |
||||
238 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
239 | * @throws \Doctrine\ORM\TransactionRequiredException |
||||
240 | * @throws \Exception |
||||
241 | */ |
||||
242 | public function addItem() |
||||
243 | { |
||||
244 | global $interbreadcrumb; |
||||
245 | |||||
246 | $categories = $this->em |
||||
247 | ->getRepository('ChamiloCoreBundle:PortfolioCategory') |
||||
248 | ->findBy(['user' => $this->owner]); |
||||
249 | |||||
250 | $form = new FormValidator('add_portfolio', 'post', $this->baseUrl.'action=add_item'); |
||||
251 | |||||
252 | if (api_get_configuration_value('save_titles_as_html')) { |
||||
253 | $form->addHtmlEditor('title', get_lang('Title'), true, false, ['ToolbarSet' => 'TitleAsHtml']); |
||||
254 | } else { |
||||
255 | $form->addText('title', get_lang('Title')); |
||||
256 | $form->applyFilter('title', 'trim'); |
||||
257 | } |
||||
258 | |||||
259 | $form->addHtmlEditor('content', get_lang('Content'), true, false, ['ToolbarSet' => 'NotebookStudent']); |
||||
260 | $form->addSelectFromCollection( |
||||
261 | 'category', |
||||
262 | [get_lang('Category'), get_lang('PortfolioCategoryFieldHelp')], |
||||
263 | $categories, |
||||
264 | [], |
||||
265 | true |
||||
266 | ); |
||||
267 | |||||
268 | $extraField = new ExtraField('portfolio'); |
||||
269 | $extra = $extraField->addElements($form); |
||||
270 | |||||
271 | $this->addAttachmentsFieldToForm($form); |
||||
272 | |||||
273 | $form->addButtonCreate(get_lang('Create')); |
||||
274 | |||||
275 | if ($form->validate()) { |
||||
276 | $values = $form->exportValues(); |
||||
277 | $currentTime = new DateTime( |
||||
278 | api_get_utc_datetime(), |
||||
279 | new DateTimeZone('UTC') |
||||
280 | ); |
||||
281 | |||||
282 | $portfolio = new Portfolio(); |
||||
283 | $portfolio |
||||
284 | ->setTitle($values['title']) |
||||
285 | ->setContent($values['content']) |
||||
286 | ->setUser($this->owner) |
||||
287 | ->setCourse($this->course) |
||||
288 | ->setSession($this->session) |
||||
289 | ->setCategory( |
||||
290 | $this->em->find('ChamiloCoreBundle:PortfolioCategory', $values['category']) |
||||
291 | ) |
||||
292 | ->setCreationDate($currentTime) |
||||
293 | ->setUpdateDate($currentTime); |
||||
294 | |||||
295 | $this->em->persist($portfolio); |
||||
296 | $this->em->flush(); |
||||
297 | |||||
298 | $values['item_id'] = $portfolio->getId(); |
||||
299 | |||||
300 | $extraFieldValue = new ExtraFieldValue('portfolio'); |
||||
301 | $extraFieldValue->saveFieldValues($values); |
||||
302 | |||||
303 | $this->processAttachments( |
||||
304 | $form, |
||||
305 | $portfolio->getUser(), |
||||
306 | $portfolio->getId(), |
||||
307 | PortfolioAttachment::TYPE_ITEM |
||||
308 | ); |
||||
309 | |||||
310 | $hook = HookPortfolioItemAdded::create(); |
||||
311 | $hook->setEventData(['portfolio' => $portfolio]); |
||||
312 | $hook->notifyItemAdded(); |
||||
313 | |||||
314 | if (1 == api_get_course_setting('email_alert_teachers_new_post')) { |
||||
315 | if ($this->session) { |
||||
316 | $messageCourseTitle = "{$this->course->getTitle()} ({$this->session->getName()})"; |
||||
0 ignored issues
–
show
The method
getTitle() does not exist on null .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed.
Loading history...
|
|||||
317 | |||||
318 | $teachers = SessionManager::getCoachesByCourseSession( |
||||
319 | $this->session->getId(), |
||||
320 | $this->course->getId() |
||||
321 | ); |
||||
322 | $userIdListToSend = array_values($teachers); |
||||
323 | } else { |
||||
324 | $messageCourseTitle = $this->course->getTitle(); |
||||
325 | |||||
326 | $teachers = CourseManager::get_teacher_list_from_course_code($this->course->getCode()); |
||||
327 | |||||
328 | $userIdListToSend = array_keys($teachers); |
||||
329 | } |
||||
330 | |||||
331 | $messageSubject = sprintf(get_lang('PortfolioAlertNewPostSubject'), $messageCourseTitle); |
||||
332 | |||||
333 | foreach ($userIdListToSend as $userIdToSend) { |
||||
334 | $messageContent = sprintf( |
||||
335 | get_lang('PortfolioAlertNewPostContent'), |
||||
336 | $this->owner->getCompleteName(), |
||||
337 | $messageCourseTitle, |
||||
338 | $this->baseUrl.http_build_query(['action' => 'view', 'id' => $portfolio->getId()]) |
||||
339 | ); |
||||
340 | |||||
341 | MessageManager::send_message_simple($userIdToSend, $messageSubject, $messageContent, 0, false, false, [], false); |
||||
342 | } |
||||
343 | } |
||||
344 | |||||
345 | Display::addFlash( |
||||
346 | Display::return_message(get_lang('PortfolioItemAdded'), 'success') |
||||
347 | ); |
||||
348 | |||||
349 | header("Location: $this->baseUrl"); |
||||
350 | exit; |
||||
351 | } |
||||
352 | |||||
353 | $interbreadcrumb[] = [ |
||||
354 | 'name' => get_lang('Portfolio'), |
||||
355 | 'url' => $this->baseUrl, |
||||
356 | ]; |
||||
357 | |||||
358 | $actions = []; |
||||
359 | $actions[] = Display::url( |
||||
360 | Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM), |
||||
361 | $this->baseUrl |
||||
362 | ); |
||||
363 | |||||
364 | $content = $form->returnForm(); |
||||
365 | |||||
366 | $this->renderView( |
||||
367 | $content."<script> $(function() { {$extra['jquery_ready_content']} }); </script>", |
||||
368 | get_lang('AddPortfolioItem'), |
||||
369 | $actions |
||||
370 | ); |
||||
371 | } |
||||
372 | |||||
373 | /** |
||||
374 | * @throws \Doctrine\ORM\ORMException |
||||
375 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
376 | * @throws \Doctrine\ORM\TransactionRequiredException |
||||
377 | * @throws \Exception |
||||
378 | */ |
||||
379 | public function editItem(Portfolio $item) |
||||
380 | { |
||||
381 | global $interbreadcrumb; |
||||
382 | |||||
383 | if (!$this->itemBelongToOwner($item)) { |
||||
384 | api_not_allowed(true); |
||||
385 | } |
||||
386 | |||||
387 | $categories = $this->em |
||||
388 | ->getRepository('ChamiloCoreBundle:PortfolioCategory') |
||||
389 | ->findBy(['user' => $this->owner]); |
||||
390 | |||||
391 | $form = new FormValidator('edit_portfolio', 'post', $this->baseUrl."action=edit_item&id={$item->getId()}"); |
||||
392 | |||||
393 | if (api_get_configuration_value('save_titles_as_html')) { |
||||
394 | $form->addHtmlEditor('title', get_lang('Title'), true, false, ['ToolbarSet' => 'TitleAsHtml']); |
||||
395 | } else { |
||||
396 | $form->addText('title', get_lang('Title')); |
||||
397 | $form->applyFilter('title', 'trim'); |
||||
398 | } |
||||
399 | |||||
400 | if ($item->getOrigin()) { |
||||
0 ignored issues
–
show
The expression
$item->getOrigin() of type integer|null is loosely compared to true ; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
Loading history...
|
|||||
401 | if (Portfolio::TYPE_ITEM === $item->getOriginType()) { |
||||
402 | $origin = $this->em->find(Portfolio::class, $item->getOrigin()); |
||||
403 | |||||
404 | $form->addLabel( |
||||
405 | sprintf(get_lang('PortfolioItemFromXUser'), $origin->getUser()->getCompleteName()), |
||||
406 | Display::panel( |
||||
407 | Security::remove_XSS($origin->getContent()) |
||||
408 | ) |
||||
409 | ); |
||||
410 | } elseif (Portfolio::TYPE_COMMENT === $item->getOriginType()) { |
||||
411 | $origin = $this->em->find(PortfolioComment::class, $item->getOrigin()); |
||||
412 | |||||
413 | $form->addLabel( |
||||
414 | sprintf(get_lang('PortfolioCommentFromXUser'), $origin->getAuthor()->getCompleteName()), |
||||
415 | Display::panel( |
||||
416 | Security::remove_XSS($origin->getContent()) |
||||
417 | ) |
||||
418 | ); |
||||
419 | } |
||||
420 | } |
||||
421 | |||||
422 | $form->addHtmlEditor('content', get_lang('Content'), true, false, ['ToolbarSet' => 'NotebookStudent']); |
||||
423 | $form->addSelectFromCollection( |
||||
424 | 'category', |
||||
425 | [get_lang('Category'), get_lang('PortfolioCategoryFieldHelp')], |
||||
426 | $categories, |
||||
427 | [], |
||||
428 | true |
||||
429 | ); |
||||
430 | |||||
431 | $extraField = new ExtraField('portfolio'); |
||||
432 | $extra = $extraField->addElements($form, $item->getId()); |
||||
433 | |||||
434 | $attachmentList = $this->generateAttachmentList($item, false); |
||||
435 | |||||
436 | if (!empty($attachmentList)) { |
||||
437 | $form->addLabel(get_lang('AttachmentFiles'), $attachmentList); |
||||
438 | } |
||||
439 | |||||
440 | $this->addAttachmentsFieldToForm($form); |
||||
441 | |||||
442 | $form->addButtonUpdate(get_lang('Update')); |
||||
443 | $form->setDefaults( |
||||
444 | [ |
||||
445 | 'title' => $item->getTitle(), |
||||
446 | 'content' => $item->getContent(), |
||||
447 | 'category' => $item->getCategory() ? $item->getCategory()->getId() : '', |
||||
448 | ] |
||||
449 | ); |
||||
450 | |||||
451 | if ($form->validate()) { |
||||
452 | $values = $form->exportValues(); |
||||
453 | $currentTime = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC')); |
||||
454 | |||||
455 | $item |
||||
456 | ->setTitle($values['title']) |
||||
457 | ->setContent($values['content']) |
||||
458 | ->setUpdateDate($currentTime) |
||||
459 | ->setCategory( |
||||
460 | $this->em->find('ChamiloCoreBundle:PortfolioCategory', $values['category']) |
||||
461 | ); |
||||
462 | |||||
463 | $values['item_id'] = $item->getId(); |
||||
464 | |||||
465 | $extraFieldValue = new ExtraFieldValue('portfolio'); |
||||
466 | $extraFieldValue->saveFieldValues($values); |
||||
467 | |||||
468 | $this->em->persist($item); |
||||
469 | $this->em->flush(); |
||||
470 | |||||
471 | $this->processAttachments( |
||||
472 | $form, |
||||
473 | $item->getUser(), |
||||
474 | $item->getId(), |
||||
475 | PortfolioAttachment::TYPE_ITEM |
||||
476 | ); |
||||
477 | |||||
478 | Display::addFlash( |
||||
479 | Display::return_message(get_lang('ItemUpdated'), 'success') |
||||
480 | ); |
||||
481 | |||||
482 | header("Location: $this->baseUrl"); |
||||
483 | exit; |
||||
484 | } |
||||
485 | |||||
486 | $interbreadcrumb[] = [ |
||||
487 | 'name' => get_lang('Portfolio'), |
||||
488 | 'url' => $this->baseUrl, |
||||
489 | ]; |
||||
490 | $actions = []; |
||||
491 | $actions[] = Display::url( |
||||
492 | Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM), |
||||
493 | $this->baseUrl |
||||
494 | ); |
||||
495 | $content = $form->returnForm(); |
||||
496 | |||||
497 | $this->renderView( |
||||
498 | $content."<script> $(function() { {$extra['jquery_ready_content']} }); </script>", |
||||
499 | get_lang('EditPortfolioItem'), |
||||
500 | $actions |
||||
501 | ); |
||||
502 | } |
||||
503 | |||||
504 | /** |
||||
505 | * @throws \Doctrine\ORM\ORMException |
||||
506 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
507 | */ |
||||
508 | public function showHideItem(Portfolio $item) |
||||
509 | { |
||||
510 | if (!$this->itemBelongToOwner($item)) { |
||||
511 | api_not_allowed(true); |
||||
512 | } |
||||
513 | |||||
514 | $item->setIsVisible( |
||||
515 | !$item->isVisible() |
||||
516 | ); |
||||
517 | |||||
518 | $this->em->persist($item); |
||||
519 | $this->em->flush(); |
||||
520 | |||||
521 | Display::addFlash( |
||||
522 | Display::return_message(get_lang('VisibilityChanged'), 'success') |
||||
523 | ); |
||||
524 | |||||
525 | header("Location: $this->baseUrl"); |
||||
526 | exit; |
||||
527 | } |
||||
528 | |||||
529 | /** |
||||
530 | * @throws \Doctrine\ORM\ORMException |
||||
531 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
532 | */ |
||||
533 | public function deleteItem(Portfolio $item) |
||||
534 | { |
||||
535 | if (!$this->itemBelongToOwner($item)) { |
||||
536 | api_not_allowed(true); |
||||
537 | } |
||||
538 | |||||
539 | $this->em->remove($item); |
||||
540 | $this->em->flush(); |
||||
541 | |||||
542 | Display::addFlash( |
||||
543 | Display::return_message(get_lang('ItemDeleted'), 'success') |
||||
544 | ); |
||||
545 | |||||
546 | header("Location: $this->baseUrl"); |
||||
547 | exit; |
||||
548 | } |
||||
549 | |||||
550 | /** |
||||
551 | * @throws \Exception |
||||
552 | */ |
||||
553 | public function index(HttpRequest $httpRequest) |
||||
554 | { |
||||
555 | $listByUser = false; |
||||
556 | |||||
557 | if ($httpRequest->query->has('user')) { |
||||
558 | $this->owner = api_get_user_entity($httpRequest->query->getInt('user')); |
||||
559 | |||||
560 | if (empty($this->owner)) { |
||||
561 | api_not_allowed(true); |
||||
562 | } |
||||
563 | |||||
564 | $listByUser = true; |
||||
565 | } |
||||
566 | |||||
567 | $currentUserId = api_get_user_id(); |
||||
568 | |||||
569 | $actions = []; |
||||
570 | |||||
571 | if ($currentUserId == $this->owner->getId()) { |
||||
572 | $actions[] = Display::url( |
||||
573 | Display::return_icon('add.png', get_lang('Add'), [], ICON_SIZE_MEDIUM), |
||||
574 | $this->baseUrl.'action=add_item' |
||||
575 | ); |
||||
576 | $actions[] = Display::url( |
||||
577 | Display::return_icon('folder.png', get_lang('AddCategory'), [], ICON_SIZE_MEDIUM), |
||||
578 | $this->baseUrl.'action=add_category' |
||||
579 | ); |
||||
580 | $actions[] = Display::url( |
||||
581 | Display::return_icon('waiting_list.png', get_lang('PortfolioDetails'), [], ICON_SIZE_MEDIUM), |
||||
582 | $this->baseUrl.'action=details' |
||||
583 | ); |
||||
584 | } else { |
||||
585 | $actions[] = Display::url( |
||||
586 | Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM), |
||||
587 | $this->baseUrl |
||||
588 | ); |
||||
589 | } |
||||
590 | |||||
591 | $frmStudentList = null; |
||||
592 | $frmTagList = null; |
||||
593 | |||||
594 | $categories = []; |
||||
595 | |||||
596 | if ($this->course) { |
||||
597 | $frmTagList = $this->createFormTagFilter($listByUser); |
||||
598 | $frmStudentList = $this->createFormStudentFilter($listByUser); |
||||
599 | $frmStudentList->setDefaults(['user' => $this->owner->getId()]); |
||||
600 | } else { |
||||
601 | $categories = $this->getCategoriesForIndex($currentUserId); |
||||
602 | } |
||||
603 | |||||
604 | $items = $this->getItemsForIndex($listByUser, $frmTagList); |
||||
605 | |||||
606 | $template = new Template(null, false, false, false, false, false, false); |
||||
607 | $template->assign('user', $this->owner); |
||||
608 | $template->assign('course', $this->course); |
||||
609 | $template->assign('session', $this->session); |
||||
610 | $template->assign('portfolio', $categories); |
||||
611 | $template->assign('uncategorized_items', $items); |
||||
612 | $template->assign('frm_student_list', $this->course ? $frmStudentList->returnForm() : ''); |
||||
613 | $template->assign('frm_tag_list', $this->course ? $frmTagList->returnForm() : ''); |
||||
614 | |||||
615 | $layout = $template->get_template('portfolio/list.html.twig'); |
||||
616 | $content = $template->fetch($layout); |
||||
617 | |||||
618 | $this->renderView($content, get_lang('Portfolio'), $actions); |
||||
619 | } |
||||
620 | |||||
621 | /** |
||||
622 | * @throws \Doctrine\ORM\ORMException |
||||
623 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
624 | * @throws \Doctrine\ORM\TransactionRequiredException |
||||
625 | */ |
||||
626 | public function view(Portfolio $item) |
||||
627 | { |
||||
628 | global $interbreadcrumb; |
||||
629 | |||||
630 | $form = $this->createCommentForm($item); |
||||
631 | |||||
632 | $commentsRepo = $this->em->getRepository(PortfolioComment::class); |
||||
633 | |||||
634 | $query = $commentsRepo->createQueryBuilder('comment') |
||||
635 | ->where('comment.item = :item') |
||||
636 | ->orderBy('comment.root, comment.lft', 'ASC') |
||||
637 | ->setParameter('item', $item) |
||||
638 | ->getQuery(); |
||||
639 | |||||
640 | $clockIcon = Display::returnFontAwesomeIcon('clock-o', '', true); |
||||
641 | |||||
642 | $commentsHtml = $commentsRepo->buildTree( |
||||
643 | $query->getArrayResult(), |
||||
644 | [ |
||||
645 | 'decorate' => true, |
||||
646 | 'rootOpen' => '<ul class="media-list">', |
||||
647 | 'rootClose' => '</ul>', |
||||
648 | 'childOpen' => function ($node) use ($commentsRepo) { |
||||
649 | /** @var PortfolioComment $comment */ |
||||
650 | $comment = $commentsRepo->find($node['id']); |
||||
651 | $author = $comment->getAuthor(); |
||||
652 | |||||
653 | $userPicture = UserManager::getUserPicture( |
||||
654 | $comment->getAuthor()->getId(), |
||||
655 | USER_IMAGE_SIZE_SMALL, |
||||
656 | null, |
||||
657 | [ |
||||
658 | 'picture_uri' => $author->getPictureUri(), |
||||
659 | 'email' => $author->getEmail(), |
||||
660 | ] |
||||
661 | ); |
||||
662 | |||||
663 | return '<li class="media" id="comment-'.$node['id'].'"> |
||||
664 | <div class="media-left"><img class="media-object thumbnail" src="'.$userPicture.'" alt="' |
||||
665 | .$author->getCompleteName().'"></div> |
||||
666 | <div class="media-body">'; |
||||
667 | }, |
||||
668 | 'childClose' => '</div></li>', |
||||
669 | 'nodeDecorator' => function ($node) use ($commentsRepo, $clockIcon, $item) { |
||||
670 | /** @var PortfolioComment $comment */ |
||||
671 | $comment = $commentsRepo->find($node['id']); |
||||
672 | |||||
673 | $commentActions[] = Display::url( |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
674 | Display::return_icon('discuss.png', get_lang('ReplyToThisComment')), |
||||
675 | '#', |
||||
676 | [ |
||||
677 | 'data-comment' => htmlspecialchars( |
||||
678 | json_encode(['id' => $comment->getId()]) |
||||
679 | ), |
||||
680 | 'role' => 'button', |
||||
681 | 'class' => 'btn-reply-to', |
||||
682 | ] |
||||
683 | ); |
||||
684 | $commentActions[] = Display::url( |
||||
685 | Display::return_icon('copy.png', get_lang('CopyToMyPortfolio')), |
||||
686 | $this->baseUrl.http_build_query( |
||||
687 | [ |
||||
688 | 'action' => 'copy', |
||||
689 | 'copy' => 'comment', |
||||
690 | 'id' => $comment->getId(), |
||||
691 | ] |
||||
692 | ) |
||||
693 | ); |
||||
694 | |||||
695 | $isAllowedToEdit = api_is_allowed_to_edit(); |
||||
696 | |||||
697 | if ($isAllowedToEdit) { |
||||
698 | $commentActions[] = Display::url( |
||||
699 | Display::return_icon('copy.png', get_lang('CopyToStudentPortfolio')), |
||||
700 | $this->baseUrl.http_build_query( |
||||
701 | [ |
||||
702 | 'action' => 'teacher_copy', |
||||
703 | 'copy' => 'comment', |
||||
704 | 'id' => $comment->getId(), |
||||
705 | ] |
||||
706 | ) |
||||
707 | ); |
||||
708 | |||||
709 | if ($comment->isImportant()) { |
||||
710 | $commentActions[] = Display::url( |
||||
711 | Display::return_icon('drawing-pin.png', get_lang('UnmarkCommentAsImportant')), |
||||
712 | $this->baseUrl.http_build_query( |
||||
713 | [ |
||||
714 | 'action' => 'mark_important', |
||||
715 | 'item' => $item->getId(), |
||||
716 | 'id' => $comment->getId(), |
||||
717 | ] |
||||
718 | ) |
||||
719 | ); |
||||
720 | } else { |
||||
721 | $commentActions[] = Display::url( |
||||
722 | Display::return_icon('drawing-pin.png', get_lang('MarkCommentAsImportant')), |
||||
723 | $this->baseUrl.http_build_query( |
||||
724 | [ |
||||
725 | 'action' => 'mark_important', |
||||
726 | 'item' => $item->getId(), |
||||
727 | 'id' => $comment->getId(), |
||||
728 | ] |
||||
729 | ) |
||||
730 | ); |
||||
731 | } |
||||
732 | |||||
733 | if ($this->course && '1' === api_get_course_setting('qualify_portfolio_comment')) { |
||||
734 | $commentActions[] = Display::url( |
||||
735 | Display::return_icon('quiz.png', get_lang('QualifyThisPortfolioComment')), |
||||
736 | $this->baseUrl.http_build_query( |
||||
737 | [ |
||||
738 | 'action' => 'qualify', |
||||
739 | 'comment' => $comment->getId(), |
||||
740 | ] |
||||
741 | ) |
||||
742 | ); |
||||
743 | } |
||||
744 | } |
||||
745 | |||||
746 | $nodeHtml = '<p class="media-heading h4">'.PHP_EOL |
||||
747 | .$comment->getAuthor()->getCompleteName().PHP_EOL.'<small>'.$clockIcon.PHP_EOL |
||||
748 | .Display::dateToStringAgoAndLongDate($comment->getDate()).'</small>'.PHP_EOL; |
||||
749 | |||||
750 | if ($comment->isImportant() |
||||
751 | && ($this->itemBelongToOwner($comment->getItem()) || $isAllowedToEdit) |
||||
752 | ) { |
||||
753 | $nodeHtml .= '<span class="label label-warning origin-style">' |
||||
754 | .get_lang('CommentMarkedAsImportant') |
||||
755 | .'</span>'.PHP_EOL; |
||||
756 | } |
||||
757 | |||||
758 | $nodeHtml .= '</p>'.PHP_EOL |
||||
759 | .'<div class="pull-right">'.implode(PHP_EOL, $commentActions).'</div>' |
||||
760 | .Security::remove_XSS($comment->getContent()) |
||||
761 | .PHP_EOL; |
||||
762 | |||||
763 | $nodeHtml .= $this->generateAttachmentList($comment); |
||||
764 | |||||
765 | return $nodeHtml; |
||||
766 | }, |
||||
767 | ] |
||||
768 | ); |
||||
769 | |||||
770 | $template = new Template(null, false, false, false, false, false, false); |
||||
771 | $template->assign('baseurl', $this->baseUrl); |
||||
772 | $template->assign('item', $item); |
||||
773 | $template->assign('item_content', $this->generateItemContent($item)); |
||||
774 | $template->assign('comments', $commentsHtml); |
||||
775 | $template->assign('form', $form); |
||||
776 | $template->assign('attachment_list', $this->generateAttachmentList($item)); |
||||
777 | |||||
778 | $layout = $template->get_template('portfolio/view.html.twig'); |
||||
779 | $content = $template->fetch($layout); |
||||
780 | |||||
781 | $interbreadcrumb[] = ['name' => get_lang('Portfolio'), 'url' => $this->baseUrl]; |
||||
782 | |||||
783 | $actions = []; |
||||
784 | $actions[] = Display::url( |
||||
785 | Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM), |
||||
786 | $this->baseUrl |
||||
787 | ); |
||||
788 | |||||
789 | $this->renderView($content, Security::remove_XSS($item->getTitle()), $actions, false); |
||||
790 | } |
||||
791 | |||||
792 | /** |
||||
793 | * @throws \Doctrine\ORM\ORMException |
||||
794 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
795 | */ |
||||
796 | public function copyItem(Portfolio $originItem) |
||||
797 | { |
||||
798 | $currentTime = api_get_utc_datetime(null, false, true); |
||||
799 | |||||
800 | $portfolio = new Portfolio(); |
||||
801 | $portfolio |
||||
802 | ->setIsVisible(false) |
||||
803 | ->setTitle( |
||||
804 | sprintf(get_lang('PortfolioItemFromXUser'), $originItem->getUser()->getCompleteName()) |
||||
805 | ) |
||||
806 | ->setContent('') |
||||
807 | ->setUser($this->owner) |
||||
808 | ->setOrigin($originItem->getId()) |
||||
809 | ->setOriginType(Portfolio::TYPE_ITEM) |
||||
810 | ->setCourse($this->course) |
||||
811 | ->setSession($this->session) |
||||
812 | ->setCreationDate($currentTime) |
||||
813 | ->setUpdateDate($currentTime); |
||||
814 | |||||
815 | $this->em->persist($portfolio); |
||||
816 | $this->em->flush(); |
||||
817 | |||||
818 | Display::addFlash( |
||||
819 | Display::return_message(get_lang('PortfolioItemAdded'), 'success') |
||||
820 | ); |
||||
821 | |||||
822 | header("Location: $this->baseUrl".http_build_query(['action' => 'edit_item', 'id' => $portfolio->getId()])); |
||||
823 | exit; |
||||
824 | } |
||||
825 | |||||
826 | /** |
||||
827 | * @throws \Doctrine\ORM\ORMException |
||||
828 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
829 | */ |
||||
830 | public function copyComment(PortfolioComment $originComment) |
||||
831 | { |
||||
832 | $currentTime = api_get_utc_datetime(null, false, true); |
||||
833 | |||||
834 | $portfolio = new Portfolio(); |
||||
835 | $portfolio |
||||
836 | ->setIsVisible(false) |
||||
837 | ->setTitle( |
||||
838 | sprintf(get_lang('PortfolioCommentFromXUser'), $originComment->getAuthor()->getCompleteName()) |
||||
839 | ) |
||||
840 | ->setContent('') |
||||
841 | ->setUser($this->owner) |
||||
842 | ->setOrigin($originComment->getId()) |
||||
843 | ->setOriginType(Portfolio::TYPE_COMMENT) |
||||
844 | ->setCourse($this->course) |
||||
845 | ->setSession($this->session) |
||||
846 | ->setCreationDate($currentTime) |
||||
847 | ->setUpdateDate($currentTime); |
||||
848 | |||||
849 | $this->em->persist($portfolio); |
||||
850 | $this->em->flush(); |
||||
851 | |||||
852 | Display::addFlash( |
||||
853 | Display::return_message(get_lang('PortfolioItemAdded'), 'success') |
||||
854 | ); |
||||
855 | |||||
856 | header("Location: $this->baseUrl".http_build_query(['action' => 'edit_item', 'id' => $portfolio->getId()])); |
||||
857 | exit; |
||||
858 | } |
||||
859 | |||||
860 | /** |
||||
861 | * @throws \Doctrine\ORM\ORMException |
||||
862 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
863 | * @throws \Exception |
||||
864 | */ |
||||
865 | public function teacherCopyItem(Portfolio $originItem) |
||||
866 | { |
||||
867 | $actionParams = http_build_query(['action' => 'teacher_copy', 'copy' => 'item', 'id' => $originItem->getId()]); |
||||
868 | |||||
869 | $form = new FormValidator('teacher_copy_portfolio', 'post', $this->baseUrl.$actionParams); |
||||
870 | |||||
871 | if (api_get_configuration_value('save_titles_as_html')) { |
||||
872 | $form->addHtmlEditor('title', get_lang('Title'), true, false, ['ToolbarSet' => 'TitleAsHtml']); |
||||
873 | } else { |
||||
874 | $form->addText('title', get_lang('Title')); |
||||
875 | $form->applyFilter('title', 'trim'); |
||||
876 | } |
||||
877 | |||||
878 | $form->addLabel( |
||||
879 | sprintf(get_lang('PortfolioItemFromXUser'), $originItem->getUser()->getCompleteName()), |
||||
880 | Display::panel( |
||||
881 | Security::remove_XSS($originItem->getContent()) |
||||
882 | ) |
||||
883 | ); |
||||
884 | $form->addHtmlEditor('content', get_lang('Content'), true, false, ['ToolbarSet' => 'NotebookStudent']); |
||||
885 | |||||
886 | $urlParams = http_build_query( |
||||
887 | [ |
||||
888 | 'a' => 'search_user_by_course', |
||||
889 | 'course_id' => $this->course->getId(), |
||||
890 | 'session_id' => $this->session ? $this->session->getId() : 0, |
||||
891 | ] |
||||
892 | ); |
||||
893 | $form->addSelectAjax( |
||||
894 | 'students', |
||||
895 | get_lang('Students'), |
||||
896 | [], |
||||
897 | [ |
||||
898 | 'url' => api_get_path(WEB_AJAX_PATH)."course.ajax.php?$urlParams", |
||||
899 | 'multiple' => true, |
||||
900 | ] |
||||
901 | ); |
||||
902 | $form->addRule('students', get_lang('ThisFieldIsRequired'), 'required'); |
||||
903 | $form->addButtonCreate(get_lang('Save')); |
||||
904 | |||||
905 | $toolName = get_lang('CopyToStudentPortfolio'); |
||||
906 | $content = $form->returnForm(); |
||||
907 | |||||
908 | if ($form->validate()) { |
||||
909 | $values = $form->exportValues(); |
||||
910 | |||||
911 | $currentTime = api_get_utc_datetime(null, false, true); |
||||
912 | |||||
913 | foreach ($values['students'] as $studentId) { |
||||
914 | $owner = api_get_user_entity($studentId); |
||||
915 | |||||
916 | $portfolio = new Portfolio(); |
||||
917 | $portfolio |
||||
918 | ->setIsVisible(false) |
||||
919 | ->setTitle($values['title']) |
||||
920 | ->setContent($values['content']) |
||||
921 | ->setUser($owner) |
||||
922 | ->setOrigin($originItem->getId()) |
||||
923 | ->setOriginType(Portfolio::TYPE_ITEM) |
||||
924 | ->setCourse($this->course) |
||||
925 | ->setSession($this->session) |
||||
926 | ->setCreationDate($currentTime) |
||||
927 | ->setUpdateDate($currentTime); |
||||
928 | |||||
929 | $this->em->persist($portfolio); |
||||
930 | } |
||||
931 | |||||
932 | $this->em->flush(); |
||||
933 | |||||
934 | Display::addFlash( |
||||
935 | Display::return_message(get_lang('PortfolioItemAddedToStudents'), 'success') |
||||
936 | ); |
||||
937 | |||||
938 | header("Location: $this->baseUrl"); |
||||
939 | exit; |
||||
940 | } |
||||
941 | |||||
942 | $this->renderView($content, $toolName); |
||||
943 | } |
||||
944 | |||||
945 | /** |
||||
946 | * @throws \Doctrine\ORM\ORMException |
||||
947 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
948 | * @throws \Exception |
||||
949 | */ |
||||
950 | public function teacherCopyComment(PortfolioComment $originComment) |
||||
951 | { |
||||
952 | $actionParams = http_build_query( |
||||
953 | [ |
||||
954 | 'action' => 'teacher_copy', |
||||
955 | 'copy' => 'comment', |
||||
956 | 'id' => $originComment->getId(), |
||||
957 | ] |
||||
958 | ); |
||||
959 | |||||
960 | $form = new FormValidator('teacher_copy_portfolio', 'post', $this->baseUrl.$actionParams); |
||||
961 | |||||
962 | if (api_get_configuration_value('save_titles_as_html')) { |
||||
963 | $form->addHtmlEditor('title', get_lang('Title'), true, false, ['ToolbarSet' => 'TitleAsHtml']); |
||||
964 | } else { |
||||
965 | $form->addText('title', get_lang('Title')); |
||||
966 | $form->applyFilter('title', 'trim'); |
||||
967 | } |
||||
968 | |||||
969 | $form->addLabel( |
||||
970 | sprintf(get_lang('PortfolioCommentFromXUser'), $originComment->getAuthor()->getCompleteName()), |
||||
971 | Display::panel( |
||||
972 | Security::remove_XSS($originComment->getContent()) |
||||
973 | ) |
||||
974 | ); |
||||
975 | $form->addHtmlEditor('content', get_lang('Content'), true, false, ['ToolbarSet' => 'NotebookStudent']); |
||||
976 | |||||
977 | $urlParams = http_build_query( |
||||
978 | [ |
||||
979 | 'a' => 'search_user_by_course', |
||||
980 | 'course_id' => $this->course->getId(), |
||||
981 | 'session_id' => $this->session ? $this->session->getId() : 0, |
||||
982 | ] |
||||
983 | ); |
||||
984 | $form->addSelectAjax( |
||||
985 | 'students', |
||||
986 | get_lang('Students'), |
||||
987 | [], |
||||
988 | [ |
||||
989 | 'url' => api_get_path(WEB_AJAX_PATH)."course.ajax.php?$urlParams", |
||||
990 | 'multiple' => true, |
||||
991 | ] |
||||
992 | ); |
||||
993 | $form->addRule('students', get_lang('ThisFieldIsRequired'), 'required'); |
||||
994 | $form->addButtonCreate(get_lang('Save')); |
||||
995 | |||||
996 | $toolName = get_lang('CopyToStudentPortfolio'); |
||||
997 | $content = $form->returnForm(); |
||||
998 | |||||
999 | if ($form->validate()) { |
||||
1000 | $values = $form->exportValues(); |
||||
1001 | |||||
1002 | $currentTime = api_get_utc_datetime(null, false, true); |
||||
1003 | |||||
1004 | foreach ($values['students'] as $studentId) { |
||||
1005 | $owner = api_get_user_entity($studentId); |
||||
1006 | |||||
1007 | $portfolio = new Portfolio(); |
||||
1008 | $portfolio |
||||
1009 | ->setIsVisible(false) |
||||
1010 | ->setTitle($values['title']) |
||||
1011 | ->setContent($values['content']) |
||||
1012 | ->setUser($owner) |
||||
1013 | ->setOrigin($originComment->getId()) |
||||
1014 | ->setOriginType(Portfolio::TYPE_COMMENT) |
||||
1015 | ->setCourse($this->course) |
||||
1016 | ->setSession($this->session) |
||||
1017 | ->setCreationDate($currentTime) |
||||
1018 | ->setUpdateDate($currentTime); |
||||
1019 | |||||
1020 | $this->em->persist($portfolio); |
||||
1021 | } |
||||
1022 | |||||
1023 | $this->em->flush(); |
||||
1024 | |||||
1025 | Display::addFlash( |
||||
1026 | Display::return_message(get_lang('PortfolioItemAddedToStudents'), 'success') |
||||
1027 | ); |
||||
1028 | |||||
1029 | header("Location: $this->baseUrl"); |
||||
1030 | exit; |
||||
1031 | } |
||||
1032 | |||||
1033 | $this->renderView($content, $toolName); |
||||
1034 | } |
||||
1035 | |||||
1036 | /** |
||||
1037 | * @throws \Doctrine\ORM\ORMException |
||||
1038 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
1039 | */ |
||||
1040 | public function markImportantCommentInItem(Portfolio $item, PortfolioComment $comment) |
||||
1041 | { |
||||
1042 | if ($comment->getItem()->getId() !== $item->getId()) { |
||||
1043 | api_not_allowed(true); |
||||
1044 | } |
||||
1045 | |||||
1046 | $comment->setIsImportant( |
||||
1047 | !$comment->isImportant() |
||||
1048 | ); |
||||
1049 | |||||
1050 | $this->em->persist($comment); |
||||
1051 | $this->em->flush(); |
||||
1052 | |||||
1053 | Display::addFlash( |
||||
1054 | Display::return_message(get_lang('CommentMarkedAsImportant'), 'success') |
||||
1055 | ); |
||||
1056 | |||||
1057 | header("Location: $this->baseUrl".http_build_query(['action' => 'view', 'id' => $item->getId()])); |
||||
1058 | exit; |
||||
1059 | } |
||||
1060 | |||||
1061 | /** |
||||
1062 | * @throws \Exception |
||||
1063 | */ |
||||
1064 | public function details(HttpRequest $httpRequest) |
||||
1065 | { |
||||
1066 | $isAllowedToFilterStudent = $this->course && api_is_allowed_to_edit(); |
||||
1067 | |||||
1068 | $actions = []; |
||||
1069 | $actions[] = Display::url( |
||||
1070 | Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM), |
||||
1071 | $this->baseUrl |
||||
1072 | ); |
||||
1073 | $actions[] = Display::url( |
||||
1074 | Display::return_icon('pdf.png', get_lang('ExportMyPortfolioDataPdf'), [], ICON_SIZE_MEDIUM), |
||||
1075 | $this->baseUrl.http_build_query(['action' => 'export_pdf']) |
||||
1076 | ); |
||||
1077 | $actions[] = Display::url( |
||||
1078 | Display::return_icon('save_pack.png', get_lang('ExportMyPortfolioDataZip'), [], ICON_SIZE_MEDIUM), |
||||
1079 | $this->baseUrl.http_build_query(['action' => 'export_zip']) |
||||
1080 | ); |
||||
1081 | |||||
1082 | $frmStudent = null; |
||||
1083 | |||||
1084 | if ($isAllowedToFilterStudent) { |
||||
1085 | if ($httpRequest->query->has('user')) { |
||||
1086 | $this->owner = api_get_user_entity($httpRequest->query->getInt('user')); |
||||
1087 | |||||
1088 | if (empty($this->owner)) { |
||||
1089 | api_not_allowed(true); |
||||
1090 | } |
||||
1091 | |||||
1092 | $actions[1] = Display::url( |
||||
1093 | Display::return_icon('pdf.png', get_lang('ExportMyPortfolioDataPdf'), [], ICON_SIZE_MEDIUM), |
||||
1094 | $this->baseUrl.http_build_query(['action' => 'export_pdf', 'user' => $this->owner->getId()]) |
||||
1095 | ); |
||||
1096 | $actions[2] = Display::url( |
||||
1097 | Display::return_icon('save_pack.png', get_lang('ExportMyPortfolioDataZip'), [], ICON_SIZE_MEDIUM), |
||||
1098 | $this->baseUrl.http_build_query(['action' => 'export_zip', 'user' => $this->owner->getId()]) |
||||
1099 | ); |
||||
1100 | } |
||||
1101 | |||||
1102 | $frmStudent = new FormValidator('frm_student_list', 'get'); |
||||
1103 | $slctStudentOptions = []; |
||||
1104 | $slctStudentOptions[$this->owner->getId()] = $this->owner->getCompleteName(); |
||||
1105 | |||||
1106 | $urlParams = http_build_query( |
||||
1107 | [ |
||||
1108 | 'a' => 'search_user_by_course', |
||||
1109 | 'course_id' => $this->course->getId(), |
||||
1110 | 'session_id' => $this->session ? $this->session->getId() : 0, |
||||
1111 | ] |
||||
1112 | ); |
||||
1113 | |||||
1114 | $frmStudent->addSelectAjax( |
||||
1115 | 'user', |
||||
1116 | get_lang('SelectLearnerPortfolio'), |
||||
1117 | $slctStudentOptions, |
||||
1118 | [ |
||||
1119 | 'url' => api_get_path(WEB_AJAX_PATH)."course.ajax.php?$urlParams", |
||||
1120 | 'placeholder' => get_lang('SearchStudent'), |
||||
1121 | ] |
||||
1122 | ); |
||||
1123 | $frmStudent->setDefaults(['user' => $this->owner->getId()]); |
||||
1124 | $frmStudent->addHidden('action', 'details'); |
||||
1125 | $frmStudent->addHidden('cidReq', $this->course->getCode()); |
||||
1126 | $frmStudent->addHidden('id_session', $this->session ? $this->session->getId() : 0); |
||||
1127 | $frmStudent->addButtonFilter(get_lang('Filter')); |
||||
1128 | } |
||||
1129 | |||||
1130 | $itemsRepo = $this->em->getRepository(Portfolio::class); |
||||
1131 | $commentsRepo = $this->em->getRepository(PortfolioComment::class); |
||||
1132 | |||||
1133 | $getItemsTotalNumber = function () use ($itemsRepo) { |
||||
1134 | $qb = $itemsRepo->createQueryBuilder('i'); |
||||
1135 | $qb |
||||
1136 | ->select('COUNT(i)') |
||||
1137 | ->where('i.user = :user') |
||||
1138 | ->setParameter('user', $this->owner); |
||||
1139 | |||||
1140 | if ($this->course) { |
||||
1141 | $qb |
||||
1142 | ->andWhere('i.course = :course') |
||||
1143 | ->setParameter('course', $this->course); |
||||
1144 | |||||
1145 | if ($this->session) { |
||||
1146 | $qb |
||||
1147 | ->andWhere('i.session = :session') |
||||
1148 | ->setParameter('session', $this->session); |
||||
1149 | } else { |
||||
1150 | $qb->andWhere('i.session IS NULL'); |
||||
1151 | } |
||||
1152 | } |
||||
1153 | |||||
1154 | return $qb->getQuery()->getSingleScalarResult(); |
||||
1155 | }; |
||||
1156 | $getItemsData = function ($from, $limit, $columnNo, $orderDirection) use ($itemsRepo) { |
||||
1157 | $qb = $itemsRepo->createQueryBuilder('item') |
||||
1158 | ->where('item.user = :user') |
||||
1159 | ->leftJoin('item.category', 'category') |
||||
1160 | ->leftJoin('item.course', 'course') |
||||
1161 | ->leftJoin('item.session', 'session') |
||||
1162 | ->setParameter('user', $this->owner); |
||||
1163 | |||||
1164 | if ($this->course) { |
||||
1165 | $qb |
||||
1166 | ->andWhere('item.course = :course_id') |
||||
1167 | ->setParameter('course_id', $this->course); |
||||
1168 | |||||
1169 | if ($this->session) { |
||||
1170 | $qb |
||||
1171 | ->andWhere('item.session = :session') |
||||
1172 | ->setParameter('session', $this->session); |
||||
1173 | } else { |
||||
1174 | $qb->andWhere('item.session IS NULL'); |
||||
1175 | } |
||||
1176 | } |
||||
1177 | |||||
1178 | if (0 == $columnNo) { |
||||
1179 | $qb->orderBy('item.title', $orderDirection); |
||||
1180 | } elseif (1 == $columnNo) { |
||||
1181 | $qb->orderBy('item.creationDate', $orderDirection); |
||||
1182 | } elseif (2 == $columnNo) { |
||||
1183 | $qb->orderBy('item.updateDate', $orderDirection); |
||||
1184 | } elseif (3 == $columnNo) { |
||||
1185 | $qb->orderBy('category.title', $orderDirection); |
||||
1186 | } elseif (5 == $columnNo) { |
||||
1187 | $qb->orderBy('item.score', $orderDirection); |
||||
1188 | } elseif (6 == $columnNo) { |
||||
1189 | $qb->orderBy('course.title', $orderDirection); |
||||
1190 | } elseif (7 == $columnNo) { |
||||
1191 | $qb->orderBy('session.name', $orderDirection); |
||||
1192 | } |
||||
1193 | |||||
1194 | $qb->setFirstResult($from)->setMaxResults($limit); |
||||
1195 | |||||
1196 | return array_map( |
||||
1197 | function (Portfolio $item) { |
||||
1198 | $category = $item->getCategory(); |
||||
1199 | |||||
1200 | $row = []; |
||||
1201 | $row[] = $item; |
||||
1202 | $row[] = $item->getCreationDate(); |
||||
1203 | $row[] = $item->getUpdateDate(); |
||||
1204 | $row[] = $category ? $item->getCategory()->getTitle() : null; |
||||
0 ignored issues
–
show
|
|||||
1205 | $row[] = $item->getComments()->count(); |
||||
1206 | $row[] = $item->getScore(); |
||||
1207 | |||||
1208 | if (!$this->course) { |
||||
1209 | $row[] = $item->getCourse(); |
||||
1210 | $row[] = $item->getSession(); |
||||
1211 | } |
||||
1212 | |||||
1213 | return $row; |
||||
1214 | }, |
||||
1215 | $qb->getQuery()->getResult() |
||||
1216 | ); |
||||
1217 | }; |
||||
1218 | |||||
1219 | $portfolioItemColumnFilter = function (Portfolio $item) { |
||||
1220 | return Display::url( |
||||
1221 | Security::remove_XSS($item->getTitle()), |
||||
1222 | $this->baseUrl.http_build_query(['action' => 'view', 'id' => $item->getId()]) |
||||
1223 | ); |
||||
1224 | }; |
||||
1225 | $convertFormatDateColumnFilter = function (DateTime $date) { |
||||
1226 | return api_convert_and_format_date($date); |
||||
1227 | }; |
||||
1228 | |||||
1229 | $tblItems = new SortableTable('tbl_items', $getItemsTotalNumber, $getItemsData, 1, 20, 'DESC'); |
||||
1230 | $tblItems->set_additional_parameters(['action' => 'details', 'user' => $this->owner->getId()]); |
||||
1231 | $tblItems->set_header(0, get_lang('Title')); |
||||
1232 | $tblItems->set_column_filter(0, $portfolioItemColumnFilter); |
||||
1233 | $tblItems->set_header(1, get_lang('CreationDate'), true, [], ['class' => 'text-center']); |
||||
1234 | $tblItems->set_column_filter(1, $convertFormatDateColumnFilter); |
||||
1235 | $tblItems->set_header(2, get_lang('LastUpdate'), true, [], ['class' => 'text-center']); |
||||
1236 | $tblItems->set_column_filter(2, $convertFormatDateColumnFilter); |
||||
1237 | $tblItems->set_header(3, get_lang('Category')); |
||||
1238 | $tblItems->set_header(4, get_lang('Comments'), false, [], ['class' => 'text-right']); |
||||
1239 | $tblItems->set_header(5, get_lang('Score'), true, [], ['class' => 'text-right']); |
||||
1240 | |||||
1241 | if (!$this->course) { |
||||
1242 | $tblItems->set_header(6, get_lang('Course')); |
||||
1243 | $tblItems->set_header(7, get_lang('Session')); |
||||
1244 | } |
||||
1245 | |||||
1246 | $getCommentsTotalNumber = function () use ($commentsRepo) { |
||||
1247 | $qb = $commentsRepo->createQueryBuilder('c'); |
||||
1248 | $qb |
||||
1249 | ->select('COUNT(c)') |
||||
1250 | ->where('c.author = :author') |
||||
1251 | ->setParameter('author', $this->owner); |
||||
1252 | |||||
1253 | if ($this->course) { |
||||
1254 | $qb |
||||
1255 | ->innerJoin('c.item', 'i') |
||||
1256 | ->andWhere('i.course = :course') |
||||
1257 | ->setParameter('course', $this->course); |
||||
1258 | |||||
1259 | if ($this->session) { |
||||
1260 | $qb |
||||
1261 | ->andWhere('i.session = :session') |
||||
1262 | ->setParameter('session', $this->session); |
||||
1263 | } else { |
||||
1264 | $qb->andWhere('i.session IS NULL'); |
||||
1265 | } |
||||
1266 | } |
||||
1267 | |||||
1268 | return $qb->getQuery()->getSingleScalarResult(); |
||||
1269 | }; |
||||
1270 | $getCommentsData = function ($from, $limit, $columnNo, $orderDirection) use ($commentsRepo) { |
||||
1271 | $qb = $commentsRepo->createQueryBuilder('comment'); |
||||
1272 | $qb |
||||
1273 | ->where('comment.author = :user') |
||||
1274 | ->innerJoin('comment.item', 'item') |
||||
1275 | ->setParameter('user', $this->owner); |
||||
1276 | |||||
1277 | if ($this->course) { |
||||
1278 | $qb |
||||
1279 | ->innerJoin('comment.item', 'i') |
||||
1280 | ->andWhere('item.course = :course') |
||||
1281 | ->setParameter('course', $this->course); |
||||
1282 | |||||
1283 | if ($this->session) { |
||||
1284 | $qb |
||||
1285 | ->andWhere('item.session = :session') |
||||
1286 | ->setParameter('session', $this->session); |
||||
1287 | } else { |
||||
1288 | $qb->andWhere('item.session IS NULL'); |
||||
1289 | } |
||||
1290 | } |
||||
1291 | |||||
1292 | if (0 == $columnNo) { |
||||
1293 | $qb->orderBy('comment.content', $orderDirection); |
||||
1294 | } elseif (1 == $columnNo) { |
||||
1295 | $qb->orderBy('comment.date', $orderDirection); |
||||
1296 | } elseif (2 == $columnNo) { |
||||
1297 | $qb->orderBy('item.title', $orderDirection); |
||||
1298 | } elseif (3 == $columnNo) { |
||||
1299 | $qb->orderBy('comment.score', $orderDirection); |
||||
1300 | } |
||||
1301 | |||||
1302 | $qb->setFirstResult($from)->setMaxResults($limit); |
||||
1303 | |||||
1304 | return array_map( |
||||
1305 | function (PortfolioComment $comment) { |
||||
1306 | return [ |
||||
1307 | $comment, |
||||
1308 | $comment->getDate(), |
||||
1309 | $comment->getItem(), |
||||
1310 | $comment->getScore(), |
||||
1311 | ]; |
||||
1312 | }, |
||||
1313 | $qb->getQuery()->getResult() |
||||
1314 | ); |
||||
1315 | }; |
||||
1316 | |||||
1317 | $tblComments = new SortableTable('tbl_comments', $getCommentsTotalNumber, $getCommentsData, 1, 20, 'DESC'); |
||||
1318 | $tblComments->set_additional_parameters(['action' => 'details', 'user' => $this->owner->getId()]); |
||||
1319 | $tblComments->set_header(0, get_lang('Resume')); |
||||
1320 | $tblComments->set_column_filter( |
||||
1321 | 0, |
||||
1322 | function (PortfolioComment $comment) { |
||||
1323 | return Display::url( |
||||
1324 | $comment->getExcerpt(), |
||||
1325 | $this->baseUrl.http_build_query(['action' => 'view', 'id' => $comment->getItem()->getId()]) |
||||
1326 | .'#comment-'.$comment->getId() |
||||
1327 | ); |
||||
1328 | } |
||||
1329 | ); |
||||
1330 | $tblComments->set_header(1, get_lang('Date'), true, [], ['class' => 'text-center']); |
||||
1331 | $tblComments->set_column_filter(1, $convertFormatDateColumnFilter); |
||||
1332 | $tblComments->set_header(2, get_lang('PortfolioItemTitle')); |
||||
1333 | $tblComments->set_column_filter(2, $portfolioItemColumnFilter); |
||||
1334 | $tblComments->set_header(3, get_lang('Score'), true, [], ['class' => 'text-right']); |
||||
1335 | |||||
1336 | $content = ''; |
||||
1337 | |||||
1338 | if ($frmStudent) { |
||||
1339 | $content .= $frmStudent->returnForm(); |
||||
1340 | } |
||||
1341 | |||||
1342 | $content .= Display::page_subheader2(get_lang('PortfolioItems')).PHP_EOL; |
||||
1343 | |||||
1344 | if ($tblItems->get_total_number_of_items() > 0) { |
||||
1345 | $content .= $tblItems->return_table().PHP_EOL; |
||||
1346 | } else { |
||||
1347 | $content .= Display::return_message(get_lang('NoItemsInYourPortfolio'), 'warning'); |
||||
1348 | } |
||||
1349 | |||||
1350 | $content .= Display::page_subheader2(get_lang('PortfolioCommentsMade')).PHP_EOL; |
||||
1351 | |||||
1352 | if ($tblComments->get_total_number_of_items() > 0) { |
||||
1353 | $content .= $tblComments->return_table().PHP_EOL; |
||||
1354 | } else { |
||||
1355 | $content .= Display::return_message(get_lang('YouHaveNotCommented'), 'warning'); |
||||
1356 | } |
||||
1357 | |||||
1358 | $this->renderView($content, get_lang('PortfolioDetails'), $actions); |
||||
1359 | } |
||||
1360 | |||||
1361 | /** |
||||
1362 | * @throws \MpdfException |
||||
1363 | */ |
||||
1364 | public function exportPdf(HttpRequest $httpRequest) |
||||
1365 | { |
||||
1366 | $isAllowedToFilterStudent = $this->course && api_is_allowed_to_edit(); |
||||
1367 | |||||
1368 | if ($isAllowedToFilterStudent) { |
||||
1369 | if ($httpRequest->query->has('user')) { |
||||
1370 | $this->owner = api_get_user_entity($httpRequest->query->getInt('user')); |
||||
1371 | |||||
1372 | if (empty($this->owner)) { |
||||
1373 | api_not_allowed(true); |
||||
1374 | } |
||||
1375 | } |
||||
1376 | } |
||||
1377 | |||||
1378 | $pdfContent = Display::page_header($this->owner->getCompleteName()); |
||||
1379 | |||||
1380 | if ($this->course) { |
||||
1381 | $pdfContent .= '<p>'.get_lang('Course').': '; |
||||
1382 | |||||
1383 | if ($this->session) { |
||||
1384 | $pdfContent .= $this->session->getName().' ('.$this->course->getTitle().')'; |
||||
1385 | } else { |
||||
1386 | $pdfContent .= $this->course->getTitle(); |
||||
1387 | } |
||||
1388 | |||||
1389 | $pdfContent .= '</p>'; |
||||
1390 | } |
||||
1391 | |||||
1392 | $items = $this->em |
||||
1393 | ->getRepository(Portfolio::class) |
||||
1394 | ->findItemsByUser($this->owner, $this->course, $this->session); |
||||
1395 | $comments = $this->em |
||||
1396 | ->getRepository(PortfolioComment::class) |
||||
1397 | ->findCommentsByUser($this->owner, $this->course, $this->session); |
||||
1398 | |||||
1399 | $itemsHtml = $this->getItemsInHtmlFormatted($items); |
||||
1400 | $commentsHtml = $this->getCommentsInHtmlFormatted($comments); |
||||
1401 | |||||
1402 | $pdfContent .= Display::page_subheader2(get_lang('PortfolioItems')); |
||||
1403 | |||||
1404 | if (count($itemsHtml) > 0) { |
||||
1405 | $pdfContent .= implode(PHP_EOL, $itemsHtml); |
||||
1406 | } else { |
||||
1407 | $pdfContent .= Display::return_message(get_lang('NoItemsInYourPortfolio'), 'warning'); |
||||
1408 | } |
||||
1409 | |||||
1410 | $pdfContent .= Display::page_subheader2(get_lang('PortfolioCommentsMade')); |
||||
1411 | |||||
1412 | if (count($commentsHtml) > 0) { |
||||
1413 | $pdfContent .= implode(PHP_EOL, $commentsHtml); |
||||
1414 | } else { |
||||
1415 | $pdfContent .= Display::return_message(get_lang('YouHaveNotCommented'), 'warning'); |
||||
1416 | } |
||||
1417 | |||||
1418 | $pdfName = $this->owner->getCompleteName() |
||||
1419 | .($this->course ? '_'.$this->course->getCode() : '') |
||||
1420 | .'_'.get_lang('Portfolio'); |
||||
1421 | |||||
1422 | $pdf = new PDF(); |
||||
1423 | $pdf->content_to_pdf( |
||||
1424 | $pdfContent, |
||||
1425 | null, |
||||
1426 | $pdfName, |
||||
1427 | $this->course ? $this->course->getCode() : null, |
||||
1428 | 'D', |
||||
1429 | false, |
||||
1430 | null, |
||||
1431 | false, |
||||
1432 | true |
||||
1433 | ); |
||||
1434 | } |
||||
1435 | |||||
1436 | public function exportZip(HttpRequest $httpRequest) |
||||
1437 | { |
||||
1438 | $isAllowedToFilterStudent = $this->course && api_is_allowed_to_edit(); |
||||
1439 | |||||
1440 | if ($isAllowedToFilterStudent) { |
||||
1441 | if ($httpRequest->query->has('user')) { |
||||
1442 | $this->owner = api_get_user_entity($httpRequest->query->getInt('user')); |
||||
1443 | |||||
1444 | if (empty($this->owner)) { |
||||
1445 | api_not_allowed(true); |
||||
1446 | } |
||||
1447 | } |
||||
1448 | } |
||||
1449 | |||||
1450 | $itemsRepo = $this->em->getRepository(Portfolio::class); |
||||
1451 | $commentsRepo = $this->em->getRepository(PortfolioComment::class); |
||||
1452 | $attachmentsRepo = $this->em->getRepository(PortfolioAttachment::class); |
||||
1453 | |||||
1454 | $items = $itemsRepo->findItemsByUser($this->owner, $this->course, $this->session); |
||||
1455 | $comments = $commentsRepo->findCommentsByUser($this->owner, $this->course, $this->session); |
||||
1456 | |||||
1457 | $itemsHtml = $this->getItemsInHtmlFormatted($items); |
||||
1458 | $commentsHtml = $this->getCommentsInHtmlFormatted($comments); |
||||
1459 | |||||
1460 | $sysArchivePath = api_get_path(SYS_ARCHIVE_PATH); |
||||
1461 | $tempPortfolioDirectory = $sysArchivePath."portfolio/{$this->owner->getId()}"; |
||||
1462 | |||||
1463 | $userDirectory = UserManager::getUserPathById($this->owner->getId(), 'system'); |
||||
1464 | $attachmentsDirectory = $userDirectory.'portfolio_attachments/'; |
||||
1465 | |||||
1466 | $tblItemsHeaders = []; |
||||
1467 | $tblItemsHeaders[] = get_lang('Title'); |
||||
1468 | $tblItemsHeaders[] = get_lang('CreationDate'); |
||||
1469 | $tblItemsHeaders[] = get_lang('LastUpdate'); |
||||
1470 | $tblItemsHeaders[] = get_lang('Category'); |
||||
1471 | $tblItemsHeaders[] = get_lang('Category'); |
||||
1472 | $tblItemsHeaders[] = get_lang('Score'); |
||||
1473 | $tblItemsHeaders[] = get_lang('Course'); |
||||
1474 | $tblItemsHeaders[] = get_lang('Session'); |
||||
1475 | $tblItemsData = []; |
||||
1476 | |||||
1477 | $tblCommentsHeaders = []; |
||||
1478 | $tblCommentsHeaders[] = get_lang('Resume'); |
||||
1479 | $tblCommentsHeaders[] = get_lang('Date'); |
||||
1480 | $tblCommentsHeaders[] = get_lang('PortfolioItemTitle'); |
||||
1481 | $tblCommentsHeaders[] = get_lang('Score'); |
||||
1482 | $tblCommentsData = []; |
||||
1483 | |||||
1484 | $filenames = []; |
||||
1485 | |||||
1486 | $fs = new Filesystem(); |
||||
1487 | |||||
1488 | /** |
||||
1489 | * @var int $i |
||||
1490 | * @var Portfolio $item |
||||
1491 | */ |
||||
1492 | foreach ($items as $i => $item) { |
||||
1493 | $itemCategory = $item->getCategory(); |
||||
1494 | $itemCourse = $item->getCourse(); |
||||
1495 | $itemSession = $item->getSession(); |
||||
1496 | |||||
1497 | $itemDirectory = $item->getCreationDate()->format('Y-m-d-H-i-s'); |
||||
1498 | |||||
1499 | $itemFilename = sprintf('%s/items/%s/item.html', $tempPortfolioDirectory, $itemDirectory); |
||||
1500 | $itemFileContent = $this->fixImagesSourcesToHtml($itemsHtml[$i]); |
||||
1501 | |||||
1502 | $fs->dumpFile($itemFilename, $itemFileContent); |
||||
1503 | |||||
1504 | $filenames[] = $itemFilename; |
||||
1505 | |||||
1506 | $attachments = $attachmentsRepo->findFromItem($item); |
||||
1507 | |||||
1508 | /** @var PortfolioAttachment $attachment */ |
||||
1509 | foreach ($attachments as $attachment) { |
||||
1510 | $attachmentFilename = sprintf( |
||||
1511 | '%s/items/%s/attachments/%s', |
||||
1512 | $tempPortfolioDirectory, |
||||
1513 | $itemDirectory, |
||||
1514 | $attachment->getFilename() |
||||
1515 | ); |
||||
1516 | |||||
1517 | $fs->copy( |
||||
1518 | $attachmentsDirectory.$attachment->getPath(), |
||||
1519 | $attachmentFilename |
||||
1520 | ); |
||||
1521 | |||||
1522 | $filenames[] = $attachmentFilename; |
||||
1523 | } |
||||
1524 | |||||
1525 | $tblItemsData[] = [ |
||||
1526 | Display::url( |
||||
1527 | Security::remove_XSS($item->getTitle()), |
||||
1528 | sprintf('items/%s/item.html', $itemDirectory) |
||||
1529 | ), |
||||
1530 | api_convert_and_format_date($item->getCreationDate()), |
||||
1531 | api_convert_and_format_date($item->getUpdateDate()), |
||||
1532 | $itemCategory ? $itemCategory->getTitle() : null, |
||||
1533 | $item->getComments()->count(), |
||||
1534 | $item->getScore(), |
||||
1535 | $itemCourse->getTitle(), |
||||
1536 | $itemSession ? $itemSession->getName() : null, |
||||
1537 | ]; |
||||
1538 | } |
||||
1539 | |||||
1540 | /** |
||||
1541 | * @var int $i |
||||
1542 | * @var PortfolioComment $comment |
||||
1543 | */ |
||||
1544 | foreach ($comments as $i => $comment) { |
||||
1545 | $commentDirectory = $comment->getDate()->format('Y-m-d-H-i-s'); |
||||
1546 | |||||
1547 | $commentFileContent = $this->fixImagesSourcesToHtml($commentsHtml[$i]); |
||||
1548 | $commentFilename = sprintf('%s/comments/%s/comment.html', $tempPortfolioDirectory, $commentDirectory); |
||||
1549 | |||||
1550 | $fs->dumpFile($commentFilename, $commentFileContent); |
||||
1551 | |||||
1552 | $filenames[] = $commentFilename; |
||||
1553 | |||||
1554 | $attachments = $attachmentsRepo->findFromComment($comment); |
||||
1555 | |||||
1556 | /** @var PortfolioAttachment $attachment */ |
||||
1557 | foreach ($attachments as $attachment) { |
||||
1558 | $attachmentFilename = sprintf( |
||||
1559 | '%s/comments/%s/attachments/%s', |
||||
1560 | $tempPortfolioDirectory, |
||||
1561 | $commentDirectory, |
||||
1562 | $attachment->getFilename() |
||||
1563 | ); |
||||
1564 | |||||
1565 | $fs->copy( |
||||
1566 | $attachmentsDirectory.$attachment->getPath(), |
||||
1567 | $attachmentFilename |
||||
1568 | ); |
||||
1569 | |||||
1570 | $filenames[] = $attachmentFilename; |
||||
1571 | } |
||||
1572 | |||||
1573 | $tblCommentsData[] = [ |
||||
1574 | Display::url( |
||||
1575 | $comment->getExcerpt(), |
||||
1576 | sprintf('comments/%s/comment.html', $commentDirectory) |
||||
1577 | ), |
||||
1578 | api_convert_and_format_date($comment->getDate()), |
||||
1579 | Security::remove_XSS($comment->getItem()->getTitle()), |
||||
1580 | $comment->getScore(), |
||||
1581 | ]; |
||||
1582 | } |
||||
1583 | |||||
1584 | $tblItems = new HTML_Table(['class' => 'table table-hover table-striped table-bordered data_table']); |
||||
1585 | $tblItems->setHeaders($tblItemsHeaders); |
||||
1586 | $tblItems->setData($tblItemsData); |
||||
1587 | |||||
1588 | $tblComments = new HTML_Table(['class' => 'table table-hover table-striped table-bordered data_table']); |
||||
1589 | $tblComments->setHeaders($tblCommentsHeaders); |
||||
1590 | $tblComments->setData($tblCommentsData); |
||||
1591 | |||||
1592 | $itemFilename = sprintf('%s/index.html', $tempPortfolioDirectory); |
||||
1593 | |||||
1594 | $filenames[] = $itemFilename; |
||||
1595 | |||||
1596 | $fs->dumpFile( |
||||
1597 | $itemFilename, |
||||
1598 | $this->formatZipIndexFile($tblItems, $tblComments) |
||||
1599 | ); |
||||
1600 | |||||
1601 | $zipName = $this->owner->getCompleteName() |
||||
1602 | .($this->course ? '_'.$this->course->getCode() : '') |
||||
1603 | .'_'.get_lang('Portfolio'); |
||||
1604 | $tempZipFile = $sysArchivePath."portfolio/$zipName.zip"; |
||||
1605 | $zip = new PclZip($tempZipFile); |
||||
1606 | |||||
1607 | foreach ($filenames as $filename) { |
||||
1608 | $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $tempPortfolioDirectory); |
||||
0 ignored issues
–
show
|
|||||
1609 | } |
||||
1610 | |||||
1611 | DocumentManager::file_send_for_download($tempZipFile, true, "$zipName.zip"); |
||||
1612 | |||||
1613 | $fs->remove($tempPortfolioDirectory); |
||||
1614 | $fs->remove($tempZipFile); |
||||
1615 | } |
||||
1616 | |||||
1617 | public function qualifyItem(Portfolio $item) |
||||
1618 | { |
||||
1619 | global $interbreadcrumb; |
||||
1620 | |||||
1621 | $em = Database::getManager(); |
||||
1622 | |||||
1623 | $formAction = $this->baseUrl.http_build_query(['action' => 'qualify', 'item' => $item->getId()]); |
||||
1624 | |||||
1625 | $form = new FormValidator('frm_qualify', 'post', $formAction); |
||||
1626 | $form->addUserAvatar('user', get_lang('Author')); |
||||
1627 | $form->addLabel(get_lang('Title'), $item->getTitle()); |
||||
1628 | |||||
1629 | $itemContent = Security::remove_XSS( |
||||
1630 | $this->generateItemContent($item) |
||||
1631 | ); |
||||
1632 | |||||
1633 | $form->addLabel(get_lang('Content'), $itemContent); |
||||
1634 | $form->addNumeric( |
||||
1635 | 'score', |
||||
1636 | [get_lang('QualifyNumeric'), null, ' / '.api_get_course_setting('portfolio_max_score')] |
||||
1637 | ); |
||||
1638 | $form->addButtonSave(get_lang('QualifyThisPortfolioItem')); |
||||
1639 | |||||
1640 | if ($form->validate()) { |
||||
1641 | $values = $form->exportValues(); |
||||
1642 | |||||
1643 | $item->setScore($values['score']); |
||||
1644 | |||||
1645 | $em->persist($item); |
||||
1646 | $em->flush(); |
||||
1647 | |||||
1648 | Display::addFlash( |
||||
1649 | Display::return_message(get_lang('PortfolioItemGraded'), 'success') |
||||
1650 | ); |
||||
1651 | |||||
1652 | header("Location: $formAction"); |
||||
1653 | exit(); |
||||
1654 | } |
||||
1655 | |||||
1656 | $form->setDefaults( |
||||
1657 | [ |
||||
1658 | 'user' => $item->getUser(), |
||||
1659 | 'score' => (float) $item->getScore(), |
||||
1660 | ] |
||||
1661 | ); |
||||
1662 | |||||
1663 | $interbreadcrumb[] = [ |
||||
1664 | 'name' => get_lang('Portfolio'), |
||||
1665 | 'url' => $this->baseUrl, |
||||
1666 | ]; |
||||
1667 | $interbreadcrumb[] = [ |
||||
1668 | 'name' => Security::remove_XSS($item->getTitle()), |
||||
1669 | 'url' => $this->baseUrl.http_build_query(['action' => 'view', 'id' => $item->getId()]), |
||||
1670 | ]; |
||||
1671 | |||||
1672 | $actions = []; |
||||
1673 | $actions[] = Display::url( |
||||
1674 | Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM), |
||||
1675 | $this->baseUrl.http_build_query(['action' => 'view', 'id' => $item->getId()]) |
||||
1676 | ); |
||||
1677 | |||||
1678 | $this->renderView($form->returnForm(), get_lang('Qualify'), $actions); |
||||
1679 | } |
||||
1680 | |||||
1681 | public function qualifyComment(PortfolioComment $comment) |
||||
1682 | { |
||||
1683 | global $interbreadcrumb; |
||||
1684 | |||||
1685 | $em = Database::getManager(); |
||||
1686 | |||||
1687 | $item = $comment->getItem(); |
||||
1688 | $commentPath = $em->getRepository(PortfolioComment::class)->getPath($comment); |
||||
1689 | |||||
1690 | $template = new Template('', false, false, false, true, false, false); |
||||
1691 | $template->assign('item', $item); |
||||
1692 | $template->assign('comments_path', $commentPath); |
||||
1693 | $commentContext = $template->fetch( |
||||
1694 | $template->get_template('portfolio/comment_context.html.twig') |
||||
1695 | ); |
||||
1696 | |||||
1697 | $formAction = $this->baseUrl.http_build_query(['action' => 'qualify', 'comment' => $comment->getId()]); |
||||
1698 | |||||
1699 | $form = new FormValidator('frm_qualify', 'post', $formAction); |
||||
1700 | $form->addHtml($commentContext); |
||||
1701 | $form->addUserAvatar('user', get_lang('Author')); |
||||
1702 | $form->addLabel(get_lang('Comment'), $comment->getContent()); |
||||
1703 | $form->addNumeric( |
||||
1704 | 'score', |
||||
1705 | [get_lang('QualifyNumeric'), null, '/ '.api_get_course_setting('portfolio_max_score')] |
||||
1706 | ); |
||||
1707 | $form->addButtonSave(get_lang('QualifyThisPortfolioComment')); |
||||
1708 | |||||
1709 | if ($form->validate()) { |
||||
1710 | $values = $form->exportValues(); |
||||
1711 | |||||
1712 | $comment->setScore($values['score']); |
||||
1713 | |||||
1714 | $em->persist($comment); |
||||
1715 | $em->flush(); |
||||
1716 | |||||
1717 | Display::addFlash( |
||||
1718 | Display::return_message(get_lang('PortfolioCommentGraded'), 'success') |
||||
1719 | ); |
||||
1720 | |||||
1721 | header("Location: $formAction"); |
||||
1722 | exit(); |
||||
1723 | } |
||||
1724 | |||||
1725 | $form->setDefaults( |
||||
1726 | [ |
||||
1727 | 'user' => $comment->getAuthor(), |
||||
1728 | 'score' => (float) $comment->getScore(), |
||||
1729 | ] |
||||
1730 | ); |
||||
1731 | |||||
1732 | $interbreadcrumb[] = [ |
||||
1733 | 'name' => get_lang('Portfolio'), |
||||
1734 | 'url' => $this->baseUrl, |
||||
1735 | ]; |
||||
1736 | $interbreadcrumb[] = [ |
||||
1737 | 'name' => Security::remove_XSS($item->getTitle()), |
||||
1738 | 'url' => $this->baseUrl.http_build_query(['action' => 'view', 'id' => $item->getId()]), |
||||
1739 | ]; |
||||
1740 | |||||
1741 | $actions = []; |
||||
1742 | $actions[] = Display::url( |
||||
1743 | Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM), |
||||
1744 | $this->baseUrl.http_build_query(['action' => 'view', 'id' => $item->getId()]) |
||||
1745 | ); |
||||
1746 | |||||
1747 | $this->renderView($form->returnForm(), get_lang('Qualify'), $actions); |
||||
1748 | } |
||||
1749 | |||||
1750 | public function downloadAttachment(HttpRequest $httpRequest) |
||||
1751 | { |
||||
1752 | $path = $httpRequest->query->get('file'); |
||||
1753 | |||||
1754 | if (empty($path)) { |
||||
1755 | api_not_allowed(true); |
||||
1756 | } |
||||
1757 | |||||
1758 | $em = Database::getManager(); |
||||
1759 | $attachmentRepo = $em->getRepository(PortfolioAttachment::class); |
||||
1760 | |||||
1761 | $attachment = $attachmentRepo->findOneByPath($path); |
||||
1762 | |||||
1763 | if (empty($attachment)) { |
||||
1764 | api_not_allowed(true); |
||||
1765 | } |
||||
1766 | |||||
1767 | $originOwnerId = 0; |
||||
1768 | |||||
1769 | if (PortfolioAttachment::TYPE_ITEM === $attachment->getOriginType()) { |
||||
1770 | $item = $em->find(Portfolio::class, $attachment->getOrigin()); |
||||
1771 | |||||
1772 | $originOwnerId = $item->getUser()->getId(); |
||||
1773 | } elseif (PortfolioAttachment::TYPE_COMMENT === $attachment->getOriginType()) { |
||||
1774 | $comment = $em->find(PortfolioComment::class, $attachment->getOrigin()); |
||||
1775 | |||||
1776 | $originOwnerId = $comment->getAuthor()->getId(); |
||||
1777 | } else { |
||||
1778 | api_not_allowed(true); |
||||
1779 | } |
||||
1780 | |||||
1781 | $userDirectory = UserManager::getUserPathById($originOwnerId, 'system'); |
||||
1782 | $attachmentsDirectory = $userDirectory.'portfolio_attachments/'; |
||||
1783 | $attachmentFilename = $attachmentsDirectory.$attachment->getPath(); |
||||
1784 | |||||
1785 | if (!Security::check_abs_path($attachmentFilename, $attachmentsDirectory)) { |
||||
1786 | api_not_allowed(true); |
||||
1787 | } |
||||
1788 | |||||
1789 | $downloaded = DocumentManager::file_send_for_download( |
||||
1790 | $attachmentFilename, |
||||
1791 | true, |
||||
1792 | $attachment->getFilename() |
||||
1793 | ); |
||||
1794 | |||||
1795 | if (!$downloaded) { |
||||
1796 | api_not_allowed(true); |
||||
1797 | } |
||||
1798 | } |
||||
1799 | |||||
1800 | public function deleteAttachment(HttpRequest $httpRequest) |
||||
1801 | { |
||||
1802 | $currentUserId = api_get_user_id(); |
||||
1803 | |||||
1804 | $path = $httpRequest->query->get('file'); |
||||
1805 | |||||
1806 | if (empty($path)) { |
||||
1807 | api_not_allowed(true); |
||||
1808 | } |
||||
1809 | |||||
1810 | $em = Database::getManager(); |
||||
1811 | $fs = new Filesystem(); |
||||
1812 | |||||
1813 | $attachmentRepo = $em->getRepository(PortfolioAttachment::class); |
||||
1814 | $attachment = $attachmentRepo->findOneByPath($path); |
||||
1815 | |||||
1816 | if (empty($attachment)) { |
||||
1817 | api_not_allowed(true); |
||||
1818 | } |
||||
1819 | |||||
1820 | $originOwnerId = 0; |
||||
1821 | $itemId = 0; |
||||
1822 | |||||
1823 | if (PortfolioAttachment::TYPE_ITEM === $attachment->getOriginType()) { |
||||
1824 | $item = $em->find(Portfolio::class, $attachment->getOrigin()); |
||||
1825 | $originOwnerId = $item->getUser()->getId(); |
||||
1826 | $itemId = $item->getId(); |
||||
1827 | } elseif (PortfolioAttachment::TYPE_COMMENT === $attachment->getOriginType()) { |
||||
1828 | $comment = $em->find(PortfolioComment::class, $attachment->getOrigin()); |
||||
1829 | $originOwnerId = $comment->getAuthor()->getId(); |
||||
1830 | $itemId = $comment->getItem()->getId(); |
||||
1831 | } |
||||
1832 | |||||
1833 | if ($currentUserId !== $originOwnerId) { |
||||
1834 | api_not_allowed(true); |
||||
1835 | } |
||||
1836 | |||||
1837 | $em->remove($attachment); |
||||
1838 | $em->flush(); |
||||
1839 | |||||
1840 | $userDirectory = UserManager::getUserPathById($originOwnerId, 'system'); |
||||
1841 | $attachmentsDirectory = $userDirectory.'portfolio_attachments/'; |
||||
1842 | $attachmentFilename = $attachmentsDirectory.$attachment->getPath(); |
||||
1843 | |||||
1844 | $fs->remove($attachmentFilename); |
||||
1845 | |||||
1846 | if ($httpRequest->isXmlHttpRequest()) { |
||||
1847 | echo Display::return_message(get_lang('AttachmentFileDeleteSuccess'), 'success'); |
||||
1848 | } else { |
||||
1849 | Display::addFlash( |
||||
1850 | Display::return_message(get_lang('AttachmentFileDeleteSuccess'), 'success') |
||||
1851 | ); |
||||
1852 | |||||
1853 | header('Location: '.$this->baseUrl.http_build_query(['action' => 'view', 'id' => $itemId])); |
||||
1854 | } |
||||
1855 | |||||
1856 | exit; |
||||
1857 | } |
||||
1858 | |||||
1859 | /** |
||||
1860 | * @param bool $showHeader |
||||
1861 | */ |
||||
1862 | private function renderView(string $content, string $toolName, array $actions = [], $showHeader = true) |
||||
1863 | { |
||||
1864 | global $this_section; |
||||
1865 | |||||
1866 | $this_section = $this->course ? SECTION_COURSES : SECTION_SOCIAL; |
||||
1867 | |||||
1868 | $view = new Template($toolName); |
||||
1869 | |||||
1870 | if ($showHeader) { |
||||
1871 | $view->assign('header', $toolName); |
||||
1872 | } |
||||
1873 | |||||
1874 | $actionsStr = ''; |
||||
1875 | |||||
1876 | if ($this->course) { |
||||
1877 | $actionsStr .= Display::return_introduction_section(TOOL_PORTFOLIO); |
||||
0 ignored issues
–
show
Are you sure the usage of
Display::return_introduc...section(TOOL_PORTFOLIO) targeting Display::return_introduction_section() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.
Loading history...
|
|||||
1878 | } |
||||
1879 | |||||
1880 | if ($actions) { |
||||
0 ignored issues
–
show
The expression
$actions 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
Loading history...
|
|||||
1881 | $actions = implode(PHP_EOL, $actions); |
||||
1882 | |||||
1883 | $actionsStr .= Display::toolbarAction('portfolio-toolbar', [$actions]); |
||||
1884 | } |
||||
1885 | |||||
1886 | $view->assign('baseurl', $this->baseUrl); |
||||
1887 | $view->assign('actions', $actionsStr); |
||||
1888 | |||||
1889 | $view->assign('content', $content); |
||||
1890 | $view->display_one_col_template(); |
||||
1891 | } |
||||
1892 | |||||
1893 | private function categoryBelongToOwner(PortfolioCategory $category): bool |
||||
1894 | { |
||||
1895 | if ($category->getUser()->getId() != $this->owner->getId()) { |
||||
1896 | return false; |
||||
1897 | } |
||||
1898 | |||||
1899 | return true; |
||||
1900 | } |
||||
1901 | |||||
1902 | private function addAttachmentsFieldToForm(FormValidator $form) |
||||
1903 | { |
||||
1904 | $form->addButton('add_attachment', get_lang('AddAttachment'), 'plus'); |
||||
1905 | $form->addHtml('<div id="container-attachments" style="display: none;">'); |
||||
1906 | $form->addFile('attachment_file[]', get_lang('FilesAttachment')); |
||||
1907 | $form->addText('attachment_comment[]', get_lang('Description'), false); |
||||
1908 | $form->addHtml('</div>'); |
||||
1909 | |||||
1910 | $script = "$(function () { |
||||
1911 | var attachmentsTemplate = $('#container-attachments').html(); |
||||
1912 | var \$btnAdd = $('[name=\"add_attachment\"]'); |
||||
1913 | var \$reference = \$btnAdd.parents('.form-group'); |
||||
1914 | |||||
1915 | \$btnAdd.on('click', function (e) { |
||||
1916 | e.preventDefault(); |
||||
1917 | |||||
1918 | $(attachmentsTemplate).insertBefore(\$reference); |
||||
1919 | }); |
||||
1920 | })"; |
||||
1921 | |||||
1922 | $form->addHtml("<script>$script</script>"); |
||||
1923 | } |
||||
1924 | |||||
1925 | private function processAttachments( |
||||
1926 | FormValidator $form, |
||||
1927 | User $user, |
||||
1928 | int $originId, |
||||
1929 | int $originType |
||||
1930 | ) { |
||||
1931 | $em = Database::getManager(); |
||||
1932 | $fs = new Filesystem(); |
||||
1933 | |||||
1934 | $comments = $form->getSubmitValue('attachment_comment'); |
||||
1935 | |||||
1936 | foreach ($_FILES['attachment_file']['error'] as $i => $attachmentFileError) { |
||||
1937 | if ($attachmentFileError != UPLOAD_ERR_OK) { |
||||
1938 | continue; |
||||
1939 | } |
||||
1940 | |||||
1941 | $_file = [ |
||||
1942 | 'name' => $_FILES['attachment_file']['name'][$i], |
||||
1943 | 'type' => $_FILES['attachment_file']['type'][$i], |
||||
1944 | 'tmp_name' => $_FILES['attachment_file']['tmp_name'][$i], |
||||
1945 | 'size' => $_FILES['attachment_file']['size'][$i], |
||||
1946 | ]; |
||||
1947 | |||||
1948 | if (empty($_file['type'])) { |
||||
1949 | $_file['type'] = DocumentManager::file_get_mime_type($_file['name']); |
||||
1950 | } |
||||
1951 | |||||
1952 | $newFileName = add_ext_on_mime(stripslashes($_file['name']), $_file['type']); |
||||
1953 | |||||
1954 | if (!filter_extension($newFileName)) { |
||||
1955 | Display::addFlash(Display::return_message(get_lang('UplUnableToSaveFileFilteredExtension'), 'error')); |
||||
1956 | continue; |
||||
1957 | } |
||||
1958 | |||||
1959 | $newFileName = uniqid(); |
||||
1960 | $attachmentsDirectory = UserManager::getUserPathById($user->getId(), 'system').'portfolio_attachments/'; |
||||
1961 | |||||
1962 | if (!$fs->exists($attachmentsDirectory)) { |
||||
1963 | $fs->mkdir($attachmentsDirectory, api_get_permissions_for_new_directories()); |
||||
1964 | } |
||||
1965 | |||||
1966 | $attachmentFilename = $attachmentsDirectory.$newFileName; |
||||
1967 | |||||
1968 | if (is_uploaded_file($_file['tmp_name'])) { |
||||
1969 | $moved = move_uploaded_file($_file['tmp_name'], $attachmentFilename); |
||||
1970 | |||||
1971 | if (!$moved) { |
||||
1972 | Display::addFlash(Display::return_message(get_lang('UplUnableToSaveFile'), 'error')); |
||||
1973 | continue; |
||||
1974 | } |
||||
1975 | } |
||||
1976 | |||||
1977 | $attachment = new PortfolioAttachment(); |
||||
1978 | $attachment |
||||
1979 | ->setFilename($_file['name']) |
||||
1980 | ->setComment($comments[$i]) |
||||
1981 | ->setPath($newFileName) |
||||
1982 | ->setOrigin($originId) |
||||
1983 | ->setOriginType($originType) |
||||
1984 | ->setSize($_file['size']); |
||||
1985 | |||||
1986 | $em->persist($attachment); |
||||
1987 | $em->flush(); |
||||
1988 | } |
||||
1989 | } |
||||
1990 | |||||
1991 | private function itemBelongToOwner(Portfolio $item): bool |
||||
1992 | { |
||||
1993 | if ($item->getUser()->getId() != $this->owner->getId()) { |
||||
1994 | return false; |
||||
1995 | } |
||||
1996 | |||||
1997 | return true; |
||||
1998 | } |
||||
1999 | |||||
2000 | private function createFormTagFilter(bool $listByUser = false): FormValidator |
||||
2001 | { |
||||
2002 | $extraField = new ExtraField('portfolio'); |
||||
2003 | $tagFieldInfo = $extraField->get_handler_field_info_by_tags('tags'); |
||||
2004 | |||||
2005 | $chbxTagOptions = array_map( |
||||
2006 | function (array $tagOption) { |
||||
2007 | return $tagOption['tag']; |
||||
2008 | }, |
||||
2009 | $tagFieldInfo['options'] ?? [] |
||||
2010 | ); |
||||
2011 | |||||
2012 | $frmTagList = new FormValidator( |
||||
2013 | 'frm_tag_list', |
||||
2014 | 'get', |
||||
2015 | $this->baseUrl.($listByUser ? 'user='.$this->owner->getId() : ''), |
||||
2016 | '', |
||||
2017 | [], |
||||
2018 | FormValidator::LAYOUT_BOX |
||||
2019 | ); |
||||
2020 | |||||
2021 | if (!empty($chbxTagOptions)) { |
||||
2022 | $frmTagList->addCheckBoxGroup('tags', $tagFieldInfo['display_text'], $chbxTagOptions); |
||||
2023 | } |
||||
2024 | |||||
2025 | $frmTagList->addText('text', get_lang('Search'), false)->setIcon('search'); |
||||
2026 | $frmTagList->applyFilter('text', 'trim'); |
||||
2027 | $frmTagList->addHtml('<br>'); |
||||
2028 | $frmTagList->addButtonFilter(get_lang('Filter')); |
||||
2029 | |||||
2030 | if ($this->course) { |
||||
2031 | $frmTagList->addHidden('cidReq', $this->course->getCode()); |
||||
2032 | $frmTagList->addHidden('id_session', $this->session ? $this->session->getId() : 0); |
||||
2033 | $frmTagList->addHidden('gidReq', 0); |
||||
2034 | $frmTagList->addHidden('gradebook', 0); |
||||
2035 | $frmTagList->addHidden('origin', ''); |
||||
2036 | |||||
2037 | if ($listByUser) { |
||||
2038 | $frmTagList->addHidden('user', $this->owner->getId()); |
||||
2039 | } |
||||
2040 | } |
||||
2041 | |||||
2042 | return $frmTagList; |
||||
2043 | } |
||||
2044 | |||||
2045 | /** |
||||
2046 | * @throws \Exception |
||||
2047 | * |
||||
2048 | * @return \FormValidator |
||||
2049 | */ |
||||
2050 | private function createFormStudentFilter(bool $listByUser = false): FormValidator |
||||
2051 | { |
||||
2052 | $frmStudentList = new FormValidator( |
||||
2053 | 'frm_student_list', |
||||
2054 | 'get', |
||||
2055 | $this->baseUrl, |
||||
2056 | '', |
||||
2057 | [], |
||||
2058 | FormValidator::LAYOUT_BOX |
||||
2059 | ); |
||||
2060 | $slctStudentOptions = []; |
||||
2061 | |||||
2062 | if ($listByUser) { |
||||
2063 | $slctStudentOptions[$this->owner->getId()] = $this->owner->getCompleteName(); |
||||
2064 | } |
||||
2065 | |||||
2066 | $urlParams = http_build_query( |
||||
2067 | [ |
||||
2068 | 'a' => 'search_user_by_course', |
||||
2069 | 'course_id' => $this->course->getId(), |
||||
2070 | 'session_id' => $this->session ? $this->session->getId() : 0, |
||||
2071 | ] |
||||
2072 | ); |
||||
2073 | |||||
2074 | $frmStudentList->addSelectAjax( |
||||
2075 | 'user', |
||||
2076 | get_lang('SelectLearnerPortfolio'), |
||||
2077 | $slctStudentOptions, |
||||
2078 | [ |
||||
2079 | 'url' => api_get_path(WEB_AJAX_PATH)."course.ajax.php?$urlParams", |
||||
2080 | 'placeholder' => get_lang('SearchStudent'), |
||||
2081 | ] |
||||
2082 | ); |
||||
2083 | |||||
2084 | if ($listByUser) { |
||||
2085 | $link = Display::url( |
||||
2086 | get_lang('BackToMainPortfolio'), |
||||
2087 | $this->baseUrl |
||||
2088 | ); |
||||
2089 | } else { |
||||
2090 | $link = Display::url( |
||||
2091 | get_lang('SeeMyPortfolio'), |
||||
2092 | $this->baseUrl.http_build_query(['user' => api_get_user_id()]) |
||||
2093 | ); |
||||
2094 | } |
||||
2095 | |||||
2096 | $frmStudentList->addHtml($link); |
||||
2097 | |||||
2098 | return $frmStudentList; |
||||
2099 | } |
||||
2100 | |||||
2101 | private function getCategoriesForIndex(int $currentUserId): array |
||||
2102 | { |
||||
2103 | $categoriesCriteria = []; |
||||
2104 | $categoriesCriteria['user'] = $this->owner; |
||||
2105 | |||||
2106 | if ($currentUserId !== $this->owner->getId()) { |
||||
2107 | $categoriesCriteria['isVisible'] = true; |
||||
2108 | } |
||||
2109 | |||||
2110 | return $this->em |
||||
2111 | ->getRepository(PortfolioCategory::class) |
||||
2112 | ->findBy($categoriesCriteria); |
||||
2113 | } |
||||
2114 | |||||
2115 | private function getItemsForIndex( |
||||
2116 | bool $listByUser = false, |
||||
2117 | FormValidator $frmFilterList = null |
||||
2118 | ) { |
||||
2119 | $currentUserId = api_get_user_id(); |
||||
2120 | |||||
2121 | if ($this->course) { |
||||
2122 | $queryBuilder = $this->em->createQueryBuilder(); |
||||
2123 | $queryBuilder |
||||
2124 | ->select('pi') |
||||
2125 | ->from(Portfolio::class, 'pi') |
||||
2126 | ->where('pi.course = :course'); |
||||
2127 | |||||
2128 | $queryBuilder->setParameter('course', $this->course); |
||||
2129 | |||||
2130 | if ($this->session) { |
||||
2131 | $queryBuilder->andWhere('pi.session = :session'); |
||||
2132 | $queryBuilder->setParameter('session', $this->session); |
||||
2133 | } else { |
||||
2134 | $queryBuilder->andWhere('pi.session IS NULL'); |
||||
2135 | } |
||||
2136 | |||||
2137 | if ($frmFilterList && $frmFilterList->validate()) { |
||||
2138 | $values = $frmFilterList->exportValues(); |
||||
2139 | |||||
2140 | if (!empty($values['tags'])) { |
||||
2141 | $queryBuilder |
||||
2142 | ->innerJoin(ExtraFieldRelTag::class, 'efrt', Join::WITH, 'efrt.itemId = pi.id') |
||||
2143 | ->innerJoin(ExtraFieldEntity::class, 'ef', Join::WITH, 'ef.id = efrt.fieldId') |
||||
2144 | ->andWhere('ef.extraFieldType = :efType') |
||||
2145 | ->andWhere('ef.variable = :variable') |
||||
2146 | ->andWhere('efrt.tagId IN (:tags)'); |
||||
2147 | |||||
2148 | $queryBuilder->setParameter('efType', ExtraFieldEntity::PORTFOLIO_TYPE); |
||||
2149 | $queryBuilder->setParameter('variable', 'tags'); |
||||
2150 | $queryBuilder->setParameter('tags', $values['tags']); |
||||
2151 | } |
||||
2152 | |||||
2153 | if (!empty($values['text'])) { |
||||
2154 | $queryBuilder->andWhere( |
||||
2155 | $queryBuilder->expr()->orX( |
||||
2156 | $queryBuilder->expr()->like('pi.title', ':text'), |
||||
2157 | $queryBuilder->expr()->like('pi.content', ':text') |
||||
2158 | ) |
||||
2159 | ); |
||||
2160 | |||||
2161 | $queryBuilder->setParameter('text', '%'.$values['text'].'%'); |
||||
2162 | } |
||||
2163 | } |
||||
2164 | |||||
2165 | if ($listByUser) { |
||||
2166 | $queryBuilder |
||||
2167 | ->andWhere('pi.user = :user') |
||||
2168 | ->setParameter('user', $this->owner); |
||||
2169 | } |
||||
2170 | |||||
2171 | $queryBuilder |
||||
2172 | ->andWhere( |
||||
2173 | $queryBuilder->expr()->orX( |
||||
2174 | 'pi.user = :current_user AND (pi.isVisible = TRUE OR pi.isVisible = FALSE)', |
||||
2175 | 'pi.user != :current_user AND pi.isVisible = TRUE' |
||||
2176 | ) |
||||
2177 | ) |
||||
2178 | ->setParameter('current_user', $currentUserId); |
||||
2179 | |||||
2180 | $queryBuilder->orderBy('pi.creationDate', 'DESC'); |
||||
2181 | |||||
2182 | $items = $queryBuilder->getQuery()->getResult(); |
||||
2183 | } else { |
||||
2184 | $itemsCriteria = []; |
||||
2185 | $itemsCriteria['category'] = null; |
||||
2186 | $itemsCriteria['user'] = $this->owner; |
||||
2187 | |||||
2188 | if ($currentUserId !== $this->owner->getId()) { |
||||
2189 | $itemsCriteria['isVisible'] = true; |
||||
2190 | } |
||||
2191 | |||||
2192 | $items = $this->em |
||||
2193 | ->getRepository(Portfolio::class) |
||||
2194 | ->findBy($itemsCriteria, ['creationDate' => 'DESC']); |
||||
2195 | } |
||||
2196 | |||||
2197 | return $items; |
||||
2198 | } |
||||
2199 | |||||
2200 | /** |
||||
2201 | * @throws \Doctrine\ORM\ORMException |
||||
2202 | * @throws \Doctrine\ORM\OptimisticLockException |
||||
2203 | * @throws \Doctrine\ORM\TransactionRequiredException |
||||
2204 | */ |
||||
2205 | private function createCommentForm(Portfolio $item): string |
||||
2206 | { |
||||
2207 | $formAction = $this->baseUrl.http_build_query(['action' => 'view', 'id' => $item->getId()]); |
||||
2208 | |||||
2209 | $form = new FormValidator('frm_comment', 'post', $formAction); |
||||
2210 | $form->addHtmlEditor('content', get_lang('Comments'), true, false, ['ToolbarSet' => 'Minimal']); |
||||
2211 | $form->addHidden('item', $item->getId()); |
||||
2212 | $form->addHidden('parent', 0); |
||||
2213 | $form->applyFilter('content', 'trim'); |
||||
2214 | |||||
2215 | $this->addAttachmentsFieldToForm($form); |
||||
2216 | |||||
2217 | $form->addButtonSave(get_lang('Save')); |
||||
2218 | |||||
2219 | if ($form->validate()) { |
||||
2220 | $values = $form->exportValues(); |
||||
2221 | |||||
2222 | $parentComment = $this->em->find(PortfolioComment::class, $values['parent']); |
||||
2223 | |||||
2224 | $comment = new PortfolioComment(); |
||||
2225 | $comment |
||||
2226 | ->setAuthor($this->owner) |
||||
2227 | ->setParent($parentComment) |
||||
2228 | ->setContent($values['content']) |
||||
2229 | ->setDate(api_get_utc_datetime(null, false, true)) |
||||
2230 | ->setItem($item); |
||||
2231 | |||||
2232 | $this->em->persist($comment); |
||||
2233 | $this->em->flush(); |
||||
2234 | |||||
2235 | $this->processAttachments( |
||||
2236 | $form, |
||||
2237 | $comment->getAuthor(), |
||||
2238 | $comment->getId(), |
||||
2239 | PortfolioAttachment::TYPE_COMMENT |
||||
2240 | ); |
||||
2241 | |||||
2242 | $hook = HookPortfolioItemCommented::create(); |
||||
2243 | $hook->setEventData(['comment' => $comment]); |
||||
2244 | $hook->notifyItemCommented(); |
||||
2245 | |||||
2246 | Display::addFlash( |
||||
2247 | Display::return_message(get_lang('CommentAdded'), 'success') |
||||
2248 | ); |
||||
2249 | |||||
2250 | header("Location: $formAction"); |
||||
2251 | exit; |
||||
0 ignored issues
–
show
In this branch, the function will implicitly return
null which is incompatible with the type-hinted return string . Consider adding a return statement or allowing null as return value.
For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example: interface ReturnsInt {
public function returnsIntHinted(): int;
}
class MyClass implements ReturnsInt {
public function returnsIntHinted(): int
{
if (foo()) {
return 123;
}
// here: null is implicitly returned
}
}
Loading history...
|
|||||
2252 | } |
||||
2253 | |||||
2254 | return $form->returnForm(); |
||||
2255 | } |
||||
2256 | |||||
2257 | private function generateAttachmentList($post, bool $includeHeader = true): string |
||||
2258 | { |
||||
2259 | $attachmentsRepo = $this->em->getRepository(PortfolioAttachment::class); |
||||
2260 | |||||
2261 | $postOwnerId = 0; |
||||
2262 | |||||
2263 | if ($post instanceof Portfolio) { |
||||
2264 | $attachments = $attachmentsRepo->findFromItem($post); |
||||
2265 | |||||
2266 | $postOwnerId = $post->getUser()->getId(); |
||||
2267 | } elseif ($post instanceof PortfolioComment) { |
||||
2268 | $attachments = $attachmentsRepo->findFromComment($post); |
||||
2269 | |||||
2270 | $postOwnerId = $post->getAuthor()->getId(); |
||||
2271 | } |
||||
2272 | |||||
2273 | if (empty($attachments)) { |
||||
2274 | return ''; |
||||
2275 | } |
||||
2276 | |||||
2277 | $currentUserId = api_get_user_id(); |
||||
2278 | |||||
2279 | $listItems = '<ul class="fa-ul">'; |
||||
2280 | |||||
2281 | $deleteIcon = Display::return_icon( |
||||
2282 | 'delete.png', |
||||
2283 | get_lang('DeleteAttachment'), |
||||
2284 | ['style' => 'display: inline-block'], |
||||
2285 | ICON_SIZE_TINY |
||||
2286 | ); |
||||
2287 | $deleteAttrs = ['class' => 'btn-portfolio-delete']; |
||||
2288 | |||||
2289 | /** @var PortfolioAttachment $attachment */ |
||||
2290 | foreach ($attachments as $attachment) { |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
2291 | $downloadParams = http_build_query(['action' => 'download_attachment', 'file' => $attachment->getPath()]); |
||||
2292 | $deleteParams = http_build_query(['action' => 'delete_attachment', 'file' => $attachment->getPath()]); |
||||
2293 | |||||
2294 | $listItems .= '<li>' |
||||
2295 | .'<span class="fa-li fa fa-paperclip" aria-hidden="true"></span>' |
||||
2296 | .Display::url( |
||||
2297 | Security::remove_XSS($attachment->getFilename()), |
||||
2298 | $this->baseUrl.$downloadParams |
||||
2299 | ); |
||||
2300 | |||||
2301 | if ($currentUserId === $postOwnerId) { |
||||
2302 | $listItems .= PHP_EOL.Display::url($deleteIcon, $this->baseUrl.$deleteParams, $deleteAttrs); |
||||
2303 | } |
||||
2304 | |||||
2305 | if ($attachment->getComment()) { |
||||
2306 | $listItems .= PHP_EOL.Display::span( |
||||
2307 | Security::remove_XSS($attachment->getComment()), |
||||
2308 | ['class' => 'text-muted'] |
||||
2309 | ); |
||||
2310 | } |
||||
2311 | |||||
2312 | $listItems .= '</li>'; |
||||
2313 | } |
||||
2314 | |||||
2315 | $listItems .= '</ul>'; |
||||
2316 | |||||
2317 | if ($includeHeader) { |
||||
2318 | $listItems = Display::page_subheader(get_lang('AttachmentFiles'), null, 'h5', ['class' => 'h4']) |
||||
2319 | .$listItems; |
||||
2320 | } |
||||
2321 | |||||
2322 | return $listItems; |
||||
2323 | } |
||||
2324 | |||||
2325 | private function generateItemContent(Portfolio $item): string |
||||
2326 | { |
||||
2327 | $originId = $item->getOrigin(); |
||||
2328 | |||||
2329 | if (empty($originId)) { |
||||
2330 | return $item->getContent(); |
||||
2331 | } |
||||
2332 | |||||
2333 | $em = Database::getManager(); |
||||
2334 | |||||
2335 | $originContent = ''; |
||||
2336 | $originContentFooter = ''; |
||||
2337 | |||||
2338 | if (Portfolio::TYPE_ITEM === $item->getOriginType()) { |
||||
2339 | $origin = $em->find(Portfolio::class, $item->getOrigin()); |
||||
2340 | |||||
2341 | if ($origin) { |
||||
2342 | $originContent = $origin->getContent(); |
||||
2343 | $originContentFooter = vsprintf( |
||||
2344 | get_lang('OriginallyPublishedAsXTitleByYUser'), |
||||
2345 | [$origin->getTitle(), $origin->getUser()->getCompleteName()] |
||||
2346 | ); |
||||
2347 | } |
||||
2348 | } elseif (Portfolio::TYPE_COMMENT === $item->getOriginType()) { |
||||
2349 | $origin = $em->find(PortfolioComment::class, $item->getOrigin()); |
||||
2350 | |||||
2351 | if ($origin) { |
||||
2352 | $originContent = $origin->getContent(); |
||||
2353 | $originContentFooter = vsprintf( |
||||
2354 | get_lang('OriginallyCommentedByXUserInYItem'), |
||||
2355 | [$origin->getAuthor()->getCompleteName(), $origin->getItem()->getTitle()] |
||||
2356 | ); |
||||
2357 | } |
||||
2358 | } |
||||
2359 | |||||
2360 | if ($originContent) { |
||||
2361 | return "<blockquote>$originContent<footer>$originContentFooter</footer></blockquote>" |
||||
2362 | .'<div class="clearfix">'.$item->getContent().'</div>'; |
||||
2363 | } |
||||
2364 | |||||
2365 | return $item->getContent(); |
||||
2366 | } |
||||
2367 | |||||
2368 | private function getItemsInHtmlFormatted(array $items): array |
||||
2369 | { |
||||
2370 | $itemsHtml = []; |
||||
2371 | |||||
2372 | /** @var Portfolio $item */ |
||||
2373 | foreach ($items as $item) { |
||||
2374 | $creationDate = api_convert_and_format_date($item->getCreationDate()); |
||||
2375 | $updateDate = api_convert_and_format_date($item->getUpdateDate()); |
||||
2376 | |||||
2377 | $metadata = '<ul class="list-unstyled text-muted">'; |
||||
2378 | |||||
2379 | if ($item->getSession()) { |
||||
2380 | $metadata .= '<li>'.get_lang('Course').': '.$item->getSession()->getName().' (' |
||||
2381 | .$item->getCourse()->getTitle().') </li>'; |
||||
2382 | } elseif (!$item->getSession() && $item->getCourse()) { |
||||
2383 | $metadata .= '<li>'.get_lang('Course').': '.$item->getCourse()->getTitle().'</li>'; |
||||
2384 | } |
||||
2385 | |||||
2386 | $metadata .= '<li>'.sprintf(get_lang('CreationDateXDate'), $creationDate).'</li>'; |
||||
2387 | $metadata .= '<li>'.sprintf(get_lang('UpdateDateXDate'), $updateDate).'</li>'; |
||||
2388 | |||||
2389 | if ($item->getCategory()) { |
||||
2390 | $metadata .= '<li>'.sprintf(get_lang('CategoryXName'), $item->getCategory()->getTitle()).'</li>'; |
||||
2391 | } |
||||
2392 | |||||
2393 | $metadata .= '</ul>'; |
||||
2394 | |||||
2395 | $itemContent = Security::remove_XSS( |
||||
2396 | $this->generateItemContent($item) |
||||
2397 | ); |
||||
2398 | |||||
2399 | $itemsHtml[] = Display::panel($itemContent, Security::remove_XSS($item->getTitle()), '', 'info', $metadata); |
||||
2400 | } |
||||
2401 | |||||
2402 | return $itemsHtml; |
||||
2403 | } |
||||
2404 | |||||
2405 | private function getCommentsInHtmlFormatted(array $comments): array |
||||
2406 | { |
||||
2407 | $commentsHtml = []; |
||||
2408 | |||||
2409 | /** @var PortfolioComment $comment */ |
||||
2410 | foreach ($comments as $comment) { |
||||
2411 | $item = $comment->getItem(); |
||||
2412 | $date = api_convert_and_format_date($comment->getDate()); |
||||
2413 | |||||
2414 | $metadata = '<ul class="list-unstyled text-muted">'; |
||||
2415 | $metadata .= '<li>'.sprintf(get_lang('DateXDate'), $date).'</li>'; |
||||
2416 | $metadata .= '<li>'.sprintf(get_lang('PortfolioItemTitleXName'), Security::remove_XSS($item->getTitle())) |
||||
2417 | .'</li>'; |
||||
2418 | $metadata .= '</ul>'; |
||||
2419 | |||||
2420 | $commentsHtml[] = Display::panel( |
||||
2421 | Security::remove_XSS($comment->getContent()), |
||||
2422 | '', |
||||
2423 | '', |
||||
2424 | 'default', |
||||
2425 | $metadata |
||||
2426 | ); |
||||
2427 | } |
||||
2428 | |||||
2429 | return $commentsHtml; |
||||
2430 | } |
||||
2431 | |||||
2432 | private function fixImagesSourcesToHtml(string $htmlContent): string |
||||
2433 | { |
||||
2434 | $doc = new DOMDocument(); |
||||
2435 | @$doc->loadHTML($htmlContent); |
||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
loadHTML() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
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...
|
|||||
2436 | |||||
2437 | $elements = $doc->getElementsByTagName('img'); |
||||
2438 | |||||
2439 | if (empty($elements->length)) { |
||||
2440 | return $htmlContent; |
||||
2441 | } |
||||
2442 | |||||
2443 | $webCoursePath = api_get_path(WEB_COURSE_PATH); |
||||
2444 | $webUploadPath = api_get_path(WEB_UPLOAD_PATH); |
||||
2445 | |||||
2446 | /** @var \DOMElement $element */ |
||||
2447 | foreach ($elements as $element) { |
||||
2448 | $src = trim($element->getAttribute('src')); |
||||
2449 | |||||
2450 | if (strpos($src, 'http') === 0) { |
||||
2451 | continue; |
||||
2452 | } |
||||
2453 | |||||
2454 | if (strpos($src, '/app/upload/') === 0) { |
||||
2455 | $element->setAttribute( |
||||
2456 | 'src', |
||||
2457 | preg_replace('/\/app/upload\//', $webUploadPath, $src, 1) |
||||
2458 | ); |
||||
2459 | |||||
2460 | continue; |
||||
2461 | } |
||||
2462 | |||||
2463 | if (strpos($src, '/courses/') === 0) { |
||||
2464 | $element->setAttribute( |
||||
2465 | 'src', |
||||
2466 | preg_replace('/\/courses\//', $webCoursePath, $src, 1) |
||||
2467 | ); |
||||
2468 | |||||
2469 | continue; |
||||
2470 | } |
||||
2471 | } |
||||
2472 | |||||
2473 | return $doc->saveHTML(); |
||||
2474 | } |
||||
2475 | |||||
2476 | private function formatZipIndexFile(HTML_Table $tblItems, HTML_Table $tblComments): string |
||||
2477 | { |
||||
2478 | $htmlContent = Display::page_header($this->owner->getCompleteNameWithUsername()); |
||||
2479 | $htmlContent .= Display::page_subheader2(get_lang('PortfolioItems')); |
||||
2480 | |||||
2481 | $htmlContent .= $tblItems->getRowCount() > 0 |
||||
2482 | ? $tblItems->toHtml() |
||||
2483 | : Display::return_message(get_lang('NoItemsInYourPortfolio'), 'warning'); |
||||
2484 | |||||
2485 | $htmlContent .= Display::page_subheader2(get_lang('PortfolioCommentsMade')); |
||||
2486 | |||||
2487 | $htmlContent .= $tblComments->getRowCount() > 0 |
||||
2488 | ? $tblComments->toHtml() |
||||
2489 | : Display::return_message(get_lang('YouHaveNotCommented'), 'warning'); |
||||
2490 | |||||
2491 | $webAssetsPath = api_get_path(WEB_PUBLIC_PATH).'assets/'; |
||||
2492 | |||||
2493 | $doc = new DOMDocument(); |
||||
2494 | @$doc->loadHTML($htmlContent); |
||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
loadHTML() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
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...
|
|||||
2495 | |||||
2496 | $stylesheet1 = $doc->createElement('link'); |
||||
2497 | $stylesheet1->setAttribute('rel', 'stylesheet'); |
||||
2498 | $stylesheet1->setAttribute('href', $webAssetsPath.'bootstrap/dist/css/bootstrap.min.css'); |
||||
2499 | $stylesheet2 = $doc->createElement('link'); |
||||
2500 | $stylesheet2->setAttribute('rel', 'stylesheet'); |
||||
2501 | $stylesheet2->setAttribute('href', $webAssetsPath.'fontawesome/css/font-awesome.min.css'); |
||||
2502 | $stylesheet3 = $doc->createElement('link'); |
||||
2503 | $stylesheet3->setAttribute('rel', 'stylesheet'); |
||||
2504 | $stylesheet3->setAttribute('href', ChamiloApi::getEditorDocStylePath()); |
||||
2505 | |||||
2506 | $head = $doc->createElement('head'); |
||||
2507 | $head->appendChild($stylesheet1); |
||||
2508 | $head->appendChild($stylesheet2); |
||||
2509 | $head->appendChild($stylesheet3); |
||||
2510 | |||||
2511 | $doc->documentElement->insertBefore( |
||||
2512 | $head, |
||||
2513 | $doc->getElementsByTagName('body')->item(0) |
||||
2514 | ); |
||||
2515 | |||||
2516 | return $doc->saveHTML(); |
||||
2517 | } |
||||
2518 | } |
||||
2519 |
Let?s assume that you have a directory layout like this:
and let?s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/Foo.php
are loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php
However, as
OtherDir/Foo.php
does not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php
, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: