1<?php
2
3namespace Sabre\VObject\Component;
4
5use DateTimeInterface;
6use Sabre\VObject;
7
8/**
9 * The VFreeBusy component.
10 *
11 * This component adds functionality to a component, specific for VFREEBUSY
12 * components.
13 *
14 * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
15 * @author Evert Pot (http://evertpot.com/)
16 * @license http://sabre.io/license/ Modified BSD License
17 */
18class VFreeBusy extends VObject\Component
19{
20    /**
21     * Checks based on the contained FREEBUSY information, if a timeslot is
22     * available.
23     *
24     * @param DateTimeInterface $start
25     * @param DateTimeInterface $end
26     *
27     * @return bool
28     */
29    public function isFree(DateTimeInterface $start, DatetimeInterface $end)
30    {
31        foreach ($this->select('FREEBUSY') as $freebusy) {
32            // We are only interested in FBTYPE=BUSY (the default),
33            // FBTYPE=BUSY-TENTATIVE or FBTYPE=BUSY-UNAVAILABLE.
34            if (isset($freebusy['FBTYPE']) && 'BUSY' !== strtoupper(substr((string) $freebusy['FBTYPE'], 0, 4))) {
35                continue;
36            }
37
38            // The freebusy component can hold more than 1 value, separated by
39            // commas.
40            $periods = explode(',', (string) $freebusy);
41
42            foreach ($periods as $period) {
43                // Every period is formatted as [start]/[end]. The start is an
44                // absolute UTC time, the end may be an absolute UTC time, or
45                // duration (relative) value.
46                list($busyStart, $busyEnd) = explode('/', $period);
47
48                $busyStart = VObject\DateTimeParser::parse($busyStart);
49                $busyEnd = VObject\DateTimeParser::parse($busyEnd);
50                if ($busyEnd instanceof \DateInterval) {
51                    $busyEnd = $busyStart->add($busyEnd);
52                }
53
54                if ($start < $busyEnd && $end > $busyStart) {
55                    return false;
56                }
57            }
58        }
59
60        return true;
61    }
62
63    /**
64     * A simple list of validation rules.
65     *
66     * This is simply a list of properties, and how many times they either
67     * must or must not appear.
68     *
69     * Possible values per property:
70     *   * 0 - Must not appear.
71     *   * 1 - Must appear exactly once.
72     *   * + - Must appear at least once.
73     *   * * - Can appear any number of times.
74     *   * ? - May appear, but not more than once.
75     *
76     * @var array
77     */
78    public function getValidationRules()
79    {
80        return [
81            'UID' => 1,
82            'DTSTAMP' => 1,
83
84            'CONTACT' => '?',
85            'DTSTART' => '?',
86            'DTEND' => '?',
87            'ORGANIZER' => '?',
88            'URL' => '?',
89
90            'ATTENDEE' => '*',
91            'COMMENT' => '*',
92            'FREEBUSY' => '*',
93            'REQUEST-STATUS' => '*',
94        ];
95    }
96}
97