PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / 1.2.21
VikAppointments Services Booking Calendar v1.2.21
1.2.21 1.2.20 trunk 1.2.17 1.2.18 1.2.19
vikappointments / site / helpers / libraries / availability / timeline.php
vikappointments / site / helpers / libraries / availability Last commit date
timeline 3 days ago implementor.php 3 days ago index.html 3 days ago manager.php 3 days ago search.php 3 days ago timeline.php 3 days ago
timeline.php
295 lines
1 <?php
2 /**
3 * @package VikAppointments
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 VAPLoader::import('libraries.availability.search');
15 VAPLoader::import('libraries.availability.timeline.block');
16
17 /**
18 * Timeline wrapper.
19 *
20 * @since 1.7
21 */
22 class VAPAvailabilityTimeline implements IteratorAggregate, JsonSerializable
23 {
24 /**
25 * The check-in date expressed in military format.
26 *
27 * @var string
28 */
29 protected $date;
30
31 /**
32 * An availability search instance
33 *
34 * @var VAPAvailabilitySearch
35 */
36 protected $search;
37
38 /**
39 * The system/employee timezone.
40 *
41 * @var DateTimeZone
42 */
43 protected $employeeTimezone;
44
45 /**
46 * An array of times.
47 *
48 * @var array
49 */
50 protected $timeline = array();
51
52 /**
53 * Class constructor.
54 *
55 * @param string $date The check-in date (military format).
56 * @param VAPAvailabilitySearch $search The search instance.
57 */
58 public function __construct($date, VAPAvailabilitySearch $search)
59 {
60 $this->date = $date;
61 $this->search = $search;
62
63 // get employee model to access helper methods
64 $model = JModelVAP::getInstance('employee');
65 // Recover default employee timezone. In case the employee is
66 // not set, the default system timezone will be used.
67 $tz = $model->getTimezone($this->search->get('id_employee'));
68
69 if ($tz)
70 {
71 // register employee timezone
72 $this->employeeTimezone = new DateTimeZone($tz);
73 }
74 }
75
76 /**
77 * Adds a new timeline level.
78 *
79 * @return self This object to support chaining.
80 */
81 public function addLevel()
82 {
83 // make sure the last added timeline is not empty
84 if (!$this->timeline || $this->timeline[count($this->timeline) - 1])
85 {
86 // add timeline level
87 $this->timeline[] = array();
88 }
89
90 return $this;
91 }
92
93 /**
94 * Creates the timeline starting from the specified array.
95 *
96 * @param array $timeline An associative array containing the time (as key)
97 * and the availability status (as value).
98 *
99 * @return self This object to support chaining.
100 */
101 public function setTimes(array $timeline)
102 {
103 // reset timeline
104 $this->timeline = array();
105
106 foreach ($timeline as $times)
107 {
108 // add level to timeline
109 $this->addLevel();
110
111 // add times one by one
112 foreach ($times as $time => $status)
113 {
114 $this->addTime($time, $status);
115 }
116 }
117
118 return $this;
119 }
120
121 /**
122 * Registers a new timeline block.
123 *
124 * @param mixed $time Either a time string or a time expressed in minutes.
125 * @param integer $status The availability status.
126 * @param integer $duration The time slot duration (in minutes).
127 * @param float $price An optional time slot price.
128 * @param array $occupancy An optional occupancy array.
129 *
130 * @return VAPAvailabilityTimelineBlock The newly created time block.
131 */
132 public function addTime($time, $status, $duration = null, $price = null, $occupancy = null)
133 {
134 $date = $this->date;
135
136 if (is_numeric($time))
137 {
138 // in case the time exceeds the midnight, change the current date to the next one
139 if ($time >= 1440)
140 {
141 $date = JFactory::getDate($this->date);
142 $date->modify('+1 day');
143 $date = $date->format('Y-m-d');
144 }
145
146 // convert minutes to time string
147 $time = JHtml::fetch('vikappointments.min2time', $time, $string = true, $format = 'H:i:s');
148 }
149
150 if (!$duration)
151 {
152 // recover duration from search
153 $model = JModelVAP::getInstance('serempassoc');
154 $override = $model->getOverrides($this->search->get('id_service'), $this->search->get('id_employee'));
155
156 if ($override)
157 {
158 $duration = $override->duration;
159 }
160 }
161
162 // create date instance coming from the timezone of the employee
163 $dt = JFactory::getDate($date . ' ' . $time, $this->employeeTimezone);
164
165 // create time block
166 $block = new VAPAvailabilityTimelineBlock($dt, $status, $duration, $price, $occupancy);
167
168 if (!$this->timeline)
169 {
170 // create first level
171 $this->addLevel();
172 }
173
174 // register block within the last timeline level
175 $this->timeline[count($this->timeline) - 1][] = $block;
176
177 return $block;
178 }
179
180 /**
181 * Checks whether the timeline as at least a level
182 * with at least a time block.
183 *
184 * @return boolean
185 */
186 public function hasTimes()
187 {
188 return $this->timeline && $this->timeline[0];
189 }
190
191 /**
192 * Returns the timeline searcher.
193 *
194 * @return VAPAvailabilitySearch
195 */
196 public function getSearch()
197 {
198 return $this->search;
199 }
200
201 /**
202 * Returns the date of the timeline, adjusted to the local timezone
203 * of the employee.
204 *
205 * @return string
206 */
207 public function getDate()
208 {
209 return JFactory::getDate($this->date, $this->employeeTimezone)
210 ->format('Y-m-d', $local = true);
211 }
212
213 /**
214 * Returns the timeline as a source array.
215 *
216 * @param boolean $flatten Whether to include the levels or not.
217 * @param boolean $statusOnly True to register only the time status, false to
218 * take all the details of the time block as array.
219 *
220 * @return array
221 */
222 public function toArray($flatten = false, $statusOnly = true)
223 {
224 $arr = array();
225
226 // iterate levels
227 foreach ($this->timeline as $level)
228 {
229 if (!$flatten)
230 {
231 // include level
232 $arr[] = array();
233 }
234
235 // iterate level times
236 foreach ($level as $time)
237 {
238 // extract time
239 $hm = $time->checkin('H:i');
240 // convert time to minutes
241 $hm = JHtml::fetch('vikappointments.time2min', $hm);
242
243 if ($statusOnly)
244 {
245 $value = $time->status;
246 }
247 else
248 {
249 $value = $time->toArray();
250 }
251
252 if ($flatten)
253 {
254 // register time slot at the same level
255 $arr[$hm] = $arr[$hm] ?? $value;
256 }
257 else
258 {
259 // register time slot at the current level
260 $arr[count($arr) - 1][$hm] = $value;
261 }
262 }
263 }
264
265 return $arr;
266 }
267
268 /**
269 * Creates an array iterator for ease of use.
270 *
271 * @return ArrayIterator
272 *
273 * @since 1.7
274 */
275 #[ReturnTypeWillChange]
276 public function getIterator()
277 {
278 return new ArrayIterator($this->timeline);
279 }
280
281 /**
282 * Creates a standard object, containing all the supported properties,
283 * to be used when this class is passed to "json_encode()".
284 *
285 * @return object
286 *
287 * @see JsonSerializable
288 */
289 #[ReturnTypeWillChange]
290 public function jsonSerialize()
291 {
292 return $this->timeline;
293 }
294 }
295