Passed
Push — master ( 323135...9f183a )
by Julito
13:17
created

ResourceController::createResource()   F

Complexity

Conditions 28
Paths 5232

Size

Total Lines 219
Code Lines 137

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 28
eloc 137
nc 5232
nop 2
dl 0
loc 219
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
namespace Chamilo\CoreBundle\Controller;
5
6
use APY\DataGridBundle\Grid\Action\MassAction;
7
use APY\DataGridBundle\Grid\Action\RowAction;
8
use APY\DataGridBundle\Grid\Export\CSVExport;
9
use APY\DataGridBundle\Grid\Export\ExcelExport;
10
use APY\DataGridBundle\Grid\Grid;
11
use APY\DataGridBundle\Grid\Source\Entity;
12
use Chamilo\CoreBundle\Component\Utils\Glide;
13
use Chamilo\CoreBundle\Entity\Resource\ResourceNode;
14
use Chamilo\CoreBundle\Entity\Resource\ResourceRight;
15
use Chamilo\CoreBundle\Repository\ResourceRepository;
16
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
17
use Chamilo\CourseBundle\Controller\CourseControllerInterface;
18
use Chamilo\CourseBundle\Controller\CourseControllerTrait;
19
use Chamilo\CourseBundle\Entity\CDocument;
20
use Chamilo\CourseBundle\Repository\CDocumentRepository;
21
use Doctrine\ORM\EntityManager;
22
use FOS\RestBundle\View\View;
23
use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent;
24
use Sylius\Component\Resource\Exception\UpdateHandlingException;
25
use Sylius\Component\Resource\ResourceActions;
26
use Symfony\Component\HttpFoundation\Request;
27
use Symfony\Component\HttpFoundation\Response;
28
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
29
use Symfony\Component\HttpFoundation\StreamedResponse;
30
use Symfony\Component\HttpKernel\Exception\HttpException;
31
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
32
use Vich\UploaderBundle\Util\Transliterator;
33
34
/**
35
 * Class ResourceController.
36
 *
37
 * @author Julio Montoya <[email protected]>.
38
 */
