Skip to content

Commit

Permalink
added SEQUENCE support to calendar events, refactored calendar to all…
Browse files Browse the repository at this point in the history
…ow batch production of events during stream export
  • Loading branch information
jasvrcek committed Jun 8, 2016
1 parent 49dcda9 commit 5fb1969
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 32 deletions.
13 changes: 12 additions & 1 deletion src/Jsvrcek/ICS/CalendarExport.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ public function __construct(CalendarStream $stream, Formatter $formatter)
$this->stream = $stream;
$this->formatter = $formatter;
}

/**
* @return CalendarStream
*/
public function getStreamObject()
{
return $this->stream;
}

/**
* @return string
Expand Down Expand Up @@ -136,7 +144,10 @@ public function getStream()

if ($event->getRecurrenceRule() instanceof RecurrenceRule)
$this->stream->addItem($event->getRecurrenceRule()->__toString());


if ($event->getSequence())
$this->stream->addItem('SEQUENCE:'.$event->getSequence());

$this->stream->addItem('STATUS:'.$event->getStatus())
->addItem('SUMMARY:'.$event->getSummary())
->addItem('DESCRIPTION:'.$event->getDescription());
Expand Down
56 changes: 37 additions & 19 deletions src/Jsvrcek/ICS/CalendarStream.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,28 @@ class CalendarStream
//length of line in bytes
const LINE_LENGTH = 70;

/**
* echo items as they are set rather than building stream in memory, for use with streaming a large calendar
*
* @var boolean
*/
private $doImmediateOutput = false;

/**
*
* @var string
*/
private $stream = '';


/**
* @param boolean $doImmediateOutput
*/
public function setDoImmediateOutput($doImmediateOutput)
{
$this->doImmediateOutput = $doImmediateOutput;
}

/**
* resets stream to blank string
*/
Expand All @@ -32,42 +47,45 @@ public function getStream()
return $this->stream;
}

/**
* splits item into new lines if necessary
/**
* splits item into new lines if necessary
* @param string $item
* @return CalendarStream
*/
public function addItem($item)
* @return CalendarStream
*/
public function addItem($item)
{
$line_breaks = array("\r\n","\n", "\r");
$item = str_replace($line_breaks,'\n',$item);

//get number of bytes
$length = strlen($item);

$block = '';

if ($length > 75)

if ($length > 75)
{
$start = 0;

while ($start < $length)
{
{
$block .= mb_strcut($item, $start, self::LINE_LENGTH, 'UTF-8');
$start = $start + self::LINE_LENGTH;

//add space if not last line
if ($start < $length) $block .= Constants::CRLF.' ';
}
}
else
}
}
else
{
$block = $item;
}

$this->stream .= $block.Constants::CRLF;

if ($this->doImmediateOutput)
{
$block = $item;
echo $this;
$this->reset();
}

$this->stream .= $block.Constants::CRLF;

return $this;
return $this;
}

/**
Expand All @@ -77,4 +95,4 @@ public function __toString()
{
return $this->getStream();
}
}
}
49 changes: 39 additions & 10 deletions src/Jsvrcek/ICS/Model/Calendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Jsvrcek\ICS\Model;

use Jsvrcek\ICS\Utility\Provider;

class Calendar
{
/**
Expand Down Expand Up @@ -39,31 +41,58 @@ class Calendar
* @var \DateTimeZone $timezone
*/
private $timezone;

/**
*
* @var array $events
*
* @var Provider
*/
private $events = array();
private $events;

/**
*
* @var array $todos
* @var Provider
*/
private $todos = array();
private $todos;

/**
*
* @var array $freeBusy
* @var Provider
*/
private $freeBusy = array();
private $freeBusy;

/**
*
*/
public function __construct()
{
$this->timezone = new \DateTimeZone('America/New_York');
$this->events = new Provider();
$this->todos = new Provider();
$this->freeBusy = new Provider();
}

