* * 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 = []; /** * The order in which the components will be rendered during build. * * Not defined components will be appended at the end. * * @var array */ private $componentsBuildOrder = ['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(self $component, $key = null) { if (null == $key) { $this->components[] = $component; } else { $this->components[$key] = $component; } } /** * Set all Components. * * @param Component[] $components The array of Component that will be set * @param null $key The key of the Component */ public function setComponents(array $components) { $this->components = $components; return $this; } /** * Renders an array containing the lines of the iCal file. * * @return array */ public function build() { $lines = []; $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 = []; 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 = []; /** @var $component Component */ foreach ($this->components as $component) { $type = $component->getType(); if (!isset($componentsByType[$type])) { $componentsByType[$type] = []; } $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 Component $component */ private function addComponentLines(array &$lines, self $component) { foreach ($component->build() as $l) { $lines[] = $l; } } }