1. Jon Langevin
  2. Moodle Reports

Commits

Jon Langevin  committed 7151305

Lessened page verbosity (logs)
Added Grouped Surveys report (added 2 new views & models)
Added Google Chart image to ranked results

  • Participants
  • Parent commits 0b4bd6c
  • Branches default

Comments (0)

Files changed (16)

File protected/config/main.php

View file
  • Ignore whitespace
 			'routes'=>array(
 				array(
 					'class'=>'CFileLogRoute',
-					'levels'=>'trace, info, error, warning',
+					'levels'=>'error, warning',
 				),
                 array(
                     'class'=>'CWebLogRoute',
-					'levels'=>'trace, info, error, warning',
+					'levels'=>'error, warning',
                 ),
                 array(
                     'class'=>'CDbLogRoute',

File protected/controllers/ReportController.php

View file
  • Ignore whitespace
             'listSurveyGroups' => array(
                 'class' => 'SurveyAction',
             ),
+            'viewSurveyGroup' => array(
+                'class' => 'SurveyAction',
+            ),
             'listSurveys' => array(
                 'class' => 'SurveyAction',
             ),

File protected/controllers/report/SurveyAction.php

View file
  • Ignore whitespace
         $defaultCategories = Yii::app()->params->defaultCourseCategories;
 
         $categorySelect = $this->selectCategory($defaultCategories);
-        $_courseCategories = $categoryId>0?$categoryId:$defaultCategories;
+        $_courseCategories = $categoryId > 0 ? $categoryId : $defaultCategories;
         $courseSelect = $this->selectCourse($_courseCategories);
 
         $condCourse = new CDbCriteria;
 
         $categorySelect = $this->selectCategory($defaultCategories);
 
-        if($categoryId>0)
-            $categories = array($categoryId);
+        if ($categoryId > 0)
+            $categoriesFilter = array($categoryId);
         else
-            $categories = Yii::app()->params->defaultCourseCategories;
-        $surveyGroups = $this->filterSurveyGroups($categories);
+            $categoriesFilter = Yii::app()->params->defaultCourseCategories;
+
+        $categories = CourseCategories::model()->
+                with(
+                    array(
+                        'surveyGroups' => array(
+                            'joinType' => 'INNER JOIN',
+                        ),
+                    )
+                )->findAllByPk($categoriesFilter);
 
         $this->render('listSurveyGroups',
             array(
-                'surveyGroups'=>$surveyGroups,
-                'categorySelect'=>$categorySelect,
-                'categoryId'=>$categoryId,
+                'categories' => $categories,
+                'categorySelect' => $categorySelect,
+                'categoryId' => $categoryId,
             )
         );
     }
 
-    protected function getSurveyGroups() {
-        $sgKey = 'surveyGroups';
+    public function actionViewSurveyGroup($surveyGroupId) {
+        $surveyGroup = QuestionnaireSurveyGroups::model()->findByPk($surveyGroupId);
 
-        if(($surveyGroups = Yii::app()->cache->get($sgKey))===false) {
-            $qs = QuestionnaireSurvey::model()->tableName();
-            $q = Questionnaire::model()->tableName();
-            $c = Course::model()->tableName();
-            $cc = CourseCategories::model()->tableName();
-            $query = Yii::app()->db->createCommand()
-                ->toggleAutoMerge(true)
-                ->select($cc.'.id AS categoryId')
-                ->select($qs.'.title')
-                ->select('COUNT(DISTINCT '.$qs.'.id) AS surveyCount')
-                ->select('GROUP_CONCAT(DISTINCT '.$qs.'.id) AS surveyIds')
-                ->from($qs)
-                ->join($q, $qs.'.id = '.$q.'.sid')
-                ->join($c, $c.'.id = '.$q.'.course AND '.$c.'.visible = 1')
-                ->join($cc, $cc.'.id = '.$c.'.category AND '.$cc.'.visible = 1')
-                ->where('realm = "private"')
-                ->group($cc.'.id, '.$qs.'.title');
-            $_sg = $query->queryAll();
-
-            /**
-             * Create unique keys for each row, turn surveyIds into an array
-             */
-            $surveyGroups = array();
-            foreach($_sg AS $k=>$v) {
-                $v['surveyIds'] = explode(',', $v['surveyIds']);
-
-                $ctKey=md5($v['categoryId'].$v['title']);
-                $surveyGroups[$ctKey] = $v;
+        $questionResponses = array();
+        foreach ($surveyGroup->surveys[0]->survey->questions('questions:exists') AS $qi => $question) {
+            if (!in_array($question->type, array('input', 'choice', 'rank')))
+                continue;
+            $questionResponses[$qi] = array();
+            foreach ($surveyGroup->surveys AS $survey) {
+                $questions = $survey->survey->questions('questions:exists');
+                switch ($question->type) {
+                    case 'input':
+                        foreach ($questions[$qi]->responses AS $response) {
+                            $key = md5(strtolower(preg_replace('/[^\d\w]/', '', $response->response)));
+                            if (!isset($questionResponses[$qi][$key]))
+                                $questionResponses[$qi][$key] = array(
+                                    'content' => $response->response,
+                                    'count' => 0,
+                                );
+                            $questionResponses[$qi][$key]['count']++;
+                        }
+                        break;
+                    case 'choice':
+                        foreach ($questions[$qi]->choices AS $choice) {
+                            $key = md5(strtolower(preg_replace('/[^\d\w]/', '', $choice->content)));
+                            if (!isset($questionResponses[$qi][$key]))
+                                $questionResponses[$qi][$key] = array(
+                                    'content' => $choice->content,
+                                    'count' => 0,
+                                );
+                            $questionResponses[$qi][$key]['count'] += $choice->countResponses($question->type_id);
+                        }
+                        break;
+                    case 'rank':
+                        $skip = array();
+                        $rankOptions = array();
+                        foreach ($question->choices AS $k => $choice) {
+                            if (preg_match('/^(\d+)\=/', $choice->content, $match)) {
+                                $rankOptions[$match[1]] = str_replace($match[1].'=', '', $choice->content);
+                                $skip[] = $k;
+                            }
+                        }
+                        ksort($rankOptions);
+                        foreach ($question->choices AS $k => $choice) {
+                            if (in_array($k, $skip))
+                                continue;
+                            $key = md5(strtolower(preg_replace('/[^\d\w]/', '', $choice->content)));
+                            if (!isset($questionResponses[$qi][$key]))
+                                $questionResponses[$qi][$key] = array(
+                                    'content' => $choice->content,
+                                    'count' => 0,
+                                    'rankOptions' => $rankOptions,
+                                    'rankResults' => array_fill_keys(array_keys($rankOptions), 0),
+                                );
+                            $questionResponses[$qi][$key]['count'] += $choice->countResponses($question->type_id);
+                            if (!empty($rankOptions)) {
+                                foreach ($rankOptions AS $rank => $text) {
+                                    $questionResponses[$qi][$key]['rankResults'][$rank] += $choice->responseRankCountGroup(
+                                        array(
+                                            'condition' => 'rank=:rank',
+                                            'params' => array(':rank' => $rank),
+                                        )
+                                    );
+                                }
+                            }
+                        }
+                        break;
+                }
             }
-
-            /**
-             * Cache for one hour
-             */
-            Yii::app()->cache->set($sgKey, $surveyGroups, 60*60);
         }
 
-        return $surveyGroups;
-    }
-
-    protected function filterSurveyGroups($categories=array()) {
-        if(empty($categories))
-            return $this->surveyGroups;
-
-        $surveyGroups = array();
-        if(!empty($this->surveyGroups))
-            foreach($this->surveyGroups AS $k=>$v) {
-                if(in_array($v['categoryId'], $categories))
-                    $surveyGroups[$k] = $v;
-            }
-
-        return $surveyGroups;
+        $this->render('viewSurveyGroup',
+            array(
+                'surveyGroup' => $surveyGroup,
+                'questionResponses' => $questionResponses,
+            )
+        );
     }
 
     protected function selectCategory($categories=array()) {
         $condCategory = new CDbCriteria;
         $condCategory->addColumnCondition(array('t.visible' => 1));
-        if(!is_array($categories))
+        if (!is_array($categories))
             $categories = array($categories);
         if (!empty($categories))
             $condCategory->addInCondition('t.id', $categories);
 
     protected function selectCourse($categories=array()) {
         $condCourse = new CDbCriteria;
-        if(!is_array($categories))
+        if (!is_array($categories))
             $categories = array($categories);
         if (!empty($categories))
             $condCourse->addInCondition('t.category', $categories);
         $condCourse->addColumnCondition(array('t.visible' => 1));
         $condCourse->addColumnCondition(array('courseCategory.visible' => 1));
         $condCourse->with = array(
-            'courseCategory' => array('joinType' => 'INNER JOIN', 'together'=>true),
+            'courseCategory' => array('joinType' => 'INNER JOIN', 'together' => true),
             'questionnaires.survey' => array('joinType' => 'INNER JOIN'),
         );
         $condCourse->order = 't.fullname ASC';

File protected/models/Course.php

View file
  • Ignore whitespace
 		);
 	}
 
+    public function defaultScope() {
+        $array = parent::defaultScope();
+        $array['alias'] = 'course';
+        return $array;
+    }
+
     public function scopes() {
         return array(
-            'visible'=>array('condition'=>'visible = 1'),
+            'visible'=>array('condition'=>'course.visible = 1'),
         );
     }
 

File protected/models/CourseCategories.php

View file
  • Ignore whitespace
 		// class name for the relations automatically generated below.
 		return array(
             'courses' => array(self::HAS_MANY, 'Course', 'category'),
-            /**
-             * @todo add scopes
-             */
-            'surveyGroups' => array(self::HAS_MANY, 'Course', 'category',
-                'with'=>array(
-                    'courses.questionnaires'=>array(
-                        '',
-                    ),
-                ),
-            ),
+            'surveyGroups' => array(self::HAS_MANY, 'QuestionnaireSurveyGroups', 'cc_id'),
 		);
 	}
 
+    public function defaultScope() {
+        $array = parent::defaultScope();
+        $array['alias'] = 'coursecategories';
+        return $array;
+    }
+
     public function scopes() {
         return array(
-            'visible'=>array('condition'=>'visible = 1'),
+            'visible'=>array('condition'=>'coursecategories.visible = 1'),
         );
     }
 

File protected/models/Questionnaire.php

View file
  • Ignore whitespace
 		// NOTE: you may need to adjust the relation name and the related
 		// class name for the relations automatically generated below.
 		return array(
-            'course' => array(self::BELONGS_TO, 'Course', 'course'),
+            'qCourse' => array(self::BELONGS_TO, 'Course', 'course'),
             'survey' => array(self::BELONGS_TO, 'QuestionnaireSurvey', 'sid'),
 		);
 	}

File protected/models/QuestionnaireSurvey.php

View file
  • Ignore whitespace
                 'order'=>'questions.position ASC'),
             'responses' => array(self::HAS_MANY, 'QuestionnaireResponse', 'survey_id'),
             'responseCount' => array(self::STAT, 'QuestionnaireResponse', 'survey_id'),
+            'surveyGroups' => array(self::HAS_MANY, 'QuestionnaireSurveyGroupIds', 'qs_id'),
 		);
 	}
 
