更新到 5.2 后第一次 SVN 提交。

yuchenghu@hawebs.net



git-svn-id: https://svn.code.sf.net/p/hawebs/svn@543 a2543c7e-f6e9-4f8a-8bff-1ffc34733512
This commit is contained in:
YuCheng Hu
2010-08-21 17:26:39 +00:00
parent d23e9e3a1e
commit 342a9e415e
127 changed files with 10886 additions and 0 deletions
@@ -0,0 +1,15 @@
Changelog for qCal, since Version 0.0.2
---------------------------------------------
January 14, 2010: v0.0.2
--------------------
* Integrated qCal_DateTime sub-components into the library.
* Removed old qCal_Date component (replaced by qCal_DateTime, qCal_DateV2,
which has been renamed qCal_Date, and qCal_Time)
* Added full documentation for the library at http://qcal.lukevisinoni.com/ as
well as inside the "docs" sub-folder.
* Added this changelog.
* Added README and VERSION files.
-- End of Changes --
+165
View File
@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
+33
View File
@@ -0,0 +1,33 @@
qCal iCalendar Library for PHP5, by Luke Visinoni
-------------------------------------------------------------------------------
qCal is an object-oriented, open-source iCalendar library for PHP5.
It is released under the LGPL license.
Homepage: http://qcal.lukevisinoni.com/
Documentation: http://qcal.lukevisinoni.com/doku.php?id=start
Mailing List: http://groups.google.com/group/qcal
Bugs: http://code.google.com/p/qcal/issues/list
Repository: https://qcal.googlecode.com/svn/
Installation
------------
This library requires no installation. At least not in the traditional sense.
Simply upload to a path within PHP's include path and include
"lib/autoload.php".
For more info, visit http://qcal.lukevisinoni.com/doku.php?id=installation
Show your support!
------------------
If you use the library and would like to show your support, feel free to make a
donation. I accept donations via PayPal. You can send me money at the following
e-mail address.
luke.visinoni@gmail.com
I didn't write this library to make money, but I do appreciate donations. In
fact, those users who donate to the project are by far cooler than those who
don't. I like donors better than non-donors. LOL!
@@ -0,0 +1 @@
qCal-v0.0.2
@@ -0,0 +1,15 @@
<?php
/**
* Include this file if you want to use the __autoload feature rather than including
* all of the files manually. It will automatically register its autoload function
* with spl's autoload mechanism.
*/
require_once 'qCal/Loader.php';
function qCal_Autoloader($name) {
qCal_Loader::loadClass($name);
}
spl_autoload_register("qCal_Autoloader");
@@ -0,0 +1,5 @@
<?php
class qCal extends qCal_Component_Vcalendar {
// this is simply a facade to qCal_Component_Calendar, a shortcut
}
?>
@@ -0,0 +1,523 @@
<?php
/**
* Base calendar component class. Events, Todos, and Calendars are
* examples of components in qCal
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* The body of the iCalendar object consists of a sequence of calendar
* properties and one or more calendar components. The calendar
* properties are attributes that apply to the calendar as a whole. The
* calendar components are collections of properties that express a
* particular calendar semantic. For example, the calendar component can
* specify an event, a to-do, a journal entry, time zone information, or
* free/busy time information, or an alarm.
*
* The body of the iCalendar object is defined by the following
* notation:
*
* icalbody = calprops component
*
* calprops = 2*(
*
* ; 'prodid' and 'version' are both REQUIRED,
* ; but MUST NOT occur more than once
*
* prodid /version /
*
* ; 'calscale' and 'method' are optional,
* ; but MUST NOT occur more than once
*
* calscale /
* method /
*
* x-prop
*
* )
*
* component = 1*(eventc / todoc / journalc / freebusyc /
* / timezonec / iana-comp / x-comp)
*
* iana-comp = "BEGIN" ":" iana-token CRLF
*
* 1*contentline
*
* "END" ":" iana-token CRLF
*
* x-comp = "BEGIN" ":" x-name CRLF
*
* 1*contentline
*
* "END" ":" x-name CRLF
*
* An iCalendar object MUST include the "PRODID" and "VERSION" calendar
* properties. In addition, it MUST include at least one calendar
* component. Special forms of iCalendar objects are possible to publish
* just busy time (i.e., only a "VFREEBUSY" calendar component) or time
* zone (i.e., only a "VTIMEZONE" calendar component) information. In
* addition, a complex iCalendar object is possible that is used to
* capture a complete snapshot of the contents of a calendar (e.g.,
* composite of many different calendar components). More commonly, an
* iCalendar object will consist of just a single "VEVENT", "VTODO" or
* "VJOURNAL" calendar component.
*/
abstract class qCal_Component {
/**
* The name of this component
* @var string
*/
protected $name;
/**
* Contains a list of allowed parent components.
* @var array
*/
protected $allowedComponents = array();
/**
* Contains an array of this component's child components (if any). It uses
* @var array
*/
protected $children = array();
/**
* Contains an array of this component's properties. Properties provide
* information about their respective components. This array is associative.
* It uses property name as key and property object as value (or array of them
* if said property can be set multiple times). This is so that I can quickly
* look up any certain property.
* @var array
*/
protected $properties = array();
/**
* Contains an array of this component's required properties
*/
protected $requiredProperties = array();
/**
* Parent component (all components but vcalendar should have one once attached)
*/
protected $parent;
/**
* Class constructor
* Accepts an array of properties, which can be simple values or actual property objects
* Pass in a null value to use a property's default value (some dont have defaults, so beware)
* Example:
* $cal = new qCal_Component_Calendar(array(
* 'prodid' => '-// Some Property Id//',
* 'someotherproperty' => null,
* qCal_Property_Version(2.0),
* ), array(
* qCal_Component_Daylight(),
* ));
*/
public function __construct($properties = array(), $components = array()) {
foreach ($components as $component) {
// if value is an array, then each value inside of it will be a component
if ($component instanceof qCal_Component) {
$this->attach($component);
}
else throw new qCal_Exception_InvalidComponent('The second argument is optional, but if provided, must be an array of components');
}
foreach ($properties as $name => $value) {
// if value is an array, then each value inside of it will be a property
if (is_array($value)) {
foreach ($value as $val) {
if ($val instanceof qCal_Property) {
$this->addProperty($val);
} else {
$this->addProperty($name, $val);
}
}
} else {
if ($value instanceof qCal_Property) {
$this->addProperty($value);
} else {
$this->addProperty($name, $value);
}
}
}
// I think it would make more sense to do validation at render time. That way you don't have
// to have all of the required components and properties when you instantiate. Also, that way
// components don't need to be aware of eachother until render time (or until validate() is called
// explicitly). @todo
// $this->validate();
}
/**
* @todo (lazy load functionality) Check that this is a valid component. This method is sort of lazy-loaded. It only gets called
* if the user has requested data that requires validation and the component has not been validated already.
* @todo Shouldn't this loop over children and validate them too? Maybe optionally?
*/
public function validate() {
// if we're missing any required properties and they have no default, throw an exception
$properties = array();
foreach ($this->getProperties() as $property) {
if (is_array($property)) {
foreach ($property as $prop) {
$properties[] = $prop->getName();
}
} else {
$properties[] = $property->getName();
}
}
$missing = array_diff($this->requiredProperties, array_unique($properties));
foreach ($missing as $propertyname) {
// the property factory will throw an exception if it's passed a null value for a property with no default
try {
$property = qCal_Property::factory($propertyname, null);
$this->addProperty($property);
} catch (qCal_Exception_InvalidPropertyValue $e) {
// if that's the case, catch the exception and throw a missing property exception
throw new qCal_Exception_MissingProperty($this->getName() . " component requires " . $propertyname . " property");
}
}
// this allows per-component validation :)
$this->doValidation();
}
/**
* Returns the component name
* @return string
*/
public function getName() {
return $this->name;
}
/**
* Returns true if this component can be attached to $component
* I'm sure there's a better way to do this, but this works for now
*/
public function canAttachTo(qCal_Component $component) {
if (in_array($component->getName(), $this->allowedComponents)) return true;
}
/**
* Attach a component to this component (alarm inside event for example)
* @todo There may be an issue with the way this is done. When parsing a file, if a component
* or property with a tzid comes before its corresponding vtimezone component, an exception
* will be thrown. I'm don't think the RFC specifies that requirement (that timezone components
* must come before their corresponding tzids)
* @todo Sub-components such as Vevent need to be able to access the main vcalendar object
* for several reasons.
* - If a vtodo has a tzid, it needs to be able to determine that the corresponding
* vtimezone component is available.
* - If components need to relate to eachother, they can only find eachother through
* the main vcalendar object.
* - Freebusy time can only be determined by polling all components in the main vcalendar
* object.
* - More to come probably
*/
public function attach(qCal_Component $component) {
if (!$component->canAttachTo($this)) {
throw new qCal_Exception_InvalidComponent($component->getName() . ' cannot be attached to ' . $this->getName());
}
$component->setParent($this);
// make sure if a timezone is requested that it is available...
$timezones = $this->getTimezones();
$tzids = array_keys($timezones);
// we only need to check if tzid exists if we are attaching something other than a timezone...
if (!($component instanceof qCal_Component_Vtimezone)) {
foreach ($component->getProperties() as $pname => $properties) {
$pname = strtoupper($pname); // probably redundant...
foreach ($properties as $property) {
switch ($pname) {
case "TZID":
$tzid = $property->getValue();
if (!array_key_exists($tzid, $tzids)) {
throw new qCal_Exception_MissingComponent('TZID "' . $tzid . '" not defined');
}
break;
}
$params = $property->getParams();
foreach ($params as $param => $val) {
$param = strtoupper($param); // probably redundant...
switch ($param) {
case "TZID":
$tzid = $val;
if (!array_key_exists($tzid, $tzids)) {
throw new qCal_Exception_MissingComponent('TZID "' . $tzid . '" not defined');
}
break;
}
}
}
}
}
$this->children[$component->getName()][] = $component;
}
/**
* Set the parent of this component
* @todo I'm not sure this will suffice. See the attach method for reasoning behind this.
*/
public function setParent(qCal_Component $component) {
$this->parent = $component;
}
/**
* Get the parent of this component (if there is one)
*/
public function getParent() {
return $this->parent;
}
/**
* The only thing I need this for so far is the parser, but it may come in handy for the facade as well
*/
static public function factory($name, $properties = array()) {
if (empty($name)) return false;
// capitalize
$component = ucfirst(strtolower($name));
$className = "qCal_Component_" . $component;
$fileName = str_replace("_", DIRECTORY_SEPARATOR, $className) . ".php";
qCal_Loader::loadFile($fileName);
$class = new $className($properties);
return $class;
}
/**
* I'm not sure how this should work. Not sure if it should be setProperty,
* addProperty, both? Because properties on some components can be set multiple
* times, while some properties have multiple values. :( I am trying to consider
* a case where somebody needs to open a calendar, change a few properties on a
* component (change event time for instance). I think the way I'll handle properties
* that can be set multiple times is I'll create a method do delete properties based
* on values, parameters, etc. since they don't really have IDs. So I tihnk I'll go
* with addProperty :)
*/
public function addProperty($property, $value = null, $params = array()) {
if (!($property instanceof qCal_Property)) {
$property = qCal_Property::factory($property, $value, $params);
}
if (!$property->of($this)) {
throw new qCal_Exception_InvalidProperty($this->getName() . " component does not allow " . $property->getName() . " property");
}
if (!$property->allowMultiple()) {
unset($this->properties[$property->getName()]);
}
$this->properties[$property->getName()][] = $property;
}
/**
* Returns property of this component by name
*
* @todo Since the same property can appear in a component more than once, this method
* doesn't make that much sense unless it returns all of the instances of the property
* @return array of qCal_Property
*/
public function getProperty($name) {
$name = strtoupper($name);
if ($this->hasProperty($name)) {
return $this->properties[$name];
}
}
/**
* Returns true if this component contains a property of $name
*
* @return boolean
*/
public function hasProperty($name) {
$name = strtoupper($name);
return isset($this->properties[$name]);
}
/**
* Returns true if this component contains a property of $name
*
* @return boolean
*/
public function hasComponent($name) {
$name = strtoupper($name);
return isset($this->children[$name]);
}
/**
* Returns the child component requested
*/
public function getComponent($name) {
$name = strtoupper($name);
if ($this->hasComponent($name)) {
return $this->children[$name];
}
}
/*
public function clearProperties() {
$this->properties = array();
}
public function clearChildren() {
$this->children = array();
}
*/
public function getProperties() {
return $this->properties;
}
public function getChildren() {
return $this->children;
}
/**
* Gets the parent-most component in the tree. I would really like to come up
* with a cleaner way to access other components from within a component, but oh well.
*/
public function getRootComponent() {
$parent = $this;
while (!($parent instanceof qCal_Component_Vcalendar)) {
if (!$parent->getParent()) break;
$parent = $parent->getParent();
}
return $parent;
}
/**
* Renders the calendar, by default in icalendar format. If you pass
* in a renderer, it will use that instead
*
* @return mixed Depends on the renderer
* @todo Would it make more sense to pass the component to the renderer, or the renderer
* to the component? I'm not sure components should know about rendering.
*/
public function render(qCal_Renderer $renderer = null) {
$this->validate();
if (is_null($renderer)) $renderer = new qCal_Renderer_iCalendar();
return $renderer->render($this);
}
/**
* Output the icalendar component as a string (render it)
*/
public function __toString() {
return $this->render();
}
/**
* getFreeBusyTime
* Looks through all of the data in the calendar and returns a qCal_Component_Vfreebusy object
* with free/busy time from $startdate to $enddate. The component will contain all components, but some
* may have their transparency set to "transparent".
* @todo This cannot be finished until recurring events are finished, since free/busy does not allow
* recurrence rules, each instance of a recurrence would need to be calculated out and passed into the free/busy
* component, so that the component would contain concrete instances of each event recurrence.
*/
public function getFreeBusyTime() {
$root = $this->getRootComponent();
foreach ($root->getChildren() as $children) {
foreach ($children as $child) {
// now get the object's free/busy time
}
}
}
/**
* getTimeZones
*/
public function getTimezones() {
$tzs = array();
$root = $this->getRootComponent();
foreach ($root->getChildren() as $children) {
foreach ($children as $child) {
// if the child is a vtimezone, add it to the results
// @todo make sure that tzid is available, throw exception otherwise
if ($child instanceof qCal_Component_Vtimezone) {
$tzid = $child->getTzid();
$tzid = strtoupper($tzid);
$tzs[$tzid] = $child;
}
}
}
return $tzs;
}
/**
* Get a specific timezone by tzid
* @param string The timezone identifier
*/
public function getTimezone($tzid) {
$tzid = strtoupper($tzid);
$root = $this->getRootComponent();
$timezones = $root->getTimezones();
if (array_key_exists($tzid, $timezones)) {
return $timezones[$tzid];
}
return false;
}
/**
* Allows for components to get and set property values by calling
* qCal_Component::getPropertyName() and qCal_Component::setPropertyName('2.0') where propertyName is the property name
* to be set and $val is the property value.
* This is just a convenience facade, it isn't going to be used within the library as much as by end-users
* @todo I can't decided whether to maybe get rid of the facade methods at least for now since some properties
* can potentially return multiple values and that makes the interface inconsistent
*/
public function __call($method, $params) {
$firstthree = substr($method, 0, 3);
$name = substr($method, 3);
if ($firstthree == "get") {
// if property is allowed multiple times, an array is returned, otherwise just the one component
if ($this->hasProperty($name)) {
$property = $this->getProperty($name);
if (!$property[0]->allowMultiple()) {
return $property[0];
} else {
return $property;
}
}
} elseif ($firstthree == "set") {
$value = isset($params[0]) ? $params[0] : null;
$params = isset($params[1]) ? $params[1] : array();
$property = qCal_Property::factory($name, $value, $params);
$this->addProperty($property);
} elseif ($firstthree == "add") {
// add property type
$property = qCal_Property::factory($name, $params);
$this->addProperty($property);
return $this;
}
// throw exception here?
// throw new qCal_Exception();
}
}
@@ -0,0 +1,367 @@
<?php
/**
* Timezone Component
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Component Name: VTIMEZONE
*
* Purpose: Provide a grouping of component properties that defines a
* time zone.
*
* Formal Definition: A "VTIMEZONE" calendar component is defined by the
* following notation:
*
* timezonec = "BEGIN" ":" "VTIMEZONE" CRLF
*
* 2*(
*
* ; 'tzid' is required, but MUST NOT occur more
* ; than once
*
* tzid /
*
* ; 'last-mod' and 'tzurl' are optional,
* but MUST NOT occur more than once
*
* last-mod / tzurl /
*
* ; one of 'standardc' or 'daylightc' MUST occur
* ..; and each MAY occur more than once.
*
* standardc / daylightc /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* x-prop
*
* )
*
* "END" ":" "VTIMEZONE" CRLF
*
* standardc = "BEGIN" ":" "STANDARD" CRLF
*
* tzprop
*
* "END" ":" "STANDARD" CRLF
*
* daylightc = "BEGIN" ":" "DAYLIGHT" CRLF
*
* tzprop
*
* "END" ":" "DAYLIGHT" CRLF
*
* tzprop = 3*(
*
* ; the following are each REQUIRED,
* ; but MUST NOT occur more than once
*
* dtstart / tzoffsetto / tzoffsetfrom /
*
* ; the following are optional,
* ; and MAY occur more than once
*
* comment / rdate / rrule / tzname / x-prop
*
* )
*
* Description: A time zone is unambiguously defined by the set of time
* measurement rules determined by the governing body for a given
* geographic area. These rules describe at a minimum the base offset
* from UTC for the time zone, often referred to as the Standard Time
* offset. Many locations adjust their Standard Time forward or backward
* by one hour, in order to accommodate seasonal changes in number of
* daylight hours, often referred to as Daylight Saving Time. Some
* locations adjust their time by a fraction of an hour. Standard Time
* is also known as Winter Time. Daylight Saving Time is also known as
* Advanced Time, Summer Time, or Legal Time in certain countries. The
* following table shows the changes in time zone rules in effect for
* New York City starting from 1967. Each line represents a description
* or rule for a particular observance.
*
* Effective Observance Rule
*
* Date (Date/Time) Offset Abbreviation
*
* 1967-* last Sun in Oct, 02:00 -0500 EST
*
* 1967-1973 last Sun in Apr, 02:00 -0400 EDT
*
* 1974-1974 Jan 6, 02:00 -0400 EDT
*
* 1975-1975 Feb 23, 02:00 -0400 EDT
*
* 1976-1986 last Sun in Apr, 02:00 -0400 EDT
*
* 1987-* first Sun in Apr, 02:00 -0400 EDT
*
* Note: The specification of a global time zone registry is not
* addressed by this document and is left for future study.
* However, implementers may find the Olson time zone database [TZ]
* a useful reference. It is an informal, public-domain collection
* of time zone information, which is currently being maintained by
* volunteer Internet participants, and is used in several
* operating systems. This database contains current and historical
* time zone information for a wide variety of locations around the
* globe; it provides a time zone identifier for every unique time
* zone rule set in actual use since 1970, with historical data
* going back to the introduction of standard time.
*
* Interoperability between two calendaring and scheduling applications,
* especially for recurring events, to-dos or journal entries, is
* dependent on the ability to capture and convey date and time
* information in an unambiguous format. The specification of current
* time zone information is integral to this behavior.
*
* If present, the "VTIMEZONE" calendar component defines the set of
* Standard Time and Daylight Saving Time observances (or rules) for a
* particular time zone for a given interval of time. The "VTIMEZONE"
* calendar component cannot be nested within other calendar components.
* Multiple "VTIMEZONE" calendar components can exist in an iCalendar
* object. In this situation, each "VTIMEZONE" MUST represent a unique
*
* time zone definition. This is necessary for some classes of events,
* such as airline flights, that start in one time zone and end in
* another.
*
* The "VTIMEZONE" calendar component MUST be present if the iCalendar
* object contains an RRULE that generates dates on both sides of a time
* zone shift (e.g. both in Standard Time and Daylight Saving Time)
* unless the iCalendar object intends to convey a floating time (See
* the section "4.1.10.11 Time" for proper interpretation of floating
* time). It can be present if the iCalendar object does not contain
* such a RRULE. In addition, if a RRULE is present, there MUST be valid
* time zone information for all recurrence instances.
*
* The "VTIMEZONE" calendar component MUST include the "TZID" property
* and at least one definition of a standard or daylight component. The
* standard or daylight component MUST include the "DTSTART",
* "TZOFFSETFROM" and "TZOFFSETTO" properties.
*
* An individual "VTIMEZONE" calendar component MUST be specified for
* each unique "TZID" parameter value specified in the iCalendar object.
*
* Each "VTIMEZONE" calendar component consists of a collection of one
* or more sub-components that describe the rule for a particular
* observance (either a Standard Time or a Daylight Saving Time
* observance). The "STANDARD" sub-component consists of a collection of
* properties that describe Standard Time. The "DAYLIGHT" sub-component
* consists of a collection of properties that describe Daylight Saving
* Time. In general this collection of properties consists of:
*
* - the first onset date-time for the observance
*
* - the last onset date-time for the observance, if a last onset
* is known.
*
* - the offset to be applied for the observance
*
* - a rule that describes the day and time when the observance
* takes effect
*
* - an optional name for the observance
*
* For a given time zone, there may be multiple unique definitions of
* the observances over a period of time. Each observance is described
* using either a "STANDARD" or "DAYLIGHT" sub-component. The collection
* of these sub-components is used to describe the time zone for a given
* period of time. The offset to apply at any given time is found by
* locating the observance that has the last onset date and time before
* the time in question, and using the offset value from that
* observance.
*
* The top-level properties in a "VTIMEZONE" calendar component are:
*
* The mandatory "TZID" property is a text value that uniquely
* identifies the VTIMZONE calendar component within the scope of an
* iCalendar object.
*
* The optional "LAST-MODIFIED" property is a UTC value that specifies
* the date and time that this time zone definition was last updated.
*
* The optional "TZURL" property is url value that points to a published
* VTIMEZONE definition. TZURL SHOULD refer to a resource that is
* accessible by anyone who might need to interpret the object. This
* SHOULD NOT normally be a file: URL or other URL that is not widely-
* accessible.
*
* The collection of properties that are used to define the STANDARD and
* DAYLIGHT sub-components include:
*
* The mandatory "DTSTART" property gives the effective onset date and
* local time for the time zone sub-component definition. "DTSTART" in
* this usage MUST be specified as a local DATE-TIME value.
*
* The mandatory "TZOFFSETFROM" property gives the UTC offset which is
* in use when the onset of this time zone observance begins.
* "TZOFFSETFROM" is combined with "DTSTART" to define the effective
* onset for the time zone sub-component definition. For example, the
* following represents the time at which the observance of Standard
* Time took effect in Fall 1967 for New York City:
*
* DTSTART:19671029T020000
*
* TZOFFSETFROM:-0400
*
* The mandatory "TZOFFSETTO " property gives the UTC offset for the
* time zone sub-component (Standard Time or Daylight Saving Time) when
* this observance is in use.
*
* The optional "TZNAME" property is the customary name for the time
* zone. It may be specified multiple times, to allow for specifying
* multiple language variants of the time zone names. This could be used
* for displaying dates.
*
* If specified, the onset for the observance defined by the time zone
* sub-component is defined by either the "RRULE" or "RDATE" property.
* If neither is specified, only one sub-component can be specified in
* the "VTIMEZONE" calendar component and it is assumed that the single
* observance specified is always in effect.
*
* The "RRULE" property defines the recurrence rule for the onset of the
* observance defined by this time zone sub-component. Some specific
* requirements for the usage of RRULE for this purpose include:
*
* - If observance is known to have an effective end date, the
* "UNTIL" recurrence rule parameter MUST be used to specify the
* last valid onset of this observance (i.e., the UNTIL date-time
* will be equal to the last instance generated by the recurrence
* pattern). It MUST be specified in UTC time.
*
* - The "DTSTART" and the "TZOFFSETTO" properties MUST be used
* when generating the onset date-time values (instances) from the
* RRULE.
*
* Alternatively, the "RDATE" property can be used to define the onset
* of the observance by giving the individual onset date and times.
* "RDATE" in this usage MUST be specified as a local DATE-TIME value in
* UTC time.
*
* The optional "COMMENT" property is also allowed for descriptive
* explanatory text.
*
* Example: The following are examples of the "VTIMEZONE" calendar
* component:
*
* This is an example showing time zone information for the Eastern
* United States using "RDATE" property. Note that this is only suitable
* for a recurring event that starts on or later than April 6, 1997 at
* 03:00:00 EDT (i.e., the earliest effective transition date and time)
* and ends no later than April 7, 1998 02:00:00 EST (i.e., latest valid
* date and time for EST in this scenario). For example, this can be
* used for a recurring event that occurs every Friday, 8am-9:00 AM,
* starting June 1, 1997, ending December 31, 1997.
*
* BEGIN:VTIMEZONE
* TZID:US-Eastern
* LAST-MODIFIED:19870101T000000Z
* BEGIN:STANDARD
* DTSTART:19971026T020000
* RDATE:19971026T020000
* TZOFFSETFROM:-0400
* TZOFFSETTO:-0500
* TZNAME:EST
* END:STANDARD
* BEGIN:DAYLIGHT
* DTSTART:19971026T020000
* RDATE:19970406T020000
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* END:VTIMEZONE
*
* This is a simple example showing the current time zone rules for the
* Eastern United States using a RRULE recurrence pattern. Note that
* there is no effective end date to either of the Standard Time or
* Daylight Time rules. This information would be valid for a recurring
* event starting today and continuing indefinitely.
*
* BEGIN:VTIMEZONE
* TZID:US-Eastern
* LAST-MODIFIED:19870101T000000Z
* TZURL:http://zones.stds_r_us.net/tz/US-Eastern
* BEGIN:STANDARD
* DTSTART:19671029T020000
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
* TZOFFSETFROM:-0400
* TZOFFSETTO:-0500
* TZNAME:EST
* END:STANDARD
* BEGIN:DAYLIGHT
* DTSTART:19870405T020000
* RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* END:VTIMEZONE
*
* This is an example showing a fictitious set of rules for the Eastern
* United States, where the Daylight Time rule has an effective end date
* (i.e., after that date, Daylight Time is no longer observed).
*
* BEGIN:VTIMEZONE
* TZID:US--Fictitious-Eastern
* LAST-MODIFIED:19870101T000000Z
* BEGIN:STANDARD
* DTSTART:19671029T020000
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
* TZOFFSETFROM:-0400
* TZOFFSETTO:-0500
* TZNAME:EST
* END:STANDARD
*
*
* BEGIN:DAYLIGHT
* DTSTART:19870405T020000
* RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=19980404T070000Z
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* END:VTIMEZONE
*
* This is an example showing a fictitious set of rules for the Eastern
* United States, where the first Daylight Time rule has an effective
* end date. There is a second Daylight Time rule that picks up where
* the other left off.
*
* BEGIN:VTIMEZONE
* TZID:US--Fictitious-Eastern
* LAST-MODIFIED:19870101T000000Z
* BEGIN:STANDARD
* DTSTART:19671029T020000
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
* TZOFFSETFROM:-0400
* TZOFFSETTO:-0500
* TZNAME:EST
* END:STANDARD
* BEGIN:DAYLIGHT
* DTSTART:19870405T020000
* RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=19980404T070000Z
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* BEGIN:DAYLIGHT
* DTSTART:19990424T020000
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=4
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* END:VTIMEZONE
*/
class qCal_Component_Daylight extends qCal_Component {
protected $name = "DAYLIGHT";
protected $allowedComponents = array('VTIMEZONE');
protected $requiredProperties = array('DTSTART','TZOFFSETFROM','TZOFFSETTO');
}
@@ -0,0 +1,367 @@
<?php
/**
* Timezone Component
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Component Name: VTIMEZONE
*
* Purpose: Provide a grouping of component properties that defines a
* time zone.
*
* Formal Definition: A "VTIMEZONE" calendar component is defined by the
* following notation:
*
* timezonec = "BEGIN" ":" "VTIMEZONE" CRLF
*
* 2*(
*
* ; 'tzid' is required, but MUST NOT occur more
* ; than once
*
* tzid /
*
* ; 'last-mod' and 'tzurl' are optional,
* but MUST NOT occur more than once
*
* last-mod / tzurl /
*
* ; one of 'standardc' or 'daylightc' MUST occur
* ..; and each MAY occur more than once.
*
* standardc / daylightc /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* x-prop
*
* )
*
* "END" ":" "VTIMEZONE" CRLF
*
* standardc = "BEGIN" ":" "STANDARD" CRLF
*
* tzprop
*
* "END" ":" "STANDARD" CRLF
*
* daylightc = "BEGIN" ":" "DAYLIGHT" CRLF
*
* tzprop
*
* "END" ":" "DAYLIGHT" CRLF
*
* tzprop = 3*(
*
* ; the following are each REQUIRED,
* ; but MUST NOT occur more than once
*
* dtstart / tzoffsetto / tzoffsetfrom /
*
* ; the following are optional,
* ; and MAY occur more than once
*
* comment / rdate / rrule / tzname / x-prop
*
* )
*
* Description: A time zone is unambiguously defined by the set of time
* measurement rules determined by the governing body for a given
* geographic area. These rules describe at a minimum the base offset
* from UTC for the time zone, often referred to as the Standard Time
* offset. Many locations adjust their Standard Time forward or backward
* by one hour, in order to accommodate seasonal changes in number of
* daylight hours, often referred to as Daylight Saving Time. Some
* locations adjust their time by a fraction of an hour. Standard Time
* is also known as Winter Time. Daylight Saving Time is also known as
* Advanced Time, Summer Time, or Legal Time in certain countries. The
* following table shows the changes in time zone rules in effect for
* New York City starting from 1967. Each line represents a description
* or rule for a particular observance.
*
* Effective Observance Rule
*
* Date (Date/Time) Offset Abbreviation
*
* 1967-* last Sun in Oct, 02:00 -0500 EST
*
* 1967-1973 last Sun in Apr, 02:00 -0400 EDT
*
* 1974-1974 Jan 6, 02:00 -0400 EDT
*
* 1975-1975 Feb 23, 02:00 -0400 EDT
*
* 1976-1986 last Sun in Apr, 02:00 -0400 EDT
*
* 1987-* first Sun in Apr, 02:00 -0400 EDT
*
* Note: The specification of a global time zone registry is not
* addressed by this document and is left for future study.
* However, implementers may find the Olson time zone database [TZ]
* a useful reference. It is an informal, public-domain collection
* of time zone information, which is currently being maintained by
* volunteer Internet participants, and is used in several
* operating systems. This database contains current and historical
* time zone information for a wide variety of locations around the
* globe; it provides a time zone identifier for every unique time
* zone rule set in actual use since 1970, with historical data
* going back to the introduction of standard time.
*
* Interoperability between two calendaring and scheduling applications,
* especially for recurring events, to-dos or journal entries, is
* dependent on the ability to capture and convey date and time
* information in an unambiguous format. The specification of current
* time zone information is integral to this behavior.
*
* If present, the "VTIMEZONE" calendar component defines the set of
* Standard Time and Daylight Saving Time observances (or rules) for a
* particular time zone for a given interval of time. The "VTIMEZONE"
* calendar component cannot be nested within other calendar components.
* Multiple "VTIMEZONE" calendar components can exist in an iCalendar
* object. In this situation, each "VTIMEZONE" MUST represent a unique
*
* time zone definition. This is necessary for some classes of events,
* such as airline flights, that start in one time zone and end in
* another.
*
* The "VTIMEZONE" calendar component MUST be present if the iCalendar
* object contains an RRULE that generates dates on both sides of a time
* zone shift (e.g. both in Standard Time and Daylight Saving Time)
* unless the iCalendar object intends to convey a floating time (See
* the section "4.1.10.11 Time" for proper interpretation of floating
* time). It can be present if the iCalendar object does not contain
* such a RRULE. In addition, if a RRULE is present, there MUST be valid
* time zone information for all recurrence instances.
*
* The "VTIMEZONE" calendar component MUST include the "TZID" property
* and at least one definition of a standard or daylight component. The
* standard or daylight component MUST include the "DTSTART",
* "TZOFFSETFROM" and "TZOFFSETTO" properties.
*
* An individual "VTIMEZONE" calendar component MUST be specified for
* each unique "TZID" parameter value specified in the iCalendar object.
*
* Each "VTIMEZONE" calendar component consists of a collection of one
* or more sub-components that describe the rule for a particular
* observance (either a Standard Time or a Daylight Saving Time
* observance). The "STANDARD" sub-component consists of a collection of
* properties that describe Standard Time. The "DAYLIGHT" sub-component
* consists of a collection of properties that describe Daylight Saving
* Time. In general this collection of properties consists of:
*
* - the first onset date-time for the observance
*
* - the last onset date-time for the observance, if a last onset
* is known.
*
* - the offset to be applied for the observance
*
* - a rule that describes the day and time when the observance
* takes effect
*
* - an optional name for the observance
*
* For a given time zone, there may be multiple unique definitions of
* the observances over a period of time. Each observance is described
* using either a "STANDARD" or "DAYLIGHT" sub-component. The collection
* of these sub-components is used to describe the time zone for a given
* period of time. The offset to apply at any given time is found by
* locating the observance that has the last onset date and time before
* the time in question, and using the offset value from that
* observance.
*
* The top-level properties in a "VTIMEZONE" calendar component are:
*
* The mandatory "TZID" property is a text value that uniquely
* identifies the VTIMZONE calendar component within the scope of an
* iCalendar object.
*
* The optional "LAST-MODIFIED" property is a UTC value that specifies
* the date and time that this time zone definition was last updated.
*
* The optional "TZURL" property is url value that points to a published
* VTIMEZONE definition. TZURL SHOULD refer to a resource that is
* accessible by anyone who might need to interpret the object. This
* SHOULD NOT normally be a file: URL or other URL that is not widely-
* accessible.
*
* The collection of properties that are used to define the STANDARD and
* DAYLIGHT sub-components include:
*
* The mandatory "DTSTART" property gives the effective onset date and
* local time for the time zone sub-component definition. "DTSTART" in
* this usage MUST be specified as a local DATE-TIME value.
*
* The mandatory "TZOFFSETFROM" property gives the UTC offset which is
* in use when the onset of this time zone observance begins.
* "TZOFFSETFROM" is combined with "DTSTART" to define the effective
* onset for the time zone sub-component definition. For example, the
* following represents the time at which the observance of Standard
* Time took effect in Fall 1967 for New York City:
*
* DTSTART:19671029T020000
*
* TZOFFSETFROM:-0400
*
* The mandatory "TZOFFSETTO " property gives the UTC offset for the
* time zone sub-component (Standard Time or Daylight Saving Time) when
* this observance is in use.
*
* The optional "TZNAME" property is the customary name for the time
* zone. It may be specified multiple times, to allow for specifying
* multiple language variants of the time zone names. This could be used
* for displaying dates.
*
* If specified, the onset for the observance defined by the time zone
* sub-component is defined by either the "RRULE" or "RDATE" property.
* If neither is specified, only one sub-component can be specified in
* the "VTIMEZONE" calendar component and it is assumed that the single
* observance specified is always in effect.
*
* The "RRULE" property defines the recurrence rule for the onset of the
* observance defined by this time zone sub-component. Some specific
* requirements for the usage of RRULE for this purpose include:
*
* - If observance is known to have an effective end date, the
* "UNTIL" recurrence rule parameter MUST be used to specify the
* last valid onset of this observance (i.e., the UNTIL date-time
* will be equal to the last instance generated by the recurrence
* pattern). It MUST be specified in UTC time.
*
* - The "DTSTART" and the "TZOFFSETTO" properties MUST be used
* when generating the onset date-time values (instances) from the
* RRULE.
*
* Alternatively, the "RDATE" property can be used to define the onset
* of the observance by giving the individual onset date and times.
* "RDATE" in this usage MUST be specified as a local DATE-TIME value in
* UTC time.
*
* The optional "COMMENT" property is also allowed for descriptive
* explanatory text.
*
* Example: The following are examples of the "VTIMEZONE" calendar
* component:
*
* This is an example showing time zone information for the Eastern
* United States using "RDATE" property. Note that this is only suitable
* for a recurring event that starts on or later than April 6, 1997 at
* 03:00:00 EDT (i.e., the earliest effective transition date and time)
* and ends no later than April 7, 1998 02:00:00 EST (i.e., latest valid
* date and time for EST in this scenario). For example, this can be
* used for a recurring event that occurs every Friday, 8am-9:00 AM,
* starting June 1, 1997, ending December 31, 1997.
*
* BEGIN:VTIMEZONE
* TZID:US-Eastern
* LAST-MODIFIED:19870101T000000Z
* BEGIN:STANDARD
* DTSTART:19971026T020000
* RDATE:19971026T020000
* TZOFFSETFROM:-0400
* TZOFFSETTO:-0500
* TZNAME:EST
* END:STANDARD
* BEGIN:DAYLIGHT
* DTSTART:19971026T020000
* RDATE:19970406T020000
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* END:VTIMEZONE
*
* This is a simple example showing the current time zone rules for the
* Eastern United States using a RRULE recurrence pattern. Note that
* there is no effective end date to either of the Standard Time or
* Daylight Time rules. This information would be valid for a recurring
* event starting today and continuing indefinitely.
*
* BEGIN:VTIMEZONE
* TZID:US-Eastern
* LAST-MODIFIED:19870101T000000Z
* TZURL:http://zones.stds_r_us.net/tz/US-Eastern
* BEGIN:STANDARD
* DTSTART:19671029T020000
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
* TZOFFSETFROM:-0400
* TZOFFSETTO:-0500
* TZNAME:EST
* END:STANDARD
* BEGIN:DAYLIGHT
* DTSTART:19870405T020000
* RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* END:VTIMEZONE
*
* This is an example showing a fictitious set of rules for the Eastern
* United States, where the Daylight Time rule has an effective end date
* (i.e., after that date, Daylight Time is no longer observed).
*
* BEGIN:VTIMEZONE
* TZID:US--Fictitious-Eastern
* LAST-MODIFIED:19870101T000000Z
* BEGIN:STANDARD
* DTSTART:19671029T020000
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
* TZOFFSETFROM:-0400
* TZOFFSETTO:-0500
* TZNAME:EST
* END:STANDARD
*
*
* BEGIN:DAYLIGHT
* DTSTART:19870405T020000
* RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=19980404T070000Z
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* END:VTIMEZONE
*
* This is an example showing a fictitious set of rules for the Eastern
* United States, where the first Daylight Time rule has an effective
* end date. There is a second Daylight Time rule that picks up where
* the other left off.
*
* BEGIN:VTIMEZONE
* TZID:US--Fictitious-Eastern
* LAST-MODIFIED:19870101T000000Z
* BEGIN:STANDARD
* DTSTART:19671029T020000
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
* TZOFFSETFROM:-0400
* TZOFFSETTO:-0500
* TZNAME:EST
* END:STANDARD
* BEGIN:DAYLIGHT
* DTSTART:19870405T020000
* RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=19980404T070000Z
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* BEGIN:DAYLIGHT
* DTSTART:19990424T020000
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=4
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* END:VTIMEZONE
*/
class qCal_Component_Standard extends qCal_Component {
protected $name = "STANDARD";
protected $allowedComponents = array('VTIMEZONE');
protected $requiredProperties = array('DTSTART','TZOFFSETFROM','TZOFFSETTO');
}
@@ -0,0 +1,339 @@
<?php
/**
* Alarm Component
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Purpose: Provide a grouping of component properties that define an
* alarm.
*
* Formal Definition: A "VALARM" calendar component is defined by the
* following notation:
*
* alarmc = "BEGIN" ":" "VALARM" CRLF
* (audioprop / dispprop / emailprop / procprop)
* "END" ":" "VALARM" CRLF
*
* audioprop = 2*(
*
* ; 'action' and 'trigger' are both REQUIRED,
* ; but MUST NOT occur more than once
*
* action / trigger /
*
* ; 'duration' and 'repeat' are both optional,
* ; and MUST NOT occur more than once each,
* ; but if one occurs, so MUST the other
*
* duration / repeat /
*
* ; the following is optional,
* ; but MUST NOT occur more than once
*
* attach /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* x-prop
*
* )
*
* dispprop = 3*(
*
* ; the following are all REQUIRED,
* ; but MUST NOT occur more than once
*
* action / description / trigger /
*
* ; 'duration' and 'repeat' are both optional,
* ; and MUST NOT occur more than once each,
* ; but if one occurs, so MUST the other
*
* duration / repeat /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* *x-prop
*
* )
*
* emailprop = 5*(
*
* ; the following are all REQUIRED,
* ; but MUST NOT occur more than once
*
* action / description / trigger / summary
*
* ; the following is REQUIRED,
* ; and MAY occur more than once
*
* attendee /
*
* ; 'duration' and 'repeat' are both optional,
* ; and MUST NOT occur more than once each,
* ; but if one occurs, so MUST the other
*
* duration / repeat /
*
* ; the following are optional,
* ; and MAY occur more than once
*
* attach / x-prop
*
* )
*
* procprop = 3*(
*
* ; the following are all REQUIRED,
* ; but MUST NOT occur more than once
*
* action / attach / trigger /
*
* ; 'duration' and 'repeat' are both optional,
* ; and MUST NOT occur more than once each,
* ; but if one occurs, so MUST the other
*
* duration / repeat /
*
* ; 'description' is optional,
* ; and MUST NOT occur more than once
*
* description /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* x-prop
*
* )
*
* Description: A "VALARM" calendar component is a grouping of component
* properties that is a reminder or alarm for an event or a to-do. For
* example, it may be used to define a reminder for a pending event or
* an overdue to-do.
*
* The "VALARM" calendar component MUST include the "ACTION" and
* "TRIGGER" properties. The "ACTION" property further constrains the
* "VALARM" calendar component in the following ways:
*
* When the action is "AUDIO", the alarm can also include one and only
* one "ATTACH" property, which MUST point to a sound resource, which is
* rendered when the alarm is triggered.
*
* When the action is "DISPLAY", the alarm MUST also include a
* "DESCRIPTION" property, which contains the text to be displayed when
* the alarm is triggered.
*
* When the action is "EMAIL", the alarm MUST include a "DESCRIPTION"
* property, which contains the text to be used as the message body, a
* "SUMMARY" property, which contains the text to be used as the message
* subject, and one or more "ATTENDEE" properties, which contain the
* email address of attendees to receive the message. It can also
* include one or more "ATTACH" properties, which are intended to be
* sent as message attachments. When the alarm is triggered, the email
* message is sent.
*
* When the action is "PROCEDURE", the alarm MUST include one and only
* one "ATTACH" property, which MUST point to a procedure resource,
* which is invoked when the alarm is triggered.
*
* The "VALARM" calendar component MUST only appear within either a
* "VEVENT" or "VTODO" calendar component. "VALARM" calendar components
* cannot be nested. Multiple mutually independent "VALARM" calendar
* components can be specified for a single "VEVENT" or "VTODO" calendar
* component.
*
* The "TRIGGER" property specifies when the alarm will be triggered.
* The "TRIGGER" property specifies a duration prior to the start of an
* event or a to-do. The "TRIGGER" edge may be explicitly set to be
* relative to the "START" or "END" of the event or to-do with the
* "RELATED" parameter of the "TRIGGER" property. The "TRIGGER" property
* value type can alternatively be set to an absolute calendar date and
* time of day value.
*
* In an alarm set to trigger on the "START" of an event or to-do, the
* "DTSTART" property MUST be present in the associated event or to-do.
* In an alarm in a "VEVENT" calendar component set to trigger on the
* "END" of the event, either the "DTEND" property MUST be present, or
* the "DTSTART" and "DURATION" properties MUST both be present. In an
* alarm in a "VTODO" calendar component set to trigger on the "END" of
* the to-do, either the "DUE" property MUST be present, or the
* "DTSTART" and "DURATION" properties MUST both be present.
*
* The alarm can be defined such that it triggers repeatedly. A
* definition of an alarm with a repeating trigger MUST include both the
* "DURATION" and "REPEAT" properties. The "DURATION" property specifies
* the delay period, after which the alarm will repeat. The "REPEAT"
* property specifies the number of additional repetitions that the
* alarm will triggered. This repitition count is in addition to the
* initial triggering of the alarm. Both of these properties MUST be
* present in order to specify a repeating alarm. If one of these two
* properties is absent, then the alarm will not repeat beyond the
* initial trigger.
*
* The "ACTION" property is used within the "VALARM" calendar component
* to specify the type of action invoked when the alarm is triggered.
* The "VALARM" properties provide enough information for a specific
* action to be invoked. It is typically the responsibility of a
* "Calendar User Agent" (CUA) to deliver the alarm in the specified
* fashion. An "ACTION" property value of AUDIO specifies an alarm that
* causes a sound to be played to alert the user; DISPLAY specifies an
* alarm that causes a text message to be displayed to the user; EMAIL
* specifies an alarm that causes an electronic email message to be
* delivered to one or more email addresses; and PROCEDURE specifies an
* alarm that causes a procedure to be executed. The "ACTION" property
* MUST specify one and only one of these values.
*
* In an AUDIO alarm, if the optional "ATTACH" property is included, it
* MUST specify an audio sound resource. The intention is that the sound
* will be played as the alarm effect. If an "ATTACH" property is
* specified that does not refer to a sound resource, or if the
* specified sound resource cannot be rendered (because its format is
* unsupported, or because it cannot be retrieved), then the CUA or
* other entity responsible for playing the sound may choose a fallback
* action, such as playing a built-in default sound, or playing no sound
* at all.
*
* In a DISPLAY alarm, the intended alarm effect is for the text value
* of the "DESCRIPTION" property to be displayed to the user.
*
* In an EMAIL alarm, the intended alarm effect is for an email message
* to be composed and delivered to all the addresses specified by the
* "ATTENDEE" properties in the "VALARM" calendar component. The
* "DESCRIPTION" property of the "VALARM" calendar component MUST be
* used as the body text of the message, and the "SUMMARY" property MUST
* be used as the subject text. Any "ATTACH" properties in the "VALARM"
* calendar component SHOULD be sent as attachments to the message.
*
* In a PROCEDURE alarm, the "ATTACH" property in the "VALARM" calendar
* component MUST specify a procedure or program that is intended to be
* invoked as the alarm effect. If the procedure or program is in a
* format that cannot be rendered, then no procedure alarm will be
* invoked. If the "DESCRIPTION" property is present, its value
* specifies the argument string to be passed to the procedure or
* program. "Calendar User Agents" that receive an iCalendar object with
* this category of alarm, can disable or allow the "Calendar User" to
* disable, or otherwise ignore this type of alarm. While a very useful
* alarm capability, the PROCEDURE type of alarm SHOULD be treated by
* the "Calendar User Agent" as a potential security risk.
*
* Example: The following example is for a "VALARM" calendar component
* that specifies an audio alarm that will sound at a precise time and
* repeat 4 more times at 15 minute intervals:
*
* BEGIN:VALARM
* TRIGGER;VALUE=DATE-TIME:19970317T133000Z
* REPEAT:4
* DURATION:PT15M
* ACTION:AUDIO
* ATTACH;FMTTYPE=audio/basic:ftp://host.com/pub/sounds/bell-01.aud
* END:VALARM
*
* The following example is for a "VALARM" calendar component that
* specifies a display alarm that will trigger 30 minutes before the
* scheduled start of the event or the due date/time of the to-do it is
* associated with and will repeat 2 more times at 15 minute intervals:
*
* BEGIN:VALARM
* TRIGGER:-PT30M
* REPEAT:2
* DURATION:PT15M
* ACTION:DISPLAY
* DESCRIPTION:Breakfast meeting with executive\n
* team at 8:30 AM EST.
* END:VALARM
*
* The following example is for a "VALARM" calendar component that
* specifies an email alarm that will trigger 2 days before the
* scheduled due date/time of a to-do it is associated with. It does not
* repeat. The email has a subject, body and attachment link.
*
* BEGIN:VALARM
* TRIGGER:-P2D
* ACTION:EMAIL
* ATTENDEE:MAILTO:john_doe@host.com
* SUMMARY:*** REMINDER: SEND AGENDA FOR WEEKLY STAFF MEETING ***
* DESCRIPTION:A draft agenda needs to be sent out to the attendees
* to the weekly managers meeting (MGR-LIST). Attached is a
* pointer the document template for the agenda file.
* ATTACH;FMTTYPE=application/binary:http://host.com/templates/agen
* da.doc
* END:VALARM
*
* The following example is for a "VALARM" calendar component that
* specifies a procedural alarm that will trigger at a precise date/time
* and will repeat 23 more times at one hour intervals. The alarm will
* invoke a procedure file.
*
* BEGIN:VALARM
* TRIGGER;VALUE=DATE-TIME:19980101T050000Z
* REPEAT:23
* DURATION:PT1H
* ACTION:PROCEDURE
* ATTACH;FMTTYPE=application/binary:ftp://host.com/novo-
* procs/felizano.exe
* END:VALARM
*/
class qCal_Component_Valarm extends qCal_Component {
protected $name = "VALARM";
protected $allowedComponents = array('VEVENT','VTODO');
protected $requiredProperties = array('ACTION', 'TRIGGER');
protected function doValidation() {
$action = $this->getAction();
switch(strtoupper($action->getValue())) {
case "AUDIO":
// action, trigger (already covered by parent constructor)
// attach can only occur once
$attach = $this->getProperty('ATTACH');
if (count($attach) > 1) {
throw new qCal_Exception_InvalidProperty('VALARM audio component can contain one and only one ATTACH property');
}
break;
case "DISPLAY":
// action, trigger, description
if (!$this->hasProperty('DESCRIPTION')) {
throw new qCal_Exception_MissingProperty("DISPLAY VALARM component requires DESCRIPTION property");
}
break;
case "EMAIL":
// action, description, trigger, summary
if (!$this->hasProperty('DESCRIPTION')) {
throw new qCal_Exception_MissingProperty("EMAIL VALARM component requires DESCRIPTION property");
}
if (!$this->hasProperty('SUMMARY')) {
throw new qCal_Exception_MissingProperty("EMAIL VALARM component requires SUMMARY property");
}
break;
case "PROCEDURE":
// action, attach, trigger
$attach = $this->getProperty('ATTACH');
if (count($attach) > 1) {
throw new qCal_Exception_InvalidProperty('VALARM procedure component can contain one and only one ATTACH property');
}
if (count($attach) < 1) {
throw new qCal_Exception_MissingProperty("PROCEDURE VALARM component requires ATTACH property");
}
break;
}
if ($this->hasProperty('DURATION')) {
if (!$this->hasProperty('REPEAT')) {
throw new qCal_Exception_MissingProperty("VALARM component with a DURATION property requires a REPEAT property");
}
}
if ($this->hasProperty('REPEAT')) {
if (!$this->hasProperty('DURATION')) {
throw new qCal_Exception_MissingProperty("VALARM component with a REPEAT property requires a DURATION property");
}
}
}
}
@@ -0,0 +1,59 @@
<?php
/**
* Calendar Component
* This is the outer-most object in an icalendar file that represents
* the calendar as a whole. All other components must be nested within
* this component.
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Implement a method of NOT allowing more than one of properties
* such as METHOD to be set.
*
* RFC 2445 Definition
*
* The Calendaring and Scheduling Core Object is a collection of
* calendaring and scheduling information. Typically, this information
* will consist of a single iCalendar object. However, multiple
* iCalendar objects can be sequentially grouped together. The first
* line and last line of the iCalendar object MUST contain a pair of
* iCalendar object delimiter strings. The syntax for an iCalendar
* object is as follows:
*
* icalobject = 1*("BEGIN" ":" "VCALENDAR" CRLF
* icalbody
* "END" ":" "VCALENDAR" CRLF)
*
* The following is a simple example of an iCalendar object:
*
* BEGIN:VCALENDAR
* VERSION:2.0
* PRODID:-//hacksw/handcal//NONSGML v1.0//EN
* BEGIN:VEVENT
* DTSTART:19970714T170000Z
* DTEND:19970715T035959Z
* SUMMARY:Bastille Day Party
* END:VEVENT
* END:VCALENDAR
*/
class qCal_Component_Vcalendar extends qCal_Component {
protected $name = "VCALENDAR";
protected $requiredProperties = array('PRODID','VERSION');
/**
* vcalendar objects have a number of requirements defined in the RFC just as most other
* components do. Each has a global set of validation rules as well as their own set. This
* is the set of rules defined by the vcalendar object.
*/
public function doValidation() {
// @todo make sure that all tzids that are specified have a corresponding vtimezone
// look for tzids and make sure there are corresponding vtimezone components for each tzid
// In order to be sure I find all tzids, I need to search through the entire tree, so either
// I need a recursive getProperties() or I need to use a stack to find all of them.
}
}
@@ -0,0 +1,165 @@
<?php
/**
* Event Component
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Component Name: "VEVENT"
*
* Purpose: Provide a grouping of component properties that describe an
* event.
*
* Format Definition: A "VEVENT" calendar component is defined by the
* following notation:
*
* eventc = "BEGIN" ":" "VEVENT" CRLF
* eventprop *alarmc
* "END" ":" "VEVENT" CRLF
*
* eventprop = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* class / created / description / dtstart / geo /
* last-mod / location / organizer / priority /
* dtstamp / seq / status / summary / transp /
* uid / url / recurid /
*
* ; either 'dtend' or 'duration' may appear in
* ; a 'eventprop', but 'dtend' and 'duration'
* ; MUST NOT occur in the same 'eventprop'
*
* dtend / duration /
*
* ; the following are optional,
* ; and MAY occur more than once
*
* attach / attendee / categories / comment /
* contact / exdate / exrule / rstatus / related /
* resources / rdate / rrule / x-prop
*
* )
*
* Description: A "VEVENT" calendar component is a grouping of component
* properties, and possibly including "VALARM" calendar components, that
* represents a scheduled amount of time on a calendar. For example, it
* can be an activity; such as a one-hour long, department meeting from
* 8:00 AM to 9:00 AM, tomorrow. Generally, an event will take up time
* on an individual calendar. Hence, the event will appear as an opaque
* interval in a search for busy time. Alternately, the event can have
* its Time Transparency set to "TRANSPARENT" in order to prevent
* blocking of the event in searches for busy time.
*
* The "VEVENT" is also the calendar component used to specify an
* anniversary or daily reminder within a calendar. These events have a
* DATE value type for the "DTSTART" property instead of the default
* data type of DATE-TIME. If such a "VEVENT" has a "DTEND" property, it
* MUST be specified as a DATE value also. The anniversary type of
* "VEVENT" can span more than one date (i.e, "DTEND" property value is
* set to a calendar date after the "DTSTART" property value).
*
* The "DTSTART" property for a "VEVENT" specifies the inclusive start
* of the event. For recurring events, it also specifies the very first
* instance in the recurrence set. The "DTEND" property for a "VEVENT"
* calendar component specifies the non-inclusive end of the event. For
* cases where a "VEVENT" calendar component specifies a "DTSTART"
* property with a DATE data type but no "DTEND" property, the events
* non-inclusive end is the end of the calendar date specified by the
* "DTSTART" property. For cases where a "VEVENT" calendar component
* specifies a "DTSTART" property with a DATE-TIME data type but no
* "DTEND" property, the event ends on the same calendar date and time
* of day specified by the "DTSTART" property.
*
* The "VEVENT" calendar component cannot be nested within another
* calendar component. However, "VEVENT" calendar components can be
* related to each other or to a "VTODO" or to a "VJOURNAL" calendar
* component with the "RELATED-TO" property.
*
* Example: The following is an example of the "VEVENT" calendar
* component used to represent a meeting that will also be opaque to
* searches for busy time:
*
* BEGIN:VEVENT
* UID:19970901T130000Z-123401@host.com
* DTSTAMP:19970901T1300Z
* DTSTART:19970903T163000Z
* DTEND:19970903T190000Z
* SUMMARY:Annual Employee Review
* CLASS:PRIVATE
* CATEGORIES:BUSINESS,HUMAN RESOURCES
* END:VEVENT
*
* The following is an example of the "VEVENT" calendar component used
* to represent a reminder that will not be opaque, but rather
* transparent, to searches for busy time:
*
* BEGIN:VEVENT
* UID:19970901T130000Z-123402@host.com
* DTSTAMP:19970901T1300Z
* DTSTART:19970401T163000Z
* DTEND:19970402T010000Z
* SUMMARY:Laurel is in sensitivity awareness class.
* CLASS:PUBLIC
* CATEGORIES:BUSINESS,HUMAN RESOURCES
* TRANSP:TRANSPARENT
* END:VEVENT
*
* The following is an example of the "VEVENT" calendar component used
* to represent an anniversary that will occur annually. Since it takes
* up no time, it will not appear as opaque in a search for busy time;
* no matter what the value of the "TRANSP" property indicates:
*
* BEGIN:VEVENT
* UID:19970901T130000Z-123403@host.com
* DTSTAMP:19970901T1300Z
* DTSTART:19971102
* SUMMARY:Our Blissful Anniversary
* CLASS:CONFIDENTIAL
* CATEGORIES:ANNIVERSARY,PERSONAL,SPECIAL OCCASION
* RRULE:FREQ=YEARLY
* END:VEVENT
*/
class qCal_Component_Vevent extends qCal_Component {
protected $name = "VEVENT";
protected $allowedComponents = array('VCALENDAR');
protected function doValidation() {
$properties = $this->getProperties();
$propnames = array_keys($properties);
if (in_array('DTEND', $propnames) && in_array('DURATION', $propnames)) {
throw new qCal_Exception_InvalidProperty('DTEND and DURATION cannot both occur in the same VEVENT component');
}
if (in_array('DTSTART', $propnames)) {
$dtstart = $this->getProperty('dtstart');
$dtstart = $dtstart[0];
// check that if dtstart is a DATE that dtend is a DATE
if ($dtstart->getType() == 'DATE') {
if (in_array('DTEND', $propnames)) {
$dtend = $this->getProperty('dtend');
$dtend = $dtend[0];
if ($dtend->getType() != 'DATE') {
throw new qCal_Exception_InvalidProperty('If DTSTART property is specified as a DATE property, so must DTEND');
}
}
}
// check that dtstart comes before dtend
if (in_array('DTEND', $propnames)) {
$dtend = $this->getProperty('dtend');
$dtend = $dtend[0];
$startdate = strtotime($dtstart->getValue());
$enddate = strtotime($dtend->getValue());
if ($startdate > $enddate) {
throw new qCal_Exception_InvalidProperty('DTSTART property must come before DTEND');
}
}
}
}
}
@@ -0,0 +1,137 @@
<?php
/**
* Freebusy Component
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Component Name: VFREEBUSY
*
* Purpose: Provide a grouping of component properties that describe
* either a request for free/busy time, describe a response to a request
* for free/busy time or describe a published set of busy time.
*
* Formal Definition: A "VFREEBUSY" calendar component is defined by the
* following notation:
*
* freebusyc = "BEGIN" ":" "VFREEBUSY" CRLF
* fbprop
* "END" ":" "VFREEBUSY" CRLF
*
* fbprop = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* contact / dtstart / dtend / duration / dtstamp /
* organizer / uid / url /
*
* ; the following are optional,
* ; and MAY occur more than once
*
* attendee / comment / freebusy / rstatus / x-prop
*
* )
*
* Description: A "VFREEBUSY" calendar component is a grouping of
* component properties that represents either a request for, a reply to
* a request for free or busy time information or a published set of
* busy time information.
*
* When used to request free/busy time information, the "ATTENDEE"
* property specifies the calendar users whose free/busy time is being
* requested; the "ORGANIZER" property specifies the calendar user who
* is requesting the free/busy time; the "DTSTART" and "DTEND"
* properties specify the window of time for which the free/busy time is
* being requested; the "UID" and "DTSTAMP" properties are specified to
* assist in proper sequencing of multiple free/busy time requests.
*
* When used to reply to a request for free/busy time, the "ATTENDEE"
* property specifies the calendar user responding to the free/busy time
* request; the "ORGANIZER" property specifies the calendar user that
* originally requested the free/busy time; the "FREEBUSY" property
* specifies the free/busy time information (if it exists); and the
*
* "UID" and "DTSTAMP" properties are specified to assist in proper
* sequencing of multiple free/busy time replies.
*
* When used to publish busy time, the "ORGANIZER" property specifies
* the calendar user associated with the published busy time; the
* "DTSTART" and "DTEND" properties specify an inclusive time window
* that surrounds the busy time information; the "FREEBUSY" property
* specifies the published busy time information; and the "DTSTAMP"
* property specifies the date/time that iCalendar object was created.
*
* The "VFREEBUSY" calendar component cannot be nested within another
* calendar component. Multiple "VFREEBUSY" calendar components can be
* specified within an iCalendar object. This permits the grouping of
* Free/Busy information into logical collections, such as monthly
* groups of busy time information.
*
* The "VFREEBUSY" calendar component is intended for use in iCalendar
* object methods involving requests for free time, requests for busy
* time, requests for both free and busy, and the associated replies.
*
* Free/Busy information is represented with the "FREEBUSY" property.
* This property provides a terse representation of time periods. One or
* more "FREEBUSY" properties can be specified in the "VFREEBUSY"
* calendar component.
*
* When present in a "VFREEBUSY" calendar component, the "DTSTART" and
* "DTEND" properties SHOULD be specified prior to any "FREEBUSY"
* properties. In a free time request, these properties can be used in
* combination with the "DURATION" property to represent a request for a
* duration of free time within a specified window of time.
*
* The recurrence properties ("RRULE", "EXRULE", "RDATE", "EXDATE") are
* not permitted within a "VFREEBUSY" calendar component. Any recurring
* events are resolved into their individual busy time periods using the
* "FREEBUSY" property.
*
* Example: The following is an example of a "VFREEBUSY" calendar
* component used to request free or busy time information:
*
* BEGIN:VFREEBUSY
* ORGANIZER:MAILTO:jane_doe@host1.com
* ATTENDEE:MAILTO:john_public@host2.com
* DTSTART:19971015T050000Z
* DTEND:19971016T050000Z
* DTSTAMP:19970901T083000Z
* END:VFREEBUSY
*
* The following is an example of a "VFREEBUSY" calendar component used
* to reply to the request with busy time information:
*
* BEGIN:VFREEBUSY
* ORGANIZER:MAILTO:jane_doe@host1.com
* ATTENDEE:MAILTO:john_public@host2.com
* DTSTAMP:19970901T100000Z
* FREEBUSY;VALUE=PERIOD:19971015T050000Z/PT8H30M,
* 19971015T160000Z/PT5H30M,19971015T223000Z/PT6H30M
* URL:http://host2.com/pub/busy/jpublic-01.ifb
* COMMENT:This iCalendar file contains busy time information for
* the next three months.
* END:VFREEBUSY
*
* The following is an example of a "VFREEBUSY" calendar component used
* to publish busy time information.
*
* BEGIN:VFREEBUSY
* ORGANIZER:jsmith@host.com
* DTSTART:19980313T141711Z
* DTEND:19980410T141711Z
* FREEBUSY:19980314T233000Z/19980315T003000Z
* FREEBUSY:19980316T153000Z/19980316T163000Z
* FREEBUSY:19980318T030000Z/19980318T040000Z
* URL:http://www.host.com/calendar/busytime/jsmith.ifb
* END:VFREEBUSY
*/
class qCal_Component_Vfreebusy extends qCal_Component {
protected $name = "VFREEBUSY";
protected $allowedComponents = array('VCALENDAR');
}
@@ -0,0 +1,86 @@
<?php
/**
* Journal Component
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Component Name: VJOURNAL
*
* Purpose: Provide a grouping of component properties that describe a
* journal entry.
*
* Formal Definition: A "VJOURNAL" calendar component is defined by the
* following notation:
*
* journalc = "BEGIN" ":" "VJOURNAL" CRLF
* jourprop
* "END" ":" "VJOURNAL" CRLF
*
* jourprop = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* class / created / description / dtstart / dtstamp /
* last-mod / organizer / recurid / seq / status /
* summary / uid / url /
*
* ; the following are optional,
* ; and MAY occur more than once
*
* attach / attendee / categories / comment /
* contact / exdate / exrule / related / rdate /
* rrule / rstatus / x-prop
*
* )
*
* Description: A "VJOURNAL" calendar component is a grouping of
* component properties that represent one or more descriptive text
* notes associated with a particular calendar date. The "DTSTART"
* property is used to specify the calendar date that the journal entry
* is associated with. Generally, it will have a DATE value data type,
* but it can also be used to specify a DATE-TIME value data type.
* Examples of a journal entry include a daily record of a legislative
* body or a journal entry of individual telephone contacts for the day
* or an ordered list of accomplishments for the day. The "VJOURNAL"
* calendar component can also be used to associate a document with a
* calendar date.
*
* The "VJOURNAL" calendar component does not take up time on a
* calendar. Hence, it does not play a role in free or busy time
* searches - - it is as though it has a time transparency value of
* TRANSPARENT. It is transparent to any such searches.
*
* The "VJOURNAL" calendar component cannot be nested within another
* calendar component. However, "VJOURNAL" calendar components can be
* related to each other or to a "VEVENT" or to a "VTODO" calendar
* component, with the "RELATED-TO" property.
*
* Example: The following is an example of the "VJOURNAL" calendar
* component:
*
* BEGIN:VJOURNAL
* UID:19970901T130000Z-123405@host.com
* DTSTAMP:19970901T1300Z
* DTSTART;VALUE=DATE:19970317
* SUMMARY:Staff meeting minutes
* DESCRIPTION:1. Staff meeting: Participants include Joe\, Lisa
* and Bob. Aurora project plans were reviewed. There is currently
* no budget reserves for this project. Lisa will escalate to
* management. Next meeting on Tuesday.\n
* 2. Telephone Conference: ABC Corp. sales representative called
* to discuss new printer. Promised to get us a demo by Friday.\n
* 3. Henry Miller (Handsoff Insurance): Car was totaled by tree.
* Is looking into a loaner car. 654-2323 (tel).
* END:VJOURNAL
*/
class qCal_Component_Vjournal extends qCal_Component {
protected $name = "VJOURNAL";
protected $allowedComponents = array('VCALENDAR');
}
@@ -0,0 +1,375 @@
<?php
/**
* Timezone Component
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Component Name: VTIMEZONE
*
* Purpose: Provide a grouping of component properties that defines a
* time zone.
*
* Formal Definition: A "VTIMEZONE" calendar component is defined by the
* following notation:
*
* timezonec = "BEGIN" ":" "VTIMEZONE" CRLF
*
* 2*(
*
* ; 'tzid' is required, but MUST NOT occur more
* ; than once
*
* tzid /
*
* ; 'last-mod' and 'tzurl' are optional,
* but MUST NOT occur more than once
*
* last-mod / tzurl /
*
* ; one of 'standardc' or 'daylightc' MUST occur
* ..; and each MAY occur more than once.
*
* standardc / daylightc /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* x-prop
*
* )
*
* "END" ":" "VTIMEZONE" CRLF
*
* standardc = "BEGIN" ":" "STANDARD" CRLF
*
* tzprop
*
* "END" ":" "STANDARD" CRLF
*
* daylightc = "BEGIN" ":" "DAYLIGHT" CRLF
*
* tzprop
*
* "END" ":" "DAYLIGHT" CRLF
*
* tzprop = 3*(
*
* ; the following are each REQUIRED,
* ; but MUST NOT occur more than once
*
* dtstart / tzoffsetto / tzoffsetfrom /
*
* ; the following are optional,
* ; and MAY occur more than once
*
* comment / rdate / rrule / tzname / x-prop
*
* )
*
* Description: A time zone is unambiguously defined by the set of time
* measurement rules determined by the governing body for a given
* geographic area. These rules describe at a minimum the base offset
* from UTC for the time zone, often referred to as the Standard Time
* offset. Many locations adjust their Standard Time forward or backward
* by one hour, in order to accommodate seasonal changes in number of
* daylight hours, often referred to as Daylight Saving Time. Some
* locations adjust their time by a fraction of an hour. Standard Time
* is also known as Winter Time. Daylight Saving Time is also known as
* Advanced Time, Summer Time, or Legal Time in certain countries. The
* following table shows the changes in time zone rules in effect for
* New York City starting from 1967. Each line represents a description
* or rule for a particular observance.
*
* Effective Observance Rule
*
* Date (Date/Time) Offset Abbreviation
*
* 1967-* last Sun in Oct, 02:00 -0500 EST
*
* 1967-1973 last Sun in Apr, 02:00 -0400 EDT
*
* 1974-1974 Jan 6, 02:00 -0400 EDT
*
* 1975-1975 Feb 23, 02:00 -0400 EDT
*
* 1976-1986 last Sun in Apr, 02:00 -0400 EDT
*
* 1987-* first Sun in Apr, 02:00 -0400 EDT
*
* Note: The specification of a global time zone registry is not
* addressed by this document and is left for future study.
* However, implementers may find the Olson time zone database [TZ]
* a useful reference. It is an informal, public-domain collection
* of time zone information, which is currently being maintained by
* volunteer Internet participants, and is used in several
* operating systems. This database contains current and historical
* time zone information for a wide variety of locations around the
* globe; it provides a time zone identifier for every unique time
* zone rule set in actual use since 1970, with historical data
* going back to the introduction of standard time.
*
* Interoperability between two calendaring and scheduling applications,
* especially for recurring events, to-dos or journal entries, is
* dependent on the ability to capture and convey date and time
* information in an unambiguous format. The specification of current
* time zone information is integral to this behavior.
*
* If present, the "VTIMEZONE" calendar component defines the set of
* Standard Time and Daylight Saving Time observances (or rules) for a
* particular time zone for a given interval of time. The "VTIMEZONE"
* calendar component cannot be nested within other calendar components.
* Multiple "VTIMEZONE" calendar components can exist in an iCalendar
* object. In this situation, each "VTIMEZONE" MUST represent a unique
* time zone definition. This is necessary for some classes of events,
* such as airline flights, that start in one time zone and end in
* another.
*
* The "VTIMEZONE" calendar component MUST be present if the iCalendar
* object contains an RRULE that generates dates on both sides of a time
* zone shift (e.g. both in Standard Time and Daylight Saving Time)
* unless the iCalendar object intends to convey a floating time (See
* the section "4.1.10.11 Time" for proper interpretation of floating
* time). It can be present if the iCalendar object does not contain
* such a RRULE. In addition, if a RRULE is present, there MUST be valid
* time zone information for all recurrence instances.
*
* The "VTIMEZONE" calendar component MUST include the "TZID" property
* and at least one definition of a standard or daylight component. The
* standard or daylight component MUST include the "DTSTART",
* "TZOFFSETFROM" and "TZOFFSETTO" properties.
*
* An individual "VTIMEZONE" calendar component MUST be specified for
* each unique "TZID" parameter value specified in the iCalendar object.
*
* Each "VTIMEZONE" calendar component consists of a collection of one
* or more sub-components that describe the rule for a particular
* observance (either a Standard Time or a Daylight Saving Time
* observance). The "STANDARD" sub-component consists of a collection of
* properties that describe Standard Time. The "DAYLIGHT" sub-component
* consists of a collection of properties that describe Daylight Saving
* Time. In general this collection of properties consists of:
*
* - the first onset date-time for the observance
*
* - the last onset date-time for the observance, if a last onset
* is known.
*
* - the offset to be applied for the observance
*
* - a rule that describes the day and time when the observance
* takes effect
*
* - an optional name for the observance
*
* For a given time zone, there may be multiple unique definitions of
* the observances over a period of time. Each observance is described
* using either a "STANDARD" or "DAYLIGHT" sub-component. The collection
* of these sub-components is used to describe the time zone for a given
* period of time. The offset to apply at any given time is found by
* locating the observance that has the last onset date and time before
* the time in question, and using the offset value from that
* observance.
*
* The top-level properties in a "VTIMEZONE" calendar component are:
*
* The mandatory "TZID" property is a text value that uniquely
* identifies the VTIMZONE calendar component within the scope of an
* iCalendar object.
*
* The optional "LAST-MODIFIED" property is a UTC value that specifies
* the date and time that this time zone definition was last updated.
*
* The optional "TZURL" property is url value that points to a published
* VTIMEZONE definition. TZURL SHOULD refer to a resource that is
* accessible by anyone who might need to interpret the object. This
* SHOULD NOT normally be a file: URL or other URL that is not widely-
* accessible.
*
* The collection of properties that are used to define the STANDARD and
* DAYLIGHT sub-components include:
*
* The mandatory "DTSTART" property gives the effective onset date and
* local time for the time zone sub-component definition. "DTSTART" in
* this usage MUST be specified as a local DATE-TIME value.
*
* The mandatory "TZOFFSETFROM" property gives the UTC offset which is
* in use when the onset of this time zone observance begins.
* "TZOFFSETFROM" is combined with "DTSTART" to define the effective
* onset for the time zone sub-component definition. For example, the
* following represents the time at which the observance of Standard
* Time took effect in Fall 1967 for New York City:
*
* DTSTART:19671029T020000
*
* TZOFFSETFROM:-0400
*
* The mandatory "TZOFFSETTO " property gives the UTC offset for the
* time zone sub-component (Standard Time or Daylight Saving Time) when
* this observance is in use.
*
* The optional "TZNAME" property is the customary name for the time
* zone. It may be specified multiple times, to allow for specifying
* multiple language variants of the time zone names. This could be used
* for displaying dates.
*
* If specified, the onset for the observance defined by the time zone
* sub-component is defined by either the "RRULE" or "RDATE" property.
* If neither is specified, only one sub-component can be specified in
* the "VTIMEZONE" calendar component and it is assumed that the single
* observance specified is always in effect.
*
* The "RRULE" property defines the recurrence rule for the onset of the
* observance defined by this time zone sub-component. Some specific
* requirements for the usage of RRULE for this purpose include:
*
* - If observance is known to have an effective end date, the
* "UNTIL" recurrence rule parameter MUST be used to specify the
* last valid onset of this observance (i.e., the UNTIL date-time
* will be equal to the last instance generated by the recurrence
* pattern). It MUST be specified in UTC time.
*
* - The "DTSTART" and the "TZOFFSETTO" properties MUST be used
* when generating the onset date-time values (instances) from the
* RRULE.
*
* Alternatively, the "RDATE" property can be used to define the onset
* of the observance by giving the individual onset date and times.
* "RDATE" in this usage MUST be specified as a local DATE-TIME value in
* UTC time.
*
* The optional "COMMENT" property is also allowed for descriptive
* explanatory text.
*
* Example: The following are examples of the "VTIMEZONE" calendar
* component:
*
* This is an example showing time zone information for the Eastern
* United States using "RDATE" property. Note that this is only suitable
* for a recurring event that starts on or later than April 6, 1997 at
* 03:00:00 EDT (i.e., the earliest effective transition date and time)
* and ends no later than April 7, 1998 02:00:00 EST (i.e., latest valid
* date and time for EST in this scenario). For example, this can be
* used for a recurring event that occurs every Friday, 8am-9:00 AM,
* starting June 1, 1997, ending December 31, 1997.
*
* BEGIN:VTIMEZONE
* TZID:US-Eastern
* LAST-MODIFIED:19870101T000000Z
* BEGIN:STANDARD
* DTSTART:19971026T020000
* RDATE:19971026T020000
* TZOFFSETFROM:-0400
* TZOFFSETTO:-0500
* TZNAME:EST
* END:STANDARD
* BEGIN:DAYLIGHT
* DTSTART:19971026T020000
* RDATE:19970406T020000
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* END:VTIMEZONE
*
* This is a simple example showing the current time zone rules for the
* Eastern United States using a RRULE recurrence pattern. Note that
* there is no effective end date to either of the Standard Time or
* Daylight Time rules. This information would be valid for a recurring
* event starting today and continuing indefinitely.
*
* BEGIN:VTIMEZONE
* TZID:US-Eastern
* LAST-MODIFIED:19870101T000000Z
* TZURL:http://zones.stds_r_us.net/tz/US-Eastern
* BEGIN:STANDARD
* DTSTART:19671029T020000
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
* TZOFFSETFROM:-0400
* TZOFFSETTO:-0500
* TZNAME:EST
* END:STANDARD
* BEGIN:DAYLIGHT
* DTSTART:19870405T020000
* RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* END:VTIMEZONE
*
* This is an example showing a fictitious set of rules for the Eastern
* United States, where the Daylight Time rule has an effective end date
* (i.e., after that date, Daylight Time is no longer observed).
*
* BEGIN:VTIMEZONE
* TZID:US--Fictitious-Eastern
* LAST-MODIFIED:19870101T000000Z
* BEGIN:STANDARD
* DTSTART:19671029T020000
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
* TZOFFSETFROM:-0400
* TZOFFSETTO:-0500
* TZNAME:EST
* END:STANDARD
* BEGIN:DAYLIGHT
* DTSTART:19870405T020000
* RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=19980404T070000Z
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* END:VTIMEZONE
*
* This is an example showing a fictitious set of rules for the Eastern
* United States, where the first Daylight Time rule has an effective
* end date. There is a second Daylight Time rule that picks up where
* the other left off.
*
* BEGIN:VTIMEZONE
* TZID:US--Fictitious-Eastern
* LAST-MODIFIED:19870101T000000Z
* BEGIN:STANDARD
* DTSTART:19671029T020000
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
* TZOFFSETFROM:-0400
* TZOFFSETTO:-0500
* TZNAME:EST
* END:STANDARD
* BEGIN:DAYLIGHT
* DTSTART:19870405T020000
* RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=19980404T070000Z
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* BEGIN:DAYLIGHT
* DTSTART:19990424T020000
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=4
* TZOFFSETFROM:-0500
* TZOFFSETTO:-0400
* TZNAME:EDT
* END:DAYLIGHT
* END:VTIMEZONE
*/
class qCal_Component_Vtimezone extends qCal_Component {
protected $name = "VTIMEZONE";
protected $allowedComponents = array('VCALENDAR');
protected $requiredProperties = array('TZID');
/**
* Make sure that all of the rules specified above are followed
*/
protected function doValidation() {
$children = $this->getChildren();
if (!array_key_exists('DAYLIGHT', $children) && !array_key_exists('STANDARD', $children)) {
throw new qCal_Exception_MissingComponent('Either a STANDARD or DAYLIGHT component is required within a VTIMEZONE component');
}
}
}
@@ -0,0 +1,81 @@
<?php
/**
* Todo Component
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Component Name: VTODO
*
* Purpose: Provide a grouping of calendar properties that describe a
* to-do.
*
* Formal Definition: A "VTODO" calendar component is defined by the
* following notation:
*
* todoc = "BEGIN" ":" "VTODO" CRLF
* todoprop *alarmc
* "END" ":" "VTODO" CRLF
*
* todoprop = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* class / completed / created / description / dtstamp /
* dtstart / geo / last-mod / location / organizer /
* percent / priority / recurid / seq / status /
* summary / uid / url /
*
* ; either 'due' or 'duration' may appear in
* ; a 'todoprop', but 'due' and 'duration'
* ; MUST NOT occur in the same 'todoprop'
*
* due / duration /
*
* ; the following are optional,
* ; and MAY occur more than once
* attach / attendee / categories / comment / contact /
* exdate / exrule / rstatus / related / resources /
* rdate / rrule / x-prop
*
* )
*
* Description: A "VTODO" calendar component is a grouping of component
* properties and possibly "VALARM" calendar components that represent
* an action-item or assignment. For example, it can be used to
* represent an item of work assigned to an individual; such as "turn in
* travel expense today".
*
* The "VTODO" calendar component cannot be nested within another
* calendar component. However, "VTODO" calendar components can be
* related to each other or to a "VTODO" or to a "VJOURNAL" calendar
* component with the "RELATED-TO" property.
*
* A "VTODO" calendar component without the "DTSTART" and "DUE" (or
* "DURATION") properties specifies a to-do that will be associated with
* each successive calendar date, until it is completed.
*
* Example: The following is an example of a "VTODO" calendar component:
*
* BEGIN:VTODO
* UID:19970901T130000Z-123404@host.com
* DTSTAMP:19970901T1300Z
* DTSTART:19970415T133000Z
* DUE:19970416T045959Z
* SUMMARY:1996 Income Tax Preparation
* CLASS:CONFIDENTIAL
* CATEGORIES:FAMILY,FINANCE
* PRIORITY:1
* STATUS:NEEDS-ACTION
* END:VTODO
*/
class qCal_Component_Vtodo extends qCal_Component {
protected $name = "VTODO";
protected $allowedComponents = array('VCALENDAR');
}
@@ -0,0 +1,590 @@
<?php
/**
* Base date object. Stores date information only (without a time). Internally the date is stored as a
* unix timestamp, but the time portion of it is not used. If you need a date with a time, use qCal_DateTime
* @package qCal
* @subpackage qCal_Date
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_Date {
/**
* @var unix timestamp
*/
protected $date;
/**
* @var int The start day of the week (defaults to Monday)
*/
protected $wkst = 1;
/**
* @var array The results of a getdate() call
*/
protected $dateArray = array();
/**
* @var string The date format that is used when outputting via __toString()
*/
protected $format = "m/d/Y";
/**
* @var array This is just a mapping of weekdays to 0 (for Sunday) through 6 (for Saturday)
* which is a direct correlation with PHP's date function's "w" metacharacter
*/
protected $weekdays = array(
"sunday",
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
);
/**
* @var array This is an array of months starting at 1 and ending on 12
*/
protected $months = array(
1 => "january",
2 => "february",
3 => "march",
4 => "april",
5 => "may",
6 => "june",
7 => "july",
8 => "august",
9 => "september",
10 => "october",
11 => "november",
12 => "december",
);
/**
* @var array The month in a two-dimensional array (picture a calendar)
*/
protected $monthMap = array();
/**
* Class constructor
* @param int The year of this date
* @param int The month of this date
* @param int The day of this date
*/
public function __construct($year = null, $month = null, $day = null, $rollover = false) {
$this->setDate($year, $month, $day, $rollover);
}
/**
* Set the date of this class
* The date defaults to now. If any part of the date is missing, it will default to whatever "now"'s
* date portion is. For instance, if the year provided is 2006 and no other portion is given, it will
* default to today's month and day, but in the year 2006. If, for any reason the date defaults to a
* nonsensical date, an exception will be thrown. For instance, if you specify the year as 2006, and
* the current date is february 29th, an exception will be thrown because the 29th of February does not
* exist in 2006.
* @param int The year of this date
* @param int The month of this date
* @param int The day of this date
* @throws qCal_Date_Exception_InvalidDate
*/
protected function setDate($year = null, $month = null, $day = null, $rollover = false) {
$now = getdate();
if (is_null($year)) {
$year = $now['year'];
}
if (is_null($month)) {
$month = $now['mon'];
}
if (is_null($day)) {
$day = $now['mday'];
}
$this->date = gmmktime(0, 0, 0, $month, $day, $year);
$this->dateArray = self::gmgetdate($this->date);
if (!$rollover) {
if ($this->dateArray["mday"] != $day || $this->dateArray["mon"] != $month || $this->dateArray["year"] != $year) {
throw new qCal_DateTime_Exception_InvalidDate("Invalid date specified for qCal_Date: \"{$month}/{$day}/{$year}\"");
}
}
// @todo Look into how much more efficient it might be to call date() only once and then break apart the result...
$formatString = "d|D|j|l|N|S|w|z|W|F|m|M|n|t|L|o|y|Y|c|r|U";
$keys = explode("|", $formatString);
$vals = explode("|", gmdate($formatString, $this->date));
$this->dateArray = array_merge($this->dateArray, array_combine($keys, $vals));
return $this;
}
/**
* This is a factory method. It allows you to create a date by string or by another date object (to make a copy)
*/
public static function factory($date) {
if (is_integer($date)) {
// @todo Handle timestamps
}
if (is_string($date)) {
if (!$timestamp = strtotime($date)) {
// if unix timestamp can't be created throw an exception
throw new qCal_Date_Exception_InvalidDate("Invalid or ambiguous date string passed to qCal_Date::factory()");
}
}
$date = self::gmgetdate($timestamp);
$newdate = gmmktime(0, 0, 0, $date['mon'], $date['mday'], $date['year']);
$newdate = self::gmgetdate($newdate);
return new qCal_Date($newdate['year'], $newdate['mon'], $newdate['mday']);
}
/**
* Set the format that should be used when calling either __toString() or format() without an argument.
* @param string $format
*/
public function setFormat($format) {
$this->format = (string) $format;
return $this;
}
/**
* Formats the date according to either the existing $this->format, or if the $format arg is passed
* in, it uses that.
* @param string The format that is to be used (according to php's date function). Only date-related metacharacters work.
*/
public function format($format) {
$escape = false;
$meta = str_split($format);
$output = array();
foreach($meta as $char) {
if ($char == '\\') {
$escape = true;
continue;
}
if (!$escape && array_key_exists($char, $this->dateArray)) {
$output[] = $this->dateArray[$char];
} else {
$output[] = $char;
}
// reset this to false after every iteration that wasn't "continued"
$escape = false;
}
return implode($output);
}
/**
* Getters
* The next dozen or so methods are just your standard getters for things such as month, day, year, week day, etc.
*/
/**
* Get the month (number) of this date
* @return integer A number between 1 and 12 inclusively
*/
public function getMonth() {
return $this->dateArray["mon"];
}
/**
* Get the month of this date
* @return string The actual name of the month, capitalized
*/
public function getMonthName() {
return $this->dateArray["month"];
}
/**
* Get the day of the month
* @return integer A number between 1 and 31 inclusively
*/
public function getDay() {
return $this->dateArray["mday"];
}
/**
* Get the day of the year
* @return integer A number between 0 and 365 inclusively
*/
public function getYearDay($startFromOne = false) {
$yearDay = $this->dateArray["yday"] + (integer) $startFromOne;
return $yearDay;
}
/**
* Find how many days until the end of the year.
* For instance, if the date is December 25th, there are 6 days until the end of the year
*/
public function getNumDaysUntilEndOfYear() {
$yearday = $this->getYearDay(true);
return $this->getNumDaysInYear() - $yearday;
}
/**
* Get how many months until the end of the year
* @todo This is really rudimentary. There is more to this, but this works for now...
*/
public function getNumMonthsUntilEndOfYear() {
return 12 - $this->getMonth();
}
/**
* Get the amount of days in the year (365 unless it is a leap-year, then it's 366)
*/
public function getNumDaysInYear() {
return ($this->isLeapYear()) ? 366 : 365;
}
/**
* Return the first day of the month as a qCal_Date object
* @return qCal_Date The first day of the month
*/
public function getFirstDayOfMonth() {
return new qCal_Date($this->getYear(), $this->getMonth(), 1);
}
/**
* Return the last day of the month as a qCal_Date object
* @return qCal_Date The last day of the month
*/
public function getLastDayOfMonth() {
$lastday = $this->format("t");
return new qCal_Date($this->getYear(), $this->getMonth(), $lastday);
}
/**
* Get the number of days until the end of the month
*/
public function getNumDaysUntilEndOfMonth() {
return $this->getNumDaysInMonth() - $this->getDay();
}
/**
* Get the year
* @return integer The year of this date, for example 1999
*/
public function getYear() {
return $this->dateArray["year"];
}
/**
* Get the day of the week
* @return integer A number between 0 (for Sunday) and 6 (for Saturday).
*/
public function getWeekDay() {
return $this->dateArray["wday"];
}
/**
* Get the day of the week
* @return string The actual name of the day of the week, capitalized
*/
public function getWeekDayName() {
return $this->dateArray["weekday"];
}
/**
* Get the amount of days in the current month of this year
* @return integer The number of days in the month
*/
public function getNumDaysInMonth() {
return $this->dateArray["t"];
}
/**
* Get the week of the year
* @return integer The week of the year (0-51 I think)
* @todo This is not accurate if the week start isn't monday. I need to adjust for that
*/
public function getWeekOfYear() {
return $this->dateArray["W"];
}
/**
* Get how many weeks until the end of the year
* @todo This is really rudimentary. There is more to this, but this works for now...
*/
public function getWeeksUntilEndOfYear() {
return 52 - $this->getWeekOfYear();
}
/**
* Determine if this is a leap year
*/
public function isLeapYear() {
return (boolean) $this->dateArray["L"];
}
/**
* Get a unix timestamp for the date
* @return integer The amount of seconds since unix epoch (January 1, 1970 UTC)
*/
public function getUnixTimestamp() {
return $this->dateArray[0];
}
/**
* Date magic
* This component is capable of doing some really convenient things with dates.
* It is capable of determining things such as how many days until the end of the year,
* which monday of the month it is (ie: third monday in february), etc.
*/
/**
* Determine the number or Tuesdays (or whatever day of the week this date is) since the
* beginning or end of the month.
* @param integer $xth A positive or negative number that determines which weekday of the month we want
* @param string|integer $weekday Either Sunday-Saturday or 0-6 to specify the weekday we want
* @param string|integer $month Either January-December or 1-12 to specify the month we want
* @param integer $year A valid year to specify which year we want
*/
public function getXthWeekdayOfMonth($xth, $weekday = null, $month = null, $year = null) {
$negpos = substr($xth, 0, 1);
if ($negpos == "+" || $negpos == "-") {
$xth = (integer) substr($xth, 1);
} else {
$negpos = "+";
}
if (is_null($weekday)) {
$weekday = $this->getWeekday();
}
if (ctype_digit((string) $weekday)) {
if (!array_key_exists($weekday, $this->weekdays)) {
throw new qCal_Date_Exception_InvalidWeekday("\"$weekday\" is not a valid weekday.");
}
} else {
$weekday = strtolower($weekday);
if (!in_array($weekday, $this->weekdays)) {
throw new qCal_Date_Exception_InvalidWeekday("\"$weekday\" is not a valid weekday.");
}
$wdays = array_flip($this->weekdays);
$weekday = $wdays[$weekday];
}
if (is_null($month)) {
$month = $this->getMonth();
}
if (ctype_digit((string) $month)) {
if (!array_key_exists($month, $this->months)) {
throw new qCal_Date_Exception_InvalidMonth("\"$month\" is not a valid month.");
}
} else {
$month = strtolower($month);
if (!in_array($month, $this->months)) {
throw new qCal_Date_Exception_InvalidMonth("\"$month\" is not a valid month.");
}
$mons = array_flip($this->months);
$month = $mons[$month];
}
if (is_null($year)) {
$year = $this->getYear();
}
if (!ctype_digit((string) $year) || strlen($year) != 4) {
throw new qCal_Date_Exception_InvalidYear("\"$year\" is not a valid year.");
}
// now, using the year, month and numbered weekday, we need to find the actual day of the month...
$firstofmonth = new qCal_Date($year, $month, 1);
$numdaysinmonth = $firstofmonth->getNumDaysInMonth();
$numweekdays = 0; // the number of weekdays that have occurred (in the loop)
$foundday = false;
if ($negpos == "+") {
$day = 1;
$wday = $firstofmonth->getWeekday();
// while we are in the current month, loop
while ($day <= $numdaysinmonth) {
// if the specified weekday == the current week day in the loop
if ($weekday == $wday) {
$numweekdays++;
if ($numweekdays == $xth) {
// break out of the loop, we've found the right day! yay!
$foundday = $day;
break;
}
}
if ($wday == 6) $wday = 0; // reset to Sunday after Saturday
else $wday++;
$day++;
}
} else {
$day = $numdaysinmonth;
$lastofmonth = $firstofmonth->getLastDayOfMonth();
$wday = $lastofmonth->getWeekday();
while ($day >= 1) {
if ($weekday == $wday) {
$numweekdays++;
if ($numweekdays == $xth) {
// break out of the loop, we've found the right day! yay!
$foundday = $day;
break;
}
}
if ($wday == 0) $wday = 6; // reset to Saturday after Sunday
else $wday--;
$day--;
}
}
if ($foundday && checkdate($month, $day, $year)) {
$date = new qCal_Date($year, $month, $day);
} else {
if ($day == 32) {
throw new qCal_DateTime_Exception_InvalidDate("You have specified an incorrect number of days for qCal_Date::getXthWeekdayOfMonth()");
} else {
throw new qCal_DateTime_Exception_InvalidDate("You have entered an invalid date.");
}
}
return $date;
}
/**
* Determine the number or Tuesdays (or whatever day of the week this date is) since the
* beginning or end of the year.
*/
public function getXthWeekdayOfYear($xth, $weekday = null, $year = null) {
$negpos = substr($xth, 0, 1);
if ($negpos == "+" || $negpos == "-") {
$xth = (integer) substr($xth, 1);
} else {
$negpos = "+";
}
if (is_null($weekday)) {
$weekday = $this->getWeekday();
}
if (ctype_digit((string) $weekday)) {
if (!array_key_exists($weekday, $this->weekdays)) {
throw new qCal_Date_Exception_InvalidWeekday("\"$weekday\" is not a valid weekday.");
}
} else {
$weekday = strtolower($weekday);
if (!in_array($weekday, $this->weekdays)) {
throw new qCal_Date_Exception_InvalidWeekday("\"$weekday\" is not a valid weekday.");
}
$wdays = array_flip($this->weekdays);
$weekday = $wdays[$weekday];
}
if (is_null($year)) {
$year = $this->getYear();
}
if (!ctype_digit((string) $year) || strlen($year) != 4) {
throw new qCal_Date_Exception_InvalidYear("\"$year\" is not a valid year.");
}
// now find the specified day by counting either forwards or backwards to the day in question
$firstofyear = new qCal_Date($year, 1, 1);
$numdaysinyear = ($firstofyear->isLeapYear()) ? 366 : 365;
$numweekdays = 0; // the number of weekdays that have occurred within the loop
$found = false; // whether or not the specified day has been found
if ($negpos == "+") {
// count forward
// loop over every day of every month looking for the right one
$day = 1;
$wday = $firstofyear->getWeekDay();
while ($day <= $numdaysinyear) {
// if the specified weekday == the current week day in the loop
if ($weekday == $wday) {
$numweekdays++;
if ($numweekdays == $xth) {
// break out of the loop, we've found the right day! yay!
$found = $day;
break;
}
}
if ($wday == 6) $wday = 0; // reset to Sunday after Saturday
else $wday++;
$day++;
}
} else {
// count backward
$lastofyear = new qCal_Date($year, 12, 31);
// count forward
// loop over every day of every month looking for the right one
$day = $numdaysinyear;
$wday = $lastofyear->getWeekDay();
while ($day >= 1) {
// if the specified weekday == the current week day in the loop
if ($weekday == $wday) {
$numweekdays++;
if ($numweekdays == $xth) {
// break out of the loop, we've found the right day! yay!
$found = $day;
break;
}
}
if ($wday == 0) $wday = 6; // reset to Saturday after Sunday
else $wday--;
$day--;
}
}
// @todo: Can't use checkdate here, so find another validation method...
if ($found) {
$date = new qCal_Date($year, 1, $found, true); // takes advantage of the rollover feature :)
} else {
throw new qCal_DateTime_Exception_InvalidDate("You have specified an incorrect number of days for qCal_Date::getXthWeekdayOfYear()");
}
return $date;
}
/**
* Magic methods
*/
/**
* Output the date as a string. Options are as follows:
* @return string The formatted date
*/
public function __toString() {
return $this->format($this->format);
}
/**
* Static methods
*/
/**
* Because PHP does not provide a gmgetdate() function, I borrowed this one from the
* comments on the getdate() function page on php.net
* @param integer The timestamp to use to create the date
*/
public static function gmgetdate($timestamp = null) {
$k = array('seconds','minutes','hours','mday','wday','mon','year','yday','weekday','month',0);
return(array_combine($k, split(":", gmdate('s:i:G:j:w:n:Y:z:l:F:U', is_null($timestamp) ? time() : $timestamp))));
}
}
@@ -0,0 +1,190 @@
<?php
/**
* qCal_DateTime
*
* In order to perform all the complex date/time based math and logic required to
* implement the iCalendar spec, we need a complex date/time class. This class represents
* a specific point in time, including the time. Internally it makes use of qCal_Date and
* qCal_Time. If only a date or only a time needs to be represented, then one of those
* classes should be used.
*
* @package qCal_Date
* @
*/
class qCal_DateTime {
/**
* @var qCal_Date An object that represents the date
*/
protected $date;
/**
* @var qCal_Time An object that represents the time
*/
protected $time;
/**
* @var string The default string representation of datetime is a direct
* correlation to the date function's "c" metacharacter
*/
protected $format = "Y-m-d\TH:i:sP";
/**
* Class constructor
* @todo Make this default to "now"
* @todo It is possible that the timezone could put the date back (or forward?) a day. This does not account for that
*/
public function __construct($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $timezone = null, $rollover = null) {
$date = new qCal_Date($year, $month, $day, $rollover);
$time = new qCal_Time($hour, $minute, $second, $timezone, $rollover);
$this->setDate($date);
$this->setTime($time);
}
/**
* Generate a datetime object via string
* @todo Should this accept qCal_Date and qCal_DateTime objects?
*/
public static function factory($datetime, $timezone = null) {
if (is_null($timezone) || !($timezone instanceof qCal_Timezone)) {
// @todo Make sure this doesn't cause any issues
// detect if we're working with a UTC string like "19970101T180000Z", where the Z means use UTC time
if (strtolower(substr($datetime, -1)) == "z") {
$timezone = "UTC";
}
$timezone = qCal_Timezone::factory($timezone);
}
// get the default timezone so we can set it back to it later
$tz = date_default_timezone_get();
// set the timezone to GMT temporarily
date_default_timezone_set("GMT");
// handles unix timestamp
if (is_integer($datetime) || ctype_digit((string) $datetime)) {
$timestamp = $datetime;
} else {
// handles just about any string representation of date/time (strtotime)
if (is_string($datetime) || empty($datetime)) {
if (!$timestamp = strtotime($datetime)) {
// if unix timestamp can't be created throw an exception
throw new qCal_DateTime_Exception("Invalid or ambiguous date/time string passed to qCal_DateTime::factory()");
}
}
}
if (!isset($timestamp)) {
throw new qCal_DateTime_Exception("Could not generate a qCal_DateTime object.");
}
list($year, $month, $day, $hour, $minute, $second) = explode("|", gmdate("Y|m|d|H|i|s", $timestamp));
// set the timezone back to what it was
date_default_timezone_set($tz);
return new qCal_DateTime($year, $month, $day, $hour, $minute, $second, $timezone);
}
/**
* Set the date component
*/
protected function setDate(qCal_Date $date) {
$this->date = $date;
}
/**
* Set the time component
*/
protected function setTime(qCal_Time $time) {
$this->time = $time;
}
/**
* Get time portion as object
*/
public function getTime() {
return $this->time;
}
/**
* Get date portion as object
*/
public function getDate() {
return $this->date;
}
/**
* Get unix timestamp
*/
public function getUnixTimestamp($useOffset = true) {
return $this->date->getUnixTimestamp() + $this->time->getTimestamp($useOffset);
}
/**
* Set the format to use when outputting as a string
*/
public function setFormat($format) {
$this->format = (string) $format;
return $this;
}
/**
* Format the date/time using PHP's date() function's meta-characters
* @todo It's obvious I need to find a better solution to formatting since I have repeated this method
* in three classes now...
*/
public function format($format) {
$escape = false;
$meta = str_split($format);
$output = array();
foreach($meta as $char) {
if ($char == '\\') {
$escape = true;
continue;
}
if (!$escape && $this->convertChar($char) != $char) {
$output[] = $this->convertChar($char);
} else {
$output[] = $char;
}
// reset this to false after every iteration that wasn't "continued"
$escape = false;
}
return implode($output);
}
/**
* convert character
*/
protected function convertChar($char) {
$char = $this->date->format($char);
$char = $this->time->format($char);
$char = $this->time->getTimezone()->format($char);
return $char;
}
/**
* Output date/time as string
*/
public function __toString() {
return $this->format($this->format);
}
/**
* Get date/time as UTC
*/
public function getUtc($humanReadable = false) {
if ($humanReadable) return gmdate('Y-m-d', $this->date->getUnixTimestamp()) . gmdate('\TH:i:s\Z', $this->time->getTimestamp());
else return gmdate('Ymd', $this->date->getUnixTimestamp()) . gmdate('\THis\Z', $this->time->getTimestamp());
}
}
@@ -0,0 +1,115 @@
<?php
/**
* Date duration
*
* @package qCal
* @subpackage qCal_DateTime
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_DateTime_Duration {
// an array of how manys seconds are in a minute, hour, day, etc.
// IMPORTANT - don't change the order of these
protected $durations = array ('W' => 604800, 'D' => 86400, 'H' => 3600, 'M' => 60, 'S' => 1);
/**
* Duration in seconds
*/
protected $duration;
/**
* If this is negative, this will be a minus symbol. Positive doesn't need a sign, so it is just null
*/
protected $sign;
/**
* Constructor
*/
public function __construct($duration = null) {
$this->setDuration($duration);
}
/**
* Set duration - accepts an integer (amount of seconds) or an icalendar-formatted duration string
*/
public function setDuration($duration) {
$duration = strtoupper($duration);
// if plus or minus precedes number, remove it set in class
if (preg_match("/^[+-]/", (string) $duration, $matches)) {
if ($matches[0] == "-") $this->sign = "-";
$duration = str_split($duration);
array_shift($duration);
$duration = implode("", $duration);
}
if (ctype_digit($duration)) {
$this->duration = $duration;
} else {
// convert value to duration in seconds
preg_match('/^P([0-9]+[W])?([0-9]+[D])?T?([0-9]+[H])?([0-9]+[M])?([0-9]+[S])?$/i', $duration, $matches);
// remove first element (which is just entire the matched string)
array_shift($matches);
$seconds = 0;
foreach ($matches as $duration) {
if (empty($duration)) continue;
$seconds += $this->calculateSeconds($duration);
}
$this->duration = $seconds;
}
return $this;
}
/**
* Pass in a string like "15W" or "1D" and this will return how many seconds are in it
*/
protected function calculateSeconds($duration) {
$amnt = preg_replace("/[^0-9]/i", "", $duration);
$inc = preg_replace("/[^A-Z]/i", "", $duration);
return $this->durations[$inc] * $amnt;
}
/**
* Converts seconds to an icalendar-formatted duration string
*/
public function toICal() {
$total = $this->duration;
$return = "P";
// this is why order is important when defining $this->durations
foreach ($this->durations as $dur => $amnt) {
// how many "weeks" are in the value?
$quotient = (int) ($total / $amnt);
// get the remainder of the division
$remainder = $total - ($quotient*$amnt);
// now if we got a whole number as quotient, add this duration to the return string
if ($quotient) {
// if this is the first "time" duration, add the required T char
if ($dur == "H" || $dur == "M" || $dur == "S") {
if (!strpos($return, "T")) $return .= "T";
}
$return .= $quotient . $dur;
}
$total = $remainder;
}
return $this->sign . $return;
}
/**
* @todo Should this be the string representation? I dont really know.
*/
public function __toString() {
return $this->toICal();
}
/**
* Get duration in seconds
*/
public function getSeconds() {
return (integer) $this->sign . $this->duration;
}
}
@@ -0,0 +1,7 @@
<?php
/**
* qCal_Date is a sub-package of qCal, so it has its own exceptions.
*/
class qCal_DateTime_Exception extends qCal_Exception {
}
@@ -0,0 +1,12 @@
<?php
/**
* Invalid Date Exception - thrown when an invalid or ambiguous date is passed to qCal_Date::setDate()
* @package qCal
* @subpackage qCal_Date
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_DateTime_Exception_InvalidDate extends qCal_DateTime_Exception {
}
@@ -0,0 +1,12 @@
<?php
/**
* Invalid Date Span Exception - thrown when somebody attempts to make a start date come after an end date
* @package qCal
* @subpackage qCal_Date
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_DateTime_Exception_InvalidPeriod extends qCal_DateTime_Exception {
}
@@ -0,0 +1,12 @@
<?php
/**
* Invalid Date Recurrence Exception - thrown when somebody attempts to create an invalid recurrence
* @package qCal
* @subpackage qCal_Date
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_DateTime_Exception_InvalidRecur extends qCal_DateTime_Exception {
}
@@ -0,0 +1,12 @@
<?php
/**
* Invalid Time Exception - thrown when an invalid or ambiguous time string is passed to qCal_Time::setTime()
* @package qCal
* @subpackage qCal_Date
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_DateTime_Exception_InvalidTime extends qCal_DateTime_Exception {
}
@@ -0,0 +1,2 @@
<?php
class qCal_DateTime_Exception_InvalidTimezone extends qCal_DateTime_Exception {}
@@ -0,0 +1,6 @@
<?php
class qCal_DateTime_Exception_InvalidWeekday extends qCal_DateTime_Exception {
// w00t!
}
@@ -0,0 +1,62 @@
<?php
/**
* Date period object - rather than a point in time, this object represents a PERIOD of time. So,
* it consists of a start and end point in time
*
* @package qCal
* @subpackage qCal_Date
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_DateTime_Period {
/**
* Start and end date/times
*/
protected $start, $end;
/**
* Constructor
*/
public function __construct($start, $end) {
if (!($start instanceof qCal_DateTime)) {
$start = qCal_DateTime::factory($start);
}
if (!($end instanceof qCal_DateTime)) {
$end = qCal_DateTime::factory($end);
}
$this->start = $start;
$this->end = $end;
if ($this->getSeconds() < 0) {
throw new qCal_DateTime_Exception_InvalidPeriod("The start date must come before the end date.");
}
}
/**
* Converts to how many seconds between the two. because this is the smallest increment
* used in this class, seconds are used to determine other increments
*/
public function getSeconds() {
return $this->end->getUnixTimestamp() - $this->start->getUnixTimestamp();
}
/**
* Returns start date
*/
public function getStart() {
return $this->start;
}
/**
* Returns end date
*/
public function getEnd() {
return $this->end;
}
}
@@ -0,0 +1,452 @@
<?php
/**
* This is a class that is used within qCal_Value_Recur to internally store a recur property
* @todo The RFC says that invalid byXXX rule parts should simply be ignored. So I'm not sure if
* I should be hurling exceptions at the poor user all over the place like I am in here.
*/
abstract class qCal_DateTime_Recur {
/**
* @var array An array of week days. Used throughout this class to validate input.
*/
protected $weekdays = array(
'MO' => 'Monday',
'TU' => 'Tuesday',
'WE' => 'Wednesday',
'TH' => 'Thursday',
'FR' => 'Friday',
'SA' => 'Saturday',
'SU' => 'Sunday',
);
/**
* @var qCal_Date The start date/time of the recurrence
*/
protected $dtstart;
/**
* @var string frequency of the recurrence
*/
protected $freq;
/**
* @var qCal_Date The date/time which the recurrence ends
*/
protected $until;
/**
* @var integer The amount of recurrences
*/
protected $count;
/**
* @var integer Interval of recurrence (for every 3 days, "3" would be the interval)
*/
protected $interval;
/**
* @var integer|array An integer between 0 and 59 (for multiple, set as an array)
*/
protected $bysecond;
/**
* @var integer|array An integer between 0 and 59 (or an array of integers for multiple)
*/
protected $byminute;
/**
* @var integer|array An integer or array of integers between 0 and 23
*/
protected $byhour;
/**
* @var string If present, represents the nth occurrence of a specific day within monthly or yearly
* so it can be something like +1MO (or simply 1MO) for the first monday within the month, whereas
* -1MO for the last monday of the month. Or it can be simply MO to represent every monday within the month
*/
protected $byday;
/**
* @var integer|array An integer or array of integers. -31 to -1 or 1 to 31. -10 would mean the tenth to last
* day of the month. [1,5,-5] would be the 1st, 5th, and 5th to last days of the month
*/
protected $bymonthday;
/**
* @var integer|array An integer or array of integers. -366 to -1 or 1 to 366. -306 represents the 306th to last
* day of the year (March 1st)
*/
protected $byyearday;
/**
* @var integer|array An integer or array of integers. -53 to -1 or 1 to 53. Only valid for yearly rules.
* 3 represents the third week of the year.
*/
protected $byweekno;
/**
* @var integer|array An integer or array of integers. 1 to 12. 3 would represent March
*/
protected $bymonth;
/**
* @var integer If present, it indicates the nth occurrence of the specific occurrence within the set of
* events specified by this recurrence rule
*/
protected $bysetpos;
/**
* @var string Must be one of the weekdays specified above (2 char). Specifies the day on which the work week
* starts. This is significant when a weekly rule has an interval greater than 1 and a byday rule part is specified.
* This is also significant when in a yearly rule when a byweekno rule part is specified. Defaults to "MO"
*/
protected $wkst = "MO";
/**
* Constructor
* @param $freq string Must be one of the freqtypes specified above.
* @throws qCal_Date_Exception_InvalidRecur if a frequency other than those specified above is passed in
*/
public function __construct($dtstart = null) {
$this->dtstart = is_null($dtstart) ? null : qCal_DateTime::factory($dtstart);
}
/**
* Specifies the date when the recurrence stops, inclusively. If not present, and there is no count specified,
* then the recurrence goes on "forever".
* This is a getter as well as a setter (if no arg is supplied, it is a getter)
* @param $until string|qCal_Date|DateTime If time is specified, it must be UTC
* @throws qCal_Date_Exception_InvalidRecur
* @return self
*/
public function until($until = null) {
if (is_null($until)) return $this->until;
if ($this->count()) throw new qCal_DateTime_Exception_InvalidRecur('A recurrence count and an until date cannot both be specified');
$this->until = qCal_DateTime::factory($until);
return $this;
}
/**
* Specifies the amount of recurrences before the recurrence ends. If neither this nor "until" is specified,
* the recurrence repeats "forever".
* This is a getter as well as a setter (if no arg is supplied, it is a getter)
* @param $count integer The amount of recurrences before it stops
* @throws qCal_Date_Exception_InvalidRecur
* @return self
*/
public function count($count = null) {
if (is_null($count)) return $this->count;
if ($this->until()) throw new qCal_DateTime_Exception_InvalidRecur('A recurrence count and an until date cannot both be specified');
$this->count = (integer) $count;
return $this;
}
/**
* Specifies the start of the work-week, which is Monday by default
*/
public function wkst($wkst = null) {
if (is_null($wkst)) return $this->wkst;
$abbrs = array_keys($this->weekdays);
if (!in_array($wkst, $abbrs)) throw new qCal_DateTime_Exception_InvalidRecur('"' . $wkst . '" is not a valid week day, must be one of the following: ' . implode(', ', $abbrs));
$this->wkst = $wkst;
// @todo I wonder if re-sorting the weekdays array would help me in any way...
}
/**
* Specifies the interval of recurrences
* This is a getter as well as a setter (if no arg is supplied, it is a getter)
* @param $interval integer The interval of recurrences, for instance every "3" days
* @throws qCal_DateTime_Exception_InvalidRecur
* @return self
*/
public function interval($interval = null) {
if (is_null($interval)) return $this->interval;
$this->interval = (integer) $interval;
return $this;
}
/**
* Specifies a rule which will happen on every nth second.
* This is a getter as well as a setter (if no arg is supplied, it is a getter)
* @param $second integer|array Can be an integer (or array of ints) between 0 and 59
* @throws qCal_DateTime_Exception_InvalidRecur
* @return self
*/
public function bySecond($second = null) {
if (is_null($second)) return $this->bysecond;
if (!is_array($second)) $second = array($second);
$this->bysecond = $second;
return $this;
}
/**
* Specifies a rule which will happen on every nth minute
* This is a getter as well as a setter (if no arg is supplied, it is a getter)
* @param $minute integer|array Can be an integer (or array of ints) between 0 and 59
* @throws qCal_DateTime_Exception_InvalidRecur
* @return self
*/
public function byMinute($minute = null) {
if (is_null($minute)) return $this->byminute;
if (!is_array($minute)) $minute = array($minute);
$this->byminute = $minute;
return $this;
}
/**
* Specifies a rule which will happen on every nth hour
* This is a getter as well as a setter (if no arg is supplied, it is a getter)
* @param $hour integer|array Can be an integer (or array of ints) between 0 and 23
* @throws qCal_DateTime_Exception_InvalidRecur
* @return self
*/
public function byHour($hour = null) {
if (is_null($hour)) return $this->byhour;
if (!is_array($hour)) $hour = array($hour);
$this->byhour = $hour;
return $this;
}
/**
* Specifies a rule which will happen on whichever day is specified. For instance, "MO" would
* mean every monday.
* This is a getter as well as a setter (if no arg is supplied, it is a getter)
* Sets $this->byday into an array of arrays like array('SU' => 1) for '1SU' and array('SU' => 0) for 'SU'
* @param $day string|array Must be one of the 2-char week days specified above. Can be preceded by
* a positive or negative integer to represent, for instance, the third monday of the month (3MO) or second to last
* Sunday of the month (-2SU)
* @throws qCal_DateTime_Exception_InvalidRecur
* @return self
*/
public function byDay($day = null) {
if (is_null($day)) {
$ret = array();
foreach ($this->byday as $val) {
$num = (current($val) == 0) ? "" : current($val);
$ret[] = $num . key($val);
}
return $ret;
}
if (!is_array($day)) $day = array($day);
$days = array();
foreach ($day as $d) {
// optional plus or minus followed by a series of digits as group 1
// two-character week day as group 2
if (preg_match('/^([+-]?[0-9]+)?(MO|TU|WE|TH|FR|SA|SU)$/', $d, $matches)) {
$num = ($matches[1] == "") ? "0" : $matches[1];
$wday = $matches[2];
if (substr($num, 0, 1) == "+") {
$num = substr($num, 1);
}
$days[] = array($wday => $num);
}
}
$this->byday = $days;
return $this;
}
/**
* Specifies a rule which will happen on the month days specified. For instance, 23 would mean the 23rd of every month.
* This is a getter as well as a setter (if no arg is supplied, it is a getter)
* @param integer|array Must be between 1 and 31 or -31 to 1 (or an array of those values)
* @throws qCal_DateTime_Exception_InvalidRecur
* @return self
*/
public function byMonthDay($monthday = null) {
if (is_null($monthday)) return $this->bymonthday;
if (!is_array($monthday)) $monthday = array($monthday);
$this->bymonthday = $monthday;
return $this;
}
/**
* Specifies a rule which will happen on the nth day of the year
* This is a getter as well as a setter (if no arg is supplied, it is a getter)
* @param integer|array Must be between 1 and 366 or -366 to -1.
* @throws qCal_DateTime_Exception_InvalidRecur
* @return self
*/
public function byYearDay($yearday = null) {
if (is_null($yearday)) return $this->byyearday;
if (!is_array($yearday)) $yearday = array($yearday);
$this->byyearday = $yearday;
return $this;
}
/**
* Specifies a rule which will happen on the nth week of the year
* This is a getter as well as a setter (if no arg is supplied, it is a getter)
* @param integer|array Must be between 1 and 53 or -53 to -1.
* @throws qCal_DateTime_Exception_InvalidRecur
* @return self
*/
public function byWeekNo($weekno = null) {
if (is_null($weekno)) return $this->byweekno;
if (!is_array($weekno)) $weekno = array($weekno);
$this->byweekno = $weekno;
return $this;
}
/**
* Specifies a rule which will happen on the nth month of the year
* This is a getter as well as a setter (if no arg is supplied, it is a getter)
* @param integer|array Must be between 1 and 12
* @throws qCal_DateTime_Exception_InvalidRecur
* @return self
*/
public function byMonth($month = null) {
if (is_null($month)) return $this->bymonth;
if (!is_array($month)) $month = array($month);
$this->bymonth = $month;
return $this;
}
/**
* Indicates the nth occurrence of the specific occurrence within the set of
* events specified by the rule.
* This is a getter as well as a setter (if no arg is supplied, it is a getter)
* @todo I don't really understand how this works... :( Figure out wtf it is for.
* @throws qCal_DateTime_Exception_InvalidRecur
* @return self
*/
public function bySetPos($setpos = null) {
if (is_null($setpos)) return $this->bysetpos;
$this->bysetpos = (integer) $setpos;
return $this;
}
/**
* Factory method generates the correct recur type based on the string it is passed: "yearly, weekly, etc."
* @param string The frequency type of recurrence rule you want to generate
* @param mixed The start date/time for the recurrence. Accepts anything qCal_Date accepts
*/
static public function factory($freq, $start) {
$freq = ucfirst(strtolower($freq));
$className = "qCal_DateTime_Recur_" . $freq;
$fileName = str_replace("_", DIRECTORY_SEPARATOR, $className) . ".php";
qCal_Loader::loadFile($fileName);
$class = new $className($start);
return $class;
}
/**
* Fetches instances of the recurrence rule in the given time period. Because recurrences
* could potentially go on forever, there is no way to fetch ALL instances of a recurrence rule
* other than providing a date range that spans the entire length of the recurrence.
*
* The way this will need to work is, depending on the frequency, I will find all possible
* occurrence of the rule. For instance, if this is a "monthly" rule, I'll find out which month
* to start in, then find all occurrence possible. Then narrow down by the other rules I guess.
*
* @idea Maybe I should build classes for each of the frequency types. That way I could loop over
* the object and get methods like qCal_DateTime_Recur_Monthly::isNthDay('SU') to find out what sunday
* of the month it is... stuff like that... I dunno... ?
*
* @throws qCal_DateTime_Exception_InvalidRecur
* @todo The giant switch in this method is a glaring code smell, but it works for now. I will refactor
* after version 0.1 and remove the switch (probably will implement qCal_DateTime_Recur_Yearly, qCal_DateTime_Recur_Monthly, etc.)
*/
public function getRecurrences($start, $end) {
$start = qCal_DateTime::factory($start);
$end = qCal_DateTime::factory($end);
if ($start->getUnixTimestamp() > $end->getUnixTimestamp()) throw new qCal_DateTime_Exception_InvalidRecur('Start date must come before end date');
if (!$this->interval) throw new qCal_DateTime_Exception_InvalidRecur('You must specify an interval');
$rules = array(
'bymonth' => array(),
'byweekno' => array(),
'byyearday' => array(),
'byday' => array(),
);
// byMonth rules
if (is_array($this->bymonth)) {
foreach ($this->bymonth as $bymonth) {
$rules['bymonth'][] = new qCal_DateTime_Recur_Rule_ByMonth($bymonth);
}
}
// byWeekNo rules
if (is_array($this->byweekno)) {
foreach ($this->byweekno as $byweekno) {
$rules['byweekno'][] = new qCal_DateTime_Recur_Rule_ByWeekNo($byweekno);
}
}
// byYearDay rules
if (is_array($this->byyearday)) {
foreach ($this->byyearday as $byyearday) {
$rules['byyearday'][] = new qCal_DateTime_Recur_Rule_ByYearDay($byyearday);
}
}
// byMonthDay rules (these get applied to bymonth rules)
if (is_array($this->bymonthday)) {
foreach ($this->bymonthday as $bymonthday) {
$bmdrule = new qCal_DateTime_Recur_Rule_ByMonthDay($bymonthday);
foreach ($rules['bymonth'] as $bymonth) {
$bymonth->attach($bmdrule);
}
}
}
// byDay rules (these get applied to bymonth rules if they exist, otherwise simply to year)
if (is_array($this->byday)) {
foreach ($this->byday as $byday) {
$bdrule = new qCal_DateTime_Recur_Rule_ByDay($byday);
if (is_array($rules['bymonth']) && !empty($rules['bymonth'])) {
foreach ($rules['bymonth'] as $bymonth) {
$bymonth->attach($bdrule);
}
} else {
$rules['byday'][] = $bdrule;
}
}
}
// byHour rules (these get applied to each rule above)
if (is_array($this->byhour)) {
foreach ($this->byhour as $byhour) {
$bhrule = new qCal_DateTime_Recur_Rule_ByHour($byhour);
foreach ($rules as $type => $ruleset) {
foreach ($ruleset as $rule) {
$rule->attach($bhrule);
}
}
}
}
// byMinute rules (these get applied to each rule above)
if (is_array($this->byminute)) {
foreach ($this->byminute as $byminute) {
$bmrule = new qCal_DateTime_Recur_Rule_ByMinute($byminute);
foreach ($rules as $type => $ruleset) {
foreach ($ruleset as $rule) {
$rule->attach($bmrule);
}
}
}
}
// bySecond rules (these get applied to each rule above)
if (is_array($this->bysecond)) {
foreach ($this->bysecond as $bysecond) {
$bsrule = new qCal_DateTime_Recur_Rule_BySecond($bysecond);
foreach ($rules as $type => $ruleset) {
foreach ($ruleset as $rule) {
$rule->attach($bsrule);
}
}
}
}
return $this->doGetRecurrences($rules, $start, $end);
}
/**
* Each type of rule needs to determine its recurrences so this is left abstract
* to be implemented by children.
*/
abstract protected function doGetRecurrences($rules, $start, $end);
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Daily extends qCal_DateTime_Recur {
protected function doGetRecurrences($rules, $start, $end) {
// do stuff!
}
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Hourly extends qCal_DateTime_Recur {
protected function doGetRecurrences($rules, $start, $end) {
// do stuff!
}
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Minutely extends qCal_DateTime_Recur {
protected function doGetRecurrences($rules, $start, $end) {
// do stuff!
}
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Monthly extends qCal_DateTime_Recur {
protected function doGetRecurrences($rules, $start, $end) {
// do stuff!
}
}
@@ -0,0 +1,35 @@
<?php
abstract class qCal_DateTime_Recur_Rule {
/**
* @var array The sub-rules of this rule.
*/
protected $rules = array();
/**
* @var mixed The value of this rule
*/
protected $value;
/**
* Constructor
* @param The value of the rule. If this is a ByMonth rule, then 1 would mean January
*/
public function __construct($value) {
$this->value = $value;
}
/**
* Attach rules to this rule. For instance, if this is a byMonth rule, then
* we can attach byDay rules like "-1SU" for the last Sunday of the month.
*/
public function attach(qCal_DateTime_Recur_Rule $rule) {
$this->rules[] = $rule;
}
/**
* Creates the recurrences for this rule. Left to children to do this.
*/
abstract public function getRecurrences();
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Rule_ByDay extends qCal_DateTime_Recur_Rule {
public function getRecurrences() {
return array();
}
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Rule_ByHour extends qCal_DateTime_Recur_Rule {
public function getRecurrences() {
return array();
}
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Rule_ByMinute extends qCal_DateTime_Recur_Rule {
public function getRecurrences() {
return array();
}
}
@@ -0,0 +1,14 @@
<?php
class qCal_DateTime_Recur_Rule_ByMonth extends qCal_DateTime_Recur_Rule {
/**
* If there are sub-rules then this rule may return more than one instance or it
* may return none.
*/
public function getRecurrences() {
return array();
}
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Rule_ByMonthDay extends qCal_DateTime_Recur_Rule {
public function getRecurrences() {
return array();
}
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Rule_BySecond extends qCal_DateTime_Recur_Rule {
public function getRecurrences() {
return array();
}
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Rule_BySetPos extends qCal_DateTime_Recur_Rule {
public function getRecurrences() {
return array();
}
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Rule_ByWeekNo extends qCal_DateTime_Recur_Rule {
public function getRecurrences() {
return array();
}
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Rule_ByYearDay extends qCal_DateTime_Recur_Rule {
public function getRecurrences() {
return array();
}
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Secondly extends qCal_DateTime_Recur {
protected function doGetRecurrences($rules, $start, $end) {
// do stuff!
}
}
@@ -0,0 +1,10 @@
<?php
class qCal_DateTime_Recur_Weekly extends qCal_DateTime_Recur {
protected function doGetRecurrences($rules, $start, $end) {
// do stuff!
}
}
@@ -0,0 +1,143 @@
<?php
class qCal_DateTime_Recur_Yearly extends qCal_DateTime_Recur {
/**
* @todo This is a god method that really should be split out into each
* of the qCal_DateTime_Recur_Rule_ByXXX classes. For now I did all the logic
* here to keep it simple and not confuse myself more than necessary.
*/
protected function doGetRecurrences($rules, $start, $end) {
// an array to store recurrences
$recurrences = array();
// start day, year, and month
$sday = $start->format('d');
$smonth = $start->format('m');
$syear = $start->format('Y');
// end day, year, and month
$eday = $end->format('d');
$emonth = $end->format('m');
$eyear = $end->format('Y');
// loop over years, by increment
$year = $syear;
while ($year <= $eyear) {
// if byMonth is specified...
if (count($this->byMonth())) {
// loop over each month
for ($month = 1; $month <= 12; $month++) {
// if this is the start year still and we haven't reached the start month, skip ahead
if ($year == $syear && $month < $smonth) {
continue;
}
// if this is the end year and we have passed the end month, break out of loop
if ($year == $eyear && $month > $emonth) {
break;
}
// if this is not one of the bymonths, continue as well
if (!in_array($month, $this->byMonth())) {
continue;
}
// now we need to loop over each day of the month to look for byday or bymonthday
$thismonth = new qCal_Date(); // used to determine total days in the current month
$thismonth->setDate($year, $month, 1);
$weekdays = array(
'MO' => 0,
'TU' => 0,
'WE' => 0,
'TH' => 0,
'FR' => 0,
'SA' => 0,
'SU' => 0,
);
// @todo For now this only allows 1SU, SU, but not -1SU (no negatives for now)
for ($day = 1; $day <= $thismonth->format('t'); $day++) {
$alreadyadded = false;
$date = new qCal_Date;
$date->setDate($year, $month, $day);
$date->setTime(0, 0, 0);
$wdname = strtoupper(substr($date->format('l'), 0, 2));
// keep track of how many of each day of the week have gone by
$weekdays[$wdname]++;
// if byDay is specified...
// @todo this is inconsistent, I don't use the getter here because of its special functionality.
// I need to either remove the special functionality or not use getters elsewhere in this method
$byday = $this->byday;
if (count($byday)) {
// by day is broken into an array of arrays like array('TH' => 0), array('FR' => 1), array('MO' => -2) etc.
// with zero meaning every instance of that particular day should be included and number meaning the Nth of that day
foreach ($byday as $val) {
// if at least one of this wday has gone by...
$num = current($val);
if ($weekdays[$wdname] > 0) {
// check if it is the right week day and if a digit is specified (like 1SU) that it is checked as well
if ($wdname == key($val) && ($weekdays[$wdname] == $num || $num == 0)) {
$recurrences[] = $date;
$alreadyadded = true;
}
}
}
}
// if byMonthDay is specified...
if (count($this->byMonthDay())) {
foreach ($this->byMonthDay() as $mday) {
// only add this day if it hasn't been added already
if ($mday == $day && !$alreadyadded) {
$recurrences[] = $date;
}
}
}
// now loop over each hour and add hours
if (count($this->byHour())) {
$hourrecurrences = array();
foreach ($this->byHour() as $hour) {
$new = new qCal_Date();
$new = $new->copy($date);
$new->setTime($hour, 0, 0);
$hourrecurrences[] = $new;
}
}
// now loop over byHours and add byMinutes
if (count($this->byMinute())) {
if (!isset($minuterecurrences)) $minuterecurrences = array();
foreach ($this->byMinute() as $minute) {
$new = new qCal_Date();
$new = $new->copy($date);
$new->setTime(0, $minute, 0);
}
}
// now loop over byMinutes and add bySeconds
}
}
}
// if in the first year we don't find an instance, don't do the interval, just increment a year
if ($year == $syear && count($recurrences)) $year += $this->interval();
else ($year++);
}
// now loop over weeks to get byWeekNo
foreach ($recurrences as $date) {
// pr($date->format("r"));
}
// exit;
return $recurrences;
// for bymonth, it would make the most sense to loop over each month until the specified one
// is found. Then loop over each day to find its sub-rules.
// for byweekno, it would make the most sense to loop over each week until the specified one
// is found. Then apply any sub-rules (actually I'm not sure how byhour and its ilk would be applied in this situation... need to read the rfc)
}
}
@@ -0,0 +1,62 @@
<?php
class qCal_Time_Timezone {
protected $format = "P";
public function __construct($timezone = null) {
if (!is_null($timezone)) {
date_default_timezone_set($timezone);
}
}
public function getOffsetSeconds() {
return date("Z");
}
public function getOffsetHours() {
return date("O");
}
public function getOffset() {
return date("P");
}
public function getAbbreviation() {
return date("T");
}
public function isDaylightSavings() {
return (boolean) date("I");
}
public function getName() {
return date("e");
}
public function format($format) {
return date($format);
}
public function __toString() {
return $this->format($this->format);
}
}
@@ -0,0 +1,11 @@
<?php
/**
* Base qCal Exception
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_Exception extends Exception {
}
@@ -0,0 +1,6 @@
<?php
class qCal_Exception_FileNotFound extends qCal_Exception {
// hooty
}
@@ -0,0 +1,12 @@
<?php
/**
* Invalid Component Exception - when an attempt is made to attach a component to another component, and it isn't allowed
* this exception is thrown, for instance attempting to attach a calendar to a todo
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_Exception_InvalidComponent extends qCal_Exception {
}
@@ -0,0 +1,2 @@
<?php
class qCal_Exception_InvalidFile extends qCal_Exception {}
@@ -0,0 +1,12 @@
<?php
/**
* Invalid Property Exception - when an attempt is made to add a certain property
* to a component that doesn't allow said property, this exception is thrown.
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_Exception_InvalidProperty extends qCal_Exception {
}
@@ -0,0 +1,12 @@
<?php
/**
* Invalid Property Value Exception - if a property requires a certain type of value, and it is given
* the wrong value type, it will throw this exception.
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_Exception_InvalidPropertyValue extends qCal_Exception {
}
@@ -0,0 +1,6 @@
<?php
class qCal_Exception_MissingComponent extends qCal_Exception {
// represents an exception that is thrown when a component requires that another component be its child
}
@@ -0,0 +1,12 @@
<?php
/**
* Invalid Property Value Exception - if a component requires a certain property, and is instantiated
* without that property, this exception is thrown.
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_Exception_MissingProperty extends qCal_Exception {
}
@@ -0,0 +1,43 @@
<?php
/**
* qCal_Loader
* Loads files from the file system. Looks through the entire include path
*/
class qCal_Loader {
/**
* Load a class
*/
static public function loadClass($name) {
$path = str_replace("_", DIRECTORY_SEPARATOR, $name) . ".php";
self::loadFile($path);
}
/**
* Loads a file or throws an exception
*/
static public function loadFile($filename) {
if (!self::fileExists($filename)) {
throw new qCal_Exception_InvalidFile("$filename does not exist.");
}
require_once $filename;
}
/**
* Looks through the include path for file name
*/
static public function fileExists($filename) {
$includepath = get_include_path();
$includepath = explode(PATH_SEPARATOR, $includepath);
foreach ($includepath as $path) {
$path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
if (file_exists($path . $filename)) return true;
}
return false;
}
}
@@ -0,0 +1,106 @@
<?php
/**
* qCal_Parser
* The parser accepts an array of qCal_Parser_Token objects and converts them
* to actual formatted icalendar data (in one of many formats). The default is
* qCal_Parser_iCal which is complient with RFC 2445, but there are others as well,
* such as qCal_Parser_xCal (xml) or qCal_Parser_hCal (microformats).
*
* @package qCal
* @subpackage qCal_Parser
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_Parser {
/**
* @param array containing any options the particular parser accepts
*/
protected $options;
/**
* Constructor
* Pass in an array of options
* @todo Come up with list of available options
* @param array parser options
*/
public function __construct($options = array()) {
// set defaults...
$this->options = array(
'searchpath' => get_include_path(),
);
$this->options = array_merge($this->options, $options);
}
/**
* @todo What should this accept? filename? actual string content? either?
* @todo Maybe even create a parse() for raw string and a parseFile() for a file name?
*/
public function parse($content, $lexer = null) {
if (is_null($lexer)) {
$lexer = new qCal_Parser_Lexer_iCalendar($content);
}
$this->lexer = $lexer;
return $this->doParse($this->lexer->tokenize());
}
/**
* Parse a file. The searchpath defaults to the include path. Also, if the filename
* provided is an absolute path, the searchpath is not used. This is determined by
* either the file starting with a forward slash, or a drive letter (for Windows)
* @todo Throw an exception if file doesn't exist
* @todo I'm not really sure that it should default to the include path. That's not really what the include path is for, is it?
* @todo Test for path starting with a drive letter for windows (or find a better way to detect that)
*/
public function parseFile($filename) {
// @todo This is hacky... but it works
if (substr($filename, 0, 1) == '/' || substr($filename, 0, 3) == 'C:\\') {
if (file_exists($filename)) {
$content = file_get_contents($filename);
return $this->parse($content);
}
} else {
$paths = explode(PATH_SEPARATOR, $this->options['searchpath']);
foreach ($paths as $path) {
$fname = $path . DIRECTORY_SEPARATOR . $filename;
if (file_exists($fname)) {
$content = file_get_contents($fname);
return $this->parse($content);
}
}
}
throw new qCal_Exception_FileNotFound('File cannot be found: "' . $filename . '"');
}
/**
* Override doParse in a child class if necessary
*/
protected function doParse($tokens) {
$properties = array();
foreach ($tokens['properties'] as $propertytoken) {
$params = array();
foreach ($propertytoken['params'] as $paramtoken) {
$params[$paramtoken['param']] = $paramtoken['value'];
}
try {
$properties[] = qCal_Property::factory($propertytoken['property'], $propertytoken['value'], $params);
} catch (qCal_Exception $e) {
// @todo There should be a better way of determining what went wrong during parsing/lexing than this
// do nothing...
// pr($e);
}
}
$component = qCal_Component::factory($tokens['component'], $properties);
foreach ($tokens['children'] as $child) {
$childcmpnt = $this->doParse($child);
$component->attach($childcmpnt);
}
return $component;
}
}
@@ -0,0 +1,34 @@
<?php
/**
* qCal_Parser_Lexer
* Not sure if I like the name of this class, but what can you do?
* Anyway, this class converts a string into "tokens" which are then
* fed to the parser
*
* @package qCal
* @subpackage qCal_Parser
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
abstract class qCal_Parser_Lexer {
/**
* @var string input text
*/
protected $content;
/**
* Constructor
* @param string containing the text to be tokenized
*/
public function __construct($content) {
$this->content = $content;
}
/**
* Tokenize content into tokens that can be used to build iCalendar objects
*/
abstract public function tokenize();
}
@@ -0,0 +1,120 @@
<?php
/**
* qCal_Parser_Lexer_iCalendar
* The lexer for iCalendar RFC 2445 format. Other formats will need their
* own lexer. The lexer converts text to an array of "tokens", which, at least
* for now, are just arrays.
*
* @package qCal
* @subpackage qCal_Parser
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure that multi-value properties are taken care of properly
*/
class qCal_Parser_Lexer_iCalendar extends qCal_Parser_Lexer {
/**
* @var string character(s) used to terminate lines
*/
protected $line_terminator;
/**
* Constructor
*/
public function __construct($content) {
parent::__construct($content);
$this->line_terminator = chr(13) . chr(10);
}
/**
* Return a list of tokens (to be fed to the parser)
* @returns array tokens
*/
public function tokenize() {
$lines = $this->unfold($this->content);
// loop through chunks of input text by separating by properties and components
// and create tokens for each one, creating a multi-dimensional array of tokens to return
$stack = array();
foreach ($lines as $line) {
// begin a component
if (preg_match('#^BEGIN:([a-z]+)$#i', $line, $matches)) {
// create new array representing the new component
$array = array(
'component' => $matches[1],
'properties' => array(),
'children' => array(),
);
$stack[] = $array;
} elseif (strpos($line, "END:") === 0) {
// end component, pop the stack
$child = array_pop($stack);
if (empty($stack)) {
$tokens = $child;
} else {
$parent =& $stack[count($stack)-1];
array_push($parent['children'], $child);
}
} else {
// continue component
if (preg_match('#^([^:]+):"?([^\n]+)?"?$#i', $line, $matches)) {
// @todo What do I do with empty values?
$value = isset($matches[2]) ? $matches[2] : "";
$component =& $stack[count($stack)-1];
// if line is a property line, start a new property, but first determine if there are any params
$property = $matches[1];
$params = array();
$propparts = explode(";", $matches[1]);
if (count($propparts) > 1) {
foreach ($propparts as $key => $part) {
// the first one is the property name
if ($key == 0) {
$property = $part;
} else {
// the rest are params
// @todo Quoted param values need to be taken care of...
list($paramname, $paramvalue) = explode("=", $part, 2);
$params[] = array(
'param' => $paramname,
'value' => $paramvalue,
);
}
}
}
$proparray = array(
'property' => $property,
'value' => $value,
'params' => $params,
);
$component['properties'][] = $proparray;
}
}
}
return $tokens;
}
/**
* Unfold the file before trying to parse it
*/
protected function unfold($content) {
$return = array();
$lines = explode($this->line_terminator, $content);
foreach ($lines as $line) {
$checkempty = trim($line);
if (empty($checkempty)) continue;
$chr1 = substr($line, 0, 1);
$therest = substr($line, 1);
// if character 1 is a whitespace character... (tab or space)
if ($chr1 == chr(9) || $chr1 == chr(32)) {
$return[count($return)-1] .= $therest;
} else {
$return[] = $line;
}
}
return $return;
}
}
@@ -0,0 +1,289 @@
<?php
/**
* Base component property class. version, attach, rrule are all examples
* of component properties.
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* A property is the definition of an individual attribute describing a
* calendar or a calendar component. A property takes the form defined
* by the "contentline" notation defined in section 4.1.1.
*
* The following is an example of a property:
*
* DTSTART:19960415T133000Z
*
* This memo imposes no ordering of properties within an iCalendar
* object.
*
* Property names, parameter names and enumerated parameter values are
* case insensitive. For example, the property name "DUE" is the same as
* "due" and "Due", DTSTART;TZID=US-Eastern:19980714T120000 is the same
* as DtStart;TzID=US-Eastern:19980714T120000.
*/
abstract class qCal_Property {
/**
* Property name (dtstart, rrule, etc)
* This can be auto-generated from the class name
* @var string
*/
protected $name;
/**
* Property value
* @var qCal_Value object
*/
protected $value;
/**
* Default value - if set to false, there is no default value
* @var mixed
*/
protected $default = false;
/**
* Property Data Type (this name gets converted to class name)
* @var string
*/
protected $type;
/**
* Property parameters
* @var array
*/
protected $params = array();
/**
* Contains a list of components this property is allowed to be specified
* for
* @var array
*/
protected $allowedComponents = array();
/**
* Some properties can be specified multiple times in a component. This
* determines whether or not that is allowed for this property.
*/
protected $allowMultiple = false;
/**
* Class constructor
*
* @todo Cast $value to whatever data type this is ($this->type)
* @todo Determine if there can be multiple params of the same name
*/
public function __construct($value = null, $params = array()) {
if (is_null($this->name)) $this->name = $this->getPropertyNameFromClassName(get_class($this));
foreach ($params as $pname => $pval) {
$this->setParam($pname, $pval);
}
// this must be set after parameters because the VALUE parameter can affect it
$this->setValue($value);
}
/**
* Generates a qCal_Property class based on property name, params, and value
* which can come directly from an icalendar file
* @todo I need a way to detect INVALID properties as they are being parsed. This
* way there can be an option to NOT stop on errors. To just log and then continue.
*/
static public function factory($name, $value, $params = array()) {
$className = self::getClassNameFromPropertyName($name);
$fileName = str_replace("_", DIRECTORY_SEPARATOR, $className) . ".php";
try {
qCal_Loader::loadFile($fileName);
$class = new $className($value, $params);
} catch (qCal_Exception_InvalidFile $e) {
// if there is no class available for this property, check if it is non-standard
$xname = strtoupper(substr($name, 0, 2));
// non-standard property
if ($xname == "X-") {
$class = new qCal_Property_NonStandard($value, $params, $name);
} else {
// if it's not a non-standard property, rethrow
throw $e;
}
}
return $class;
}
/**
* Returns the property name (formatted and exactly to spec)
* @return string
*/
public function getName() {
return $this->name;
}
/**
* Returns the property value (as a string)
* If you want the actual object, use getValueObject()
* I wish I could just pass the object back and have php do some overloading magicness, but
* it doesn't know how :(
* @return string
*/
public function getValue() {
return $this->value->__toString();
}
/**
* Just returns getValue()
*/
public function __toString() {
return $this->getValue();
}
/**
* Returns raw value object (or for multi-value, an array)
* @return string
*/
public function getValueObject() {
return $this->value;
}
/**
* Sets the property value
* @param mixed
*/
public function setValue($value) {
// if value sent is null and this property doesn't have a default value,
// the property can't be created, so throw an invalidpropertyvalue exception
if (is_null($value)) {
if ($this->default === false) {
// this is caught by factory and reported as a conformance error
throw new qCal_Exception_InvalidPropertyValue($this->getName() . ' property must have a value');
} else {
$value = $this->default;
}
}
$this->value = $this->convertValue($value);
return $this;
}
/**
* Converts a value into whatever internal storage mechanism the property uses
*/
protected function convertValue($value) {
return qCal_Value::factory($this->getType(), $value);
}
/**
* Returns the property type
* @return string
*/
public function getType() {
return $this->type;
}
/**
* Check if this is a property of a certain component. Some properties
* can only be set on certain Components. This method looks inside this
* property's $allowedComponents and returns true if $component is allowed
*
* @return boolean True if this is a property of $component, false otherwise
* @param qCal_Component The component we're evaluating
**/
public function of(qCal_Component $component) {
return in_array($component->getName(), $this->allowedComponents);
}
/**
* Retreive the value of a parameter
*
* @return mixed parameter value
*/
public function getParam($name) {
if (isset($this->params[strtoupper($name)])) {
return $this->params[strtoupper($name)];
}
}
/**
* Returns an array of all params
*/
public function getParams() {
return $this->params;
}
/**
* Set the value of a parameter
*/
public function setParam($name, $value) {
$name = strtoupper($name);
// if value param has been passed in, change the type of this property to its value
if ($name == "VALUE") {
$value = strtoupper($value);
$this->type = $value;
}
$this->params[$name] = $value;
return $this;
}
/**
* Determine's this property's name from the class name by adding a dash after
* every capital letter and upper-casing
*
* @return string The RFC property name
* @todo This method is flawed. The class name XLvFoo gets converted to X-L-VFOO when
* it should be X-LV-FOO
**/
protected function getPropertyNameFromClassName($classname) {
// determine the property name by class name
$parts = explode("_", $classname);
end($parts);
// find where capital letters are and insert dash
$chars = str_split(current($parts));
// make a copy @todo Why make a copy?
$newchars = $chars;
foreach ($chars as $pos => $char) {
// don't add a dash for the first letter
if (!$pos) continue;
$num = ord($char);
// if character is a capital letter
if ($num >= 65 && $num <= 90) {
// insert dash
array_splice($newchars, $pos, 0, '-');
}
}
return strtoupper(implode("", $newchars));
}
/**
* Determine's this property's class name from the property name
*
* @return string The property class name
**/
protected function getClassNameFromPropertyName($name) {
// remove dashes, capitalize properly
$parts = explode("-", $name);
$property = "";
foreach ($parts as $part) $property .= trim(ucfirst(strtolower($part)));
// get the class, and instantiate
$className = "qCal_Property_" . $property;
return $className;
}
/**
* Is this property allowed to be specified multiple times in a component?
* @return boolean
*/
public function allowMultiple() {
return (boolean) $this->allowMultiple;
}
}
@@ -0,0 +1,51 @@
<?php
/**
* Action Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: ACTION
*
* Purpose: This property defines the action to be invoked when an alarm
* is triggered.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: This property MUST be specified once in a "VALARM"
* calendar component.
*
* Description: Each "VALARM" calendar component has a particular type
* of action associated with it. This property specifies the type of
* action
*
* Format Definition: The property is defined by the following notation:
*
* action = "ACTION" actionparam ":" actionvalue CRLF
*
* actionparam = *(";" xparam)
*
* actionvalue = "AUDIO" / "DISPLAY" / "EMAIL" / "PROCEDURE"
* / iana-token / x-name
*
* Example: The following are examples of this property in a "VALARM"
* calendar component:
*
* ACTION:AUDIO
*
* ACTION:DISPLAY
*
* ACTION:PROCEDURE
*/
class qCal_Property_Action extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VALARM');
}
@@ -0,0 +1,65 @@
<?php
/**
* Attach Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: ATTACH
*
* Purpose: The property provides the capability to associate a document
* object with a calendar component.
*
* Value Type: The default value type for this property is URI. The
* value type can also be set to BINARY to indicate inline binary
* encoded content information.
*
* Property Parameters: Non-standard, inline encoding, format type and
* value data type property parameters can be specified on this
* property.
*
* Conformance: The property can be specified in a "VEVENT", "VTODO",
* "VJOURNAL" or "VALARM" calendar components.
*
* Description: The property can be specified within "VEVENT", "VTODO",
* "VJOURNAL", or "VALARM" calendar components. This property can be
* specified multiple times within an iCalendar object.
*
* Format Definition: The property is defined by the following notation:
*
* attach = "ATTACH" attparam ":" uri CRLF
*
* attach =/ "ATTACH" attparam ";" "ENCODING" "=" "BASE64"
* ";" "VALUE" "=" "BINARY" ":" binary
*
* attparam = *(
*
* ; the following is optional,
* ; but MUST NOT occur more than once
*
* (";" fmttypeparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* Example: The following are examples of this property:
*
* ATTACH:CID:jsmith.part3.960817T083000.xyzMail@host1.com
*
* ATTACH;FMTTYPE=application/postscript:ftp://xyzCorp.com/pub/
* reports/r-960812.ps
*/
class qCal_Property_Attach extends qCal_Property {
protected $type = 'URI';
protected $allowedComponents = array('VALARM','VEVENT','VJOURNAL','VTODO');
protected $allowMultiple = true;
}
@@ -0,0 +1,144 @@
<?php
/**
* Attendee Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure that allowedComponents is correct. I am still a little
* confused about how this property works. It is apparent that it is
* used differently based on compoenent. I think the correct place
* to put logic like that is in the component itself.
*
* RFC 2445 Definition
*
* Property Name: ATTENDEE
*
* Purpose: The property defines an "Attendee" within a calendar
* component.
*
* Value Type: CAL-ADDRESS
*
* Property Parameters: Non-standard, language, calendar user type,
* group or list membership, participation role, participation status,
* RSVP expectation, delegatee, delegator, sent by, common name or
* directory entry reference property parameters can be specified on
* this property.
*
* Conformance: This property MUST be specified in an iCalendar object
* that specifies a group scheduled calendar entity. This property MUST
* NOT be specified in an iCalendar object when publishing the calendar
* information (e.g., NOT in an iCalendar object that specifies the
* publication of a calendar user's busy time, event, to-do or journal).
* This property is not specified in an iCalendar object that specifies
* only a time zone definition or that defines calendar entities that
* are not group scheduled entities, but are entities only on a single
* user's calendar.
*
* Description: The property MUST only be specified within calendar
* components to specify participants, non-participants and the chair of
* a group scheduled calendar entity. The property is specified within
* an "EMAIL" category of the "VALARM" calendar component to specify an
* email address that is to receive the email type of iCalendar alarm.
*
* The property parameter CN is for the common or displayable name
* associated with the calendar address; ROLE, for the intended role
* that the attendee will have in the calendar component; PARTSTAT, for
* the status of the attendee's participation; RSVP, for indicating
* whether the favor of a reply is requested; CUTYPE, to indicate the
* type of calendar user; MEMBER, to indicate the groups that the
* attendee belongs to; DELEGATED-TO, to indicate the calendar users
* that the original request was delegated to; and DELEGATED-FROM, to
* indicate whom the request was delegated from; SENT-BY, to indicate
* whom is acting on behalf of the ATTENDEE; and DIR, to indicate the
* URI that points to the directory information corresponding to the
* attendee. These property parameters can be specified on an "ATTENDEE"
* property in either a "VEVENT", "VTODO" or "VJOURNAL" calendar
* component. They MUST not be specified in an "ATTENDEE" property in a
* "VFREEBUSY" or "VALARM" calendar component. If the LANGUAGE property
* parameter is specified, the identified language applies to the CN
* parameter.
*
* A recipient delegated a request MUST inherit the RSVP and ROLE values
* from the attendee that delegated the request to them.
*
* Multiple attendees can be specified by including multiple "ATTENDEE"
* properties within the calendar component.
*
* Format Definition: The property is defined by the following notation:
*
* attendee = "ATTENDEE" attparam ":" cal-address CRLF
*
* attparam = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" cutypeparam) / (";"memberparam) /
* (";" roleparam) / (";" partstatparam) /
* (";" rsvpparam) / (";" deltoparam) /
* (";" delfromparam) / (";" sentbyparam) /
* (";"cnparam) / (";" dirparam) /
* (";" languageparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* Example: The following are examples of this property's use for a to-
* do:
*
* ORGANIZER:MAILTO:jsmith@host1.com
* ATTENDEE;MEMBER="MAILTO:DEV-GROUP@host2.com":
* MAILTO:joecool@host2.com
* ATTENDEE;DELEGATED-FROM="MAILTO:immud@host3.com":
* MAILTO:ildoit@host1.com
*
* The following is an example of this property used for specifying
* multiple attendees to an event:
*
* ORGANIZER:MAILTO:jsmith@host1.com
* ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=TENTATIVE;CN=Henry Cabot
* :MAILTO:hcabot@host2.com
* ATTENDEE;ROLE=REQ-PARTICIPANT;DELEGATED-FROM="MAILTO:bob@host.com"
* ;PARTSTAT=ACCEPTED;CN=Jane Doe:MAILTO:jdoe@host1.com
*
* The following is an example of this property with a URI to the
* directory information associated with the attendee:
*
* ATTENDEE;CN=John Smith;DIR="ldap://host.com:6666/o=eDABC%
* 20Industries,c=3DUS??(cn=3DBJim%20Dolittle)":MAILTO:jimdo@
* host1.com
*
* The following is an example of this property with "delegatee" and
* "delegator" information for an event:
*
* ORGANIZER;CN=John Smith:MAILTO:jsmith@host.com
* ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=TENTATIVE;DELEGATED-FROM=
* "MAILTO:iamboss@host2.com";CN=Henry Cabot:MAILTO:hcabot@
* host2.com
* ATTENDEE;ROLE=NON-PARTICIPANT;PARTSTAT=DELEGATED;DELEGATED-TO=
* "MAILTO:hcabot@host2.com";CN=The Big Cheese:MAILTO:iamboss
* @host2.com
* ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Jane Doe
* :MAILTO:jdoe@host1.com
*
* Example: The following is an example of this property's use when
* another calendar user is acting on behalf of the "Attendee":
*
* ATTENDEE;SENT-BY=MAILTO:jan_doe@host1.com;CN=John Smith:MAILTO:
* jsmith@host1.com
*/
class qCal_Property_Attendee extends qCal_Property {
protected $type = 'CAL-ADDRESS';
// If I'm reading the RFC correctly above, this property can be specified
// on the following components, but I'm still a bit confused about it. I
// need to read up on it more to really understand
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL','VALARM');
protected $allowMultiple = true;
}
@@ -0,0 +1,48 @@
<?php
/**
* Calendar Scale Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: CALSCALE
*
* Purpose: This property defines the calendar scale used for the
* calendar information specified in the iCalendar object.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: Property can be specified in an iCalendar object. The
* default value is "GREGORIAN".
*
* Description: This memo is based on the Gregorian calendar scale. The
* Gregorian calendar scale is assumed if this property is not specified
* in the iCalendar object. It is expected that other calendar scales
* will be defined in other specifications or by future versions of this
* memo.
*
* Format Definition: The property is defined by the following notation:
*
* calscale = "CALSCALE" calparam ":" calvalue CRLF
*
* calparam = *(";" xparam)
*
* calvalue = "GREGORIAN" / iana-token
*
* Example: The following is an example of this property:
*
* CALSCALE:GREGORIAN
*/
class qCal_Property_Calscale extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VCALENDAR');
protected $default = "GREGORIAN";
}
@@ -0,0 +1,61 @@
<?php
/**
* Categories Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: CATEGORIES
*
* Purpose: This property defines the categories for a calendar
* component.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard and language property parameters
* can be specified on this property.
*
* Conformance: The property can be specified within "VEVENT", "VTODO"
* or "VJOURNAL" calendar components.
*
* Description: This property is used to specify categories or subtypes
* of the calendar component. The categories are useful in searching for
* a calendar component of a particular type and category. Within the
* "VEVENT", "VTODO" or "VJOURNAL" calendar components, more than one
* category can be specified as a list of categories separated by the
* COMMA character (US-ASCII decimal 44).
*
* Format Definition: The property is defined by the following notation:
*
* categories = "CATEGORIES" catparam ":" text *("," text)
* CRLF
*
* catparam = *(
*
* ; the following is optional,
* ; but MUST NOT occur more than once
*
* (";" languageparam ) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* Example: The following are examples of this property:
*
* CATEGORIES:APPOINTMENT,EDUCATION
*
* CATEGORIES:MEETING
*/
class qCal_Property_Categories extends qCal_Property_MultiValue {
protected $type = 'TEXT';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL');
}
@@ -0,0 +1,59 @@
<?php
/**
* Classification Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: CLASS
*
* Purpose: This property defines the access classification for a
* calendar component.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: The property can be specified once in a "VEVENT",
* "VTODO" or "VJOURNAL" calendar components.
*
* Description: An access classification is only one component of the
* general security system within a calendar application. It provides a
* method of capturing the scope of the access the calendar owner
* intends for information within an individual calendar entry. The
* access classification of an individual iCalendar component is useful
* when measured along with the other security components of a calendar
* system (e.g., calendar user authentication, authorization, access
* rights, access role, etc.). Hence, the semantics of the individual
* access classifications cannot be completely defined by this memo
* alone. Additionally, due to the "blind" nature of most exchange
* processes using this memo, these access classifications cannot serve
* as an enforcement statement for a system receiving an iCalendar
* object. Rather, they provide a method for capturing the intention of
* the calendar owner for the access to the calendar component.
*
* Format Definition: The property is defined by the following notation:
*
* class = "CLASS" classparam ":" classvalue CRLF
*
* classparam = *(";" xparam)
*
* classvalue = "PUBLIC" / "PRIVATE" / "CONFIDENTIAL" / iana-token
* / x-name
* ;Default is PUBLIC
*
* Example: The following is an example of this property:
*
* CLASS:PUBLIC
*/
class qCal_Property_Class extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VEVENT', 'VTODO','VJOURNAL');
protected $default = "PUBLIC";
}
@@ -0,0 +1,58 @@
<?php
/**
* Comment Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Purpose: This property specifies non-processing information intended
* to provide a comment to the calendar user.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard, alternate text representation and
* language property parameters can be specified on this property.
*
* Conformance: This property can be specified in "VEVENT", "VTODO",
* "VJOURNAL", "VTIMEZONE" or "VFREEBUSY" calendar components.
*
* Description: The property can be specified multiple times.
*
* Format Definition: The property is defined by the following notation:
*
* comment = "COMMENT" commparam ":" text CRLF
*
* commparam = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" altrepparam) / (";" languageparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* Example: The following is an example of this property:
*
* COMMENT:The meeting really needs to include both ourselves
* and the customer. We can't hold this meeting without them.
* As a matter of fact\, the venue for the meeting ought to be at
*
* their site. - - John
*
* The data type for this property is TEXT.
*/
class qCal_Property_Comment extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VEVENT', 'VTODO','VJOURNAL','VTIMEZONE','VFREEBUSY');
protected $allowMultiple = true;
}
@@ -0,0 +1,41 @@
<?php
/**
* Completed Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: COMPLETED
*
* Purpose: This property defines the date and time that a to-do was
* actually completed.
*
* Value Type: DATE-TIME
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: The property can be specified in a "VTODO" calendar
* component.
*
* Description: The date and time MUST be in a UTC format.
*
* Format Definition: The property is defined by the following notation:
*
* completed = "COMPLETED" compparam ":" date-time CRLF
*
* compparam = *(";" xparam)
*
* Example: The following is an example of this property:
*
* COMPLETED:19960401T235959Z
*/
class qCal_Property_Completed extends qCal_Property {
protected $type = 'DATE-TIME';
protected $allowedComponents = array('VTODO');
}
@@ -0,0 +1,80 @@
<?php
/**
* Contact Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: CONTACT
*
* Purpose: The property is used to represent contact information or
* alternately a reference to contact information associated with the
* calendar component.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard, alternate text representation and
* language property parameters can be specified on this property.
*
* Conformance: The property can be specified in a "VEVENT", "VTODO",
* "VJOURNAL" or "VFREEBUSY" calendar component.
*
* Description: The property value consists of textual contact
* information. An alternative representation for the property value can
* also be specified that refers to a URI pointing to an alternate form,
* such as a vCard [RFC 2426], for the contact information.
*
* Format Definition: The property is defined by the following notation:
*
* contact = "CONTACT" contparam ":" text CRLF
*
* contparam = *(
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" altrepparam) / (";" languageparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* Example: The following is an example of this property referencing
* textual contact information:
*
* CONTACT:Jim Dolittle\, ABC Industries\, +1-919-555-1234
*
* The following is an example of this property with an alternate
* representation of a LDAP URI to a directory entry containing the
* contact information:
*
* CONTACT;ALTREP="ldap://host.com:6666/o=3DABC%20Industries\,
* c=3DUS??(cn=3DBJim%20Dolittle)":Jim Dolittle\, ABC Industries\,
* +1-919-555-1234
*
* The following is an example of this property with an alternate
* representation of a MIME body part containing the contact
* information, such as a vCard [RFC 2426] embedded in a [MIME-DIR]
* content-type:
*
* CONTACT;ALTREP="CID=<part3.msg970930T083000SILVER@host.com>":Jim
* Dolittle\, ABC Industries\, +1-919-555-1234
*
* The following is an example of this property referencing a network
* resource, such as a vCard [RFC 2426] object containing the contact
* information:
*
* CONTACT;ALTREP="http://host.com/pdi/jdoe.vcf":Jim
* Dolittle\, ABC Industries\, +1-919-555-1234
*/
class qCal_Property_Contact extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL','VFREEBUSY');
}
@@ -0,0 +1,45 @@
<?php
/**
* Dated/Time Created Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: CREATED
*
* Purpose: This property specifies the date and time that the calendar
* information was created by the calendar user agent in the calendar
* store.
*
* Note: This is analogous to the creation date and time for a file
* in the file system.
*
* Value Type: DATE-TIME
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: The property can be specified once in "VEVENT", "VTODO"
* or "VJOURNAL" calendar components.
*
* Description: The date and time is a UTC value.
*
* Format Definition: The property is defined by the following notation:
*
* created = "CREATED" creaparam ":" date-time CRLF
*
* creaparam = *(";" xparam)
*
* Example: The following is an example of this property:
*
* CREATED:19960329T133000Z
*/
class qCal_Property_Created extends qCal_Property {
protected $type = 'DATE-TIME';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL');
}
@@ -0,0 +1,72 @@
<?php
/**
* Description Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: DESCRIPTION
*
* Purpose: This property provides a more complete description of the
* calendar component, than that provided by the "SUMMARY" property.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard, alternate text representation and
* language property parameters can be specified on this property.
*
* Conformance: The property can be specified in the "VEVENT", "VTODO",
* "VJOURNAL" or "VALARM" calendar components. The property can be
* specified multiple times only within a "VJOURNAL" calendar component.
*
* Description: This property is used in the "VEVENT" and "VTODO" to
* capture lengthy textual decriptions associated with the activity.
*
* This property is used in the "VJOURNAL" calendar component to capture
* one more textual journal entries.
*
* This property is used in the "VALARM" calendar component to capture
* the display text for a DISPLAY category of alarm, to capture the body
* text for an EMAIL category of alarm and to capture the argument
* string for a PROCEDURE category of alarm.
*
* Format Definition: The property is defined by the following notation:
*
* description = "DESCRIPTION" descparam ":" text CRLF
*
* descparam = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" altrepparam) / (";" languageparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* Example: The following is an example of the property with formatted
* line breaks in the property value:
*
* DESCRIPTION:Meeting to provide technical review for "Phoenix"
* design.\n Happy Face Conference Room. Phoenix design team
* MUST attend this meeting.\n RSVP to team leader.
*
* The following is an example of the property with folding of long
* lines:
*
* DESCRIPTION:Last draft of the new novel is to be completed
* for the editor's proof today.
*/
class qCal_Property_Description extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VEVENT', 'VTODO','VJOURNAL','VALARM');
}
@@ -0,0 +1,69 @@
<?php
/**
* Date/Time End Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Find a way of making sure that if there is a DTSTART, that its date
* is earlier than that of this property.
*
* RFC 2445 Definition
*
* Property Name: DTEND
*
* Purpose: This property specifies the date and time that a calendar
* component ends.
*
* Value Type: The default value type is DATE-TIME. The value type can
* be set to a DATE value type.
*
* Property Parameters: Non-standard, value data type, time zone
* identifier property parameters can be specified on this property.
*
* Conformance: This property can be specified in "VEVENT" or
* "VFREEBUSY" calendar components.
*
* Description: Within the "VEVENT" calendar component, this property
* defines the date and time by which the event ends. The value MUST be
* later in time than the value of the "DTSTART" property.
*
* Within the "VFREEBUSY" calendar component, this property defines the
* end date and time for the free or busy time information. The time
* MUST be specified in the UTC time format. The value MUST be later in
* time than the value of the "DTSTART" property.
*
* Format Definition: The property is defined by the following notation:
*
* dtend = "DTEND" dtendparam":" dtendval CRLF
*
* dtendparam = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" "VALUE" "=" ("DATE-TIME" / "DATE")) /
* (";" tzidparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* dtendval = date-time / date
* ;Value MUST match value type
*
* Example: The following is an example of this property:
*
* DTEND:19960401T235959Z
*
* DTEND;VALUE=DATE:19980704
*/
class qCal_Property_Dtend extends qCal_Property {
protected $type = 'DATE-TIME';
protected $allowedComponents = array('VEVENT','VFREEBUSY','DAYLIGHT','STANDARD');
}
@@ -0,0 +1,53 @@
<?php
/**
* Dated/Time Stamp Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure that this is specified in UTC format.
*
* RFC 2445 Definition
*
* Property Name: DTSTAMP
*
* Purpose: The property indicates the date/time that the instance of
* the iCalendar object was created.
*
* Value Type: DATE-TIME
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: This property MUST be included in the "VEVENT", "VTODO",
* "VJOURNAL" or "VFREEBUSY" calendar components.
*
* Description: The value MUST be specified in the UTC time format.
*
* This property is also useful to protocols such as [IMIP] that have
* inherent latency issues with the delivery of content. This property
* will assist in the proper sequencing of messages containing iCalendar
* objects.
*
* This property is different than the "CREATED" and "LAST-MODIFIED"
* properties. These two properties are used to specify when the
* particular calendar data in the calendar store was created and last
* modified. This is different than when the iCalendar object
* representation of the calendar service information was created or
* last modified.
* Format Definition: The property is defined by the following notation:
*
* dtstamp = "DTSTAMP" stmparam ":" date-time CRLF
*
* stmparam = *(";" xparam)
*
* Example:
*
* DTSTAMP:19971210T080000Z
*/
class qCal_Property_Dtstamp extends qCal_Property {
protected $type = 'DATE-TIME';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL','VFREEBUSY');
}
@@ -0,0 +1,80 @@
<?php
/**
* Date/Time Start Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure that if there is an DTEND property, its date is after
* this property's date.
*
* RFC 2445 Definition
*
* Property Name: DTSTART
*
* Purpose: This property specifies when the calendar component begins.
*
* Value Type: The default value type is DATE-TIME. The time value MUST
* be one of the forms defined for the DATE-TIME value type. The value
* type can be set to a DATE value type.
*
* Property Parameters: Non-standard, value data type, time zone
* identifier property parameters can be specified on this property.
*
* Conformance: This property can be specified in the "VEVENT", "VTODO",
* "VFREEBUSY", or "VTIMEZONE" calendar components.
*
* Description: Within the "VEVENT" calendar component, this property
* defines the start date and time for the event. The property is
* REQUIRED in "VEVENT" calendar components. Events can have a start
* date/time but no end date/time. In that case, the event does not take
* up any time.
*
* Within the "VFREEBUSY" calendar component, this property defines the
* start date and time for the free or busy time information. The time
* MUST be specified in UTC time.
*
* Within the "VTIMEZONE" calendar component, this property defines the
* effective start date and time for a time zone specification. This
* property is REQUIRED within each STANDARD and DAYLIGHT part included
* in "VTIMEZONE" calendar components and MUST be specified as a local
* DATE-TIME without the "TZID" property parameter.
*
* Format Definition: The property is defined by the following notation:
*
* dtstart = "DTSTART" dtstparam ":" dtstval CRLF
*
* dtstparam = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" "VALUE" "=" ("DATE-TIME" / "DATE")) /
* (";" tzidparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* *(";" xparam)
*
* )
*
* dtstval = date-time / date
* ;Value MUST match value type
*
* Example: The following is an example of this property:
*
* DTSTART:19980118T073000Z
*/
class qCal_Property_Dtstart extends qCal_Property {
protected $type = 'DATE-TIME';
protected $allowedComponents = array('VEVENT','VTODO','VFREEBUSY','VTIMEZONE','VJOURNAL','STANDARD','DAYLIGHT');
/**
* Strange that in the notes for this, it says:
* Conformance: This property can be specified in the "VEVENT", "VTODO",
* "VFREEBUSY", or "VTIMEZONE" calendar components.
* But in the notes for journal it says that dtstart is allowed in a journal
*/
}
@@ -0,0 +1,60 @@
<?php
/**
* Date/Time Due Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure that the date of this is equal to or after the DTSTART
* date, if specified.
*
* RFC 2445 Definition
*
* Property Name: DUE
*
* Purpose: This property defines the date and time that a to-do is
* expected to be completed.
*
* Value Type: The default value type is DATE-TIME. The value type can
* be set to a DATE value type.
*
* Property Parameters: Non-standard, value data type, time zone
* identifier property parameters can be specified on this property.
*
* Conformance: The property can be specified once in a "VTODO" calendar
* component.
*
* Description: The value MUST be a date/time equal to or after the
* DTSTART value, if specified.
*
* Format Definition: The property is defined by the following notation:
*
* due = "DUE" dueparam":" dueval CRLF
*
* dueparam = *(
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" "VALUE" "=" ("DATE-TIME" / "DATE")) /
* (";" tzidparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* *(";" xparam)
*
* )
*
* dueval = date-time / date
* ;Value MUST match value type
*
* Example: The following is an example of this property:
*
* DUE:19980430T235959Z
*/
class qCal_Property_Due extends qCal_Property {
protected $type = 'DATE-TIME';
protected $allowedComponents = array('VTODO');
}
@@ -0,0 +1,54 @@
<?php
/**
* Duration Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: DURATION
*
* Purpose: The property specifies a positive duration of time.
*
* Value Type: DURATION
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: The property can be specified in "VEVENT", "VTODO",
* "VFREEBUSY" or "VALARM" calendar components.
*
* Description: In a "VEVENT" calendar component the property may be
* used to specify a duration of the event, instead of an explicit end
* date/time. In a "VTODO" calendar component the property may be used
* to specify a duration for the to-do, instead of an explicit due
* date/time. In a "VFREEBUSY" calendar component the property may be
* used to specify the interval of free time being requested. In a
* "VALARM" calendar component the property may be used to specify the
* delay period prior to repeating an alarm.
*
* Format Definition: The property is defined by the following notation:
*
* duration = "DURATION" durparam ":" dur-value CRLF
* ;consisting of a positive duration of time.
*
* durparam = *(";" xparam)
*
* Example: The following is an example of this property that specifies
* an interval of time of 1 hour and zero minutes and zero seconds:
*
* DURATION:PT1H0M0S
*
* The following is an example of this property that specifies an
* interval of time of 15 minutes.
*
* DURATION:PT15M
*/
class qCal_Property_Duration extends qCal_Property {
protected $type = 'DURATION';
protected $allowedComponents = array('VEVENT','VTODO','VFREEBUSY','VALARM');
}
@@ -0,0 +1,85 @@
<?php
/**
* Exception Date/Times Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure allowedComponents is correct. The RFC isn't dead clear.
* Perhaps this means that it can be included in any component that
* includes an rdate or rrule property?
*
* RFC 2445 Definition
*
* Property Name: EXDATE
*
* Purpose: This property defines the list of date/time exceptions for a
* recurring calendar component.
*
* Value Type: The default value type for this property is DATE-TIME.
* The value type can be set to DATE.
*
* Property Parameters: Non-standard, value data type and time zone
* identifier property parameters can be specified on this property.
*
* Conformance: This property can be specified in an iCalendar object
* that includes a recurring calendar component.
*
* Description: The exception dates, if specified, are used in computing
* the recurrence set. The recurrence set is the complete set of
* recurrence instances for a calendar component. The recurrence set is
* generated by considering the initial "DTSTART" property along with
* the "RRULE", "RDATE", "EXDATE" and "EXRULE" properties contained
* within the iCalendar object. The "DTSTART" property defines the first
* instance in the recurrence set. Multiple instances of the "RRULE" and
* "EXRULE" properties can also be specified to define more
* sophisticated recurrence sets. The final recurrence set is generated
* by gathering all of the start date-times generated by any of the
* specified "RRULE" and "RDATE" properties, and then excluding any
* start date and times which fall within the union of start date and
* times generated by any specified "EXRULE" and "EXDATE" properties.
* This implies that start date and times within exclusion related
* properties (i.e., "EXDATE" and "EXRULE") take precedence over those
* specified by inclusion properties (i.e., "RDATE" and "RRULE"). Where
* duplicate instances are generated by the "RRULE" and "RDATE"
* properties, only one recurrence is considered. Duplicate instances
* are ignored.
*
* The "EXDATE" property can be used to exclude the value specified in
* "DTSTART". However, in such cases the original "DTSTART" date MUST
* still be maintained by the calendaring and scheduling system because
* the original "DTSTART" value has inherent usage dependencies by other
* properties such as the "RECURRENCE-ID".
*
* Format Definition: The property is defined by the following notation:
*
* exdate = "EXDATE" exdtparam ":" exdtval *("," exdtval) CRLF
*
* exdtparam = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" "VALUE" "=" ("DATE-TIME" / "DATE")) /
* (";" tzidparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* exdtval = date-time / date
* ;Value MUST match value type
*
* Example: The following is an example of this property:
*
* EXDATE:19960402T010000Z,19960403T010000Z,19960404T010000Z
*/
class qCal_Property_Exdate extends qCal_Property_MultiValue {
protected $type = 'DATE-TIME';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL','VTIMEZONE');
}
@@ -0,0 +1,78 @@
<?php
/**
* Exception Rule Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure allowedCompoents is correct. The RFC isn't dead clear
* See the todo for EXDATE
*
* RFC 2445 Definition
*
* Property Name: EXRULE
*
* Purpose: This property defines a rule or repeating pattern for an
* exception to a recurrence set.
*
* Value Type: RECUR
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: This property can be specified in "VEVENT", "VTODO" or
* "VJOURNAL" calendar components.
*
* Description: The exception rule, if specified, is used in computing
* the recurrence set. The recurrence set is the complete set of
* recurrence instances for a calendar component. The recurrence set is
* generated by considering the initial "DTSTART" property along with
* the "RRULE", "RDATE", "EXDATE" and "EXRULE" properties contained
* within the iCalendar object. The "DTSTART" defines the first instance
* in the recurrence set. Multiple instances of the "RRULE" and "EXRULE"
* properties can also be specified to define more sophisticated
* recurrence sets. The final recurrence set is generated by gathering
* all of the start date-times generated by any of the specified "RRULE"
* and "RDATE" properties, and excluding any start date and times which
* fall within the union of start date and times generated by any
* specified "EXRULE" and "EXDATE" properties. This implies that start
* date and times within exclusion related properties (i.e., "EXDATE"
* and "EXRULE") take precedence over those specified by inclusion
*
*
* properties (i.e., "RDATE" and "RRULE"). Where duplicate instances are
* generated by the "RRULE" and "RDATE" properties, only one recurrence
* is considered. Duplicate instances are ignored.
*
* The "EXRULE" property can be used to exclude the value specified in
* "DTSTART". However, in such cases the original "DTSTART" date MUST
* still be maintained by the calendaring and scheduling system because
* the original "DTSTART" value has inherent usage dependencies by other
* properties such as the "RECURRENCE-ID".
*
* Format Definition: The property is defined by the following notation:
*
* exrule = "EXRULE" exrparam ":" recur CRLF
*
* exrparam = *(";" xparam)
*
* Example: The following are examples of this property. Except every
* other week, on Tuesday and Thursday for 4 occurrences:
*
* EXRULE:FREQ=WEEKLY;COUNT=4;INTERVAL=2;BYDAY=TU,TH
*
* Except daily for 10 occurrences:
*
* EXRULE:FREQ=DAILY;COUNT=10
*
* Except yearly in June and July for 8 occurrences:
*
* EXRULE:FREQ=YEARLY;COUNT=8;BYMONTH=6,7
*/
class qCal_Property_Exrule extends qCal_Property {
protected $type = 'RECUR';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL');
protected $allowMultiple = true;
}
@@ -0,0 +1,78 @@
<?php
/**
* Free/Busy Time Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure that values in the property are sorted as described below
*
* RFC 2445 Definition
*
* Property Name: FREEBUSY
*
* Purpose: The property defines one or more free or busy time
* intervals.
*
* Value Type: PERIOD. The date and time values MUST be in an UTC time
* format.
*
* Property Parameters: Non-standard or free/busy time type property
* parameters can be specified on this property.
*
* Conformance: The property can be specified in a "VFREEBUSY" calendar
* component.
*
* Property Parameter: "FBTYPE" and non-standard parameters can be
* specified on this property.
*
* Description: These time periods can be specified as either a start
* and end date-time or a start date-time and duration. The date and
* time MUST be a UTC time format.
*
* "FREEBUSY" properties within the "VFREEBUSY" calendar component
* SHOULD be sorted in ascending order, based on start time and then end
* time, with the earliest periods first.
*
* The "FREEBUSY" property can specify more than one value, separated by
* the COMMA character (US-ASCII decimal 44). In such cases, the
* "FREEBUSY" property values SHOULD all be of the same "FBTYPE"
* property parameter type (e.g., all values of a particular "FBTYPE"
* listed together in a single property).
*
* Format Definition: The property is defined by the following notation:
*
* freebusy = "FREEBUSY" fbparam ":" fbvalue
* CRLF
*
* fbparam = *(
* ; the following is optional,
* ; but MUST NOT occur more than once
*
* (";" fbtypeparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* fbvalue = period *["," period]
* ;Time value MUST be in the UTC time format.
*
* Example: The following are some examples of this property:
*
* FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:19970308T160000Z/PT8H30M
*
* FREEBUSY;FBTYPE=FREE:19970308T160000Z/PT3H,19970308T200000Z/PT1H
*
* FREEBUSY;FBTYPE=FREE:19970308T160000Z/PT3H,19970308T200000Z/PT1H,
* 19970308T230000Z/19970309T000000Z
*/
class qCal_Property_Freebusy extends qCal_Property_MultiValue {
protected $type = 'PERIOD';
protected $allowedComponents = array('VFREEBUSY');
}
@@ -0,0 +1,93 @@
<?php
/**
* Geographic Position Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: GEO
*
* Purpose: This property specifies information related to the global
* position for the activity specified by a calendar component.
*
* Value Type: FLOAT. The value MUST be two SEMICOLON separated FLOAT
* values.
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: This property can be specified in "VEVENT" or "VTODO"
* calendar components.
*
* Description: The property value specifies latitude and longitude, in
* that order (i.e., "LAT LON" ordering). The longitude represents the
* location east or west of the prime meridian as a positive or negative
* real number, respectively. The longitude and latitude values MAY be
* specified up to six decimal places, which will allow for accuracy to
* within one meter of geographical position. Receiving applications
* MUST accept values of this precision and MAY truncate values of
* greater precision.
*
* Values for latitude and longitude shall be expressed as decimal
* fractions of degrees. Whole degrees of latitude shall be represented
* by a two-digit decimal number ranging from 0 through 90. Whole
* degrees of longitude shall be represented by a decimal number ranging
* from 0 through 180. When a decimal fraction of a degree is specified,
* it shall be separated from the whole number of degrees by a decimal
* point.
*
* Latitudes north of the equator shall be specified by a plus sign (+),
* or by the absence of a minus sign (-), preceding the digits
* designating degrees. Latitudes south of the Equator shall be
* designated by a minus sign (-) preceding the digits designating
* degrees. A point on the Equator shall be assigned to the Northern
* Hemisphere.
*
* Longitudes east of the prime meridian shall be specified by a plus
* sign (+), or by the absence of a minus sign (-), preceding the digits
* designating degrees. Longitudes west of the meridian shall be
* designated by minus sign (-) preceding the digits designating
* degrees. A point on the prime meridian shall be assigned to the
* Eastern Hemisphere. A point on the 180th meridian shall be assigned
* to the Western Hemisphere. One exception to this last convention is
* permitted. For the special condition of describing a band of latitude
* around the earth, the East Bounding Coordinate data element shall be
* assigned the value +180 (180) degrees.
*
* Any spatial address with a latitude of +90 (90) or -90 degrees will
* specify the position at the North or South Pole, respectively. The
* component for longitude may have any legal value.
*
* With the exception of the special condition described above, this
* form is specified in Department of Commerce, 1986, Representation of
* geographic point locations for information interchange (Federal
* Information Processing Standard 70-1): Washington, Department of
* Commerce, National Institute of Standards and Technology.
*
* The simple formula for converting degrees-minutes-seconds into
* decimal degrees is:
*
* decimal = degrees + minutes/60 + seconds/3600.
*
* Format Definition: The property is defined by the following notation:
*
* geo = "GEO" geoparam ":" geovalue CRLF
*
* geoparam = *(";" xparam)
*
* geovalue = float ";" float
* ;Latitude and Longitude components
*
* Example: The following is an example of this property:
*
* GEO:37.386013;-122.082932
*/
class qCal_Property_Geo extends qCal_Property {
protected $type = 'FLOAT';
protected $allowedComponents = array('VEVENT', 'VTODO');
}
@@ -0,0 +1,47 @@
<?php
/**
* Last Modified Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure that the date is converted to UTC
*
* RFC 2445 Definition
*
* Property Name: LAST-MODIFIED
*
* Purpose: The property specifies the date and time that the
* information associated with the calendar component was last revised
* in the calendar store.
*
* Note: This is analogous to the modification date and time for a
* file in the file system.
*
* Value Type: DATE-TIME
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: This property can be specified in the "EVENT", "VTODO",
* "VJOURNAL" or "VTIMEZONE" calendar components.
*
* Description: The property value MUST be specified in the UTC time
* format.
*
* Format Definition: The property is defined by the following notation:
*
* last-mod = "LAST-MODIFIED" lstparam ":" date-time CRLF
*
* lstparam = *(";" xparam)
*
* Example: The following is are examples of this property:
*
* LAST-MODIFIED:19960817T133000Z
*/
class qCal_Property_LastModified extends qCal_Property {
protected $type = 'DATE-TIME';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL','VTIMEZONE');
}
@@ -0,0 +1,62 @@
<?php
/**
* Location Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
* Property Name: LOCATION
*
* Purpose: The property defines the intended venue for the activity
* defined by a calendar component.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard, alternate text representation and
* language property parameters can be specified on this property.
*
* Conformance: This property can be specified in "VEVENT" or "VTODO"
* calendar component.
*
* Description: Specific venues such as conference or meeting rooms may
* be explicitly specified using this property. An alternate
* representation may be specified that is a URI that points to
* directory information with more structured specification of the
* location. For example, the alternate representation may specify
* either an LDAP URI pointing to an LDAP server entry or a CID URI
* pointing to a MIME body part containing a vCard [RFC 2426] for the
* location.
*
* Format Definition: The property is defined by the following notation:
*
* location = "LOCATION locparam ":" text CRLF
*
* locparam = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" altrepparam) / (";" languageparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* Example: The following are some examples of this property:
*
* LOCATION:Conference Room - F123, Bldg. 002
*
* LOCATION;ALTREP="http://xyzcorp.com/conf-rooms/f123.vcf":
* Conference Room - F123, Bldg. 002
*/
class qCal_Property_Location extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VEVENT', 'VTODO');
}
@@ -0,0 +1,58 @@
<?php
/**
* Method Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: METHOD
*
* Purpose: This property defines the iCalendar object method associated
* with the calendar object.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: The property can be specified in an iCalendar object.
*
* Description: When used in a MIME message entity, the value of this
* property MUST be the same as the Content-Type "method" parameter
* value. This property can only appear once within the iCalendar
* object. If either the "METHOD" property or the Content-Type "method"
* parameter is specified, then the other MUST also be specified.
*
* No methods are defined by this specification. This is the subject of
* other specifications, such as the iCalendar Transport-independent
*
* Interoperability Protocol (iTIP) defined by [ITIP].
*
* If this property is not present in the iCalendar object, then a
* scheduling transaction MUST NOT be assumed. In such cases, the
* iCalendar object is merely being used to transport a snapshot of some
* calendar information; without the intention of conveying a scheduling
* semantic.
*
* Format Definition: The property is defined by the following notation:
*
* method = "METHOD" metparam ":" metvalue CRLF
*
* metparam = *(";" xparam)
*
* metvalue = iana-token
*
* Example: The following is a hypothetical example of this property to
* convey that the iCalendar object is a request for a meeting:
*
* METHOD:REQUEST
*/
class qCal_Property_Method extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VCALENDAR');
}
@@ -0,0 +1,57 @@
<?php
/**
* Categories Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*/
class qCal_Property_MultiValue extends qCal_Property {
/**
* Property value
* @var qCal_Value object
*/
protected $value = array();
/**
* MultiValue properties contain an array of values rather than one, so we
* store them in an array and return them comma-separated.
*/
public function getValue() {
$return = array();
foreach ($this->value as $value) {
$return[] = $value->__toString();
}
return implode(chr(44), $return);
}
/**
* Sets the value of this property. Overwrites any previous values. Use addValue to
* add rather than overwrite.
* @todo I'm not sure I like how this is done. Eventually I will come back to it.
*/
public function setValue($value) {
if (!is_array($value)) {
$value = array($value);
}
// parent::setValue($value);
$this->value = array();
foreach ($value as $val) {
$this->value[] = $this->convertValue($val);
}
return $this;
}
/**
* Add a value to the array of values (rather than overwrite)
*/
public function addValue($value) {
$this->value[] = $this->convertValue($value);
return $this;
}
}
@@ -0,0 +1,70 @@
<?php
/**
* Non-standard Property(s)
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo I am not sure exactly how I plan on dealing with non-standard
* properties, but for now, I'm representing them with this class
* @todo Should this be a MultiValue?
* @todo Should this allow multiple instances?
*
* RFC 2445 Definition
*
* Property Name: Any property name with a "X-" prefix
*
* Purpose: This class of property provides a framework for defining
* non-standard properties.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard and language property parameters
* can be specified on this property.
*
* Conformance: This property can be specified in any calendar
* component.
*
* Description: The MIME Calendaring and Scheduling Content Type
* provides a "standard mechanism for doing non-standard things". This
* extension support is provided for implementers to "push the envelope"
* on the existing version of the memo. Extension properties are
* specified by property and/or property parameter names that have the
* prefix text of "X-" (the two character sequence: LATIN CAPITAL LETTER
* X character followed by the HYPEN-MINUS character). It is recommended
* that vendors concatenate onto this sentinel another short prefix text
* to identify the vendor. This will facilitate readability of the
* extensions and minimize possible collision of names between different
* vendors. User agents that support this content type are expected to
* be able to parse the extension properties and property parameters but
* can ignore them.
*
* At present, there is no registration authority for names of extension
* properties and property parameters. The data type for this property
* is TEXT. Optionally, the data type can be any of the other valid data
* types.
*
* Format Definition: The property is defined by the following notation:
*
* x-prop = x-name *(";" xparam) [";" languageparam] ":" text CRLF
* ; Lines longer than 75 octets should be folded
*
* Example: The following might be the ABC vendor's extension for an
* audio-clip form of subject property:
*
* X-ABC-MMSUBJ;X-ABC-MMSUBJTYPE=wave:http://load.noise.org/mysubj.wav
*/
class qCal_Property_NonStandard extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL',
'VALARM','VTIMEZONE','VFREEBUSY','VCALENDAR');
protected $allowMultiple = true;
public function __construct($value, $params, $name) {
parent::__construct($value, $params);
$this->name = strtoupper($name);
}
}
@@ -0,0 +1,89 @@
<?php
/**
* Organizer Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: ORGANIZER
*
* Purpose: The property defines the organizer for a calendar component.
*
* Value Type: CAL-ADDRESS
*
* Property Parameters: Non-standard, language, common name, directory
* entry reference, sent by property parameters can be specified on this
* property.
*
* Conformance: This property MUST be specified in an iCalendar object
* that specifies a group scheduled calendar entity. This property MUST
* be specified in an iCalendar object that specifies the publication of
* a calendar user's busy time. This property MUST NOT be specified in
* an iCalendar object that specifies only a time zone definition or
* that defines calendar entities that are not group scheduled entities,
* but are entities only on a single user's calendar.
*
* Description: The property is specified within the "VEVENT", "VTODO",
* "VJOURNAL calendar components to specify the organizer of a group
* scheduled calendar entity. The property is specified within the
* "VFREEBUSY" calendar component to specify the calendar user
* requesting the free or busy time. When publishing a "VFREEBUSY"
* calendar component, the property is used to specify the calendar that
* the published busy time came from.
*
* The property has the property parameters CN, for specifying the
* common or display name associated with the "Organizer", DIR, for
* specifying a pointer to the directory information associated with the
* "Organizer", SENT-BY, for specifying another calendar user that is
* acting on behalf of the "Organizer". The non-standard parameters may
* also be specified on this property. If the LANGUAGE property
* parameter is specified, the identified language applies to the CN
* parameter value.
*
* Format Definition: The property is defined by the following notation:
*
* organizer = "ORGANIZER" orgparam ":"
* cal-address CRLF
*
* orgparam = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" cnparam) / (";" dirparam) / (";" sentbyparam) /
* (";" languageparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* Example: The following is an example of this property:
*
* ORGANIZER;CN=John Smith:MAILTO:jsmith@host1.com
*
* The following is an example of this property with a pointer to the
* directory information associated with the organizer:
*
* ORGANIZER;CN=JohnSmith;DIR="ldap://host.com:6666/o=3DDC%20Associ
* ates,c=3DUS??(cn=3DJohn%20Smith)":MAILTO:jsmith@host1.com
*
* The following is an example of this property used by another calendar
* user who is acting on behalf of the organizer, with responses
* intended to be sent back to the organizer, not the other calendar
* user:
*
* ORGANIZER;SENT-BY="MAILTO:jane_doe@host.com":
* MAILTO:jsmith@host1.com
*/
class qCal_Property_Organizer extends qCal_Property {
protected $type = 'CAL-ADDRESS';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL');
}
@@ -0,0 +1,55 @@
<?php
/**
* Percent Complete Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Should this default to zero?
*
* RFC 2445 Definition
*
* Property Name: PERCENT-COMPLETE
*
* Purpose: This property is used by an assignee or delegatee of a to-do
* to convey the percent completion of a to-do to the Organizer.
*
* Value Type: INTEGER
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: This property can be specified in a "VTODO" calendar
* component.
*
* Description: The property value is a positive integer between zero
* and one hundred. A value of "0" indicates the to-do has not yet been
* started. A value of "100" indicates that the to-do has been
* completed. Integer values in between indicate the percent partially
* complete.
*
* When a to-do is assigned to multiple individuals, the property value
* indicates the percent complete for that portion of the to-do assigned
* to the assignee or delegatee. For example, if a to-do is assigned to
* both individuals "A" and "B". A reply from "A" with a percent
* complete of "70" indicates that "A" has completed 70% of the to-do
* assigned to them. A reply from "B" with a percent complete of "50"
* indicates "B" has completed 50% of the to-do assigned to them.
*
* Format Definition: The property is defined by the following notation:
*
* percent = "PERCENT-COMPLETE" pctparam ":" integer CRLF
*
* pctparam = *(";" xparam)
*
* Example: The following is an example of this property to show 39%
* completion:
*
* PERCENT-COMPLETE:39
*/
class qCal_Property_PercentComplete extends qCal_Property {
protected $type = 'INTEGER';
protected $allowedComponents = array('VTODO');
}
@@ -0,0 +1,87 @@
<?php
/**
* Priority Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: PRIORITY
*
* Purpose: The property defines the relative priority for a calendar
* component.
*
* Value Type: INTEGER
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: The property can be specified in a "VEVENT" or "VTODO"
* calendar component.
*
* Description: The priority is specified as an integer in the range
* zero to nine. A value of zero (US-ASCII decimal 48) specifies an
* undefined priority. A value of one (US-ASCII decimal 49) is the
* highest priority. A value of two (US-ASCII decimal 50) is the second
* highest priority. Subsequent numbers specify a decreasing ordinal
* priority. A value of nine (US-ASCII decimal 58) is the lowest
* priority.
*
* A CUA with a three-level priority scheme of "HIGH", "MEDIUM" and
* "LOW" is mapped into this property such that a property value in the
* range of one (US-ASCII decimal 49) to four (US-ASCII decimal 52)
* specifies "HIGH" priority. A value of five (US-ASCII decimal 53) is
* the normal or "MEDIUM" priority. A value in the range of six (US-
* ASCII decimal 54) to nine (US-ASCII decimal 58) is "LOW" priority.
*
* A CUA with a priority schema of "A1", "A2", "A3", "B1", "B2", ...,
* "C3" is mapped into this property such that a property value of one
* (US-ASCII decimal 49) specifies "A1", a property value of two (US-
* ASCII decimal 50) specifies "A2", a property value of three (US-ASCII
* decimal 51) specifies "A3", and so forth up to a property value of 9
* (US-ASCII decimal 58) specifies "C3".
*
* Other integer values are reserved for future use.
*
* Within a "VEVENT" calendar component, this property specifies a
* priority for the event. This property may be useful when more than
* one event is scheduled for a given time period.
*
* Within a "VTODO" calendar component, this property specified a
* priority for the to-do. This property is useful in prioritizing
* multiple action items for a given time period.
*
* Format Definition: The property is specified by the following
* notation:
*
* priority = "PRIORITY" prioparam ":" privalue CRLF
* ;Default is zero
*
* prioparam = *(";" xparam)
*
* privalue = integer ;Must be in the range [0..9]
* ; All other values are reserved for future use
*
* The following is an example of a property with the highest priority:
*
* PRIORITY:1
*
* The following is an example of a property with a next highest
* priority:
*
* PRIORITY:2
*
* Example: The following is an example of a property with no priority.
* This is equivalent to not specifying the "PRIORITY" property:
*
* PRIORITY:0
*/
class qCal_Property_Priority extends qCal_Property {
protected $type = 'INTEGER';
protected $allowedComponents = array('VEVENT','VTODO');
protected $default = 0;
}
@@ -0,0 +1,57 @@
<?php
/**
* Product Identifier Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Find a way to make sure that this is a globally unique id
* @todo I don't want my name in the default for this. Actually, I'm not even
* sure I want this property to have a default.
*
* RFC 2445 Definition
*
* Property Name: PRODID
*
* Purpose: This property specifies the identifier for the product that
* created the iCalendar object.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: The property MUST be specified once in an iCalendar
* object.
*
* Description: The vendor of the implementation SHOULD assure that this
* is a globally unique identifier; using some technique such as an FPI
* value, as defined in [ISO 9070].
*
* This property SHOULD not be used to alter the interpretation of an
* iCalendar object beyond the semantics specified in this memo. For
* example, it is not to be used to further the understanding of non-
* standard properties.
*
* Format Definition: The property is defined by the following notation:
*
* prodid = "PRODID" pidparam ":" pidvalue CRLF
*
* pidparam = *(";" xparam)
*
* pidvalue = text
* ;Any text that describes the product and version
* ;and that is generally assured of being unique.
*
* Example: The following is an example of this property. It does not
* imply that English is the default language.
*
* PRODID:-//ABC Corporation//NONSGML My Product//EN
*/
class qCal_Property_Prodid extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VCALENDAR');
protected $default = "-//Luke Visinoni//qCal v0.1//EN";
}
@@ -0,0 +1,89 @@
<?php
/**
* Recurrence Date/Times Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure allowedCompoents is correct. The RFC isn't dead clear
*
* RFC 2445 Definition
*
* Property Name: RDATE
*
* Purpose: This property defines the list of date/times for a
* recurrence set.
*
* Value Type: The default value type for this property is DATE-TIME.
* The value type can be set to DATE or PERIOD.
*
* Property Parameters: Non-standard, value data type and time zone
* identifier property parameters can be specified on this property.
*
* Conformance: The property can be specified in "VEVENT", "VTODO",
* "VJOURNAL" or "VTIMEZONE" calendar components.
*
* Description: This property can appear along with the "RRULE" property
* to define an aggregate set of repeating occurrences. When they both
* appear in an iCalendar object, the recurring events are defined by
* the union of occurrences defined by both the "RDATE" and "RRULE".
*
* The recurrence dates, if specified, are used in computing the
* recurrence set. The recurrence set is the complete set of recurrence
* instances for a calendar component. The recurrence set is generated
* by considering the initial "DTSTART" property along with the "RRULE",
* "RDATE", "EXDATE" and "EXRULE" properties contained within the
* iCalendar object. The "DTSTART" property defines the first instance
* in the recurrence set. Multiple instances of the "RRULE" and "EXRULE"
* properties can also be specified to define more sophisticated
* recurrence sets. The final recurrence set is generated by gathering
* all of the start date/times generated by any of the specified "RRULE"
* and "RDATE" properties, and excluding any start date/times which fall
* within the union of start date/times generated by any specified
* "EXRULE" and "EXDATE" properties. This implies that start date/times
* within exclusion related properties (i.e., "EXDATE" and "EXRULE")
* take precedence over those specified by inclusion properties (i.e.,
* "RDATE" and "RRULE"). Where duplicate instances are generated by the
* "RRULE" and "RDATE" properties, only one recurrence is considered.
* Duplicate instances are ignored.
*
* Format Definition: The property is defined by the following notation:
*
* rdate = "RDATE" rdtparam ":" rdtval *("," rdtval) CRLF
*
* rdtparam = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" "VALUE" "=" ("DATE-TIME" / "DATE" / "PERIOD")) /
* (";" tzidparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* rdtval = date-time / date / period
* ;Value MUST match value type
*
* Example: The following are examples of this property:
*
* RDATE:19970714T123000Z
*
* RDATE;TZID=US-EASTERN:19970714T083000
*
* RDATE;VALUE=PERIOD:19960403T020000Z/19960403T040000Z,
* 19960404T010000Z/PT3H
*
* RDATE;VALUE=DATE:19970101,19970120,19970217,19970421
* 19970526,19970704,19970901,19971014,19971128,19971129,19971225
*/
class qCal_Property_Rdate extends qCal_Property_MultiValue {
protected $type = 'DATE-TIME';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL','VTIMEZONE');
}
@@ -0,0 +1,96 @@
<?php
/**
* Recurrence Id Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo This has some pretty specific rules as to how it is to be used.
* Make sure that all of them are considered.
*
* RFC 2445 Definition
*
* Property Name: RECURRENCE-ID
*
* Purpose: This property is used in conjunction with the "UID" and
* "SEQUENCE" property to identify a specific instance of a recurring
* "VEVENT", "VTODO" or "VJOURNAL" calendar component. The property
* value is the effective value of the "DTSTART" property of the
* recurrence instance.
*
* Value Type: The default value type for this property is DATE-TIME.
* The time format can be any of the valid forms defined for a DATE-TIME
* value type. See DATE-TIME value type definition for specific
* interpretations of the various forms. The value type can be set to
* DATE.
*
* Property Parameters: Non-standard property, value data type, time
* zone identifier and recurrence identifier range parameters can be
* specified on this property.
*
* Conformance: This property can be specified in an iCalendar object
* containing a recurring calendar component.
*
* Description: The full range of calendar components specified by a
* recurrence set is referenced by referring to just the "UID" property
* value corresponding to the calendar component. The "RECURRENCE-ID"
* property allows the reference to an individual instance within the
* recurrence set.
*
* If the value of the "DTSTART" property is a DATE type value, then the
* value MUST be the calendar date for the recurrence instance.
*
* The date/time value is set to the time when the original recurrence
* instance would occur; meaning that if the intent is to change a
* Friday meeting to Thursday, the date/time is still set to the
* original Friday meeting.
*
* The "RECURRENCE-ID" property is used in conjunction with the "UID"
* and "SEQUENCE" property to identify a particular instance of a
* recurring event, to-do or journal. For a given pair of "UID" and
* "SEQUENCE" property values, the "RECURRENCE-ID" value for a
* recurrence instance is fixed. When the definition of the recurrence
* set for a calendar component changes, and hence the "SEQUENCE"
* property value changes, the "RECURRENCE-ID" for a given recurrence
* instance might also change.The "RANGE" parameter is used to specify
* the effective range of recurrence instances from the instance
* specified by the "RECURRENCE-ID" property value. The default value
* for the range parameter is the single recurrence instance only. The
* value can also be "THISANDPRIOR" to indicate a range defined by the
* given recurrence instance and all prior instances or the value can be
* "THISANDFUTURE" to indicate a range defined by the given recurrence
* instance and all subsequent instances.
*
* Format Definition: The property is defined by the following notation:
*
* recurid = "RECURRENCE-ID" ridparam ":" ridval CRLF
*
* ridparam = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" "VALUE" "=" ("DATE-TIME" / "DATE)) /
* (";" tzidparam) / (";" rangeparam) /
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* ridval = date-time / date
* ;Value MUST match value type
*
* Example: The following are examples of this property:
*
* RECURRENCE-ID;VALUE=DATE:19960401
*
* RECURRENCE-ID;RANGE=THISANDFUTURE:19960120T120000Z
*/
class qCal_Property_RecurrenceId extends qCal_Property {
protected $type = 'DATE-TIME';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL');
}
@@ -0,0 +1,82 @@
<?php
/**
* Related To Id Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: RELATED-TO
*
* Purpose: The property is used to represent a relationship or
* reference between one calendar component and another.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard and relationship type property
* parameters can be specified on this property.
*
* Conformance: The property can be specified one or more times in the
* "VEVENT", "VTODO" or "VJOURNAL" calendar components.
*
* Description: The property value consists of the persistent, globally
* unique identifier of another calendar component. This value would be
* represented in a calendar component by the "UID" property.
*
* By default, the property value points to another calendar component
* that has a PARENT relationship to the referencing object. The
* "RELTYPE" property parameter is used to either explicitly state the
* default PARENT relationship type to the referenced calendar component
* or to override the default PARENT relationship type and specify
* either a CHILD or SIBLING relationship. The PARENT relationship
* indicates that the calendar component is a subordinate of the
* referenced calendar component. The CHILD relationship indicates that
* the calendar component is a superior of the referenced calendar
* component. The SIBLING relationship indicates that the calendar
* component is a peer of the referenced calendar component.
*
*
* Changes to a calendar component referenced by this property can have
* an implicit impact on the related calendar component. For example, if
* a group event changes its start or end date or time, then the
* related, dependent events will need to have their start and end dates
* changed in a corresponding way. Similarly, if a PARENT calendar
* component is canceled or deleted, then there is an implied impact to
* the related CHILD calendar components. This property is intended only
* to provide information on the relationship of calendar components. It
* is up to the target calendar system to maintain any property
* implications of this relationship.
*
* Format Definition: The property is defined by the following notation:
*
* related = "RELATED-TO" [relparam] ":" text CRLF
*
* relparam = *(
*
* ; the following is optional,
* ; but MUST NOT occur more than once
*
* (";" reltypeparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparm)
*
* )
*
* The following is an example of this property:
*
* RELATED-TO:<jsmith.part7.19960817T083000.xyzMail@host3.com>
*
* RELATED-TO:<19960401-080045-4000F192713-0052@host1.com>
*/
class qCal_Property_RecurrenceId extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL');
protected $allowMultiple = true;
}
@@ -0,0 +1,47 @@
<?php
/**
* Repeat Count Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure that if the alarm triggers more than once, that this
* specifies a duration property.
*
* RFC 2445 Definition
*
* Property Name: REPEAT
*
* Purpose: This property defines the number of time the alarm should be
* repeated, after the initial trigger.
* Value Type: INTEGER
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: This property can be specified in a "VALARM" calendar
* component.
*
* Description: If the alarm triggers more than once, then this property
* MUST be specified along with the "DURATION" property.
*
* Format Definition: The property is defined by the following notation:
*
* repeatcnt = "REPEAT" repparam ":" integer CRLF
* ;Default is "0", zero.
*
* repparam = *(";" xparam)
*
* Example: The following is an example of this property for an alarm
* that repeats 4 additional times with a 5 minute delay after the
* initial triggering of the alarm:
*
* REPEAT:4
* DURATION:PT5M
*/
class qCal_Property_Repeat extends qCal_Property {
protected $type = 'INTEGER';
protected $allowedComponents = array('VALARM');
}
@@ -0,0 +1,124 @@
<?php
/**
* Request Status Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo This allows some strange stuff in its value. Make sure that it won't
* break the parser.
* @todo This allows the specification of "components" within the text. I will
* need to figure out how to deal with these.
*
* RFC 2445 Definition
*
* Property Name: REQUEST-STATUS
*
* Purpose: This property defines the status code returned for a
* scheduling request.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard and language property parameters
* can be specified on this property.
*
* Conformance: The property can be specified in "VEVENT", "VTODO",
* "VJOURNAL" or "VFREEBUSY" calendar component.
*
* Description: This property is used to return status code information
* related to the processing of an associated iCalendar object. The data
* type for this property is TEXT.
*
* The value consists of a short return status component, a longer
* return status description component, and optionally a status-specific
* data component. The components of the value are separated by the
* SEMICOLON character (US-ASCII decimal 59).
* The short return status is a PERIOD character (US-ASCII decimal 46)
* separated 3-tuple of integers. For example, "3.1.1". The successive
* levels of integers provide for a successive level of status code
* granularity.
*
* The following are initial classes for the return status code.
* Individual iCalendar object methods will define specific return
* status codes for these classes. In addition, other classes for the
* return status code may be defined using the registration process
* defined later in this memo.
*
* |==============+===============================================|
* | Short Return | Longer Return Status Description |
* | Status Code | |
* |==============+===============================================|
* | 1.xx | Preliminary success. This class of status |
* | | of status code indicates that the request has |
* | | request has been initially processed but that |
* | | completion is pending. |
* |==============+===============================================|
* | 2.xx | Successful. This class of status code |
* | | indicates that the request was completed |
* | | successfuly. However, the exact status code |
* | | can indicate that a fallback has been taken. |
* |==============+===============================================|
* | 3.xx | Client Error. This class of status code |
* | | indicates that the request was not successful.|
* | | The error is the result of either a syntax or |
* | | a semantic error in the client formatted |
* | | request. Request should not be retried until |
* | | the condition in the request is corrected. |
* |==============+===============================================|
* | 4.xx | Scheduling Error. This class of status code |
* | | indicates that the request was not successful.|
* | | Some sort of error occurred within the |
* | | calendaring and scheduling service, not |
* | | directly related to the request itself. |
* |==============+===============================================|
*
* Format Definition: The property is defined by the following notation:
*
* rstatus = "REQUEST-STATUS" rstatparam ":"
* statcode ";" statdesc [";" extdata]
*
* rstatparam = *(
*
* ; the following is optional,
* ; but MUST NOT occur more than once
* (";" languageparm) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* statcode = 1*DIGIT *("." 1*DIGIT)
* ;Hierarchical, numeric return status code
*
* statdesc = text
* ;Textual status description
*
* extdata = text
* ;Textual exception data. For example, the offending property
* ;name and value or complete property line.
*
* Example: The following are some possible examples of this property.
* The COMMA and SEMICOLON separator characters in the property value
* are BACKSLASH character escaped because they appear in a text value.
*
* REQUEST-STATUS:2.0;Success
*
* REQUEST-STATUS:3.1;Invalid property value;DTSTART:96-Apr-01
*
* REQUEST-STATUS:2.8; Success\, repeating event ignored. Scheduled
* as a single event.;RRULE:FREQ=WEEKLY\;INTERVAL=2
*
* REQUEST-STATUS:4.1;Event conflict. Date/time is busy.
*
* REQUEST-STATUS:3.7;Invalid calendar user;ATTENDEE:
* MAILTO:jsmith@host.com
*/
class qCal_Property_Sequence extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL','VFREEBUSY');
}
@@ -0,0 +1,59 @@
<?php
/**
* Resources Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: RESOURCES
*
* Purpose: This property defines the equipment or resources anticipated
* for an activity specified by a calendar entity..
*
* Value Type: TEXT
*
* Property Parameters: Non-standard, alternate text representation and
* language property parameters can be specified on this property.
*
* Conformance: This property can be specified in "VEVENT" or "VTODO"
* calendar component.
*
* Description: The property value is an arbitrary text. More than one
* resource can be specified as a list of resources separated by the
* COMMA character (US-ASCII decimal 44).
*
* Format Definition: The property is defined by the following notation:
*
* resources = "RESOURCES" resrcparam ":" text *("," text) CRLF
*
* resrcparam = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" altrepparam) / (";" languageparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
*
*
* (";" xparam)
*
* )
*
* Example: The following is an example of this property:
*
* RESOURCES:EASEL,PROJECTOR,VCR
*
* RESOURCES;LANGUAGE=fr:1 raton-laveur
*/
class qCal_Property_Resources extends qCal_Property_MultiValue {
protected $type = 'TEXT';
protected $allowedComponents = array('VEVENT','VTODO');
}
@@ -0,0 +1,442 @@
<?php
/**
* Recurrence Rule Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure allowedCompoents is correct. The RFC isn't dead clear
* @todo There are a lot of rules for this guy. Make sure you take them all
* into consideration and conform to the shit below.
* @todo This property doesn't require a value. Make sure it is possible to
* render the property without the colon that comes between name, params and value
*
* RFC 2445 Definition
*
* Property Name: RRULE
*
* Purpose: This property defines a rule or repeating pattern for
* recurring events, to-dos, or time zone definitions.
*
* Value Type: RECUR
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: This property can be specified one or more times in
* recurring "VEVENT", "VTODO" and "VJOURNAL" calendar components. It
* can also be specified once in each STANDARD or DAYLIGHT sub-component
* of the "VTIMEZONE" calendar component.
*
* Description: The recurrence rule, if specified, is used in computing
* the recurrence set. The recurrence set is the complete set of
* recurrence instances for a calendar component. The recurrence set is
* generated by considering the initial "DTSTART" property along with
* the "RRULE", "RDATE", "EXDATE" and "EXRULE" properties contained
* within the iCalendar object. The "DTSTART" property defines the first
* instance in the recurrence set. Multiple instances of the "RRULE" and
* "EXRULE" properties can also be specified to define more
* sophisticated recurrence sets. The final recurrence set is generated
* by gathering all of the start date/times generated by any of the
* specified "RRULE" and "RDATE" properties, and excluding any start
* date/times which fall within the union of start date/times generated
* by any specified "EXRULE" and "EXDATE" properties. This implies that
* start date/times within exclusion related properties (i.e., "EXDATE"
* and "EXRULE") take precedence over those specified by inclusion
* properties (i.e., "RDATE" and "RRULE"). Where duplicate instances are
* generated by the "RRULE" and "RDATE" properties, only one recurrence
* is considered. Duplicate instances are ignored.
*
*
*
* The "DTSTART" and "DTEND" property pair or "DTSTART" and "DURATION"
* property pair, specified within the iCalendar object defines the
* first instance of the recurrence. When used with a recurrence rule,
* the "DTSTART" and "DTEND" properties MUST be specified in local time
* and the appropriate set of "VTIMEZONE" calendar components MUST be
* included. For detail on the usage of the "VTIMEZONE" calendar
* component, see the "VTIMEZONE" calendar component definition.
*
* Any duration associated with the iCalendar object applies to all
* members of the generated recurrence set. Any modified duration for
* specific recurrences MUST be explicitly specified using the "RDATE"
* property.
*
* Format Definition: This property is defined by the following
* notation:
*
* rrule = "RRULE" rrulparam ":" recur CRLF
*
* rrulparam = *(";" xparam)
*
* Example: All examples assume the Eastern United States time zone.
*
* Daily for 10 occurrences:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=DAILY;COUNT=10
*
* ==> (1997 9:00 AM EDT)September 2-11
*
* Daily until December 24, 1997:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=DAILY;UNTIL=19971224T000000Z
*
* ==> (1997 9:00 AM EDT)September 2-30;October 1-25
* (1997 9:00 AM EST)October 26-31;November 1-30;December 1-23
*
* Every other day - forever:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=DAILY;INTERVAL=2
* ==> (1997 9:00 AM EDT)September2,4,6,8...24,26,28,30;
* October 2,4,6...20,22,24
* (1997 9:00 AM EST)October 26,28,30;November 1,3,5,7...25,27,29;
* Dec 1,3,...
*
* Every 10 days, 5 occurrences:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5
*
* ==> (1997 9:00 AM EDT)September 2,12,22;October 2,12
*
* Everyday in January, for 3 years:
*
* DTSTART;TZID=US-Eastern:19980101T090000
* RRULE:FREQ=YEARLY;UNTIL=20000131T090000Z;
* BYMONTH=1;BYDAY=SU,MO,TU,WE,TH,FR,SA
* or
* RRULE:FREQ=DAILY;UNTIL=20000131T090000Z;BYMONTH=1
*
* ==> (1998 9:00 AM EDT)January 1-31
* (1999 9:00 AM EDT)January 1-31
* (2000 9:00 AM EDT)January 1-31
*
* Weekly for 10 occurrences
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=WEEKLY;COUNT=10
*
* ==> (1997 9:00 AM EDT)September 2,9,16,23,30;October 7,14,21
* (1997 9:00 AM EST)October 28;November 4
*
* Weekly until December 24, 1997
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=WEEKLY;UNTIL=19971224T000000Z
*
* ==> (1997 9:00 AM EDT)September 2,9,16,23,30;October 7,14,21
* (1997 9:00 AM EST)October 28;November 4,11,18,25;
* December 2,9,16,23
* Every other week - forever:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=SU
*
* ==> (1997 9:00 AM EDT)September 2,16,30;October 14
* (1997 9:00 AM EST)October 28;November 11,25;December 9,23
* (1998 9:00 AM EST)January 6,20;February
* ...
*
* Weekly on Tuesday and Thursday for 5 weeks:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=WEEKLY;UNTIL=19971007T000000Z;WKST=SU;BYDAY=TU,TH
* or
* RRULE:FREQ=WEEKLY;COUNT=10;WKST=SU;BYDAY=TU,TH
*
* ==> (1997 9:00 AM EDT)September 2,4,9,11,16,18,23,25,30;October 2
*
* Every other week on Monday, Wednesday and Friday until December 24,
* 1997, but starting on Tuesday, September 2, 1997:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;
* BYDAY=MO,WE,FR
* ==> (1997 9:00 AM EDT)September 2,3,5,15,17,19,29;October
* 1,3,13,15,17
* (1997 9:00 AM EST)October 27,29,31;November 10,12,14,24,26,28;
* December 8,10,12,22
*
* Every other week on Tuesday and Thursday, for 8 occurrences:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=8;WKST=SU;BYDAY=TU,TH
*
* ==> (1997 9:00 AM EDT)September 2,4,16,18,30;October 2,14,16
*
* Monthly on the 1st Friday for ten occurrences:
*
* DTSTART;TZID=US-Eastern:19970905T090000
* RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR
*
* ==> (1997 9:00 AM EDT)September 5;October 3
* (1997 9:00 AM EST)November 7;Dec 5
* (1998 9:00 AM EST)January 2;February 6;March 6;April 3
* (1998 9:00 AM EDT)May 1;June 5
*
* Monthly on the 1st Friday until December 24, 1997:
*
* DTSTART;TZID=US-Eastern:19970905T090000
* RRULE:FREQ=MONTHLY;UNTIL=19971224T000000Z;BYDAY=1FR
*
* ==> (1997 9:00 AM EDT)September 5;October 3
* (1997 9:00 AM EST)November 7;December 5
*
* Every other month on the 1st and last Sunday of the month for 10
* occurrences:
*
* DTSTART;TZID=US-Eastern:19970907T090000
* RRULE:FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU
*
* ==> (1997 9:00 AM EDT)September 7,28
* (1997 9:00 AM EST)November 2,30
* (1998 9:00 AM EST)January 4,25;March 1,29
* (1998 9:00 AM EDT)May 3,31
*
* Monthly on the second to last Monday of the month for 6 months:
*
* DTSTART;TZID=US-Eastern:19970922T090000
* RRULE:FREQ=MONTHLY;COUNT=6;BYDAY=-2MO
*
* ==> (1997 9:00 AM EDT)September 22;October 20
* (1997 9:00 AM EST)November 17;December 22
* (1998 9:00 AM EST)January 19;February 16
*
* Monthly on the third to the last day of the month, forever:
*
* DTSTART;TZID=US-Eastern:19970928T090000
* RRULE:FREQ=MONTHLY;BYMONTHDAY=-3
*
* ==> (1997 9:00 AM EDT)September 28
* (1997 9:00 AM EST)October 29;November 28;December 29
* (1998 9:00 AM EST)January 29;February 26
* ...
*
* Monthly on the 2nd and 15th of the month for 10 occurrences:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=2,15
*
* ==> (1997 9:00 AM EDT)September 2,15;October 2,15
* (1997 9:00 AM EST)November 2,15;December 2,15
* (1998 9:00 AM EST)January 2,15
*
* Monthly on the first and last day of the month for 10 occurrences:
*
* DTSTART;TZID=US-Eastern:19970930T090000
* RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1
*
* ==> (1997 9:00 AM EDT)September 30;October 1
* (1997 9:00 AM EST)October 31;November 1,30;December 1,31
* (1998 9:00 AM EST)January 1,31;February 1
*
* Every 18 months on the 10th thru 15th of the month for 10
* occurrences:
*
* DTSTART;TZID=US-Eastern:19970910T090000
* RRULE:FREQ=MONTHLY;INTERVAL=18;COUNT=10;BYMONTHDAY=10,11,12,13,14,
* 15
*
* ==> (1997 9:00 AM EDT)September 10,11,12,13,14,15
* (1999 9:00 AM EST)March 10,11,12,13
*
* Every Tuesday, every other month:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=MONTHLY;INTERVAL=2;BYDAY=TU
*
* ==> (1997 9:00 AM EDT)September 2,9,16,23,30
* (1997 9:00 AM EST)November 4,11,18,25
* (1998 9:00 AM EST)January 6,13,20,27;March 3,10,17,24,31
* ...
*
* Yearly in June and July for 10 occurrences:
*
* DTSTART;TZID=US-Eastern:19970610T090000
* RRULE:FREQ=YEARLY;COUNT=10;BYMONTH=6,7
* ==> (1997 9:00 AM EDT)June 10;July 10
* (1998 9:00 AM EDT)June 10;July 10
* (1999 9:00 AM EDT)June 10;July 10
* (2000 9:00 AM EDT)June 10;July 10
* (2001 9:00 AM EDT)June 10;July 10
* Note: Since none of the BYDAY, BYMONTHDAY or BYYEARDAY components
* are specified, the day is gotten from DTSTART
*
* Every other year on January, February, and March for 10 occurrences:
*
* DTSTART;TZID=US-Eastern:19970310T090000
* RRULE:FREQ=YEARLY;INTERVAL=2;COUNT=10;BYMONTH=1,2,3
*
* ==> (1997 9:00 AM EST)March 10
* (1999 9:00 AM EST)January 10;February 10;March 10
* (2001 9:00 AM EST)January 10;February 10;March 10
* (2003 9:00 AM EST)January 10;February 10;March 10
*
* Every 3rd year on the 1st, 100th and 200th day for 10 occurrences:
*
* DTSTART;TZID=US-Eastern:19970101T090000
* RRULE:FREQ=YEARLY;INTERVAL=3;COUNT=10;BYYEARDAY=1,100,200
*
* ==> (1997 9:00 AM EST)January 1
* (1997 9:00 AM EDT)April 10;July 19
* (2000 9:00 AM EST)January 1
* (2000 9:00 AM EDT)April 9;July 18
* (2003 9:00 AM EST)January 1
* (2003 9:00 AM EDT)April 10;July 19
* (2006 9:00 AM EST)January 1
*
* Every 20th Monday of the year, forever:
* DTSTART;TZID=US-Eastern:19970519T090000
* RRULE:FREQ=YEARLY;BYDAY=20MO
*
* ==> (1997 9:00 AM EDT)May 19
* (1998 9:00 AM EDT)May 18
* (1999 9:00 AM EDT)May 17
* ...
*
* Monday of week number 20 (where the default start of the week is
* Monday), forever:
*
* DTSTART;TZID=US-Eastern:19970512T090000
* RRULE:FREQ=YEARLY;BYWEEKNO=20;BYDAY=MO
*
* ==> (1997 9:00 AM EDT)May 12
* (1998 9:00 AM EDT)May 11
* (1999 9:00 AM EDT)May 17
* ...
*
* Every Thursday in March, forever:
*
* DTSTART;TZID=US-Eastern:19970313T090000
* RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=TH
*
* ==> (1997 9:00 AM EST)March 13,20,27
* (1998 9:00 AM EST)March 5,12,19,26
* (1999 9:00 AM EST)March 4,11,18,25
* ...
*
* Every Thursday, but only during June, July, and August, forever:
*
* DTSTART;TZID=US-Eastern:19970605T090000
* RRULE:FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8
*
* ==> (1997 9:00 AM EDT)June 5,12,19,26;July 3,10,17,24,31;
* August 7,14,21,28
* (1998 9:00 AM EDT)June 4,11,18,25;July 2,9,16,23,30;
* August 6,13,20,27
* (1999 9:00 AM EDT)June 3,10,17,24;July 1,8,15,22,29;
* August 5,12,19,26
* ...
*
* Every Friday the 13th, forever:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* EXDATE;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13
*
* ==> (1998 9:00 AM EST)February 13;March 13;November 13
* (1999 9:00 AM EDT)August 13
* (2000 9:00 AM EDT)October 13
* ...
*
* The first Saturday that follows the first Sunday of the month,
* forever:
*
* DTSTART;TZID=US-Eastern:19970913T090000
* RRULE:FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13
*
* ==> (1997 9:00 AM EDT)September 13;October 11
* (1997 9:00 AM EST)November 8;December 13
* (1998 9:00 AM EST)January 10;February 7;March 7
* (1998 9:00 AM EDT)April 11;May 9;June 13...
* ...
*
* Every four years, the first Tuesday after a Monday in November,
* forever (U.S. Presidential Election day):
*
* DTSTART;TZID=US-Eastern:19961105T090000
* RRULE:FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,
* 5,6,7,8
*
* ==> (1996 9:00 AM EST)November 5
* (2000 9:00 AM EST)November 7
* (2004 9:00 AM EST)November 2
* ...
*
* The 3rd instance into the month of one of Tuesday, Wednesday or
* Thursday, for the next 3 months:
*
* DTSTART;TZID=US-Eastern:19970904T090000
* RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3
*
* ==> (1997 9:00 AM EDT)September 4;October 7
* (1997 9:00 AM EST)November 6
*
* The 2nd to last weekday of the month:
*
* DTSTART;TZID=US-Eastern:19970929T090000
* RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2
*
* ==> (1997 9:00 AM EDT)September 29
* (1997 9:00 AM EST)October 30;November 27;December 30
* (1998 9:00 AM EST)January 29;February 26;March 30
* ...
*
* Every 3 hours from 9:00 AM to 5:00 PM on a specific day:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=HOURLY;INTERVAL=3;UNTIL=19970902T170000Z
*
* ==> (September 2, 1997 EDT)09:00,12:00,15:00
*
* Every 15 minutes for 6 occurrences:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=MINUTELY;INTERVAL=15;COUNT=6
*
* ==> (September 2, 1997 EDT)09:00,09:15,09:30,09:45,10:00,10:15
*
* Every hour and a half for 4 occurrences:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=MINUTELY;INTERVAL=90;COUNT=4
*
* ==> (September 2, 1997 EDT)09:00,10:30;12:00;13:30
*
* Every 20 minutes from 9:00 AM to 4:40 PM every day:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* RRULE:FREQ=DAILY;BYHOUR=9,10,11,12,13,14,15,16;BYMINUTE=0,20,40
* or
* RRULE:FREQ=MINUTELY;INTERVAL=20;BYHOUR=9,10,11,12,13,14,15,16
*
* ==> (September 2, 1997 EDT)9:00,9:20,9:40,10:00,10:20,
* ... 16:00,16:20,16:40
* (September 3, 1997 EDT)9:00,9:20,9:40,10:00,10:20,
* ...16:00,16:20,16:40
* ...
*
* An example where the days generated makes a difference because of
* WKST:
*
* DTSTART;TZID=US-Eastern:19970805T090000
* RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=MO
*
* ==> (1997 EDT)Aug 5,10,19,24
*
* changing only WKST from MO to SU, yields different results...
*
* DTSTART;TZID=US-Eastern:19970805T090000
* RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=SU
* ==> (1997 EDT)August 5,17,19,31
*/
class qCal_Property_Rrule extends qCal_Property {
protected $type = 'RECUR';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL','VTIMEZONE','DAYLIGHT','STANDARD');
protected $allowMultiple = true;
}
@@ -0,0 +1,94 @@
<?php
/**
* Sequence Number Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo A lot of the conformance below relates more to the application making
* use of this library, but make sure to conform however possible.
*
* RFC 2445 Definition
*
* Property Name: SEQUENCE
*
* Purpose: This property defines the revision sequence number of the
* calendar component within a sequence of revisions.
* Value Type: integer
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: The property can be specified in "VEVENT", "VTODO" or
* "VJOURNAL" calendar component.
*
* Description: When a calendar component is created, its sequence
* number is zero (US-ASCII decimal 48). It is monotonically incremented
* by the "Organizer's" CUA each time the "Organizer" makes a
* significant revision to the calendar component. When the "Organizer"
* makes changes to one of the following properties, the sequence number
* MUST be incremented:
*
* . "DTSTART"
*
* . "DTEND"
*
* . "DUE"
*
* . "RDATE"
*
* . "RRULE"
*
* . "EXDATE"
*
* . "EXRULE"
*
* . "STATUS"
*
* In addition, changes made by the "Organizer" to other properties can
* also force the sequence number to be incremented. The "Organizer" CUA
* MUST increment the sequence number when ever it makes changes to
* properties in the calendar component that the "Organizer" deems will
* jeopardize the validity of the participation status of the
* "Attendees". For example, changing the location of a meeting from one
* locale to another distant locale could effectively impact the
* participation status of the "Attendees".
*
* The "Organizer" includes this property in an iCalendar object that it
* sends to an "Attendee" to specify the current version of the calendar
* component.
*
* The "Attendee" includes this property in an iCalendar object that it
* sends to the "Organizer" to specify the version of the calendar
* component that the "Attendee" is referring to.
*
* A change to the sequence number is not the mechanism that an
* "Organizer" uses to request a response from the "Attendees". The
* "RSVP" parameter on the "ATTENDEE" property is used by the
* "Organizer" to indicate that a response from the "Attendees" is
* requested.
*
* Format Definition: This property is defined by the following
* notation:
*
* seq = "SEQUENCE" seqparam ":" integer CRLF
* ; Default is "0"
*
* seqparam = *(";" xparam)
*
* Example: The following is an example of this property for a calendar
* component that was just created by the "Organizer".
*
* SEQUENCE:0
*
* The following is an example of this property for a calendar component
* that has been revised two different times by the "Organizer".
*
* SEQUENCE:2
*/
class qCal_Property_Sequence extends qCal_Property {
protected $type = 'INTEGER';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL');
}
@@ -0,0 +1,81 @@
<?php
/**
* Status Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure that if this doesn't allow arbitrary status values that
* the use can't specify arbitrary values.
*
* RFC 2445 Definition
*
* Property Name: STATUS
*
* Purpose: This property defines the overall status or confirmation for
* the calendar component.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: This property can be specified in "VEVENT", "VTODO" or
* "VJOURNAL" calendar components.
*
* Description: In a group scheduled calendar component, the property is
* used by the "Organizer" to provide a confirmation of the event to the
* "Attendees". For example in a "VEVENT" calendar component, the
* "Organizer" can indicate that a meeting is tentative, confirmed or
* cancelled. In a "VTODO" calendar component, the "Organizer" can
* indicate that an action item needs action, is completed, is in
* process or being worked on, or has been cancelled. In a "VJOURNAL"
* calendar component, the "Organizer" can indicate that a journal entry
* is draft, final or has been cancelled or removed.
*
* Format Definition: The property is defined by the following notation:
*
* status = "STATUS" statparam] ":" statvalue CRLF
*
* statparam = *(";" xparam)
*
* statvalue = "TENTATIVE" ;Indicates event is
* ;tentative.
* / "CONFIRMED" ;Indicates event is
* ;definite.
* / "CANCELLED" ;Indicates event was
* ;cancelled.
* ;Status values for a "VEVENT"
*
* statvalue =/ "NEEDS-ACTION" ;Indicates to-do needs action.
* / "COMPLETED" ;Indicates to-do completed.
* / "IN-PROCESS" ;Indicates to-do in process of
* / "CANCELLED" ;Indicates to-do was cancelled.
* ;Status values for "VTODO".
*
* statvalue =/ "DRAFT" ;Indicates journal is draft.
* / "FINAL" ;Indicates journal is final.
* / "CANCELLED" ;Indicates journal is removed.
* ;Status values for "VJOURNAL".
*
* Example: The following is an example of this property for a "VEVENT"
* calendar component:
*
* STATUS:TENTATIVE
*
* The following is an example of this property for a "VTODO" calendar
* component:
*
* STATUS:NEEDS-ACTION
*
* The following is an example of this property for a "VJOURNAL"
* calendar component:
*
* STATUS:DRAFT
*/
class qCal_Property_Status extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL');
}
@@ -0,0 +1,58 @@
<?php
/**
* Summary Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
*
* RFC 2445 Definition
*
* Property Name: SUMMARY
*
* Purpose: This property defines a short summary or subject for the
* calendar component.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard, alternate text representation and
* language property parameters can be specified on this property.
*
* Conformance: The property can be specified in "VEVENT", "VTODO",
* "VJOURNAL" or "VALARM" calendar components.
*
* Description: This property is used in the "VEVENT", "VTODO" and
* "VJOURNAL" calendar components to capture a short, one line summary
* about the activity or journal entry.
*
* This property is used in the "VALARM" calendar component to capture
* the subject of an EMAIL category of alarm.
*
* Format Definition: The property is defined by the following notation:
*
* summary = "SUMMARY" summparam ":" text CRLF
*
* summparam = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" altrepparam) / (";" languageparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* )
*
* Example: The following is an example of this property:
*
* SUMMARY:Department Party
*/
class qCal_Property_Summary extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VEVENT','VTODO','VJOURNAL','VALARM');
}
@@ -0,0 +1,60 @@
<?php
/**
* Time Transparency Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Should this default to OPAQUE?
* @todo There needs to be a library-level method of finding "visible" free-busy time
*
* RFC 2445 Definition
*
* Property Name: TRANSP
*
* Purpose: This property defines whether an event is transparent or not
* to busy time searches.
*
* Value Type: TEXT
*
* Property Parameters: Non-standard property parameters can be
* specified on this property.
*
* Conformance: This property can be specified once in a "VEVENT"
* calendar component.
*
* Description: Time Transparency is the characteristic of an event that
* determines whether it appears to consume time on a calendar. Events
* that consume actual time for the individual or resource associated
* with the calendar SHOULD be recorded as OPAQUE, allowing them to be
* detected by free-busy time searches. Other events, which do not take
* up the individual's (or resource's) time SHOULD be recorded as
* TRANSPARENT, making them invisible to free-busy time searches.
*
* Format Definition: The property is specified by the following
* notation:
*
* transp = "TRANSP" tranparam ":" transvalue CRLF
*
* tranparam = *(";" xparam)
*
* transvalue = "OPAQUE" ;Blocks or opaque on busy time searches.
* / "TRANSPARENT" ;Transparent on busy time searches.
* ;Default value is OPAQUE
*
* Example: The following is an example of this property for an event
* that is transparent or does not block on free/busy time searches:
*
* TRANSP:TRANSPARENT
*
* The following is an example of this property for an event that is
* opaque or blocks on free/busy time searches:
*
* TRANSP:OPAQUE
*/
class qCal_Property_Transp extends qCal_Property {
protected $type = 'TEXT';
protected $allowedComponents = array('VEVENT');
}
@@ -0,0 +1,119 @@
<?php
/**
* Trigger Property
* @package qCal
* @copyright Luke Visinoni (luke.visinoni@gmail.com)
* @author Luke Visinoni (luke.visinoni@gmail.com)
* @license GNU Lesser General Public License
* @todo Make sure this behaves as expected when various other properties are
* introduced.
*
* RFC 2445 Definition
*
* Property Name: TRIGGER
*
* Purpose: This property specifies when an alarm will trigger.
*
* Value Type: The default value type is DURATION. The value type can be
* set to a DATE-TIME value type, in which case the value MUST specify a
* UTC formatted DATE-TIME value.
*
* Property Parameters: Non-standard, value data type, time zone
* identifier or trigger relationship property parameters can be
* specified on this property. The trigger relationship property
* parameter MUST only be specified when the value type is DURATION.
*
* Conformance: This property MUST be specified in the "VALARM" calendar
* component.
*
* Description: Within the "VALARM" calendar component, this property
* defines when the alarm will trigger. The default value type is
* DURATION, specifying a relative time for the trigger of the alarm.
* The default duration is relative to the start of an event or to-do
* that the alarm is associated with. The duration can be explicitly set
* to trigger from either the end or the start of the associated event
* or to-do with the "RELATED" parameter. A value of START will set the
* alarm to trigger off the start of the associated event or to-do. A
* value of END will set the alarm to trigger off the end of the
* associated event or to-do.
*
* Either a positive or negative duration may be specified for the
* "TRIGGER" property. An alarm with a positive duration is triggered
* after the associated start or end of the event or to-do. An alarm
* with a negative duration is triggered before the associated start or
* end of the event or to-do.
*
* The "RELATED" property parameter is not valid if the value type of
* the property is set to DATE-TIME (i.e., for an absolute date and time
* alarm trigger). If a value type of DATE-TIME is specified, then the
* property value MUST be specified in the UTC time format. If an
* absolute trigger is specified on an alarm for a recurring event or
* to-do, then the alarm will only trigger for the specified absolute
* date/time, along with any specified repeating instances.
*
* If the trigger is set relative to START, then the "DTSTART" property
* MUST be present in the associated "VEVENT" or "VTODO" calendar
* component. If an alarm is specified for an event with the trigger set
* relative to the END, then the "DTEND" property or the "DSTART" and
* "DURATION' properties MUST be present in the associated "VEVENT"
* calendar component. If the alarm is specified for a to-do with a
* trigger set relative to the END, then either the "DUE" property or
* the "DSTART" and "DURATION' properties MUST be present in the
* associated "VTODO" calendar component.
*
* Alarms specified in an event or to-do which is defined in terms of a
* DATE value type will be triggered relative to 00:00:00 UTC on the
* specified date. For example, if "DTSTART:19980205, then the duration
* trigger will be relative to19980205T000000Z.
*
* Format Definition: The property is defined by the following notation:
*
* trigger = "TRIGGER" (trigrel / trigabs)
*
* trigrel = *(
*
* ; the following are optional,
* ; but MUST NOT occur more than once
*
* (";" "VALUE" "=" "DURATION") /
* (";" trigrelparam) /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
* ) ":" dur-value
*
* trigabs = 1*(
*
* ; the following is REQUIRED,
* ; but MUST NOT occur more than once
*
* (";" "VALUE" "=" "DATE-TIME") /
*
* ; the following is optional,
* ; and MAY occur more than once
*
* (";" xparam)
*
* ) ":" date-time
*
* Example: A trigger set 15 minutes prior to the start of the event or
* to-do.
*
* TRIGGER:-P15M
*
* A trigger set 5 minutes after the end of the event or to-do.
*
* TRIGGER;RELATED=END:P5M
*
* A trigger set to an absolute date/time.
*
* TRIGGER;VALUE=DATE-TIME:19980101T050000Z
*/
class qCal_Property_Trigger extends qCal_Property {
protected $type = 'DURATION';
protected $allowedComponents = array('VALARM');
}

Some files were not shown because too many files have changed in this diff Show More