See Release Notes
Long Term Support Release
Differences Between: [Versions 400 and 401] [Versions 401 and 403]
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 if (!in_array(LtiConstants::AGS_SCOPE_SCORE, $this->getScope())) { 34 throw new LtiException('Missing required scope', 1); 35 } 36 37 $lineitem = $this->ensureLineItemExists($lineitem); 38 39 $scoreUrl = $lineitem->getId(); 40 41 // Place '/scores' before url params 42 $pos = strpos($scoreUrl, '?'); 43 $scoreUrl = $pos === false ? $scoreUrl.'/scores' : substr_replace($scoreUrl, '/scores', $pos, 0); 44 45 $request = new ServiceRequest( 46 ServiceRequest::METHOD_POST, 47 $scoreUrl, 48 ServiceRequest::TYPE_SYNC_GRADE 49 ); 50 $request->setBody($grade); 51 $request->setContentType(static::CONTENTTYPE_SCORE); 52 53 return $this->makeServiceRequest($request); 54 } 55 56 public function findLineItem(LtiLineitem $newLineItem): ?LtiLineitem 57 { 58 $lineitems = $this->getLineItems(); 59 60 foreach ($lineitems as $lineitem) { 61 if ($this->isMatchingLineitem($lineitem, $newLineItem)) { 62 return new LtiLineitem($lineitem); 63 } 64 } 65 66 return null; 67 } 68 69 public function updateLineitem(LtiLineItem $lineitemToUpdate): LtiLineitem 70 { 71 $request = new ServiceRequest( 72 ServiceRequest::METHOD_PUT, 73 $this->getServiceData()['lineitems'], 74 ServiceRequest::TYPE_UPDATE_LINEITEM 75 ); 76 77 $request->setBody($lineitemToUpdate) 78 ->setContentType(static::CONTENTTYPE_LINEITEM) 79 ->setAccept(static::CONTENTTYPE_LINEITEM); 80 81 $updatedLineitem = $this->makeServiceRequest($request); 82 83 return new LtiLineitem($updatedLineitem['body']); 84 } 85 86 public function createLineitem(LtiLineitem $newLineItem): LtiLineitem 87 { 88 $request = new ServiceRequest( 89 ServiceRequest::METHOD_POST, 90 $this->getServiceData()['lineitems'], 91 ServiceRequest::TYPE_CREATE_LINEITEM 92 ); 93 $request->setBody($newLineItem) 94 ->setContentType(static::CONTENTTYPE_LINEITEM) 95 ->setAccept(static::CONTENTTYPE_LINEITEM); 96 $createdLineItem = $this->makeServiceRequest($request); 97 98 return new LtiLineitem($createdLineItem['body']); 99 } 100 101 public function findOrCreateLineitem(LtiLineitem $newLineItem): LtiLineitem 102 { 103 return $this->findLineItem($newLineItem) ?? $this->createLineitem($newLineItem); 104 } 105 106 public function getGrades(LtiLineitem $lineitem = null) 107 { 108 $lineitem = $this->ensureLineItemExists($lineitem); 109 $resultsUrl = $lineitem->getId(); 110 111 // Place '/results' before url params 112 $pos = strpos($resultsUrl, '?'); 113 $resultsUrl = $pos === false ? $resultsUrl.'/results' : substr_replace($resultsUrl, '/results', $pos, 0); 114 115 $request = new ServiceRequest( 116 ServiceRequest::METHOD_GET, 117 $resultsUrl, 118 ServiceRequest::TYPE_GET_GRADES 119 ); 120 $request->setAccept(static::CONTENTTYPE_RESULTCONTAINER); 121 $scores = $this->makeServiceRequest($request); 122 123 return $scores['body']; 124 } 125 126 public function getLineItems(): array 127 { 128 if (!in_array(LtiConstants::AGS_SCOPE_LINEITEM, $this->getScope())) { 129 throw new LtiException('Missing required scope', 1); 130 } 131 132 $request = new ServiceRequest( 133 ServiceRequest::METHOD_GET, 134 $this->getServiceData()['lineitems'], 135 ServiceRequest::TYPE_GET_LINEITEMS 136 ); 137 $request->setAccept(static::CONTENTTYPE_LINEITEMCONTAINER); 138 139 $lineitems = $this->getAll($request); 140 141 // If there is only one item, then wrap it in an array so the foreach works 142 if (isset($lineitems['body']['id'])) { 143 $lineitems['body'] = [$lineitems['body']]; 144 } 145 146 return $lineitems; 147 } 148 149 public function getLineItem(string $url): LtiLineitem 150 { 151 if (!in_array(LtiConstants::AGS_SCOPE_LINEITEM, $this->getScope())) { 152 throw new LtiException('Missing required scope', 1); 153 } 154 155 $request = new ServiceRequest( 156 ServiceRequest::METHOD_GET, 157 $url, 158 ServiceRequest::TYPE_GET_LINEITEM 159 ); 160 $request->setAccept(static::CONTENTTYPE_LINEITEM); 161 162 $response = $this->makeServiceRequest($request)['body']; 163 164 return new LtiLineitem($response); 165 } 166 167 private function ensureLineItemExists(LtiLineitem $lineitem = null): LtiLineitem 168 { 169 // If no line item is passed in, attempt to use the one associated with 170 // this launch. 171 if (!isset($lineitem)) { 172 $lineitem = $this->getResourceLaunchLineItem(); 173 } 174 175 // If none exists still, create a default line item. 176 if (!isset($lineitem)) { 177 $defaultLineitem = LtiLineitem::new() 178 ->setLabel('default') 179 ->setScoreMaximum(100); 180 $lineitem = $this->createLineitem($defaultLineitem); 181 } 182 183 // If the line item does not contain an ID, find or create it. 184 if (empty($lineitem->getId())) { 185 $lineitem = $this->findOrCreateLineitem($lineitem); 186 } 187 188 return $lineitem; 189 } 190 191 private function isMatchingLineitem(array $lineitem, LtiLineitem $newLineItem): bool 192 { 193 return $newLineItem->getTag() == ($lineitem['tag'] ?? null) && 194 $newLineItem->getResourceId() == ($lineitem['resourceId'] ?? null) && 195 $newLineItem->getResourceLinkId() == ($lineitem['resourceLinkId'] ?? null); 196 } 197 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body