39
class ResourceController extends BaseController implements CourseControllerInterface
40
{
41
    use CourseControllerTrait;
42
43
    /**
44
     * @param Request $request
45
     *
46
     * @return Response
47
     */
48
    public function indexAction(Request $request): Response
49
    {
50
        return [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array() returns the type array which is incompatible with the type-hinted return Symfony\Component\HttpFoundation\Response.
Loading history...
51
52
        $source = new Entity('ChamiloCourseBundle:CDocument');
0 ignored issues
show
Unused Code introduced by
$source = new APY\DataGr...ourseBundle:CDocument') is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
53
54
        /* @var Grid $grid */
55
        $grid = $this->get('grid');
56
57
        /*$tableAlias = $source->getTableAlias();
58
        $source->manipulateQuery(function (QueryBuilder $query) use ($tableAlias, $course) {
59
                $query->andWhere($tableAlias . '.cId = '.$course->getId());
60
                //$query->resetDQLPart('orderBy');
61
            }
62
        );*/
63
64
        $repository = $this->get('Chamilo\CourseBundle\Repository\CDocumentRepository');
65
66
        $course = $this->getCourse();
67
        $tool = $repository->getTool('document');
68
69
        $parentId = $request->get('parent');
70
        $parent = null;
71
        if (!empty($parentId)) {
72
            $parent = $repository->find($parentId);
73
        }
74
        $resources = $repository->getResourceByCourse($course, $tool, $parent);
75
76
        $source->setData($resources);
77
        $grid->setSource($source);
78
79
        //$grid->hideFilters();
80
        $grid->setLimits(20);
81
        //$grid->isReadyForRedirect();
82
        //$grid->setMaxResults(1);
83
        //$grid->setLimits(2);
84
        /*$grid->getColumn('id')->manipulateRenderCell(
85
            function ($value, $row, $router) use ($course) {
86
                //$router = $this->get('router');
87
                return $router->generate(
88
                    'chamilo_notebook_show',
89
                    array('id' => $row->getField('id'), 'course' => $course)
90
                );
91
            }
92
        );*/
93
94
        $courseIdentifier = $course->getCode();
95
96
        if ($this->isGranted(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)) {
97
            $deleteMassAction = new MassAction(
98
                'Delete',
99
                'chamilo.controller.notebook:deleteMassAction',
100
                true,
101
                ['course' => $courseIdentifier]
102
            );
103
            $grid->addMassAction($deleteMassAction);
104
        }
105
106
        $translation = $this->container->get('translator');
107
108
        $myRowAction = new RowAction(
109
            $translation->trans('View'),
110
            'app_document_show',
111
            false,
112
            '_self',
113
            ['class' => 'btn btn-secondary']
114
        );
115
        $myRowAction->setRouteParameters(['course' => $courseIdentifier, 'id']);
116
        $grid->addRowAction($myRowAction);
117
118
        if ($this->isGranted(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)) {
119
            $myRowAction = new RowAction(
120
                $translation->trans('Edit'),
121
                'app_document_update',
122
                false,
123
                '_self',
124
                ['class' => 'btn btn-secondary']
125
            );
126
            $myRowAction->setRouteParameters(['course' => $courseIdentifier, 'id']);
127
            $grid->addRowAction($myRowAction);
128
129
            $myRowAction = new RowAction(
130
                $translation->trans('Delete'),
131
                'app_document_delete',
132
                false,
133
                '_self',
134
                ['class' => 'btn btn-danger', 'form_delete' => true]
135
            );
136
            $myRowAction->setRouteParameters(['course' => $courseIdentifier, 'id']);
137
            $grid->addRowAction($myRowAction);
138
        }
139
140
        $grid->addExport(new CSVExport($translation->trans('CSV Export'), 'export', ['course' => $courseIdentifier]));
141
142
        $grid->addExport(
143
            new ExcelExport(
144
                $translation->trans('Excel Export'),
145
                'export',
146
                ['course' => $courseIdentifier]
147
            )
148
        );
149
150
        return $grid->getGridResponse('ChamiloCoreBundle:Document:index.html.twig', ['parent_id' => $parentId]);
151
    }
152
153
    /**
154
     * @param Request $request
155
     * @param string  $fileType
156
     *
157
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response|null
158
     */
159
    public function createResource(Request $request, $fileType = 'file')
160
    {
161
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
162
163
        $this->isGrantedOr403($configuration, ResourceActions::CREATE);
164
        /** @var CDocument $newResource */
165
        $newResource = $this->newResourceFactory->create($configuration, $this->factory);
166
        $form = $this->resourceFormFactory->create($configuration, $newResource);
167
168
        $course = $this->getCourse();
169
        $session = $this->getSession();
170
        $newResource->setCourse($course);
171
        $newResource->c_id = $course->getId();
172
        $newResource->setFiletype($fileType);
173
        $form->setData($newResource);
174
175
        $parentId = $request->get('parent');
176
        $parent = null;
177
        if (!empty($parentId)) {
178
            /** @var CDocument $parent */
179
            $parent = $this->repository->find($parentId);
180
        }
181
182
        if ($request->isMethod('POST') && $form->handleRequest($request)->isValid()) {
183
            /** @var CDocument $newResource */
184
            $newResource = $form->getData();
185
            $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $configuration, $newResource);
186
187
            if ($event->isStopped() && !$configuration->isHtmlRequest()) {
188
                throw new HttpException($event->getErrorCode(), $event->getMessage());
189
            }
190
            if ($event->isStopped()) {
191
                $this->flashHelper->addFlashFromEvent($configuration, $event);
192
193
                if ($event->hasResponse()) {
194
                    return $event->getResponse();
195
                }
196
197
                return $this->redirectHandler->redirectToIndex($configuration, $newResource);
198
            }
199
200
            if ($configuration->hasStateMachine()) {
201
                $this->stateMachine->apply($configuration, $newResource);
202
            }
203
204
            //$sharedType = $form->get('shared')->getData();
205
            $shareList = [];
206
            $sharedType = 'this_course';
207
208
            switch ($sharedType) {
209
                case 'this_course':
210
                    if (empty($course)) {
211
                        break;
212
                    }
213
                    // Default Chamilo behaviour:
214
                    // Teachers can edit and students can see
215
                    $shareList = [
216
                        [
217
                            'sharing' => 'course',
218
                            'mask' => ResourceNodeVoter::getReaderMask(),
219
                            'role' => ResourceNodeVoter::ROLE_CURRENT_COURSE_STUDENT,
220
                            'search' => $course->getId(),
221
                        ],
222
                        [
223
                            'sharing' => 'course',
224
                            'mask' => ResourceNodeVoter::getEditorMask(),
225
                            'role' => ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER,
226
                            'search' => $course->getId(),
227
                        ],
228
                    ];
229
                    break;
230
                case 'shared':
231
                    $shareList = $form->get('rights')->getData();
232
                    break;
233
                case 'only_me':
234
                    $shareList = [
235
                        [
236
                            'sharing' => 'user',
237
                            'only_me' => true,
238
                        ],
239
                    ];
240
                    break;
241
            }
242
243
            $resourceNode = $repository->addResourceNode($newResource, $this->getUser(), $parent);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $repository seems to be never defined.
Loading history...
244
245
            // Loops all sharing options
246
            foreach ($shareList as $share) {
247
                $idList = [];
248
                if (isset($share['search'])) {
249
                    $idList = explode(',', $share['search']);
250
                }
251
252
                $resourceRight = null;
253
                if (isset($share['mask'])) {
254
                    $resourceRight = new ResourceRight();
255
                    $resourceRight
256
                        ->setMask($share['mask'])
257
                        ->setRole($share['role'])
258
                    ;
259
                }
260
261
                // Build links
262
                switch ($share['sharing']) {
263
                    case 'everyone':
264
                        $repository->addResourceToEveryone(
265
                            $resourceNode,
266
                            $resourceRight
267
                        );
268
                        break;
269
                    case 'course':
270
                        $repository->addResourceToCourse(
271
                            $resourceNode,
272
                            $course,
273
                            $resourceRight
274
                        );
275
                        break;
276
                    case 'session':
277
                        $repository->addResourceToSession(
278
                            $resourceNode,
279
                            $course,
280
                            $session,
281
                            $resourceRight
282
                        );
283
                        break;
284
                    case 'user':
285
                        // Only for me
286
                        if (isset($share['only_me'])) {
287
                            $repository->addResourceOnlyToMe($resourceNode);
288
                        } else {
289
                            // To other users
290
                            $repository->addResourceToUserList($resourceNode, $idList);
291
                        }
292
                        break;
293
                    case 'group':
294
                        // @todo
295
                        break;
296
                }
297
            }
298
299
            $newResource
300
                ->setCourse($course)
301
                ->setFiletype($fileType)
302
                ->setSession($session)
303
                //->setTitle($title)
304
                //->setComment($comment)
305
                ->setReadonly(false)
306
                ->setResourceNode($resourceNode)
307
            ;
308
309
            $path = \URLify::filter($newResource->getTitle());
310
311
            switch ($fileType) {
312
                case 'folder':
313
                    $newResource
314
                        ->setPath($path)
315
                        ->setSize(0)
316
                    ;
317
                    break;
318
                case 'file':
319
                    $newResource
320
                        ->setPath($path)
321
                        ->setSize(0)
322
                    ;
323
                    break;
324
            }
325
326
            $this->repository->add($newResource);
327
            $postEvent = $this->eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $configuration, $newResource);
328
329
            $newResource->setId($newResource->getIid());
330
            $this->getDoctrine()->getManager()->persist($newResource);
331
            $this->getDoctrine()->getManager()->flush();
332
333
            if (!$configuration->isHtmlRequest()) {
334
                return $this->viewHandler->handle($configuration, View::create($newResource, Response::HTTP_CREATED));
335
            }
336
337
            $this->addFlash('success', 'saved');
338
339
            //$this->flashHelper->addSuccessFlash($configuration, ResourceActions::CREATE, $newResource);
340
            if ($postEvent->hasResponse()) {
341
                return $postEvent->getResponse();
342
            }
343
344
            return $this->redirectToRoute(
345
                'app_document_show',
346
                [
347
                    'id' => $newResource->getIid(),
348
                    'course' => $course->getCode(),
349
                    'parent_id' => $parentId,
350
                ]
351
            );
352
            //return $this->redirectHandler->redirectToResource($configuration, $newResource);
353
        }
354
355
        if (!$configuration->isHtmlRequest()) {
356
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
357
        }
358
359
        $initializeEvent = $this->eventDispatcher->dispatchInitializeEvent(ResourceActions::CREATE, $configuration, $newResource);
360
        if ($initializeEvent->hasResponse()) {
361
            return $initializeEvent->getResponse();
362
        }
363
364
        $view = View::create()
365
            ->setData([
366
                'configuration' => $configuration,
367
                'metadata' => $this->metadata,
368
                'resource' => $newResource,
369
                $this->metadata->getName() => $newResource,
370
                'form' => $form->createView(),
371
                'parent_id' => $parentId,
372
                'file_type' => $fileType,
373
            ])
374
            ->setTemplate($configuration->getTemplate(ResourceActions::CREATE.'.html'))
375
        ;
376
377
        return $this->viewHandler->handle($configuration, $view);
378
    }