+    public function defaultScope() {
+        $array = parent::defaultScope();
+        $array['alias'] = 'questionnairesurvey';
+        return $array;
+    }
+
     public function scopes() {
         return array(
-            'private'=>array('condition'=>'realm = "private"'),
+            'private'=>array('condition'=>'questionnairesurvey.realm = "private"'),
         );
     }
 

File protected/models/QuestionnaireSurveyGroupIds.php

View file
  • Ignore whitespace
+<?php
+
+/**
+ * This is the model class for table "questionnaire_survey_group_ids".
+ *
+ * @todo Need to add code to create view if not exist
+ *
+ * The followings are the available columns in table 'questionnaire_survey_group_ids':
+ * @property string $cc_id
+ * @property string $qs_id
+ * @property string $qs_title
+ * @property string $md5_id
+ */
+class QuestionnaireSurveyGroupIds extends Model
+{
+	/**
+	 * Returns the static model of the specified AR class.
+	 * @return QuestionnaireSurveyGroups the static model class
+	 */
+	public static function model($className=__CLASS__)
+	{
+		return parent::model($className);
+	}
+
+    public function primaryKey() {
+        return array('cc_id', 'qs_id');
+    }
+
+	/**
+	 * @return string the associated database table name
+	 */
+	public function tableName()
+	{
+		return 'questionnaire_survey_group_ids';
+	}
+
+	/**
+	 * @return array validation rules for model attributes.
+	 */
+	public function rules()
+	{
+		// NOTE: you should only define rules for those attributes that
+		// will receive user inputs.
+		return array(
+			array('cc_id, qs_id', 'length', 'max'=>10),
+			array('qs_title', 'length', 'max'=>255),
+			array('md5_id', 'length', 'max'=>32),
+			// The following rule is used by search().
+			// Please remove those attributes that should not be searched.
+			array('cc_id, qs_id, qs_title, md5_id', 'safe', 'on'=>'search'),
+		);
+	}
+
+	/**
+	 * @return array relational rules.
+	 */
+	public function relations()
+	{
+		// NOTE: you may need to adjust the relation name and the related
+		// class name for the relations automatically generated below.
+		return array(
+            'category' => array(self::BELONGS_TO, 'CourseCategories', 'cc_id'),
+            'surveyGroup' => array(self::BELONGS_TO, 'QuestionnaireSurveyGroups', 'md5_id'),
+            'survey' => array(self::BELONGS_TO, 'QuestionnaireSurvey', 'qs_id'),
+		);
+	}
+
+    public function defaultScope() {
+        return array(
+            'order'=>'cc_id ASC',
+        );
+    }
+
+	/**
+	 * @return array customized attribute labels (name=>label)
+	 */
+	public function attributeLabels()
+	{
+		return array(
+			'cc_id' => 'Category ID',
+			'qs_id' => 'Survey ID',
+			'qs_title' => 'Survey Title',
+			'md5_id' => 'Group ID',
+		);
+	}
+
+	/**
+	 * Retrieves a list of models based on the current search/filter conditions.
+	 * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
+	 */
+	public function search()
+	{
+		// Warning: Please modify the following code to remove attributes that
+		// should not be searched.
+
+		$criteria=new CDbCriteria;
+
+		$criteria->compare('cc_id',$this->cc_id,true);
+		$criteria->compare('qs_id',$this->qs_id,true);
+		$criteria->compare('qs_title',$this->qs_title,true);
+		$criteria->compare('md5_id',$this->md5_id,true);
+
+		return new CActiveDataProvider(get_class($this), array(
+			'criteria'=>$criteria,
+		));
+	}
+}

