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