Passed
Pull Request — 1.11.x (#4364)
by Angel Fernando Quiroz
16:05 queued 06:41
created

LtiLineItemResource::process()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 31
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 22
c 0
b 0
f 0
dl 0
loc 31
rs 8.9457
cc 6
nc 6
nop 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\PluginBundle\Entity\ImsLti\LineItem;
5
use Doctrine\ORM\OptimisticLockException;
6
use Doctrine\ORM\ORMException;
7
use Doctrine\ORM\TransactionRequiredException;
8
use Symfony\Component\HttpFoundation\Request;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Request. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/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 before OtherDir/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:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
9
use Symfony\Component\HttpFoundation\Response;
10
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
11
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
12
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
13
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
14
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
15
16
/**
17
 * Class LtiLineItemResource.
18
 */
19
class LtiLineItemResource extends LtiAdvantageServiceResource
20
{
21
    const URL_TEMPLATE = '/context_id/lineitems/line_item_id';
22
23
    /**
24
     * @var LineItem|null
25
     */
26
    private $lineItem;
27
28
    /**
29
     * LtiLineItemResource constructor.
30
     *
31
     * @param int $toolId
32
     * @param int $courseId
33
     * @param int $lineItemId
34
     *
35
     * @throws ORMException
36
     * @throws OptimisticLockException
37
     * @throws TransactionRequiredException
38
     */
39
    public function __construct($toolId, $courseId, $lineItemId)
40
    {
41
        parent::__construct($toolId, $courseId);
42
43
        $this->lineItem = Database::getManager()->find('ChamiloPluginBundle:ImsLti\LineItem', (int) $lineItemId);
44
    }
45
46
    /**
47
     * @throws OptimisticLockException
48
     */
49
    public function process()
50
    {
51
        switch ($this->request->getMethod()) {
52
            case Request::METHOD_GET:
53
                $this->validateToken(
54
                    [LtiAssignmentGradesService::SCOPE_LINE_ITEM]
55
                );
56
                $this->processGet();
57
                break;
58
            case Request::METHOD_PUT:
59
                if (LtiAssignmentGradesService::AGS_FULL !== $this->tool->getAdvantageServices()['ags']) {
60
                    throw new MethodNotAllowedHttpException([Request::METHOD_GET]);
61
                }
62
63
                $this->validateToken(
64
                    [LtiAssignmentGradesService::SCOPE_LINE_ITEM]
65
                );
66
                $this->processPut();
67
                break;
68
            case Request::METHOD_DELETE:
69
                if (LtiAssignmentGradesService::AGS_FULL !== $this->tool->getAdvantageServices()['ags']) {
70
                    throw new MethodNotAllowedHttpException([Request::METHOD_GET]);
71
                }
72
73
                $this->validateToken(
74
                    [LtiAssignmentGradesService::SCOPE_LINE_ITEM]
75
                );
76
                $this->processDelete();
77
                break;
78
            default:
79
                throw new MethodNotAllowedHttpException([Request::METHOD_GET, Request::METHOD_PUT, Request::METHOD_DELETE]);
80
        }
81
    }
82
83
    /**
84
     * Validate the values for the resource URL.
85
     */
86
    public function validate()
87
    {
88
        if (!$this->course) {
89
            throw new BadRequestHttpException('Course not found.');
90
        }
91
92
        if (!$this->tool) {
93
            throw new BadRequestHttpException('Tool not found.');
94
        }
95
96
        if ($this->tool->getCourse()->getId() !== $this->course->getId()) {
97
            throw new AccessDeniedHttpException('Tool not found in course.');
98
        }
99
100
        if ($this->request->server->get('HTTP_ACCEPT') !== LtiAssignmentGradesService::TYPE_LINE_ITEM) {
101
            throw new UnsupportedMediaTypeHttpException('Unsupported media type.');
102
        }
103
104
        $parentTool = $this->tool->getParent();
105
106
        if ($parentTool) {
107
            $advServices = $parentTool->getAdvantageServices();
108
109
            if (LtiAssignmentGradesService::AGS_NONE === $advServices['ags']) {
110
                throw new AccessDeniedHttpException('Assigment and grade service is not enabled for this tool.');
111
            }
112
        }
113
114
        if (!$this->lineItem) {
115
            throw new NotFoundHttpException('Line item not found');
116
        }
117
118
        if ($this->lineItem->getTool()->getId() !== $this->tool->getId()) {
119
            throw new AccessDeniedHttpException('Line item not found for the tool.');
120
        }
121
    }
122
123
    private function processGet()
124
    {
125
        $data = $this->lineItem->toArray();
0 ignored issues
show
Bug introduced by
The method toArray() 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 ignore-call  annotation

125
        /** @scrutinizer ignore-call */ 
126
        $data = $this->lineItem->toArray();

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...
126
        $data['id'] = LtiAssignmentGradesService::getLineItemUrl(
127
            $this->course->getId(),
128
            $this->lineItem->getId(),
129
            $this->tool->getId()
130
        );
131
132
        $this->response->headers->set('Content-Type', LtiAssignmentGradesService::TYPE_LINE_ITEM);
133
        $this->response->setData($data);
134
    }
135
136
    /**
137
     * @throws OptimisticLockException
138
     */
139
    private function processPut()
140
    {
141
        $data = json_decode($this->request->getContent(), true);
142
143
        if (empty($data) || empty($data['label']) || empty($data['scoreMaximum'])) {
144
            throw new BadRequestHttpException('Missing data to update line item.');
145
        }
146
147
        $this->updateLineItem($data);
148
149
        $data['id'] = LtiAssignmentGradesService::getLineItemUrl(
150
            $this->course->getId(),
151
            $this->lineItem->getId(),
152
            $this->tool->getId()
153
        );
154
        $data['scoreMaximum'] = $this->lineItem->getEvaluation()->getMax();
155
156
        $this->response->headers->set('Content-Type', LtiAssignmentGradesService::TYPE_LINE_ITEM);
157
        $this->response->setEncodingOptions(JSON_UNESCAPED_SLASHES);
158
        $this->response->setData($data);
159
    }
160
161
    /**
162
     * @throws OptimisticLockException
163
     */
164
    private function updateLineItem(array $data)
165
    {
166
        $lineItemEvaluation = $this->lineItem->getEvaluation();
167
        $evaluations = Evaluation::load($lineItemEvaluation->getId());
168
        /** @var Evaluation $evaluation */
169
        $evaluation = $evaluations[0];
170
171
        $lineItemEvaluation->setName($data['label']);
172
173
        if (isset($data['resourceId'])) {
174
            $this->lineItem->setResourceId($data['resourceId']);
175
        }
176
177
        if (isset($data['tag'])) {
178
            $this->lineItem->setTag($data['tag']);
179
        }
180
181
        if (!empty($data['startDateTime'])) {
182
            $startDate = new DateTime($data['startDateTime']);
183
            $this->lineItem->setStartDate($startDate);
184
        }
185
186
        if (!empty($data['endDateTime'])) {
187
            $endDate = new DateTime($data['endDateTime']);
188
            $this->lineItem->setEndDate($endDate);
189
        }
190
191
        if (!$evaluation->has_results()) {
192
            $lineItemEvaluation->setMax($data['scoreMaximum']);
193
        }
194
195
        $em = Database::getManager();
196
        $em->persist($this->lineItem);
197
        $em->persist($lineItemEvaluation);
198
199
        $em->flush();
200
    }
201
202
    /**
203
     * @throws OptimisticLockException
204
     */
205
    private function processDelete()
206
    {
207
        $this->deleteLineItem();
208
209
        $this->response->setStatusCode(Response::HTTP_NO_CONTENT);
210
    }
211
212
    /**
213
     * @throws OptimisticLockException
214
     */
215
    private function deleteLineItem()
216
    {
217
        $lineItemEvaluation = $this->lineItem->getEvaluation();
218
        $evaluations = Evaluation::load($lineItemEvaluation->getId());
219
220
        /** @var Evaluation $evaluation */
221
        $evaluation = $evaluations[0];
222
223
        $em = Database::getManager();
224
225
        $em->remove($this->lineItem);
226
        $em->flush();
227
228
        $evaluation->delete_with_results();
229
    }
230
}
231