Skip to content

Commit

Permalink
Merge pull request #39 from oat-sa/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Jérôme Bogaerts authored Jul 26, 2016
2 parents 4865896 + c2330ba commit 705af31
Show file tree
Hide file tree
Showing 29 changed files with 351 additions and 28 deletions.
4 changes: 2 additions & 2 deletions src/qtism/data/AssessmentSectionCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2013-2014 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
* Copyright (c) 2013-2016 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
*
* @author Jérôme Bogaerts <[email protected]>
* @license GPLv2
Expand All @@ -30,7 +30,7 @@
* @author Jérôme Bogaerts <[email protected]>
*
*/
class AssessmentSectionCollection extends QtiIdentifiableCollection
class AssessmentSectionCollection extends SectionPartCollection
{
/**
* Check if $value is an AssessmentSection object.
Expand Down
4 changes: 2 additions & 2 deletions src/qtism/data/ExtendedTestPart.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ class ExtendedTestPart extends TestPart
* Create a new ExtendedTestPart object.
*
* @param string $identifier An identifier.
* @param \qtism\data\AssessmentSectionCollection $assessmentSections A collection of AssessmentSection objects.
* @param \qtism\data\SectionPartCollection $assessmentSections A collection of AssessmentSection and/or AssessmentSectionRef objects.
* @param integer $navigationMode A value from the NavigationMode enumeration.
* @param integer $submissionMode A value from the SubmissionMode enumeration.
* @throws \InvalidArgumentException If any of the arguments is invalid.
*/
public function __construct($identifier, AssessmentSectionCollection $assessmentSections, $navigationMode = NavigationMode::LINEAR, $submissionMode = SubmissionMode::INDIVIDUAL)
public function __construct($identifier, SectionPartCollection $assessmentSections, $navigationMode = NavigationMode::LINEAR, $submissionMode = SubmissionMode::INDIVIDUAL)
{
parent::__construct($identifier, $assessmentSections, $navigationMode, $submissionMode);
$this->setTestFeedbackRefs(new TestFeedbackRefCollection());
Expand Down
28 changes: 18 additions & 10 deletions src/qtism/data/TestPart.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2013-2014 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
* Copyright (c) 2013-2016 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
*
* @author Jérôme Bogaerts <[email protected]>
* @license GPLv2
Expand Down Expand Up @@ -113,7 +113,7 @@ class TestPart extends QtiComponent implements QtiIdentifiable
*
* The items contained in each testPart are arranged into sections and sub-sections.
*
* @var \qtism\data\AssessmentSectionCollection
* @var \qtism\data\SectionPartCollection
* @qtism-bean-property
*/
private $assessmentSections;
Expand All @@ -139,12 +139,12 @@ class TestPart extends QtiComponent implements QtiIdentifiable
* Create a new instance of TestPart.
*
* @param string $identifier A QTI Identifier;
* @param AssessmentSectionCollection $assessmentSections A collection of AssessmentSection objects.
* @param SectionPartCollection $assessmentSections A collection of AssessmentSection or AssessmentSectionRef objects objects.
* @param int $navigationMode A value of the NavigationMode enumeration.
* @param int $submissionMode A value of the SubmissionMode enumeration.
* @throws \InvalidArgumentException If an argument has the wrong type or format.
*/
public function __construct($identifier, AssessmentSectionCollection $assessmentSections, $navigationMode = NavigationMode::LINEAR, $submissionMode = SubmissionMode::INDIVIDUAL)
public function __construct($identifier, SectionPartCollection $assessmentSections, $navigationMode = NavigationMode::LINEAR, $submissionMode = SubmissionMode::INDIVIDUAL)
{
$this->setObservers(new SplObjectStorage());

Expand Down Expand Up @@ -341,24 +341,32 @@ public function hasTimeLimits()
}

/**
* Set the AssessmentSection that are part of this Test Part.
* Get the AssessmentSections and/or AssessmentSectionRefs that are part of this Test Part.
*
* @return \qtism\data\AssessmentSectionCollection A collection of AssessmentSection object.
* @return \qtism\data\SectionPartCollection A collection of AssessmentSection and/or AssessmentSectionRef objects.
*/
public function getAssessmentSections()
{
return $this->assessmentSections;
}

/**
* Set the AssessmentSection that are part of this Test Part.
* Set the AssessmentSections and/or AssessmentSectionRefs that are part of this Test Part.
*
* @param AssessmentSectionCollection $assessmentSections A collection of AssessmentSection objects.
* @throws \InvalidArgumentException If $assessmentSections is an empty collection.
* @param SectionPartCollection $assessmentSections A collection of AssessmentSection and/or AssessmentSectionRef objects.
* @throws \InvalidArgumentException If $assessmentSections is an empty collection or contains something else than AssessmentSection and/or AssessmentSectionRef objects.
*/
public function setAssessmentSections(AssessmentSectionCollection $assessmentSections)
public function setAssessmentSections(SectionPartCollection $assessmentSections)
{
if (count($assessmentSections) > 0) {
// Check that we have only AssessmentSection and/ord AssessmentSectionRef objects.
foreach ($assessmentSections as $assessmentSection) {
if (!$assessmentSection instanceof AssessmentSection && !$assessmentSection instanceof AssessmentSectionRef) {
$msg = "A TestPart contain only contain AssessmentSection or AssessmentSectionRef objects.";
throw new InvalidArgumentException($msg);
}
}

$this->assessmentSections = $assessmentSections;
} else {
$msg = 'A TestPart must contain at least one AssessmentSection.';
Expand Down
1 change: 1 addition & 0 deletions src/qtism/data/storage/xml/XmlCompactDocument.php
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ protected static function resolveAssessmentSectionRef(AssessmentSectionRef $asse

$doc = new XmlDocument();
$doc->load($href);
$doc->xInclude();

return $doc->getDocumentComponent();
} catch (XmlStorageException $e) {
Expand Down
54 changes: 52 additions & 2 deletions src/qtism/data/storage/xml/XmlDocument.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
use qtism\data\QtiComponentIterator;
use qtism\data\QtiDocument;
use qtism\data\AssessmentItem;
use qtism\data\AssessmentSectionRef;
use qtism\data\TestPart;
use qtism\data\processing\ResponseProcessing;
use qtism\data\storage\xml\marshalling\Qti20MarshallerFactory;
use qtism\data\storage\xml\marshalling\Qti21MarshallerFactory;
Expand Down Expand Up @@ -411,7 +413,7 @@ public function xInclude($validate = false) {
}
}
} else {
$msg = "Cannot include fragments prior to loading any file.";
$msg = "Cannot include fragments via XInclude before loading any file.";
throw new LogicException($msg);
}
}
Expand Down Expand Up @@ -454,7 +456,55 @@ public function resolveTemplateLocation($validate = false)
}
}
} else {
$msg = "Cannot resolve template location loading any file.";
$msg = "Cannot resolve template location before loading any file.";
throw new LogicException($msg);
}
}

