.scrutinizer.yml 0000666 00000000556 13436751250 0007746 0 ustar 00 filter:
excluded_paths:
- tests/*
tools:
php_cs_fixer: true
php_code_sniffer:
config:
standard: PSR2
php_mess_detector: true
php_analyzer: true
sensiolabs_security_checker: true
external_code_coverage:
timeout: 300
runs: 1
checks:
php:
code_rating: true
duplication: true
LICENSE 0000666 00000002051 13436751250 0005561 0 ustar 00 Copyright (c) 2012-2015 Markus Poerschke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
UPGRADE.md 0000666 00000000540 13436751250 0006166 0 ustar 00 # v0.8.0 -> v0.9.0
- The signature of the ```Event::setOrganizer``` method was changed:
Now there is is only one parameter that must be an instance of ```Property\Organizer```.
# v0.7.0 -> v0.8.0
- The signature of the ```Event::setOrganizer``` method was changed: Now there are
two parameters name and email instead of an already formatted string.
README.md 0000666 00000010634 13436751250 0006041 0 ustar 00 # eluceo — iCal
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/markuspoerschke/iCal/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/markuspoerschke/iCal/?branch=master) [![Code Coverage](https://scrutinizer-ci.com/g/markuspoerschke/iCal/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/markuspoerschke/iCal/?branch=master) [![Build Status](https://travis-ci.org/markuspoerschke/iCal.svg?branch=master)](https://travis-ci.org/markuspoerschke/iCal)
This package offers a abstraction layer for creating iCalendars. The output will
follow [RFC 5545](http://www.ietf.org/rfc/rfc5545.txt) as best as possible.
The following components are supported at this time:
* VCALENDAR
* VEVENT
* VALARM
* VTIMEZONE
## Installation
You can install this package by using [Composer](http://getcomposer.org), running this command:
```sh
composer require eluceo/ical
```
Link to Packagist: https://packagist.org/packages/eluceo/ical
## Usage
### Basic Usage
#### 1. Create a Calendar object
```PHP
$vCalendar = new \Eluceo\iCal\Component\Calendar('www.example.com');
```
#### 2. Create an Event object
```PHP
$vEvent = new \Eluceo\iCal\Component\Event();
```
#### 3. Add your information to the Event
```PHP
$vEvent
->setDtStart(new \DateTime('2012-12-24'))
->setDtEnd(new \DateTime('2012-12-24'))
->setNoTime(true)
->setSummary('Christmas')
;
```
#### 4. Add Event to Calendar
```PHP
$vCalendar->addComponent($vEvent);
```
#### 5. Set HTTP-headers
```PHP
header('Content-Type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename="cal.ics"');
```
#### 6. Send output
```PHP
echo $vCalendar->render();
```
### Timezone support
This package supports three different types of handling timezones:
#### 1. UTC (default)
In the default setting, UTC/GMT will be used as Timezone. The time will be formated as following:
```
DTSTART:20121224T180000Z
```
#### 2. Use explicit timezone
You can use an explicit timezone by calling `$vEvent->setUseTimezone(true);`. The timezone of your
`\DateTime` object will be used. In this case the non-standard field "X-WR-TIMEZONE" will be used.
Be awre that this is a simple solution which is not supported by all calendar clients.
The output will be as following:
```
DTSTART;TZID=Europe/Berlin:20121224T180000
```
#### 3. Use explicit timezone with definition
You can use an explicit timezone and define it using `Timezone()` and `TimezoneRule()` (see example5.php).
The timezone of your `\DateTime` object will be used. The output will be as following:
```
BEGIN:VTIMEZONE
TZID:Europe/Berlin
X-LIC-LOCATION:Europe/Berlin
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19810329T030000
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19961027T030000
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
...
DTSTART;TZID=Europe/Berlin:20121224T180000
```
#### 4. Use locale time
You can use local time by calling `$vEvent->setUseUtc(false);`. The output will be:
```
DTSTART:20121224T180000
```
## Running the tests
To setup and run tests:
- go to the root directory of this project
- download composer: `wget https://getcomposer.org/composer.phar`
- install dev dependencies: `php composer.phar install --dev`
- run `./bin/phpunit`
## License
This package is released under the __MIT license__.
Copyright (c) 2012-2015 Markus Poerschke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
examples/example6.php 0000666 00000001560 13436751250 0010630 0 ustar 00 setDtStart(new \DateTime('2012-12-24'));
$vEvent->setDtEnd(new \DateTime('2012-12-24'));
$vEvent->setNoTime(true);
$vEvent->setSummary('Christmas');
// add some location information for apple devices
$vEvent->setLocation("Infinite Loop\nCupertino CA 95014", 'Infinite Loop', '37.332095,-122.030743');
// 3. Add event to calendar
$vCalendar->addComponent($vEvent);
// 4. Set headers
header('Content-Type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename="cal.ics"');
// 5. Output
echo $vCalendar->render();
examples/example7.php 0000666 00000001726 13436751250 0010635 0 ustar 00 setDtStart(new \DateTime('2012-12-24'));
$vEvent->setDtEnd(new \DateTime('2012-12-24'));
$vEvent->setNoTime(true);
$vEvent->setSummary('Christmas');
$vEvent->setDescription('Happy Christmas!');
$vEvent->setDescriptionHTML('Happy Christmas!');
// add some location information for apple devices
$vEvent->setLocation("Infinite Loop\nCupertino CA 95014", 'Infinite Loop', '37.332095,-122.030743');
// 3. Add event to calendar
$vCalendar->addComponent($vEvent);
// 4. Set headers
header('Content-Type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename="cal.ics"');
// 5. Output
echo $vCalendar->render();
examples/example1.php 0000666 00000001425 13436751250 0010623 0 ustar 00 setDtStart(new \DateTime('2012-12-24'));
$vEvent->setDtEnd(new \DateTime('2012-12-24'));
$vEvent->setNoTime(true);
$vEvent->setSummary('Christmas');
// Adding Timezone (optional)
$vEvent->setUseTimezone(true);
// 3. Add event to calendar
$vCalendar->addComponent($vEvent);
// 4. Set headers
header('Content-Type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename="cal.ics"');
// 5. Output
echo $vCalendar->render();
examples/example4.php 0000666 00000002031 13436751250 0010620 0 ustar 00 setDtStart(new \DateTime('2012-11-11 13:00:00'));
$vEvent->setDtEnd(new \DateTime('2012-11-11 14:30:00'));
$vEvent->setSummary('Weekly lunch with Markus');
// Set recurrence rule
$recurrenceRule = new \Eluceo\iCal\Property\Event\RecurrenceRule();
$recurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_WEEKLY);
$recurrenceRule->setInterval(1);
$vEvent->setRecurrenceRule($recurrenceRule);
// Adding Timezone (optional)
$vEvent->setUseTimezone(true);
// 3. Add event to calendar
$vCalendar->addComponent($vEvent);
// 4. Set headers
header('Content-Type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename="cal.ics"');
// 5. Output
echo $vCalendar->render();
examples/example5.php 0000666 00000004753 13436751250 0010636 0 ustar 00 setTzName('CEST');
$vTimezoneRuleDst->setDtStart(new \DateTime('1981-03-29 02:00:00', $dtz));
$vTimezoneRuleDst->setTzOffsetFrom('+0100');
$vTimezoneRuleDst->setTzOffsetTo('+0200');
$dstRecurrenceRule = new \Eluceo\iCal\Property\Event\RecurrenceRule();
$dstRecurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_YEARLY);
$dstRecurrenceRule->setByMonth(3);
$dstRecurrenceRule->setByDay('-1SU');
$vTimezoneRuleDst->setRecurrenceRule($dstRecurrenceRule);
// 3. Create timezone rule object for Standard Time
$vTimezoneRuleStd = new \Eluceo\iCal\Component\TimezoneRule(\Eluceo\iCal\Component\TimezoneRule::TYPE_STANDARD);
$vTimezoneRuleStd->setTzName('CET');
$vTimezoneRuleStd->setDtStart(new \DateTime('1996-10-27 03:00:00', $dtz));
$vTimezoneRuleStd->setTzOffsetFrom('+0200');
$vTimezoneRuleStd->setTzOffsetTo('+0100');
$stdRecurrenceRule = new \Eluceo\iCal\Property\Event\RecurrenceRule();
$stdRecurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_YEARLY);
$stdRecurrenceRule->setByMonth(10);
$stdRecurrenceRule->setByDay('-1SU');
$vTimezoneRuleStd->setRecurrenceRule($stdRecurrenceRule);
// 4. Create timezone definition and add rules
$vTimezone = new \Eluceo\iCal\Component\Timezone($tz);
$vTimezone->addComponent($vTimezoneRuleDst);
$vTimezone->addComponent($vTimezoneRuleStd);
$vCalendar->setTimezone($vTimezone);
// 5. Create an event
$vEvent = new \Eluceo\iCal\Component\Event();
$vEvent->setDtStart(new \DateTime('2012-12-24', $dtz));
$vEvent->setDtEnd(new \DateTime('2012-12-24', $dtz));
$vEvent->setSummary('Summary with some german "umlauten" and a backslash \\: Kinder mögen Äpfel pflücken.');
// 6. Adding Timezone
$vEvent->setUseTimezone(true);
// 7. Add event to calendar
$vCalendar->addComponent($vEvent);
// 8. Set headers
header('Content-Type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename="cal.ics"');
// 9. Output
echo $vCalendar->render();
examples/example2.php 0000666 00000001611 13436751250 0010621 0 ustar 00 setDtStart(new \DateTime('2012-12-24'));
$vEvent->setDtEnd(new \DateTime('2012-12-24'));
$vEvent->setNoTime(true);
$vEvent->setSummary('Summary with some german "umlauten" and a backslash \\: Kinder mögen Äpfel pflücken.');
$vEvent->setCategories(['holidays']);
// Adding Timezone (optional)
$vEvent->setUseTimezone(true);
// 3. Add event to calendar
$vCalendar->addComponent($vEvent);
// 4. Set headers
header('Content-Type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename="cal.ics"');
// 5. Output
echo $vCalendar->render();
examples/example3.php 0000666 00000002031 13436751250 0010617 0 ustar 00 setDtStart(new \DateTime('2012-12-31'));
$vEvent->setDtEnd(new \DateTime('2012-12-31'));
$vEvent->setNoTime(true);
$vEvent->setSummary('New Year’s Eve');
// Set recurrence rule
$recurrenceRule = new \Eluceo\iCal\Property\Event\RecurrenceRule();
$recurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_YEARLY);
$recurrenceRule->setInterval(1);
$vEvent->setRecurrenceRule($recurrenceRule);
// Adding Timezone (optional)
$vEvent->setUseTimezone(true);
// 3. Add event to calendar
$vCalendar->addComponent($vEvent);
// 4. Set headers
header('Content-Type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename="cal.ics"');
// 5. Output
echo $vCalendar->render();
src/Property/RawStringValue.php 0000666 00000000603 13436751250 0012616 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Property;
class RawStringValue extends StringValue
{
public function getEscapedValue()
{
return $this->getValue();
}
}
src/Property/Event/Geo.php 0000666 00000004071 13436751250 0011477 0 ustar 00 latitude = $latitude;
$this->longitude = $longitude;
if ($this->latitude < -90 || $this->latitude > 90) {
throw new \InvalidArgumentException(
"The geographical latitude must be a value between -90 and 90 degrees. '{$this->latitude}' was given."
);
}
if ($this->longitude < -180 || $this->longitude > 180) {
throw new \InvalidArgumentException(
"The geographical longitude must be a value between -180 and 180 degrees. '{$this->longitude}' was given."
);
}
parent::__construct('GEO', new Property\RawStringValue($this->getGeoLocationAsString()));
}
/**
* @deprecated This method is used to allow backwards compatibility for Event::setLocation
*
* @param string $geoLocationString
* @return Geo
*/
public static function fromString(string $geoLocationString)
{
$geoLocationString = str_replace(',', ';', $geoLocationString);
$parts = explode(';', $geoLocationString);
return new static((float) $parts[0], (float) $parts[1]);
}
/**
* Returns the coordinates as a string.
*
* @example 37.386013;-122.082932
*
* @param string $separator
* @return string
*/
public function getGeoLocationAsString(string $separator = ';')
{
return number_format($this->latitude, 6) . $separator . number_format($this->longitude, 6);
}
/**
* @return float
*/
public function getLatitude()
{
return $this->latitude;
}
/**
* @return float
*/
public function getLongitude()
{
return $this->longitude;
}
}
src/Eluceo/iCal/PropertyBag.php 0000666 00000003316 13436751250 0012403 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal;
class PropertyBag implements \IteratorAggregate
{
/**
* @var array
*/
protected $elements = array();
/**
* Creates a new Property with $name, $value and $params.
*
* @param $name
* @param $value
* @param array $params
*
* @return $this
*/
public function set($name, $value, $params = array())
{
$property = new Property($name, $value, $params);
$this->elements[] = $property;
return $this;
}
/**
* @param string $name
*
* @return null|Property
*/
public function get($name)
{
// Searching Property in elements-array
/** @var $property Property */
foreach ($this->elements as $property) {
if ($property->getName() == $name) {
return $property;
}
}
}
/**
* Adds a Property. If Property already exists an Exception will be thrown.
*
* @param Property $property
*
* @return $this
*
* @throws \Exception
*/
public function add(Property $property)
{
// Property already exists?
if (null !== $this->get($property->getName())) {
throw new \Exception("Property with name '{$property->getName()}' already exists");
}
$this->elements[] = $property;
return $this;
}
public function getIterator()
{
return new \ArrayObject($this->elements);
}
}
src/Eluceo/iCal/Util/PropertyValueUtil.php 0000666 00000002202 13436751250 0014532 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Util;
class PropertyValueUtil
{
public static function escapeValue($value)
{
$value = self::escapeValueAllowNewLine($value);
$value = str_replace("\n", '\\n', $value);
return $value;
}
public static function escapeValueAllowNewLine($value)
{
$value = str_replace('\\', '\\\\', $value);
$value = str_replace('"', '\\"', $value);
$value = str_replace(',', '\\,', $value);
$value = str_replace(';', '\\;', $value);
$value = str_replace(array(
"\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07",
"\x08", "\x09", /* \n*/ "\x0B", "\x0C", "\x0D", "\x0E", "\x0F",
"\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17",
"\x18", "\x19", "\x1A", "\x1B", "\x1C", "\x1D", "\x1E", "\x1F",
"\x7F",
), '', $value);
return $value;
}
}
src/Eluceo/iCal/Util/DateUtil.php 0000666 00000003534 13436751250 0012577 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Util;
class DateUtil
{
public static function getDefaultParams(\DateTime $dateTime = null, $noTime = false, $useTimezone = false)
{
$params = array();
if ($useTimezone && $noTime === false) {
$timeZone = $dateTime->getTimezone()->getName();
$params['TZID'] = $timeZone;
}
if ($noTime) {
$params['VALUE'] = 'DATE';
}
return $params;
}
/**
* Returns a formatted date string.
*
* @param \DateTime|null $dateTime The DateTime object
* @param bool $noTime Indicates if the time will be added
* @param bool $useTimezone
* @param bool $useUtc
*
* @return mixed
*/
public static function getDateString(\DateTime $dateTime = null, $noTime = false, $useTimezone = false, $useUtc = false)
{
if (empty($dateTime)) {
$dateTime = new \DateTime();
}
return $dateTime->format(self::getDateFormat($noTime, $useTimezone, $useUtc));
}
/**
* Returns the date format that can be passed to DateTime::format().
*
* @param bool $noTime Indicates if the time will be added
* @param bool $useTimezone
* @param bool $useUtc
*
* @return string
*/
public static function getDateFormat($noTime = false, $useTimezone = false, $useUtc = false)
{
// Do not use UTC time (Z) if timezone support is enabled.
if ($useTimezone || !$useUtc) {
return $noTime ? 'Ymd' : 'Ymd\THis';
}
return $noTime ? 'Ymd' : 'Ymd\THis\Z';
}
}
src/Eluceo/iCal/Util/ComponentUtil.php 0000666 00000002044 13436751250 0013657 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Util;
class ComponentUtil
{
/**
* Folds a single line.
*
* According to RFC 2445, all lines longer than 75 characters will be folded
*
* @link http://www.ietf.org/rfc/rfc2445.txt
*
* @param $string
*
* @return array
*/
public static function fold($string)
{
$lines = array();
$array = preg_split('/(? 75) {
$line = ' ' . $char;
++$lineNo;
} else {
$line .= $char;
}
$lines[$lineNo] = $line;
}
return $lines;
}
}
src/Eluceo/iCal/Component/Alarm.php 0000666 00000005521 13436751250 0013143 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Component;
use Eluceo\iCal\Component;
use Eluceo\iCal\PropertyBag;
use Eluceo\iCal\Property;
/**
* Implementation of the VALARM component.
*/
class Alarm extends Component
{
/**
* Alarm ACTION property.
*
* According to RFC 5545: 3.8.6.1. Action
*
* @link http://tools.ietf.org/html/rfc5545#section-3.8.6.1
*/
const ACTION_AUDIO = 'AUDIO';
const ACTION_DISPLAY = 'DISPLAY';
const ACTION_EMAIL = 'EMAIL';
protected $action;
protected $repeat;
protected $duration;
protected $description;
protected $attendee;
protected $trigger;
public function getType()
{
return 'VALARM';
}
public function getAction()
{
return $this->action;
}
public function getRepeat()
{
return $this->repeat;
}
public function getDuration()
{
return $this->duration;
}
public function getDescription()
{
return $this->description;
}
public function getAttendee()
{
return $this->attendee;
}
public function getTrigger()
{
return $this->trigger;
}
public function setAction($action)
{
$this->action = $action;
return $this;
}
public function setRepeat($repeat)
{
$this->repeat = $repeat;
return $this;
}
public function setDuration($duration)
{
$this->duration = $duration;
return $this;
}
public function setDescription($description)
{
$this->description = $description;
return $this;
}
public function setAttendee($attendee)
{
$this->attendee = $attendee;
return $this;
}
public function setTrigger($trigger)
{
$this->trigger = $trigger;
return $this;
}
/**
* {@inheritdoc}
*/
public function buildPropertyBag()
{
$propertyBag = new PropertyBag();
if (null != $this->trigger) {
$propertyBag->set('TRIGGER', $this->trigger);
}
if (null != $this->action) {
$propertyBag->set('ACTION', $this->action);
}
if (null != $this->repeat) {
$propertyBag->set('REPEAT', $this->repeat);
}
if (null != $this->duration) {
$propertyBag->set('DURATION', $this->duration);
}
if (null != $this->description) {
$propertyBag->set('DESCRIPTION', $this->description);
}
if (null != $this->attendee) {
$propertyBag->set('ATTENDEE', $this->attendee);
}
return $propertyBag;
}
}
src/Eluceo/iCal/Component/Calendar.php 0000666 00000016710 13436751250 0013622 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Component;
use Eluceo\iCal\Component;
use Eluceo\iCal\PropertyBag;
class Calendar extends Component
{
/**
* Methods for calendar components.
*
* According to RFP 5545: 3.7.2. Method
*
* @link http://tools.ietf.org/html/rfc5545#section-3.7.2
*
* And then according to RFC 2446: 3 APPLICATION PROTOCOL ELEMENTS
* @link https://www.ietf.org/rfc/rfc2446.txt
*/
const METHOD_PUBLISH = 'PUBLISH';
const METHOD_REQUEST = 'REQUEST';
const METHOD_REPLY = 'REPLY';
const METHOD_ADD = 'ADD';
const METHOD_CANCEL = 'CANCEL';
const METHOD_REFRESH = 'REFRESH';
const METHOD_COUNTER = 'COUNTER';
const METHOD_DECLINECOUNTER = 'DECLINECOUNTER';
/**
* This property defines the calendar scale used for the calendar information specified in the iCalendar object.
*
* According to RFC 5545: 3.7.1. Calendar Scale
*
* @link http://tools.ietf.org/html/rfc5545#section-3.7
*/
const CALSCALE_GREGORIAN = 'GREGORIAN';
/**
* The Product Identifier.
*
* According to RFC 2445: 4.7.3 Product Identifier
*
* This property specifies the identifier for the product that created the Calendar object.
*
* @link http://www.ietf.org/rfc/rfc2445.txt
*
* @var string
*/
protected $prodId = null;
protected $method = null;
protected $name = null;
protected $description = null;
protected $timezone = null;
/**
* This property defines the calendar scale used for the
* calendar information specified in the iCalendar object.
*
* Also identifies the calendar type of a non-Gregorian recurring appointment.
*
* @var string
*
* @see http://tools.ietf.org/html/rfc5545#section-3.7
* @see http://msdn.microsoft.com/en-us/library/ee237520(v=exchg.80).aspx
*/
protected $calendarScale = null;
/**
* Specifies whether or not the iCalendar file only contains one appointment.
*
* @var bool
*
* @see http://msdn.microsoft.com/en-us/library/ee203486(v=exchg.80).aspx
*/
protected $forceInspectOrOpen = false;
/**
* Specifies a globally unique identifier for the calendar.
*
* @var string
*
* @see http://msdn.microsoft.com/en-us/library/ee179588(v=exchg.80).aspx
*/
protected $calId = null;
/**
* Specifies a suggested iCalendar file download frequency for clients and
* servers with sync capabilities.
*
* @var string
*
* @see http://msdn.microsoft.com/en-us/library/ee178699(v=exchg.80).aspx
*/
protected $publishedTTL = 'P1W';
/**
* Specifies a color for the calendar in calendar for Apple/Outlook.
*
* @var string
*
* @see http://msdn.microsoft.com/en-us/library/ee179588(v=exchg.80).aspx
*/
protected $calendarColor = null;
public function __construct($prodId)
{
if (empty($prodId)) {
throw new \UnexpectedValueException('PRODID cannot be empty');
}
$this->prodId = $prodId;
}
/**
* {@inheritdoc}
*/
public function getType()
{
return 'VCALENDAR';
}
/**
* @param $method
*
* @return $this
*/
public function setMethod($method)
{
$this->method = $method;
return $this;
}
/**
* @param $name
*
* @return $this
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* @param $description
*
* @return $this
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* @param $timezone
*
* @return $this
*/
public function setTimezone($timezone)
{
$this->timezone = $timezone;
return $this;
}
/**
* @param $calendarColor
*
* @return $this
*/
public function setCalendarColor($calendarColor)
{
$this->calendarColor = $calendarColor;
return $this;
}
/**
* @param $calendarScale
*
* @return $this
*/
public function setCalendarScale($calendarScale)
{
$this->calendarScale = $calendarScale;
return $this;
}
/**
* @param bool $forceInspectOrOpen
*
* @return $this
*/
public function setForceInspectOrOpen($forceInspectOrOpen)
{
$this->forceInspectOrOpen = $forceInspectOrOpen;
return $this;
}
/**
* @param string $calId
*
* @return $this
*/
public function setCalId($calId)
{
$this->calId = $calId;
return $this;
}
/**
* @param string $ttl
*
* @return $this
*/
public function setPublishedTTL($ttl)
{
$this->publishedTTL = $ttl;
return $this;
}
/**
* {@inheritdoc}
*/
public function buildPropertyBag()
{
$propertyBag = new PropertyBag();
$propertyBag->set('VERSION', '2.0');
$propertyBag->set('PRODID', $this->prodId);
if ($this->method) {
$propertyBag->set('METHOD', $this->method);
}
if ($this->calendarColor) {
$propertyBag->set('X-APPLE-CALENDAR-COLOR', $this->calendarColor);
$propertyBag->set('X-OUTLOOK-COLOR', $this->calendarColor);
$propertyBag->set('X-FUNAMBOL-COLOR', $this->calendarColor);
}
if ($this->calendarScale) {
$propertyBag->set('CALSCALE', $this->calendarScale);
$propertyBag->set('X-MICROSOFT-CALSCALE', $this->calendarScale);
}
if ($this->name) {
$propertyBag->set('X-WR-CALNAME', $this->name);
}
if ($this->description) {
$propertyBag->set('X-WR-CALDESC', $this->description);
}
if ($this->timezone) {
if ($this->timezone instanceof Timezone) {
$propertyBag->set('X-WR-TIMEZONE', $this->timezone->getZoneIdentifier());
$this->addComponent($this->timezone);
} else {
$propertyBag->set('X-WR-TIMEZONE', $this->timezone);
$this->addComponent(new Timezone($this->timezone));
}
}
if ($this->forceInspectOrOpen) {
$propertyBag->set('X-MS-OLK-FORCEINSPECTOROPEN', $this->forceInspectOrOpen);
}
if ($this->calId) {
$propertyBag->set('X-WR-RELCALID', $this->calId);
}
if ($this->publishedTTL) {
$propertyBag->set('X-PUBLISHED-TTL', $this->publishedTTL);
}
return $propertyBag;
}
/**
* Adds an Event to the Calendar.
*
* Wrapper for addComponent()
*
* @see Eluceo\iCal::addComponent
* @deprecated Please, use public method addComponent() from abstract Component class
*
* @param Event $event
*/
public function addEvent(Event $event)
{
$this->addComponent($event);
}
/**
* @return null|string
*/
public function getProdId()
{
return $this->prodId;
}
public function getMethod()
{
return $this->method;
}
}
src/Eluceo/iCal/Component/Event.php 0000666 00000043172 13436751250 0013174 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Component;
use Eluceo\iCal\Component;
use Eluceo\iCal\Property;
use Eluceo\iCal\Property\DateTimeProperty;
use Eluceo\iCal\Property\Event\Attendees;
use Eluceo\iCal\Property\Event\Geo;
use Eluceo\iCal\Property\Event\Organizer;
use Eluceo\iCal\Property\Event\RecurrenceRule;
use Eluceo\iCal\Property\Event\Description;
use Eluceo\iCal\Property\RawStringValue;
use Eluceo\iCal\PropertyBag;
use Eluceo\iCal\Property\Event\RecurrenceId;
use Eluceo\iCal\Property\DateTimesProperty;
/**
* Implementation of the EVENT component.
*/
class Event extends Component
{
const TIME_TRANSPARENCY_OPAQUE = 'OPAQUE';
const TIME_TRANSPARENCY_TRANSPARENT = 'TRANSPARENT';
const STATUS_TENTATIVE = 'TENTATIVE';
const STATUS_CONFIRMED = 'CONFIRMED';
const STATUS_CANCELLED = 'CANCELLED';
/**
* @var string
*/
protected $uniqueId;
/**
* The property indicates the date/time that the instance of
* the iCalendar object was created.
*
* The value MUST be specified in the UTC time format.
*
* @var \DateTime
*/
protected $dtStamp;
/**
* @var \DateTime
*/
protected $dtStart;
/**
* Preferentially chosen over the duration if both are set.
*
* @var \DateTime
*/
protected $dtEnd;
/**
* @var \DateInterval
*/
protected $duration;
/**
* @var bool
*/
protected $noTime = false;
/**
* @var string
*/
protected $url;
/**
* @var string
*/
protected $location;
/**
* @var string
*/
protected $locationTitle;
/**
* @var Geo
*/
protected $locationGeo;
/**
* @var string
*/
protected $summary;
/**
* @var Organizer
*/
protected $organizer;
/**
* @see http://www.ietf.org/rfc/rfc2445.txt 4.8.2.7 Time Transparency
*
* @var string
*/
protected $transparency = self::TIME_TRANSPARENCY_OPAQUE;
/**
* If set to true the timezone will be added to the event.
*
* @var bool
*/
protected $useTimezone = false;
/**
* @var int
*/
protected $sequence = 0;
/**
* @var Attendees
*/
protected $attendees;
/**
* @var string
*/
protected $description;
/**
* @var string
*/
protected $descriptionHTML;
/**
* @var string
*/
protected $status;
/**
* @var RecurrenceRule
*/
protected $recurrenceRule;
/**
* @var array
*/
protected $recurrenceRules = array();
/**
* This property specifies the date and time that the calendar
* information was created.
*
* The value MUST be specified in the UTC time format.
*
* @var \DateTime
*/
protected $created;
/**
* The property specifies the date and time that the information
* associated with the calendar component was last revised.
*
* The value MUST be specified in the UTC time format.
*
* @var \DateTime
*/
protected $modified;
/**
* Indicates if the UTC time should be used or not.
*
* @var bool
*/
protected $useUtc = true;
/**
* @var bool
*/
protected $cancelled;
/**
* 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.
*
* @see https://tools.ietf.org/html/rfc5545#section-3.8.1.2
*
* @var array
*/
protected $categories;
/**
* https://tools.ietf.org/html/rfc5545#section-3.8.1.3.
*
* @var bool
*/
protected $isPrivate = false;
/**
* Dates to be excluded from a series of events.
*
* @var \DateTime[]
*/
protected $exDates = array();
/**
* @var RecurrenceId
*/
protected $recurrenceId;
public function __construct($uniqueId = null)
{
if (null == $uniqueId) {
$uniqueId = uniqid();
}
$this->uniqueId = $uniqueId;
}
/**
* {@inheritdoc}
*/
public function getType()
{
return 'VEVENT';
}
/**
* {@inheritdoc}
*/
public function buildPropertyBag()
{
$propertyBag = new PropertyBag();
// mandatory information
$propertyBag->set('UID', $this->uniqueId);
$propertyBag->add(new DateTimeProperty('DTSTART', $this->dtStart, $this->noTime, $this->useTimezone, $this->useUtc));
$propertyBag->set('SEQUENCE', $this->sequence);
$propertyBag->set('TRANSP', $this->transparency);
if ($this->status) {
$propertyBag->set('STATUS', $this->status);
}
// An event can have a 'dtend' or 'duration', but not both.
if (null != $this->dtEnd) {
if($this->noTime === true) {
$this->dtEnd->add(new \DateInterval('P1D'));
}
$propertyBag->add(new DateTimeProperty('DTEND', $this->dtEnd, $this->noTime, $this->useTimezone, $this->useUtc));
} elseif (null != $this->duration) {
$propertyBag->set('DURATION', $this->duration->format('P%dDT%hH%iM%sS'));
}
// optional information
if (null != $this->url) {
$propertyBag->set('URL', $this->url);
}
if (null != $this->location) {
$propertyBag->set('LOCATION', $this->location);
if (null != $this->locationGeo) {
$propertyBag->add(
new Property(
'X-APPLE-STRUCTURED-LOCATION',
new RawStringValue('geo:' . $this->locationGeo->getGeoLocationAsString(',')),
array(
'VALUE' => 'URI',
'X-ADDRESS' => $this->location,
'X-APPLE-RADIUS' => 49,
'X-TITLE' => $this->locationTitle,
)
)
);
}
}
if (null != $this->locationGeo) {
$propertyBag->add($this->locationGeo);
}
if (null != $this->summary) {
$propertyBag->set('SUMMARY', $this->summary);
}
if (null != $this->attendees) {
$propertyBag->add($this->attendees);
}
$propertyBag->set('CLASS', $this->isPrivate ? 'PRIVATE' : 'PUBLIC');
if (null != $this->description) {
$propertyBag->set('DESCRIPTION', new Description($this->description));
}
if (null != $this->descriptionHTML) {
$propertyBag->add(
new Property(
'X-ALT-DESC',
$this->descriptionHTML,
array(
'FMTTYPE' => 'text/html',
)
)
);
}
if (null != $this->recurrenceRule) {
$propertyBag->set('RRULE', $this->recurrenceRule);
}
foreach ($this->recurrenceRules as $recurrenceRule) {
$propertyBag->set('RRULE', $recurrenceRule);
}
if (null != $this->recurrenceId) {
$this->recurrenceId->applyTimeSettings($this->noTime, $this->useTimezone, $this->useUtc);
$propertyBag->add($this->recurrenceId);
}
if (!empty($this->exDates)) {
$propertyBag->add(new DateTimesProperty('EXDATE', $this->exDates, $this->noTime, $this->useTimezone, $this->useUtc));
}
if ($this->cancelled) {
$propertyBag->set('STATUS', 'CANCELLED');
}
if (null != $this->organizer) {
$propertyBag->add($this->organizer);
}
if ($this->noTime) {
$propertyBag->set('X-MICROSOFT-CDO-ALLDAYEVENT', 'TRUE');
}
if (null != $this->categories) {
$propertyBag->set('CATEGORIES', $this->categories);
}
$propertyBag->add(
new DateTimeProperty('DTSTAMP', $this->dtStamp ?: new \DateTime(), false, false, true)
);
if ($this->created) {
$propertyBag->add(new DateTimeProperty('CREATED', $this->created, false, false, true));
}
if ($this->modified) {
$propertyBag->add(new DateTimeProperty('LAST-MODIFIED', $this->modified, false, false, true));
}
return $propertyBag;
}
/**
* @param $dtEnd
*
* @return $this
*/
public function setDtEnd($dtEnd)
{
$this->dtEnd = $dtEnd;
return $this;
}
public function getDtEnd()
{
return $this->dtEnd;
}
public function setDtStart($dtStart)
{
$this->dtStart = $dtStart;
return $this;
}
public function getDtStart()
{
return $this->dtStart;
}
/**
* @param $dtStamp
*
* @return $this
*/
public function setDtStamp($dtStamp)
{
$this->dtStamp = $dtStamp;
return $this;
}
/**
* @param $duration
*
* @return $this
*/
public function setDuration($duration)
{
$this->duration = $duration;
return $this;
}
/**
* @param string $location
* @param string $title
* @param Geo|string $geo
*
* @return $this
*/
public function setLocation($location, $title = '', $geo = null)
{
if (is_scalar($geo)) {
$geo = Geo::fromString($geo);
} else if (!$geo instanceof Geo) {
$className = get_class($geo);
throw new \InvalidArgumentException(
"The parameter 'geo' must be a string or an instance of \\Eluceo\\iCal\\Property\\Event\\Geo"
. " but an instance of {$className} was given."
);
}
$this->location = $location;
$this->locationTitle = $title;
$this->locationGeo = $geo;
return $this;
}
/**
* @param Geo $geoProperty
* @return $this
*/
public function setGeoLocation(Geo $geoProperty)
{
$this->locationGeo = $geoProperty;
return $this;
}
/**
* @param $noTime
*
* @return $this
*/
public function setNoTime($noTime)
{
$this->noTime = $noTime;
return $this;
}
/**
* @param int $sequence
*
* @return $this
*/
public function setSequence($sequence)
{
$this->sequence = $sequence;
return $this;
}
/**
* @return int
*/
public function getSequence()
{
return $this->sequence;
}
/**
* @param Organizer $organizer
*
* @return $this
*/
public function setOrganizer(Organizer $organizer)
{
$this->organizer = $organizer;
return $this;
}
/**
* @param $summary
*
* @return $this
*/
public function setSummary($summary)
{
$this->summary = $summary;
return $this;
}
/**
* @param $uniqueId
*
* @return $this
*/
public function setUniqueId($uniqueId)
{
$this->uniqueId = $uniqueId;
return $this;
}
/**
* @return string
*/
public function getUniqueId()
{
return $this->uniqueId;
}
/**
* @param $url
*
* @return $this
*/
public function setUrl($url)
{
$this->url = $url;
return $this;
}
/**
* @param $useTimezone
*
* @return $this
*/
public function setUseTimezone($useTimezone)
{
$this->useTimezone = $useTimezone;
return $this;
}
/**
* @return bool
*/
public function getUseTimezone()
{
return $this->useTimezone;
}
/**
* @param Attendees $attendees
*
* @return $this
*/
public function setAttendees(Attendees $attendees)
{
$this->attendees = $attendees;
return $this;
}
/**
* @param string $attendee
* @param array $params
*
* @return $this
*/
public function addAttendee($attendee, $params = array())
{
if (!isset($this->attendees)) {
$this->attendees = new Attendees();
}
$this->attendees->add($attendee, $params);
return $this;
}
/**
* @return Attendees
*/
public function getAttendees()
{
return $this->attendees;
}
/**
* @param $description
*
* @return $this
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* @param $descriptionHTML
*
* @return $this
*/
public function setDescriptionHTML($descriptionHTML)
{
$this->descriptionHTML = $descriptionHTML;
return $this;
}
/**
* @param bool $useUtc
*
* @return $this
*/
public function setUseUtc($useUtc = true)
{
$this->useUtc = $useUtc;
return $this;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* @return string
*/
public function getDescriptionHTML()
{
return $this->descriptionHTML;
}
/**
* @param $status
*
* @return $this
*/
public function setCancelled($status)
{
$this->cancelled = (bool)$status;
return $this;
}
/**
* @param $transparency
*
* @return $this
*
* @throws \InvalidArgumentException
*/
public function setTimeTransparency($transparency)
{
$transparency = strtoupper($transparency);
if ($transparency === self::TIME_TRANSPARENCY_OPAQUE
|| $transparency === self::TIME_TRANSPARENCY_TRANSPARENT
) {
$this->transparency = $transparency;
} else {
throw new \InvalidArgumentException('Invalid value for transparancy');
}
return $this;
}
/**
* @param $status
*
* @return $this
*
* @throws \InvalidArgumentException
*/
public function setStatus($status)
{
$status = strtoupper($status);
if ($status == self::STATUS_CANCELLED
|| $status == self::STATUS_CONFIRMED
|| $status == self::STATUS_TENTATIVE
) {
$this->status = $status;
} else {
throw new \InvalidArgumentException('Invalid value for status');
}
return $this;
}
/**
* @deprecated Deprecated since version 0.11.0, to be removed in 1.0. Use addRecurrenceRule instead.
*
* @param RecurrenceRule $recurrenceRule
*
* @return $this
*/
public function setRecurrenceRule(RecurrenceRule $recurrenceRule)
{
@trigger_error('setRecurrenceRule() is deprecated since version 0.11.0 and will be removed in 1.0. Use addRecurrenceRule instead.', E_USER_DEPRECATED);
$this->recurrenceRule = $recurrenceRule;
return $this;
}
/**
* @deprecated Deprecated since version 0.11.0, to be removed in 1.0. Use getRecurrenceRules instead.
*
* @return RecurrenceRule
*/
public function getRecurrenceRule()
{
@trigger_error('getRecurrenceRule() is deprecated since version 0.11.0 and will be removed in 1.0. Use getRecurrenceRules instead.', E_USER_DEPRECATED);
return $this->recurrenceRule;
}
/**
* @param RecurrenceRule $recurrenceRule
*
* @return $this
*/
public function addRecurrenceRule(RecurrenceRule $recurrenceRule)
{
$this->recurrenceRules[] = $recurrenceRule;
return $this;
}
/**
* @return array
*/
public function getRecurrenceRules()
{
return $this->recurrenceRules;
}
/**
* @param $dtStamp
*
* @return $this
*/
public function setCreated($dtStamp)
{
$this->created = $dtStamp;
return $this;
}
/**
* @param $dtStamp
*
* @return $this
*/
public function setModified($dtStamp)
{
$this->modified = $dtStamp;
return $this;
}
/**
* @param $categories
*
* @return $this
*/
public function setCategories($categories)
{
$this->categories = $categories;
return $this;
}
/**
* Sets the event privacy.
*
* @param bool $flag
*
* @return $this
*/
public function setIsPrivate($flag)
{
$this->isPrivate = (bool)$flag;
return $this;
}
/**
* @param \DateTime $dateTime
*
* @return \Eluceo\iCal\Component\Event
*/
public function addExDate(\DateTime $dateTime)
{
$this->exDates[] = $dateTime;
return $this;
}
/**
* @return \DateTime[]
*/
public function getExDates()
{
return $this->exDates;
}
/**
* @param \DateTime[]
*
* @return \Eluceo\iCal\Component\Event
*/
public function setExDates(array $exDates)
{
$this->exDates = $exDates;
return $this;
}
/**
* @return \Eluceo\iCal\Property\Event\RecurrenceId
*/
public function getRecurrenceId()
{
return $this->recurrenceId;
}
/**
* @param RecurrenceId $recurrenceId
*
* @return \Eluceo\iCal\Component\Event
*/
public function setRecurrenceId(RecurrenceId $recurrenceId)
{
$this->recurrenceId = $recurrenceId;
return $this;
}
}
src/Eluceo/iCal/Component/Timezone.php 0000666 00000002004 13436751250 0013672 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Component;
use Eluceo\iCal\Component;
use Eluceo\iCal\PropertyBag;
/**
* Implementation of the TIMEZONE component.
*/
class Timezone extends Component
{
/**
* @var string
*/
protected $timezone;
public function __construct($timezone)
{
$this->timezone = $timezone;
}
/**
* {@inheritdoc}
*/
public function getType()
{
return 'VTIMEZONE';
}
/**
* {@inheritdoc}
*/
public function buildPropertyBag()
{
$propertyBag = new PropertyBag();
$propertyBag->set('TZID', $this->timezone);
$propertyBag->set('X-LIC-LOCATION', $this->timezone);
return $propertyBag;
}
public function getZoneIdentifier()
{
return $this->timezone;
}
}
src/Eluceo/iCal/Component/TimezoneRule.php 0000666 00000010021 13436751250 0014520 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Component;
use Eluceo\iCal\Component;
use Eluceo\iCal\PropertyBag;
use Eluceo\iCal\Property\Event\RecurrenceRule;
/**
* Implementation of Standard Time and Daylight Saving Time observances (or rules)
* which define the TIMEZONE component.
*/
class TimezoneRule extends Component
{
const TYPE_DAYLIGHT = 'DAYLIGHT';
const TYPE_STANDARD = 'STANDARD';
/**
* @var string
*/
protected $type;
/**
* @var string
*/
protected $tzOffsetFrom;
/**
* @var string
*/
protected $tzOffsetTo;
/**
* @var string
*/
protected $tzName;
/**
* @var \DateTime
*/
protected $dtStart;
/**
* @var RecurrenceRule
*/
protected $recurrenceRule;
/**
* create new Timezone Rule object by giving a rule type identifier.
*
* @param string $ruleType one of DAYLIGHT or STANDARD
*
* @throws \InvalidArgumentException
*/
public function __construct($ruleType)
{
$ruleType = strtoupper($ruleType);
if ($ruleType === self::TYPE_DAYLIGHT || $ruleType === self::TYPE_STANDARD) {
$this->type = $ruleType;
} else {
throw new \InvalidArgumentException('Invalid value for timezone rule type');
}
}
/**
* {@inheritdoc}
*/
public function buildPropertyBag()
{
$propertyBag = new PropertyBag();
if ($this->getTzName()) {
$propertyBag->set('TZNAME', $this->getTzName());
}
if ($this->getTzOffsetFrom()) {
$propertyBag->set('TZOFFSETFROM', $this->getTzOffsetFrom());
}
if ($this->getTzOffsetTo()) {
$propertyBag->set('TZOFFSETTO', $this->getTzOffsetTo());
}
if ($this->getDtStart()) {
$propertyBag->set('DTSTART', $this->getDtStart());
}
if ($this->recurrenceRule) {
$propertyBag->set('RRULE', $this->recurrenceRule);
}
return $propertyBag;
}
/**
* @param $offset
*
* @return $this
*/
public function setTzOffsetFrom($offset)
{
$this->tzOffsetFrom = $offset;
return $this;
}
/**
* @param $offset
*
* @return $this
*/
public function setTzOffsetTo($offset)
{
$this->tzOffsetTo = $offset;
return $this;
}
/**
* @param $name
*
* @return $this
*/
public function setTzName($name)
{
$this->tzName = $name;
return $this;
}
/**
* @param \DateTime $dtStart
*
* @return $this
*/
public function setDtStart(\DateTime $dtStart)
{
$this->dtStart = $dtStart;
return $this;
}
/**
* @param RecurrenceRule $recurrenceRule
*
* @return $this
*/
public function setRecurrenceRule(RecurrenceRule $recurrenceRule)
{
$this->recurrenceRule = $recurrenceRule;
return $this;
}
/**
* {@inheritdoc}
*/
public function getType()
{
return $this->type;
}
/**
* @return string
*/
public function getTzOffsetFrom()
{
return $this->tzOffsetFrom;
}
/**
* @return string
*/
public function getTzOffsetTo()
{
return $this->tzOffsetTo;
}
/**
* @return string
*/
public function getTzName()
{
return $this->tzName;
}
/**
* @return RecurrenceRule
*/
public function getRecurrenceRule()
{
return $this->recurrenceRule;
}
/**
* @return mixed return string representation of start date or NULL if no date was given
*/
public function getDtStart()
{
if ($this->dtStart) {
return $this->dtStart->format('Ymd\THis');
}
return;
}
}
src/Eluceo/iCal/Property.php 0000666 00000005675 13436751250 0012003 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal;
use Eluceo\iCal\Property\ArrayValue;
use Eluceo\iCal\Property\StringValue;
use Eluceo\iCal\Property\ValueInterface;
/**
* The Property Class represents a property as defined in RFC 2445.
*
* The content of a line (unfolded) will be rendered in this class
*/
class Property
{
/**
* The value of the Property.
*
* @var ValueInterface
*/
protected $value;
/**
* The params of the Property.
*
* @var ParameterBag
*/
protected $parameterBag;
/**
* @var string
*/
protected $name;
/**
* @param $name
* @param $value
* @param array $params
*/
public function __construct($name, $value, $params = array())
{
$this->name = $name;
$this->setValue($value);
$this->parameterBag = new ParameterBag($params);
}
/**
* Renders an unfolded line.
*
* @return string
*/
public function toLine()
{
// Property-name
$line = $this->getName();
// Adding params
//@todo added check for $this->parameterBag because doctrine/orm proxies won't execute constructor - ok?
if ($this->parameterBag && $this->parameterBag->hasParams()) {
$line .= ';' . $this->parameterBag->toString();
}
// Property value
$line .= ':' . $this->value->getEscapedValue();
return $line;
}
/**
* Get all unfolded lines.
*
* @return array
*/
public function toLines()
{
return array($this->toLine());
}
/**
* @param string $name
* @param mixed $value
*
* @return $this
*/
public function setParam($name, $value)
{
$this->parameterBag->setParam($name, $value);
return $this;
}
/**
* @param $name
*/
public function getParam($name)
{
return $this->parameterBag->getParam($name);
}
/**
* @param mixed $value
*
* @return $this
*
* @throws \Exception
*/
public function setValue($value)
{
if (is_scalar($value)) {
$this->value = new StringValue($value);
} elseif (is_array($value)) {
$this->value = new ArrayValue($value);
} else {
if (!$value instanceof ValueInterface) {
throw new \Exception('The value must implement the ValueInterface.');
} else {
$this->value = $value;
}
}
return $this;
}
/**
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
}
src/Eluceo/iCal/Component.php 0000666 00000007577 13436751250 0012124 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal;
use Eluceo\iCal\Util\ComponentUtil;
/**
* Abstract Calender Component.
*/
abstract class Component
{
/**
* Array of Components.
*
* @var Component[]
*/
protected $components = array();
/**
* The order in which the components will be rendered during build.
*
* Not defined components will be appended at the end.
*
* @var array
*/
private $componentsBuildOrder = array('VTIMEZONE', 'DAYLIGHT', 'STANDARD');
/**
* The type of the concrete Component.
*
* @abstract
*
* @return string
*/
abstract public function getType();
/**
* Building the PropertyBag.
*
* @abstract
*
* @return PropertyBag
*/
abstract public function buildPropertyBag();
/**
* Adds a Component.
*
* If $key is given, the component at $key will be replaced else the component will be append.
*
* @param Component $component The Component that will be added
* @param null $key The key of the Component
*/
public function addComponent(Component $component, $key = null)
{
if (null == $key) {
$this->components[] = $component;
} else {
$this->components[$key] = $component;
}
}
/**
* Renders an array containing the lines of the iCal file.
*
* @return array
*/
public function build()
{
$lines = array();
$lines[] = sprintf('BEGIN:%s', $this->getType());
/** @var $property Property */
foreach ($this->buildPropertyBag() as $property) {
foreach ($property->toLines() as $l) {
$lines[] = $l;
}
}
$this->buildComponents($lines);
$lines[] = sprintf('END:%s', $this->getType());
$ret = array();
foreach ($lines as $line) {
foreach (ComponentUtil::fold($line) as $l) {
$ret[] = $l;
}
}
return $ret;
}
/**
* Renders the output.
*
* @return string
*/
public function render()
{
return implode("\r\n", $this->build());
}
/**
* Renders the output when treating the class as a string.
*
* @return string
*/
public function __toString()
{
return $this->render();
}
/**
* @param $lines
*
* @return array
*/
private function buildComponents(array &$lines)
{
$componentsByType = array();
/** @var $component Component */
foreach ($this->components as $component) {
$type = $component->getType();
if (!isset($componentsByType[$type])) {
$componentsByType[$type] = array();
}
$componentsByType[$type][] = $component;
}
// render ordered components
foreach ($this->componentsBuildOrder as $type) {
if (!isset($componentsByType[$type])) {
continue;
}
foreach ($componentsByType[$type] as $component) {
$this->addComponentLines($lines, $component);
}
unset($componentsByType[$type]);
}
// render all other
foreach ($componentsByType as $components) {
foreach ($components as $component) {
$this->addComponentLines($lines, $component);
}
}
}
/**
* @param array $lines
* @param Component $component
*/
private function addComponentLines(array &$lines, Component $component)
{
foreach ($component->build() as $l) {
$lines[] = $l;
}
}
}
src/Eluceo/iCal/Property/ValueInterface.php 0000666 00000001015 13436751250 0014660 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Property;
interface ValueInterface
{
/**
* Return the value of the Property as an escaped string.
*
* Escape values as per RFC 2445. See http://www.kanzaki.com/docs/ical/text.html
*
* @return string
*/
public function getEscapedValue();
}
src/Eluceo/iCal/Property/StringValue.php 0000666 00000002140 13436751250 0014226 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Property;
use Eluceo\iCal\Util\PropertyValueUtil;
class StringValue implements ValueInterface
{
/**
* The value.
*
* @var string
*/
protected $value;
public function __construct($value)
{
$this->value = $value;
}
/**
* Return the value of the Property as an escaped string.
*
* Escape values as per RFC 2445. See http://www.kanzaki.com/docs/ical/text.html
*
* @return string
*/
public function getEscapedValue()
{
return PropertyValueUtil::escapeValue((string) $this->value);
}
/**
* @param string $value
*
* @return $this
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* @return string
*/
public function getValue()
{
return $this->value;
}
}
src/Eluceo/iCal/Property/DateTimesProperty.php 0000666 00000002005 13436751250 0015407 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Property;
use Eluceo\iCal\Property;
use Eluceo\iCal\Util\DateUtil;
class DateTimesProperty extends Property
{
/**
* @param string $name
* @param \DateTime[] $dateTimes
* @param bool $noTime
* @param bool $useTimezone
* @param bool $useUtc
*/
public function __construct(
$name,
$dateTimes = array(),
$noTime = false,
$useTimezone = false,
$useUtc = false
) {
$dates = array();
foreach ($dateTimes as $dateTime) {
$dates[] = DateUtil::getDateString($dateTime, $noTime, $useTimezone, $useUtc);
}
$params = DateUtil::getDefaultParams($dateTime, $noTime, $useTimezone);
parent::__construct($name, $dates, $params);
}
}
src/Eluceo/iCal/Property/Event/Description.php 0000666 00000002343 13436751250 0015334 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Property\Event;
use Eluceo\iCal\Property\ValueInterface;
use Eluceo\iCal\Util\PropertyValueUtil;
/**
* Class Description
* Alows new line charectars to be in the description.
*/
class Description implements ValueInterface
{
/**
* The value.
*
* @var string
*/
protected $value;
public function __construct($value)
{
$this->value = $value;
}
/**
* Return the value of the Property as an escaped string.
*
* Escape values as per RFC 2445. See http://www.kanzaki.com/docs/ical/text.html
*
* @return string
*/
public function getEscapedValue()
{
return PropertyValueUtil::escapeValue((string) $this->value);
}
/**
* @param string $value
*
* @return $this
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* @return string
*/
public function getValue()
{
return $this->value;
}
}
src/Eluceo/iCal/Property/Event/Organizer.php 0000666 00000001323 13436751250 0015006 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Property\Event;
use Eluceo\iCal\Property;
/**
* Class Organizer.
*/
class Organizer extends Property
{
const PROPERTY_NAME = 'ORGANIZER';
/**
* @param string $value
* @param array $params
*/
public function __construct($value, $params = array())
{
parent::__construct(self::PROPERTY_NAME, $value, $params);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return self::PROPERTY_NAME;
}
}
src/Eluceo/iCal/Property/Event/RecurrenceId.php 0000666 00000005751 13436751250 0015431 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Property\Event;
use Eluceo\iCal\ParameterBag;
use Eluceo\iCal\Property;
use Eluceo\iCal\Util\DateUtil;
use Eluceo\iCal\Property\ValueInterface;
/**
* Implementation of Recurrence Id.
*
* @see http://www.ietf.org/rfc/rfc2445.txt 4.8.4.4 Recurrence ID
*/
class RecurrenceId extends Property
{
const PROPERTY_NAME = 'RECURRENCE-ID';
/**
* The effective range of recurrence instances from the instance
* specified by the recurrence identifier specified by the property.
*/
const RANGE_THISANDPRIOR = 'THISANDPRIOR';
const RANGE_THISANDFUTURE = 'THISANDFUTURE';
/**
* The dateTime to identify a particular instance of a recurring event which is getting modified.
*
* @var \DateTime
*/
protected $dateTime;
/**
* Specify the effective range of recurrence instances from the instance.
*
* @var string
*/
protected $range;
public function __construct(\DateTime $dateTime = null)
{
$this->parameterBag = new ParameterBag();
if (isset($dateTime)) {
$this->dateTime = $dateTime;
}
}
public function applyTimeSettings($noTime = false, $useTimezone = false, $useUtc = false)
{
$params = DateUtil::getDefaultParams($this->dateTime, $noTime, $useTimezone, $useUtc);
foreach ($params as $name => $value) {
$this->parameterBag->setParam($name, $value);
}
if ($this->range) {
$this->parameterBag->setParam('RANGE', $this->range);
}
$this->setValue(DateUtil::getDateString($this->dateTime, $noTime, $useTimezone, $useUtc));
}
/**
* @return DateTime
*/
public function getDatetime()
{
return $this->dateTime;
}
/**
* @param \DateTime $dateTime
*
* @return \Eluceo\iCal\Property\Event\RecurrenceId
*/
public function setDatetime(\DateTime $dateTime)
{
$this->dateTime = $dateTime;
return $this;
}
/**
* @return string
*/
public function getRange()
{
return $this->range;
}
/**
* @param string $range
*
* @return \Eluceo\iCal\Property\Event\RecurrenceId
*/
public function setRange($range)
{
$this->range = $range;
}
/**
* Get all unfolded lines.
*
* @return array
*/
public function toLines()
{
if (!$this->value instanceof ValueInterface) {
throw new \Exception('The value must implement the ValueInterface. Call RecurrenceId::applyTimeSettings() before adding RecurrenceId.');
} else {
return parent::toLines();
}
}
/**
* {@inheritdoc}
*/
public function getName()
{
return self::PROPERTY_NAME;
}
}
src/Eluceo/iCal/Property/Event/Attendees.php 0000666 00000003614 13436751250 0014767 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Property\Event;
use Eluceo\iCal\Property;
class Attendees extends Property
{
/** @var Property[] */
protected $attendees = array();
const PROPERTY_NAME = 'ATTENDEES';
public function __construct()
{
// Overwrites constructor functionality of Property
}
/**
* @param $value
* @param array $params
*
* @return $this
*/
public function add($value, $params = array())
{
$this->attendees[] = new Property('ATTENDEE', $value, $params);
return $this;
}
/**
* @param Property[] $value
*
* @return $this
*/
public function setValue($value)
{
$this->attendees = $value;
return $this;
}
/**
* @return Property[]
*/
public function getValue()
{
return $this->attendees;
}
/**
* {@inheritdoc}
*/
public function toLines()
{
$lines = array();
foreach ($this->attendees as $attendee) {
$lines[] = $attendee->toLine();
}
return $lines;
}
/**
* @param string $name
* @param mixed $value
*
* @throws \BadMethodCallException
*/
public function setParam($name, $value)
{
throw new \BadMethodCallException('Cannot call setParam on Attendees Property');
}
/**
* @param $name
*
* @throws \BadMethodCallException
*/
public function getParam($name)
{
throw new \BadMethodCallException('Cannot call getParam on Attendees Property');
}
/**
* {@inheritdoc}
*/
public function getName()
{
return self::PROPERTY_NAME;
}
}
src/Eluceo/iCal/Property/Event/RecurrenceRule.php 0000666 00000023652 13436751250 0016004 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Property\Event;
use Eluceo\iCal\Property\ValueInterface;
use Eluceo\iCal\ParameterBag;
use InvalidArgumentException;
/**
* Implementation of Recurrence Rule.
*
* @see http://www.ietf.org/rfc/rfc2445.txt 3.3.10. Recurrence Rule
*/
class RecurrenceRule implements ValueInterface
{
const FREQ_YEARLY = 'YEARLY';
const FREQ_MONTHLY = 'MONTHLY';
const FREQ_WEEKLY = 'WEEKLY';
const FREQ_DAILY = 'DAILY';
const FREQ_HOURLY = 'HOURLY';
const FREQ_MINUTELY = 'MINUTELY';
const FREQ_SECONDLY = 'SECONDLY';
const WEEKDAY_SUNDAY = 'SU';
const WEEKDAY_MONDAY = 'MO';
const WEEKDAY_TUESDAY = 'TU';
const WEEKDAY_WEDNESDAY = 'WE';
const WEEKDAY_THURSDAY = 'TH';
const WEEKDAY_FRIDAY = 'FR';
const WEEKDAY_SATURDAY = 'SA';
/**
* The frequency of an Event.
*
* @var string
*/
protected $freq = self::FREQ_YEARLY;
/**
* @var null|int
*/
protected $interval = 1;
/**
* @var null|int
*/
protected $count = null;
/**
* @var null|\DateTime
*/
protected $until = null;
/**
* @var null|string
*/
protected $wkst;
/**
* @var null|string
*/
protected $byMonth;
/**
* @var null|string
*/
protected $byWeekNo;
/**
* @var null|string
*/
protected $byYearDay;
/**
* @var null|string
*/
protected $byMonthDay;
/**
* @var null|string
*/
protected $byDay;
/**
* @var null|string
*/
protected $byHour;
/**
* @var null|string
*/
protected $byMinute;
/**
* @var null|string
*/
protected $bySecond;
/**
* Return the value of the Property as an escaped string.
*
* Escape values as per RFC 2445. See http://www.kanzaki.com/docs/ical/text.html
*
* @return string
*/
public function getEscapedValue()
{
return $this->buildParameterBag()->toString();
}
/**
* @return ParameterBag
*/
protected function buildParameterBag()
{
$parameterBag = new ParameterBag();
$parameterBag->setParam('FREQ', $this->freq);
if (null !== $this->interval) {
$parameterBag->setParam('INTERVAL', $this->interval);
}
if (null !== $this->count) {
$parameterBag->setParam('COUNT', $this->count);
}
if (null != $this->until) {
$parameterBag->setParam('UNTIL', $this->until->format('Ymd\THis\Z'));
}
if (null !== $this->wkst) {
$parameterBag->setParam('WKST', $this->wkst);
}
if (null !== $this->byMonth) {
$parameterBag->setParam('BYMONTH', $this->byMonth);
}
if (null !== $this->byWeekNo) {
$parameterBag->setParam('BYWEEKNO', $this->byWeekNo);
}
if (null !== $this->byYearDay) {
$parameterBag->setParam('BYYEARDAY', $this->byYearDay);
}
if (null !== $this->byMonthDay) {
$parameterBag->setParam('BYMONTHDAY', $this->byMonthDay);
}
if (null !== $this->byDay) {
$parameterBag->setParam('BYDAY', $this->byDay);
}
if (null !== $this->byHour) {
$parameterBag->setParam('BYHOUR', $this->byHour);
}
if (null !== $this->byMinute) {
$parameterBag->setParam('BYMINUTE', $this->byMinute);
}
if (null !== $this->bySecond) {
$parameterBag->setParam('BYSECOND', $this->bySecond);
}
return $parameterBag;
}
/**
* @param int|null $count
*
* @return $this
*/
public function setCount($count)
{
$this->count = $count;
return $this;
}
/**
* @return int|null
*/
public function getCount()
{
return $this->count;
}
/**
* @param \DateTime|null $until
*
* @return $this
*/
public function setUntil(\DateTime $until = null)
{
$this->until = $until;
return $this;
}
/**
* @return \DateTime|null
*/
public function getUntil()
{
return $this->until;
}
/**
* The FREQ rule part identifies the type of recurrence rule. This
* rule part MUST be specified in the recurrence rule. Valid values
* include.
*
* SECONDLY, to specify repeating events based on an interval of a second or more;
* MINUTELY, to specify repeating events based on an interval of a minute or more;
* HOURLY, to specify repeating events based on an interval of an hour or more;
* DAILY, to specify repeating events based on an interval of a day or more;
* WEEKLY, to specify repeating events based on an interval of a week or more;
* MONTHLY, to specify repeating events based on an interval of a month or more;
* YEARLY, to specify repeating events based on an interval of a year or more.
*
* @param string $freq
*
* @return $this
*
* @throws \InvalidArgumentException
*/
public function setFreq($freq)
{
if (@constant('static::FREQ_' . $freq) !== null) {
$this->freq = $freq;
} else {
throw new \InvalidArgumentException("The Frequency {$freq} is not supported.");
}
return $this;
}
/**
* @return string
*/
public function getFreq()
{
return $this->freq;
}
/**
* The INTERVAL rule part contains a positive integer representing at
* which intervals the recurrence rule repeats.
*
* @param int|null $interval
*
* @return $this
*/
public function setInterval($interval)
{
$this->interval = $interval;
return $this;
}
/**
* @return int|null
*/
public function getInterval()
{
return $this->interval;
}
/**
* The WKST rule part specifies the day on which the workweek starts.
* Valid values are MO, TU, WE, TH, FR, SA, and SU.
*
* @param string $value
*
* @return $this
*/
public function setWkst($value)
{
$this->wkst = $value;
return $this;
}
/**
* The BYMONTH rule part specifies a COMMA-separated list of months of the year.
* Valid values are 1 to 12.
*
* @param int $month
*
* @throws InvalidArgumentException
*
* @return $this
*/
public function setByMonth($month)
{
if (!is_integer($month) || $month < 0 || $month > 12) {
throw new InvalidArgumentException('Invalid value for BYMONTH');
}
$this->byMonth = $month;
return $this;
}
/**
* The BYWEEKNO rule part specifies a COMMA-separated list of ordinals specifying weeks of the year.
* Valid values are 1 to 53 or -53 to -1.
*
* @param int $value
*
* @return $this
*/
public function setByWeekNo($value)
{
$this->byWeekNo = $value;
return $this;
}
/**
* The BYYEARDAY rule part specifies a COMMA-separated list of days of the year.
* Valid values are 1 to 366 or -366 to -1.
*
* @param int $day
*
* @return $this
*/
public function setByYearDay($day)
{
$this->byYearDay = $day;
return $this;
}
/**
* The BYMONTHDAY rule part specifies a COMMA-separated list of days of the month.
* Valid values are 1 to 31 or -31 to -1.
*
* @param int $day
*
* @return $this
*/
public function setByMonthDay($day)
{
$this->byMonthDay = $day;
return $this;
}
/**
* The BYDAY rule part specifies a COMMA-separated list of days of the week;.
*
* SU indicates Sunday; MO indicates Monday; TU indicates Tuesday;
* WE indicates Wednesday; TH indicates Thursday; FR indicates Friday; and SA indicates Saturday.
*
* Each BYDAY value can also be preceded by a positive (+n) or negative (-n) integer.
* If present, this indicates the nth occurrence of a specific day within the MONTHLY or YEARLY "RRULE".
*
* @param string $day
*
* @return $this
*/
public function setByDay($day)
{
$this->byDay = $day;
return $this;
}
/**
* The BYHOUR rule part specifies a COMMA-separated list of hours of the day.
* Valid values are 0 to 23.
*
* @param int $value
*
* @return $this
*
* @throws \InvalidArgumentException
*/
public function setByHour($value)
{
if (!is_integer($value) || $value < 0 || $value > 23) {
throw new \InvalidArgumentException('Invalid value for BYHOUR');
}
$this->byHour = $value;
return $this;
}
/**
* The BYMINUTE rule part specifies a COMMA-separated list of minutes within an hour.
* Valid values are 0 to 59.
*
* @param int $value
*
* @return $this
*
* @throws \InvalidArgumentException
*/
public function setByMinute($value)
{
if (!is_integer($value) || $value < 0 || $value > 59) {
throw new \InvalidArgumentException('Invalid value for BYMINUTE');
}
$this->byMinute = $value;
return $this;
}
/**
* The BYSECOND rule part specifies a COMMA-separated list of seconds within a minute.
* Valid values are 0 to 60.
*
* @param int $value
*
* @return $this
*
* @throws \InvalidArgumentException
*/
public function setBySecond($value)
{
if (!is_integer($value) || $value < 0 || $value > 60) {
throw new \InvalidArgumentException('Invalid value for BYSECOND');
}
$this->bySecond = $value;
return $this;
}
}
src/Eluceo/iCal/Property/ArrayValue.php 0000666 00000001510 13436751250 0014036 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Property;
use Eluceo\iCal\Util\PropertyValueUtil;
class ArrayValue implements ValueInterface
{
/**
* The value.
*
* @var array
*/
protected $values;
public function __construct(array $values)
{
$this->values = $values;
}
public function setValues(array $values)
{
$this->values = $values;
return $this;
}
public function getEscapedValue()
{
return implode(',', array_map(function ($value) {
return PropertyValueUtil::escapeValue((string) $value);
}, $this->values));
}
}
src/Eluceo/iCal/Property/DateTimeProperty.php 0000666 00000001667 13436751250 0015241 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal\Property;
use Eluceo\iCal\Property;
use Eluceo\iCal\Util\DateUtil;
class DateTimeProperty extends Property
{
/**
* @param string $name
* @param \DateTime $dateTime
* @param bool $noTime
* @param bool $useTimezone
* @param bool $useUtc
*/
public function __construct(
$name,
\DateTime $dateTime = null,
$noTime = false,
$useTimezone = false,
$useUtc = false
) {
$dateString = DateUtil::getDateString($dateTime, $noTime, $useTimezone, $useUtc);
$params = DateUtil::getDefaultParams($dateTime, $noTime, $useTimezone);
parent::__construct($name, $dateString, $params);
}
}
src/Eluceo/iCal/ParameterBag.php 0000666 00000004271 13436751250 0012500 0 ustar 00
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Eluceo\iCal;
class ParameterBag
{
/**
* The params.
*
* @var array
*/
protected $params;
public function __construct($params = array())
{
$this->params = $params;
}
/**
* @param string $name
* @param mixed $value
*/
public function setParam($name, $value)
{
$this->params[$name] = $value;
}
/**
* @param $name
*/
public function getParam($name)
{
if (array_key_exists($name, $this->params)) {
return $this->params[$name];
}
}
/**
* Checks if there are any params.
*
* @return bool
*/
public function hasParams()
{
return count($this->params) > 0;
}
/**
* @return string
*/
public function toString()
{
$line = '';
foreach ($this->params as $param => $paramValues) {
if (!is_array($paramValues)) {
$paramValues = array($paramValues);
}
foreach ($paramValues as $k => $v) {
$paramValues[$k] = $this->escapeParamValue($v);
}
if ('' != $line) {
$line .= ';';
}
$line .= $param . '=' . implode(',', $paramValues);
}
return $line;
}
/**
* Returns an escaped string for a param value.
*
* @param string $value
*
* @return string
*/
public function escapeParamValue($value)
{
$count = 0;
$value = str_replace('\\', '\\\\', $value);
$value = str_replace('"', '\"', $value, $count);
$value = str_replace("\n", '\\n', $value);
if (false !== strpos($value, ';') || false !== strpos($value, ',') || false !== strpos($value, ':') || $count) {
$value = '"' . $value . '"';
}
return $value;
}
/**
* @return string
*/
public function __toString()
{
return $this->toString();
}
}
composer.json 0000666 00000002231 13436751250 0007276 0 ustar 00 {
"name": "eluceo/ical",
"description": "The eluceo/iCal package offers a abstraction layer for creating iCalendars. You can easily create iCal files by using PHP object instead of typing your *.ics file by hand. The output will follow RFC 2445 as best as possible.",
"license": "MIT",
"homepage": "https://github.com/markuspoerschke/iCal",
"authors": [
{
"name": "Markus Poerschke",
"email": "markus@eluceo.de",
"role": "Developer"
},
{
"name": "Maciej Łebkowski",
"email": "m.lebkowski@gmail.com",
"role": "Contributor"
}
],
"keywords": [
"ical",
"php calendar",
"icalendar",
"ics",
"calendar"
],
"support": {
"issues": "https://github.com/markuspoerschke/iCal/issues",
"source": "https://github.com/markuspoerschke/iCal"
},
"autoload": {
"psr-0": {
"Eluceo\\iCal": "src/"
}
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "~4.3"
},
"config": {
"bin-dir": "bin"
}
}
.travis.yml 0000666 00000000510 13436751250 0006663 0 ustar 00 language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
before_script:
- composer self-update
- composer install
script: ./bin/phpunit --coverage-clover=coverage.clover
after_script:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover coverage.clover
phpunit.xml.dist 0000666 00000001330 13436751250 0007726 0 ustar 00
./tests/Eluceo/iCal/
.php_cs 0000666 00000001142 13436751250 0006031 0 ustar 00
This source file is subject to the MIT license that is bundled
with this source code in the file LICENSE.
EOF
);
$finder = Symfony\CS\Finder\DefaultFinder::create();
$finder->in(__DIR__ . '/src');
return Symfony\CS\Config\Config::create()
->fixers(array(
'header_comment',
'concat_with_spaces',
'align_equals',
'align_double_arrow',
'unused_use',
'long_array_syntax',
))
->finder($finder)
;
CHANGELOG.md 0000666 00000005456 13436751250 0006401 0 ustar 00 # Change Log
All notable changes to this project will be documented in this file.
## [0.11.2] - 2017-04-21
### Fixed
- Do not escape value of the GEO property [#79](https://github.com/markuspoerschke/iCal/pull/79)
## [0.11.1] - 2017-04-04
### Fixed
- All days events (no time) ends on the next day. [#83](https://github.com/markuspoerschke/iCal/pull/83)
- Timezone will not applied on all days events [#83](https://github.com/markuspoerschke/iCal/pull/83)
### Added
- Add `Event::getDtStart` method [#83](https://github.com/markuspoerschke/iCal/pull/83)
## [0.11.0] - 2016-09-16
### Added
- Allow multiple recurrence rules in an event [#77](https://github.com/markuspoerschke/iCal/pull/77)
- RecurrenceRule now also allows hourly, minutely and secondly frequencies [#78](https://github.com/markuspoerschke/iCal/pull/78)
### Deprecated
- Adding a single recurrence rule to an event using `Event::setRecurrenceRule()` is deprecated and will be removed in 1.0. Use `Event::addRecurrenceRule()` instead. [#77](https://github.com/markuspoerschke/iCal/pull/77)
## [0.10.1] - 2016-05-09
### Fixed
- Problem with GEO property when importing into Google Calendar [#74](https://github.com/markuspoerschke/iCal/pull/74)
## [0.10.0] - 2016-04-26
### Changed
- Use 'escapeValue' to escape the new line character. [#60](https://github.com/markuspoerschke/iCal/pull/60)
- Order components by type when building ical file. [#65](https://github.com/markuspoerschke/iCal/pull/65)
### Added
- X-ALT-DESC for HTML types with new descriptionHTML field. [#55](https://github.com/markuspoerschke/iCal/pull/55)
- Added a property and setter for calendar color. [#68](https://github.com/markuspoerschke/iCal/pull/68)
- Write also GEO property if geo location is given. [#66](https://github.com/markuspoerschke/iCal/pull/66)
## [0.9.0] - 2015-11-13
### Added
- CHANGELOG.md based on [’Keep a CHANGELOG’](https://github.com/olivierlacan/keep-a-changelog)
- Support event properties EXDATE and RECURRENCE-ID [#50](https://github.com/markuspoerschke/iCal/pull/53)
### Changed
- Allow new lines in event descriptions [#53](https://github.com/markuspoerschke/iCal/pull/53)
- **Breaking Change:** Changed signature of the ```Event::setOrganizer``` method. Now there is is only one parameter that must be an instance of ```Property\Organizer```.
- Updated install section in README.md [#54](https://github.com/markuspoerschke/iCal/pull/53)
[0.11.2]: https://github.com/markuspoerschke/iCal/compare/0.11.1...0.11.2
[0.11.1]: https://github.com/markuspoerschke/iCal/compare/0.11.0...0.11.1
[0.11.0]: https://github.com/markuspoerschke/iCal/compare/0.10.1...0.11.0
[0.10.1]: https://github.com/markuspoerschke/iCal/compare/0.10.0...0.10.1
[0.10.0]: https://github.com/markuspoerschke/iCal/compare/0.9.0...0.10.0
[0.9.0]: https://github.com/markuspoerschke/iCal/compare/0.8.0...0.9.0
tests/Eluceo/iCal/PropertyBagTest.php 0000666 00000000753 13436751250 0013620 0 ustar 00 setExpectedException('\\Exception', "Property with name 'propName' already exists");
$propertyBag = new PropertyBag();
$propertyBag->add(new Property('propName', ''));
$propertyBag->add(new Property('propName', ''));
}
}
tests/Eluceo/iCal/Component/CalendarIntegrationTest.php 0000666 00000003774 13436751250 0017247 0 ustar 00 setDtStart(new \DateTime('2012-12-31', $timeZone));
$vEvent->setDtEnd(new \DateTime('2012-12-31', $timeZone));
$vEvent->setNoTime(true);
$vEvent->setIsPrivate(true);
$vEvent->setSummary('New Year’s Eve');
// Set recurrence rule
$recurrenceRule = new \Eluceo\iCal\Property\Event\RecurrenceRule();
$recurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_YEARLY);
$recurrenceRule->setInterval(1);
$vEvent->addRecurrenceRule($recurrenceRule);
// Adding Timezone (optional)
$vEvent->setUseTimezone(true);
// 3. Add event to calendar
$vCalendar->addComponent($vEvent);
$lines = array(
'/BEGIN:VCALENDAR/',
'/VERSION:2\.0/',
'/PRODID:www\.example\.com/',
'/X-PUBLISHED-TTL:P1W/',
'/BEGIN:VEVENT/',
'/UID:123456/',
'/DTSTART;VALUE=DATE:20121231/',
'/SEQUENCE:0/',
'/TRANSP:OPAQUE/',
'/DTEND;VALUE=DATE:20130101/',
'/SUMMARY:New Year’s Eve/',
'/CLASS:PRIVATE/',
'/RRULE:FREQ=YEARLY;INTERVAL=1/',
'/X-MICROSOFT-CDO-ALLDAYEVENT:TRUE/',
'/DTSTAMP:20\d{6}T\d{6}Z/',
'/END:VEVENT/',
'/END:VCALENDAR/',
);
foreach (explode("\n", $vCalendar->render()) as $key => $line)
{
$this->assertTrue(isset($lines[$key]), 'Too many lines... ' . $line);
$this->assertRegExp($lines[$key], $line);
}
}
}
tests/Eluceo/iCal/Property/ArrayValueTest.php 0000666 00000001223 13436751250 0015252 0 ustar 00 assertEquals($expectedOutput, $arrayValue->getEscapedValue());
}
public function arrayValuesProvider()
{
return array(
array(array(), ''),
array(array('Lorem'), 'Lorem'),
array(array('Lorem', 'Ipsum'), 'Lorem,Ipsum'),
array(array('Lorem', '"doublequotes"'), 'Lorem,\"doublequotes\"'),
);
}
}
tests/Eluceo/iCal/Property/Event/OrganizerTest.php 0000666 00000003400 13436751250 0016217 0 ustar 00
*/
namespace Eluceo\iCal\Property\Event;
/**
* OrganizerTest
*/
class OrganizerTest extends \PHPUnit_Framework_TestCase
{
public function testOrganizerValueOnly()
{
$value = "MAILTO:name.lastname@example.com";
$expected = "ORGANIZER:$value";
$vCalendar = $this->createCalendarWithOrganizer(
new \Eluceo\iCal\Property\Event\Organizer($value)
);
foreach (explode("\n", $vCalendar->render()) as $line)
{
if (preg_match('/^ORGANIZER[:;](.*)$/', $line)) {
$this->assertEquals($expected, trim($line));
}
}
}
public function testOrganizerValueAndParameter()
{
$value = "MAILTO:name.lastname@example.com";
$param = "Name LastName";
$expected = "ORGANIZER;CN=$param:$value";
$vCalendar = $this->createCalendarWithOrganizer(
new \Eluceo\iCal\Property\Event\Organizer($value, array('CN' => $param))
);
foreach (explode("\n", $vCalendar->render()) as $line)
{
if (preg_match('/^ORGANIZER[:;](.*)$/', $line)) {
$this->assertEquals($expected, trim($line));
}
}
}
/**
* @param Organizer $vOrganizer
* @return \Eluceo\iCal\Component\Calendar
*/
private function createCalendarWithOrganizer(\Eluceo\iCal\Property\Event\Organizer $vOrganizer)
{
$vCalendar = new \Eluceo\iCal\Component\Calendar('www.example.com');
$vEvent = new \Eluceo\iCal\Component\Event('123456');
$vEvent->setOrganizer($vOrganizer);
$vCalendar->addComponent($vEvent);
return $vCalendar;
}
}
tests/Eluceo/iCal/Property/Event/DescriptionTest.php 0000666 00000000616 13436751250 0016550 0 ustar 00 assertEquals(
str_replace("\n", "\\n", $testString),
$description->getEscapedValue()
);
}
}
tests/Eluceo/iCal/Property/Event/RecurrenceRuleTest.php 0000666 00000001041 13436751250 0017203 0 ustar 00 setFreq(RecurrenceRule::FREQ_DAILY);
$rule->setInterval(null);
$rule->setUntil(new \DateTime('1997-12-24'));
$this->assertEquals(
'FREQ=DAILY;UNTIL=19971224T000000Z',
$rule->getEscapedValue()
);
}
}
tests/Eluceo/iCal/Property/StringValueTest.php 0000666 00000003121 13436751250 0015441 0 ustar 00 assertEquals(
'LOREM',
$stringValue->getEscapedValue(),
'No escaping necessary'
);
}
public function testValueContainsBackslash()
{
$stringValue = new StringValue('text contains backslash: \\');
$this->assertEquals(
'text contains backslash: \\\\',
$stringValue->getEscapedValue(),
'Text contains backslash'
);
}
public function testEscapingDoubleQuotes()
{
$stringValue = new StringValue('text with "doublequotes" will be escaped');
$this->assertEquals(
'text with \\"doublequotes\\" will be escaped',
$stringValue->getEscapedValue(),
'Escaping double quotes'
);
}
public function testEscapingSemicolonAndComma()
{
$stringValue = new StringValue('text with , and ; will also be escaped');
$this->assertEquals(
'text with \\, and \\; will also be escaped',
$stringValue->getEscapedValue(),
'Escaping ; and ,'
);
}
public function testNewLineEscaping()
{
$stringValue = new StringValue("Text with new\n line");
$this->assertEquals(
'Text with new\\n line',
$stringValue->getEscapedValue(),
'Escape new line to text'
);
}
}
tests/Eluceo/iCal/ParameterBagTest.php 0000666 00000001737 13436751250 0013717 0 ustar 00 assertEquals(
'test string',
$propertyObject->escapeParamValue('test string'),
'No escaping necessary'
);
$this->assertEquals(
'"Containing \\"double-quotes\\""',
$propertyObject->escapeParamValue('Containing "double-quotes"'),
'Text contains double quotes'
);
$this->assertEquals(
'"Containing forbidden chars like a ;"',
$propertyObject->escapeParamValue('Containing forbidden chars like a ;'),
'Text with semicolon'
);
$this->assertEquals(
'"Containing forbidden chars like a :"',
$propertyObject->escapeParamValue('Containing forbidden chars like a :'),
'Text with colon'
);
}
}
tests/Eluceo/iCal/PropertyTest.php 0000666 00000002217 13436751250 0013203 0 ustar 00 assertEquals(
'DTSTAMP:20131020T153112',
$property->toLine()
);
}
public function testPropertyWithValueAndParams()
{
$property = new Property('DTSTAMP', '20131020T153112', array('TZID' => 'Europe/Berlin'));
$this->assertEquals(
'DTSTAMP;TZID=Europe/Berlin:20131020T153112',
$property->toLine()
);
}
public function testPropertyWithEscapedSingleValue()
{
$property = new Property('SOMEPROP', 'Escape me!"');
$this->assertEquals(
'SOMEPROP:Escape me!\\"',
$property->toLine()
);
}
public function testPropertyWithEscapedValues()
{
$property = new Property('SOMEPROP', 'Escape me!"', array('TEST' => 'Lorem "test" ipsum'));
$this->assertEquals(
'SOMEPROP;TEST="Lorem \\"test\\" ipsum":Escape me!\\"',
$property->toLine()
);
}
}
tests/Eluceo/iCal/ComponentTest.php 0000666 00000002754 13436751250 0013327 0 ustar 00 setDtStart(new \DateTime('2014-12-24'));
$vEvent->setDtEnd(new \DateTime('2014-12-24'));
$vEvent->setDescription($input);
$vAlarm = new \Eluceo\iCal\Component\Alarm;
$vAlarm->setAction(\Eluceo\iCal\Component\Alarm::ACTION_DISPLAY);
$vAlarm->setDescription($input);
$vAlarm->setTrigger('PT0S', true);
$vEvent->addComponent($vAlarm);
$vCalendar->addComponent($vEvent);
$output = $vCalendar->render();
$output = preg_replace('/\r\n /u', '', $output);
$this->assertContains($input, $output);
}
public function testDescriptionWithNewLines()
{
$input = "new string \n new line \n new line \n new string";
$vCalendar = new \Eluceo\iCal\Component\Calendar('www.example.com');
$vEvent = new \Eluceo\iCal\Component\Event();
$vEvent->setDtStart(new \DateTime('2014-12-24'));
$vEvent->setDtEnd(new \DateTime('2014-12-24'));
$vEvent->setDescription($input);
$vCalendar->addComponent($vEvent);
$output = $vCalendar->render();
$this->assertContains(str_replace("\n", "\\n", $input), $output);
}
}
.gitignore 0000666 00000000031 13436751250 0006540 0 ustar 00 vendor
composer.lock
bin