GitHub – oat-sa/qti-sdk: A QTI (Question & Test Interoperability) Software Development Kit for PHP

QTI-SDK

Latest Version
Coverage Status
License GPL2
Packagist Downloads

QTI Software Development Kit for PHP

An IMS QTI (Question & Test Interoperability) Software Development Kit for PHP 7.0 and higher supporting a wide
range of features described by the IMS QTI specification family.

This implementation of QTI is under constant enhancement. The API of the master branch might change at any time.

Features

  • Targets QTI 2.0, 2.1 and partially 2.2
  • Complete QTI Information Model
  • Complete QTI Rule Engine Support
  • Custom Operator Hooks through PSR-0/PSR-4
  • Wilbert Kraan’s / Steve Lay’s Goldilocks Rendering
  • CSS Parser for direct QTI Information Model mapping at rendering time
  • Item and Test Sessions (with lightning fast binary persistence)
  • Nice and Clean API for QTI Document manipulation/traversal
  • PreConditions & Branching
  • Selection and Ordering
  • Response, Outcome and Template Processing
  • aria-* attributes
  • Unit test driven

Installation (developers)

  1. Clone the repository.
  2. Make sure you know how Composer works and it is installed on your system.
  3. php composer.phar install
  4. You are ready!

Unit Tests (developers)

Run Unit Tests by invoking the following shell command:

cp phpunit.xml.dist phpunit.xml
./vendor/bin/phpunit 

test

Contribute

We are always looking for people to feed the project with:

  • Bug reports
  • Unit tests
  • New features

Please make yourself known!

QTI Item Session Management

Introduction Example

The following example demonstrates how to instantiate an item session for a given QTI XML item document. The item
in use in this example is the “Composition of Water” item, from the QTI 2.1 Implementation Guide.

<?php

use

qtism\common\enums\

BaseType

;

use

qtism\common\enums\

Cardinality

;

use

qtism\common\datatypes\

QtiIdentifier

;

use

qtism\data\storage\xml\

XmlDocument

;

use

qtism\runtime\common\

State

;

use

qtism\runtime\common\

ResponseVariable

;

use

qtism\runtime\common\

MultipleContainer

;

use

qtism\runtime\tests\

AssessmentItemSession

;

// Instantiate a new QTI XML document, and load a QTI XML document.

$

itemDoc =

new

XmlDocument

(

'2.1'

);

$

itemDoc->

load

(

'choice_multiple.xml'

);

/*

* A QTI XML document can be used to load various pieces of QTI content such as assessmentItem,

* assessmentTest, responseProcessing, ... components. Our target is an assessmentItem, which is the

* root component of our document.

*/

$

item =

$

itemDoc->

getDocumentComponent

();

/*

* The item session represents the collected and computed data related to the interactions a

* candidate performs on a single assessmentItem. As per the QTI specification, "an item session

* is the accumulation of all attempts at a particular instance of an assessmentItem made by

* a candidate.

*/

$

itemSession =

new

AssessmentItemSession

(

$

item);

// The candidate is entering the item session, and is beginning his first attempt.

$

itemSession->

beginItemSession

();

$

itemSession->

beginAttempt

();

/*

* We instantiate the responses provided by the candidate for this assessmentItem, for the current

* item session. For this assessmentItem, the data collected from the candidate is represented by

* a State, composed of a single ResponseVariable named 'RESPONSE'.

*/

$

responses =

new

State

(

array

(

// The 'RESPONSE' ResponseVariable has a QTI multiple cardinality, and a QTI identifier baseType.

new

ResponseVariable

(

'RESPONSE'

,

Cardinality

::

MULTIPLE

,

BaseType

::

IDENTIFIER

,

/*

* The ResponseVariable value is a Container with multiple cardinality and an identifier

* baseType to meet the cardinality and baseType requirements of the ResponseVariable.

*/

new

MultipleContainer

(

BaseType

::

IDENTIFIER

,

/*

* The values composing the Container are identifiers 'H' and 'O', which represent

* the correct response to this item.

*/

array

(

new

QtiIdentifier

(

'H'

),

new

QtiIdentifier

(

'O'

) ) ) ) ) );

/*

* The candidate is finishing the current attempt, by providing a correct response.

* ResponseProcessing takes place to produce a new value for the 'SCORE' OutcomeVariable.

*/

$

itemSession->

endAttempt

(

$

responses);

// The item session variables and their values can be accessed by their identifier.

echo

'numAttempts: '

.

$

itemSession[

'numAttempts'

] . "\n";

echo

'completionStatus: '

.

$

itemSession[

'completionStatus'

] . "\n";

echo

'RESPONSE: '

.

$

itemSession[

'RESPONSE'

] . "\n";

echo

'SCORE: '

.

$

itemSession[

'SCORE'

] . "\n";

/*

* numAttempts: 1

* completionStatus: completed

* RESPONSE: ['H'; 'O']

* SCORE: 2

*/

// End the current item session.

$

itemSession->

endItemSession

();

Multiple Attempts Example

