-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathRegistrationAnswerSummaryCsv.php
More file actions
379 lines (350 loc) · 12.3 KB
/
RegistrationAnswerSummaryCsv.php
File metadata and controls
379 lines (350 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
<?php
/**
* RegistrationAnswerSummary Model
*
* @property Registration $Registration
* @property User $User
* @property RegistrationAnswer $RegistrationAnswer
*
* @author Noriko Arai <arai@nii.ac.jp>
* @author AllCreator <info@allcreator.net>
* @link http://www.netcommons.org NetCommons Project
* @license http://www.netcommons.org/license.txt NetCommons License
*/
App::uses('RegistrationsAppModel', 'Registrations.Model');
/**
* Summary for RegistrationAnswerSummary Model
*/
class RegistrationAnswerSummaryCsv extends RegistrationsAppModel {
/**
* use table
*
* @var array
*/
public $useTable = 'registration_answer_summaries';
/**
* use behaviors
*
* @var array
*/
public $actsAs = array(
'NetCommons.Trackable',
);
/**
* Validation rules
*
* @var array
*/
public $validate = array(
);
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
* belongsTo associations
*
* @var array
*/
public $belongsTo = array(
);
/**
* hasMany associations
*
* @var array
*/
public $hasMany = array(
);
/**
* Constructor. Binds the model's database table to the object.
*
* @param bool|int|string|array $id Set this ID for this model on startup,
* can also be an array of options, see above.
* @param string $table Name of database table to use.
* @param string $ds DataSource connection name.
* @see Model::__construct()
* @SuppressWarnings(PHPMD.BooleanArgumentFlag)
*/
public function __construct($id = false, $table = null, $ds = null) {
parent::__construct($id, $table, $ds);
$this->loadModels([
'Registration' => 'Registrations.Registration',
'RegistrationAnswer' => 'Registrations.RegistrationAnswer',
]);
}
/**
* getRegistrationForAnswerCsv
*
* @param int $registrationKey registration key
* @return array registration data
*/
public function getRegistrationForAnswerCsv($registrationKey) {
// 指定の登録フォームデータを取得
// CSVの取得は公開してちゃんとした登録を得ている登録フォームに限定である
$registration = $this->Registration->find('first', array(
'conditions' => array(
'Registration.block_id' => Current::read('Block.id'),
'Registration.key' => $registrationKey,
'Registration.is_active' => true,
'Registration.language_id' => Current::read('Language.id'),
),
'recursive' => -1
));
return $registration;
}
/**
* getAnswerSummaryCsv
*
* @param array $registration registration data
* @param int $limit record limit
* @param int $offset offset
* @return array
*/
public function getAnswerSummaryCsv($registration, $limit, $offset) {
// 指定された登録フォームの登録データをCsvに出力しやすい行形式で返す
$retArray = array();
// $offset == 0 のときのみヘッダ行を出す
if ($offset == 0) {
$retArray[] = $this->_putHeader($registration);
}
// $registrationにはページデータ、項目データが入っていることを前提とする
// 登録フォームのkeyを取得
$key = $registration['Registration']['key'];
// keyに一致するsummaryを取得(テストじゃない、完了している)
$summaries = $this->find('all', array(
'fields' => array('RegistrationAnswerSummaryCsv.*', 'User.handlename'),
'conditions' => array(
'answer_status' => RegistrationsComponent::ACTION_ACT,
'test_status' => RegistrationsComponent::TEST_ANSWER_STATUS_PEFORM,
'registration_key' => $key,
),
'recursive' => -1,
'joins' => array(
array(
'table' => 'users',
'alias' => 'User',
'type' => 'LEFT',
'conditions' => array(
'RegistrationAnswerSummaryCsv.user_id = User.id',
)
)
),
'limit' => $limit,
'offset' => $offset,
'order' => array('RegistrationAnswerSummaryCsv.created ASC'),
));
if (empty($summaries)) {
return $retArray;
}
// 項目のIDを取得
$questionIds = Hash::extract(
$registration['RegistrationPage'],
'{n}.RegistrationQuestion.{n}.id');
// summary loop
foreach ($summaries as $summary) {
//$answers = $summary['RegistrationAnswer'];
// 何回もSQLを発行するのは無駄かなと思いつつも
// RegistrationAnswerに登録データの取り扱いしやすい形への整備機能を組み込んであるので、それを利用したかった
// このクラスからでも利用できないかと試みたが
// AnswerとQuestionがJOINされた形でFindしないと整備機能が発動しない
// そうするためにはrecursive=2でないといけないわけだが、recursive=2にするとRoleのFindでSQLエラーになる
// 仕方ないのでこの形式で処理を行う
//$answers = $this->RegistrationAnswer->find('all', array(
// 'fields' => array('RegistrationAnswer.*', 'RegistrationQuestion.*'),
// 'conditions' => array(
// 'registration_answer_summary_id' => $summary[$this->alias]['id'],
// 'RegistrationQuestion.id' => $questionIds
// ),
// 'recursive' => -1,
// 'joins' => array(
// array(
// 'table' => 'registration_questions',
// 'alias' => 'RegistrationQuestion',
// 'type' => 'LEFT',
// 'conditions' => array(
// 'RegistrationAnswer.registration_question_key = RegistrationQuestion.key',
// )
// )
// )
//));
$answers = $this->RegistrationAnswer->getAnswersBySummary(
$summary,
$questionIds,
$this->alias);
$retArray[] = $this->_getRows($registration, $summary, $answers);
}
return $retArray;
}
/**
* _putHeader
*
* @param array $registration registration data
* @return array
*/
protected function _putHeader($registration) {
$cols = array();
$cols[] = __d('registrations', 'Registration Number');
// "登録者","登録日","回数"
$cols[] = __d('registrations', 'Respondent');
$cols[] = __d('registrations', 'Answer Date');
$cols[] = __d('registrations', 'Number');
foreach ($registration['RegistrationPage'] as $page) {
foreach ($page['RegistrationQuestion'] as $question) {
$pageNumber = $page['page_sequence'] + 1;
$questionNumber = $question['question_sequence'] + 1;
if (RegistrationsComponent::isMatrixInputType($question['question_type'])) {
$choiceSeq = 1;
foreach ($question['RegistrationChoice'] as $choice) {
if ($choice['matrix_type'] == RegistrationsComponent::MATRIX_TYPE_ROW_OR_NO_MATRIX) {
$cols[] = sprintf('%d-%d-%d. %s:%s',
$pageNumber,
$questionNumber,
$choiceSeq++,
$question['question_value'],
$choice['choice_label']);
}
}
} else {
$cols[] = sprintf('%d-%d. %s',
$pageNumber,
$questionNumber,
$question['question_value']);
}
}
}
return $cols;
}
/**
* _getRow
*
* @param array $registration registration data
* @param array $summary answer summary
* @param array $answers answer data
* @return array
*/
protected function _getRows($registration, $summary, $answers) {
// ページ、項目のループから、取り出すべき項目のIDを順番に取り出す
// question loop
// 返却用配列にquestionのIDにマッチするAnswerを配列要素として追加、Answerがないときは空文字
// なお選択肢系のものはchoice_idが登録にくっついているのでそれを削除する
// MatrixのものはMatrixの行数分返却行の列を加える
// その他の選択肢の場合は、入力されたその他のテキストを入れる
$cols = array();
$cols[] = $summary['RegistrationAnswerSummaryCsv']['serial_number'];
$cols[] = $this->_getUserName($registration, $summary);
$cols[] = $summary['RegistrationAnswerSummaryCsv']['modified'];
$cols[] = $summary['RegistrationAnswerSummaryCsv']['answer_number'];
foreach ($registration['RegistrationPage'] as $page) {
foreach ($page['RegistrationQuestion'] as $question) {
if (RegistrationsComponent::isMatrixInputType($question['question_type'])) {
foreach ($question['RegistrationChoice'] as $choice) {
if ($choice['matrix_type'] == RegistrationsComponent::MATRIX_TYPE_ROW_OR_NO_MATRIX) {
$cols[] = $this->_getMatrixAns($question, $choice, $answers);
}
}
} else {
$cols[] = $this->_getAns($question, $answers);
}
}
}
return $cols;
}
/**
* _getUserName
*
* @param array $registration registration data
* @param array $summary answer summary
* @return string
*/
protected function _getUserName($registration, $summary) {
if ($registration['Registration']['is_anonymity']) {
return __d('registrations', 'Anonymity');
}
if (empty($summary['User']['handlename'])) {
return __d('registrations', 'Guest');
}
return $summary['User']['handlename'];
}
/**
* _getAns
*
* @param array $question question data
* @param array $answers answer data
* @return string
*/
protected function _getAns($question, $answers) {
$retAns = '';
// 登録配列データの中から、現在指定された項目に該当するものを取り出す
$ans = Hash::extract(
$answers,
'{n}.RegistrationAnswer[registration_question_key=' . $question['key'] . ']');
// 登録が存在するとき処理
if (! $ans) {
// 通常の処理ではこのような場面はありえない
// 登録フォームは空登録であっても登録レコードを作成するからです
// データレコード異常があった場合のみです
// ただ、この登録を異常データだからといってオミットすると、サマリの合計数と
// 合わなくなって集計データが狂ってしまうので空登録だったように装って処理します
return $retAns;
}
$ans = $ans[0];
// 単純入力タイプのときは登録の値をそのまま返す
if (RegistrationsComponent::isOnlyInputType($question['question_type'])) {
$retAns = $ans['answer_value'];
} elseif (RegistrationsComponent::isSelectionInputType($question['question_type'])) {
// choice_id と choice_valueに分けられた登録選択肢配列を得る
// 選択されていた数分処理
foreach ($ans['answer_values'] as $choiceKey => $dividedAns) {
// idから判断して、その他が選ばれていた場合、other_answer_valueを入れる
$choice = Hash::extract(
$question['RegistrationChoice'],
'{n}[key=' . $choiceKey . ']');
if ($choice) {
$choice = $choice[0];
if ($choice['other_choice_type'] !=
RegistrationsComponent::OTHER_CHOICE_TYPE_NO_OTHER_FILED) {
$retAns .= $ans['other_answer_value'];
} else {
$retAns .= $dividedAns;
}
$retAns .= RegistrationsComponent::ANSWER_DELIMITER;
}
}
$retAns = trim($retAns, RegistrationsComponent::ANSWER_DELIMITER);
}
return $retAns;
}
/**
* _getMatrixAns
*
* @param array $question question data
* @param array $choice question choice data
* @param array $answers answer data
* @return string
*/
protected function _getMatrixAns($question, $choice, $answers) {
$retAns = '';
// 登録配列データの中から、現在指定された項目に該当するものを取り出す
// マトリクスタイプのときは複数存在する(行数分)
$anss = Hash::extract(
$answers,
'{n}.RegistrationAnswer[registration_question_key=' . $question['key'] . ']');
if (empty($anss)) {
// 通常の処理ではこのような場面はありえない
// 登録フォームは空登録であっても登録レコードを作成するからです
// データレコード異常があった場合のみです
// ただ、この登録を異常データだからといってオミットすると、サマリの合計数と
// 合わなくなって集計データが狂ってしまうので空登録だったように装って処理します
return $retAns;
}
// その中かから現在指定された選択肢行に該当するものを取り出す
$ans = Hash::extract($anss, '{n}[matrix_choice_key=' . $choice['key'] . ']');
// 登録が存在するとき処理
if ($ans) {
$ans = $ans[0];
// idから判断して、その他が選ばれていた場合、other_answer_valueを入れる
if ($choice['other_choice_type'] != RegistrationsComponent::OTHER_CHOICE_TYPE_NO_OTHER_FILED) {
$retAns = $ans['other_answer_value'] . RegistrationsComponent::ANSWER_VALUE_DELIMITER;
}
$retAns .= implode(RegistrationsComponent::ANSWER_DELIMITER, $ans['answer_values']);
}
return $retAns;
}
}