зеркало из https://github.com/mozilla/pjs.git
Reworked the database. we now have "question sets" which will allow us versioning
This commit is contained in:
Родитель
11b41fa276
Коммит
ab4df73b13
|
@ -11,7 +11,7 @@ class ResultsController extends AppController {
|
|||
* Model's this controller uses
|
||||
* @var array
|
||||
*/
|
||||
var $uses = array('Application','Result','Intention','Issue');
|
||||
var $uses = array('Application','Collection','Choice','Result');
|
||||
|
||||
/**
|
||||
* Cake Helpers
|
||||
|
@ -62,8 +62,7 @@ class ResultsController extends AppController {
|
|||
$_input_name = $this->Sanitize->Sql(isset($this->data['application'][0]) ? $this->data['application'][0] : (isset($this->params['url']['application']) ? $this->params['url']['application'] : ''));
|
||||
$_input_ua = $this->Sanitize->Sql(isset($this->data['ua'][0]) ? $this->data['ua'][0] : (isset($this->params['url']['ua']) ? $this->params['url']['ua'] : ''));
|
||||
|
||||
// Please, oh please can we talk about standards in the future. :) The ua
|
||||
// comes over $_GET in the form:
|
||||
// The ua comes over $_GET in the form:
|
||||
// x.x.x.x (aa-bb)
|
||||
// Where x is the versions and a and b are locale information. We're not
|
||||
// interested in the locale information,
|
||||
|
@ -83,7 +82,6 @@ class ResultsController extends AppController {
|
|||
|
||||
$app_id = $app->getLastInsertID();
|
||||
|
||||
// Warning: hard coding ahead! - Hopefully this is a temporary thing.
|
||||
// The database will handle any combination of questions
|
||||
// (issues/intentions) and applications+versions. However, since we're
|
||||
// adding stuff in that comes in over the URL, we kinda have to guess at
|
||||
|
@ -92,18 +90,18 @@ class ResultsController extends AppController {
|
|||
// then manually adding those values to the table.
|
||||
if (stristr($this->params['url']['application'], 'Firefox') !== false) {
|
||||
// Intention Id's
|
||||
$this->Intention->query("INSERT INTO applications_intentions VALUES ({$app_id}, 1), ({$app_id}, 2), ({$app_id}, 3), ({$app_id}, 9)");
|
||||
$this->Application->query("INSERT INTO applications_collections VALUES ({$app_id}, ".DEFAULT_FIREFOX_INTENTION_SET_ID.")");
|
||||
|
||||
// Issue Id's
|
||||
$this->Issue->query("INSERT INTO applications_issues VALUES ({$app_id}, 1), ({$app_id}, 2), ({$app_id}, 3), ({$app_id}, 4), ({$app_id}, 5), ({$app_id}, 6), ({$app_id}, 7), ({$app_id}, 8), ({$app_id}, 9), ({$app_id}, 15)");
|
||||
$this->Application->query("INSERT INTO applications_collections VALUES ({$app_id}, ".DEFAULT_FIREFOX_ISSUE_SET_ID.")");
|
||||
|
||||
} elseif (stristr($this->params['url']['application'], 'Thunderbird') !== false) {
|
||||
|
||||
// Intention Id's
|
||||
$this->Intention->query("INSERT INTO applications_intentions VALUES ({$app_id}, 5), ({$app_id}, 6), ({$app_id}, 7), ({$app_id}, 8), ({$app_id}, 9)");
|
||||
$this->Application->query("INSERT INTO applications_collections VALUES ({$app_id}, ".DEFAULT_THUNDERBIRD_INTENTION_SET_ID.")");
|
||||
|
||||
// Issue Id's
|
||||
$this->Issue->query("INSERT INTO applications_issues VALUES ({$app_id}, 10), ({$app_id}, 11), ({$app_id}, 12), ({$app_id}, 13), ({$app_id}, 14), ({$app_id}, 15)");
|
||||
$this->Application->query("INSERT INTO applications_collections VALUES ({$app_id}, ".DEFAULT_THUNDERBIRD_ISSUE_SET_ID.")");
|
||||
|
||||
} else {
|
||||
// Whatever they entered doesn't have firefox or thunderbird in it.
|
||||
|
@ -118,13 +116,12 @@ class ResultsController extends AppController {
|
|||
$_conditions = "name LIKE '{$_input_name}' AND version LIKE '{$_input_ua}' AND 1=1";
|
||||
$_application = $this->Application->findAll($_conditions);
|
||||
}
|
||||
|
||||
// Pull the information for our radio buttons (only the
|
||||
// questions for their applications will be shown)
|
||||
$this->set('intentions', $this->Intention->Application->findById($_application[0]['Application']['id']));
|
||||
$this->set('intentions', $this->Application->getIntentions($this->Sanitize->sql($_application[0]['Application']['id'])));
|
||||
|
||||
// Checkboxes
|
||||
$this->set('issues', $this->Issue->Application->findById($_application[0]['Application']['id']));
|
||||
$this->set('issues', $this->Application->getIssues($this->Sanitize->sql($_application[0]['Application']['id'])));
|
||||
|
||||
// We'll need the url parameters to put in hidden fields
|
||||
$this->set('url_params', $this->Sanitize->html($this->params['url']));
|
||||
|
@ -166,6 +163,9 @@ class ResultsController extends AppController {
|
|||
// We'll need to include the graphing libraries
|
||||
$this->set('include_graph_libraries', true);
|
||||
|
||||
// Fill in our question sets
|
||||
$this->set('collections',$this->Application->getCollectionsFromUrl($this->params['url'],'issue'));
|
||||
|
||||
// Core data to show on page
|
||||
$this->set('descriptionAndTotalsData',$this->Result->getDescriptionAndTotalsData($this->params['url']));
|
||||
}
|
||||
|
@ -215,8 +215,17 @@ class ResultsController extends AppController {
|
|||
// Get rid of the header/footer/etc.
|
||||
$this->layout = null;
|
||||
|
||||
// Auto generated .csv's are turned off since they were taking too much
|
||||
// cpu/ram. If you turn them back on, be sure to check the code - there was
|
||||
// a substantial database change between the time they were disabled and now.
|
||||
return false;
|
||||
|
||||
$csv = new csv();
|
||||
|
||||
$csv->loadDataFromArray($this->Result->getCsvExportData($this->params['url'], false));
|
||||
|
||||
// Our CSV library sends headers and everything. Keep the view empty!
|
||||
csv_send_csv($this->Result->getCsvExportData($this->params['url']));
|
||||
$csv->sendCSV();
|
||||
|
||||
// I'm not exiting here in case someone is going to use post callback stuff.
|
||||
// In development, that means extra lines get added to our CSVs, but in
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
uses('Sanitize');
|
||||
class Application extends AppModel {
|
||||
var $name = 'Application';
|
||||
|
||||
|
@ -10,14 +11,177 @@ class Application extends AppModel {
|
|||
//var $hasOne = array('Result');
|
||||
|
||||
var $hasAndBelongsToMany = array(
|
||||
'Intention' => array(
|
||||
'className' => 'Intention',
|
||||
'order' => 'pos'
|
||||
),
|
||||
'Issue' => array(
|
||||
'className' => 'Issue',
|
||||
'order' => 'pos'
|
||||
)
|
||||
'Collection' => array( 'className' => 'Collection')
|
||||
);
|
||||
|
||||
var $Sanitize;
|
||||
|
||||
function Application() {
|
||||
parent::AppModel();
|
||||
|
||||
$this->Sanitize = new Sanitize();
|
||||
}
|
||||
/**
|
||||
* @param int application id
|
||||
* @return array set of intentions
|
||||
*/
|
||||
function getIntentions($id) {
|
||||
// this should never happen...
|
||||
if (!is_numeric($id)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$_query = "
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
applications
|
||||
JOIN applications_collections ON application_id = applications.id
|
||||
JOIN collections ON collections.id = applications_collections.collection_id
|
||||
JOIN choices_collections ON choices_collections.collection_id = collections.id
|
||||
JOIN choices ON choices.id = choices_collections.choice_id
|
||||
WHERE
|
||||
applications.id={$id}
|
||||
AND
|
||||
choices.type='intention'";
|
||||
|
||||
return $this->query($_query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int application id
|
||||
* @return array set of issues
|
||||
*/
|
||||
function getIssues($id)
|
||||
{
|
||||
// this should never happen...
|
||||
if (!is_numeric($id)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$_max_id = $this->getMaxCollectionId($id,'issue');
|
||||
if (!is_numeric($_max_id[0][0]['max'])) {
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
$_query = "
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
applications
|
||||
JOIN applications_collections ON application_id = applications.id
|
||||
JOIN collections ON collections.id = applications_collections.collection_id
|
||||
JOIN choices_collections ON choices_collections.collection_id = collections.id
|
||||
JOIN choices ON choices.id = choices_collections.choice_id
|
||||
WHERE
|
||||
applications.id={$id}
|
||||
AND
|
||||
choices.type='issue'
|
||||
AND
|
||||
collections.id={$_max_id[0][0]['max']}
|
||||
";
|
||||
|
||||
return $this->query($_query);
|
||||
}
|
||||
|
||||
function getMaxCollectionId($id, $type)
|
||||
{
|
||||
if (!is_numeric($id)) {
|
||||
return false;
|
||||
}
|
||||
$_type = $this->Sanitize->sql($type);
|
||||
|
||||
$_query = "
|
||||
SELECT
|
||||
MAX(collections.id) as max
|
||||
FROM
|
||||
applications
|
||||
JOIN applications_collections ON application_id = applications.id
|
||||
JOIN collections ON collections.id = applications_collections.collection_id
|
||||
JOIN choices_collections ON choices_collections.collection_id = collections.id
|
||||
JOIN choices ON choices.id = choices_collections.choice_id
|
||||
WHERE
|
||||
applications.id={$id}
|
||||
AND
|
||||
choices.type='{$_type}'
|
||||
";
|
||||
|
||||
return $this->query($_query);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array cake url array
|
||||
* @return array set of collections
|
||||
*/
|
||||
function getCollectionsFromUrl($params, $type)
|
||||
{
|
||||
// Clean parameters for inserting into SQL
|
||||
$params = $this->cleanArrayForSql($params);
|
||||
|
||||
$_conditions = "1=1";
|
||||
// Firstly, determine our application
|
||||
if (!empty($params['product'])) {
|
||||
|
||||
// product's come in looking like:
|
||||
// Mozilla Firefox 1.5.0.1
|
||||
$_exp = explode(' ',urldecode($params['product']));
|
||||
|
||||
if(count($_exp) == 3) {
|
||||
$_product = $_exp[0].' '.$_exp[1];
|
||||
|
||||
$_version = $_exp[2];
|
||||
|
||||
$_conditions .= " AND `Application`.`name` LIKE '{$_product}'";
|
||||
$_conditions .= " AND `Application`.`version` LIKE '{$_version}'";
|
||||
} else {
|
||||
// defaults I guess?
|
||||
$_conditions .= " AND `Application`.`name` LIKE '".DEFAULT_APP_NAME."'";
|
||||
$_conditions .= " AND `Application`.`version` LIKE '".DEFAULT_APP_VERSION."'";
|
||||
}
|
||||
} else {
|
||||
// I'm providing a default here, because otherwise all results will be
|
||||
// returned (across all applications) and that is not desired
|
||||
$_conditions .= " AND `Application`.`name` LIKE '".DEFAULT_APP_NAME."'";
|
||||
$_conditions .= " AND `Application`.`version` LIKE '".DEFAULT_APP_VERSION."'";
|
||||
}
|
||||
|
||||
$_application_id = $this->findAll($_conditions, 'Application.id');
|
||||
return $this->getCollections($_application_id[0]['Application']['id'], $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int application id
|
||||
* @param string choice type (either 'issue' or 'intention' right now)
|
||||
* @return array set of collections
|
||||
*/
|
||||
function getCollections($id, $type)
|
||||
{
|
||||
// this should never happen...
|
||||
if (!is_numeric($id)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$_type = $this->Sanitize->sql($type);
|
||||
$_query = "
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
applications
|
||||
JOIN applications_collections ON application_id = applications.id
|
||||
JOIN collections ON collections.id = applications_collections.collection_id
|
||||
JOIN choices_collections ON choices_collections.collection_id = collections.id
|
||||
JOIN choices ON choices.id = choices_collections.choice_id
|
||||
WHERE
|
||||
applications.id={$id}
|
||||
AND
|
||||
choices.type='{$_type}'
|
||||
GROUP BY collections.description
|
||||
ORDER BY collections.id DESC";
|
||||
|
||||
return $this->query($_query);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -2,17 +2,22 @@
|
|||
class Result extends AppModel {
|
||||
var $name = 'Result';
|
||||
|
||||
var $belongsTo = array('Application', 'Intention');
|
||||
var $belongsTo = array('Application');
|
||||
|
||||
var $hasAndBelongsToMany = array('Issue' =>
|
||||
array('className' => 'Issue',
|
||||
'joinTable' => 'issues_results',
|
||||
'foreignKey'=> 'issue_id',
|
||||
'assocationForeignKey'=>'result_id',
|
||||
var $hasAndBelongsToMany = array('Choice' =>
|
||||
array('className' => 'Choice',
|
||||
'uniq' => true
|
||||
)
|
||||
);
|
||||
|
||||
var $Sanitize;
|
||||
|
||||
function Result()
|
||||
{
|
||||
parent::appModel();
|
||||
$this->Sanitize = new Sanitize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Count's all the comments, according to the parameters.
|
||||
* @param array URL parameters
|
||||
|
@ -59,15 +64,15 @@ class Result extends AppModel {
|
|||
array_push($_conditions, "`Application`.`version` LIKE '{$_version}'");
|
||||
} else {
|
||||
// defaults I guess?
|
||||
array_push($_conditions, "`Application`.`name` LIKE 'Mozilla Firefox'");
|
||||
array_push($_conditions, "`Application`.`version` LIKE '1.5'");
|
||||
array_push($_conditions, "`Application`.`name` LIKE '".DEFAULT_APP_NAME."'");
|
||||
array_push($_conditions, "`Application`.`version` LIKE '".DEFAULT_APP_VERSION."'");
|
||||
}
|
||||
|
||||
} else {
|
||||
// I'm providing a default here, because otherwise all results will be
|
||||
// returned (across all applications) and that is not desired
|
||||
array_push($_conditions, "`Application`.`name` LIKE 'Mozilla Firefox'");
|
||||
array_push($_conditions, "`Application`.`version` LIKE '1.5'");
|
||||
array_push($_conditions, "`Application`.`name` LIKE '".DEFAULT_APP_NAME."'");
|
||||
array_push($_conditions, "`Application`.`version` LIKE '".DEFAULT_APP_VERSION."'");
|
||||
}
|
||||
|
||||
// Do the actual query
|
||||
|
@ -124,34 +129,43 @@ class Result extends AppModel {
|
|||
array_push($_conditions, "`Application`.`version` LIKE '{$_version}'");
|
||||
} else {
|
||||
// defaults I guess?
|
||||
array_push($_conditions, "`Application`.`name` LIKE 'Mozilla Firefox'");
|
||||
array_push($_conditions, "`Application`.`version` LIKE '1.5'");
|
||||
array_push($_conditions, "`Application`.`name` LIKE '".DEFAULT_APP_NAME."'");
|
||||
array_push($_conditions, "`Application`.`version` LIKE '".DEFAULT_APP_VERSION."'");
|
||||
}
|
||||
|
||||
} else {
|
||||
// I'm providing a default here, because otherwise all results will be
|
||||
// returned (across all applications) and that is not desired
|
||||
array_push($_conditions, "`Application`.`name` LIKE 'Mozilla Firefox'");
|
||||
array_push($_conditions, "`Application`.`version` LIKE '1.5'");
|
||||
array_push($_conditions, "`Application`.`name` LIKE '".DEFAULT_APP_NAME."'");
|
||||
array_push($_conditions, "`Application`.`version` LIKE '".DEFAULT_APP_VERSION."'");
|
||||
}
|
||||
|
||||
// Save ourselves quite a few joins
|
||||
$this->unBindModel(array('hasAndBelongsToMany' => array('Issue')));
|
||||
$comments = $this->findAll($_conditions, null, $pagination['order'], $pagination['show'], $pagination['page']);
|
||||
|
||||
if ($privacy) {
|
||||
// Pull out all the email addresses and phone numbers
|
||||
// Pull out all the email addresses and phone numbers. The original
|
||||
// lines are below, but commented out for the sake of speed.
|
||||
// preg_replace() will replace a single level of an array according to a
|
||||
// pattern. This behavior doesn't seem to be documented (at this time), so I'm not sure
|
||||
// if they are going to "fix" it later. If they do, you can replace the
|
||||
// current code with the commented ones, but realize it will take about
|
||||
// twice as long.
|
||||
foreach ($comments as $var => $val) {
|
||||
|
||||
// Handle foo@bar.com
|
||||
$_email_regex = '/\ ?(.+)?@(.+)?\.(.+)?\ ?/';
|
||||
$comments[$var]['Result']['comments'] = preg_replace($_email_regex,'$1@****.$3',$comments[$var]['Result']['comments']);
|
||||
$comments[$var]['Result']['intention_text'] = preg_replace($_email_regex,'$1@****.$3',$comments[$var]['Result']['intention_text']);
|
||||
$comments[$var]['Result'] = preg_replace($_email_regex,'$1@****.$3',$comments[$var]['Result']);
|
||||
|
||||
//$comments[$var]['Result']['comments'] = preg_replace($_email_regex,'$1@****.$3',$comments[$var]['Result']['comments']);
|
||||
//$comments[$var]['Result']['intention_text'] = preg_replace($_email_regex,'$1@****.$3',$comments[$var]['Result']['intention_text']);
|
||||
|
||||
// Handle xxx-xxx-xxxx
|
||||
$_phone_regex = '/([0-9]{3})[ .-]?[0-9]{4}/';
|
||||
$comments[$var]['Result']['comments'] = preg_replace($_phone_regex,'$1-****',$comments[$var]['Result']['comments']);
|
||||
$comments[$var]['Result']['intention_text'] = preg_replace($_phone_regex,'$1-****',$comments[$var]['Result']['intention_text']);
|
||||
$comments[$var]['Result'] = preg_replace($_phone_regex,'$1-****',$comments[$var]['Result']);
|
||||
|
||||
//$comments[$var]['Result']['comments'] = preg_replace($_phone_regex,'$1-****',$comments[$var]['Result']['comments']);
|
||||
//$comments[$var]['Result']['intention_text'] = preg_replace($_phone_regex,'$1-****',$comments[$var]['Result']['intention_text']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,14 +234,14 @@ class Result extends AppModel {
|
|||
$_query .= " AND `applications`.`version` LIKE '{$_version}'";
|
||||
} else {
|
||||
// defaults I guess?
|
||||
$_query .= " AND `applications`.`name` LIKE 'Mozilla Firefox'";
|
||||
$_query .= " AND `applications`.`version` LIKE '1.5'";
|
||||
$_query .= " AND `applications`.`name` LIKE '".DEFAULT_APP_NAME."'";
|
||||
$_query .= " AND `applications`.`version` LIKE '".DEFAULT_APP_VERSION."'";
|
||||
}
|
||||
} else {
|
||||
// I'm providing a default here, because otherwise all results will be
|
||||
// returned (across all applications) and that is not desired
|
||||
$_query .= " AND `applications`.`name` LIKE 'Mozilla Firefox'";
|
||||
$_query .= " AND `applications`.`version` LIKE '1.5'";
|
||||
$_query .= " AND `applications`.`name` LIKE '".DEFAULT_APP_NAME."'";
|
||||
$_query .= " AND `applications`.`version` LIKE '".DEFAULT_APP_VERSION."'";
|
||||
}
|
||||
|
||||
$_query .= " ORDER BY `results`.`created` ASC";
|
||||
|
@ -236,7 +250,6 @@ class Result extends AppModel {
|
|||
|
||||
// Since we're exporting to a CSV, we need to flatten the results into a 2
|
||||
// dimensional table array
|
||||
$newdata = array();
|
||||
|
||||
foreach ($res as $result) {
|
||||
|
||||
|
@ -244,18 +257,28 @@ class Result extends AppModel {
|
|||
}
|
||||
|
||||
if ($privacy) {
|
||||
// Pull out all the email addresses and phone numbers
|
||||
// Pull out all the email addresses and phone numbers. The original
|
||||
// lines are below, but commented out for the sake of speed.
|
||||
// preg_replace() will replace a single level of an array according to a
|
||||
// pattern. This behavior doesn't seem to be documented (at this time), so I'm not sure
|
||||
// if they are going to "fix" it later. If they do, you can replace the
|
||||
// current code with the commented ones, but realize it will take about
|
||||
// twice as long.
|
||||
foreach ($newdata as $var => $val) {
|
||||
|
||||
// Handle foo@bar.com
|
||||
$_email_regex = '/\ ?(.+)?@(.+)?\.(.+)?\ ?/';
|
||||
$newdata[$var]['comments'] = preg_replace($_email_regex,'$1@****.$3',$newdata[$var]['comments']);
|
||||
$newdata[$var]['intention_other'] = preg_replace($_email_regex,'$1@****.$3',$newdata[$var]['intention_other']);
|
||||
$newdata[$var] = preg_replace($_email_regex,'$1@****.$3',$newdata[$var]);
|
||||
|
||||
//$newdata[$var]['comments'] = preg_replace($_email_regex,'$1@****.$3',$newdata[$var]['comments']);
|
||||
//$newdata[$var]['intention_other'] = preg_replace($_email_regex,'$1@****.$3',$newdata[$var]['intention_other']);
|
||||
|
||||
// Handle xxx-xxx-xxxx
|
||||
$_phone_regex = '/([0-9]{3})[ .-]?[0-9]{4}/';
|
||||
$newdata[$var]['comments'] = preg_replace($_phone_regex,'$1-****',$newdata[$var]['comments']);
|
||||
$newdata[$var]['intention_other'] = preg_replace($_phone_regex,'$1-****',$newdata[$var]['intention_other']);
|
||||
$newdata[$var] = preg_replace($_phone_regex,'$1-****',$newdata[$var]);
|
||||
|
||||
//$newdata[$var]['comments'] = preg_replace($_phone_regex,'$1-****',$newdata[$var]['comments']);
|
||||
//$newdata[$var]['intention_other'] = preg_replace($_phone_regex,'$1-****',$newdata[$var]['intention_other']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,7 +304,7 @@ class Result extends AppModel {
|
|||
|
||||
/* Below is the original query for this function. It was beautiful and
|
||||
* brought back just what we needed. However, it took 5.5s to run with 43000
|
||||
* results, and since that number is just going up, it won't due to have a
|
||||
* results, and since that number is just going up, it won't do to have a
|
||||
* query take that long (especially one on the front page).
|
||||
|
||||
//It would be nice to drop something like this in the SELECT:
|
||||
|
@ -323,34 +346,56 @@ class Result extends AppModel {
|
|||
$_conditions .= " AND `Application`.`version` LIKE '{$_version}'";
|
||||
} else {
|
||||
// defaults I guess?
|
||||
$_conditions .= " AND `Application`.`name` LIKE 'Mozilla Firefox'";
|
||||
$_conditions .= " AND `Application`.`version` LIKE '1.5'";
|
||||
$_conditions .= " AND `Application`.`name` LIKE '".DEFAULT_APP_NAME."'";
|
||||
$_conditions .= " AND `Application`.`version` LIKE '".DEFAULT_APP_VERSION."'";
|
||||
}
|
||||
} else {
|
||||
// I'm providing a default here, because otherwise all results will be
|
||||
// returned (across all applications) and that is not desired
|
||||
$_conditions .= " AND `Application`.`name` LIKE 'Mozilla Firefox'";
|
||||
$_conditions .= " AND `Application`.`version` LIKE '1.5'";
|
||||
$_conditions .= " AND `Application`.`name` LIKE '".DEFAULT_APP_NAME."'";
|
||||
$_conditions .= " AND `Application`.`version` LIKE '".DEFAULT_APP_VERSION."'";
|
||||
}
|
||||
|
||||
// Save ourselves some joins
|
||||
$this->Application->unBindModel(array('hasAndBelongsToMany' => array('Intention','Issue')));
|
||||
|
||||
$_application_id = $this->Application->findAll($_conditions, 'Application.id');
|
||||
|
||||
// Next determine our collection
|
||||
if (!empty($params['collection'])) {
|
||||
$_collection_id = $this->Choice->Collection->findByDescription($params['collection']);
|
||||
$clear = true;
|
||||
foreach ($_collection_id['Application'] as $var => $val) {
|
||||
if ($_application_id[0]['Application']['id'] == $val['id']) {
|
||||
$clear = false;
|
||||
}
|
||||
}
|
||||
if ($clear) {
|
||||
$_id = $this->Application->getMaxCollectionId($_application_id[0]['Application']['id'], 'issue');
|
||||
$_collection_id['Collection']['id'] = $_id[0][0]['max'];
|
||||
}
|
||||
} else {
|
||||
$_id = $this->Application->getMaxCollectionId($_application_id[0]['Application']['id'], 'issue');
|
||||
$_collection_id['Collection']['id'] = $_id[0][0]['max'];
|
||||
}
|
||||
|
||||
// The second query will retrieve all the issues that are related to our
|
||||
// application.
|
||||
$_query = "
|
||||
SELECT
|
||||
issues.description, issues.id
|
||||
choices.description, choices.id
|
||||
FROM
|
||||
applications_issues, issues
|
||||
WHERE
|
||||
applications_issues.application_id = {$_application_id[0]['Application']['id']}
|
||||
AND
|
||||
issues.id = applications_issues.issue_id
|
||||
choices
|
||||
JOIN choices_collections ON choices_collections.choice_id = choices.id
|
||||
JOIN collections ON collections.id = choices_collections.collection_id
|
||||
JOIN applications_collections ON applications_collections.collection_id = collections.id
|
||||
JOIN applications ON applications.id = applications_collections.application_id
|
||||
AND applications.id = {$_application_id[0]['Application']['id']}
|
||||
AND choices.type = 'issue'
|
||||
";
|
||||
if (!empty($_collection_id['Collection']['id'])) {
|
||||
$_query .= "AND collections.id = {$_collection_id['Collection']['id']}";
|
||||
}
|
||||
$_query .= "
|
||||
ORDER BY
|
||||
issues.description DESC
|
||||
choices.description DESC
|
||||
";
|
||||
|
||||
$_issues = $this->query($_query);
|
||||
|
@ -363,24 +408,27 @@ class Result extends AppModel {
|
|||
// Cake has a pretty specific way it stores data, and this is consistent
|
||||
// with the old query. Here we start our results array so it's holding the
|
||||
// descriptions and a zeroed total
|
||||
$_results[$val['issues']['id']]['issues']['description'] = $val['issues']['description'];
|
||||
$_results[$val['issues']['id']][0]['total'] = 0; // default to nothing - this will get filled in later
|
||||
$_results[$val['choices']['id']]['choices']['description'] = $val['choices']['description'];
|
||||
$_results[$val['choices']['id']][0]['total'] = 0; // default to nothing - this will get filled in later
|
||||
|
||||
// Since we're already walking through this loop, we might as well build
|
||||
// up a query string to get our totals
|
||||
$_issue_ids .= empty($_issue_ids) ? $val['issues']['id'] : ', '.$val['issues']['id'];
|
||||
$_issue_ids .= empty($_issue_ids) ? $val['choices']['id'] : ',
|
||||
'.$val['choices']['id'];
|
||||
}
|
||||
|
||||
$_query = "
|
||||
SELECT
|
||||
issues_results.issue_id, count(id)
|
||||
choices_results.choice_id, count(results.id)
|
||||
AS
|
||||
total
|
||||
FROM
|
||||
issues_results
|
||||
JOIN results ON results.id=issues_results.result_id
|
||||
AND results.application_id={$_application_id[0]['Application']['id']}
|
||||
AND issues_results.issue_id in ({$_issue_ids})
|
||||
results
|
||||
JOIN choices_results ON results.id = choices_results.result_id
|
||||
WHERE
|
||||
results.application_id = {$_application_id[0]['Application']['id']}
|
||||
AND
|
||||
choices_results.choice_id in ({$_issue_ids})
|
||||
";
|
||||
|
||||
if (!empty($params['start_date'])) {
|
||||
|
@ -401,13 +449,13 @@ class Result extends AppModel {
|
|||
}
|
||||
}
|
||||
|
||||
$_query .= "GROUP BY issue_id";
|
||||
$_query .= " GROUP BY choices_results.choice_id";
|
||||
|
||||
$ret = $this->query($_query);
|
||||
|
||||
foreach ($ret as $var => $val) {
|
||||
// fill in the totals we retrieved
|
||||
$_results[$val['issues_results']['issue_id']][0]['total'] = $val[0]['total'];
|
||||
$_results[$val['choices_results']['choice_id']][0]['total'] = $val[0]['total'];
|
||||
}
|
||||
|
||||
return $_results;
|
||||
|
@ -427,10 +475,10 @@ class Result extends AppModel {
|
|||
// Apparently these are all escaped for us by cake. It still makes me
|
||||
// nervous.
|
||||
$_application_id = $data['Application']['id'];
|
||||
$_intention_id = $data['Result']['intention_id'];
|
||||
$_intention_id = $data['Intention']['id']; // Doesn't quite conform to cake standards
|
||||
$_comments = $data['Result']['comments'];
|
||||
$_issues_text = $data['issues_results']['other'];
|
||||
$_intention_text = $data['Result']['intention_text'];
|
||||
$_issues_text = $this->Sanitize->Sql($data['Issue']['text']);
|
||||
$_intention_text = $this->Sanitize->Sql($data['Intention']['text']);
|
||||
// Joined for legacy reasons
|
||||
$_user_agent = mysql_real_escape_string("{$data['ua'][0]} {$data['lang'][0]}");
|
||||
$_http_user_agent = mysql_real_escape_string($_SERVER['HTTP_USER_AGENT']);
|
||||
|
@ -443,16 +491,21 @@ class Result extends AppModel {
|
|||
// Special cases for the "other" fields. If their corresponding option isn't
|
||||
// set, we don't want the field values.
|
||||
// issue is determined below
|
||||
$_issue_array = $this->Issue->findByDescription('other');
|
||||
$_intention_array = $this->Intention->findByDescription('other');
|
||||
$this->Choice->unBindModel(array('hasAndBelongsToMany' => array('Result')));
|
||||
$this->Choice->unBindModel(array('hasAndBelongsToMany' => array('Collection')));
|
||||
//$_issue_array = $this->Issue->findByDescription('other');
|
||||
$_conditions = "description LIKE 'Other' AND type='intention'";
|
||||
$_intention_array = $this->Choice->findAll($_conditions);
|
||||
|
||||
if ($_intention_id != $_intention_array['Intention']['id']) {
|
||||
$_conditions = "description LIKE 'Other' AND type='issue'";
|
||||
$_issue_array = $this->Choice->findAll($_conditions);
|
||||
|
||||
if ($_intention_id != $_intention_array[0]['Choice']['id']) {
|
||||
echo 'not equal!';
|
||||
$_intention_text = '';
|
||||
}
|
||||
|
||||
$this->set('application_id', $_application_id);
|
||||
$this->set('intention_id', $_intention_id);
|
||||
$this->set('intention_text', $_intention_text);
|
||||
$this->set('comments', $_comments);
|
||||
$this->set('useragent', $_user_agent);
|
||||
$this->set('http_user_agent', $_http_user_agent);
|
||||
|
@ -460,12 +513,29 @@ class Result extends AppModel {
|
|||
// We kinda overrode $this's save(), so we'll have to ask our guardians
|
||||
parent::save();
|
||||
|
||||
$_result_id = $this->getLastInsertID();
|
||||
|
||||
// The issues_results table isn't represented by a class in cake, so we have
|
||||
// Insert our intention
|
||||
if (!empty($_intention_id)) {
|
||||
$_query = "
|
||||
INSERT INTO choices_results(
|
||||
result_id,
|
||||
choice_id,
|
||||
other
|
||||
) VALUES (
|
||||
{$_result_id},
|
||||
{$_intention_id},
|
||||
'{$_intention_text}'
|
||||
)
|
||||
";
|
||||
$this->query($_query);
|
||||
}
|
||||
|
||||
|
||||
// The choices_results table isn't represented by a class in cake, so we have
|
||||
// to do the query manually.
|
||||
if (!empty($data['Issue']['id'])) {
|
||||
|
||||
$_result_id = $this->getLastInsertID();
|
||||
$_query = '';
|
||||
|
||||
foreach ($data['Issue']['id'] as $var => $val) {
|
||||
|
@ -475,15 +545,15 @@ class Result extends AppModel {
|
|||
}
|
||||
|
||||
// If the 'other' id matches the id we're putting in, add the issue text
|
||||
$_other_text = ($val == $_issue_array['Issue']['id']) ? $_issues_text : '';
|
||||
$_other_text = ($val == $_issue_array[0]['Choice']['id']) ? $_issues_text : '';
|
||||
|
||||
$_query .= empty($_query) ? "({$_result_id},{$val},'{$_other_text}')" : ",({$_result_id},{$val},'{$_other_text}')";
|
||||
}
|
||||
|
||||
$_query = "
|
||||
INSERT INTO issues_results(
|
||||
INSERT INTO choices_results(
|
||||
result_id,
|
||||
issue_id,
|
||||
choice_id,
|
||||
other
|
||||
) VALUES
|
||||
{$_query}
|
||||
|
@ -494,5 +564,6 @@ class Result extends AppModel {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -32,5 +32,25 @@ class ExportHelper
|
|||
|
||||
return "{$this->webroot}{$url}{$seperator}{$arguments}";
|
||||
}
|
||||
|
||||
function buildCsvExportString($params)
|
||||
{
|
||||
if (array_key_exists('product', $params)) {
|
||||
$filename = $params['product'];
|
||||
} else {
|
||||
$filename = DEFAULT_APP_NAME.' '.DEFAULT_APP_VERSION;
|
||||
}
|
||||
|
||||
// Our filenames have underscores
|
||||
$filename = str_replace(' ','_',$filename);
|
||||
|
||||
$filename = "export-{$filename}.csv";
|
||||
|
||||
if (is_readable(ROOT.DS.APP_DIR.DS.WEBROOT_DIR.DS.'export'.DS.$filename)) {
|
||||
return "{$this->webroot}export/{$filename}";
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<?php echo $html->formTag('/results/add'); ?>
|
||||
|
||||
<?php if(!empty($intentions['Intention'])): ?>
|
||||
<h2>How did you intend to use <?php echo $intentions['Application']['name']; ?> when you installed it?</h2>
|
||||
<?php foreach ($intentions['Intention'] as $var => $val) : ?>
|
||||
<input type="radio" name="data[Result][intention_id]" id="radio<?php echo $val['id']; ?>" value="<?php echo $val['id']; ?>"><label for="radio<?php echo $val['id']; ?>"><?php echo $val['description']; ?></label>
|
||||
<?php if(!empty($intentions)): ?>
|
||||
<h2>How did you intend to use <?php echo $intentions[0]['applications']['name']; ?> when you installed it?</h2>
|
||||
<?php foreach ($intentions as $var => $val) : ?>
|
||||
<input type="radio" name="data[Intention][id]" id="radio<?php echo $val['choices']['id']; ?>" value="<?php echo $val['choices']['id']; ?>"><label for="radio<?php echo $val['choices']['id']; ?>"><?php echo $val['choices']['description']; ?></label>
|
||||
<?php
|
||||
if ($val['description'] == 'Other') {
|
||||
echo $html->input('Result/intention_text');
|
||||
if ($val['choices']['description'] == 'Other') {
|
||||
echo $html->input('Intention/text');
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -14,21 +14,20 @@
|
|||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<?php if(!empty($issues['Issue'])): ?>
|
||||
<h2>Why did you uninstall <?php echo $intentions['Application']['name']; ?>? (select all that apply)</h2>
|
||||
<?php foreach ($issues['Issue'] as $var => $val) : ?>
|
||||
<input type="checkbox" name="data[Issue][id][]" id="checkbox<?php echo $val['id']; ?>" value="<?php echo $val['id']; ?>"><label for="checkbox<?php echo $val['id']; ?>"><?php echo $val['description']; ?></label>
|
||||
<?php if(!empty($issues)): ?>
|
||||
<h2>Why did you uninstall <?php echo $issues[0]['applications']['name']; ?>? (select all that apply)</h2>
|
||||
<?php foreach ($issues as $var => $val) : ?>
|
||||
<input type="checkbox" name="data[Issue][id][]" id="checkbox<?php echo $val['choices']['id']; ?>" value="<?php echo $val['choices']['id']; ?>"><label for="checkbox<?php echo $val['choices']['id']; ?>"><?php echo $val['choices']['description']; ?></label>
|
||||
<?php
|
||||
if ($val['description'] == 'Other') {
|
||||
echo $html->input('issues_results/other');
|
||||
if ($val['choices']['description'] == 'Other') {
|
||||
echo $html->input('Issue/text');
|
||||
}
|
||||
?>
|
||||
<br />
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2>How can we improve <?php echo $intentions['Application']['name']; ?>?</h2>
|
||||
<h2>How can we improve <?php echo $intentions[0]['applications']['name']; ?>?</h2>
|
||||
<p>Please share your ideas, suggestions or details about any issues below.</p>
|
||||
<p><?php echo $html->textarea('Result/comments',array('id'=>'comments'));?></p>
|
||||
|
||||
|
@ -37,6 +36,5 @@
|
|||
<?php echo $html->hidden('ua', 'value="'.$url_params['ua'].'"') ?>
|
||||
<?php echo $html->hidden('lang', 'value="'.$url_params['lang'].'"') ?>
|
||||
|
||||
|
||||
<p><?php echo $html->submit('Save') ?></p>
|
||||
</form>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<h1><?php echo Inflector::humanize($this->name); ?></h1>
|
||||
|
||||
<div id="queryform">
|
||||
<?php echo $html->formTag('/results/','get'); ?>
|
||||
<?php echo $html->formTag('/results/','get');?>
|
||||
<span>
|
||||
<label for="start_date">Start Date:</label>
|
||||
<label for="start_date">Start:</label>
|
||||
<input type="text" name="start_date" id="start_date" value="<? echo isset($url_params['start_date']) ? $url_params['start_date'] : ''; ?>" />
|
||||
<label for="end_date">End Date:</label>
|
||||
<label for="end_date">End:</label>
|
||||
<input type="text" name="end_date" id="end_date" value="<? echo isset($url_params['end_date']) ? $url_params['end_date'] : ''; ?>" />
|
||||
</span>
|
||||
|
||||
|
@ -20,6 +20,24 @@
|
|||
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php if (!empty($collections)) : ?>
|
||||
<label for="collection">Questions:</label>
|
||||
<select name="collection" id="collection">
|
||||
<?php
|
||||
foreach ($collections as $select) :
|
||||
$collection = $select['collections']['description'];
|
||||
// php's built in functions won't decode UTF-8 or numeric
|
||||
// entities. Since we've only got 1, I'm putting in this to
|
||||
// get this done quickly. :(
|
||||
$url_params['collection'] = str_replace('-','-',urldecode($url_params['collection']));
|
||||
echo "{$url_params['collection']}<br />";
|
||||
$selected = ($collection == trim($url_params['collection'])) ? ' selected="selected" ' : '';
|
||||
?>
|
||||
<option<?=$selected?>><?=$collection?></option>
|
||||
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php endif; ?>
|
||||
|
||||
<input type="submit" name="submit" id="submit" value="Go" />
|
||||
</form>
|
||||
|
@ -43,7 +61,7 @@
|
|||
}
|
||||
foreach ($descriptionAndTotalsData as $var => $val) {
|
||||
// We're putting this in a js string, so escape the double quotes
|
||||
$_description = str_replace('"','\"',$val['issues']['description']);
|
||||
$_description = str_replace('"','\"',$val['choices']['description']);
|
||||
$_percentage = intval(($val[0]['total'] / $_total)*100);
|
||||
|
||||
$_dataset .= "[{$_count}, {$val[0]['total']}, \"{$_description} (n={$val[0]['total']}, {$_percentage}%)\"], ";
|
||||
|
@ -56,12 +74,12 @@
|
|||
<table class="results" summary="Firefox Uninstallation results.">
|
||||
<tr><th>Reason for uninstalling</th><th>Total</th></tr>
|
||||
<?php foreach ($descriptionAndTotalsData as $var => $val) : ?>
|
||||
<tr><td><?=$val['issues']['description']?></td><td><?=$val[0]['total']?></td></tr>
|
||||
<tr><td><?=$val['choices']['description']?></td><td><?=$val[0]['total']?></td></tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
</canvas>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
<script type="text/javascript"><!--
|
||||
var layout = new PlotKit.Layout("bar", {"barOrientation":"horizontal"});
|
||||
layout.addDataset("results", <?=$_dataset?>);
|
||||
layout.evaluate();
|
||||
|
@ -78,11 +96,17 @@
|
|||
});
|
||||
|
||||
plotter.render();
|
||||
</script>
|
||||
--></script>
|
||||
|
||||
|
||||
<div id="exportbox">
|
||||
<a href="<?php echo $export->buildUrlString('results/comments/',$url_params); ?>">View Any Associated Comments»</a><br />
|
||||
<?php
|
||||
$export_url = $export->buildCsvExportString($url_params);
|
||||
if (!empty($export_url)):
|
||||
?>
|
||||
<a href="<?php echo $export_url; ?>">Download the Complete Dataset»</a><br />
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
|
|
Загрузка…
Ссылка в новой задаче