[147] | 1 | \documentclass{article}
|
---|
| 2 | \title{Database Connection for the CPS Facilitator Tool}
|
---|
| 3 | \author{Jos Kraaijeveld}
|
---|
| 4 | \date{\today}
|
---|
| 5 | \usepackage{moreverb}
|
---|
| 6 | \usepackage{fullpage}
|
---|
| 7 | \usepackage{framed}
|
---|
| 8 | \usepackage{float}
|
---|
| 9 | \usepackage{multirow}
|
---|
[160] | 10 | \usepackage[final]{pdfpages}
|
---|
| 11 | \usepackage{hyperref}
|
---|
[147] | 12 | \begin{document}
|
---|
| 13 |
|
---|
| 14 | \maketitle
|
---|
| 15 |
|
---|
| 16 | \pagebreak
|
---|
| 17 |
|
---|
| 18 | \tableofcontents
|
---|
| 19 |
|
---|
| 20 | \pagebreak
|
---|
[231] | 21 | \section{Changelog}
|
---|
| 22 | \textit{13-01-2012}: Fixed the issue with Open-Closed, updated documentation accordingly.
|
---|
[147] | 23 |
|
---|
| 24 | \section{Introduction}
|
---|
| 25 | This document describes the database design and implementation for the CPS Facilitator Tool. The goal is to make
|
---|
| 26 | sure everyone can communicate with the RDF-based database without having to write queries. The DBInterface is
|
---|
| 27 | written in PHP and requires slight PHP knowledge before use. It is heavily based on initial work by Bas van Nuland. \\
|
---|
| 28 |
|
---|
| 29 | If you use this framework, you can skip to the `How to use'-part of this document (\ref{howtouse}). If you are
|
---|
| 30 | planning to improve this framework, I recommend reading the RDF Primer\footnote{http://www.w3.org/TR/rdf-primer/} and
|
---|
| 31 | SPARQL Query Language for RDF\footnote{http://www.w3.org/TR/rdf-sparql-query/}. A full specification of the current
|
---|
| 32 | implementation can be found in section \ref{spec}. The areas I suggest improving upon first are described in section
|
---|
| 33 | \ref{futurework}.
|
---|
| 34 |
|
---|
| 35 | \section{How to use}\label{howtouse}
|
---|
| 36 | \subsection{Initialization}
|
---|
[231] | 37 | Before the database can be used, you should remember to import master.php on every page:
|
---|
[147] | 38 | \begin{verbatimtab}
|
---|
[231] | 39 | require 'classes/master.php';
|
---|
[147] | 40 | \end{verbatimtab}
|
---|
| 41 |
|
---|
| 42 | \subsection{Basic queries}
|
---|
| 43 | \subsubsection{Retrieving data}
|
---|
[231] | 44 | Getting data is done by calling the get method of the class for which you want to retrieve data. The
|
---|
| 45 | specification for this method is the same for every class and is as follows.\\ \\
|
---|
[147] | 46 | \begin{tabular}{| l || r |} \hline
|
---|
| 47 | \multicolumn{2}{|c|}{Function get()} \\ \hline
|
---|
| 48 | Second argument: \$arguments & Array \\ \hline
|
---|
| 49 | Return type: & Array/Variable \\ \hline
|
---|
| 50 | \end{tabular} \\ \\
|
---|
| 51 |
|
---|
[231] | 52 | The return type is an Array of objects with the type corresponding to the class you caled it on. For
|
---|
| 53 | instance, if you call User::get() you will only get User objects. Below are a few examples showing the usage
|
---|
[147] | 54 | of get(). A description of what arguments are possible per type is given in section \ref{arguments}.
|
---|
| 55 |
|
---|
| 56 | \begin{figure}[H]
|
---|
| 57 | \caption{Retrieving all questions and echo their title.}
|
---|
| 58 | \begin{framed}
|
---|
| 59 | \begin{verbatimtab}
|
---|
[231] | 60 | $questions = User::get(array());
|
---|
[147] | 61 | foreach ($questions as $question)
|
---|
| 62 | {
|
---|
| 63 | echo $question->title;
|
---|
| 64 | }
|
---|
| 65 | \end{verbatimtab}
|
---|
| 66 | \end{framed}
|
---|
| 67 | \end{figure}
|
---|
| 68 |
|
---|
| 69 | \begin{figure}[H]
|
---|
| 70 | \caption{Retrieving all surveys containing questions with IDs q1 and q2, created by the user
|
---|
| 71 | Jos, printing all questions in those surveys}
|
---|
| 72 | \begin{framed}
|
---|
| 73 | \begin{verbatimtab}
|
---|
| 74 | //To get all surveys created by the user Jos, we need his UID.
|
---|
| 75 | //We first query the database for the User object belonging to Jos.
|
---|
[231] | 76 | $userResults = User::get(array("name" => "Jos"));
|
---|
[147] | 77 | //Assuming there is a result, the UID is:
|
---|
| 78 | $josUID = $userResults[0]->uid;
|
---|
| 79 | //Now to get the requested surveys:
|
---|
[231] | 80 | $surveys = Survey::get(array("questions" => array("q1", "q2"),
|
---|
[147] | 81 | "creator" => $josUID));
|
---|
| 82 | //And to print all the questions in these surveys:
|
---|
| 83 | foreach($surveys as $survey)
|
---|
| 84 | {
|
---|
| 85 | echo "All the questions in " . $survey->name;
|
---|
| 86 | foreach($survey->questions as $question)
|
---|
| 87 | {
|
---|
| 88 | print_r($question);
|
---|
| 89 | }
|
---|
| 90 | }
|
---|
| 91 | \end{verbatimtab}
|
---|
| 92 | \end{framed}
|
---|
| 93 | \end{figure}
|
---|
| 94 |
|
---|
| 95 | \subsubsection{Storing data}
|
---|
[231] | 96 | Storing data is easy, as long as you stick to using the given PHP Classes. Retrieve these objects by using
|
---|
| 97 | the get() function, and call the save() function of the objects.: \\ \\
|
---|
[147] | 98 | \begin{tabular}{| l || r |} \hline
|
---|
[231] | 99 | \multicolumn{2}{|c|}{Function save()} \\ \hline
|
---|
| 100 | Returns: \$boolean & succeeded \\ \hline
|
---|
[147] | 101 | \end{tabular} \\ \\
|
---|
[231] | 102 | If the save function returns false, there is an invalid references in that object which needs to be resolved
|
---|
| 103 | before saving. This ensures the database is always valid.
|
---|
[147] | 104 | Another important thing to note is that currently it will overwrite a previous object with the same UID in
|
---|
| 105 | the database. The following examples show how to create new objects and save them, as well as edit old
|
---|
| 106 | objects and save them.
|
---|
| 107 |
|
---|
| 108 | \begin{figure}[H]
|
---|
| 109 | \caption{Creating a new Answer object and storing this in the database.}
|
---|
| 110 | \begin{framed}
|
---|
| 111 | \begin{verbatimtab}
|
---|
| 112 | //For this example, I choose a random question to answer
|
---|
[231] | 113 | $questions = Question::get(array());
|
---|
[147] | 114 | $question = $questions[2];
|
---|
| 115 | //Note two things:
|
---|
| 116 | //1 - If you pass 'null' as first argument when creating any object
|
---|
| 117 | // A new UID will be generated, indicating a new object.
|
---|
| 118 | //2 - Depending on the question, there can be multiple answers
|
---|
| 119 | // This means the values-argument (third argument) is an array.
|
---|
| 120 | $answer = new Answer(null, $question, array("12345", "four"));
|
---|
| 121 | //Save the answer in the database
|
---|
[231] | 122 | if($answer->save())
|
---|
| 123 | echo "Success";
|
---|
[147] | 124 | \end{verbatimtab}
|
---|
| 125 | \end{framed}
|
---|
| 126 | \end{figure}
|
---|
| 127 |
|
---|
| 128 | \begin{figure}[H]
|
---|
| 129 | \caption{Getting a Survey object from the database and removing the first question. Also alter this
|
---|
| 130 | question.}
|
---|
| 131 | \begin{framed}
|
---|
| 132 | \begin{verbatimtab}
|
---|
| 133 | //Get the survey
|
---|
[231] | 134 | $surveyResults = Survey::get(array("uid" => "b91d39e8667372e220bb861b3f94b5bd"));
|
---|
[147] | 135 | $survey = surveyResults[0];
|
---|
| 136 | //Remove the question
|
---|
| 137 | $question = $survey->questions[0];
|
---|
| 138 | unset($survey->questions[0]);
|
---|
| 139 | //Change the question
|
---|
| 140 | $question->title = "New Title";
|
---|
| 141 | //Save the survey and question
|
---|
[231] | 142 | $question->save(); $survey->save();
|
---|
[147] | 143 | \end{verbatimtab}
|
---|
| 144 | \end{framed}
|
---|
| 145 | \end{figure}
|
---|
| 146 |
|
---|
| 147 |
|
---|
| 148 | \subsection{Arguments}\label{arguments}
|
---|
| 149 | The arguments you can supply when calling the get() function differ greatly per type. Unfortunately, there is no
|
---|
| 150 | way around this, so here is a complete overview of arguments per type. \\
|
---|
| 151 | \begin{tabular}{| l | c | c | l |} \hline
|
---|
[196] | 152 | \textbf{Type} & \textbf{Argument name} & \textbf{Argument type} & \textbf{Extra notes} \\ \hline \hline
|
---|
| 153 | \multirow{3}{*}{Answer} & uid & String & \\
|
---|
[147] | 154 | & question & String & UID of the question \\
|
---|
[196] | 155 | & values & Array of Strings & \\ \hline \hline
|
---|
| 156 | \multirow{4}{*}{AnswerSet} & uid & String & \\
|
---|
[147] | 157 | & survey & String & UID of the Survey \\
|
---|
| 158 | & respondent & String & UID of the Respondent \\
|
---|
[196] | 159 | & answers & Array of Strings & UIDs of the Answers \\ \hline \hline
|
---|
| 160 | \multirow{4}{*}{Application} & uid & String & \\
|
---|
[147] | 161 | & title & String & \\
|
---|
[196] | 162 | & description & String & \\
|
---|
| 163 | & style & String & \\ \hline \hline
|
---|
| 164 | \multirow{5}{*}{Question} & code & String & \\
|
---|
[147] | 165 | & title & String & \\
|
---|
[196] | 166 | & type & String & \\
|
---|
| 167 | & description & String & \\
|
---|
[147] | 168 | & category & String & \\
|
---|
[196] | 169 | & definedanswers & Array of Strings & String values of possible answers \\ \hline \hline
|
---|
| 170 | \multirow{3}{*}{Respondent/User} & uid & String & \\
|
---|
| 171 | & name & String & \\
|
---|
[147] | 172 | & password & String & Use hashes to store passwords \\ \hline \hline
|
---|
[196] | 173 | \multirow{7}{*}{Session} & uid & String & \\
|
---|
[147] | 174 | & title & String & \\
|
---|
[160] | 175 | & creator & String & UID of the User \\
|
---|
[196] | 176 | & creationdate & String & Unix Timestamp. No way to search on intervals (yet). \\
|
---|
| 177 | & applications & Array of Strings & UIDs of the Applications \\
|
---|
| 178 | & surveys & Array of Strings & UIDs of the Surveys \\
|
---|
| 179 | & answersets & Array of Strings & UIDs of the AnswerSets \\ \hline \hline
|
---|
| 180 | \multirow{9}{*}{SessionInstance} & uid & String & \\
|
---|
[147] | 181 | & title & String & \\
|
---|
[196] | 182 | & location & String & \\
|
---|
| 183 | & facilitator & String & UID of the user that facilitated the session \\
|
---|
| 184 | & startime & String & Unix Timestamp. No way to search on intervals (yet). \\
|
---|
| 185 | & endtime & String & Unix Timestamp. No way to search on intervals (yet). \\
|
---|
| 186 | & notes & Array of Strings & \\
|
---|
| 187 | & session & String & UID of the Session this Instance refers to. \\
|
---|
| 188 | & resultset & String & UID of the ResultSet this Instance has. \\ \hline \hline
|
---|
| 189 | \multirow{4}{*}{Survey} & uid & String & \\
|
---|
| 190 | & title & String & \\
|
---|
| 191 | & description & String & \\
|
---|
[147] | 192 | & creator & String & UID of the user that created this survey \\
|
---|
[196] | 193 | & questions & Array of Strings & UIDs of the Questions \\ \hline \hline
|
---|
[147] | 194 | \end{tabular} \\
|
---|
| 195 |
|
---|
| 196 | Whenever an Array has to be supplied, it will match for results that satisfy \textit{all} the constraints given
|
---|
| 197 | in the array.
|
---|
| 198 |
|
---|
[160] | 199 | \section{Specification}\label{spec}
|
---|
| 200 | \subsection{Models}
|
---|
| 201 | The framework heavily relies on the Object Oriented Programming paradigm, and only allows you to create, edit
|
---|
| 202 | and store data through instances of precreated classes. All these classes inherit from a global
|
---|
| 203 | ResearchToolObject class. A UML class diagram of the model classes can be found in Appendix \ref{models}.
|
---|
[189] | 204 | The most important thing to note is that references to other objects are not evaluated immediately. Rather,
|
---|
| 205 | these classes with references have to override the evaluate() function, which in turn tries to query the
|
---|
| 206 | database and resolve those UIDs to model objects. This gives us two advantages: initial queries do not scale
|
---|
| 207 | exponentially because of the 'lazy' evaluation, and the boolean return value notifies us when there exists an
|
---|
| 208 | incorrect reference. By evaluating before saving an object, we ensure that there cannot exist invalid values in
|
---|
| 209 | the database.
|
---|
| 210 |
|
---|
[231] | 211 | \subsection{Static functions, non-static functions}
|
---|
| 212 | It is important to note that the get() function of each object is static, whilst the save() function is not.
|
---|
| 213 | This is to provide a better saving mechanism in the future: tracking when an object gets changed and saving it
|
---|
| 214 | automatically. The get() function is static because there is no reason for it to be linked to a specific Object,
|
---|
| 215 | only to the type it describes as a whole.
|
---|
| 216 |
|
---|
| 217 | \subsection{Adding to the system}
|
---|
| 218 | Adding support for new datatypes is easy and can be done by extending the ResearchToolObject class and ensuring
|
---|
| 219 | the get() and save() methods are implemented correctly. Simply look at the existing classes and stick to the
|
---|
| 220 | same idea unless you want to radically change the infrastructure.
|
---|
| 221 |
|
---|
[160] | 222 | \subsection{PHPDoc}
|
---|
| 223 | PHPDoc for the database classes can be found at
|
---|
[172] | 224 | \href{http://svn.tbm.tudelft.nl/TBM-CPS/RESEARCHTOOL/Doc/Backend/PHPDoc/index.html}{SVN}.
|
---|
[147] | 225 |
|
---|
| 226 | \section{Future Work}\label{futurework}
|
---|
[179] | 227 | \subsection{Deal with invalid or missing values}
|
---|
| 228 | This goes in two parts. Firstly, the database now assumes that given an entry, all the fields for its type are there and
|
---|
| 229 | filled in. This is unwanted since it can cause issues with backwards compatability of certain .rdf files. Secondly, it
|
---|
[196] | 230 | assumes that fields containing a UID to a different entry actually point to a valid entry. For instance, a Survey evaluation will
|
---|
| 231 | try to get a User object as its creator value from the database as well, assuming it exists. It will return false if this user object
|
---|
[179] | 232 | does not exist.
|
---|
| 233 |
|
---|
[160] | 234 | \appendix
|
---|
| 235 | \pagebreak
|
---|
| 236 | \section{Class diagram of the models}\label{models}
|
---|
| 237 | \begin{figure}
|
---|
| 238 | \includepdf[scale=1.22]{DBModels.pdf}
|
---|
| 239 | \end{figure}
|
---|
[147] | 240 |
|
---|
| 241 | \end{document}
|
---|