/**
* For use if you want CalendarExport::getStream to get events in batches from a database during
* the output of the ics feed, instead of adding all events to the Calendar object before outputting
* the ics feed.
* - CalendarExport::getStream iterates through the Calendar::$events internal data array. The $eventsProvider
* closure will be called every time this data array reaches its end during iteration, and the closure should
* return the next batch of events
* - A $startKey argument with the current key of the data array will be passed to the $eventsProvider closure
* - The $eventsProvider must return an array of CalendarEvent objects
*
* Example: Calendar::setEventsProvider(function($startKey){
* //get database rows starting with $startKey
* //return an array of CalendarEvent objects
* })
*
* @param \Closure $eventsProvider
* @return \Jsvrcek\ICS\Model\Calendar
*/
public function setEventsProvider(\Closure $eventsProvider)
{
$this->events = new Provider($eventsProvider);
return $this;
}

/**
Expand Down Expand Up @@ -189,7 +218,7 @@ public function setTimezone(\DateTimeZone $timezone)
}

/**
* @return array
* @return Provider
*/
public function getEvents()
{
Expand All @@ -202,7 +231,7 @@ public function getEvents()
*/
public function addEvent(CalendarEvent $event)
{
$this->events[] = $event;
$this->events->add($event);
return $this;
}

Expand Down
24 changes: 24 additions & 0 deletions src/Jsvrcek/ICS/Model/CalendarEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ class CalendarEvent
*/
private $recuringId;

/**
*
* @var integer
*/
private $sequence;

/**
*
* @var array $attendees
Expand Down Expand Up @@ -486,6 +492,24 @@ public function setRecuringId($recuringId)
$this->recuringId = $recuringId;
return $this;
}

/**
* @return integer
*/
public function getSequence()
{
return $this->sequence;
}

/**
* @param integer $sequence
* @return \Jsvrcek\ICS\Model\CalendarEvent
*/
public function setSequence($sequence)
{
$this->sequence = $sequence;
return $this;
}

/**
*
Expand Down
110 changes: 110 additions & 0 deletions src/Jsvrcek/ICS/Utility/Provider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php

namespace Jsvrcek\ICS\Utility;

class Provider implements \Iterator
{
/**
*
* @var \Closure
*/
private $provider;

/**
*
* @var array
*/
public $data = array();

/**
*
* @var array
*/
public $manuallyAddedData = array();

/**
*
* @var integer
*/
private $key;

/**
* @param \Closure $provider An optional closure for adding items in batches during iteration. The closure will be
* called each time the end of the internal data array is reached during iteration, and the current data
* array key value will be passed as an argument. The closure should return an array containing the next
* batch of items.
*/
public function __construct(\Closure $provider = null)
{
$this->provider = $provider;
}

/**
* for manually adding items, rather than using a provider closure to add items in batches during iteration
* Cannot be used in conjunction with a provider closure!
*
* @param mixed $item
*/
public function add($item)
{
$this->manuallyAddedData[] = $item;
}

/* (non-PHPdoc)
* @see Iterator::current()
*/
public function current()
{
return current($this->data);
}

/* (non-PHPdoc)
* @see Iterator::key()
*/
public function key()
{
return $this->key;
}

/* (non-PHPdoc)
* @see Iterator::next()
*/
public function next()
{
array_shift($this->data);
$this->key++;
}

/* (non-PHPdoc)
* @see Iterator::rewind()
*/
public function rewind()
{
$this->data = array();
$this->key = 0;
}

/**
* get next batch from provider if data array is at the end
*
* (non-PHPdoc)
* @see Iterator::valid()
*/
public function valid()
{
if (count($this->data) < 1)
{
if ($this->provider instanceof \Closure)
{
$this->data = $this->provider->__invoke($this->key);
}
else
{
$this->data = $this->manuallyAddedData;
$this->manuallyAddedData = array();
}
}

return count($this->data) > 0;
}
}
Loading

0 comments on commit 5fb1969

Please sign in to comment.