Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
namespace Packback\Lti1p3;
4
 
5
class LtiAssignmentsGradesService extends LtiAbstractService
6
{
7
    public const CONTENTTYPE_SCORE = 'application/vnd.ims.lis.v1.score+json';
8
    public const CONTENTTYPE_LINEITEM = 'application/vnd.ims.lis.v2.lineitem+json';
9
    public const CONTENTTYPE_LINEITEMCONTAINER = 'application/vnd.ims.lis.v2.lineitemcontainer+json';
10
    public const CONTENTTYPE_RESULTCONTAINER = 'application/vnd.ims.lis.v2.resultcontainer+json';
11
 
12
    public function getScope(): array
13
    {
14
        return $this->getServiceData()['scope'];
15
    }
16
 
17
    // https://www.imsglobal.org/spec/lti-ags/v2p0#assignment-and-grade-service-claim
18
    // When an LTI message is launching a resource associated to one and only one lineitem,
19
    // the claim must include the endpoint URL for accessing the associated line item;
20
    // in all other cases, this property must be either blank or not included in the claim.
21
    public function getResourceLaunchLineItem(): ?LtiLineitem
22
    {
23
        $serviceData = $this->getServiceData();
24
        if (empty($serviceData['lineitem'])) {
25
            return null;
26
        }
27
 
28
        return LtiLineitem::new()->setId($serviceData['lineitem']);
29
    }
30
 
31
    public function putGrade(LtiGrade $grade, ?LtiLineitem $lineitem = null)
32
    {
33
        $this->validateScopes([LtiConstants::AGS_SCOPE_SCORE]);
34
 
35
        $lineitem = $this->ensureLineItemExists($lineitem);
36
        $scoreUrl = $this->appendLineItemPath($lineitem, '/scores');
37
 
38
        $request = new ServiceRequest(
39
            ServiceRequest::METHOD_POST,
40
            $scoreUrl,
41
            ServiceRequest::TYPE_SYNC_GRADE
42
        );
43
        $request->setBody($grade);
44
        $request->setContentType(static::CONTENTTYPE_SCORE);
45
 
46
        return $this->makeServiceRequest($request);
47
    }
48
 
49
    public function findLineItem(LtiLineitem $newLineItem): ?LtiLineitem
50
    {
51
        $lineitems = $this->getLineItems();
52
 
53
        foreach ($lineitems as $lineitem) {
54
            if ($this->isMatchingLineitem($lineitem, $newLineItem)) {
55
                return new LtiLineitem($lineitem);
56
            }
57
        }
58
 
59
        return null;
60
    }
61
 
62
    public function updateLineitem(LtiLineitem $lineitemToUpdate): LtiLineitem
63
    {
64
        $request = new ServiceRequest(
65
            ServiceRequest::METHOD_PUT,
66
            $lineitemToUpdate->getId(),
67
            ServiceRequest::TYPE_UPDATE_LINEITEM
68
        );
69
 
70
        $request->setBody($lineitemToUpdate)
71
            ->setContentType(static::CONTENTTYPE_LINEITEM)
72
            ->setAccept(static::CONTENTTYPE_LINEITEM);
73
 
74
        $updatedLineitem = $this->makeServiceRequest($request);
75
 
76
        return new LtiLineitem($updatedLineitem['body']);
77
    }
78
 
79
    public function createLineitem(LtiLineitem $newLineItem): LtiLineitem
80
    {
81
        $request = new ServiceRequest(
82
            ServiceRequest::METHOD_POST,
83
            $this->getServiceData()['lineitems'],
84
            ServiceRequest::TYPE_CREATE_LINEITEM
85
        );
86
        $request->setBody($newLineItem)
87
            ->setContentType(static::CONTENTTYPE_LINEITEM)
88
            ->setAccept(static::CONTENTTYPE_LINEITEM);
89
        $createdLineItem = $this->makeServiceRequest($request);
90
 
91
        return new LtiLineitem($createdLineItem['body']);
92
    }
93
 
94
    public function deleteLineitem(): array
95
    {
96
        $request = new ServiceRequest(
97
            ServiceRequest::METHOD_DELETE,
98
            $this->getServiceData()['lineitem'],
99
            ServiceRequest::TYPE_DELETE_LINEITEM
100
        );
101
 
102
        return $this->makeServiceRequest($request);
103
    }
104
 
105
    public function findOrCreateLineitem(LtiLineitem $newLineItem): LtiLineitem
106
    {
107
        return $this->findLineItem($newLineItem) ?? $this->createLineitem($newLineItem);
108
    }
109
 
110
    public function getGrades(?LtiLineitem $lineitem = null)
111
    {
112
        $lineitem = $this->ensureLineItemExists($lineitem);
113
        $resultsUrl = $this->appendLineItemPath($lineitem, '/results');
114
 
115
        $request = new ServiceRequest(
116
            ServiceRequest::METHOD_GET,
117
            $resultsUrl,
118
            ServiceRequest::TYPE_GET_GRADES
119
        );
120
        $request->setAccept(static::CONTENTTYPE_RESULTCONTAINER);
121
 
122
        return $this->getAll($request);
123
    }
124
 
125
    public function getLineItems(): array
126
    {
127
        $this->validateScopes([LtiConstants::AGS_SCOPE_LINEITEM, LtiConstants::AGS_SCOPE_LINEITEM_READONLY]);
128
 
129
        $request = new ServiceRequest(
130
            ServiceRequest::METHOD_GET,
131
            $this->getServiceData()['lineitems'],
132
            ServiceRequest::TYPE_GET_LINEITEMS
133
        );
134
        $request->setAccept(static::CONTENTTYPE_LINEITEMCONTAINER);
135
 
136
        $lineitems = $this->getAll($request);
137
 
138
        // If there is only one item, then wrap it in an array so the foreach works
139
        if (isset($lineitems['body']['id'])) {
140
            $lineitems['body'] = [$lineitems['body']];
141
        }
142
 
143
        return $lineitems;
144
    }
145
 
146
    public function getLineItem(string $url): LtiLineitem
147
    {
148
        $this->validateScopes([LtiConstants::AGS_SCOPE_LINEITEM, LtiConstants::AGS_SCOPE_LINEITEM_READONLY]);
149
 
150
        $request = new ServiceRequest(
151
            ServiceRequest::METHOD_GET,
152
            $url,
153
            ServiceRequest::TYPE_GET_LINEITEM
154
        );
155
        $request->setAccept(static::CONTENTTYPE_LINEITEM);
156
 
157
        $response = $this->makeServiceRequest($request)['body'];
158
 
159
        return new LtiLineitem($response);
160
    }
161
 
162
    private function ensureLineItemExists(?LtiLineitem $lineitem = null): LtiLineitem
163
    {
164
        // If no line item is passed in, attempt to use the one associated with
165
        // this launch.
166
        if (!isset($lineitem)) {
167
            $lineitem = $this->getResourceLaunchLineItem();
168
        }
169
 
170
        // If none exists still, create a default line item.
171
        if (!isset($lineitem)) {
172
            $defaultLineitem = LtiLineitem::new()
173
                ->setLabel('default')
174
                ->setScoreMaximum(100);
175
            $lineitem = $this->createLineitem($defaultLineitem);
176
        }
177
 
178
        // If the line item does not contain an ID, find or create it.
179
        if (empty($lineitem->getId())) {
180
            $lineitem = $this->findOrCreateLineitem($lineitem);
181
        }
182
 
183
        return $lineitem;
184
    }
185
 
186
    private function isMatchingLineitem(array $lineitem, LtiLineitem $newLineItem): bool
187
    {
188
        return $newLineItem->getTag() == ($lineitem['tag'] ?? null) &&
189
            $newLineItem->getResourceId() == ($lineitem['resourceId'] ?? null) &&
190
            $newLineItem->getResourceLinkId() == ($lineitem['resourceLinkId'] ?? null);
191
    }
192
 
193
    private function appendLineItemPath(LtiLineitem $lineItem, string $suffix): string
194
    {
195
        $url = $lineItem->getId();
196
        $pos = strpos($url, '?');
197
 
198
        if ($pos === false) {
199
            $url = $url.$suffix;
200
        } else {
201
            $url = substr_replace($url, $suffix, $pos, 0);
202
        }
203
 
204
        return $url;
205
    }
206
}