ILIAS  trunk Revision v13.0_alpha-62-g3b72d83f2e5
class.ilLTIAdministrationPlatformForm.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
23use ILIAS\Refinery\Factory as Refinery;
24use Psr\Http\Message\ServerRequestInterface;
25use Random\RandomException;
26
38{
39 private const array REGISTRATION_FIELDS = [
40 "platform_id" => "lti_13_platform_id",
41 "client_id" => "lti_13_client_id",
42 "deployment_id" => "lti_13_deployment_id",
43 "keyset_url" => "lti_13_keyset_url",
44 "token_url" => "lti_13_token_url",
45 "authentication_url" => "lti_13_authentication_url",
46 ];
47
48 public function __construct(
49 private readonly ilDBInterface $db,
50 private readonly ilLanguage $lng,
51 private readonly Factory $ui_factory,
52 private readonly ilObjectDefinition $obj_definition,
53 private readonly ilRbacReview $rbac_review,
54 private readonly int $platform_id,
55 private readonly string $version,
56 private readonly Refinery $refinery
57 ) {
58 }
59
60 public function isAdvantage(): bool
61 {
62 return $this->version === ilLTITool::VERSION_ADVANTAGE;
63 }
64
65 public function getForm(string $action): Form
66 {
67 $field = $this->ui_factory->input()->field();
68 $values = $this->platform_id > 0 ? $this->read() : ["active" => false, "types" => []];
69 $role_options = $this->getRoleOptions();
70 $type_options = $this->getObjectTypeOptions();
71
72 $inputs = [
73 "title" => $field->text($this->lng->txt("title"))->withRequired(true)->withValue($values["title"] ?? ""),
74 "description" => $field->text($this->lng->txt("description"))->withValue($values["description"] ?? ""),
75 "prefix" => $field->text($this->lng->txt("prefix"))->withRequired(true)->withValue($values["prefix"] ?? ""),
76 "language" => $field->select($this->lng->txt("language"), $this->getLanguageOptions())->withRequired(true),
77 "types" => $field->multiSelect($this->lng->txt("act_lti_for_obj_type"), $type_options)
78 ->withValue(array_values(array_intersect($values["types"], array_keys($type_options)))),
79 "role" => $field->select($this->lng->txt("gbl_roles_to_users"), $role_options)->withRequired(true),
80 "active" => $field->checkbox($this->lng->txt("active"))->withValue($values["active"]),
81 ];
82 if ($this->isAdvantage()) {
83 $inputs["names_roles"] = $field->checkbox(
84 $this->lng->txt("lti_con_names_roles"),
85 $this->lng->txt("lti_platform_names_roles_info")
86 )->withValue($values["names_roles"] ?? false);
87 }
88 if (isset($values["language"], $this->getLanguageOptions()[$values["language"]])) {
89 $inputs["language"] = $inputs["language"]->withValue($values["language"]);
90 }
91 if (isset($values["role"], $role_options[$values["role"]])) {
92 $inputs["role"] = $inputs["role"]->withValue($values["role"]);
93 }
94
95 $sections = [
96 "general" => $field->section(
97 $inputs,
98 $this->lng->txt($this->platform_id > 0 ? "lti_edit_consumer" : "lti_create_consumer")
99 ),
100 ];
101 if ($this->isAdvantage()) {
102 $registration = $this->readRegistration();
103 $inputs = [];
104 foreach (self::REGISTRATION_FIELDS as $key => $txt) {
105 $inputs[$key] = $field->text($this->lng->txt($txt))->withValue($registration[$key]);
106 }
107 // Dynamic Registration fills the registration in, so it may stay empty, but not half filled
108 $sections["registration"] = $field->section($inputs + [
109 "dynamic_registration_url" => $field->text(
110 $this->lng->txt("lti_dyn_reg_tool_url"),
111 $this->lng->txt($this->platform_id > 0 ? "lti_dyn_reg_tool_url_info" : "lti_dyn_reg_tool_url_after_save")
112 )->withValue($this->platform_id > 0 ? $this->getDynamicRegistrationUrl() : "")->withDisabled(true),
113 // read only data the platform needs: where it starts the login and posts the launch and the Deep
114 // Linking request, and the key set of ILIAS. The objects released to the platform show their target link.
115 "launch_url" => $field->text($this->lng->txt("lti_launch_url"))
116 ->withValue(ilLTIEndpoint::getUrl(ilLTIEndpoint::LAUNCH))->withDisabled(true),
117 "deep_linking_url" => $field->text($this->lng->txt("lti_deep_linking_url"))
118 ->withValue(ilLTIEndpoint::getUrl(ilLTIEndpoint::LAUNCH))->withDisabled(true),
119 "ilias_keyset_url" => $field->text($this->lng->txt("lti_con_key_type_jwk"))
120 ->withValue(ilLTIAdvantageKeyPair::getJwksUrl())->withDisabled(true),
121 ], $this->lng->txt("lti_platform_registration"), $this->lng->txt("lti_platform_registration_info"))
122 ->withAdditionalTransformation($this->refinery->custom()->constraint(
123 static fn(array $data): bool => count(array_unique(array_map(
124 static fn(string $key): bool => trim((string) $data[$key]) === "",
125 array_keys(self::REGISTRATION_FIELDS)
126 ))) === 1,
127 $this->lng->txt("lti_platform_registration_incomplete")
128 ))
129 ->withAdditionalTransformation($this->refinery->custom()->transformation(
130 static fn(array $data): array => array_map(
131 "trim",
132 array_intersect_key($data, self::REGISTRATION_FIELDS)
133 )
134 ))
135 // a launch names the platform by these ids, so two platforms cannot share them
136 ->withAdditionalTransformation($this->refinery->custom()->constraint(
137 fn(array $data): bool => $data["platform_id"] === "" || in_array(
138 ilLTIPlatform::lookupIdByRegistration($data["platform_id"], $data["client_id"], $data["deployment_id"]),
139 [0, $this->platform_id],
140 true
141 ),
142 $this->lng->txt("lti_platform_registration_taken")
143 ));
144 }
145
146 return $this->ui_factory->input()->container()->form()->standard($action, $sections);
147 }
148
152 public function save(string $action, ServerRequestInterface $request): ?Form
153 {
154 $form = $this->getForm($action)->withRequest($request);
155 $data = $form->getData();
156 if ($data === null) {
157 return $form;
158 }
159 $registration = $data["registration"] ?? null;
160 $data = $data["general"];
161
162 $fields = [
163 "title" => ["text", $data["title"]],
164 "description" => ["text", $data["description"]],
165 "prefix" => ["text", $data["prefix"]],
166 "user_language" => ["text", $data["language"]],
167 "role" => ["integer", (int) $data["role"]],
168 "active" => ["integer", (int) $data["active"]],
169 "names_roles" => ["integer", (int) ($data["names_roles"] ?? false)],
170 ];
171 $platform_id = $this->platform_id;
172 if ($platform_id > 0) {
173 $this->db->update("lti_ext_consumer", $fields, ["id" => ["integer", $platform_id]]);
174 } else {
175 $platform_id = $this->db->nextId("lti_ext_consumer");
176 $this->db->insert("lti_ext_consumer", $fields + ["id" => ["integer", $platform_id]]);
177 }
178
179 $this->db->manipulate("DELETE FROM lti_ext_consumer_otype WHERE consumer_id = " . $this->db->quote($platform_id, "integer"));
180 foreach ((array) $data["types"] as $type) {
181 $this->db->insert("lti_ext_consumer_otype", [
182 "consumer_id" => ["integer", $platform_id],
183 "object_type" => ["text", $type],
184 ]);
185 }
186
187 if ($registration !== null) {
188 // a new URL for Dynamic Registration is not used up by saving the form
189 $settings = array_intersect_key(
192 );
193 ilLTIPlatform::saveRegistration($platform_id, $data["title"], (bool) $data["active"], $registration, $settings);
194 }
195
196 return null;
197 }
198
202 private function getDynamicRegistrationUrl(): string
203 {
204 try {
206 } catch (ilException|RandomException $e) {
207 global $DIC;
208
209 $DIC->logger()->forComponent('lti')->error($e->getMessage());
210 return "";
211 }
212 }
213
217 private function readRegistration(): array
218 {
219 // the registration of the platform, or the one of its first released object in older installations
220 $this->db->setLimit(1);
221 $row = $this->platform_id > 0 ? $this->db->fetchAssoc($this->db->query(
222 "SELECT platform_id, client_id, deployment_id, settings FROM lti2_consumer WHERE lti_version = "
223 . $this->db->quote(ilLTITool::VERSION_ADVANTAGE, "text") . " AND ext_consumer_id = "
224 . $this->db->quote($this->platform_id, "integer") . " ORDER BY ref_id"
225 )) : null;
226 $settings = json_decode((string) ($row["settings"] ?? ""), true);
227 $settings = is_array($settings) ? $settings : [];
228
229 return [
230 "platform_id" => (string) ($row["platform_id"] ?? ""),
231 "client_id" => (string) ($row["client_id"] ?? ""),
232 "deployment_id" => (string) ($row["deployment_id"] ?? ""),
233 "keyset_url" => (string) ($settings["_jku"] ?? ""),
234 "token_url" => (string) ($settings["_oauth2_access_token_url"] ?? ""),
235 "authentication_url" => (string) ($settings["_authentication_request_url"] ?? ""),
236 ];
237 }
238
242 private function read(): array
243 {
244 $row = ilLTIPlatform::lookupAdministrationRow($this->platform_id);
245 $types = ilLTIPlatform::lookupObjectTypes($this->platform_id);
246
247 return [
248 "title" => (string) ($row["title"] ?? ""),
249 "description" => (string) ($row["description"] ?? ""),
250 "prefix" => (string) ($row["prefix"] ?? ""),
251 "language" => (string) ($row["user_language"] ?? ""),
252 "role" => (string) ($row["role"] ?? ""),
253 "active" => (bool) ($row["active"] ?? false),
254 "names_roles" => (bool) ($row["names_roles"] ?? false),
255 "types" => $types,
256 ];
257 }
258
262 private function getLanguageOptions(): array
263 {
264 $options = [];
265 foreach ($this->lng->getInstalledLanguages() as $lang_key) {
266 $options[$lang_key] = ilLanguage::_lookupEntry($lang_key, "meta", "meta_l_" . $lang_key);
267 }
268
269 return $options;
270 }
271
275 private function getObjectTypeOptions(): array
276 {
277 $options = [];
278 foreach ($this->obj_definition->getLTIProviderTypes() as $type) {
279 $options[$type] = $this->lng->txt("objs_" . $type);
280 }
281
282 return $options;
283 }
284
288 private function getRoleOptions(): array
289 {
290 $this->lng->loadLanguageModule("rbac");
291 $options = [];
292 foreach (array_diff($this->rbac_review->getGlobalRoles(), [SYSTEM_ROLE_ID, ANONYMOUS_ROLE_ID]) as $role_id) {
293 $options[(string) $role_id] = ilObjRole::_getTranslation(ilObject::_lookupTitle((int) $role_id));
294 }
295
296 return $options;
297 }
298}
$version
Definition: plugin.php:24
$settings
Definition: index.php:44
Builds a Color from either hex- or rgb values.
Definition: Factory.php:31
Builds data types.
Definition: Factory.php:36
Base class for ILIAS Exception handling.
Create and edit form of a platform that may launch ILIAS as an LTI tool.
getDynamicRegistrationUrl()
A new URL each time the form is shown, as each one can be used once.
save(string $action, ServerRequestInterface $request)
Stores the submitted form.
__construct(private readonly ilDBInterface $db, private readonly ilLanguage $lng, private readonly Factory $ui_factory, private readonly ilObjectDefinition $obj_definition, private readonly ilRbacReview $rbac_review, private readonly int $platform_id, private readonly string $version, private readonly Refinery $refinery)
const string SETTING_USED_TOKEN
The setting of the registration of the platform that keeps the id of the token it was made with.
static getRegistrationUrl(int $platform_id)
A new registration URL for the platform of the administration, valid for a day and for one registrati...
static getUrl(string $script, string $suffix='')
The URL of an entry point, with the query or path that follows it.
const string LAUNCH
static lookupIdByRegistration(string $issuer, string $client_id, string $deployment_id)
The platform of the administration an LTI Advantage registration belongs to, 0 when none has it.
static lookupRegistrationSettings(int $platform_id)
The settings of celtic/lti the LTI Advantage registration of a platform of the administration has.
static lookupAdministrationRow(int $platform_id)
The platform of the administration as stored in lti_ext_consumer, empty when it does not exist.
static lookupObjectTypes(int $platform_id)
The types of the objects that can be released to a platform of the administration.
static saveRegistration(int $platform_id, string $name, bool $enabled, array $registration, array $settings=[])
Stores the LTI Advantage registration of a platform of the administration, once for the whole platfor...
const string VERSION_ADVANTAGE
language handling
static _lookupEntry(string $a_lang_key, string $a_mod, string $a_id)
static _getTranslation(string $a_role_title)
parses the objects.xml it handles the xml-description of all ilias objects
static _lookupTitle(int $obj_id)
class ilRbacReview Contains Review functions of core Rbac.
const SYSTEM_ROLE_ID
Definition: constants.php:29
const ANONYMOUS_ROLE_ID
Definition: constants.php:28
This describes a standard form.
Definition: Standard.php:30
This is how the factory for UI elements looks.
Definition: Factory.php:38
Interface ilDBInterface.
$request
@ilCtrl_Calls ilObjLearningSequenceContentGUI: ilObjLearningSequenceConditionsGUI
Definition: ltiauth.php:39
global $lng
Definition: privfeed.php:26
global $DIC
Definition: shib_login.php:26
$data
Definition: storeScorm.php:45