Moodle

Synchronizing dataitems between calculated questions in a quiz

Details

  • Type: New Feature New Feature
  • Status: Development in progress Development in progress
  • Priority: Minor Minor
  • Resolution: Unresolved
  • Affects Version/s: 2.0
  • Fix Version/s: None
  • Component/s: Questions
  • Labels:
    None
  • Affected Branches:
    MOODLE_20_STABLE

Description

Synchronizing calculated questions so that identical data can be shared between questions in a quiz.
See http://moodle.org/mod/forum/discuss.php?d=82806#p486405
This mechanism should be sufficient for most uses and will not necessitate the creation of a multianswer version of calculated question.

  1. 19install.xml.patch
    29/Nov/08 6:36 AM
    2 kB
    Pierre Pichet
  2. 19upgrade.php.patch
    29/Nov/08 6:37 AM
    1 kB
    Pierre Pichet
  3. install.xml.patch
    27/Nov/08 11:20 PM
    2 kB
    Pierre Pichet
  4. install.xml.patch
    27/Nov/08 9:18 AM
    2 kB
    Pierre Pichet
  5. upgrade.php.patch
    28/Nov/08 12:36 AM
    2 kB
    Pierre Pichet

Issue Links

Activity

Hide
Pierre Pichet added a comment -

CVS a first version on 2.0 but wrote 17228 instead of MDL-17278

Show
Pierre Pichet added a comment - CVS a first version on 2.0 but wrote 17228 instead of MDL-17278
Hide
Pierre Pichet added a comment -

Tim,
I think that a simple setting that synchronize calculated questions will eliminate the needs for a multinaswer calculated question.
Synchronizing means that for every calculated question the random number defining which item is chosen (i.e. 9th, 23th) will be the same for all calculated questions in a given quiz attempt.
If the datasets are category defined, this means that all question using i.e. parameter a will have the same a value.
So with the same data you can ask different questions.

This can be done by adding a new parameter to the quiz editor (and quiz table) or more simpler (the first option coded and CVS to HEAD) add the string 'synchronize_calculated' somewhere in the quiz intro text.
This string can be hidden as an image equivalent text for example.

This appears to me as the simplest mechanism to do this synchronizing.
It is left to the user to create a similar number of dataitems in each datasets.
If the number of dataset item of a given question is lower than the number to synchronize, the question will not crash. It won't fullly synchronize but the question and the answers will be valid...

This could be easily implemented in 1.9 after some additional testing.

The big part will be to fully document all the versatiltiy of the calculated question type which is finally easier than to build and maintain a complex multianswer...

Show
Pierre Pichet added a comment - Tim, I think that a simple setting that synchronize calculated questions will eliminate the needs for a multinaswer calculated question. Synchronizing means that for every calculated question the random number defining which item is chosen (i.e. 9th, 23th) will be the same for all calculated questions in a given quiz attempt. If the datasets are category defined, this means that all question using i.e. parameter a will have the same a value. So with the same data you can ask different questions. This can be done by adding a new parameter to the quiz editor (and quiz table) or more simpler (the first option coded and CVS to HEAD) add the string 'synchronize_calculated' somewhere in the quiz intro text. This string can be hidden as an image equivalent text for example. This appears to me as the simplest mechanism to do this synchronizing. It is left to the user to create a similar number of dataitems in each datasets. If the number of dataset item of a given question is lower than the number to synchronize, the question will not crash. It won't fullly synchronize but the question and the answers will be valid... This could be easily implemented in 1.9 after some additional testing. The big part will be to fully document all the versatiltiy of the calculated question type which is finally easier than to build and maintain a complex multianswer...
Hide
Tim Hunt added a comment -

Yes. This is a good idea. And actually, something we did at the Open University, when building our OpenMark system.

I don't know if you read Java code, but in https://openmark.dev.java.net/source/browse/openmark/trunk/src/om/tnavigator/NavigatorServlet.java?rev=314&view=markup, in initTestAttempt, we create a random seed for the test attempt and store it in the database. Then in the startQuestion method, we send that random seed to the question when it is started. Finally, in https://openmark.dev.java.net/source/browse/openmark/trunk/src/om/stdquestion/StandardQuestion.java?rev=230&view=markup, there are two copies of the getRandom method. The first gets a random number generator seeded based on a combination of the random seed passed, and also something unique to the current question, combined with the seed we were passed. The other one uses a group name, so different questions in a test can get the same random number generator, if they all use the same group name.

And in the Opaque question type, which lets you use OpenMark questions in Moodle, I had to do a quick hack, to store the random seed for each question http://cvs.moodle.org/contrib/plugins/question/type/opaque/questiontype.php?view=markup - look in the create_session_and_responses method - but actually, since that is making up a new random seed for each question, it will break the grouping bit in OpenMark.

So it has been in the back of my mind to do something like this in the Moodle quiz.

As you say, what we need is a random seed stored in the quiz_attempts table. That would automatically be available to the question types, because mod/quiz/attempt.php passes over the $attempt when it calls question_load_states in lib/questionlib.php, and that in turn passes on $attemtp when it calls $QTYPES[...]->create_session_and_responses.

