<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.limesurvey.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ttielu</id>
	<title>LimeSurvey Manual - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://www.limesurvey.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ttielu"/>
	<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/Special:Contributions/Ttielu"/>
	<updated>2026-08-18T11:10:17Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.9</generator>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Project_ideas_for_GSOC_2011&amp;diff=2488</id>
		<title>Project ideas for GSOC 2011</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Project_ideas_for_GSOC_2011&amp;diff=2488"/>
		<updated>2011-03-28T16:45:57Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Welcome=&lt;br /&gt;
&lt;br /&gt;
Welcome Google Summer of Code Student aspirants (:razz:)&lt;br /&gt;
&lt;br /&gt;
This page lists project ideas developed by the LimeSurvey Community. These tend to be areas that will get the most support as projects since they have been developed by people who know the project and what it needs the most. &#039;&#039;&#039;However&#039;&#039;&#039;, if you have your own idea for a project discuss your awesome idea with us in our [http://www.limesurvey.org/en/forum forums], [https://lists.sourceforge.net/lists/listinfo/limesurvey-developers mailing list] or at [http://www.limesurvey.org/en/support/live-chat #limesurvey on irc.freenode.net]. Then submit your proposal. Good Luck (:biggrin:)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=Project ideas=&lt;br /&gt;
&lt;br /&gt;
==Central participants database (User panel)==&lt;br /&gt;
&lt;br /&gt;
Develop a central &#039;participants&#039; database for LimeSurvey that can be used as a central registry of participants between surveys. The database should allow&lt;br /&gt;
* adding/removing of users along with flexible data to store related information for users&lt;br /&gt;
* simple copying of user-information to individual survey token tables&lt;br /&gt;
* ability to link user entries with survey responses if the linked survey was not unanimous (UUIDs?)&lt;br /&gt;
* ability for survey participants to register in the panel&lt;br /&gt;
* ability to update the flexible user data from collected results&lt;br /&gt;
* a &#039;do not email&#039; blacklist to allow people to automatically unsubscribe&lt;br /&gt;
* data ownership features for multi-user systems - allow different LimeSurvey users to &#039;own&#039; different participants&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Database and PHP coding&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Moderate to high - the coding would be relatively simple, but will entail complex relationships&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Jason Cleeland&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Port the LimeSurvey front-end to CodeIgniter==&lt;br /&gt;
&lt;br /&gt;
LimeSurvey is still written using old procedural code. We want to take the next step into the future and use a MVC-framework name CodeIgniter and port the whole application to this new framework. However proting the whole application is too much for one students. That is why we will split the task into smaller ones. This particular task deals with porting the front-end of LimeSurvey to CodeIgniter - this means all the parts that can be seen by the average survey participant:&lt;br /&gt;
*Survey taking&lt;br /&gt;
*Public statistics&lt;br /&gt;
*Central landing page&lt;br /&gt;
&lt;br /&gt;
During the rewrite you will be prompted also to encapsulate certain functions to objects where easily doable and it makes sense - we do not want you to rewrite everything. Since you are only working on a certain part of LimeSurvey and other students will port the back-end (=administration) of LimeSurvey you will be required to coordinate your coding with the other students.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
OOP experience in PHP and experience with a PHP framework like CakePHP or CodeIgniter are definately a must. You should get busy with LimeSurvey as early as possible. Students can raise their chance to get accepted by showing off according knowledge about LimeSurvey inner workings.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you fulfill the requirements above the difficulty in this task is to gradually modernize an application with a modern coding approach while resisting the natural urge to rewrite everything at once. Our mantra to modernizing the application is that the framework is just laying the new fundaments while the fance walls can be built later. So we lay the fundament first and make it stable, then we build new walls (See also [[LimeSurvey roadmap|the LimeSurvey roadmap]] )&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Carsten Schmitz (c_schmitz)&lt;br /&gt;
&lt;br /&gt;
Thibault le Meur (tlemeur)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Port the LimeSurvey back-end (administration) to CodeIgniter==&lt;br /&gt;
&lt;br /&gt;
LimeSurvey is still written using old procedural code. We want to take the next step into the future and use a MVC-framework name CodeIgniter and port the whole application to this new framework. However porting the whole application is too much for one student. That is why we will split the task into smaller ones. This particular task deals with porting the backend of LimeSurvey to CodeIgniter - this means all the parts that can be seen by an administration user.&lt;br /&gt;
&lt;br /&gt;
During the rewrite you will be prompted also to encapsulate certain functions to objects where easily doable and it makes sense - we do not want you to rewrite everything. Since you are only working on a certain part of LimeSurvey and another student will port the front-end (=administration) of LimeSurvey you will be required to coordinate your coding with the other student.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
OOP experience in PHP and experience with a PHP framework like CakePHP or CodeIgniter are definately a must. You should get busy with LimeSurvey as early as possible. Students can raise their chance to get accepted by showing off according knowledge about LimeSurvey inner workings.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you are a very good PHP coder (and fit the demanded skills above) then the main difficulty in this task is the sheer size of it. The administration consists of a great number of different screens and functions which need to be ported. If you don&#039;t manage to port all of it then at least the unported parts still have to be working - still best would be if you manage to do the whole administration.&lt;br /&gt;
&lt;br /&gt;
Also the difficulty in this task is to gradually modernize an application with a modern coding approach while resisting the natural urge to rewrite everything at once. Our mantra to modernizing the application is that the framework is just laying the new foundation while the fancy walls can be built later. So we lay the foundation first and make it stable (your task in the administration), then we build new walls (See also [[LimeSurvey roadmap|the LimeSurvey roadmap]] )&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Carsten Schmitz (c_schmitz)&lt;br /&gt;
&lt;br /&gt;
Thibault le Meur (tlemeur)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Implement a modular authentication framework==&lt;br /&gt;
&lt;br /&gt;
The idea is to design and implement a modular authentication &amp;quot;framework&amp;quot; for LimeSurvey as well as some authentication modules. The Authentication framework will define the API each authentication plugin must (or may) implement and propose basic methods that can be used by plugins (for instance how to store the plugins parameters in DB, how to display a form using the survey template). A plugin will be responsible to implement, for each particular authentication backend, specific methods (some mandatory, some optionnal) such as: user authentication, user provisionning, user rights, ...&lt;br /&gt;
&lt;br /&gt;
Currently authentication is only used for the survey-administration GUI and not the participants interface (tokens are used for this). With the new authentication framework it will be possible to define several authentication backends and use some of them for participants-authentication.&lt;br /&gt;
&lt;br /&gt;
The generic authentication framework must define the following services:&lt;br /&gt;
* User authentication: this interface must return the identity of the authenticated user if authentication is successful.&lt;br /&gt;
** Authentication may not always be based on a simple user/password form, so the proposed framework must be generic enough to enable authentication based on other schemes (using any numbers or interaction-pages between the server and the end-user or any other contextual parameter such as Referrer, session variable...&lt;br /&gt;
* User provisionning:&lt;br /&gt;
** when activated on the survey administration interface, an authentication module might be able to create a newly authenticated user into the LimeSurvey internal DB (which is required for setting the user rights on the platform). The newly created user can be assigned a default profile or a per-user profile (queried from an external database).&lt;br /&gt;
** when activated on the participants interface, the authentication module will provision the token table of the correspoding survey // alternatively the general-purpose cross-survey participants-database as described in the above GSoC idea.&lt;br /&gt;
&lt;br /&gt;
The already existing authentication schemes will be ported to the new framework (internal-DB and Web server authentication delegation) and at least a new one will be implemented (openID, CAS, Shibboleth).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP, SQL, CodeIgniter, Authentication protocols (openID, CAS, LDAP-bind, ...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Medium&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable Mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
lemeur (Thibault Le Meur)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Want to know more&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Please read the [http://docs.limesurvey.org/tiki-index.php?page=GSOC+2010++Authentication+framework#FAQ FAQ about this project]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Rewrite and extend the conditions in LimeSurvey==&lt;br /&gt;
&lt;br /&gt;
[[File:addNewCondition1.png]]&lt;br /&gt;
&lt;br /&gt;
Rewrite the conditions engine that will let survey administrators design, store and evaluate conditions. Conditions must be implemented in such a way that they can be used in several features such as question branching (survey logic), assessments, quotas, ...&lt;br /&gt;
&lt;br /&gt;
This projects will at least end up with:&lt;br /&gt;
* A working GUI to design complex conditions:&lt;br /&gt;
** several atomic conditions can be combined by AND or OR logical operators and will support for grouping conditions with parentheses&lt;br /&gt;
** an atomic condition representation can be&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&amp;lt;left operand&amp;gt; &amp;lt;operator&amp;gt; &amp;lt;right operand&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
** an atomic condition editor will implement&lt;br /&gt;
*** several operators (equality, inequality, string-comparisons, numerical-comparisons, regexp),...&lt;br /&gt;
*** meta operators surch as &#039;Not displayed&#039;&lt;br /&gt;
** left and right operands can be answers from previous questions, or a static values. It should be extensible so that we are able in the future to use more complex operand such as the result of a specific function (for instance the sum of some previous integer questions)&lt;br /&gt;
* A working DB storage backend using a string in [http://en.wikipedia.org/wiki/Reverse_Polish_Notation RPN] (Reverse Polish Notation) to describe each condition&lt;br /&gt;
* The evaluation of conditions for the question branching feature.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP, CodeIgniter, JQuery and User Interface Design Skills&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
High&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable Mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Thibault Le Meur (lemeur)&lt;br /&gt;
&lt;br /&gt;
Carsten Schmitz&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Want to know more&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Discussion about the [http://docs.limesurvey.org/tiki-index.php?page=GSOC+2010+Condition+engine LS2 conditions engine] is an interresting start. Note however that the task will be easier this year because of the existing conditions engine and the stable database layout of LS1.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Custom Report Generation==&lt;br /&gt;
&lt;br /&gt;
The task is to make a module which will generate custom reports. Module should be able to do these things(at least) :-&lt;br /&gt;
*Creating various types of reports i.e. using tables, pie charts, graphs and bar-charts to name few.&lt;br /&gt;
*The resulting charts and other illustrations should be easy to read and understand, and should include the ability to export into standard office suites.&lt;br /&gt;
*Reports can be general or survey specific.&lt;br /&gt;
**General in the sense that it should show basic findings of a general survey graphically like number of users completing the survey, average time taken to complete the survey, average number of correct responses etc.&lt;br /&gt;
**Survey specific results should also be addressed properly e.g. how many users choose first option as there answer of a particular question, how many users didn&#039;t answer a specific question etc.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
OOP experience in PHP and experience with a PHP framework like CakePHP or CodeIgniter, jQuery. Strong mathematical background will help!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Moderate&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Carsten Schmitz (c_schmitz)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Adding new questions/subquestions and groups dynamically==&lt;br /&gt;
&lt;br /&gt;
Currently in LimeSurvey once a survey is activate we can not&lt;br /&gt;
*Add or delete groups&lt;br /&gt;
*Add or delete questions&lt;br /&gt;
*Add or delete subquestions or change their codes&lt;br /&gt;
&lt;br /&gt;
The idea is to cover these shortcomings. And in addition, all those participants who have already taken that survey must also be notified about the changes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Experience with a PHP framework like CakePHP or CodeIgniter and knowledge of inner working of LimeSurvey is must!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Moderate&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Carsten Schmitz (c_schmitz)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Extend the use of assessments==&lt;br /&gt;
&lt;br /&gt;
[http://docs.limesurvey.org/Assessments&amp;amp;structure;=English+Instructions+for+LimeSurvey Assessments] are used a lot at Limesurvey but currently this feature only covers very basic needs. Users have asked for some additional assessment features, unfortunately most of them can&#039;t be implemented until we start saving assessment results at the database instead of calculating assessment scores at runtime.&lt;br /&gt;
&lt;br /&gt;
So the first step is to extend the database layout of Limesurvey and add a new table for storing assessment results. Once this is done advanced features can be implemented such as:&lt;br /&gt;
* Export assessment results when exporting survey data&lt;br /&gt;
* Include assessment results at confirmation emails&lt;br /&gt;
* Extend statistics to include information about assessment results such as max score, min score, mean score, standard deviation, ...&lt;br /&gt;
* Connect [http://docs.limesurvey.org/Quotas&amp;amp;structure;=English+Instructions+for+LimeSurvey quotas] and assessments so that assessment results can be used to screen users at the beginning of a survey.&lt;br /&gt;
* Enable assessment scores at [http://docs.limesurvey.org/Setting+conditions&amp;amp;structure;=English+Instructions+for+LimeSurvey conditions] so that a condition like &amp;quot;&#039;&#039;Show question X if &amp;lt;assessment_score1&amp;gt; &amp;gt; 10&#039;&#039;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP, MySQL, CodeIgniter, JQuery and some basic User Interface Design Skills&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Medium&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable Mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Carsten Schmitz (c_schmitz)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==&#039;&#039;&#039;NEW&#039;&#039;&#039; Rebuild the database frontend using CodeIgniter==&lt;br /&gt;
&lt;br /&gt;
During last years GSoC, a database frontend was developed using CakePHP. Limesurvey has since decided to switch to the CodeIgniter framework. As such, last years work needs to be ported to CodeIgniter.&lt;br /&gt;
&lt;br /&gt;
All documentation from last year is available at [[Database Storage Engine Project|here]] aswell as the source of the developed CakePHP modules which can be found [https://limesurvey.svn.sourceforge.net/svnroot/limesurvey/source/limesurvey20/limesurvey-dev/app/plugins/ here] - the plugins market with dbse.&lt;br /&gt;
&lt;br /&gt;
The final project has to comply with the API developed last year, changes have to be discussed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP, SQL, Object oriented programming &amp;amp; design patterns, CodeIgniter, CakePHP&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Medium, Main challenges will be database abstraction and automatic generation of sql code out of survey structures.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable Mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Maarten Tielemans (ttielu)&lt;br /&gt;
&lt;br /&gt;
Pieter-Jan Speelmans (MrP001)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Idea template==&lt;br /&gt;
&lt;br /&gt;
Describe the idea here in general terms&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Explain what sort of coding skills would be needed for a student to implement this project&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Explain the level of difficulty involved&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable Mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Put your name (and tag) here if you are willing to mentor a student for this idea&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=More information=&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
[[GSoC getting started|Check out our &#039;Get started&#039; page]] for setting up the development environment, coding standards, and all the other important stuff that you need to know before the real fun begins!&lt;br /&gt;
&lt;br /&gt;
==Frequently Asked Questions==&lt;br /&gt;
&lt;br /&gt;
Check out [[GSoC FAQ|our GSoC FAQ page.]]&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Project_ideas_for_GSOC_2011&amp;diff=2489</id>
		<title>Project ideas for GSOC 2011</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Project_ideas_for_GSOC_2011&amp;diff=2489"/>
		<updated>2011-03-28T16:45:56Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Welcome=&lt;br /&gt;
&lt;br /&gt;
Welcome Google Summer of Code Student aspirants (:razz:)&lt;br /&gt;
&lt;br /&gt;
This page lists project ideas developed by the LimeSurvey Community. These tend to be areas that will get the most support as projects since they have been developed by people who know the project and what it needs the most. &#039;&#039;&#039;However&#039;&#039;&#039;, if you have your own idea for a project discuss your awesome idea with us in our [http://www.limesurvey.org/en/forum forums], [https://lists.sourceforge.net/lists/listinfo/limesurvey-developers mailing list] or at [http://www.limesurvey.org/en/support/live-chat #limesurvey on irc.freenode.net]. Then submit your proposal. Good Luck (:biggrin:)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=Project ideas=&lt;br /&gt;
&lt;br /&gt;
==Central participants database (User panel)==&lt;br /&gt;
&lt;br /&gt;
Develop a central &#039;participants&#039; database for LimeSurvey that can be used as a central registry of participants between surveys. The database should allow&lt;br /&gt;
* adding/removing of users along with flexible data to store related information for users&lt;br /&gt;
* simple copying of user-information to individual survey token tables&lt;br /&gt;
* ability to link user entries with survey responses if the linked survey was not unanimous (UUIDs?)&lt;br /&gt;
* ability for survey participants to register in the panel&lt;br /&gt;
* ability to update the flexible user data from collected results&lt;br /&gt;
* a &#039;do not email&#039; blacklist to allow people to automatically unsubscribe&lt;br /&gt;
* data ownership features for multi-user systems - allow different LimeSurvey users to &#039;own&#039; different participants&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Database and PHP coding&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Moderate to high - the coding would be relatively simple, but will entail complex relationships&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Jason Cleeland&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Port the LimeSurvey front-end to CodeIgniter==&lt;br /&gt;
&lt;br /&gt;
LimeSurvey is still written using old procedural code. We want to take the next step into the future and use a MVC-framework name CodeIgniter and port the whole application to this new framework. However proting the whole application is too much for one students. That is why we will split the task into smaller ones. This particular task deals with porting the front-end of LimeSurvey to CodeIgniter - this means all the parts that can be seen by the average survey participant:&lt;br /&gt;
*Survey taking&lt;br /&gt;
*Public statistics&lt;br /&gt;
*Central landing page&lt;br /&gt;
&lt;br /&gt;
During the rewrite you will be prompted also to encapsulate certain functions to objects where easily doable and it makes sense - we do not want you to rewrite everything. Since you are only working on a certain part of LimeSurvey and other students will port the back-end (=administration) of LimeSurvey you will be required to coordinate your coding with the other students.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
OOP experience in PHP and experience with a PHP framework like CakePHP or CodeIgniter are definately a must. You should get busy with LimeSurvey as early as possible. Students can raise their chance to get accepted by showing off according knowledge about LimeSurvey inner workings.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you fulfill the requirements above the difficulty in this task is to gradually modernize an application with a modern coding approach while resisting the natural urge to rewrite everything at once. Our mantra to modernizing the application is that the framework is just laying the new fundaments while the fance walls can be built later. So we lay the fundament first and make it stable, then we build new walls (See also [[LimeSurvey roadmap|the LimeSurvey roadmap]] )&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Carsten Schmitz (c_schmitz)&lt;br /&gt;
&lt;br /&gt;
Thibault le Meur (tlemeur)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Port the LimeSurvey back-end (administration) to CodeIgniter==&lt;br /&gt;
&lt;br /&gt;
LimeSurvey is still written using old procedural code. We want to take the next step into the future and use a MVC-framework name CodeIgniter and port the whole application to this new framework. However porting the whole application is too much for one student. That is why we will split the task into smaller ones. This particular task deals with porting the backend of LimeSurvey to CodeIgniter - this means all the parts that can be seen by an administration user.&lt;br /&gt;
&lt;br /&gt;
During the rewrite you will be prompted also to encapsulate certain functions to objects where easily doable and it makes sense - we do not want you to rewrite everything. Since you are only working on a certain part of LimeSurvey and another student will port the front-end (=administration) of LimeSurvey you will be required to coordinate your coding with the other student.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
OOP experience in PHP and experience with a PHP framework like CakePHP or CodeIgniter are definately a must. You should get busy with LimeSurvey as early as possible. Students can raise their chance to get accepted by showing off according knowledge about LimeSurvey inner workings.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you are a very good PHP coder (and fit the demanded skills above) then the main difficulty in this task is the sheer size of it. The administration consists of a great number of different screens and functions which need to be ported. If you don&#039;t manage to port all of it then at least the unported parts still have to be working - still best would be if you manage to do the whole administration.&lt;br /&gt;
&lt;br /&gt;
Also the difficulty in this task is to gradually modernize an application with a modern coding approach while resisting the natural urge to rewrite everything at once. Our mantra to modernizing the application is that the framework is just laying the new foundation while the fancy walls can be built later. So we lay the foundation first and make it stable (your task in the administration), then we build new walls (See also [[LimeSurvey roadmap|the LimeSurvey roadmap]] )&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Carsten Schmitz (c_schmitz)&lt;br /&gt;
&lt;br /&gt;
Thibault le Meur (tlemeur)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Implement a modular authentication framework==&lt;br /&gt;
&lt;br /&gt;
The idea is to design and implement a modular authentication &amp;quot;framework&amp;quot; for LimeSurvey as well as some authentication modules. The Authentication framework will define the API each authentication plugin must (or may) implement and propose basic methods that can be used by plugins (for instance how to store the plugins parameters in DB, how to display a form using the survey template). A plugin will be responsible to implement, for each particular authentication backend, specific methods (some mandatory, some optionnal) such as: user authentication, user provisionning, user rights, ...&lt;br /&gt;
&lt;br /&gt;
Currently authentication is only used for the survey-administration GUI and not the participants interface (tokens are used for this). With the new authentication framework it will be possible to define several authentication backends and use some of them for participants-authentication.&lt;br /&gt;
&lt;br /&gt;
The generic authentication framework must define the following services:&lt;br /&gt;
* User authentication: this interface must return the identity of the authenticated user if authentication is successful.&lt;br /&gt;
** Authentication may not always be based on a simple user/password form, so the proposed framework must be generic enough to enable authentication based on other schemes (using any numbers or interaction-pages between the server and the end-user or any other contextual parameter such as Referrer, session variable...&lt;br /&gt;
* User provisionning:&lt;br /&gt;
** when activated on the survey administration interface, an authentication module might be able to create a newly authenticated user into the LimeSurvey internal DB (which is required for setting the user rights on the platform). The newly created user can be assigned a default profile or a per-user profile (queried from an external database).&lt;br /&gt;
** when activated on the participants interface, the authentication module will provision the token table of the correspoding survey // alternatively the general-purpose cross-survey participants-database as described in the above GSoC idea.&lt;br /&gt;
&lt;br /&gt;
The already existing authentication schemes will be ported to the new framework (internal-DB and Web server authentication delegation) and at least a new one will be implemented (openID, CAS, Shibboleth).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP, SQL, CodeIgniter, Authentication protocols (openID, CAS, LDAP-bind, ...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Medium&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable Mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
lemeur (Thibault Le Meur)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Want to know more&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Please read the [http://docs.limesurvey.org/tiki-index.php?page=GSOC+2010++Authentication+framework#FAQ FAQ about this project]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Rewrite and extend the conditions in LimeSurvey==&lt;br /&gt;
&lt;br /&gt;
[[File:addNewCondition1.png]]&lt;br /&gt;
&lt;br /&gt;
Rewrite the conditions engine that will let survey administrators design, store and evaluate conditions. Conditions must be implemented in such a way that they can be used in several features such as question branching (survey logic), assessments, quotas, ...&lt;br /&gt;
&lt;br /&gt;
This projects will at least end up with:&lt;br /&gt;
* A working GUI to design complex conditions:&lt;br /&gt;
** several atomic conditions can be combined by AND or OR logical operators and will support for grouping conditions with parentheses&lt;br /&gt;
** an atomic condition representation can be&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&amp;lt;left operand&amp;gt; &amp;lt;operator&amp;gt; &amp;lt;right operand&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
** an atomic condition editor will implement&lt;br /&gt;
*** several operators (equality, inequality, string-comparisons, numerical-comparisons, regexp),...&lt;br /&gt;
*** meta operators surch as &#039;Not displayed&#039;&lt;br /&gt;
** left and right operands can be answers from previous questions, or a static values. It should be extensible so that we are able in the future to use more complex operand such as the result of a specific function (for instance the sum of some previous integer questions)&lt;br /&gt;
* A working DB storage backend using a string in [http://en.wikipedia.org/wiki/Reverse_Polish_Notation RPN] (Reverse Polish Notation) to describe each condition&lt;br /&gt;
* The evaluation of conditions for the question branching feature.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP, CodeIgniter, JQuery and User Interface Design Skills&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
High&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable Mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Thibault Le Meur (lemeur)&lt;br /&gt;
&lt;br /&gt;
Carsten Schmitz&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Want to know more&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Discussion about the [http://docs.limesurvey.org/tiki-index.php?page=GSOC+2010+Condition+engine LS2 conditions engine] is an interresting start. Note however that the task will be easier this year because of the existing conditions engine and the stable database layout of LS1.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Custom Report Generation==&lt;br /&gt;
&lt;br /&gt;
The task is to make a module which will generate custom reports. Module should be able to do these things(at least) :-&lt;br /&gt;
*Creating various types of reports i.e. using tables, pie charts, graphs and bar-charts to name few.&lt;br /&gt;
*The resulting charts and other illustrations should be easy to read and understand, and should include the ability to export into standard office suites.&lt;br /&gt;
*Reports can be general or survey specific.&lt;br /&gt;
**General in the sense that it should show basic findings of a general survey graphically like number of users completing the survey, average time taken to complete the survey, average number of correct responses etc.&lt;br /&gt;
**Survey specific results should also be addressed properly e.g. how many users choose first option as there answer of a particular question, how many users didn&#039;t answer a specific question etc.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
OOP experience in PHP and experience with a PHP framework like CakePHP or CodeIgniter, jQuery. Strong mathematical background will help!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Moderate&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Carsten Schmitz (c_schmitz)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Adding new questions/subquestions and groups dynamically==&lt;br /&gt;
&lt;br /&gt;
Currently in LimeSurvey once a survey is activate we can not&lt;br /&gt;
*Add or delete groups&lt;br /&gt;
*Add or delete questions&lt;br /&gt;
*Add or delete subquestions or change their codes&lt;br /&gt;
&lt;br /&gt;
The idea is to cover these shortcomings. And in addition, all those participants who have already taken that survey must also be notified about the changes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Experience with a PHP framework like CakePHP or CodeIgniter and knowledge of inner working of LimeSurvey is must!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Moderate&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Carsten Schmitz (c_schmitz)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Extend the use of assessments==&lt;br /&gt;
&lt;br /&gt;
[http://docs.limesurvey.org/Assessments&amp;amp;structure;=English+Instructions+for+LimeSurvey Assessments] are used a lot at Limesurvey but currently this feature only covers very basic needs. Users have asked for some additional assessment features, unfortunately most of them can&#039;t be implemented until we start saving assessment results at the database instead of calculating assessment scores at runtime.&lt;br /&gt;
&lt;br /&gt;
So the first step is to extend the database layout of Limesurvey and add a new table for storing assessment results. Once this is done advanced features can be implemented such as:&lt;br /&gt;
* Export assessment results when exporting survey data&lt;br /&gt;
* Include assessment results at confirmation emails&lt;br /&gt;
* Extend statistics to include information about assessment results such as max score, min score, mean score, standard deviation, ...&lt;br /&gt;
* Connect [http://docs.limesurvey.org/Quotas&amp;amp;structure;=English+Instructions+for+LimeSurvey quotas] and assessments so that assessment results can be used to screen users at the beginning of a survey.&lt;br /&gt;
* Enable assessment scores at [http://docs.limesurvey.org/Setting+conditions&amp;amp;structure;=English+Instructions+for+LimeSurvey conditions] so that a condition like &amp;quot;&#039;&#039;Show question X if &amp;lt;assessment_score1&amp;gt; &amp;gt; 10&#039;&#039;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP, MySQL, CodeIgniter, JQuery and some basic User Interface Design Skills&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Medium&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable Mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Carsten Schmitz (c_schmitz)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==&#039;&#039;&#039;NEW&#039;&#039;&#039; Rebuild the database frontend using CodeIgniter==&lt;br /&gt;
&lt;br /&gt;
During last years GSoC, a database frontend was developed using CakePHP. Limesurvey has since decided to switch to the CodeIgniter framework. As such, last years work needs to be ported to CodeIgniter.&lt;br /&gt;
&lt;br /&gt;
All documentation from last year is available at [[Database Storage Engine Project|here]] aswell as the source of the developed CakePHP modules which can be found [https://limesurvey.svn.sourceforge.net/svnroot/limesurvey/source/limesurvey20/limesurvey-dev/app/plugins/ here] - the plugins market with dbse.&lt;br /&gt;
&lt;br /&gt;
The final project has to comply with the API developed last year, changes have to be discussed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP, SQL, Object oriented programming &amp;amp; design patterns, CodeIgniter, CakePHP&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Medium, Main challenges will be database abstraction and automatic generation of sql code out of survey structures.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable Mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Maarten Tielemans (ttielu)&lt;br /&gt;
&lt;br /&gt;
Pieter-Jan Speelmans (MrP001)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Idea template==&lt;br /&gt;
&lt;br /&gt;
Describe the idea here in general terms&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Skills&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Explain what sort of coding skills would be needed for a student to implement this project&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Difficulty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Explain the level of difficulty involved&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probable Mentors&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Put your name (and tag) here if you are willing to mentor a student for this idea&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=More information=&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
[[GSoC getting started|Check out our &#039;Get started&#039; page]] for setting up the development environment, coding standards, and all the other important stuff that you need to know before the real fun begins!&lt;br /&gt;
&lt;br /&gt;
==Frequently Asked Questions==&lt;br /&gt;
&lt;br /&gt;
Check out [[GSoC FAQ|our GSoC FAQ page.]]&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M3_Class_diagram&amp;diff=4274</id>
		<title>Database Storage Engine Project M3 Class diagram</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M3_Class_diagram&amp;diff=4274"/>
		<updated>2010-08-11T13:44:21Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes documenting the [[Database Storage Engine Project|Database Storage Engine]] with a class diagram. This will make it easier for future developers to make changes to the database system. This milestone is closely linked to the [[Database Storage Engine Project M2 API|API]] milestone since the controllers will have to implement this API.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Identify the important classes and define the data-classes for the system (done)&lt;br /&gt;
*Define the structure of the database designs (done)&lt;br /&gt;
&lt;br /&gt;
= Diagrams=&lt;br /&gt;
&lt;br /&gt;
There are three big parts in the diagrams: the enginefactory, the components and the model classes. Packages used in the diagrams will not result in namespaces.&lt;br /&gt;
&lt;br /&gt;
== Model classes==&lt;br /&gt;
&lt;br /&gt;
[[File:models.png]]&lt;br /&gt;
&lt;br /&gt;
== Components==&lt;br /&gt;
&lt;br /&gt;
[[File:components.png]]&lt;br /&gt;
&lt;br /&gt;
This also contains the DbseObserver components, which can be used to register classes implementing the DbseObserver interface.&lt;br /&gt;
&lt;br /&gt;
== Engine factory==&lt;br /&gt;
&lt;br /&gt;
[[File:enginefactory.png]]&lt;br /&gt;
&lt;br /&gt;
This also contains the DbseObserver interface, which can be implemented.&lt;br /&gt;
&lt;br /&gt;
== Question types==&lt;br /&gt;
&lt;br /&gt;
A list of question types can be found at:&lt;br /&gt;
&lt;br /&gt;
[[Database Storage Engine Project M1 Database Design|#Mappings_for_QuestionType_classes_to_table_columns]]&lt;br /&gt;
&lt;br /&gt;
Methods for these classes will be documented when they are implemented.&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M3_Class_diagram&amp;diff=4275</id>
		<title>Database Storage Engine Project M3 Class diagram</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M3_Class_diagram&amp;diff=4275"/>
		<updated>2010-08-11T13:43:29Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes documenting the [[Database Storage Engine Project|Database Storage Engine]] with a class diagram. This will make it easier for future developers to make changes to the database system. This milestone is closely linked to the [[Database Storage Engine Project M2 API|API]] milestone since the controllers will have to implement this API.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Identify the important classes and define the data-classes for the system (done)&lt;br /&gt;
*Define the structure of the database designs (done)&lt;br /&gt;
&lt;br /&gt;
= Diagrams=&lt;br /&gt;
&lt;br /&gt;
There are three big parts in the diagrams: the factory part, the controllers and the general classes. Packages used in the diagrams will not result in namespaces.&lt;br /&gt;
&lt;br /&gt;
== Model classes==&lt;br /&gt;
&lt;br /&gt;
[[File:models.png]]&lt;br /&gt;
&lt;br /&gt;
== Components==&lt;br /&gt;
&lt;br /&gt;
[[File:components.png]]&lt;br /&gt;
&lt;br /&gt;
This also contains the DbseObserver components, which can be used to register classes implementing the DbseObserver interface.&lt;br /&gt;
&lt;br /&gt;
== Engine factory==&lt;br /&gt;
&lt;br /&gt;
[[File:enginefactory.png]]&lt;br /&gt;
&lt;br /&gt;
This also contains the DbseObserver interface, which can be implemented.&lt;br /&gt;
&lt;br /&gt;
== Question types==&lt;br /&gt;
&lt;br /&gt;
A list of question types can be found at:&lt;br /&gt;
&lt;br /&gt;
[[Database Storage Engine Project M1 Database Design|#Mappings_for_QuestionType_classes_to_table_columns]]&lt;br /&gt;
&lt;br /&gt;
Methods for these classes will be documented when they are implemented.&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M3_Class_diagram&amp;diff=4279</id>
		<title>Database Storage Engine Project M3 Class diagram</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M3_Class_diagram&amp;diff=4279"/>
		<updated>2010-07-08T09:48:39Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes documenting the [[Database Storage Engine Project|Database Storage Engine]] with a class diagram. This will make it easier for future developers to make changes to the database system. This milestone is closely linked to the [[Database Storage Engine Project M2 API|API]] milestone since the controllers will have to implement this API.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Identify the important classes and define the data-classes for the system&lt;br /&gt;
*Define the structure of the database designs&lt;br /&gt;
&lt;br /&gt;
= Diagrams=&lt;br /&gt;
&lt;br /&gt;
There are three big parts in the diagrams: the factory part, the controllers and the general classes. Packages used in the diagrams will not result in namespaces.&lt;br /&gt;
&lt;br /&gt;
== General classes==&lt;br /&gt;
&lt;br /&gt;
[[File:general.png]]&lt;br /&gt;
&lt;br /&gt;
== Controllers==&lt;br /&gt;
&lt;br /&gt;
[[File:controllers.png]]&lt;br /&gt;
&lt;br /&gt;
== Engine factory==&lt;br /&gt;
&lt;br /&gt;
The engine classes (like the one in the DBSESF package) are trivial classes (one for each type of table).&lt;br /&gt;
&lt;br /&gt;
[[File:eninefactory.png]]&lt;br /&gt;
&lt;br /&gt;
== Exceptions==&lt;br /&gt;
&lt;br /&gt;
The exceptions classes. They will have a message which will describe the exception.&lt;br /&gt;
&lt;br /&gt;
[[File:exceptions.png]]&lt;br /&gt;
&lt;br /&gt;
== Question types==&lt;br /&gt;
&lt;br /&gt;
A list of question types can be found at:&lt;br /&gt;
&lt;br /&gt;
[[Database Storage Engine Project M1 Database Design|#Mappings_for_QuestionType_classes_to_table_columns]]&lt;br /&gt;
&lt;br /&gt;
Methods for these classes will be documented when they are implemented.&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4262</id>
		<title>Database Storage Engine Project M2 API</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4262"/>
		<updated>2010-07-02T18:02:09Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes building the API for the [[Database Storage Engine Project|database system]].&lt;br /&gt;
&lt;br /&gt;
We will release a preview of the API before the 1st of June in order to have plenty of time for the community to comment.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Develop basic API and post it on the forums&lt;br /&gt;
*Explore comments on the basic API&lt;br /&gt;
*Complete the API&lt;br /&gt;
*Make sure it is possible to add/have support for current en future metadata related to single &amp;lt;u&amp;gt;questions&amp;lt;/u&amp;gt; &amp;amp; whole &amp;lt;u&amp;gt;surveys&amp;lt;/u&amp;gt;.&lt;br /&gt;
*Add methods to add and remove observers&lt;br /&gt;
&lt;br /&gt;
= Basic API version (06-25)=&lt;br /&gt;
&lt;br /&gt;
Below you find the first draft of the API.&lt;br /&gt;
&lt;br /&gt;
== Survey==&lt;br /&gt;
&lt;br /&gt;
A survey is a collection of sections. Surveys can have various metadata like a respondent e-mail adres, a name, ...&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaData(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the survey.&lt;br /&gt;
&lt;br /&gt;
== Section==&lt;br /&gt;
&lt;br /&gt;
A section is a part of a survey, grouping questions together. Using conditions it is possible to loop or branch over sections.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the section.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the section.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the section.&lt;br /&gt;
&lt;br /&gt;
== QuestionType==&lt;br /&gt;
&lt;br /&gt;
A survey can have various types of questions, ranging from string &amp;amp; integers up to fileinput and matrix types. QuestionType will have subclasses: basic question types like IntegerQuestionType, StringQuestionType, DateQuestionType ... and structures like MatrixQuestionType, ArrayQuestionType, ...&lt;br /&gt;
&lt;br /&gt;
=== abstract string render()===&lt;br /&gt;
&lt;br /&gt;
Returns a template for this questiontype.&lt;br /&gt;
&lt;br /&gt;
=== abstract mixed getFields()===&lt;br /&gt;
&lt;br /&gt;
Returns a list of all fields required by this questiontype and their types.&lt;br /&gt;
&lt;br /&gt;
=== abstract bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== Question==&lt;br /&gt;
&lt;br /&gt;
A question is a combination of a string (the question) a QuestionType and possible various options - depending on the type.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the question.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the question.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the question.&lt;br /&gt;
&lt;br /&gt;
=== bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== ModelAnswer==&lt;br /&gt;
&lt;br /&gt;
A model answer for a closed question.&lt;br /&gt;
&lt;br /&gt;
=== mixed getValue()===&lt;br /&gt;
&lt;br /&gt;
Returns the value of this model answer.&lt;br /&gt;
&lt;br /&gt;
== Response==&lt;br /&gt;
&lt;br /&gt;
A response is a combination of a token, questionID, answervalue and metadata.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== date getStartTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was started. This means when the question was displayed.&lt;br /&gt;
&lt;br /&gt;
=== date getEndTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was ended. This means when the question was filled in.&lt;br /&gt;
&lt;br /&gt;
=== int getIteration()===&lt;br /&gt;
&lt;br /&gt;
Returns the iteration of this response (used for loops).&lt;br /&gt;
&lt;br /&gt;
== ModelAnswerManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of model answers.&lt;br /&gt;
&lt;br /&gt;
=== void storeModelAnswer(questionID, ModelAnswer)===&lt;br /&gt;
&lt;br /&gt;
Stores the given model answer to the database. If the model answer has no ID, it will be considered a new model answer. In this case ModelAnswer-&amp;gt;id will be set to the ID appointed to this model answer. The model answer must have a valid question id.&lt;br /&gt;
&lt;br /&gt;
=== ModelAnswer[] listModelAnswers(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all model answers of the given question.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(modelAnswerID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the front of the question.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(modelAnswerID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the end of the question.&lt;br /&gt;
&lt;br /&gt;
=== void reorder(assoc(modelAnswerId =&amp;gt; orderNumber))===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given model answers to the given order numbers. O6rders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
=== ModelAnswer getModelAnswer(modelAnswerID)===&lt;br /&gt;
&lt;br /&gt;
Returns the model answer belonging to the given model answer ID.&lt;br /&gt;
&lt;br /&gt;
=== void removeModelAnswer(modelAnswerID)===&lt;br /&gt;
&lt;br /&gt;
Removes the model answer with the given model answer ID.&lt;br /&gt;
&lt;br /&gt;
== SurveyManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of surveys.&lt;br /&gt;
&lt;br /&gt;
=== Survey[] listSurveys()===&lt;br /&gt;
&lt;br /&gt;
Lists all surveys.&lt;br /&gt;
&lt;br /&gt;
=== void storeSurvey(Survey)===&lt;br /&gt;
&lt;br /&gt;
Stores the given survey to the database. If the survey has no ID, it will be considered a new survey. In this case Survey-&amp;gt;id will be set to the ID appointed to this survey.&lt;br /&gt;
&lt;br /&gt;
=== Survey getSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted survey.&lt;br /&gt;
&lt;br /&gt;
=== void removeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Removes survey data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void openSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to open.&lt;br /&gt;
&lt;br /&gt;
=== void closeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to closed.&lt;br /&gt;
&lt;br /&gt;
=== void setDatabaseEngine(surveyID, engineID)===&lt;br /&gt;
&lt;br /&gt;
Enables the chosen database engine for the given survey. Can only be called the first time before the survey is opened.&lt;br /&gt;
&lt;br /&gt;
=== string[] getPossibleDatabaseEngines(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the possible engineID&#039;s of the database engines which are possible for this survey.&lt;br /&gt;
&lt;br /&gt;
== SectionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of sections.&lt;br /&gt;
&lt;br /&gt;
=== Section[] listSections(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Lists all sections in the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void storeSection(Section)===&lt;br /&gt;
&lt;br /&gt;
Stores the given section to the database. If the section has no ID, it will be considered a new section. In this case Section-&amp;gt;id will be set to the ID appointed to this section. The section must have a valid survey id.&lt;br /&gt;
&lt;br /&gt;
=== Section getSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted section.&lt;br /&gt;
&lt;br /&gt;
=== void removeSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Removes section data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(sectionId, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the front of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(sectionId, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the end of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void &amp;lt;nowiki&amp;gt;reorder(assoc(sectionId =&amp;gt; orderNumber))&amp;lt;/nowiki&amp;gt;===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given sections to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== interface DBSEObserver==&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyCreated(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyChanged(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on update of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionCreated(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionChanged(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on update of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionCreated(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionChanged(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on update of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyResponse(Response response)===&lt;br /&gt;
&lt;br /&gt;
Called on submission of a response.&lt;br /&gt;
&lt;br /&gt;
== QuestionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of questions.&lt;br /&gt;
&lt;br /&gt;
=== Question[] listQuestions(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Lists all questions in the given section.&lt;br /&gt;
&lt;br /&gt;
=== void storeQuestion(Question)===&lt;br /&gt;
&lt;br /&gt;
Stores the given question to the database. If the question has no ID, it will be considered a new question. In this case Question-&amp;gt;id will be set to the ID appointed to this question. The question must have a valid section id.&lt;br /&gt;
&lt;br /&gt;
=== Question getQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted question.&lt;br /&gt;
&lt;br /&gt;
=== void removeQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Removes question data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(questionID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the front of the section.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(questionID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the end of the section.&lt;br /&gt;
&lt;br /&gt;
=== void reorder(assoc(questionID =&amp;gt; orderNumber))===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given questions to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== AnswerAccessController==&lt;br /&gt;
&lt;br /&gt;
This controller provides methodes to store and retrieve survey answers.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&#039;construct(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Constructs a new controller for the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void addResponse(participantID, questionID, value, starttime, endtime, iteration=0)===&lt;br /&gt;
&lt;br /&gt;
Adds the given answer and metadata for the given question to the answers of the given participant. If there already was an answer to the given question for the given participant, the answer will be overridden. The iteration parameter is used to express this is the answer for the i&#039;th loop. If the given answer value is invalid for the given question, an exception will be thrown.&lt;br /&gt;
&lt;br /&gt;
=== Response getResponse(participantID, questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the response of the given participant to the given question and its metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponsesToQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the given question and their metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the survey.&lt;br /&gt;
&lt;br /&gt;
=== mixed exportResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns a double array containing all response information from the survey.&lt;br /&gt;
&lt;br /&gt;
=== boolean hasFinished(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given participant already finished the survey. Returns false if the participant did not complete the survey.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
== ObserverController==&lt;br /&gt;
&lt;br /&gt;
=== static ObserverController getInstance()===&lt;br /&gt;
&lt;br /&gt;
Returns a statical instance to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void addObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Adds an observer to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void removeObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Removes an observer from the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void notifyObservers(callback $function  ~091~,  mixed $parameter  ~091~,  mixed $...  ~093&amp;lt;span style=&amp;quot;color:093~)===&lt;br /&gt;
&lt;br /&gt;
Notifies all registered observers with the specific function and the given parameters.&lt;br /&gt;
&lt;br /&gt;
==Global notes==&lt;br /&gt;
*Metadata keys can be chained in dot-notation. &#039;color.red&#039; means the key &#039;color&#039; with subkey &#039;red&#039;.&lt;br /&gt;
*The returning of subkeys in metadata will result in assocs in the array. The &#039;color.red&#039; example will give&amp;quot;&amp;gt; array(color =&amp;gt; array(red =&amp;gt; ...)). When you use a subkey, you cannot use the key itself anymore.&lt;br /&gt;
*Exceptions will be used for reporting errors. The exceptions thrown by each method will be added later in the development process.&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Comments from Machaven:==&lt;br /&gt;
&lt;br /&gt;
 1. All the functions that do not return anything (void)&lt;br /&gt;
*Should functions not return true/false (bool) depending on success or failure?&lt;br /&gt;
&lt;br /&gt;
 2. void updateMetaDate(key, value, newValue)&lt;br /&gt;
*Should this be spelled: updateMetaData?&lt;br /&gt;
*Why is the original value required to change the metadata? Are the keys not unique?&lt;br /&gt;
&lt;br /&gt;
 3. How are errors handled?&lt;br /&gt;
* Can we trigger some action on error, set logging or retrieve error information?&lt;br /&gt;
&lt;br /&gt;
== Comments from Jason:==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From May&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 1. There has been some discussion about the use of the word token to represent each unique participant&lt;br /&gt;
*this may be better expressed using a different word internally. Since survey participants/token recipients will be represented as &amp;quot;users&amp;quot; maybe &amp;quot;userID&amp;quot; would be a better label than tokens - ie instead of &amp;quot;Answer getAnswer(token, questionID)&amp;quot;, &amp;quot;Answer getAnswer(userID, questionID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 2. The AnswerAccess controller, should it also be storing responses?&lt;br /&gt;
* So, there should be an equivalent of &amp;quot;getAnswer&amp;quot;, being &amp;quot;putAnswer&amp;quot; (or &amp;quot;saveAnswer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 3. Once answers are being stored, either in a flatfile table, or a normalised one, there will be some kind of unique id for the &amp;quot;collection&amp;quot; of answers, so they can be grouped together.&lt;br /&gt;
* A collection of survey responses, with their unique identifier, become the &amp;quot;sheet of answers&amp;quot; to a particular survey. In the case of a controlled survey - where the user has been specifically invited, so we know who they are, they&#039;ll have a unique userID from the users table. In the case of open/anonymous or general public surveys, this unique identifier will have to be something else - where is that reflected in the getAnswers, and where will it be reflected in the putAnswer(s) call?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New June Comments&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
I&#039;ve had a thought that the moveUp and moveDown methods should take an option of how many positions to move them. When you have 20 questions in a section, and you want to move your question to the top, moving it up one at a time can be really annoying. Can we have void moveUp(sectionId,positions) so if we want to move something 5 places up in the order, it could have a 5 for the positions? Default, of course, would be 1.&lt;br /&gt;
&lt;br /&gt;
== Comments from Hai:==&lt;br /&gt;
* Add functions for reordering questions (something that would take an array and/or an assoc. map)&lt;br /&gt;
* Make sure you handle scalability for conditions well. This includes:&lt;br /&gt;
** ability to link survey elements to multiple conditions, each condition linkable to multiple actions.&lt;br /&gt;
** providing functions for various condition actions, such as question hiding, branching etc. (sorry, I know this is extremely vague, I&#039;ll try to specify later on)&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4263</id>
		<title>Database Storage Engine Project M2 API</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4263"/>
		<updated>2010-07-02T17:55:47Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes building the API for the [[Database Storage Engine Project|database system]].&lt;br /&gt;
&lt;br /&gt;
We will release a preview of the API before the 1st of June in order to have plenty of time for the community to comment.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Develop basic API and post it on the forums&lt;br /&gt;
*Explore comments on the basic API&lt;br /&gt;
*Complete the API&lt;br /&gt;
*Make sure it is possible to add/have support for current en future metadata related to single &amp;lt;u&amp;gt;questions&amp;lt;/u&amp;gt; &amp;amp; whole &amp;lt;u&amp;gt;surveys&amp;lt;/u&amp;gt;.&lt;br /&gt;
*Add methods to add and remove observers&lt;br /&gt;
&lt;br /&gt;
= Basic API version (06-25)=&lt;br /&gt;
&lt;br /&gt;
Below you find the first draft of the API.&lt;br /&gt;
&lt;br /&gt;
== Survey==&lt;br /&gt;
&lt;br /&gt;
A survey is a collection of sections. Surveys can have various metadata like a respondent e-mail adres, a name, ...&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaData(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the survey.&lt;br /&gt;
&lt;br /&gt;
== Section==&lt;br /&gt;
&lt;br /&gt;
A section is a part of a survey, grouping questions together. Using conditions it is possible to loop or branch over sections.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the section.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the section.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the section.&lt;br /&gt;
&lt;br /&gt;
== QuestionType==&lt;br /&gt;
&lt;br /&gt;
A survey can have various types of questions, ranging from string &amp;amp; integers up to fileinput and matrix types. QuestionType will have subclasses: basic question types like IntegerQuestionType, StringQuestionType, DateQuestionType ... and structures like MatrixQuestionType, ArrayQuestionType, ...&lt;br /&gt;
&lt;br /&gt;
=== abstract string render()===&lt;br /&gt;
&lt;br /&gt;
Returns a template for this questiontype.&lt;br /&gt;
&lt;br /&gt;
=== abstract mixed getFields()===&lt;br /&gt;
&lt;br /&gt;
Returns a list of all fields required by this questiontype and their types.&lt;br /&gt;
&lt;br /&gt;
=== abstract bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== Question==&lt;br /&gt;
&lt;br /&gt;
A question is a combination of a string (the question) a QuestionType and possible various options - depending on the type.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the question.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the question.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the question.&lt;br /&gt;
&lt;br /&gt;
=== bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== ModelAnswer==&lt;br /&gt;
&lt;br /&gt;
A model answer for a closed question.&lt;br /&gt;
&lt;br /&gt;
=== mixed getValue()===&lt;br /&gt;
&lt;br /&gt;
Returns the value of this model answer.&lt;br /&gt;
&lt;br /&gt;
== Response==&lt;br /&gt;
&lt;br /&gt;
A response is a combination of a token, questionID, answervalue and metadata.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== date getStartTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was started. This means when the question was displayed.&lt;br /&gt;
&lt;br /&gt;
=== date getEndTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was ended. This means when the question was filled in.&lt;br /&gt;
&lt;br /&gt;
=== int getIteration()===&lt;br /&gt;
&lt;br /&gt;
Returns the iteration of this response (used for loops).&lt;br /&gt;
&lt;br /&gt;
== ModelAnswerManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of model answers.&lt;br /&gt;
&lt;br /&gt;
=== void storeModelAnswer(questionID, ModelAnswer)===&lt;br /&gt;
&lt;br /&gt;
Stores the given model answer to the database. If the model answer has no ID, it will be considered a new model answer. In this case ModelAnswer-&amp;gt;id will be set to the ID appointed to this model answer. The model answer must have a valid question id.&lt;br /&gt;
&lt;br /&gt;
=== ModelAnswer[] listModelAnswers(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all model answers of the given question.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(modelAnswerID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the front of the question.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(modelAnswerID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the end of the question.&lt;br /&gt;
&lt;br /&gt;
== SurveyManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of surveys.&lt;br /&gt;
&lt;br /&gt;
=== Survey[] listSurveys()===&lt;br /&gt;
&lt;br /&gt;
Lists all surveys.&lt;br /&gt;
&lt;br /&gt;
=== void storeSurvey(Survey)===&lt;br /&gt;
&lt;br /&gt;
Stores the given survey to the database. If the survey has no ID, it will be considered a new survey. In this case Survey-&amp;gt;id will be set to the ID appointed to this survey.&lt;br /&gt;
&lt;br /&gt;
=== Survey getSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted survey.&lt;br /&gt;
&lt;br /&gt;
=== void removeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Removes survey data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void openSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to open.&lt;br /&gt;
&lt;br /&gt;
=== void closeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to closed.&lt;br /&gt;
&lt;br /&gt;
=== void setDatabaseEngine(surveyID, engineID)===&lt;br /&gt;
&lt;br /&gt;
Enables the chosen database engine for the given survey. Can only be called the first time before the survey is opened.&lt;br /&gt;
&lt;br /&gt;
=== string[] getPossibleDatabaseEngines(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the possible engineID&#039;s of the database engines which are possible for this survey.&lt;br /&gt;
&lt;br /&gt;
== SectionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of sections.&lt;br /&gt;
&lt;br /&gt;
=== Section[] listSections(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Lists all sections in the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void storeSection(Section)===&lt;br /&gt;
&lt;br /&gt;
Stores the given section to the database. If the section has no ID, it will be considered a new section. In this case Section-&amp;gt;id will be set to the ID appointed to this section. The section must have a valid survey id.&lt;br /&gt;
&lt;br /&gt;
=== Section getSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted section.&lt;br /&gt;
&lt;br /&gt;
=== void removeSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Removes section data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(sectionId, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the front of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(sectionId, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the end of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void &amp;lt;nowiki&amp;gt;reorder(assoc(sectionId =&amp;gt; orderNumber))&amp;lt;/nowiki&amp;gt;===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given sections to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== interface DBSEObserver==&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyCreated(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyChanged(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on update of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionCreated(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionChanged(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on update of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionCreated(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionChanged(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on update of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyResponse(Response response)===&lt;br /&gt;
&lt;br /&gt;
Called on submission of a response.&lt;br /&gt;
&lt;br /&gt;
== QuestionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of questions.&lt;br /&gt;
&lt;br /&gt;
=== Question[] listQuestions(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Lists all questions in the given section.&lt;br /&gt;
&lt;br /&gt;
=== void storeQuestion(Question)===&lt;br /&gt;
&lt;br /&gt;
Stores the given question to the database. If the question has no ID, it will be considered a new question. In this case Question-&amp;gt;id will be set to the ID appointed to this question. The question must have a valid section id.&lt;br /&gt;
&lt;br /&gt;
=== Question getQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted question.&lt;br /&gt;
&lt;br /&gt;
=== void removeQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Removes question data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(questionID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the front of the section.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(questionID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the end of the section.&lt;br /&gt;
&lt;br /&gt;
=== void reorder(assoc(questionID =&amp;gt; orderNumber))===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given questions to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== AnswerAccessController==&lt;br /&gt;
&lt;br /&gt;
This controller provides methodes to store and retrieve survey answers.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&#039;construct(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Constructs a new controller for the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void addResponse(participantID, questionID, value, starttime, endtime, iteration=0)===&lt;br /&gt;
&lt;br /&gt;
Adds the given answer and metadata for the given question to the answers of the given participant. If there already was an answer to the given question for the given participant, the answer will be overridden. The iteration parameter is used to express this is the answer for the i&#039;th loop. If the given answer value is invalid for the given question, an exception will be thrown.&lt;br /&gt;
&lt;br /&gt;
=== Response getResponse(participantID, questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the response of the given participant to the given question and its metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponsesToQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the given question and their metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the survey.&lt;br /&gt;
&lt;br /&gt;
=== mixed exportResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns a double array containing all response information from the survey.&lt;br /&gt;
&lt;br /&gt;
=== boolean hasFinished(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given participant already finished the survey. Returns false if the participant did not complete the survey.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
== ObserverController==&lt;br /&gt;
&lt;br /&gt;
=== static ObserverController getInstance()===&lt;br /&gt;
&lt;br /&gt;
Returns a statical instance to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void addObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Adds an observer to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void removeObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Removes an observer from the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void notifyObservers(callback $function  ~091~,  mixed $parameter  ~091~,  mixed $...  ~093&amp;lt;span style=&amp;quot;color:093~)===&lt;br /&gt;
&lt;br /&gt;
Notifies all registered observers with the specific function and the given parameters.&lt;br /&gt;
&lt;br /&gt;
==Global notes==&lt;br /&gt;
*Metadata keys can be chained in dot-notation. &#039;color.red&#039; means the key &#039;color&#039; with subkey &#039;red&#039;.&lt;br /&gt;
*The returning of subkeys in metadata will result in assocs in the array. The &#039;color.red&#039; example will give&amp;quot;&amp;gt; array(color =&amp;gt; array(red =&amp;gt; ...)). When you use a subkey, you cannot use the key itself anymore.&lt;br /&gt;
*Exceptions will be used for reporting errors. The exceptions thrown by each method will be added later in the development process.&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Comments from Machaven:==&lt;br /&gt;
&lt;br /&gt;
 1. All the functions that do not return anything (void)&lt;br /&gt;
*Should functions not return true/false (bool) depending on success or failure?&lt;br /&gt;
&lt;br /&gt;
 2. void updateMetaDate(key, value, newValue)&lt;br /&gt;
*Should this be spelled: updateMetaData?&lt;br /&gt;
*Why is the original value required to change the metadata? Are the keys not unique?&lt;br /&gt;
&lt;br /&gt;
 3. How are errors handled?&lt;br /&gt;
* Can we trigger some action on error, set logging or retrieve error information?&lt;br /&gt;
&lt;br /&gt;
== Comments from Jason:==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From May&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 1. There has been some discussion about the use of the word token to represent each unique participant&lt;br /&gt;
*this may be better expressed using a different word internally. Since survey participants/token recipients will be represented as &amp;quot;users&amp;quot; maybe &amp;quot;userID&amp;quot; would be a better label than tokens - ie instead of &amp;quot;Answer getAnswer(token, questionID)&amp;quot;, &amp;quot;Answer getAnswer(userID, questionID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 2. The AnswerAccess controller, should it also be storing responses?&lt;br /&gt;
* So, there should be an equivalent of &amp;quot;getAnswer&amp;quot;, being &amp;quot;putAnswer&amp;quot; (or &amp;quot;saveAnswer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 3. Once answers are being stored, either in a flatfile table, or a normalised one, there will be some kind of unique id for the &amp;quot;collection&amp;quot; of answers, so they can be grouped together.&lt;br /&gt;
* A collection of survey responses, with their unique identifier, become the &amp;quot;sheet of answers&amp;quot; to a particular survey. In the case of a controlled survey - where the user has been specifically invited, so we know who they are, they&#039;ll have a unique userID from the users table. In the case of open/anonymous or general public surveys, this unique identifier will have to be something else - where is that reflected in the getAnswers, and where will it be reflected in the putAnswer(s) call?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New June Comments&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
I&#039;ve had a thought that the moveUp and moveDown methods should take an option of how many positions to move them. When you have 20 questions in a section, and you want to move your question to the top, moving it up one at a time can be really annoying. Can we have void moveUp(sectionId,positions) so if we want to move something 5 places up in the order, it could have a 5 for the positions? Default, of course, would be 1.&lt;br /&gt;
&lt;br /&gt;
== Comments from Hai:==&lt;br /&gt;
* Add functions for reordering questions (something that would take an array and/or an assoc. map)&lt;br /&gt;
* Make sure you handle scalability for conditions well. This includes:&lt;br /&gt;
** ability to link survey elements to multiple conditions, each condition linkable to multiple actions.&lt;br /&gt;
** providing functions for various condition actions, such as question hiding, branching etc. (sorry, I know this is extremely vague, I&#039;ll try to specify later on)&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4264</id>
		<title>Database Storage Engine Project M2 API</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4264"/>
		<updated>2010-07-02T17:55:38Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes building the API for the [[Database Storage Engine Project|database system]].&lt;br /&gt;
&lt;br /&gt;
We will release a preview of the API before the 1st of June in order to have plenty of time for the community to comment.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Develop basic API and post it on the forums&lt;br /&gt;
*Explore comments on the basic API&lt;br /&gt;
*Complete the API&lt;br /&gt;
*Make sure it is possible to add/have support for current en future metadata related to single &amp;lt;u&amp;gt;questions&amp;lt;/u&amp;gt; &amp;amp; whole &amp;lt;u&amp;gt;surveys&amp;lt;/u&amp;gt;.&lt;br /&gt;
*Add methods to add and remove observers&lt;br /&gt;
&lt;br /&gt;
= Basic API version (06-25)=&lt;br /&gt;
&lt;br /&gt;
Below you find the first draft of the API.&lt;br /&gt;
&lt;br /&gt;
== Survey==&lt;br /&gt;
&lt;br /&gt;
A survey is a collection of sections. Surveys can have various metadata like a respondent e-mail adres, a name, ...&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaData(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the survey.&lt;br /&gt;
&lt;br /&gt;
== Section==&lt;br /&gt;
&lt;br /&gt;
A section is a part of a survey, grouping questions together. Using conditions it is possible to loop or branch over sections.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the section.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the section.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the section.&lt;br /&gt;
&lt;br /&gt;
== QuestionType==&lt;br /&gt;
&lt;br /&gt;
A survey can have various types of questions, ranging from string &amp;amp; integers up to fileinput and matrix types. QuestionType will have subclasses: basic question types like IntegerQuestionType, StringQuestionType, DateQuestionType ... and structures like MatrixQuestionType, ArrayQuestionType, ...&lt;br /&gt;
&lt;br /&gt;
=== abstract string render()===&lt;br /&gt;
&lt;br /&gt;
Returns a template for this questiontype.&lt;br /&gt;
&lt;br /&gt;
=== abstract mixed getFields()===&lt;br /&gt;
&lt;br /&gt;
Returns a list of all fields required by this questiontype and their types.&lt;br /&gt;
&lt;br /&gt;
=== abstract bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== Question==&lt;br /&gt;
&lt;br /&gt;
A question is a combination of a string (the question) a QuestionType and possible various options - depending on the type.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the question.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the question.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the question.&lt;br /&gt;
&lt;br /&gt;
=== bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== ModelAnswer==&lt;br /&gt;
&lt;br /&gt;
A model answer for a closed question.&lt;br /&gt;
&lt;br /&gt;
=== mixed getValue()===&lt;br /&gt;
&lt;br /&gt;
Returns the value of this model answer.&lt;br /&gt;
&lt;br /&gt;
== Response==&lt;br /&gt;
&lt;br /&gt;
A response is a combination of a token, questionID, answervalue and metadata.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== date getStartTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was started. This means when the question was displayed.&lt;br /&gt;
&lt;br /&gt;
=== date getEndTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was ended. This means when the question was filled in.&lt;br /&gt;
&lt;br /&gt;
=== int getIteration()===&lt;br /&gt;
&lt;br /&gt;
Returns the iteration of this response (used for loops).&lt;br /&gt;
&lt;br /&gt;
== ModelAnswerManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of model answers.&lt;br /&gt;
&lt;br /&gt;
=== void storeModelAnswer(questionID, ModelAnswer)===&lt;br /&gt;
&lt;br /&gt;
Stores the given model answer to the database. If the model answer has no ID, it will be considered a new model answer. In this case ModelAnswer-&amp;gt;id will be set to the ID appointed to this model answer. The model answer must have a valid question id.&lt;br /&gt;
&lt;br /&gt;
=== ModelAnswer[] listModelAnswers(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all model answers of the given question.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(modelAnswerID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the front of the question.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(modelAnswerID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the end of the question.&lt;br /&gt;
&lt;br /&gt;
== SurveyManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of surveys.&lt;br /&gt;
&lt;br /&gt;
=== Survey[] listSurveys()===&lt;br /&gt;
&lt;br /&gt;
Lists all surveys.&lt;br /&gt;
&lt;br /&gt;
=== void storeSurvey(Survey)===&lt;br /&gt;
&lt;br /&gt;
Stores the given survey to the database. If the survey has no ID, it will be considered a new survey. In this case Survey-&amp;gt;id will be set to the ID appointed to this survey.&lt;br /&gt;
&lt;br /&gt;
=== Survey getSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted survey.&lt;br /&gt;
&lt;br /&gt;
=== void removeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Removes survey data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void openSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to open.&lt;br /&gt;
&lt;br /&gt;
=== void closeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to closed.&lt;br /&gt;
&lt;br /&gt;
=== void setDatabaseEngine(surveyID, engineID)===&lt;br /&gt;
&lt;br /&gt;
Enables the chosen database engine for the given survey. Can only be called the first time before the survey is opened.&lt;br /&gt;
&lt;br /&gt;
=== string[] getPossibleDatabaseEngines(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the possible engineID&#039;s of the database engines which are possible for this survey.&lt;br /&gt;
&lt;br /&gt;
== SectionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of sections.&lt;br /&gt;
&lt;br /&gt;
=== Section[] listSections(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Lists all sections in the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void storeSection(Section)===&lt;br /&gt;
&lt;br /&gt;
Stores the given section to the database. If the section has no ID, it will be considered a new section. In this case Section-&amp;gt;id will be set to the ID appointed to this section. The section must have a valid survey id.&lt;br /&gt;
&lt;br /&gt;
=== Section getSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted section.&lt;br /&gt;
&lt;br /&gt;
=== void removeSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Removes section data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(sectionId, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the front of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(sectionId, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the end of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void &amp;lt;nowiki&amp;gt;reorder(assoc(sectionId =&amp;gt; orderNumber))&amp;lt;/nowiki&amp;gt;===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given sections to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== interface DBSEObserver==&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyCreated(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyChanged(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on update of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionCreated(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionChanged(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on update of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionCreated(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionChanged(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on update of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyResponse(Response response)===&lt;br /&gt;
&lt;br /&gt;
Called on submission of a response.&lt;br /&gt;
&lt;br /&gt;
== QuestionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of questions.&lt;br /&gt;
&lt;br /&gt;
=== Question[] listQuestions(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Lists all questions in the given section.&lt;br /&gt;
&lt;br /&gt;
=== void storeQuestion(Question)===&lt;br /&gt;
&lt;br /&gt;
Stores the given question to the database. If the question has no ID, it will be considered a new question. In this case Question-&amp;gt;id will be set to the ID appointed to this question. The question must have a valid section id.&lt;br /&gt;
&lt;br /&gt;
=== Question getQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted question.&lt;br /&gt;
&lt;br /&gt;
=== void removeQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Removes question data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(questionID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the front of the section.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the end of the section.&lt;br /&gt;
&lt;br /&gt;
=== void reorder(assoc(questionID =&amp;gt; orderNumber))===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given questions to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== AnswerAccessController==&lt;br /&gt;
&lt;br /&gt;
This controller provides methodes to store and retrieve survey answers.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&#039;construct(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Constructs a new controller for the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void addResponse(participantID, questionID, value, starttime, endtime, iteration=0)===&lt;br /&gt;
&lt;br /&gt;
Adds the given answer and metadata for the given question to the answers of the given participant. If there already was an answer to the given question for the given participant, the answer will be overridden. The iteration parameter is used to express this is the answer for the i&#039;th loop. If the given answer value is invalid for the given question, an exception will be thrown.&lt;br /&gt;
&lt;br /&gt;
=== Response getResponse(participantID, questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the response of the given participant to the given question and its metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponsesToQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the given question and their metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the survey.&lt;br /&gt;
&lt;br /&gt;
=== mixed exportResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns a double array containing all response information from the survey.&lt;br /&gt;
&lt;br /&gt;
=== boolean hasFinished(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given participant already finished the survey. Returns false if the participant did not complete the survey.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
== ObserverController==&lt;br /&gt;
&lt;br /&gt;
=== static ObserverController getInstance()===&lt;br /&gt;
&lt;br /&gt;
Returns a statical instance to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void addObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Adds an observer to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void removeObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Removes an observer from the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void notifyObservers(callback $function  ~091~,  mixed $parameter  ~091~,  mixed $...  ~093&amp;lt;span style=&amp;quot;color:093~)===&lt;br /&gt;
&lt;br /&gt;
Notifies all registered observers with the specific function and the given parameters.&lt;br /&gt;
&lt;br /&gt;
==Global notes==&lt;br /&gt;
*Metadata keys can be chained in dot-notation. &#039;color.red&#039; means the key &#039;color&#039; with subkey &#039;red&#039;.&lt;br /&gt;
*The returning of subkeys in metadata will result in assocs in the array. The &#039;color.red&#039; example will give&amp;quot;&amp;gt; array(color =&amp;gt; array(red =&amp;gt; ...)). When you use a subkey, you cannot use the key itself anymore.&lt;br /&gt;
*Exceptions will be used for reporting errors. The exceptions thrown by each method will be added later in the development process.&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Comments from Machaven:==&lt;br /&gt;
&lt;br /&gt;
 1. All the functions that do not return anything (void)&lt;br /&gt;
*Should functions not return true/false (bool) depending on success or failure?&lt;br /&gt;
&lt;br /&gt;
 2. void updateMetaDate(key, value, newValue)&lt;br /&gt;
*Should this be spelled: updateMetaData?&lt;br /&gt;
*Why is the original value required to change the metadata? Are the keys not unique?&lt;br /&gt;
&lt;br /&gt;
 3. How are errors handled?&lt;br /&gt;
* Can we trigger some action on error, set logging or retrieve error information?&lt;br /&gt;
&lt;br /&gt;
== Comments from Jason:==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From May&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 1. There has been some discussion about the use of the word token to represent each unique participant&lt;br /&gt;
*this may be better expressed using a different word internally. Since survey participants/token recipients will be represented as &amp;quot;users&amp;quot; maybe &amp;quot;userID&amp;quot; would be a better label than tokens - ie instead of &amp;quot;Answer getAnswer(token, questionID)&amp;quot;, &amp;quot;Answer getAnswer(userID, questionID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 2. The AnswerAccess controller, should it also be storing responses?&lt;br /&gt;
* So, there should be an equivalent of &amp;quot;getAnswer&amp;quot;, being &amp;quot;putAnswer&amp;quot; (or &amp;quot;saveAnswer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 3. Once answers are being stored, either in a flatfile table, or a normalised one, there will be some kind of unique id for the &amp;quot;collection&amp;quot; of answers, so they can be grouped together.&lt;br /&gt;
* A collection of survey responses, with their unique identifier, become the &amp;quot;sheet of answers&amp;quot; to a particular survey. In the case of a controlled survey - where the user has been specifically invited, so we know who they are, they&#039;ll have a unique userID from the users table. In the case of open/anonymous or general public surveys, this unique identifier will have to be something else - where is that reflected in the getAnswers, and where will it be reflected in the putAnswer(s) call?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New June Comments&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
I&#039;ve had a thought that the moveUp and moveDown methods should take an option of how many positions to move them. When you have 20 questions in a section, and you want to move your question to the top, moving it up one at a time can be really annoying. Can we have void moveUp(sectionId,positions) so if we want to move something 5 places up in the order, it could have a 5 for the positions? Default, of course, would be 1.&lt;br /&gt;
&lt;br /&gt;
== Comments from Hai:==&lt;br /&gt;
* Add functions for reordering questions (something that would take an array and/or an assoc. map)&lt;br /&gt;
* Make sure you handle scalability for conditions well. This includes:&lt;br /&gt;
** ability to link survey elements to multiple conditions, each condition linkable to multiple actions.&lt;br /&gt;
** providing functions for various condition actions, such as question hiding, branching etc. (sorry, I know this is extremely vague, I&#039;ll try to specify later on)&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4265</id>
		<title>Database Storage Engine Project M2 API</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4265"/>
		<updated>2010-07-02T17:55:17Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes building the API for the [[Database Storage Engine Project|database system]].&lt;br /&gt;
&lt;br /&gt;
We will release a preview of the API before the 1st of June in order to have plenty of time for the community to comment.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Develop basic API and post it on the forums&lt;br /&gt;
*Explore comments on the basic API&lt;br /&gt;
*Complete the API&lt;br /&gt;
*Make sure it is possible to add/have support for current en future metadata related to single &amp;lt;u&amp;gt;questions&amp;lt;/u&amp;gt; &amp;amp; whole &amp;lt;u&amp;gt;surveys&amp;lt;/u&amp;gt;.&lt;br /&gt;
*Add methods to add and remove observers&lt;br /&gt;
&lt;br /&gt;
= Basic API version (06-25)=&lt;br /&gt;
&lt;br /&gt;
Below you find the first draft of the API.&lt;br /&gt;
&lt;br /&gt;
== Survey==&lt;br /&gt;
&lt;br /&gt;
A survey is a collection of sections. Surveys can have various metadata like a respondent e-mail adres, a name, ...&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaData(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the survey.&lt;br /&gt;
&lt;br /&gt;
== Section==&lt;br /&gt;
&lt;br /&gt;
A section is a part of a survey, grouping questions together. Using conditions it is possible to loop or branch over sections.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the section.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the section.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the section.&lt;br /&gt;
&lt;br /&gt;
== QuestionType==&lt;br /&gt;
&lt;br /&gt;
A survey can have various types of questions, ranging from string &amp;amp; integers up to fileinput and matrix types. QuestionType will have subclasses: basic question types like IntegerQuestionType, StringQuestionType, DateQuestionType ... and structures like MatrixQuestionType, ArrayQuestionType, ...&lt;br /&gt;
&lt;br /&gt;
=== abstract string render()===&lt;br /&gt;
&lt;br /&gt;
Returns a template for this questiontype.&lt;br /&gt;
&lt;br /&gt;
=== abstract mixed getFields()===&lt;br /&gt;
&lt;br /&gt;
Returns a list of all fields required by this questiontype and their types.&lt;br /&gt;
&lt;br /&gt;
=== abstract bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== Question==&lt;br /&gt;
&lt;br /&gt;
A question is a combination of a string (the question) a QuestionType and possible various options - depending on the type.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the question.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the question.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the question.&lt;br /&gt;
&lt;br /&gt;
=== bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== ModelAnswer==&lt;br /&gt;
&lt;br /&gt;
A model answer for a closed question.&lt;br /&gt;
&lt;br /&gt;
=== mixed getValue()===&lt;br /&gt;
&lt;br /&gt;
Returns the value of this model answer.&lt;br /&gt;
&lt;br /&gt;
== Response==&lt;br /&gt;
&lt;br /&gt;
A response is a combination of a token, questionID, answervalue and metadata.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== date getStartTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was started. This means when the question was displayed.&lt;br /&gt;
&lt;br /&gt;
=== date getEndTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was ended. This means when the question was filled in.&lt;br /&gt;
&lt;br /&gt;
=== int getIteration()===&lt;br /&gt;
&lt;br /&gt;
Returns the iteration of this response (used for loops).&lt;br /&gt;
&lt;br /&gt;
== ModelAnswerManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of model answers.&lt;br /&gt;
&lt;br /&gt;
=== void storeModelAnswer(questionID, ModelAnswer)===&lt;br /&gt;
&lt;br /&gt;
Stores the given model answer to the database. If the model answer has no ID, it will be considered a new model answer. In this case ModelAnswer-&amp;gt;id will be set to the ID appointed to this model answer. The model answer must have a valid question id.&lt;br /&gt;
&lt;br /&gt;
=== ModelAnswer[] listModelAnswers(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all model answers of the given question.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(modelAnswerID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the front of the question.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(modelAnswerID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the end of the question.&lt;br /&gt;
&lt;br /&gt;
== SurveyManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of surveys.&lt;br /&gt;
&lt;br /&gt;
=== Survey[] listSurveys()===&lt;br /&gt;
&lt;br /&gt;
Lists all surveys.&lt;br /&gt;
&lt;br /&gt;
=== void storeSurvey(Survey)===&lt;br /&gt;
&lt;br /&gt;
Stores the given survey to the database. If the survey has no ID, it will be considered a new survey. In this case Survey-&amp;gt;id will be set to the ID appointed to this survey.&lt;br /&gt;
&lt;br /&gt;
=== Survey getSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted survey.&lt;br /&gt;
&lt;br /&gt;
=== void removeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Removes survey data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void openSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to open.&lt;br /&gt;
&lt;br /&gt;
=== void closeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to closed.&lt;br /&gt;
&lt;br /&gt;
=== void setDatabaseEngine(surveyID, engineID)===&lt;br /&gt;
&lt;br /&gt;
Enables the chosen database engine for the given survey. Can only be called the first time before the survey is opened.&lt;br /&gt;
&lt;br /&gt;
=== string[] getPossibleDatabaseEngines(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the possible engineID&#039;s of the database engines which are possible for this survey.&lt;br /&gt;
&lt;br /&gt;
== SectionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of sections.&lt;br /&gt;
&lt;br /&gt;
=== Section[] listSections(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Lists all sections in the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void storeSection(Section)===&lt;br /&gt;
&lt;br /&gt;
Stores the given section to the database. If the section has no ID, it will be considered a new section. In this case Section-&amp;gt;id will be set to the ID appointed to this section. The section must have a valid survey id.&lt;br /&gt;
&lt;br /&gt;
=== Section getSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted section.&lt;br /&gt;
&lt;br /&gt;
=== void removeSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Removes section data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(sectionId, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the front of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(sectionId, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the end of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void &amp;lt;nowiki&amp;gt;reorder(assoc(sectionId =&amp;gt; orderNumber))&amp;lt;/nowiki&amp;gt;===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given sections to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== interface DBSEObserver==&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyCreated(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyChanged(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on update of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionCreated(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionChanged(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on update of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionCreated(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionChanged(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on update of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyResponse(Response response)===&lt;br /&gt;
&lt;br /&gt;
Called on submission of a response.&lt;br /&gt;
&lt;br /&gt;
== QuestionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of questions.&lt;br /&gt;
&lt;br /&gt;
=== Question[] listQuestions(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Lists all questions in the given section.&lt;br /&gt;
&lt;br /&gt;
=== void storeQuestion(Question)===&lt;br /&gt;
&lt;br /&gt;
Stores the given question to the database. If the question has no ID, it will be considered a new question. In this case Question-&amp;gt;id will be set to the ID appointed to this question. The question must have a valid section id.&lt;br /&gt;
&lt;br /&gt;
=== Question getQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted question.&lt;br /&gt;
&lt;br /&gt;
=== void removeQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Removes question data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the front of the section.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the end of the section.&lt;br /&gt;
&lt;br /&gt;
=== void reorder(assoc(questionID =&amp;gt; orderNumber))===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given questions to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== AnswerAccessController==&lt;br /&gt;
&lt;br /&gt;
This controller provides methodes to store and retrieve survey answers.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&#039;construct(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Constructs a new controller for the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void addResponse(participantID, questionID, value, starttime, endtime, iteration=0)===&lt;br /&gt;
&lt;br /&gt;
Adds the given answer and metadata for the given question to the answers of the given participant. If there already was an answer to the given question for the given participant, the answer will be overridden. The iteration parameter is used to express this is the answer for the i&#039;th loop. If the given answer value is invalid for the given question, an exception will be thrown.&lt;br /&gt;
&lt;br /&gt;
=== Response getResponse(participantID, questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the response of the given participant to the given question and its metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponsesToQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the given question and their metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the survey.&lt;br /&gt;
&lt;br /&gt;
=== mixed exportResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns a double array containing all response information from the survey.&lt;br /&gt;
&lt;br /&gt;
=== boolean hasFinished(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given participant already finished the survey. Returns false if the participant did not complete the survey.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
== ObserverController==&lt;br /&gt;
&lt;br /&gt;
=== static ObserverController getInstance()===&lt;br /&gt;
&lt;br /&gt;
Returns a statical instance to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void addObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Adds an observer to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void removeObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Removes an observer from the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void notifyObservers(callback $function  ~091~,  mixed $parameter  ~091~,  mixed $...  ~093&amp;lt;span style=&amp;quot;color:093~)===&lt;br /&gt;
&lt;br /&gt;
Notifies all registered observers with the specific function and the given parameters.&lt;br /&gt;
&lt;br /&gt;
==Global notes==&lt;br /&gt;
*Metadata keys can be chained in dot-notation. &#039;color.red&#039; means the key &#039;color&#039; with subkey &#039;red&#039;.&lt;br /&gt;
*The returning of subkeys in metadata will result in assocs in the array. The &#039;color.red&#039; example will give&amp;quot;&amp;gt; array(color =&amp;gt; array(red =&amp;gt; ...)). When you use a subkey, you cannot use the key itself anymore.&lt;br /&gt;
*Exceptions will be used for reporting errors. The exceptions thrown by each method will be added later in the development process.&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Comments from Machaven:==&lt;br /&gt;
&lt;br /&gt;
 1. All the functions that do not return anything (void)&lt;br /&gt;
*Should functions not return true/false (bool) depending on success or failure?&lt;br /&gt;
&lt;br /&gt;
 2. void updateMetaDate(key, value, newValue)&lt;br /&gt;
*Should this be spelled: updateMetaData?&lt;br /&gt;
*Why is the original value required to change the metadata? Are the keys not unique?&lt;br /&gt;
&lt;br /&gt;
 3. How are errors handled?&lt;br /&gt;
* Can we trigger some action on error, set logging or retrieve error information?&lt;br /&gt;
&lt;br /&gt;
== Comments from Jason:==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From May&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 1. There has been some discussion about the use of the word token to represent each unique participant&lt;br /&gt;
*this may be better expressed using a different word internally. Since survey participants/token recipients will be represented as &amp;quot;users&amp;quot; maybe &amp;quot;userID&amp;quot; would be a better label than tokens - ie instead of &amp;quot;Answer getAnswer(token, questionID)&amp;quot;, &amp;quot;Answer getAnswer(userID, questionID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 2. The AnswerAccess controller, should it also be storing responses?&lt;br /&gt;
* So, there should be an equivalent of &amp;quot;getAnswer&amp;quot;, being &amp;quot;putAnswer&amp;quot; (or &amp;quot;saveAnswer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 3. Once answers are being stored, either in a flatfile table, or a normalised one, there will be some kind of unique id for the &amp;quot;collection&amp;quot; of answers, so they can be grouped together.&lt;br /&gt;
* A collection of survey responses, with their unique identifier, become the &amp;quot;sheet of answers&amp;quot; to a particular survey. In the case of a controlled survey - where the user has been specifically invited, so we know who they are, they&#039;ll have a unique userID from the users table. In the case of open/anonymous or general public surveys, this unique identifier will have to be something else - where is that reflected in the getAnswers, and where will it be reflected in the putAnswer(s) call?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New June Comments&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
I&#039;ve had a thought that the moveUp and moveDown methods should take an option of how many positions to move them. When you have 20 questions in a section, and you want to move your question to the top, moving it up one at a time can be really annoying. Can we have void moveUp(sectionId,positions) so if we want to move something 5 places up in the order, it could have a 5 for the positions? Default, of course, would be 1.&lt;br /&gt;
&lt;br /&gt;
== Comments from Hai:==&lt;br /&gt;
* Add functions for reordering questions (something that would take an array and/or an assoc. map)&lt;br /&gt;
* Make sure you handle scalability for conditions well. This includes:&lt;br /&gt;
** ability to link survey elements to multiple conditions, each condition linkable to multiple actions.&lt;br /&gt;
** providing functions for various condition actions, such as question hiding, branching etc. (sorry, I know this is extremely vague, I&#039;ll try to specify later on)&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4266</id>
		<title>Database Storage Engine Project M2 API</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4266"/>
		<updated>2010-07-02T17:55:06Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes building the API for the [[Database Storage Engine Project|database system]].&lt;br /&gt;
&lt;br /&gt;
We will release a preview of the API before the 1st of June in order to have plenty of time for the community to comment.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Develop basic API and post it on the forums&lt;br /&gt;
*Explore comments on the basic API&lt;br /&gt;
*Complete the API&lt;br /&gt;
*Make sure it is possible to add/have support for current en future metadata related to single &amp;lt;u&amp;gt;questions&amp;lt;/u&amp;gt; &amp;amp; whole &amp;lt;u&amp;gt;surveys&amp;lt;/u&amp;gt;.&lt;br /&gt;
*Add methods to add and remove observers&lt;br /&gt;
&lt;br /&gt;
= Basic API version (06-25)=&lt;br /&gt;
&lt;br /&gt;
Below you find the first draft of the API.&lt;br /&gt;
&lt;br /&gt;
== Survey==&lt;br /&gt;
&lt;br /&gt;
A survey is a collection of sections. Surveys can have various metadata like a respondent e-mail adres, a name, ...&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaData(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the survey.&lt;br /&gt;
&lt;br /&gt;
== Section==&lt;br /&gt;
&lt;br /&gt;
A section is a part of a survey, grouping questions together. Using conditions it is possible to loop or branch over sections.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the section.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the section.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the section.&lt;br /&gt;
&lt;br /&gt;
== QuestionType==&lt;br /&gt;
&lt;br /&gt;
A survey can have various types of questions, ranging from string &amp;amp; integers up to fileinput and matrix types. QuestionType will have subclasses: basic question types like IntegerQuestionType, StringQuestionType, DateQuestionType ... and structures like MatrixQuestionType, ArrayQuestionType, ...&lt;br /&gt;
&lt;br /&gt;
=== abstract string render()===&lt;br /&gt;
&lt;br /&gt;
Returns a template for this questiontype.&lt;br /&gt;
&lt;br /&gt;
=== abstract mixed getFields()===&lt;br /&gt;
&lt;br /&gt;
Returns a list of all fields required by this questiontype and their types.&lt;br /&gt;
&lt;br /&gt;
=== abstract bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== Question==&lt;br /&gt;
&lt;br /&gt;
A question is a combination of a string (the question) a QuestionType and possible various options - depending on the type.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the question.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the question.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the question.&lt;br /&gt;
&lt;br /&gt;
=== bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== ModelAnswer==&lt;br /&gt;
&lt;br /&gt;
A model answer for a closed question.&lt;br /&gt;
&lt;br /&gt;
=== mixed getValue()===&lt;br /&gt;
&lt;br /&gt;
Returns the value of this model answer.&lt;br /&gt;
&lt;br /&gt;
== Response==&lt;br /&gt;
&lt;br /&gt;
A response is a combination of a token, questionID, answervalue and metadata.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== date getStartTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was started. This means when the question was displayed.&lt;br /&gt;
&lt;br /&gt;
=== date getEndTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was ended. This means when the question was filled in.&lt;br /&gt;
&lt;br /&gt;
=== int getIteration()===&lt;br /&gt;
&lt;br /&gt;
Returns the iteration of this response (used for loops).&lt;br /&gt;
&lt;br /&gt;
== ModelAnswerManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of model answers.&lt;br /&gt;
&lt;br /&gt;
=== void storeModelAnswer(questionID, ModelAnswer)===&lt;br /&gt;
&lt;br /&gt;
Stores the given model answer to the database. If the model answer has no ID, it will be considered a new model answer. In this case ModelAnswer-&amp;gt;id will be set to the ID appointed to this model answer. The model answer must have a valid question id.&lt;br /&gt;
&lt;br /&gt;
=== ModelAnswer[] listModelAnswers(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all model answers of the given question.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(modelAnswerID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the front of the question.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(modelAnswerID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the end of the question.&lt;br /&gt;
&lt;br /&gt;
== SurveyManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of surveys.&lt;br /&gt;
&lt;br /&gt;
=== Survey[] listSurveys()===&lt;br /&gt;
&lt;br /&gt;
Lists all surveys.&lt;br /&gt;
&lt;br /&gt;
=== void storeSurvey(Survey)===&lt;br /&gt;
&lt;br /&gt;
Stores the given survey to the database. If the survey has no ID, it will be considered a new survey. In this case Survey-&amp;gt;id will be set to the ID appointed to this survey.&lt;br /&gt;
&lt;br /&gt;
=== Survey getSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted survey.&lt;br /&gt;
&lt;br /&gt;
=== void removeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Removes survey data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void openSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to open.&lt;br /&gt;
&lt;br /&gt;
=== void closeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to closed.&lt;br /&gt;
&lt;br /&gt;
=== void setDatabaseEngine(surveyID, engineID)===&lt;br /&gt;
&lt;br /&gt;
Enables the chosen database engine for the given survey. Can only be called the first time before the survey is opened.&lt;br /&gt;
&lt;br /&gt;
=== string[] getPossibleDatabaseEngines(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the possible engineID&#039;s of the database engines which are possible for this survey.&lt;br /&gt;
&lt;br /&gt;
== SectionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of sections.&lt;br /&gt;
&lt;br /&gt;
=== Section[] listSections(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Lists all sections in the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void storeSection(Section)===&lt;br /&gt;
&lt;br /&gt;
Stores the given section to the database. If the section has no ID, it will be considered a new section. In this case Section-&amp;gt;id will be set to the ID appointed to this section. The section must have a valid survey id.&lt;br /&gt;
&lt;br /&gt;
=== Section getSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted section.&lt;br /&gt;
&lt;br /&gt;
=== void removeSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Removes section data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(sectionId, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the front of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(sectionId)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the end of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void &amp;lt;nowiki&amp;gt;reorder(assoc(sectionId =&amp;gt; orderNumber))&amp;lt;/nowiki&amp;gt;===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given sections to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== interface DBSEObserver==&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyCreated(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyChanged(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on update of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionCreated(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionChanged(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on update of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionCreated(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionChanged(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on update of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyResponse(Response response)===&lt;br /&gt;
&lt;br /&gt;
Called on submission of a response.&lt;br /&gt;
&lt;br /&gt;
== QuestionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of questions.&lt;br /&gt;
&lt;br /&gt;
=== Question[] listQuestions(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Lists all questions in the given section.&lt;br /&gt;
&lt;br /&gt;
=== void storeQuestion(Question)===&lt;br /&gt;
&lt;br /&gt;
Stores the given question to the database. If the question has no ID, it will be considered a new question. In this case Question-&amp;gt;id will be set to the ID appointed to this question. The question must have a valid section id.&lt;br /&gt;
&lt;br /&gt;
=== Question getQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted question.&lt;br /&gt;
&lt;br /&gt;
=== void removeQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Removes question data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the front of the section.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the end of the section.&lt;br /&gt;
&lt;br /&gt;
=== void reorder(assoc(questionID =&amp;gt; orderNumber))===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given questions to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== AnswerAccessController==&lt;br /&gt;
&lt;br /&gt;
This controller provides methodes to store and retrieve survey answers.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&#039;construct(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Constructs a new controller for the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void addResponse(participantID, questionID, value, starttime, endtime, iteration=0)===&lt;br /&gt;
&lt;br /&gt;
Adds the given answer and metadata for the given question to the answers of the given participant. If there already was an answer to the given question for the given participant, the answer will be overridden. The iteration parameter is used to express this is the answer for the i&#039;th loop. If the given answer value is invalid for the given question, an exception will be thrown.&lt;br /&gt;
&lt;br /&gt;
=== Response getResponse(participantID, questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the response of the given participant to the given question and its metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponsesToQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the given question and their metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the survey.&lt;br /&gt;
&lt;br /&gt;
=== mixed exportResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns a double array containing all response information from the survey.&lt;br /&gt;
&lt;br /&gt;
=== boolean hasFinished(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given participant already finished the survey. Returns false if the participant did not complete the survey.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
== ObserverController==&lt;br /&gt;
&lt;br /&gt;
=== static ObserverController getInstance()===&lt;br /&gt;
&lt;br /&gt;
Returns a statical instance to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void addObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Adds an observer to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void removeObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Removes an observer from the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void notifyObservers(callback $function  ~091~,  mixed $parameter  ~091~,  mixed $...  ~093&amp;lt;span style=&amp;quot;color:093~)===&lt;br /&gt;
&lt;br /&gt;
Notifies all registered observers with the specific function and the given parameters.&lt;br /&gt;
&lt;br /&gt;
==Global notes==&lt;br /&gt;
*Metadata keys can be chained in dot-notation. &#039;color.red&#039; means the key &#039;color&#039; with subkey &#039;red&#039;.&lt;br /&gt;
*The returning of subkeys in metadata will result in assocs in the array. The &#039;color.red&#039; example will give&amp;quot;&amp;gt; array(color =&amp;gt; array(red =&amp;gt; ...)). When you use a subkey, you cannot use the key itself anymore.&lt;br /&gt;
*Exceptions will be used for reporting errors. The exceptions thrown by each method will be added later in the development process.&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Comments from Machaven:==&lt;br /&gt;
&lt;br /&gt;
 1. All the functions that do not return anything (void)&lt;br /&gt;
*Should functions not return true/false (bool) depending on success or failure?&lt;br /&gt;
&lt;br /&gt;
 2. void updateMetaDate(key, value, newValue)&lt;br /&gt;
*Should this be spelled: updateMetaData?&lt;br /&gt;
*Why is the original value required to change the metadata? Are the keys not unique?&lt;br /&gt;
&lt;br /&gt;
 3. How are errors handled?&lt;br /&gt;
* Can we trigger some action on error, set logging or retrieve error information?&lt;br /&gt;
&lt;br /&gt;
== Comments from Jason:==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From May&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 1. There has been some discussion about the use of the word token to represent each unique participant&lt;br /&gt;
*this may be better expressed using a different word internally. Since survey participants/token recipients will be represented as &amp;quot;users&amp;quot; maybe &amp;quot;userID&amp;quot; would be a better label than tokens - ie instead of &amp;quot;Answer getAnswer(token, questionID)&amp;quot;, &amp;quot;Answer getAnswer(userID, questionID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 2. The AnswerAccess controller, should it also be storing responses?&lt;br /&gt;
* So, there should be an equivalent of &amp;quot;getAnswer&amp;quot;, being &amp;quot;putAnswer&amp;quot; (or &amp;quot;saveAnswer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 3. Once answers are being stored, either in a flatfile table, or a normalised one, there will be some kind of unique id for the &amp;quot;collection&amp;quot; of answers, so they can be grouped together.&lt;br /&gt;
* A collection of survey responses, with their unique identifier, become the &amp;quot;sheet of answers&amp;quot; to a particular survey. In the case of a controlled survey - where the user has been specifically invited, so we know who they are, they&#039;ll have a unique userID from the users table. In the case of open/anonymous or general public surveys, this unique identifier will have to be something else - where is that reflected in the getAnswers, and where will it be reflected in the putAnswer(s) call?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New June Comments&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
I&#039;ve had a thought that the moveUp and moveDown methods should take an option of how many positions to move them. When you have 20 questions in a section, and you want to move your question to the top, moving it up one at a time can be really annoying. Can we have void moveUp(sectionId,positions) so if we want to move something 5 places up in the order, it could have a 5 for the positions? Default, of course, would be 1.&lt;br /&gt;
&lt;br /&gt;
== Comments from Hai:==&lt;br /&gt;
* Add functions for reordering questions (something that would take an array and/or an assoc. map)&lt;br /&gt;
* Make sure you handle scalability for conditions well. This includes:&lt;br /&gt;
** ability to link survey elements to multiple conditions, each condition linkable to multiple actions.&lt;br /&gt;
** providing functions for various condition actions, such as question hiding, branching etc. (sorry, I know this is extremely vague, I&#039;ll try to specify later on)&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4267</id>
		<title>Database Storage Engine Project M2 API</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4267"/>
		<updated>2010-07-02T17:54:49Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes building the API for the [[Database Storage Engine Project|database system]].&lt;br /&gt;
&lt;br /&gt;
We will release a preview of the API before the 1st of June in order to have plenty of time for the community to comment.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Develop basic API and post it on the forums&lt;br /&gt;
*Explore comments on the basic API&lt;br /&gt;
*Complete the API&lt;br /&gt;
*Make sure it is possible to add/have support for current en future metadata related to single &amp;lt;u&amp;gt;questions&amp;lt;/u&amp;gt; &amp;amp; whole &amp;lt;u&amp;gt;surveys&amp;lt;/u&amp;gt;.&lt;br /&gt;
*Add methods to add and remove observers&lt;br /&gt;
&lt;br /&gt;
= Basic API version (06-25)=&lt;br /&gt;
&lt;br /&gt;
Below you find the first draft of the API.&lt;br /&gt;
&lt;br /&gt;
== Survey==&lt;br /&gt;
&lt;br /&gt;
A survey is a collection of sections. Surveys can have various metadata like a respondent e-mail adres, a name, ...&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaData(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the survey.&lt;br /&gt;
&lt;br /&gt;
== Section==&lt;br /&gt;
&lt;br /&gt;
A section is a part of a survey, grouping questions together. Using conditions it is possible to loop or branch over sections.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the section.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the section.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the section.&lt;br /&gt;
&lt;br /&gt;
== QuestionType==&lt;br /&gt;
&lt;br /&gt;
A survey can have various types of questions, ranging from string &amp;amp; integers up to fileinput and matrix types. QuestionType will have subclasses: basic question types like IntegerQuestionType, StringQuestionType, DateQuestionType ... and structures like MatrixQuestionType, ArrayQuestionType, ...&lt;br /&gt;
&lt;br /&gt;
=== abstract string render()===&lt;br /&gt;
&lt;br /&gt;
Returns a template for this questiontype.&lt;br /&gt;
&lt;br /&gt;
=== abstract mixed getFields()===&lt;br /&gt;
&lt;br /&gt;
Returns a list of all fields required by this questiontype and their types.&lt;br /&gt;
&lt;br /&gt;
=== abstract bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== Question==&lt;br /&gt;
&lt;br /&gt;
A question is a combination of a string (the question) a QuestionType and possible various options - depending on the type.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the question.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the question.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the question.&lt;br /&gt;
&lt;br /&gt;
=== bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== ModelAnswer==&lt;br /&gt;
&lt;br /&gt;
A model answer for a closed question.&lt;br /&gt;
&lt;br /&gt;
=== mixed getValue()===&lt;br /&gt;
&lt;br /&gt;
Returns the value of this model answer.&lt;br /&gt;
&lt;br /&gt;
== Response==&lt;br /&gt;
&lt;br /&gt;
A response is a combination of a token, questionID, answervalue and metadata.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== date getStartTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was started. This means when the question was displayed.&lt;br /&gt;
&lt;br /&gt;
=== date getEndTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was ended. This means when the question was filled in.&lt;br /&gt;
&lt;br /&gt;
=== int getIteration()===&lt;br /&gt;
&lt;br /&gt;
Returns the iteration of this response (used for loops).&lt;br /&gt;
&lt;br /&gt;
== ModelAnswerManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of model answers.&lt;br /&gt;
&lt;br /&gt;
=== void storeModelAnswer(questionID, ModelAnswer)===&lt;br /&gt;
&lt;br /&gt;
Stores the given model answer to the database. If the model answer has no ID, it will be considered a new model answer. In this case ModelAnswer-&amp;gt;id will be set to the ID appointed to this model answer. The model answer must have a valid question id.&lt;br /&gt;
&lt;br /&gt;
=== ModelAnswer[] listModelAnswers(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all model answers of the given question.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(modelAnswerID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the front of the question.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(modelAnswerID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the end of the question.&lt;br /&gt;
&lt;br /&gt;
== SurveyManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of surveys.&lt;br /&gt;
&lt;br /&gt;
=== Survey[] listSurveys()===&lt;br /&gt;
&lt;br /&gt;
Lists all surveys.&lt;br /&gt;
&lt;br /&gt;
=== void storeSurvey(Survey)===&lt;br /&gt;
&lt;br /&gt;
Stores the given survey to the database. If the survey has no ID, it will be considered a new survey. In this case Survey-&amp;gt;id will be set to the ID appointed to this survey.&lt;br /&gt;
&lt;br /&gt;
=== Survey getSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted survey.&lt;br /&gt;
&lt;br /&gt;
=== void removeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Removes survey data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void openSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to open.&lt;br /&gt;
&lt;br /&gt;
=== void closeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to closed.&lt;br /&gt;
&lt;br /&gt;
=== void setDatabaseEngine(surveyID, engineID)===&lt;br /&gt;
&lt;br /&gt;
Enables the chosen database engine for the given survey. Can only be called the first time before the survey is opened.&lt;br /&gt;
&lt;br /&gt;
=== string[] getPossibleDatabaseEngines(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the possible engineID&#039;s of the database engines which are possible for this survey.&lt;br /&gt;
&lt;br /&gt;
== SectionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of sections.&lt;br /&gt;
&lt;br /&gt;
=== Section[] listSections(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Lists all sections in the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void storeSection(Section)===&lt;br /&gt;
&lt;br /&gt;
Stores the given section to the database. If the section has no ID, it will be considered a new section. In this case Section-&amp;gt;id will be set to the ID appointed to this section. The section must have a valid survey id.&lt;br /&gt;
&lt;br /&gt;
=== Section getSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted section.&lt;br /&gt;
&lt;br /&gt;
=== void removeSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Removes section data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(sectionId)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the front of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(sectionId)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the end of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void &amp;lt;nowiki&amp;gt;reorder(assoc(sectionId =&amp;gt; orderNumber))&amp;lt;/nowiki&amp;gt;===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given sections to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== interface DBSEObserver==&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyCreated(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyChanged(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on update of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionCreated(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionChanged(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on update of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionCreated(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionChanged(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on update of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyResponse(Response response)===&lt;br /&gt;
&lt;br /&gt;
Called on submission of a response.&lt;br /&gt;
&lt;br /&gt;
== QuestionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of questions.&lt;br /&gt;
&lt;br /&gt;
=== Question[] listQuestions(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Lists all questions in the given section.&lt;br /&gt;
&lt;br /&gt;
=== void storeQuestion(Question)===&lt;br /&gt;
&lt;br /&gt;
Stores the given question to the database. If the question has no ID, it will be considered a new question. In this case Question-&amp;gt;id will be set to the ID appointed to this question. The question must have a valid section id.&lt;br /&gt;
&lt;br /&gt;
=== Question getQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted question.&lt;br /&gt;
&lt;br /&gt;
=== void removeQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Removes question data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the front of the section.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the end of the section.&lt;br /&gt;
&lt;br /&gt;
=== void reorder(assoc(questionID =&amp;gt; orderNumber))===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given questions to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== AnswerAccessController==&lt;br /&gt;
&lt;br /&gt;
This controller provides methodes to store and retrieve survey answers.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&#039;construct(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Constructs a new controller for the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void addResponse(participantID, questionID, value, starttime, endtime, iteration=0)===&lt;br /&gt;
&lt;br /&gt;
Adds the given answer and metadata for the given question to the answers of the given participant. If there already was an answer to the given question for the given participant, the answer will be overridden. The iteration parameter is used to express this is the answer for the i&#039;th loop. If the given answer value is invalid for the given question, an exception will be thrown.&lt;br /&gt;
&lt;br /&gt;
=== Response getResponse(participantID, questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the response of the given participant to the given question and its metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponsesToQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the given question and their metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the survey.&lt;br /&gt;
&lt;br /&gt;
=== mixed exportResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns a double array containing all response information from the survey.&lt;br /&gt;
&lt;br /&gt;
=== boolean hasFinished(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given participant already finished the survey. Returns false if the participant did not complete the survey.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
== ObserverController==&lt;br /&gt;
&lt;br /&gt;
=== static ObserverController getInstance()===&lt;br /&gt;
&lt;br /&gt;
Returns a statical instance to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void addObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Adds an observer to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void removeObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Removes an observer from the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void notifyObservers(callback $function  ~091~,  mixed $parameter  ~091~,  mixed $...  ~093&amp;lt;span style=&amp;quot;color:093~)===&lt;br /&gt;
&lt;br /&gt;
Notifies all registered observers with the specific function and the given parameters.&lt;br /&gt;
&lt;br /&gt;
==Global notes==&lt;br /&gt;
*Metadata keys can be chained in dot-notation. &#039;color.red&#039; means the key &#039;color&#039; with subkey &#039;red&#039;.&lt;br /&gt;
*The returning of subkeys in metadata will result in assocs in the array. The &#039;color.red&#039; example will give&amp;quot;&amp;gt; array(color =&amp;gt; array(red =&amp;gt; ...)). When you use a subkey, you cannot use the key itself anymore.&lt;br /&gt;
*Exceptions will be used for reporting errors. The exceptions thrown by each method will be added later in the development process.&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Comments from Machaven:==&lt;br /&gt;
&lt;br /&gt;
 1. All the functions that do not return anything (void)&lt;br /&gt;
*Should functions not return true/false (bool) depending on success or failure?&lt;br /&gt;
&lt;br /&gt;
 2. void updateMetaDate(key, value, newValue)&lt;br /&gt;
*Should this be spelled: updateMetaData?&lt;br /&gt;
*Why is the original value required to change the metadata? Are the keys not unique?&lt;br /&gt;
&lt;br /&gt;
 3. How are errors handled?&lt;br /&gt;
* Can we trigger some action on error, set logging or retrieve error information?&lt;br /&gt;
&lt;br /&gt;
== Comments from Jason:==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From May&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 1. There has been some discussion about the use of the word token to represent each unique participant&lt;br /&gt;
*this may be better expressed using a different word internally. Since survey participants/token recipients will be represented as &amp;quot;users&amp;quot; maybe &amp;quot;userID&amp;quot; would be a better label than tokens - ie instead of &amp;quot;Answer getAnswer(token, questionID)&amp;quot;, &amp;quot;Answer getAnswer(userID, questionID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 2. The AnswerAccess controller, should it also be storing responses?&lt;br /&gt;
* So, there should be an equivalent of &amp;quot;getAnswer&amp;quot;, being &amp;quot;putAnswer&amp;quot; (or &amp;quot;saveAnswer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 3. Once answers are being stored, either in a flatfile table, or a normalised one, there will be some kind of unique id for the &amp;quot;collection&amp;quot; of answers, so they can be grouped together.&lt;br /&gt;
* A collection of survey responses, with their unique identifier, become the &amp;quot;sheet of answers&amp;quot; to a particular survey. In the case of a controlled survey - where the user has been specifically invited, so we know who they are, they&#039;ll have a unique userID from the users table. In the case of open/anonymous or general public surveys, this unique identifier will have to be something else - where is that reflected in the getAnswers, and where will it be reflected in the putAnswer(s) call?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New June Comments&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
I&#039;ve had a thought that the moveUp and moveDown methods should take an option of how many positions to move them. When you have 20 questions in a section, and you want to move your question to the top, moving it up one at a time can be really annoying. Can we have void moveUp(sectionId,positions) so if we want to move something 5 places up in the order, it could have a 5 for the positions? Default, of course, would be 1.&lt;br /&gt;
&lt;br /&gt;
== Comments from Hai:==&lt;br /&gt;
* Add functions for reordering questions (something that would take an array and/or an assoc. map)&lt;br /&gt;
* Make sure you handle scalability for conditions well. This includes:&lt;br /&gt;
** ability to link survey elements to multiple conditions, each condition linkable to multiple actions.&lt;br /&gt;
** providing functions for various condition actions, such as question hiding, branching etc. (sorry, I know this is extremely vague, I&#039;ll try to specify later on)&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4268</id>
		<title>Database Storage Engine Project M2 API</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4268"/>
		<updated>2010-07-02T17:54:37Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes building the API for the [[Database Storage Engine Project|database system]].&lt;br /&gt;
&lt;br /&gt;
We will release a preview of the API before the 1st of June in order to have plenty of time for the community to comment.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Develop basic API and post it on the forums&lt;br /&gt;
*Explore comments on the basic API&lt;br /&gt;
*Complete the API&lt;br /&gt;
*Make sure it is possible to add/have support for current en future metadata related to single &amp;lt;u&amp;gt;questions&amp;lt;/u&amp;gt; &amp;amp; whole &amp;lt;u&amp;gt;surveys&amp;lt;/u&amp;gt;.&lt;br /&gt;
*Add methods to add and remove observers&lt;br /&gt;
&lt;br /&gt;
= Basic API version (06-25)=&lt;br /&gt;
&lt;br /&gt;
Below you find the first draft of the API.&lt;br /&gt;
&lt;br /&gt;
== Survey==&lt;br /&gt;
&lt;br /&gt;
A survey is a collection of sections. Surveys can have various metadata like a respondent e-mail adres, a name, ...&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaData(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the survey.&lt;br /&gt;
&lt;br /&gt;
== Section==&lt;br /&gt;
&lt;br /&gt;
A section is a part of a survey, grouping questions together. Using conditions it is possible to loop or branch over sections.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the section.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the section.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the section.&lt;br /&gt;
&lt;br /&gt;
== QuestionType==&lt;br /&gt;
&lt;br /&gt;
A survey can have various types of questions, ranging from string &amp;amp; integers up to fileinput and matrix types. QuestionType will have subclasses: basic question types like IntegerQuestionType, StringQuestionType, DateQuestionType ... and structures like MatrixQuestionType, ArrayQuestionType, ...&lt;br /&gt;
&lt;br /&gt;
=== abstract string render()===&lt;br /&gt;
&lt;br /&gt;
Returns a template for this questiontype.&lt;br /&gt;
&lt;br /&gt;
=== abstract mixed getFields()===&lt;br /&gt;
&lt;br /&gt;
Returns a list of all fields required by this questiontype and their types.&lt;br /&gt;
&lt;br /&gt;
=== abstract bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== Question==&lt;br /&gt;
&lt;br /&gt;
A question is a combination of a string (the question) a QuestionType and possible various options - depending on the type.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the question.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the question.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the question.&lt;br /&gt;
&lt;br /&gt;
=== bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== ModelAnswer==&lt;br /&gt;
&lt;br /&gt;
A model answer for a closed question.&lt;br /&gt;
&lt;br /&gt;
=== mixed getValue()===&lt;br /&gt;
&lt;br /&gt;
Returns the value of this model answer.&lt;br /&gt;
&lt;br /&gt;
== Response==&lt;br /&gt;
&lt;br /&gt;
A response is a combination of a token, questionID, answervalue and metadata.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== date getStartTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was started. This means when the question was displayed.&lt;br /&gt;
&lt;br /&gt;
=== date getEndTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was ended. This means when the question was filled in.&lt;br /&gt;
&lt;br /&gt;
=== int getIteration()===&lt;br /&gt;
&lt;br /&gt;
Returns the iteration of this response (used for loops).&lt;br /&gt;
&lt;br /&gt;
== ModelAnswerManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of model answers.&lt;br /&gt;
&lt;br /&gt;
=== void storeModelAnswer(questionID, ModelAnswer)===&lt;br /&gt;
&lt;br /&gt;
Stores the given model answer to the database. If the model answer has no ID, it will be considered a new model answer. In this case ModelAnswer-&amp;gt;id will be set to the ID appointed to this model answer. The model answer must have a valid question id.&lt;br /&gt;
&lt;br /&gt;
=== ModelAnswer[] listModelAnswers(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all model answers of the given question.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(modelAnswerID, places)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the front of the question.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(modelAnswerID)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the end of the question.&lt;br /&gt;
&lt;br /&gt;
== SurveyManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of surveys.&lt;br /&gt;
&lt;br /&gt;
=== Survey[] listSurveys()===&lt;br /&gt;
&lt;br /&gt;
Lists all surveys.&lt;br /&gt;
&lt;br /&gt;
=== void storeSurvey(Survey)===&lt;br /&gt;
&lt;br /&gt;
Stores the given survey to the database. If the survey has no ID, it will be considered a new survey. In this case Survey-&amp;gt;id will be set to the ID appointed to this survey.&lt;br /&gt;
&lt;br /&gt;
=== Survey getSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted survey.&lt;br /&gt;
&lt;br /&gt;
=== void removeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Removes survey data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void openSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to open.&lt;br /&gt;
&lt;br /&gt;
=== void closeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to closed.&lt;br /&gt;
&lt;br /&gt;
=== void setDatabaseEngine(surveyID, engineID)===&lt;br /&gt;
&lt;br /&gt;
Enables the chosen database engine for the given survey. Can only be called the first time before the survey is opened.&lt;br /&gt;
&lt;br /&gt;
=== string[] getPossibleDatabaseEngines(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the possible engineID&#039;s of the database engines which are possible for this survey.&lt;br /&gt;
&lt;br /&gt;
== SectionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of sections.&lt;br /&gt;
&lt;br /&gt;
=== Section[] listSections(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Lists all sections in the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void storeSection(Section)===&lt;br /&gt;
&lt;br /&gt;
Stores the given section to the database. If the section has no ID, it will be considered a new section. In this case Section-&amp;gt;id will be set to the ID appointed to this section. The section must have a valid survey id.&lt;br /&gt;
&lt;br /&gt;
=== Section getSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted section.&lt;br /&gt;
&lt;br /&gt;
=== void removeSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Removes section data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(sectionId)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the front of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(sectionId)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the end of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void &amp;lt;nowiki&amp;gt;reorder(assoc(sectionId =&amp;gt; orderNumber))&amp;lt;/nowiki&amp;gt;===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given sections to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== interface DBSEObserver==&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyCreated(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyChanged(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on update of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionCreated(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionChanged(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on update of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionCreated(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionChanged(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on update of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyResponse(Response response)===&lt;br /&gt;
&lt;br /&gt;
Called on submission of a response.&lt;br /&gt;
&lt;br /&gt;
== QuestionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of questions.&lt;br /&gt;
&lt;br /&gt;
=== Question[] listQuestions(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Lists all questions in the given section.&lt;br /&gt;
&lt;br /&gt;
=== void storeQuestion(Question)===&lt;br /&gt;
&lt;br /&gt;
Stores the given question to the database. If the question has no ID, it will be considered a new question. In this case Question-&amp;gt;id will be set to the ID appointed to this question. The question must have a valid section id.&lt;br /&gt;
&lt;br /&gt;
=== Question getQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted question.&lt;br /&gt;
&lt;br /&gt;
=== void removeQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Removes question data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the front of the section.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the end of the section.&lt;br /&gt;
&lt;br /&gt;
=== void reorder(assoc(questionID =&amp;gt; orderNumber))===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given questions to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== AnswerAccessController==&lt;br /&gt;
&lt;br /&gt;
This controller provides methodes to store and retrieve survey answers.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&#039;construct(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Constructs a new controller for the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void addResponse(participantID, questionID, value, starttime, endtime, iteration=0)===&lt;br /&gt;
&lt;br /&gt;
Adds the given answer and metadata for the given question to the answers of the given participant. If there already was an answer to the given question for the given participant, the answer will be overridden. The iteration parameter is used to express this is the answer for the i&#039;th loop. If the given answer value is invalid for the given question, an exception will be thrown.&lt;br /&gt;
&lt;br /&gt;
=== Response getResponse(participantID, questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the response of the given participant to the given question and its metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponsesToQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the given question and their metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the survey.&lt;br /&gt;
&lt;br /&gt;
=== mixed exportResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns a double array containing all response information from the survey.&lt;br /&gt;
&lt;br /&gt;
=== boolean hasFinished(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given participant already finished the survey. Returns false if the participant did not complete the survey.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
== ObserverController==&lt;br /&gt;
&lt;br /&gt;
=== static ObserverController getInstance()===&lt;br /&gt;
&lt;br /&gt;
Returns a statical instance to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void addObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Adds an observer to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void removeObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Removes an observer from the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void notifyObservers(callback $function  ~091~,  mixed $parameter  ~091~,  mixed $...  ~093&amp;lt;span style=&amp;quot;color:093~)===&lt;br /&gt;
&lt;br /&gt;
Notifies all registered observers with the specific function and the given parameters.&lt;br /&gt;
&lt;br /&gt;
==Global notes==&lt;br /&gt;
*Metadata keys can be chained in dot-notation. &#039;color.red&#039; means the key &#039;color&#039; with subkey &#039;red&#039;.&lt;br /&gt;
*The returning of subkeys in metadata will result in assocs in the array. The &#039;color.red&#039; example will give&amp;quot;&amp;gt; array(color =&amp;gt; array(red =&amp;gt; ...)). When you use a subkey, you cannot use the key itself anymore.&lt;br /&gt;
*Exceptions will be used for reporting errors. The exceptions thrown by each method will be added later in the development process.&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Comments from Machaven:==&lt;br /&gt;
&lt;br /&gt;
 1. All the functions that do not return anything (void)&lt;br /&gt;
*Should functions not return true/false (bool) depending on success or failure?&lt;br /&gt;
&lt;br /&gt;
 2. void updateMetaDate(key, value, newValue)&lt;br /&gt;
*Should this be spelled: updateMetaData?&lt;br /&gt;
*Why is the original value required to change the metadata? Are the keys not unique?&lt;br /&gt;
&lt;br /&gt;
 3. How are errors handled?&lt;br /&gt;
* Can we trigger some action on error, set logging or retrieve error information?&lt;br /&gt;
&lt;br /&gt;
== Comments from Jason:==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From May&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 1. There has been some discussion about the use of the word token to represent each unique participant&lt;br /&gt;
*this may be better expressed using a different word internally. Since survey participants/token recipients will be represented as &amp;quot;users&amp;quot; maybe &amp;quot;userID&amp;quot; would be a better label than tokens - ie instead of &amp;quot;Answer getAnswer(token, questionID)&amp;quot;, &amp;quot;Answer getAnswer(userID, questionID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 2. The AnswerAccess controller, should it also be storing responses?&lt;br /&gt;
* So, there should be an equivalent of &amp;quot;getAnswer&amp;quot;, being &amp;quot;putAnswer&amp;quot; (or &amp;quot;saveAnswer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 3. Once answers are being stored, either in a flatfile table, or a normalised one, there will be some kind of unique id for the &amp;quot;collection&amp;quot; of answers, so they can be grouped together.&lt;br /&gt;
* A collection of survey responses, with their unique identifier, become the &amp;quot;sheet of answers&amp;quot; to a particular survey. In the case of a controlled survey - where the user has been specifically invited, so we know who they are, they&#039;ll have a unique userID from the users table. In the case of open/anonymous or general public surveys, this unique identifier will have to be something else - where is that reflected in the getAnswers, and where will it be reflected in the putAnswer(s) call?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New June Comments&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
I&#039;ve had a thought that the moveUp and moveDown methods should take an option of how many positions to move them. When you have 20 questions in a section, and you want to move your question to the top, moving it up one at a time can be really annoying. Can we have void moveUp(sectionId,positions) so if we want to move something 5 places up in the order, it could have a 5 for the positions? Default, of course, would be 1.&lt;br /&gt;
&lt;br /&gt;
== Comments from Hai:==&lt;br /&gt;
* Add functions for reordering questions (something that would take an array and/or an assoc. map)&lt;br /&gt;
* Make sure you handle scalability for conditions well. This includes:&lt;br /&gt;
** ability to link survey elements to multiple conditions, each condition linkable to multiple actions.&lt;br /&gt;
** providing functions for various condition actions, such as question hiding, branching etc. (sorry, I know this is extremely vague, I&#039;ll try to specify later on)&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4269</id>
		<title>Database Storage Engine Project M2 API</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4269"/>
		<updated>2010-07-02T17:33:07Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes building the API for the [[Database Storage Engine Project|database system]].&lt;br /&gt;
&lt;br /&gt;
We will release a preview of the API before the 1st of June in order to have plenty of time for the community to comment.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Develop basic API and post it on the forums&lt;br /&gt;
*Explore comments on the basic API&lt;br /&gt;
*Complete the API&lt;br /&gt;
*Make sure it is possible to add/have support for current en future metadata related to single &amp;lt;u&amp;gt;questions&amp;lt;/u&amp;gt; &amp;amp; whole &amp;lt;u&amp;gt;surveys&amp;lt;/u&amp;gt;.&lt;br /&gt;
*Add methods to add and remove observers&lt;br /&gt;
&lt;br /&gt;
= Basic API version (06-25)=&lt;br /&gt;
&lt;br /&gt;
Below you find the first draft of the API.&lt;br /&gt;
&lt;br /&gt;
== Survey==&lt;br /&gt;
&lt;br /&gt;
A survey is a collection of sections. Surveys can have various metadata like a respondent e-mail adres, a name, ...&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaData(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the survey.&lt;br /&gt;
&lt;br /&gt;
== Section==&lt;br /&gt;
&lt;br /&gt;
A section is a part of a survey, grouping questions together. Using conditions it is possible to loop or branch over sections.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the section.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the section.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the section.&lt;br /&gt;
&lt;br /&gt;
== QuestionType==&lt;br /&gt;
&lt;br /&gt;
A survey can have various types of questions, ranging from string &amp;amp; integers up to fileinput and matrix types. QuestionType will have subclasses: basic question types like IntegerQuestionType, StringQuestionType, DateQuestionType ... and structures like MatrixQuestionType, ArrayQuestionType, ...&lt;br /&gt;
&lt;br /&gt;
=== abstract string render()===&lt;br /&gt;
&lt;br /&gt;
Returns a template for this questiontype.&lt;br /&gt;
&lt;br /&gt;
=== abstract mixed getFields()===&lt;br /&gt;
&lt;br /&gt;
Returns a list of all fields required by this questiontype and their types.&lt;br /&gt;
&lt;br /&gt;
=== abstract bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== Question==&lt;br /&gt;
&lt;br /&gt;
A question is a combination of a string (the question) a QuestionType and possible various options - depending on the type.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the question.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the question.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the question.&lt;br /&gt;
&lt;br /&gt;
=== bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== ModelAnswer==&lt;br /&gt;
&lt;br /&gt;
A model answer for a closed question.&lt;br /&gt;
&lt;br /&gt;
=== mixed getValue()===&lt;br /&gt;
&lt;br /&gt;
Returns the value of this model answer.&lt;br /&gt;
&lt;br /&gt;
== Response==&lt;br /&gt;
&lt;br /&gt;
A response is a combination of a token, questionID, answervalue and metadata.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== date getStartTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was started. This means when the question was displayed.&lt;br /&gt;
&lt;br /&gt;
=== date getEndTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was ended. This means when the question was filled in.&lt;br /&gt;
&lt;br /&gt;
=== int getIteration()===&lt;br /&gt;
&lt;br /&gt;
Returns the iteration of this response (used for loops).&lt;br /&gt;
&lt;br /&gt;
== ModelAnswerManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of model answers.&lt;br /&gt;
&lt;br /&gt;
=== void storeModelAnswer(questionID, ModelAnswer)===&lt;br /&gt;
&lt;br /&gt;
Stores the given model answer to the database. If the model answer has no ID, it will be considered a new model answer. In this case ModelAnswer-&amp;gt;id will be set to the ID appointed to this model answer. The model answer must have a valid question id.&lt;br /&gt;
&lt;br /&gt;
=== ModelAnswer[] listModelAnswers(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all model answers of the given question.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(modelAnswerID)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the front of the question.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(modelAnswerID)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the end of the question.&lt;br /&gt;
&lt;br /&gt;
== SurveyManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of surveys.&lt;br /&gt;
&lt;br /&gt;
=== Survey[] listSurveys()===&lt;br /&gt;
&lt;br /&gt;
Lists all surveys.&lt;br /&gt;
&lt;br /&gt;
=== void storeSurvey(Survey)===&lt;br /&gt;
&lt;br /&gt;
Stores the given survey to the database. If the survey has no ID, it will be considered a new survey. In this case Survey-&amp;gt;id will be set to the ID appointed to this survey.&lt;br /&gt;
&lt;br /&gt;
=== Survey getSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted survey.&lt;br /&gt;
&lt;br /&gt;
=== void removeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Removes survey data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void openSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to open.&lt;br /&gt;
&lt;br /&gt;
=== void closeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to closed.&lt;br /&gt;
&lt;br /&gt;
=== void setDatabaseEngine(surveyID, engineID)===&lt;br /&gt;
&lt;br /&gt;
Enables the chosen database engine for the given survey. Can only be called the first time before the survey is opened.&lt;br /&gt;
&lt;br /&gt;
=== string[] getPossibleDatabaseEngines(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the possible engineID&#039;s of the database engines which are possible for this survey.&lt;br /&gt;
&lt;br /&gt;
== SectionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of sections.&lt;br /&gt;
&lt;br /&gt;
=== Section[] listSections(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Lists all sections in the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void storeSection(Section)===&lt;br /&gt;
&lt;br /&gt;
Stores the given section to the database. If the section has no ID, it will be considered a new section. In this case Section-&amp;gt;id will be set to the ID appointed to this section. The section must have a valid survey id.&lt;br /&gt;
&lt;br /&gt;
=== Section getSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted section.&lt;br /&gt;
&lt;br /&gt;
=== void removeSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Removes section data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(sectionId)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the front of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(sectionId)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the end of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void &amp;lt;nowiki&amp;gt;reorder(assoc(sectionId =&amp;gt; orderNumber))&amp;lt;/nowiki&amp;gt;===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given sections to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== interface DBSEObserver==&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyCreated(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyChanged(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on update of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionCreated(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionChanged(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on update of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionCreated(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionChanged(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on update of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyResponse(Response response)===&lt;br /&gt;
&lt;br /&gt;
Called on submission of a response.&lt;br /&gt;
&lt;br /&gt;
== QuestionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of questions.&lt;br /&gt;
&lt;br /&gt;
=== Question[] listQuestions(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Lists all questions in the given section.&lt;br /&gt;
&lt;br /&gt;
=== void storeQuestion(Question)===&lt;br /&gt;
&lt;br /&gt;
Stores the given question to the database. If the question has no ID, it will be considered a new question. In this case Question-&amp;gt;id will be set to the ID appointed to this question. The question must have a valid section id.&lt;br /&gt;
&lt;br /&gt;
=== Question getQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted question.&lt;br /&gt;
&lt;br /&gt;
=== void removeQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Removes question data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the front of the section.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the end of the section.&lt;br /&gt;
&lt;br /&gt;
=== void reorder(assoc(questionID =&amp;gt; orderNumber))===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given questions to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== AnswerAccessController==&lt;br /&gt;
&lt;br /&gt;
This controller provides methodes to store and retrieve survey answers.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&#039;construct(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Constructs a new controller for the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void addResponse(participantID, questionID, value, starttime, endtime, iteration=0)===&lt;br /&gt;
&lt;br /&gt;
Adds the given answer and metadata for the given question to the answers of the given participant. If there already was an answer to the given question for the given participant, the answer will be overridden. The iteration parameter is used to express this is the answer for the i&#039;th loop. If the given answer value is invalid for the given question, an exception will be thrown.&lt;br /&gt;
&lt;br /&gt;
=== Response getResponse(participantID, questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the response of the given participant to the given question and its metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponsesToQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the given question and their metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the survey.&lt;br /&gt;
&lt;br /&gt;
=== mixed exportResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns a double array containing all response information from the survey.&lt;br /&gt;
&lt;br /&gt;
=== boolean hasFinished(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given participant already finished the survey. Returns false if the participant did not complete the survey.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
== ObserverController==&lt;br /&gt;
&lt;br /&gt;
=== static ObserverController getInstance()===&lt;br /&gt;
&lt;br /&gt;
Returns a statical instance to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void addObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Adds an observer to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void removeObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Removes an observer from the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void notifyObservers(callback $function  ~091~,  mixed $parameter  ~091~,  mixed $...  ~093&amp;lt;span style=&amp;quot;color:093~)===&lt;br /&gt;
&lt;br /&gt;
Notifies all registered observers with the specific function and the given parameters.&lt;br /&gt;
&lt;br /&gt;
==Global notes==&lt;br /&gt;
*Metadata keys can be chained in dot-notation. &#039;color.red&#039; means the key &#039;color&#039; with subkey &#039;red&#039;.&lt;br /&gt;
*The returning of subkeys in metadata will result in assocs in the array. The &#039;color.red&#039; example will give&amp;quot;&amp;gt; array(color =&amp;gt; array(red =&amp;gt; ...)). When you use a subkey, you cannot use the key itself anymore.&lt;br /&gt;
*Exceptions will be used for reporting errors. The exceptions thrown by each method will be added later in the development process.&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Comments from Machaven:==&lt;br /&gt;
&lt;br /&gt;
 1. All the functions that do not return anything (void)&lt;br /&gt;
*Should functions not return true/false (bool) depending on success or failure?&lt;br /&gt;
&lt;br /&gt;
 2. void updateMetaDate(key, value, newValue)&lt;br /&gt;
*Should this be spelled: updateMetaData?&lt;br /&gt;
*Why is the original value required to change the metadata? Are the keys not unique?&lt;br /&gt;
&lt;br /&gt;
 3. How are errors handled?&lt;br /&gt;
* Can we trigger some action on error, set logging or retrieve error information?&lt;br /&gt;
&lt;br /&gt;
== Comments from Jason:==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From May&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 1. There has been some discussion about the use of the word token to represent each unique participant&lt;br /&gt;
*this may be better expressed using a different word internally. Since survey participants/token recipients will be represented as &amp;quot;users&amp;quot; maybe &amp;quot;userID&amp;quot; would be a better label than tokens - ie instead of &amp;quot;Answer getAnswer(token, questionID)&amp;quot;, &amp;quot;Answer getAnswer(userID, questionID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 2. The AnswerAccess controller, should it also be storing responses?&lt;br /&gt;
* So, there should be an equivalent of &amp;quot;getAnswer&amp;quot;, being &amp;quot;putAnswer&amp;quot; (or &amp;quot;saveAnswer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 3. Once answers are being stored, either in a flatfile table, or a normalised one, there will be some kind of unique id for the &amp;quot;collection&amp;quot; of answers, so they can be grouped together.&lt;br /&gt;
* A collection of survey responses, with their unique identifier, become the &amp;quot;sheet of answers&amp;quot; to a particular survey. In the case of a controlled survey - where the user has been specifically invited, so we know who they are, they&#039;ll have a unique userID from the users table. In the case of open/anonymous or general public surveys, this unique identifier will have to be something else - where is that reflected in the getAnswers, and where will it be reflected in the putAnswer(s) call?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New June Comments&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
I&#039;ve had a thought that the moveUp and moveDown methods should take an option of how many positions to move them. When you have 20 questions in a section, and you want to move your question to the top, moving it up one at a time can be really annoying. Can we have void moveUp(sectionId,positions) so if we want to move something 5 places up in the order, it could have a 5 for the positions? Default, of course, would be 1.&lt;br /&gt;
&lt;br /&gt;
== Comments from Hai:==&lt;br /&gt;
* Add functions for reordering questions (something that would take an array and/or an assoc. map)&lt;br /&gt;
* Make sure you handle scalability for conditions well. This includes:&lt;br /&gt;
** ability to link survey elements to multiple conditions, each condition linkable to multiple actions.&lt;br /&gt;
** providing functions for various condition actions, such as question hiding, branching etc. (sorry, I know this is extremely vague, I&#039;ll try to specify later on)&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4270</id>
		<title>Database Storage Engine Project M2 API</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4270"/>
		<updated>2010-07-02T17:32:39Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes building the API for the [[Database Storage Engine Project|database system]].&lt;br /&gt;
&lt;br /&gt;
We will release a preview of the API before the 1st of June in order to have plenty of time for the community to comment.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Develop basic API and post it on the forums&lt;br /&gt;
*Explore comments on the basic API&lt;br /&gt;
*Complete the API&lt;br /&gt;
*Make sure it is possible to add/have support for current en future metadata related to single &amp;lt;u&amp;gt;questions&amp;lt;/u&amp;gt; &amp;amp; whole &amp;lt;u&amp;gt;surveys&amp;lt;/u&amp;gt;.&lt;br /&gt;
*Add methods to add and remove observers&lt;br /&gt;
&lt;br /&gt;
= Basic API version (06-25)=&lt;br /&gt;
&lt;br /&gt;
Below you find the first draft of the API.&lt;br /&gt;
&lt;br /&gt;
== Survey==&lt;br /&gt;
&lt;br /&gt;
A survey is a collection of sections. Surveys can have various metadata like a respondent e-mail adres, a name, ...&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaData(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the survey.&lt;br /&gt;
&lt;br /&gt;
== Section==&lt;br /&gt;
&lt;br /&gt;
A section is a part of a survey, grouping questions together. Using conditions it is possible to loop or branch over sections.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the section.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the section.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the section.&lt;br /&gt;
&lt;br /&gt;
== QuestionType==&lt;br /&gt;
&lt;br /&gt;
A survey can have various types of questions, ranging from string &amp;amp; integers up to fileinput and matrix types. QuestionType will have subclasses: basic question types like IntegerQuestionType, StringQuestionType, DateQuestionType ... and structures like MatrixQuestionType, ArrayQuestionType, ...&lt;br /&gt;
&lt;br /&gt;
=== abstract string render()===&lt;br /&gt;
&lt;br /&gt;
Returns a template for this questiontype.&lt;br /&gt;
&lt;br /&gt;
=== abstract mixed getFields()===&lt;br /&gt;
&lt;br /&gt;
Returns a list of all fields required by this questiontype and their types.&lt;br /&gt;
&lt;br /&gt;
=== abstract bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== Question==&lt;br /&gt;
&lt;br /&gt;
A question is a combination of a string (the question) a QuestionType and possible various options - depending on the type.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the question.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the question.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the question.&lt;br /&gt;
&lt;br /&gt;
=== bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== ModelAnswer==&lt;br /&gt;
&lt;br /&gt;
A model answer for a closed question.&lt;br /&gt;
&lt;br /&gt;
=== mixed getValue()===&lt;br /&gt;
&lt;br /&gt;
Returns the value of this model answer.&lt;br /&gt;
&lt;br /&gt;
== Response==&lt;br /&gt;
&lt;br /&gt;
A response is a combination of a token, questionID, answervalue and metadata.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== date getStartTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was started. This means when the question was displayed.&lt;br /&gt;
&lt;br /&gt;
=== date getEndTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was ended. This means when the question was filled in.&lt;br /&gt;
&lt;br /&gt;
=== int getIteration()===&lt;br /&gt;
&lt;br /&gt;
Returns the iteration of this response (used for loops).&lt;br /&gt;
&lt;br /&gt;
== ModelAnswerManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of model answers.&lt;br /&gt;
&lt;br /&gt;
=== void storeModelAnswer(questionID, ModelAnswer)===&lt;br /&gt;
&lt;br /&gt;
Stores the given model answer to the database. If the model answer has no ID, it will be considered a new model answer. In this case ModelAnswer-&amp;gt;id will be set to the ID appointed to this model answer. The model answer must have a valid question id.&lt;br /&gt;
&lt;br /&gt;
=== ModelAnswer[] listModelAnswers(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all model answers of the given question.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(modelAnswerID)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the front of the question.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(modelAnswerID)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the end of the question.&lt;br /&gt;
&lt;br /&gt;
== SurveyManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of surveys.&lt;br /&gt;
&lt;br /&gt;
=== Survey[] listSurveys()===&lt;br /&gt;
&lt;br /&gt;
Lists all surveys.&lt;br /&gt;
&lt;br /&gt;
=== void storeSurvey(Survey)===&lt;br /&gt;
&lt;br /&gt;
Stores the given survey to the database. If the survey has no ID, it will be considered a new survey. In this case Survey-&amp;gt;id will be set to the ID appointed to this survey.&lt;br /&gt;
&lt;br /&gt;
=== Survey getSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted survey.&lt;br /&gt;
&lt;br /&gt;
=== void removeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Removes survey data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void openSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to open.&lt;br /&gt;
&lt;br /&gt;
=== void closeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to closed.&lt;br /&gt;
&lt;br /&gt;
=== void setDatabaseEngine(surveyID, engineID)===&lt;br /&gt;
&lt;br /&gt;
Enables the chosen database engine for the given survey. Can only be called the first time before the survey is opened.&lt;br /&gt;
&lt;br /&gt;
=== string[] getPossibleDatabaseEngines(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the possible engineID&#039;s of the database engines which are possible for this survey.&lt;br /&gt;
&lt;br /&gt;
== SectionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of sections.&lt;br /&gt;
&lt;br /&gt;
=== Section[] listSections(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Lists all sections in the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void storeSection(Section)===&lt;br /&gt;
&lt;br /&gt;
Stores the given section to the database. If the section has no ID, it will be considered a new section. In this case Section-&amp;gt;id will be set to the ID appointed to this section. The section must have a valid survey id.&lt;br /&gt;
&lt;br /&gt;
=== Section getSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted section.&lt;br /&gt;
&lt;br /&gt;
=== void removeSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Removes section data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(sectionId)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the front of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(sectionId)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the end of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void &amp;lt;nowiki&amp;gt;reorder(assoc(sectionId =&amp;gt; orderNumber))&amp;lt;/nowiki&amp;gt;===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given sections to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== interface DBSEObserver==&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyCreated(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyChanged(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on update of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionCreated(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionChanged(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on update of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionCreated(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionChanged(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on update of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyResponse(Response response)===&lt;br /&gt;
&lt;br /&gt;
Called on submission of a response.&lt;br /&gt;
&lt;br /&gt;
== QuestionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of questions.&lt;br /&gt;
&lt;br /&gt;
=== Question[] listQuestions(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Lists all questions in the given section.&lt;br /&gt;
&lt;br /&gt;
=== void storeQuestion(Question)===&lt;br /&gt;
&lt;br /&gt;
Stores the given question to the database. If the question has no ID, it will be considered a new question. In this case Question-&amp;gt;id will be set to the ID appointed to this question. The question must have a valid section id.&lt;br /&gt;
&lt;br /&gt;
=== Question getQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted question.&lt;br /&gt;
&lt;br /&gt;
=== void removeQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Removes question data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the front of the section.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the end of the section.&lt;br /&gt;
&lt;br /&gt;
=== void reorder(assoc(questionID =&amp;gt; orderNumber))===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given questions to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== AnswerAccessController==&lt;br /&gt;
&lt;br /&gt;
This controller provides methodes to store and retrieve survey answers.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&#039;construct(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Constructs a new controller for the given section.&lt;br /&gt;
&lt;br /&gt;
=== void addResponse(participantID, questionID, value, starttime, endtime, iteration=0)===&lt;br /&gt;
&lt;br /&gt;
Adds the given answer and metadata for the given question to the answers of the given participant. If there already was an answer to the given question for the given participant, the answer will be overridden. The iteration parameter is used to express this is the answer for the i&#039;th loop. If the given answer value is invalid for the given question, an exception will be thrown.&lt;br /&gt;
&lt;br /&gt;
=== Response getResponse(participantID, questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the response of the given participant to the given question and its metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponsesToQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the given question and their metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the survey.&lt;br /&gt;
&lt;br /&gt;
=== mixed exportResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns a double array containing all response information from the survey.&lt;br /&gt;
&lt;br /&gt;
=== boolean hasFinished(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given participant already finished the survey. Returns false if the participant did not complete the survey.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
== ObserverController==&lt;br /&gt;
&lt;br /&gt;
=== static ObserverController getInstance()===&lt;br /&gt;
&lt;br /&gt;
Returns a statical instance to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void addObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Adds an observer to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void removeObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Removes an observer from the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void notifyObservers(callback $function  ~091~,  mixed $parameter  ~091~,  mixed $...  ~093&amp;lt;span style=&amp;quot;color:093~)===&lt;br /&gt;
&lt;br /&gt;
Notifies all registered observers with the specific function and the given parameters.&lt;br /&gt;
&lt;br /&gt;
==Global notes==&lt;br /&gt;
*Metadata keys can be chained in dot-notation. &#039;color.red&#039; means the key &#039;color&#039; with subkey &#039;red&#039;.&lt;br /&gt;
*The returning of subkeys in metadata will result in assocs in the array. The &#039;color.red&#039; example will give&amp;quot;&amp;gt; array(color =&amp;gt; array(red =&amp;gt; ...)). When you use a subkey, you cannot use the key itself anymore.&lt;br /&gt;
*Exceptions will be used for reporting errors. The exceptions thrown by each method will be added later in the development process.&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Comments from Machaven:==&lt;br /&gt;
&lt;br /&gt;
 1. All the functions that do not return anything (void)&lt;br /&gt;
*Should functions not return true/false (bool) depending on success or failure?&lt;br /&gt;
&lt;br /&gt;
 2. void updateMetaDate(key, value, newValue)&lt;br /&gt;
*Should this be spelled: updateMetaData?&lt;br /&gt;
*Why is the original value required to change the metadata? Are the keys not unique?&lt;br /&gt;
&lt;br /&gt;
 3. How are errors handled?&lt;br /&gt;
* Can we trigger some action on error, set logging or retrieve error information?&lt;br /&gt;
&lt;br /&gt;
== Comments from Jason:==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From May&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 1. There has been some discussion about the use of the word token to represent each unique participant&lt;br /&gt;
*this may be better expressed using a different word internally. Since survey participants/token recipients will be represented as &amp;quot;users&amp;quot; maybe &amp;quot;userID&amp;quot; would be a better label than tokens - ie instead of &amp;quot;Answer getAnswer(token, questionID)&amp;quot;, &amp;quot;Answer getAnswer(userID, questionID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 2. The AnswerAccess controller, should it also be storing responses?&lt;br /&gt;
* So, there should be an equivalent of &amp;quot;getAnswer&amp;quot;, being &amp;quot;putAnswer&amp;quot; (or &amp;quot;saveAnswer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 3. Once answers are being stored, either in a flatfile table, or a normalised one, there will be some kind of unique id for the &amp;quot;collection&amp;quot; of answers, so they can be grouped together.&lt;br /&gt;
* A collection of survey responses, with their unique identifier, become the &amp;quot;sheet of answers&amp;quot; to a particular survey. In the case of a controlled survey - where the user has been specifically invited, so we know who they are, they&#039;ll have a unique userID from the users table. In the case of open/anonymous or general public surveys, this unique identifier will have to be something else - where is that reflected in the getAnswers, and where will it be reflected in the putAnswer(s) call?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New June Comments&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
I&#039;ve had a thought that the moveUp and moveDown methods should take an option of how many positions to move them. When you have 20 questions in a section, and you want to move your question to the top, moving it up one at a time can be really annoying. Can we have void moveUp(sectionId,positions) so if we want to move something 5 places up in the order, it could have a 5 for the positions? Default, of course, would be 1.&lt;br /&gt;
&lt;br /&gt;
== Comments from Hai:==&lt;br /&gt;
* Add functions for reordering questions (something that would take an array and/or an assoc. map)&lt;br /&gt;
* Make sure you handle scalability for conditions well. This includes:&lt;br /&gt;
** ability to link survey elements to multiple conditions, each condition linkable to multiple actions.&lt;br /&gt;
** providing functions for various condition actions, such as question hiding, branching etc. (sorry, I know this is extremely vague, I&#039;ll try to specify later on)&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4271</id>
		<title>Database Storage Engine Project M2 API</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4271"/>
		<updated>2010-07-02T17:27:25Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes building the API for the [[Database Storage Engine Project|database system]].&lt;br /&gt;
&lt;br /&gt;
We will release a preview of the API before the 1st of June in order to have plenty of time for the community to comment.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Develop basic API and post it on the forums&lt;br /&gt;
*Explore comments on the basic API&lt;br /&gt;
*Complete the API&lt;br /&gt;
*Make sure it is possible to add/have support for current en future metadata related to single &amp;lt;u&amp;gt;questions&amp;lt;/u&amp;gt; &amp;amp; whole &amp;lt;u&amp;gt;surveys&amp;lt;/u&amp;gt;.&lt;br /&gt;
*Add methods to add and remove observers&lt;br /&gt;
&lt;br /&gt;
= Basic API version (06-25)=&lt;br /&gt;
&lt;br /&gt;
Below you find the first draft of the API.&lt;br /&gt;
&lt;br /&gt;
== Survey==&lt;br /&gt;
&lt;br /&gt;
A survey is a collection of sections. Surveys can have various metadata like a respondent e-mail adres, a name, ...&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaData(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the survey.&lt;br /&gt;
&lt;br /&gt;
== Section==&lt;br /&gt;
&lt;br /&gt;
A section is a part of a survey, grouping questions together. Using conditions it is possible to loop or branch over sections.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the section.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the section.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the section.&lt;br /&gt;
&lt;br /&gt;
== QuestionType==&lt;br /&gt;
&lt;br /&gt;
A survey can have various types of questions, ranging from string &amp;amp; integers up to fileinput and matrix types. QuestionType will have subclasses: basic question types like IntegerQuestionType, StringQuestionType, DateQuestionType ... and structures like MatrixQuestionType, ArrayQuestionType, ...&lt;br /&gt;
&lt;br /&gt;
=== abstract string render()===&lt;br /&gt;
&lt;br /&gt;
Returns a template for this questiontype.&lt;br /&gt;
&lt;br /&gt;
=== abstract mixed getFields()===&lt;br /&gt;
&lt;br /&gt;
Returns a list of all fields required by this questiontype and their types.&lt;br /&gt;
&lt;br /&gt;
=== abstract bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== Question==&lt;br /&gt;
&lt;br /&gt;
A question is a combination of a string (the question) a QuestionType and possible various options - depending on the type.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the question.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the question.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the question.&lt;br /&gt;
&lt;br /&gt;
=== bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== ModelAnswer==&lt;br /&gt;
&lt;br /&gt;
A model answer for a closed question.&lt;br /&gt;
&lt;br /&gt;
=== mixed getValue()===&lt;br /&gt;
&lt;br /&gt;
Returns the value of this model answer.&lt;br /&gt;
&lt;br /&gt;
== Response==&lt;br /&gt;
&lt;br /&gt;
A response is a combination of a token, questionID, answervalue and metadata.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== date getStartTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was started. This means when the question was displayed.&lt;br /&gt;
&lt;br /&gt;
=== date getEndTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was ended. This means when the question was filled in.&lt;br /&gt;
&lt;br /&gt;
=== int getIteration()===&lt;br /&gt;
&lt;br /&gt;
Returns the iteration of this response (used for loops).&lt;br /&gt;
&lt;br /&gt;
== ModelAnswerManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of model answers.&lt;br /&gt;
&lt;br /&gt;
=== void storeModelAnswer(questionID, ModelAnswer)===&lt;br /&gt;
&lt;br /&gt;
Stores the given model answer to the database. If the model answer has no ID, it will be considered a new model answer. In this case ModelAnswer-&amp;gt;id will be set to the ID appointed to this model answer. The model answer must have a valid question id.&lt;br /&gt;
&lt;br /&gt;
=== ModelAnswer[] listModelAnswers(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all model answers of the given question.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(modelAnswerID)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the front of the question.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(modelAnswerID)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the end of the question.&lt;br /&gt;
&lt;br /&gt;
== SurveyManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of surveys.&lt;br /&gt;
&lt;br /&gt;
=== Survey[] listSurveys()===&lt;br /&gt;
&lt;br /&gt;
Lists all surveys.&lt;br /&gt;
&lt;br /&gt;
=== void storeSurvey(Survey)===&lt;br /&gt;
&lt;br /&gt;
Stores the given survey to the database. If the survey has no ID, it will be considered a new survey. In this case Survey-&amp;gt;id will be set to the ID appointed to this survey.&lt;br /&gt;
&lt;br /&gt;
=== Survey getSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted survey.&lt;br /&gt;
&lt;br /&gt;
=== void removeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Removes survey data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void openSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to open.&lt;br /&gt;
&lt;br /&gt;
=== void closeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to closed.&lt;br /&gt;
&lt;br /&gt;
=== void setDatabaseEngine(surveyID, engineID)===&lt;br /&gt;
&lt;br /&gt;
Enables the chosen database engine for the given survey. Can only be called the first time before the survey is opened.&lt;br /&gt;
&lt;br /&gt;
=== string[] getPossibleDatabaseEngines(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the possible engineID&#039;s of the database engines which are possible for this survey.&lt;br /&gt;
&lt;br /&gt;
== SectionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of sections.&lt;br /&gt;
&lt;br /&gt;
=== Section[] listSections(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Lists all sections in the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void storeSection(Section)===&lt;br /&gt;
&lt;br /&gt;
Stores the given section to the database. If the section has no ID, it will be considered a new section. In this case Section-&amp;gt;id will be set to the ID appointed to this section. The section must have a valid survey id.&lt;br /&gt;
&lt;br /&gt;
=== Section getSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted section.&lt;br /&gt;
&lt;br /&gt;
=== void removeSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Removes section data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(sectionId)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the front of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(sectionId)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the end of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void &amp;lt;nowiki&amp;gt;reorder(assoc(sectionId =&amp;gt; orderNumber))&amp;lt;/nowiki&amp;gt;===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given sections to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== interface DBSEObserver==&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyCreated(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyChanged(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on update of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionCreated(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionChanged(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on update of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionCreated(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionChanged(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on update of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyResponse(Response response)===&lt;br /&gt;
&lt;br /&gt;
Called on submission of a response.&lt;br /&gt;
&lt;br /&gt;
== QuestionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of questions.&lt;br /&gt;
&lt;br /&gt;
=== Question[] listQuestions(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Lists all questions in the given section.&lt;br /&gt;
&lt;br /&gt;
=== void storeQuestion(Question)===&lt;br /&gt;
&lt;br /&gt;
Stores the given question to the database. If the question has no ID, it will be considered a new question. In this case Question-&amp;gt;id will be set to the ID appointed to this question. The question must have a valid section id.&lt;br /&gt;
&lt;br /&gt;
=== Question getQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted question.&lt;br /&gt;
&lt;br /&gt;
=== void removeQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Removes question data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the front of the section.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the end of the section.&lt;br /&gt;
&lt;br /&gt;
=== void reorder(assoc(questionID =&amp;gt; orderNumber))===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given questions to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== AnswerAccessController==&lt;br /&gt;
&lt;br /&gt;
This controller provides methodes to store and retrieve survey answers.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&#039;construct(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Constructs a new controller for the given section.&lt;br /&gt;
&lt;br /&gt;
=== void addResponse(participantID, questionID, value, starttime, endtime, iteration=0)===&lt;br /&gt;
&lt;br /&gt;
Adds the given answer and metadata for the given question to the answers of the given participant. If there already was an answer to the given question for the given participant, the answer will be overridden. The iteration parameter is used to express this is the answer for the i&#039;th loop. If the given answer value is invalid for the given question, an exception will be thrown.&lt;br /&gt;
&lt;br /&gt;
=== Response getResponse(participantID, questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the response of the given participant to the given question and its metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponsesToQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the given question and their metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the survey.&lt;br /&gt;
&lt;br /&gt;
=== boolean hasFinished(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given participant already finished the survey. Returns false if the participant did not complete the survey.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
== ObserverController==&lt;br /&gt;
&lt;br /&gt;
=== static ObserverController getInstance()===&lt;br /&gt;
&lt;br /&gt;
Returns a statical instance to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void addObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Adds an observer to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void removeObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Removes an observer from the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void notifyObservers(callback $function  ~091~,  mixed $parameter  ~091~,  mixed $...  ~093&amp;lt;span style=&amp;quot;color:093~)===&lt;br /&gt;
&lt;br /&gt;
Notifies all registered observers with the specific function and the given parameters.&lt;br /&gt;
&lt;br /&gt;
==Global notes==&lt;br /&gt;
*Metadata keys can be chained in dot-notation. &#039;color.red&#039; means the key &#039;color&#039; with subkey &#039;red&#039;.&lt;br /&gt;
*The returning of subkeys in metadata will result in assocs in the array. The &#039;color.red&#039; example will give&amp;quot;&amp;gt; array(color =&amp;gt; array(red =&amp;gt; ...)). When you use a subkey, you cannot use the key itself anymore.&lt;br /&gt;
*Exceptions will be used for reporting errors. The exceptions thrown by each method will be added later in the development process.&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Comments from Machaven:==&lt;br /&gt;
&lt;br /&gt;
 1. All the functions that do not return anything (void)&lt;br /&gt;
*Should functions not return true/false (bool) depending on success or failure?&lt;br /&gt;
&lt;br /&gt;
 2. void updateMetaDate(key, value, newValue)&lt;br /&gt;
*Should this be spelled: updateMetaData?&lt;br /&gt;
*Why is the original value required to change the metadata? Are the keys not unique?&lt;br /&gt;
&lt;br /&gt;
 3. How are errors handled?&lt;br /&gt;
* Can we trigger some action on error, set logging or retrieve error information?&lt;br /&gt;
&lt;br /&gt;
== Comments from Jason:==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From May&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 1. There has been some discussion about the use of the word token to represent each unique participant&lt;br /&gt;
*this may be better expressed using a different word internally. Since survey participants/token recipients will be represented as &amp;quot;users&amp;quot; maybe &amp;quot;userID&amp;quot; would be a better label than tokens - ie instead of &amp;quot;Answer getAnswer(token, questionID)&amp;quot;, &amp;quot;Answer getAnswer(userID, questionID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 2. The AnswerAccess controller, should it also be storing responses?&lt;br /&gt;
* So, there should be an equivalent of &amp;quot;getAnswer&amp;quot;, being &amp;quot;putAnswer&amp;quot; (or &amp;quot;saveAnswer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 3. Once answers are being stored, either in a flatfile table, or a normalised one, there will be some kind of unique id for the &amp;quot;collection&amp;quot; of answers, so they can be grouped together.&lt;br /&gt;
* A collection of survey responses, with their unique identifier, become the &amp;quot;sheet of answers&amp;quot; to a particular survey. In the case of a controlled survey - where the user has been specifically invited, so we know who they are, they&#039;ll have a unique userID from the users table. In the case of open/anonymous or general public surveys, this unique identifier will have to be something else - where is that reflected in the getAnswers, and where will it be reflected in the putAnswer(s) call?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New June Comments&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
I&#039;ve had a thought that the moveUp and moveDown methods should take an option of how many positions to move them. When you have 20 questions in a section, and you want to move your question to the top, moving it up one at a time can be really annoying. Can we have void moveUp(sectionId,positions) so if we want to move something 5 places up in the order, it could have a 5 for the positions? Default, of course, would be 1.&lt;br /&gt;
&lt;br /&gt;
== Comments from Hai:==&lt;br /&gt;
* Add functions for reordering questions (something that would take an array and/or an assoc. map)&lt;br /&gt;
* Make sure you handle scalability for conditions well. This includes:&lt;br /&gt;
** ability to link survey elements to multiple conditions, each condition linkable to multiple actions.&lt;br /&gt;
** providing functions for various condition actions, such as question hiding, branching etc. (sorry, I know this is extremely vague, I&#039;ll try to specify later on)&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4272</id>
		<title>Database Storage Engine Project M2 API</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M2_API&amp;diff=4272"/>
		<updated>2010-07-02T17:24:52Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes building the API for the [[Database Storage Engine Project|database system]].&lt;br /&gt;
&lt;br /&gt;
We will release a preview of the API before the 1st of June in order to have plenty of time for the community to comment.&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Develop basic API and post it on the forums&lt;br /&gt;
*Explore comments on the basic API&lt;br /&gt;
*Complete the API&lt;br /&gt;
*Make sure it is possible to add/have support for current en future metadata related to single &amp;lt;u&amp;gt;questions&amp;lt;/u&amp;gt; &amp;amp; whole &amp;lt;u&amp;gt;surveys&amp;lt;/u&amp;gt;.&lt;br /&gt;
*Add methods to add and remove observers&lt;br /&gt;
&lt;br /&gt;
= Basic API version (06-25)=&lt;br /&gt;
&lt;br /&gt;
Below you find the first draft of the API.&lt;br /&gt;
&lt;br /&gt;
== Survey==&lt;br /&gt;
&lt;br /&gt;
A survey is a collection of sections. Surveys can have various metadata like a respondent e-mail adres, a name, ...&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the survey.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaData(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the survey.&lt;br /&gt;
&lt;br /&gt;
== Section==&lt;br /&gt;
&lt;br /&gt;
A section is a part of a survey, grouping questions together. Using conditions it is possible to loop or branch over sections.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the section.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the section.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the section.&lt;br /&gt;
&lt;br /&gt;
== QuestionType==&lt;br /&gt;
&lt;br /&gt;
A survey can have various types of questions, ranging from string &amp;amp; integers up to fileinput and matrix types. QuestionType will have subclasses: basic question types like IntegerQuestionType, StringQuestionType, DateQuestionType ... and structures like MatrixQuestionType, ArrayQuestionType, ...&lt;br /&gt;
&lt;br /&gt;
=== abstract string render()===&lt;br /&gt;
&lt;br /&gt;
Returns a template for this questiontype.&lt;br /&gt;
&lt;br /&gt;
=== abstract mixed getFields()===&lt;br /&gt;
&lt;br /&gt;
Returns a list of all fields required by this questiontype and their types.&lt;br /&gt;
&lt;br /&gt;
=== abstract bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== Question==&lt;br /&gt;
&lt;br /&gt;
A question is a combination of a string (the question) a QuestionType and possible various options - depending on the type.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== void set()===&lt;br /&gt;
&lt;br /&gt;
Setter method for the properties.&lt;br /&gt;
&lt;br /&gt;
=== assoc(key =&amp;gt; value) listMetaData()===&lt;br /&gt;
&lt;br /&gt;
Lists all metadata belonging to the question.&lt;br /&gt;
&lt;br /&gt;
=== void addMetaData(key, value)===&lt;br /&gt;
&lt;br /&gt;
Adds the given metadata to the question.&lt;br /&gt;
&lt;br /&gt;
=== void updateMetaDate(key, newValue)===&lt;br /&gt;
&lt;br /&gt;
Updates the given metadata with the new value.&lt;br /&gt;
&lt;br /&gt;
=== void removeMetaData(key)===&lt;br /&gt;
&lt;br /&gt;
Removes the given metadata from the question.&lt;br /&gt;
&lt;br /&gt;
=== bool checkResponse(value)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given value is a valid response to the question.&lt;br /&gt;
&lt;br /&gt;
== ModelAnswer==&lt;br /&gt;
&lt;br /&gt;
A model answer for a closed question.&lt;br /&gt;
&lt;br /&gt;
=== mixed getValue()===&lt;br /&gt;
&lt;br /&gt;
Returns the value of this model answer.&lt;br /&gt;
&lt;br /&gt;
== Response==&lt;br /&gt;
&lt;br /&gt;
A response is a combination of a token, questionID, answervalue and metadata.&lt;br /&gt;
&lt;br /&gt;
=== mixed get()===&lt;br /&gt;
&lt;br /&gt;
Getter method for all properties.&lt;br /&gt;
&lt;br /&gt;
=== date getStartTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was started. This means when the question was displayed.&lt;br /&gt;
&lt;br /&gt;
=== date getEndTime()===&lt;br /&gt;
&lt;br /&gt;
Returns the time this response was ended. This means when the question was filled in.&lt;br /&gt;
&lt;br /&gt;
=== int getIteration()===&lt;br /&gt;
&lt;br /&gt;
Returns the iteration of this response (used for loops).&lt;br /&gt;
&lt;br /&gt;
== ModelAnswerManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of model answers.&lt;br /&gt;
&lt;br /&gt;
=== void storeModelAnswer(questionID, ModelAnswer)===&lt;br /&gt;
&lt;br /&gt;
Stores the given model answer to the database. If the model answer has no ID, it will be considered a new model answer. In this case ModelAnswer-&amp;gt;id will be set to the ID appointed to this model answer. The model answer must have a valid question id.&lt;br /&gt;
&lt;br /&gt;
=== ModelAnswer[] listModelAnswers(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all model answers of the given question.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(modelAnswerID)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the front of the question.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(modelAnswerID)===&lt;br /&gt;
&lt;br /&gt;
Moves the model answer one place to the end of the question.&lt;br /&gt;
&lt;br /&gt;
== SurveyManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of surveys.&lt;br /&gt;
&lt;br /&gt;
=== Survey[] listSurveys()===&lt;br /&gt;
&lt;br /&gt;
Lists all surveys.&lt;br /&gt;
&lt;br /&gt;
=== void storeSurvey(Survey)===&lt;br /&gt;
&lt;br /&gt;
Stores the given survey to the database. If the survey has no ID, it will be considered a new survey. In this case Survey-&amp;gt;id will be set to the ID appointed to this survey.&lt;br /&gt;
&lt;br /&gt;
=== Survey getSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted survey.&lt;br /&gt;
&lt;br /&gt;
=== void removeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Removes survey data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void openSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to open.&lt;br /&gt;
&lt;br /&gt;
=== void closeSurvey(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Changes the state of the survey to closed.&lt;br /&gt;
&lt;br /&gt;
=== void setDatabaseEngine(surveyID, engineID)===&lt;br /&gt;
&lt;br /&gt;
Enables the chosen database engine for the given survey. Can only be called the first time before the survey is opened.&lt;br /&gt;
&lt;br /&gt;
=== string[] getPossibleDatabaseEngines(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Returns the possible engineID&#039;s of the database engines which are possible for this survey.&lt;br /&gt;
&lt;br /&gt;
== SectionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of sections.&lt;br /&gt;
&lt;br /&gt;
=== Section[] listSections(surveyID)===&lt;br /&gt;
&lt;br /&gt;
Lists all sections in the given survey.&lt;br /&gt;
&lt;br /&gt;
=== void storeSection(Section)===&lt;br /&gt;
&lt;br /&gt;
Stores the given section to the database. If the section has no ID, it will be considered a new section. In this case Section-&amp;gt;id will be set to the ID appointed to this section. The section must have a valid survey id.&lt;br /&gt;
&lt;br /&gt;
=== Section getSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted section.&lt;br /&gt;
&lt;br /&gt;
=== void removeSection(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Removes section data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(sectionId)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the front of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(sectionId)===&lt;br /&gt;
&lt;br /&gt;
Moves the section one place to the end of the survey.&lt;br /&gt;
&lt;br /&gt;
=== void &amp;lt;nowiki&amp;gt;reorder(assoc(sectionId =&amp;gt; orderNumber))&amp;lt;/nowiki&amp;gt;===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given sections to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== interface DBSEObserver==&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyCreated(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySurveyChanged(Survey survey)===&lt;br /&gt;
&lt;br /&gt;
Called on update of survey.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionCreated(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifySectionChanged(Section section)===&lt;br /&gt;
&lt;br /&gt;
Called on update of section.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionCreated(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on creation of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionRemoved(int id)===&lt;br /&gt;
&lt;br /&gt;
Called on removal of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyQuestionChanged(Question question)===&lt;br /&gt;
&lt;br /&gt;
Called on update of question.&lt;br /&gt;
&lt;br /&gt;
=== void notifyResponse(Response response)===&lt;br /&gt;
&lt;br /&gt;
Called on submission of a response.&lt;br /&gt;
&lt;br /&gt;
== QuestionManagementController==&lt;br /&gt;
&lt;br /&gt;
This controller will handle the management of questions.&lt;br /&gt;
&lt;br /&gt;
=== Question[] listQuestions(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Lists all questions in the given section.&lt;br /&gt;
&lt;br /&gt;
=== void storeQuestion(Question)===&lt;br /&gt;
&lt;br /&gt;
Stores the given question to the database. If the question has no ID, it will be considered a new question. In this case Question-&amp;gt;id will be set to the ID appointed to this question. The question must have a valid section id.&lt;br /&gt;
&lt;br /&gt;
=== Question getQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the wanted question.&lt;br /&gt;
&lt;br /&gt;
=== void removeQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Removes question data and all answers.&lt;br /&gt;
&lt;br /&gt;
=== void moveUp(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the front of the section.&lt;br /&gt;
&lt;br /&gt;
=== void moveDown(questionID)===&lt;br /&gt;
&lt;br /&gt;
Moves the question one place to the end of the section.&lt;br /&gt;
&lt;br /&gt;
=== void reorder(assoc(questionID =&amp;gt; orderNumber))===&lt;br /&gt;
&lt;br /&gt;
Changes the order of the given questions to the given order numbers. Orders must be unique. When there are clashes, an exception will be thrown (defined later).&lt;br /&gt;
&lt;br /&gt;
== AnswerAccessController==&lt;br /&gt;
&lt;br /&gt;
This controller provides methodes to store and retrieve survey answers.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&#039;construct(sectionID)===&lt;br /&gt;
&lt;br /&gt;
Constructs a new controller for the given section.&lt;br /&gt;
&lt;br /&gt;
=== void addResponse(participantID, questionID, value, starttime, endtime, iteration=0)===&lt;br /&gt;
&lt;br /&gt;
Adds the given answer and metadata for the given question to the answers of the given participant. If there already was an answer to the given question for the given participant, the answer will be overridden. The iteration parameter is used to express this is the answer for the i&#039;th loop. If the given answer value is invalid for the given question, an exception will be thrown.&lt;br /&gt;
&lt;br /&gt;
=== Response getResponse(participantID, questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns the response of the given participant to the given question and its metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponsesToQuestion(questionID)===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the given question and their metadata.&lt;br /&gt;
&lt;br /&gt;
=== Response[] getResponses()===&lt;br /&gt;
&lt;br /&gt;
Returns all responses to the survey.&lt;br /&gt;
&lt;br /&gt;
=== boolean participated(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns true if the given participant already finished the survey. Returns false if the participant did not complete the survey.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== date getSurveyEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end time of this participant.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionStart(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the start times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
=== assoc(section_id =&amp;gt; date) getSectionEnd(participantID)===&lt;br /&gt;
&lt;br /&gt;
Returns the end times of this participant for each section.&lt;br /&gt;
&lt;br /&gt;
== ObserverController==&lt;br /&gt;
&lt;br /&gt;
=== static ObserverController getInstance()===&lt;br /&gt;
&lt;br /&gt;
Returns a statical instance to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void addObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Adds an observer to the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void removeObserver(DBSEObserver observer)===&lt;br /&gt;
&lt;br /&gt;
Removes an observer from the ObserverController.&lt;br /&gt;
&lt;br /&gt;
=== void notifyObservers(callback $function  ~091~,  mixed $parameter  ~091~,  mixed $...  ~093&amp;lt;span style=&amp;quot;color:093~)===&lt;br /&gt;
&lt;br /&gt;
Notifies all registered observers with the specific function and the given parameters.&lt;br /&gt;
&lt;br /&gt;
==Global notes==&lt;br /&gt;
*Metadata keys can be chained in dot-notation. &#039;color.red&#039; means the key &#039;color&#039; with subkey &#039;red&#039;.&lt;br /&gt;
*The returning of subkeys in metadata will result in assocs in the array. The &#039;color.red&#039; example will give&amp;quot;&amp;gt; array(color =&amp;gt; array(red =&amp;gt; ...)). When you use a subkey, you cannot use the key itself anymore.&lt;br /&gt;
*Exceptions will be used for reporting errors. The exceptions thrown by each method will be added later in the development process.&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Comments from Machaven:==&lt;br /&gt;
&lt;br /&gt;
 1. All the functions that do not return anything (void)&lt;br /&gt;
*Should functions not return true/false (bool) depending on success or failure?&lt;br /&gt;
&lt;br /&gt;
 2. void updateMetaDate(key, value, newValue)&lt;br /&gt;
*Should this be spelled: updateMetaData?&lt;br /&gt;
*Why is the original value required to change the metadata? Are the keys not unique?&lt;br /&gt;
&lt;br /&gt;
 3. How are errors handled?&lt;br /&gt;
* Can we trigger some action on error, set logging or retrieve error information?&lt;br /&gt;
&lt;br /&gt;
== Comments from Jason:==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From May&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 1. There has been some discussion about the use of the word token to represent each unique participant&lt;br /&gt;
*this may be better expressed using a different word internally. Since survey participants/token recipients will be represented as &amp;quot;users&amp;quot; maybe &amp;quot;userID&amp;quot; would be a better label than tokens - ie instead of &amp;quot;Answer getAnswer(token, questionID)&amp;quot;, &amp;quot;Answer getAnswer(userID, questionID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 2. The AnswerAccess controller, should it also be storing responses?&lt;br /&gt;
* So, there should be an equivalent of &amp;quot;getAnswer&amp;quot;, being &amp;quot;putAnswer&amp;quot; (or &amp;quot;saveAnswer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 3. Once answers are being stored, either in a flatfile table, or a normalised one, there will be some kind of unique id for the &amp;quot;collection&amp;quot; of answers, so they can be grouped together.&lt;br /&gt;
* A collection of survey responses, with their unique identifier, become the &amp;quot;sheet of answers&amp;quot; to a particular survey. In the case of a controlled survey - where the user has been specifically invited, so we know who they are, they&#039;ll have a unique userID from the users table. In the case of open/anonymous or general public surveys, this unique identifier will have to be something else - where is that reflected in the getAnswers, and where will it be reflected in the putAnswer(s) call?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New June Comments&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
I&#039;ve had a thought that the moveUp and moveDown methods should take an option of how many positions to move them. When you have 20 questions in a section, and you want to move your question to the top, moving it up one at a time can be really annoying. Can we have void moveUp(sectionId,positions) so if we want to move something 5 places up in the order, it could have a 5 for the positions? Default, of course, would be 1.&lt;br /&gt;
&lt;br /&gt;
== Comments from Hai:==&lt;br /&gt;
* Add functions for reordering questions (something that would take an array and/or an assoc. map)&lt;br /&gt;
* Make sure you handle scalability for conditions well. This includes:&lt;br /&gt;
** ability to link survey elements to multiple conditions, each condition linkable to multiple actions.&lt;br /&gt;
** providing functions for various condition actions, such as question hiding, branching etc. (sorry, I know this is extremely vague, I&#039;ll try to specify later on)&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M1_Database_Design&amp;diff=4240</id>
		<title>Database Storage Engine Project M1 Database Design</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M1_Database_Design&amp;diff=4240"/>
		<updated>2010-06-24T17:48:58Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes creating documentation and descriptions of the database schemes explained at [[Database Storage Engine Project]].&lt;br /&gt;
&lt;br /&gt;
=Questions : Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the design to store survey, section and question information and their related metadata.&lt;br /&gt;
&lt;br /&gt;
[[File:survey_section_question_diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=Responses : Flat Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the layout we propose for storing survey responses in a single database table.&lt;br /&gt;
&lt;br /&gt;
[[File:Flat.png]]&lt;br /&gt;
&lt;br /&gt;
=Responses : Multitable Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the layout we propose for storing survey responses in multiple tables. Responses for each &amp;lt;u&amp;gt;question&amp;lt;/u&amp;gt; get stored in a seperate table.&lt;br /&gt;
&lt;br /&gt;
[[File:Multitable2.png]]&lt;br /&gt;
&lt;br /&gt;
=Responses : Sectionflat Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the layout we propose for storing survey responses in multiple tables. Responses for each &amp;lt;u&amp;gt;section&amp;lt;/u&amp;gt; get stored in a seperate table.&lt;br /&gt;
&lt;br /&gt;
[[File:SectionFlat2.png]]&lt;br /&gt;
&lt;br /&gt;
=Question Type mockups=&lt;br /&gt;
&lt;br /&gt;
These are database mockups of the question types presented [[Question types in version 1.90|here]]. Since the question types are presented as single questions, there is no difference between the 3 proposed database layouts.&lt;br /&gt;
&lt;br /&gt;
==Array==&lt;br /&gt;
&lt;br /&gt;
Choice matrix questions | ChoiceMatrixQuestionType with NumberOfRows child questions of type ChoiceQuestion&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Design flat DB layout (Awaiting comments)&lt;br /&gt;
*Design normalized DB layout (Awaiting comments)&lt;br /&gt;
*Design section-flat DB layout (Awaiting comments)&lt;br /&gt;
*Keep in mind all the Question types supported by Limesurvey1 : [[Question types]]&lt;br /&gt;
*Problem with loops with current response layouts (sectionflat and multitable), flat has no support for loops. (Done)&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Metadata requirements for databases==&lt;br /&gt;
&lt;br /&gt;
- time question displayed/made available to participant (added by Jason)&lt;br /&gt;
&lt;br /&gt;
this may be an indication of when the page was served to the participants browser (time can be generated by web server/php) or in the case of conditional questions, it may need to indicate the time that the question became visible on the page (in which case it may need to be generated by javascript, with all those inherent problems.. maybe it should indicate how many seconds since the page was loaded, and that can be added to the page-load time?)&lt;br /&gt;
&lt;br /&gt;
- time question answered by participant (added by Jason)&lt;br /&gt;
&lt;br /&gt;
this may be a recording of the time that the data in the question was posted (time could be generated by web serer/php) or the time that the question lost focus (after having gained it) - which would be a javascript issue&lt;br /&gt;
&lt;br /&gt;
Any other metadata requirements?&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M1_Database_Design&amp;diff=4241</id>
		<title>Database Storage Engine Project M1 Database Design</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M1_Database_Design&amp;diff=4241"/>
		<updated>2010-06-24T17:28:58Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes creating documentation and descriptions of the database schemes explained at [[Database Storage Engine Project]].&lt;br /&gt;
&lt;br /&gt;
=Questions : Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the design to store survey, section and question information and their related metadata.&lt;br /&gt;
&lt;br /&gt;
[[File:survey_section_question_diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=Responses : Flat Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the layout we propose for storing survey responses in a single database table.&lt;br /&gt;
&lt;br /&gt;
[[File:Flat.png]]&lt;br /&gt;
&lt;br /&gt;
=Responses : Multitable Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the layout we propose for storing survey responses in multiple tables. Responses for each &amp;lt;u&amp;gt;question&amp;lt;/u&amp;gt; get stored in a seperate table.&lt;br /&gt;
&lt;br /&gt;
[[File:Multitable2.png]]&lt;br /&gt;
&lt;br /&gt;
=Responses : Sectionflat Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the layout we propose for storing survey responses in multiple tables. Responses for each &amp;lt;u&amp;gt;section&amp;lt;/u&amp;gt; get stored in a seperate table.&lt;br /&gt;
&lt;br /&gt;
[[File:SectionFlat2.png]]&lt;br /&gt;
&lt;br /&gt;
=Question Type mockups=&lt;br /&gt;
&lt;br /&gt;
These are database mockups of the question types presented [[Question types in version 1.90|here]]. Since the question types are presented as single questions, there is no difference between the 3 proposed database layouts.&lt;br /&gt;
&lt;br /&gt;
==Array==&lt;br /&gt;
&lt;br /&gt;
Stuff goes here&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Design flat DB layout (Awaiting comments)&lt;br /&gt;
*Design normalized DB layout (Awaiting comments)&lt;br /&gt;
*Design section-flat DB layout (Awaiting comments)&lt;br /&gt;
*Keep in mind all the Question types supported by Limesurvey1 : [[Question types]]&lt;br /&gt;
*Problem with loops with current response layouts (sectionflat and multitable), flat has no support for loops. (Done)&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Metadata requirements for databases==&lt;br /&gt;
&lt;br /&gt;
- time question displayed/made available to participant (added by Jason)&lt;br /&gt;
&lt;br /&gt;
this may be an indication of when the page was served to the participants browser (time can be generated by web server/php) or in the case of conditional questions, it may need to indicate the time that the question became visible on the page (in which case it may need to be generated by javascript, with all those inherent problems.. maybe it should indicate how many seconds since the page was loaded, and that can be added to the page-load time?)&lt;br /&gt;
&lt;br /&gt;
- time question answered by participant (added by Jason)&lt;br /&gt;
&lt;br /&gt;
this may be a recording of the time that the data in the question was posted (time could be generated by web serer/php) or the time that the question lost focus (after having gained it) - which would be a javascript issue&lt;br /&gt;
&lt;br /&gt;
Any other metadata requirements?&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M1_Database_Design&amp;diff=4242</id>
		<title>Database Storage Engine Project M1 Database Design</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M1_Database_Design&amp;diff=4242"/>
		<updated>2010-06-24T17:21:31Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes creating documentation and descriptions of the database schemes explained at [[Database Storage Engine Project]].&lt;br /&gt;
&lt;br /&gt;
=Questions : Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the design to store survey, section and question information and their related metadata.&lt;br /&gt;
&lt;br /&gt;
[[File:survey_section_question_diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=Responses : Flat Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the layout we propose for storing survey responses in a single database table.&lt;br /&gt;
&lt;br /&gt;
[[File:Flat.png]]&lt;br /&gt;
&lt;br /&gt;
=Responses : Multitable Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the layout we propose for storing survey responses in multiple tables. Responses for each &amp;lt;u&amp;gt;question&amp;lt;/u&amp;gt; get stored in a seperate table.&lt;br /&gt;
&lt;br /&gt;
[[File:Multitable2.png]]&lt;br /&gt;
&lt;br /&gt;
=Responses : Sectionflat Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the layout we propose for storing survey responses in multiple tables. Responses for each &amp;lt;u&amp;gt;section&amp;lt;/u&amp;gt; get stored in a seperate table.&lt;br /&gt;
&lt;br /&gt;
[[File:SectionFlat2.png]]&lt;br /&gt;
&lt;br /&gt;
=Question Type mockups=&lt;br /&gt;
&lt;br /&gt;
These are mockups of the question types presented [[Question types in version 1.90|here]].&lt;br /&gt;
&lt;br /&gt;
==Array==&lt;br /&gt;
&lt;br /&gt;
Bla&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Design flat DB layout (Awaiting comments)&lt;br /&gt;
*Design normalized DB layout (Awaiting comments)&lt;br /&gt;
*Design section-flat DB layout (Awaiting comments)&lt;br /&gt;
*Keep in mind all the Question types supported by Limesurvey1 : [[Question types]]&lt;br /&gt;
*Problem with loops with current response layouts (sectionflat and multitable), flat has no support for loops. (Done)&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Metadata requirements for databases==&lt;br /&gt;
&lt;br /&gt;
- time question displayed/made available to participant (added by Jason)&lt;br /&gt;
&lt;br /&gt;
this may be an indication of when the page was served to the participants browser (time can be generated by web server/php) or in the case of conditional questions, it may need to indicate the time that the question became visible on the page (in which case it may need to be generated by javascript, with all those inherent problems.. maybe it should indicate how many seconds since the page was loaded, and that can be added to the page-load time?)&lt;br /&gt;
&lt;br /&gt;
- time question answered by participant (added by Jason)&lt;br /&gt;
&lt;br /&gt;
this may be a recording of the time that the data in the question was posted (time could be generated by web serer/php) or the time that the question lost focus (after having gained it) - which would be a javascript issue&lt;br /&gt;
&lt;br /&gt;
Any other metadata requirements?&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M1_Database_Design&amp;diff=4246</id>
		<title>Database Storage Engine Project M1 Database Design</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M1_Database_Design&amp;diff=4246"/>
		<updated>2010-06-20T13:05:58Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes creating documentation and descriptions of the database schemes explained at [[Database Storage Engine Project]].&lt;br /&gt;
&lt;br /&gt;
=Questions : Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the design to store survey, section and question information and their related metadata.&lt;br /&gt;
&lt;br /&gt;
[[File:survey_section_question_diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=Responses : Flat Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the layout we propose for storing survey responses in a single database table.&lt;br /&gt;
&lt;br /&gt;
[[File:Flat.png]]&lt;br /&gt;
&lt;br /&gt;
=Responses : Multitable Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the layout we propose for storing survey responses in multiple tables. Responses for each &amp;lt;u&amp;gt;question&amp;lt;/u&amp;gt; get stored in a seperate table.&lt;br /&gt;
&lt;br /&gt;
[[File:Multitable.png]]&lt;br /&gt;
&lt;br /&gt;
=Responses : Sectionflat Database Layout=&lt;br /&gt;
&lt;br /&gt;
This is the layout we propose for storing survey responses in multiple tables. Responses for each &amp;lt;u&amp;gt;section&amp;lt;/u&amp;gt; get stored in a seperate table.&lt;br /&gt;
&lt;br /&gt;
[[File:SectionFlat.png]]&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Design flat DB layout&lt;br /&gt;
*Design normalized DB layout&lt;br /&gt;
*Design section-flat DB layout&lt;br /&gt;
*Keep in mind all the Question types supported by Limesurvey1 : [[Question types]]&lt;br /&gt;
*Problem with loops with current response layouts (sectionflat and multitable), flat has no support for loops.&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Metadata requirements for databases==&lt;br /&gt;
&lt;br /&gt;
- time question displayed/made available to participant (added by Jason)&lt;br /&gt;
&lt;br /&gt;
this may be an indication of when the page was served to the participants browser (time can be generated by web server/php) or in the case of conditional questions, it may need to indicate the time that the question became visible on the page (in which case it may need to be generated by javascript, with all those inherent problems.. maybe it should indicate how many seconds since the page was loaded, and that can be added to the page-load time?)&lt;br /&gt;
&lt;br /&gt;
- time question answered by participant (added by Jason)&lt;br /&gt;
&lt;br /&gt;
this may be a recording of the time that the data in the question was posted (time could be generated by web serer/php) or the time that the question lost focus (after having gained it) - which would be a javascript issue&lt;br /&gt;
&lt;br /&gt;
Any other metadata requirements?&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M1_Database_Design&amp;diff=4250</id>
		<title>Database Storage Engine Project M1 Database Design</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project_M1_Database_Design&amp;diff=4250"/>
		<updated>2010-05-21T13:20:00Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= About the milestone=&lt;br /&gt;
&lt;br /&gt;
This milestone includes creating documentation and descriptions of the database schemes explained at [[Database Storage Engine Project]].&lt;br /&gt;
&lt;br /&gt;
= Todo=&lt;br /&gt;
*Design flat DB layout&lt;br /&gt;
*Design normalized DB layout&lt;br /&gt;
*Design section-flat DB layout&lt;br /&gt;
*Keep in mind all the Question types supported by Limesurvey1 : http://docs.limesurvey.org/tiki-index.php?page=Question+types&amp;amp;structure;=English+Instructions+for+LimeSurvey&lt;br /&gt;
&lt;br /&gt;
= Discussions=&lt;br /&gt;
&lt;br /&gt;
Comments and ideas here please:&lt;br /&gt;
&lt;br /&gt;
== Metadata requirements for databases==&lt;br /&gt;
&lt;br /&gt;
- time question displayed/made available to participant (added by Jason)&lt;br /&gt;
&lt;br /&gt;
this may be an indication of when the page was served to the participants browser (time can be generated by web server/php) or in the case of conditional questions, it may need to indicate the time that the question became visible on the page (in which case it may need to be generated by javascript, with all those inherent problems.. maybe it should indicate how many seconds since the page was loaded, and that can be added to the page-load time?)&lt;br /&gt;
&lt;br /&gt;
- time question answered by participant (added by Jason)&lt;br /&gt;
&lt;br /&gt;
this may be a recording of the time that the data in the question was posted (time could be generated by web serer/php) or the time that the question lost focus (after having gained it) - which would be a javascript issue&lt;br /&gt;
&lt;br /&gt;
Any other metadata requirements?&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project&amp;diff=4222</id>
		<title>Database Storage Engine Project</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project&amp;diff=4222"/>
		<updated>2010-05-14T18:42:00Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Outline=&lt;br /&gt;
&lt;br /&gt;
The project is focused around the Google Summer Of Code of 2010. Maarten [[(UserPage ttielu|ttielu]]) and Pieter-Jan [[(UserPage MrP|MrP]]) are the students assigned to the project.&lt;br /&gt;
&lt;br /&gt;
The project is based on the DB Storage Engine proposal found at [[LimeSurvey 2 Project Ideas for GSOC 2010]].&lt;br /&gt;
&lt;br /&gt;
= Design and implementation=&lt;br /&gt;
&lt;br /&gt;
A basic domain model of the problem can be found in [http://www.mediafire.com/?mytzjeggien this] pdf file.&lt;br /&gt;
&lt;br /&gt;
This domain model can be used to build multiple databases. One would be to see the objects as tables. For the inheritance there would have to be some analysis to see how they should be mapped to the database. Here it would be important to use a low amount of joins. This structure has the disadvantage that when querying all information of a certain user, loads of joins might be required (depending on the complexity of the survey). On the other hand, queries about all answers on a single question can be very efficient. On top of that, tables are small.&lt;br /&gt;
&lt;br /&gt;
Another example could be to remove the QuestionDependency and make one table per section. This would allow a more flat database structure, which reduces the number of joins necessary to retrieve all data from a single user. This could however create large tables and removes the possibility to loop over one question. This question will have to be placed into a new section and the loop will have to go over that section.&lt;br /&gt;
&lt;br /&gt;
To allow these multiple database formats, we plan on using a [http://en.wikipedia.org/wiki/Factory_pattern factory pattern]. A DatabaseLayoutFactory can be used to choose the layout for a survey and in this way make it possible to add new database layouts for future use (for example a database which duplicates the data in both structures to get fast retrieval of both types of query).&lt;br /&gt;
&lt;br /&gt;
Our plan would be to model the presented database models in detail and then implement at least one of them. Also we would want to model an API for the database (and of course implement that).&lt;br /&gt;
&lt;br /&gt;
After creation of the survey, questions will be more or less static. To build upon this, it would be a good idea to store/cache the questions in a more static form, like a generated html-form, after creation of the survey.&lt;br /&gt;
&lt;br /&gt;
== Database layouts==&lt;br /&gt;
&lt;br /&gt;
=== Flat database===&lt;br /&gt;
&lt;br /&gt;
A flat database would exist of a single table containing all answers to all questions.&lt;br /&gt;
&lt;br /&gt;
Properties of this layout are:&lt;br /&gt;
* easy to export&lt;br /&gt;
* fast database operations&lt;br /&gt;
* hard to implement loops, branching &amp;amp; conditioning (introduce maximums on looping and have loads of NULL values OR use TEXT/BLOB fields containing sub structures =&amp;gt; slow and unsearchable with quick operations)&lt;br /&gt;
* not suited for exotic question types (upload picture, matrix questions, multiple answer, multiple type questions, ...)&lt;br /&gt;
* database column limits might be hit&lt;br /&gt;
* best for simple surveys with huge amounts of answer data&lt;br /&gt;
&lt;br /&gt;
=== Multitable database===&lt;br /&gt;
&lt;br /&gt;
A multitable database would exist of multiple tables each containing the answers of a single question or questiontype.&lt;br /&gt;
&lt;br /&gt;
Properties of this layout are:&lt;br /&gt;
* more difficult to export&lt;br /&gt;
* slower database operations (joins)&lt;br /&gt;
* supports all sorts of branching, conditioning, loops, ... including future features&lt;br /&gt;
* can support pictures, matrix questions, ... easily&lt;br /&gt;
* no problems with database column limits&lt;br /&gt;
* better for complex surveys with smaller amounts of replies&lt;br /&gt;
&lt;br /&gt;
=== Hybrid database (section flat)===&lt;br /&gt;
&lt;br /&gt;
The section flat model is a mix of the previous two models. In stead of mapping all answers in one table, we would map all answers to one section in one table. This allows the more advanced features (like looping, ...) to be handled between sections while still having a fast export of the different sections.&lt;br /&gt;
&lt;br /&gt;
Properties of this layout are:&lt;br /&gt;
* easy to export&lt;br /&gt;
* fast database operations for simple surveys, operations for surveys with loads of loops, branching, ... will need joins (to handle the dependencies)&lt;br /&gt;
* database column limit only for really long sections (but they could be split in multiple sections, solving the problem)&lt;br /&gt;
* can support multiple question types (might result in using more columns, like in case of matrix questions)&lt;br /&gt;
* results in looping over sections instead of looping over questions in sections (hence if there is a loop over one question, there will be a section containing only this question; multiple questions in the same loop can be grouped in one section)&lt;br /&gt;
&lt;br /&gt;
=== Layout mock-ups===&lt;br /&gt;
&lt;br /&gt;
Mock-ups for the database layouts can be found in [http://www.mediafire.com/?nwjwy2c34mw this] pdf file.&lt;br /&gt;
&lt;br /&gt;
The survey used is:&lt;br /&gt;
&lt;br /&gt;
1) how many children do you have? &#039;&#039;&#039;int&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
loop: amount of children {&lt;br /&gt;
&lt;br /&gt;
2.1) give the name of you i&#039;th child &#039;&#039;&#039;string&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2.2) what is the age of your i&#039;th child &#039;&#039;&#039;int&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
3) what kind of ice cream do you like? (multiple choise)&lt;br /&gt;
&lt;br /&gt;
3.1) i don&#039;t like ice cream&lt;br /&gt;
&lt;br /&gt;
3.2) vanilla&lt;br /&gt;
&lt;br /&gt;
3.3) strawberry&lt;br /&gt;
&lt;br /&gt;
3.4) chocolate&lt;br /&gt;
&lt;br /&gt;
3.5) other: 3e) &#039;&#039;&#039;string&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
4) what do you eat? (multiple answer: checkboxes)&lt;br /&gt;
&lt;br /&gt;
4.1) dogs&lt;br /&gt;
&lt;br /&gt;
4.2) pussy&lt;br /&gt;
&lt;br /&gt;
4.3) birds&lt;br /&gt;
&lt;br /&gt;
= Action Plan=&lt;br /&gt;
&lt;br /&gt;
(To be specified more in detail later)&lt;br /&gt;
&lt;br /&gt;
== Outline==&lt;br /&gt;
&lt;br /&gt;
Main deliverables:&lt;br /&gt;
*Database design for flat database&lt;br /&gt;
*Database design for multitable database&lt;br /&gt;
*Database design for section-flat database&lt;br /&gt;
*Class diagram for the database system&lt;br /&gt;
*API and documentation with the database system - keep support for metadata in mind.&lt;br /&gt;
*Implementation of the database system with at least one database layout (more if spare time is found)&lt;br /&gt;
&lt;br /&gt;
== Milestones==&lt;br /&gt;
&lt;br /&gt;
The first series of milestones is slightly smaller since both Maarten and Pieter-Jan have exams in the month of June.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|Milestone||Deadline&lt;br /&gt;
|-&lt;br /&gt;
|[[Database Storage Engine Project M1 Database Design||Database designs]]||26th of June&lt;br /&gt;
|-&lt;br /&gt;
|[[Database Storage Engine Project M2 API||API]]||30th of June&lt;br /&gt;
|-&lt;br /&gt;
|[[Database Storage Engine Project M3 Class diagram||Class diagram]]||7th of July&lt;br /&gt;
|-&lt;br /&gt;
|[[Database Storage Engine Project M4 Basic implementation||Implement basic classes]]||14th of July&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The second series of milestones will contain the biggest part of the implementation work and will be more specified once the class diagram has been fully worked out.&lt;br /&gt;
*Finish implementing basic classes&lt;br /&gt;
*Implement database layout engine&lt;br /&gt;
*Implement specific database layout&lt;br /&gt;
*Test and debug&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project&amp;diff=4226</id>
		<title>Database Storage Engine Project</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project&amp;diff=4226"/>
		<updated>2010-04-28T10:24:18Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Outline=&lt;br /&gt;
&lt;br /&gt;
The project is focused around the Google Summer Of Code of 2010. Maarten [[(UserPage ttielu|ttielu]]) and Pieter-Jan [[(UserPage MrP|MrP]]) are the students assigned to the project.&lt;br /&gt;
&lt;br /&gt;
The project is based on the DB Storage Engine proposal found at [[LimeSurvey 2 Project Ideas for GSOC 2010]].&lt;br /&gt;
&lt;br /&gt;
= Design and implementation=&lt;br /&gt;
&lt;br /&gt;
A basic domain model of the problem can be found in [http://www.mediafire.com/?mytzjeggien this] pdf file.&lt;br /&gt;
&lt;br /&gt;
This domain model can be used to build multiple databases. One would be to see the objects as tables. For the inheritance there would have to be some analysis to see how they should be mapped to the database. Here it would be important to use a low amount of joins. This structure has the disadvantage that when querying all information of a certain user, loads of joins might be required (depending on the complexity of the survey). On the other hand, queries about all answers on a single question can be very efficient. On top of that, tables are small.&lt;br /&gt;
&lt;br /&gt;
Another example could be to remove the QuestionDependency and make one table per section. This would allow a more flat database structure, which reduces the number of joins necessary to retrieve all data from a single user. This could however create large tables and removes the possibility to loop over one question. This question will have to be placed into a new section and the loop will have to go over that section.&lt;br /&gt;
&lt;br /&gt;
To allow these multiple database formats, we plan on using a [http://en.wikipedia.org/wiki/Factory_pattern factory pattern]. A DatabaseLayoutFactory can be used to choose the layout for a survey and in this way make it possible to add new database layouts for future use (for example a database which duplicates the data in both structures to get fast retrieval of both types of query).&lt;br /&gt;
&lt;br /&gt;
Our plan would be to model the presented database models in detail and then implement at least one of them. Also we would want to model an API for the database (and of course implement that).&lt;br /&gt;
&lt;br /&gt;
After creation of the survey, questions will be more or less static. To build upon this, it would be a good idea to store/cache the questions in a more static form, like a generated html-form, after creation of the survey.&lt;br /&gt;
&lt;br /&gt;
== Database layouts==&lt;br /&gt;
&lt;br /&gt;
=== Flat database===&lt;br /&gt;
&lt;br /&gt;
A flat database would exist of a single table containing all answers to all questions.&lt;br /&gt;
&lt;br /&gt;
Properties of this layout are:&lt;br /&gt;
* easy to export&lt;br /&gt;
* fast database operations&lt;br /&gt;
* hard to implement loops, branching &amp;amp; conditioning (introduce maximums on looping and have loads of NULL values OR use TEXT/BLOB fields containing sub structures =&amp;gt; slow and unsearchable with quick operations)&lt;br /&gt;
* not suited for exotic question types (upload picture, matrix questions, multiple answer, multiple type questions, ...)&lt;br /&gt;
* database column limits might be hit&lt;br /&gt;
* best for simple surveys with huge amounts of answer data&lt;br /&gt;
&lt;br /&gt;
=== Multitable database===&lt;br /&gt;
&lt;br /&gt;
A multitable database would exist of multiple tables each containing the answers of a single question or questiontype.&lt;br /&gt;
&lt;br /&gt;
Properties of this layout are:&lt;br /&gt;
* more difficult to export&lt;br /&gt;
* slower database operations (joins)&lt;br /&gt;
* supports all sorts of branching, conditioning, loops, ... including future features&lt;br /&gt;
* can support pictures, matrix questions, ... easily&lt;br /&gt;
* no problems with database column limits&lt;br /&gt;
* better for complex surveys with smaller amounts of replies&lt;br /&gt;
&lt;br /&gt;
=== Hybrid database (section flat)===&lt;br /&gt;
&lt;br /&gt;
The section flat model is a mix of the previous two models. In stead of mapping all answers in one table, we would map all answers to one section in one table. This allows the more advanced features (like looping, ...) to be handled between sections while still having a fast export of the different sections.&lt;br /&gt;
&lt;br /&gt;
Properties of this layout are:&lt;br /&gt;
* easy to export&lt;br /&gt;
* fast database operations for simple surveys, operations for surveys with loads of loops, branching, ... will need joins (to handle the dependencies)&lt;br /&gt;
* database column limit only for really long sections (but they could be split in multiple sections, solving the problem)&lt;br /&gt;
* can support multiple question types (might result in using more columns, like in case of matrix questions)&lt;br /&gt;
* results in looping over sections instead of looping over questions in sections (hence if there is a loop over one question, there will be a section containing only this question; multiple questions in the same loop can be grouped in one section)&lt;br /&gt;
&lt;br /&gt;
=== Layout mock-ups===&lt;br /&gt;
&lt;br /&gt;
Mock-ups for the database layouts can be found in [http://www.mediafire.com/?nwjwy2c34mw this] pdf file.&lt;br /&gt;
&lt;br /&gt;
The survey used is:&lt;br /&gt;
&lt;br /&gt;
1) how many children do you have? &#039;&#039;&#039;int&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
loop: amount of children {&lt;br /&gt;
&lt;br /&gt;
2.1) give the name of you i&#039;th child &#039;&#039;&#039;string&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2.2) what is the age of your i&#039;th child &#039;&#039;&#039;int&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
3) what kind of ice cream do you like? (multiple choise)&lt;br /&gt;
&lt;br /&gt;
3.1) i don&#039;t like ice cream&lt;br /&gt;
&lt;br /&gt;
3.2) vanilla&lt;br /&gt;
&lt;br /&gt;
3.3) strawberry&lt;br /&gt;
&lt;br /&gt;
3.4) chocolate&lt;br /&gt;
&lt;br /&gt;
3.5) other: 3e) &#039;&#039;&#039;string&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
4) what do you eat? (multiple answer: checkboxes)&lt;br /&gt;
&lt;br /&gt;
4.1) dogs&lt;br /&gt;
&lt;br /&gt;
4.2) pussy&lt;br /&gt;
&lt;br /&gt;
4.3) birds&lt;br /&gt;
&lt;br /&gt;
= Action Plan=&lt;br /&gt;
&lt;br /&gt;
(To be specified more in detail later)&lt;br /&gt;
&lt;br /&gt;
== Outline==&lt;br /&gt;
&lt;br /&gt;
Main deliverables:&lt;br /&gt;
*Database design for flat database&lt;br /&gt;
*Database design for multitable database&lt;br /&gt;
*Database design for section-flat database&lt;br /&gt;
*Class diagram for the database system&lt;br /&gt;
*API and documentation with the database system&lt;br /&gt;
*Implementation of the database system with at least one database layout (more if spare time is found)&lt;br /&gt;
&lt;br /&gt;
== Milestones==&lt;br /&gt;
&lt;br /&gt;
The first series of milestones is slightly smaller since both Maarten and Pieter-Jan have exams in the month of June.&lt;br /&gt;
*Database designs&lt;br /&gt;
&lt;br /&gt;
+ # Flat layout&lt;br /&gt;
&lt;br /&gt;
+ # multitable layout&lt;br /&gt;
&lt;br /&gt;
+ # section-flat layout&lt;br /&gt;
*Class diagram&lt;br /&gt;
*API&lt;br /&gt;
*Implement basic classes&lt;br /&gt;
&lt;br /&gt;
The second series of milestones will contain the biggest part of the implementation work and will be more specified once the class diagram has been fully worked out.&lt;br /&gt;
*Finish implementing basic classes&lt;br /&gt;
*Implement database layout engine&lt;br /&gt;
*Implement specific database layout&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
	<entry>
		<id>https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project&amp;diff=4227</id>
		<title>Database Storage Engine Project</title>
		<link rel="alternate" type="text/html" href="https://www.limesurvey.org/manual/index.php?title=Database_Storage_Engine_Project&amp;diff=4227"/>
		<updated>2010-04-28T10:23:54Z</updated>

		<summary type="html">&lt;p&gt;Ttielu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Outline=&lt;br /&gt;
&lt;br /&gt;
The project is focused around the Google Summer Of Code of 2010. Maarten [[UserPage ttielu|ttielu]] and Pieter-Jan [[(UserPage MrP|MrP]]) are the students assigned to the project.&lt;br /&gt;
&lt;br /&gt;
The project is based on the DB Storage Engine proposal found at [[LimeSurvey 2 Project Ideas for GSOC 2010]].&lt;br /&gt;
&lt;br /&gt;
= Design and implementation=&lt;br /&gt;
&lt;br /&gt;
A basic domain model of the problem can be found in [http://www.mediafire.com/?mytzjeggien this] pdf file.&lt;br /&gt;
&lt;br /&gt;
This domain model can be used to build multiple databases. One would be to see the objects as tables. For the inheritance there would have to be some analysis to see how they should be mapped to the database. Here it would be important to use a low amount of joins. This structure has the disadvantage that when querying all information of a certain user, loads of joins might be required (depending on the complexity of the survey). On the other hand, queries about all answers on a single question can be very efficient. On top of that, tables are small.&lt;br /&gt;
&lt;br /&gt;
Another example could be to remove the QuestionDependency and make one table per section. This would allow a more flat database structure, which reduces the number of joins necessary to retrieve all data from a single user. This could however create large tables and removes the possibility to loop over one question. This question will have to be placed into a new section and the loop will have to go over that section.&lt;br /&gt;
&lt;br /&gt;
To allow these multiple database formats, we plan on using a [http://en.wikipedia.org/wiki/Factory_pattern factory pattern]. A DatabaseLayoutFactory can be used to choose the layout for a survey and in this way make it possible to add new database layouts for future use (for example a database which duplicates the data in both structures to get fast retrieval of both types of query).&lt;br /&gt;
&lt;br /&gt;
Our plan would be to model the presented database models in detail and then implement at least one of them. Also we would want to model an API for the database (and of course implement that).&lt;br /&gt;
&lt;br /&gt;
After creation of the survey, questions will be more or less static. To build upon this, it would be a good idea to store/cache the questions in a more static form, like a generated html-form, after creation of the survey.&lt;br /&gt;
&lt;br /&gt;
== Database layouts==&lt;br /&gt;
&lt;br /&gt;
=== Flat database===&lt;br /&gt;
&lt;br /&gt;
A flat database would exist of a single table containing all answers to all questions.&lt;br /&gt;
&lt;br /&gt;
Properties of this layout are:&lt;br /&gt;
* easy to export&lt;br /&gt;
* fast database operations&lt;br /&gt;
* hard to implement loops, branching &amp;amp; conditioning (introduce maximums on looping and have loads of NULL values OR use TEXT/BLOB fields containing sub structures =&amp;gt; slow and unsearchable with quick operations)&lt;br /&gt;
* not suited for exotic question types (upload picture, matrix questions, multiple answer, multiple type questions, ...)&lt;br /&gt;
* database column limits might be hit&lt;br /&gt;
* best for simple surveys with huge amounts of answer data&lt;br /&gt;
&lt;br /&gt;
=== Multitable database===&lt;br /&gt;
&lt;br /&gt;
A multitable database would exist of multiple tables each containing the answers of a single question or questiontype.&lt;br /&gt;
&lt;br /&gt;
Properties of this layout are:&lt;br /&gt;
* more difficult to export&lt;br /&gt;
* slower database operations (joins)&lt;br /&gt;
* supports all sorts of branching, conditioning, loops, ... including future features&lt;br /&gt;
* can support pictures, matrix questions, ... easily&lt;br /&gt;
* no problems with database column limits&lt;br /&gt;
* better for complex surveys with smaller amounts of replies&lt;br /&gt;
&lt;br /&gt;
=== Hybrid database (section flat)===&lt;br /&gt;
&lt;br /&gt;
The section flat model is a mix of the previous two models. In stead of mapping all answers in one table, we would map all answers to one section in one table. This allows the more advanced features (like looping, ...) to be handled between sections while still having a fast export of the different sections.&lt;br /&gt;
&lt;br /&gt;
Properties of this layout are:&lt;br /&gt;
* easy to export&lt;br /&gt;
* fast database operations for simple surveys, operations for surveys with loads of loops, branching, ... will need joins (to handle the dependencies)&lt;br /&gt;
* database column limit only for really long sections (but they could be split in multiple sections, solving the problem)&lt;br /&gt;
* can support multiple question types (might result in using more columns, like in case of matrix questions)&lt;br /&gt;
* results in looping over sections instead of looping over questions in sections (hence if there is a loop over one question, there will be a section containing only this question; multiple questions in the same loop can be grouped in one section)&lt;br /&gt;
&lt;br /&gt;
=== Layout mock-ups===&lt;br /&gt;
&lt;br /&gt;
Mock-ups for the database layouts can be found in [http://www.mediafire.com/?nwjwy2c34mw this] pdf file.&lt;br /&gt;
&lt;br /&gt;
The survey used is:&lt;br /&gt;
&lt;br /&gt;
1) how many children do you have? &#039;&#039;&#039;int&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
loop: amount of children {&lt;br /&gt;
&lt;br /&gt;
2.1) give the name of you i&#039;th child &#039;&#039;&#039;string&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2.2) what is the age of your i&#039;th child &#039;&#039;&#039;int&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
3) what kind of ice cream do you like? (multiple choise)&lt;br /&gt;
&lt;br /&gt;
3.1) i don&#039;t like ice cream&lt;br /&gt;
&lt;br /&gt;
3.2) vanilla&lt;br /&gt;
&lt;br /&gt;
3.3) strawberry&lt;br /&gt;
&lt;br /&gt;
3.4) chocolate&lt;br /&gt;
&lt;br /&gt;
3.5) other: 3e) &#039;&#039;&#039;string&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
4) what do you eat? (multiple answer: checkboxes)&lt;br /&gt;
&lt;br /&gt;
4.1) dogs&lt;br /&gt;
&lt;br /&gt;
4.2) pussy&lt;br /&gt;
&lt;br /&gt;
4.3) birds&lt;br /&gt;
&lt;br /&gt;
= Action Plan=&lt;br /&gt;
&lt;br /&gt;
(To be specified more in detail later)&lt;br /&gt;
&lt;br /&gt;
== Outline==&lt;br /&gt;
&lt;br /&gt;
Main deliverables:&lt;br /&gt;
*Database design for flat database&lt;br /&gt;
*Database design for multitable database&lt;br /&gt;
*Database design for section-flat database&lt;br /&gt;
*Class diagram for the database system&lt;br /&gt;
*API and documentation with the database system&lt;br /&gt;
*Implementation of the database system with at least one database layout (more if spare time is found)&lt;br /&gt;
&lt;br /&gt;
== Milestones==&lt;br /&gt;
&lt;br /&gt;
The first series of milestones is slightly smaller since both Maarten and Pieter-Jan have exams in the month of June.&lt;br /&gt;
*Database designs&lt;br /&gt;
&lt;br /&gt;
+ # Flat layout&lt;br /&gt;
&lt;br /&gt;
+ # multitable layout&lt;br /&gt;
&lt;br /&gt;
+ # section-flat layout&lt;br /&gt;
*Class diagram&lt;br /&gt;
*API&lt;br /&gt;
*Implement basic classes&lt;br /&gt;
&lt;br /&gt;
The second series of milestones will contain the biggest part of the implementation work and will be more specified once the class diagram has been fully worked out.&lt;br /&gt;
*Finish implementing basic classes&lt;br /&gt;
*Implement database layout engine&lt;br /&gt;
*Implement specific database layout&lt;/div&gt;</summary>
		<author><name>Ttielu</name></author>
	</entry>
</feed>