379
380
    /**
381
     * @param Request $request
382
     *
383
     * @return Response
384
     */
385
    public function createAction(Request $request): Response
386
    {
387
        return $this->createResource($request, 'folder');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->createResource($request, 'folder') could return the type null which is incompatible with the type-hinted return Symfony\Component\HttpFoundation\Response. Consider adding an additional type-check to rule them out.
Loading history...
388
    }
389
390
    /**
391
     * @param Request $request
392
     *
393
     * @return Response
394
     */
395
    public function createDocumentAction(Request $request): Response
396
    {
397
        return $this->createResource($request, 'file');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->createResource($request, 'file') could return the type null which is incompatible with the type-hinted return Symfony\Component\HttpFoundation\Response. Consider adding an additional type-check to rule them out.
Loading history...
398
    }
399
400
    /**
401
     * Shows a resource.
402
     *
403
     * @param Request             $request
404
     * @param CDocumentRepository $documentRepo
405
     * @param Glide               $glide
406
     *
407
     * @return Response
408
     */
409
    public function getResourceFileAction(Request $request, Glide $glide): Response
410
    {
411
        $id = $request->get('id');
412
        $em = $this->getDoctrine();
413
        $resourceNode = $em->getRepository('ChamiloCoreBundle:Resource\ResourceNode')->find($id);
414
415
        return $this->showFile($resourceNode, $glide, 'show', '');
416
417
418
        /*
419
        $fs = $documentRepo->getFileSystem();
420
        $stream = $fs->readStream($filePath);
421
        $response = new StreamedResponse(function () use ($stream): void {
422
            stream_copy_to_stream($stream, fopen('php://output', 'wb'));
423
        });
424
        $disposition = $response->headers->makeDisposition(
425
            $forceDownload ? ResponseHeaderBag::DISPOSITION_ATTACHMENT : ResponseHeaderBag::DISPOSITION_INLINE,
426
            Transliterator::transliterate($fileName)
427
        );
428
        $response->headers->set('Content-Disposition', $disposition);
429
        $response->headers->set('Content-Type', $mimeType ?: 'application/octet-stream');
430
431
        return $response;*/
432
    }