File protected/models/QuestionnaireSurveyGroups.php

View file
  • Ignore whitespace
+<?php
+
+/**
+ * This is the model class for table "questionnaire_survey_groups".
+ *
+ * @todo Need to add code to create view if not exist
+ *
+ * The followings are the available columns in table 'questionnaire_survey_groups':
+ * @property string $md5_id
+ * @property string $cc_id
+ * @property string $qs_title
+ */
+class QuestionnaireSurveyGroups extends Model
+{
+    /**
+     * Returns the static model of the specified AR class.
+     * @return QuestionnaireSurveyGroups the static model class
+     */
+    public static function model($className=__CLASS__)
+    {
+        return parent::model($className);
+    }
+
+    public function primaryKey() {
+        return 'md5_id';
+    }
+
+    /**
+     * @return string the associated database table name
+     */
+    public function tableName()
+    {
+        return 'questionnaire_survey_groups';
+    }
+
+    /**
+     * @return array validation rules for model attributes.
+     */
+    public function rules()
+    {
+        // NOTE: you should only define rules for those attributes that
+        // will receive user inputs.
+        return array(
+            array('md5_id', 'length', 'max'=>32),
+            array('cc_id', 'length', 'max'=>10),
+            array('qs_title', 'length', 'max'=>255),
+            // The following rule is used by search().
+            // Please remove those attributes that should not be searched.
+            array('md5_id, cc_id, qs_title', 'safe', 'on'=>'search'),
+        );
+    }
+
+    /**
+     * @return array relational rules.
+     */
+    public function relations()
+    {
+        // NOTE: you may need to adjust the relation name and the related
+        // class name for the relations automatically generated below.
+        return array(
+            'category' => array(self::BELONGS_TO, 'CourseCategories', 'cc_id'),
+            'surveys' => array(self::HAS_MANY, 'QuestionnaireSurveyGroupIds', 'md5_id'),
+        );
+    }
+
+    /**
+     * @return array customized attribute labels (name=>label)
+     */
+    public function attributeLabels()
+    {
+        return array(
+            'md5_id' => 'Unique ID',
+            'cc_id' => 'Category ID',
+            'qs_title' => 'Survey Title',
+        );
+    }
+
+    /**
+     * Retrieves a list of models based on the current search/filter conditions.
+     * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
+     */
+    public function search()
+    {
+        // Warning: Please modify the following code to remove attributes that
+        // should not be searched.
+
+        $criteria=new CDbCriteria;
+
+        $criteria->compare('md5_id',$this->md5_id,true);
+        $criteria->compare('cc_id',$this->cc_id,true);
+        $criteria->compare('qs_title',$this->qs_title,true);
+
+        return new CActiveDataProvider(get_class($this), array(
+            'criteria'=>$criteria,
+        ));
+    }
+}