As per the QTI specification, item sessions allow a single attempt to be performed by default. Trying to begin an
attempt that will make the item session exceeding the maximum number of attempts will lead to a PHP exception, as in
the following example.

<?php

use

qtism\data\storage\xml\

XmlDocument

;

use

qtism\runtime\common\

State

;

use

qtism\runtime\tests\

AssessmentItemSession

;

use

qtism\runtime\tests\

AssessmentItemSessionException

;

$

itemDoc =

new

XmlDocument

(

'2.1'

);

$

itemDoc->

load

(

'choice_multiple.xml'

);

$

item =

$

itemDoc->

getDocumentComponent

();

$

itemSession =

new

AssessmentItemSession

(

$

item);

$

itemSession->

beginItemSession

();

// Begin 1st attempt.

$

itemSession->

beginAttempt

();

// End attempt by providing an empty response...

$

itemSession->

endAttempt

(

new

State

());

// Begin 2nd attempt, but by default, maximum number of attempts is 1.

try

{

$

itemSession->

beginAttempt

(); }

catch

(

AssessmentItemSessionException

$

e) {

echo

$

e->

getMessage

();

// A new attempt for item 'choiceMultiple' is not allowed. The maximum number of attempts (1) is reached.

}

If multiple attempts are permitted on a given assessmentItem, the itemSessionControl‘s maxAttempts attribute
can be modified to allow multiple or unlimited attempts that can be performed by a candidate.

<?php

use

qtism\data\

ItemSessionControl

;

use

qtism\data\storage\xml\

XmlDocument

;

use

qtism\runtime\common\

State

;

use

qtism\runtime\tests\

AssessmentItemSession

;

$

itemDoc =

new

XmlDocument

(

'2.1'

);

$

itemDoc->

load

(

'choice_multiple.xml'

);

$

item =

$

itemDoc->

getDocumentComponent

();

$

itemSession =

new

AssessmentItemSession

(

$

item);

// Set the maximum number of attempts to 0 (means unlimited).

$

itemSessionControl =

new

ItemSessionControl

();

$

itemSessionControl->

setMaxAttempts

(

0

);

$

itemSession->

setItemSessionControl

(

$

itemSessionControl);

// Performing multiple attempts will not lead to a PHP exception anymore, because the maximum number of attemps is unlimited!

$

itemSession->

beginItemSession

();

// 1st attempt will be an incorrect response from the candidate (['H'; 'Cl']).

$

responses =

new

State

(

array

(

new

ResponseVariable

(

'RESPONSE'

,

Cardinality

::

MULTIPLE

,

BaseType

::

IDENTIFIER

,

new

MultipleContainer

(

BaseType

::

IDENTIFIER

,

array

(

new

QtiIdentifier

(

'H'

),

new

QtiIdentifier

(

'Cl'

) ) ) ) ) );

$

itemSession->

endAttempt

(

$

responses);

echo

'numAttempts: '

.

$

itemSession[

'numAttempts'

] . "\n";

echo

'completionStatus: '

.

$

itemSession[

'completionStatus'

] . "\n";

echo

'RESPONSE: '

.

$

itemSession[

'RESPONSE'

] . "\n";

echo

'SCORE: '

.

$

itemSession[

'SCORE'

] . "\n";

/*

* numAttempts: 1

* completionStatus: completed

* RESPONSE: ['H'; 'N']

* SCORE: 0

*/

// 2nd attempt will send a correct response this time (['H'; 'O'])!

$

itemSession->

beginAttempt

();

$

responses[

'RESPONSE'

][

1

]->

setValue

(

'O'

);

$

itemSession->

endAttempt

();

echo

'numAttempts: '

.

$

itemSession[

'numAttempts'

] . "\n";

echo

'completionStatus: '

.

$

itemSession[

'completionStatus'

] . "\n";

echo

'RESPONSE: '

.

$

itemSession[

'RESPONSE'

] . "\n";

echo

'SCORE: '

.

$

itemSession[

'SCORE'

] . "\n";

/*

* numAttempts: 2

* completionStatus: completed

* RESPONSE: ['H'; 'O']

* SCORE: 2

*/

$

itemSession->

endItemSession

();

You can get more information on the QTI-SDK GitHub Wiki!

QTI Rendering

The QTI Software Development Kit enables you to transform XML serialized QTI files
into their (X)HTML5 Goldilocks equivalent. The following shell command renders the path/to/qti.xml QTI file into an HTML5
document using the (X)HTML5 Golidlocks rendering flavour with indentation formatting. The rendering output (stdout)
is redirected to the /home/jerome/qti.html file.

./vendor/bin/qtisdk render -df --source path/to/qti.xml --flavour goldilocks 

>

/home/jerome/qti.html

For additional help and information, just call the help screen to know about the features provided by the rendering binaries!

./vendor/bin/qtisdk render --help

Configuration

As for other major PHP frameworks such as Doctrine QTI-SDK makes use
of annotations. In such a context, the two following Zend Opcache configuration directives must be
configured as below.