433
434
    /**
435
     * @param ResourceNode $resourceNode
436
     * @param              $glide
437
     * @param              $type
438
     * @param              $filter
439
     *
440
     * @return StreamedResponse
441
     * @throws \League\Flysystem\FileNotFoundException
442
     */
443
    private function showFile(ResourceNode $resourceNode, $glide, $type, $filter)
444
    {
445
        $fs = $this-> container->get('oneup_flysystem.resources_filesystem');
446
447
        $this->denyAccessUnlessGranted(
448
            ResourceNodeVoter::VIEW,
449
            $resourceNode,
450
            'Unauthorised access to resource'
451
        );
452
        $resourceFile = $resourceNode->getResourceFile();
453
454
        if (!$resourceFile) {
0 ignored issues
show
introduced by
$resourceFile is of type Chamilo\CoreBundle\Entity\Resource\ResourceFile, thus it always evaluated to true.
Loading history...
455
            throw new NotFoundHttpException();
456
        }
457
458
        $fileName = $resourceNode->getName();
459
        $filePath = $resourceFile->getFile()->getPathname();
460
        $mimeType = $resourceFile->getMimeType();
461
462
        switch ($type) {
463
            case 'download':
464
                $forceDownload = true;
465
                break;
466
            case 'show':
467
            default:
468
                $forceDownload = false;
469
                // See filter definition
470
                if (!empty($filter)) {
471
                    $server = $glide->getServer();
472
                    $filter = $glide->getFilters()[$filter] ?? [];
473
474
                    return $server->getImageResponse($filePath, $filter);
475
                }
476
                break;
477
        }
478
479
        $stream = $fs->readStream($filePath);
480
        $response = new StreamedResponse(function () use ($stream): void {
481
            stream_copy_to_stream($stream, fopen('php://output', 'wb'));
0 ignored issues
show
Bug introduced by
It seems like fopen('php://output', 'wb') can also be of type false; however, parameter $dest of stream_copy_to_stream() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

481
            stream_copy_to_stream($stream, /** @scrutinizer ignore-type */ fopen('php://output', 'wb'));
Loading history...
482
        });
483
        $disposition = $response->headers->makeDisposition(
484
            $forceDownload ? ResponseHeaderBag::DISPOSITION_ATTACHMENT : ResponseHeaderBag::DISPOSITION_INLINE,
485
            Transliterator::transliterate($fileName)
486
        );
487
        $response->headers->set('Content-Disposition', $disposition);
488
        $response->headers->set('Content-Type', $mimeType ?: 'application/octet-stream');
489
490
        return $response;
491
    }
