1*a1a3b679SAndreas Boehler<?php 2*a1a3b679SAndreas Boehler 3*a1a3b679SAndreas Boehlernamespace Sabre\VObject; 4*a1a3b679SAndreas Boehler 5*a1a3b679SAndreas Boehler/** 6*a1a3b679SAndreas Boehler * Document 7*a1a3b679SAndreas Boehler * 8*a1a3b679SAndreas Boehler * A document is just like a component, except that it's also the top level 9*a1a3b679SAndreas Boehler * element. 10*a1a3b679SAndreas Boehler * 11*a1a3b679SAndreas Boehler * Both a VCALENDAR and a VCARD are considered documents. 12*a1a3b679SAndreas Boehler * 13*a1a3b679SAndreas Boehler * This class also provides a registry for document types. 14*a1a3b679SAndreas Boehler * 15*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/). 16*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/) 17*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License 18*a1a3b679SAndreas Boehler */ 19*a1a3b679SAndreas Boehlerabstract class Document extends Component { 20*a1a3b679SAndreas Boehler 21*a1a3b679SAndreas Boehler /** 22*a1a3b679SAndreas Boehler * Unknown document type 23*a1a3b679SAndreas Boehler */ 24*a1a3b679SAndreas Boehler const UNKNOWN = 1; 25*a1a3b679SAndreas Boehler 26*a1a3b679SAndreas Boehler /** 27*a1a3b679SAndreas Boehler * vCalendar 1.0 28*a1a3b679SAndreas Boehler */ 29*a1a3b679SAndreas Boehler const VCALENDAR10 = 2; 30*a1a3b679SAndreas Boehler 31*a1a3b679SAndreas Boehler /** 32*a1a3b679SAndreas Boehler * iCalendar 2.0 33*a1a3b679SAndreas Boehler */ 34*a1a3b679SAndreas Boehler const ICALENDAR20 = 3; 35*a1a3b679SAndreas Boehler 36*a1a3b679SAndreas Boehler /** 37*a1a3b679SAndreas Boehler * vCard 2.1 38*a1a3b679SAndreas Boehler */ 39*a1a3b679SAndreas Boehler const VCARD21 = 4; 40*a1a3b679SAndreas Boehler 41*a1a3b679SAndreas Boehler /** 42*a1a3b679SAndreas Boehler * vCard 3.0 43*a1a3b679SAndreas Boehler */ 44*a1a3b679SAndreas Boehler const VCARD30 = 5; 45*a1a3b679SAndreas Boehler 46*a1a3b679SAndreas Boehler /** 47*a1a3b679SAndreas Boehler * vCard 4.0 48*a1a3b679SAndreas Boehler */ 49*a1a3b679SAndreas Boehler const VCARD40 = 6; 50*a1a3b679SAndreas Boehler 51*a1a3b679SAndreas Boehler /** 52*a1a3b679SAndreas Boehler * The default name for this component. 53*a1a3b679SAndreas Boehler * 54*a1a3b679SAndreas Boehler * This should be 'VCALENDAR' or 'VCARD'. 55*a1a3b679SAndreas Boehler * 56*a1a3b679SAndreas Boehler * @var string 57*a1a3b679SAndreas Boehler */ 58*a1a3b679SAndreas Boehler static public $defaultName; 59*a1a3b679SAndreas Boehler 60*a1a3b679SAndreas Boehler /** 61*a1a3b679SAndreas Boehler * List of properties, and which classes they map to. 62*a1a3b679SAndreas Boehler * 63*a1a3b679SAndreas Boehler * @var array 64*a1a3b679SAndreas Boehler */ 65*a1a3b679SAndreas Boehler static public $propertyMap = array(); 66*a1a3b679SAndreas Boehler 67*a1a3b679SAndreas Boehler /** 68*a1a3b679SAndreas Boehler * List of components, along with which classes they map to. 69*a1a3b679SAndreas Boehler * 70*a1a3b679SAndreas Boehler * @var array 71*a1a3b679SAndreas Boehler */ 72*a1a3b679SAndreas Boehler static public $componentMap = array(); 73*a1a3b679SAndreas Boehler 74*a1a3b679SAndreas Boehler /** 75*a1a3b679SAndreas Boehler * List of value-types, and which classes they map to. 76*a1a3b679SAndreas Boehler * 77*a1a3b679SAndreas Boehler * @var array 78*a1a3b679SAndreas Boehler */ 79*a1a3b679SAndreas Boehler static public $valueMap = array(); 80*a1a3b679SAndreas Boehler 81*a1a3b679SAndreas Boehler /** 82*a1a3b679SAndreas Boehler * Creates a new document. 83*a1a3b679SAndreas Boehler * 84*a1a3b679SAndreas Boehler * We're changing the default behavior slightly here. First, we don't want 85*a1a3b679SAndreas Boehler * to have to specify a name (we already know it), and we want to allow 86*a1a3b679SAndreas Boehler * children to be specified in the first argument. 87*a1a3b679SAndreas Boehler * 88*a1a3b679SAndreas Boehler * But, the default behavior also works. 89*a1a3b679SAndreas Boehler * 90*a1a3b679SAndreas Boehler * So the two sigs: 91*a1a3b679SAndreas Boehler * 92*a1a3b679SAndreas Boehler * new Document(array $children = array(), $defaults = true); 93*a1a3b679SAndreas Boehler * new Document(string $name, array $children = array(), $defaults = true) 94*a1a3b679SAndreas Boehler * 95*a1a3b679SAndreas Boehler * @return void 96*a1a3b679SAndreas Boehler */ 97*a1a3b679SAndreas Boehler public function __construct() { 98*a1a3b679SAndreas Boehler 99*a1a3b679SAndreas Boehler $args = func_get_args(); 100*a1a3b679SAndreas Boehler if (count($args)===0 || is_array($args[0])) { 101*a1a3b679SAndreas Boehler array_unshift($args, $this, static::$defaultName); 102*a1a3b679SAndreas Boehler call_user_func_array(array('parent', '__construct'), $args); 103*a1a3b679SAndreas Boehler } else { 104*a1a3b679SAndreas Boehler array_unshift($args, $this); 105*a1a3b679SAndreas Boehler call_user_func_array(array('parent', '__construct'), $args); 106*a1a3b679SAndreas Boehler } 107*a1a3b679SAndreas Boehler 108*a1a3b679SAndreas Boehler } 109*a1a3b679SAndreas Boehler 110*a1a3b679SAndreas Boehler /** 111*a1a3b679SAndreas Boehler * Returns the current document type. 112*a1a3b679SAndreas Boehler * 113*a1a3b679SAndreas Boehler * @return void 114*a1a3b679SAndreas Boehler */ 115*a1a3b679SAndreas Boehler public function getDocumentType() { 116*a1a3b679SAndreas Boehler 117*a1a3b679SAndreas Boehler return self::UNKNOWN; 118*a1a3b679SAndreas Boehler 119*a1a3b679SAndreas Boehler } 120*a1a3b679SAndreas Boehler 121*a1a3b679SAndreas Boehler /** 122*a1a3b679SAndreas Boehler * Creates a new component or property. 123*a1a3b679SAndreas Boehler * 124*a1a3b679SAndreas Boehler * If it's a known component, we will automatically call createComponent. 125*a1a3b679SAndreas Boehler * otherwise, we'll assume it's a property and call createProperty instead. 126*a1a3b679SAndreas Boehler * 127*a1a3b679SAndreas Boehler * @param string $name 128*a1a3b679SAndreas Boehler * @param string $arg1,... Unlimited number of args 129*a1a3b679SAndreas Boehler * @return mixed 130*a1a3b679SAndreas Boehler */ 131*a1a3b679SAndreas Boehler public function create($name) { 132*a1a3b679SAndreas Boehler 133*a1a3b679SAndreas Boehler if (isset(static::$componentMap[strtoupper($name)])) { 134*a1a3b679SAndreas Boehler 135*a1a3b679SAndreas Boehler return call_user_func_array(array($this,'createComponent'), func_get_args()); 136*a1a3b679SAndreas Boehler 137*a1a3b679SAndreas Boehler } else { 138*a1a3b679SAndreas Boehler 139*a1a3b679SAndreas Boehler return call_user_func_array(array($this,'createProperty'), func_get_args()); 140*a1a3b679SAndreas Boehler 141*a1a3b679SAndreas Boehler } 142*a1a3b679SAndreas Boehler 143*a1a3b679SAndreas Boehler } 144*a1a3b679SAndreas Boehler 145*a1a3b679SAndreas Boehler /** 146*a1a3b679SAndreas Boehler * Creates a new component 147*a1a3b679SAndreas Boehler * 148*a1a3b679SAndreas Boehler * This method automatically searches for the correct component class, based 149*a1a3b679SAndreas Boehler * on its name. 150*a1a3b679SAndreas Boehler * 151*a1a3b679SAndreas Boehler * You can specify the children either in key=>value syntax, in which case 152*a1a3b679SAndreas Boehler * properties will automatically be created, or you can just pass a list of 153*a1a3b679SAndreas Boehler * Component and Property object. 154*a1a3b679SAndreas Boehler * 155*a1a3b679SAndreas Boehler * By default, a set of sensible values will be added to the component. For 156*a1a3b679SAndreas Boehler * an iCalendar object, this may be something like CALSCALE:GREGORIAN. To 157*a1a3b679SAndreas Boehler * ensure that this does not happen, set $defaults to false. 158*a1a3b679SAndreas Boehler * 159*a1a3b679SAndreas Boehler * @param string $name 160*a1a3b679SAndreas Boehler * @param array $children 161*a1a3b679SAndreas Boehler * @param bool $defaults 162*a1a3b679SAndreas Boehler * @return Component 163*a1a3b679SAndreas Boehler */ 164*a1a3b679SAndreas Boehler public function createComponent($name, array $children = null, $defaults = true) { 165*a1a3b679SAndreas Boehler 166*a1a3b679SAndreas Boehler $name = strtoupper($name); 167*a1a3b679SAndreas Boehler $class = 'Sabre\\VObject\\Component'; 168*a1a3b679SAndreas Boehler 169*a1a3b679SAndreas Boehler if (isset(static::$componentMap[$name])) { 170*a1a3b679SAndreas Boehler $class=static::$componentMap[$name]; 171*a1a3b679SAndreas Boehler } 172*a1a3b679SAndreas Boehler if (is_null($children)) $children = array(); 173*a1a3b679SAndreas Boehler return new $class($this, $name, $children, $defaults); 174*a1a3b679SAndreas Boehler 175*a1a3b679SAndreas Boehler } 176*a1a3b679SAndreas Boehler 177*a1a3b679SAndreas Boehler /** 178*a1a3b679SAndreas Boehler * Factory method for creating new properties 179*a1a3b679SAndreas Boehler * 180*a1a3b679SAndreas Boehler * This method automatically searches for the correct property class, based 181*a1a3b679SAndreas Boehler * on its name. 182*a1a3b679SAndreas Boehler * 183*a1a3b679SAndreas Boehler * You can specify the parameters either in key=>value syntax, in which case 184*a1a3b679SAndreas Boehler * parameters will automatically be created, or you can just pass a list of 185*a1a3b679SAndreas Boehler * Parameter objects. 186*a1a3b679SAndreas Boehler * 187*a1a3b679SAndreas Boehler * @param string $name 188*a1a3b679SAndreas Boehler * @param mixed $value 189*a1a3b679SAndreas Boehler * @param array $parameters 190*a1a3b679SAndreas Boehler * @param string $valueType Force a specific valuetype, such as URI or TEXT 191*a1a3b679SAndreas Boehler * @return Property 192*a1a3b679SAndreas Boehler */ 193*a1a3b679SAndreas Boehler public function createProperty($name, $value = null, array $parameters = null, $valueType = null) { 194*a1a3b679SAndreas Boehler 195*a1a3b679SAndreas Boehler // If there's a . in the name, it means it's prefixed by a groupname. 196*a1a3b679SAndreas Boehler if (($i=strpos($name,'.'))!==false) { 197*a1a3b679SAndreas Boehler $group = substr($name, 0, $i); 198*a1a3b679SAndreas Boehler $name = strtoupper(substr($name, $i+1)); 199*a1a3b679SAndreas Boehler } else { 200*a1a3b679SAndreas Boehler $name = strtoupper($name); 201*a1a3b679SAndreas Boehler $group = null; 202*a1a3b679SAndreas Boehler } 203*a1a3b679SAndreas Boehler 204*a1a3b679SAndreas Boehler $class = null; 205*a1a3b679SAndreas Boehler 206*a1a3b679SAndreas Boehler if ($valueType) { 207*a1a3b679SAndreas Boehler // The valueType argument comes first to figure out the correct 208*a1a3b679SAndreas Boehler // class. 209*a1a3b679SAndreas Boehler $class = $this->getClassNameForPropertyValue($valueType); 210*a1a3b679SAndreas Boehler } 211*a1a3b679SAndreas Boehler 212*a1a3b679SAndreas Boehler if (is_null($class) && isset($parameters['VALUE'])) { 213*a1a3b679SAndreas Boehler // If a VALUE parameter is supplied, we should use that. 214*a1a3b679SAndreas Boehler $class = $this->getClassNameForPropertyValue($parameters['VALUE']); 215*a1a3b679SAndreas Boehler } 216*a1a3b679SAndreas Boehler if (is_null($class)) { 217*a1a3b679SAndreas Boehler $class = $this->getClassNameForPropertyName($name); 218*a1a3b679SAndreas Boehler } 219*a1a3b679SAndreas Boehler if (is_null($parameters)) $parameters = array(); 220*a1a3b679SAndreas Boehler 221*a1a3b679SAndreas Boehler return new $class($this, $name, $value, $parameters, $group); 222*a1a3b679SAndreas Boehler 223*a1a3b679SAndreas Boehler } 224*a1a3b679SAndreas Boehler 225*a1a3b679SAndreas Boehler /** 226*a1a3b679SAndreas Boehler * This method returns a full class-name for a value parameter. 227*a1a3b679SAndreas Boehler * 228*a1a3b679SAndreas Boehler * For instance, DTSTART may have VALUE=DATE. In that case we will look in 229*a1a3b679SAndreas Boehler * our valueMap table and return the appropriate class name. 230*a1a3b679SAndreas Boehler * 231*a1a3b679SAndreas Boehler * This method returns null if we don't have a specialized class. 232*a1a3b679SAndreas Boehler * 233*a1a3b679SAndreas Boehler * @param string $valueParam 234*a1a3b679SAndreas Boehler * @return void 235*a1a3b679SAndreas Boehler */ 236*a1a3b679SAndreas Boehler public function getClassNameForPropertyValue($valueParam) { 237*a1a3b679SAndreas Boehler 238*a1a3b679SAndreas Boehler $valueParam = strtoupper($valueParam); 239*a1a3b679SAndreas Boehler if (isset(static::$valueMap[$valueParam])) { 240*a1a3b679SAndreas Boehler return static::$valueMap[$valueParam]; 241*a1a3b679SAndreas Boehler } 242*a1a3b679SAndreas Boehler 243*a1a3b679SAndreas Boehler } 244*a1a3b679SAndreas Boehler 245*a1a3b679SAndreas Boehler /** 246*a1a3b679SAndreas Boehler * Returns the default class for a property name. 247*a1a3b679SAndreas Boehler * 248*a1a3b679SAndreas Boehler * @param string $propertyName 249*a1a3b679SAndreas Boehler * @return string 250*a1a3b679SAndreas Boehler */ 251*a1a3b679SAndreas Boehler public function getClassNameForPropertyName($propertyName) { 252*a1a3b679SAndreas Boehler 253*a1a3b679SAndreas Boehler if (isset(static::$propertyMap[$propertyName])) { 254*a1a3b679SAndreas Boehler return static::$propertyMap[$propertyName]; 255*a1a3b679SAndreas Boehler } else { 256*a1a3b679SAndreas Boehler return 'Sabre\\VObject\\Property\\Unknown'; 257*a1a3b679SAndreas Boehler } 258*a1a3b679SAndreas Boehler 259*a1a3b679SAndreas Boehler } 260*a1a3b679SAndreas Boehler 261*a1a3b679SAndreas Boehler} 262