Issues (359)

classes/Divisions.php (2 issues)

1
<?php
2
/**
3
 * Policy Positions
4
 *
5
 * @package TheyWorkForYou
6
 */
7
8
namespace MySociety\TheyWorkForYou;
9
10
class Divisions {
11
12
    /**
13
     * Member
14
     */
15
16
    private $member;
17
18
    /**
19
     * DB handle
20
     */
21
    private $db;
22
23
    private $positions;
24
    private $policies;
25
26
    /**
27
     * Constructor
28
     *
29
     * @param Member   $member   The member to get positions for.
30
     */
31
32
    public function __construct(Member $member = null, PolicyPositions $positions = null)
33
    {
34
        $this->member = $member;
35
        $this->positions = $positions;
36
        $this->policies = new Policies;
37
        $this->db = new \ParlDB;
38
    }
39
40
    public static function getMostRecentDivisionDate() {
41
        $db = new \ParlDB;
42
        $q = $db->query(
43
            "SELECT policy_id, max(division_date) as recent
44
            FROM policydivisions
45
                JOIN divisions USING(division_id)
46
            GROUP BY policy_id"
47
        );
48
49
        $policy_maxes = array();
50
        foreach ($q as $row) {
51
            $policy_maxes[$row['policy_id']] = $row['recent'];
52
        }
53
        $policy_maxes['latest'] = $policy_maxes ? max(array_values($policy_maxes)) : '';
54
        return $policy_maxes;
55
    }
56
57
    /**
58
     * @param  int              $number  Number of divisions to return. Optional.
59
     * @param  string|string[]  $houses  House name (eg: "commons") or array of
60
     *                                   house names. Optional.
61
     */
62
    public function getRecentDivisions($number = 20, $houses = null) {
63
        $select = '';
64
        $order = 'ORDER BY division_date DESC, division_number DESC';
65
        $limit = 'LIMIT :count';
66
        $params = array(
67
            ':count' => $number
68
        );
69
70
        $where = [];
71
        if ($houses) {
72
            if ( is_string($houses) ) {
73
                $houses = array( $houses );
74
            }
75
            $where[] = 'house IN ("' . implode('", "', $houses) . '")';
76
        }
77
        if (!$houses || in_array('senedd', $houses)) {
0 ignored issues
show
It seems like $houses can also be of type string; however, parameter $haystack of in_array() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

77
        if (!$houses || in_array('senedd', /** @scrutinizer ignore-type */ $houses)) {
Loading history...
78
            if (LANGUAGE == 'cy') {
0 ignored issues
show
The condition MySociety\TheyWorkForYou\LANGUAGE == 'cy' is always false.
Loading history...
79
                $where[] = "divisions.division_id NOT LIKE '%-en-%'";
80
            } else {
81
                $where[] = "divisions.division_id NOT LIKE '%-cy-%'";
82
            }
83
        }
84
        $where = 'WHERE ' . join(' AND ', $where);
85
86
        if ( $this->member ) {
87
            $select = "SELECT divisions.*, vote FROM divisions
88
                LEFT JOIN persondivisionvotes ON divisions.division_id=persondivisionvotes.division_id AND person_id=:person_id";
89
            $params[':person_id'] = $this->member->person_id;
90
        } else {
91
            $select = "SELECT * FROM divisions";
92
        }
93
94
        $q = $this->db->query(
95
            sprintf("%s %s %s %s", $select, $where, $order, $limit),
96
            $params
97
        );
98
99
        $divisions = array();
100
        foreach ($q as $division) {
101
            $data = $this->getParliamentDivisionDetails($division);
102
103
            $mp_vote = '';
104
            if (array_key_exists('vote', $division)) {
105
                if ($division['vote'] == 'aye') {
106
                    $mp_vote = 'voted in favour';
107
                } elseif ($division['vote'] == 'tellaye') {
108
                    $mp_vote = 'voted (as a teller) in favour';
109
                } elseif ($division['vote'] == 'no') {
110
                    $mp_vote = 'voted against';
111
                } elseif ($division['vote'] == 'tellno') {
112
                    $mp_vote = 'voted (as a teller) against';
113
                } elseif ($division['vote'] == 'absent') {
114
                    $mp_vote = ' was absent';
115
                } elseif ($division['vote'] == 'both') {
116
                    $mp_vote = ' abstained';
117
                }
118
            }
119
            $data['mp_vote'] = $mp_vote;
120
            $house = Utility\House::division_house_name_to_number($division['house']);
121
            $data['members'] = \MySociety\TheyWorkForYou\Utility\House::house_to_members($house);
122
            $divisions[] = $data;
123
        }
124
125
        return array('divisions' => $divisions);
126
    }
127
128
    /**
129
     * @param  int              $number  Number of divisions to return. Optional.
130
     * @param  int|int[]        $majors  Major types (e.g. 1) or array of
131
     *                                   major types. Optional.
132
     */
133
    public function getRecentDebatesWithDivisions($number = 20, $majors = null) {
134
        global $hansardmajors;
135
136
        if (!is_array($majors)) {
137
            $majors = [$majors];
138
        }
139
140
        $where = '';
141
        if (count($majors) > 0) {
142
            $where = 'AND h.major IN (' . implode(', ', $majors) . ')';
143
        }
144
145
        # Fetch any division speech, its subsection gid for the link, and
146
        # section/subsection bodies to construct a debate title
147
        $q = $this->db->query(
148
            "SELECT min(eps.body) as section_body, min(epss.body) as subsection_body,
149
                min(ss.gid) as debate_gid, min(h.gid) AS gid, min(h.hdate) as hdate,
150
                min(h.major) as major, count(h.gid) AS c
151
            FROM hansard h, hansard ss, epobject eps, epobject epss
152
            WHERE h.section_id = eps.epobject_id
153
                AND h.subsection_id = epss.epobject_id
154
                AND h.subsection_id = ss.epobject_id
155
                AND h.htype=14
156
            $where
157
            GROUP BY h.subsection_id
158
            ORDER BY h.hdate DESC, h.hpos DESC
159
            LIMIT :count",
160
            array(':count' => $number)
161
        );
162
163
        $debates = array();
164
        foreach ($q as $debate) {
165
            $debate_gid = fix_gid_from_db($debate['debate_gid']);
166
            $anchor = '';
167
            if ($debate['c'] == 1) {
168
                $anchor = '#g' . gid_to_anchor(fix_gid_from_db($debate['gid']));
169
            }
170
            $url = new Url($hansardmajors[$debate['major']]['page']);
171
            $url->insert(array('gid' => $debate_gid));
172
            $debates[] = [
173
                'url' => $url->generate() . $anchor,
174
                'title' => "$debate[section_body] : $debate[subsection_body]",
175
                'date' => $debate['hdate'],
176
            ];
177
        }
178
179
        return $debates;
180
    }
181
182
    public function getRecentDivisionsForPolicies($policies, $number = 20) {
183
        $args = array(':number' => $number);
184
185
        $quoted = array();
186
        foreach ($policies as $policy) {
187
            $quoted[] = $this->db->quote($policy);
188
        }
189
        $policies_str = implode(',', $quoted);
190
191
        $q = $this->db->query(
192
            "SELECT divisions.*
193
            FROM policydivisions
194
                JOIN divisions USING(division_id)
195
            WHERE policy_id in ($policies_str)
196
            GROUP BY division_id
197
            ORDER by division_date DESC LIMIT :number",
198
            $args
199
        );
200
201
        $divisions = array();
202
        foreach ($q as $row) {
203
          $divisions[] = $this->getParliamentDivisionDetails($row);
204
        }
205
206
        return $divisions;
207
    }
208
209
    /**
210
     *
211
     * Get a list of division votes related to a policy
212
     *
213
     * Returns an array with one key ( the policyID ) containing a hash
214
     * with a policy_id key and a divisions key which contains an array
215
     * with details of all the divisions.
216
     *
217
     * Each division is a hash with the following fields:
218
     *    division_id, date, vote, gid, url, text, strong
219
     *
220
     * @param int|null $policyId The ID of the policy to get divisions for
221
     */
222
223
    public function getMemberDivisionsForPolicy($policyID = null) {
224
        $where_extra = '';
225
        $args = array(':person_id' => $this->member->person_id);
226
        if ( $policyID ) {
227
            $where_extra = 'AND policy_id = :policy_id';
228
            $args[':policy_id'] = $policyID;
229
        }
230
        $q = $this->db->query(
231
            "SELECT policy_id, division_id, division_title, yes_text, no_text, division_date, division_number, vote, gid, direction
232
            FROM policydivisions JOIN persondivisionvotes USING(division_id)
233
                JOIN divisions USING(division_id)
234
            WHERE person_id = :person_id AND direction <> 'abstention' $where_extra
235
            ORDER by policy_id, division_date DESC",
236
            $args
237
        );
238
        # possibly add another query here to get related policies that use the same votes
239
        return $this->divisionsByPolicy($q);
240
    }
241
242
    public function getMemberDivisionDetails($strong_only = false) {
243
        $args = array(':person_id' => $this->member->person_id);
244
245
        $policy_divisions = array();
246
        if ($strong_only) {
247
            $where_extra = "AND (policy_vote = 'no3' OR policy_vote = 'aye3')";
248
        } else {
249
            $where_extra = '';
250
        }
251
        $q = $this->db->query(
252
            "SELECT policy_id, policy_vote, vote, count(division_id) as total,
253
            max(year(division_date)) as latest, min(year(division_date)) as earliest
254
            FROM policydivisions JOIN persondivisionvotes USING(division_id)
255
                JOIN divisions USING(division_id)
256
            WHERE person_id = :person_id AND direction <> 'abstention' $where_extra
257
            GROUP BY policy_id, policy_vote, vote",
258
            $args
259
        );
260
261
        foreach ($q as $row) {
262
          $policy_id = $row['policy_id'];
263
264
          if (!array_key_exists($policy_id, $policy_divisions)) {
265
            $summary = array(
266
              'max' => $row['latest'],
267
              'min' => $row['earliest'],
268
              'total' => $row['total'],
269
              'for' => 0, 'against' => 0, 'absent' => 0, 'both' => 0, 'tell' => 0
270
            );
271
272
            $policy_divisions[$policy_id] = $summary;
273
          }
274
275
          $summary = $policy_divisions[$policy_id];
276
277
          $summary['total'] += $row['total'];
278
          if ($summary['max'] < $row['latest']) {
279
              $summary['max'] = $row['latest'];
280
          }
281
          if ($summary['min'] > $row['latest']) {
282
              $summary['min'] = $row['latest'];
283
          }
284
285
          $vote = $row['vote'];
286
          $policy_vote = str_replace('3', '', $row['policy_vote']);
287
          if ( $vote == 'absent' ) {
288
              $summary['absent'] += $row['total'];
289
          } else if ( $vote == 'both' ) {
290
              $summary['both'] += $row['total'];
291
          } else if ( strpos($vote, 'tell') !== false ) {
292
              $summary['tell'] += $row['total'];
293
          } else if ( $policy_vote == $vote ) {
294
              $summary['for'] += $row['total'];
295
          } else if ( $policy_vote != $vote ) {
296
              $summary['against'] += $row['total'];
297
          }
298
299
          $policy_divisions[$policy_id] = $summary;
300
        }
301
302
        // for each key in $policy_divisions, we want to add agreement information
303
    
304
        $policies_list = new \MySociety\TheyWorkForYou\Policies();
305
        foreach ($policy_divisions as $policy_id => &$summary) {
306
            $agreement_details = $this->member->member_agreements($policy_id, HOUSE_TYPE_COMMONS, $policies_list );
307
            $summary["agreements_for"] = 0;
308
            $summary["agreements_against"] = 0;
309
            foreach ($agreement_details as $agreement){
310
                if ($strong_only == true & $agreement["strength"] != "strong") {
311
                    continue;
312
                }
313
                if ($agreement["alignment"] == "agree") {
314
                    $summary["agreements_for"] += 1;
315
                } else {
316
                    $summary["agreements_against"] += 1;
317
                }
318
            }
319
        }
320
        return $policy_divisions;
321
    }
322
323
    public function getDivisionByGid($gid) {
324
        $args = array(
325
            ':gid' => $gid
326
        );
327
        $q = $this->db->query("SELECT * FROM divisions WHERE gid = :gid", $args)->first();
328
329
        if (!$q) {
330
            return false;
331
        }
332
333
        return $this->_division_data($q);
334
    }
335
336
    public function getDivisionResults($division_id) {
337
        $args = array(
338
            ':division_id' => $division_id
339
        );
340
        $q = $this->db->query("SELECT * FROM divisions WHERE division_id = :division_id", $args)->first();
341
342
        if (!$q) {
343
            return false;
344
        }
345
346
        return $this->_division_data($q);
347
348
    }
349
350
    private function _division_data($row) {
351
352
        $details = $this->getParliamentDivisionDetails($row);
353
354
        $house = $row['house'];
355
        $args['division_id'] = $row['division_id'];
356
        $args['division_date'] = $row['division_date'];
357
        $args['house'] = \MySociety\TheyWorkForYou\Utility\House::division_house_name_to_number($house);
358
359
        $q = $this->db->query(
360
            "SELECT pdv.person_id, vote, proxy, title, given_name, family_name, lordofname, party
361
            FROM persondivisionvotes AS pdv JOIN person_names AS pn ON (pdv.person_id = pn.person_id)
362
            JOIN member AS m ON (pdv.person_id = m.person_id)
363
            WHERE division_id = :division_id
364
            AND house = :house AND entered_house <= :division_date AND left_house >= :division_date
365
            AND start_date <= :division_date AND end_date >= :division_date
366
            ORDER by family_name",
367
            $args
368
        );
369
370
        $votes = array(
371
          'yes_votes' => array(),
372
          'no_votes' => array(),
373
          'absent_votes' => array(),
374
          'both_votes' => array()
375
        );
376
377
        $party_breakdown = array(
378
          'yes_votes' => array(),
379
          'no_votes' => array(),
380
          'absent_votes' => array(),
381
          'both_votes' => array()
382
        );
383
384
        # Sort Lords specially
385
        $data = $q->fetchAll();
386
        if ($args['house'] == HOUSE_TYPE_LORDS) {
387
            uasort($data, 'by_peer_name');
388
        }
389
390
        foreach ($data as $vote) {
391
            $detail = array(
392
              'person_id' => $vote['person_id'],
393
              'name' => ucfirst(member_full_name($args['house'], $vote['title'], $vote['given_name'],
394
                    $vote['family_name'], $vote['lordofname'])),
395
              'party' => $vote['party'],
396
              'proxy' => false,
397
              'teller' => false
398
            );
399
400
            if (strpos($vote['vote'], 'tell') !== false) {
401
                $detail['teller'] = true;
402
            }
403
404
            if ($vote['proxy']) {
405
                $q = $this->db->query(
406
                    "SELECT title, given_name, family_name, lordofname
407
                    FROM person_names AS pn
408
                    WHERE person_id = :person_id
409
                    AND start_date <= :division_date AND end_date >= :division_date",
410
                    [ ':person_id' => $vote['proxy'], ':division_date' => $row['division_date'] ]
411
                )->first();
412
                $detail['proxy'] = ucfirst(member_full_name(
413
                    HOUSE_TYPE_COMMONS, $q['title'], $q['given_name'],
414
                    $q['family_name'], $q['lordofname']));
415
            }
416
417
            if ($vote['vote'] == 'aye' or $vote['vote'] == 'tellaye') {
418
              $votes['yes_votes'][] = $detail;
419
              @$party_breakdown['yes_votes'][$detail['party']]++;
420
            } else if ($vote['vote'] == 'no' or $vote['vote'] == 'tellno') {
421
              $votes['no_votes'][] = $detail;
422
              @$party_breakdown['no_votes'][$detail['party']]++;
423
            } else if ($vote['vote'] == 'absent') {
424
              $votes['absent_votes'][] = $detail;
425
              @$party_breakdown['absent_votes'][$detail['party']]++;
426
            } else if ($vote['vote'] == 'both') {
427
              $votes['both_votes'][] = $detail;
428
              @$party_breakdown['both_votes'][$detail['party']]++;
429
            }
430
        }
431
432
        foreach ($votes as $vote => $count) { // array('yes_votes', 'no_votes', 'absent_votes', 'both_votes') as $vote) {
433
          $votes[$vote . '_by_party'] = $votes[$vote];
434
          usort($votes[$vote . '_by_party'], function ($a, $b) {
435
                return $a['party']>$b['party'];
436
            });
437
        }
438
439
        foreach ($party_breakdown as $vote => $parties) {
440
            $summary = array();
441
            foreach ($parties as $party => $count) {
442
                array_push($summary, "$party: $count");
443
            }
444
445
            sort($summary);
446
            $party_breakdown[$vote] = implode(', ', $summary);
447
        }
448
449
        $details = array_merge($details, $votes);
450
        $details['party_breakdown'] = $party_breakdown;
451
        $details['members'] = \MySociety\TheyWorkForYou\Utility\House::house_to_members($args['house']);
452
        $details['house'] = $house;
453
        $details['house_number'] = $args['house'];
454
455
        return $details;
456
    }
457
458
    public function getDivisionResultsForMember($division_id, $person_id) {
459
        $args = array(
460
            ':division_id' => $division_id,
461
            ':person_id' => $person_id
462
        );
463
        $q = $this->db->query(
464
            "SELECT division_id, division_title, yes_text, no_text, division_date, division_number, gid, vote
465
            FROM divisions JOIN persondivisionvotes USING(division_id)
466
            WHERE division_id = :division_id AND person_id = :person_id",
467
            $args
468
        )->first();
469
470
        // if the vote was before or after the MP was in Parliament
471
        // then there won't be a row
472
        if (!$q) {
473
            return false;
474
        }
475
476
        $details = $this->getDivisionDetails($q);
477
        return $details;
478
    }
479
480
    public function generateSummary($votes) {
481
        $max = $votes['max'];
482
        $min = $votes['min'];
483
484
        $actions = array(
485
            $votes['for'] . ' ' . make_plural('vote', $votes['for']) . ' for',
486
            $votes['against'] . ' ' . make_plural('vote', $votes['against']) . ' against'
487
        );
488
489
        if ( $votes['agreements_for']) {
490
            $actions[] = $votes['agreements_for'] . ' ' . make_plural('agreement', $votes['agreements_for']) . ' for';
491
        }
492
493
        if ( $votes['agreements_against']) {
494
            $actions[] = $votes['agreements_against'] . ' ' . make_plural('agreement', $votes['agreements_against']) . ' against';
495
        }
496
497
        if ( $votes['both'] ) {
498
            $actions[] = $votes['both'] . ' ' . make_plural('abstention', $votes['both']);
499
        }
500
        if ( $votes['absent'] ) {
501
            $actions[] = $votes['absent'] . ' ' . make_plural('absence', $votes['absent']);
502
        }
503
        if ($max == $min) {
504
            return join(', ', $actions) . ', in ' . $max;
505
        } else {
506
            return join(', ', $actions) . ', between ' . $min . '&ndash;' . $max;
507
        }
508
    }
509
510
    /**
511
     *
512
     * Get all the divisions a member has voted in keyed by policy
513
     *
514
     * Returns an array with keys for each policyID, each of these contains
515
     * the same structure as getMemberDivisionsForPolicy
516
     *
517
     */
518
519
    public function getAllMemberDivisionsByPolicy() {
520
        $policies = $this->getMemberDivisionsForPolicy();
521
        return Utility\Shuffle::keyValue($policies);
522
    }
523
524
525
    /**
526
     * Get the last n votes for a member
527
     *
528
     * @param $number int - How many divisions to return. Defaults to 20
529
     * @param $context string - The context of the page the results are being presented in.
530
     *    This affects the summary details and can either be 'Parliament' in which case the
531
     *    overall vote for all MPs is returned, plus additional information on how the MP passed
532
     *    in to the constructor voted, or the default of 'MP' which is just the vote of the
533
     *    MP passed in to the constructor.
534
     *
535
     * Returns an array of divisions
536
     */
537
    public function getRecentMemberDivisions($number = 20) {
538
        $args = array(':person_id' => $this->member->person_id, ':number' => $number);
539
        $q = $this->db->query(
540
            "SELECT *
541
            FROM persondivisionvotes
542
                JOIN divisions USING(division_id)
543
            WHERE person_id = :person_id
544
            ORDER by division_date DESC, division_number DESC, division_id DESC LIMIT :number",
545
            $args
546
        );
547
548
        $divisions = array();
549
        foreach ($q as $row) {
550
            $divisions[] = $this->getDivisionDetails($row);
551
        }
552
553
        return $divisions;
554
    }
555
556
    private function constructYesNoVoteDescription($direction, $title, $short_text) {
557
        $text = ' ' ;
558
        if ( $short_text ) {
559
            $text .= sprintf(gettext('voted %s'), $short_text);
560
        } else {
561
            $text .= sprintf(gettext('voted %s on <em>%s</em>'), $direction, $title);
562
        }
563
564
        return $text;
565
    }
566
567
    private function constructVoteDescription($vote, $yes_text, $no_text, $division_title) {
568
        /*
569
         * for most post 2010 votes we have nice single sentence summaries of
570
         * what voting for or against means so we use that if it's there, however
571
         * we don't have anything nice for people being absent or for pre 2010
572
         * votes so we need to generate some text using the title of the division
573
         */
574
575
        switch ( strtolower($vote) ) {
576
            case 'yes':
577
            case 'aye':
578
                $description = $this->constructYesNoVoteDescription('yes', $division_title, $yes_text);
579
                break;
580
            case 'no':
581
                $description = $this->constructYesNoVoteDescription('no', $division_title, $no_text);
582
                break;
583
            case 'absent':
584
                $description = ' was absent for a vote on <em>' . $division_title . '</em>';
585
                break;
586
            case 'both':
587
                $description = ' abstained on a vote on <em>' . $division_title . '</em>';
588
                break;
589
            case 'tellyes':
590
            case 'tellno':
591
            case 'tellaye':
592
                $description = ' acted as teller for a vote on <em>' . $division_title . '</em>';
593
                break;
594
            default:
595
                $description = $division_title;
596
        }
597
598
        return $description;
599
    }
600
601
    private function getBasicDivisionDetails($row, $vote) {
602
        $yes_text = $row['yes_text'];
603
        $no_text = $row['no_text'];
604
605
        $division = array(
606
            'division_id' => $row['division_id'],
607
            'date' => $row['division_date'],
608
            'gid' => fix_gid_from_db($row['gid']),
609
            'number' => $row['division_number'],
610
            'text' => $this->constructVoteDescription($vote, $yes_text, $no_text, $row['division_title']),
611
            'has_description' => $yes_text && $no_text,
612
            'vote' => $vote,
613
        );
614
615
        if ($row['gid']) {
616
            $division['debate_url'] = $this->divisionUrlFromGid($row['gid']);
617
        }
618
619
        # Policy-related information
620
621
        # So one option is just to query for it here
622
        # we want to add an array of policies aside the current policy
623
        # and if they have the same or different direction as thie current division
624
        # in the row
625
626
        # fetch related policies from database
627
        $q = $this->db->query(
628
            "SELECT policy_id, direction
629
            FROM policydivisions
630
            WHERE division_id = :division_id",
631
            array(':division_id' => $row['division_id'])
632
        );
633
        $division['related_policies'] = array();
634
635
        $policy_lookup = $this->policies->getPolicies();
636
        foreach ($q as $policy) {
637
            $division['related_policies'][] = array(
638
                'policy_id' => $policy['policy_id'],
639
                'policy_title' => preg_replace('#</?a[^>]*>#', '', $policy_lookup[$policy['policy_id']]),
640
                'direction' => $policy['direction'],
641
            );
642
        }
643
644
        if (array_key_exists('direction', $row)) {
645
            $division['direction'] = $row['direction'];
646
            if ( strpos( $row['direction'], 'strong') !== false ) {
647
                $division['strong'] = true;
648
            } else {
649
                $division['strong'] = false;
650
            }
651
        }
652
653
        return $division;
654
    }
655
656
    private function getDivisionDetails($row) {
657
        return $this->getBasicDivisionDetails($row, $row['vote']);
658
    }
659
660
    private function getParliamentDivisionDetails($row) {
661
        $division = $this->getBasicDivisionDetails($row, $row['majority_vote']);
662
663
        $division['division_title'] = $row['division_title'];
664
        $division['for'] = $row['yes_total'];
665
        $division['against'] = $row['no_total'];
666
        $division['both'] = $row['both_total'];
667
        $division['absent'] = $row['absent_total'];
668
669
        return $division;
670
    }
671
672
    private function divisionsByPolicy($q) {
673
        $policies = array();
674
675
        # iterate through each division, and adds it to an array of policies
676
        # if there is only one policy being queried, it will be an array of 1
677
        foreach ($q as $row) {
678
            $policy_id = $row['policy_id'];
679
680
            # if this policy hasn't come up yet, create the key for it
681
            if ( !array_key_exists($policy_id, $policies) ) {
682
                $policies[$policy_id] = array(
683
                    'policy_id' => $policy_id,
684
                    'divisions' => array()
685
                );
686
                $policies[$policy_id]['desc'] = $this->policies->getPolicies()[$policy_id];
687
                $policies[$policy_id]['header'] = $this->policies->getPolicyDetails($policy_id);
688
                if ( $this->positions ) {
689
                    $policies[$policy_id]['position'] = $this->positions->positionsById[$policy_id];
690
                }
691
            }
692
693
            
694
            $division = $this->getDivisionDetails($row);
695
696
            $policies[$policy_id]['divisions'][] = $division;
697
        };
698
699
        return $policies;
700
    }
701
702
    private function divisionUrlFromGid($gid) {
703
        global $hansardmajors;
704
705
        $gid = get_canonical_gid($gid);
706
707
        $q = $this->db->query("SELECT gid, major FROM hansard WHERE epobject_id = ( SELECT subsection_id FROM hansard WHERE gid = :gid )", array( ':gid' => $gid ))->first();
708
        if (!$q) {
709
            return '';
710
        }
711
        $parent_gid = fix_gid_from_db($q['gid']);
712
        $url = new Url($hansardmajors[$q['major']]['page']);
713
        $url->insert(array('gid' => $parent_gid));
714
        return $url->generate() . '#g' . gid_to_anchor(fix_gid_from_db($gid));
715
    }
716
}
717