Skip to content

Commit

Permalink
feat: adjust to split ui parts
Browse files Browse the repository at this point in the history
  • Loading branch information
janbritz committed Jul 11, 2024
1 parent 3ad4770 commit 5d8f040
Show file tree
Hide file tree
Showing 21 changed files with 701 additions and 600 deletions.
58 changes: 58 additions & 0 deletions classes/api/attempt_file.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php
// This file is part of the QuestionPy Moodle plugin - https://questionpy.org
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

namespace qtype_questionpy\api;

use qtype_questionpy\array_converter\array_converter;
use qtype_questionpy\array_converter\converter_config;

defined('MOODLE_INTERNAL') || die;

/**
* A file used in an attempt at a QuestionPy question.
*
* @package qtype_questionpy
* @author Jan Britz
* @copyright 2024 TU Berlin, innoCampus {@link https://www.questionpy.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class attempt_file {
/** @var string */
public string $name;

/** @var string|null */
public ?string $mimetype = null;

/** @var string $data */
public string $data;

/**
* Initializes a new instance.
*
* @param string $name
* @param string $data
* @param string|null $mimetype
*/
public function __construct(string $name, string $data, ?string $mimetype = null) {
$this->name = $name;
$this->data = $data;
$this->mimetype = $mimetype;
}
}

array_converter::configure(attempt_file::class, function (converter_config $config) {
$config->rename("mimetype", "mime_type");
});
7 changes: 6 additions & 1 deletion classes/api/attempt_scored.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,17 @@ class attempt_scored extends attempt {
* @param attempt_ui $ui
* @param string $scoringstate
* @param string $scoringcode
* @param float|null $score
* @param array|null $classification
*/
public function __construct(int $variant, attempt_ui $ui, string $scoringstate, string $scoringcode) {
public function __construct(int $variant, attempt_ui $ui, string $scoringstate, string $scoringcode, ?float $score = null,
?array $classification = null) {
parent::__construct($variant, $ui);

$this->scoringstate = $scoringstate;
$this->scoringcode = $scoringcode;
$this->score = $score;
$this->classification = $classification;
}
}

Expand Down
57 changes: 41 additions & 16 deletions classes/api/attempt_ui.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,36 +31,61 @@
*/
class attempt_ui {
/** @var string */
public string $content;
public string $formulation;

/** @var array string to string mapping of placeholder names to the values (to be replaced in the content) */
public array $placeholders = [];
/** @var string|null */
public ?string $generalfeedback = null;

/** @var string|null specifics TBD */
public ?string $includeinlinecss = null;
/** @var string|null */
public ?string $specificfeedback = null;

/** @var string|null specifics TBD */
public ?string $includecssfile = null;
/** @var string|null */
public ?string $rightanswer = null;

/** @var string specifics TBD */
public string $cachecontrol = "private";
/** @var array<string, string> string to string mapping of placeholder names to the values (to be replaced in the content) */
public array $placeholders = [];

/** @var object[] specifics TBD */
/** @var string[]|null */
public ?array $cssfiles = null;

/** @var array<string, attempt_file> specifics TBD */
public array $files = [];

/** @var string specifics TBD */
public string $cachecontrol = "PRIVATE_CACHE";

/**
* Initializes a new instance.
*
* @param string $content
* @param string $formulation
* @param string|null $generalfeedback
* @param string|null $specificfeedback
* @param string|null $rightanswer
* @param array $placeholders
* @param array|null $cssfiles
* @param array $files
* @param string $cachecontrol
*/
public function __construct(string $content) {
$this->content = $content;
public function __construct(string $formulation, ?string $generalfeedback = null, ?string $specificfeedback = null,
?string $rightanswer = null, array $placeholders = [], ?array $cssfiles = null, array $files = [],
string $cachecontrol = "PRIVATE_CACHE") {
$this->formulation = $formulation;
$this->generalfeedback = $generalfeedback;
$this->specificfeedback = $specificfeedback;
$this->rightanswer = $rightanswer;
$this->placeholders = $placeholders;
$this->cssfiles = $cssfiles;
$this->files = $files;
$this->cachecontrol = $cachecontrol;
}
}

array_converter::configure(attempt_ui::class, function (converter_config $config) {
$config
->rename("includeinlinecss", "include_inline_css")
->rename("includecssfile", "include_css_file")
->rename("cachecontrol", "cache_control");
->rename("generalfeedback", "general_feedback")
->rename("specificfeedback", "specific_feedback")
->rename("rightanswer", "right_answer")
->rename("cssfiles", "css_files")
->rename("cachecontrol", "cache_control")
->array_elements("files", attempt_file::class);
});
112 changes: 112 additions & 0 deletions classes/question_ui_metadata_extractor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php
// This file is part of the QuestionPy Moodle plugin - https://questionpy.org
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

namespace qtype_questionpy;

use DOMAttr;
use DOMDocument;
use DOMElement;
use DOMXPath;

/**
* Parses the question UI XML and extracts the metadata.
*
* @package qtype_questionpy
* @author Maximilian Haye
* @copyright 2023 TU Berlin, innoCampus {@link https://www.questionpy.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class question_ui_metadata_extractor {
/** @var string XML namespace for XHTML */
private const XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
/** @var string XML namespace for our custom things */
private const QPY_NAMESPACE = "http://questionpy.org/ns/question";

/** @var DOMDocument $xml */
private DOMDocument $xml;

/** @var DOMXPath $xpath */
private DOMXPath $xpath;

/** @var question_metadata|null $metadata */
private ?question_metadata $metadata = null;

/**
* Parses the given XML and initializes a new {@see question_ui_metadata_extractor} instance.
*
* @param string $xml XML as returned by the QPy Server
*/
public function __construct(string $xml) {
$this->xml = new DOMDocument();
$this->xml->loadXML($xml);

$this->xpath = new DOMXPath($this->xml);
$this->xpath->registerNamespace("xhtml", self::XHTML_NAMESPACE);
$this->xpath->registerNamespace("qpy", self::QPY_NAMESPACE);
}

/**
* Extracts metadata from the question UI.
*
* @return question_metadata
*/
public function extract(): question_metadata {
if (!is_null($this->metadata)) {
return $this->metadata;
}

$this->metadata = new question_metadata();
/** @var DOMAttr $attr */
foreach ($this->xpath->query("//@qpy:correct-response") as $attr) {
/** @var DOMElement $element */
$element = $attr->ownerElement;
$name = $element->getAttribute("name");
if (!$name) {
continue;
}

if (is_null($this->metadata->correctresponse)) {
$this->metadata->correctresponse = [];
}

if ($element->tagName == "input" && $element->getAttribute("type") == "radio") {
// On radio buttons, we expect the correct option to be marked with correct-response.
$radiovalue = $element->getAttribute("value");
$this->metadata->correctresponse[$name] = $radiovalue;
} else {
$this->metadata->correctresponse[$name] = $attr->value;
}
}

/** @var DOMElement $element */
foreach (
$this->xpath->query(
"//*[self::xhtml:input or self::xhtml:select or self::xhtml:textarea or self::xhtml:button]"
) as $element
) {
$name = $element->getAttribute("name");
if ($name) {
$this->metadata->expecteddata[$name] = PARAM_RAW;

if ($element->hasAttribute("required")) {
$this->metadata->requiredfields[] = $name;
}
}
}

return $this->metadata;
}
}
Loading

0 comments on commit 5d8f040

Please sign in to comment.