From 5970e1eacef13337648f57a4a013382d4ac7fddf Mon Sep 17 00:00:00 2001 From: jcleeland Date: Fri, 20 Jul 2012 22:41:00 +1000 Subject: [PATCH 01/71] Fixed issue #6355 - Change graph type in statistics view not working --- application/controllers/admin/statistics.php | 9 +- .../helpers/admin/statistics_helper.php | 6 +- .../views/admin/export/statistics_view.php | 4 +- scripts/admin/statistics.js | 152 +++++++++--------- 4 files changed, 87 insertions(+), 84 deletions(-) diff --git a/application/controllers/admin/statistics.php b/application/controllers/admin/statistics.php index 3c881cb4f66..6d8bbec58da 100644 --- a/application/controllers/admin/statistics.php +++ b/application/controllers/admin/statistics.php @@ -559,7 +559,7 @@ public function run($surveyid, $subaction = null) function graph() { - Yii::app()->loadHelper('admin/statistics_helper'); + Yii::app()->loadHelper('admin/statistics'); Yii::app()->loadHelper("surveytranslator"); // Initialise PCHART @@ -571,8 +571,8 @@ function graph() $aData['success'] = 1; - if (isset($_POST['cmd']) || !isset($_POST['id'])) { - list($qsid, $qgid, $qqid) = explode("X", substr($_POST['id'], 1), 3); + if (isset($_POST['cmd']) && isset($_POST['id'])) { + list($qsid, $qgid, $qqid) = explode("X", substr($_POST['id'], 0), 3); $qtype = substr($_POST['id'], 0, 1); $aattr = getQuestionAttributeValues($qqid, substr($_POST['id'], 0, 1)); $field = substr($_POST['id'], 1); @@ -655,7 +655,8 @@ function graph() $aData['success'] = 0; } - $this->_renderWrappedTemplate('export', 'statistics_graph_view', $aData); + //$this->_renderWrappedTemplate('export', 'statistics_graph_view', $aData); + $this->getController()->render('export/statistics_graph_view', $aData); } /** diff --git a/application/helpers/admin/statistics_helper.php b/application/helpers/admin/statistics_helper.php index c5a840b5d5e..b15e79f74f4 100644 --- a/application/helpers/admin/statistics_helper.php +++ b/application/helpers/admin/statistics_helper.php @@ -156,11 +156,11 @@ function createChart($qid, $sid, $type, $lbl, $gdata, $grawdata, $cache) else { // this block is to remove the items with value == 0 - // and an unelegant way to remove comments from List with Comments questions + // and an inelegant way to remove comments from List with Comments questions $i = 0; while (isset ($gdata[$i])) { - if ($gdata[$i] == 0 || ($qtype == "O" && substr($lbl[$i],0,strlen($statlang->gT("Comments")))==$statlang->gT("Comments"))) + if ($gdata[$i] == 0 || ($type == "O" && substr($lbl[$i],0,strlen($statlang->gT("Comments")))==$statlang->gT("Comments"))) { array_splice ($gdata, $i, 1); array_splice ($lbl, $i, 1); @@ -3418,7 +3418,7 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, break; case 'html': - $statisticsoutput .= "" + $statisticsoutput .= "\n" .""; return $statisticsoutput; diff --git a/application/views/admin/export/statistics_view.php b/application/views/admin/export/statistics_view.php index d149495a83e..35afdc4bc30 100644 --- a/application/views/admin/export/statistics_view.php +++ b/application/views/admin/export/statistics_view.php @@ -6,7 +6,9 @@ exit; } ?> - +
eT("General filters"); ?>
diff --git a/scripts/admin/statistics.js b/scripts/admin/statistics.js index 4ea8634a654..dd278e75c35 100644 --- a/scripts/admin/statistics.js +++ b/scripts/admin/statistics.js @@ -1,71 +1,71 @@ $(document).ready(function(){ $('#usegraph').click( function(){ if ($('#grapherror').length>0) - { + { $('#grapherror').show(); $('#usegraph').attr('checked',false); } }) $('#viewsummaryall').click( function(){ if ($('#viewsummaryall').attr('checked')==true) - { + { $('#filterchoices input[type=checkbox]').attr('checked', true); } else { $('#filterchoices input[type=checkbox]').attr('checked', false); - + } }) $('#hidefilter').click( function(){ $('#filterchoices').hide(); $('#filterchoice_state').val('1'); - $('#vertical_slide2').hide(); + $('#vertical_slide2').hide(); }) $('#showfilter').click( function(){ $('#filterchoices').show(); $('#filterchoice_state').val(''); - $('#vertical_slide2').show(); + $('#vertical_slide2').show(); }) - + if (typeof aGMapData == "object") { for (var i in aGMapData) { gMapInit("statisticsmap_" + i, aGMapData[i]); - } + } } - + if (typeof aStatData == "object") { for (var i in aStatData) { statInit(aStatData[i]); } } - + $(".stats-hidegraph").click (function () { - + var id = statGetId(this.parentNode); if (!id) { return; } - - $("#statzone_" + id).html(getWaiter()); + + $("#statzone_" + id).html(getWaiter()); graphQuery(id, 'hidegraph', function (res) { if (!res) { ajaxError(); return; } - + data = JSON.parse(res); - + if (!data || !data.ok) { ajaxError(); return; } - + isWaiting[id] = false; aStatData[id].sg = false; statInit(aStatData[id]); -}); + }); }); $(".stats-showgraph").click(function () @@ -74,7 +74,7 @@ $(document).ready(function(){ if (!id) { return; } - + $("#statzone_" + id).html(getWaiter()).show(); graphQuery(id, 'showgraph', function (res) { if (!res) { @@ -82,101 +82,101 @@ $(document).ready(function(){ return; } data = JSON.parse(res); - + if (!data || !data.ok || !data.chartdata) { ajaxError(); return; } - + isWaiting[id] = false; aStatData[id].sg = true; statInit(aStatData[id]); - + $("#statzone_" + id).append(""); - + if (aStatData[id].sm) { if (!data.mapdata) { ajaxError(); return; } - - $("#statzone_" + id).append("
"); + + $("#statzone_" + id).append("
"); gMapInit('statisticsmap_' + id, data.mapdata); } - + $("#statzone_" + id + " .wait").remove(); - + }); }); - + $(".stats-hidemap").click (function () { var id = statGetId(this.parentNode); if (!id) { return; } - + $("#statzone_" + id + ">div").replaceWith(getWaiter()); - + graphQuery(id, 'hidemap', function (res) { if (!res) { ajaxError(); return; } - + data = JSON.parse(res); - + if (!data || !data.ok) { ajaxError(); return; } - + isWaiting[id] = false; aStatData[id].sm = false; statInit(aStatData[id]); - + $("#statzone_" + id + " .wait").remove(); }); }); - + $(".stats-showmap").click(function () { var id = statGetId(this.parentNode); if (!id) { return; } - + $("#statzone_" + id).append(getWaiter()); - + graphQuery(id, 'showmap', function (res) { if (!res) { ajaxError(); return; } - + data = JSON.parse(res); - + if (!data || !data.ok || !data.mapdata) { ajaxError(); return; } - + isWaiting[id] = false; aStatData[id].sm = true; statInit(aStatData[id]); - + $("#statzone_" + id + " .wait").remove(); $("#statzone_" + id).append("
"); - + gMapInit('statisticsmap_' + id, data.mapdata); }); }); - + $(".stats-showbar").click(function () { changeGraphType('showbar', this.parentNode); }); - + $(".stats-showpie").click(function () { changeGraphType('showpie', this.parentNode); @@ -193,13 +193,13 @@ function getWaiter() function graphQuery (id, cmd, success) { $.ajax({ type: "POST", - url: site_url + '/admin/statistics/graph', + url: graphUrl, data: { 'id': id, - 'cmd': cmd, + 'cmd': cmd, }, success: success, - error: function (res) + error: function (res) { ajaxError(); } @@ -220,12 +220,12 @@ function showhidefilters(value) { } function selectCheckboxes(Div, CheckBoxName, Button) -{ +{ var aDiv = document.getElementById(Div); var nInput = aDiv.getElementsByTagName("input"); var Value = document.getElementById(Button).checked; //alert(Value); - + for(var i = 0; i < nInput.length; i++) { if(nInput[i].getAttribute("name")==CheckBoxName) @@ -238,54 +238,54 @@ function nographs() } function gMapInit(id, data) -{ - if (!data || !data["coord"] || !data["zoom"] || +{ + if (!data || !data["coord"] || !data["zoom"] || !data.width || !data.height || typeof google == "undefined") { return; } - + $("#" + id).width(data.width); $("#" + id).height(data.height); - + var latlng; if (data["coord"].length > 0) { var c = data["coord"][0].split(" "); latlng = new google.maps.LatLng(parseFloat(c[0]), parseFloat(c[1])); - } else { - latlng = new google.maps.LatLng(0.1, 0.1); + } else { + latlng = new google.maps.LatLng(0.1, 0.1); } - + var myOptions = { zoom: parseFloat(data["zoom"]), center: latlng, mapTypeId: google.maps.MapTypeId.ROADMAP }; - + var map = new google.maps.Map(document.getElementById(id), myOptions); for (var i = 0; i < data["coord"].length; ++i) { var c = data["coord"][i].split(" "); - - var marker = new google.maps.Marker({ - position: new google.maps.LatLng(parseFloat(c[0]), parseFloat(c[1])), - map: map - }); + + var marker = new google.maps.Marker({ + position: new google.maps.LatLng(parseFloat(c[0]), parseFloat(c[1])), + map: map + }); } } function statGetId(elem) { var id = $(elem).attr("id"); - + if (id.substr(0, 6) == "stats_") { return id.substr(6, id.length); } - - if (id == '' || isWaiting[id]) { + + if (id == '' || isWaiting[id]) { return false; - } - + } + isWaiting[id] = true; return id; } @@ -293,17 +293,17 @@ function statGetId(elem) function statInit(data) { var elem = $("#stats_" + data.id); - + elem.children().hide(); - + if (data.sg) { $("#statzone_" + data.id).show(); $(".stats-hidegraph", elem).show(); - + if (data.ap) { $(".stats-" + (data.sp ? "showbar" : "showpie"), elem).show(); } - + if (data.am) { $(".stats-" + (data.sm ? "hidemap" : "showmap"), elem).show(); } @@ -320,30 +320,30 @@ function changeGraphType (cmd, id) { if (!id) { return; } - + if (!aStatData[id].ap) { return; } - + $("#statzone_" + id).append(getWaiter()); - + graphQuery(id, cmd, function (res) { if (!res) { ajaxError(); return; } - + data = JSON.parse(res); - + if (!data || !data.ok || !data.chartdata) { ajaxError(); return; } - + isWaiting[id] = false; aStatData[id].sp = (cmd == 'showpie'); statInit(aStatData[id]); - + $("#statzone_" + id + " .wait").remove(); $("#statzone_" + id + ">img:first").attr("src", temppath +"/"+data.chartdata); }); From 2ba0b519de929fcba4e3bd8c4c2f98d90469db08 Mon Sep 17 00:00:00 2001 From: jcleeland Date: Fri, 20 Jul 2012 22:44:38 +1000 Subject: [PATCH 02/71] Fixed issue #6354 - typo. De-typo-ified (thx sammousa :-)) --- application/controllers/admin/participantsaction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/controllers/admin/participantsaction.php b/application/controllers/admin/participantsaction.php index ce1135117aa..13021e348f1 100644 --- a/application/controllers/admin/participantsaction.php +++ b/application/controllers/admin/participantsaction.php @@ -521,7 +521,7 @@ function exporttocsvcount() else // If no search criteria it will simply return the number of participants { $iUserID = Yii::app()->session['loginID']; - $query = Particiapnts::getParticipantsOwner($iUserID); + $query = Participants::getParticipantsOwner($iUserID); } echo sprintf($clang->gT("Export %s participant(s) to CSV"), count($query)); From fc8e2a399b0f7086698e63c3301ac35977e516b4 Mon Sep 17 00:00:00 2001 From: jcleeland Date: Fri, 20 Jul 2012 23:17:33 +1000 Subject: [PATCH 03/71] Fixed issue: statistics script not able to build query selector for array(column) question type --- application/views/admin/export/statistics_view.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/views/admin/export/statistics_view.php b/application/views/admin/export/statistics_view.php index 35afdc4bc30..98607dab8b2 100644 --- a/application/views/admin/export/statistics_view.php +++ b/application/views/admin/export/statistics_view.php @@ -899,7 +899,7 @@ * - sortorder * - language */ - $fresult = $fresults[$key1][$key]; + $fresult = $fresults[$key1]; //for debugging only: //echo $fquery; From 3244e3810e8e3c988e9080c3c6c6e9666b6f7a88 Mon Sep 17 00:00:00 2001 From: jcleeland Date: Fri, 20 Jul 2012 23:35:40 +1000 Subject: [PATCH 04/71] Fixed issue: numerical calculations in statistics were not working --- application/helpers/admin/statistics_helper.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/helpers/admin/statistics_helper.php b/application/helpers/admin/statistics_helper.php index b15e79f74f4..2416ebd94fb 100644 --- a/application/helpers/admin/statistics_helper.php +++ b/application/helpers/admin/statistics_helper.php @@ -1369,10 +1369,10 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, if ($sql != "NULL") {$query .= " AND $sql";} //execute query - $result=Yii::app()->db->createCommand($query)->query(); + $result=Yii::app()->db->createCommand($query)->queryAll(); //get calculated data - foreach ($nresult->readAll() as $row) + foreach ($result as $row) { //put translation of mean and calculated data into $showem array $showem[]=array($statlang->gT("Sum"), $row['sum']); @@ -1540,7 +1540,7 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $query = $querystarter . " ORDER BY ".Yii::app()->db->quoteColumnName($fieldname)."*1"; $result = Yii::app()->db->createCommand($query)->limit(1, $q3c); - foreach ($result->readAll() as $row) + foreach ($result->queryAll() as $row) { $showem[]=array($statlang->gT("3rd quartile (Q3)"), $row[$fieldname]); } From d1a5d5255163914ad2d1b802a15f660bc3e6395d Mon Sep 17 00:00:00 2001 From: Thomas White Date: Fri, 20 Jul 2012 16:11:41 -0400 Subject: [PATCH 05/71] Fixed issue #06349: condition does not work while using slider with stars Dev this fixes bug from 1.92, but stars do not display at all in 2.0, so there is an additional bug there. --- application/helpers/qanda_helper.php | 1 + 1 file changed, 1 insertion(+) diff --git a/application/helpers/qanda_helper.php b/application/helpers/qanda_helper.php index b1cbd363000..01c6643bc80 100644 --- a/application/helpers/qanda_helper.php +++ b/application/helpers/qanda_helper.php @@ -1015,6 +1015,7 @@ function do_5pointchoice($ia) $('#$id input').each(function(){ $(this).removeAttr('checked');}); $('#answer$ia[1]'+value).attr('checked','checked'); } + checkconditions(value,'$ia[1]','radio'); } }); From 22d3f57064981238a07fc4ee7ddbb5c540dcd1ab Mon Sep 17 00:00:00 2001 From: Denis Chenu Date: Sat, 21 Jul 2012 14:05:29 +0200 Subject: [PATCH 06/71] Fixed issue : 5 point star rating breaked in Yii Dev: move js and css in good directory --- application/helpers/qanda_helper.php | 4 +- scripts/admin/rating/delete.gif | Bin 752 -> 0 bytes scripts/admin/rating/documentation.css | 80 - scripts/admin/rating/documentation.html | 1169 ---- scripts/admin/rating/documentation.js | 15 - scripts/admin/rating/index.html | 19 - scripts/admin/rating/jquery.MetaData.js | 121 - scripts/admin/rating/jquery.js | 6001 ----------------- scripts/admin/rating/jquery.rating.pack.js | 11 - scripts/{admin/rating => }/jquery.rating.js | 0 .../jquery.rating.css | 12 +- .../rating-img}/star.gif | Bin .../rating-img}/star1.gif | Bin .../rating-img}/star2.gif | Bin .../rating-img}/star3.gif | Bin .../rating-img}/star4.gif | Bin .../rating-img}/star5.gif | Bin 17 files changed, 8 insertions(+), 7424 deletions(-) delete mode 100644 scripts/admin/rating/delete.gif delete mode 100644 scripts/admin/rating/documentation.css delete mode 100644 scripts/admin/rating/documentation.html delete mode 100644 scripts/admin/rating/documentation.js delete mode 100644 scripts/admin/rating/index.html delete mode 100644 scripts/admin/rating/jquery.MetaData.js delete mode 100644 scripts/admin/rating/jquery.js delete mode 100644 scripts/admin/rating/jquery.rating.pack.js rename scripts/{admin/rating => }/jquery.rating.js (100%) rename {scripts/admin/rating => styles-public}/jquery.rating.css (68%) rename {scripts/admin/rating => styles-public/rating-img}/star.gif (100%) rename {scripts/admin/rating => styles-public/rating-img}/star1.gif (100%) rename {scripts/admin/rating => styles-public/rating-img}/star2.gif (100%) rename {scripts/admin/rating => styles-public/rating-img}/star3.gif (100%) rename {scripts/admin/rating => styles-public/rating-img}/star4.gif (100%) rename {scripts/admin/rating => styles-public/rating-img}/star5.gif (100%) diff --git a/application/helpers/qanda_helper.php b/application/helpers/qanda_helper.php index 01c6643bc80..36df63dab78 100644 --- a/application/helpers/qanda_helper.php +++ b/application/helpers/qanda_helper.php @@ -989,8 +989,8 @@ function do_5pointchoice($ia) $answer .= "\ngetConfig('surveyID')][$ia[1]]."\" />\n"; $inputnames[]=$ia[1]; if($aQuestionAttributes['slider_rating']==1){ - header_includes('/admin/scripts/rating/jquery.rating.css','css'); - header_includes('/admin/scripts/rating/jquery.rating.js','js'); + header_includes('jquery.rating.css','css'); + header_includes('jquery.rating.js','js'); $answer.=" - - - - - - - - - - - - - -
-
- jQuery Plugins: - Multiple File Upload, - Star Rating, - NEW: - CKEditor - (old: FCKEditor), - Codepress, - XML to JSON - - - - - - -
- -
- - - -
- - - - - - - -
-

What is this?

-

- The Star Rating Plugin is a plugin - for the jQuery Javascript library that creates a non-obstrusive - star rating control based on a set of radio input boxes. -

- -

What does it do?

-
    -
  • - It turns a collection of radio boxes into a neat star-rating control. -
  • -
  • - It creates the interface based on standard form elements, which means the - basic functionality will still be available even if Javascript is disabled. -
  • -
  • - NEW (12-Mar-08): - In read only mode (using the 'readOnly' option or disabled property), the plugin is a neat way of - displaying star-like values without any additional code -
  • -
- -

How do I use it?

-

- Just add the star class to your radio boxes -

- - - - - - -
-
<input name="star1" type="radio" class="star"/>
-<input name="star1" type="radio" class="star"/>
-<input name="star1" type="radio" class="star"/>
-<input name="star1" type="radio" class="star"/>
-<input name="star1" type="radio" class="star"/>
-
» - - - - - -
- -

- Use the checked property to specify the initial/default value of the control -

- - - - - - -
-
<input name="star2" type="radio" class="star"/>
-<input name="star2" type="radio" class="star"/>
-<input name="star2" type="radio" class="star" checked="checked"/>
-<input name="star2" type="radio" class="star"/>
-<input name="star2" type="radio" class="star"/>
-
» - - - - - -
- -

- Use the disabled property to use a control for display purposes only -

- - - - - - -
-
<input name="star3" type="radio" class="star" disabled="disabled"/>
-<input name="star3" type="radio" class="star" disabled="disabled"/>
-<input name="star3" type="radio" class="star" disabled="disabled" checked="checked"/>
-<input name="star3" type="radio" class="star" disabled="disabled"/>
-<input name="star3" type="radio" class="star" disabled="disabled"/>
-
» - - - - - -
- -

What about split stars and 'half ratings'???

-

- Use metadata plugin to pass advanced settings to the plugin via the class property. -

- - - - - - -
-
<input name="adv1" type="radio" class="star {split:4}"/>
-<input name="adv1" type="radio" class="star {split:4}"/>
-<input name="adv1" type="radio" class="star {split:4}"/>
-<input name="adv1" type="radio" class="star {split:4}"/>
-<input name="adv1" type="radio" class="star {split:4}" checked="checked"/>
-<input name="adv1" type="radio" class="star {split:4}"/>
-<input name="adv1" type="radio" class="star {split:4}"/>
-<input name="adv1" type="radio" class="star {split:4}"/>
-
» - - - - - - - - -
- -

- Use custom selector -

- - - - - - -
- -
$(function(){ // wait for document to load
- $('input.wow').rating();
-});
-
<input name="adv2" type="radio" class="wow {split:4}"/>
-<input name="adv2" type="radio" class="wow {split:4}"/>
-<input name="adv2" type="radio" class="wow {split:4}"/>
-<input name="adv2" type="radio" class="wow {split:4}"/>
-<input name="adv2" type="radio" class="wow {split:4}" checked="checked"/>
-<input name="adv2" type="radio" class="wow {split:4}"/>
-<input name="adv2" type="radio" class="wow {split:4}"/>
-<input name="adv2" type="radio" class="wow {split:4}"/>
-
» - - - - - - - - -
-
- -
-

Test Suite

- - - -
 
-
-Test 1 - A blank form - - - - - -
- - - - - -
-
- Rating 1: - (N/M/Y) - - - -
-
-
- Rating 2: - (10 - 50) - - - - - -
-
-
- Rating 3: - (1 - 7) - - - - - - - -
-
-
- Rating 4: - (1 - 5) - - - - - -
-
-
- Rating 5: - (1 - 5) - - - - - -
-
-
- Rating 6 (readonly): - (1 - 5) - - - - - -
-
-
  -   - Test results:

-
- Results will be displayed here -
-
-
- -
 
 
- -
-Test 2 - With defaults ('checked') - - - - - -
- - - - - -
-
- Rating 1: - (N/M/Y, default M) -
-
- - - -
-
- Rating 2: - (10 - 50, default 30) -
-
- - - - - -
-
- Rating 3: - (1 - 7, default 4) -
-
- - - - - - - -
-
-
- Rating 4: - (1 - 5, default 1) -
-
- - - - - -
-
- Rating 5: - (1 - 5, default 5) -
-
- - - - - -
-
- Rating 6 (readonly): - (1 - 5, default 3) -
-
- - - - - -
-
-
  -   - Test results:

-
- Results will be displayed here -
-
-
- -
 
 
- -
- -Test 3-A - With callback - - - - - -
-
- Rating 1: - (1 - 3, default 2) - - - -
-
-
$('.auto-submit-star').rating({
-  callback: function(value, link){
-    alert(value);
-  }
-});
-
-
  -   - Test results:

-
- Results will be displayed here -
-
-
- -
 
 
- - -
-Test 3-B - With hover effects - - - - - -
-
- Rating 1: - (1 - 3, default 2) -
- - - - - - Hover tips will appear in here -
-
-
-
$('.hover-star').rating({
-  focus: function(value, link){
-    var tip = $('#hover-test');
-    tip[0].data = tip[0].data || tip.html();
-    tip.html(link.title || 'value: '+value);
-  },
-  blur: function(value, link){
-    var tip = $('#hover-test');
-    $('#hover-test').html(tip[0].data || '');
-  }
-});
-
-
  -   - Test results:

-
- Results will be displayed here -
-
-
- -
 
 
- -
-Test 4 - Half Stars and Split Stars - - - - - -
- - - - - -
-
- Rating 1: - (N/M/Y/?) -
<input class="star {half:true}"
- - - - -
-
-
- Rating 2: - (10 - 60) -
<input class="star {split:3}"
- - - - - - -
-
-
- Rating 3: - (0-5.0, default 3.5) -
<input class="star {split:2}"
- - - - - - - - - - -
-
-
- Rating 4: - (1-6, default 5) -
<input class="star {split:2}"
- - - - - - -
-
-
- Rating 5: - (1-20, default 11) -
<input class="star {split:4}"
- - - - - - - - - - - - - - - - - - - - -
-
-
- Rating 6 (readonly): - (1-20, default 13) -
<input class="star {split:4}"
- - - - - - - - - - - - - - - - - - - - -
-
-
  -   - Test results:

-
- Results will be displayed here -
-
-
-
- -
-

API

-

NEW to v3

- -

API methods can be invoked this this:

-
$(selector).rating(
- 'method', // method name
- [] // method arguments (not required)
-);
- -


- -

$().rating('select', index / value)

-

- Use this method to set the value (and display) of the star rating control - via javascript. It accepts the index of the star you want to select (0 based) - or its value (which must be passed as a string. -

-

- Example: (values A/B/C/D/E) -

-
- - - - - - - -
- By index: - - - - - - eg.: $('input').rating('select',3) -
- By value: - - - - - - eg.: $('input').rating('select','C') -
- -


- -

$().rating('readOnly', true / false)

-

- Use this method to set the value (and display) of the star rating control - via javascript. It accepts the index of the star you want to select (0 based) - or its value (which must be passed as a string. -

-

- Example: (values 1,2,3...10) -

-
- - - - - - - - - - - - -
- - eg.: $('input').rating('readOnly',true) -
- - eg.: $('input').rating('readOnly',false) or simply $('input').rating('readOnly'); -
- -


- -

$().rating('disable') / $().rating('enable')

-

- These methods bahve almost exactly as the readOnly method, however - they also control whether or not the select value is submitted with - the form. -

-

- Example: (values 1,2,3...10) -

-
- - - - - - - - - - - - -
- - eg.: $('input').rating('disable') -
- - eg.: $('input').rating('enable'); -
-
- -
-

Database Integration

-

- I'm sorry to say that for the time being, it is up to you - to create the server-side code that will - process the form submission, store it somewhere (like a database) and do stuff with it - - such as displaying averages and stop users from voting more than once. -

-

- However, here are a few alternatives if you don't feel - like getting down and dirty with some good old coding: -
http://www.yvoschaap.com/index.php/weblog/css_star_rater_ajax_version/ -
-
and -
part 1: http://www.komodomedia.com/blog/2005/08/creating-a-star-rater-using-css/ -
part 2: http://slim.climaxdesigns.com/tutorial.php?section=slim&id=2 -
part 3: http://slim.climaxdesigns.com/tutorial.php?section=slim&id=3 -
part 4: http://slim.climaxdesigns.com/tutorial.php?section=slim&id=9 -

-
- -
-

Background Information

-

As far as I know, this is how it goes...

-
    -
  • It all started with Will Stuckey's jQuery Star Rating Super Interface!
  • -
  • The original then became the inspiration for Ritesh Agrawal's Simple Star Rating System, - which allows for a GMail like star/un-star toggle.
  • -
  • This was followed by several spin-offs... (one of which is the Half-star rating plugin)
  • -
  • Then someone at PHPLetter.com modified the plugin to overcome the issues - then plugin was now based on standard form elements, meaning - the interface would still work with Javascript disabled making it beautifully downgradable.
  • -
  • Then I came along and noticed a fundamental flaw with the latter: there could only - be one star rating control per page. The rest of the story is what you will see below...
  • -
  • NEW (12-Mar-08): Then Keith Wood added some very nice functionality to the plugin: - option to disable the cancel button, option to make the plugin readOnly and ability to accept any value (other than whole numbers)
  • -
  • NEW (20-Mar-08): Now supports half-star, third-star, quater-star, etc... Not additional code required. No additional images required.
  • -
  • NEW (31-Mar-08): Two new events, hover/blur (arguments: [value, linkElement])
  • -
-
- -
-

Download

-

- This project (and all related files) can also be accessed via its - Google Code Project Page. -

- - - - - - - - - - - - - - - - - -
Full Package: - - - v3.13 - star-rating.zip - -
-
- Stay up-to-date! - - Major updates will be announced on - Twitter: - @fyneworks - -
-
Core Files: - These are the individual required files (already included in the zip package above) - -
jQuery: - jquery-latest.js (see jQuery.com) -
- -

Related Downloads

- - - - - -
Related: - Metadata plugin - Used to retrieve inline configuration from class variable -
- Form plugin - Used to submit forms via ajax -
- -

SVN Repository

-

- If you're a major geek or if you really really want to stay up-to-date with - with future updates of this plugin, go ahead and plug yourself to the - SVN Repository - on the official - Google Code Project Page. -

- - - - - - - - - -
SVN Checkout: - - SVN Checkout Instructions -
Browse Online: - - Browse Source -
- -

Alternative Download - From this website

-

- Just in case it's the end of the world and the Google Code site becomes unavailable, - the project files can also be downloaded form this site. -
- However, please note that this site is updated periodically whereas the Google Code - project is kept up-to-date almost instantaneously. If you'd like the very latest - version of this plugin - you are advised to use the links above and download the files from Google Code - - this will ensure the files you download have the very latest features and bug fixes. -

- - - - - - - - - - - - - - - - - -
Full Package: - - v3.13 - star-rating.zip -
-
- Stay up-to-date! - - Major updates will be announced on - Twitter: - @fyneworks - -
-
Core Files: - These are the individual required files (already included in the zip package above) - -
jQuery: - jquery-latest.js (see jQuery.com) -
- -
- -
- -

Support

-

- Quick Support Links: Help me! - | Report a bug - | Suggest new feature - -

-

- Support for this plugin is available through the jQuery Mailing List. - This is a very active list to which many jQuery developers and users subscribe. -
- Access to the jQuery Mailing List is also available through - Nabble Forums - and the - jQuery Google Group. -

-

- WARNING: - Support will not be provided via the jQuery Plugins - website. - If you need help, please direct your questions to the - jQuery Mailing List - or - report an issue - on the official - Google Code Project Page. -

- -

Official Links

- - -

Credit

-
    -
  • Diego A. - Author, London SEO Consultant
  • -
  • Keith Wood - The brain behind v2.1
  • -
  • Dean Edwards - Author of JS Packer used to compress the plugin
  • -
  • Will Stuckey, Ritesh Agrawal and everyone else who worked in the previous versions of the plugin - I'm not so good with research...
  • -
-
- - - - - - - -
-

Attribute this work

-
- - - - - - - - - -
Attribution link:© Fyneworks.com
HTML Code: - -
-
-

License Info

-
- - - - - - - - -
- Star Rating Plugin - by Fyneworks.com - is licensed under the - MIT License and the - GPL License. - Creative Commons License
- -
-
-
-
- -
-
-
- - - - - - - - - diff --git a/scripts/admin/rating/documentation.js b/scripts/admin/rating/documentation.js deleted file mode 100644 index 7d6fb907f16..00000000000 --- a/scripts/admin/rating/documentation.js +++ /dev/null @@ -1,15 +0,0 @@ -// chili-1.7.packed.ks -eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('8={3b:"1.6",2o:"1B.1Y,1B.23,1B.2e",2i:"",2H:1a,12:"",2C:1a,Z:"",2a:\'$$\',R:"&#F;",1j:"&#F;&#F;&#F;&#F;",1f:"&#F;<1W/>",3c:5(){9 $(y).39("1k")[0]},I:{},N:{}};(5($){$(5(){5 1J(l,a){5 2I(A,h){4 3=(1v h.3=="1h")?h.3:h.3.1w;k.1m({A:A,3:"("+3+")",u:1+(3.c(/\\\\./g,"%").c(/\\[.*?\\]/g,"%").3a(/\\((?!\\?)/g)||[]).u,z:(h.z)?h.z:8.2a})}5 2z(){4 1E=0;4 1x=x 2A;Q(4 i=0;i\';8.N[X]=1H;7($.31.34){4 W=J.1L(Y);4 $W=$(W);$("2d").1O($W)}v{$("2d").1O(Y)}}}5 1q(e,a){4 l=e&&e.1g&&e.1g[0]&&e.1g[0].37;7(!l)l="";l=l.c(/\\r\\n?/g,"\\n");4 C=1J(l,a);7(8.1j){C=C.c(/\\t/g,8.1j)}7(8.1f){C=C.c(/\\n/g,8.1f)}$(e).38(c)}5 1o(q,13){4 1l={12:8.12,2x:q+".1d",Z:8.Z,2w:q+".2u"};4 B;7(13&&1v 13=="2l")B=$.35(1l,13);v B=1l;9{a:B.12+B.2x,1p:B.Z+B.2w}}7($.2q)$.2q({36:"2l.15"});4 2n=x 1u("\\\\b"+8.2i+"\\\\b","2j");4 1e=[];$(8.2o).2D(5(){4 e=y;4 1n=$(e).3i("V");7(!1n){9}4 q=$.3u(1n.c(2n,""));7(\'\'!=q){1e.1m(e);4 f=1o(q,e.15);7(8.2H||e.15){7(!8.N[f.a]){1D{8.N[f.a]=1H;$.3v(f.a,5(M){M.f=f.a;8.I[f.a]=M;7(8.2C){2B(f.1p)}$("."+q).2D(5(){4 f=1o(q,y.15);7(M.f==f.a){1q(y,M)}})})}1I(3s){3t("a 3w Q: "+q+\'@\'+3z)}}}v{4 a=8.I[f.a];7(a){1q(e,a)}}}});7(J.1i&&J.1i.29){5 22(p){7(\'\'==p){9""}1z{4 16=(x 3A()).2k()}19(p.3x(16)>-1);p=p.c(/\\<1W[^>]*?\\>/3y,16);4 e=J.1L(\'<1k>\');e.3l=p;p=e.3m.c(x 1u(16,"g"),\'\\r\\n\');9 p}4 T="";4 18=1G;$(1e).3j().G("1k").U("2c",5(){18=y}).U("1M",5(){7(18==y)T=J.1i.29().3k});$("3n").U("3q",5(){7(\'\'!=T){2p.3r.3o(\'3p\',22(T));2V.2R=1a}}).U("2c",5(){T=""}).U("1M",5(){18=1G})}})})(1Z);8.I["1Y.1d"]={k:{2M:{3:/\\/\\*[^*]*\\*+(?:[^\\/][^*]*\\*+)*\\//},25:{3:/\\ + +   + + +   +


+
+
eT("Attribute management"); ?>

diff --git a/scripts/admin/attributeControl.js b/scripts/admin/attributeControl.js index 861887eb070..36ab0f31bf5 100644 --- a/scripts/admin/attributeControl.js +++ b/scripts/admin/attributeControl.js @@ -76,5 +76,16 @@ function ajaxSave(rowid) { { state = "FALSE"; } - $.post(editAttributeUrl, { id: rowid, visible: state, oper : 'edit' } ); + $.post(editAttributeUrl, { + id: rowid, + visible: state, + oper : 'edit' + }, + function (data) { + $("p#flashmessagetext").html(data); + $("#flashinfo").css("display", ""); + $("#flashinfo").css("opacity", 0); + $("#flashinfo").animate({opacity: 1.0}, 1500).fadeOut("slow"); + } + ); } \ No newline at end of file From 7b775f8408f3f76d249ca938c17f1ac79886c649 Mon Sep 17 00:00:00 2001 From: jcleeland Date: Sun, 22 Jul 2012 11:51:04 +1000 Subject: [PATCH 08/71] Fixed issue #6363 Statistics repsonse filters don't display speaker icon, show question text twice New feature Statistics output screen cleaned up, placed inside collapsible divs --- .../views/admin/export/statistics_view.php | 263 ++++++++++-------- scripts/admin/statistics.js | 15 +- styles/gringegreen/adminstyle.css | 13 +- 3 files changed, 168 insertions(+), 123 deletions(-) diff --git a/application/views/admin/export/statistics_view.php b/application/views/admin/export/statistics_view.php index 98607dab8b2..b22252b6c82 100644 --- a/application/views/admin/export/statistics_view.php +++ b/application/views/admin/export/statistics_view.php @@ -10,131 +10,138 @@ var graphUrl="getController()->createUrl("admin/statistics/graph"); ?>";
-
eT("General filters"); ?>
-
- '.$clang->gT('You do not have the GD Library installed. Showing charts requires the GD library to function properly.'); - $error .= '
'.$clang->gT('visit http://us2.php.net/manual/en/ref.image.php for more information').'
'; - } - else if (!function_exists("imageftbbox")) { - $error .= '
'.$clang->gT('You do not have the Freetype Library installed. Showing charts requires the Freetype library to function properly.'); +
+
<?php $clang->eT("Maximize"); ?><?php $clang->eT("Minimize"); ?>
+ eT("General filters"); ?> +
+ + - -

- - ', '_top')" /> -

- +
<?php $clang->eT("Maximize"); ?><?php $clang->eT("Minimize"); ?>
eT("Response filters"); ?>
- + + - +
@@ -183,7 +190,8 @@ + || $flt[2]=='G' || $flt[2]=='I' || $flt[2]=='O' || $flt[2]=='Y' || $flt[2]=='!') + { ?> /> +
@@ -1251,22 +1260,36 @@

-
+
+ +
+
+
<?php $clang->eT("Maximize"); ?><?php $clang->eT("Minimize"); ?>
+ eT("Statistics"); ?> +
+ +
+
lang; - $sImageURL = Yii::app()->getConfig("imageurl"); + $sImageURL = Yii::app()->getConfig('adminimageurl'); if(!isset($maxchars)) { $maxchars = 100; } $htmlhinttext=str_replace("'",''',$hinttext); //the string is already HTML except for single quotes so we just replace these only - $jshinttext=javascriptEscape($hinttext,true,true); + $jshinttext=javascriptEscape($hinttext,true,true); //Build a javascript safe version of the string if(strlen($hinttext) > ($maxchars)) { @@ -1275,15 +1298,15 @@ function _showSpeaker($hinttext) $shortstring = htmlspecialchars(mb_strcut(html_entity_decode($shortstring,ENT_QUOTES,'UTF-8'), 0, $maxchars, 'UTF-8')); //output with hoover effect - $reshtml= "gT("Question","js").": $jshinttext')\">" ." \"$shortstring...\" " - ."$htmlhinttextgT("Question","js").": $jshinttext')\" />"; } else { - $reshtml= " \"$htmlhinttext\""; + $reshtml= " \"$htmlhinttext\""; } return $reshtml; } diff --git a/scripts/admin/statistics.js b/scripts/admin/statistics.js index dd278e75c35..76692f3ea5b 100644 --- a/scripts/admin/statistics.js +++ b/scripts/admin/statistics.js @@ -18,16 +18,29 @@ $(document).ready(function(){ } }) $('#hidefilter').click( function(){ + $('#statisticsresponsefilters').hide(1000); $('#filterchoices').hide(); $('#filterchoice_state').val('1'); $('#vertical_slide2').hide(); }) $('#showfilter').click( function(){ + $('#statisticsresponsefilters').show(1000); $('#filterchoices').show(); $('#filterchoice_state').val(''); $('#vertical_slide2').show(); }) - + $('#hidegfilter').click( function(){ + $('#statisticsgeneralfilters').hide(1000); + }) + $('#showgfilter').click( function(){ + $('#statisticsgeneralfilters').show(1000); + }) + $('#hidesfilter').click( function(){ + $('#statisticsoutput').hide(1000); + }) + $('#showsfilter').click( function(){ + $('#statisticsoutput').show(1000); + }) if (typeof aGMapData == "object") { for (var i in aGMapData) { gMapInit("statisticsmap_" + i, aGMapData[i]); diff --git a/styles/gringegreen/adminstyle.css b/styles/gringegreen/adminstyle.css index 6555d1261d3..df68966b0f2 100644 --- a/styles/gringegreen/adminstyle.css +++ b/styles/gringegreen/adminstyle.css @@ -493,8 +493,17 @@ th.admincell { .header_statistics { height:21px; - padding:1px; - padding-left:42px; + padding:1px 8px 1px 15px; + margin-bottom: 0; +} +.statisticsfilters { + width: 99%; + border: 1px solid #85BD00; + margin-bottom: 20px; +} +.scrollheight_400 { + height: 400px; + overflow: auto; } .btnaddanswer, From 619c400aa9cd30542aaecc10cb09d0d1ef8262b6 Mon Sep 17 00:00:00 2001 From: jcleeland Date: Sun, 22 Jul 2012 11:57:07 +1000 Subject: [PATCH 09/71] Fixed issue #6363 updated blobblueish style for earlier fix --- styles/blobblueish/adminstyle.css | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/styles/blobblueish/adminstyle.css b/styles/blobblueish/adminstyle.css index f7447867208..cc42b035e98 100644 --- a/styles/blobblueish/adminstyle.css +++ b/styles/blobblueish/adminstyle.css @@ -487,8 +487,17 @@ th.admincell { .header_statistics { height:21px; - padding:1px; - padding-left:42px; + padding:1px 8px 1px 15px; + margin-bottom: 0; +} +.statisticsfilters { + width: 99%; + border: 1px solid #C0FFC0; + margin-bottom: 20px; +} +.scrollheight_400 { + height: 400px; + overflow: auto; } .btnaddanswer, From fbc70dc99c5664710c7189110c2141ad1222a948 Mon Sep 17 00:00:00 2001 From: jcleeland Date: Sun, 22 Jul 2012 12:11:07 +1000 Subject: [PATCH 10/71] Fixed issue #6359 - installations with postgres as database fail because of syntax error --- installer/sql/create-pgsql.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer/sql/create-pgsql.sql b/installer/sql/create-pgsql.sql index c10563f5e3c..6a35ce9fd6b 100644 --- a/installer/sql/create-pgsql.sql +++ b/installer/sql/create-pgsql.sql @@ -339,7 +339,7 @@ CREATE TABLE prefix_survey_links ( "survey_id" integer NOT NULL, "date_created" timestamp, "date_invited" timestamp, - "date_completed" timestamp + "date_completed" timestamp, CONSTRAINT prefix_survey_links_pkey PRIMARY KEY (participant_id,token_id,survey_id) ); From 3e0482123f112391acd66e4fda61ccfd676e1484 Mon Sep 17 00:00:00 2001 From: jcleeland Date: Sun, 22 Jul 2012 14:56:06 +1000 Subject: [PATCH 11/71] New feature: question save/save and close options - instead of just updating and closing, now choice is to save and keep editing, or to save and return to question view. My wife made me do it. --- application/controllers/admin/database.php | 6 +++++- .../survey/Question/editQuestion_view.php | 12 +++++++++--- scripts/admin/surveytoolbar.js | 19 ++++++++++++------- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/application/controllers/admin/database.php b/application/controllers/admin/database.php index 6f6507c5e42..df97a11c9ce 100644 --- a/application/controllers/admin/database.php +++ b/application/controllers/admin/database.php @@ -851,7 +851,11 @@ function index($sa = null) } else { - $this->getController()->redirect($this->getController()->createUrl('admin/survey/view/surveyid/'.$surveyid.'/gid/'.$gid.'/qid/'.$qid)); + if(Yii::app()->request->getPost('newpage') == "return") { + $this->getController()->redirect($this->getController()->createUrl('admin/question/editquestion/surveyid/'.$surveyid.'/gid/'.$gid.'/qid/'.$qid)); + } else { + $this->getController()->redirect($this->getController()->createUrl('admin/survey/view/surveyid/'.$surveyid.'/gid/'.$gid.'/qid/'.$qid)); + } } } diff --git a/application/views/admin/survey/Question/editQuestion_view.php b/application/views/admin/survey/Question/editQuestion_view.php index ad22ee4e7a3..be1481ffddc 100644 --- a/application/views/admin/survey/Question/editQuestion_view.php +++ b/application/views/admin/survey/Question/editQuestion_view.php @@ -14,6 +14,7 @@ eT("Edit question"); ?> +
@@ -32,7 +33,11 @@ ?>
');"> -
+
+

+ +

+
  • eT("Note: You MUST enter a new question code!"); ?> @@ -227,7 +232,6 @@

- @@ -244,8 +248,10 @@ else { ?> + -

+

+


diff --git a/scripts/admin/surveytoolbar.js b/scripts/admin/surveytoolbar.js index d19a699530b..405ad9ba84a 100644 --- a/scripts/admin/surveytoolbar.js +++ b/scripts/admin/surveytoolbar.js @@ -2,7 +2,7 @@ // based on TTabs from http://interface.eyecon.ro/ $(document).ready(function(){ - // Load the superfish menu + // Load the superfish menu $('ul.sf-menu').superfish({ speed:'fast' }); @@ -12,18 +12,18 @@ $(document).ready(function(){ { $(this).qtip({ style: { name: 'cream', - tip:true, - color:'#1D2D45', + tip:true, + color:'#1D2D45', border: { width: 1, radius: 5, color: '#EADF95'} - }, - position: { adjust: { + }, + position: { adjust: { screen: true, scroll:true }, corner: { target: 'topRight', - tooltip: 'bottomLeft'} + tooltip: 'bottomLeft'} }, show: {effect: { length:50}, delay:1000 @@ -33,5 +33,10 @@ $(document).ready(function(){ }); } - }); + }); + $(".saveandreturn").click(function() { + var form=$(this).parents('form:first'); //Get the parent form info + $("#newpage").val('return'); + form.submit(); + }); }); From 2b16a42be189559448769e8205c546f81d8b657e Mon Sep 17 00:00:00 2001 From: jcleeland Date: Sun, 22 Jul 2012 21:29:49 +1000 Subject: [PATCH 12/71] Fixed issue #6367 Participants database not importing from CSV even though CSV file in correct format --- application/controllers/admin/participantsaction.php | 4 +++- scripts/admin/displayParticipant.js | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/application/controllers/admin/participantsaction.php b/application/controllers/admin/participantsaction.php index 3c87014f038..61b7ba1ecbd 100644 --- a/application/controllers/admin/participantsaction.php +++ b/application/controllers/admin/participantsaction.php @@ -1417,6 +1417,7 @@ function uploadCSV() $imported = 0; $dupcount = 0; $overwritten = 0; + $dupreason="nameemail"; $duplicatelist = array(); $invalidemaillist = array(); $invalidformatlist = array(); @@ -1499,7 +1500,7 @@ function uploadCSV() $ignoredcolumns[] = $fieldname; } } - if ((!in_array('firstname', $firstline) || !in_array('lastname', $firstline) || !in_array('email', $firstline)) || !in_array('participant_id', $firstline)) + if ((!in_array('firstname', $firstline) && !in_array('lastname', $firstline) && !in_array('email', $firstline)) && !in_array('participant_id', $firstline)) { $recordcount = count($tokenlistarray); break; @@ -1507,6 +1508,7 @@ function uploadCSV() } else { // After looking at the first line, we now import the actual values $line = convertCSVRowToArray($buffer, $separator, '"'); + if (count($firstline) != count($line)) { $invalidformatlist[] = $recordcount; diff --git a/scripts/admin/displayParticipant.js b/scripts/admin/displayParticipant.js index 2c3edae279d..ad2af270d2c 100644 --- a/scripts/admin/displayParticipant.js +++ b/scripts/admin/displayParticipant.js @@ -109,6 +109,7 @@ $(document).ready(function() { /* The main jqGrid, displaying Participants */ jQuery("#displayparticipants").jqGrid({ align:"center", + headertitles: true, url: jsonUrl, editurl: editUrl, datatype: "json", From 383e06f6060795538665d7eb9abd26b160df40c8 Mon Sep 17 00:00:00 2001 From: jcleeland Date: Sun, 22 Jul 2012 21:38:28 +1000 Subject: [PATCH 13/71] Fixed issue #6368 Some older tokens tables don't have all required fields - lists, exports & searches fail - system checks for existence of fields and creates them if needed (would love confirmation from postgres db that this works ok for them) --- application/controllers/admin/tokens.php | 3 +++ application/models/Tokens_dynamic.php | 14 ++++++++++++++ scripts/admin/tokens.js | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/application/controllers/admin/tokens.php b/application/controllers/admin/tokens.php index ed0e269be9a..635c729d5ce 100644 --- a/application/controllers/admin/tokens.php +++ b/application/controllers/admin/tokens.php @@ -57,6 +57,9 @@ function index($iSurveyId) } else { + //Check that the tokens table has the required fields + Tokens_dynamic::model($iSurveyId)->checkColumns(); + $aData['thissurvey'] = $thissurvey; $aData['surveyid'] = $iSurveyId; $aData['queries'] = Tokens_dynamic::model($iSurveyId)->summary(); diff --git a/application/models/Tokens_dynamic.php b/application/models/Tokens_dynamic.php index 96a39d6e75b..99b80085ca4 100644 --- a/application/models/Tokens_dynamic.php +++ b/application/models/Tokens_dynamic.php @@ -97,6 +97,20 @@ public function summary() return $data; } + /** + * Checks to make sure that all required columns exist in this tokens table + * (some older tokens tables dont' get udated properly) + * + */ + public function checkColumns() { + $sid = self::$sid; + $surveytable='{{tokens_'.$sid.'}}'; + $columns = Yii::app()->db->schema->getTable($surveytable)->getColumnNames(); + if(!in_array('participant_id', $columns)) Yii::app()->db->createCommand()->addColumn($surveytable, "participant_id", "text null"); + if(!in_array('validuntil', $columns)) Yii::app()->db->createCommand()->addColumn($surveytable, 'validuntil', 'date null'); + if(!in_array('validfrom', $columns)) Yii::app()->db->createCommand()->addColumn($surveytable, 'validfrom', 'date null'); + } + public function findUninvited($aTokenIds = false, $iMaxEmails = 0, $bEmail = true, $SQLemailstatuscondition = '', $SQLremindercountcondition = '', $SQLreminderdelaycondition = '') { $emquery = "SELECT * FROM {{tokens_" . self::$sid . "}} WHERE ((completed ='N') or (completed='')) AND token <> '' AND email <> ''"; diff --git a/scripts/admin/tokens.js b/scripts/admin/tokens.js index 9afcd64acc5..4930be2c684 100644 --- a/scripts/admin/tokens.js +++ b/scripts/admin/tokens.js @@ -110,13 +110,13 @@ $(document).ready(function() { var lastSel,lastSel2; jQuery("#displaytokens").jqGrid({ align:"center", + headertitles: true, url: jsonUrl, editurl: editUrl, datatype: "json", mtype: "post", colNames : colNames, colModel: colModels, - toppager: true, height: "100%", rowNum: 25, editable:true, From 15f0f60a27e8b15528d3a0c6d02bf030e7df559d Mon Sep 17 00:00:00 2001 From: Denis Chenu Date: Sun, 22 Jul 2012 13:40:04 +0200 Subject: [PATCH 14/71] Fixed issue : Link for next/previous breaked --- .../views/admin/responses/browseallheader_view.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/application/views/admin/responses/browseallheader_view.php b/application/views/admin/responses/browseallheader_view.php index 1aff50fbefd..987fd368122 100644 --- a/application/views/admin/responses/browseallheader_view.php +++ b/application/views/admin/responses/browseallheader_view.php @@ -11,15 +11,15 @@ - + From 54251ad2b4ab57c1b3d4377386327c8221d90d37 Mon Sep 17 00:00:00 2001 From: jcleeland Date: Sun, 22 Jul 2012 22:21:33 +1000 Subject: [PATCH 15/71] New feature: dropdown inline search options for jqGrid survey list (useful for active/expired/inactive) --- .../views/admin/survey/listSurveys_view.php | 11 +++++++++ scripts/admin/listsurvey.js | 24 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/application/views/admin/survey/listSurveys_view.php b/application/views/admin/survey/listSurveys_view.php index c2d6fd10284..5a54e5accac 100644 --- a/application/views/admin/survey/listSurveys_view.php +++ b/application/views/admin/survey/listSurveys_view.php @@ -24,4 +24,15 @@
+ +
diff --git a/scripts/admin/listsurvey.js b/scripts/admin/listsurvey.js index 5d75659841c..c2fe212a73e 100644 --- a/scripts/admin/listsurvey.js +++ b/scripts/admin/listsurvey.js @@ -148,4 +148,28 @@ $(document).ready(function(){ $('.wrapper').width($('#displaysurveys').width()*1.006); $('.footer').width(($('#displaysurveys').width()*1.006)-10); + /* Trigger the inline search when the status list changes */ + $('#gs_status_select').change(function() { + $("#gs_status").val($('#gs_status_select').val()); + var e = jQuery.Event("keydown"); + $("#gs_status").trigger(e); + }); + /* Trigger the inline search when the access list changes */ + $('#gs_access_select').change(function() { + $("#gs_access").val($('#gs_access_select').val()); + var e = jQuery.Event("keydown"); + $("#gs_access").trigger(e); + }); + /* Change the text search above "Status" icons to a dropdown */ + var parentDiv=$('#gs_status').parent(); + parentDiv.prepend($('#gs_status_select')); + $('#gs_status_select').css("display", ""); + $('#gs_status').css("display", "none"); + /* Change the text search above "Access" to a dropdown */ + var parentADiv=$('#gs_access').parent(); + parentADiv.prepend($('#gs_access_select')); + $('#gs_access_select').css("display", ""); + $('#gs_access').css("display", "none"); + + }); From 8972c76e6254ff51c67fa69445c883f86cd4e0c3 Mon Sep 17 00:00:00 2001 From: jcleeland Date: Mon, 23 Jul 2012 08:55:38 +1000 Subject: [PATCH 16/71] Fixed issue #6354 (another typo found by SamMousa :-)) --- application/helpers/admin/import_helper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/helpers/admin/import_helper.php b/application/helpers/admin/import_helper.php index f636550f6af..6af1b61484d 100644 --- a/application/helpers/admin/import_helper.php +++ b/application/helpers/admin/import_helper.php @@ -3169,7 +3169,7 @@ function CSVImportSurvey($sFullFilepath,$iDesiredSurveyId=NULL,$bTranslateLinks= $asrowdata["sid"]=$iNewSID; unset($asrowdata["id"]); - $result=Assesments::model()->insertRecords($asrowdata) or safeDie("Couldn't insert assessment
"); + $result=Assessments::model()->insertRecords($asrowdata) or safeDie("Couldn't insert assessment
"); unset($newgid); } From 1edd37e3ebd03183151fa25e3506111d058de8f5 Mon Sep 17 00:00:00 2001 From: jcleeland Date: Mon, 23 Jul 2012 13:30:24 +1000 Subject: [PATCH 17/71] Fixed issue #6371 Statistics not checking selected checkboxes in response filter section after displaying stats --- application/controllers/admin/statistics.php | 4 +- .../helpers/admin/statistics_helper.php | 10 +- .../views/admin/export/statistics_view.php | 107 +++++++++++------- .../survey/Question/editQuestion_view.php | 29 ++--- 4 files changed, 88 insertions(+), 62 deletions(-) diff --git a/application/controllers/admin/statistics.php b/application/controllers/admin/statistics.php index 6d8bbec58da..dcb0083c704 100644 --- a/application/controllers/admin/statistics.php +++ b/application/controllers/admin/statistics.php @@ -527,10 +527,11 @@ public function run($surveyid, $subaction = null) { $usegraph = 0; } + $aData['usegraph'] = $usegraph; $outputType = $_POST['outputtype']; - switch($outputType){ + switch($outputType){ case 'html': $statisticsoutput .= generate_statistics($surveyid,$summary,$summary,$usegraph,$outputType,'DD',$statlang); break; @@ -552,6 +553,7 @@ public function run($surveyid, $subaction = null) $aData['sStatisticsLanguage']=$statlang; $aData['output'] = $statisticsoutput; + $aData['summary'] = $summary; $this->_renderWrappedTemplate('export', 'statistics_view', $aData); diff --git a/application/helpers/admin/statistics_helper.php b/application/helpers/admin/statistics_helper.php index 2416ebd94fb..7a144c2219b 100644 --- a/application/helpers/admin/statistics_helper.php +++ b/application/helpers/admin/statistics_helper.php @@ -1834,8 +1834,8 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, { $qrow=array_values($qrow); $fquery = "SELECT * FROM {{answers}} WHERE qid='{$qiqid}' AND scale_id=0 AND code = '{$licode}' AND language='{$language}'ORDER BY sortorder, code"; - $fresult = dbExecuteAssoc($fquery); - foreach ($result->readAll() as $frow) + $fresult = Yii::app()->db->createCommand($fquery)->query(); + foreach ($fresult->readAll() as $frow) { $alist[]=array($frow['code'], $frow['answer']); $ltext=$frow['answer']; @@ -1895,13 +1895,13 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $qresult=Yii::app()->db->createCommand($qquery)->query(); //loop through answers - foreach ($result->readAll() as $qrow) + foreach ($qresult->readAll() as $qrow) { $qrow=array_values($qrow); //this question type uses its own labels $fquery = "SELECT * FROM {{answers}} WHERE qid='{$qiqid}' AND scale_id=0 AND language='{$language}'ORDER BY sortorder, code"; - $fresult = dbExecuteAssoc($fquery); + $fresult = Yii::app()->db->createCommand($fquery)->query(); //add code and title to results for outputting them later foreach ($fresult->readAll() as $frow) @@ -3351,7 +3351,7 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, //close table/output if($outputType=='html') { - if ($usegraph) { + if ($usegraph==1) { $sImgUrl = Yii::app()->getConfig('adminimageurl'); $statisticsoutput .= "
" diff --git a/application/views/admin/export/statistics_view.php b/application/views/admin/export/statistics_view.php index b22252b6c82..2b3798f64a5 100644 --- a/application/views/admin/export/statistics_view.php +++ b/application/views/admin/export/statistics_view.php @@ -25,9 +25,9 @@ $error .= '
'.$clang->gT('visit http://us2.php.net/manual/en/ref.image.php for more information').'
'; } else if (!function_exists("imageftbbox")) { - $error .= '
'.$clang->gT('You do not have the Freetype Library installed. Showing charts requires the Freetype library to function properly.'); - $error .= '
'.$clang->gT('visit http://us2.php.net/manual/en/ref.image.php for more information').'
'; - } + $error .= '
'.$clang->gT('You do not have the Freetype Library installed. Showing charts requires the Freetype library to function properly.'); + $error .= '
'.$clang->gT('visit http://us2.php.net/manual/en/ref.image.php for more information').'
'; + } ?>
eT("Data selection"); ?> @@ -145,32 +145,44 @@ > - - $flt): ?> - - - + $flt) { + if (!isset($previousquestiontype)) {$previousquestiontype="";} + if ($flt[1] != $currentgroup) { + if ($currentgroup!='') { ?>
- +
- - (gT("Question group").$flt[1]; ?>) + + + + + + (gT("Question group").$flt[1]; ?>) +
-
- - - - - '> +
+ + + $previousquestiontype == ";")) { ?> - - - - + { ?>
- - + /> + || array_search("N{$surveyid}X{$flt[1]}X{$flt[0]}", $summary) !== FALSE)) { echo " checked='checked'"; } + ?> />
- multiple='multiple'> + "; echo " - +
diff --git a/application/views/admin/survey/Question/editQuestion_view.php b/application/views/admin/survey/Question/editQuestion_view.php index be1481ffddc..5aaf9a64b59 100644 --- a/application/views/admin/survey/Question/editQuestion_view.php +++ b/application/views/admin/survey/Question/editQuestion_view.php @@ -33,25 +33,26 @@ ?> ');"> -
+

+
-
  • - eT("Note: You MUST enter a new question code!"); ?> -
  • - - - gT("Question:", "js")."](".$eqrow['language'].")",$surveyid,$gid,$qid,$action); ?> -
  • - - - gT("Help:", "js")."](".$eqrow['language'].")",$surveyid,$gid,$qid,$action); ?> -
  • -
-
+
  • + eT("Note: You MUST enter a new question code!"); ?> +
  • + + + gT("Question:", "js")."](".$eqrow['language'].")",$surveyid,$gid,$qid,$action); ?> +
  • + + + gT("Help:", "js")."](".$eqrow['language'].")",$surveyid,$gid,$qid,$action); ?> +
  • +
+
Date: Mon, 23 Jul 2012 09:16:27 +0200 Subject: [PATCH 18/71] Fixed issue #6350: Error html_entity_decode(): charset `ANSI_X3.4-1968' not supported, assuming iso-8859-1 on survey save when sending confirmation email --- application/helpers/frontend_helper.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/application/helpers/frontend_helper.php b/application/helpers/frontend_helper.php index a7088c2795c..f79e4c46462 100644 --- a/application/helpers/frontend_helper.php +++ b/application/helpers/frontend_helper.php @@ -9,9 +9,8 @@ * is derivative of works licensed under the GNU General Public License or * other free or open source software licenses. * See COPYRIGHT.php for copyright notices and details. - * - * $Id$ */ + function loadanswers() { global $surveyid; @@ -1020,13 +1019,13 @@ function remove_nulls_from_array($array) */ function submittokens($quotaexit=false) { - global $thissurvey, $timeadjust, $emailcharset ; + global $thissurvey; global $surveyid; global $thistpl, $clienttoken; $clang = Yii::app()->lang; $sitename = Yii::app()->getConfig("sitename"); - + $emailcharset = Yii::app()->getConfig("emailcharset"); // Shift the date due to global timeadjust setting $today = dateShift(date("Y-m-d H:i:s"), "Y-m-d H:i", Yii::app()->getConfig("timeadjust")); @@ -1163,7 +1162,6 @@ function submittokens($quotaexit=false) function sendSubmitNotifications($surveyid) { global $thissurvey, $debug; - global $emailcharset; global $homeurl, $maildebug, $tokensexist; $clang = Yii::app()->lang; From 5013658875c2433aef4440314696ad267ee0b616 Mon Sep 17 00:00:00 2001 From: Carsten Schmitz Date: Mon, 23 Jul 2012 09:54:17 +0200 Subject: [PATCH 19/71] Fixed issue #6347: display of question text different in 1.92+ and 2.0 when view question in admin mode Dev Partial fix --- application/core/Survey_Common_Action.php | 1 - .../views/admin/survey/Question/questionbar_view.php | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/application/core/Survey_Common_Action.php b/application/core/Survey_Common_Action.php index 1fc861e70e9..1480b31a3a8 100644 --- a/application/core/Survey_Common_Action.php +++ b/application/core/Survey_Common_Action.php @@ -352,7 +352,6 @@ function _questionbar($iSurveyId, $gid, $qid, $action = null) foreach ($qrresult as $qrrow) { $qrrow = $qrrow->attributes; - $qrrow = array_map('flattenText', $qrrow); if (hasSurveyPermission($iSurveyId, 'surveycontent', 'read')) { if (count(Survey::model()->findByPk($iSurveyId)->additionalLanguages) != 0) diff --git a/application/views/admin/survey/Question/questionbar_view.php b/application/views/admin/survey/Question/questionbar_view.php index cb969b139f9..571f563af81 100644 --- a/application/views/admin/survey/Question/questionbar_view.php +++ b/application/views/admin/survey/Question/questionbar_view.php @@ -166,20 +166,20 @@ eT("Question:"); ?> eT("Help:"); ?> - eT("Validation:"); ?> + eT("Validation:"); ?> @@ -252,7 +252,7 @@ : + if ($aAdvancedSetting['i18n']==false) echo htmlspecialchars($aAdvancedSetting['value']); else echo htmlspecialchars($aAdvancedSetting[$baselang]['value'])?> From 8eec5761a017e6e93ce6cb1cab77b566eee15aba Mon Sep 17 00:00:00 2001 From: Carsten Schmitz Date: Mon, 23 Jul 2012 10:01:55 +0200 Subject: [PATCH 20/71] Fixed issue #6360: No Server time displayed in global settings --- application/views/admin/globalSettings_view.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/views/admin/globalSettings_view.php b/application/views/admin/globalSettings_view.php index 477c43da1e9..aa152e4ca28 100644 --- a/application/views/admin/globalSettings_view.php +++ b/application/views/admin/globalSettings_view.php @@ -178,7 +178,7 @@ session['dateformat']); ?>
  • - eT("Server time:").' '.convertDateTimeFormat(date('Y-m-d H:i:s'),'Y-m-d H:i:s',$dateformatdata['phpdate'].' H:i')." - ". $clang->gT("Corrected time :").' '.convertDateTimeFormat(dateShift(date("Y-m-d H:i:s"), 'Y-m-d H:i:s', getGlobalSetting('timeadjust')),'Y-m-d H:i:s',$dateformatdata['phpdate'].' H:i'); ?> + gT("Server time:").' '.convertDateTimeFormat(date('Y-m-d H:i:s'),'Y-m-d H:i:s',$dateformatdata['phpdate'].' H:i')." - ". $clang->gT("Corrected time :").' '.convertDateTimeFormat(dateShift(date("Y-m-d H:i:s"), 'Y-m-d H:i:s', getGlobalSetting('timeadjust')),'Y-m-d H:i:s',$dateformatdata['phpdate'].' H:i'); ?>
  • From 1ed2940a6644fda66b110b279e1d15c8159fc5bb Mon Sep 17 00:00:00 2001 From: jcleeland Date: Mon, 23 Jul 2012 22:34:39 +1000 Subject: [PATCH 21/71] Fixed issue #6372 Browse text responses does not work --- application/controllers/admin/statistics.php | 20 + .../helpers/admin/statistics_helper.php | 795 +++++++++--------- .../views/admin/export/statistics_view.php | 6 +- scripts/admin/statistics.js | 11 + styles/blobblueish/adminstyle.css | 15 + styles/gartergrey/adminstyle.css | 14 + styles/gringegreen/adminstyle.css | 16 + 7 files changed, 500 insertions(+), 377 deletions(-) diff --git a/application/controllers/admin/statistics.php b/application/controllers/admin/statistics.php index dcb0083c704..25d07bf1731 100644 --- a/application/controllers/admin/statistics.php +++ b/application/controllers/admin/statistics.php @@ -531,6 +531,9 @@ public function run($surveyid, $subaction = null) $aData['usegraph'] = $usegraph; $outputType = $_POST['outputtype']; + $selects=buildSelects($summary, $surveyid, $statlang); + $aData['sql']=implode(" AND ", $selects); + switch($outputType){ case 'html': $statisticsoutput .= generate_statistics($surveyid,$summary,$summary,$usegraph,$outputType,'DD',$statlang); @@ -559,6 +562,23 @@ public function run($surveyid, $subaction = null) } + /* Returns a simple list of values in a particular column, that meet the + * requirements of the SQL + * + * */ + function listcolumn($surveyid, $column, $sql) + { + $results=Survey_dynamic::model($surveyid)->findAll($column." != ''"); + foreach($results as $row) { + ?> +
    + +
    +
    loadHelper('admin/statistics'); diff --git a/application/helpers/admin/statistics_helper.php b/application/helpers/admin/statistics_helper.php index 7a144c2219b..9bf1da3a205 100644 --- a/application/helpers/admin/statistics_helper.php +++ b/application/helpers/admin/statistics_helper.php @@ -256,6 +256,232 @@ function getQuestionMapData($sField, $qsid) return $d; } +/** Builds the list of addon SQL select statements +* that builds the query result set +* +* @param $allfields +* @param $fieldmap +* @param $language +* +* @return array $selects array of individual select statements that can be added/appended to +* the 'where' portion of a SQL statement to restrict the result set +* ie: array("`FIELDNAME`='Y'", "`FIELDNAME2`='Hello'"); +* +*/ +function buildSelects($allfields, $surveyid, $language) { + + $selects=array(); + + $fieldmap=createFieldMap($surveyid, "full", false, false, $language); + + $aQuestionMap=array(); + + foreach ($fieldmap as $field) + { + if(isset($field['qid']) && $field['qid']!='') + $aQuestionMap[]=$field['sid'].'X'.$field['gid'].'X'.$field['qid']; + } + // creates array of post variable names + for (reset($_POST); $key=key($_POST); next($_POST)) { $postvars[]=$key;} + /* + * Iterate through postvars to create "nice" data for SQL later. + * + * Remember there might be some filters applied which have to be put into an SQL statement + * + * This foreach iterates through the name ($key) of each post value and builds a SELECT + * statement out of it. It returns an array called $selects[] which will have a select query + * for each filter chosen. ie: $select[0]="`74X71X428EXP` ='Y'"; + * + * This array is used later to build the overall query used to limit the number of responses + * + */ + if(isset($postvars)) + foreach ($postvars as $pv) + { + //Only do this if there is actually a value for the $pv + if (in_array($pv, $allfields) || in_array(substr($pv,1),$aQuestionMap) || in_array($pv,$aQuestionMap) || (($pv[0]=='D' || $pv[0]=='N' || $pv[0]=='K') && in_array(substr($pv,1,strlen($pv)-2),$aQuestionMap))) + { + $firstletter=substr($pv,0,1); + /* + * these question types WON'T be handled here: + * M = Multiple choice + * T - Long Free Text + * Q - Multiple Short Text + * D - Date + * N - Numerical Input + * | - File Upload + * K - Multiple Numerical Input + */ + if ($pv != "sid" && $pv != "display" && $firstletter != "M" && $firstletter != "P" && $firstletter != "T" && + $firstletter != "Q" && $firstletter != "D" && $firstletter != "N" && $firstletter != "K" && $firstletter != "|" && + $pv != "summary" && substr($pv, 0, 2) != "id" && substr($pv, 0, 9) != "datestamp") //pull out just the fieldnames + { + //put together some SQL here + $thisquestion = Yii::app()->db->quoteColumnName($pv)." IN ("; + + foreach ($_POST[$pv] as $condition) + { + $thisquestion .= "'$condition', "; + } + + $thisquestion = substr($thisquestion, 0, -2) + . ")"; + + //we collect all the to be selected data in this array + $selects[]=$thisquestion; + } + + //M - Multiple choice + //P - Multiple choice with comments + elseif ($firstletter == "M" || $firstletter == "P") + { + $mselects=array(); + //create a list out of the $pv array + list($lsid, $lgid, $lqid) = explode("X", $pv); + + $aquery="SELECT title FROM {{questions}} WHERE parent_qid=$lqid AND language='{$language}' and scale_id=0 ORDER BY question_order"; + $aresult=Yii::app()->db->createCommand($aquery)->query(); + + // go through every possible answer + foreach ($aresult->readAll() as $arow) + { + $arow=array_values($arow); + // only add condition if answer has been chosen + if (in_array($arow[0], $_POST[$pv])) + { + $mselects[]=Yii::app()->db->quoteColumnName(substr($pv, 1, strlen($pv)).$arow[0])." = 'Y'"; + } + } + if ($mselects) + { + $thismulti=implode(" OR ", $mselects); + $selects[]="($thismulti)"; + $mselects = ""; + } + } + + + //N - Numerical Input + //K - Multiple Numerical Input + elseif ($firstletter == "N" || $firstletter == "K") + { + //value greater than + if (substr($pv, strlen($pv)-1, 1) == "G" && $_POST[$pv] != "") + { + $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 1, -1))." > ".sanitize_int($_POST[$pv]); + } + + //value less than + if (substr($pv, strlen($pv)-1, 1) == "L" && $_POST[$pv] != "") + { + $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 1, -1))." < ".sanitize_int($_POST[$pv]); + } + } + + //| - File Upload Question Type + else if ($firstletter == "|") + { + // no. of files greater than + if (substr($pv, strlen($pv)-1, 1) == "G" && $_POST[$pv] != "") + $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 1, -1)."_filecount")." > ".sanitize_int($_POST[$pv]); + + // no. of files less than + if (substr($pv, strlen($pv)-1, 1) == "L" && $_POST[$pv] != "") + $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 1, -1)."_filecount")." < ".sanitize_int($_POST[$pv]); + } + + //"id" is a built in field, the unique database id key of each response row + elseif (substr($pv, 0, 2) == "id") + { + if (substr($pv, strlen($pv)-1, 1) == "G" && $_POST[$pv] != "") + { + $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 0, -1))." > '".$_POST[$pv]."'"; + } + if (substr($pv, strlen($pv)-1, 1) == "L" && $_POST[$pv] != "") + { + $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 0, -1))." < '".$_POST[$pv]."'"; + } + } + + //T - Long Free Text + //Q - Multiple Short Text + elseif (($firstletter == "T" || $firstletter == "Q" ) && $_POST[$pv] != "") + { + $selectSubs = array(); + //We intepret and * and % as wildcard matches, and use ' OR ' and , as the seperators + $pvParts = explode(",",str_replace('*','%', str_replace(' OR ',',',$_POST[$pv]))); + if(is_array($pvParts) AND count($pvParts)){ + foreach($pvParts AS $pvPart){ + $selectSubs[]=Yii::app()->db->quoteColumnName(substr($pv, 1, strlen($pv)))." LIKE '".trim($pvPart)."'"; + } + if(count($selectSubs)){ + $selects[] = ' ('.implode(' OR ',$selectSubs).') '; + } + } + } + + //D - Date + elseif ($firstletter == "D" && $_POST[$pv] != "") + { + //Date equals + if (substr($pv, -1, 1) == "eq") + { + $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 1, strlen($pv)-2))." = '".$_POST[$pv]."'"; + } + else + { + //date less than + if (substr($pv, -1, 1) == "less") + { + $selects[]= Yii::app()->db->quoteColumnName(substr($pv, 1, strlen($pv)-2)) . " >= '".$_POST[$pv]."'"; + } + + //date greater than + if (substr($pv, -1, 1) == "more") + { + $selects[]= Yii::app()->db->quoteColumnName(substr($pv, 1, strlen($pv)-2)) . " <= '".$_POST[$pv]."'"; + } + } + } + + //check for datestamp of given answer + elseif (substr($pv, 0, 9) == "datestamp") + { + //timestamp equals + $formatdata=getDateFormatData(Yii::app()->session['dateformat']); + if (substr($pv, -1, 1) == "E" && !empty($_POST[$pv])) + { + $datetimeobj = new Date_Time_Converter($_POST[$pv], $formatdata['phpdate'].' H:i'); + $_POST[$pv]=$datetimeobj->convert("Y-m-d"); + + $selects[] = Yii::app()->db->quoteColumnName('datestamp')." >= '".$_POST[$pv]." 00:00:00' and ".Yii::app()->db->quoteColumnName('datestamp')." <= '".$_POST[$pv]." 23:59:59'"; + } + else + { + //timestamp less than + if (substr($pv, -1, 1) == "L" && !empty($_POST[$pv])) + { + $datetimeobj = new Date_Time_Converter($_POST[$pv], $formatdata['phpdate'].' H:i'); + $_POST[$pv]=$datetimeobj->convert("Y-m-d H:i:s"); + $selects[]= Yii::app()->db->quoteColumnName('datestamp')." < '".$_POST[$pv]."'"; + } + + //timestamp greater than + if (substr($pv, -1, 1) == "G" && !empty($_POST[$pv])) + { + $datetimeobj = new Date_Time_Converter($_POST[$pv], $formatdata['phpdate'].' H:i'); + $_POST[$pv]=$datetimeobj->convert("Y-m-d H:i:s"); + $selects[]= Yii::app()->db->quoteColumnName('datestamp')." > '".$_POST[$pv]."'"; + } + } + } + } + + } //end foreach -> loop through filter options to create SQL + + return $selects; + +} /** * Generates statistics @@ -301,8 +527,6 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $statlang = new Limesurvey_lang($statlangcode); } - $fieldmap=createFieldMap($surveyid, "full", false, false, $statlang->getlangcode()); - /* * this variable is used in the function shortencode() which cuts off a question/answer title * after $maxchars and shows the rest as tooltip (in html mode) @@ -324,6 +548,8 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $surveylanguagecodes = Survey::model()->findByPk($surveyid)->additionalLanguages; $surveylanguagecodes[] = Survey::model()->findByPk($surveyid)->language; + $fieldmap=createFieldMap($surveyid, "full", false, false, $statlang->getlangcode()); + // Set language for questions and answers to base language of this survey $language=$statlangcode; @@ -452,254 +678,54 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, // set default monospaced font $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED); - //set margins - $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); - $pdf->SetHeaderMargin(PDF_MARGIN_HEADER); - $pdf->SetFooterMargin(PDF_MARGIN_FOOTER); - - //set auto page breaks - $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); - - //set image scale factor - $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); - - //set some language-dependent strings - $pdf->setLanguageArray($l); - } - if($outputType=='xls') - { - /** - * Initiate the Spreadsheet_Excel_Writer - */ - Yii::import('application.libraries.admin.pear.Spreadsheet.Excel.Xlswriter', true); - if($pdfOutput=='F') - $workbook = new Xlswriter($tempdir.'/statistic-survey'.$surveyid.'.xls'); - else - $workbook = new Xlswriter(); - - $workbook->setVersion(8); - // Inform the module that our data will arrive as UTF-8. - // Set the temporary directory to avoid PHP error messages due to open_basedir restrictions and calls to tempnam("", ...) - if (!empty($tempdir)) { - $workbook->setTempDir($tempdir); - } - if ($pdfOutput!='F') - $workbook->send('statistic-survey'.$surveyid.'.xls'); - - // Creating the first worksheet - $sheet =& $workbook->addWorksheet(utf8_decode('results-survey'.$surveyid)); - $sheet->setInputEncoding('utf-8'); - $sheet->setColumn(0,20,20); - $separator="~|"; - /**XXX*/ - } - /** - * Start generating - */ - - // creates array of post variable names - for (reset($_POST); $key=key($_POST); next($_POST)) { $postvars[]=$key;} - - $aQuestionMap=array(); - foreach ($fieldmap as $field) - { - if(isset($field['qid']) && $field['qid']!='') - $aQuestionMap[]=$field['sid'].'X'.$field['gid'].'X'.$field['qid']; - } - - /* - * Iterate through postvars to create "nice" data for SQL later. - * - * Remember there might be some filters applied which have to be put into an SQL statement - */ - if(isset($postvars)) - - foreach ($postvars as $pv) - { - //Only do this if there is actually a value for the $pv - if (in_array($pv, $allfields) || in_array(substr($pv,1),$aQuestionMap) || in_array($pv,$aQuestionMap) || (($pv[0]=='D' || $pv[0]=='N' || $pv[0]=='K') && in_array(substr($pv,1,strlen($pv)-2),$aQuestionMap))) - { - $firstletter=substr($pv,0,1); - /* - * these question types WON'T be handled here: - * M = Multiple choice - * T - Long Free Text - * Q - Multiple Short Text - * D - Date - * N - Numerical Input - * | - File Upload - * K - Multiple Numerical Input - */ - if ($pv != "sid" && $pv != "display" && $firstletter != "M" && $firstletter != "P" && $firstletter != "T" && - $firstletter != "Q" && $firstletter != "D" && $firstletter != "N" && $firstletter != "K" && $firstletter != "|" && - $pv != "summary" && substr($pv, 0, 2) != "id" && substr($pv, 0, 9) != "datestamp") //pull out just the fieldnames - { - //put together some SQL here - $thisquestion = Yii::app()->db->quoteColumnName($pv)." IN ("; - - foreach ($_POST[$pv] as $condition) - { - $thisquestion .= "'$condition', "; - } - - $thisquestion = substr($thisquestion, 0, -2) - . ")"; - - //we collect all the to be selected data in this array - $selects[]=$thisquestion; - } - - //M - Multiple choice - //P - Multiple choice with comments - elseif ($firstletter == "M" || $firstletter == "P") - { - $mselects=array(); - //create a list out of the $pv array - list($lsid, $lgid, $lqid) = explode("X", $pv); - - $aquery="SELECT title FROM {{questions}} WHERE parent_qid=$lqid AND language='{$language}' and scale_id=0 ORDER BY question_order"; - $aresult=Yii::app()->db->createCommand($aquery)->query(); - - // go through every possible answer - foreach ($aresult->readAll() as $arow) - { - $arow=array_values($arow); - // only add condition if answer has been chosen - if (in_array($arow[0], $_POST[$pv])) - { - $mselects[]=Yii::app()->db->quoteColumnName(substr($pv, 1, strlen($pv)).$arow[0])." = 'Y'"; - } - } - if ($mselects) - { - $thismulti=implode(" OR ", $mselects); - $selects[]="($thismulti)"; - $mselects = ""; - } - } - - - //N - Numerical Input - //K - Multiple Numerical Input - elseif ($firstletter == "N" || $firstletter == "K") - { - //value greater than - if (substr($pv, strlen($pv)-1, 1) == "G" && $_POST[$pv] != "") - { - $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 1, -1))." > ".sanitize_int($_POST[$pv]); - } - - //value less than - if (substr($pv, strlen($pv)-1, 1) == "L" && $_POST[$pv] != "") - { - $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 1, -1))." < ".sanitize_int($_POST[$pv]); - } - } - - //| - File Upload Question Type - else if ($firstletter == "|") - { - // no. of files greater than - if (substr($pv, strlen($pv)-1, 1) == "G" && $_POST[$pv] != "") - $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 1, -1)."_filecount")." > ".sanitize_int($_POST[$pv]); - - // no. of files less than - if (substr($pv, strlen($pv)-1, 1) == "L" && $_POST[$pv] != "") - $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 1, -1)."_filecount")." < ".sanitize_int($_POST[$pv]); - } + //set margins + $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); + $pdf->SetHeaderMargin(PDF_MARGIN_HEADER); + $pdf->SetFooterMargin(PDF_MARGIN_FOOTER); - //"id" is a built in field, the unique database id key of each response row - elseif (substr($pv, 0, 2) == "id") - { - if (substr($pv, strlen($pv)-1, 1) == "G" && $_POST[$pv] != "") - { - $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 0, -1))." > '".$_POST[$pv]."'"; - } - if (substr($pv, strlen($pv)-1, 1) == "L" && $_POST[$pv] != "") - { - $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 0, -1))." < '".$_POST[$pv]."'"; - } - } + //set auto page breaks + $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); - //T - Long Free Text - //Q - Multiple Short Text - elseif (($firstletter == "T" || $firstletter == "Q" ) && $_POST[$pv] != "") - { - $selectSubs = array(); - //We intepret and * and % as wildcard matches, and use ' OR ' and , as the seperators - $pvParts = explode(",",str_replace('*','%', str_replace(' OR ',',',$_POST[$pv]))); - if(is_array($pvParts) AND count($pvParts)){ - foreach($pvParts AS $pvPart){ - $selectSubs[]=Yii::app()->db->quoteColumnName(substr($pv, 1, strlen($pv)))." LIKE '".trim($pvPart)."'"; - } - if(count($selectSubs)){ - $selects[] = ' ('.implode(' OR ',$selectSubs).') '; - } - } - } + //set image scale factor + $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); - //D - Date - elseif ($firstletter == "D" && $_POST[$pv] != "") - { - //Date equals - if (substr($pv, -1, 1) == "eq") - { - $selects[]=Yii::app()->db->quoteColumnName(substr($pv, 1, strlen($pv)-2))." = '".$_POST[$pv]."'"; - } - else - { - //date less than - if (substr($pv, -1, 1) == "less") - { - $selects[]= Yii::app()->db->quoteColumnName(substr($pv, 1, strlen($pv)-2)) . " >= '".$_POST[$pv]."'"; - } + //set some language-dependent strings + $pdf->setLanguageArray($l); + } + if($outputType=='xls') + { + /** + * Initiate the Spreadsheet_Excel_Writer + */ + Yii::import('application.libraries.admin.pear.Spreadsheet.Excel.Xlswriter', true); + if($pdfOutput=='F') + $workbook = new Xlswriter($tempdir.'/statistic-survey'.$surveyid.'.xls'); + else + $workbook = new Xlswriter(); - //date greater than - if (substr($pv, -1, 1) == "more") - { - $selects[]= Yii::app()->db->quoteColumnName(substr($pv, 1, strlen($pv)-2)) . " <= '".$_POST[$pv]."'"; - } - } - } + $workbook->setVersion(8); + // Inform the module that our data will arrive as UTF-8. + // Set the temporary directory to avoid PHP error messages due to open_basedir restrictions and calls to tempnam("", ...) + if (!empty($tempdir)) { + $workbook->setTempDir($tempdir); + } + if ($pdfOutput!='F') + $workbook->send('statistic-survey'.$surveyid.'.xls'); - //check for datestamp of given answer - elseif (substr($pv, 0, 9) == "datestamp") - { - //timestamp equals - $formatdata=getDateFormatData(Yii::app()->session['dateformat']); - if (substr($pv, -1, 1) == "E" && !empty($_POST[$pv])) - { - $datetimeobj = new Date_Time_Converter($_POST[$pv], $formatdata['phpdate'].' H:i'); - $_POST[$pv]=$datetimeobj->convert("Y-m-d"); + // Creating the first worksheet + $sheet =& $workbook->addWorksheet(utf8_decode('results-survey'.$surveyid)); + $sheet->setInputEncoding('utf-8'); + $sheet->setColumn(0,20,20); + $separator="~|"; + /**XXX*/ + } + /** + * Start generating + */ - $selects[] = Yii::app()->db->quoteColumnName('datestamp')." >= '".$_POST[$pv]." 00:00:00' and ".Yii::app()->db->quoteColumnName('datestamp')." <= '".$_POST[$pv]." 23:59:59'"; - } - else - { - //timestamp less than - if (substr($pv, -1, 1) == "L" && !empty($_POST[$pv])) - { - $datetimeobj = new Date_Time_Converter($_POST[$pv], $formatdata['phpdate'].' H:i'); - $_POST[$pv]=$datetimeobj->convert("Y-m-d H:i:s"); - $selects[]= Yii::app()->db->quoteColumnName('datestamp')." < '".$_POST[$pv]."'"; - } - //timestamp greater than - if (substr($pv, -1, 1) == "G" && !empty($_POST[$pv])) - { - $datetimeobj = new Date_Time_Converter($_POST[$pv], $formatdata['phpdate'].' H:i'); - $_POST[$pv]=$datetimeobj->convert("Y-m-d H:i:s"); - $selects[]= Yii::app()->db->quoteColumnName('datestamp')." > '".$_POST[$pv]."'"; - } - } - } - } - else - { - $statisticsoutput .= ""; - } - } //end foreach -> loop through filter options to create SQL + $selects=buildSelects($allfields, $surveyid, $language); //count number of answers $query = "SELECT count(*) FROM {{survey_$surveyid}}"; @@ -800,6 +826,8 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, } //put everything from $selects array into a string connected by AND + //This string ($sql) can then be passed on to other functions so you can + //browse these results if (isset ($selects) && $selects) {$sql=implode(" AND ", $selects);} elseif (!empty($newsql)) {$sql = $newsql;} @@ -823,7 +851,11 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, } } //end if (results > 0) - //Show Summary results + /* Show Summary results + * The $summary array contains each fieldname that we want to display statistics for + * + * */ + if (isset($summary) && $summary) { //let's run through the survey @@ -842,7 +874,6 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $legitqids[] = $lw['qid']; } - //loop through all selected questions foreach ($runthrough as $rt) { @@ -1001,7 +1032,7 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, } - //RANKING OPTION THEREFORE CONFUSING + //RANKING OPTION elseif ($firstletter == "R") { //getting the needed IDs somehow @@ -1036,165 +1067,165 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, } else if ($firstletter == "|") // File UPload - { + { - //get SGQ data - list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); + //get SGQ data + list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); - //select details for this question - $nquery = "SELECT title, type, question, parent_qid, other FROM {{questions}} WHERE language='{$language}' AND parent_qid=0 AND qid='$qqid'"; - $nresult = Yii::app()->db->createCommand($nquery)->query(); + //select details for this question + $nquery = "SELECT title, type, question, parent_qid, other FROM {{questions}} WHERE language='{$language}' AND parent_qid=0 AND qid='$qqid'"; + $nresult = Yii::app()->db->createCommand($nquery)->query(); - //loop through question data - foreach ($nresult->readAll() as $nrow) - { - $nrow=array_values($nrow); - $qtitle=$nrow[0]; - $qtype=$nrow[1]; - $qquestion=flattenText($nrow[2]); - $qlid=$nrow[3]; - $qother=$nrow[4]; - } + //loop through question data + foreach ($nresult->readAll() as $nrow) + { + $nrow=array_values($nrow); + $qtitle=$nrow[0]; + $qtype=$nrow[1]; + $qquestion=flattenText($nrow[2]); + $qlid=$nrow[3]; + $qother=$nrow[4]; + } - /* - 4) Average size of file per respondent - 5) Average no. of files - 5) Summary/count of file types (ie: 37 jpg, 65 gif, 12 png) - 6) Total size of all files (useful if you re about to download them all) - 7) You could also add things like smallest file size, largest file size, median file size - 8) no. of files corresponding to each extension - 9) max file size - 10) min file size - */ + /* + 4) Average size of file per respondent + 5) Average no. of files + 5) Summary/count of file types (ie: 37 jpg, 65 gif, 12 png) + 6) Total size of all files (useful if you re about to download them all) + 7) You could also add things like smallest file size, largest file size, median file size + 8) no. of files corresponding to each extension + 9) max file size + 10) min file size + */ - // 1) Total number of files uploaded - // 2) Number of respondents who uploaded at least one file (with the inverse being the number of respondents who didn t upload any) - $fieldname=substr($rt, 1, strlen($rt)); - $query = "SELECT SUM(".Yii::app()->db->quoteColumnName($fieldname.'_filecount').") as sum, AVG(".Yii::app()->db->quoteColumnName($fieldname.'_filecount').") as avg FROM {{survey_$surveyid}}"; - $result=Yii::app()->db->createCommand($query)->query(); + // 1) Total number of files uploaded + // 2) Number of respondents who uploaded at least one file (with the inverse being the number of respondents who didn t upload any) + $fieldname=substr($rt, 1, strlen($rt)); + $query = "SELECT SUM(".Yii::app()->db->quoteColumnName($fieldname.'_filecount').") as sum, AVG(".Yii::app()->db->quoteColumnName($fieldname.'_filecount').") as avg FROM {{survey_$surveyid}}"; + $result=Yii::app()->db->createCommand($query)->query(); - $showem = array(); + $showem = array(); - foreach ($result->readAll() as $row) - { - $showem[]=array($statlang->gT("Total number of files"), $row['sum']); - $showem[]=array($statlang->gT("Average no. of files per respondent"), $row['avg']); - } + foreach ($result->readAll() as $row) + { + $showem[]=array($statlang->gT("Total number of files"), $row['sum']); + $showem[]=array($statlang->gT("Average no. of files per respondent"), $row['avg']); + } - $query = "SELECT ". $fieldname ." as json FROM {{survey_$surveyid}}"; - $result=Yii::app()->db->createCommand($query)->query(); + $query = "SELECT ". $fieldname ." as json FROM {{survey_$surveyid}}"; + $result=Yii::app()->db->createCommand($query)->query(); - $responsecount = 0; - $filecount = 0; - $size = 0; + $responsecount = 0; + $filecount = 0; + $size = 0; - foreach ($result->readAll() as $row) - { + foreach ($result->readAll() as $row) + { - $json = $row['json']; - $phparray = json_decode($json); + $json = $row['json']; + $phparray = json_decode($json); - foreach ($phparray as $metadata) - { - $size += (int) $metadata->size; - $filecount++; - } - $responsecount++; + foreach ($phparray as $metadata) + { + $size += (int) $metadata->size; + $filecount++; } - $showem[] = array($statlang->gT("Total size of files"), $size." KB"); - $showem[] = array($statlang->gT("Average file size"), $size/$filecount . " KB"); - $showem[] = array($statlang->gT("Average size per respondent"), $size/$responsecount . " KB"); - - /* $query="SELECT title, question FROM {{questions}} WHERE parent_qid='$qqid' AND language='{$language}' ORDER BY question_order"; - $result=db_execute_num($query) or safeDie("Couldn't get list of subquestions for multitype
    $query
    "); + $responsecount++; + } + $showem[] = array($statlang->gT("Total size of files"), $size." KB"); + $showem[] = array($statlang->gT("Average file size"), $size/$filecount . " KB"); + $showem[] = array($statlang->gT("Average size per respondent"), $size/$responsecount . " KB"); - //loop through multiple answers - while ($row=$result->FetchRow()) - { - $mfield=substr($rt, 1, strlen($rt))."$row[0]"; + /* $query="SELECT title, question FROM {{questions}} WHERE parent_qid='$qqid' AND language='{$language}' ORDER BY question_order"; + $result=db_execute_num($query) or safeDie("Couldn't get list of subquestions for multitype
    $query
    "); - //create an array containing answer code, answer and fieldname(??) - $alist[]=array("$row[0]", flattenText($row[1]), $mfield); - } + //loop through multiple answers + while ($row=$result->FetchRow()) + { + $mfield=substr($rt, 1, strlen($rt))."$row[0]"; - */ - //outputting - switch($outputType) - { - case 'xls': + //create an array containing answer code, answer and fieldname(??) + $alist[]=array("$row[0]", flattenText($row[1]), $mfield); + } - $headXLS = array(); - $tableXLS = array(); - $footXLS = array(); + */ + //outputting + switch($outputType) + { + case 'xls': - $xlsTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8')); - $xlsDesc = html_entity_decode($qquestion,ENT_QUOTES,'UTF-8'); - ++$xlsRow; - ++$xlsRow; + $headXLS = array(); + $tableXLS = array(); + $footXLS = array(); - ++$xlsRow; - $sheet->write($xlsRow, 0,$xlsTitle); - ++$xlsRow; - $sheet->write($xlsRow, 0,$xlsDesc); + $xlsTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8')); + $xlsDesc = html_entity_decode($qquestion,ENT_QUOTES,'UTF-8'); + ++$xlsRow; + ++$xlsRow; - $headXLS[] = array($statlang->gT("Calculation"),$statlang->gT("Result")); - ++$xlsRow; - $sheet->write($xlsRow, 0,$statlang->gT("Calculation")); - $sheet->write($xlsRow, 1,$statlang->gT("Result")); + ++$xlsRow; + $sheet->write($xlsRow, 0,$xlsTitle); + ++$xlsRow; + $sheet->write($xlsRow, 0,$xlsDesc); - break; - case 'pdf': + $headXLS[] = array($statlang->gT("Calculation"),$statlang->gT("Result")); + ++$xlsRow; + $sheet->write($xlsRow, 0,$statlang->gT("Calculation")); + $sheet->write($xlsRow, 1,$statlang->gT("Result")); - $headPDF = array(); - $tablePDF = array(); - $footPDF = array(); + break; + case 'pdf': - $pdfTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8')); - $titleDesc = html_entity_decode($qquestion,ENT_QUOTES,'UTF-8'); + $headPDF = array(); + $tablePDF = array(); + $footPDF = array(); - $headPDF[] = array($statlang->gT("Calculation"),$statlang->gT("Result")); + $pdfTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8')); + $titleDesc = html_entity_decode($qquestion,ENT_QUOTES,'UTF-8'); - break; + $headPDF[] = array($statlang->gT("Calculation"),$statlang->gT("Result")); - case 'html': + break; - $statisticsoutput .= "\n\n" - ."\t\n" - ."\t\n" - ."\t\n\t\t\n" - ."\t\t\n" - ."\t\n"; + case 'html': - foreach ($showem as $res) - $statisticsoutput .= ""; - break; + $statisticsoutput .= "\n
    ".sprintf($statlang->gT("Field summary for %s"),$qtitle).":" - ."
    $qquestion
    " - .$statlang->gT("Calculation")."" - .$statlang->gT("Result")."
    ".$res[0]."".$res[1]."
    \n" + ."\t\n" + ."\t\n" + ."\t\n\t\t\n" + ."\t\t\n" + ."\t\n"; + + foreach ($showem as $res) + $statisticsoutput .= ""; + break; - default: - break; - } + default: + break; } + } - //N = numerical input - //K = multiple numerical input - elseif ($firstletter == "N" || $firstletter == "K") //NUMERICAL TYPE + //N = numerical input + //K = multiple numerical input + elseif ($firstletter == "N" || $firstletter == "K") //NUMERICAL TYPE + { + //Zero handling + if (!isset($excludezeros)) //If this hasn't been set, set it to on as default: { - //Zero handling - if (!isset($excludezeros)) //If this hasn't been set, set it to on as default: - { - $excludezeros=1; - } - //check last character, greater/less/equals don't need special treatment - if (substr($rt, -1) == "G" || substr($rt, -1) == "L" || substr($rt, -1) == "=") + $excludezeros=1; + } + //check last character, greater/less/equals don't need special treatment + if (substr($rt, -1) == "G" || substr($rt, -1) == "L" || substr($rt, -1) == "=") { //DO NOTHING } else { - $showem = array(); + $showem = array(); //create SGQ identifier list($qsid, $qgid, $qqid) = explode("X", $rt, 3); @@ -1694,7 +1725,6 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, */ } - // NICE SIMPLE SINGLE OPTION ANSWERS else { @@ -2122,7 +2152,7 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, //loop thorugh the array which contains all answer data foreach ($alist as $al) { - //picks out alist that come from the multiple list above + //picks out answer list ($alist/$al)) that come from the multiple list above if (isset($al[2]) && $al[2]) { //handling for "other" option @@ -2271,7 +2301,8 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $TotalCompleted -=$row[0]; } $fname="$al[1]"; - if ($browse===true) $fname .= " "; + if ($browse===true) $fname .= " "; } /* @@ -2291,9 +2322,8 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, if ($al[0] == "Answers") { $fname= "$al[1]"; - if ($browse===true) $fname .= " "; + if ($browse===true) $fname .= " "; } elseif ($al[0] == "NoAnswer") { @@ -2669,10 +2699,19 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, * 3 (25%) = percentage */ $statisticsoutput .= "\t\n\t\t\n" + ."\t\t\n"; + /* + * If there is a "browse" button in this label, let's make sure there's an extra row afterwards + * to store the columnlist + * + * */ + if(strpos($label[$i], "class='statisticsbrowsebutton'")) + { + $extraline="\n"; + } //output absolute number of records - ."\t\t"; + $statisticsoutput .= "\t\t"; //no data @@ -2711,8 +2750,10 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, } elseif ($qtype == "S" || $qtype == "U" || $qtype == "T" || $qtype == "Q") { - $statisticsoutput .= "\n\t\n"; + $statisticsoutput .= "\n\t"; } + $statisticsoutput .= "\n"; //Close the row + if(isset($extraline)) {$statisticsoutput .= $extraline;} break; default: @@ -3110,6 +3151,7 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $statisticsoutput .= "\t\t"; //end output per line. there has to be a whitespace within the table cell to display correctly $statisticsoutput .= "\t\t \n\t\n"; + if(isset($extraline)) {$statisticsoutput .= $extraline;} break; default: @@ -3128,6 +3170,9 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $itemcounter++; + //Clear extraline + unset($extraline); + } //end while //only show additional values when this setting is enabled diff --git a/application/views/admin/export/statistics_view.php b/application/views/admin/export/statistics_view.php index 2b3798f64a5..752f6b6b527 100644 --- a/application/views/admin/export/statistics_view.php +++ b/application/views/admin/export/statistics_view.php @@ -8,6 +8,8 @@ ?>
    @@ -15,7 +17,7 @@ eT("General filters"); ?>
    -
    ".sprintf($statlang->gT("Field summary for %s"),$qtitle).":" + ."
    $qquestion
    " + .$statlang->gT("Calculation")."" + .$statlang->gT("Result")."
    ".$res[0]."".$res[1]."
    " . $label[$i] ."\n" - ."\t\t
    " . $grawdata[$i] . "\n" . $grawdata[$i] . "\n
    > diff --git a/scripts/admin/statistics.js b/scripts/admin/statistics.js index 76692f3ea5b..9df9b863b25 100644 --- a/scripts/admin/statistics.js +++ b/scripts/admin/statistics.js @@ -1,4 +1,14 @@ $(document).ready(function(){ + $('.statisticsbrowsebutton').click( function(){ + var destinationdiv=$('#columnlist_'+this.id); + destinationdiv.parents("td:first").toggle(); + if(destinationdiv.parents("td:first").css("display") != "none") { + $.post(listColumnUrl+'/'+this.id+'/sql/'+sql, function(data) { + destinationdiv.html(data); + }); + } + + }); $('#usegraph').click( function(){ if ($('#grapherror').length>0) { @@ -360,4 +370,5 @@ function changeGraphType (cmd, id) { $("#statzone_" + id + " .wait").remove(); $("#statzone_" + id + ">img:first").attr("src", temppath +"/"+data.chartdata); }); + } diff --git a/styles/blobblueish/adminstyle.css b/styles/blobblueish/adminstyle.css index cc42b035e98..efc0d525327 100644 --- a/styles/blobblueish/adminstyle.css +++ b/styles/blobblueish/adminstyle.css @@ -961,6 +961,21 @@ table.statisticstable, table.statisticssummary { text-align:center; } +.statisticsbrowsecolumn { + text-align: left; + width: 100%; +} +.statisticscolumnid { + float: left; + text-align: center; + width: 9%; + padding-right: 4px; +} +.statisticscolumndata { + float: left; + width: 89%; +} + div.messagebox { width: 550px; margin:10px auto; diff --git a/styles/gartergrey/adminstyle.css b/styles/gartergrey/adminstyle.css index 8f60568810c..04ff0ce262e 100644 --- a/styles/gartergrey/adminstyle.css +++ b/styles/gartergrey/adminstyle.css @@ -665,6 +665,20 @@ div.messagebox .warningheader { padding:3px 10px; } +.statisticsbrowsecolumn { + text-align: left; + width: 100%; +} +.statisticscolumnid { + float: left; + text-align: center; + width: 9%; + padding-right: 4px; +} +.statisticscolumndata { + float: left; + width: 89%; +} .conditionlist, .conditionlist table, diff --git a/styles/gringegreen/adminstyle.css b/styles/gringegreen/adminstyle.css index df68966b0f2..6061782336c 100644 --- a/styles/gringegreen/adminstyle.css +++ b/styles/gringegreen/adminstyle.css @@ -986,6 +986,22 @@ table.statisticstable, table.statisticssummary { text-align:center; } +.statisticsbrowsecolumn { + text-align: left; + width: 100%; + background-color: #EFFBDB; +} +.statisticscolumnid { + float: left; + text-align: center; + width: 9%; + padding-right: 4px; +} +.statisticscolumndata { + float: left; + width: 89%; +} + div.messagebox { width: 550px; margin:10px auto; From 1b837e94e66b42bc553d88fb84f2ec51eb887c41 Mon Sep 17 00:00:00 2001 From: Carsten Schmitz Date: Mon, 23 Jul 2012 15:22:32 +0200 Subject: [PATCH 22/71] Fixed issue #6348: Bar chart not translated in statistics when changing statistics language --- .../helpers/admin/statistics_helper.php | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/application/helpers/admin/statistics_helper.php b/application/helpers/admin/statistics_helper.php index 9bf1da3a205..a74242d9e77 100644 --- a/application/helpers/admin/statistics_helper.php +++ b/application/helpers/admin/statistics_helper.php @@ -17,8 +17,8 @@ /** * * Generate a chart for a question -* @param mixed $qid ID of the question -* @param mixed $sid ID of the survey +* @param mixed $iQuestionID ID of the question +* @param mixed $iSurveyID ID of the survey * @param mixed $type Type of the chart to be created * @param mixed $cache * @param mixed $lbl @@ -27,7 +27,7 @@ * @param mixed $cache * @return Name */ -function createChart($qid, $sid, $type, $lbl, $gdata, $grawdata, $cache) +function createChart($iQuestionID, $iSurveyID, $type, $lbl, $gdata, $grawdata, $cache) { $rootdir = Yii::app()->getConfig("rootdir"); $homedir = Yii::app()->getConfig("homedir"); @@ -36,7 +36,7 @@ function createChart($qid, $sid, $type, $lbl, $gdata, $grawdata, $cache) $scriptname = Yii::app()->getConfig("scriptname"); $chartfontfile = Yii::app()->getConfig("chartfontfile"); $chartfontsize = Yii::app()->getConfig("chartfontsize"); - $language = Survey::model()->findByPk($sid)->language; + $language = Survey::model()->findByPk($iSurveyID)->language; if ($chartfontfile=='auto') { @@ -114,9 +114,9 @@ function createChart($qid, $sid, $type, $lbl, $gdata, $grawdata, $cache) $counter++; } - if ($cache->IsInCache("graph".$sid,$DataSet->GetData())) + if ($cache->IsInCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData())) { - $cachefilename=basename($cache->GetFileFromCache("graph".$sid,$DataSet->GetData())); + $cachefilename=basename($cache->GetFileFromCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData())); } else { @@ -146,8 +146,8 @@ function createChart($qid, $sid, $type, $lbl, $gdata, $grawdata, $cache) $graph->setFontProperties($rootdir.DIRECTORY_SEPARATOR.'fonts'.DIRECTORY_SEPARATOR.$chartfontfile, $chartfontsize); $graph->drawLegend(510,30,$DataSet->GetDataDescription(),255,255,255); - $cache->WriteToCache("graph".$sid,$DataSet->GetData(),$graph); - $cachefilename=basename($cache->GetFileFromCache("graph".$sid,$DataSet->GetData())); + $cache->WriteToCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData(),$graph); + $cachefilename=basename($cache->GetFileFromCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData())); unset($graph); } } //end if (bar chart) @@ -203,9 +203,9 @@ function createChart($qid, $sid, $type, $lbl, $gdata, $grawdata, $cache) $DataSet->AddAllSeries(); $DataSet->SetAbsciseLabelSerie("Serie2"); - if ($cache->IsInCache("graph".$sid, $DataSet->GetData())) + if ($cache->IsInCache("graph".$statlang->langcode.$iSurveyID, $DataSet->GetData())) { - $cachefilename=basename($cache->GetFileFromCache("graph".$sid,$DataSet->GetData())); + $cachefilename=basename($cache->GetFileFromCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData())); } else { @@ -221,8 +221,8 @@ function createChart($qid, $sid, $type, $lbl, $gdata, $grawdata, $cache) $graph->drawPieGraph($DataSet->GetData(),$DataSet->GetDataDescription(),225,round($gheight/2),170,PIE_PERCENTAGE,TRUE,50,20,5); $graph->setFontProperties($rootdir."/fonts/".$chartfontfile,$chartfontsize); $graph->drawPieLegend(430,12,$DataSet->GetData(),$DataSet->GetDataDescription(),250,250,250); - $cache->WriteToCache("graph".$sid,$DataSet->GetData(),$graph); - $cachefilename=basename($cache->GetFileFromCache("graph".$sid,$DataSet->GetData())); + $cache->WriteToCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData(),$graph); + $cachefilename=basename($cache->GetFileFromCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData())); unset($graph); } } //end else -> pie charts @@ -984,13 +984,13 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, while (!in_array ($tmpqid,$legitqids)) $tmpqid=substr($tmpqid, 0, strlen($tmpqid)-1); //length of QID - $qidlength=strlen($tmpqid); + $iQuestionIDlength=strlen($tmpqid); //we somehow get the answer code (see SQL later) from the $qqid - $qaid=substr($qqid, $qidlength, strlen($qqid)-$qidlength); + $qaid=substr($qqid, $iQuestionIDlength, strlen($qqid)-$iQuestionIDlength); //get some question data - $nquery = "SELECT title, type, question, other FROM {{questions}} WHERE qid='".substr($qqid, 0, $qidlength)."' AND parent_qid=0 AND language='{$language}'"; + $nquery = "SELECT title, type, question, other FROM {{questions}} WHERE qid='".substr($qqid, 0, $iQuestionIDlength)."' AND parent_qid=0 AND language='{$language}'"; $nresult = Yii::app()->db->createCommand($nquery)->query(); //more substrings @@ -1006,7 +1006,7 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, } //get answers - $qquery = "SELECT title as code, question as answer FROM {{questions}} WHERE parent_qid='".substr($qqid, 0, $qidlength)."' AND title='$qaid' AND language='{$language}' ORDER BY question_order"; + $qquery = "SELECT title as code, question as answer FROM {{questions}} WHERE parent_qid='".substr($qqid, 0, $iQuestionIDlength)."' AND title='$qaid' AND language='{$language}' ORDER BY question_order"; $qresult=Yii::app()->db->createCommand($qquery)->query(); //loop through answer data @@ -1240,15 +1240,15 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $tmpqid=substr($tmpqid, 0, strlen($tmpqid)-1); //check lenght of ID - $qidlength=strlen($tmpqid); + $iQuestionIDlength=strlen($tmpqid); //get answer ID from qid - $qaid=substr($qqid, $qidlength, strlen($qqid)-$qidlength); + $qaid=substr($qqid, $iQuestionIDlength, strlen($qqid)-$iQuestionIDlength); //get question details from DB $nquery = "SELECT title, type, question, qid, parent_qid FROM {{questions}} - WHERE parent_qid=0 AND qid='".substr($qqid, 0, $qidlength)."' + WHERE parent_qid=0 AND qid='".substr($qqid, 0, $iQuestionIDlength)."' AND language='{$language}'"; $nresult = Yii::app()->db->createCommand($nquery)->query(); } @@ -1879,31 +1879,31 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, case ":": //Array (Multiple Flexi) (Numbers) - $qidattributes=getQuestionAttributeValues($qiqid); - if (trim($qidattributes['multiflexible_max'])!='') { - $maxvalue=$qidattributes['multiflexible_max']; + $aQuestionAttributes=getQuestionAttributeValues($qiqid); + if (trim($aQuestionAttributes['multiflexible_max'])!='') { + $maxvalue=$aQuestionAttributes['multiflexible_max']; } else { $maxvalue=10; } - if (trim($qidattributes['multiflexible_min'])!='') + if (trim($aQuestionAttributes['multiflexible_min'])!='') { - $minvalue=$qidattributes['multiflexible_min']; + $minvalue=$aQuestionAttributes['multiflexible_min']; } else { $minvalue=1; } - if (trim($qidattributes['multiflexible_step'])!='') + if (trim($aQuestionAttributes['multiflexible_step'])!='') { - $stepvalue=$qidattributes['multiflexible_step']; + $stepvalue=$aQuestionAttributes['multiflexible_step']; } else { $stepvalue=1; } - if ($qidattributes['multiflexible_checkbox']!=0) { + if ($aQuestionAttributes['multiflexible_checkbox']!=0) { $minvalue=0; $maxvalue=1; $stepvalue=1; @@ -1988,7 +1988,7 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $sSubquestion = flattenText($questionDesc["question"]); //get question attributes - $qidattributes=getQuestionAttributeValues($qqid); + $aQuestionAttributes=getQuestionAttributeValues($qqid); //check last character -> label 1 if (substr($rt,-1,1) == 0) @@ -1997,9 +1997,9 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $fquery = "SELECT * FROM {{answers}} WHERE qid='{$qqid}' AND scale_id=0 AND language='{$language}' ORDER BY sortorder, code"; //header available? - if (trim($qidattributes['dualscale_headerA'][$language])!='') { + if (trim($aQuestionAttributes['dualscale_headerA'][$language])!='') { //output - $labelheader= "[".$qidattributes['dualscale_headerA'][$language]."]"; + $labelheader= "[".$aQuestionAttributes['dualscale_headerA'][$language]."]"; } //no header @@ -2019,9 +2019,9 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $fquery = "SELECT * FROM {{answers}} WHERE qid='{$qqid}' AND scale_id=1 AND language='{$language}' ORDER BY sortorder, code"; //header available? - if (trim($qidattributes['dualscale_headerB'][$language])!='') { + if (trim($aQuestionAttributes['dualscale_headerB'][$language])!='') { //output - $labelheader= "[".$qidattributes['dualscale_headerB'][$language]."]"; + $labelheader= "[".$aQuestionAttributes['dualscale_headerB'][$language]."]"; } //no header From e2aca66c357190841c1617252ec0ac74a5609bc8 Mon Sep 17 00:00:00 2001 From: Carsten Schmitz Date: Mon, 23 Jul 2012 15:28:31 +0200 Subject: [PATCH 23/71] Fixed issue #6348: Bar chart not translated in statistics when changing statistics language --- application/helpers/admin/statistics_helper.php | 16 ++++++++-------- .../views/admin/export/statistics_view.php | 2 +- tmp/.gitignore | 1 + 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/application/helpers/admin/statistics_helper.php b/application/helpers/admin/statistics_helper.php index a74242d9e77..659f0ff34d7 100644 --- a/application/helpers/admin/statistics_helper.php +++ b/application/helpers/admin/statistics_helper.php @@ -114,9 +114,9 @@ function createChart($iQuestionID, $iSurveyID, $type, $lbl, $gdata, $grawdata, $ $counter++; } - if ($cache->IsInCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData())) + if ($cache->IsInCache("graph".$language.$iSurveyID,$DataSet->GetData())) { - $cachefilename=basename($cache->GetFileFromCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData())); + $cachefilename=basename($cache->GetFileFromCache("graph".$language.$iSurveyID,$DataSet->GetData())); } else { @@ -146,8 +146,8 @@ function createChart($iQuestionID, $iSurveyID, $type, $lbl, $gdata, $grawdata, $ $graph->setFontProperties($rootdir.DIRECTORY_SEPARATOR.'fonts'.DIRECTORY_SEPARATOR.$chartfontfile, $chartfontsize); $graph->drawLegend(510,30,$DataSet->GetDataDescription(),255,255,255); - $cache->WriteToCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData(),$graph); - $cachefilename=basename($cache->GetFileFromCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData())); + $cache->WriteToCache("graph".$language.$iSurveyID,$DataSet->GetData(),$graph); + $cachefilename=basename($cache->GetFileFromCache("graph".$language.$iSurveyID,$DataSet->GetData())); unset($graph); } } //end if (bar chart) @@ -203,9 +203,9 @@ function createChart($iQuestionID, $iSurveyID, $type, $lbl, $gdata, $grawdata, $ $DataSet->AddAllSeries(); $DataSet->SetAbsciseLabelSerie("Serie2"); - if ($cache->IsInCache("graph".$statlang->langcode.$iSurveyID, $DataSet->GetData())) + if ($cache->IsInCache("graph".$language.$iSurveyID, $DataSet->GetData())) { - $cachefilename=basename($cache->GetFileFromCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData())); + $cachefilename=basename($cache->GetFileFromCache("graph".$language.$iSurveyID,$DataSet->GetData())); } else { @@ -221,8 +221,8 @@ function createChart($iQuestionID, $iSurveyID, $type, $lbl, $gdata, $grawdata, $ $graph->drawPieGraph($DataSet->GetData(),$DataSet->GetDataDescription(),225,round($gheight/2),170,PIE_PERCENTAGE,TRUE,50,20,5); $graph->setFontProperties($rootdir."/fonts/".$chartfontfile,$chartfontsize); $graph->drawPieLegend(430,12,$DataSet->GetData(),$DataSet->GetDataDescription(),250,250,250); - $cache->WriteToCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData(),$graph); - $cachefilename=basename($cache->GetFileFromCache("graph".$statlang->langcode.$iSurveyID,$DataSet->GetData())); + $cache->WriteToCache("graph".$language.$iSurveyID,$DataSet->GetData(),$graph); + $cachefilename=basename($cache->GetFileFromCache("graph".$language.$iSurveyID,$DataSet->GetData())); unset($graph); } } //end else -> pie charts diff --git a/application/views/admin/export/statistics_view.php b/application/views/admin/export/statistics_view.php index 752f6b6b527..97861b2f8c1 100644 --- a/application/views/admin/export/statistics_view.php +++ b/application/views/admin/export/statistics_view.php @@ -9,7 +9,7 @@
    diff --git a/tmp/.gitignore b/tmp/.gitignore index c09eefefa1f..9d875d2e4ef 100644 --- a/tmp/.gitignore +++ b/tmp/.gitignore @@ -1,3 +1,4 @@ *.html /*.lss +/*.png From 5ff46ab813a851efb0328322e6312bbc1835e086 Mon Sep 17 00:00:00 2001 From: Denis Chenu Date: Mon, 23 Jul 2012 17:55:55 +0200 Subject: [PATCH 24/71] Dev fixed issue : Bad HTML for statistics with Ranking with HTML Dev: replace htmlspecialchars by flattenText : is this good ? --- application/helpers/qanda_helper.php | 2 +- application/views/admin/export/statistics_view.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/helpers/qanda_helper.php b/application/helpers/qanda_helper.php index 36df63dab78..ee93be325c7 100644 --- a/application/helpers/qanda_helper.php +++ b/application/helpers/qanda_helper.php @@ -2112,7 +2112,7 @@ function do_ranking($ia) $answer .= SELECTED; $thisvalue=$_SESSION['survey_'.Yii::app()->getConfig('surveyID')][$myfname]; } - $answer .=">".htmlspecialchars($ansrow['answer'], ENT_QUOTES)."\n"; + $answer .=">".flattenText($ansrow['answer'])."\n"; } $answer .=""; // Hidden form: maybe can be replaced with ranking.js diff --git a/application/views/admin/export/statistics_view.php b/application/views/admin/export/statistics_view.php index 97861b2f8c1..cd32c96ed2a 100644 --- a/application/views/admin/export/statistics_view.php +++ b/application/views/admin/export/statistics_view.php @@ -1017,7 +1017,7 @@ //pre-select if (isset($_POST[$myfield3]) && is_array($_POST[$myfield3]) && in_array("$ans[0]", $_POST[$myfield3])) {echo " selected";} - echo ">$ans[1]\n"; + echo ">".flattenText($ans[1])."\n"; } echo "\t\n\t\n"; From ad34a775ee539c5fe38c00d8908db9e758151e4f Mon Sep 17 00:00:00 2001 From: Denis Chenu Date: Mon, 23 Jul 2012 18:21:42 +0200 Subject: [PATCH 25/71] Dev: flateText an some option answer in quanda to have clean HTML --- application/helpers/qanda_helper.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/application/helpers/qanda_helper.php b/application/helpers/qanda_helper.php index ee93be325c7..ab9217dffb2 100644 --- a/application/helpers/qanda_helper.php +++ b/application/helpers/qanda_helper.php @@ -1427,7 +1427,7 @@ function do_list_dropdown($ia) if ($prefixStyle == 1) { $_prefix = ++$_rowNum . ') '; } - $answer .= "\n"; + $answer .= "\n"; } } else @@ -1451,7 +1451,7 @@ function do_list_dropdown($ia) foreach ($optgroups as $categoryname => $optionlistarray) { - $answer .= ' + $answer .= ' '; foreach ($optionlistarray as $optionarray) @@ -1465,7 +1465,7 @@ function do_list_dropdown($ia) $opt_select = ''; } - $answer .= ' + $answer .= ' '; } @@ -1483,7 +1483,7 @@ function do_list_dropdown($ia) $opt_select = ''; } - $answer .= ' + $answer .= ' '; } } @@ -1506,7 +1506,7 @@ function do_list_dropdown($ia) if ($prefixStyle == 1) { $_prefix = ++$_rowNum . ') '; } - $answer .= ' \n"; + $answer .= ' \n"; } if (($_SESSION['survey_'.Yii::app()->getConfig('surveyID')][$ia[1]] || $_SESSION['survey_'.Yii::app()->getConfig('surveyID')][$ia[1]] != '') && $ia[6] != 'Y' && $ia[6] != 'Y' && SHOW_NO_ANSWER == 1) @@ -5071,7 +5071,7 @@ function do_array($ia) { $answer .= SELECTED; } - $answer .= '>'.$lrow['answer']."\n"; + $answer .= '>'.flattenText($lrow['answer'])."\n"; } // If not mandatory and showanswer, show no ans if ($ia[6] != 'Y' && SHOW_NO_ANSWER == 1) @@ -6517,7 +6517,7 @@ function do_array_dual($ia) { $answer .= SELECTED; } - $answer .= '>'.$lrow['title']."\n"; + $answer .= '>'.flattenText($lrow['title'])."\n"; } // If not mandatory and showanswer, show no ans if ($ia[6] != 'Y' && SHOW_NO_ANSWER == 1) @@ -6571,7 +6571,7 @@ function do_array_dual($ia) { $answer .= SELECTED; } - $answer .= '>'.$lrow1['title']."\n"; + $answer .= '>'.flattenText($lrow1['title'])."\n"; } // If not mandatory and showanswer, show no ans if ($ia[6] != 'Y' && SHOW_NO_ANSWER == 1) From ffd139de85d2bb1d8579f61373ee19aa88157142 Mon Sep 17 00:00:00 2001 From: Carsten Schmitz Date: Mon, 23 Jul 2012 20:52:51 +0200 Subject: [PATCH 26/71] Fixed issue #6374: Cannot delete survey response --- application/controllers/admin/dataentry.php | 10 +- application/controllers/admin/responses.php | 54 ++-- .../admin/responses/browseallrow_view.php | 4 +- scripts/admin/browse.js | 293 +++++++++--------- 4 files changed, 187 insertions(+), 174 deletions(-) diff --git a/application/controllers/admin/dataentry.php b/application/controllers/admin/dataentry.php index b195338626b..37aebe75fdd 100644 --- a/application/controllers/admin/dataentry.php +++ b/application/controllers/admin/dataentry.php @@ -1445,19 +1445,21 @@ public function editdata($subaction, $id, $surveyid, $language='') */ public function delete() { - $subaction = Yii::app()->request->getPost('subaction'); - $surveyid = $_REQUEST['surveyid']; + if (isset($_REQUEST['surveyid']) && !empty($_REQUEST['surveyid'])) + { + $surveyid = $_REQUEST['surveyid']; + } if (!empty($_REQUEST['sid'])) $surveyid = (int)$_REQUEST['sid']; $surveyid = sanitize_int($surveyid); - $id = Yii::app()->request->getPost('id'); + $id = $_REQUEST['id']; $aData = array( 'surveyid' => $surveyid, 'id' => $id ); - if (hasSurveyPermission($surveyid, 'responses','read') && $subaction == "delete" && hasSurveyPermission($surveyid, 'responses', 'delete')) + if (hasSurveyPermission($surveyid, 'responses','read') && hasSurveyPermission($surveyid, 'responses', 'delete')) { $surveytable = "{{survey_".$surveyid.'}}'; $aData['thissurvey'] = getSurveyInfo($surveyid); diff --git a/application/controllers/admin/responses.php b/application/controllers/admin/responses.php index f27a1edfb77..947490eb0c7 100644 --- a/application/controllers/admin/responses.php +++ b/application/controllers/admin/responses.php @@ -294,13 +294,36 @@ public function index($iSurveyId) $aViewUrls[] = 'browseallfiltered_view'; } + $clang = $aData['clang']; + $aData['num_total_answers'] = Survey_dynamic::model($iSurveyId)->count(); + $aData['num_completed_answers'] = Survey_dynamic::model($iSurveyId)->count('submitdate IS NOT NULL'); + $aData['with_token']= Yii::app()->db->schema->getTable('{{tokens_' . $iSurveyId . '}}'); + if($aData['with_token']) + { + $aData['tokeninfo'] = Tokens_dynamic::model($iSurveyId)->summary(); + } + + $aViewUrls[] = 'browseindex_view'; + $this->_renderWrappedTemplate('',$aViewUrls, $aData); + } + + + function browse($iSurveyId) + { + $aData = $this->_getData($iSurveyId); + extract($aData); + $aViewUrls = array(); + $oBrowseLanguage = new Limesurvey_lang($aData['language']); + + + //Delete Individual answer using inrow delete buttons/links - checked if (Yii::app()->request->getPost('deleteanswer') && Yii::app()->request->getPost('deleteanswer') != '' && Yii::app()->request->getPost('deleteanswer') != 'marked' && hasSurveyPermission($iSurveyId, 'responses', 'delete')) { - $_POST['deleteanswer'] = (int) Yii::app()->request->getPost('deleteanswer'); // sanitize the value + $iResponseID = (int) Yii::app()->request->getPost('deleteanswer'); // sanitize the value // delete the files as well if its a fuqt - $fieldmap = createFieldMap($iSurveyId,'full',false,false,Yii::app()->session['browselang']); + $fieldmap = createFieldMap($iSurveyId,'full',false,false,$oBrowseLanguage->langcode); $fuqtquestions = array(); // find all fuqt questions foreach ($fieldmap as $field) @@ -329,7 +352,9 @@ public function index($iSurveyId) } // delete the row - Survey_dynamic::model($iSurveyId)->deleteAllByAttributes(array('id' => mysql_real_escape_string(Yii::app()->request->getPost('deleteanswer')))); + Survey_dynamic::model($iSurveyId)->deleteAllByAttributes(array('id' => $iResponseID)); + Yii::app()->session['flashmessage'] = sprintf($clang->gT("Response ID %s was successfully deleted."),$iResponseID); + } // Marked responses -> deal with the whole batch of marked responses if (Yii::app()->request->getPost('markedresponses') && count(Yii::app()->request->getPost('markedresponses')) > 0 && hasSurveyPermission($iSurveyId, 'responses', 'delete')) @@ -337,7 +362,7 @@ public function index($iSurveyId) // Delete the marked responses - checked if (Yii::app()->request->getPost('deleteanswer') && Yii::app()->request->getPost('deleteanswer') === 'marked') { - $fieldmap = createFieldMap($iSurveyId,'full',false,false,Yii::app()->session['browselang']); + $fieldmap = createFieldMap($iSurveyId,'full',false,false,$oBrowseLanguage->langcode); $fuqtquestions = array(); // find all fuqt questions foreach ($fieldmap as $field) @@ -371,6 +396,8 @@ public function index($iSurveyId) Survey_dynamic::model($iSurveyId)->deleteAllByAttributes(array('id' => $iResponseID)); } + Yii::app()->session['flashmessage'] = sprintf($clang->ngT("%s response was successfully deleted.","%s responses were successfully deleted.",count(Yii::app()->request->getPost('markedresponses'))),count(Yii::app()->request->getPost('markedresponses'))); + } // Download all files for all marked responses - checked else if (Yii::app()->request->getPost('downloadfile') && Yii::app()->request->getPost('downloadfile') === 'marked') @@ -422,25 +449,6 @@ public function index($iSurveyId) } } - $clang = $aData['clang']; - $aData['num_total_answers'] = Survey_dynamic::model($iSurveyId)->count(); - $aData['num_completed_answers'] = Survey_dynamic::model($iSurveyId)->count('submitdate IS NOT NULL'); - $aData['with_token']= Yii::app()->db->schema->getTable('{{tokens_' . $iSurveyId . '}}'); - if($aData['with_token']) - { - $aData['tokeninfo'] = Tokens_dynamic::model($iSurveyId)->summary(); - } - - $aViewUrls[] = 'browseindex_view'; - $this->_renderWrappedTemplate('',$aViewUrls, $aData); - } - function browse($iSurveyId) - { - $aData = $this->_getData($iSurveyId); - extract($aData); - $aViewUrls = array(); - $oBrowseLanguage = new Limesurvey_lang($aData['language']); - /** * fnames is used as informational array * it containts diff --git a/application/views/admin/responses/browseallrow_view.php b/application/views/admin/responses/browseallrow_view.php index 2b920719bb6..d3487b37eb8 100644 --- a/application/views/admin/responses/browseallrow_view.php +++ b/application/views/admin/responses/browseallrow_view.php @@ -8,11 +8,11 @@ - ' src='/down.png' alt='eT('Download all files in this response as a zip file'); ?>' class='downloadfile'/> + ' src='down.png' alt='eT('Download all files in this response as a zip file'); ?>' class='downloadfile'/> - ' src='/token_delete.png' alt='eT('Delete this response'); ?>' class='deleteresponse'/> + ' src='token_delete.png' alt='eT('Delete this response'); ?>' class='deleteresponse'/> 0) - { - thisid=removechars($(this).attr('id')); - answer = confirm(strDeleteAllConfirm); - if (answer==true) - { - $('#deleteanswer').val('marked'); - $('#resulttableform').submit(); - } - } - else - alert(noFilesSelectedForDeletion) - }); - // Download individual file bundle - $(".downloadfile").click(function() { - thisid = removechars($(this).attr('id')); - $('#downloadfile').val(thisid); - $('.cbResponseMarker').attr('checked', false); - $('#resulttableform').submit(); - }); - // Download all marked files - $("#imgDownloadMarkedFiles").click(function() { - if ($('.cbResponseMarker:checked').size() > 0) - { - $('#downloadfile').val('marked'); - $('#resulttableform').submit(); - } - else - alert(noFilesSelectedForDnld) - }); $("#selectall").click(function(){ $('.cbResponseMarker').attr('checked',$(this).attr('checked')); @@ -65,30 +21,30 @@ $(document).ready(function(){ $('#browseresponses').qtip({ content:{ - text:$('#browselangpopup') + text:$('#browselangpopup') }, style: { name: 'cream', - tip:true, - color:'#111111', - border: { - width: 1, - radius: 5, - color: '#EADF95'} - }, + tip:true, + color:'#111111', + border: { + width: 1, + radius: 5, + color: '#EADF95'} + }, position: { adjust: { screen: true, scroll:true }, - corner: { - target: 'bottomMiddle', - tooltip: 'topMiddle'} - }, + corner: { + target: 'bottomMiddle', + tooltip: 'topMiddle'} + }, show: {effect: { length:50}, - when: { - event:'click' - }}, + when: { + event:'click' + }}, hide: {fixed:true, - when: { - event:'unfocus' - }} + when: { + event:'unfocus' + }} }); // Fix the heigh of the cell @@ -102,7 +58,7 @@ $(document).ready(function(){ $(this).addClass("content"); $(this).attr("title",$(this).text()); } - }); + }); $('.browsetable td span.content').qtip({ hide: { @@ -128,121 +84,168 @@ $(document).ready(function(){ } } }); + // Delete individual file + $(".deleteresponse").click(function(){ + thisid=removechars($(this).attr('id')); + answer = confirm(strdeleteconfirm); + if (answer==true) + { + $('#deleteanswer').val(thisid); + $('.cbResponseMarker').attr('checked',false); + $('#resulttableform').submit(); + } + }); + // Delete all marked responses + $("#imgDeleteMarkedResponses").click(function(){ + if ($('.cbResponseMarker:checked').size()>0) + { + thisid=removechars($(this).attr('id')); + answer = confirm(strDeleteAllConfirm); + if (answer==true) + { + $('#deleteanswer').val('marked'); + $('#resulttableform').submit(); + } + } + else + alert(noFilesSelectedForDeletion) + }); + + // Download individual file bundle + $(".downloadfile").click(function() { + thisid = removechars($(this).attr('id')); + $('#downloadfile').val(thisid); + $('.cbResponseMarker').attr('checked', false); + $('#resulttableform').submit(); + }); + + // Download all marked files + $("#imgDownloadMarkedFiles").click(function() { + if ($('.cbResponseMarker:checked').size() > 0) + { + $('#downloadfile').val('marked'); + $('#resulttableform').submit(); + } + else + alert(noFilesSelectedForDnld) + }); + + }); /* $("#responseTable") - .jqGrid({ - url: siteURL + "/admin/responses/" + surveyID + "/grid", - editurl: siteURL + "/admin/responses/" + surveyID + "/grid", - datatype: "json", - mtype: "POST", - caption: "Responses", - width: "100%", - height: "100%", - rowNum: 25, - pager: "#responsePager", - editable: true, - colNames: colNames, - colModel: colModel, - sortname: 'id', - sortorder: 'asc', - viewrecords : true, - gridview: true, - multiselect: true, - loadonce: true, - rowList: [25,50,100,250,500,1000,5000,10000], - ondblClickRow: function(id) { - if (lastSel != id) { - $('#responseTable').saveRow(lastSel); - $('#responseTable').editRow(id, true); - lastSel=id; - } - }, - onSelectRow: function(id) { - $('#responseTable').saveRow(lastSel); - } - }) - .filterToolbar({ - 'autosearch': true, - 'searchOnEnter': false - }) - .navGrid("#responsePager", { - 'add': false, - 'refresh': false, - 'edit': false - }) - .navButtonAdd("#responsePager", { - 'caption': 'Download marked files', - 'onClickButton': function (rows) { - var rows = $("#responseTable").getGridParam('selarrrow'); - - if (rows.length <= 0) { - alert ("Please select some records first!"); - return; - } - - sendPost(siteURL + "/admin/responses/" + surveyID + "/grid", { - 'oper': 'downloadarchives', - 'ids': rows - }); - } - }) */ +.jqGrid({ +url: siteURL + "/admin/responses/" + surveyID + "/grid", +editurl: siteURL + "/admin/responses/" + surveyID + "/grid", +datatype: "json", +mtype: "POST", +caption: "Responses", +width: "100%", +height: "100%", +rowNum: 25, +pager: "#responsePager", +editable: true, +colNames: colNames, +colModel: colModel, +sortname: 'id', +sortorder: 'asc', +viewrecords : true, +gridview: true, +multiselect: true, +loadonce: true, +rowList: [25,50,100,250,500,1000,5000,10000], +ondblClickRow: function(id) { +if (lastSel != id) { +$('#responseTable').saveRow(lastSel); +$('#responseTable').editRow(id, true); +lastSel=id; +} +}, +onSelectRow: function(id) { +$('#responseTable').saveRow(lastSel); +} +}) +.filterToolbar({ +'autosearch': true, +'searchOnEnter': false +}) +.navGrid("#responsePager", { +'add': false, +'refresh': false, +'edit': false +}) +.navButtonAdd("#responsePager", { +'caption': 'Download marked files', +'onClickButton': function (rows) { +var rows = $("#responseTable").getGridParam('selarrrow'); + +if (rows.length <= 0) { +alert ("Please select some records first!"); +return; +} + +sendPost(siteURL + "/admin/responses/" + surveyID + "/grid", { +'oper': 'downloadarchives', +'ids': rows +}); +} +}) */ /** - Send a post request to the server to download a file +Send a post request to the server to download a file - @param myaction post action - @param data parameters for $_POST +@param myaction post action +@param data parameters for $_POST */ function sendPost(myaction, data) { - var myform = document.createElement('form'); - document.body.appendChild(myform); - myform.action = myaction; - myform.method = 'POST'; + var myform = document.createElement('form'); + document.body.appendChild(myform); + myform.action = myaction; + myform.method = 'POST'; - for (var key in data) { + for (var key in data) { var myel = document.createElement('input'); myel.type = 'hidden'; myel.name = key; myform.appendChild(myel); myel.value = data[key]; - } + } - myform.submit(); + myform.submit(); } /** - Dowload a file from a response - @param id ID of the response - @param column Field of the text upload question - @param filename Name of the file +Dowload a file from a response +@param id ID of the response +@param column Field of the text upload question +@param filename Name of the file */ function getFile(id, field, filename) { - sendPost(siteURL + "/admin/responses/" + surveyID + "/grid", { - 'id': id, - 'fieldname': field, - 'oper': 'downloadfile', - 'filename': filename - }); + sendPost(siteURL + "/admin/responses/" + surveyID + "/grid", { + 'id': id, + 'fieldname': field, + 'oper': 'downloadfile', + 'filename': filename + }); } /** - Get an archive containing all the file from a response - @param id ID of the response +Get an archive containing all the file from a response +@param id ID of the response */ function getArchive(id) { - sendPost(siteURL + "/admin/responses/" + surveyID + "/grid", { - 'oper': 'downloadarchive', - 'id': id - }); + sendPost(siteURL + "/admin/responses/" + surveyID + "/grid", { + 'oper': 'downloadarchive', + 'id': id + }); } From eddd048f4d7ae3ac926ce7d2284302f62870effb Mon Sep 17 00:00:00 2001 From: jcleeland Date: Tue, 24 Jul 2012 16:36:49 +1000 Subject: [PATCH 27/71] Fixed issue #6372 Browse text responses doesn't work. Also reworked much of the stats function a lot of which is still spaghetti code. Fixed issue: statistics pdf header was referring to old /image directory - updated to default to admin style image directory --- application/config/tcpdf.php | 4 +- application/controllers/admin/statistics.php | 1 + .../helpers/admin/statistics_helper.php | 4897 +++++++++-------- 3 files changed, 2467 insertions(+), 2435 deletions(-) diff --git a/application/config/tcpdf.php b/application/config/tcpdf.php index 4d5844462a9..2154ffe687f 100644 --- a/application/config/tcpdf.php +++ b/application/config/tcpdf.php @@ -75,8 +75,8 @@ * ADD TRAILING SLASH! ***********************************************************/ - $tcpdf['image_directory'] = Yii::app()->getConfig('imagedir').DIRECTORY_SEPARATOR; - + //$tcpdf['image_directory'] = Yii::app()->getConfig('imagedir').DIRECTORY_SEPARATOR; + $tcpdf['image_directory'] = Yii::app()->getConfig('rootdir').DIRECTORY_SEPARATOR.'styles'.DIRECTORY_SEPARATOR.Yii::app()->getConfig('admintheme').DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR; /************************************************************ * TCPDF default (blank) image diff --git a/application/controllers/admin/statistics.php b/application/controllers/admin/statistics.php index 25d07bf1731..10dc7b2e41b 100644 --- a/application/controllers/admin/statistics.php +++ b/application/controllers/admin/statistics.php @@ -42,6 +42,7 @@ public function run($surveyid, $subaction = null) $imageurl = Yii::app()->getConfig("imageurl"); $aData = array('clang' => $clang, 'imageurl' => $imageurl); + $aData['sql']=''; /* * We need this later: diff --git a/application/helpers/admin/statistics_helper.php b/application/helpers/admin/statistics_helper.php index 9bf1da3a205..742d6610aff 100644 --- a/application/helpers/admin/statistics_helper.php +++ b/application/helpers/admin/statistics_helper.php @@ -484,851 +484,772 @@ function buildSelects($allfields, $surveyid, $language) { } /** -* Generates statistics +* Builds an array containing information about this particular question/answer combination * -* @param int $surveyid The survey id -* @param mixed $allfields -* @param mixed $q2show -* @param mixed $usegraph -* @param string $outputType Optional - Can be xls, html or pdf - Defaults to pdf -* @param string $pdfOutput Sets the target for the PDF output: DD=File download , F=Save file to local disk -* @param string $statlangcode Lamguage for statistics -* @param mixed $browse Show browse buttons -* @return buffer +* @param string $rt The code passed from the statistics form listing the field/answer (SGQA) combination to be displayed +* @param mixed $language The language to present output in +* @param mixed $surveyid The survey id +* @param string $outputType +* +* @output array $output An array containing "alist"=>A list of answers to the question, "qtitle"=>The title of the question, +* "qquestion"=>The description of the question, "qtype"=>The question type code */ -function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $outputType='pdf', $pdfOutput='I',$statlangcode=null, $browse = true) -{ - //$allfields =""; - - global $rooturl, $rootdir, $homedir, $homeurl, $scriptname, - $chartfontfile, $chartfontsize, $admintheme, $pdfdefaultfont, $pdffontsize; - - //load surveytranslator helper - Yii::import('application.helpers.surveytranslator_helper', true); - - $imagedir = Yii::app()->getConfig("imagedir"); - $tempdir = Yii::app()->getConfig("tempdir"); - $tempurl = Yii::app()->getConfig("tempurl"); - $clang = Yii::app()->lang; - - - $astatdata = array(); +function buildOutputList($rt, $language, $surveyid, $outputType) { + + //Set up required variables + $alist=array(); + $qtitle=""; + $qquestion=""; + $qtype=""; + $statlangcode = getBaseLanguageFromSurveyID($surveyid); + $statlang = new Limesurvey_lang($statlangcode); + $firstletter = substr($rt, 0, 1); + $fieldmap=createFieldMap($surveyid, "full", false, false, $language); + $sDatabaseType = Yii::app()->db->getDriverName(); - // Used for getting coordinates for google maps - $agmapdata = array(); - //pick the best font file if font setting is 'auto' - if (is_null($statlangcode)) + /* Some variable depend on output type, actually : only line feed */ + switch($outputType) { - $statlang = getBaseLanguageFromSurveyID($surveyid); + case 'xls': + $linefeed = "\n"; + break; + case 'pdf': + $linefeed = "\n"; + break; + case 'html': + $linefeed = "
    \n"; + break; + default: + break; } - else + + // 1. Get answers for question ############################################################## + //M - Multiple choice, therefore multiple fields + if ($firstletter == "M" || $firstletter == "P") { - $statlang = new Limesurvey_lang($statlangcode); - } + //get SGQ data + list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); - /* - * this variable is used in the function shortencode() which cuts off a question/answer title - * after $maxchars and shows the rest as tooltip (in html mode) - */ - $maxchars = 13; - //we collect all the html-output within this variable - $statisticsoutput =''; - /** - * $outputType: html || pdf || - */ - /** - * get/set Survey Details - */ + //select details for this question + $nquery = "SELECT title, type, question, parent_qid, other FROM {{questions}} WHERE language='{$language}' AND parent_qid=0 AND qid='$qqid'"; + $nresult = Yii::app()->db->createCommand($nquery)->query(); - //no survey ID? -> come and get one - if (!isset($surveyid)) {$surveyid=returnGlobal('sid');} + //loop through question data + foreach ($nresult->readAll() as $nrow) + { + $nrow=array_values($nrow); + $qtitle=$nrow[0]; + $qtype=$nrow[1]; + $qquestion=flattenText($nrow[2]); + $qlid=$nrow[3]; + $qother=$nrow[4]; + } - //Get an array of codes of all available languages in this survey - $surveylanguagecodes = Survey::model()->findByPk($surveyid)->additionalLanguages; - $surveylanguagecodes[] = Survey::model()->findByPk($surveyid)->language; + //1. Get list of answers + $query="SELECT title, question FROM {{questions}} WHERE parent_qid='$qqid' AND language='{$language}' and scale_id=0 ORDER BY question_order"; + $result=Yii::app()->db->createCommand($query)->query(); - $fieldmap=createFieldMap($surveyid, "full", false, false, $statlang->getlangcode()); + //loop through multiple answers + foreach ($result->readAll() as $row) + { + $row=array_values($row); + $mfield=substr($rt, 1, strlen($rt))."$row[0]"; - // Set language for questions and answers to base language of this survey - $language=$statlangcode; + //create an array containing answer code, answer and fieldname(??) + $alist[]=array("$row[0]", flattenText($row[1]), $mfield); + } - if ($usegraph==1) - { - //for creating graphs we need some more scripts which are included here - require_once(APPPATH.'/third_party/pchart/pchart/pChart.class'); - require_once(APPPATH.'/third_party/pchart/pchart/pData.class'); - require_once(APPPATH.'/third_party/pchart/pchart/pCache.class'); - $MyCache = new pCache($tempdir.'/'); + //check "other" field. is it set? + if ($qother == "Y") + { + $mfield=substr($rt, 1, strlen($rt))."other"; + + //create an array containing answer code, answer and fieldname(??) + $alist[]=array($statlang->gT("Other"), $statlang->gT("Other"), $mfield); + } } - if($q2show=='all' ) + + //S - Short Free Text + //T - Long Free Text + elseif ($firstletter == "T" || $firstletter == "S") //Short and long text { - $summarySql=" SELECT gid, parent_qid, qid, type " - ." FROM {{questions}} WHERE parent_qid=0" - ." AND sid=$surveyid "; - $summaryRs = Yii::app()->db->createCommand($summarySql)->query()->readAll(); + //search for key + $fld = substr($rt, 1, strlen($rt)); + $fielddata=$fieldmap[$fld]; - foreach($summaryRs as $field) - { - $myField = $surveyid."X".$field['gid']."X".$field['qid']; + //get SGQA IDs + $qsid=$fielddata['sid']; + $qgid=$fielddata['gid']; + $qqid=$fielddata['qid']; - // Multiple choice get special treatment - if ($field['type'] == "M") {$myField = "M$myField";} - if ($field['type'] == "P") {$myField = "P$myField";} - //numerical input will get special treatment (arihtmetic mean, standard derivation, ...) - if ($field['type'] == "N") {$myField = "N$myField";} - if ($field['type'] == "|") {$myField = "|$myField";} + list($qanswer, $qlid)=!empty($fielddata['aid']) ? explode("_", $fielddata['aid']) : array("", ""); + //get SGQ data + //list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); - if ($field['type'] == "Q") {$myField = "Q$myField";} - // textfields get special treatment - if ($field['type'] == "S" || $field['type'] == "T" || $field['type'] == "U"){$myField = "T$myField";} - //statistics for Date questions are not implemented yet. - if ($field['type'] == "D") {$myField = "D$myField";} - if ($field['type'] == "F" || $field['type'] == "H") - { - //Get answers. We always use the answer code because the label might be too long elsewise - $query = "SELECT code, answer FROM {{answers}} WHERE qid='".$field['qid']."' AND scale_id=0 AND language='{$language}' ORDER BY sortorder, answer"; - $result = Yii::app()->db->createCommand($query)->query(); - $counter2=0; - //check all the answers - foreach ($result->readAll() as $row) - { - $row=array_values($row); - $myField = "$myField{$row[0]}"; - } - //$myField = "{$surveyid}X{$flt[1]}X{$flt[0]}{$row[0]}[]"; + //get question data + $nquery = "SELECT title, type, question, other, parent_qid FROM {{questions}} WHERE parent_qid=0 AND qid='$qqid' AND language='{$language}'"; + $nresult = Yii::app()->db->createCommand($nquery)->query(); + //loop through question data + foreach ($nresult->readAll() as $nrow) + { + $nrow=array_values($nrow); + $qtitle=flattenText($nrow[0]); + $qtype=$nrow[1]; + $qquestion=flattenText($nrow[2]); + $nlid=$nrow[4]; + } - } - if($q2show=='all') - $summary[]=$myField; + $mfield=substr($rt, 1, strlen($rt)); - //$allfields[]=$myField; - } + //Text questions either have an answer, or they don't. There's no other way of quantising the results. + // So, instead of building an array of predefined answers like we do with lists & other types, + // we instead create two "types" of possible answer - either there is a response.. or there isn't. + // This question type then can provide a % of the question answered in the summary. + $alist[]=array("Answers", $statlang->gT("Answer"), $mfield); + $alist[]=array("NoAnswer", $statlang->gT("No answer"), $mfield); } - else - { - // This gets all the 'to be shown questions' from the POST and puts these into an array - if (!is_array($q2show)) - $summary=returnGlobal('summary'); - else - $summary = $q2show; - //print_r($_POST); - //if $summary isn't an array we create one - if (isset($summary) && !is_array($summary)) - { - $summary = explode("+", $summary); - } - } - /* Some variable depend on output type, actually : only line feed */ - switch($outputType) + //Multiple short text + elseif ($firstletter == "Q") { - case 'xls': - $linefeed = "\n"; - break; - case 'pdf': - $linefeed = "\n"; - break; - case 'html': - $linefeed = "
    \n"; - break; - default: + //get SGQ data + list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); - break; - } + //separating another ID + $tmpqid=substr($qqid, 0, strlen($qqid)-1); - /** - * pdf Config - */ - if($outputType=='pdf') - { - //require_once('classes/tcpdf/config/lang/eng.php'); - global $l; - $l['w_page'] = $statlang->gT("Page",'unescaped'); - //require_once('classes/tcpdf/mypdf.php'); - Yii::import('application.libraries.admin.pdf', true); - // create new PDF document - $pdf = new Pdf(); - $pdf->SetFont($pdfdefaultfont,'',$pdffontsize); + //check if we have legid QIDs. if not create them by substringing + while (!in_array ($tmpqid,$legitqids)) $tmpqid=substr($tmpqid, 0, strlen($tmpqid)-1); - $surveyInfo = getSurveyInfo($surveyid,$language); + //length of QID + $qidlength=strlen($tmpqid); - // set document information - $pdf->SetCreator(PDF_CREATOR); - $pdf->SetAuthor('LimeSurvey'); - $pdf->SetTitle('Statistic survey '.$surveyid); - $pdf->SetSubject($surveyInfo['surveyls_title']); - $pdf->SetKeywords('LimeSurvey, Statistics, Survey '.$surveyid.''); - $pdf->SetDisplayMode('fullpage', 'two'); + //we somehow get the answer code (see SQL later) from the $qqid + $qaid=substr($qqid, $qidlength, strlen($qqid)-$qidlength); - // set header and footer fonts - $pdf->setHeaderFont(Array($pdfdefaultfont, '', PDF_FONT_SIZE_MAIN)); - $pdf->setFooterFont(Array($pdfdefaultfont, '', PDF_FONT_SIZE_DATA)); + //get some question data + $nquery = "SELECT title, type, question, other FROM {{questions}} WHERE qid='".substr($qqid, 0, $qidlength)."' AND parent_qid=0 AND language='{$language}'"; + $nresult = Yii::app()->db->createCommand($nquery)->query(); - // set default header data - $pdf->SetHeaderData("statistics.png", 10, $statlang->gT("Quick statistics",'unescaped') , $statlang->gT("Survey")." ".$surveyid." '".flattenText($surveyInfo['surveyls_title'],false,true,'UTF-8')."'"); + //more substrings + $count = substr($qqid, strlen($qqid)-1); + //loop through question data + foreach ($nresult->readAll() as $nrow) + { + $nrow=array_values($nrow); + $qtitle=flattenText($nrow[0]).'-'.$count; + $qtype=$nrow[1]; + $qquestion=flattenText($nrow[2]); + } - // set default monospaced font - $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED); + //get answers + $qquery = "SELECT title as code, question as answer FROM {{questions}} WHERE parent_qid='".substr($qqid, 0, $qidlength)."' AND title='$qaid' AND language='{$language}' ORDER BY question_order"; + $qresult=Yii::app()->db->createCommand($qquery)->query(); - //set margins - $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); - $pdf->SetHeaderMargin(PDF_MARGIN_HEADER); - $pdf->SetFooterMargin(PDF_MARGIN_FOOTER); + //loop through answer data + foreach ($qresult->readAll() as $qrow) + { + $qrow=array_values($qrow); + //store each answer here + $atext=flattenText($qrow[1]); + } - //set auto page breaks - $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); + //add this to the question title + $qtitle .= " [$atext]"; - //set image scale factor - $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); + //even more substrings... + $mfield=substr($rt, 1, strlen($rt)); - //set some language-dependent strings - $pdf->setLanguageArray($l); + //Text questions either have an answer, or they don't. There's no other way of quantising the results. + // So, instead of building an array of predefined answers like we do with lists & other types, + // we instead create two "types" of possible answer - either there is a response.. or there isn't. + // This question type then can provide a % of the question answered in the summary. + $alist[]=array("Answers", $statlang->gT("Answer"), $mfield); + $alist[]=array("NoAnswer", $statlang->gT("No answer"), $mfield); } - if($outputType=='xls') + + + //RANKING OPTION + elseif ($firstletter == "R") { - /** - * Initiate the Spreadsheet_Excel_Writer - */ - Yii::import('application.libraries.admin.pear.Spreadsheet.Excel.Xlswriter', true); - if($pdfOutput=='F') - $workbook = new Xlswriter($tempdir.'/statistic-survey'.$surveyid.'.xls'); - else - $workbook = new Xlswriter(); + //getting the needed IDs somehow + $lengthofnumeral=substr($rt, strpos($rt, "-")+1, 1); + list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strpos($rt, "-")-($lengthofnumeral+1)), 3); - $workbook->setVersion(8); - // Inform the module that our data will arrive as UTF-8. - // Set the temporary directory to avoid PHP error messages due to open_basedir restrictions and calls to tempnam("", ...) - if (!empty($tempdir)) { - $workbook->setTempDir($tempdir); + //get question data + $nquery = "SELECT title, type, question FROM {{questions}} WHERE parent_qid=0 AND qid='$qqid' AND language='{$language}'"; + $nresult = Yii::app()->db->createCommand($nquery)->query(); + + //loop through question data + foreach ($nresult->readAll() as $nrow) + { + $nrow=array_values($nrow); + $qtitle=flattenText($nrow[0]). " [".substr($rt, strpos($rt, "-")-($lengthofnumeral), $lengthofnumeral)."]"; + $qtype=$nrow[1]; + $qquestion=flattenText($nrow[2]). "[".$statlang->gT("Ranking")." ".substr($rt, strpos($rt, "-")-($lengthofnumeral), $lengthofnumeral)."]"; } - if ($pdfOutput!='F') - $workbook->send('statistic-survey'.$surveyid.'.xls'); - // Creating the first worksheet - $sheet =& $workbook->addWorksheet(utf8_decode('results-survey'.$surveyid)); - $sheet->setInputEncoding('utf-8'); - $sheet->setColumn(0,20,20); - $separator="~|"; - /**XXX*/ + //get answers + $query="SELECT code, answer FROM {{answers}} WHERE qid='$qqid' AND scale_id=0 AND language='{$language}' ORDER BY sortorder, answer"; + $result=Yii::app()->db->createCommand($query)->query(); + + //loop through answers + foreach ($result->readAll() as $row) + { + $row=array_values($row); + //create an array containing answer code, answer and fieldname(??) + $mfield=substr($rt, 1, strpos($rt, "-")-1); + $alist[]=array("$row[0]", flattenText($row[1]), $mfield); + } } - /** - * Start generating - */ + else if ($firstletter == "|") // File UPload + { + //get SGQ data + list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); - $selects=buildSelects($allfields, $surveyid, $language); + //select details for this question + $nquery = "SELECT title, type, question, parent_qid, other FROM {{questions}} WHERE language='{$language}' AND parent_qid=0 AND qid='$qqid'"; + $nresult = Yii::app()->db->createCommand($nquery)->query(); - //count number of answers - $query = "SELECT count(*) FROM {{survey_$surveyid}}"; + //loop through question data + foreach ($nresult->readAll() as $nrow) + { + $nrow=array_values($nrow); + $qtitle=$nrow[0]; + $qtype=$nrow[1]; + $qquestion=flattenText($nrow[2]); + $qlid=$nrow[3]; + $qother=$nrow[4]; + } - //if incompleted answers should be filtert submitdate has to be not null - if (incompleteAnsFilterState() == "inc") {$query .= " WHERE submitdate is null";} - elseif (incompleteAnsFilterState() == "filter") {$query .= " WHERE submitdate is not null";} - $result = Yii::app()->db->createCommand($query)->query(); + /* + 4) Average size of file per respondent + 5) Average no. of files + 5) Summary/count of file types (ie: 37 jpg, 65 gif, 12 png) + 6) Total size of all files (useful if you re about to download them all) + 7) You could also add things like smallest file size, largest file size, median file size + 8) no. of files corresponding to each extension + 9) max file size + 10) min file size + */ - //$total = total number of answers - $row=$result->read(); $total=reset($row); + // 1) Total number of files uploaded + // 2) Number of respondents who uploaded at least one file (with the inverse being the number of respondents who didn t upload any) + $fieldname=substr($rt, 1, strlen($rt)); + $query = "SELECT SUM(".Yii::app()->db->quoteColumnName($fieldname.'_filecount').") as sum, AVG(".Yii::app()->db->quoteColumnName($fieldname.'_filecount').") as avg FROM {{survey_$surveyid}}"; + $result=Yii::app()->db->createCommand($query)->query(); - //are there any filters that have to be taken care of? - if (isset($selects) && $selects) - { - //filter incomplete answers? - if (incompleteAnsFilterState() == "filter" || incompleteAnsFilterState() == "inc") {$query .= " AND ";} + $showem = array(); - else {$query .= " WHERE ";} + foreach ($result->readAll() as $row) + { + $showem[]=array($statlang->gT("Total number of files"), $row['sum']); + $showem[]=array($statlang->gT("Average no. of files per respondent"), $row['avg']); + } - //add filter criteria to SQL - $query .= implode(" AND ", $selects); - } + $query = "SELECT ". $fieldname ." as json FROM {{survey_$surveyid}}"; + $result=Yii::app()->db->createCommand($query)->query(); - //get me some data Scotty - $result=Yii::app()->db->createCommand($query)->query(); + $responsecount = 0; + $filecount = 0; + $size = 0; - //put all results into $results - $row=$result->read(); $results=reset($row); + foreach ($result->readAll() as $row) + { - if ($total) - { - $percent=sprintf("%01.2f", ($results/$total)*100); - - } - switch($outputType) - { - case "xls": - $xlsRow = 0; - $sheet->write($xlsRow,0,$statlang->gT("Number of records in this query:",'unescaped')); - $sheet->write($xlsRow,1,$results); - ++$xlsRow; - $sheet->write($xlsRow,0,$statlang->gT("Total records in survey:",'unescaped')); - $sheet->write($xlsRow,1,$total); + $json = $row['json']; + $phparray = json_decode($json); - if($total) + foreach ($phparray as $metadata) { - ++$xlsRow; - $sheet->write($xlsRow,0,$statlang->gT("Percentage of total:",'unescaped')); - $sheet->write($xlsRow,1,$percent."%"); + $size += (int) $metadata->size; + $filecount++; } + $responsecount++; + } + $showem[] = array($statlang->gT("Total size of files"), $size." KB"); + $showem[] = array($statlang->gT("Average file size"), $size/$filecount . " KB"); + $showem[] = array($statlang->gT("Average size per respondent"), $size/$responsecount . " KB"); - break; - case 'pdf': + /* $query="SELECT title, question FROM {{questions}} WHERE parent_qid='$qqid' AND language='{$language}' ORDER BY question_order"; + $result=db_execute_num($query) or safeDie("Couldn't get list of subquestions for multitype
    $query
    "); - // add summary to pdf - $array = array(); - //$array[] = array($statlang->gT("Results"),""); - $array[] = array($statlang->gT("Number of records in this query:",'unescaped'), $results); - $array[] = array($statlang->gT("Total records in survey:",'unescaped'), $total); + //loop through multiple answers + while ($row=$result->FetchRow()) + { + $mfield=substr($rt, 1, strlen($rt))."$row[0]"; - if($total) - $array[] = array($statlang->gT("Percentage of total:",'unescaped'), $percent."%"); + //create an array containing answer code, answer and fieldname(??) + $alist[]=array("$row[0]", flattenText($row[1]), $mfield); + } - $pdf->addPage('P','A4'); + */ + //outputting + switch($outputType) + { + case 'xls': - $pdf->Bookmark($pdf->delete_html($statlang->gT("Results",'unescaped')), 0, 0); - $pdf->titleintopdf($statlang->gT("Results",'unescaped'),$statlang->gT("Survey",'unescaped')." ".$surveyid); - $pdf->tableintopdf($array); + $headXLS = array(); + $tableXLS = array(); + $footXLS = array(); - $pdf->addPage('P','A4'); + $xlsTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8')); + $xlsDesc = html_entity_decode($qquestion,ENT_QUOTES,'UTF-8'); + ++$xlsRow; + ++$xlsRow; - break; - case 'html': + ++$xlsRow; + $sheet->write($xlsRow, 0,$xlsTitle); + ++$xlsRow; + $sheet->write($xlsRow, 0,$xlsDesc); - $statisticsoutput .= "
    \n
    \n" - ."\t\n" - ."\t' - ."\n" - ."\t' - ."\n"; + $headXLS[] = array($statlang->gT("Calculation"),$statlang->gT("Result")); + ++$xlsRow; + $sheet->write($xlsRow, 0,$statlang->gT("Calculation")); + $sheet->write($xlsRow, 1,$statlang->gT("Result")); - //only calculate percentage if $total is set - if ($total) - { - $percent=sprintf("%01.2f", ($results/$total)*100); - $statisticsoutput .= "\t' - ."\n"; - } - $statisticsoutput .="
    ".$statlang->gT("Results")."
    ".$statlang->gT("Number of records in this query:").'$results
    ".$statlang->gT("Total records in survey:").'$total
    ".$statlang->gT("Percentage of total:").'$percent%
    \n"; + break; + case 'pdf': + $headPDF = array(); + $tablePDF = array(); + $footPDF = array(); - break; - default: + $pdfTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8')); + $titleDesc = html_entity_decode($qquestion,ENT_QUOTES,'UTF-8'); + $headPDF[] = array($statlang->gT("Calculation"),$statlang->gT("Result")); - break; - } + break; - //put everything from $selects array into a string connected by AND - //This string ($sql) can then be passed on to other functions so you can - //browse these results - if (isset ($selects) && $selects) {$sql=implode(" AND ", $selects);} + case 'html': - elseif (!empty($newsql)) {$sql = $newsql;} + $statisticsoutput .= "\n\n" + ."\t\n" + ."\t\n" + ."\t\n\t\t\n" + ."\t\t\n" + ."\t\n"; - if (!isset($sql) || !$sql) {$sql="NULL";} + foreach ($showem as $res) + $statisticsoutput .= ""; + break; - //only continue if we have something to output - if ($results > 0) - { - if($outputType=='html' && $browse === true) - { - //add a buttons to browse results - $statisticsoutput .= "\n" - ."\t\t

    " - ."\t\t\t\n" - ."\t\t\t\n" - ."\t\t\t\n" - ."\t\t\t\n" - ."\t\t

    " - ."\t\t\n"; + default: + break; } - } //end if (results > 0) - - /* Show Summary results - * The $summary array contains each fieldname that we want to display statistics for - * - * */ + } - if (isset($summary) && $summary) + //N = numerical input + //K = multiple numerical input + elseif ($firstletter == "N" || $firstletter == "K") //NUMERICAL TYPE { - //let's run through the survey - $runthrough=$summary; - - //START Chop up fieldname and find matching questions - - //GET LIST OF LEGIT QIDs FOR TESTING LATER - $lq = "SELECT DISTINCT qid FROM {{questions}} WHERE sid=$surveyid and parent_qid=0"; - $lr = Yii::app()->db->createCommand($lq)->query(); - - //loop through the IDs - foreach ($lr->readAll() as $lw) + //Zero handling + if (!isset($excludezeros)) //If this hasn't been set, set it to on as default: { - //this creates an array of question id's' - $legitqids[] = $lw['qid']; + $excludezeros=1; } - - //loop through all selected questions - foreach ($runthrough as $rt) + //check last character, greater/less/equals don't need special treatment + if (substr($rt, -1) == "G" || substr($rt, -1) == "L" || substr($rt, -1) == "=") + { + //DO NOTHING + } + else { - $firstletter = substr($rt, 0, 1); - // 1. Get answers for question ############################################################## + $showem = array(); + //create SGQ identifier + list($qsid, $qgid, $qqid) = explode("X", $rt, 3); - //M - Multiple choice, therefore multiple fields - if ($firstletter == "M" || $firstletter == "P") + //multiple numerical input + if($firstletter == "K") { - //get SGQ data - list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); - - //select details for this question - $nquery = "SELECT title, type, question, parent_qid, other FROM {{questions}} WHERE language='{$language}' AND parent_qid=0 AND qid='$qqid'"; - $nresult = Yii::app()->db->createCommand($nquery)->query(); + // This is a multiple numerical question so we need to strip of the answer id to find the question title + $tmpqid=substr($qqid, 0, strlen($qqid)-1); - //loop through question data - foreach ($nresult->readAll() as $nrow) - { - $nrow=array_values($nrow); - $qtitle=$nrow[0]; - $qtype=$nrow[1]; - $qquestion=flattenText($nrow[2]); - $qlid=$nrow[3]; - $qother=$nrow[4]; - } + //did we get a valid ID? + while (!in_array ($tmpqid,$legitqids)) + $tmpqid=substr($tmpqid, 0, strlen($tmpqid)-1); - //1. Get list of answers - $query="SELECT title, question FROM {{questions}} WHERE parent_qid='$qqid' AND language='{$language}' and scale_id=0 ORDER BY question_order"; - $result=Yii::app()->db->createCommand($query)->query(); + //check lenght of ID + $qidlength=strlen($tmpqid); - //loop through multiple answers - foreach ($result->readAll() as $row) - { - $row=array_values($row); - $mfield=substr($rt, 1, strlen($rt))."$row[0]"; + //get answer ID from qid + $qaid=substr($qqid, $qidlength, strlen($qqid)-$qidlength); - //create an array containing answer code, answer and fieldname(??) - $alist[]=array("$row[0]", flattenText($row[1]), $mfield); - } + //get question details from DB + $nquery = "SELECT title, type, question, qid, parent_qid + FROM {{questions}} + WHERE parent_qid=0 AND qid='".substr($qqid, 0, $qidlength)."' + AND language='{$language}'"; + $nresult = Yii::app()->db->createCommand($nquery)->query(); + } - //check "other" field. is it set? - if ($qother == "Y") - { - $mfield=substr($rt, 1, strlen($rt))."other"; + //probably question type "N" = numerical input + else + { + //we can use the qqid without any editing + $nquery = "SELECT title, type, question, qid, parent_qid FROM {{questions}} WHERE parent_qid=0 AND qid='$qqid' AND language='{$language}'"; + $nresult = Yii::app()->db->createCommand($nquery)->query(); + } - //create an array containing answer code, answer and fieldname(??) - $alist[]=array($statlang->gT("Other"), $statlang->gT("Other"), $mfield); - } + //loop through results + foreach ($nresult->readAll() as $nrow) + { + $nrow=array_values($nrow); + $qtitle=flattenText($nrow[0]); //clean up title + $qtype=$nrow[1]; + $qquestion=flattenText($nrow[2]); + $qiqid=$nrow[3]; + $qlid=$nrow[4]; } + //Get answer texts for multiple numerical + if(substr($rt, 0, 1) == "K") + { + //get answer data + $atext=Yii::app()->db->createCommand("SELECT question FROM {{questions}} WHERE parent_qid='{$qiqid}' AND scale_id=0 AND title='{$qaid}' AND language='{$language}'")->queryScalar(); + //put single items in brackets at output + $qtitle .= " [$atext]"; + } - //S - Short Free Text - //T - Long Free Text - elseif ($firstletter == "T" || $firstletter == "S") //Short and long text + //outputting + switch($outputType) { + case 'xls': - //search for key - $fld = substr($rt, 1, strlen($rt)); - $fielddata=$fieldmap[$fld]; + $headXLS = array(); + $tableXLS = array(); + $footXLS = array(); - //get SGQA IDs - $qsid=$fielddata['sid']; - $qgid=$fielddata['gid']; - $qqid=$fielddata['qid']; + $xlsTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8')); + $xlsDesc = html_entity_decode($qquestion,ENT_QUOTES,'UTF-8'); + ++$xlsRow; + ++$xlsRow; + ++$xlsRow; + $sheet->setCellValueByColumnAndRow(0,$xlsRow,$xlsTitle); + ++$xlsRow; + $sheet->setCellValueByColumnAndRow(0,$xlsRow,$xlsDesc); - list($qanswer, $qlid)=!empty($fielddata['aid']) ? explode("_", $fielddata['aid']) : array("", ""); - //get SGQ data - //list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); + $headXLS[] = array($statlang->gT("Calculation"),$statlang->gT("Result")); + ++$xlsRow; + $sheet->setCellValueByColumnAndRow(0,$xlsRow,$statlang->gT("Calculation")); + $sheet->setCellValueByColumnAndRow(1,$xlsRow,$statlang->gT("Result")); + break; + case 'pdf': - //get question data - $nquery = "SELECT title, type, question, other, parent_qid FROM {{questions}} WHERE parent_qid=0 AND qid='$qqid' AND language='{$language}'"; - $nresult = Yii::app()->db->createCommand($nquery)->query(); + $headPDF = array(); + $tablePDF = array(); + $footPDF = array(); - //loop through question data - foreach ($nresult->readAll() as $nrow) - { - $nrow=array_values($nrow); - $qtitle=flattenText($nrow[0]); - $qtype=$nrow[1]; - $qquestion=flattenText($nrow[2]); - $nlid=$nrow[4]; - } + $pdfTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8')); + $titleDesc = html_entity_decode($qquestion,ENT_QUOTES,'UTF-8'); + + $headPDF[] = array($statlang->gT("Calculation"),$statlang->gT("Result")); + + break; + case 'html': - $mfield=substr($rt, 1, strlen($rt)); + $statisticsoutput .= "\n
    ".sprintf($statlang->gT("Field summary for %s"),$qtitle).":" + ."
    $qquestion
    " + .$statlang->gT("Calculation")."" + .$statlang->gT("Result")."
    ".$res[0]."".$res[1]."
    \n" + ."\t\n" + ."\t\n" + ."\t\n\t\t\n" + ."\t\t\n" + ."\t\n"; - //Text questions either have an answer, or they don't. There's no other way of quantising the results. - // So, instead of building an array of predefined answers like we do with lists & other types, - // we instead create two "types" of possible answer - either there is a response.. or there isn't. - // This question type then can provide a % of the question answered in the summary. - $alist[]=array("Answers", $statlang->gT("Answer"), $mfield); - $alist[]=array("NoAnswer", $statlang->gT("No answer"), $mfield); + break; + default: + + + break; } + //this field is queried using mathematical functions + $fieldname=substr($rt, 1, strlen($rt)); - //Multiple short text - elseif ($firstletter == "Q") + //special treatment for MS SQL databases + if ($sDatabaseType == 'mssql' || $sDatabaseType == 'sqlsrv') { - //get SGQ data - list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); - - //separating another ID - $tmpqid=substr($qqid, 0, strlen($qqid)-1); + //standard deviation + $query = "SELECT STDEVP(".Yii::app()->db->quoteColumnName($fieldname)."*1) as stdev"; + } - //check if we have legid QIDs. if not create them by substringing - while (!in_array ($tmpqid,$legitqids)) $tmpqid=substr($tmpqid, 0, strlen($tmpqid)-1); + //other databases (MySQL, Postgres) + else + { + //standard deviation + $query = "SELECT STDDEV(".Yii::app()->db->quoteColumnName($fieldname).") as stdev"; + } - //length of QID - $qidlength=strlen($tmpqid); + //sum + $query .= ", SUM(".Yii::app()->db->quoteColumnName($fieldname)."*1) as sum"; - //we somehow get the answer code (see SQL later) from the $qqid - $qaid=substr($qqid, $qidlength, strlen($qqid)-$qidlength); + //average + $query .= ", AVG(".Yii::app()->db->quoteColumnName($fieldname)."*1) as average"; - //get some question data - $nquery = "SELECT title, type, question, other FROM {{questions}} WHERE qid='".substr($qqid, 0, $qidlength)."' AND parent_qid=0 AND language='{$language}'"; - $nresult = Yii::app()->db->createCommand($nquery)->query(); + //min + $query .= ", MIN(".Yii::app()->db->quoteColumnName($fieldname)."*1) as minimum"; - //more substrings - $count = substr($qqid, strlen($qqid)-1); + //max + $query .= ", MAX(".Yii::app()->db->quoteColumnName($fieldname)."*1) as maximum"; + //Only select responses where there is an actual number response, ignore nulls and empties (if these are included, they are treated as zeroes, and distort the deviation/mean calculations) - //loop through question data - foreach ($nresult->readAll() as $nrow) + //special treatment for MS SQL databases + if ($sDatabaseType == 'mssql' || $sDatabaseType == 'sqlsrv') + { + //no NULL/empty values please + $query .= " FROM {{survey_$surveyid}} WHERE ".Yii::app()->db->quoteColumnName($fieldname)." IS NOT NULL"; + if(!$excludezeros) { - $nrow=array_values($nrow); - $qtitle=flattenText($nrow[0]).'-'.$count; - $qtype=$nrow[1]; - $qquestion=flattenText($nrow[2]); + //NO ZERO VALUES + $query .= " AND (".Yii::app()->db->quoteColumnName($fieldname)." <> 0)"; } + } - //get answers - $qquery = "SELECT title as code, question as answer FROM {{questions}} WHERE parent_qid='".substr($qqid, 0, $qidlength)."' AND title='$qaid' AND language='{$language}' ORDER BY question_order"; - $qresult=Yii::app()->db->createCommand($qquery)->query(); - - //loop through answer data - foreach ($qresult->readAll() as $qrow) + //other databases (MySQL, Postgres) + else + { + //no NULL/empty values please + $query .= " FROM {{survey_$surveyid}} WHERE ".Yii::app()->db->quoteColumnName($fieldname)." IS NOT NULL"; + if(!$excludezeros) { - $qrow=array_values($qrow); - //store each answer here - $atext=flattenText($qrow[1]); + //NO ZERO VALUES + $query .= " AND (".Yii::app()->db->quoteColumnName($fieldname)." != 0)"; } + } - //add this to the question title - $qtitle .= " [$atext]"; - - //even more substrings... - $mfield=substr($rt, 1, strlen($rt)); + //filter incomplete answers if set + if (incompleteAnsFilterState() == "inc") {$query .= " AND submitdate is null";} + elseif (incompleteAnsFilterState() == "filter") {$query .= " AND submitdate is not null";} - //Text questions either have an answer, or they don't. There's no other way of quantising the results. - // So, instead of building an array of predefined answers like we do with lists & other types, - // we instead create two "types" of possible answer - either there is a response.. or there isn't. - // This question type then can provide a % of the question answered in the summary. - $alist[]=array("Answers", $statlang->gT("Answer"), $mfield); - $alist[]=array("NoAnswer", $statlang->gT("No answer"), $mfield); - } + //$sql was set somewhere before + if ($sql != "NULL") {$query .= " AND $sql";} + //execute query + $result=Yii::app()->db->createCommand($query)->queryAll(); - //RANKING OPTION - elseif ($firstletter == "R") + //get calculated data + foreach ($result as $row) { - //getting the needed IDs somehow - $lengthofnumeral=substr($rt, strpos($rt, "-")+1, 1); - list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strpos($rt, "-")-($lengthofnumeral+1)), 3); - - //get question data - $nquery = "SELECT title, type, question FROM {{questions}} WHERE parent_qid=0 AND qid='$qqid' AND language='{$language}'"; - $nresult = Yii::app()->db->createCommand($nquery)->query(); + //put translation of mean and calculated data into $showem array + $showem[]=array($statlang->gT("Sum"), $row['sum']); + $showem[]=array($statlang->gT("Standard deviation"), round($row['stdev'],2)); + $showem[]=array($statlang->gT("Average"), round($row['average'],2)); + $showem[]=array($statlang->gT("Minimum"), $row['minimum']); + + //Display the maximum and minimum figures after the quartiles for neatness + $maximum=$row['maximum']; + $minimum=$row['minimum']; + } - //loop through question data - foreach ($nresult->readAll() as $nrow) - { - $nrow=array_values($nrow); - $qtitle=flattenText($nrow[0]). " [".substr($rt, strpos($rt, "-")-($lengthofnumeral), $lengthofnumeral)."]"; - $qtype=$nrow[1]; - $qquestion=flattenText($nrow[2]). "[".$statlang->gT("Ranking")." ".substr($rt, strpos($rt, "-")-($lengthofnumeral), $lengthofnumeral)."]"; - } - //get answers - $query="SELECT code, answer FROM {{answers}} WHERE qid='$qqid' AND scale_id=0 AND language='{$language}' ORDER BY sortorder, answer"; - $result=Yii::app()->db->createCommand($query)->query(); - //loop through answers - foreach ($result->readAll() as $row) - { - $row=array_values($row); - //create an array containing answer code, answer and fieldname(??) - $mfield=substr($rt, 1, strpos($rt, "-")-1); - $alist[]=array("$row[0]", flattenText($row[1]), $mfield); - } - } + //CALCULATE QUARTILES - else if ($firstletter == "|") // File UPload + //get data + $query ="SELECT ".Yii::app()->db->quoteColumnName($fieldname)." FROM {{survey_$surveyid}} WHERE ".Yii::app()->db->quoteColumnName($fieldname)." IS NOT null"; + //NO ZEROES + if(!$excludezeros) { + $query .= " AND ".Yii::app()->db->quoteColumnName($fieldname)." != 0"; + } - //get SGQ data - list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); + //filtering enabled? + if (incompleteAnsFilterState() == "inc") {$query .= " AND submitdate is null";} + elseif (incompleteAnsFilterState() == "filter") {$query .= " AND submitdate is not null";} - //select details for this question - $nquery = "SELECT title, type, question, parent_qid, other FROM {{questions}} WHERE language='{$language}' AND parent_qid=0 AND qid='$qqid'"; - $nresult = Yii::app()->db->createCommand($nquery)->query(); + //if $sql values have been passed to the statistics script from another script, incorporate them + if ($sql != "NULL") {$query .= " AND $sql";} - //loop through question data - foreach ($nresult->readAll() as $nrow) - { - $nrow=array_values($nrow); - $qtitle=$nrow[0]; - $qtype=$nrow[1]; - $qquestion=flattenText($nrow[2]); - $qlid=$nrow[3]; - $qother=$nrow[4]; - } + //execute query + $result = Yii::app()->db->createCommand($query)->query(); + $querystarter="SELECT ".Yii::app()->db->quoteColumnName($fieldname)." FROM {{survey_$surveyid}} WHERE ".Yii::app()->db->quoteColumnName($fieldname)." IS NOT null"; + //No Zeroes + if(!$excludezeros) + { + $querystart .= " AND ".Yii::app()->db->quoteColumnName($fieldname)." != 0"; + } + //filtering enabled? + if (incompleteAnsFilterState() == "inc") {$querystarter .= " AND submitdate is null";} + elseif (incompleteAnsFilterState() == "filter") {$querystarter .= " AND submitdate is not null";} - /* - 4) Average size of file per respondent - 5) Average no. of files - 5) Summary/count of file types (ie: 37 jpg, 65 gif, 12 png) - 6) Total size of all files (useful if you re about to download them all) - 7) You could also add things like smallest file size, largest file size, median file size - 8) no. of files corresponding to each extension - 9) max file size - 10) min file size - */ + //if $sql values have been passed to the statistics script from another script, incorporate them + if ($sql != "NULL") {$querystarter .= " AND $sql";} - // 1) Total number of files uploaded - // 2) Number of respondents who uploaded at least one file (with the inverse being the number of respondents who didn t upload any) - $fieldname=substr($rt, 1, strlen($rt)); - $query = "SELECT SUM(".Yii::app()->db->quoteColumnName($fieldname.'_filecount').") as sum, AVG(".Yii::app()->db->quoteColumnName($fieldname.'_filecount').") as avg FROM {{survey_$surveyid}}"; - $result=Yii::app()->db->createCommand($query)->query(); + //we just count the number of records returned + $medcount=$result->getRowCount(); - $showem = array(); + //put the total number of records at the beginning of this array + array_unshift($showem, array($statlang->gT("Count"), $medcount)); - foreach ($result->readAll() as $row) - { - $showem[]=array($statlang->gT("Total number of files"), $row['sum']); - $showem[]=array($statlang->gT("Average no. of files per respondent"), $row['avg']); - } + //no more comment from Mazi regarding the calculation - $query = "SELECT ". $fieldname ." as json FROM {{survey_$surveyid}}"; - $result=Yii::app()->db->createCommand($query)->query(); + // Calculating only makes sense with more than one result + if ($medcount>1) + { + //1ST QUARTILE (Q1) + $q1=(1/4)*($medcount+1); + $q1b=(int)((1/4)*($medcount+1)); + $q1c=$q1b-1; + $q1diff=$q1-$q1b; + $total=0; - $responsecount = 0; - $filecount = 0; - $size = 0; + // fix if there are too few values to evaluate. + if ($q1c<0) {$q1c=0;} - foreach ($result->readAll() as $row) + if ($q1 != $q1b) { + //ODD NUMBER + $query = $querystarter . " ORDER BY ".Yii::app()->db->quoteColumnName($fieldname)."*1 "; + $result=Yii::app()->db->createCommand($query)->limit(2, $q1c)->query(); - $json = $row['json']; - $phparray = json_decode($json); - - foreach ($phparray as $metadata) + foreach ($result->readAll() as $row) { - $size += (int) $metadata->size; - $filecount++; + if ($total == 0) {$total=$total-$row[$fieldname];} + + else {$total=$total+$row[$fieldname];} + + $lastnumber=$row[$fieldname]; } - $responsecount++; - } - $showem[] = array($statlang->gT("Total size of files"), $size." KB"); - $showem[] = array($statlang->gT("Average file size"), $size/$filecount . " KB"); - $showem[] = array($statlang->gT("Average size per respondent"), $size/$responsecount . " KB"); - /* $query="SELECT title, question FROM {{questions}} WHERE parent_qid='$qqid' AND language='{$language}' ORDER BY question_order"; - $result=db_execute_num($query) or safeDie("Couldn't get list of subquestions for multitype
    $query
    "); + $q1total=$lastnumber-((1-$q1diff)*$total); - //loop through multiple answers - while ($row=$result->FetchRow()) - { - $mfield=substr($rt, 1, strlen($rt))."$row[0]"; + if ($q1total < $minimum) {$q1total=$minimum;} - //create an array containing answer code, answer and fieldname(??) - $alist[]=array("$row[0]", flattenText($row[1]), $mfield); + $showem[]=array($statlang->gT("1st quartile (Q1)"), $q1total); } - - */ - //outputting - switch($outputType) + else { - case 'xls': + //EVEN NUMBER + $query = $querystarter . " ORDER BY ".Yii::app()->db->quoteColumnName($fieldname)."*1 "; + $result=Yii::app()->db->createCommand($query)->limit(1, $q1c)->query(); - $headXLS = array(); - $tableXLS = array(); - $footXLS = array(); + foreach ($result->readAll() as $row) + { + $showem[]=array($statlang->gT("1st quartile (Q1)"), $row[$fieldname]); + } + } - $xlsTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8')); - $xlsDesc = html_entity_decode($qquestion,ENT_QUOTES,'UTF-8'); - ++$xlsRow; - ++$xlsRow; + $total=0; - ++$xlsRow; - $sheet->write($xlsRow, 0,$xlsTitle); - ++$xlsRow; - $sheet->write($xlsRow, 0,$xlsDesc); - $headXLS[] = array($statlang->gT("Calculation"),$statlang->gT("Result")); - ++$xlsRow; - $sheet->write($xlsRow, 0,$statlang->gT("Calculation")); - $sheet->write($xlsRow, 1,$statlang->gT("Result")); + //MEDIAN (Q2) + $median=(1/2)*($medcount+1); + $medianb=(int)((1/2)*($medcount+1)); + $medianc=$medianb-1; + $mediandiff=$median-$medianb; - break; - case 'pdf': + if ($median != $medianb) + { + //remainder + $query = $querystarter . " ORDER BY ".Yii::app()->db->quoteColumnName($fieldname)."*1 "; + $result=Yii::app()->db->createCommand($query)->limit(2, $medianc)->query(); - $headPDF = array(); - $tablePDF = array(); - $footPDF = array(); + foreach ($result->readAll() as $row) {$total=$total+$row[$fieldname];} - $pdfTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8')); - $titleDesc = html_entity_decode($qquestion,ENT_QUOTES,'UTF-8'); + $showem[]=array($statlang->gT("2nd quartile (Median)"), $total/2); + } - $headPDF[] = array($statlang->gT("Calculation"),$statlang->gT("Result")); + else + { + //EVEN NUMBER + $query = $querystarter . " ORDER BY ".Yii::app()->db->quoteColumnName($fieldname)."*1 "; + $result = Yii::app()->db->createCommand($query)->limit(1, $medianc-1)->query(); - break; + foreach ($result->readAll() as $row) + { + $showem[]=array($statlang->gT("Median value"), $row[$fieldname]); + } + } - case 'html': + $total=0; - $statisticsoutput .= "\n
    ".sprintf($statlang->gT("Field summary for %s"),$qtitle).":" + ."
    $qquestion
    " + .$statlang->gT("Calculation")."" + .$statlang->gT("Result")."
    \n" - ."\t\n" - ."\t\n" - ."\t\n\t\t\n" - ."\t\t\n" - ."\t\n"; - - foreach ($showem as $res) - $statisticsoutput .= ""; - break; - default: - break; - } - } + //3RD QUARTILE (Q3) + $q3=(3/4)*($medcount+1); + $q3b=(int)((3/4)*($medcount+1)); + $q3c=$q3b-1; + $q3diff=$q3-$q3b; - //N = numerical input - //K = multiple numerical input - elseif ($firstletter == "N" || $firstletter == "K") //NUMERICAL TYPE - { - //Zero handling - if (!isset($excludezeros)) //If this hasn't been set, set it to on as default: + if ($q3 != $q3b) { - $excludezeros=1; - } - //check last character, greater/less/equals don't need special treatment - if (substr($rt, -1) == "G" || substr($rt, -1) == "L" || substr($rt, -1) == "=") - { - //DO NOTHING - } - else - { - $showem = array(); - //create SGQ identifier - list($qsid, $qgid, $qqid) = explode("X", $rt, 3); + $query = $querystarter . " ORDER BY ".Yii::app()->db->quoteColumnName($fieldname)."*1 "; + $result = Yii::app()->db->createCommand($query)->limit(2,$q3c)->query(); - //multiple numerical input - if($firstletter == "K") + foreach ($result->readAll() as $row) { - // This is a multiple numerical question so we need to strip of the answer id to find the question title - $tmpqid=substr($qqid, 0, strlen($qqid)-1); + if ($total == 0) {$total=$total-$row[$fieldname];} - //did we get a valid ID? - while (!in_array ($tmpqid,$legitqids)) - $tmpqid=substr($tmpqid, 0, strlen($tmpqid)-1); + else {$total=$total+$row[$fieldname];} - //check lenght of ID - $qidlength=strlen($tmpqid); + $lastnumber=$row[$fieldname]; + } + $q3total=$lastnumber-((1-$q3diff)*$total); - //get answer ID from qid - $qaid=substr($qqid, $qidlength, strlen($qqid)-$qidlength); + if ($q3total < $maximum) {$q1total=$maximum;} - //get question details from DB - $nquery = "SELECT title, type, question, qid, parent_qid - FROM {{questions}} - WHERE parent_qid=0 AND qid='".substr($qqid, 0, $qidlength)."' - AND language='{$language}'"; - $nresult = Yii::app()->db->createCommand($nquery)->query(); - } + $showem[]=array($statlang->gT("3rd quartile (Q3)"), $q3total); + } - //probably question type "N" = numerical input - else - { - //we can use the qqid without any editing - $nquery = "SELECT title, type, question, qid, parent_qid FROM {{questions}} WHERE parent_qid=0 AND qid='$qqid' AND language='{$language}'"; - $nresult = Yii::app()->db->createCommand($nquery)->query(); - } + else + { + $query = $querystarter . " ORDER BY ".Yii::app()->db->quoteColumnName($fieldname)."*1"; + $result = Yii::app()->db->createCommand($query)->limit(1, $q3c); - //loop through results - foreach ($nresult->readAll() as $nrow) + foreach ($result->queryAll() as $row) { - $nrow=array_values($nrow); - $qtitle=flattenText($nrow[0]); //clean up title - $qtype=$nrow[1]; - $qquestion=flattenText($nrow[2]); - $qiqid=$nrow[3]; - $qlid=$nrow[4]; + $showem[]=array($statlang->gT("3rd quartile (Q3)"), $row[$fieldname]); } + } - //Get answer texts for multiple numerical - if(substr($rt, 0, 1) == "K") - { - //get answer data - $atext=Yii::app()->db->createCommand("SELECT question FROM {{questions}} WHERE parent_qid='{$qiqid}' AND scale_id=0 AND title='{$qaid}' AND language='{$language}'")->queryScalar(); - //put single items in brackets at output - $qtitle .= " [$atext]"; - } + $total=0; + + $showem[]=array($statlang->gT("Maximum"), $maximum); - //outputting + //output results + foreach ($showem as $shw) + { switch($outputType) { case 'xls': - $headXLS = array(); - $tableXLS = array(); - $footXLS = array(); - - $xlsTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8')); - $xlsDesc = html_entity_decode($qquestion,ENT_QUOTES,'UTF-8'); - ++$xlsRow; ++$xlsRow; + $sheet->write($xlsRow, 0,html_entity_decode($shw[0],ENT_QUOTES,'UTF-8')); + $sheet->write($xlsRow, 1,html_entity_decode($shw[1],ENT_QUOTES,'UTF-8')); - ++$xlsRow; - $sheet->setCellValueByColumnAndRow(0,$xlsRow,$xlsTitle); - ++$xlsRow; - $sheet->setCellValueByColumnAndRow(0,$xlsRow,$xlsDesc); - $headXLS[] = array($statlang->gT("Calculation"),$statlang->gT("Result")); - ++$xlsRow; - $sheet->setCellValueByColumnAndRow(0,$xlsRow,$statlang->gT("Calculation")); - $sheet->setCellValueByColumnAndRow(1,$xlsRow,$statlang->gT("Result")); + $tableXLS[] = array($shw[0],$shw[1]); break; case 'pdf': - $headPDF = array(); - $tablePDF = array(); - $footPDF = array(); - - $pdfTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8')); - $titleDesc = html_entity_decode($qquestion,ENT_QUOTES,'UTF-8'); - - $headPDF[] = array($statlang->gT("Calculation"),$statlang->gT("Result")); + $tablePDF[] = array(html_entity_decode($shw[0],ENT_QUOTES,'UTF-8'),html_entity_decode($shw[1],ENT_QUOTES,'UTF-8')); break; case 'html': - $statisticsoutput .= "\n
    ".sprintf($statlang->gT("Field summary for %s"),$qtitle).":" - ."
    $qquestion
    " - .$statlang->gT("Calculation")."" - .$statlang->gT("Result")."
    ".$res[0]."".$res[1]."
    \n" - ."\t\n" - ."\t\n" - ."\t\n\t\t\n" - ."\t\t\n" - ."\t\n"; + $statisticsoutput .= "\t\n" + ."\t\t\n" + ."\t\t\n" + ."\t\n"; break; default: @@ -1336,2096 +1257,2206 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, break; } + } + switch($outputType) + { + case 'xls': - //this field is queried using mathematical functions - $fieldname=substr($rt, 1, strlen($rt)); + ++$xlsRow; + $sheet->write($xlsRow, 0,$statlang->gT("Null values are ignored in calculations")); + ++$xlsRow; + $sheet->write($xlsRow, 0,sprintf($statlang->gT("Q1 and Q3 calculated using %s"), $statlang->gT("minitab method"))); - //special treatment for MS SQL databases - $sDatabaseType = Yii::app()->db->getDriverName(); - if ($sDatabaseType == 'mssql' || $sDatabaseType == 'sqlsrv') - { - //standard deviation - $query = "SELECT STDEVP(".Yii::app()->db->quoteColumnName($fieldname)."*1) as stdev"; - } + $footXLS[] = array($statlang->gT("Null values are ignored in calculations")); + $footXLS[] = array(sprintf($statlang->gT("Q1 and Q3 calculated using %s"), $statlang->gT("minitab method"))); - //other databases (MySQL, Postgres) - else - { - //standard deviation - $query = "SELECT STDDEV(".Yii::app()->db->quoteColumnName($fieldname).") as stdev"; - } - - //sum - $query .= ", SUM(".Yii::app()->db->quoteColumnName($fieldname)."*1) as sum"; + break; + case 'pdf': - //average - $query .= ", AVG(".Yii::app()->db->quoteColumnName($fieldname)."*1) as average"; + $footPDF[] = array($statlang->gT("Null values are ignored in calculations")); + $footPDF[] = array(sprintf($statlang->gT("Q1 and Q3 calculated using %s"), "".$statlang->gT("minitab method")."")); + $pdf->addPage('P','A4'); + $pdf->Bookmark($pdf->delete_html($qquestion), 1, 0); + $pdf->titleintopdf($pdfTitle,$titleDesc); - //min - $query .= ", MIN(".Yii::app()->db->quoteColumnName($fieldname)."*1) as minimum"; + $pdf->headTable($headPDF, $tablePDF); - //max - $query .= ", MAX(".Yii::app()->db->quoteColumnName($fieldname)."*1) as maximum"; - //Only select responses where there is an actual number response, ignore nulls and empties (if these are included, they are treated as zeroes, and distort the deviation/mean calculations) + $pdf->tablehead($footPDF); - //special treatment for MS SQL databases - if ($sDatabaseType == 'mssql' || $sDatabaseType == 'sqlsrv') - { - //no NULL/empty values please - $query .= " FROM {{survey_$surveyid}} WHERE ".Yii::app()->db->quoteColumnName($fieldname)." IS NOT NULL"; - if(!$excludezeros) - { - //NO ZERO VALUES - $query .= " AND (".Yii::app()->db->quoteColumnName($fieldname)." <> 0)"; - } - } + break; + case 'html': - //other databases (MySQL, Postgres) - else - { - //no NULL/empty values please - $query .= " FROM {{survey_$surveyid}} WHERE ".Yii::app()->db->quoteColumnName($fieldname)." IS NOT NULL"; - if(!$excludezeros) - { - //NO ZERO VALUES - $query .= " AND (".Yii::app()->db->quoteColumnName($fieldname)." != 0)"; - } - } + //footer of question type "N" + $statisticsoutput .= "\t\n" + ."\t\t\n" + ."\t\n
    ".sprintf($statlang->gT("Field summary for %s"),$qtitle).":" - ."
    $qquestion
    " - .$statlang->gT("Calculation")."" - .$statlang->gT("Result")."
    $shw[0]$shw[1]
    \n" + ."\t\t\t".$statlang->gT("Null values are ignored in calculations")."
    \n" + ."\t\t\t".sprintf($statlang->gT("Q1 and Q3 calculated using %s"), "".$statlang->gT("minitab method")."") + ."
    \n" + ."\t\t
    \n"; - //filter incomplete answers if set - if (incompleteAnsFilterState() == "inc") {$query .= " AND submitdate is null";} - elseif (incompleteAnsFilterState() == "filter") {$query .= " AND submitdate is not null";} + break; + default: - //$sql was set somewhere before - if ($sql != "NULL") {$query .= " AND $sql";} - //execute query - $result=Yii::app()->db->createCommand($query)->queryAll(); + break; + } - //get calculated data - foreach ($result as $row) - { - //put translation of mean and calculated data into $showem array - $showem[]=array($statlang->gT("Sum"), $row['sum']); - $showem[]=array($statlang->gT("Standard deviation"), round($row['stdev'],2)); - $showem[]=array($statlang->gT("Average"), round($row['average'],2)); - $showem[]=array($statlang->gT("Minimum"), $row['minimum']); - - //Display the maximum and minimum figures after the quartiles for neatness - $maximum=$row['maximum']; - $minimum=$row['minimum']; - } + //clean up + unset($showem); + } //end if (enough results?) + //not enough (<1) results for calculation + else + { + switch($outputType) + { + case 'xls': - //CALCULATE QUARTILES + $tableXLS = array(); + $tableXLS[] = array($statlang->gT("Not enough values for calculation")); - //get data - $query ="SELECT ".Yii::app()->db->quoteColumnName($fieldname)." FROM {{survey_$surveyid}} WHERE ".Yii::app()->db->quoteColumnName($fieldname)." IS NOT null"; - //NO ZEROES - if(!$excludezeros) - { - $query .= " AND ".Yii::app()->db->quoteColumnName($fieldname)." != 0"; - } + ++$xlsRow; + $sheet->write($xlsRow, 0, $statlang->gT("Not enough values for calculation")); - //filtering enabled? - if (incompleteAnsFilterState() == "inc") {$query .= " AND submitdate is null";} - elseif (incompleteAnsFilterState() == "filter") {$query .= " AND submitdate is not null";} - //if $sql values have been passed to the statistics script from another script, incorporate them - if ($sql != "NULL") {$query .= " AND $sql";} - //execute query - $result = Yii::app()->db->createCommand($query)->query(); - $querystarter="SELECT ".Yii::app()->db->quoteColumnName($fieldname)." FROM {{survey_$surveyid}} WHERE ".Yii::app()->db->quoteColumnName($fieldname)." IS NOT null"; - //No Zeroes - if(!$excludezeros) - { - $querystart .= " AND ".Yii::app()->db->quoteColumnName($fieldname)." != 0"; - } - //filtering enabled? - if (incompleteAnsFilterState() == "inc") {$querystarter .= " AND submitdate is null";} - elseif (incompleteAnsFilterState() == "filter") {$querystarter .= " AND submitdate is not null";} + break; + case 'pdf': - //if $sql values have been passed to the statistics script from another script, incorporate them - if ($sql != "NULL") {$querystarter .= " AND $sql";} + $tablePDF = array(); + $tablePDF[] = array($statlang->gT("Not enough values for calculation")); + $pdf->addPage('P','A4'); + $pdf->Bookmark($pdf->delete_html($qquestion), 1, 0); + $pdf->titleintopdf($pdfTitle,$titleDesc); - //we just count the number of records returned - $medcount=$result->getRowCount(); + $pdf->equalTable($tablePDF); - //put the total number of records at the beginning of this array - array_unshift($showem, array($statlang->gT("Count"), $medcount)); + break; + case 'html': + //output + $statisticsoutput .= "\t\n" + ."\t\t".$statlang->gT("Not enough values for calculation")."\n" + ."\t\n
    \n"; - //no more comment from Mazi regarding the calculation + break; + default: - // Calculating only makes sense with more than one result - if ($medcount>1) - { - //1ST QUARTILE (Q1) - $q1=(1/4)*($medcount+1); - $q1b=(int)((1/4)*($medcount+1)); - $q1c=$q1b-1; - $q1diff=$q1-$q1b; - $total=0; - // fix if there are too few values to evaluate. - if ($q1c<0) {$q1c=0;} + break; + } - if ($q1 != $q1b) - { - //ODD NUMBER - $query = $querystarter . " ORDER BY ".Yii::app()->db->quoteColumnName($fieldname)."*1 "; - $result=Yii::app()->db->createCommand($query)->limit(2, $q1c)->query(); + unset($showem); - foreach ($result->readAll() as $row) - { - if ($total == 0) {$total=$total-$row[$fieldname];} + } - else {$total=$total+$row[$fieldname];} + } //end else -> check last character, greater/less/equals don't need special treatment - $lastnumber=$row[$fieldname]; - } + } //end else-if -> multiple numerical types - $q1total=$lastnumber-((1-$q1diff)*$total); + //is there some "id", "datestamp" or "D" within the type? + elseif (substr($rt, 0, 2) == "id" || substr($rt, 0, 9) == "datestamp" || ($firstletter == "D")) + { + /* + * DON'T show anything for date questions + * because there aren't any statistics implemented yet! + * + * See bug report #2539 and + * feature request #2620 + */ + } - if ($q1total < $minimum) {$q1total=$minimum;} + // NICE SIMPLE SINGLE OPTION ANSWERS + else + { + //search for key + $fielddata=$fieldmap[$rt]; + //print_r($fielddata); + //get SGQA IDs + $qsid=$fielddata['sid']; + $qgid=$fielddata['gid']; + $qqid=$fielddata['qid']; + $qanswer=$fielddata['aid']; + + //question type + $qtype=$fielddata['type']; + + //question string + $qastring=$fielddata['question']; + + //question ID + $rqid=$qqid; + + //get question data + $nquery = "SELECT title, type, question, qid, parent_qid, other FROM {{questions}} WHERE qid='{$rqid}' AND parent_qid=0 and language='{$language}'"; + $nresult = Yii::app()->db->createCommand($nquery)->query(); + + //loop though question data + foreach ($nresult->readAll() as $nrow) + { + $nrow=array_values($nrow); + $qtitle=flattenText($nrow[0]); + $qtype=$nrow[1]; + $qquestion=flattenText($nrow[2]); + $qiqid=$nrow[3]; + $qparentqid=$nrow[4]; + $qother=$nrow[5]; + } - $showem[]=array($statlang->gT("1st quartile (Q1)"), $q1total); - } - else - { - //EVEN NUMBER - $query = $querystarter . " ORDER BY ".Yii::app()->db->quoteColumnName($fieldname)."*1 "; - $result=Yii::app()->db->createCommand($query)->limit(1, $q1c)->query(); - - foreach ($result->readAll() as $row) - { - $showem[]=array($statlang->gT("1st quartile (Q1)"), $row[$fieldname]); - } - } + //check question types + switch($qtype) + { + //Array of 5 point choices (several items to rank!) + case "A": - $total=0; + //get data + $qquery = "SELECT title, question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qanswer' AND language='{$language}' ORDER BY question_order"; + $qresult=Yii::app()->db->createCommand($qquery)->query(); + //loop through results + foreach ($qresult->readAll() as $qrow) + { + $qrow=array_values($qrow); + //5-point array + for ($i=1; $i<=5; $i++) + { + //add data + $alist[]=array("$i", "$i"); + } + //add counter + $atext=flattenText($qrow[1]); + } - //MEDIAN (Q2) - $median=(1/2)*($medcount+1); - $medianb=(int)((1/2)*($medcount+1)); - $medianc=$medianb-1; - $mediandiff=$median-$medianb; + //list IDs and answer codes in brackets + $qquestion .= $linefeed."[".$atext."]"; + $qtitle .= "($qanswer)"; + break; - if ($median != $medianb) - { - //remainder - $query = $querystarter . " ORDER BY ".Yii::app()->db->quoteColumnName($fieldname)."*1 "; - $result=Yii::app()->db->createCommand($query)->limit(2, $medianc)->query(); - foreach ($result->readAll() as $row) {$total=$total+$row[$fieldname];} - $showem[]=array($statlang->gT("2nd quartile (Median)"), $total/2); - } + //Array of 10 point choices + //same as above just with 10 items + case "B": + $qquery = "SELECT title, question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qanswer' AND language='{$language}' ORDER BY question_order"; + $qresult=Yii::app()->db->createCommand($qquery)->query(); + foreach ($qresult->readAll() as $qrow) + { + $qrow=array_values($qrow); + for ($i=1; $i<=10; $i++) + { + $alist[]=array("$i", "$i"); + } + $atext=flattenText($qrow[1]); + } - else - { - //EVEN NUMBER - $query = $querystarter . " ORDER BY ".Yii::app()->db->quoteColumnName($fieldname)."*1 "; - $result = Yii::app()->db->createCommand($query)->limit(1, $medianc-1)->query(); - - foreach ($result->readAll() as $row) - { - $showem[]=array($statlang->gT("Median value"), $row[$fieldname]); - } - } + $qquestion .= $linefeed."[".$atext."]"; + $qtitle .= "($qanswer)"; + break; - $total=0; - //3RD QUARTILE (Q3) - $q3=(3/4)*($medcount+1); - $q3b=(int)((3/4)*($medcount+1)); - $q3c=$q3b-1; - $q3diff=$q3-$q3b; + //Array of Yes/No/$statlang->gT("Uncertain") + case "C": + $qquery = "SELECT title, question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qanswer' AND language='{$language}' ORDER BY question_order"; + $qresult=Yii::app()->db->createCommand($qquery)->query(); - if ($q3 != $q3b) - { - $query = $querystarter . " ORDER BY ".Yii::app()->db->quoteColumnName($fieldname)."*1 "; - $result = Yii::app()->db->createCommand($query)->limit(2,$q3c)->query(); + //loop thorugh results + foreach ($qresult->readAll() as $qrow) + { + $qrow=array_values($qrow); + //add results + $alist[]=array("Y", $statlang->gT("Yes")); + $alist[]=array("N", $statlang->gT("No")); + $alist[]=array("U", $statlang->gT("Uncertain")); + $atext=flattenText($qrow[1]); + } + //output + $qquestion .= $linefeed."[".$atext."]"; + $qtitle .= "($qanswer)"; + break; - foreach ($result->readAll() as $row) - { - if ($total == 0) {$total=$total-$row[$fieldname];} - else {$total=$total+$row[$fieldname];} - $lastnumber=$row[$fieldname]; - } - $q3total=$lastnumber-((1-$q3diff)*$total); + //Array of Yes/No/$statlang->gT("Uncertain") + //same as above + case "E": + $qquery = "SELECT title, question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qanswer' AND language='{$language}' ORDER BY question_order"; + $qresult=Yii::app()->db->createCommand($qquery)->query(); + foreach ($qresult->readAll() as $qrow) + { + $qrow=array_values($qrow); + $alist[]=array("I", $statlang->gT("Increase")); + $alist[]=array("S", $statlang->gT("Same")); + $alist[]=array("D", $statlang->gT("Decrease")); + $atext=flattenText($qrow[1]); + } + $qquestion .= $linefeed."[".$atext."]"; + $qtitle .= "($qanswer)"; + break; - if ($q3total < $maximum) {$q1total=$maximum;} - $showem[]=array($statlang->gT("3rd quartile (Q3)"), $q3total); - } + case ";": //Array (Multi Flexi) (Text) + list($qacode, $licode)=explode("_", $qanswer); - else - { - $query = $querystarter . " ORDER BY ".Yii::app()->db->quoteColumnName($fieldname)."*1"; - $result = Yii::app()->db->createCommand($query)->limit(1, $q3c); + $qquery = "SELECT title, question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qacode' AND language='{$language}' ORDER BY question_order"; + $qresult=Yii::app()->db->createCommand($qquery)->query(); - foreach ($result->queryAll() as $row) - { - $showem[]=array($statlang->gT("3rd quartile (Q3)"), $row[$fieldname]); - } - } + foreach ($qresult->readAll() as $qrow) + { + $qrow=array_values($qrow); + $fquery = "SELECT * FROM {{answers}} WHERE qid='{$qiqid}' AND scale_id=0 AND code = '{$licode}' AND language='{$language}'ORDER BY sortorder, code"; + $fresult = Yii::app()->db->createCommand($fquery)->query(); + foreach ($fresult->readAll() as $frow) + { + $alist[]=array($frow['code'], $frow['answer']); + $ltext=$frow['answer']; + } + $atext=flattenText($qrow[1]); + } - $total=0; + $qquestion .= $linefeed."[".$atext."] [".$ltext."]"; + $qtitle .= "($qanswer)"; + break; - $showem[]=array($statlang->gT("Maximum"), $maximum); - //output results - foreach ($showem as $shw) - { - switch($outputType) - { - case 'xls': + case ":": //Array (Multiple Flexi) (Numbers) + $qidattributes=getQuestionAttributeValues($qiqid); + if (trim($qidattributes['multiflexible_max'])!='') { + $maxvalue=$qidattributes['multiflexible_max']; + } + else { + $maxvalue=10; + } - ++$xlsRow; - $sheet->write($xlsRow, 0,html_entity_decode($shw[0],ENT_QUOTES,'UTF-8')); - $sheet->write($xlsRow, 1,html_entity_decode($shw[1],ENT_QUOTES,'UTF-8')); + if (trim($qidattributes['multiflexible_min'])!='') + { + $minvalue=$qidattributes['multiflexible_min']; + } + else { + $minvalue=1; + } + if (trim($qidattributes['multiflexible_step'])!='') + { + $stepvalue=$qidattributes['multiflexible_step']; + } + else { + $stepvalue=1; + } - $tableXLS[] = array($shw[0],$shw[1]); + if ($qidattributes['multiflexible_checkbox']!=0) { + $minvalue=0; + $maxvalue=1; + $stepvalue=1; + } - break; - case 'pdf': + for($i=$minvalue; $i<=$maxvalue; $i+=$stepvalue) + { + $alist[]=array($i, $i); + } - $tablePDF[] = array(html_entity_decode($shw[0],ENT_QUOTES,'UTF-8'),html_entity_decode($shw[1],ENT_QUOTES,'UTF-8')); + $qquestion .= $linefeed."[".$fielddata['subquestion1']."] [".$fielddata['subquestion2']."]"; + list($myans, $mylabel)=explode("_", $qanswer); + $qtitle .= "[$myans][$mylabel]"; + break; - break; - case 'html': + case "F": //Array of Flexible + case "H": //Array of Flexible by Column + $qquery = "SELECT title, question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qanswer' AND language='{$language}' ORDER BY question_order"; + $qresult=Yii::app()->db->createCommand($qquery)->query(); - $statisticsoutput .= "\t\n" - ."\t\t$shw[0]\n" - ."\t\t$shw[1]\n" - ."\t\n"; + //loop through answers + foreach ($qresult->readAll() as $qrow) + { + $qrow=array_values($qrow); - break; - default: + //this question type uses its own labels + $fquery = "SELECT * FROM {{answers}} WHERE qid='{$qiqid}' AND scale_id=0 AND language='{$language}'ORDER BY sortorder, code"; + $fresult = Yii::app()->db->createCommand($fquery)->query(); + //add code and title to results for outputting them later + foreach ($fresult->readAll() as $frow) + { + $alist[]=array($frow['code'], flattenText($frow['answer'])); + } - break; - } - } - switch($outputType) - { - case 'xls': + //counter + $atext=flattenText($qrow[1]); + } - ++$xlsRow; - $sheet->write($xlsRow, 0,$statlang->gT("Null values are ignored in calculations")); - ++$xlsRow; - $sheet->write($xlsRow, 0,sprintf($statlang->gT("Q1 and Q3 calculated using %s"), $statlang->gT("minitab method"))); + //output + $qquestion .= $linefeed."[".$atext."]"; + $qtitle .= "($qanswer)"; + break; - $footXLS[] = array($statlang->gT("Null values are ignored in calculations")); - $footXLS[] = array(sprintf($statlang->gT("Q1 and Q3 calculated using %s"), $statlang->gT("minitab method"))); - break; - case 'pdf': - $footPDF[] = array($statlang->gT("Null values are ignored in calculations")); - $footPDF[] = array(sprintf($statlang->gT("Q1 and Q3 calculated using %s"), "".$statlang->gT("minitab method")."")); - $pdf->addPage('P','A4'); - $pdf->Bookmark($pdf->delete_html($qquestion), 1, 0); - $pdf->titleintopdf($pdfTitle,$titleDesc); + case "G": //Gender + $alist[]=array("F", $statlang->gT("Female")); + $alist[]=array("M", $statlang->gT("Male")); + break; - $pdf->headTable($headPDF, $tablePDF); - $pdf->tablehead($footPDF); - break; - case 'html': + case "Y": //Yes\No + $alist[]=array("Y", $statlang->gT("Yes")); + $alist[]=array("N", $statlang->gT("No")); + break; - //footer of question type "N" - $statisticsoutput .= "\t\n" - ."\t\t\n" - ."\t\t\t".$statlang->gT("Null values are ignored in calculations")."
    \n" - ."\t\t\t".sprintf($statlang->gT("Q1 and Q3 calculated using %s"), "".$statlang->gT("minitab method")."") - ."
    \n" - ."\t\t\n" - ."\t\n\n"; - break; - default: + case "I": //Language + // Using previously defined $surveylanguagecodes array of language codes + foreach ($surveylanguagecodes as $availlang) + { + $alist[]=array($availlang, getLanguageNameFromCode($availlang,false)); + } + break; - break; - } - //clean up - unset($showem); + case "5": //5 Point (just 1 item to rank!) + for ($i=1; $i<=5; $i++) + { + $alist[]=array("$i", "$i"); + } + break; - } //end if (enough results?) - //not enough (<1) results for calculation - else - { - switch($outputType) - { - case 'xls': + case "1": //array (dual scale) - $tableXLS = array(); - $tableXLS[] = array($statlang->gT("Not enough values for calculation")); + $sSubquestionQuery = "SELECT question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qanswer' AND language='{$language}' ORDER BY question_order"; + $questionDesc = Yii::app()->db->createCommand($sSubquestionQuery)->query()->read(); + $sSubquestion = flattenText($questionDesc["question"]); - ++$xlsRow; - $sheet->write($xlsRow, 0, $statlang->gT("Not enough values for calculation")); + //get question attributes + $qidattributes=getQuestionAttributeValues($qqid); + //check last character -> label 1 + if (substr($rt,-1,1) == 0) + { + //get label 1 + $fquery = "SELECT * FROM {{answers}} WHERE qid='{$qqid}' AND scale_id=0 AND language='{$language}' ORDER BY sortorder, code"; + //header available? + if (trim($qidattributes['dualscale_headerA'][$language])!='') { + //output + $labelheader= "[".$qidattributes['dualscale_headerA'][$language]."]"; + } - break; - case 'pdf': + //no header + else + { + $labelheader =''; + } - $tablePDF = array(); - $tablePDF[] = array($statlang->gT("Not enough values for calculation")); - $pdf->addPage('P','A4'); - $pdf->Bookmark($pdf->delete_html($qquestion), 1, 0); - $pdf->titleintopdf($pdfTitle,$titleDesc); + //output + $labelno = sprintf($clang->gT('Label %s'),'1'); + } - $pdf->equalTable($tablePDF); + //label 2 + else + { + //get label 2 + $fquery = "SELECT * FROM {{answers}} WHERE qid='{$qqid}' AND scale_id=1 AND language='{$language}' ORDER BY sortorder, code"; - break; - case 'html': + //header available? + if (trim($qidattributes['dualscale_headerB'][$language])!='') { + //output + $labelheader= "[".$qidattributes['dualscale_headerB'][$language]."]"; + } - //output - $statisticsoutput .= "\t\n" - ."\t\t".$statlang->gT("Not enough values for calculation")."\n" - ."\t\n
    \n"; + //no header + else + { + $labelheader =''; + } - break; - default: + //output + $labelno = sprintf($clang->gT('Label %s'),'2'); + } + //get data + $fresult = Yii::app()->db->createCommand($fquery)->query(); - break; - } + //put label code and label title into array + foreach ($fresult->readAll() as $frow) + { + $alist[]=array($frow['code'], flattenText($frow['answer'])); + } - unset($showem); + //adapt title and question + $qtitle = $qtitle." [".$sSubquestion."][".$labelno."]"; + $qquestion = $qastring .$labelheader; + break; - } - } //end else -> check last character, greater/less/equals don't need special treatment - } //end else-if -> multiple numerical types - //is there some "id", "datestamp" or "D" within the type? - elseif (substr($rt, 0, 2) == "id" || substr($rt, 0, 9) == "datestamp" || ($firstletter == "D")) - { - /* - * DON'T show anything for date questions - * because there aren't any statistics implemented yet! - * - * See bug report #2539 and - * feature request #2620 - */ - } + default: //default handling - // NICE SIMPLE SINGLE OPTION ANSWERS - else - { - //search for key - $fielddata=$fieldmap[$rt]; - //print_r($fielddata); - //get SGQA IDs - $qsid=$fielddata['sid']; - $qgid=$fielddata['gid']; - $qqid=$fielddata['qid']; - $qanswer=$fielddata['aid']; - - //question type - $qtype=$fielddata['type']; - - //question string - $qastring=$fielddata['question']; - - //question ID - $rqid=$qqid; - - //get question data - $nquery = "SELECT title, type, question, qid, parent_qid, other FROM {{questions}} WHERE qid='{$rqid}' AND parent_qid=0 and language='{$language}'"; - $nresult = Yii::app()->db->createCommand($nquery)->query(); + //get answer code and title + $qquery = "SELECT code, answer FROM {{answers}} WHERE qid='$qqid' AND scale_id=0 AND language='{$language}' ORDER BY sortorder, answer"; + $qresult = Yii::app()->db->createCommand($qquery)->query(); - //loop though question data - foreach ($nresult->readAll() as $nrow) + //put answer code and title into array + foreach ($qresult->readAll() as $qrow) { - $nrow=array_values($nrow); - $qtitle=flattenText($nrow[0]); - $qtype=$nrow[1]; - $qquestion=flattenText($nrow[2]); - $qiqid=$nrow[3]; - $qparentqid=$nrow[4]; - $qother=$nrow[5]; + $qrow=array_values($qrow); + $alist[]=array("$qrow[0]", flattenText($qrow[1])); } - //check question types - switch($qtype) + //handling for "other" field for list radio or list drowpdown + if ((($qtype == "L" || $qtype == "!") && $qother == "Y")) { - //Array of 5 point choices (several items to rank!) - case "A": - - //get data - $qquery = "SELECT title, question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qanswer' AND language='{$language}' ORDER BY question_order"; - $qresult=Yii::app()->db->createCommand($qquery)->query(); + //add "other" + $alist[]=array($statlang->gT("Other"),$statlang->gT("Other"),$fielddata['fieldname'].'other'); + } + if ( $qtype == "O") + { + //add "comment" + $alist[]=array($statlang->gT("Comments"),$statlang->gT("Comments"),$fielddata['fieldname'].'comment'); + } - //loop through results - foreach ($qresult->readAll() as $qrow) - { - $qrow=array_values($qrow); - //5-point array - for ($i=1; $i<=5; $i++) - { - //add data - $alist[]=array("$i", "$i"); - } - //add counter - $atext=flattenText($qrow[1]); - } + } //end switch question type - //list IDs and answer codes in brackets - $qquestion .= $linefeed."[".$atext."]"; - $qtitle .= "($qanswer)"; - break; + //moved because it's better to have "no answer" at the end of the list instead of the beginning + //put data into array + $alist[]=array("", $statlang->gT("No answer")); + } + return array("alist"=>$alist, "qtitle"=>$qtitle, "qquestion"=>$qquestion, "qtype"=>$qtype); +} - //Array of 10 point choices - //same as above just with 10 items - case "B": - $qquery = "SELECT title, question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qanswer' AND language='{$language}' ORDER BY question_order"; - $qresult=Yii::app()->db->createCommand($qquery)->query(); - foreach ($qresult->readAll() as $qrow) - { - $qrow=array_values($qrow); - for ($i=1; $i<=10; $i++) - { - $alist[]=array("$i", "$i"); - } - $atext=flattenText($qrow[1]); - } +/** +* displayResults builds html output to display the actual results from a survey +* +* @param mixed $outputs +* @param INT $results The number of results being displayed overall +* @param mixed $rt +* @param mixed $outputType +* @param mixed $surveyid +* @param mixed $sql +* @param mixed $usegraph +*/ +function displayResults($outputs, $results, $rt, $outputType, $surveyid, $sql, $usegraph, $browse, $pdf) { - $qquestion .= $linefeed."[".$atext."]"; - $qtitle .= "($qanswer)"; - break; + /* Set up required variables */ + $TotalCompleted = 0; //Count of actually completed answers + $statlangcode = getBaseLanguageFromSurveyID($surveyid); + $statlang = new Limesurvey_lang($statlangcode); + $statisticsoutput=""; + $sDatabaseType = Yii::app()->db->getDriverName(); + switch($outputType) + { + case 'xls': + $xlsTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($outputs['qtitle'],ENT_QUOTES,'UTF-8')); + $xlsDesc = html_entity_decode($outputs['qquestion'],ENT_QUOTES,'UTF-8'); - //Array of Yes/No/$statlang->gT("Uncertain") - case "C": - $qquery = "SELECT title, question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qanswer' AND language='{$language}' ORDER BY question_order"; - $qresult=Yii::app()->db->createCommand($qquery)->query(); + ++$xlsRow; + ++$xlsRow; - //loop thorugh results - foreach ($qresult->readAll() as $qrow) - { - $qrow=array_values($qrow); - //add results - $alist[]=array("Y", $statlang->gT("Yes")); - $alist[]=array("N", $statlang->gT("No")); - $alist[]=array("U", $statlang->gT("Uncertain")); - $atext=flattenText($qrow[1]); - } - //output - $qquestion .= $linefeed."[".$atext."]"; - $qtitle .= "($qanswer)"; - break; + ++$xlsRow; + $sheet->write($xlsRow, 0,$xlsTitle); + ++$xlsRow; + $sheet->write($xlsRow, 0,$xlsDesc); + $tableXLS = array(); + $footXLS = array(); + break; + case 'pdf': - //Array of Yes/No/$statlang->gT("Uncertain") - //same as above - case "E": - $qquery = "SELECT title, question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qanswer' AND language='{$language}' ORDER BY question_order"; - $qresult=Yii::app()->db->createCommand($qquery)->query(); - foreach ($qresult->readAll() as $qrow) - { - $qrow=array_values($qrow); - $alist[]=array("I", $statlang->gT("Increase")); - $alist[]=array("S", $statlang->gT("Same")); - $alist[]=array("D", $statlang->gT("Decrease")); - $atext=flattenText($qrow[1]); - } - $qquestion .= $linefeed."[".$atext."]"; - $qtitle .= "($qanswer)"; - break; + $sPDFQuestion=flattenText($outputs['qquestion'],false,true); + $pdfTitle = $pdf->delete_html(sprintf($statlang->gT("Field summary for %s"),html_entity_decode($outputs['qtitle'],ENT_QUOTES,'UTF-8'))); + $titleDesc = $sPDFQuestion; + $pdf->addPage('P','A4'); + $pdf->Bookmark($sPDFQuestion, 1, 0); + $pdf->titleintopdf($pdfTitle,$sPDFQuestion); + $tablePDF = array(); + $footPDF = array(); - case ";": //Array (Multi Flexi) (Text) - list($qacode, $licode)=explode("_", $qanswer); + break; + case 'html': + //output + $statisticsoutput .= "\n" + ."\t\n" + ."\t\n" + ."\t\n\t\t\n" + ."\t\t\n" + ."\t\t\n" + ."\t\n"; + } - case "I": //Language - // Using previously defined $surveylanguagecodes array of language codes - foreach ($surveylanguagecodes as $availlang) + //check if aggregated results should be shown + elseif (Yii::app()->getConfig('showaggregateddata') == 1) + { + if(!isset($showheadline) || $showheadline != false) + { + if($outputs['qtype'] == "5" || $outputs['qtype'] == "A") + { + switch($outputType) { - $alist[]=array($availlang, getLanguageNameFromCode($availlang,false)); - } - break; + case 'xls': + $headXLS = array(); + $headXLS[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage"),$statlang->gT("Sum")); - case "5": //5 Point (just 1 item to rank!) - for ($i=1; $i<=5; $i++) - { - $alist[]=array("$i", "$i"); - } - break; + ++$xlsRow; + $sheet->write($xlsRow,0,$statlang->gT("Answer")); + $sheet->write($xlsRow,1,$statlang->gT("Count")); + $sheet->write($xlsRow,2,$statlang->gT("Percentage")); + $sheet->write($xlsRow,3,$statlang->gT("Sum")); + + break; + case 'pdf': + $headPDF = array(); + $headPDF[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage"),$statlang->gT("Sum")); + + break; + case 'html': + //four columns + $statisticsoutput .= "".$statlang->gT("Answer")."\n" + ."\t\t\n" + ."\t\t\n" + ."\t\t\n" + ."\t\n"; + break; + default: - case "1": //array (dual scale) - $sSubquestionQuery = "SELECT question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qanswer' AND language='{$language}' ORDER BY question_order"; - $questionDesc = Yii::app()->db->createCommand($sSubquestionQuery)->query()->read(); - $sSubquestion = flattenText($questionDesc["question"]); + break; + } - //get question attributes - $qidattributes=getQuestionAttributeValues($qqid); - //check last character -> label 1 - if (substr($rt,-1,1) == 0) + $showheadline = false; + } + else + { + switch($outputType) { - //get label 1 - $fquery = "SELECT * FROM {{answers}} WHERE qid='{$qqid}' AND scale_id=0 AND language='{$language}' ORDER BY sortorder, code"; + case 'xls': - //header available? - if (trim($qidattributes['dualscale_headerA'][$language])!='') { - //output - $labelheader= "[".$qidattributes['dualscale_headerA'][$language]."]"; - } + $headXLS = array(); + $headXLS[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage")); - //no header - else - { - $labelheader =''; - } + ++$xlsRow; + $sheet->write($xlsRow,0,$statlang->gT("Answer")); + $sheet->write($xlsRow,1,$statlang->gT("Count")); + $sheet->write($xlsRow,2,$statlang->gT("Percentage")); - //output - $labelno = sprintf($clang->gT('Label %s'),'1'); - } + break; - //label 2 - else - { - //get label 2 - $fquery = "SELECT * FROM {{answers}} WHERE qid='{$qqid}' AND scale_id=1 AND language='{$language}' ORDER BY sortorder, code"; + case 'pdf': + + $headPDF = array(); + $headPDF[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage")); - //header available? - if (trim($qidattributes['dualscale_headerB'][$language])!='') { - //output - $labelheader= "[".$qidattributes['dualscale_headerB'][$language]."]"; - } + break; + case 'html': + //three columns + $statisticsoutput .= "".$statlang->gT("Answer")."\n" + ."\t\t\n" + ."\t\t\n" + ."\t\n"; + break; + default: - //no header - else - { - $labelheader =''; - } - //output - $labelno = sprintf($clang->gT('Label %s'),'2'); + break; } - //get data - $fresult = Yii::app()->db->createCommand($fquery)->query(); + $showheadline = false; + } - //put label code and label title into array - foreach ($fresult->readAll() as $frow) - { - $alist[]=array($frow['code'], flattenText($frow['answer'])); - } + } - //adapt title and question - $qtitle = $qtitle." [".$sSubquestion."][".$labelno."]"; - $qquestion = $qastring .$labelheader; - break; + //text for answer column is always needed + $fname="$al[1] ($al[0])"; + //these question types get special treatment by Yii::app()->getConfig('showaggregateddata') + if($outputs['qtype'] == "5" || $outputs['qtype'] == "A") + { + //put non-edited data in here because $row will be edited later + $grawdata[]=$row[0]; + $showaggregated_indice=count($grawdata) - 1; + $showaggregated_indice_table[$showaggregated_indice]="aggregated"; + $showaggregated_indice=-1; + + //keep in mind that we already added data (will be checked later) + $justadded = true; + + //we need a counter because we want to sum up certain values + //reset counter if 5 items have passed + if(!isset($testcounter) || $testcounter >= 4) + { + $testcounter = 0; + } + else + { + $testcounter++; + } + //beside the known percentage value a new aggregated value should be shown + //therefore this item is marked in a certain way + if($testcounter == 0 ) //add 300 to original value + { + //store the original value! + $tempcount = $row[0]; + //HACK: add three times the total number of results to the value + //This way we get a 300 + X percentage which can be checked later + $row[0] += (3*$results); + } - default: //default handling + //the third value should be shown twice later -> mark it + if($testcounter == 2) //add 400 to original value + { + //store the original value! + $tempcount = $row[0]; + //HACK: add four times the total number of results to the value + //This way there should be a 400 + X percentage which can be checked later + $row[0] += (4*$results); + } - //get answer code and title - $qquery = "SELECT code, answer FROM {{answers}} WHERE qid='$qqid' AND scale_id=0 AND language='{$language}' ORDER BY sortorder, answer"; - $qresult = Yii::app()->db->createCommand($qquery)->query(); + //the last value aggregates the data of item 4 + item 5 later + if($testcounter == 4 ) //add 200 to original value + { + //store the original value! + $tempcount = $row[0]; + //HACK: add two times the total number of results to the value + //This way there should be a 200 + X percentage which can be checked later + $row[0] += (2*$results); + } - //put answer code and title into array - foreach ($qresult->readAll() as $qrow) - { - $qrow=array_values($qrow); - $alist[]=array("$qrow[0]", flattenText($qrow[1])); - } + } //end if -> question type = "5"/"A" - //handling for "other" field for list radio or list drowpdown - if ((($qtype == "L" || $qtype == "!") && $qother == "Y")) - { - //add "other" - $alist[]=array($statlang->gT("Other"),$statlang->gT("Other"),$fielddata['fieldname'].'other'); - } - if ( $qtype == "O") - { - //add "comment" - $alist[]=array($statlang->gT("Comments"),$statlang->gT("Comments"),$fielddata['fieldname'].'comment'); - } + } //end if -> show aggregated data - } //end switch question type + //handling what's left + else + { + if(!isset($showheadline) || $showheadline != false) + { + switch($outputType) + { + case 'xls': - //moved because it's better to have "no answer" at the end of the list instead of the beginning - //put data into array - $alist[]=array("", $statlang->gT("No answer")); + $headXLS = array(); + $headXLS[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage")); - } //end else -> single option answers + ++$xlsRow; + $sheet->write($xlsRow,0,$statlang->gT("Answer")); + $sheet->write($xlsRow,1,$statlang->gT("Count")); + $sheet->write($xlsRow,2,$statlang->gT("Percentage")); - //foreach ($alist as $al) {$statisticsoutput .= "$al[0] - $al[1]
    ";} //debugging line - //foreach ($fvalues as $fv) {$statisticsoutput .= "$fv | ";} //debugging line + break; + case 'pdf': + $headPDF = array(); + $headPDF[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage")); + break; + case 'html': + //three columns + $statisticsoutput .= "".$statlang->gT("Answer")."\n" + ."\t\t\n" + ."\t\t\n" + ."\t\n"; + break; + default: - //2. Collect and Display results ####################################################################### - if (isset($alist) && $alist) //Make sure there really is an answerlist, and if so: - { + break; + } - // this will count the answers considered completed - $TotalCompleted = 0; - switch($outputType) - { - case 'xls': + $showheadline = false; - $xlsTitle = sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8')); - $xlsDesc = html_entity_decode($qquestion,ENT_QUOTES,'UTF-8'); + } + //answer text + $fname="$al[1] ($al[0])"; + } - ++$xlsRow; - ++$xlsRow; + //are there some results to play with? + if ($results > 0) + { + //calculate percentage + $gdata[] = ($row[0]/$results)*100; + } + //no results + else + { + //no data! + $gdata[] = "N/A"; + } - ++$xlsRow; - $sheet->write($xlsRow, 0,$xlsTitle); - ++$xlsRow; - $sheet->write($xlsRow, 0,$xlsDesc); + //only add this if we don't handle question type "5"/"A" + if(!isset($justadded)) + { + //put absolute data into array + $grawdata[]=$row[0]; + } + else + { + //unset to handle "no answer" data correctly + unset($justadded); + } - $tableXLS = array(); - $footXLS = array(); + //put question title and code into array + $label[]=$fname; - break; - case 'pdf': + //put only the code into the array + $justcode[]=$al[0]; - $sPDFQuestion=flattenText($qquestion,false,true); - $pdfTitle = $pdf->delete_html(sprintf($statlang->gT("Field summary for %s"),html_entity_decode($qtitle,ENT_QUOTES,'UTF-8'))); - $titleDesc = $sPDFQuestion; + //edit labels and put them into antoher array - $pdf->addPage('P','A4'); - $pdf->Bookmark($sPDFQuestion, 1, 0); - $pdf->titleintopdf($pdfTitle,$sPDFQuestion); - $tablePDF = array(); - $footPDF = array(); + //first check if $tempcount is > 0. If yes, $row[0] has been modified and $tempcount has the original count. + if ($tempcount > 0) + { + $lbl[] = wordwrap(FlattenText("$al[1] ($tempcount)"), 25, "\n"); // NMO 2009-03-24 + $lblrtl[] = UTF8Strrev(wordwrap(FlattenText("$al[1] )$tempcount("), 25, "\n")); // NMO 2009-03-24 + } + else + { + $lbl[] = wordwrap(FlattenText("$al[1] ($row[0])"), 25, "\n"); // NMO 2009-03-24 + $lblrtl[] = UTF8Strrev(wordwrap(FlattenText("$al[1] )$row[0]("), 25, "\n")); // NMO 2009-03-24 - break; - case 'html': - //output - $statisticsoutput .= "
    " + + //headline + .sprintf($statlang->gT("Field summary for %s"),$outputs['qtitle'])."" + ."
    " + + //question title + .$outputs['qquestion']."
    "; + break; + default: - $qquery = "SELECT title, question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qacode' AND language='{$language}' ORDER BY question_order"; - $qresult=Yii::app()->db->createCommand($qquery)->query(); - foreach ($qresult->readAll() as $qrow) - { - $qrow=array_values($qrow); - $fquery = "SELECT * FROM {{answers}} WHERE qid='{$qiqid}' AND scale_id=0 AND code = '{$licode}' AND language='{$language}'ORDER BY sortorder, code"; - $fresult = Yii::app()->db->createCommand($fquery)->query(); - foreach ($fresult->readAll() as $frow) - { - $alist[]=array($frow['code'], $frow['answer']); - $ltext=$frow['answer']; - } - $atext=flattenText($qrow[1]); - } + break; + } + echo ''; - $qquestion .= $linefeed."[".$atext."] [".$ltext."]"; - $qtitle .= "($qanswer)"; - break; + //loop thorugh the array which contains all answer data + foreach ($outputs['alist'] as $al) + { + //picks out answer list ($outputs['alist']/$al)) that come from the multiple list above + if (isset($al[2]) && $al[2]) + { + //handling for "other" option + if ($al[0] == $statlang->gT("Other")) + { + if($outputs['qtype']=='!' || $outputs['qtype']=='L') + { + // It is better for single choice question types to filter on the number of '-oth-' entries, than to + // just count the number of 'other' values - that way with failing Javascript the statistics don't get messed up + $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE ".Yii::app()->db->quoteColumnName(substr($al[2],0,strlen($al[2])-5))."='-oth-'"; + } + else + { + //get data + $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE "; + $query .= ($sDatabaseType == "mysql")? Yii::app()->db->quoteColumnName($al[2])." != ''" : "NOT (".Yii::app()->db->quoteColumnName($al[2])." LIKE '')"; + } + } - case ":": //Array (Multiple Flexi) (Numbers) - $qidattributes=getQuestionAttributeValues($qiqid); - if (trim($qidattributes['multiflexible_max'])!='') { - $maxvalue=$qidattributes['multiflexible_max']; - } - else { - $maxvalue=10; - } + /* + * text questions: + * + * U = huge free text + * T = long free text + * S = short free text + * Q = multiple short text + */ - if (trim($qidattributes['multiflexible_min'])!='') - { - $minvalue=$qidattributes['multiflexible_min']; - } - else { - $minvalue=1; - } + elseif ($outputs['qtype'] == "U" || $outputs['qtype'] == "T" || $outputs['qtype'] == "S" || $outputs['qtype'] == "Q" || $outputs['qtype'] == ";") + { + $sDatabaseType = Yii::app()->db->getDriverName(); - if (trim($qidattributes['multiflexible_step'])!='') - { - $stepvalue=$qidattributes['multiflexible_step']; - } - else { - $stepvalue=1; - } + //free text answers + if($al[0]=="Answers") + { + $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE "; + $query .= ($sDatabaseType == "mysql")? Yii::app()->db->quoteColumnName($al[2])." != ''" : "NOT (".Yii::app()->db->quoteColumnName($al[2])." LIKE '')"; + } + //"no answer" handling + elseif($al[0]=="NoAnswer") + { + $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE ( "; + $query .= ($sDatabaseType == "mysql")? Yii::app()->db->quoteColumnName($al[2])." = '')" : " (".Yii::app()->db->quoteColumnName($al[2])." LIKE ''))"; + } + } + elseif ($outputs['qtype'] == "O") + { + $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE ( "; + $query .= ($sDatabaseType == "mysql")? Yii::app()->db->quoteColumnName($al[2])." <> '')" : " (".Yii::app()->db->quoteColumnName($al[2])." NOT LIKE ''))"; + // all other question types + } + else + { + $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE " . Yii::app()->db->quoteColumnName($al[2])." ="; - if ($qidattributes['multiflexible_checkbox']!=0) { - $minvalue=0; - $maxvalue=1; - $stepvalue=1; - } + //ranking question? + if (substr($rt, 0, 1) == "R") + { + $query .= " '$al[0]'"; + } + else + { + $query .= " 'Y'"; + } + } - for($i=$minvalue; $i<=$maxvalue; $i+=$stepvalue) - { - $alist[]=array($i, $i); - } + } //end if -> alist set - $qquestion .= $linefeed."[".$fielddata['subquestion1']."] [".$fielddata['subquestion2']."]"; - list($myans, $mylabel)=explode("_", $qanswer); - $qtitle .= "[$myans][$mylabel]"; - break; + else + { + if ($al[0] != "") + { + //get more data + $sDatabaseType = Yii::app()->db->getDriverName(); + if ($sDatabaseType == 'mssql' || $sDatabaseType == 'sqlsrv') + { + // mssql cannot compare text blobs so we have to cast here + $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE cast(".Yii::app()->db->quoteColumnName($rt)." as varchar)= '$al[0]'"; + } + else + $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE " . Yii::app()->db->quoteColumnName($rt)." = '$al[0]'"; + } + else + { // This is for the 'NoAnswer' case + // We need to take into account several possibilities + // * NoAnswer cause the participant clicked the NoAnswer radio + // ==> in this case value is '' or ' ' + // * NoAnswer in text field + // ==> value is '' + // * NoAnswer due to conditions, or a page not displayed + // ==> value is NULL + if ($sDatabaseType == 'mssql' || $sDatabaseType == 'sqlsrv') + { + // mssql cannot compare text blobs so we have to cast here + //$query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE (".sanitize_int($rt)." IS NULL " + $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE ( " + // . "OR cast(".sanitize_int($rt)." as varchar) = '' " + . "cast(".Yii::app()->db->quoteColumnName($rt)." as varchar) = '' " + . "OR cast(".Yii::app()->db->quoteColumnName($rt)." as varchar) = ' ' )"; + } + else + // $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE (".sanitize_int($rt)." IS NULL " + $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE ( " + // . "OR ".sanitize_int($rt)." = '' " + . " ".Yii::app()->db->quoteColumnName($rt)." = '' " + . "OR ".Yii::app()->db->quoteColumnName($rt)." = ' ') "; + } - case "F": //Array of Flexible - case "H": //Array of Flexible by Column - $qquery = "SELECT title, question FROM {{questions}} WHERE parent_qid='$qiqid' AND title='$qanswer' AND language='{$language}' ORDER BY question_order"; - $qresult=Yii::app()->db->createCommand($qquery)->query(); + } - //loop through answers - foreach ($qresult->readAll() as $qrow) - { - $qrow=array_values($qrow); + //check filter option + if (incompleteAnsFilterState() == "inc") {$query .= " AND submitdate is null";} + elseif (incompleteAnsFilterState() == "filter") {$query .= " AND submitdate is not null";} - //this question type uses its own labels - $fquery = "SELECT * FROM {{answers}} WHERE qid='{$qiqid}' AND scale_id=0 AND language='{$language}'ORDER BY sortorder, code"; - $fresult = Yii::app()->db->createCommand($fquery)->query(); + //check for any "sql" that has been passed from another script + if ($sql != "NULL") {$query .= " AND $sql";} - //add code and title to results for outputting them later - foreach ($fresult->readAll() as $frow) - { - $alist[]=array($frow['code'], flattenText($frow['answer'])); - } + //get data + $result=Yii::app()->db->createCommand($query)->query(); - //counter - $atext=flattenText($qrow[1]); - } + // $statisticsoutput .= "\n\n\n"; - //output - $qquestion .= $linefeed."[".$atext."]"; - $qtitle .= "($qanswer)"; - break; + // this just extracts the data, after we present + foreach ($result->readAll() as $row) + { + $row=array_values($row); + //store temporarily value of answer count of question type '5' and 'A'. + $tempcount = -1; //count can't be less han zero + //increase counter + $TotalCompleted += $row[0]; - case "G": //Gender - $alist[]=array("F", $statlang->gT("Female")); - $alist[]=array("M", $statlang->gT("Male")); - break; + //"no answer" handling + if ($al[0] === "") + {$fname=$statlang->gT("No answer");} + //"other" handling + //"Answers" means that we show an option to list answer to "other" text field + elseif ($al[0] === $statlang->gT("Other") || $al[0] === "Answers" || ($outputs['qtype'] === "O" && $al[0] === $statlang->gT("Comments")) || $outputs['qtype'] === "P") + { + if ($outputs['qtype'] == "P") $ColumnName_RM = $al[2]."comment"; + else $ColumnName_RM = $al[2]; + if ($outputs['qtype']=='O') { + $TotalCompleted -=$row[0]; + } + $fname="$al[1]"; + if ($browse===true) $fname .= " "; + } + /* + * text questions: + * + * U = huge free text + * T = long free text + * S = short free text + * Q = multiple short text + */ + elseif ($outputs['qtype'] == "S" || $outputs['qtype'] == "U" || $outputs['qtype'] == "T" || $outputs['qtype'] == "Q") + { + $headPDF = array(); + $headPDF[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage")); - case "Y": //Yes\No - $alist[]=array("Y", $statlang->gT("Yes")); - $alist[]=array("N", $statlang->gT("No")); - break; + //show free text answers + if ($al[0] == "Answers") + { + $fname= "$al[1]"; + if ($browse===true) $fname .= " "; + } + elseif ($al[0] == "NoAnswer") + { + $fname= "$al[1]"; + } + $statisticsoutput .= "" + ."".$statlang->gT("Count")."" + ."".$statlang->gT("Percentage")."
    " + ."".$statlang->gT("Count")."" + ."".$statlang->gT("Percentage")."" + ."".$statlang->gT("Sum")."
    " + ."".$statlang->gT("Count")."" + ."".$statlang->gT("Percentage")."
    " + ."".$statlang->gT("Count")."" + ."".$statlang->gT("Percentage")."
    \n" - ."\t\n" - ."\t\n" - ."\t\n\t\t\n" - ."\t\t\n" - ."\t\t\n" - ."\t\n"; - } + //loop through all available answers + while (isset($gdata[$i])) + { + //repeat header (answer, count, ...) for each new question + unset($showheadline); - //check if aggregated results should be shown - elseif (Yii::app()->getConfig('showaggregateddata') == 1) - { - if(!isset($showheadline) || $showheadline != false) - { - if($qtype == "5" || $qtype == "A") - { - switch($outputType) - { - case 'xls': - - $headXLS = array(); - $headXLS[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage"),$statlang->gT("Sum")); - - ++$xlsRow; - $sheet->write($xlsRow,0,$statlang->gT("Answer")); - $sheet->write($xlsRow,1,$statlang->gT("Count")); - $sheet->write($xlsRow,2,$statlang->gT("Percentage")); - $sheet->write($xlsRow,3,$statlang->gT("Sum")); - - break; - case 'pdf': - - $headPDF = array(); - $headPDF[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage"),$statlang->gT("Sum")); - - break; - case 'html': - //four columns - $statisticsoutput .= "".$statlang->gT("Answer")."\n" - ."\t\t\n" - ."\t\t\n" - ."\t\t\n" - ."\t\n"; - break; - default: - - - break; - } - - - $showheadline = false; - } - else - { - switch($outputType) - { - case 'xls': - - $headXLS = array(); - $headXLS[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage")); - - ++$xlsRow; - $sheet->write($xlsRow,0,$statlang->gT("Answer")); - $sheet->write($xlsRow,1,$statlang->gT("Count")); - $sheet->write($xlsRow,2,$statlang->gT("Percentage")); - - break; - - case 'pdf': - - $headPDF = array(); - $headPDF[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage")); - - break; - case 'html': - //three columns - $statisticsoutput .= "".$statlang->gT("Answer")."\n" - ."\t\t\n" - ."\t\t\n" - ."\t\n"; - break; - default: - - - break; - } - - $showheadline = false; - } - - } - - //text for answer column is always needed - $fname="$al[1] ($al[0])"; - - //these question types get special treatment by Yii::app()->getConfig('showaggregateddata') - if($qtype == "5" || $qtype == "A") - { - //put non-edited data in here because $row will be edited later - $grawdata[]=$row[0]; - $showaggregated_indice=count($grawdata) - 1; - $showaggregated_indice_table[$showaggregated_indice]="aggregated"; - $showaggregated_indice=-1; - - //keep in mind that we already added data (will be checked later) - $justadded = true; - - //we need a counter because we want to sum up certain values - //reset counter if 5 items have passed - if(!isset($testcounter) || $testcounter >= 4) - { - $testcounter = 0; - } - else - { - $testcounter++; - } - - //beside the known percentage value a new aggregated value should be shown - //therefore this item is marked in a certain way - - if($testcounter == 0 ) //add 300 to original value - { - //store the original value! - $tempcount = $row[0]; - //HACK: add three times the total number of results to the value - //This way we get a 300 + X percentage which can be checked later - $row[0] += (3*$results); - } - - //the third value should be shown twice later -> mark it - if($testcounter == 2) //add 400 to original value - { - //store the original value! - $tempcount = $row[0]; - //HACK: add four times the total number of results to the value - //This way there should be a 400 + X percentage which can be checked later - $row[0] += (4*$results); - } - - //the last value aggregates the data of item 4 + item 5 later - if($testcounter == 4 ) //add 200 to original value - { - //store the original value! - $tempcount = $row[0]; - //HACK: add two times the total number of results to the value - //This way there should be a 200 + X percentage which can be checked later - $row[0] += (2*$results); - } - - } //end if -> question type = "5"/"A" - - } //end if -> show aggregated data - - //handling what's left - else - { - if(!isset($showheadline) || $showheadline != false) - { - switch($outputType) - { - case 'xls': - - $headXLS = array(); - $headXLS[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage")); - - ++$xlsRow; - $sheet->write($xlsRow,0,$statlang->gT("Answer")); - $sheet->write($xlsRow,1,$statlang->gT("Count")); - $sheet->write($xlsRow,2,$statlang->gT("Percentage")); - - break; - case 'pdf': - - $headPDF = array(); - $headPDF[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage")); - - break; - case 'html': - //three columns - $statisticsoutput .= "".$statlang->gT("Answer")."\n" - ."\t\t\n" - ."\t\t\n" - ."\t\n"; - break; - default: - - - break; - } - - $showheadline = false; - - } - //answer text - $fname="$al[1] ($al[0])"; - } + /* + * there are 3 colums: + * + * 1 (50%) = answer (title and code in brackets) + * 2 (25%) = count (absolute) + * 3 (25%) = percentage + */ + $statisticsoutput .= "\t\n\t\t\n"; + /* + * If there is a "browse" button in this label, let's make sure there's an extra row afterwards + * to store the columnlist + * + * */ + if(strpos($label[$i], "class='statisticsbrowsebutton'")) + { + $extraline="\n"; + } - //are there some results to play with? - if ($results > 0) - { - //calculate percentage - $gdata[] = ($row[0]/$results)*100; - } - //no results - else - { - //no data! - $gdata[] = "N/A"; - } + //output absolute number of records + $statisticsoutput .= "\t\t"; - //only add this if we don't handle question type "5"/"A" - if(!isset($justadded)) - { - //put absolute data into array - $grawdata[]=$row[0]; - } - else - { - //unset to handle "no answer" data correctly - unset($justadded); - } - //put question title and code into array - $label[]=$fname; + //no data + if ($gdata[$i] == "N/A") + { + switch($outputType) + { + case 'xls': - //put only the code into the array - $justcode[]=$al[0]; + $label[$i]=flattenText($label[$i]); + $tableXLS[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $gdata[$i]). "%"); - //edit labels and put them into antoher array + ++$xlsRow; + $sheet->write($xlsRow,0,$label[$i]); + $sheet->write($xlsRow,1,$grawdata[$i]); + $sheet->write($xlsRow,2,sprintf("%01.2f", $gdata[$i]). "%"); - //first check if $tempcount is > 0. If yes, $row[0] has been modified and $tempcount has the original count. - if ($tempcount > 0) - { - $lbl[] = wordwrap(FlattenText("$al[1] ($tempcount)"), 25, "\n"); // NMO 2009-03-24 - $lblrtl[] = UTF8Strrev(wordwrap(FlattenText("$al[1] )$tempcount("), 25, "\n")); // NMO 2009-03-24 - } - else - { - $lbl[] = wordwrap(FlattenText("$al[1] ($row[0])"), 25, "\n"); // NMO 2009-03-24 - $lblrtl[] = UTF8Strrev(wordwrap(FlattenText("$al[1] )$row[0]("), 25, "\n")); // NMO 2009-03-24 + break; + case 'pdf': - } + $tablePDF[] = array(flattenText($label[$i]),$grawdata[$i],sprintf("%01.2f", $gdata[$i]). "%", ""); - } //end while -> loop through results + break; + case 'html': + //output when having no data + $statisticsoutput .= "\t\t"; + } + elseif ($outputs['qtype'] == "S" || $outputs['qtype'] == "U" || $outputs['qtype'] == "T" || $outputs['qtype'] == "Q") { - //calculate total number of incompleted records - $TotalIncomplete = $results - $TotalCompleted; + $statisticsoutput .= "\n\t"; + } + $statisticsoutput .= "\n"; //Close the row + if(isset($extraline)) {$statisticsoutput .= $extraline;} + break; + default: - //output - if ((incompleteAnsFilterState() != "filter")) - { - $fname=$statlang->gT("Not completed or Not displayed"); - } - else - { - $fname=$statlang->gT("Not displayed"); - } - //we need some data - if ($results > 0) - { - //calculate percentage - $gdata[] = ($TotalIncomplete/$results)*100; - } + break; + } - //no data :( - else - { - $gdata[] = "N/A"; - } + } - //put data of incompleted records into array - $grawdata[]=$TotalIncomplete; + //data available + else + { + //check if data should be aggregated + if(Yii::app()->getConfig('showaggregateddata') == 1 && ($outputs['qtype'] == "5" || $outputs['qtype'] == "A")) + { + //mark that we have done soemthing special here + $aggregated = true; - //put question title ("Not completed") into array - $label[]= $fname; + //just calculate everything once. the data is there in the array + if($itemcounter == 1) + { + //there are always 5 answers + for($x = 0; $x < 5; $x++) + { + //put 5 items into array for further calculations + array_push($stddevarray, $grawdata[$x]); + } + } - //put the code ("Not completed") into the array - $justcode[]=$fname; + //"no answer" & items 2 / 4 - nothing special to do here, just adjust output + if($gdata[$i] <= 100) + { + if($itemcounter == 2 && $label[$i+4] == $statlang->gT("No answer")) + { + //prevent division by zero + if(($results - $grawdata[$i+4]) > 0) + { + //re-calculate percentage + $percentage = ($grawdata[$i] / ($results - $grawdata[$i+4])) * 100; + } + else + { + $percentage = 0; + } - //edit labels and put them into antoher array - if ((incompleteAnsFilterState() != "filter")) + } + elseif($itemcounter == 4 && $label[$i+2] == $statlang->gT("No answer")) + { + //prevent division by zero + if(($results - $grawdata[$i+2]) > 0) { - $lbl[] = wordwrap(flattenText($statlang->gT("Not completed or Not displayed")." ($TotalIncomplete)"), 20, "\n"); // NMO 2009-03-24 + //re-calculate percentage + $percentage = ($grawdata[$i] / ($results - $grawdata[$i+2])) * 100; } else { - $lbl[] = wordwrap(flattenText($statlang->gT("Not displayed")." ($TotalIncomplete)"), 20, "\n"); // NMO 2009-03-24 + $percentage = 0; } - } //end else -> noncompleted NOT checked + } + else + { + $percentage = $gdata[$i]; + } + switch($outputType) + { + case 'xls': - } //end if -> no filtering of incomplete answers and no multiple option questions + $label[$i]=flattenText($label[$i]); + $tableXLS[]= array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%"); + ++$xlsRow; + $sheet->write($xlsRow,0,$label[$i]); + $sheet->write($xlsRow,1,$grawdata[$i]); + $sheet->write($xlsRow,2,sprintf("%01.2f", $percentage)."%"); - //counter - $i=0; + break; + case 'pdf': + $label[$i]=flattenText($label[$i]); + $tablePDF[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%", ""); - //we need to know which item we are editing - $itemcounter = 1; + break; + case 'html': + //output + $statisticsoutput .= "\t\t"; + break; + default: - /* - * there are 3 colums: - * - * 1 (50%) = answer (title and code in brackets) - * 2 (25%) = count (absolute) - * 3 (25%) = percentage - */ - $statisticsoutput .= "\t\n\t\t\n"; - /* - * If there is a "browse" button in this label, let's make sure there's an extra row afterwards - * to store the columnlist - * - * */ - if(strpos($label[$i], "class='statisticsbrowsebutton'")) - { - $extraline="\n"; + break; } - //output absolute number of records - $statisticsoutput .= "\t\t"; + } + //item 3 - just show results twice + //old: if($gdata[$i] >= 400) + //trying to fix bug #2583: + if($gdata[$i] >= 400 && $i != 0) + { + //remove "400" which was added before + $gdata[$i] -= 400; - //no data - if ($gdata[$i] == "N/A") + if($itemcounter == 3 && $label[$i+3] == $statlang->gT("No answer")) { - switch($outputType) + //prevent division by zero + if(($results - $grawdata[$i+3]) > 0) { - case 'xls': + //re-calculate percentage + $percentage = ($grawdata[$i] / ($results - $grawdata[$i+3])) * 100; + } + else + { + $percentage = 0; + } + } + else + { + //get the original percentage + $percentage = $gdata[$i]; + } + switch($outputType) + { + case 'xls': - $label[$i]=flattenText($label[$i]); - $tableXLS[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $gdata[$i]). "%"); + $label[$i]=flattenText($label[$i]); + $tableXLS[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%",sprintf("%01.2f", $percentage)."%"); - ++$xlsRow; - $sheet->write($xlsRow,0,$label[$i]); - $sheet->write($xlsRow,1,$grawdata[$i]); - $sheet->write($xlsRow,2,sprintf("%01.2f", $gdata[$i]). "%"); + ++$xlsRow; + $sheet->write($xlsRow,0,$label[$i]); + $sheet->write($xlsRow,1,$grawdata[$i]); + $sheet->write($xlsRow,2,sprintf("%01.2f", $percentage)."%"); + $sheet->write($xlsRow,3,sprintf("%01.2f", $percentage)."%"); - break; - case 'pdf': + break; + case 'pdf': + $label[$i]=flattenText($label[$i]); + $tablePDF[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%",sprintf("%01.2f", $percentage)."%"); - $tablePDF[] = array(flattenText($label[$i]),$grawdata[$i],sprintf("%01.2f", $gdata[$i]). "%", ""); + break; + case 'html': + //output percentage + $statisticsoutput .= "\t\t"; + + //output again (no real aggregation here) + $statisticsoutput .= "\t\t\t\t"; + break; + default: - break; - case 'html': - //output when having no data - $statisticsoutput .= "\t\t"; - } - elseif ($qtype == "S" || $qtype == "U" || $qtype == "T" || $qtype == "Q") - { - $statisticsoutput .= "\n\t"; - } - $statisticsoutput .= "\n"; //Close the row - if(isset($extraline)) {$statisticsoutput .= $extraline;} - break; - default: + break; + } - break; - } + } - } + //FIRST value -> add percentage of item 1 + item 2 + //old: if($gdata[$i] >= 300 && $gdata[$i] < 400) + //trying to fix bug #2583: + if(($gdata[$i] >= 300 && $gdata[$i] < 400) || ($i == 0 && $gdata[$i] <= 400)) + { + //remove "300" which was added before + $gdata[$i] -= 300; - //data available - else + if($itemcounter == 1 && $label[$i+5] == $statlang->gT("No answer")) { - //check if data should be aggregated - if(Yii::app()->getConfig('showaggregateddata') == 1 && ($qtype == "5" || $qtype == "A")) + //prevent division by zero + if(($results - $grawdata[$i+5]) > 0) { - //mark that we have done soemthing special here - $aggregated = true; - - //just calculate everything once. the data is there in the array - if($itemcounter == 1) - { - //there are always 5 answers - for($x = 0; $x < 5; $x++) - { - //put 5 items into array for further calculations - array_push($stddevarray, $grawdata[$x]); - } - } - - //"no answer" & items 2 / 4 - nothing special to do here, just adjust output - if($gdata[$i] <= 100) - { - if($itemcounter == 2 && $label[$i+4] == $statlang->gT("No answer")) - { - //prevent division by zero - if(($results - $grawdata[$i+4]) > 0) - { - //re-calculate percentage - $percentage = ($grawdata[$i] / ($results - $grawdata[$i+4])) * 100; - } - else - { - $percentage = 0; - } - - } - elseif($itemcounter == 4 && $label[$i+2] == $statlang->gT("No answer")) - { - //prevent division by zero - if(($results - $grawdata[$i+2]) > 0) - { - //re-calculate percentage - $percentage = ($grawdata[$i] / ($results - $grawdata[$i+2])) * 100; - } - else - { - $percentage = 0; - } - } - else - { - $percentage = $gdata[$i]; - } - switch($outputType) - { - case 'xls': - - $label[$i]=flattenText($label[$i]); - $tableXLS[]= array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%"); - - ++$xlsRow; - $sheet->write($xlsRow,0,$label[$i]); - $sheet->write($xlsRow,1,$grawdata[$i]); - $sheet->write($xlsRow,2,sprintf("%01.2f", $percentage)."%"); - - break; - case 'pdf': - $label[$i]=flattenText($label[$i]); - $tablePDF[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%", ""); - - break; - case 'html': - //output - $statisticsoutput .= "\t\t"; - break; - default: - - - break; - } - - } - - //item 3 - just show results twice - //old: if($gdata[$i] >= 400) - //trying to fix bug #2583: - if($gdata[$i] >= 400 && $i != 0) - { - //remove "400" which was added before - $gdata[$i] -= 400; - - if($itemcounter == 3 && $label[$i+3] == $statlang->gT("No answer")) - { - //prevent division by zero - if(($results - $grawdata[$i+3]) > 0) - { - //re-calculate percentage - $percentage = ($grawdata[$i] / ($results - $grawdata[$i+3])) * 100; - } - else - { - $percentage = 0; - } - } - else - { - //get the original percentage - $percentage = $gdata[$i]; - } - switch($outputType) - { - case 'xls': - - $label[$i]=flattenText($label[$i]); - $tableXLS[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%",sprintf("%01.2f", $percentage)."%"); - - ++$xlsRow; - $sheet->write($xlsRow,0,$label[$i]); - $sheet->write($xlsRow,1,$grawdata[$i]); - $sheet->write($xlsRow,2,sprintf("%01.2f", $percentage)."%"); - $sheet->write($xlsRow,3,sprintf("%01.2f", $percentage)."%"); - - break; - case 'pdf': - $label[$i]=flattenText($label[$i]); - $tablePDF[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%",sprintf("%01.2f", $percentage)."%"); - - break; - case 'html': - //output percentage - $statisticsoutput .= "\t\t"; - - //output again (no real aggregation here) - $statisticsoutput .= "\t\t\t\t"; - break; - default: - - - break; - } - - } - - //FIRST value -> add percentage of item 1 + item 2 - //old: if($gdata[$i] >= 300 && $gdata[$i] < 400) - //trying to fix bug #2583: - if(($gdata[$i] >= 300 && $gdata[$i] < 400) || ($i == 0 && $gdata[$i] <= 400)) - { - //remove "300" which was added before - $gdata[$i] -= 300; - - if($itemcounter == 1 && $label[$i+5] == $statlang->gT("No answer")) - { - //prevent division by zero - if(($results - $grawdata[$i+5]) > 0) - { - //re-calculate percentage - $percentage = ($grawdata[$i] / ($results - $grawdata[$i+5])) * 100; - $percentage2 = ($grawdata[$i + 1] / ($results - $grawdata[$i+5])) * 100; - } - else - { - $percentage = 0; - $percentage2 = 0; - - } - } - else - { - $percentage = $gdata[$i]; - $percentage2 = $gdata[$i+1]; - } - //percentage of item 1 + item 2 - $aggregatedgdata = $percentage + $percentage2; - - - switch($outputType) - { - case 'xls': - - $label[$i]=flattenText($label[$i]); - $tableXLS[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%",sprintf("%01.2f", $aggregatedgdata)."%"); - - ++$xlsRow; - $sheet->write($xlsRow,0,$label[$i]); - $sheet->write($xlsRow,1,$grawdata[$i]); - $sheet->write($xlsRow,2,sprintf("%01.2f", $percentage)."%"); - $sheet->write($xlsRow,3,sprintf("%01.2f", $aggregatedgdata)."%"); - - break; - case 'pdf': - $label[$i]=flattenText($label[$i]); - $tablePDF[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%",sprintf("%01.2f", $aggregatedgdata)."%"); - - break; - case 'html': - //output percentage - $statisticsoutput .= "\t\t"; - - //output aggregated data - $statisticsoutput .= "\t\t\t\t"; - break; - default: - - - break; - } - } - - //LAST value -> add item 4 + item 5 - if($gdata[$i] > 100 && $gdata[$i] < 300) - { - //remove "200" which was added before - $gdata[$i] -= 200; - - if($itemcounter == 5 && $label[$i+1] == $statlang->gT("No answer")) - { - //prevent division by zero - if(($results - $grawdata[$i+1]) > 0) - { - //re-calculate percentage - $percentage = ($grawdata[$i] / ($results - $grawdata[$i+1])) * 100; - $percentage2 = ($grawdata[$i - 1] / ($results - $grawdata[$i+1])) * 100; - } - else - { - $percentage = 0; - $percentage2 = 0; - } - } - else - { - $percentage = $gdata[$i]; - $percentage2 = $gdata[$i-1]; - } - - //item 4 + item 5 - $aggregatedgdata = $percentage + $percentage2; - switch($outputType) - { - case 'xls': - - $label[$i]=flattenText($label[$i]); - $tableXLS[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%",sprintf("%01.2f", $aggregatedgdata)."%"); - - ++$xlsRow; - $sheet->write($xlsRow,0,$label[$i]); - $sheet->write($xlsRow,1,$grawdata[$i]); - $sheet->write($xlsRow,2,sprintf("%01.2f", $percentage)."%"); - $sheet->write($xlsRow,3,sprintf("%01.2f", $aggregatedgdata)."%"); - - break; - case 'pdf': - $label[$i]=flattenText($label[$i]); - $tablePDF[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%",sprintf("%01.2f", $aggregatedgdata)."%"); - - break; - case 'html': - //output percentage - $statisticsoutput .= "\t\t"; - - //output aggregated data - $statisticsoutput .= "\t\t\t\t"; - break; - default: - - - break; - } - - // create new row "sum" - //calculate sum of items 1-5 - $sumitems = $grawdata[$i] - + $grawdata[$i-1] - + $grawdata[$i-2] - + $grawdata[$i-3] - + $grawdata[$i-4]; - - //special treatment for zero values - if($sumitems > 0) - { - $sumpercentage = "100.00"; - } - else - { - $sumpercentage = "0"; - } - //special treatment for zero values - if($TotalCompleted > 0) - { - $casepercentage = "100.00"; - } - else - { - $casepercentage = "0"; - } - switch($outputType) - { - case 'xls': - - - $footXLS[] = array($statlang->gT("Sum")." (".$statlang->gT("Answers").")",$sumitems,$sumpercentage."%",$sumpercentage."%"); - $footXLS[] = array($statlang->gT("Number of cases"),$TotalCompleted,$casepercentage."%",""); - - ++$xlsRow; - $sheet->write($xlsRow,0,$statlang->gT("Sum")." (".$statlang->gT("Answers").")"); - $sheet->write($xlsRow,1,$sumitems); - $sheet->write($xlsRow,2,$sumpercentage."%"); - $sheet->write($xlsRow,3,$sumpercentage."%"); - ++$xlsRow; - $sheet->write($xlsRow,0,$statlang->gT("Number of cases")); - $sheet->write($xlsRow,1,$TotalCompleted); - $sheet->write($xlsRow,2,$casepercentage."%"); - - break; - case 'pdf': - - $footPDF[] = array($statlang->gT("Sum")." (".$statlang->gT("Answers").")",$sumitems,$sumpercentage."%",$sumpercentage."%"); - $footPDF[] = array($statlang->gT("Number of cases"),$TotalCompleted,$casepercentage."%",""); - - break; - case 'html': - $statisticsoutput .= "\t\t \n\t\n"; - $statisticsoutput .= ""; - $statisticsoutput .= ""; - $statisticsoutput .= ""; - $statisticsoutput .= ""; - $statisticsoutput .= "\t\t \n\t\n"; - - $statisticsoutput .= ""; //German: "Fallzahl" - $statisticsoutput .= ""; - $statisticsoutput .= ""; - //there has to be a whitespace within the table cell to display correctly - $statisticsoutput .= ""; - break; - default: - - - break; - } - - } - - } //end if -> show aggregated data - - //don't show aggregated data + //re-calculate percentage + $percentage = ($grawdata[$i] / ($results - $grawdata[$i+5])) * 100; + $percentage2 = ($grawdata[$i + 1] / ($results - $grawdata[$i+5])) * 100; + } else { - switch($outputType) - { - case 'xls': - $label[$i]=flattenText($label[$i]); - $tableXLS[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $gdata[$i])."%", ""); - - ++$xlsRow; - $sheet->write($xlsRow,0,$label[$i]); - $sheet->write($xlsRow,1,$grawdata[$i]); - $sheet->write($xlsRow,2,sprintf("%01.2f", $gdata[$i])."%"); - - break; - case 'pdf': - $label[$i]=flattenText($label[$i]); - $tablePDF[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $gdata[$i])."%", ""); - - break; - case 'html': - //output percentage - $statisticsoutput .= "\t\t\n\t\n"; - if(isset($extraline)) {$statisticsoutput .= $extraline;} - break; - default: - - - break; - } + $percentage = 0; + $percentage2 = 0; } + } + else + { + $percentage = $gdata[$i]; + $percentage2 = $gdata[$i+1]; + } + //percentage of item 1 + item 2 + $aggregatedgdata = $percentage + $percentage2; + - } //end else -> $gdata[$i] != "N/A" + switch($outputType) + { + case 'xls': + $label[$i]=flattenText($label[$i]); + $tableXLS[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%",sprintf("%01.2f", $aggregatedgdata)."%"); + ++$xlsRow; + $sheet->write($xlsRow,0,$label[$i]); + $sheet->write($xlsRow,1,$grawdata[$i]); + $sheet->write($xlsRow,2,sprintf("%01.2f", $percentage)."%"); + $sheet->write($xlsRow,3,sprintf("%01.2f", $aggregatedgdata)."%"); - //increase counter - $i++; + break; + case 'pdf': + $label[$i]=flattenText($label[$i]); + $tablePDF[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%",sprintf("%01.2f", $aggregatedgdata)."%"); - $itemcounter++; + break; + case 'html': + //output percentage + $statisticsoutput .= "\t\t"; + + //output aggregated data + $statisticsoutput .= "\t\t\t\t"; + break; + default: - //Clear extraline - unset($extraline); - } //end while + break; + } + } - //only show additional values when this setting is enabled - if(Yii::app()->getConfig('showaggregateddata') == 1 ) + //LAST value -> add item 4 + item 5 + if($gdata[$i] > 100 && $gdata[$i] < 300) { - //it's only useful to calculate standard deviation and arithmetic means for question types - //5 = 5 Point Scale - //A = Array (5 Point Choice) - if($qtype == "5" || $qtype == "A") - { - $stddev = 0; - $am = 0; + //remove "200" which was added before + $gdata[$i] -= 200; - //calculate arithmetic mean - if(isset($sumitems) && $sumitems > 0) + if($itemcounter == 5 && $label[$i+1] == $statlang->gT("No answer")) + { + //prevent division by zero + if(($results - $grawdata[$i+1]) > 0) { - - - //calculate and round results - //there are always 5 items - for($x = 0; $x < 5; $x++) - { - //create product of item * value - $am += (($x+1) * $stddevarray[$x]); - } - - //prevent division by zero - if(isset($stddevarray) && array_sum($stddevarray) > 0) - { - $am = round($am / array_sum($stddevarray),2); - } - else - { - $am = 0; - } - - //calculate standard deviation -> loop through all data - /* - * four steps to calculate the standard deviation - * 1 = calculate difference between item and arithmetic mean and multiply with the number of elements - * 2 = create sqaure value of difference - * 3 = sum up square values - * 4 = multiply result with 1 / (number of items) - * 5 = get root - */ - - - - for($j = 0; $j < 5; $j++) - { - //1 = calculate difference between item and arithmetic mean - $diff = (($j+1) - $am); - - //2 = create square value of difference - $squarevalue = square($diff); - - //3 = sum up square values and multiply them with the occurence - //prevent divison by zero - if($squarevalue != 0 && $stddevarray[$j] != 0) - { - $stddev += $squarevalue * $stddevarray[$j]; - } - - } - - //4 = multiply result with 1 / (number of items (=5)) - //There are two different formulas to calculate standard derivation - //$stddev = $stddev / array_sum($stddevarray); //formula source: http://de.wikipedia.org/wiki/Standardabweichung - - //prevent division by zero - if((array_sum($stddevarray)-1) != 0 && $stddev != 0) - { - $stddev = $stddev / (array_sum($stddevarray)-1); //formula source: http://de.wikipedia.org/wiki/Empirische_Varianz - } - else - { - $stddev = 0; - } - - //5 = get root - $stddev = sqrt($stddev); - $stddev = round($stddev,2); + //re-calculate percentage + $percentage = ($grawdata[$i] / ($results - $grawdata[$i+1])) * 100; + $percentage2 = ($grawdata[$i - 1] / ($results - $grawdata[$i+1])) * 100; } - switch($outputType) + else { - case 'xls': + $percentage = 0; + $percentage2 = 0; + } + } + else + { + $percentage = $gdata[$i]; + $percentage2 = $gdata[$i-1]; + } - $tableXLS[] = array($statlang->gT("Arithmetic mean"),$am,'',''); - $tableXLS[] = array($statlang->gT("Standard deviation"),$stddev,'',''); + //item 4 + item 5 + $aggregatedgdata = $percentage + $percentage2; + switch($outputType) + { + case 'xls': - ++$xlsRow; - $sheet->write($xlsRow,0,$statlang->gT("Arithmetic mean")); - $sheet->write($xlsRow,1,$am); + $label[$i]=flattenText($label[$i]); + $tableXLS[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%",sprintf("%01.2f", $aggregatedgdata)."%"); - ++$xlsRow; - $sheet->write($xlsRow,0,$statlang->gT("Standard deviation")); - $sheet->write($xlsRow,1,$stddev); + ++$xlsRow; + $sheet->write($xlsRow,0,$label[$i]); + $sheet->write($xlsRow,1,$grawdata[$i]); + $sheet->write($xlsRow,2,sprintf("%01.2f", $percentage)."%"); + $sheet->write($xlsRow,3,sprintf("%01.2f", $aggregatedgdata)."%"); - break; - case 'pdf': + break; + case 'pdf': + $label[$i]=flattenText($label[$i]); + $tablePDF[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $percentage)."%",sprintf("%01.2f", $aggregatedgdata)."%"); - $tablePDF[] = array($statlang->gT("Arithmetic mean"),$am,'',''); - $tablePDF[] = array($statlang->gT("Standard deviation"),$stddev,'',''); + break; + case 'html': + //output percentage + $statisticsoutput .= "\t\t"; + + //output aggregated data + $statisticsoutput .= "\t\t\t\t"; + break; + default: - break; - case 'html': - //calculate standard deviation - $statisticsoutput .= ""; //German: "Fallzahl" - $statisticsoutput .= ""; - $statisticsoutput .= ""; //German: "Fallzahl" - $statisticsoutput .= ""; - break; - default: + break; + } + // create new row "sum" + //calculate sum of items 1-5 + $sumitems = $grawdata[$i] + + $grawdata[$i-1] + + $grawdata[$i-2] + + $grawdata[$i-3] + + $grawdata[$i-4]; - break; - } + //special treatment for zero values + if($sumitems > 0) + { + $sumpercentage = "100.00"; + } + else + { + $sumpercentage = "0"; + } + //special treatment for zero values + if($TotalCompleted > 0) + { + $casepercentage = "100.00"; + } + else + { + $casepercentage = "0"; + } + switch($outputType) + { + case 'xls': + + + $footXLS[] = array($statlang->gT("Sum")." (".$statlang->gT("Answers").")",$sumitems,$sumpercentage."%",$sumpercentage."%"); + $footXLS[] = array($statlang->gT("Number of cases"),$TotalCompleted,$casepercentage."%",""); + + ++$xlsRow; + $sheet->write($xlsRow,0,$statlang->gT("Sum")." (".$statlang->gT("Answers").")"); + $sheet->write($xlsRow,1,$sumitems); + $sheet->write($xlsRow,2,$sumpercentage."%"); + $sheet->write($xlsRow,3,$sumpercentage."%"); + ++$xlsRow; + $sheet->write($xlsRow,0,$statlang->gT("Number of cases")); + $sheet->write($xlsRow,1,$TotalCompleted); + $sheet->write($xlsRow,2,$casepercentage."%"); + + break; + case 'pdf': + + $footPDF[] = array($statlang->gT("Sum")." (".$statlang->gT("Answers").")",$sumitems,$sumpercentage."%",$sumpercentage."%"); + $footPDF[] = array($statlang->gT("Number of cases"),$TotalCompleted,$casepercentage."%",""); + + break; + case 'html': + $statisticsoutput .= "\t\t \n\t\n"; + $statisticsoutput .= ""; + $statisticsoutput .= ""; + $statisticsoutput .= ""; + $statisticsoutput .= ""; + $statisticsoutput .= "\t\t \n\t\n"; + + $statisticsoutput .= ""; //German: "Fallzahl" + $statisticsoutput .= ""; + $statisticsoutput .= ""; + //there has to be a whitespace within the table cell to display correctly + $statisticsoutput .= ""; + break; + default: + + + break; } + } - if($outputType=='pdf') //XXX TODO PDF + } //end if -> show aggregated data + + //don't show aggregated data + else + { + switch($outputType) { - //$tablePDF = array(); - $tablePDF = array_merge_recursive($tablePDF, $footPDF); - $pdf->headTable($headPDF,$tablePDF); - //$pdf->tableintopdf($tablePDF); - - // if(isset($footPDF)) - // foreach($footPDF as $foot) - // { - // $footA = array($foot); - // $pdf->tablehead($footA); - // } - } - - if ($outputType=='html') { - $statisticsoutput .= "\n\t\n"; + if(isset($extraline)) {$statisticsoutput .= $extraline;} + break; + default: - $pdf->AddPage('P','A4'); - $pdf->titleintopdf($pdfTitle,$titleDesc); - $pdf->Image($tempdir."/".$cachefilename, 0, 70, 180, 0, '', $homeurl."/admin.php?sid=$surveyid", 'B', true, 150,'C',false,false,0,true); + break; + } - break; - case 'html': - $statisticsoutput .= ""; - - $aattr = getQuestionAttributeValues($qqid, $firstletter); - if ($bShowMap) { - $statisticsoutput .= "
    "; - - $agmapdata[$rt] = array ( - "coord" => getQuestionMapData(substr($rt, 1), $qsid), - "zoom" => $aattr['location_mapzoom'], - "width" => $aattr['location_mapwidth'], - "height" => $aattr['location_mapheight'] - ); - } - break; - default: + } + } //end else -> $gdata[$i] != "N/A" - break; - } - } + + //increase counter + $i++; + + $itemcounter++; + + //Clear extraline + unset($extraline); + + } //end while + + //only show additional values when this setting is enabled + if(Yii::app()->getConfig('showaggregateddata') == 1 ) + { + //it's only useful to calculate standard deviation and arithmetic means for question types + //5 = 5 Point Scale + //A = Array (5 Point Choice) + if($outputs['qtype'] == "5" || $outputs['qtype'] == "A") + { + $stddev = 0; + $am = 0; + + //calculate arithmetic mean + if(isset($sumitems) && $sumitems > 0) + { + + + //calculate and round results + //there are always 5 items + for($x = 0; $x < 5; $x++) + { + //create product of item * value + $am += (($x+1) * $stddevarray[$x]); } - //close table/output - if($outputType=='html') { - if ($usegraph==1) { - $sImgUrl = Yii::app()->getConfig('adminimageurl'); + //prevent division by zero + if(isset($stddevarray) && array_sum($stddevarray) > 0) + { + $am = round($am / array_sum($stddevarray),2); + } + else + { + $am = 0; + } + + //calculate standard deviation -> loop through all data + /* + * four steps to calculate the standard deviation + * 1 = calculate difference between item and arithmetic mean and multiply with the number of elements + * 2 = create sqaure value of difference + * 3 = sum up square values + * 4 = multiply result with 1 / (number of items) + * 5 = get root + */ + + + + for($j = 0; $j < 5; $j++) + { + //1 = calculate difference between item and arithmetic mean + $diff = (($j+1) - $am); - $statisticsoutput .= ""; + //2 = create square value of difference + $squarevalue = square($diff); + //3 = sum up square values and multiply them with the occurence + //prevent divison by zero + if($squarevalue != 0 && $stddevarray[$j] != 0) + { + $stddev += $squarevalue * $stddevarray[$j]; } - $statisticsoutput .= "
    " + } - //headline - .sprintf($statlang->gT("Field summary for %s"),$qtitle)."" - ."
    " + } //end while -> loop through results - //question title - .$qquestion."
    "; - break; - default: + } //end foreach -> loop through answer data + //no filtering of incomplete answers and NO multiple option questions + //if ((incompleteAnsFilterState() != "filter") and ($outputs['qtype'] != "M") and ($outputs['qtype'] != "P")) + //error_log("TIBO ".print_r($showaggregated_indice_table,true)); + if (($outputs['qtype'] != "M") and ($outputs['qtype'] != "P")) + { + //is the checkbox "Don't consider NON completed responses (only works when Filter incomplete answers is Disable)" checked? + //if (isset($_POST["noncompleted"]) and ($_POST["noncompleted"] == "on") && (isset(Yii::app()->getConfig('showaggregateddata')) && Yii::app()->getConfig('showaggregateddata') == 0)) + // TIBO: TODO WE MUST SKIP THE FOLLOWING SECTION FOR TYPE A and 5 when + // showaggreagated data is set and set to 1 + if (isset($_POST["noncompleted"]) and ($_POST["noncompleted"] == "on") ) + { + //counter + $i=0; - break; + while (isset($gdata[$i])) + { + if (isset($showaggregated_indice_table[$i]) && $showaggregated_indice_table[$i]=="aggregated") + { // do nothing, we don't rewrite aggregated results + // or at least I don't know how !!! (lemeur) } - echo ''; - - //loop thorugh the array which contains all answer data - foreach ($alist as $al) + else { - //picks out answer list ($alist/$al)) that come from the multiple list above - if (isset($al[2]) && $al[2]) + //we want to have some "real" data here + if ($gdata[$i] != "N/A") { - //handling for "other" option + //calculate percentage + $gdata[$i] = ($grawdata[$i]/$TotalCompleted)*100; + } + } - if ($al[0] == $statlang->gT("Other")) - { - if($qtype=='!' || $qtype=='L') - { - // It is better for single choice question types to filter on the number of '-oth-' entries, than to - // just count the number of 'other' values - that way with failing Javascript the statistics don't get messed up - $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE ".Yii::app()->db->quoteColumnName(substr($al[2],0,strlen($al[2])-5))."='-oth-'"; - } - else - { - //get data - $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE "; - $query .= ($sDatabaseType == "mysql")? Yii::app()->db->quoteColumnName($al[2])." != ''" : "NOT (".Yii::app()->db->quoteColumnName($al[2])." LIKE '')"; - } - } + //increase counter + $i++; - /* - * text questions: - * - * U = huge free text - * T = long free text - * S = short free text - * Q = multiple short text - */ + } //end while (data available) - elseif ($qtype == "U" || $qtype == "T" || $qtype == "S" || $qtype == "Q" || $qtype == ";") - { - $sDatabaseType = Yii::app()->db->getDriverName(); - - //free text answers - if($al[0]=="Answers") - { - $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE "; - $query .= ($sDatabaseType == "mysql")? Yii::app()->db->quoteColumnName($al[2])." != ''" : "NOT (".Yii::app()->db->quoteColumnName($al[2])." LIKE '')"; - } - //"no answer" handling - elseif($al[0]=="NoAnswer") - { - $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE ( "; - $query .= ($sDatabaseType == "mysql")? Yii::app()->db->quoteColumnName($al[2])." = '')" : " (".Yii::app()->db->quoteColumnName($al[2])." LIKE ''))"; - } - } - elseif ($qtype == "O") - { - $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE ( "; - $query .= ($sDatabaseType == "mysql")? Yii::app()->db->quoteColumnName($al[2])." <> '')" : " (".Yii::app()->db->quoteColumnName($al[2])." NOT LIKE ''))"; - // all other question types - } - else - { - $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE " . Yii::app()->db->quoteColumnName($al[2])." ="; - - //ranking question? - if (substr($rt, 0, 1) == "R") - { - $query .= " '$al[0]'"; - } - else - { - $query .= " 'Y'"; - } - } + } //end if -> noncompleted checked - } //end if -> alist set + //noncompleted is NOT checked + else + { + //calculate total number of incompleted records + $TotalIncomplete = $results - $TotalCompleted; - else - { - if ($al[0] != "") - { - //get more data - $sDatabaseType = Yii::app()->db->getDriverName(); - if ($sDatabaseType == 'mssql' || $sDatabaseType == 'sqlsrv') - { - // mssql cannot compare text blobs so we have to cast here - $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE cast(".Yii::app()->db->quoteColumnName($rt)." as varchar)= '$al[0]'"; - } - else - $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE " . Yii::app()->db->quoteColumnName($rt)." = '$al[0]'"; - } - else - { // This is for the 'NoAnswer' case - // We need to take into account several possibilities - // * NoAnswer cause the participant clicked the NoAnswer radio - // ==> in this case value is '' or ' ' - // * NoAnswer in text field - // ==> value is '' - // * NoAnswer due to conditions, or a page not displayed - // ==> value is NULL - if ($sDatabaseType == 'mssql' || $sDatabaseType == 'sqlsrv') - { - // mssql cannot compare text blobs so we have to cast here - //$query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE (".sanitize_int($rt)." IS NULL " - $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE ( " - // . "OR cast(".sanitize_int($rt)." as varchar) = '' " - . "cast(".Yii::app()->db->quoteColumnName($rt)." as varchar) = '' " - . "OR cast(".Yii::app()->db->quoteColumnName($rt)." as varchar) = ' ' )"; - } - else - // $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE (".sanitize_int($rt)." IS NULL " - $query = "SELECT count(*) FROM {{survey_$surveyid}} WHERE ( " - // . "OR ".sanitize_int($rt)." = '' " - . " ".Yii::app()->db->quoteColumnName($rt)." = '' " - . "OR ".Yii::app()->db->quoteColumnName($rt)." = ' ') "; - } + //output + if ((incompleteAnsFilterState() != "filter")) + { + $fname=$statlang->gT("Not completed or Not displayed"); + } + else + { + $fname=$statlang->gT("Not displayed"); + } - } + //we need some data + if ($results > 0) + { + //calculate percentage + $gdata[] = ($TotalIncomplete/$results)*100; + } - //check filter option - if (incompleteAnsFilterState() == "inc") {$query .= " AND submitdate is null";} - elseif (incompleteAnsFilterState() == "filter") {$query .= " AND submitdate is not null";} + //no data :( + else + { + $gdata[] = "N/A"; + } - //check for any "sql" that has been passed from another script - if ($sql != "NULL") {$query .= " AND $sql";} + //put data of incompleted records into array + $grawdata[]=$TotalIncomplete; - //get data - $result=Yii::app()->db->createCommand($query)->query(); + //put question title ("Not completed") into array + $label[]= $fname; - // $statisticsoutput .= "\n\n\n"; + //put the code ("Not completed") into the array + $justcode[]=$fname; - // this just extracts the data, after we present - foreach ($result->readAll() as $row) - { - $row=array_values($row); + //edit labels and put them into antoher array + if ((incompleteAnsFilterState() != "filter")) + { + $lbl[] = wordwrap(flattenText($statlang->gT("Not completed or Not displayed")." ($TotalIncomplete)"), 20, "\n"); // NMO 2009-03-24 + } + else + { + $lbl[] = wordwrap(flattenText($statlang->gT("Not displayed")." ($TotalIncomplete)"), 20, "\n"); // NMO 2009-03-24 + } + } //end else -> noncompleted NOT checked - //store temporarily value of answer count of question type '5' and 'A'. - $tempcount = -1; //count can't be less han zero + } //end if -> no filtering of incomplete answers and no multiple option questions - //increase counter - $TotalCompleted += $row[0]; - //"no answer" handling - if ($al[0] === "") - {$fname=$statlang->gT("No answer");} + //counter + $i=0; - //"other" handling - //"Answers" means that we show an option to list answer to "other" text field - elseif ($al[0] === $statlang->gT("Other") || $al[0] === "Answers" || ($qtype === "O" && $al[0] === $statlang->gT("Comments")) || $qtype === "P") - { - if ($qtype == "P") $ColumnName_RM = $al[2]."comment"; - else $ColumnName_RM = $al[2]; - if ($qtype=='O') { - $TotalCompleted -=$row[0]; - } - $fname="$al[1]"; - if ($browse===true) $fname .= " "; - } + //we need to know which item we are editing + $itemcounter = 1; - /* - * text questions: - * - * U = huge free text - * T = long free text - * S = short free text - * Q = multiple short text - */ - elseif ($qtype == "S" || $qtype == "U" || $qtype == "T" || $qtype == "Q") - { - $headPDF = array(); - $headPDF[] = array($statlang->gT("Answer"),$statlang->gT("Count"),$statlang->gT("Percentage")); + //array to store items 1 - 5 of question types "5" and "A" + $stddevarray = array(); - //show free text answers - if ($al[0] == "Answers") - { - $fname= "$al[1]"; - if ($browse===true) $fname .= " "; - } - elseif ($al[0] == "NoAnswer") - { - $fname= "$al[1]"; - } - - $statisticsoutput .= "" - ."".$statlang->gT("Count")."" - ."".$statlang->gT("Percentage")."
    " - ."".$statlang->gT("Count")."" - ."".$statlang->gT("Percentage")."" - ."".$statlang->gT("Sum")."
    " - ."".$statlang->gT("Count")."" - ."".$statlang->gT("Percentage")."
    " - ."".$statlang->gT("Count")."" - ."".$statlang->gT("Percentage")."
    " . $label[$i] ."\n" + ."\t\t
    " . $grawdata[$i] . "\n"; - } //end foreach -> loop through answer data + //percentage = 0 + $statisticsoutput .= sprintf("%01.2f", $gdata[$i]) . "%"; + $gdata[$i] = 0; - //no filtering of incomplete answers and NO multiple option questions - //if ((incompleteAnsFilterState() != "filter") and ($qtype != "M") and ($qtype != "P")) - //error_log("TIBO ".print_r($showaggregated_indice_table,true)); - if (($qtype != "M") and ($qtype != "P")) - { - //is the checkbox "Don't consider NON completed responses (only works when Filter incomplete answers is Disable)" checked? - //if (isset($_POST["noncompleted"]) and ($_POST["noncompleted"] == "on") && (isset(Yii::app()->getConfig('showaggregateddata')) && Yii::app()->getConfig('showaggregateddata') == 0)) - // TIBO: TODO WE MUST SKIP THE FOLLOWING SECTION FOR TYPE A and 5 when - // showaggreagated data is set and set to 1 - if (isset($_POST["noncompleted"]) and ($_POST["noncompleted"] == "on") ) + //check if we have to adjust ouput due to Yii::app()->getConfig('showaggregateddata') setting + if(Yii::app()->getConfig('showaggregateddata') == 1 && ($outputs['qtype'] == "5" || $outputs['qtype'] == "A")) { - //counter - $i=0; - - while (isset($gdata[$i])) - { - if (isset($showaggregated_indice_table[$i]) && $showaggregated_indice_table[$i]=="aggregated") - { // do nothing, we don't rewrite aggregated results - // or at least I don't know how !!! (lemeur) - } - else - { - //we want to have some "real" data here - if ($gdata[$i] != "N/A") - { - //calculate percentage - $gdata[$i] = ($grawdata[$i]/$TotalCompleted)*100; - } - } - - //increase counter - $i++; - - } //end while (data available) - - } //end if -> noncompleted checked - - //noncompleted is NOT checked - else + $statisticsoutput .= "\t\t
    "; - //array to store items 1 - 5 of question types "5" and "A" - $stddevarray = array(); + //output percentage + $statisticsoutput .= sprintf("%01.2f", $percentage) . "%"; - //loop through all available answers - while (isset($gdata[$i])) - { - //repeat header (answer, count, ...) for each new question - unset($showheadline); + //adjust output + $statisticsoutput .= "\t\t
    " . $label[$i] ."\n" - ."\t\t
    " . $grawdata[$i] . "\n"; + $statisticsoutput .= sprintf("%01.2f", $percentage) . "%"; + $statisticsoutput .= sprintf("%01.2f", $percentage)."%"; + $statisticsoutput .= ""; - - //percentage = 0 - $statisticsoutput .= sprintf("%01.2f", $gdata[$i]) . "%"; - $gdata[$i] = 0; - - //check if we have to adjust ouput due to Yii::app()->getConfig('showaggregateddata') setting - if(Yii::app()->getConfig('showaggregateddata') == 1 && ($qtype == "5" || $qtype == "A")) - { - $statisticsoutput .= "\t\t
    "; - - //output percentage - $statisticsoutput .= sprintf("%01.2f", $percentage) . "%"; - - //adjust output - $statisticsoutput .= "\t\t"; - $statisticsoutput .= sprintf("%01.2f", $percentage) . "%"; - $statisticsoutput .= sprintf("%01.2f", $percentage)."%"; - $statisticsoutput .= ""; - $statisticsoutput .= sprintf("%01.2f", $percentage) . "%"; - $statisticsoutput .= sprintf("%01.2f", $aggregatedgdata)."%"; - $statisticsoutput .= ""; - $statisticsoutput .= sprintf("%01.2f", $percentage) . "%"; - $statisticsoutput .= sprintf("%01.2f", $aggregatedgdata)."%"; - $statisticsoutput .= "
    ".$statlang->gT("Sum")." (".$statlang->gT("Answers").")".$sumitems."$sumpercentage%$sumpercentage%
    ".$statlang->gT("Number of cases")."".$TotalCompleted."$casepercentage% 
    "; - $statisticsoutput .= sprintf("%01.2f", $gdata[$i]) . "%"; - $statisticsoutput .= "\t\t"; - //end output per line. there has to be a whitespace within the table cell to display correctly - $statisticsoutput .= "\t\t 
    "; + $statisticsoutput .= sprintf("%01.2f", $percentage) . "%"; + $statisticsoutput .= sprintf("%01.2f", $aggregatedgdata)."%"; + $statisticsoutput .= ""; + $statisticsoutput .= sprintf("%01.2f", $percentage) . "%"; + $statisticsoutput .= sprintf("%01.2f", $aggregatedgdata)."%"; + $statisticsoutput .= "
    ".$statlang->gT("Arithmetic mean")."  $am 
    ".$statlang->gT("Standard deviation")." $stddev 
    ".$statlang->gT("Sum")." (".$statlang->gT("Answers").")".$sumitems."$sumpercentage%$sumpercentage%
    ".$statlang->gT("Number of cases")."".$TotalCompleted."$casepercentage% 
    "; - } - - - - //-------------------------- PCHART OUTPUT ---------------------------- - list($qsid, $qgid, $qqid) = explode("X", $rt, 3); - $qsid = $surveyid; - $aattr = getQuestionAttributeValues($qqid, substr($rt, 0, 1)); - - //PCHART has to be enabled and we need some data - if ($usegraph == 1) { - $bShowGraph = $aattr["statistics_showgraph"] == "1"; - $bAllowPieChart = ($qtype != "M" && $qtype != "P"); - $bAllowMap = (isset($aattr["location_mapservice"]) && $aattr["location_mapservice"] == "1"); - $bShowMap = ($bAllowMap && $aattr["statistics_showmap"] == "1"); - $bShowPieChart = ($bAllowPieChart && $aattr["statistics_graphtype"] == "1"); - - $astatdata[$rt] = array( - 'id' => $rt, - 'sg' => $bShowGraph, - 'ap' => $bAllowPieChart, - 'am' => $bAllowMap, - 'sm' => $bShowMap, - 'sp' => $bShowPieChart - ); - - $stats=Yii::app()->session['stats']; - $stats[$rt]=array( - 'lbl' => $lbl, - 'gdata' => $gdata, - 'grawdata' => $grawdata - ); - Yii::app()->session['stats'] = $stats; - - if (array_sum($gdata)>0 && $bShowGraph == true) - { - $cachefilename = createChart($qqid, $qsid, $bShowPieChart, $lbl, $gdata, $grawdata, $MyCache); - //introduce new counter - if (!isset($ci)) {$ci=0;} + case 'xls': + $label[$i]=flattenText($label[$i]); + $tableXLS[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $gdata[$i])."%", ""); - //increase counter, start value -> 1 - $ci++; - switch($outputType) - { - case 'xls': + ++$xlsRow; + $sheet->write($xlsRow,0,$label[$i]); + $sheet->write($xlsRow,1,$grawdata[$i]); + $sheet->write($xlsRow,2,sprintf("%01.2f", $gdata[$i])."%"); - /** - * No Image for Excel... - */ + break; + case 'pdf': + $label[$i]=flattenText($label[$i]); + $tablePDF[] = array($label[$i],$grawdata[$i],sprintf("%01.2f", $gdata[$i])."%", ""); - break; - case 'pdf': + break; + case 'html': + //output percentage + $statisticsoutput .= "\t\t"; + $statisticsoutput .= sprintf("%01.2f", $gdata[$i]) . "%"; + $statisticsoutput .= "\t\t"; + //end output per line. there has to be a whitespace within the table cell to display correctly + $statisticsoutput .= "\t\t 
    " - ."" - ."" - ."" - ."" - ."" - ."" - ."

    \n"; + } - } //end if -> collect and display results + //4 = multiply result with 1 / (number of items (=5)) + //There are two different formulas to calculate standard derivation + //$stddev = $stddev / array_sum($stddevarray); //formula source: http://de.wikipedia.org/wiki/Standardabweichung + + //prevent division by zero + if((array_sum($stddevarray)-1) != 0 && $stddev != 0) + { + $stddev = $stddev / (array_sum($stddevarray)-1); //formula source: http://de.wikipedia.org/wiki/Empirische_Varianz + } + else + { + $stddev = 0; + } + + //5 = get root + $stddev = sqrt($stddev); + $stddev = round($stddev,2); + } + switch($outputType) + { + case 'xls': + + $tableXLS[] = array($statlang->gT("Arithmetic mean"),$am,'',''); + $tableXLS[] = array($statlang->gT("Standard deviation"),$stddev,'',''); + + ++$xlsRow; + $sheet->write($xlsRow,0,$statlang->gT("Arithmetic mean")); + $sheet->write($xlsRow,1,$am); + + ++$xlsRow; + $sheet->write($xlsRow,0,$statlang->gT("Standard deviation")); + $sheet->write($xlsRow,1,$stddev); + + break; + case 'pdf': + + $tablePDF[] = array($statlang->gT("Arithmetic mean"),$am,'',''); + $tablePDF[] = array($statlang->gT("Standard deviation"),$stddev,'',''); + + break; + case 'html': + //calculate standard deviation + $statisticsoutput .= "".$statlang->gT("Arithmetic mean").""; //German: "Fallzahl" + $statisticsoutput .= "  $am "; + $statisticsoutput .= "".$statlang->gT("Standard deviation").""; //German: "Fallzahl" + $statisticsoutput .= " $stddev "; + + break; + default: + + + break; + } + } + } + + if($outputType=='pdf') //XXX TODO PDF + { + //$tablePDF = array(); + $tablePDF = array_merge_recursive($tablePDF, $footPDF); + $pdf->headTable($headPDF,$tablePDF); + //$pdf->tableintopdf($tablePDF); + + // if(isset($footPDF)) + // foreach($footPDF as $foot) + // { + // $footA = array($foot); + // $pdf->tablehead($footA); + // } + } + + if ($outputType=='html') { + $statisticsoutput .= ""; + } + + + + //-------------------------- PCHART OUTPUT ---------------------------- + list($qsid, $qgid, $qqid) = explode("X", $rt, 3); + $qsid = $surveyid; + $aattr = getQuestionAttributeValues($qqid, substr($rt, 0, 1)); + + //PCHART has to be enabled and we need some data + if ($usegraph == 1) { + $bShowGraph = $aattr["statistics_showgraph"] == "1"; + $bAllowPieChart = ($outputs['qtype'] != "M" && $outputs['qtype'] != "P"); + $bAllowMap = (isset($aattr["location_mapservice"]) && $aattr["location_mapservice"] == "1"); + $bShowMap = ($bAllowMap && $aattr["statistics_showmap"] == "1"); + $bShowPieChart = ($bAllowPieChart && $aattr["statistics_graphtype"] == "1"); + + $astatdata[$rt] = array( + 'id' => $rt, + 'sg' => $bShowGraph, + 'ap' => $bAllowPieChart, + 'am' => $bAllowMap, + 'sm' => $bShowMap, + 'sp' => $bShowPieChart + ); + + $stats=Yii::app()->session['stats']; + $stats[$rt]=array( + 'lbl' => $lbl, + 'gdata' => $gdata, + 'grawdata' => $grawdata + ); + Yii::app()->session['stats'] = $stats; + + if (array_sum($gdata)>0 && $bShowGraph == true) + { + $cachefilename = createChart($qqid, $qsid, $bShowPieChart, $lbl, $gdata, $grawdata, $MyCache); + //introduce new counter + if (!isset($ci)) {$ci=0;} + + //increase counter, start value -> 1 + $ci++; + switch($outputType) + { + case 'xls': + + /** + * No Image for Excel... + */ + + break; + case 'pdf': + + $pdf->AddPage('P','A4'); + + $pdf->titleintopdf($pdfTitle,$titleDesc); + $pdf->Image($tempdir."/".$cachefilename, 0, 70, 180, 0, '', Yii::app()->getController()->createUrl("admin/survey/view/surveyid/".$surveyid), 'B', true, 150,'C',false,false,0,true); + + break; + case 'html': + $statisticsoutput .= ""; + + $aattr = getQuestionAttributeValues($qqid, $firstletter); + if ($bShowMap) { + $statisticsoutput .= "
    "; + + $agmapdata[$rt] = array ( + "coord" => getQuestionMapData(substr($rt, 1), $qsid), + "zoom" => $aattr['location_mapzoom'], + "width" => $aattr['location_mapwidth'], + "height" => $aattr['location_mapheight'] + ); + } + break; + default: + break; + } + + } + } + + //close table/output + if($outputType=='html') { + if ($usegraph==1) { + $sImgUrl = Yii::app()->getConfig('adminimageurl'); + + $statisticsoutput .= "
    " + ."" + ."" + ."" + ."" + ."" + ."" + ."
    "; + + } + $statisticsoutput .= "
    \n"; + } + + return array("statisticsoutput"=>$statisticsoutput, "pdf"=>$pdf); + +} + + +/** +* Generates statistics +* +* @param int $surveyid The survey id +* @param mixed $allfields +* @param mixed $q2show +* @param mixed $usegraph +* @param string $outputType Optional - Can be xls, html or pdf - Defaults to pdf +* @param string $pdfOutput Sets the target for the PDF output: DD=File download , F=Save file to local disk +* @param string $statlangcode Lamguage for statistics +* @param mixed $browse Show browse buttons +* @return buffer +*/ +function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, $outputType='pdf', $pdfOutput='I',$statlangcode=null, $browse = true) +{ + //$allfields =""; + + global $pdfdefaultfont, $pdffontsize; + + //load surveytranslator helper + Yii::import('application.helpers.surveytranslator_helper', true); + + $statisticsoutput = ""; //This string carries all the actual HTML code to print. + $imagedir = Yii::app()->getConfig("imagedir"); + $tempdir = Yii::app()->getConfig("tempdir"); + $tempurl = Yii::app()->getConfig("tempurl"); + $clang = Yii::app()->lang; + $pdf=array(); //Make sure $pdf exists - it will be replaced with an object if a $pdf is actually being created + + + $astatdata = array(); + + // Used for getting coordinates for google maps + $agmapdata = array(); + + //pick the best font file if font setting is 'auto' + if (is_null($statlangcode)) + { + $statlangcode = getBaseLanguageFromSurveyID($surveyid); + } + else + { + $statlang = new Limesurvey_lang($statlangcode); + } + + /* + * this variable is used in the function shortencode() which cuts off a question/answer title + * after $maxchars and shows the rest as tooltip (in html mode) + */ + $maxchars = 13; + //we collect all the html-output within this variable + $statisticsoutput =''; + /** + * $outputType: html || pdf || + */ + /** + * get/set Survey Details + */ + + //no survey ID? -> come and get one + if (!isset($surveyid)) {$surveyid=returnGlobal('sid');} + + //Get an array of codes of all available languages in this survey + $surveylanguagecodes = Survey::model()->findByPk($surveyid)->additionalLanguages; + $surveylanguagecodes[] = Survey::model()->findByPk($surveyid)->language; + + $fieldmap=createFieldMap($surveyid, "full", false, false, $statlang->getlangcode()); + + // Set language for questions and answers to base language of this survey + $language=$statlangcode; + + if ($usegraph==1) + { + //for creating graphs we need some more scripts which are included here + require_once(APPPATH.'/third_party/pchart/pchart/pChart.class'); + require_once(APPPATH.'/third_party/pchart/pchart/pData.class'); + require_once(APPPATH.'/third_party/pchart/pchart/pCache.class'); + $MyCache = new pCache($tempdir.'/'); + } + + if($q2show=='all' ) + { + $summarySql=" SELECT gid, parent_qid, qid, type " + ." FROM {{questions}} WHERE parent_qid=0" + ." AND sid=$surveyid "; + + $summaryRs = Yii::app()->db->createCommand($summarySql)->query()->readAll(); + + foreach($summaryRs as $field) + { + $myField = $surveyid."X".$field['gid']."X".$field['qid']; + + // Multiple choice get special treatment + if ($field['type'] == "M") {$myField = "M$myField";} + if ($field['type'] == "P") {$myField = "P$myField";} + //numerical input will get special treatment (arihtmetic mean, standard derivation, ...) + if ($field['type'] == "N") {$myField = "N$myField";} + + if ($field['type'] == "|") {$myField = "|$myField";} + + if ($field['type'] == "Q") {$myField = "Q$myField";} + // textfields get special treatment + if ($field['type'] == "S" || $field['type'] == "T" || $field['type'] == "U"){$myField = "T$myField";} + //statistics for Date questions are not implemented yet. + if ($field['type'] == "D") {$myField = "D$myField";} + if ($field['type'] == "F" || $field['type'] == "H") + { + //Get answers. We always use the answer code because the label might be too long elsewise + $query = "SELECT code, answer FROM {{answers}} WHERE qid='".$field['qid']."' AND scale_id=0 AND language='{$language}' ORDER BY sortorder, answer"; + $result = Yii::app()->db->createCommand($query)->query(); + $counter2=0; + + //check all the answers + foreach ($result->readAll() as $row) + { + $row=array_values($row); + $myField = "$myField{$row[0]}"; + } + //$myField = "{$surveyid}X{$flt[1]}X{$flt[0]}{$row[0]}[]"; + + + } + if($q2show=='all') + $summary[]=$myField; + + //$allfields[]=$myField; + } + } + else + { + // This gets all the 'to be shown questions' from the POST and puts these into an array + if (!is_array($q2show)) + $summary=returnGlobal('summary'); + else + $summary = $q2show; + + //print_r($_POST); + //if $summary isn't an array we create one + if (isset($summary) && !is_array($summary)) + { + $summary = explode("+", $summary); + } + } + + /** + * pdf Config + */ + if($outputType=='pdf') + { + //require_once('classes/tcpdf/config/lang/eng.php'); + global $l; + $l['w_page'] = $statlang->gT("Page",'unescaped'); + //require_once('classes/tcpdf/mypdf.php'); + Yii::import('application.libraries.admin.pdf', true); + // create new PDF document + $pdf = new Pdf(); + $pdf->SetFont($pdfdefaultfont,'',$pdffontsize); + + $surveyInfo = getSurveyInfo($surveyid,$language); + + // set document information + $pdf->SetCreator(PDF_CREATOR); + $pdf->SetAuthor('LimeSurvey'); + $pdf->SetTitle('Statistic survey '.$surveyid); + $pdf->SetSubject($surveyInfo['surveyls_title']); + $pdf->SetKeywords('LimeSurvey, Statistics, Survey '.$surveyid.''); + $pdf->SetDisplayMode('fullpage', 'two'); + + // set header and footer fonts + $pdf->setHeaderFont(Array($pdfdefaultfont, '', PDF_FONT_SIZE_MAIN)); + $pdf->setFooterFont(Array($pdfdefaultfont, '', PDF_FONT_SIZE_DATA)); + + // set default header data + $pdf->SetHeaderData("statistics.png", 10, $statlang->gT("Quick statistics",'unescaped') , $statlang->gT("Survey")." ".$surveyid." '".flattenText($surveyInfo['surveyls_title'],false,true,'UTF-8')."'"); + + + // set default monospaced font + $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED); + + //set margins + $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); + $pdf->SetHeaderMargin(PDF_MARGIN_HEADER); + $pdf->SetFooterMargin(PDF_MARGIN_FOOTER); + + //set auto page breaks + $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); + + //set image scale factor + $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); + + //set some language-dependent strings + $pdf->setLanguageArray($l); + } + if($outputType=='xls') + { + /** + * Initiate the Spreadsheet_Excel_Writer + */ + Yii::import('application.libraries.admin.pear.Spreadsheet.Excel.Xlswriter', true); + if($pdfOutput=='F') + $workbook = new Xlswriter($tempdir.'/statistic-survey'.$surveyid.'.xls'); + else + $workbook = new Xlswriter(); + + $workbook->setVersion(8); + // Inform the module that our data will arrive as UTF-8. + // Set the temporary directory to avoid PHP error messages due to open_basedir restrictions and calls to tempnam("", ...) + if (!empty($tempdir)) { + $workbook->setTempDir($tempdir); + } + if ($pdfOutput!='F') + $workbook->send('statistic-survey'.$surveyid.'.xls'); + + // Creating the first worksheet + $sheet =& $workbook->addWorksheet(utf8_decode('results-survey'.$surveyid)); + $sheet->setInputEncoding('utf-8'); + $sheet->setColumn(0,20,20); + $separator="~|"; + /**XXX*/ + } + /** + * Start generating + */ + + + + $selects=buildSelects($allfields, $surveyid, $language); + + //count number of answers + $query = "SELECT count(*) FROM {{survey_$surveyid}}"; + + //if incompleted answers should be filtert submitdate has to be not null + if (incompleteAnsFilterState() == "inc") {$query .= " WHERE submitdate is null";} + elseif (incompleteAnsFilterState() == "filter") {$query .= " WHERE submitdate is not null";} + $result = Yii::app()->db->createCommand($query)->query(); + + //$total = total number of answers + $row=$result->read(); $total=reset($row); + + //are there any filters that have to be taken care of? + if (isset($selects) && $selects) + { + //filter incomplete answers? + if (incompleteAnsFilterState() == "filter" || incompleteAnsFilterState() == "inc") {$query .= " AND ";} + + else {$query .= " WHERE ";} + + //add filter criteria to SQL + $query .= implode(" AND ", $selects); + } + + + //get me some data Scotty + $result=Yii::app()->db->createCommand($query)->query(); + + //put all results into $results + $row=$result->read(); $results=reset($row); + + if ($total) + { + $percent=sprintf("%01.2f", ($results/$total)*100); + + } + switch($outputType) + { + case "xls": + $xlsRow = 0; + $sheet->write($xlsRow,0,$statlang->gT("Number of records in this query:",'unescaped')); + $sheet->write($xlsRow,1,$results); + ++$xlsRow; + $sheet->write($xlsRow,0,$statlang->gT("Total records in survey:",'unescaped')); + $sheet->write($xlsRow,1,$total); + + if($total) + { + ++$xlsRow; + $sheet->write($xlsRow,0,$statlang->gT("Percentage of total:",'unescaped')); + $sheet->write($xlsRow,1,$percent."%"); + } + + break; + case 'pdf': + + // add summary to pdf + $array = array(); + //$array[] = array($statlang->gT("Results"),""); + $array[] = array($statlang->gT("Number of records in this query:",'unescaped'), $results); + $array[] = array($statlang->gT("Total records in survey:",'unescaped'), $total); + + if($total) + $array[] = array($statlang->gT("Percentage of total:",'unescaped'), $percent."%"); + + $pdf->addPage('P','A4'); + + $pdf->Bookmark($pdf->delete_html($statlang->gT("Results",'unescaped')), 0, 0); + $pdf->titleintopdf($statlang->gT("Results",'unescaped'),$statlang->gT("Survey",'unescaped')." ".$surveyid); + $pdf->tableintopdf($array); + + $pdf->addPage('P','A4'); + + break; + case 'html': + + $statisticsoutput .= "
    \n\n" + ."\t\n" + ."\t' + ."\n" + ."\t' + ."\n"; + + //only calculate percentage if $total is set + if ($total) + { + $percent=sprintf("%01.2f", ($results/$total)*100); + $statisticsoutput .= "\t' + ."\n"; + } + $statisticsoutput .="
    ".$statlang->gT("Results")."
    ".$statlang->gT("Number of records in this query:").'$results
    ".$statlang->gT("Total records in survey:").'$total
    ".$statlang->gT("Percentage of total:").'$percent%
    \n"; + + break; + default: + + + break; + } + + //put everything from $selects array into a string connected by AND + //This string ($sql) can then be passed on to other functions so you can + //browse these results + if (isset ($selects) && $selects) {$sql=implode(" AND ", $selects);} + + elseif (!empty($newsql)) {$sql = $newsql;} + + if (!isset($sql) || !$sql) {$sql="NULL";} + + //only continue if we have something to output + if ($results > 0) + { + if($outputType=='html' && $browse === true) + { + //add a buttons to browse results + $statisticsoutput .= "
    \n" + ."\t\t

    " + ."\t\t\t\n" + ."\t\t\t\n" + ."\t\t\t\n" + ."\t\t\t\n" + ."\t\t

    " + ."\t\t
    \n"; + } + } //end if (results > 0) + + /* Show Summary results + * The $summary array contains each fieldname that we want to display statistics for + * + * */ + + if (isset($summary) && $summary) + { + //let's run through the survey + $runthrough=$summary; + + //START Chop up fieldname and find matching questions + + //Build an array of legitimate qid's for testing later + $qidquery = Questions::model()->findAll("sid=:surveyid AND parent_qid=0", array(":surveyid"=>$surveyid)); + foreach ($qidquery as $row) { $legitqids[] = $row['qid']; } + + //loop through all selected questions + foreach ($runthrough as $rt) + { + + //Step 1: Get information about this response field (SGQA) for the summary + $outputs=buildOutputList($rt, $language, $surveyid, $outputType); + + //2. Collect and Display results ####################################################################### + if (isset($outputs['alist']) && $outputs['alist']) //Make sure there really is an answerlist, and if so: + { + $display=displayResults($outputs, $results, $rt, $outputType, $surveyid, $sql, $usegraph, $browse, $pdf); + $statisticsoutput .= $display['statisticsoutput']; + } //end if -> collect and display results - //delete data - unset($gdata); - unset($grawdata); - unset($label); - unset($lbl); - unset($lblrtl); - unset($lblout); - unset($justcode); - unset ($alist); + //Delete Build Outputs data + unset($outputs); + unset($display); } // end foreach -> loop through all questions //output From b1947782aa59a1dcfdff865329c45f7fae031753 Mon Sep 17 00:00:00 2001 From: Carsten Schmitz Date: Tue, 24 Jul 2012 13:07:08 +0200 Subject: [PATCH 28/71] Fixed issue #6377: Large integer values corrupted in survey responses --- application/helpers/admin/activate_helper.php | 2 +- application/views/admin/survey/Question/questionbar_view.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/helpers/admin/activate_helper.php b/application/helpers/admin/activate_helper.php index 8386c09bb7f..3d1e3b582de 100644 --- a/application/helpers/admin/activate_helper.php +++ b/application/helpers/admin/activate_helper.php @@ -301,7 +301,7 @@ function activateSurvey($iSurveyID, $simulate = false) $createsurvey[$arow['fieldname']] = "integer"; break; case "N": //NUMERICAL - $createsurvey[$arow['fieldname']] = "float"; + $createsurvey[$arow['fieldname']] = "decimal (30,10)"; break; case "S": //SHORT TEXT if (Yii::app()->db->driverName == 'mysql' || Yii::app()->db->driverName == 'mysqli') {$createsurvey[$arow['fieldname']] = "text";} diff --git a/application/views/admin/survey/Question/questionbar_view.php b/application/views/admin/survey/Question/questionbar_view.php index 571f563af81..5fcef8d6f3f 100644 --- a/application/views/admin/survey/Question/questionbar_view.php +++ b/application/views/admin/survey/Question/questionbar_view.php @@ -7,7 +7,7 @@ \ No newline at end of file From 4d98e921136d73a7e52e275d5e9fe65286ffe86a Mon Sep 17 00:00:00 2001 From: jcleeland Date: Fri, 27 Jul 2012 14:41:57 +1000 Subject: [PATCH 57/71] Fixed issue: multiple short text and multiple numerical results in statistics were endlessly looping, continued cleaning up code --- application/controllers/admin/statistics.php | 72 +------- .../helpers/admin/statistics_helper.php | 154 +++++++----------- .../views/admin/export/statistics_view.php | 3 + 3 files changed, 63 insertions(+), 166 deletions(-) diff --git a/application/controllers/admin/statistics.php b/application/controllers/admin/statistics.php index 00775624ced..7a25c4b2189 100644 --- a/application/controllers/admin/statistics.php +++ b/application/controllers/admin/statistics.php @@ -37,8 +37,7 @@ public function run($surveyid, $subaction = null) { $surveyid = sanitize_int($surveyid); //TODO: Convert question types to views - - $clang = $this->getController()->lang; + $clang = $this->getController()->lang; $imageurl = Yii::app()->getConfig("imageurl"); $aData = array('clang' => $clang, 'imageurl' => $imageurl); @@ -89,15 +88,6 @@ public function run($surveyid, $subaction = null) */ $maxchars = 50; - - - //don't call this script directly! - //if (isset($_REQUEST['homedir'])) {die('You cannot start this script directly');} - - //some includes, the progressbar is used to show a progressbar while generating the graphs - //include_once("login_check.php"); - //require_once('classes/core/class.progressbar.php'); - //we collect all the output within this variable $statisticsoutput =''; @@ -124,54 +114,8 @@ public function run($surveyid, $subaction = null) $language = Survey::model()->findByPk($surveyid)->language; $aData['language'] = $language; -// $chartfontfile = Yii::app()->getConfig("chartfontfile"); -// //pick the best font file if font setting is 'auto' -// if ($chartfontfile=='auto') -// { -// $chartfontfile='vera.ttf'; -// if ( $language=='ar') -// { -// $chartfontfile='KacstOffice.ttf'; -// } -// elseif ($language=='fa' ) -// { -// $chartfontfile='KacstFarsi.ttf'; -// } -// elseif ($language=='el' ) -// { -// $chartfontfile='DejaVuLGCSans.ttf'; -// } -// elseif ($language=='zh-Hant-HK' || $language=='zh-Hant-TW' || $language=='zh-Hans') -// { -// $chartfontfile='fireflysung.ttf'; -// } -// -// } - - //$statisticsoutput .= " - //"; - - //hide/show the filter - //filtersettings by default aren't shown when showing the results - //$statisticsoutput .= ''; + + //Call the javascript file $this->getController()->_js_admin_includes(Yii::app()->getConfig('adminscripts') . 'statistics.js'); $aData['display']['menu_bars']['browse'] = $clang->gT("Quick statistics"); @@ -275,11 +219,6 @@ public function run($surveyid, $subaction = null) $aData['selectinc'] = $selectinc; $aData['error'] = $error; - //if ($selecthide!='') - //{ - // $statisticsoutput .= " style='display:none' "; - //} - $survlangs = Survey::model()->findByPk($surveyid)->additionalLanguages; $survlangs[] = Survey::model()->findByPk($surveyid)->language; $aData['survlangs'] = $survlangs; @@ -287,13 +226,10 @@ public function run($surveyid, $subaction = null) //if the survey contains timestamps you can filter by timestamp, too - //Output selector - //second row below options -> filter settings headline - $filterchoice_state=returnGlobal('filterchoice_state'); $aData['filterchoice_state'] = $filterchoice_state; @@ -510,8 +446,6 @@ public function run($surveyid, $subaction = null) //used to adjust linebreaks $previousquestiontype = $flt[2]; - //Group close - //$statisticsoutput .= "\n\t\t\t\t\n\t\t\t\n"; } // ----------------------------------- END FILTER FORM --------------------------------------- diff --git a/application/helpers/admin/statistics_helper.php b/application/helpers/admin/statistics_helper.php index cfacea6f606..2dd41e172f6 100644 --- a/application/helpers/admin/statistics_helper.php +++ b/application/helpers/admin/statistics_helper.php @@ -497,8 +497,12 @@ function buildSelects($allfields, $surveyid, $language) { * @param mixed $surveyid The survey id * @param string $outputType * -* @output array $output An array containing "alist"=>A list of answers to the question, "qtitle"=>The title of the question, -* "qquestion"=>The description of the question, "qtype"=>The question type code +* @output array $output An array containing "alist"=>A list of answers to the question in the form of an array ($alist array +* contains an array for every field to be displayed - with the Actual Question Code/Title, The text (flattened) +* of the question, and the fieldname where the data is stored. +* "qtitle"=>The title of the question, +* "qquestion"=>The description of the question, +* "qtype"=>The question type code */ function buildOutputList($rt, $language, $surveyid, $outputType, $sql) { @@ -528,71 +532,54 @@ function buildOutputList($rt, $language, $surveyid, $outputType, $sql) { break; } - //M - Multiple choice, therefore multiple fields + //M - Multiple choice, therefore multiple fields - one for each answer if ($firstletter == "M" || $firstletter == "P") { //get SGQ data list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); //select details for this question - $nresult = Questions::model()->findAll('language=:language AND parent_qid=0 AND qid=:qid', array(':language'=>$language, ':qid'=>$qqid)); - //$nquery = "SELECT title, type, question, parent_qid, other FROM {{questions}} WHERE language='{$language}' AND parent_qid=0 AND qid='$qqid'"; - //$nresult = Yii::app()->db->createCommand($nquery)->query(); - - //loop through question data - foreach ($nresult as $nrow) - { - $qtitle=$nrow['title']; - $qtype=$nrow['type']; - $qquestion=flattenText($nrow['question']); - $qlid=$nrow['parent_qid']; - $qother=$nrow['other']; - } + $nresult = Questions::model()->find('language=:language AND parent_qid=0 AND qid=:qid', array(':language'=>$language, ':qid'=>$qqid)); + $qtitle=$nresult->title; + $qtype=$nresult->type; + $qquestion=flattenText($nresult->question); + $qlid=$nresult->parent_qid; + $qother=$nresult->other; //1. Get list of answers - $result=Questions::model()->findAll(array('order'=>'question_order', 'condition'=>'language=:language AND parent_qid=:qid AND scale_id=0', 'params'=>array(':language'=>$language, ':qid'=>$qqid))); + $result=Questions::model()->findAll(array('order'=>'question_order', + 'condition'=>'language=:language AND parent_qid=:qid AND scale_id=0', + 'params'=>array(':language'=>$language, ':qid'=>$qqid) + )); foreach ($result as $row) { $mfield=substr($rt, 1, strlen($rt)).$row['title']; - - //create an array containing answer code, answer and fieldname(??) $alist[]=array($row['title'], flattenText($row['question']), $mfield); } - //check "other" field. is it set? + //Add the "other" answer if it exists if ($qother == "Y") { $mfield=substr($rt, 1, strlen($rt))."other"; - - //create an array containing answer code, answer and fieldname(??) $alist[]=array($statlang->gT("Other"), $statlang->gT("Other"), $mfield); } } - - //S - Short Free Text - //T - Long Free Text + //S - Short Free Text and T - Long Free Text elseif ($firstletter == "T" || $firstletter == "S") //Short and long text { - //search for key $fld = substr($rt, 1, strlen($rt)); $fielddata=$fieldmap[$fld]; list($qanswer, $qlid)=!empty($fielddata['aid']) ? explode("_", $fielddata['aid']) : array("", ""); - //get SGQ data - //list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); - //get question data - $nresult = Questions::model()->findAll('language=:language AND parent_qid=0 AND qid=:qid', array(':language'=>$language, ':qid'=>$fielddata['qid'])); - foreach ($nresult as $nrow) - { - $qtitle=$nrow['title']; - $qtype=$nrow['type']; - $qquestion=flattenText($nrow['question']); - $nlid=$nrow['parent_qid']; - } + $nresult = Questions::model()->find('language=:language AND parent_qid=0 AND qid=:qid', array(':language'=>$language, ':qid'=>$fielddata['qid'])); + $qtitle=$nresult->title; + $qtype=$nresult->type; + $qquestion=flattenText($nresult->question); + $qlid=$nresult->parent_qid; $mfield=substr($rt, 1, strlen($rt)); @@ -604,53 +591,41 @@ function buildOutputList($rt, $language, $surveyid, $outputType, $sql) { $alist[]=array("NoAnswer", $statlang->gT("No answer"), $mfield); } - - //Multiple short text + //Q - Multiple short text elseif ($firstletter == "Q") { + //Build an array of legitimate qid's for testing later + $qidquery = Questions::model()->findAll("sid=:surveyid AND parent_qid=0", array(":surveyid"=>$surveyid)); + foreach ($qidquery as $row) { $legitqids[] = $row['qid']; } //get SGQ data list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); - //separating another ID $tmpqid=substr($qqid, 0, strlen($qqid)-1); - //check if we have legid QIDs. if not create them by substringing + //check if we have a QID that actually exists. if not create them by substringing. Note that + //all of this is due to the fact that when we create a field for an subquestion, we don't seperate + //the question id from the subquestion id - and this is a weird, backwards way of doing that. while (!in_array ($tmpqid,$legitqids)) $tmpqid=substr($tmpqid, 0, strlen($tmpqid)-1); - //length of QID $iQuestionIDlength=strlen($tmpqid); - //we somehow get the answer code (see SQL later) from the $qqid $qaid=substr($qqid, $iQuestionIDlength, strlen($qqid)-$iQuestionIDlength); - //get some question data - $nquery = "SELECT title, type, question, other FROM {{questions}} WHERE qid='".substr($qqid, 0, $iQuestionIDlength)."' AND parent_qid=0 AND language='{$language}'"; - $nresult = Yii::app()->db->createCommand($nquery)->query(); + //get question data + $nresult = Questions::model()->find('language=:language AND parent_qid=0 AND qid=:qid', array(':language'=>$language, ':qid'=>substr($qqid, 0, $iQuestionIDlength))); + $qtitle=$nresult->title; + $qtype=$nresult->type; + $qquestion=flattenText($nresult->question); //more substrings $count = substr($qqid, strlen($qqid)-1); - //loop through question data - foreach ($nresult->readAll() as $nrow) - { - $nrow=array_values($nrow); - $qtitle=flattenText($nrow[0]).'-'.$count; - $qtype=$nrow[1]; - $qquestion=flattenText($nrow[2]); - } - //get answers - $qquery = "SELECT title as code, question as answer FROM {{questions}} WHERE parent_qid='".substr($qqid, 0, $iQuestionIDlength)."' AND title='$qaid' AND language='{$language}' ORDER BY question_order"; - $qresult=Yii::app()->db->createCommand($qquery)->query(); - - //loop through answer data - foreach ($qresult->readAll() as $qrow) - { - $qrow=array_values($qrow); - //store each answer here - $atext=flattenText($qrow[1]); - } - + $nresult = Questions::model()->find(array('order'=>'question_order', + 'condition'=>'language=:language AND parent_qid=:parent_qid AND title=:title', + 'params'=>array(':language'=>$language, ':parent_qid'=>substr($qqid, 0, $iQuestionIDlength), ':title'=>$qaid) + )); + $atext=flattenText($nresult->question); //add this to the question title $qtitle .= " [$atext]"; @@ -665,7 +640,6 @@ function buildOutputList($rt, $language, $surveyid, $outputType, $sql) { $alist[]=array("NoAnswer", $statlang->gT("No answer"), $mfield); } - //RANKING OPTION elseif ($firstletter == "R") { @@ -707,20 +681,12 @@ function buildOutputList($rt, $language, $surveyid, $outputType, $sql) { list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); //select details for this question - $nquery = "SELECT title, type, question, parent_qid, other FROM {{questions}} WHERE language='{$language}' AND parent_qid=0 AND qid='$qqid'"; - $nresult = Yii::app()->db->createCommand($nquery)->query(); - - //loop through question data - foreach ($nresult->readAll() as $nrow) - { - $nrow=array_values($nrow); - $qtitle=$nrow[0]; - $qtype=$nrow[1]; - $qquestion=flattenText($nrow[2]); - $qlid=$nrow[3]; - $qother=$nrow[4]; - } - + $nresult = Questions::model()->find('language=:language AND parent_qid=0 AND qid=:qid', array(':language'=>$language, ':qid'=>substr($qqid, 0, $iQuestionIDlength))); + $qtitle=$nresult->title; + $qtype=$nresult->type; + $qquestion=flattenText($nresult->question); + $qlid=$nresult->parent_qid; + $qother=$nresult->other; /* 4) Average size of file per respondent 5) Average no. of files @@ -756,7 +722,6 @@ function buildOutputList($rt, $language, $surveyid, $outputType, $sql) { foreach ($result->readAll() as $row) { - $json = $row['json']; $phparray = json_decode($json); @@ -865,6 +830,9 @@ function buildOutputList($rt, $language, $surveyid, $outputType, $sql) { //multiple numerical input if($firstletter == "K") { + //Build an array of legitimate qid's for testing later + $qidquery = Questions::model()->findAll("sid=:surveyid AND parent_qid=0", array(":surveyid"=>$surveyid)); + foreach ($qidquery as $row) { $legitqids[] = $row['qid']; } // This is a multiple numerical question so we need to strip of the answer id to find the question title $tmpqid=substr($qqid, 0, strlen($qqid)-1); @@ -879,19 +847,21 @@ function buildOutputList($rt, $language, $surveyid, $outputType, $sql) { $qaid=substr($qqid, $iQuestionIDlength, strlen($qqid)-$iQuestionIDlength); //get question details from DB - $nquery = "SELECT title, type, question, qid, parent_qid + $nresult=Questions::model()->findAll('parent_qid=0 AND qid=:qid AND language=:language', array(':qid'=>substr($qqid, 0, $iQuestionIDlength), ':language'=>$language)); + /* $nquery = "SELECT title, type, question, qid, parent_qid FROM {{questions}} WHERE parent_qid=0 AND qid='".substr($qqid, 0, $iQuestionIDlength)."' AND language='{$language}'"; - $nresult = Yii::app()->db->createCommand($nquery)->query(); + $nresult = Yii::app()->db->createCommand($nquery)->query(); */ } //probably question type "N" = numerical input else { + $nresult=Questions::model()->findAll('parent_qid=0 AND qid=:qid AND language=:language', array(':qid'=>$qqid, ':language'=>$language)); //we can use the qqid without any editing - $nquery = "SELECT title, type, question, qid, parent_qid FROM {{questions}} WHERE parent_qid=0 AND qid='$qqid' AND language='{$language}'"; - $nresult = Yii::app()->db->createCommand($nquery)->query(); + /* $nquery = "SELECT title, type, question, qid, parent_qid FROM {{questions}} WHERE parent_qid=0 AND qid='$qqid' AND language='{$language}'"; + $nresult = Yii::app()->db->createCommand($nquery)->query(); */ } //loop through results @@ -1394,19 +1364,14 @@ function buildOutputList($rt, $language, $surveyid, $outputType, $sql) { { //search for key $fielddata=$fieldmap[$rt]; - //print_r($fielddata); //get SGQA IDs $qsid=$fielddata['sid']; $qgid=$fielddata['gid']; $qqid=$fielddata['qid']; $qanswer=$fielddata['aid']; - - //question type $qtype=$fielddata['type']; - //question string $qastring=$fielddata['question']; - //question ID $rqid=$qqid; @@ -1843,8 +1808,8 @@ function displayResults($outputs, $results, $rt, $outputType, $surveyid, $sql, $ //picks out answer list ($outputs['alist']/$al)) that come from the multiple list above if (isset($al[2]) && $al[2]) { - //handling for "other" option + //handling for "other" option if ($al[0] == $statlang->gT("Other")) { if($outputs['qtype']=='!' || $outputs['qtype']=='L') @@ -1869,7 +1834,6 @@ function displayResults($outputs, $results, $rt, $outputType, $surveyid, $sql, $ * S = short free text * Q = multiple short text */ - elseif ($outputs['qtype'] == "U" || $outputs['qtype'] == "T" || $outputs['qtype'] == "S" || $outputs['qtype'] == "Q" || $outputs['qtype'] == ";") { $sDatabaseType = Yii::app()->db->getDriverName(); @@ -3454,10 +3418,6 @@ function generate_statistics($surveyid, $allfields, $q2show='all', $usegraph=0, //START Chop up fieldname and find matching questions - //Build an array of legitimate qid's for testing later - $qidquery = Questions::model()->findAll("sid=:surveyid AND parent_qid=0", array(":surveyid"=>$surveyid)); - foreach ($qidquery as $row) { $legitqids[] = $row['qid']; } - //loop through all selected questions foreach ($runthrough as $rt) { diff --git a/application/views/admin/export/statistics_view.php b/application/views/admin/export/statistics_view.php index 5a682f3ade4..e7818d04e54 100644 --- a/application/views/admin/export/statistics_view.php +++ b/application/views/admin/export/statistics_view.php @@ -1293,6 +1293,9 @@
    +
    <?php $clang->eT("Maximize"); ?><?php $clang->eT("Minimize"); ?>
    eT("Statistics"); ?> From 8fdaa8d2e31c60c5c5a1fc3f317bc0785a30aa71 Mon Sep 17 00:00:00 2001 From: jcleeland Date: Fri, 27 Jul 2012 14:56:56 +1000 Subject: [PATCH 58/71] Fixed issue: escaping in statistics browse text responses view, also added title/hover info for browse view --- application/views/admin/export/statistics_browse_view.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/application/views/admin/export/statistics_browse_view.php b/application/views/admin/export/statistics_browse_view.php index af72a17d91d..83fe22fa332 100644 --- a/application/views/admin/export/statistics_browse_view.php +++ b/application/views/admin/export/statistics_browse_view.php @@ -1,3 +1,6 @@ +lang; +?>
    - +
    Date: Fri, 27 Jul 2012 15:44:08 +1000 Subject: [PATCH 59/71] Fixed issue #6287: unable to export QueXML with Postgresql 9.1 Fixed issue #6297: QueXML Export broken Dev Removed condition checking for queXML export --- application/helpers/export_helper.php | 58 +-------------------------- 1 file changed, 2 insertions(+), 56 deletions(-) diff --git a/application/helpers/export_helper.php b/application/helpers/export_helper.php index ed1a0b5b429..4528ec42200 100644 --- a/application/helpers/export_helper.php +++ b/application/helpers/export_helper.php @@ -816,65 +816,11 @@ function QueXMLFixedArray($array) * @return bool|string Text of item to skip to otherwise false if nothing to skip to * @author Adam Zammit * @since 2010-10-28 +* @TODO Correctly handle conditions in a database agnostic way */ function QueXMLSkipTo($qid,$value,$cfieldname = "") { - global $iSurveyID, $quexmllang; - $qlang = new limesurvey_lang($quexmllang); - - $zeros = "0000000000"; - - $Query = "SELECT q.*," . concat("RIGHT(" . concat($zeros,'g.gid') . ",10)","RIGHT(". concat($zeros,'q.question_order') .",10)") ." as globalorder - FROM {{questions}} as q, {{questions}} as q2, {{groups}} as g, {{groups}} as g2 - WHERE q.parent_qid = 0 - AND q2.parent_qid = 0 - AND q.sid=$iSurveyID - AND q2.sid=$iSurveyID - AND q2.qid = $qid - AND g2.gid =q2.gid - AND g.gid = q.gid - AND " . concat("RIGHT(" . concat($zeros,'g.gid') . ",10)","RIGHT(". concat($zeros,'q.question_order') .",10)") ." > " . concat("RIGHT(" . concat($zeros,'g2.gid') . ",10)","RIGHT(". concat($zeros,'q2.question_order') .",10)") ." - ORDER BY globalorder"; - - $QueryResult = Yii::app()->db->createCommand($Query)->query(); - - $nextqid=""; - $nextorder=""; - - $Row = $QueryResult->read(); - if ($Row) - { - $nextqid = $Row['qid']; - $nextorder = $Row['globalorder']; - } - else - return false; - - - $Query = "SELECT q.* - FROM {{questions}} as q - JOIN {{groups}} as g ON (g.gid = q.gid) - LEFT JOIN {{conditions}} as c ON (c.cqid = '$qid' AND c.qid = q.qid AND c.method LIKE '==' AND c.value NOT LIKE '$value' $cfieldname) - WHERE q.sid = $iSurveyID - AND q.parent_qid = 0 - AND " . concat("RIGHT(" . concat($zeros,'g.gid') . ",10)","RIGHT(". concat($zeros,'q.question_order') .",10)") ." >= $nextorder - AND c.cqid IS NULL - ORDER BY " . concat("RIGHT(" . concat($zeros,'g.gid') . ",10)","RIGHT(". concat($zeros,'q.question_order') .",10)"); - - - $QueryResult = Yii::app()->db->createCommand($Query)->query(); - - $Row = $QueryResult->read(); - if ($Row) - { - if ($nextqid == $Row['qid']) - return false; - else - return $Row['title']; - } - else - return $qlang->gT("End"); - + return false; } /** From 5421bbd628b0466702e0834c0300c209144d58bb Mon Sep 17 00:00:00 2001 From: Carsten Schmitz Date: Fri, 27 Jul 2012 08:41:55 +0200 Subject: [PATCH 60/71] Fixed issue #6395: QuickAdd permits longer codes than 5 characters --- scripts/admin/answers.js | 2 +- scripts/admin/subquestions.js | 2 +- scripts/admin/updateset.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/admin/answers.js b/scripts/admin/answers.js index 11b7e7cb0bd..6a569b62700 100644 --- a/scripts/admin/answers.js +++ b/scripts/admin/answers.js @@ -599,7 +599,7 @@ function quickaddlabels() } else { - thisrow[0]=thisrow[0].replace(/[^A-Za-z0-9]/g, ""); + thisrow[0]=thisrow[0].replace(/[^A-Za-z0-9]/g, "").substr(0,5); } if (typeof thisrow[parseInt(x)+1]=='undefined') diff --git a/scripts/admin/subquestions.js b/scripts/admin/subquestions.js index 2a85c61ca15..b1c272cd267 100644 --- a/scripts/admin/subquestions.js +++ b/scripts/admin/subquestions.js @@ -559,7 +559,7 @@ function quickaddlabels() } else { - thisrow[0]=thisrow[0].replace(/[^A-Za-z0-9]/g, ""); + thisrow[0]=thisrow[0].replace(/[^A-Za-z0-9]/g, "").substr(0,5); } var randomid='new'+Math.floor(Math.random()*111111) diff --git a/scripts/admin/updateset.js b/scripts/admin/updateset.js index 96338efc6b2..fbdf0cf568d 100644 --- a/scripts/admin/updateset.js +++ b/scripts/admin/updateset.js @@ -92,7 +92,7 @@ function quickaddfunction(){ params = element.split(seperatorchar); k = 0; if (params.length > $(".lslanguage").length){ - code = params[0].replace(/[^a-zA-Z 0-9]+/g,''); + code = params[0].replace(/[^a-zA-Z 0-9]+/g,'').substr(0,5); i++; } @@ -344,4 +344,4 @@ function code_duplicates_check() function is_numeric (mixed_var) { return (typeof(mixed_var) === 'number' || typeof(mixed_var) === 'string') && mixed_var !== '' && !isNaN(mixed_var); -} \ No newline at end of file +} From 03b34c89bb359cea1d14a8c74b1b50648fa01640 Mon Sep 17 00:00:00 2001 From: jcleeland Date: Fri, 27 Jul 2012 16:42:18 +1000 Subject: [PATCH 61/71] Fixed issue: the background color of the jqGrid loading modal is too dark. This may not be the best colour, but it's better :-) --- application/controllers/admin/statistics.php | 2 -- styles/gringegreen/jquery-ui/jquery-ui.css | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/application/controllers/admin/statistics.php b/application/controllers/admin/statistics.php index 7a25c4b2189..545dcccfd21 100644 --- a/application/controllers/admin/statistics.php +++ b/application/controllers/admin/statistics.php @@ -476,9 +476,7 @@ public function run($surveyid, $subaction = null) exit; break; default: - break; - } } //end if -> show summary results diff --git a/styles/gringegreen/jquery-ui/jquery-ui.css b/styles/gringegreen/jquery-ui/jquery-ui.css index 053f3132a7d..4466e537644 100644 --- a/styles/gringegreen/jquery-ui/jquery-ui.css +++ b/styles/gringegreen/jquery-ui/jquery-ui.css @@ -147,7 +147,8 @@ } .ui-state-active,.ui-widget-content .ui-state-active { - background-color: #797979; + /* background-color: #797979; */ + background-color: #DBEAF9; font-weight: bold; color: #4e8632; outline: none; From 85598c958007448993739631ba4c01dcd0b13fac Mon Sep 17 00:00:00 2001 From: jcleeland Date: Fri, 27 Jul 2012 17:29:57 +1000 Subject: [PATCH 62/71] Fixed issue: tokens table not displaying more than 25 entries. Also added sort capabilities. --- application/controllers/admin/tokens.php | 6 +++++- scripts/admin/tokens.js | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/application/controllers/admin/tokens.php b/application/controllers/admin/tokens.php index 79c4804031d..f97dd94dd6b 100644 --- a/application/controllers/admin/tokens.php +++ b/application/controllers/admin/tokens.php @@ -356,10 +356,14 @@ function getTokens_json($iSurveyId) } $clang = $this->getController()->lang; $page = Yii::app()->request->getPost('page'); + $sidx = Yii::app()->request->getPost('sidx'); + $sidx = !empty($sidx) ? $sidx : "lastname"; + $sord = Yii::app()->request->getPost('sord'); + $sord = !empty($sord) ? $sord : "asc"; $limit = Yii::app()->request->getPost('rows'); $limit = isset($limit) ? $limit : 25; //Stop division by zero errors $page = isset($page) ? $page : 1; //Stop division by zero errors - $tokens = Tokens_dynamic::model($iSurveyId)->findAll(); + $tokens = Tokens_dynamic::model($iSurveyId)->findAll(array("order"=>$sidx. " ". $sord)); $aData = new stdClass; $aData->page = $page; diff --git a/scripts/admin/tokens.js b/scripts/admin/tokens.js index 4930be2c684..3902e21595d 100644 --- a/scripts/admin/tokens.js +++ b/scripts/admin/tokens.js @@ -122,12 +122,12 @@ $(document).ready(function() { editable:true, scrollOffset:0, sortable : true, - sortname: 'id', + sortname: 'tid', sortorder: 'asc', viewrecords : true, rowList: [25,50,100,250,500,1000,5000,10000], multiselect: true, - loadonce : true, + loadonce : false, loadComplete: function() { /* Sneaky way of adding custom icons to jqGrid pager buttons */ From 2fd21671f150f0bcfe09e073622925b5ec2bc892 Mon Sep 17 00:00:00 2001 From: Carsten Schmitz Date: Fri, 27 Jul 2012 11:26:44 +0200 Subject: [PATCH 63/71] Fixed issue #6066: File upload fails if single oder double quotes are used --- .../helpers/expressions/em_manager_helper.php | 6 +++++ scripts/uploader.js | 22 ++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/application/helpers/expressions/em_manager_helper.php b/application/helpers/expressions/em_manager_helper.php index bf15c992488..ce5f7cafad3 100644 --- a/application/helpers/expressions/em_manager_helper.php +++ b/application/helpers/expressions/em_manager_helper.php @@ -4554,6 +4554,12 @@ private function _UpdateValuesInDatabase($updatedValues, $finished=false) } // otherwise will already be in yyyy-mm-dd format after ProcessCurrentResponses() break; + case '|': //File upload + // This block can be removed once we require 5.3 or later + if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) { + $val=addslashes($val); + } + break; case 'N': //NUMERICAL QUESTION TYPE case 'K': //MULTIPLE NUMERICAL QUESTION if (trim($val)=='') { diff --git a/scripts/uploader.js b/scripts/uploader.js index c393cbcc4f2..c04d3225254 100644 --- a/scripts/uploader.js +++ b/scripts/uploader.js @@ -28,11 +28,11 @@ $(document).ready(function(){ previewblock += ""; if ($('#'+fieldname+'_show_title').val() == 1 && $('#'+fieldname+'_show_comment').val() == 1) - previewblock += "



    "; + previewblock += "



    "; else if ($('#'+fieldname+'_show_title').val() == 1) - previewblock += ""; + previewblock += ""; else if ($('#'+fieldname+'_show_comment').val() == 1) - previewblock += ""; + previewblock += ""; previewblock += ""+ ""+ @@ -202,7 +202,7 @@ function passJSON(fieldname, show_title, show_comment, pos) { var i = 1; while (i <= licount) { - + if ($("#"+fieldname+"_li_"+i).is(':visible')) { if (filecount > 0) @@ -210,9 +210,9 @@ function passJSON(fieldname, show_title, show_comment, pos) { json += '{'; if ($("#"+fieldname+"_show_title").val() == 1) - json += '"title":"' +$("#"+fieldname+"_title_" +i).val()+'",'; + json += '"title":"' +$("#"+fieldname+"_title_" +i).val().replace(/"/g, '\"')+'",'; if ($("#"+fieldname+"_show_comment").val() == 1) - json += '"comment":"'+$("#"+fieldname+"_comment_"+i).val()+'",'; + json += '"comment":"'+$("#"+fieldname+"_comment_"+i).val().replace(/"/g, '\"')+'",'; json += '"size":"' +$("#"+fieldname+"_size_" +i).val()+'",'+ '"name":"' +$("#"+fieldname+"_name_" +i).val()+'",'+ '"filename":"' +$("#"+fieldname+"_filename_" +i).val()+'",'+ @@ -297,3 +297,13 @@ function deletefile(fieldname, count) { xmlhttp.open('GET',uploadurl+'/delete/1/fieldname/'+fieldname+'/filename/'+filename+'/name/'+encodeURI(name), true); xmlhttp.send(); } + + +function escapeHtml(unsafe) { + return unsafe + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} From 0521fbf65a64bf5f08d7ba8bcf3f166bce13267c Mon Sep 17 00:00:00 2001 From: Carsten Schmitz Date: Fri, 27 Jul 2012 12:40:38 +0200 Subject: [PATCH 64/71] Fixed issue: Survey breaking if configured template does not exist --- application/controllers/OptinController.php | 2 +- application/controllers/OptoutController.php | 4 +- .../controllers/RegisterController.php | 2 +- application/controllers/survey/index.php | 29 +++---- application/helpers/SurveyRuntimeHelper.php | 50 ++++++------ application/helpers/common_helper.php | 34 ++++---- application/helpers/frontend_helper.php | 78 ++++++++++--------- application/helpers/qanda_helper.php | 6 +- application/helpers/replacements_helper.php | 2 +- application/libraries/Load_answers.php | 8 +- application/libraries/Save.php | 9 ++- .../views/admin/dataentry/content_view.php | 2 +- 12 files changed, 116 insertions(+), 110 deletions(-) diff --git a/application/controllers/OptinController.php b/application/controllers/OptinController.php index f9fbe1c15ec..b9d2a8fb89d 100644 --- a/application/controllers/OptinController.php +++ b/application/controllers/OptinController.php @@ -93,7 +93,7 @@ function actionLocal($surveyid, $token, $langcode = '') //PRINT COMPLETED PAGE if (!$thissurvey['templatedir']) { - $thistpl=getTemplatePath($defaulttemplate); + $thistpl=getTemplatePath(Yii::app()->getConfig("defaulttemplate")); } else { diff --git a/application/controllers/OptoutController.php b/application/controllers/OptoutController.php index 960e3e055be..e466fc6a9e6 100644 --- a/application/controllers/OptoutController.php +++ b/application/controllers/OptoutController.php @@ -96,7 +96,7 @@ function actiontokens() //PRINT COMPLETED PAGE if (!$thissurvey['templatedir']) { - $thistpl=getTemplatePath($defaulttemplate); + $thistpl=getTemplatePath(Yii::app()->getConfig("defaulttemplate")); } else { @@ -196,7 +196,7 @@ function actionparticipants() //PRINT COMPLETED PAGE if (!$thissurvey['templatedir']) { - $thistpl=getTemplatePath($defaulttemplate); + $thistpl=getTemplatePath(Yii::app()->getConfig("defaulttemplate")); } else { diff --git a/application/controllers/RegisterController.php b/application/controllers/RegisterController.php index 0dad4b36045..f54e5e1e2a6 100644 --- a/application/controllers/RegisterController.php +++ b/application/controllers/RegisterController.php @@ -29,9 +29,9 @@ function actionAJAXRegisterForm Yii::app()->loadHelper('database'); Yii::app()->loadHelper('replacements'); $redata = compact(array_keys(get_defined_vars())); - $thistpl = Yii::app()->getConfig("standardtemplaterootdir").'/default'; $surveyid = sanitize_int($surveyid); $row = Survey::model()->find('sid=:sid',array(':sid' => $surveyid)) or show_error("Can't find survey data"); + $thistpl=getTemplatePath(validateTemplateDir($row->template)); $data['sid'] = $surveyid; $data['startdate'] = $row->startdate; $data['enddate'] = $row->expires; diff --git a/application/controllers/survey/index.php b/application/controllers/survey/index.php index c3b06110ee1..a44aebf84a5 100644 --- a/application/controllers/survey/index.php +++ b/application/controllers/survey/index.php @@ -20,7 +20,7 @@ public function run() function action() { - global $surveyid, $thistpl, $totalquestions; + global $surveyid, $totalquestions; global $thissurvey, $thisstep; global $clienttoken, $tokensexist, $token; $clang = Yii::app()->lang; @@ -160,10 +160,7 @@ function action() $sDisplayLanguage = Yii::app()->getConfig('defaultlang'); } $clang = $this->_loadLimesurveyLang($sDisplayLanguage); - if(!isset($defaulttemplate)) - { - $defaulttemplate=Yii::app()->getConfig("defaulttemplate"); - } + $languagechanger = makeLanguageChanger($sDisplayLanguage); //Find out if there are any publicly available surveys $query = "SELECT sid, surveyls_title, publicstatistics, language @@ -276,24 +273,23 @@ function action() "list"=>implode("\n",$list), ); - $thissurvey['templatedir'] = $defaulttemplate; $data['thissurvey'] = $thissurvey; //$data['privacy'] = $privacy; $data['surveylist'] = $surveylist; $data['surveyid'] = $surveyid; - $data['templatedir'] = getTemplatePath($defaulttemplate); - $data['templateurl'] = getTemplateURL($defaulttemplate)."/"; - $data['templatename'] = $defaulttemplate; + $data['templatedir'] = getTemplatePath(Yii::app()->getConfig("defaulttemplate")); + $data['templateurl'] = getTemplateURL(Yii::app()->getConfig("defaulttemplate"))."/"; + $data['templatename'] = Yii::app()->getConfig("defaulttemplate"); $data['sitename'] = Yii::app()->getConfig("sitename"); $data['languagechanger'] = $languagechanger; //A nice exit sendCacheHeaders(); doHeader(); - $this->_printTemplateContent(getTemplatePath($defaulttemplate)."/startpage.pstpl", $data, __LINE__); + $this->_printTemplateContent(getTemplatePath(Yii::app()->getConfig("defaulttemplate"))."/startpage.pstpl", $data, __LINE__); - $this->_printTemplateContent(getTemplatePath($defaulttemplate)."/surveylist.pstpl", $data, __LINE__); + $this->_printTemplateContent(getTemplatePath(Yii::app()->getConfig("defaulttemplate"))."/surveylist.pstpl", $data, __LINE__); echo '\n\n"; echo "
    \n"; - echo templatereplace(file_get_contents("$thistpl/load.pstpl"),array(),$redata); + echo templatereplace(file_get_contents($sTemplatePath."load.pstpl"),array(),$redata); //PRESENT OPTIONS SCREEN (Replace with Template Later) //END echo "\n"; @@ -41,7 +41,7 @@ function run($args) { } echo "
    "; - echo templatereplace(file_get_contents("$thistpl/endpage.pstpl"),array(),$redata); + echo templatereplace(file_get_contents($sTemplatePath."endpage.pstpl"),array(),$redata); doFooter(); exit; diff --git a/application/libraries/Save.php b/application/libraries/Save.php index e7083da2399..771970758bb 100644 --- a/application/libraries/Save.php +++ b/application/libraries/Save.php @@ -58,11 +58,12 @@ class Save { function showsaveform() { //Show 'SAVE FORM' only when click the 'Save so far' button the first time, or when duplicate is found on SAVE FORM. - global $thistpl, $errormsg, $thissurvey, $surveyid, $clang, $clienttoken, $thisstep; + global $errormsg, $thissurvey, $surveyid, $clang, $clienttoken, $thisstep; $redata = compact(array_keys(get_defined_vars())); + $sTemplatePath=$_SESSION['survey_'.$surveyid]['templatepath']; sendCacheHeaders(); doHeader(); - echo templatereplace(file_get_contents("$thistpl/startpage.pstpl"),array(),$redata); + echo templatereplace(file_get_contents($sTemplatePath."startpage.pstpl"),array(),$redata); echo "\n\n\n" ."\t