public function includeAssessmentSectionRefs($validate = false)
{
if (($root = $this->getDocumentComponent()) !== null) {

$baseUri = str_replace('\\', '/', $this->getDomDocument()->documentElement->baseURI);
$pathinfo = pathinfo($baseUri);
$basePath = $pathinfo['dirname'];

$count = count($root->getComponentsByClassName('assessmentSectionRef'));
while ($count > 0) {
$iterator = new QtiComponentIterator($root, array('assessmentSectionRef'));
foreach ($iterator as $assessmentSectionRef) {
$parent = $iterator->parent();
$href = $assessmentSectionRef->getHref();

if (Url::isRelative($href) === true) {
$href = Url::rtrim($basePath) . '/' . Url::ltrim($href);

$doc = new XmlDocument();
$doc->load($href, $validate);
$sectionRoot = $doc->getDocumentComponent();

foreach ($sectionRoot->getComponentsByClassName(array('assessmentSectionRef', 'assessmentItemRef')) as $sectionPart) {
$newBasePath = Url::ltrim(str_replace($basePath, '', $href));
$pathinfo = pathinfo($newBasePath);
$newHref = $pathinfo['dirname'] . '/' . Url::ltrim($sectionPart->getHref());
$sectionPart->setHref($newHref);
}

if ($parent instanceof TestPart) {
$collection = $parent->getAssessmentSections();
} else {
$collection = $parent->getSectionParts();
}

$collection->detach($assessmentSectionRef);
$collection->attach($sectionRoot);
}
}

$count = count($root->getComponentsByClassName('assessmentSectionRef'));
}
} else {
$msg = "Cannot resolve assessmentSectionRefs before loading any file.";
throw new LogicException($msg);
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/qtism/data/storage/xml/marshalling/TestPartMarshaller.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
use qtism\data\TestPart;
use qtism\data\TestFeedbackCollection;
use qtism\data\ItemSessionControl;
use qtism\data\AssessmentSectionCollection;
use qtism\data\SectionPartCollection;
use qtism\data\rules\PreConditionCollection;
use qtism\data\rules\BranchRuleCollection;
use qtism\data\TimeLimits;
Expand Down Expand Up @@ -102,8 +102,8 @@ protected function unmarshall(DOMElement $element)
// We do not use the regular DOMElement::getElementsByTagName method
// because it is recursive. We only want the first level elements with
// tagname = 'assessmentSection'.
$assessmentSectionElts = self::getChildElementsByTagName($element, 'assessmentSection');
$assessmentSections = new AssessmentSectionCollection();
$assessmentSectionElts = self::getChildElementsByTagName($element, array('assessmentSection', 'assessmentSectionRef'));
$assessmentSections = new SectionPartCollection();
foreach ($assessmentSectionElts as $sectElt) {
$marshaller = $this->getMarshallerFactory()->createMarshaller($sectElt);
$assessmentSections[] = $marshaller->unmarshall($sectElt);
Expand Down
12 changes: 6 additions & 6 deletions src/qtism/runtime/rendering/markup/xhtml/RubricBlockRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,32 +67,32 @@ protected function appendAttributes(DOMDocumentFragment $fragment, QtiComponent
$dataView = array();

if ($component->getViews()->contains(View::AUTHOR)) {
$this->additionalClass('qti-view-author');
$this->additionalUserClass('qti-view-author');
$dataView[] = 'author';
}

if ($component->getViews()->contains(View::CANDIDATE)) {
$this->additionalClass('qti-view-candidate');
$this->additionalUserClass('qti-view-candidate');
$dataView[] = 'candidate';
}

if ($component->getViews()->contains(View::PROCTOR)) {
$this->additionalClass('qti-view-proctor');
$this->additionalUserClass('qti-view-proctor');
$dataView[] = 'proctor';
}

if ($component->getViews()->contains(View::SCORER)) {
$this->additionalClass('qti-view-scorer');
$this->additionalUserClass('qti-view-scorer');
$dataView[] = 'scorer';
}

if ($component->getViews()->contains(View::TEST_CONSTRUCTOR)) {
$this->additionClass('qti-view-testConstructor');
$this->additionalUserClass('qti-view-testConstructor');
$dataView[] = 'testConstructor';
}

if ($component->getViews()->contains(View::TUTOR)) {
$this->additionalClass('qti-view-tutor');
$this->additionalUserClass('qti-view-tutor');
$dataView[] = 'tutor';
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,49 @@ public function testItemSessionControls() {
$this->assertInstanceOf('qtism\\data\\TestPart', $p02);
$this->assertEquals(4, $p02->getItemSessionControl()->getMaxAttempts());
}

public function testAssessmentSectionRefsInTestParts() {
$doc = new XmlDocument();
$doc->load(self::samplesDir() . 'custom/tests/nested_assessment_section_refs/test_definition/test.xml', true);

$testParts = $doc->getDocumentComponent()->getTestParts();
$this->assertTrue(isset($testParts['T01']));

$sectionParts = $testParts['T01']->getAssessmentSections();
$this->assertTrue(isset($sectionParts['SR01']));
$this->assertInstanceOf('qtism\\data\\AssessmentSectionRef', $sectionParts['SR01']);
}

public function testIncludeAssessmentSectionRefsInTestParts() {
$doc = new XmlDocument();
$doc->load(self::samplesDir() . 'custom/tests/nested_assessment_section_refs/test_definition/test.xml', true);
$doc->includeAssessmentSectionRefs();

$root = $doc->getDocumentComponent();

$testParts = $root->getTestParts();
$this->assertTrue(isset($testParts['T01']));

// Check that assessmentSectionRef 'SR01' has been resolved.
$sectionParts = $testParts['T01']->getAssessmentSections();

$this->assertTrue(isset($sectionParts['S01']));
$this->assertFalse(isset($sectionParts['SR01']));
$this->assertTrue(isset($sectionParts['S01']->getSectionParts()['S02']));

// Check that the final assessmentSection contains the assessmentItemRefs.
$assessmentItemRefs = $sectionParts['S01']->getSectionParts()['S02']->getSectionParts();
$this->assertEquals(3, count($assessmentItemRefs));

$this->assertInstanceOf('qtism\\data\\AssessmentItemRef', $assessmentItemRefs['Q01']);
$this->assertEquals('../sections/../sections/../items/question1.xml', $assessmentItemRefs['Q01']->getHref());
$this->assertInstanceOf('qtism\\data\\AssessmentItemRef', $assessmentItemRefs['Q02']);
$this->assertEquals('../sections/../sections/../items/question2.xml', $assessmentItemRefs['Q02']->getHref());
$this->assertInstanceOf('qtism\\data\\AssessmentItemRef', $assessmentItemRefs['Q03']);
$this->assertEquals('../sections/../sections/../items/question3.xml', $assessmentItemRefs['Q03']->getHref());
}

private static function decorateUri($uri) {
return dirname(__FILE__) . '/../../../../samples/ims/tests/' . $uri;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ public function testCreateFromAssessmentTestEndAttemptIdentifiers() {

$assessmentItemRef = $assessmentItemRefs[0];
$endAttemptIdentifiers = $assessmentItemRef->getEndAttemptIdentifiers();
$this->assertEquals('Q01', $assessmentItemRef->getIdentifier());
$this->assertEquals(1, count($endAttemptIdentifiers));
$this->assertEquals('HINT', $endAttemptIdentifiers[0]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function testCorrectlyFormed() {
public function testNotLoaded() {
$doc = new XmlDocument();

$this->setExpectedException('\\LogicException', 'Cannot resolve template location loading any file.');
$this->setExpectedException('\\LogicException', 'Cannot resolve template location before loading any file.');
$doc->resolveTemplateLocation();
}

Expand Down
Loading

0 comments on commit 705af31

Please sign in to comment.