Then we need a way for different calculated questions to decide how to take the attempt's random seed, and make a private random seed from that. The default options will be: each question uses a separate random seed. And the proposed new option is: all questions use the same random seed. A possible third option is: questions from the same category share a random seed.

I don't really like the idea of putting this setting on the quiz settings page. Most teachers don't use the calculated question type, so will probably just be confused by it. Can we put it on the question settings form? A dropdown with three choices:

Pick the random variant for this question:

  • independantly of other questions
  • to be the same as other question from the same category
  • to be the same as all other questions in the quiz

Since this change involves some key parts of questionlib.php, I would appreciate it if you could post a patch here for review before committing anything.

I think a change like this should be done for Moodle 2.0 only.

Show
Tim Hunt added a comment - Yes. This is a good idea. And actually, something we did at the Open University, when building our OpenMark system. I don't know if you read Java code, but in https://openmark.dev.java.net/source/browse/openmark/trunk/src/om/tnavigator/NavigatorServlet.java?rev=314&view=markup, in initTestAttempt, we create a random seed for the test attempt and store it in the database. Then in the startQuestion method, we send that random seed to the question when it is started. Finally, in https://openmark.dev.java.net/source/browse/openmark/trunk/src/om/stdquestion/StandardQuestion.java?rev=230&view=markup, there are two copies of the getRandom method. The first gets a random number generator seeded based on a combination of the random seed passed, and also something unique to the current question, combined with the seed we were passed. The other one uses a group name, so different questions in a test can get the same random number generator, if they all use the same group name. And in the Opaque question type, which lets you use OpenMark questions in Moodle, I had to do a quick hack, to store the random seed for each question http://cvs.moodle.org/contrib/plugins/question/type/opaque/questiontype.php?view=markup - look in the create_session_and_responses method - but actually, since that is making up a new random seed for each question, it will break the grouping bit in OpenMark. So it has been in the back of my mind to do something like this in the Moodle quiz. As you say, what we need is a random seed stored in the quiz_attempts table. That would automatically be available to the question types, because mod/quiz/attempt.php passes over the $attempt when it calls question_load_states in lib/questionlib.php, and that in turn passes on $attemtp when it calls $QTYPES[...]->create_session_and_responses. Then we need a way for different calculated questions to decide how to take the attempt's random seed, and make a private random seed from that. The default options will be: each question uses a separate random seed. And the proposed new option is: all questions use the same random seed. A possible third option is: questions from the same category share a random seed. I don't really like the idea of putting this setting on the quiz settings page. Most teachers don't use the calculated question type, so will probably just be confused by it. Can we put it on the question settings form? A dropdown with three choices: Pick the random variant for this question:
  • independantly of other questions
  • to be the same as other question from the same category
  • to be the same as all other questions in the quiz
Since this change involves some key parts of questionlib.php, I would appreciate it if you could post a patch here for review before committing anything. I think a change like this should be done for Moodle 2.0 only.
Hide
Pierre Pichet added a comment -

First no problem with Java , C++ even Modula ...My first programs where on punch cards...

I think that the 'synchropnize_calculated' put in the quiz info should be added to 1.9 as this allow peoples that use heavily calculated questions,will be happy of this feature. There was some universities that ask for synchronized calculated on the forum.

The actual implementation of datasets allow to check if the random seeds give good values for all asnwers or values display in the question text. The calculated question store the rank of the dataitems in the data sets.
The number of dataitems generated can vary but effectively should be equal for each synchronized questions.

My first simple proposal let the user check that everything is Ok. This is a kind of feature for specialist that does not interfere with the casual user because if 'synchropnize_calculated' is not in the quiz->intro text the feature is not activated.

We could however plan something else for 2.0 and I will look closely to your references to see how they can be useful for calculated .

Don't worry, i will never CVS something in the questionlib without your approval not even in type/questiontype.php.

Show
Pierre Pichet added a comment - First no problem with Java , C++ even Modula ...My first programs where on punch cards... I think that the 'synchropnize_calculated' put in the quiz info should be added to 1.9 as this allow peoples that use heavily calculated questions,will be happy of this feature. There was some universities that ask for synchronized calculated on the forum. The actual implementation of datasets allow to check if the random seeds give good values for all asnwers or values display in the question text. The calculated question store the rank of the dataitems in the data sets. The number of dataitems generated can vary but effectively should be equal for each synchronized questions. My first simple proposal let the user check that everything is Ok. This is a kind of feature for specialist that does not interfere with the casual user because if 'synchropnize_calculated' is not in the quiz->intro text the feature is not activated. We could however plan something else for 2.0 and I will look closely to your references to see how they can be useful for calculated . Don't worry, i will never CVS something in the questionlib without your approval not even in type/questiontype.php.
Hide
Pierre Pichet added a comment -

"As you say, what we need is a random seed stored in the quiz_attempts table"
Thisa is not necessary as the random seed to use your term is already stored in the question_states-> answer