492
493
    /**
494
     * Shows a resource.
495
     *
496
     * @param Request             $request
497
     * @param CDocumentRepository $documentRepo
498
     * @param Glide               $glide
499
     *
500
     * @return Response
501
     */
502
    public function showAction(Request $request, CDocumentRepository $documentRepo, Glide $glide): Response
503
    {
504
        $file = $request->get('file');
505
        $type = $request->get('type');
506
        // see list of filters in config/services.yaml
507
        $filter = $request->get('filter');
508
        $type = !empty($type) ? $type : 'show';
509
510
        $criteria = [
511
            'path' => "/$file",
512
            'course' => $this->getCourse(),
513
        ];
514
515
        $document = $documentRepo->findOneBy($criteria);
516
517
        if (null === $document) {
518
            throw new NotFoundHttpException();
519
        }
520
521
        /** @var ResourceNode $resourceNode */
522
        $resourceNode = $document->getResourceNode();
523
524
        return $this->showFile($resourceNode, $glide, $type, $filter);
525
    }
526
527
    /**
528
     * @param Request $request
529
     *
530
     * @return Response
531
     */
532
    public function updateAction(Request $request): Response
533
    {
534
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
535
536
        $this->isGrantedOr403($configuration, ResourceActions::UPDATE);
537
        /** @var CDocument $resource */
538
        $resource = $this->findOr404($configuration);
539
        $resourceNode = $resource->getResourceNode();
540
541
        $this->denyAccessUnlessGranted(
542
            ResourceNodeVoter::EDIT,
543
            $resourceNode,
544
            'Unauthorised access to resource'
545
        );
546
547
        $form = $this->resourceFormFactory->create($configuration, $resource);
548
549
        if (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH'], true) && $form->handleRequest($request)->isValid()) {
550
            $resource = $form->getData();
551
552
            /** @var ResourceControllerEvent $event */
553
            $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource);
554
555
            if ($event->isStopped() && !$configuration->isHtmlRequest()) {
556
                throw new HttpException($event->getErrorCode(), $event->getMessage());
557
            }
558
            if ($event->isStopped()) {
559
                $this->flashHelper->addFlashFromEvent($configuration, $event);
560
561
                if ($event->hasResponse()) {
562
                    return $event->getResponse();
563
                }
564
565
                return $this->redirectHandler->redirectToResource($configuration, $resource);
566
            }
567
568
            try {
569
                $this->resourceUpdateHandler->handle($resource, $configuration, $this->manager);
570
            } catch (UpdateHandlingException $exception) {
571
                if (!$configuration->isHtmlRequest()) {
572
                    return $this->viewHandler->handle(
573
                        $configuration,
574
                        View::create($form, $exception->getApiResponseCode())
575
                    );
576
                }
577
578
                $this->flashHelper->addErrorFlash($configuration, $exception->getFlash());
579
580
                return $this->redirectHandler->redirectToReferer($configuration);
581
            }
582
583
            $postEvent = $this->eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource);
584
585
            if (!$configuration->isHtmlRequest()) {
586
                $view = $configuration->getParameters()->get('return_content', false) ? View::create($resource, Response::HTTP_OK) : View::create(null, Response::HTTP_NO_CONTENT);
587
588
                return $this->viewHandler->handle($configuration, $view);
589
            }
590
591
            $this->flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource);
592
593
            if ($postEvent->hasResponse()) {
594
                return $postEvent->getResponse();
595
            }
596
597
            return $this->redirectHandler->redirectToResource($configuration, $resource);
598
        }
599
600
        if (!$configuration->isHtmlRequest()) {
601
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
602
        }
603
604
        $initializeEvent = $this->eventDispatcher->dispatchInitializeEvent(ResourceActions::UPDATE, $configuration, $resource);
605
        if ($initializeEvent->hasResponse()) {
606
            return $initializeEvent->getResponse();
607
        }
608
609
        $view = View::create()
610
            ->setData([
611
                'configuration' => $configuration,
612
                'metadata' => $this->metadata,
613
                'resource' => $resource,
614
                $this->metadata->getName() => $resource,
615
                'form' => $form->createView(),
616
            ])
617
            ->setTemplate($configuration->getTemplate(ResourceActions::UPDATE.'.html'))
618
        ;
619
620
        return $this->viewHandler->handle($configuration, $view);
621
    }
622
}
623