1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Event collection class.
19 *
20 * @package    core_calendar
21 * @copyright  2017 Cameron Ball <cameron@cameron1729.xyz>
22 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25namespace core_calendar\local\event\entities;
26
27defined('MOODLE_INTERNAL') || die();
28
29use core_calendar\local\event\factories\event_factory_interface;
30
31/**
32 * Class representing a collection of repeat events.
33 *
34 * @copyright 2017 Cameron Ball <cameron@cameron1729.xyz>
35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 */
37class repeat_event_collection implements event_collection_interface {
38    /**
39     * @var int DB_QUERY_LIMIT How many records to pull from the DB at once.
40     */
41    const DB_QUERY_LIMIT = 100;
42
43    /**
44     * @var int $parentid The ID of the event which the events in this collection are repeats of.
45     */
46    protected $parentid;
47
48    /**
49     * @var \stdClass $parentrecord The parent event record from the database.
50     */
51    protected $parentrecord;
52
53    /**
54     * @var event_factory_interface $factory Event factory.
55     */
56    protected $factory;
57
58    /**
59     * @var int $num Total number of events that could be retrieved by this collection.
60     */
61    protected $num;
62
63    /**
64     * Constructor.
65     *
66     * @param stdClass                $dbrow    The event dbrow that is being repeated.
67     * @param event_factory_interface $factory  Event factory.
68     */
69    public function __construct($dbrow, event_factory_interface $factory) {
70        $eventid = $dbrow->id;
71        $repeatid = $dbrow->repeatid;
72
73        if (empty($repeatid)) {
74            $this->parentrecord = $dbrow;
75            $this->parentid = $eventid;
76        } else {
77            $this->parentid = $repeatid;
78        }
79
80        if ($eventid === $repeatid) {
81            // This means the record we've been given is the parent
82            // record.
83            $this->parentrecord = $dbrow;
84        }
85
86        $this->factory = $factory;
87    }
88
89    public function get_id() {
90        return $this->parentid;
91    }
92
93    public function get_num() {
94        global $DB;
95        // Subtract one because the original event has repeatid = its own id.
96        return $this->num = max(
97            isset($this->num) ? $this->num : ($DB->count_records('event', ['repeatid' => $this->parentid]) - 1),
98            0
99        );
100    }
101
102    public function getIterator() {
103        $parentrecord = $this->get_parent_record();
104        foreach ($this->load_event_records() as $eventrecords) {
105            foreach ($eventrecords as $eventrecord) {
106                // In the case of the repeat event having unset information, fallback on the parent.
107                yield $this->factory->create_instance((object)array_merge((array)$parentrecord, (array)$eventrecord));
108            }
109        }
110    }
111
112    /**
113     * Return the parent DB record.
114     *
115     * @return \stdClass
116     */
117    protected function get_parent_record() {
118        global $DB;
119
120        if (!isset($this->parentrecord)) {
121            $this->parentrecord = $DB->get_record('event', ['id' => $this->parentid]);
122        }
123
124        return $this->parentrecord;
125    }
126
127    /**
128     * Generate more event records.
129     *
130     * @param int $start Start offset.
131     * @return \stdClass[]
132     */
133    protected function load_event_records($start = 0) {
134        global $DB;
135        while ($records = $DB->get_records_select(
136            'event',
137            'id <> :parentid AND repeatid = :repeatid',
138            [
139                'parentid' => $this->parentid,
140                'repeatid' => $this->parentid,
141            ],
142            'id ASC',
143            '*',
144            $start,
145            self::DB_QUERY_LIMIT
146        )) {
147            yield $records;
148            $start += self::DB_QUERY_LIMIT;
149        }
150    }
151}
152