questlab/questtypes/dragndrop/DragndropQuesttypeController.inc

528 lines
21 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Questlab
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @copyright 2014 2016 Heinrich-Heine-Universität Düsseldorf
* @license http://www.gnu.org/licenses/gpl.html
* @link https://github.com/coderkun/questlab
*/
namespace hhu\z\questtypes;
/**
* Controller of the DragndropQuesttypeAgent for Drag&Drop.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class DragndropQuesttypeController extends \hhu\z\controllers\QuesttypeController
{
/**
* Required models
*
* @var array
*/
public $models = array('media');
/**
* Required components
*
* @var array
*/
public $components = array('validation');
/**
* Save the answers of a Character for a Quest.
*
* @param array $seminary Current Seminary data
* @param array $questgroup Current Questgroup data
* @param array $quest Current Quest data
* @param array $character Current Character data
* @param array $answers Character answers for the Quest
*/
public function saveAnswersOfCharacter($seminary, $questgroup, $quest, $character, $answers)
{
// Get Drag&Drop field
$dndField = $this->Dragndrop->getDragndrop($quest['id']);
// Get Drops
$drops = $this->Dragndrop->getDrops($dndField['quest_id']);
// Save user answers
foreach($drops as &$drop)
{
// Determine user answer
$answer = null;
if(array_key_exists($drop['id'], $answers) && !empty($answers[$drop['id']]))
{
$a = intval(substr($answers[$drop['id']], 4));
if($a !== false && $a > 0) {
$answer = $a;
}
}
// Update database record
$this->Dragndrop->setCharacterSubmission($drop['id'], $character['id'], $answer);
}
}
/**
* Save additional data for the answers of a Character for a Quest.
*
* @param array $seminary Current Seminary data
* @param array $questgroup Current Questgroup data
* @param array $quest Current Quest data
* @param array $character Current Character data
* @param array $data Additional (POST-) data
*/
public function saveDataForCharacterAnswers($seminary, $questgroup, $quest, $character, $data)
{
}
/**
* Check if answers of a Character for a Quest match the correct ones.
*
* @param array $seminary Current Seminary data
* @param array $questgroup Current Questgroup data
* @param array $quest Current Quest data
* @param array $character Current Character data
* @param array $answers Character answers for the Quest
* @return boolean True/false for a right/wrong answer or null for moderator evaluation
*/
public function matchAnswersOfCharacter($seminary, $questgroup, $quest, $character, $answers)
{
// Get Drag&Drop field
$dndField = $this->Dragndrop->getDragndrop($quest['id']);
// Get Drags
$drags = $this->Dragndrop->getDrags($dndField['quest_id'], true);
// Match drags with user answers
foreach($drags as &$drag)
{
$founds = array_keys($answers, 'drag'.$drag['id']);
if(count($founds) != 1) {
return false;
}
if(!$this->Dragndrop->dragMatchesDrop($drag['id'], $founds[0])) {
return false;
}
}
// Set status
return true;
}
/**
* Action: quest.
*
* Display a text with input fields and evaluate if user input
* matches with stored regular expressions.
*
* @param array $seminary Current Seminary data
* @param array $questgroup Current Questgroup data
* @param array $quest Current Quest data
* @param array $character Current Character data
* @param \Exception $exception Character submission exception
*/
public function quest($seminary, $questgroup, $quest, $character, $exception)
{
// Get Drag&Drop field
$dndField = $this->Dragndrop->getDragndrop($quest['id']);
if(!is_null($dndField) && !is_null($dndField['questmedia_id'])) {
$dndField['media'] = $this->Media->getSeminaryMediaById($dndField['questmedia_id']);
}
// Get Drags
$drags = array();
if(!is_null($dndField))
{
$dragsByIndex = $this->Dragndrop->getDrags($dndField['quest_id']);
foreach($dragsByIndex as &$drag) {
$drag['media'] = $this->Media->getSeminaryMediaById($drag['questmedia_id']);
$drags[$drag['id']] = $drag;
}
}
// Get Drops
$drops = array();
if(!is_null($dndField)) {
$drops = $this->Dragndrop->getDrops($dndField['quest_id']);
}
// Get Character answers
if($this->request->getGetParam('show-answer') == 'true' || !$this->Quests->hasCharacterSolvedQuest($quest['id'], $character['id']) || $this->request->getGetParam('status') == 'solved')
{
foreach($drops as &$drop)
{
$drop['answer'] = $this->Dragndrop->getCharacterSubmission($drop['id'], $character['id']);
if(!is_null($drop['answer']))
{
$drop['answer'] = $drags[$drop['answer']];
unset($drags[$drop['answer']['id']]);
}
}
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('field', $dndField);
$this->set('drops', $drops);
$this->set('drags', $drags);
}
/**
* Action: submission.
*
* Show the submission of a Character for a Quest.
*
* @param array $seminary Current Seminary data
* @param array $questgroup Current Questgroup data
* @param array $quest Current Quest data
* @param array $character Current Character data
*/
public function submission($seminary, $questgroup, $quest, $character)
{
// Get Drag&Drop field
$dndField = $this->Dragndrop->getDragndrop($quest['id']);
$dndField['media'] = $this->Media->getSeminaryMediaById($dndField['questmedia_id']);
// Get Drags
$drags = array();
$dragsByIndex = $this->Dragndrop->getDrags($dndField['quest_id']);
foreach($dragsByIndex as &$drag) {
$drag['media'] = $this->Media->getSeminaryMediaById($drag['questmedia_id']);
$drags[$drag['id']] = $drag;
}
// Get Drops
$drops = $this->Dragndrop->getDrops($dndField['quest_id']);
// Get Character answers
foreach($drops as &$drop)
{
$drop['answer'] = $this->Dragndrop->getCharacterSubmission($drop['id'], $character['id']);
if(!is_null($drop['answer']))
{
$drop['answer'] = $drags[$drop['answer']];
unset($drags[$drop['answer']['id']]);
}
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('field', $dndField);
$this->set('drops', $drops);
$this->set('drags', $drags);
}
/**
* Action: edittask.
*
* Edit the task of a Quest.
*
* @param array $seminary Current Seminary data
* @param array $questgroup Current Questgroup data
* @param array $quest Current Quest data
*/
public function edittask($seminary, $questgroup, $quest)
{
// Get Drag&Drop field
$dndField = $this->Dragndrop->getDragndrop($quest['id']);
if(!is_null($dndField)) {
$dndField['media'] = $this->Media->getSeminaryMediaById($dndField['questmedia_id']);
}
// Get Drop-items
$drops = array();
if(!is_null($dndField)) {
$drops = $this->Dragndrop->getDrops($dndField['quest_id']);
}
// Get Drag-items
$drags = array();
if(!is_null($dndField))
{
$drags = $this->Dragndrop->getDrags($dndField['quest_id']);
foreach($drags as &$d)
{
$d['media'] = $this->Media->getSeminaryMediaById($d['questmedia_id']);
$d['drops'] = array_map(function($d) { return $d['id']; }, $this->Dragndrop->getDropsForDrag($d['id']));
}
}
// Get allowed mimetypes
$mimetypes = \nre\configs\AppConfig::$mimetypes['questtypes'];
// Values
$step = 0;
$steps = 2;
$validation = true;
$dragsValidation = true;
// Save submitted data
if($this->request->getRequestMethod() == 'POST')
{
// Get current step
$step = max(0, min($steps, intval($this->request->getPostParam('step'))));
// Drag&Drop-field (background image)
if($step == 0)
{
// Validate zone
$zone = null;
if(!empty($_FILES) && array_key_exists('zone', $_FILES) && $_FILES['zone']['error'] != UPLOAD_ERR_NO_FILE)
{
$zone = $_FILES['zone'];
// Check error
if($zone['error'] !== UPLOAD_ERR_OK) {
$validation = $this->Validation->addValidationResult($validation, 'zone', 'error', $zone['error']);
}
// Check mimetype
$mediaMimetype = null;
$zone['mimetype'] = \hhu\z\Utils::getMimetype($zone['tmp_name'], $zone['type']);
foreach($mimetypes as &$mimetype) {
if($mimetype['mimetype'] == $zone['mimetype']) {
$mediaMimetype = $mimetype;
break;
}
}
if(is_null($mediaMimetype)) {
$validation = $this->Validation->addValidationResult($validation, 'zone', 'mimetype', $zone['mimetype']);
}
elseif($zone['size'] > $mediaMimetype['size']) {
$validation = $this->Validation->addValidationResult($validation, 'zone', 'size', $mediaMimetype['size']);
}
}
// Set zone
if($validation === true)
{
// Upload background image
$mediaId = $this->Media->createQuestMedia(
$this->Auth->getUserId(),
$seminary['id'],
sprintf('quest-dnd-%s', $quest['url']),
'',
$zone['mimetype'],
$zone['tmp_name']
);
if($mediaId !== false)
{
// Create Drag&Drop zone
$this->Dragndrop->createDragndrop(
$this->Auth->getUserId(),
$quest['id'],
$mediaId
);
}
// Reload Drag&Drop field
$dndField = $this->Dragndrop->getDragndrop($quest['id']);
$dndField['media'] = $this->Media->getSeminaryMediaById($dndField['questmedia_id']);
}
}
// Drop-items
elseif($step == 1)
{
// Get new Drop-items and organize them
$dropsNew = array();
$dropsUpdate = array();
foreach($this->request->getPostParam('drops') as $drop)
{
if(array_key_exists('id', $drop)) {
$dropsUpdate[$drop['id']] = $drop;
}
else {
$dropsNew[] = $drop;
}
}
// Update Drop-items
foreach($drops as $drop)
{
if(array_key_exists($drop['id'], $dropsUpdate))
{
$drop = $dropsUpdate[$drop['id']];
$this->Dragndrop->editDrop($drop['id'], $drop['width'], $drop['height'], $drop['x'], $drop['y']);
}
else {
$this->Dragndrop->deleteDrop($drop['id']);
}
}
// Add new Drop-items
foreach($dropsNew as $drop) {
$this->Dragndrop->addDrop($dndField['quest_id'], $drop['width'], $drop['height'], $drop['x'], $drop['y']);
}
// Reload Drop-items
$drops = $this->Dragndrop->getDrops($dndField['quest_id']);
}
// Drag-items
elseif($step == 2)
{
// Get new Drop-items and organize them
$dragsNew = array();
$dragsUpdate = array();
foreach($this->request->getPostParam('drags') as $index => $drag)
{
// Get file
if(array_key_exists($index, $_FILES['drags']['error']) && $_FILES['drags']['error'][$index] !== UPLOAD_ERR_NO_FILE)
{
$drag['file'] = array(
'name' => $_FILES['drags']['name'][$index],
'type' => $_FILES['drags']['type'][$index],
'tmp_name' => $_FILES['drags']['tmp_name'][$index],
'error' => $_FILES['drags']['error'][$index],
'size' => $_FILES['drags']['size'][$index]
);
// Validate file
$dragValidation = true;
// Check error
if($drag['file']['error'] !== UPLOAD_ERR_OK) {
$dragValidation = $this->Validation->addValidationResult($dragValidation, 'file', 'error', $drag['file']['error']);
}
// Check mimetype
$dragMimetype = null;
$drag['file']['mimetype'] = \hhu\z\Utils::getMimetype($drag['file']['tmp_name'], $drag['file']['type']);
foreach($mimetypes as &$mimetype) {
if($mimetype['mimetype'] == $drag['file']['mimetype']) {
$dragMimetype = $mimetype;
break;
}
}
if(is_null($dragMimetype)) {
$dragValidation = $this->Validation->addValidationResult($dragValidation, 'file', 'mimetype', $drag['file']['mimetype']);
}
elseif($drag['file']['size'] > $dragMimetype['size']) {
$dragValidation = $this->Validation->addValidationResult($dragValidation, 'file', 'size', $dragMimetype['size']);
}
// Add validation result
if($dragValidation !== true)
{
if(!is_array($dragsValidation)) {
$dragsValidation = array();
}
$dragsValidation[$index] = $dragValidation;
}
// Upload Drag-item file
if($dragValidation === true)
{
$drag['file']['media_id'] = $this->Media->createQuestMedia(
$this->Auth->getUserId(),
$seminary['id'],
sprintf('quest-dnd-%s-%s', substr($quest['url'], 0, 25), substr($drag['file']['name'], 0, 25)),
'',
$drag['file']['mimetype'],
$drag['file']['tmp_name']
);
}
}
// Add to array
if(array_key_exists('id', $drag)) {
$dragsUpdate[$drag['id']] = $drag;
}
else {
$dragsNew[] = $drag;
}
}
// Update Drag-items
foreach($drags as $drag)
{
if(array_key_exists($drag['id'], $dragsUpdate))
{
$drag = $dragsUpdate[$drag['id']];
// Edit Drag-items
if(array_key_exists('file', $drag) && array_key_exists('media_id', $drag['file'])) {
$this->Dragndrop->editDrag($drag['id'], $drag['file']['media_id']);
}
// Set correct Drop-items for Drag-item
$this->Dragndrop->setDropsForDrag(
$this->Auth->getUserId(),
$drag['id'],
array_key_exists('drops', $drag) ? array_keys($drag['drops']) : array()
);
}
else {
$this->Dragndrop->deleteDrag($drag['id']);
}
}
// Add new Drag-items
foreach($dragsNew as $drag)
{
if(array_key_exists('file', $drag) && array_key_exists('media_id', $drag['file']))
{
// Create Drag-item
$dragId = $this->Dragndrop->addDrag($dndField['quest_id'], $drag['file']['media_id']);
// Set Drop-items for Drag-item
$this->Dragndrop->setDropsForDrag(
$this->Auth->getUserId(),
$dragId,
array_key_exists('drops', $drag) ? array_keys($drag['drops']) : array()
);
}
}
// Reload Drag-items
$drags = $this->Dragndrop->getDrags($dndField['quest_id']);
foreach($drags as &$drag)
{
$drag['media'] = $this->Media->getSeminaryMediaById($drag['questmedia_id']);
$drag['drops'] = array_map(function($d) { return $d['id']; }, $this->Dragndrop->getDropsForDrag($drag['id']));
}
}
// Go to next/previous step
if($validation === true && $dragsValidation === true)
{
if(!is_null($this->request->getPostParam('prev'))) {
$step--;
}
else {
$step++;
}
// Redirect after last step
if($step > $steps) {
$this->redirect($this->linker->link(array('quest', $seminary['url'], $questgroup['url'], $quest['url']), 1));
}
}
}
// Pass data to view
$this->set('seminary', $seminary);
$this->set('zone', $dndField);
$this->set('drops', $drops);
$this->set('drags', $drags);
$this->set('mimetypes', $mimetypes);
$this->set('step', $step);
$this->set('validation', $validation);
$this->set('dragsValidation', $dragsValidation);
}
}
?>