File protected/views/report/index.php

View file
  • Ignore whitespace
     <li>
         <?php echo CHtml::link('List Surveys', array('report/listSurveys')); ?>
     </li>
+    <li>
+        <?php echo CHtml::link('List Grouped Survey Results', array('report/listSurveyGroups')); ?>
+    </li>
 </ul>

File protected/views/report/survey/_responseGroup.php

View file
  • Ignore whitespace
+<?php
+switch($question->type){
+    case 'input':
+        $responseType = 'user input';
+        break;
+    case 'choice':
+        $responseType = 'selection';
+        break;
+    case 'rank':
+        $responseType = 'rate each option';
+        break;
+}
+?>
+- (<?php echo $responseType; ?>)
+<ul>
+    <?php
+    foreach($responses AS $response):
+        ?>
+    <li>
+    <?php echo stripslashes(strip_tags($response['content'])); ?>
+    <?php
+    if($question->type != 'rank'):
+        ?> - <b><?php echo $response['count']; ?></b><?php
+    elseif($question->type == 'rank'):
+        ?><br />
+        <?php
+        krsort($response['rankResults']);
+        ksort($response['rankOptions']);
+        $chart = array(
+            'chxr'=>'0,0,'.$response['count'].'|1,1,'.count($response['rankOptions']),
+            'chxt'=>'x,y',
+            'chbh'=>'a',
+            'chs'=>'300x100',
+            'cht'=>'bhs',
+            'chco'=>'3399CC',
+            'chds'=>'0,'.$response['count'],
+            'chd'=>'t:'.implode(',',$response['rankResults']),
+            'chxl'=>'1:|'.CHtml::encode(implode('|',$response['rankOptions'])),
+        );
+        $chartAPI = 'http://chart.apis.google.com/chart?' . http_build_query($chart);
+        ?>
+        <img src="<?php echo $chartAPI; ?>" width="300" height="100" alt="" />
+        <?php
+    endif;
+    ?>
+    </li>
+        <?php
+    endforeach;
+    ?>
+</ul>

