COMMENTLIST::display()   B
last analyzed

Complexity

Conditions 10
Paths 5

Size

Total Lines 41
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
cc 10
eloc 16
nc 5
nop 3
dl 0
loc 41
rs 7.6666
c 0
b 0
f 0
ccs 0
cts 14
cp 0
crap 110

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*	 The class for displaying one or more comments.
4
    (There's also a function for adding a new comment to the DB because I wasn't
5
    sure where else to put it!).
6
7
    This works similarly to the HANSARDLIST class.
8
9
    To display all the comments for an epobject you'll do:
10
11
        $args = array ('epobject_id' => $epobject_id);
12
        $COMMENTLIST = new COMMENTLIST;
13
        $COMMENTLIST->display ('ep', $args);
14
15
    This will call the _get_data_by_ep() function which passes variables to the
16
    _get_comment_data() function. This gets the comments from the DB and returns
17
    an array of comments.
18
19
    The render() function is then called, which includes a template and
20
    goes through the array, displaying the comments. See the HTML comments.php
21
    template for the format.
22
    NOTE: You'll need to pass the 'body' of the comment through filter_user_input()
23
    and linkify() first.
24
25
    You could also just call the $COMMENTLIST->render() array with an array
26
    of comment data and display directly (used for previewing user input).
27
28
*/
29
30
class COMMENTLIST {
31
    public function __construct() {
32
        global $this_page;
33
34
        $this->db = new ParlDB();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
35
36
        // We use this to create permalinks to comments. For the moment we're
37
        // assuming they're on the same page we're currently looking at:
38
        // debate, wran, etc.
39
        $this->page = $this_page;
0 ignored issues
show
Bug Best Practice introduced by
The property page does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
40
41
    }
42
43
44
    public function display($view, $args = [], $format = 'html') {
45
        // $view is what we're viewing by:
46
        //	'ep' is all the comments attached to an epobject.
47
        //	'user' is all the comments written by a user.
48
        //	'recent' is the most recent comments.
49
50
        // $args is an associative array of stuff like
51
        //	'epobject_id' => '37'
52
        // Where 'epobject_id' is an epobject_id.
53
        // Or 'gid' is a hansard item gid.
54
55
        // Replace a hansard object gid with an epobject_id.
56
        //		$args = $this->_fix_gid($args);
57
58
        // $format is the format the data should be rendered in.
59
60
        if ($view == 'ep' || $view == 'user' || $view == 'recent' || $view == 'search' || $view == 'dates') {
61
            // What function do we call for this view?
62
            $function = '_get_data_by_' . $view;
63
            // Get all the dta that's to be rendered.
64
            $data = $this->$function($args);
65
66
        } else {
67
            // Don't have a valid $view;
68
            $PAGE->error_message("You haven't specified a view type.");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $PAGE seems to be never defined.
Loading history...
69
            return false;
70
        }
71
72
        if ($view == 'user') {
73
            $template = 'comments_user';
74
        } elseif ($view == 'recent' or $view == 'dates') {
75
            $template = 'comments_recent';
76
        } elseif ($view == 'search') {
77
            $template = 'comments_search';
78
        } else {
79
            $template = 'comments';
80
        }
81
82
        $this->render($data, $format, $template);
83
84
        return true;
85
    }
86
87
    public function render($data, $format = 'html', $template = 'comments') {
88
        include(INCLUDESPATH . "easyparliament/templates/$format/$template.php");
89
    }
90
91
    public function _get_data_by_ep($args) {
92
        // Get all the data attached to an epobject.
93
        global $PAGE;
94
95
        twfy_debug(get_class($this), "getting data by epobject");
96
97
        // What we return.
98
        $data = [];
99
        if (!is_numeric($args['epobject_id'])) {
100
            $PAGE->error_message("Sorry, we don't have a valid epobject id");
101
            return $data;
102
        }
103
104
        // For getting the data.
105
        $input =  [
106
            'amount' =>  [
107
                'user' => true,
108
            ],
109
            'where' =>  [
110
                'comments.epobject_id=' => $args['epobject_id'],
111
                #'visible=' => '1'
112
            ],
113
            'order' => 'posted ASC',
114
        ];
115
116
        $commentsdata = $this->_get_comment_data($input);
117
118
        $data['comments'] = $commentsdata;
119
120
        if (isset($args['user_id']) && $args['user_id'] != '') {
121
            // We'll pass this on to the template so it can highlight the user's comments.
122
            $data['info']['user_id'] = $args['user_id'];
123
        }
124
125
        return $data;
126
127
    }
128
129
130
131
    public function _get_data_by_user($args) {
132
        // Get a user's most recent comments.
133
        // Could perhaps be modified to get different lists of a user's
134
        // comments by things in $args?
135
        global $PAGE;
136
137
        twfy_debug(get_class($this), "getting data by user");
138
139
        // What we return.
140
        $data = [];
141
142
        if (!is_numeric($args['user_id'])) {
143
            $PAGE->error_message("Sorry, we don't have a valid user id");
144
            return $data;
145
        }
146
147
        if (isset($args['num']) && is_numeric($args['num'])) {
148
            $num = $args['num'];
149
        } else {
150
            $num = 10;
151
        }
152
153
        if (isset($args['page']) && is_numeric($args['page']) && $args['page'] > 1) {
154
            $page = $args['page'];
155
        } else {
156
            $page = 1;
157
        }
158
159
        $limit = $num * ($page - 1) . ',' . $num;
160
161
        // We're getting the most recent comments posted to epobjects.
162
        // We're grouping them by epobject so we can just link to each hansard thing once.
163
        // When there are numerous comments on an epobject we're getting the most recent
164
        // 		comment_id and posted date.
165
        // We're getting the body details for the epobject.
166
        // We're NOT getting the comment bodies. Why? Because adding them to this query
167
        // would fetch the text for the oldest comment on an epobject group, rather
168
        // than the most recent. So we'll get the comment bodies later...
169
        $q = $this->db->query(
170
            "SELECT MAX(comments.comment_id) AS comment_id,
171
                                MAX(comments.posted) AS posted,
172
                                COUNT(*) AS total_comments,
173
                                comments.epobject_id,
174
                                hansard.major,
175
                                hansard.gid,
176
                                users.firstname,
177
                                users.lastname,
178
                                epobject.body
179
                        FROM 	comments
180
                            join hansard  on comments.epobject_id = hansard.epobject_id
181
                            join users    on comments.user_id = users.user_id
182
                            join epobject on comments.epobject_id = epobject.epobject_id
183
                        where	users.user_id=:user_id
184
                        AND 	visible='1'
185
                        GROUP BY epobject_id
186
                        ORDER BY posted DESC
187
                        LIMIT " . $limit,
188
            [':user_id' => $args['user_id']]
189
        );
190
191
        $comments = [];
192
        $comment_ids = [];
193
194
        if ($q->rows() > 0) {
195
196
            foreach ($q as $row) {
197
198
                $urldata = [
199
                    'major' => $row['major'],
200
                    'gid' => $row['gid'],
201
                    'comment_id' => $row['comment_id'],
202
                    'user_id' => $args['user_id'],
203
                ];
204
205
                $comments[] = [
206
                    'comment_id' => $row['comment_id'],
207
                    'posted' => $row['posted'],
208
                    'total_comments' => $row['total_comments'],
209
                    'epobject_id' => $row['epobject_id'],
210
                    'firstname' => $row['firstname'],
211
                    'lastname' => $row['lastname'],
212
                    // Hansard item body, not comment body.
213
                    'hbody' => $row['body'],
214
                    'url' => $this->_comment_url($urldata),
215
                ];
216
217
                // We'll need these for getting the comment bodies.
218
                $comment_ids[] = $row['comment_id'];
219
220
            }
221
222
            $in = implode(', ', $comment_ids);
223
224
            $r = $this->db->query("SELECT comment_id,
225
                                    body
226
                            FROM	comments
227
                            WHERE	comment_id IN ($in)
228
                            ");
229
230
            if ($r->rows() > 0) {
231
232
                $commentbodies = [];
233
234
                foreach ($r as $row2) {
235
                    $commentbodies[$row2['comment_id']] = $row2['body'];
236
                }
237
238
                // This does rely on both this and the previous query returning
239
                // stuff in the same order...
240
                foreach ($comments as $n => $commentdata) {
241
                    $comments[$n]['body'] = $commentbodies[ $comments[$n]['comment_id'] ];
242
                }
243
            }
244
        }
245
246
        $data['comments'] = $comments;
247
        $data['results_per_page'] = $num;
248
        $data['page'] = $page;
249
        $q = $this->db->query('SELECT COUNT(DISTINCT(epobject_id)) AS count FROM comments WHERE visible=1 AND user_id=' . $args['user_id'])->first();
250
        $data['total_results'] = $q['count'];
251
        return $data;
252
253
    }
254
255
256
257
    public function _get_data_by_recent($args) {
258
        // $args should contain 'num', indicating how many to get.
259
        // and perhaps pid too, for a particular person
260
261
        twfy_debug(get_class($this), "getting data by recent");
262
263
        // What we return.
264
        $data = [];
265
266
        if (isset($args['num']) && is_numeric($args['num'])) {
267
            $num = $args['num'];
268
        } else {
269
            $num = 25;
270
        }
271
272
        if (isset($args['page']) && is_numeric($args['page'])) {
273
            $page = $args['page'];
274
        } else {
275
            $page = 1;
276
        }
277
278
        $limit = $num * ($page - 1) . ',' . $num;
279
280
        $where = [
281
            'visible=' => '1',
282
        ];
283
        if (isset($args['pid']) && is_numeric($args['pid'])) {
284
            $where['person_id='] = $args['pid'];
285
        }
286
        $input =  [
287
            'amount' =>  [
288
                'user' => true,
289
            ],
290
            'where'  => $where,
291
            'order' => 'posted DESC',
292
            'limit' => $limit,
293
        ];
294
295
        $commentsdata = $this->_get_comment_data($input);
296
297
        $data['comments'] = $commentsdata;
298
        $data['results_per_page'] = $num;
299
        $data['page'] = $page;
300
        $params = [];
301
        if (isset($args['pid']) && is_numeric($args['pid'])) {
302
            $data['pid'] = $args['pid'];
303
            $q = 'SELECT title, given_name, family_name, lordofname, house FROM member m, person_names p WHERE m.person_id=p.person_id AND p.type="name" AND left_house="9999-12-31" AND m.person_id = :pid';
304
            $q = $this->db->query($q, [':pid' => $args['pid']])->first();
305
            $data['full_name'] = member_full_name($q['house'], $q['title'], $q['given_name'], $q['family_name'], $q['lordofname']);
306
            $q = 'SELECT COUNT(*) AS count FROM comments,hansard WHERE visible=1 AND comments.epobject_id = hansard.epobject_id and hansard.person_id = :pid';
307
            $params[':pid'] = $args['pid'];
308
        } else {
309
            $q = 'SELECT COUNT(*) AS count FROM comments WHERE visible=1';
310
        }
311
        $q = $this->db->query($q, $params)->first();
312
        $data['total_results'] = $q['count'];
313
        return $data;
314
    }
315
316
    public function _get_data_by_dates($args) {
317
        // $args should contain start_date and end_date
318
319
        twfy_debug(get_class($this), "getting data by recent");
320
        $data = [];
321
        $where = [
322
            'visible=' => '1',
323
            'date(posted)>=' => $args['start_date'],
324
            'date(posted)<=' => $args['end_date'],
325
        ];
326
        $input =  [
327
            'amount' =>  [
328
                'user' => true,
329
            ],
330
            'where'  => $where,
331
            'order'  => 'posted DESC',
332
        ];
333
        $commentsdata = $this->_get_comment_data($input);
334
        $data['comments'] = $commentsdata;
335
        return $data;
336
    }
337
338
    public function _get_data_by_search($args) {
339
        // $args should contain 'num', indicating how many to get.
340
341
        twfy_debug(get_class($this), "getting data by search");
342
343
        // What we return.
344
        $data = [];
345
346
        if (isset($args['num']) && is_numeric($args['num'])) {
347
            $num = $args['num'];
348
        } else {
349
            $num = 10;
350
        }
351
352
        if (isset($args['page']) && is_numeric($args['page'])) {
353
            $page = $args['page'];
354
        } else {
355
            $page = 1;
356
        }
357
358
        $limit = $num * ($page - 1) . ',' . $num;
359
360
        $input =  [
361
            'amount' =>  [
362
                'user' => true,
363
            ],
364
            'where'  =>  [
365
                'comments.body LIKE' => "%$args[s]%",
366
            ],
367
            'order' => 'posted DESC',
368
            'limit' => $limit,
369
        ];
370
371
        $commentsdata = $this->_get_comment_data($input);
372
373
        $data['comments'] = $commentsdata;
374
        $data['search'] = $args['s'];
375
        #		$data['results_per_page'] = $num;
376
        #		$data['page'] = $page;
377
        #		$q = $this->db->query('SELECT COUNT(*) AS count FROM comments WHERE visible=1')->first();
378
        #		$data['total_results'] = $q['count'];
379
        return $data;
380
    }
381
382
383
    public function _comment_url($urldata) {
384
        global $hansardmajors;
385
386
        // Pass it the major and gid of the comment's epobject and the comment_id.
387
        // And optionally the user's id, for highlighting the comments on the destination page.
388
        // It returns the URL for the comment.
389
390
        $major 		= $urldata['major'];
391
        $gid 		= $urldata['gid'];
392
        $comment_id = $urldata['comment_id'];
393
        $user_id = $urldata['user_id'] ?? false;
394
395
        // If you change stuff here, you might have to change it in
396
        // $COMMENT->_set_url() too...
397
398
        // We'll generate permalinks for each comment.
399
        // Assuming every comment is from the same major...
400
        $page = $hansardmajors[$major]['page'];
401
402
        $URL = new \MySociety\TheyWorkForYou\Url($page);
403
404
        $gid = fix_gid_from_db($gid); // In includes/utility.php
405
        $URL->insert(['id' => $gid ]);
406
        if ($user_id) {
407
            $URL->insert(['u' => $user_id]);
408
        }
409
        $url = $URL->generate() . '#c' . $comment_id;
410
411
        return $url;
412
    }
413
414
415
416
    /*	function _fix_gid($args) {
417
418
            // Replace a hansard object gid with an epobject_id.
419
            // $args may have a 'gid' element. If so, we replace it
420
            // with the hansard object's epobject_id as 'epobject_id', because
421
            // comments are tied to epobject_ids.
422
            // Returns the corrected $args array.
423
424
            global $this_page;
425
426
            if (isset($args['gid']) && !isset($args['epobject_id'])) {
427
428
                if ($this_page == 'wran' || $this_page == 'wrans') {
429
                    $gidextra = 'wrans';
430
                } else {
431
                    $gidextra = 'debate';
432
                }
433
434
                $q = $this->db->query ("SELECT epobject_id FROM hansard WHERE gid = 'uk.org.publicwhip/" . $gidextra . '/' . addslashes($args['gid']) . "'")->first();
435
436
                if ($q) {
437
                    unset($args['gid']);
438
                    $args['epobject_id'] = $q['epobject_id'];
439
                }
440
            }
441
442
            return $args;
443
444
        }
445
        */
446
447
    public function _get_comment_data($input) {
448
        // Generic function for getting hansard data from the DB.
449
        // It returns an empty array if no data was found.
450
        // It returns an array of items if 1 or more were found.
451
        // Each item is an array of key/value pairs.
452
        // eg:
453
        /*
454
            array (
455
                0	=> array (
456
                    'comment_id'	=> '2',
457
                    'user_id'		=> '10',
458
                    'body'			=> 'The text of the comment is here.',
459
                    etc...
460
                ),
461
                1	=> array (
462
                    'comment_id'	=> '3',
463
                    etc...
464
                )
465
            );
466
        */
467
468
        // $input is an array of things needed for the SQL query:
469
        // 'amount' has one or more of :
470
        //		'user'=>true - Users' names.
471
        //  	'hansard'=>true - Body text from the hansard items.
472
        // 'where' is an associative array of stuff for the WHERE clause, eg:
473
        // 		array ('id=' => '37', 'posted>' => '2003-12-31 00:00:00');
474
        // 'order' is a string for the $order clause, eg 'hpos DESC'.
475
        // 'limit' as a string for the $limit clause, eg '21,20'.
476
477
        $amount = $input['amount'] ?? [];
478
        $wherearr = $input['where'];
479
        $order = $input['order'] ?? '';
480
        $limit = $input['limit'] ?? '';
481
482
        // The fields to fetch from db. 'table' => array ('field1', 'field2').
483
        $fieldsarr =  [
484
            'comments' =>  ['comment_id', 'user_id', 'epobject_id', 'body', 'posted', 'modflagged', 'visible'],
485
            'hansard' =>  ['major', 'gid'],
486
        ];
487
488
        // Yes, we need the gid of a comment's associated hansard object
489
        // to make the comment's URL. And we have to go via the epobject
490
        // table to do that.
491
        $join = 'INNER JOIN epobject ON comments.epobject_id = epobject.epobject_id
492
                    INNER JOIN hansard ON comments.epobject_id = hansard.epobject_id';
493
494
        // Add on the stuff for getting a user's details.
495
        if (isset($amount['user']) && $amount['user'] == true) {
496
            $fieldsarr['users'] =  ['firstname', 'lastname', 'user_id'];
497
            // Like doing "FROM comments, users" but it's easier to add
498
            // an "INNER JOIN..." automatically to the query.
499
            $join .= ' INNER JOIN users ON comments.user_id = users.user_id ';
500
        }
501
502
        // Add on that we need to get the hansard item's body.
503
        if (isset($amount['hansard']) && $amount['hansard'] == true) {
504
            $fieldsarr['epobject'] = ['body'];
505
        }
506
507
        $fieldsarr2 =  [];
508
        // Construct the $fields clause.
509
        foreach ($fieldsarr as $table => $tablesfields) {
510
            foreach ($tablesfields as $n => $field) {
511
                // HACK.
512
                // If we're getting the body of a hansard object, we need to
513
                // get it AS 'hbody', so we don't confuse with the comment's 'body'
514
                // element.
515
                if ($table == 'epobject' && $field == 'body') {
516
                    $field .= ' AS hbody';
517
                }
518
                $fieldsarr2[] = $table . '.' . $field;
519
            }
520
        }
521
        $fields = implode(', ', $fieldsarr2);
522
523
524
        $wherearr2 =  [];
525
        $params = [];
526
        $i = 0;
527
        // Construct the $where clause.
528
        foreach ($wherearr as $key => $val) {
529
            $wherearr2[] = "$key :where$i";
530
            $params[":where$i"] = $val;
531
            $i++;
532
        }
533
        $where = implode(" AND ", $wherearr2);
534
535
        if ($order != '') {
536
            $order = "ORDER BY $order";
537
        }
538
        if ($limit != '') {
539
            # Can't use parameter as >1 argument
540
            $limit = "LIMIT $limit";
541
        }
542
543
        // Finally, do the query!
544
        $q = $this->db->query("SELECT $fields
545
                        FROM 	comments
546
                        $join
547
                        WHERE $where
548
                        $order
549
                        $limit
550
                        ", $params);
551
552
        // Format the data into an array for returning.
553
        $data =  [];
554
555
        // If you change stuff here, you might have to change it in
556
        // $COMMENT->_set_url() too...
557
558
        // We'll generate permalinks for each comment.
559
        // Assuming every comment is from the same major...
560
561
        foreach ($q as $row) {
562
563
            $out = [];
564
565
            // Put each row returned into its own array in $data.
566
            foreach ($fieldsarr as $table => $tablesfields) {
567
                foreach ($tablesfields as $m => $field) {
568
569
                    // HACK 2.
570
                    // If we're getting the body of a hansard object, we have
571
                    // got it AS 'hbody', so we didn't duplicate the comment's 'body'
572
                    // element.
573
                    if ($table == 'epobject' && $field == 'body') {
574
                        $field = 'hbody';
575
                    }
576
577
                    $out[$field] = $row[$field];
578
                }
579
            }
580
581
            $urldata = [
582
                'major' => $row['major'],
583
                'gid' => $out['gid'],
584
                'comment_id' => $out['comment_id'],
585
                #					'user_id' =>
586
            ];
587
            $out['url'] = $this->_comment_url($urldata);
588
            $data[] = $out;
589
        }
590
591
        return $data;
592
593
    }
594
}
595