Location: PHPKode > projects > PhpiCalLib > parameters.php
<?php
/**
 * parameters.php iCalendar parameter classes
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * @copyright Copyright (C) 2008 Nigel Swinson, hide@address.com 
 * @author  Nigel Swinson
 * @package PhpiCalLib
 * @version 1.0
 */

require_once 'exceptions.php';
require_once 'datatypes.php';

$iPHPICALLIB_PARAMETERINDEX = 1;
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2
//       3.2.  Property Parameters
define('PHPICALLIB_PARAMETER_IANAPARAM', $iPHPICALLIB_PARAMETERINDEX++);
define('PHPICALLIB_PARAMETER_XPARAM', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.1
//       3.2.1.  Alternate Text Representation . . . . . . . . . . . .  14
define('PHPICALLIB_PARAMETER_ALTREP', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.2
//       3.2.2.  Common Name . . . . . . . . . . . . . . . . . . . . .  15
define('PHPICALLIB_PARAMETER_CN', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.3
//       3.2.3.  Calendar User Type  . . . . . . . . . . . . . . . . .  16
define('PHPICALLIB_PARAMETER_CUTYPE', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.4
//       3.2.4.  Delegators  . . . . . . . . . . . . . . . . . . . . .  16
define('PHPICALLIB_PARAMETER_DELEGATED_FROM', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.5
//       3.2.5.  Delegatees  . . . . . . . . . . . . . . . . . . . . .  17
define('PHPICALLIB_PARAMETER_DELEGATED_TO', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.6
//       3.2.6.  Directory Entry Reference . . . . . . . . . . . . . .  18
define('PHPICALLIB_PARAMETER_DIR', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.7
//       3.2.7.  Inline Encoding . . . . . . . . . . . . . . . . . . .  18
define('PHPICALLIB_PARAMETER_ENCODING', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.8
//       3.2.8.  Format Type . . . . . . . . . . . . . . . . . . . . .  19
define('PHPICALLIB_PARAMETER_FMTTYPE', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.9
//       3.2.9.  Free/Busy Time Type . . . . . . . . . . . . . . . . .  19
define('PHPICALLIB_PARAMETER_FBTYPE', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.10
//       3.2.10. Language  . . . . . . . . . . . . . . . . . . . . . .  20
define('PHPICALLIB_PARAMETER_LANGUAGE', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.11
//       3.2.11. Group or List Membership  . . . . . . . . . . . . . .  21
define('PHPICALLIB_PARAMETER_MEMBER', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.12
//       3.2.12. Participation Status  . . . . . . . . . . . . . . . .  21
define('PHPICALLIB_PARAMETER_PARTSTAT', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.13
//       3.2.13. Recurrence Identifier Range . . . . . . . . . . . . .  24
define('PHPICALLIB_PARAMETER_RANGE', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.14
//       3.2.14. Alarm Trigger Relationship  . . . . . . . . . . . . .  24
define('PHPICALLIB_PARAMETER_RELATED', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.15
//       3.2.15. Relationship Type . . . . . . . . . . . . . . . . . .  25
define('PHPICALLIB_PARAMETER_RELTYPE', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.16
//       3.2.16. Participation Role  . . . . . . . . . . . . . . . . .  26
define('PHPICALLIB_PARAMETER_ROLE', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.17
//       3.2.17. RSVP Expectation  . . . . . . . . . . . . . . . . . .  27
define('PHPICALLIB_PARAMETER_RSVP', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.18
//       3.2.18. Sent By . . . . . . . . . . . . . . . . . . . . . . .  27
define('PHPICALLIB_PARAMETER_SENT_BY', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.19
//       3.2.19. Time Zone Identifier  . . . . . . . . . . . . . . . .  28
define('PHPICALLIB_PARAMETER_TZID', $iPHPICALLIB_PARAMETERINDEX++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.20
//       3.2.20. Value Data Types  . . . . . . . . . . . . . . . . . .  29
define('PHPICALLIB_PARAMETER_VALUE', $iPHPICALLIB_PARAMETERINDEX++);


/**
 * Base class for all contentline parameters
 *
 */
class PhpiCalLib_Parameter {
	/**
	 * The "param-name" token
	 * @var string
	 */
	protected $Name = '';
	/**
	 * @var integer The type of this parameter
	 */
	protected $Type = 0;
	/**
	 * The "param-value" tokens
	 * @var array: of strings
	 */
	protected $aValues = array();
	
	/**
	 * Map a property type to it's string property name.
	 *
	 * @var array Keyed by PHPICALLIB_COMPONENT_?, value is a string
	 */
	private static $TypeMap = array(
			PHPICALLIB_PARAMETER_ALTREP => 'ALTREP',
			PHPICALLIB_PARAMETER_CN => 'CN',
			PHPICALLIB_PARAMETER_CUTYPE => 'CUTYPE',
			PHPICALLIB_PARAMETER_DELEGATED_FROM => 'DELEGATED-FROM',
			PHPICALLIB_PARAMETER_DELEGATED_TO => 'DELEGATED-TO',
			PHPICALLIB_PARAMETER_DIR => 'DIR',
			PHPICALLIB_PARAMETER_ENCODING => 'ENCODING',
			PHPICALLIB_PARAMETER_FMTTYPE => 'FMTTYPE',
			PHPICALLIB_PARAMETER_FBTYPE => 'FBTYPE',
			PHPICALLIB_PARAMETER_LANGUAGE => 'LANGUAGE',
			PHPICALLIB_PARAMETER_MEMBER => 'MEMBER',
			PHPICALLIB_PARAMETER_PARTSTAT => 'PARTSTAT',
			PHPICALLIB_PARAMETER_RANGE => 'RANGE',
			PHPICALLIB_PARAMETER_RELATED => 'RELATED',
			PHPICALLIB_PARAMETER_RELTYPE => 'RELTYPE',
			PHPICALLIB_PARAMETER_ROLE => 'ROLE',
			PHPICALLIB_PARAMETER_RSVP => 'RSVP',
			PHPICALLIB_PARAMETER_SENT_BY => 'SENT-BY',
			PHPICALLIB_PARAMETER_TZID => 'TZID',
			PHPICALLIB_PARAMETER_VALUE => 'VALUE');
	// array_flip() on $TypeMap, built on first use.
	private static $ReverseTypeMap = null;
	
	/**
	 * Regex to capture validate an iana-token
	 * @link http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.1
	 *      iana-token    = 1*(ALPHA / DIGIT / "-")
	 * 
	 * @var string
	 */
	static public $IanaTokenRegex = '[a-zA-Z0-9-]+';
	
	/**
	 * A regular express to match the SAFE-CHAR token.
	 * <pre>
	 *      SAFE-CHAR     = WSP / %x21 / %x23-2B / %x2D-39 / %x3C-7E
	 *                    / NON-US-ASCII
	 *      ; Any character except CONTROL, DQUOTE, ";", ":", ","
	 * ==>
	 * ### Note we are going to assume that the utf-8 decoding has been done for us already and that
	 * our string is essentially in unicode
	 *      SAFE-CHAR     = %x09 / %x20-21 / %x23-2B / %x2D-39 / %x3C-7E
	 * </pre>
	 * @link http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.1
	 * @var string
	 */
	static public $SafeCharRegex = '[\x09\x20\x21\x23-\x2B\x2D-\x39\x3C-\x7E]';
	/**
	 * An array to locate the converse of {@link SafeCharRegex}.
	 *
	 * @var string
	 * @see SafeCharRegex
	 */
	static public $UnSafeCharRegex = '[^\x09\x20\x21\x23-\x2B\x2D-\x39\x3C-\x7E]';
	
	/**
	 * A regular expression to match the QSAFE-CHAR token.
	 * <pre>
	 *      QSAFE-CHAR    = WSP / %x21 / %x23-7E / NON-US-ASCII
	 * ==>
	 * ### Note we are going to assume that the utf-8 decoding has been done for us already and that
	 * our string is essentially in unicode
	 *      QSAFE-CHAR    = %x09 / %x20-21 / %x23-7E
	 * </pre>
	 * @var string
	 * @link http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.1
	 */
	static public $QSafeCharRegex = '[\x09\x20\x21\x23-\x7E]';
	
	/**
	 * A quick regular expression to validate a param token.
	 * <pre>
	 * ==>
	 *      param         = param-name "=" param-value *("," param-value)
	 *      param-name    = iana-token / x-name
	 * </pre>
	 * @link http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.1
	 * @return string
	 */
	static public function GetParamRegex() {
		return sprintf('%s=%s(,%s)*',self::$IanaTokenRegex,self::GetParamValueRegex(), self::GetParamValueRegex());
	}

	/**
	 * A quick regular expression to validate a param-value
	 *      param-value   = paramtext / quoted-string
	 *      paramtext     = *SAFE-CHAR
	 *      ; Any character except CONTROL, DQUOTE, ";", ":", ","
	 *      quoted-string = DQUOTE *QSAFE-CHAR DQUOTE
	 *      ; Any character except CONTROL and DQUOTE
	 * </pre>
	 * @
	 * @link http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.1
	 * @return string
	 */
	private static function GetParamValueRegex() {
		return sprintf('(%s*|"%s*")',self::$SafeCharRegex,self::$QSafeCharRegex);
	}
	static public $BadParamSplitRegex = '[^\x09\x20-\x39\x3c-\x7e]';
	
	/**
	 * Constructor
	 */
	public function __construct() {
		$this->aValues = array();
	}
	
	/**
	 * Convert a parameter name to it's defined type
	 *
	 * @param string $Name a "name" RFC2445 token
	 * @return int one of the PHPICALLIB_PARAMETER_* properties
	 */
	static public function ToParameterType($Name) {
		// Build the type map on first access
		if (!self::$ReverseTypeMap) {
			self::$ReverseTypeMap = array_flip(self::$TypeMap);
		}
		// If we have a key for this name, return the unique type
		if (isset(self::$ReverseTypeMap[$Name])) {
			return self::$ReverseTypeMap[$Name];
		}
		// It must be an iana defined extension or x-comp that we don't really recognize.
		if (preg_match('/^X-.*$/', $Name)) { 
			return PHPICALLIB_PARAMETER_XPARAM;
		}
		return PHPICALLIB_PARAMETER_IANAPARAM;
	}
	
	/**
	 * Create a new Parameter object
	 *
	 * A component would override this class, providing a new version of this function
	 * in order to choose the right kind of class to create which will offer better validation.
	 * 
	 * @param string $Name The name of the param
	 * @return PhpiCalLib_Parameter derived class
	 */
	protected function CreateParameter($Name) {
		$Result = new PhpiCalLib_Parameter();
		$Result->SetName($Name);
		return $Result;
	}
	
	/**
	 * Parse a param from the string, returning the new object
	 *
	 * @param string $String The encoded value that represents the parameter
	 * @return A PhpiCalLib_Parameter derived class, according to what CreateParameter returned
	 */
	public function Create($Param) {
		// Do a quick check first
		$Pattern = sprintf('/^%s$/D', self::GetParamRegex());
		if (!preg_match($Pattern, $Param)) {
			throw new PhpiCalLib_ParseException(sprintf("Invalid param (%s) token: %s", $Pattern, $Param));
		}
		
		// Split out the param-name
		//      param         = param-name "=" param-value *("," param-value)
		//      param-name    = iana-token / x-name
		$Pattern = '/^([a-zA-Z0-9-]+)=(.*)$/D';
		$aMatches = array();
		if (!preg_match($Pattern, $Param, $aMatches)) {
			throw new PhpiCalLib_ParseException(sprintf("Invalid param (%s) in contentline: %s", $Pattern, $Param));
		}
		
		$Name = $aMatches[1];
		$aValues = array();
		
		// Check we got at least one param-value.  Note ',' is valid inside a param-value by means of quoted-string, but
		// we'll address that later.
		$aParamValues = explode(",",$aMatches[2]);
		
		// Process each of the param-values
		//      param-value   = paramtext / quoted-string
		//      paramtext     = *SAFE-CHAR
		//      quoted-string = DQUOTE *QSAFE-CHAR DQUOTE
		while (!empty($aParamValues)) {
			$ParamValue = array_shift($aParamValues);

			// If the value is empty, that's legitimate, store and continue;
			if (empty($ParamValue)) {
				$aValues[] = '';
				continue;
			}

			// If it starts with a DQUOTE, then it's a quoted string
			if ($ParamValue[0] == '"') {
				// A ',' is valid inside a param-value by means of a a quoted-string, but we explode(',') to begin with
				// so we may have to stitch together the quoted-strings again
				while (strlen($ParamValue) == 1 || substr($ParamValue, -1) != '"') {
					if (empty($aParamValues)) {
						throw new PhpiCalLib_ParseException(sprintf("Invalid quoted-string (%s) in param: %s", $Pattern, $ParamValue));
					}
					$ParamValue = sprintf("%s,%s", $ParamValue, array_shift($aParamValues));
				}

				// It's a quoted-string
				//      quoted-string = DQUOTE *QSAFE-CHAR DQUOTE
				//      QSAFE-CHAR    = WSP / %x21 / %x23-7E / NON-US-ASCII
				$Pattern = sprintf('/^"(%s*)"$/D', self::$QSafeCharRegex);
				$aMatches = array();
				if (!preg_match($Pattern, $ParamValue, $aMatches)) {
					throw new PhpiCalLib_ParseException(sprintf("Invalid quoted-string (%s) in param: %s", $Pattern, $ParamValue));
				}
				$aValues[] = $aMatches[1];
			} else {
				// It's a sraight text value
				//      paramtext     = *SAFE-CHAR
				//      SAFE-CHAR     = WSP / %x21 / %x23-2B / %x2D-39 / %x3C-7E
				//                    / NON-US-ASCII
				$Pattern = sprintf('/^%s*$/D', self::$SafeCharRegex);
				if (!preg_match($Pattern, $ParamValue)) {
					throw new PhpiCalLib_ParseException(sprintf("Invalid paramtext (%s) in param: %s", $Pattern, $ParamValue));
				}
				$aValues[] = $ParamValue;
			}
		}
		
		// Create the right kind of content line property to populate, assigning it's name
		$Result = $this->CreateParameter($Name);
		$Result->SetValues($aValues);
		return $Result;
	}
	
	/**
	 * Access the name of the parameter
	 *
	 * @return string
	 */
	public function GetName() {
		if (empty($this->Name)) {
			throw new PhpiCalLib_Exception('No name assigned to this parameter yet');
		}
		return $this->Name;
	}
	
	/**
	 * Set the name of the parameter
	 *
	 * @param string $Name
	 */
	public function SetName($Name) {
		// Further parse the name before storage.
		//      param-name    = iana-token / x-name
		//      iana-token    = 1*(ALPHA / DIGIT / "-")
		//      x-name        = "X-" [vendorid "-"] 1*(ALPHA / DIGIT / "-")
		//      vendorid      = 3*(ALPHA / DIGIT)
		// Note an invalid x-name becomes an iana-token, so we just check for valid iana-tokens
		$Pattern = sprintf("/^%s$/D", self::$IanaTokenRegex);
		if (!preg_match($Pattern, $Name)) {
			throw new PhpiCalLib_ParameterException(sprintf("Invalid iana-token (%s) in property name: %s", $Pattern, $Name));
		}
		
		if (strlen($Name) > 2 && substr($Name, 0, 2) == "X-") {
			// x-param
			$this->Name = $Name;
			$this->Type = PHPICALLIB_PARAMETER_XPARAM;
		} else {
			// iana-param
			$this->Type = $this->ToParameterType($Name);
			$this->Name = $Name;
		}
	}

	/**
	 * Access the component type
	 * 
	 * Note this will return PHPICALLIB_PARAMETER_IANAPARAM for components that it doesn't recognize
	 *
	 * @return PHPICALLIB_PARAMETER_*
	 */
	public function GetType() {
		return $this->Type;
	}
	
	/**
	 * Set the type of the component
	 *
	 * @param integer $Type
	 */
	public function SetType($Type) {
		// Check they aren't trying to set this to an x-comp or an iana-comp
		switch ($Type) {
			case PHPICALLIB_PARAMETER_IANAPARAM:
			case PHPICALLIB_PARAMETER_XPARAM:
				throw new PhpiCalLib_Exception('Can\'t set parameter type to iana-param or x-param.  Use SetName instead');
		}
		// Pull out the name, note if we ever add a PHPICALLIB_PARAMETER_? and forget to amend $TypeMap, then
		// this can start to fail
		$this->Name = self::$TypeMap[$Type];
		// Store the type.
		$this->Type = $Type;
	}
	
	/**
	 * Get all the values of this parameter
	 * 
	 * @return array Of the parameter values
	 */
	public function GetValues() {
		return $this->aValues;
	}

	/**
	 * Add another parameter value
	 *
	 * @param string $ParamValue
	 */
	public function AddValue($ParamValue) {
		// If the value is empty, that's legitimate, store and continue;
		if (empty($ParamValue)) {
			$this->aValues[] = '';
			return;
		}
		
		// We'll be able to store paramtext or quoted-string.
		//      quoted-string = DQUOTE *QSAFE-CHAR DQUOTE
		//      QSAFE-CHAR    = WSP / %x21 / %x23-7E / NON-US-ASCII
		//      paramtext     = *SAFE-CHAR
		//      SAFE-CHAR     = WSP / %x21 / %x23-2B / %x2D-39 / %x3C-7E
		//                    / NON-US-ASCII
		// quoted-strings are more flexible, so we check it could be a valid quoted string
		$Pattern = sprintf('/^(%s*)$/D', self::$QSafeCharRegex);
		$aMatches = array();
		if (!preg_match($Pattern, $ParamValue, $aMatches)) {
			throw new PhpiCalLib_ParseException(sprintf("Invalid quoted-string (%s) in param: %s", $Pattern, $ParamValue));
		}
		$this->aValues[] = $ParamValue;
	}
	
	/**
	 * Set the new property values.
	 *
	 * @param array $aValues The new parameter values, to replace the existing values.
	 */
	public function SetValues($aValues) {
		// Empty the existing values
		$this->aValues = array();
		foreach ($aValues as $Value) {
			$this->AddValue($Value);
		}
	}
	
	/**
	 * Get the value of this single value property
	 * 
	 * If the property has more than one value, it returns the first.
	 * If it has no values, it returns an empty string
	 * @return string
	 */
	public function GetValue() {
		if (empty($this->aValues)) return '';
		return $this->aValues[0];
	}
	
	/**
	 * Set the values to a single new value
	 *
	 * @param string $Value
	 */
	public function SetValue($Value) {
		$this->SetValues(array($Value));
	}
	
	/**
	 * Dump the parameter to a string
	 * 
	 * @return A string representation in the default code page
	 */
	public function ToString() {
		//      param         = param-name "=" param-value *("," param-value)
		$aParamValues = array();
		foreach ($this->aValues as $Value) {
			// If the string contains any unsafe chars, we must print it as a quoted-string
			$Pattern = sprintf('/%s/',self::$UnSafeCharRegex);
			if (preg_match($Pattern, $Value)) {
				$aParamValues[] = sprintf('"%s"', $Value);
			} else {
				$aParamValues[] = $Value;
			}
		}
		return sprintf("%s=%s", $this->Name, implode(',', $aParamValues));
	}
}

/**
 * The VALUE parameter.
 * <pre>
 *         valuetypeparam = "VALUE" "=" valuetype
 *         valuetype  = ("BINARY"
 *                    / "BOOLEAN"
 *                    / "CAL-ADDRESS"
 *                    / "DATE"
 *                    / "DATE-TIME"
 *                    / "DURATION"
 *                    / "FLOAT"
 *                    / "INTEGER"
 *                    / "PERIOD"
 *                    / "RECUR"
 *                    / "TEXT"
 *                    / "TIME"
 *                    / "URI"
 *                    / "UTC-OFFSET"
 *                    / x-name
 *                    ; Some experimental iCalendar value type.
 *                    / iana-token)
 *                    ; Some other IANA registered iCalendar value type.
 * </pre>
 * @link http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.2.20
 */
class PhpiCalLib_Parameters_Value extends PhpiCalLib_Parameter {
	public function __construct() {
		parent::__construct();
		$this->SetType(PHPICALLIB_PARAMETER_VALUE);
	}
	
	/**
	 * Overridden because this property only allows one value
	 *
	 * @param string $Value The new value
	 */
	public function AddValue($Value) {
		if (count($this->aValues) >= 1) {
			throw new PhpiCalLib_ParameterException('The VALUE parameter can only have one value');
		}
		
		//        valuetype  = ("BINARY"
		//                   / "BOOLEAN"
		//                   / "CAL-ADDRESS"
		//                   / "DATE"
		//                   / "DATE-TIME"
		//                   / "DURATION"
		//                   / "FLOAT"
		//                   / "INTEGER"
		//                   / "PERIOD"
		//                   / "RECUR"
		//                   / "TEXT"
		//                   / "TIME"
		//                   / "URI"
		//                   / "UTC-OFFSET"
		//                   / x-name
		//                   ; Some experimental iCalendar value type.
		//                   / iana-token)
		//                   ; Some other IANA registered iCalendar value type.
		// Note an invalid x-name becomes an iana-token, so we just check for valid iana-tokens
		// iana-token
		$Pattern = sprintf("/^%s$/D", PhpiCalLib_DataType::$IanaTokenRegex);
		if (!preg_match($Pattern, $Value)) {
			throw new PhpiCalLib_ParameterException(sprintf("Invalid iana-token (%s) in value parameter: %s", $Pattern, $Value));
		}
		
		// Carry on and add the parameter
		parent::AddValue($Value);
	}
	
	/**
	 * Access the data type id
	 *
	 * @return integer One of the PHPICALLIB_DATATYPE_* values
	 */
	public function ToDataType() {
		return PhpiCalLib_DataType::ToDataType($this->aValues[0]);
	}
	
	/**
	 * Set the parameter value by specifying the data type
	 *
	 * @param integer $DataTypeId
	 */
	public function FromDataType($DataTypeId) {
		$this->SetValue(PhpiCalLib_DataType::FromDataType($DataTypeId));
	}
}
?>
Return current item: PhpiCalLib