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 / view / classes / employeesearch.php
vikappointments / site / helpers / libraries / view / classes Last commit date
employeesearch.php 4 days ago index.html 4 days ago servicesearch.php 4 days ago
employeesearch.php
515 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 /**
15 * VikAppointments Employee Search view contents handler.
16 * This class provides helpful tools to enhance the
17 * <head> of the employeesearch pages.
18 *
19 * @since 1.6
20 */
21 class VAPViewContentsEmployeeSearch extends VAPViewContents
22 {
23 /**
24 * A registry containing the employee information.
25 *
26 * @var JRegistry
27 */
28 protected $employee;
29
30 /**
31 * The employee description.
32 *
33 * @var string
34 */
35 protected $description = null;
36
37 /**
38 * The maximum number of characters to display
39 * for the employee description.
40 *
41 * @var integer
42 */
43 protected $descLength = 256;
44
45 /**
46 * Class constructor.
47 *
48 * @param mixed $page The view object.
49 * @param string $type The view file/type. If not provided
50 * it will be calculated from the $page class name.
51 */
52 public function __construct($page, $type = null)
53 {
54 parent::__construct($page, $type);
55
56 if (isset($page->employee))
57 {
58 $tmp = $page->employee;
59 }
60 else
61 {
62 $tmp = array();
63 }
64
65 $this->employee = new JRegistry($tmp);
66 }
67
68 /**
69 * @override
70 * Sets the meta description according to the settings of the page.
71 *
72 * @return boolean True if set, otherwise false.
73 */
74 public function setMetaDescription()
75 {
76 // before all, set the description of the current menu item
77 $set = parent::setMetaDescription();
78
79 // if the description was empty or the current menu item is
80 // not equals to the view set in the request, try to use
81 // the description related to the employee
82 if (!$set || $this->activeView != $this->currentView)
83 {
84 // get employee description
85 $desc = strip_tags($this->employee->get('note', ''));
86
87 if ($desc)
88 {
89 $this->page->document->setDescription($desc);
90
91 $set = true;
92 }
93 }
94
95 return $set;
96 }
97
98 /**
99 * @override
100 * Sets the browser page title.
101 *
102 * @return boolean True if set, otherwise false.
103 *
104 * @since 1.6.1
105 */
106 public function setPageTitle()
107 {
108 // if the current menu item is not equals to the view set
109 // in the request, try to use the title related to the employee
110 if ($this->activeView != $this->currentView)
111 {
112 $title = $this->page->document->getTitle() . ' - ' . $this->employee->get('nickname');
113
114 $this->page->document->setTitle($title);
115
116 return true;
117 }
118
119 return false;
120 }
121
122 /**
123 * Returns the employee description.
124 *
125 * @return string A short version of the description.
126 */
127 protected function getEmployeeDescription()
128 {
129 if ($this->description === null)
130 {
131 // get employee description
132 $desc = $this->employee->get('note', '');
133
134 if ($desc)
135 {
136 // render HTML description to grab plugin contents and short description
137 VikAppointments::renderHtmlDescription($desc, 'microdata');
138
139 // strip HTML tags from description
140 $desc = strip_tags($desc);
141
142 // check if the description length exceeds the limit
143 if (strlen($desc) > $this->descLength)
144 {
145 // use the first N characters of the employee description
146 $desc = mb_substr(strip_tags($desc), 0, $this->descLength, 'UTF-8') . '...';
147 }
148 }
149
150 // cache description
151 $this->description = $desc;
152 }
153
154 return $this->description;
155 }
156
157 /**
158 * @override
159 * Creates the OPEN GRAPH protocol according to the
160 * entity of the current page.
161 *
162 * @return self This object to support chaining.
163 *
164 * @uses getEmployeeDescription()
165 */
166 public function buildOpenGraph()
167 {
168 $doc = $this->page->document;
169
170 // basic metadata
171 $doc->setMetaData('og:title' , $this->employee->get('nickname'));
172 $doc->setMetaData('og:description', $this->getEmployeeDescription());
173 $doc->setMetaData('og:type' , 'profile');
174
175 if ($this->employee->get('image'))
176 {
177 $doc->setMetaData('og:image', VAPMEDIA_URI . $this->employee->get('image'));
178 }
179
180 // profile metadata
181 $doc->setMetaData('profile:first_name', $this->employee->get('firstname'));
182 $doc->setMetaData('profile:last_name' , $this->employee->get('lastname'));
183 $doc->setMetaData('profile:username' , $this->employee->get('nickname'));
184
185 // invoke parent to include generic metadata
186 return parent::buildOpenGraph();
187 }
188
189 /**
190 * @override
191 * Returns the microdata object to include within the head of the page.
192 * Inherits this method to dispatch the attachment of the properties to
193 * children classes.
194 *
195 * @param object &$json The root object used to attach microdata.
196 *
197 * @return boolean True in case the object should be attached, otherwise false.
198 */
199 protected function getMicrodataObject(&$json)
200 {
201 /**
202 * Organization schema type.
203 *
204 * @link https://schema.org/Organization
205 */
206
207 $config = VAPFactory::getConfig();
208
209 // define schema type
210 $json->{"@context"} = 'http://schema.org';
211 $json->{"@type"} = 'Organization';
212
213 // add employee information
214 $json->name = $this->employee->get('nickname');
215 $json->description = $this->getEmployeeDescription();
216
217 if ($this->employee->get('image'))
218 {
219 $json->image = VAPMEDIA_URI . $this->employee->get('image');
220 }
221
222 // get reviews
223 $reviews = $this->employee->get('reviews');
224
225 // add reviews
226 if ($reviews && $reviews->size > 0)
227 {
228 /**
229 * AggregateRating schema type.
230 *
231 * @link https://schema.org/AggregateRating
232 */
233 $json->aggregateRating = new stdClass;
234 $json->aggregateRating->{"@type"} = 'AggregateRating';
235 $json->aggregateRating->ratingValue = $this->employee->get('rating');
236 $json->aggregateRating->reviewCount = $reviews->size;
237
238 // add latest 2 reviews
239 $json->review = array();
240
241 // number of reviews to show
242 $lim = min(array((int) $reviews->size, 2));
243
244 for ($i = 0; $i < $lim; $i++)
245 {
246 $tmp = $reviews->rows[$i];
247
248 /**
249 * Review schema type.
250 *
251 * @link https://schema.org/Review
252 */
253 $review = new stdClass;
254 $review->{"@type"} = 'Review';
255 $review->author = $tmp->name;
256 $review->datePublished = JFactory::getDate($tmp->timestamp)->format('Y-m-d');
257 $review->description = $tmp->comment;
258 $review->name = $tmp->title;
259
260 /**
261 * Rating schema type.
262 *
263 * @link https://schema.org/Rating
264 */
265 $review->reviewRating = new stdClass;
266 $review->reviewRating->{"@type"} = 'Rating';
267 $review->reviewRating->bestRating = 5;
268 $review->reviewRating->ratingValue = $tmp->rating;
269 $review->reviewRating->worstRating = 1;
270
271 $json->review[] = $review;
272 }
273 }
274
275 // get supported services
276 $services = $this->employee->get('services');
277
278 // add offers
279 if ($services)
280 {
281 $json->makesOffer = array();
282
283 foreach ($services as $service)
284 {
285 /**
286 * Offer schema type.
287 *
288 * @link https://schema.org/Offer
289 */
290 $offer = new stdClass;
291 $offer->{"@type"} = 'Offer';
292 $offer->name = $service->name;
293 $offer->price = $service->price;
294 $offer->priceCurrency = $config->get('currencyname');
295
296 $json->makesOffer[] = $offer;
297 }
298
299 if (count($json->makesOffer) == 1)
300 {
301 // use a singe offer instead of an array in case
302 // the employee is assigned to only one service
303 $json->makesOffer = $json->makesOffer[0];
304 }
305 }
306
307 // get supported locations
308 $locations = $this->employee->get('locations');
309
310 // add location address
311 if ($locations)
312 {
313 $json->address = array();
314
315 foreach ($locations as $location)
316 {
317 /**
318 * PostalAddress schema type.
319 *
320 * @link https://schema.org/PostalAddress
321 */
322 $addr = new stdClass;
323 $addr->{"@type"} = 'PostalAddress';
324 $addr->name = $location->name;
325 $addr->postalCode = $location->zip;
326 $addr->streetAddress = $location->address;
327
328 if ($location->countryCode2)
329 {
330 $addr->addressCountry = $location->countryCode2;
331 }
332
333 if ($location->stateCode2)
334 {
335 $addr->addressRegion = $location->stateCode2;
336 }
337
338 if ($location->cityName)
339 {
340 $addr->addressLocality = $location->cityName;
341 }
342
343 // add opening hours
344 $worktimes = $this->getEmployeeWorktimes($location->id);
345
346 if ($worktimes)
347 {
348 $addr->hoursAvailable = array();
349
350 foreach ($worktimes as $time)
351 {
352 $addr->hoursAvailable[] = $time;
353 }
354 }
355
356 $json->address[] = $addr;
357 }
358
359 if (count($json->address) == 1)
360 {
361 // use a singe address instead of an array in case
362 // the employee is located in only one venue
363 $json->address = $json->address[0];
364 }
365 }
366
367 // add contact info
368 if ($this->employee->get('email'))
369 {
370 $json->email = $this->employee->get('email');
371 }
372
373 if ($this->employee->get('showphone') && $this->employee->get('phone'))
374 {
375 $json->telephone = $this->employee->get('phone');
376 }
377
378 return true;
379 }
380
381 /**
382 * Returns the employee working times using the
383 * OpeningHoursSpecification schema format.
384 *
385 * @param integer $location The ID of the location for which the employee works.
386 *
387 * @return array The available working times.
388 */
389 protected function getEmployeeWorktimes($location)
390 {
391 if (!isset($this->worktimes))
392 {
393 $dbo = JFactory::getDbo();
394
395 $this->worktimes = array();
396
397 $q = $dbo->getQuery(true)
398 ->select('*')
399 ->from($dbo->qn('#__vikappointments_emp_worktime'))
400 ->where(array(
401 $dbo->qn('id_employee') . ' = ' . $this->employee->get('id'),
402 $dbo->qn('id_service') . ' <= 0',
403 ))
404 ->andWhere(array(
405 $dbo->qn('ts') . ' <= 0',
406 $dbo->qn('ts') . ' BETWEEN ' . strtotime('today 00:00:00') . ' AND ' . strtotime('+7 days 00:00:00'),
407 ), 'OR')
408 ->order(array(
409 $dbo->qn('ts') . ' ASC',
410 $dbo->qn('day') . ' ASC',
411 ));
412
413 $dbo->setQuery($q);
414
415 foreach ($dbo->loadObjectList() as $time)
416 {
417 if (!isset($this->worktimes[$time->id_location]))
418 {
419 $this->worktimes[$time->id_location] = array();
420 }
421
422 $this->worktimes[$time->id_location][] = $time;
423 }
424 }
425
426 $times = array();
427
428 if (isset($this->worktimes[$location]))
429 {
430 $times = $this->worktimes[$location];
431 }
432
433 if ($location > 0 && isset($this->worktimes['-1']))
434 {
435 // merge global working times
436 $times = array_merge($times, $this->worktimes['-1']);
437 }
438
439 $tmp = array();
440
441 foreach ($times as $time)
442 {
443 /**
444 * OpeningHoursSpecification schema type.
445 *
446 * @link https://schema.org/OpeningHoursSpecification
447 */
448 $spec = new stdClass;
449 $spec->{"@type"} = 'OpeningHoursSpecification';
450
451 /**
452 * The place is open if the opens property is specified, and closed otherwise.
453 * So, do not provide *opens* and *closes* in case the working day is closed.
454 */
455 if (!$time->closed)
456 {
457 /**
458 * Swapped times, since the opens property was using the closing time and viceversa.
459 *
460 * @since 1.7
461 */
462 $spec->opens = JHtml::fetch('vikappointments.min2time', $time->fromts, 'H:i:s');
463 $spec->closes = JHtml::fetch('vikappointments.min2time', $time->endts, 'H:i:s');
464 }
465
466 if ($time->ts <= 0)
467 {
468 // day of the week
469 switch ($time->day)
470 {
471 case 1:
472 $spec->dayOfWeek = 'Monday';
473 break;
474
475 case 2:
476 $spec->dayOfWeek = 'Tuesday';
477 break;
478
479 case 3:
480 $spec->dayOfWeek = 'Wednesday';
481 break;
482
483 case 4:
484 $spec->dayOfWeek = 'Thursday';
485 break;
486
487 case 5:
488 $spec->dayOfWeek = 'Friday';
489 break;
490
491 case 6:
492 $spec->dayOfWeek = 'Saturday';
493 break;
494
495 default:
496 $spec->dayOfWeek = 'Sunday';
497
498 }
499
500 $spec->dayOfWeek = 'http://schema.org/' . $spec->dayOfWeek;
501 }
502 else
503 {
504 // day of the year
505 $spec->validFrom = JFactory::getDate($time->tsdate)->format('Y-m-d');
506 $spec->validTo = JFactory::getDate('+1 day ' . $spec->validFrom)->format('Y-m-d');
507 }
508
509 $tmp[] = $spec;
510 }
511
512 return $tmp;
513 }
514 }
515