Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Dev implemented importing of custom question attributes.
  • Loading branch information
SamMousa committed Jul 5, 2015
1 parent 7cc4a78 commit 7f78346
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 132 deletions.
3 changes: 2 additions & 1 deletion application/controllers/SurveysController.php
Expand Up @@ -216,7 +216,8 @@ public function actionImport() {
if (isset($file)) {
$importer = ImportFactory::getForLss($file->getTempName());
if (null !== $survey = $importer->run()) {
App()->user->setFlash('success', "Survey imported.");

App()->user->setFlash('success', "Survey imported ({$survey->groupCount}/{$survey->questionCount}).");
$this->redirect(['surveys/update', 'id' => $survey->primaryKey]);
} else {
App()->user->setFlash('error', "Survey not imported.");
Expand Down
1 change: 1 addition & 0 deletions application/core/WebApplication.php
Expand Up @@ -29,6 +29,7 @@
* @property CHttpSession $session
* @property CClientScript $clientScript
* @property MigrationManager $migrationManager
* @property CSecurityManager $securityManager
*/
class WebApplication extends CWebApplication
{
Expand Down
8 changes: 8 additions & 0 deletions application/helpers/import/BaseElementXmlImport.php
Expand Up @@ -106,6 +106,13 @@ protected function constructQuestion($question, $language, $data)
}
}

// Add attributes
foreach (isset($data['question_attributes']) ? $data['question_attributes']['rows'] : [] as $attribute) {
if ($attribute['qid'] == $question['qid']) {
$question[$attribute['attribute']] = $attribute['value'];
}
}

return $question;
}

Expand All @@ -132,6 +139,7 @@ protected function constructGroup($group, $language, $data) {
foreach($data['questions']['rows'] as $question) {
// Only handle the base language.
if ($question['gid'] == $group['gid'] && $question['language'] == $language) {

$group['questions'][] = $this->constructQuestion($question, $language, $data);
}

Expand Down
3 changes: 3 additions & 0 deletions application/helpers/import/BaseImport.php
Expand Up @@ -5,6 +5,9 @@ public function __construct() {}

abstract public function setSource($file);

/**
* @return \Survey
*/
abstract public function run();


Expand Down
20 changes: 11 additions & 9 deletions application/helpers/import/importers/Import178.php
Expand Up @@ -25,7 +25,6 @@ public function run()
$transaction = App()->db->beginTransaction();

try {
$groupMap = [];
/** @var \Survey $survey */
$result = $this->importSurvey($this->parsedDocument);
} catch(\Exception $e) {
Expand All @@ -47,11 +46,12 @@ protected function importTranslation(TranslatableBehavior $translatable, array $
$translatedFields = [];
foreach ($translatable->attributes as $attribute) {
if (isset($data[$attribute])) {
$translatedFields = $data[$attribute];
$translatedFields[$attribute] = $data[$attribute];
}
}
if (!empty($translatedFields)) {
$translation = new \Translation();
$translation->language = $data['language'];
$translation->model = $translatable->getModel();
$translation->model_id = $translatable->owner->primaryKey;
$translation->dataStore = $translatedFields;
Expand Down Expand Up @@ -173,24 +173,26 @@ protected function importQuestion(array $data, \QuestionGroup $group, array &$qu
/**
* If we only have 1 language, use it even if it is not the "base" language.
*/
if (count($data) == 1 && isset($data['translations']) && count($data['translations']) == 1) {
$data = $data['translations'][0];
}
$translations = \TbArray::popValue('translations', $data, []);
$subQuestions = \TbArray::popValue('subquestions', $data, []);
$conditions = \TbArray::popValue('conditions', $data, []);
$answers = \TbArray::popValue('answers', $data, []);
$data = $this->prepareQuestion($data, $group, $parent);
$question = new \Question();
// We want the "correct class".
$class = \Question::resolveClass($data['type']);
/** @var \Question $question */
$question = new $class();
$question->type = $data['type'];
foreach($data as $key => $value) {
if (!($question->canSetProperty($key) || $question->hasAttribute($key))) {
throw new \Exception("Could not set property $key");
throw new \Exception("Could not set property $key for " . get_class($question));
} else {
$question->$key = $value;
}
}
$question->setAttributes($data, false);
$oldKey = $question->primaryKey;
$question->primaryKey = null;
$question->parent_qid = !isset($parent) ? 0 : $parent->qid;
$question->parent_qid = !isset($parent) ? 0 : $parent->primaryKey;

if ($result = $question->save()) {
$question->group = $group;
Expand Down
193 changes: 128 additions & 65 deletions application/models/Question.php
Expand Up @@ -22,15 +22,73 @@
* @property-read Translation[] $translations Relation added by translatable behavior
* @property-read bool $hasSubQuestions
* @property-read bool $hasAnswers
* @property-read string $type
* @property QuestionGroup $group;
* @property string $title
* @property-read Survey $survey
* @property-read QuestionAttribute[] $questionAttributes
*/
class Question extends LSActiveRecord
{

protected $customAttributes = [];
public $before;

protected function afterFind()
{
parent::afterFind();
// Fill the question attributes.
foreach($this->questionAttributes as $questionAttribute) {
if (!isset($questionAttribute->language)) {
$this->customAttributes[$questionAttribute->attribute] = $questionAttribute;
}

}
}

protected function afterSave()
{
parent::afterSave();
$this->updateAttributes();

}

protected function updateAttributes() {
// Save the question attributes that do not use i18n.
$db = self::getDbConnection();
if (!isset($db->currentTransaction)) {
$transaction = $db->beginTransaction();
}
try {
QuestionAttribute::model()->deleteAllByAttributes([
'qid' => $this->primaryKey,
'language' => null

]);
$rows = [];
foreach ($this->customAttributes as $key => $value) {
$rows[] = [
'attribute' => $key,
'value' => $value,
'language' => null
];
}
if (!empty($rows)) {
$db->commandBuilder->createMultipleInsertCommand(QuestionAttribute::model()->tableName(),
$rows)->execute();
}
} catch (\Exception $e) {
if (isset($transaction)) {
$transaction->rollback();
}
throw $e;
}
if (isset($transaction)) {
$transaction->commit();
}

}


public function getHasSubQuestions()
{
return false;
Expand Down Expand Up @@ -58,19 +116,6 @@ public function behaviors() {
];
}

/**
* Returns the static model of Settings table
*
* @static
* @access public
* @param string $class
* @return CActiveRecord
*/
public static function model($class = __CLASS__)
{
return parent::model($class);
}

public function beforeSave() {
if ($this->isNewRecord && empty($this->parent_qid) && empty($this->question_order)) {
// Set order.
Expand Down Expand Up @@ -108,8 +153,8 @@ public function __get($name)
{
if (substr($name, 0, 5) == 'bool_') {
$result = parent::__get(substr($name, 5)) === 'Y';
} elseif (substr($name, 0, 2) == 'a_') {
$result = isset($this->questionAttributes[substr($name, 2)]) ? $this->questionAttributes[substr($name, 2)]->value : null;
} elseif ($name != 'type' && in_array($name, $this->customAttributeNames())) {
$result = isset($this->customAttributes[$name]) ? $this->customAttributes[$name] : null;
} else {
$result = parent::__get($name);
}
Expand All @@ -120,14 +165,8 @@ public function __set($name, $value)
{
if (substr($name, 0, 5) == 'bool_') {
parent::__set(substr($name, 5), $value ? 'Y' : 'N');
} elseif (substr($name, 0, 2) == 'a_') {
throw new \Exception("Saving not yet supported");
/**
* Several implementation options:
* 1. Save to database on set. (Bad because the record might not get saved.)
* 2. Save to memory, watch before/after Save and commit to db then. (Better but loses atomicity).
* 3. Save to memory, override save and use a transaction.
*/
} elseif (in_array($name, $this->customAttributeNames())) {
$this->customAttributes[$name] = $value;

} else {
parent::__set($name, $value);
Expand Down Expand Up @@ -288,7 +327,9 @@ public function getAdvancedSettingsWithValues($iQuestionID, $sQuestionType, $iSu

if ($iQuestionID)
{
$oAttributeValues = QuestionAttribute::model()->findAll("qid=:qid",array('qid'=>$iQuestionID));
$oAttributeValues = QuestionAttribute::model()->findAllByAttributes([
'qid' => $iQuestionID
]);
$aAttributeValues=array();
foreach($oAttributeValues as $oAttributeValue)
{
Expand Down Expand Up @@ -817,47 +858,52 @@ protected function instantiate($attributes) {
if (!empty($attributes['parent_qid'])) {
$class = \ls\models\questions\SubQuestion::class;
} else {
switch ($attributes['type']) {
case 'N':
$class = \ls\models\questions\NumericalQuestion::class;
break;
case 'D': // Date time
case 'U': // Huge free text
case 'S': // Short free text
case 'T':
$class = \ls\models\questions\TextQuestion::class;
break;
case 'O': // Single choice with comments.
case '!': // Single choice dropdown.
case 'L': // Single choice (Radio);
$class = \ls\models\questions\SingleChoiceQuestion::class;
break;
case 'Q': // Multiple (short) text.
$class = \ls\models\questions\MultipleTextQuestion::class;
break;
case 'R': // Ranking
$class = \ls\models\questions\RankingQuestion::class;
break;
case 'F': // Array
$class = \ls\models\questions\ArrayQuestion::class;
break;
case '5': // 5 point choice
case 'Y': // Yes no
case '|':
case 'X': // Text display
$class = get_class($this);
break;
case 'M': // Multiple choice
$class = \ls\models\questions\MultipleChoiceQuestion::class;
break;
default:
die("noo class for type {$attributes['type']}");

}
$class = self::resolveClass($attributes['type']);
}
return new $class(null);
}

public static function resolveClass($type) {
switch ($type) {
case 'N':
$class = \ls\models\questions\NumericalQuestion::class;
break;
case 'D': // Date time
case 'U': // Huge free text
case 'S': // Short free text
case 'T':
$class = \ls\models\questions\TextQuestion::class;
break;
case 'O': // Single choice with comments.
case '!': // Single choice dropdown.
case 'L': // Single choice (Radio);
$class = \ls\models\questions\SingleChoiceQuestion::class;
break;
case 'Q': // Multiple (short) text.
$class = \ls\models\questions\MultipleTextQuestion::class;
break;
case 'R': // Ranking
$class = \ls\models\questions\RankingQuestion::class;
break;
case 'F': // Array
$class = \ls\models\questions\ArrayQuestion::class;
break;
case '5': // 5 point choice
case 'Y': // Yes no
case '|':
case 'X': // Text display
$class = __CLASS__;
break;
case 'M': // Multiple choice
$class = \ls\models\questions\MultipleChoiceQuestion::class;
break;
default:
die("noo class for type {$type}");

}
return $class;
}

public function getTypeName() {
return $this->typeList()[$this->type]['description'];
}
Expand Down Expand Up @@ -914,9 +960,26 @@ public function deleteDependent() {
}
}

/**
* Returns the question attributes that do use i18n.
* @return string[]
*/
public function customAttributeNames() {
if (isset($this->type)) {
$attributes = array_filter(questionAttributes()[$this->type], function ($attribute) {
return $attribute['i18n'] === false;
});
$result = array_keys($attributes);
} else {
$result = [];
}
return $result;
}

}

public function hasAttribute($name)
{
return in_array($name, $this->customAttributeNames()) || parent::hasAttribute($name);
}


?>
}

0 comments on commit 7f78346

Please sign in to comment.