File protected/views/report/survey/_responseRank.php

View file
  • Ignore whitespace
     $rankOptions = array();
     foreach($question->choices AS $k=>$choice) {
         if(preg_match('/^(\d+)\=/',$choice->content, $match)) {
-            $rankOptions[$match[1]] = $choice->content;
+            $rankOptions[$match[1]] = str_replace($match[1].'=', '', $choice->content);
             $skip[] = $k;
         }
     }
             continue;
         ?>
     <li>
-    <?php echo $choice->content; ?> - <b><?php echo $choice->countResponses($question->type_id); ?></b> responses
-    <?php if(!empty($rankOptions)): ?>
-        <ul>
-            <?php foreach($rankOptions AS $rank=>$text): ?>
-            <li>
-                <?php echo str_replace($rank.'=', '', $text); ?> -
-                <b><?php
-                echo $choice->responseRankCountGroup(
-                    array(
-                        'condition'=>'rank=:rank',
-                        'params'=>array(':rank'=>$rank),
-                    )
-                );
-                ?></b>
-            </li>
-            <?php endforeach; ?>
-        </ul>
+    <?php echo $choice->content; ?><br />
+    <?php if(!empty($rankOptions)):
+        $rankResults = array_fill_keys(array_keys($rankOptions), 0);
+        foreach($rankOptions AS $rank=>$text){
+            $rankResults[$rank] = $choice->responseRankCountGroup(
+                array(
+                    'condition'=>'rank=:rank',
+                    'params'=>array(':rank'=>$rank),
+                )
+            );
+        }
+
+        krsort($rankResults);
+        ksort($rankOptions);
+        $chart = array(
+            'chxr'=>'0,0,'.$choice->countResponses($question->type_id).'|1,1,'.count($rankOptions),
+            'chxt'=>'x,y',
+            'chbh'=>'a',
+            'chs'=>'200x100',
+            'cht'=>'bhs',
+            'chco'=>'3399CC',
+            'chds'=>'0,'.$choice->countResponses($question->type_id),
+            'chd'=>'t:'.implode(',',$rankResults),
+            'chxl'=>'1:|'.CHtml::encode(implode('|',$rankOptions)),
+        );
+        $chartAPI = 'http://chart.apis.google.com/chart?' . http_build_query($chart);
+        ?>
+        <img src="<?php echo $chartAPI; ?>" width="200" height="100" alt="" />
     <?php endif; ?>
     </li>
         <?php

File protected/views/report/survey/listSurveyGroups.php