set_field('question_states', 'answer', $responses, array('id'=> $state->id);

The mechanism I use, is to look at $cmoptions->intro and store the seed in a $cmoption->synchronize_calculated

// Choose a random dataset
if (!isset($cmoptions->intro) || strstr($cmoptions->intro, 'synchronize_calculated') === false ) { $state->options->datasetitem = rand(1, $maxnumber); }else{
if( !isset($cmoptions->synchronize_calculated)) { $state->options->datasetitem = rand(1, $maxnumber); $cmoptions->synchronize_calculated = $state->options->datasetitem ; }else {
if ($cmoptions->synchronize_calculated <= $maxnumber){ $state->options->datasetitem = $cmoptions->synchronize_calculated ; }else { $state->options->datasetitem = rand(1, $maxnumber); }
}
};
$state->options->dataset =
$this->pick_question_dataset($question,$state->options->datasetitem);
$state->responses = array('' => '');

So the first calculated question generates the random and each questions use it and stored it.

As long as we can add a new field in calculated question storing the dropdown with three choices, we have sufficient control.

Pick the random variant for this question:

  • independantly of other questions
  • to be the same as other question from the same category
  • to be the same as all other questions in the quiz

So could we add a new field in the question_calculated for 1.9 as this version is already released?
If yes, the solution will be the same for 1.9.

I will use this new field as an equivalent to the 'synchronize_calculated' in quiz->intro.

One more interesting thing will be to set a parameter in $cmoptions that identify a preview from a real quiz.

If preview, we could display a message to the quiz creator that everything is Ok or not about the size of the datasets from the different questions that will shared the seed parameter.

So
1 a new field in question_calculated
2 a new parameter in $cmoptions to identify a preview from a real quiz. This field could be used to other messages as for random questions problems.

Show
Pierre Pichet added a comment - "As you say, what we need is a random seed stored in the quiz_attempts table" Thisa is not necessary as the random seed to use your term is already stored in the question_states-> answer set_field('question_states', 'answer', $responses, array('id'=> $state->id); The mechanism I use, is to look at $cmoptions->intro and store the seed in a $cmoption->synchronize_calculated // Choose a random dataset if (!isset($cmoptions->intro) || strstr($cmoptions->intro, 'synchronize_calculated') === false ) { $state->options->datasetitem = rand(1, $maxnumber); }else{ if( !isset($cmoptions->synchronize_calculated)) { $state->options->datasetitem = rand(1, $maxnumber); $cmoptions->synchronize_calculated = $state->options->datasetitem ; }else { if ($cmoptions->synchronize_calculated <= $maxnumber){ $state->options->datasetitem = $cmoptions->synchronize_calculated ; }else { $state->options->datasetitem = rand(1, $maxnumber); } } }; $state->options->dataset = $this->pick_question_dataset($question,$state->options->datasetitem); $state->responses = array('' => ''); So the first calculated question generates the random and each questions use it and stored it. As long as we can add a new field in calculated question storing the dropdown with three choices, we have sufficient control. Pick the random variant for this question:
  • independantly of other questions
  • to be the same as other question from the same category
  • to be the same as all other questions in the quiz
So could we add a new field in the question_calculated for 1.9 as this version is already released? If yes, the solution will be the same for 1.9. I will use this new field as an equivalent to the 'synchronize_calculated' in quiz->intro. One more interesting thing will be to set a parameter in $cmoptions that identify a preview from a real quiz. If preview, we could display a message to the quiz creator that everything is Ok or not about the size of the datasets from the different questions that will shared the seed parameter. So 1 a new field in question_calculated 2 a new parameter in $cmoptions to identify a preview from a real quiz. This field could be used to other messages as for random questions problems.
Hide
Tim Hunt added a comment -

If you can do it with only adding a field to question_calculated, and if, by default, it does not change the behaviour of any existing questions, then it is fine to do it in 1.9

Do remember to backup and restore, and import and export the new field. And use the default if you restore, import an old file that does not contain any value for this setting. (You probably know that already!)

You don't need an parameter in $cmoptions (I think), you should be able to get it from $attemtp. Hmm. Which questiontype method are you thinking of?

Show
Tim Hunt added a comment - If you can do it with only adding a field to question_calculated, and if, by default, it does not change the behaviour of any existing questions, then it is fine to do it in 1.9 Do remember to backup and restore, and import and export the new field. And use the default if you restore, import an old file that does not contain any value for this setting. (You probably know that already!) You don't need an parameter in $cmoptions (I think), you should be able to get it from $attemtp. Hmm. Which questiontype method are you thinking of?
Hide
Pierre Pichet added a comment -

function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
I have access effectively to the preview so this is OK.

However a calcualted question will need to see if it will synchronized to a question in this quiz, so it needs the questions data.

And all the questions data is already built in the questions parameter of get_question_states() in questionlib.php

So I propose that the questions parameter (as address) should be added as a fifth parameter to the create_session_and_responses() call.

It will be easy for a calculated question to find if its synchronizes with another question in the quiz and if the number of dataitems are OK.
If there is some possible problems then the resulting analysis could be shown on preview .

Show
Pierre Pichet added a comment - function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) { I have access effectively to the preview so this is OK. However a calcualted question will need to see if it will synchronized to a question in this quiz, so it needs the questions data. And all the questions data is already built in the questions parameter of get_question_states() in questionlib.php So I propose that the questions parameter (as address) should be added as a fifth parameter to the create_session_and_responses() call. It will be easy for a calculated question to find if its synchronizes with another question in the quiz and if the number of dataitems are OK. If there is some possible problems then the resulting analysis could be shown on preview .
Hide
Pierre Pichet added a comment -

As long as we can add a new field in calculated question storing the dropdown with three choices, we have sufficient control.

Pick the random variant for this question:

  • independantly of other questions
  • to be the same as other question from the same category
  • to be the same as all other questions in the quiz

However the case is simpler because there is no interest to synchronize calculated questions unless they share at least one category dataset.
If all there datasets are private, the synchronize will have no real effect.

So the synchronize button should be set at the second page of editing calculated question where the user choose between private and category level datasets.

Show
Pierre Pichet added a comment - As long as we can add a new field in calculated question storing the dropdown with three choices, we have sufficient control. Pick the random variant for this question:
  • independantly of other questions
  • to be the same as other question from the same category
  • to be the same as all other questions in the quiz
However the case is simpler because there is no interest to synchronize calculated questions unless they share at least one category dataset. If all there datasets are private, the synchronize will have no real effect. So the synchronize button should be set at the second page of editing calculated question where the user choose between private and category level datasets.
Hide
Pierre Pichet added a comment -

The synchronization could be set at the dataset level i.e. the user could want to have one parameter that is shared and another one not.
So the field synchronize should be added to the question_datasets table which links question to the datasets.

As this is set at the second page of editing calculated question where the user choose between private and category level datasets, this is easy to implement and natural to set for the user.

Show
Pierre Pichet added a comment - The synchronization could be set at the dataset level i.e. the user could want to have one parameter that is shared and another one not. So the field synchronize should be added to the question_datasets table which links question to the datasets. As this is set at the second page of editing calculated question where the user choose between private and category level datasets, this is easy to implement and natural to set for the user.
Hide
Pierre Pichet added a comment -

So I will work on giving maximum flexibility to synchronize the category level datasets.
needed
1. a new field in question_datasets table
2; &$questions added to call
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt,&$questions) {

in questionlib.php
Will study if is_usable_by_random() should be set to false. or not .

So put this on my to-do list...

Show
Pierre Pichet added a comment - So I will work on giving maximum flexibility to synchronize the category level datasets. needed 1. a new field in question_datasets table 2; &$questions added to call function create_session_and_responses(&$question, &$state, $cmoptions, $attempt,&$questions) { in questionlib.php Will study if is_usable_by_random() should be set to false. or not . So put this on my to-do list...
Hide
Pierre Pichet added a comment -

Finaaly, I can work a solution that does not imply modifications to create_session_and_responses() and will work with random.
So the noly change seems a new field in question_datasets table .

Show
Pierre Pichet added a comment - Finaaly, I can work a solution that does not imply modifications to create_session_and_responses() and will work with random. So the noly change seems a new field in question_datasets table .
Hide
Tim Hunt added a comment -

Wow! that sounds brilliant. No problem putting it in 1.9 then.

Show
Tim Hunt added a comment - Wow! that sounds brilliant. No problem putting it in 1.9 then.
Hide
Pierre Pichet added a comment - - edited

Tim,
This work as this.
There is a search of all question_datasets where the synchonize (new field to add) is set using the $cmoptions->questions if

1. a preceding question has not put the result already on $state using a new parameter ( i.e.synchronize_calculated ) that should not be saved after the quiz end.
2. the $question-> id is not found on $cmoptions->questions . This detect random calculated.

Then if synchronization should be done, tests are done to detect if the number of dataitems are coherent.

If not, default values are applied and if $attempt ->preview is set, a message is displayed.

Is it OK to store temporarely the search result on $cmoptions ? .

Given the fact that random can change, there will be a notice to users that synchronization could not done to full extent if the number of dataitems is not as large as the other calculated synchronized question when using random question.
This is not a problem with normal question as the synchronized random seed is set at the first calculated question encounter in the quiz.

The user should set to identical number of items the questions in a given category to use full synchronization of category shared datasets in any cases.

Show
Pierre Pichet added a comment - - edited Tim, This work as this. There is a search of all question_datasets where the synchonize (new field to add) is set using the $cmoptions->questions if 1. a preceding question has not put the result already on $state using a new parameter ( i.e.synchronize_calculated ) that should not be saved after the quiz end. 2. the $question-> id is not found on $cmoptions->questions . This detect random calculated. Then if synchronization should be done, tests are done to detect if the number of dataitems are coherent. If not, default values are applied and if $attempt ->preview is set, a message is displayed. Is it OK to store temporarely the search result on $cmoptions ? . Given the fact that random can change, there will be a notice to users that synchronization could not done to full extent if the number of dataitems is not as large as the other calculated synchronized question when using random question. This is not a problem with normal question as the synchronized random seed is set at the first calculated question encounter in the quiz. The user should set to identical number of items the questions in a given category to use full synchronization of category shared datasets in any cases.
Hide
Pierre Pichet added a comment -

The common obect to all question is $cmoptions.
However this is not given as an address but as an object.
So I change in the calculated
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt,&$questions)
changing $cmoptions to &$cmoptions.
function create_session_and_responses(&$question, &$state, &$cmoptions, $attempt,&$questions)

In PHP 5 this seems ot work and give a way to share and modify parameter between the questions at least when creating the quiz as object are passed by reference in PHP 5 I think.

Should this work on a 1.9 version using PHP4 ?

Show
Pierre Pichet added a comment - The common obect to all question is $cmoptions. However this is not given as an address but as an object. So I change in the calculated function create_session_and_responses(&$question, &$state, $cmoptions, $attempt,&$questions) changing $cmoptions to &$cmoptions. function create_session_and_responses(&$question, &$state, &$cmoptions, $attempt,&$questions) In PHP 5 this seems ot work and give a way to share and modify parameter between the questions at least when creating the quiz as object are passed by reference in PHP 5 I think. Should this work on a 1.9 version using PHP4 ?
Hide
Tim Hunt added a comment -

That will work in PHP4, but it is a horrible hack.

This function is being sent $cmoptions so it has read-only access to the quiz options, if it needs it. It is really not intended that $cmoptions is changed.

Passing information around like this is very risky. Is it guaranteed to work in all situations (single and multi-page quizzes, adaptive mode, non-adaptive mode and each attempt builds on last)?

An alternative approach would be, when you are trying to synchronise, don't use PHP's random number generator at all. Instead consider getting a 'random' number by doing something like md5($attempt->timestart . '' . $attempt>id . '' . $question>categoryid) and extracting a number in the right range from that string. That is probably effectively random, but without having to store a seed.

Also, remember that $attempt already has $attempt->layout, which gives you the question ids. That might mean you don't need to change the parameters for create_session_and_responses.

Show
Tim Hunt added a comment - That will work in PHP4, but it is a horrible hack. This function is being sent $cmoptions so it has read-only access to the quiz options, if it needs it. It is really not intended that $cmoptions is changed. Passing information around like this is very risky. Is it guaranteed to work in all situations (single and multi-page quizzes, adaptive mode, non-adaptive mode and each attempt builds on last)? An alternative approach would be, when you are trying to synchronise, don't use PHP's random number generator at all. Instead consider getting a 'random' number by doing something like md5($attempt->timestart . '' . $attempt>id . '' . $question>categoryid) and extracting a number in the right range from that string. That is probably effectively random, but without having to store a seed. Also, remember that $attempt already has $attempt->layout, which gives you the question ids. That might mean you don't need to change the parameters for create_session_and_responses.
Hide
Pierre Pichet added a comment -

"Passing information around like this is very risky. Is it guaranteed to work in all situations (single and multi-page quizzes, adaptive mode, non-adaptive mode and each attempt builds on last)? "

I have to check this and comme back with the results.(Already OK for single and multipage).

Show
Pierre Pichet added a comment - "Passing information around like this is very risky. Is it guaranteed to work in all situations (single and multi-page quizzes, adaptive mode, non-adaptive mode and each attempt builds on last)? " I have to check this and comme back with the results.(Already OK for single and multipage).
Hide
Pierre Pichet added a comment -

Tim,
Thanks for the $attempt->timestart cue as a common "random" parameter that can be used to synchonize calculated questions having category datasets.

So we won't need a "horrible hack" that was temporary horrible until we would have changed $cmoptions if it was the only way to get a common value to all questions in a quiz.

I don't need a complex random because this number choose between the actual 100 maximum dataitems in a dataset.
So I just use the last 2 digits of $attempt->timestart to set the item number used to choose the values for the datasets that are defined as synchronized,

There is no problem about adaptive mode, non-adaptive mode and each attempt builds on last as calculated are not adaptative and they generate new values for each attempt.
In their case each attempt builds on last just mean that the response stored is the last one or the highest grading.

So I need to modify the second calculated question editing page to set the synchronize bit and do all the restore, backup, export-import.
We should also finish the code for moving calculated question datasets to other categories.

Given the other projects on my to-do list, a workable version should be available in january as I will be in Punta Cana at the end of december and I don't want to CVS this just before an holiday...

In the mean time I will post here the steps solved.

Show
Pierre Pichet added a comment - Tim, Thanks for the $attempt->timestart cue as a common "random" parameter that can be used to synchonize calculated questions having category datasets. So we won't need a "horrible hack" that was temporary horrible until we would have changed $cmoptions if it was the only way to get a common value to all questions in a quiz. I don't need a complex random because this number choose between the actual 100 maximum dataitems in a dataset. So I just use the last 2 digits of $attempt->timestart to set the item number used to choose the values for the datasets that are defined as synchronized, There is no problem about adaptive mode, non-adaptive mode and each attempt builds on last as calculated are not adaptative and they generate new values for each attempt. In their case each attempt builds on last just mean that the response stored is the last one or the highest grading. So I need to modify the second calculated question editing page to set the synchronize bit and do all the restore, backup, export-import. We should also finish the code for moving calculated question datasets to other categories. Given the other projects on my to-do list, a workable version should be available in january as I will be in Punta Cana at the end of december and I don't want to CVS this just before an holiday... In the mean time I will post here the steps solved.
Hide
Pierre Pichet added a comment -

Tim,

My first hypothesis was that synchronizing could be done at the category shared datasets. i.e that the user could say this dataset is synchronizd and that one not.
The synchonization does not have any meaning to private datasets so that they synchronized if there is at least one category that is synchronizing i.e. they use the same item number.
This seems good until I came to storing the question results or attempt.

I realize that I will need to store the item number for each datasets in the response field of question_states or actually this is not the case.
The common dataset number is stored followed by the responses.
This could be changed but will not be coherent with the actual data stored and more complex .

Setting the synchronize bit for each category shared can be done at the editing page two , but then the interface becomes overcrowded and the user could forget to synchronize a category shared on one question and get a non completely synchonize question.

So I decide to simplify the process and to set the syncronization at the question level and not at the datasets level.

The same dataitem number will be used by all datasets as the actual code.
If the synchronize bit is set, then this dataitem number comes from the $attempt->timestart otherwise it is generated from the random function.

This will be easier to implement and will give a less complex code and a less complex question editing form.

So synchronize should be set at the question level.

However there is NO question level database table for calculated questiontype as there is one for multichoice.

The question_calculated table store the answer data for each answer.

I have almost completed the code using the question_datasets table to store the synchronize to each dataset used by a question but effectively adding a new question_calculated_parameters table with three fields id, question, synchonize will simplify the code and could eventually be useful .

Which option should we use ?
a new table (question_calculated_parameters)
or
a new field in question_datasets table (more complex code).

In the mean time I proposed a simpler calculated question (MDL-17376).

Show
Pierre Pichet added a comment - Tim, My first hypothesis was that synchronizing could be done at the category shared datasets. i.e that the user could say this dataset is synchronizd and that one not. The synchonization does not have any meaning to private datasets so that they synchronized if there is at least one category that is synchronizing i.e. they use the same item number. This seems good until I came to storing the question results or attempt. I realize that I will need to store the item number for each datasets in the response field of question_states or actually this is not the case. The common dataset number is stored followed by the responses. This could be changed but will not be coherent with the actual data stored and more complex . Setting the synchronize bit for each category shared can be done at the editing page two , but then the interface becomes overcrowded and the user could forget to synchronize a category shared on one question and get a non completely synchonize question. So I decide to simplify the process and to set the syncronization at the question level and not at the datasets level. The same dataitem number will be used by all datasets as the actual code. If the synchronize bit is set, then this dataitem number comes from the $attempt->timestart otherwise it is generated from the random function. This will be easier to implement and will give a less complex code and a less complex question editing form. So synchronize should be set at the question level. However there is NO question level database table for calculated questiontype as there is one for multichoice. The question_calculated table store the answer data for each answer. I have almost completed the code using the question_datasets table to store the synchronize to each dataset used by a question but effectively adding a new question_calculated_parameters table with three fields id, question, synchonize will simplify the code and could eventually be useful . Which option should we use ? a new table (question_calculated_parameters) or a new field in question_datasets table (more complex code). In the mean time I proposed a simpler calculated question (MDL-17376).
Hide
Tim Hunt added a comment -

Synchronising by question sounds much easier to understand and explain to teachers, so I think that is the right choice.

It is a pity that the question_calculated is called that. Ideally we would rename that to question_calculated_answers, and make a new question_calculated table. However, that might be more trouble than it is worth. In which case your question_calculated_parameters is OK.

Actually, question_calculated_options is better, because it will be loaded into $question->options in memory.

(MDL-17376 does not exist yet! did you mistype?)

Show
Tim Hunt added a comment - Synchronising by question sounds much easier to understand and explain to teachers, so I think that is the right choice. It is a pity that the question_calculated is called that. Ideally we would rename that to question_calculated_answers, and make a new question_calculated table. However, that might be more trouble than it is worth. In which case your question_calculated_parameters is OK. Actually, question_calculated_options is better, because it will be loaded into $question->options in memory. (MDL-17376 does not exist yet! did you mistype?)
Hide
Pierre Pichet added a comment -

Yes MDL-17366.

By the way , I mistyped a MDL- reference in a recent CVS so it is shown in another bug. I put a note in this bug.
Is there a way to change the history or is as normal "history is history".

So I will work with question_calculated_options.
A first proposal coud be prepare in the following days.

I will put the diffs here about creating the new table as we have done when we eliminate the datasetdependent type.

Show
Pierre Pichet added a comment - Yes MDL-17366. By the way , I mistyped a MDL- reference in a recent CVS so it is shown in another bug. I put a note in this bug. Is there a way to change the history or is as normal "history is history". So I will work with question_calculated_options. A first proposal coud be prepare in the following days. I will put the diffs here about creating the new table as we have done when we eliminate the datasetdependent type.
Hide
Tim Hunt added a comment -

No, no way to change CVS history. You have to be careful. I alway copy and paste, rather than trusting my typing.

OK, I'll review the patches when you attach them.

Show
Tim Hunt added a comment - No, no way to change CVS history. You have to be careful. I alway copy and paste, rather than trusting my typing. OK, I'll review the patches when you attach them.
Hide
Pierre Pichet added a comment -

Tim ,
I am almost ready to CVS to HEAD the calculated/questiontype.php and datasetdefinitions.php
Here is the patch for the install.xml

I really don't know how to write correctly the update.php file to create a new table as I have not done this before.

So could you do the install on HEAD so that I can CVs the new code using this new table.
I have set the synchronize as a 2 bit integer because it will not store no more than 0 an 1

Thanks

Show
Pierre Pichet added a comment - Tim , I am almost ready to CVS to HEAD the calculated/questiontype.php and datasetdefinitions.php Here is the patch for the install.xml I really don't know how to write correctly the update.php file to create a new table as I have not done this before. So could you do the install on HEAD so that I can CVs the new code using this new table. I have set the synchronize as a 2 bit integer because it will not store no more than 0 an 1 Thanks
Hide
Tim Hunt added a comment -

The question_calculated_options.question column should be called question_calculated_options.questionid. (The coding standards for this used to be different years ago, which is why some old tables like question_calculated are 'wrong'.)

You can get the XMLDB editor to generate the upgrade code for you. Use the generate PHP option, and tell it to give you the code for creating that table.

Show
Tim Hunt added a comment - The question_calculated_options.question column should be called question_calculated_options.questionid. (The coding standards for this used to be different years ago, which is why some old tables like question_calculated are 'wrong'.) You can get the XMLDB editor to generate the upgrade code for you. Use the generate PHP option, and tell it to give you the code for creating that table.
Hide
Pierre Pichet added a comment -

Here is the new install.xml.
Should we changed the comment on question_calculated as shown here?

Show
Pierre Pichet added a comment - Here is the new install.xml. Should we changed the comment on question_calculated as shown here?
Hide
Pierre Pichet added a comment -

Here is the upgrade patch creating the new table.
actual version is 2008112600
How do I set the XXXXXXXX if I want that the table to be created in the actual version so that I can CVS after this new upgrade the new code i.e calculated/questiontype.php ?
Although the robot change the displayed version each days, the actual version is changed for other reasons.

Show
Pierre Pichet added a comment - Here is the upgrade patch creating the new table. actual version is 2008112600 How do I set the XXXXXXXX if I want that the table to be created in the actual version so that I can CVS after this new upgrade the new code i.e calculated/questiontype.php ? Although the robot change the displayed version each days, the actual version is changed for other reasons.
Hide
Tim Hunt added a comment -

The XXXXXXXXXX in question/type/calculated/db/update.php corresponds to the version number in question/type/calculated/version.php - that is, it is the plugin version number.

And you need to be careful when you make database changes on a stable branch, and also on HEAD. You need to think about/test all the cases: (Assuming your code goes into HEAD and 1.9.3+ now)

  • User installs 1.9.3, upgrades to 1.9.4, then upgrades to 2.0
  • User installs 1.9.3, upgrades to 2.0.
  • User installs 1.9.4, upgrades to 2.0
  • User installs 2.0

You need to ensure that in all cases, the database is defined correctly, and on each upgrades, the right things are changed.

(By the way, note that the function names to use in upgrade.php are different between 1.9 and HEAD, to be careful when merging.)

Also, you are still using the column name question, not questionid.

Show
Tim Hunt added a comment - The XXXXXXXXXX in question/type/calculated/db/update.php corresponds to the version number in question/type/calculated/version.php - that is, it is the plugin version number. And you need to be careful when you make database changes on a stable branch, and also on HEAD. You need to think about/test all the cases: (Assuming your code goes into HEAD and 1.9.3+ now)
  • User installs 1.9.3, upgrades to 1.9.4, then upgrades to 2.0
  • User installs 1.9.3, upgrades to 2.0.
  • User installs 1.9.4, upgrades to 2.0
  • User installs 2.0
You need to ensure that in all cases, the database is defined correctly, and on each upgrades, the right things are changed. (By the way, note that the function names to use in upgrade.php are different between 1.9 and HEAD, to be careful when merging.) Also, you are still using the column name question, not questionid.
Hide
Pierre Pichet added a comment -

Thanks,
I will do the modifications and test it on my 1.9 and HEAD sites in the weekend and come back here before CVS anything...

Show
Pierre Pichet added a comment - Thanks, I will do the modifications and test it on my 1.9 and HEAD sites in the weekend and come back here before CVS anything...
Hide
Pierre Pichet added a comment -

Everything works fine for HEAD when upgrading, the table is created correctly (with questionid..) and the synchonize code is working correctly.

Show
Pierre Pichet added a comment - Everything works fine for HEAD when upgrading, the table is created correctly (with questionid..) and the synchonize code is working correctly.
Hide
Pierre Pichet added a comment -

Everything works fine for 1.9 when upgrading, the table is created correctly .
Changes need to be done in calculated question code

Show
Pierre Pichet added a comment - Everything works fine for 1.9 when upgrading, the table is created correctly . Changes need to be done in calculated question code
Hide
Pierre Pichet added a comment -

Tim,
I looked at the history of calculated/db/install.xml, calculated/db/upbrade.php and calculated/version.php all 1.9 version seem to have common code. The only changes were done in HEAD .
Do you think I can change HEAD and 1.9MERGED without creating any problems when the different 1.9 will update.to 2.0?
If yes, I will CVS the database changes to HEAD and merged in 1.9 in the same day so the version number will be the same.
As this is a new table , it won't be used until I CVS new calculated code.
In this case, I will CVS new calculated code to HEAD, test it and merged to 1.9 when OK.

Show
Pierre Pichet added a comment - Tim, I looked at the history of calculated/db/install.xml, calculated/db/upbrade.php and calculated/version.php all 1.9 version seem to have common code. The only changes were done in HEAD . Do you think I can change HEAD and 1.9MERGED without creating any problems when the different 1.9 will update.to 2.0? If yes, I will CVS the database changes to HEAD and merged in 1.9 in the same day so the version number will be the same. As this is a new table , it won't be used until I CVS new calculated code. In this case, I will CVS new calculated code to HEAD, test it and merged to 1.9 when OK.
Hide
Pierre Pichet added a comment -

1.9 patchs

Show
Pierre Pichet added a comment - 1.9 patchs
Hide
Pierre Pichet added a comment -

The head version has been CVS (see MDL-19519).(Sorry another time I misspelled MDL_17278, CVS many files remain a stressfull event for me...)
For 1.9 all versions of calculated are 2006032200;
For 1.9 the version settings after adding question_calculated_options will be a number between 2006032200 and 2008091700 where in HEAD the datasetdependent has been dropped , say 2008081700.
Although this is not the real date, it will allow the datasetdependent change to be done to ALL 1.9 version when migrating from 1.9 to HEAD (2.0).
In all cases the handling of question_calculated_options database will be done by the $dbman->table_exists() test.

/// Define table question_calculated_options to be created
$table = new xmldb_table('question_calculated_options');

/// Adding fields to table question_calculated_options
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
$table->add_field('question', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
$table->add_field('synchronize', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');

/// Adding keys to table question_calculated_options
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
$table->add_key('question', XMLDB_KEY_FOREIGN, array('question'), 'question', array('id'));

/// Conditionally launch create table for question_calculated_options
if (!$dbman->table_exists($table)) { $result = $dbman->create_table($table); }
So all 1.9 or 2.0 upgrades with have the table('question_calculated_options') and the datasetdependent change.

The 1.9 CVS willnor be done before Tim comments and more testing in the next month...

Show
Pierre Pichet added a comment - The head version has been CVS (see MDL-19519).(Sorry another time I misspelled MDL_17278, CVS many files remain a stressfull event for me...) For 1.9 all versions of calculated are 2006032200; For 1.9 the version settings after adding question_calculated_options will be a number between 2006032200 and 2008091700 where in HEAD the datasetdependent has been dropped , say 2008081700. Although this is not the real date, it will allow the datasetdependent change to be done to ALL 1.9 version when migrating from 1.9 to HEAD (2.0). In all cases the handling of question_calculated_options database will be done by the $dbman->table_exists() test. /// Define table question_calculated_options to be created $table = new xmldb_table('question_calculated_options'); /// Adding fields to table question_calculated_options $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); $table->add_field('question', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0'); $table->add_field('synchronize', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0'); /// Adding keys to table question_calculated_options $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); $table->add_key('question', XMLDB_KEY_FOREIGN, array('question'), 'question', array('id')); /// Conditionally launch create table for question_calculated_options if (!$dbman->table_exists($table)) { $result = $dbman->create_table($table); } So all 1.9 or 2.0 upgrades with have the table('question_calculated_options') and the datasetdependent change. The 1.9 CVS willnor be done before Tim comments and more testing in the next month...
Hide
Pierre Pichet added a comment -

The synchronization has been implemented in the actual 3 steps process.
It will work if the questions are not move from their original category or move by question editing process.
I will add the necessary info in the docs.
Complete solution will need to solve correctly the moving process of category share datasets.
The main idea is that if there is already a category dataset with the same name where we move the question, the name will be changed "automatically" like adding a postfix like __1 , __2 .
This can be done by a search and replace in the question text and answer texts.
more news later

Show
Pierre Pichet added a comment - The synchronization has been implemented in the actual 3 steps process. It will work if the questions are not move from their original category or move by question editing process. I will add the necessary info in the docs. Complete solution will need to solve correctly the moving process of category share datasets. The main idea is that if there is already a category dataset with the same name where we move the question, the name will be changed "automatically" like adding a postfix like __1 , __2 . This can be done by a search and replace in the question text and answer texts. more news later
Hide
Pierre Pichet added a comment -

Adding display of shared datasets in the question name as option and test of coherence of shared datasets (i.e. their category == the question category ,they had not been moved.

Show
Pierre Pichet added a comment - Adding display of shared datasets in the question name as option and test of coherence of shared datasets (i.e. their category == the question category ,they had not been moved.

People

Vote (3)
Watch (6)

Dates

  • Created:
    Updated: