closedquestion-8.x-3.x-dev/src/Question/CqOption.php
src/Question/CqOption.php
<?php
namespace Drupal\closedquestion\Question;
use Drupal\closedquestion\Question\Mapping\CqFeedback;
/**
* Class CqOption.
*
* An option in a multiple choice question.
*
* @package Drupal\closedquestion\Question
*/
class CqOption {
/**
* The identifier of this option.
*
* @var string
*/
private $identifier;
/**
* The html to show to the user.
*
* @var string
*/
private $text = '';
/**
* Is this option (part of) the correct answer?
*
* 1 Yes
* 0 No
* -1 Selecting this option doesn't matter.
*
* @var int
*/
private $correct = 0;
/**
* The list of CqFeedback items to use if this item is selected.
*
* @var \Drupal\closedquestion\Question\Mapping\CqFeedback[]
*/
private $feedback = array();
/**
* The list of CqFeedback items to use if this item is not selected.
*
* @var \Drupal\closedquestion\Question\Mapping\CqFeedback[]
*/
private $feedbackUnselected = array();
/**
* HTML for an extended description to use in for instance a mouse-over.
*
* @var string
*/
private $description = '';
/**
* Creates a new CqOption.
*
* @param \DOMElement $node
* Containing the option definition.
* @param CqQuestionInterface $context
* The question or other object that the mapping can query for
* things like the current answer, draggables, hotspots and the parsing of
* html.
*/
public function __construct(\DOMElement $node, CqQuestionInterface $context) {
/** @var \Drupal\closedquestion\Utility\XmlLib $xmlLib */
$xmlLib = \Drupal::service('closedquestion.utility.xml_lib');
foreach ($node->getElementsByTagName('choice') as $choice) {
$this->text .= $xmlLib->getTextContent($choice, $context);
}
foreach ($node->getElementsByTagName('description') as $description) {
$this->description .= $xmlLib->getTextContent($description, $context);
}
foreach ($node->getElementsByTagName('feedback') as $fb) {
$this->feedback[] = CqFeedback::newCqFeedback($fb, $context);
}
foreach ($node->getElementsByTagName('feedbackunselected') as $fb) {
$this->feedbackUnselected[] = CqFeedback::newCqFeedback($fb, $context);
}
$attribs = $node->attributes;
$item = $attribs->getNamedItem('correct');
if ($item !== NULL) {
$this->correct = (int) $item->value;
}
$item = $attribs->getNamedItem('identifier');
if ($item === NULL) {
$item = $attribs->getNamedItem('id');
}
if ($item === NULL) {
$item = $attribs->getNamedItem('name');
}
if ($item !== NULL) {
$this->identifier = $item->nodeValue;
}
}
/**
* Getter for the identifier.
*
* @return int
* ID.
*/
public function getIdentifier() {
return $this->identifier;
}
/**
* Getter for the text.
*
* @return string
* Text.
*/
public function getText() {
return $this->text;
}
/**
* Getter for the description.
*
* @return string
* Description.
*/
public function getDescription() {
return $this->description;
}
/**
* Is this option (part of) the correct answer?
*
* 1 Yes
* 0 No
* -1 Selecting this option doesn't matter.
*
* @return int
* Result of the check.
*/
public function getCorrect() {
return $this->correct;
}
/**
* Check if the user gave the correct answer for this option.
*
* @param string $answer
* A string longer than 1 character if the option is selected, a string of 1
* character or shorter of the option is not selected.
*
* @return bool
* TRUE if answer is correct.
*/
public function correctlyAnswered($answer) {
if (mb_strlen($answer) <= 1 && $this->correct != 0) {
return FALSE;
}
if (mb_strlen($answer) > 1 && $this->correct == 0) {
return FALSE;
}
return TRUE;
}
/**
* Returns feedback items.
*
* Return the relevant feedback items for the given number of tries and the
* given selected status.
*
* @param int $tries
* The number of times the student already tried to answer this question.
* @param bool $selected
* Has the student selected this option? Defaults to TRUE.
*
* @return \Drupal\closedquestion\Question\Mapping\CqFeedback[]
* Feedback items.
*/
public function getFeedback($tries, $selected = TRUE) {
$retVal = array();
if ($selected) {
foreach ($this->feedback as $fb) {
if ($fb->inRange($tries)) {
$retVal[] = $fb;
}
}
}
else {
foreach ($this->feedbackUnselected as $fb) {
if ($fb->inRange($tries)) {
$retVal[] = $fb;
}
}
}
return $retVal;
}
/**
* Gets feedback.
*
* Getter for feedback, the full list of feedback items used when the option
* is selected.
*
* @return \Drupal\closedquestion\Question\Mapping\CqFeedback[]
* Feedback items.
*/
public function getFeedbackItems() {
return $this->feedback;
}
/**
* Gets unused feedback.
*
* Getter for feedbackUnselected, the full list of feedback items used when
* the option is not selected.
*
* @return \Drupal\closedquestion\Question\Mapping\CqFeedback[]
* Feedback items.
*/
public function getFeedbackUnselectedItems() {
return $this->feedbackUnselected;
}
/**
* Get all the text in the option, for easier reviewing for spelling, etc.
*
* @return array
* Themeable form array.
*/
public function getAllText() {
$retval = array();
$retval['#theme'] = 'closedquestion_option';
$retval['#identifier'] = $this->getIdentifier();
$retval['#correct'] = $this->getCorrect();
$retval['#text'] = $this->getText();
$description = $this->getDescription();
if ($description) {
$retval['description'] = $description;
}
$feedback = $this->getFeedbackItems();
if (count($feedback) > 0) {
$retval['feedback'] = array(
'#theme' => 'closedquestion_feedback_list',
'#extended' => TRUE,
);
foreach ($feedback as $fbitem) {
$retval['feedback']['items'][] = $fbitem->getAllText();
}
}
$feedback = $this->getFeedbackUnselectedItems();
if (count($feedback) > 0) {
$retval['feedback_notselected'] = array(
'#theme' => 'closedquestion_feedback_list',
'#extended' => TRUE,
);
foreach ($feedback as $fbitem) {
$retval['feedback_notselected']['items'][] = $fbitem->getAllText();
}
}
return $retval;
}
}