View file
  • Ignore whitespace
 $this->pageTitle='Reports :: List Survey Groups';
 $this->breadcrumbs=array(
     'Reports'=>array('report/'),
-    'List Surveys',
+    'List Survey Groups',
 );
 ?>
 
 echo CHtml::endForm();
 ?><br />
 
-Filter by Course:
-<?php
-echo CHtml::form(array('report/listSurveyGroups'), 'get');
-echo CHtml::dropDownList(
-    'courseId',
-    $courseId,
-    CHtml::listData(
-        $courseSelect,
-        'id',
-        'fullname'
-    ),
-    array(
-        'prompt'=>'',
-        'submit'=>array('report/listSurveyGroups'),
-        'type'=>'get',
-    )
-);
-echo CHtml::endForm();
-?><br />
-<br />
-
 <?php
 if(empty($categories)):
     ?>
 foreach($categories AS $category):
     ?>
     <li>
-        <b><?php echo $category->name; ?></b>
+        <b><?php echo CHtml::link($category->name,
+            array('report/listSurveyGroups', 'categoryId'=>$category->id)); ?></b>
         <ul>
             <?php
-            // @todo NOT DONE
-            foreach($surveyGroups AS $k=>$v):
+            foreach($category->surveyGroups AS $surveyGroup):
                 ?>
-            <li><?php echo CHtml::encode($v['title']); ?></li>
+            <li><?php echo CHtml::link($surveyGroup->qs_title,
+            array('report/viewSurveyGroup', 'surveyGroupId'=>$surveyGroup->md5_id)); ?></li>
                 <?php
             endforeach;
             ?>

File protected/views/report/survey/listSurveys.php

View file
  • Ignore whitespace
 foreach($categories AS $category):
     ?>
     <li>
-        <b><?php echo $category->name; ?></b>
+        <b><?php echo CHtml::link($category->name,
+            array('report/listSurveys', 'categoryId'=>$category->id)); ?></b>
         <?php if(!empty($category->courses)): ?>
         <ul>
         <?php
         foreach($category->courses AS $course):
             ?>
             <li>
+            <?php /*echo CHtml::link($course->fullname,
+            array('report/listSurveys', 'courseId'=>$course->id));*/ ?>
             <?php echo $course->fullname; ?>
                 <?php if(!empty($course->questionnaires)): ?>
                 <ul>

File protected/views/report/survey/viewSurvey.php

View file
  • Ignore whitespace
 );
 ?>
 
-<h3><?php echo $questionnaire->survey->title; ?></h3>
+<h3><?php echo CHtml::link($questionnaire->qCourse->fullname,
+    array('report/listSurveys', 'courseId'=>$questionnaire->qCourse->id)); ?></h3>
+<h4><?php echo $questionnaire->survey->title; ?></h4>
 
 <?php if(!empty($questionnaire->survey->questions)): ?>
 <ol>
     if($question->type=='label'):
         ?>
 </ol>
-<h4><?php echo strip_tags($question->content); ?></h4>
+<h5><?php echo strip_tags($question->content); ?></h5>
 <ol>
         <?php
         continue;

File protected/views/report/survey/viewSurveyGroup.php

View file
  • Ignore whitespace
+<?php
+$this->pageTitle='Report :: Survey Group :: ' . $surveyGroup->qs_title;
+$this->breadcrumbs=array(
+    'Reports'=>array('report/'),
+    'List Survey Groups'=>array('report/listSurveyGroups'),
+	$surveyGroup->qs_title,
+);
+?>
+
+<h3><?php echo CHtml::link($surveyGroup->category->name,
+    array('report/listSurveyGroups', 'categoryId'=>$surveyGroup->category->id)); ?></h3>
+<h4><?php echo $surveyGroup->qs_title; ?></h4>
+
+<ol>
+<?php
+/**
+ * Run through all questions for the first survey
+ * Use first survey to render questions/answers from all surveys
+ */
+foreach($surveyGroup->surveys[0]->survey->questions('questions:exists') AS $qi=>$question):
+    if($question->type=='label'):
+        ?>
+</ol>
+<h5><?php echo strip_tags($question->content); ?></h5>
+<ol>
+        <?php
+        continue;
+    endif;
+    ?>
+    <li>
+        <b><?php echo strip_tags($question->content); ?></b>
+        <?php
+        $this->renderPartial('survey/_responseGroup', array(
+            'question'=>$question,
+            'responses'=>$questionResponses[$qi],
+            )
+        );
+        ?>
+    </li>
+    <?php
+endforeach;
+?>
+</ol>