mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-09 06:28:28 +03:00
Sabre/VObject 4.5.4 for #1311
This commit is contained in:
parent
90a657c0fb
commit
70a2ebb671
75 changed files with 1213 additions and 1944 deletions
|
|
@ -15,31 +15,25 @@ class BirthdayCalendarGenerator
|
|||
{
|
||||
/**
|
||||
* Input objects.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $objects = [];
|
||||
protected array $objects = [];
|
||||
|
||||
/**
|
||||
* Default year.
|
||||
* Used for dates without a year.
|
||||
*/
|
||||
const DEFAULT_YEAR = 2000;
|
||||
public const DEFAULT_YEAR = 2000;
|
||||
|
||||
/**
|
||||
* Output format for the SUMMARY.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $format = '%1$s\'s Birthday';
|
||||
protected string $format = '%1$s\'s Birthday';
|
||||
|
||||
/**
|
||||
* Creates the generator.
|
||||
*
|
||||
* Check the setTimeRange and setObjects methods for details about the
|
||||
* arguments.
|
||||
*
|
||||
* @param mixed $objects
|
||||
*/
|
||||
public function __construct($objects = null)
|
||||
{
|
||||
|
|
@ -53,10 +47,8 @@ class BirthdayCalendarGenerator
|
|||
*
|
||||
* You must either supply a vCard as a string or as a Component/VCard object.
|
||||
* It's also possible to supply an array of strings or objects.
|
||||
*
|
||||
* @param mixed $objects
|
||||
*/
|
||||
public function setObjects($objects)
|
||||
public function setObjects($objects): void
|
||||
{
|
||||
if (!is_array($objects)) {
|
||||
$objects = [$objects];
|
||||
|
|
@ -81,20 +73,16 @@ class BirthdayCalendarGenerator
|
|||
|
||||
/**
|
||||
* Sets the output format for the SUMMARY.
|
||||
*
|
||||
* @param string $format
|
||||
*/
|
||||
public function setFormat($format)
|
||||
public function setFormat(string $format): void
|
||||
{
|
||||
$this->format = $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the input data and returns a VCALENDAR.
|
||||
*
|
||||
* @return Component/VCalendar
|
||||
*/
|
||||
public function getResult()
|
||||
public function getResult(): VCalendar
|
||||
{
|
||||
$calendar = new VCalendar();
|
||||
|
||||
|
|
@ -111,7 +99,7 @@ class BirthdayCalendarGenerator
|
|||
continue;
|
||||
}
|
||||
|
||||
// We're always converting to vCard 4.0 so we can rely on the
|
||||
// We're always converting to vCard 4.0, so we can rely on the
|
||||
// VCardConverter handling the X-APPLE-OMIT-YEAR property for us.
|
||||
$object = $object->convert(Document::VCARD40);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Sabre\VObject\Parser\Json;
|
||||
use Sabre\VObject\Parser\MimeDir;
|
||||
use Sabre\VObject\Parser\Parser;
|
||||
|
||||
/**
|
||||
* This is the CLI interface for sabre-vobject.
|
||||
|
|
@ -15,45 +17,28 @@ class Cli
|
|||
{
|
||||
/**
|
||||
* No output.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $quiet = false;
|
||||
|
||||
/**
|
||||
* Help display.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $showHelp = false;
|
||||
protected bool $quiet = false;
|
||||
|
||||
/**
|
||||
* Whether to spit out 'mimedir' or 'json' format.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $format;
|
||||
protected ?string $format = null;
|
||||
|
||||
/**
|
||||
* JSON pretty print.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $pretty;
|
||||
protected bool $pretty = false;
|
||||
|
||||
/**
|
||||
* Source file.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $inputPath;
|
||||
protected string $inputPath;
|
||||
|
||||
/**
|
||||
* Destination file.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $outputPath;
|
||||
protected string $outputPath;
|
||||
|
||||
/**
|
||||
* output stream.
|
||||
|
|
@ -78,24 +63,18 @@ class Cli
|
|||
|
||||
/**
|
||||
* Input format (one of json or mimedir).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $inputFormat;
|
||||
protected ?string $inputFormat = null;
|
||||
|
||||
/**
|
||||
* Makes the parser less strict.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $forgiving = false;
|
||||
protected bool $forgiving = false;
|
||||
|
||||
/**
|
||||
* Main function.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function main(array $argv)
|
||||
public function main(array $argv): int
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
// We cannot easily test this, so we'll skip it. Pretty basic anyway.
|
||||
|
|
@ -130,34 +109,31 @@ class Cli
|
|||
$this->showHelp();
|
||||
|
||||
return 0;
|
||||
break;
|
||||
case 'format':
|
||||
switch ($value) {
|
||||
// jcard/jcal documents
|
||||
case 'jcard':
|
||||
case 'jcal':
|
||||
// specific document versions
|
||||
// specific document versions
|
||||
case 'vcard21':
|
||||
case 'vcard30':
|
||||
case 'vcard40':
|
||||
case 'icalendar20':
|
||||
// specific formats
|
||||
// specific formats
|
||||
case 'json':
|
||||
case 'mimedir':
|
||||
// icalendar/vcad
|
||||
// icalendar/vcard
|
||||
case 'icalendar':
|
||||
case 'vcard':
|
||||
$this->format = $value;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unknown format: '.$value);
|
||||
throw new \InvalidArgumentException('Unknown format: '.$value);
|
||||
}
|
||||
break;
|
||||
case 'pretty':
|
||||
if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||
$this->pretty = true;
|
||||
}
|
||||
$this->pretty = true;
|
||||
break;
|
||||
case 'forgiving':
|
||||
$this->forgiving = true;
|
||||
|
|
@ -171,7 +147,7 @@ class Cli
|
|||
$this->inputFormat = 'json';
|
||||
break;
|
||||
|
||||
// mimedir formats
|
||||
// mimedir formats
|
||||
case 'mimedir':
|
||||
case 'icalendar':
|
||||
case 'vcard':
|
||||
|
|
@ -183,11 +159,11 @@ class Cli
|
|||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unknown format: '.$value);
|
||||
throw new \InvalidArgumentException('Unknown format: '.$value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InvalidArgumentException('Unknown option: '.$name);
|
||||
throw new \InvalidArgumentException('Unknown option: '.$name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -198,17 +174,17 @@ class Cli
|
|||
}
|
||||
|
||||
if (1 === count($positional)) {
|
||||
throw new InvalidArgumentException('Inputfile is a required argument');
|
||||
throw new \InvalidArgumentException('Inputfile is a required argument');
|
||||
}
|
||||
|
||||
if (count($positional) > 3) {
|
||||
throw new InvalidArgumentException('Too many arguments');
|
||||
throw new \InvalidArgumentException('Too many arguments');
|
||||
}
|
||||
|
||||
if (!in_array($positional[0], ['validate', 'repair', 'convert', 'color'])) {
|
||||
throw new InvalidArgumentException('Unknown command: '.$positional[0]);
|
||||
throw new \InvalidArgumentException('Unknown command: '.$positional[0]);
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->showHelp();
|
||||
$this->log('Error: '.$e->getMessage(), 'red');
|
||||
|
||||
|
|
@ -218,20 +194,20 @@ class Cli
|
|||
$command = $positional[0];
|
||||
|
||||
$this->inputPath = $positional[1];
|
||||
$this->outputPath = isset($positional[2]) ? $positional[2] : '-';
|
||||
$this->outputPath = $positional[2] ?? '-';
|
||||
|
||||
if ('-' !== $this->outputPath) {
|
||||
$this->stdout = fopen($this->outputPath, 'w');
|
||||
}
|
||||
|
||||
if (!$this->inputFormat) {
|
||||
if (null === $this->inputFormat) {
|
||||
if ('.json' === substr($this->inputPath, -5)) {
|
||||
$this->inputFormat = 'json';
|
||||
} else {
|
||||
$this->inputFormat = 'mimedir';
|
||||
}
|
||||
}
|
||||
if (!$this->format) {
|
||||
if (null === $this->format) {
|
||||
if ('.json' === substr($this->outputPath, -5)) {
|
||||
$this->format = 'json';
|
||||
} else {
|
||||
|
|
@ -262,7 +238,7 @@ class Cli
|
|||
/**
|
||||
* Shows the help message.
|
||||
*/
|
||||
protected function showHelp()
|
||||
protected function showHelp(): void
|
||||
{
|
||||
$this->log('Usage:', 'yellow');
|
||||
$this->log(' vobject [options] command [arguments]');
|
||||
|
|
@ -275,10 +251,7 @@ class Cli
|
|||
$this->log(' vcard30, vcard40, icalendar20, jcal, jcard, json, mimedir.');
|
||||
$this->log($this->colorize('green', ' --inputformat ').'If the input format cannot be guessed from the extension, it');
|
||||
$this->log(' must be specified here.');
|
||||
// Only PHP 5.4 and up
|
||||
if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||
$this->log($this->colorize('green', ' --pretty ').'json pretty-print.');
|
||||
}
|
||||
$this->log($this->colorize('green', ' --pretty ').'json pretty-print.');
|
||||
$this->log('');
|
||||
$this->log('Commands:', 'yellow');
|
||||
$this->log($this->colorize('green', ' validate').' source_file Validates a file for correctness.');
|
||||
|
|
@ -286,7 +259,7 @@ class Cli
|
|||
$this->log($this->colorize('green', ' convert').' source_file [output_file] Converts a file.');
|
||||
$this->log($this->colorize('green', ' color').' source_file Colorize a file, useful for debugging.');
|
||||
$this->log(
|
||||
<<<HELP
|
||||
<<<HELP
|
||||
|
||||
If source_file is set as '-', STDIN will be used.
|
||||
If output_file is omitted, STDOUT will be used.
|
||||
|
|
@ -306,10 +279,8 @@ HELP
|
|||
|
||||
/**
|
||||
* Validates a VObject file.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function validate(Component $vObj)
|
||||
protected function validate(Component $vObj): int
|
||||
{
|
||||
$returnCode = 0;
|
||||
|
||||
|
|
@ -346,10 +317,8 @@ HELP
|
|||
|
||||
/**
|
||||
* Repairs a VObject file.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function repair(Component $vObj)
|
||||
protected function repair(Component $vObj): int
|
||||
{
|
||||
$returnCode = 0;
|
||||
|
||||
|
|
@ -387,12 +356,8 @@ HELP
|
|||
|
||||
/**
|
||||
* Converts a vObject file to a new format.
|
||||
*
|
||||
* @param Component $vObj
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function convert($vObj)
|
||||
protected function convert(Component $vObj): int
|
||||
{
|
||||
$json = false;
|
||||
$convertVersion = null;
|
||||
|
|
@ -451,22 +416,18 @@ HELP
|
|||
|
||||
/**
|
||||
* Colorizes a file.
|
||||
*
|
||||
* @param Component $vObj
|
||||
*/
|
||||
protected function color($vObj)
|
||||
protected function color(Component $vObj): int
|
||||
{
|
||||
$this->serializeComponent($vObj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ansi color string for a color name.
|
||||
*
|
||||
* @param string $color
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function colorize($color, $str, $resetTo = 'default')
|
||||
protected function colorize(string $color, string $str, string $resetTo = 'default'): string
|
||||
{
|
||||
$colors = [
|
||||
'cyan' => '1;36',
|
||||
|
|
@ -483,16 +444,13 @@ HELP
|
|||
|
||||
/**
|
||||
* Writes out a string in specific color.
|
||||
*
|
||||
* @param string $color
|
||||
* @param string $str
|
||||
*/
|
||||
protected function cWrite($color, $str)
|
||||
protected function cWrite(string $color, string $str): void
|
||||
{
|
||||
fwrite($this->stdout, $this->colorize($color, $str));
|
||||
}
|
||||
|
||||
protected function serializeComponent(Component $vObj)
|
||||
protected function serializeComponent(Component $vObj): void
|
||||
{
|
||||
$this->cWrite('cyan', 'BEGIN');
|
||||
$this->cWrite('red', ':');
|
||||
|
|
@ -507,48 +465,40 @@ HELP
|
|||
* To avoid score collisions, each "score category" has a reasonable
|
||||
* space to accommodate elements. The $key is added to the $score to
|
||||
* preserve the original relative order of elements.
|
||||
*
|
||||
* @param int $key
|
||||
* @param array $array
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
$sortScore = function ($key, $array) {
|
||||
$sortScore = function (int $key, array $array): int {
|
||||
if ($array[$key] instanceof Component) {
|
||||
// We want to encode VTIMEZONE first, this is a personal
|
||||
// preference.
|
||||
if ('VTIMEZONE' === $array[$key]->name) {
|
||||
$score = 300000000;
|
||||
|
||||
return $score + $key;
|
||||
} else {
|
||||
$score = 400000000;
|
||||
|
||||
return $score + $key;
|
||||
}
|
||||
} else {
|
||||
// Properties get encoded first
|
||||
// VCARD version 4.0 wants the VERSION property to appear first
|
||||
if ($array[$key] instanceof Property) {
|
||||
if ('VERSION' === $array[$key]->name) {
|
||||
$score = 100000000;
|
||||
|
||||
return $score + $key;
|
||||
} else {
|
||||
// All other properties
|
||||
$score = 200000000;
|
||||
|
||||
return $score + $key;
|
||||
}
|
||||
}
|
||||
return $score + $key;
|
||||
}
|
||||
// Properties get encoded first
|
||||
// VCARD version 4.0 wants the VERSION property to appear first
|
||||
if ($array[$key] instanceof Property) {
|
||||
if ('VERSION' === $array[$key]->name) {
|
||||
$score = 100000000;
|
||||
} else {
|
||||
// All other properties
|
||||
$score = 200000000;
|
||||
}
|
||||
|
||||
return $score + $key;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
$children = $vObj->children();
|
||||
$tmp = $children;
|
||||
uksort(
|
||||
$children,
|
||||
function ($a, $b) use ($sortScore, $tmp) {
|
||||
function ($a, $b) use ($sortScore, $tmp): int {
|
||||
$sA = $sortScore($a, $tmp);
|
||||
$sB = $sortScore($b, $tmp);
|
||||
|
||||
|
|
@ -572,7 +522,7 @@ HELP
|
|||
/**
|
||||
* Colorizes a property.
|
||||
*/
|
||||
protected function serializeProperty(Property $property)
|
||||
protected function serializeProperty(Property $property): void
|
||||
{
|
||||
if ($property->group) {
|
||||
$this->cWrite('default', $property->group);
|
||||
|
|
@ -630,7 +580,7 @@ HELP
|
|||
/**
|
||||
* Parses the list of arguments.
|
||||
*/
|
||||
protected function parseArguments(array $argv)
|
||||
protected function parseArguments(array $argv): array
|
||||
{
|
||||
$positional = [];
|
||||
$options = [];
|
||||
|
|
@ -664,14 +614,16 @@ HELP
|
|||
return [$options, $positional];
|
||||
}
|
||||
|
||||
protected $parser;
|
||||
protected ?Parser $parser = null;
|
||||
|
||||
/**
|
||||
* Reads the input file.
|
||||
*
|
||||
* @return Component
|
||||
* @throws EofException
|
||||
* @throws ParseException
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
protected function readInput()
|
||||
protected function readInput(): ?Document
|
||||
{
|
||||
if (!$this->parser) {
|
||||
if ('-' !== $this->inputPath) {
|
||||
|
|
@ -679,9 +631,9 @@ HELP
|
|||
}
|
||||
|
||||
if ('mimedir' === $this->inputFormat) {
|
||||
$this->parser = new Parser\MimeDir($this->stdin, ($this->forgiving ? Reader::OPTION_FORGIVING : 0));
|
||||
$this->parser = new MimeDir($this->stdin, $this->forgiving ? Reader::OPTION_FORGIVING : 0);
|
||||
} else {
|
||||
$this->parser = new Parser\Json($this->stdin, ($this->forgiving ? Reader::OPTION_FORGIVING : 0));
|
||||
$this->parser = new Json($this->stdin, $this->forgiving ? Reader::OPTION_FORGIVING : 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -690,10 +642,8 @@ HELP
|
|||
|
||||
/**
|
||||
* Sends a message to STDERR.
|
||||
*
|
||||
* @param string $msg
|
||||
*/
|
||||
protected function log($msg, $color = 'default')
|
||||
protected function log(string $msg, string $color = 'default'): void
|
||||
{
|
||||
if (!$this->quiet) {
|
||||
if ('default' !== $color) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
use Sabre\VObject;
|
||||
use Sabre\Xml;
|
||||
|
||||
/**
|
||||
|
|
@ -13,6 +14,8 @@ use Sabre\Xml;
|
|||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*
|
||||
* @property VObject\Property\FlatText UID
|
||||
*/
|
||||
class Component extends Node
|
||||
{
|
||||
|
|
@ -20,17 +23,15 @@ class Component extends Node
|
|||
* Component name.
|
||||
*
|
||||
* This will contain a string such as VEVENT, VTODO, VCALENDAR, VCARD.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
public string $name;
|
||||
|
||||
/**
|
||||
* A list of properties and/or sub-components.
|
||||
*
|
||||
* @var array<string, Component|Property>
|
||||
*/
|
||||
protected $children = [];
|
||||
protected array $children = [];
|
||||
|
||||
/**
|
||||
* Creates a new component.
|
||||
|
|
@ -43,10 +44,9 @@ class Component extends Node
|
|||
* an iCalendar object, this may be something like CALSCALE:GREGORIAN. To
|
||||
* ensure that this does not happen, set $defaults to false.
|
||||
*
|
||||
* @param string|null $name such as VCALENDAR, VEVENT
|
||||
* @param bool $defaults
|
||||
* @param string|null $name such as VCALENDAR, VEVENT
|
||||
*/
|
||||
public function __construct(Document $root, $name, array $children = [], $defaults = true)
|
||||
public function __construct(Document $root, ?string $name, array $children = [], bool $defaults = true)
|
||||
{
|
||||
$this->name = isset($name) ? strtoupper($name) : '';
|
||||
$this->root = $root;
|
||||
|
|
@ -97,10 +97,8 @@ class Component extends Node
|
|||
* add($name, $value, array $parameters = []) // Adds a new property
|
||||
* add($name, array $children = []) // Adds a new component
|
||||
* by name.
|
||||
*
|
||||
* @return Node
|
||||
*/
|
||||
public function add()
|
||||
public function add(): Node
|
||||
{
|
||||
$arguments = func_get_args();
|
||||
|
||||
|
|
@ -116,6 +114,7 @@ class Component extends Node
|
|||
throw new \InvalidArgumentException('The first argument must either be a \\Sabre\\VObject\\Node or a string');
|
||||
}
|
||||
|
||||
/** @var Component|Property|Parameter $newNode */
|
||||
$name = $newNode->name;
|
||||
if (isset($this->children[$name])) {
|
||||
$this->children[$name][] = $newNode;
|
||||
|
|
@ -136,10 +135,10 @@ class Component extends Node
|
|||
*
|
||||
* @param string|Property|Component $item
|
||||
*/
|
||||
public function remove($item)
|
||||
public function remove($item): void
|
||||
{
|
||||
if (is_string($item)) {
|
||||
// If there's no dot in the name, it's an exact property name and
|
||||
// If there's no dot in the name, it's an exact property name,
|
||||
// we can just wipe out all those properties.
|
||||
//
|
||||
if (false === strpos($item, '.')) {
|
||||
|
|
@ -168,10 +167,8 @@ class Component extends Node
|
|||
/**
|
||||
* Returns a flat list of all the properties and components in this
|
||||
* component.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function children()
|
||||
public function children(): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($this->children as $childGroup) {
|
||||
|
|
@ -184,10 +181,8 @@ class Component extends Node
|
|||
/**
|
||||
* This method only returns a list of sub-components. Properties are
|
||||
* ignored.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getComponents()
|
||||
public function getComponents(): array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
|
|
@ -211,12 +206,8 @@ class Component extends Node
|
|||
* search for a property in a specific group, you can select on the entire
|
||||
* string ("HOME.EMAIL"). If you want to search on a specific property that
|
||||
* has not been assigned a group, specify ".EMAIL".
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function select($name)
|
||||
public function select(string $name): array
|
||||
{
|
||||
$group = null;
|
||||
$name = strtoupper($name);
|
||||
|
|
@ -228,7 +219,7 @@ class Component extends Node
|
|||
}
|
||||
|
||||
if (!is_null($name)) {
|
||||
$result = isset($this->children[$name]) ? $this->children[$name] : [];
|
||||
$result = $this->children[$name] ?? [];
|
||||
|
||||
if (is_null($group)) {
|
||||
return $result;
|
||||
|
|
@ -260,10 +251,8 @@ class Component extends Node
|
|||
|
||||
/**
|
||||
* Turns the object back into a serialized blob.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function serialize()
|
||||
public function serialize(): string
|
||||
{
|
||||
$str = 'BEGIN:'.$this->name."\r\n";
|
||||
|
||||
|
|
@ -282,42 +271,39 @@ class Component extends Node
|
|||
*
|
||||
* @return int
|
||||
*/
|
||||
$sortScore = function ($key, $array) {
|
||||
$sortScore = function (int $key, array $array): ?int {
|
||||
if ($array[$key] instanceof Component) {
|
||||
// We want to encode VTIMEZONE first, this is a personal
|
||||
// preference.
|
||||
if ('VTIMEZONE' === $array[$key]->name) {
|
||||
$score = 300000000;
|
||||
|
||||
return $score + $key;
|
||||
} else {
|
||||
$score = 400000000;
|
||||
|
||||
return $score + $key;
|
||||
}
|
||||
} else {
|
||||
// Properties get encoded first
|
||||
// VCARD version 4.0 wants the VERSION property to appear first
|
||||
if ($array[$key] instanceof Property) {
|
||||
if ('VERSION' === $array[$key]->name) {
|
||||
$score = 100000000;
|
||||
|
||||
return $score + $key;
|
||||
} else {
|
||||
// All other properties
|
||||
$score = 200000000;
|
||||
|
||||
return $score + $key;
|
||||
}
|
||||
}
|
||||
return $score + $key;
|
||||
}
|
||||
// Properties get encoded first
|
||||
// VCARD version 4.0 wants the VERSION property to appear first
|
||||
if ($array[$key] instanceof Property) {
|
||||
if ('VERSION' === $array[$key]->name) {
|
||||
$score = 100000000;
|
||||
} else {
|
||||
// All other properties
|
||||
$score = 200000000;
|
||||
}
|
||||
|
||||
return $score + $key;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
$children = $this->children();
|
||||
$tmp = $children;
|
||||
uksort(
|
||||
$children,
|
||||
function ($a, $b) use ($sortScore, $tmp) {
|
||||
function ($a, $b) use ($sortScore, $tmp): int {
|
||||
$sA = $sortScore($a, $tmp);
|
||||
$sB = $sortScore($b, $tmp);
|
||||
|
||||
|
|
@ -336,11 +322,9 @@ class Component extends Node
|
|||
/**
|
||||
* This method returns an array, with the representation as it should be
|
||||
* encoded in JSON. This is used to create jCard or jCal documents.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$components = [];
|
||||
$properties = [];
|
||||
|
|
@ -410,10 +394,8 @@ class Component extends Node
|
|||
|
||||
/**
|
||||
* This method should return a list of default property values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDefaults()
|
||||
protected function getDefaults(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
|
@ -430,11 +412,9 @@ class Component extends Node
|
|||
*
|
||||
* $event = $calendar->VEVENT;
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Property|null
|
||||
* @return Property|Component
|
||||
*/
|
||||
public function __get($name)
|
||||
public function __get(string $name): ?Node
|
||||
{
|
||||
if ('children' === $name) {
|
||||
throw new \RuntimeException('Starting sabre/vobject 4.0 the children property is now protected. You should use the children() method instead');
|
||||
|
|
@ -442,7 +422,7 @@ class Component extends Node
|
|||
|
||||
$matches = $this->select($name);
|
||||
if (0 === count($matches)) {
|
||||
return;
|
||||
return null;
|
||||
} else {
|
||||
$firstMatch = current($matches);
|
||||
/* @var $firstMatch Property */
|
||||
|
|
@ -454,12 +434,8 @@ class Component extends Node
|
|||
|
||||
/**
|
||||
* This method checks if a sub-element with the specified name exists.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name)
|
||||
public function __isset(string $name): bool
|
||||
{
|
||||
$matches = $this->select($name);
|
||||
|
||||
|
|
@ -474,11 +450,8 @@ class Component extends Node
|
|||
*
|
||||
* If the item already exists, it will be removed. If you want to add
|
||||
* a new item with the same name, always use the add() method.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
public function __set(string $name, $value): void
|
||||
{
|
||||
$name = strtoupper($name);
|
||||
$this->remove($name);
|
||||
|
|
@ -492,10 +465,8 @@ class Component extends Node
|
|||
/**
|
||||
* Removes all properties and components within this component with the
|
||||
* specified name.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function __unset($name)
|
||||
public function __unset(string $name): void
|
||||
{
|
||||
$this->remove($name);
|
||||
}
|
||||
|
|
@ -536,10 +507,8 @@ class Component extends Node
|
|||
*
|
||||
* See the VEVENT implementation for getValidationRules for a more complex
|
||||
* example.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public function getValidationRules()
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
|
@ -563,12 +532,8 @@ class Component extends Node
|
|||
* 1 - The issue was repaired (only happens if REPAIR was turned on).
|
||||
* 2 - A warning.
|
||||
* 3 - An error.
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate($options = 0)
|
||||
public function validate(int $options = 0): array
|
||||
{
|
||||
$rules = $this->getValidationRules();
|
||||
$defaults = $this->getDefaults();
|
||||
|
|
@ -659,7 +624,7 @@ class Component extends Node
|
|||
* It's intended to remove all circular references, so PHP can easily clean
|
||||
* it up.
|
||||
*/
|
||||
public function destroy()
|
||||
public function destroy(): void
|
||||
{
|
||||
parent::destroy();
|
||||
foreach ($this->children as $childGroup) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ use Sabre\VObject;
|
|||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Ivan Enderlin
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*
|
||||
* @property VObject\Property\ICalendar\DateTime DTSTART
|
||||
* @property VObject\Property\ICalendar\DateTime DTEND
|
||||
* @property VObject\Property\ICalendar\Duration DURATION
|
||||
*/
|
||||
class Available extends VObject\Component
|
||||
{
|
||||
|
|
@ -26,9 +30,9 @@ class Available extends VObject\Component
|
|||
* If either the start or end is 'unbounded' its value will be null
|
||||
* instead.
|
||||
*
|
||||
* @return array
|
||||
* @throws VObject\InvalidDataException
|
||||
*/
|
||||
public function getEffectiveStartEnd()
|
||||
public function getEffectiveStartEnd(): array
|
||||
{
|
||||
$effectiveStart = $this->DTSTART->getDateTime();
|
||||
if (isset($this->DTEND)) {
|
||||
|
|
@ -52,10 +56,8 @@ class Available extends VObject\Component
|
|||
* * + - Must appear at least once.
|
||||
* * * - Can appear any number of times.
|
||||
* * ? - May appear, but not more than once.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public function getValidationRules()
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
return [
|
||||
'UID' => 1,
|
||||
|
|
@ -101,12 +103,8 @@ class Available extends VObject\Component
|
|||
* 1 - The issue was repaired (only happens if REPAIR was turned on).
|
||||
* 2 - A warning.
|
||||
* 3 - An error.
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate($options = 0)
|
||||
public function validate(int $options = 0): array
|
||||
{
|
||||
$result = parent::validate($options);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject\Component;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Sabre\VObject;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
|
||||
|
|
@ -15,6 +13,12 @@ use Sabre\VObject\InvalidDataException;
|
|||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*
|
||||
* @property VObject\Property\ICalendar\DateTime DTSTART
|
||||
* @property VObject\Property\ICalendar\DateTime DTEND
|
||||
* @property VObject\Property\ICalendar\Duration DURATION
|
||||
* @property VObject\Property\ICalendar\Duration|VObject\Property\ICalendar\DateTime TRIGGER
|
||||
* @property VObject\Property\IntegerValue REPEAT
|
||||
*/
|
||||
class VAlarm extends VObject\Component
|
||||
{
|
||||
|
|
@ -23,15 +27,16 @@ class VAlarm extends VObject\Component
|
|||
*
|
||||
* This ignores repeated alarm, only the first trigger is returned.
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function getEffectiveTriggerTime()
|
||||
public function getEffectiveTriggerTime(): \DateTimeImmutable
|
||||
{
|
||||
$trigger = $this->TRIGGER;
|
||||
if (!isset($trigger['VALUE']) || 'DURATION' === strtoupper($trigger['VALUE'])) {
|
||||
if (!isset($trigger['VALUE']) || ($trigger['VALUE'] && 'DURATION' === strtoupper($trigger['VALUE']))) {
|
||||
$triggerDuration = VObject\DateTimeParser::parseDuration($this->TRIGGER);
|
||||
$related = (isset($trigger['RELATED']) && 'END' == strtoupper($trigger['RELATED'])) ? 'END' : 'START';
|
||||
|
||||
/** @var VEvent|VTodo $parentComponent */
|
||||
$parentComponent = $this->parent;
|
||||
if ('START' === $related) {
|
||||
if ('VTODO' === $parentComponent->name) {
|
||||
|
|
@ -41,7 +46,6 @@ class VAlarm extends VObject\Component
|
|||
}
|
||||
|
||||
$effectiveTrigger = $parentComponent->$propName->getDateTime();
|
||||
$effectiveTrigger = $effectiveTrigger->add($triggerDuration);
|
||||
} else {
|
||||
if ('VTODO' === $parentComponent->name) {
|
||||
$endProp = 'DUE';
|
||||
|
|
@ -53,17 +57,15 @@ class VAlarm extends VObject\Component
|
|||
|
||||
if (isset($parentComponent->$endProp)) {
|
||||
$effectiveTrigger = $parentComponent->$endProp->getDateTime();
|
||||
$effectiveTrigger = $effectiveTrigger->add($triggerDuration);
|
||||
} elseif (isset($parentComponent->DURATION)) {
|
||||
$effectiveTrigger = $parentComponent->DTSTART->getDateTime();
|
||||
$duration = VObject\DateTimeParser::parseDuration($parentComponent->DURATION);
|
||||
$effectiveTrigger = $effectiveTrigger->add($duration);
|
||||
$effectiveTrigger = $effectiveTrigger->add($triggerDuration);
|
||||
} else {
|
||||
$effectiveTrigger = $parentComponent->DTSTART->getDateTime();
|
||||
$effectiveTrigger = $effectiveTrigger->add($triggerDuration);
|
||||
}
|
||||
}
|
||||
$effectiveTrigger = $effectiveTrigger->add($triggerDuration);
|
||||
} else {
|
||||
$effectiveTrigger = $trigger->getDateTime();
|
||||
}
|
||||
|
|
@ -78,12 +80,9 @@ class VAlarm extends VObject\Component
|
|||
* The rules used to determine if an event falls within the specified
|
||||
* time-range is based on the CalDAV specification.
|
||||
*
|
||||
* @param DateTime $start
|
||||
* @param DateTime $end
|
||||
*
|
||||
* @return bool
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end)
|
||||
public function isInTimeRange(\DateTimeInterface $start, \DateTimeInterface $end): bool
|
||||
{
|
||||
$effectiveTrigger = $this->getEffectiveTriggerTime();
|
||||
|
||||
|
|
@ -120,10 +119,8 @@ class VAlarm extends VObject\Component
|
|||
* * + - Must appear at least once.
|
||||
* * * - Can appear any number of times.
|
||||
* * ? - May appear, but not more than once.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public function getValidationRules()
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
return [
|
||||
'ACTION' => 1,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject\Component;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
|
|
@ -14,6 +13,10 @@ use Sabre\VObject;
|
|||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Ivan Enderlin
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*
|
||||
* @property VObject\Property\ICalendar\DateTime DTSTART
|
||||
* @property VObject\Property\ICalendar\DateTime DTEND
|
||||
* @property VObject\Property\ICalendar\Duration DURATION
|
||||
*/
|
||||
class VAvailability extends VObject\Component
|
||||
{
|
||||
|
|
@ -26,15 +29,15 @@ class VAvailability extends VObject\Component
|
|||
*
|
||||
* https://tools.ietf.org/html/draft-daboo-calendar-availability-05#section-3.1
|
||||
*
|
||||
* @return bool
|
||||
* @throws VObject\InvalidDataException
|
||||
*/
|
||||
public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end)
|
||||
public function isInTimeRange(\DateTimeInterface $start, \DateTimeInterface $end): bool
|
||||
{
|
||||
list($effectiveStart, $effectiveEnd) = $this->getEffectiveStartEnd();
|
||||
|
||||
return
|
||||
(is_null($effectiveStart) || $start < $effectiveEnd) &&
|
||||
(is_null($effectiveEnd) || $end > $effectiveStart)
|
||||
(is_null($effectiveStart) || $start < $effectiveEnd)
|
||||
&& (is_null($effectiveEnd) || $end > $effectiveStart)
|
||||
;
|
||||
}
|
||||
|
||||
|
|
@ -48,9 +51,9 @@ class VAvailability extends VObject\Component
|
|||
* If either the start or end is 'unbounded' its value will be null
|
||||
* instead.
|
||||
*
|
||||
* @return array
|
||||
* @throws VObject\InvalidDataException
|
||||
*/
|
||||
public function getEffectiveStartEnd()
|
||||
public function getEffectiveStartEnd(): array
|
||||
{
|
||||
$effectiveStart = null;
|
||||
$effectiveEnd = null;
|
||||
|
|
@ -79,10 +82,8 @@ class VAvailability extends VObject\Component
|
|||
* * + - Must appear at least once.
|
||||
* * * - Can appear any number of times.
|
||||
* * ? - May appear, but not more than once.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public function getValidationRules()
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
return [
|
||||
'UID' => 1,
|
||||
|
|
@ -127,12 +128,8 @@ class VAvailability extends VObject\Component
|
|||
* 1 - The issue was repaired (only happens if REPAIR was turned on).
|
||||
* 2 - A warning.
|
||||
* 3 - An error.
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate($options = 0)
|
||||
public function validate(int $options = 0): array
|
||||
{
|
||||
$result = parent::validate($options);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject\Component;
|
||||
|
||||
use DateTimeInterface;
|
||||
use DateTimeZone;
|
||||
use Sabre\VObject;
|
||||
use Sabre\VObject\Component;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
|
|
@ -19,6 +17,11 @@ use Sabre\VObject\Recur\NoInstancesException;
|
|||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*
|
||||
* @property VEvent VEVENT
|
||||
* @property VJournal VJOURNAL
|
||||
* @property VObject\Property\Text ORG
|
||||
* @property VObject\Property\FlatText METHOD
|
||||
*/
|
||||
class VCalendar extends VObject\Document
|
||||
{
|
||||
|
|
@ -26,17 +29,13 @@ class VCalendar extends VObject\Document
|
|||
* The default name for this component.
|
||||
*
|
||||
* This should be 'VCALENDAR' or 'VCARD'.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $defaultName = 'VCALENDAR';
|
||||
public static ?string $defaultName = 'VCALENDAR';
|
||||
|
||||
/**
|
||||
* This is a list of components, and which classes they should map to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $componentMap = [
|
||||
public static array $componentMap = [
|
||||
'VCALENDAR' => self::class,
|
||||
'VALARM' => VAlarm::class,
|
||||
'VEVENT' => VEvent::class,
|
||||
|
|
@ -50,10 +49,8 @@ class VCalendar extends VObject\Document
|
|||
|
||||
/**
|
||||
* List of value-types, and which classes they map to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $valueMap = [
|
||||
public static array $valueMap = [
|
||||
'BINARY' => VObject\Property\Binary::class,
|
||||
'BOOLEAN' => VObject\Property\Boolean::class,
|
||||
'CAL-ADDRESS' => VObject\Property\ICalendar\CalAddress::class,
|
||||
|
|
@ -73,10 +70,8 @@ class VCalendar extends VObject\Document
|
|||
|
||||
/**
|
||||
* List of properties, and which classes they map to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $propertyMap = [
|
||||
public static array $propertyMap = [
|
||||
// Calendar properties
|
||||
'CALSCALE' => VObject\Property\FlatText::class,
|
||||
'METHOD' => VObject\Property\FlatText::class,
|
||||
|
|
@ -154,10 +149,8 @@ class VCalendar extends VObject\Document
|
|||
|
||||
/**
|
||||
* Returns the current document type.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getDocumentType()
|
||||
public function getDocumentType(): int
|
||||
{
|
||||
return self::ICALENDAR20;
|
||||
}
|
||||
|
|
@ -169,13 +162,13 @@ class VCalendar extends VObject\Document
|
|||
*
|
||||
* VTIMEZONE components will always be excluded.
|
||||
*
|
||||
* @param string $componentName filter by component name
|
||||
* @param string|null $componentName filter by component name
|
||||
*
|
||||
* @return VObject\Component[]
|
||||
*/
|
||||
public function getBaseComponents($componentName = null)
|
||||
public function getBaseComponents(string $componentName = null): array
|
||||
{
|
||||
$isBaseComponent = function ($component) {
|
||||
$isBaseComponent = function ($component): bool {
|
||||
if (!$component instanceof VObject\Component) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -220,13 +213,13 @@ class VCalendar extends VObject\Document
|
|||
*
|
||||
* If there is no such component, null will be returned.
|
||||
*
|
||||
* @param string $componentName filter by component name
|
||||
* @param string|null $componentName filter by component name
|
||||
*
|
||||
* @return VObject\Component|null
|
||||
*/
|
||||
public function getBaseComponent($componentName = null)
|
||||
public function getBaseComponent(string $componentName = null): ?Component
|
||||
{
|
||||
$isBaseComponent = function ($component) {
|
||||
$isBaseComponent = function ($component): bool {
|
||||
if (!$component instanceof VObject\Component) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -270,34 +263,35 @@ class VCalendar extends VObject\Document
|
|||
* can be used to expand the event into multiple sub-events.
|
||||
*
|
||||
* Each event will be stripped from its recurrence information, and only
|
||||
* the instances of the event in the specified timerange will be left
|
||||
* the instances of the event in the specified time range will be left
|
||||
* alone.
|
||||
*
|
||||
* In addition, this method will cause timezone information to be stripped,
|
||||
* and normalized to UTC.
|
||||
*
|
||||
* @param DateTimeZone $timeZone reference timezone for floating dates and
|
||||
* times
|
||||
* @param \DateTimeZone|null $timeZone reference timezone for floating dates and
|
||||
* times
|
||||
*
|
||||
* @return VCalendar
|
||||
* @throws InvalidDataException
|
||||
* @throws VObject\Recur\MaxInstancesExceededException
|
||||
*/
|
||||
public function expand(DateTimeInterface $start, DateTimeInterface $end, DateTimeZone $timeZone = null)
|
||||
public function expand(\DateTimeInterface $start, \DateTimeInterface $end, \DateTimeZone $timeZone = null): VCalendar
|
||||
{
|
||||
$newChildren = [];
|
||||
$recurringEvents = [];
|
||||
|
||||
if (!$timeZone) {
|
||||
$timeZone = new DateTimeZone('UTC');
|
||||
$timeZone = new \DateTimeZone('UTC');
|
||||
}
|
||||
|
||||
$stripTimezones = function (Component $component) use ($timeZone, &$stripTimezones) {
|
||||
$stripTimezones = function (Component $component) use ($timeZone, &$stripTimezones): Component {
|
||||
foreach ($component->children() as $componentChild) {
|
||||
if ($componentChild instanceof Property\ICalendar\DateTime && $componentChild->hasTime()) {
|
||||
$dt = $componentChild->getDateTimes($timeZone);
|
||||
// We only need to update the first timezone, because
|
||||
// setDateTimes will match all other timezones to the
|
||||
// first.
|
||||
$dt[0] = $dt[0]->setTimeZone(new DateTimeZone('UTC'));
|
||||
$dt[0] = $dt[0]->setTimeZone(new \DateTimeZone('UTC'));
|
||||
$componentChild->setDateTimes($dt);
|
||||
} elseif ($componentChild instanceof Component) {
|
||||
$stripTimezones($componentChild);
|
||||
|
|
@ -356,10 +350,8 @@ class VCalendar extends VObject\Document
|
|||
|
||||
/**
|
||||
* This method should return a list of default property values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDefaults()
|
||||
protected function getDefaults(): array
|
||||
{
|
||||
return [
|
||||
'VERSION' => '2.0',
|
||||
|
|
@ -380,10 +372,8 @@ class VCalendar extends VObject\Document
|
|||
* * + - Must appear at least once.
|
||||
* * * - Can appear any number of times.
|
||||
* * ? - May appear, but not more than once.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public function getValidationRules()
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
return [
|
||||
'PRODID' => 1,
|
||||
|
|
@ -413,12 +403,8 @@ class VCalendar extends VObject\Document
|
|||
* 1 - The issue was repaired (only happens if REPAIR was turned on).
|
||||
* 2 - A warning.
|
||||
* 3 - An error.
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate($options = 0)
|
||||
public function validate(int $options = 0): array
|
||||
{
|
||||
$warnings = parent::validate($options);
|
||||
|
||||
|
|
@ -511,10 +497,8 @@ class VCalendar extends VObject\Document
|
|||
|
||||
/**
|
||||
* Returns all components with a specific UID value.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getByUID($uid)
|
||||
public function getByUID($uid): array
|
||||
{
|
||||
return array_filter($this->getComponents(), function ($item) use ($uid) {
|
||||
if (!$itemUid = $item->select('UID')) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ use Sabre\Xml;
|
|||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*
|
||||
* @property VObject\Property\FlatText FN
|
||||
* @property VObject\Property\Text ORG
|
||||
* @property VObject\Property\FlatText EMAIL
|
||||
*/
|
||||
class VCard extends VObject\Document
|
||||
{
|
||||
|
|
@ -21,33 +25,25 @@ class VCard extends VObject\Document
|
|||
* The default name for this component.
|
||||
*
|
||||
* This should be 'VCALENDAR' or 'VCARD'.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $defaultName = 'VCARD';
|
||||
public static ?string $defaultName = 'VCARD';
|
||||
|
||||
/**
|
||||
* Caching the version number.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $version = null;
|
||||
private ?int $version = null;
|
||||
|
||||
/**
|
||||
* This is a list of components, and which classes they should map to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $componentMap = [
|
||||
public static array $componentMap = [
|
||||
'VCARD' => VCard::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* List of value-types, and which classes they map to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $valueMap = [
|
||||
public static array $valueMap = [
|
||||
'BINARY' => VObject\Property\Binary::class,
|
||||
'BOOLEAN' => VObject\Property\Boolean::class,
|
||||
'CONTENT-ID' => VObject\Property\FlatText::class, // vCard 2.1 only
|
||||
|
|
@ -69,10 +65,8 @@ class VCard extends VObject\Document
|
|||
|
||||
/**
|
||||
* List of properties, and which classes they map to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $propertyMap = [
|
||||
public static array $propertyMap = [
|
||||
// vCard 2.1 properties and up
|
||||
'N' => VObject\Property\Text::class,
|
||||
'FN' => VObject\Property\FlatText::class,
|
||||
|
|
@ -142,10 +136,8 @@ class VCard extends VObject\Document
|
|||
|
||||
/**
|
||||
* Returns the current document type.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getDocumentType()
|
||||
public function getDocumentType(): int
|
||||
{
|
||||
if (!$this->version) {
|
||||
$version = (string) $this->VERSION;
|
||||
|
|
@ -180,11 +172,9 @@ class VCard extends VObject\Document
|
|||
*
|
||||
* If input and output version are identical, a clone is returned.
|
||||
*
|
||||
* @param int $target
|
||||
*
|
||||
* @return VCard
|
||||
* @throws VObject\InvalidDataException
|
||||
*/
|
||||
public function convert($target)
|
||||
public function convert(int $target): VCard
|
||||
{
|
||||
$converter = new VObject\VCardConverter();
|
||||
|
||||
|
|
@ -196,7 +186,7 @@ class VCard extends VObject\Document
|
|||
*
|
||||
* If the VCARD doesn't know its version, 2.1 is assumed.
|
||||
*/
|
||||
const DEFAULT_VERSION = self::VCARD21;
|
||||
public const DEFAULT_VERSION = self::VCARD21;
|
||||
|
||||
/**
|
||||
* Validates the node for correctness.
|
||||
|
|
@ -215,12 +205,8 @@ class VCard extends VObject\Document
|
|||
* 1 - The issue was repaired (only happens if REPAIR was turned on)
|
||||
* 2 - An inconsequential issue
|
||||
* 3 - A severe issue.
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate($options = 0)
|
||||
public function validate(int $options = 0): array
|
||||
{
|
||||
$warnings = [];
|
||||
|
||||
|
|
@ -329,10 +315,8 @@ class VCard extends VObject\Document
|
|||
* * + - Must appear at least once.
|
||||
* * * - Can appear any number of times.
|
||||
* * ? - May appear, but not more than once.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public function getValidationRules()
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
return [
|
||||
'ADR' => '*',
|
||||
|
|
@ -386,12 +370,8 @@ class VCard extends VObject\Document
|
|||
*
|
||||
* If neither of those parameters are specified, the first is returned, if
|
||||
* a field with that name does not exist, null is returned.
|
||||
*
|
||||
* @param string $fieldName
|
||||
*
|
||||
* @return VObject\Property|null
|
||||
*/
|
||||
public function preferred($propertyName)
|
||||
public function preferred(string $propertyName): ?VObject\Property
|
||||
{
|
||||
$preferred = null;
|
||||
$lastPref = 101;
|
||||
|
|
@ -418,26 +398,23 @@ class VCard extends VObject\Document
|
|||
* This function will return null if the property does not exist. If there are
|
||||
* multiple properties with the same TYPE value, only one will be returned.
|
||||
*
|
||||
* @param string $propertyName
|
||||
* @param string $type
|
||||
*
|
||||
* @return VObject\Property|null
|
||||
* @return \ArrayAccess|array|null
|
||||
*/
|
||||
public function getByType($propertyName, $type)
|
||||
public function getByType(string $propertyName, string $type)
|
||||
{
|
||||
foreach ($this->select($propertyName) as $field) {
|
||||
if (isset($field['TYPE']) && $field['TYPE']->has($type)) {
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should return a list of default property values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDefaults()
|
||||
protected function getDefaults(): array
|
||||
{
|
||||
return [
|
||||
'VERSION' => '4.0',
|
||||
|
|
@ -449,11 +426,9 @@ class VCard extends VObject\Document
|
|||
/**
|
||||
* This method returns an array, with the representation as it should be
|
||||
* encoded in json. This is used to create jCard or jCal documents.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
// A vcard does not have sub-components, so we're overriding this
|
||||
// method to remove that array element.
|
||||
|
|
@ -472,8 +447,6 @@ class VCard extends VObject\Document
|
|||
/**
|
||||
* This method serializes the data into XML. This is used to create xCard or
|
||||
* xCal documents.
|
||||
*
|
||||
* @param Xml\Writer $writer XML writer
|
||||
*/
|
||||
public function xmlSerialize(Xml\Writer $writer): void
|
||||
{
|
||||
|
|
@ -524,12 +497,8 @@ class VCard extends VObject\Document
|
|||
|
||||
/**
|
||||
* Returns the default class for a property name.
|
||||
*
|
||||
* @param string $propertyName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClassNameForPropertyName($propertyName)
|
||||
public function getClassNameForPropertyName(string $propertyName): string
|
||||
{
|
||||
$className = parent::getClassNameForPropertyName($propertyName);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject\Component;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Sabre\VObject;
|
||||
use Sabre\VObject\Recur\EventIterator;
|
||||
use Sabre\VObject\Recur\NoInstancesException;
|
||||
|
|
@ -15,6 +14,18 @@ use Sabre\VObject\Recur\NoInstancesException;
|
|||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*
|
||||
* @property VObject\Property\ICalendar\DateTime DTSTART
|
||||
* @property VObject\Property\ICalendar\DateTime DTEND
|
||||
* @property VObject\Property\ICalendar\DateTime DTSTAMP
|
||||
* @property VObject\Property\ICalendar\Duration DURATION
|
||||
* @property VObject\Property\ICalendar\Recur RRULE
|
||||
* @property VObject\Property\ICalendar\DateTime[] EXDATE
|
||||
* @property VObject\Property\ICalendar\DateTime RDATE
|
||||
* @property VObject\Property\ICalendar\Recur EXRULE
|
||||
* @property VObject\Property\ICalendar\DateTime RECURRENCE-ID
|
||||
* @property VObject\Property\FlatText TRANSP
|
||||
* @property VObject\Property\FlatText STATUS
|
||||
*/
|
||||
class VEvent extends VObject\Component
|
||||
{
|
||||
|
|
@ -25,9 +36,10 @@ class VEvent extends VObject\Component
|
|||
* The rules used to determine if an event falls within the specified
|
||||
* time-range is based on the CalDAV specification.
|
||||
*
|
||||
* @return bool
|
||||
* @throws VObject\InvalidDataException
|
||||
* @throws VObject\Recur\MaxInstancesExceededException
|
||||
*/
|
||||
public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end)
|
||||
public function isInTimeRange(\DateTimeInterface $start, \DateTimeInterface $end): bool
|
||||
{
|
||||
if ($this->RRULE) {
|
||||
try {
|
||||
|
|
@ -44,14 +56,14 @@ class VEvent extends VObject\Component
|
|||
// recurrence instance exceeded the start of the requested
|
||||
// time-range.
|
||||
//
|
||||
// If the starttime of the recurrence did not exceed the
|
||||
// If the start time of the recurrence did not exceed the
|
||||
// end of the time range as well, we have a match.
|
||||
return $it->getDTStart() < $end && $it->getDTEnd() > $start;
|
||||
}
|
||||
|
||||
$effectiveStart = $this->DTSTART->getDateTime($start->getTimezone());
|
||||
if (isset($this->DTEND)) {
|
||||
// The DTEND property is considered non inclusive. So for a 3 day
|
||||
// The DTEND property is considered non-inclusive. So for a 3-day
|
||||
// event in july, dtstart and dtend would have to be July 1st and
|
||||
// July 4th respectively.
|
||||
//
|
||||
|
|
@ -73,10 +85,8 @@ class VEvent extends VObject\Component
|
|||
|
||||
/**
|
||||
* This method should return a list of default property values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDefaults()
|
||||
protected function getDefaults(): array
|
||||
{
|
||||
return [
|
||||
'UID' => 'sabre-vobject-'.VObject\UUIDUtil::getUUID(),
|
||||
|
|
@ -96,10 +106,8 @@ class VEvent extends VObject\Component
|
|||
* * + - Must appear at least once.
|
||||
* * * - Can appear any number of times.
|
||||
* * ? - May appear, but not more than once.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public function getValidationRules()
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
$hasMethod = isset($this->parent->METHOD);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject\Component;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
|
|
@ -14,6 +13,8 @@ use Sabre\VObject;
|
|||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*
|
||||
* @property VObject\Property\ICalendar\Period FREEBUSY
|
||||
*/
|
||||
class VFreeBusy extends VObject\Component
|
||||
{
|
||||
|
|
@ -21,9 +22,9 @@ class VFreeBusy extends VObject\Component
|
|||
* Checks based on the contained FREEBUSY information, if a timeslot is
|
||||
* available.
|
||||
*
|
||||
* @return bool
|
||||
* @throws VObject\InvalidDataException
|
||||
*/
|
||||
public function isFree(DateTimeInterface $start, DatetimeInterface $end)
|
||||
public function isFree(\DateTimeInterface $start, \DatetimeInterface $end): bool
|
||||
{
|
||||
foreach ($this->select('FREEBUSY') as $freebusy) {
|
||||
// We are only interested in FBTYPE=BUSY (the default),
|
||||
|
|
@ -69,10 +70,8 @@ class VFreeBusy extends VObject\Component
|
|||
* * + - Must appear at least once.
|
||||
* * * - Can appear any number of times.
|
||||
* * ? - May appear, but not more than once.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public function getValidationRules()
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
return [
|
||||
'UID' => 1,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject\Component;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
|
|
@ -13,6 +12,8 @@ use Sabre\VObject;
|
|||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*
|
||||
* @property VObject\Property\ICalendar\DateTime DTSTART
|
||||
*/
|
||||
class VJournal extends VObject\Component
|
||||
{
|
||||
|
|
@ -23,9 +24,9 @@ class VJournal extends VObject\Component
|
|||
* The rules used to determine if an event falls within the specified
|
||||
* time-range is based on the CalDAV specification.
|
||||
*
|
||||
* @return bool
|
||||
* @throws VObject\InvalidDataException
|
||||
*/
|
||||
public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end)
|
||||
public function isInTimeRange(\DateTimeInterface $start, \DateTimeInterface $end): bool
|
||||
{
|
||||
$dtstart = isset($this->DTSTART) ? $this->DTSTART->getDateTime() : null;
|
||||
if ($dtstart) {
|
||||
|
|
@ -52,10 +53,8 @@ class VJournal extends VObject\Component
|
|||
* * + - Must appear at least once.
|
||||
* * * - Can appear any number of times.
|
||||
* * ? - May appear, but not more than once.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public function getValidationRules()
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
return [
|
||||
'UID' => 1,
|
||||
|
|
@ -88,10 +87,8 @@ class VJournal extends VObject\Component
|
|||
|
||||
/**
|
||||
* This method should return a list of default property values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDefaults()
|
||||
protected function getDefaults(): array
|
||||
{
|
||||
return [
|
||||
'UID' => 'sabre-vobject-'.VObject\UUIDUtil::getUUID(),
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Sabre\VObject\Component;
|
||||
|
||||
use DateTimeZone;
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
|
|
@ -13,6 +14,8 @@ use Sabre\VObject;
|
|||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*
|
||||
* @property VObject\Property\FlatText TZID
|
||||
*/
|
||||
class VTimeZone extends VObject\Component
|
||||
{
|
||||
|
|
@ -21,10 +24,8 @@ class VTimeZone extends VObject\Component
|
|||
*
|
||||
* If we can't accurately determine the timezone, this method will return
|
||||
* UTC.
|
||||
*
|
||||
* @return \DateTimeZone
|
||||
*/
|
||||
public function getTimeZone()
|
||||
public function getTimeZone(): \DateTimeZone
|
||||
{
|
||||
return VObject\TimeZoneUtil::getTimeZone((string) $this->TZID, $this->root);
|
||||
}
|
||||
|
|
@ -41,10 +42,8 @@ class VTimeZone extends VObject\Component
|
|||
* * + - Must appear at least once.
|
||||
* * * - Can appear any number of times.
|
||||
* * ? - May appear, but not more than once.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public function getValidationRules()
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
return [
|
||||
'TZID' => 1,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject\Component;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
|
|
@ -13,6 +12,19 @@ use Sabre\VObject;
|
|||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*
|
||||
* @property VObject\Property\ICalendar\DateTime DTSTART
|
||||
* @property VObject\Property\ICalendar\DateTime DTEND
|
||||
* @property VObject\Property\ICalendar\DateTime DTSTAMP
|
||||
* @property VObject\Property\ICalendar\Duration DURATION
|
||||
* @property VObject\Property\ICalendar\Recur RRULE
|
||||
* @property VObject\Property\ICalendar\DateTime EXDATE
|
||||
* @property VObject\Property\ICalendar\DateTime RDATE
|
||||
* @property VObject\Property\ICalendar\Recur EXRULE
|
||||
* @property VObject\Property\ICalendar\DateTime {'RECURRENCE-ID'}
|
||||
* @property VObject\Property\ICalendar\DateTime DUE
|
||||
* @property VObject\Property\ICalendar\DateTime COMPLETED
|
||||
* @property VObject\Property\ICalendar\DateTime CREATED
|
||||
*/
|
||||
class VTodo extends VObject\Component
|
||||
{
|
||||
|
|
@ -23,9 +35,9 @@ class VTodo extends VObject\Component
|
|||
* The rules used to determine if an event falls within the specified
|
||||
* time-range is based on the CalDAV specification.
|
||||
*
|
||||
* @return bool
|
||||
* @throws VObject\InvalidDataException
|
||||
*/
|
||||
public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end)
|
||||
public function isInTimeRange(\DateTimeInterface $start, \DateTimeInterface $end): bool
|
||||
{
|
||||
$dtstart = isset($this->DTSTART) ? $this->DTSTART->getDateTime() : null;
|
||||
$duration = isset($this->DURATION) ? VObject\DateTimeParser::parseDuration($this->DURATION) : null;
|
||||
|
|
@ -40,8 +52,8 @@ class VTodo extends VObject\Component
|
|||
return $start <= $effectiveEnd && $end > $dtstart;
|
||||
} elseif ($due) {
|
||||
return
|
||||
($start < $due || $start <= $dtstart) &&
|
||||
($end > $dtstart || $end >= $due);
|
||||
($start < $due || $start <= $dtstart)
|
||||
&& ($end > $dtstart || $end >= $due);
|
||||
} else {
|
||||
return $start <= $dtstart && $end > $dtstart;
|
||||
}
|
||||
|
|
@ -51,8 +63,8 @@ class VTodo extends VObject\Component
|
|||
}
|
||||
if ($completed && $created) {
|
||||
return
|
||||
($start <= $created || $start <= $completed) &&
|
||||
($end >= $created || $end >= $completed);
|
||||
($start <= $created || $start <= $completed)
|
||||
&& ($end >= $created || $end >= $completed);
|
||||
}
|
||||
if ($completed) {
|
||||
return $start <= $completed && $end >= $completed;
|
||||
|
|
@ -76,10 +88,8 @@ class VTodo extends VObject\Component
|
|||
* * + - Must appear at least once.
|
||||
* * * - Can appear any number of times.
|
||||
* * ? - May appear, but not more than once.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public function getValidationRules()
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
return [
|
||||
'UID' => 1,
|
||||
|
|
@ -137,11 +147,9 @@ class VTodo extends VObject\Component
|
|||
* 2 - An inconsequential issue
|
||||
* 3 - A severe issue.
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
* @throws VObject\InvalidDataException
|
||||
*/
|
||||
public function validate($options = 0)
|
||||
public function validate(int $options = 0): array
|
||||
{
|
||||
$result = parent::validate($options);
|
||||
if (isset($this->DUE) && isset($this->DTSTART)) {
|
||||
|
|
@ -168,10 +176,8 @@ class VTodo extends VObject\Component
|
|||
|
||||
/**
|
||||
* This method should return a list of default property values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDefaults()
|
||||
protected function getDefaults(): array
|
||||
{
|
||||
return [
|
||||
'UID' => 'sabre-vobject-'.VObject\UUIDUtil::getUUID(),
|
||||
|
|
|
|||
|
|
@ -4,12 +4,11 @@ namespace Sabre\VObject;
|
|||
|
||||
use DateInterval;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
|
||||
/**
|
||||
* DateTimeParser.
|
||||
*
|
||||
* This class is responsible for parsing the several different date and time
|
||||
* This class is responsible for parsing the several date and time
|
||||
* formats iCalendar and vCards have.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
|
|
@ -26,12 +25,9 @@ class DateTimeParser
|
|||
* if the non-UTC format is used. The argument is used as a reference, the
|
||||
* returned DateTimeImmutable object will still be in the UTC timezone.
|
||||
*
|
||||
* @param string $dt
|
||||
* @param DateTimeZone $tz
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public static function parseDateTime($dt, DateTimeZone $tz = null)
|
||||
public static function parseDateTime(string $dt, \DateTimeZone $tz = null): \DateTimeImmutable
|
||||
{
|
||||
// Format is YYYYMMDD + "T" + hhmmss
|
||||
$result = preg_match('/^([0-9]{4})([0-1][0-9])([0-3][0-9])T([0-2][0-9])([0-5][0-9])([0-5][0-9])([Z]?)$/', $dt, $matches);
|
||||
|
|
@ -41,11 +37,11 @@ class DateTimeParser
|
|||
}
|
||||
|
||||
if ('Z' === $matches[7] || is_null($tz)) {
|
||||
$tz = new DateTimeZone('UTC');
|
||||
$tz = new \DateTimeZone('UTC');
|
||||
}
|
||||
|
||||
try {
|
||||
$date = new DateTimeImmutable($matches[1].'-'.$matches[2].'-'.$matches[3].' '.$matches[4].':'.$matches[5].':'.$matches[6], $tz);
|
||||
$date = new \DateTimeImmutable($matches[1].'-'.$matches[2].'-'.$matches[3].' '.$matches[4].':'.$matches[5].':'.$matches[6], $tz);
|
||||
} catch (\Exception $e) {
|
||||
throw new InvalidDataException('The supplied iCalendar datetime value is incorrect: '.$dt);
|
||||
}
|
||||
|
|
@ -56,12 +52,9 @@ class DateTimeParser
|
|||
/**
|
||||
* Parses an iCalendar (rfc5545) formatted date and returns a DateTimeImmutable object.
|
||||
*
|
||||
* @param string $date
|
||||
* @param DateTimeZone $tz
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public static function parseDate($date, DateTimeZone $tz = null)
|
||||
public static function parseDate(string $date, \DateTimeZone $tz = null): \DateTimeImmutable
|
||||
{
|
||||
// Format is YYYYMMDD
|
||||
$result = preg_match('/^([0-9]{4})([0-1][0-9])([0-3][0-9])$/', $date, $matches);
|
||||
|
|
@ -71,11 +64,11 @@ class DateTimeParser
|
|||
}
|
||||
|
||||
if (is_null($tz)) {
|
||||
$tz = new DateTimeZone('UTC');
|
||||
$tz = new \DateTimeZone('UTC');
|
||||
}
|
||||
|
||||
try {
|
||||
$date = new DateTimeImmutable($matches[1].'-'.$matches[2].'-'.$matches[3], $tz);
|
||||
$date = new \DateTimeImmutable($matches[1].'-'.$matches[2].'-'.$matches[3], $tz);
|
||||
} catch (\Exception $e) {
|
||||
throw new InvalidDataException('The supplied iCalendar date value is incorrect: '.$date);
|
||||
}
|
||||
|
|
@ -86,29 +79,25 @@ class DateTimeParser
|
|||
/**
|
||||
* Parses an iCalendar (RFC5545) formatted duration value.
|
||||
*
|
||||
* This method will either return a DateTimeInterval object, or a string
|
||||
* suitable for strtotime or DateTime::modify.
|
||||
* This method will return a DateTimeInterval object
|
||||
*
|
||||
* @param string $duration
|
||||
* @param bool $asString
|
||||
*
|
||||
* @return DateInterval|string
|
||||
* @throws InvalidDataException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function parseDuration($duration, $asString = false)
|
||||
public static function parseDuration(string $duration): \DateInterval
|
||||
{
|
||||
$result = preg_match('/^(?<plusminus>\+|-)?P((?<week>\d+)W)?((?<day>\d+)D)?(T((?<hour>\d+)H)?((?<minute>\d+)M)?((?<second>\d+)S)?)?$/', $duration, $matches);
|
||||
if (!$result) {
|
||||
throw new InvalidDataException('The supplied iCalendar duration value is incorrect: '.$duration);
|
||||
}
|
||||
|
||||
if (!$asString) {
|
||||
$invert = false;
|
||||
$invert = false;
|
||||
|
||||
if ('-' === $matches['plusminus']) {
|
||||
$invert = true;
|
||||
}
|
||||
if (isset($matches['plusminus']) && '-' === $matches['plusminus']) {
|
||||
$invert = true;
|
||||
}
|
||||
|
||||
$parts = [
|
||||
$parts = [
|
||||
'week',
|
||||
'day',
|
||||
'hour',
|
||||
|
|
@ -116,50 +105,64 @@ class DateTimeParser
|
|||
'second',
|
||||
];
|
||||
|
||||
foreach ($parts as $part) {
|
||||
$matches[$part] = isset($matches[$part]) && $matches[$part] ? (int) $matches[$part] : 0;
|
||||
foreach ($parts as $part) {
|
||||
$matches[$part] = isset($matches[$part]) && $matches[$part] ? (int) $matches[$part] : 0;
|
||||
}
|
||||
|
||||
// We need to re-construct the $duration string, because weeks and
|
||||
// days are not supported by DateInterval in the same string.
|
||||
$duration = 'P';
|
||||
$days = $matches['day'];
|
||||
|
||||
if ($matches['week']) {
|
||||
$days += $matches['week'] * 7;
|
||||
}
|
||||
|
||||
if ($days) {
|
||||
$duration .= $days.'D';
|
||||
}
|
||||
|
||||
if ($matches['minute'] || $matches['second'] || $matches['hour']) {
|
||||
$duration .= 'T';
|
||||
|
||||
if ($matches['hour']) {
|
||||
$duration .= $matches['hour'].'H';
|
||||
}
|
||||
|
||||
// We need to re-construct the $duration string, because weeks and
|
||||
// days are not supported by DateInterval in the same string.
|
||||
$duration = 'P';
|
||||
$days = $matches['day'];
|
||||
|
||||
if ($matches['week']) {
|
||||
$days += $matches['week'] * 7;
|
||||
if ($matches['minute']) {
|
||||
$duration .= $matches['minute'].'M';
|
||||
}
|
||||
|
||||
if ($days) {
|
||||
$duration .= $days.'D';
|
||||
if ($matches['second']) {
|
||||
$duration .= $matches['second'].'S';
|
||||
}
|
||||
}
|
||||
|
||||
if ($matches['minute'] || $matches['second'] || $matches['hour']) {
|
||||
$duration .= 'T';
|
||||
if ('P' === $duration) {
|
||||
$duration = 'PT0S';
|
||||
}
|
||||
|
||||
if ($matches['hour']) {
|
||||
$duration .= $matches['hour'].'H';
|
||||
}
|
||||
$iv = new \DateInterval($duration);
|
||||
|
||||
if ($matches['minute']) {
|
||||
$duration .= $matches['minute'].'M';
|
||||
}
|
||||
if ($invert) {
|
||||
$iv->invert = true;
|
||||
}
|
||||
|
||||
if ($matches['second']) {
|
||||
$duration .= $matches['second'].'S';
|
||||
}
|
||||
}
|
||||
return $iv;
|
||||
}
|
||||
|
||||
if ('P' === $duration) {
|
||||
$duration = 'PT0S';
|
||||
}
|
||||
|
||||
$iv = new DateInterval($duration);
|
||||
|
||||
if ($invert) {
|
||||
$iv->invert = true;
|
||||
}
|
||||
|
||||
return $iv;
|
||||
/**
|
||||
* Parses an iCalendar (RFC5545) formatted duration value.
|
||||
*
|
||||
* This method will return a string suitable for strtotime or DateTime::modify.
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public static function parseDurationAsString(string $duration): string
|
||||
{
|
||||
$result = preg_match('/^(?<plusminus>\+|-)?P((?<week>\d+)W)?((?<day>\d+)D)?(T((?<hour>\d+)H)?((?<minute>\d+)M)?((?<second>\d+)S)?)?$/', $duration, $matches);
|
||||
if (!$result) {
|
||||
throw new InvalidDataException('The supplied iCalendar duration value is incorrect: '.$duration);
|
||||
}
|
||||
|
||||
$parts = [
|
||||
|
|
@ -190,12 +193,13 @@ class DateTimeParser
|
|||
/**
|
||||
* Parses either a Date or DateTime, or Duration value.
|
||||
*
|
||||
* @param string $date
|
||||
* @param DateTimeZone|string $referenceTz
|
||||
* @param \DateTimeZone|string $referenceTz
|
||||
*
|
||||
* @return DateTimeImmutable|DateInterval
|
||||
* @return \DateInterval|\DateTimeImmutable
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public static function parse($date, $referenceTz = null)
|
||||
public static function parse(string $date, $referenceTz = null)
|
||||
{
|
||||
if ('P' === $date[0] || ('-' === $date[0] && 'P' === $date[1])) {
|
||||
return self::parseDuration($date);
|
||||
|
|
@ -258,11 +262,9 @@ class DateTimeParser
|
|||
* Times may be postfixed by a timezone offset. This can be either 'Z' for
|
||||
* UTC, or a string like -0500 or +1100.
|
||||
*
|
||||
* @param string $date
|
||||
*
|
||||
* @return array
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public static function parseVCardDateTime($date)
|
||||
public static function parseVCardDateTime(string $date): array
|
||||
{
|
||||
$regex = '/^
|
||||
(?: # date part
|
||||
|
|
@ -377,11 +379,9 @@ class DateTimeParser
|
|||
* Times may be postfixed by a timezone offset. This can be either 'Z' for
|
||||
* UTC, or a string like -0500 or +11:00.
|
||||
*
|
||||
* @param string $date
|
||||
*
|
||||
* @return array
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public static function parseVCardTime($date)
|
||||
public static function parseVCardTime(string $date): array
|
||||
{
|
||||
$regex = '/^
|
||||
(?<hour> [0-9]{2} | -)
|
||||
|
|
@ -483,11 +483,9 @@ class DateTimeParser
|
|||
* Times may be postfixed by a timezone offset. This can be either 'Z' for
|
||||
* UTC, or a string like -0500 or +1100.
|
||||
*
|
||||
* @param string $date
|
||||
*
|
||||
* @return array
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public static function parseVCardDateAndOrTime($date)
|
||||
public static function parseVCardDateAndOrTime(string $date): array
|
||||
{
|
||||
// \d{8}|\d{4}-\d\d|--\d\d(\d\d)?|---\d\d
|
||||
$valueDate = '/^(?J)(?:'.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
* Document.
|
||||
*
|
||||
|
|
@ -15,68 +17,62 @@ namespace Sabre\VObject;
|
|||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*
|
||||
* @property VObject\Property\FlatText VERSION
|
||||
*/
|
||||
abstract class Document extends Component
|
||||
{
|
||||
/**
|
||||
* Unknown document type.
|
||||
*/
|
||||
const UNKNOWN = 1;
|
||||
public const UNKNOWN = 1;
|
||||
|
||||
/**
|
||||
* vCalendar 1.0.
|
||||
*/
|
||||
const VCALENDAR10 = 2;
|
||||
public const VCALENDAR10 = 2;
|
||||
|
||||
/**
|
||||
* iCalendar 2.0.
|
||||
*/
|
||||
const ICALENDAR20 = 3;
|
||||
public const ICALENDAR20 = 3;
|
||||
|
||||
/**
|
||||
* vCard 2.1.
|
||||
*/
|
||||
const VCARD21 = 4;
|
||||
public const VCARD21 = 4;
|
||||
|
||||
/**
|
||||
* vCard 3.0.
|
||||
*/
|
||||
const VCARD30 = 5;
|
||||
public const VCARD30 = 5;
|
||||
|
||||
/**
|
||||
* vCard 4.0.
|
||||
*/
|
||||
const VCARD40 = 6;
|
||||
public const VCARD40 = 6;
|
||||
|
||||
/**
|
||||
* The default name for this component.
|
||||
*
|
||||
* This should be 'VCALENDAR' or 'VCARD'.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $defaultName;
|
||||
public static ?string $defaultName = null;
|
||||
|
||||
/**
|
||||
* List of properties, and which classes they map to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $propertyMap = [];
|
||||
public static array $propertyMap = [];
|
||||
|
||||
/**
|
||||
* List of components, along with which classes they map to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $componentMap = [];
|
||||
public static array $componentMap = [];
|
||||
|
||||
/**
|
||||
* List of value-types, and which classes they map to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $valueMap = [];
|
||||
public static array $valueMap = [];
|
||||
|
||||
/**
|
||||
* Creates a new document.
|
||||
|
|
@ -97,22 +93,20 @@ abstract class Document extends Component
|
|||
$args = func_get_args();
|
||||
$name = static::$defaultName;
|
||||
if (0 === count($args) || is_array($args[0])) {
|
||||
$children = isset($args[0]) ? $args[0] : [];
|
||||
$defaults = isset($args[1]) ? $args[1] : true;
|
||||
$children = $args[0] ?? [];
|
||||
$defaults = $args[1] ?? true;
|
||||
} else {
|
||||
$name = $args[0];
|
||||
$children = isset($args[1]) ? $args[1] : [];
|
||||
$defaults = isset($args[2]) ? $args[2] : true;
|
||||
$children = $args[1] ?? [];
|
||||
$defaults = $args[2] ?? true;
|
||||
}
|
||||
parent::__construct($this, $name, $children, $defaults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current document type.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getDocumentType()
|
||||
public function getDocumentType(): int
|
||||
{
|
||||
return self::UNKNOWN;
|
||||
}
|
||||
|
|
@ -122,13 +116,8 @@ abstract class Document extends Component
|
|||
*
|
||||
* If it's a known component, we will automatically call createComponent.
|
||||
* otherwise, we'll assume it's a property and call createProperty instead.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $arg1,... Unlimited number of args
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function create($name)
|
||||
public function create(string $name)
|
||||
{
|
||||
if (isset(static::$componentMap[strtoupper($name)])) {
|
||||
return call_user_func_array([$this, 'createComponent'], func_get_args());
|
||||
|
|
@ -150,14 +139,8 @@ abstract class Document extends Component
|
|||
* By default, a set of sensible values will be added to the component. For
|
||||
* an iCalendar object, this may be something like CALSCALE:GREGORIAN. To
|
||||
* ensure that this does not happen, set $defaults to false.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $children
|
||||
* @param bool $defaults
|
||||
*
|
||||
* @return Component
|
||||
*/
|
||||
public function createComponent($name, array $children = null, $defaults = true)
|
||||
public function createComponent(string $name, array $children = null, bool $defaults = true): Component
|
||||
{
|
||||
$name = strtoupper($name);
|
||||
$class = Component::class;
|
||||
|
|
@ -182,16 +165,13 @@ abstract class Document extends Component
|
|||
* parameters will automatically be created, or you can just pass a list of
|
||||
* Parameter objects.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
* @param array $parameters
|
||||
* @param string $valueType Force a specific valuetype, such as URI or TEXT
|
||||
* @param string|null $valueType Force a specific valueType, such as URI or TEXT
|
||||
*
|
||||
* @return Property
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function createProperty($name, $value = null, array $parameters = null, $valueType = null)
|
||||
public function createProperty(string $name, $value = null, array $parameters = null, string $valueType = null): Property
|
||||
{
|
||||
// If there's a . in the name, it means it's prefixed by a groupname.
|
||||
// If there's a . in the name, it means it's prefixed by a group name.
|
||||
if (false !== ($i = strpos($name, '.'))) {
|
||||
$group = substr($name, 0, $i);
|
||||
$name = strtoupper(substr($name, $i + 1));
|
||||
|
|
@ -234,11 +214,9 @@ abstract class Document extends Component
|
|||
*
|
||||
* This method returns null if we don't have a specialized class.
|
||||
*
|
||||
* @param string $valueParam
|
||||
*
|
||||
* @return string|null
|
||||
* @return string|void|null
|
||||
*/
|
||||
public function getClassNameForPropertyValue($valueParam)
|
||||
public function getClassNameForPropertyValue(string $valueParam)
|
||||
{
|
||||
$valueParam = strtoupper($valueParam);
|
||||
if (isset(static::$valueMap[$valueParam])) {
|
||||
|
|
@ -248,17 +226,9 @@ abstract class Document extends Component
|
|||
|
||||
/**
|
||||
* Returns the default class for a property name.
|
||||
*
|
||||
* @param string $propertyName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClassNameForPropertyName($propertyName)
|
||||
public function getClassNameForPropertyName(string $propertyName): string
|
||||
{
|
||||
if (isset(static::$propertyMap[$propertyName])) {
|
||||
return static::$propertyMap[$propertyName];
|
||||
} else {
|
||||
return Property\Unknown::class;
|
||||
}
|
||||
return static::$propertyMap[$propertyName] ?? Property\Unknown::class;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
use ArrayIterator;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* VObject ElementList.
|
||||
*
|
||||
|
|
@ -15,20 +12,19 @@ use LogicException;
|
|||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class ElementList extends ArrayIterator
|
||||
class ElementList extends \ArrayIterator
|
||||
{
|
||||
/* {{{ ArrayAccess Interface */
|
||||
|
||||
/**
|
||||
* Sets an item through ArrayAccess.
|
||||
*
|
||||
* @param int $offset
|
||||
* @param mixed $value
|
||||
* @param int $offset
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetSet($offset, $value)
|
||||
public function offsetSet($offset, $value): void
|
||||
{
|
||||
throw new LogicException('You can not add new objects to an ElementList');
|
||||
throw new \LogicException('You can not add new objects to an ElementList');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -39,9 +35,9 @@ class ElementList extends ArrayIterator
|
|||
* @param int $offset
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetUnset($offset)
|
||||
public function offsetUnset($offset): void
|
||||
{
|
||||
throw new LogicException('You can not remove objects from an ElementList');
|
||||
throw new \LogicException('You can not remove objects from an ElementList');
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
|
|
|||
|
|
@ -13,26 +13,20 @@ class FreeBusyData
|
|||
{
|
||||
/**
|
||||
* Start timestamp.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $start;
|
||||
protected int $start;
|
||||
|
||||
/**
|
||||
* End timestamp.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $end;
|
||||
protected int $end;
|
||||
|
||||
/**
|
||||
* A list of free-busy times.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $data;
|
||||
protected array $data;
|
||||
|
||||
public function __construct($start, $end)
|
||||
public function __construct(int $start, int $end)
|
||||
{
|
||||
$this->start = $start;
|
||||
$this->end = $end;
|
||||
|
|
@ -46,16 +40,14 @@ class FreeBusyData
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds free or busytime to the data.
|
||||
* Adds free or busy time to the data.
|
||||
*
|
||||
* @param int $start
|
||||
* @param int $end
|
||||
* @param string $type FREE, BUSY, BUSY-UNAVAILABLE or BUSY-TENTATIVE
|
||||
* @param string $type FREE, BUSY, BUSY-UNAVAILABLE or BUSY-TENTATIVE
|
||||
*/
|
||||
public function add($start, $end, $type)
|
||||
public function add(int $start, int $end, string $type): void
|
||||
{
|
||||
if ($start > $this->end || $end < $this->start) {
|
||||
// This new data is outside our timerange.
|
||||
// This new data is outside our time range.
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +170,7 @@ class FreeBusyData
|
|||
}
|
||||
}
|
||||
|
||||
public function getData()
|
||||
public function getData(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use DateTimeZone;
|
||||
use Sabre\VObject\Component\VCalendar;
|
||||
use Sabre\VObject\Component\VEvent;
|
||||
use Sabre\VObject\Component\VFreeBusy;
|
||||
use Sabre\VObject\Property\ICalendar\DateTime;
|
||||
use Sabre\VObject\Recur\EventIterator;
|
||||
use Sabre\VObject\Recur\NoInstancesException;
|
||||
|
||||
|
|
@ -27,31 +27,23 @@ class FreeBusyGenerator
|
|||
{
|
||||
/**
|
||||
* Input objects.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $objects = [];
|
||||
protected array $objects = [];
|
||||
|
||||
/**
|
||||
* Start of range.
|
||||
*
|
||||
* @var DateTimeInterface|null
|
||||
*/
|
||||
protected $start;
|
||||
protected ?\DateTimeInterface $start;
|
||||
|
||||
/**
|
||||
* End of range.
|
||||
*
|
||||
* @var DateTimeInterface|null
|
||||
*/
|
||||
protected $end;
|
||||
protected ?\DateTimeInterface $end;
|
||||
|
||||
/**
|
||||
* VCALENDAR object.
|
||||
*
|
||||
* @var Document
|
||||
*/
|
||||
protected $baseObject;
|
||||
protected ?Document $baseObject = null;
|
||||
|
||||
/**
|
||||
* Reference timezone.
|
||||
|
|
@ -63,33 +55,24 @@ class FreeBusyGenerator
|
|||
* This is also used for all-day events.
|
||||
*
|
||||
* This defaults to UTC.
|
||||
*
|
||||
* @var DateTimeZone
|
||||
*/
|
||||
protected $timeZone;
|
||||
protected \DateTimeZone $timeZone;
|
||||
|
||||
/**
|
||||
* A VAVAILABILITY document.
|
||||
*
|
||||
* If this is set, its information will be included when calculating
|
||||
* freebusy time.
|
||||
*
|
||||
* @var Document
|
||||
*/
|
||||
protected $vavailability;
|
||||
protected ?Document $vavailability = null;
|
||||
|
||||
/**
|
||||
* Creates the generator.
|
||||
*
|
||||
* Check the setTimeRange and setObjects methods for details about the
|
||||
* arguments.
|
||||
*
|
||||
* @param DateTimeInterface $start
|
||||
* @param DateTimeInterface $end
|
||||
* @param mixed $objects
|
||||
* @param DateTimeZone $timeZone
|
||||
*/
|
||||
public function __construct(DateTimeInterface $start = null, DateTimeInterface $end = null, $objects = null, DateTimeZone $timeZone = null)
|
||||
public function __construct(\DateTimeInterface $start = null, \DateTimeInterface $end = null, $objects = null, \DateTimeZone $timeZone = null)
|
||||
{
|
||||
$this->setTimeRange($start, $end);
|
||||
|
||||
|
|
@ -97,7 +80,7 @@ class FreeBusyGenerator
|
|||
$this->setObjects($objects);
|
||||
}
|
||||
if (is_null($timeZone)) {
|
||||
$timeZone = new DateTimeZone('UTC');
|
||||
$timeZone = new \DateTimeZone('UTC');
|
||||
}
|
||||
$this->setTimeZone($timeZone);
|
||||
}
|
||||
|
|
@ -110,7 +93,7 @@ class FreeBusyGenerator
|
|||
*
|
||||
* The VFREEBUSY object will be automatically added though.
|
||||
*/
|
||||
public function setBaseObject(Document $vcalendar)
|
||||
public function setBaseObject(Document $vcalendar): void
|
||||
{
|
||||
$this->baseObject = $vcalendar;
|
||||
}
|
||||
|
|
@ -118,7 +101,7 @@ class FreeBusyGenerator
|
|||
/**
|
||||
* Sets a VAVAILABILITY document.
|
||||
*/
|
||||
public function setVAvailability(Document $vcalendar)
|
||||
public function setVAvailability(Document $vcalendar): void
|
||||
{
|
||||
$this->vavailability = $vcalendar;
|
||||
}
|
||||
|
|
@ -129,10 +112,8 @@ class FreeBusyGenerator
|
|||
* You must either specify a vcalendar object as a string, or as the parse
|
||||
* Component.
|
||||
* It's also possible to specify multiple objects as an array.
|
||||
*
|
||||
* @param mixed $objects
|
||||
*/
|
||||
public function setObjects($objects)
|
||||
public function setObjects($objects): void
|
||||
{
|
||||
if (!is_array($objects)) {
|
||||
$objects = [$objects];
|
||||
|
|
@ -153,18 +134,17 @@ class FreeBusyGenerator
|
|||
/**
|
||||
* Sets the time range.
|
||||
*
|
||||
* Any freebusy object falling outside of this time range will be ignored.
|
||||
* Any freebusy object falling outside this time range will be ignored.
|
||||
*
|
||||
* @param DateTimeInterface $start
|
||||
* @param DateTimeInterface $end
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function setTimeRange(DateTimeInterface $start = null, DateTimeInterface $end = null)
|
||||
public function setTimeRange(\DateTimeInterface $start = null, \DateTimeInterface $end = null): void
|
||||
{
|
||||
if (!$start) {
|
||||
$start = new DateTimeImmutable(Settings::$minDate);
|
||||
$start = new \DateTimeImmutable(Settings::$minDate);
|
||||
}
|
||||
if (!$end) {
|
||||
$end = new DateTimeImmutable(Settings::$maxDate);
|
||||
$end = new \DateTimeImmutable(Settings::$maxDate);
|
||||
}
|
||||
$this->start = $start;
|
||||
$this->end = $end;
|
||||
|
|
@ -173,7 +153,7 @@ class FreeBusyGenerator
|
|||
/**
|
||||
* Sets the reference timezone for floating times.
|
||||
*/
|
||||
public function setTimeZone(DateTimeZone $timeZone)
|
||||
public function setTimeZone(\DateTimeZone $timeZone): void
|
||||
{
|
||||
$this->timeZone = $timeZone;
|
||||
}
|
||||
|
|
@ -181,16 +161,14 @@ class FreeBusyGenerator
|
|||
/**
|
||||
* Parses the input data and returns a correct VFREEBUSY object, wrapped in
|
||||
* a VCALENDAR.
|
||||
*
|
||||
* @return Component
|
||||
*/
|
||||
public function getResult()
|
||||
public function getResult(): Component
|
||||
{
|
||||
$fbData = new FreeBusyData(
|
||||
$this->start->getTimeStamp(),
|
||||
$this->end->getTimeStamp()
|
||||
);
|
||||
if ($this->vavailability) {
|
||||
if (null !== $this->vavailability) {
|
||||
$this->calculateAvailability($fbData, $this->vavailability);
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +181,7 @@ class FreeBusyGenerator
|
|||
* This method takes a VAVAILABILITY component and figures out all the
|
||||
* available times.
|
||||
*/
|
||||
protected function calculateAvailability(FreeBusyData $fbData, VCalendar $vavailability)
|
||||
protected function calculateAvailability(FreeBusyData $fbData, VCalendar $vavailability): void
|
||||
{
|
||||
$vavailComps = iterator_to_array($vavailability->VAVAILABILITY);
|
||||
usort(
|
||||
|
|
@ -231,7 +209,7 @@ class FreeBusyGenerator
|
|||
// Now we go over all the VAVAILABILITY components and figure if
|
||||
// there's any we don't need to consider.
|
||||
//
|
||||
// This is can be because of one of two reasons: either the
|
||||
// This is because of one of two reasons: either the
|
||||
// VAVAILABILITY component falls outside the time we are interested in,
|
||||
// or a different VAVAILABILITY component with a higher priority has
|
||||
// already completely covered the time-range.
|
||||
|
|
@ -241,7 +219,7 @@ class FreeBusyGenerator
|
|||
foreach ($old as $vavail) {
|
||||
list($compStart, $compEnd) = $vavail->getEffectiveStartEnd();
|
||||
|
||||
// We don't care about datetimes that are earlier or later than the
|
||||
// We don't care about date-times that are earlier or later than the
|
||||
// start and end of the freebusy report, so this gets normalized
|
||||
// first.
|
||||
if (is_null($compStart) || $compStart < $this->start) {
|
||||
|
|
@ -251,7 +229,7 @@ class FreeBusyGenerator
|
|||
$compEnd = $this->end;
|
||||
}
|
||||
|
||||
// If the item fell out of the timerange, we can just skip it.
|
||||
// If the item fell out of the time range, we can just skip it.
|
||||
if ($compStart > $this->end || $compEnd < $this->start) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -261,8 +239,8 @@ class FreeBusyGenerator
|
|||
foreach ($new as $higherVavail) {
|
||||
list($higherStart, $higherEnd) = $higherVavail->getEffectiveStartEnd();
|
||||
if (
|
||||
(is_null($higherStart) || $higherStart < $compStart) &&
|
||||
(is_null($higherEnd) || $higherEnd > $compEnd)
|
||||
(is_null($higherStart) || $higherStart < $compStart)
|
||||
&& (is_null($higherEnd) || $higherEnd > $compEnd)
|
||||
) {
|
||||
// Component is fully covered by a higher priority
|
||||
// component. We can skip this component.
|
||||
|
|
@ -305,18 +283,18 @@ class FreeBusyGenerator
|
|||
foreach ($vavail->AVAILABLE as $available) {
|
||||
list($availStart, $availEnd) = $available->getEffectiveStartEnd();
|
||||
$fbData->add(
|
||||
$availStart->getTimeStamp(),
|
||||
$availEnd->getTimeStamp(),
|
||||
'FREE'
|
||||
);
|
||||
$availStart->getTimeStamp(),
|
||||
$availEnd->getTimeStamp(),
|
||||
'FREE'
|
||||
);
|
||||
|
||||
if ($available->RRULE) {
|
||||
// Our favourite thing: recurrence!!
|
||||
|
||||
$rruleIterator = new Recur\RRuleIterator(
|
||||
$available->RRULE->getValue(),
|
||||
$availStart
|
||||
);
|
||||
$available->RRULE->getValue(),
|
||||
$availStart
|
||||
);
|
||||
$rruleIterator->fastForward($vavailStart);
|
||||
|
||||
$startEndDiff = $availStart->diff($availEnd);
|
||||
|
|
@ -326,7 +304,7 @@ class FreeBusyGenerator
|
|||
$recurEnd = $recurStart->add($startEndDiff);
|
||||
|
||||
if ($recurStart > $vavailEnd) {
|
||||
// We're beyond the legal timerange.
|
||||
// We're beyond the legal time range.
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -337,10 +315,10 @@ class FreeBusyGenerator
|
|||
}
|
||||
|
||||
$fbData->add(
|
||||
$recurStart->getTimeStamp(),
|
||||
$recurEnd->getTimeStamp(),
|
||||
'FREE'
|
||||
);
|
||||
$recurStart->getTimeStamp(),
|
||||
$recurEnd->getTimeStamp(),
|
||||
'FREE'
|
||||
);
|
||||
|
||||
$rruleIterator->next();
|
||||
}
|
||||
|
|
@ -355,13 +333,16 @@ class FreeBusyGenerator
|
|||
* times on fbData.
|
||||
*
|
||||
* @param VCalendar[] $objects
|
||||
*
|
||||
* @throws InvalidDataException|Recur\MaxInstancesExceededException
|
||||
*/
|
||||
protected function calculateBusy(FreeBusyData $fbData, array $objects)
|
||||
protected function calculateBusy(FreeBusyData $fbData, array $objects): void
|
||||
{
|
||||
foreach ($objects as $key => $object) {
|
||||
foreach ($object->getBaseComponents() as $component) {
|
||||
switch ($component->name) {
|
||||
case 'VEVENT':
|
||||
/** @var VEvent $component */
|
||||
$FBTYPE = 'BUSY';
|
||||
if (isset($component->TRANSP) && ('TRANSPARENT' === strtoupper($component->TRANSP))) {
|
||||
break;
|
||||
|
|
@ -447,6 +428,7 @@ class FreeBusyGenerator
|
|||
break;
|
||||
|
||||
case 'VFREEBUSY':
|
||||
/** @var VFreeBusy $component */
|
||||
foreach ($component->FREEBUSY as $freebusy) {
|
||||
$fbType = isset($freebusy['FBTYPE']) ? strtoupper($freebusy['FBTYPE']) : 'BUSY';
|
||||
|
||||
|
|
@ -491,11 +473,12 @@ class FreeBusyGenerator
|
|||
* This method takes a FreeBusyData object and generates the VCALENDAR
|
||||
* object associated with it.
|
||||
*
|
||||
* @return VCalendar
|
||||
* @throws InvalidDataException
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function generateFreeBusyCalendar(FreeBusyData $fbData)
|
||||
protected function generateFreeBusyCalendar(FreeBusyData $fbData): VCalendar
|
||||
{
|
||||
if ($this->baseObject) {
|
||||
if (null !== $this->baseObject) {
|
||||
$calendar = $this->baseObject;
|
||||
} else {
|
||||
$calendar = new VCalendar();
|
||||
|
|
@ -505,19 +488,22 @@ class FreeBusyGenerator
|
|||
$calendar->add($vfreebusy);
|
||||
|
||||
if ($this->start) {
|
||||
/** @var DateTime $dtstart */
|
||||
$dtstart = $calendar->createProperty('DTSTART');
|
||||
$dtstart->setDateTime($this->start);
|
||||
$vfreebusy->add($dtstart);
|
||||
}
|
||||
if ($this->end) {
|
||||
/** @var DateTime $dtend */
|
||||
$dtend = $calendar->createProperty('DTEND');
|
||||
$dtend->setDateTime($this->end);
|
||||
$vfreebusy->add($dtend);
|
||||
}
|
||||
|
||||
$tz = new \DateTimeZone('UTC');
|
||||
/** @var DateTime $dtstamp */
|
||||
$dtstamp = $calendar->createProperty('DTSTAMP');
|
||||
$dtstamp->setDateTime(new DateTimeImmutable('now', $tz));
|
||||
$dtstamp->setDateTime(new \DateTimeImmutable('now', $tz));
|
||||
$vfreebusy->add($dtstamp);
|
||||
|
||||
foreach ($fbData->getData() as $busyTime) {
|
||||
|
|
|
|||
|
|
@ -3,9 +3,14 @@
|
|||
namespace Sabre\VObject\ITip;
|
||||
|
||||
use Sabre\VObject\Component\VCalendar;
|
||||
use Sabre\VObject\Component\VEvent;
|
||||
use Sabre\VObject\DateTimeParser;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
use Sabre\VObject\ParseException;
|
||||
use Sabre\VObject\Reader;
|
||||
use Sabre\VObject\Recur\EventIterator;
|
||||
use Sabre\VObject\Recur\MaxInstancesExceededException;
|
||||
use Sabre\VObject\Recur\NoInstancesException;
|
||||
|
||||
/**
|
||||
* The ITip\Broker class is a utility class that helps with processing
|
||||
|
|
@ -13,7 +18,7 @@ use Sabre\VObject\Recur\EventIterator;
|
|||
*
|
||||
* iTip is defined in rfc5546, stands for iCalendar Transport-Independent
|
||||
* Interoperability Protocol, and describes the underlying mechanism for
|
||||
* using iCalendar for scheduling for for example through email (also known as
|
||||
* using iCalendar for scheduling, for example, through email (also known as
|
||||
* IMip) and CalDAV Scheduling.
|
||||
*
|
||||
* This class helps by:
|
||||
|
|
@ -27,7 +32,7 @@ use Sabre\VObject\Recur\EventIterator;
|
|||
* a received invite.
|
||||
* 4. It can also process an invite update on a local event, ensuring that any
|
||||
* overridden properties from attendees are retained.
|
||||
* 5. It can create a accepted or declined iTip reply based on an invite.
|
||||
* 5. It can create an accepted or declined iTip reply based on an invite.
|
||||
* 6. It can process a reply from an invite and update an events attendee
|
||||
* status based on a reply.
|
||||
*
|
||||
|
|
@ -49,10 +54,8 @@ class Broker
|
|||
* CLIENT will be ignored. This is the desired behavior for a CalDAV
|
||||
* server, but if you're writing an iTip application that doesn't deal with
|
||||
* CalDAV, you may want to ignore this parameter.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $scheduleAgentServerRules = true;
|
||||
public bool $scheduleAgentServerRules = true;
|
||||
|
||||
/**
|
||||
* The broker will try during 'parseEvent' figure out whether the change
|
||||
|
|
@ -66,7 +69,7 @@ class Broker
|
|||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $significantChangeProperties = [
|
||||
public array $significantChangeProperties = [
|
||||
'DTSTART',
|
||||
'DTEND',
|
||||
'DURATION',
|
||||
|
|
@ -104,9 +107,11 @@ class Broker
|
|||
*
|
||||
* If the iTip message was not supported, we will always return false.
|
||||
*
|
||||
* @param VCalendar $existingObject
|
||||
* @return VCalendar|false|void|null
|
||||
*
|
||||
* @return VCalendar|null
|
||||
* @throws InvalidDataException
|
||||
* @throws MaxInstancesExceededException
|
||||
* @throws NoInstancesException
|
||||
*/
|
||||
public function processMessage(Message $itipMessage, VCalendar $existingObject = null)
|
||||
{
|
||||
|
|
@ -129,8 +134,6 @@ class Broker
|
|||
// Unsupported iTip message
|
||||
return;
|
||||
}
|
||||
|
||||
return $existingObject;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -156,13 +159,16 @@ class Broker
|
|||
* people. If the user was an attendee, we need to make sure that the
|
||||
* organizer gets the 'declined' message.
|
||||
*
|
||||
* @param VCalendar|string $calendar
|
||||
* @param string|array $userHref
|
||||
* @param VCalendar|string $oldCalendar
|
||||
* @param VCalendar|string $calendar
|
||||
* @param string|array $userHref
|
||||
* @param VCalendar|string|null $oldCalendar
|
||||
*
|
||||
* @return array
|
||||
* @throws ITipException
|
||||
* @throws InvalidDataException
|
||||
* @throws ParseException
|
||||
* @throws SameOrganizerForAllComponentsException
|
||||
*/
|
||||
public function parseEvent($calendar, $userHref, $oldCalendar = null)
|
||||
public function parseEvent($calendar, $userHref, $oldCalendar = null): array
|
||||
{
|
||||
if ($oldCalendar) {
|
||||
if (is_string($oldCalendar)) {
|
||||
|
|
@ -216,7 +222,7 @@ class Broker
|
|||
// The calendar object got deleted, we need to process this as a
|
||||
// cancellation / decline.
|
||||
if (!$oldCalendar) {
|
||||
// No old and no new calendar, there's no thing to do.
|
||||
// No old and no new calendar, there's nothing to do.
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
@ -261,20 +267,13 @@ class Broker
|
|||
*
|
||||
* This is message from an organizer, and is either a new event
|
||||
* invite, or an update to an existing one.
|
||||
*
|
||||
* @param VCalendar $existingObject
|
||||
*
|
||||
* @return VCalendar|null
|
||||
*/
|
||||
protected function processMessageRequest(Message $itipMessage, VCalendar $existingObject = null)
|
||||
protected function processMessageRequest(Message $itipMessage, VCalendar $existingObject = null): ?VCalendar
|
||||
{
|
||||
if (!$existingObject) {
|
||||
// This is a new invite, and we're just going to copy over
|
||||
// all the components from the invite.
|
||||
$existingObject = new VCalendar();
|
||||
foreach ($itipMessage->message->getComponents() as $component) {
|
||||
$existingObject->add(clone $component);
|
||||
}
|
||||
} else {
|
||||
// We need to update an existing object with all the new
|
||||
// information. We can just remove all existing components
|
||||
|
|
@ -282,9 +281,9 @@ class Broker
|
|||
foreach ($existingObject->getComponents() as $component) {
|
||||
$existingObject->remove($component);
|
||||
}
|
||||
foreach ($itipMessage->message->getComponents() as $component) {
|
||||
$existingObject->add(clone $component);
|
||||
}
|
||||
}
|
||||
foreach ($itipMessage->message->getComponents() as $component) {
|
||||
$existingObject->add(clone $component);
|
||||
}
|
||||
|
||||
return $existingObject;
|
||||
|
|
@ -296,12 +295,8 @@ class Broker
|
|||
* This is a message from an organizer, and means that either an
|
||||
* attendee got removed from an event, or an event got cancelled
|
||||
* altogether.
|
||||
*
|
||||
* @param VCalendar $existingObject
|
||||
*
|
||||
* @return VCalendar|null
|
||||
*/
|
||||
protected function processMessageCancel(Message $itipMessage, VCalendar $existingObject = null)
|
||||
protected function processMessageCancel(Message $itipMessage, VCalendar $existingObject = null): ?VCalendar
|
||||
{
|
||||
if (!$existingObject) {
|
||||
// The event didn't exist in the first place, so we're just
|
||||
|
|
@ -322,16 +317,16 @@ class Broker
|
|||
* The message is a reply. This is for example an attendee telling
|
||||
* an organizer he accepted the invite, or declined it.
|
||||
*
|
||||
* @param VCalendar $existingObject
|
||||
*
|
||||
* @return VCalendar|null
|
||||
* @throws InvalidDataException
|
||||
* @throws MaxInstancesExceededException
|
||||
* @throws NoInstancesException
|
||||
*/
|
||||
protected function processMessageReply(Message $itipMessage, VCalendar $existingObject = null)
|
||||
protected function processMessageReply(Message $itipMessage, VCalendar $existingObject = null): ?VCalendar
|
||||
{
|
||||
// A reply can only be processed based on an existing object.
|
||||
// If the object is not available, the reply is ignored.
|
||||
if (!$existingObject) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
$instances = [];
|
||||
$requestStatus = '2.0';
|
||||
|
|
@ -386,7 +381,7 @@ class Broker
|
|||
|
||||
if (!$masterObject) {
|
||||
// No master object, we can't add new instances.
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
// If we got replies to instances that did not exist in the
|
||||
// original list, it means that new exceptions must be created.
|
||||
|
|
@ -446,10 +441,8 @@ class Broker
|
|||
*
|
||||
* We will detect which attendees got added, which got removed and create
|
||||
* specific messages for these situations.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function parseEventForOrganizer(VCalendar $calendar, array $eventInfo, array $oldEventInfo)
|
||||
protected function parseEventForOrganizer(VCalendar $calendar, array $eventInfo, array $oldEventInfo): array
|
||||
{
|
||||
// Merging attendee lists.
|
||||
$attendees = [];
|
||||
|
|
@ -511,6 +504,7 @@ class Broker
|
|||
|
||||
$icalMsg->METHOD = $message->method;
|
||||
|
||||
/** @var VEvent $event */
|
||||
$event = $icalMsg->add('VEVENT', [
|
||||
'UID' => $message->uid,
|
||||
'SEQUENCE' => $message->sequence,
|
||||
|
|
@ -551,10 +545,10 @@ class Broker
|
|||
$newAttendeeInstances = array_keys($attendee['newInstances']);
|
||||
|
||||
$message->significantChange =
|
||||
'REQUEST' === $attendee['forceSend'] ||
|
||||
count($oldAttendeeInstances) != count($newAttendeeInstances) ||
|
||||
count(array_diff($oldAttendeeInstances, $newAttendeeInstances)) > 0 ||
|
||||
$oldEventInfo['significantChangeHash'] !== $eventInfo['significantChangeHash'];
|
||||
'REQUEST' === $attendee['forceSend']
|
||||
|| count($oldAttendeeInstances) != count($newAttendeeInstances)
|
||||
|| count(array_diff($oldAttendeeInstances, $newAttendeeInstances)) > 0
|
||||
|| $oldEventInfo['significantChangeHash'] !== $eventInfo['significantChangeHash'];
|
||||
|
||||
foreach ($attendee['newInstances'] as $instanceId => $instanceInfo) {
|
||||
$currentEvent = clone $eventInfo['instances'][$instanceId];
|
||||
|
|
@ -615,11 +609,11 @@ class Broker
|
|||
*
|
||||
* This function figures out if we need to send a reply to an organizer.
|
||||
*
|
||||
* @param string $attendee
|
||||
*
|
||||
* @return Message[]
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
protected function parseEventForAttendee(VCalendar $calendar, array $eventInfo, array $oldEventInfo, $attendee)
|
||||
protected function parseEventForAttendee(VCalendar $calendar, array $eventInfo, array $oldEventInfo, string $attendee): array
|
||||
{
|
||||
if ($this->scheduleAgentServerRules && 'CLIENT' === $eventInfo['organizerScheduleAgent']) {
|
||||
return [];
|
||||
|
|
@ -710,6 +704,7 @@ class Broker
|
|||
continue;
|
||||
}
|
||||
|
||||
/** @var VEvent $event */
|
||||
$event = $icalMsg->add('VEVENT', [
|
||||
'UID' => $message->uid,
|
||||
'SEQUENCE' => $message->sequence,
|
||||
|
|
@ -796,11 +791,10 @@ class Broker
|
|||
* 11. significantChangeHash
|
||||
* 12. status
|
||||
*
|
||||
* @param VCalendar $calendar
|
||||
*
|
||||
* @return array
|
||||
* @throws ITipException
|
||||
* @throws SameOrganizerForAllComponentsException
|
||||
*/
|
||||
protected function parseEventInfo(VCalendar $calendar = null)
|
||||
protected function parseEventInfo(VCalendar $calendar): array
|
||||
{
|
||||
$uid = null;
|
||||
$organizer = null;
|
||||
|
|
@ -811,8 +805,6 @@ class Broker
|
|||
$status = null;
|
||||
$organizerScheduleAgent = 'SERVER';
|
||||
|
||||
$significantChangeHash = '';
|
||||
|
||||
// Now we need to collect a list of attendees, and which instances they
|
||||
// are a part of.
|
||||
$attendees = [];
|
||||
|
|
@ -841,7 +833,7 @@ class Broker
|
|||
if (isset($vevent->ORGANIZER)) {
|
||||
if (is_null($organizer)) {
|
||||
$organizer = $vevent->ORGANIZER->getNormalizedValue();
|
||||
$organizerName = isset($vevent->ORGANIZER['CN']) ? $vevent->ORGANIZER['CN'] : null;
|
||||
$organizerName = $vevent->ORGANIZER['CN'] ?? null;
|
||||
} else {
|
||||
if (strtoupper($organizer) !== strtoupper($vevent->ORGANIZER->getNormalizedValue())) {
|
||||
throw new SameOrganizerForAllComponentsException('Every instance of the event must have the same organizer.');
|
||||
|
|
@ -894,9 +886,9 @@ class Broker
|
|||
}
|
||||
if (isset($vevent->ATTENDEE)) {
|
||||
foreach ($vevent->ATTENDEE as $attendee) {
|
||||
if ($this->scheduleAgentServerRules &&
|
||||
isset($attendee['SCHEDULE-AGENT']) &&
|
||||
'CLIENT' === strtoupper($attendee['SCHEDULE-AGENT']->getValue())
|
||||
if ($this->scheduleAgentServerRules
|
||||
&& isset($attendee['SCHEDULE-AGENT'])
|
||||
&& 'CLIENT' === strtoupper($attendee['SCHEDULE-AGENT']->getValue())
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -955,9 +947,7 @@ class Broker
|
|||
|
||||
asort($significantChangeEventProperties);
|
||||
|
||||
foreach ($significantChangeEventProperties as $eventSignificantChangeHash) {
|
||||
$significantChangeHash .= $eventSignificantChangeHash;
|
||||
}
|
||||
$significantChangeHash = implode('', $significantChangeEventProperties);
|
||||
$significantChangeHash = md5($significantChangeHash);
|
||||
|
||||
return compact(
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject\ITip;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* This message is emitted in case of serious problems with iTip messages.
|
||||
*
|
||||
|
|
@ -11,6 +9,6 @@ use Exception;
|
|||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class ITipException extends Exception
|
||||
class ITipException extends \Exception
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Sabre\VObject\ITip;
|
||||
|
||||
use Sabre\VObject\Component\VCalendar;
|
||||
|
||||
/**
|
||||
* This class represents an iTip message.
|
||||
*
|
||||
|
|
@ -18,32 +20,24 @@ class Message
|
|||
{
|
||||
/**
|
||||
* The object's UID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $uid;
|
||||
public string $uid;
|
||||
|
||||
/**
|
||||
* The component type, such as VEVENT.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component;
|
||||
public string $component;
|
||||
|
||||
/**
|
||||
* Contains the ITip method, which is something like REQUEST, REPLY or
|
||||
* CANCEL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $method;
|
||||
public ?string $method;
|
||||
|
||||
/**
|
||||
* The current sequence number for the event.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $sequence;
|
||||
public ?int $sequence;
|
||||
|
||||
/**
|
||||
* The senders' email address.
|
||||
|
|
@ -51,33 +45,25 @@ class Message
|
|||
* Note that this does not imply that this has to be used in a From: field
|
||||
* if the message is sent by email. It may also be populated in Reply-To:
|
||||
* or not at all.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $sender;
|
||||
public string $sender;
|
||||
|
||||
/**
|
||||
* The name of the sender. This is often populated from a CN parameter from
|
||||
* either the ORGANIZER or ATTENDEE, depending on the message.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $senderName;
|
||||
public ?string $senderName;
|
||||
|
||||
/**
|
||||
* The recipient's email address.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $recipient;
|
||||
public string $recipient;
|
||||
|
||||
/**
|
||||
* The name of the recipient. This is usually populated with the CN
|
||||
* parameter from the ATTENDEE or ORGANIZER property, if it's available.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $recipientName;
|
||||
public ?string $recipientName;
|
||||
|
||||
/**
|
||||
* After the message has been delivered, this should contain a string such
|
||||
|
|
@ -87,17 +73,13 @@ class Message
|
|||
*
|
||||
* See:
|
||||
* http://tools.ietf.org/html/rfc6638#section-7.3
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $scheduleStatus;
|
||||
public ?string $scheduleStatus = null;
|
||||
|
||||
/**
|
||||
* The iCalendar / iTip body.
|
||||
*
|
||||
* @var \Sabre\VObject\Component\VCalendar
|
||||
*/
|
||||
public $message;
|
||||
public VCalendar $message;
|
||||
|
||||
/**
|
||||
* This will be set to true, if the iTip broker considers the change
|
||||
|
|
@ -110,10 +92,8 @@ class Message
|
|||
*
|
||||
* To see the list of properties that are considered 'significant', check
|
||||
* out Sabre\VObject\ITip\Broker::$significantChangeProperties.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $significantChange = true;
|
||||
public bool $significantChange = true;
|
||||
|
||||
/**
|
||||
* Returns the schedule status as a string.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable, \Js
|
|||
* If REPAIR is set, the validator will attempt to repair any broken data
|
||||
* (if possible).
|
||||
*/
|
||||
const REPAIR = 1;
|
||||
public const REPAIR = 1;
|
||||
|
||||
/**
|
||||
* If this option is set, the validator will operate on the vcards on the
|
||||
|
|
@ -28,7 +28,7 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable, \Js
|
|||
* This means for example that the UID is required, whereas it is not for
|
||||
* regular vcards.
|
||||
*/
|
||||
const PROFILE_CARDDAV = 2;
|
||||
public const PROFILE_CARDDAV = 2;
|
||||
|
||||
/**
|
||||
* If this option is set, the validator will operate on iCalendar objects
|
||||
|
|
@ -37,41 +37,33 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable, \Js
|
|||
* This means for example that calendars can only contain objects with
|
||||
* identical component types and UIDs.
|
||||
*/
|
||||
const PROFILE_CALDAV = 4;
|
||||
public const PROFILE_CALDAV = 4;
|
||||
|
||||
/**
|
||||
* Reference to the parent object, if this is not the top object.
|
||||
*
|
||||
* @var Node
|
||||
*/
|
||||
public $parent;
|
||||
public ?Node $parent;
|
||||
|
||||
/**
|
||||
* Iterator override.
|
||||
*
|
||||
* @var ElementList
|
||||
*/
|
||||
protected $iterator = null;
|
||||
protected ?ElementList $iterator = null;
|
||||
|
||||
/**
|
||||
* The root document.
|
||||
*
|
||||
* @var Component
|
||||
*/
|
||||
protected $root;
|
||||
protected ?Component $root;
|
||||
|
||||
/**
|
||||
* Serializes the node into a mimedir format.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function serialize();
|
||||
abstract public function serialize(): string;
|
||||
|
||||
/**
|
||||
* This method returns an array, with the representation as it should be
|
||||
* encoded in JSON. This is used to create jCard or jCal documents.
|
||||
*
|
||||
* @return array
|
||||
* @return array|string
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
abstract public function jsonSerialize();
|
||||
|
|
@ -90,7 +82,7 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable, \Js
|
|||
* It's intended to remove all circular references, so PHP can easily clean
|
||||
* it up.
|
||||
*/
|
||||
public function destroy()
|
||||
public function destroy(): void
|
||||
{
|
||||
$this->parent = null;
|
||||
$this->root = null;
|
||||
|
|
@ -100,11 +92,9 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable, \Js
|
|||
|
||||
/**
|
||||
* Returns the iterator for this object.
|
||||
*
|
||||
* @return ElementList
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function getIterator()
|
||||
public function getIterator(): ?ElementList
|
||||
{
|
||||
if (!is_null($this->iterator)) {
|
||||
return $this->iterator;
|
||||
|
|
@ -118,7 +108,7 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable, \Js
|
|||
*
|
||||
* Note that this is not actually part of the iterator interface
|
||||
*/
|
||||
public function setIterator(ElementList $iterator)
|
||||
public function setIterator(ElementList $iterator): void
|
||||
{
|
||||
$this->iterator = $iterator;
|
||||
}
|
||||
|
|
@ -140,12 +130,8 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable, \Js
|
|||
* 1 - The issue was repaired (only happens if REPAIR was turned on)
|
||||
* 2 - An inconsequential issue
|
||||
* 3 - A severe issue.
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate($options = 0)
|
||||
public function validate(int $options = 0): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
|
@ -156,11 +142,9 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable, \Js
|
|||
|
||||
/**
|
||||
* Returns the number of elements.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function count()
|
||||
public function count(): int
|
||||
{
|
||||
$it = $this->getIterator();
|
||||
|
||||
|
|
@ -177,11 +161,9 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable, \Js
|
|||
* This method just forwards the request to the inner iterator
|
||||
*
|
||||
* @param int $offset
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetExists($offset)
|
||||
public function offsetExists($offset): bool
|
||||
{
|
||||
$iterator = $this->getIterator();
|
||||
|
||||
|
|
@ -194,8 +176,6 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable, \Js
|
|||
* This method just forwards the request to the inner iterator
|
||||
*
|
||||
* @param int $offset
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetGet($offset)
|
||||
|
|
@ -210,19 +190,18 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable, \Js
|
|||
*
|
||||
* This method just forwards the request to the inner iterator
|
||||
*
|
||||
* @param int $offset
|
||||
* @param mixed $value
|
||||
* @param int $offset
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetSet($offset, $value)
|
||||
public function offsetSet($offset, $value): void
|
||||
{
|
||||
$iterator = $this->getIterator();
|
||||
$iterator->offsetSet($offset, $value);
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
//
|
||||
// This method always throws an exception, so we ignore the closing
|
||||
// brace
|
||||
//
|
||||
// This method always throws an exception, so we ignore the closing
|
||||
// brace
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
|
@ -235,15 +214,15 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable, \Js
|
|||
* @param int $offset
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetUnset($offset)
|
||||
public function offsetUnset($offset): void
|
||||
{
|
||||
$iterator = $this->getIterator();
|
||||
$iterator->offsetUnset($offset);
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
//
|
||||
// This method always throws an exception, so we ignore the closing
|
||||
// brace
|
||||
//
|
||||
// This method always throws an exception, so we ignore the closing
|
||||
// brace
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
|
|
|||
|
|
@ -30,9 +30,8 @@ trait PHPUnitAssertions
|
|||
*
|
||||
* @param resource|string|Component $expected
|
||||
* @param resource|string|Component $actual
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertVObjectEqualsVObject($expected, $actual, $message = '')
|
||||
public function assertVObjectEqualsVObject($expected, $actual, string $message = ''): void
|
||||
{
|
||||
$getObj = function ($input) {
|
||||
if (is_resource($input)) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
use ArrayIterator;
|
||||
use Sabre\Xml;
|
||||
|
||||
/**
|
||||
|
|
@ -21,24 +20,20 @@ class Parameter extends Node
|
|||
{
|
||||
/**
|
||||
* Parameter name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
public string $name;
|
||||
|
||||
/**
|
||||
* vCard 2.1 allows parameters to be encoded without a name.
|
||||
*
|
||||
* We can deduce the parameter name based on its value.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $noName = false;
|
||||
public bool $noName = false;
|
||||
|
||||
/**
|
||||
* Parameter value.
|
||||
*
|
||||
* @var string
|
||||
* @var string|array|null
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
|
|
@ -47,10 +42,9 @@ class Parameter extends Node
|
|||
*
|
||||
* It's recommended to use the create:: factory method instead.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @param string|array|null $value
|
||||
*/
|
||||
public function __construct(Document $root, $name, $value = null)
|
||||
public function __construct(Document $root, ?string $name, $value = null)
|
||||
{
|
||||
$this->root = $root;
|
||||
if (is_null($name)) {
|
||||
|
|
@ -77,12 +71,8 @@ class Parameter extends Node
|
|||
* Figuring out what the name should have been. Note that a ton of
|
||||
* these are rather silly in 2014 and would probably rarely be
|
||||
* used, but we like to be complete.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function guessParameterNameByValue($value)
|
||||
public static function guessParameterNameByValue(string $value): string
|
||||
{
|
||||
switch (strtoupper($value)) {
|
||||
// Encodings
|
||||
|
|
@ -92,16 +82,16 @@ class Parameter extends Node
|
|||
$name = 'ENCODING';
|
||||
break;
|
||||
|
||||
// Common types
|
||||
// Common types
|
||||
case 'WORK':
|
||||
case 'HOME':
|
||||
case 'PREF':
|
||||
// Delivery Label Type
|
||||
// Delivery Label Type
|
||||
case 'DOM':
|
||||
case 'INTL':
|
||||
case 'POSTAL':
|
||||
case 'PARCEL':
|
||||
// Telephone types
|
||||
// Telephone types
|
||||
case 'VOICE':
|
||||
case 'FAX':
|
||||
case 'MSG':
|
||||
|
|
@ -112,7 +102,7 @@ class Parameter extends Node
|
|||
case 'CAR':
|
||||
case 'ISDN':
|
||||
case 'VIDEO':
|
||||
// EMAIL types (lol)
|
||||
// EMAIL types (lol)
|
||||
case 'AOL':
|
||||
case 'APPLELINK':
|
||||
case 'ATTMAIL':
|
||||
|
|
@ -125,7 +115,7 @@ class Parameter extends Node
|
|||
case 'PRODIGY':
|
||||
case 'TLX':
|
||||
case 'X400':
|
||||
// Photo / Logo format types
|
||||
// Photo / Logo format types
|
||||
case 'GIF':
|
||||
case 'CGM':
|
||||
case 'WMF':
|
||||
|
|
@ -140,17 +130,17 @@ class Parameter extends Node
|
|||
case 'MPEG2':
|
||||
case 'AVI':
|
||||
case 'QTIME':
|
||||
// Sound Digital Audio Type
|
||||
// Sound Digital Audio Type
|
||||
case 'WAVE':
|
||||
case 'PCM':
|
||||
case 'AIFF':
|
||||
// Key types
|
||||
// Key types
|
||||
case 'X509':
|
||||
case 'PGP':
|
||||
$name = 'TYPE';
|
||||
break;
|
||||
|
||||
// Value types
|
||||
// Value types
|
||||
case 'INLINE':
|
||||
case 'URL':
|
||||
case 'CONTENT-ID':
|
||||
|
|
@ -172,7 +162,7 @@ class Parameter extends Node
|
|||
*
|
||||
* @param string|array $value
|
||||
*/
|
||||
public function setValue($value)
|
||||
public function setValue($value): void
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
|
@ -182,10 +172,8 @@ class Parameter extends Node
|
|||
*
|
||||
* This method will always return a string, or null. If there were multiple
|
||||
* values, it will automatically concatenate them (separated by comma).
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getValue()
|
||||
public function getValue(): ?string
|
||||
{
|
||||
if (is_array($this->value)) {
|
||||
return implode(',', $this->value);
|
||||
|
|
@ -197,7 +185,7 @@ class Parameter extends Node
|
|||
/**
|
||||
* Sets multiple values for this parameter.
|
||||
*/
|
||||
public function setParts(array $value)
|
||||
public function setParts(array $value): void
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
|
@ -206,10 +194,8 @@ class Parameter extends Node
|
|||
* Returns all values for this parameter.
|
||||
*
|
||||
* If there were no values, an empty array will be returned.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getParts()
|
||||
public function getParts(): array
|
||||
{
|
||||
if (is_array($this->value)) {
|
||||
return $this->value;
|
||||
|
|
@ -228,7 +214,7 @@ class Parameter extends Node
|
|||
*
|
||||
* @param string|array $part
|
||||
*/
|
||||
public function addValue($part)
|
||||
public function addValue($part): void
|
||||
{
|
||||
if (is_null($this->value)) {
|
||||
$this->value = $part;
|
||||
|
|
@ -240,15 +226,11 @@ class Parameter extends Node
|
|||
/**
|
||||
* Checks if this parameter contains the specified value.
|
||||
*
|
||||
* This is a case-insensitive match. It makes sense to call this for for
|
||||
* instance the TYPE parameter, to see if it contains a keyword such as
|
||||
* This is a case-insensitive match. It makes sense to call this for
|
||||
* the TYPE parameter, for instance, to see if it contains a keyword such as
|
||||
* 'WORK' or 'FAX'.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has($value)
|
||||
public function has(string $value): bool
|
||||
{
|
||||
return in_array(
|
||||
strtolower($value),
|
||||
|
|
@ -258,10 +240,8 @@ class Parameter extends Node
|
|||
|
||||
/**
|
||||
* Turns the object back into a serialized blob.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function serialize()
|
||||
public function serialize(): string
|
||||
{
|
||||
$value = $this->getParts();
|
||||
|
||||
|
|
@ -320,7 +300,7 @@ class Parameter extends Node
|
|||
* This method returns an array, with the representation as it should be
|
||||
* encoded in JSON. This is used to create jCard or jCal documents.
|
||||
*
|
||||
* @return array
|
||||
* @return array|string|null
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
|
|
@ -336,33 +316,29 @@ class Parameter extends Node
|
|||
*/
|
||||
public function xmlSerialize(Xml\Writer $writer): void
|
||||
{
|
||||
foreach (explode(',', $this->value) as $value) {
|
||||
foreach (is_array($this->value) ? $this->value : explode(',', $this->value) as $value) {
|
||||
$writer->writeElement('text', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this object is being cast to a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the iterator for this object.
|
||||
*
|
||||
* @return ElementList
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function getIterator()
|
||||
public function getIterator(): ElementList
|
||||
{
|
||||
if (!is_null($this->iterator)) {
|
||||
return $this->iterator;
|
||||
}
|
||||
|
||||
return $this->iterator = new ArrayIterator((array) $this->value);
|
||||
return $this->iterator = new ElementList((array) $this->value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
namespace Sabre\VObject\Parser;
|
||||
|
||||
use Sabre\VObject\Component;
|
||||
use Sabre\VObject\Component\VCalendar;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\Document;
|
||||
use Sabre\VObject\EofException;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
use Sabre\VObject\ParseException;
|
||||
use Sabre\VObject\Property;
|
||||
use Sabre\VObject\Property\FlatText;
|
||||
use Sabre\VObject\Property\Text;
|
||||
|
||||
|
|
@ -23,17 +26,13 @@ class Json extends Parser
|
|||
{
|
||||
/**
|
||||
* The input data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $input;
|
||||
protected ?array $input;
|
||||
|
||||
/**
|
||||
* Root component.
|
||||
*
|
||||
* @var Document
|
||||
*/
|
||||
protected $root;
|
||||
protected ?Document $root;
|
||||
|
||||
/**
|
||||
* This method starts the parsing process.
|
||||
|
|
@ -44,11 +43,12 @@ class Json extends Parser
|
|||
* If either input or options are not supplied, the defaults will be used.
|
||||
*
|
||||
* @param resource|string|array|null $input
|
||||
* @param int $options
|
||||
*
|
||||
* @return \Sabre\VObject\Document
|
||||
* @throws EofException
|
||||
* @throws ParseException
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function parse($input = null, $options = 0)
|
||||
public function parse($input = null, int $options = 0): ?Document
|
||||
{
|
||||
if (!is_null($input)) {
|
||||
$this->setInput($input);
|
||||
|
|
@ -80,7 +80,7 @@ class Json extends Parser
|
|||
}
|
||||
}
|
||||
|
||||
// Resetting the input so we can throw an feof exception the next time.
|
||||
// Resetting the input so that we can throw an feof exception the next time.
|
||||
$this->input = null;
|
||||
|
||||
return $this->root;
|
||||
|
|
@ -89,9 +89,9 @@ class Json extends Parser
|
|||
/**
|
||||
* Parses a component.
|
||||
*
|
||||
* @return \Sabre\VObject\Component
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function parseComponent(array $jComp)
|
||||
public function parseComponent(array $jComp): Component
|
||||
{
|
||||
// We can remove $self from PHP 5.4 onward.
|
||||
$self = $this;
|
||||
|
|
@ -117,16 +117,16 @@ class Json extends Parser
|
|||
return $this->root->createComponent(
|
||||
$jComp[0],
|
||||
array_merge($properties, $components),
|
||||
$defaults = false
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses properties.
|
||||
*
|
||||
* @return \Sabre\VObject\Property
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function parseProperty(array $jProp)
|
||||
public function parseProperty(array $jProp): Property
|
||||
{
|
||||
list(
|
||||
$propertyName,
|
||||
|
|
@ -181,7 +181,7 @@ class Json extends Parser
|
|||
*
|
||||
* @param resource|string|array $input
|
||||
*/
|
||||
public function setInput($input)
|
||||
public function setInput($input): void
|
||||
{
|
||||
if (is_resource($input)) {
|
||||
$input = stream_get_contents($input);
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
namespace Sabre\VObject\Parser;
|
||||
|
||||
use Sabre\VObject\Component;
|
||||
use Sabre\VObject\Component\VCalendar;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\Document;
|
||||
use Sabre\VObject\EofException;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
use Sabre\VObject\Node;
|
||||
use Sabre\VObject\ParseException;
|
||||
use Sabre\VObject\Property;
|
||||
|
||||
/**
|
||||
* MimeDir parser.
|
||||
|
|
@ -34,13 +35,11 @@ class MimeDir extends Parser
|
|||
|
||||
/**
|
||||
* Root component.
|
||||
*
|
||||
* @var Component
|
||||
*/
|
||||
protected $root;
|
||||
protected ?Document $root;
|
||||
|
||||
/**
|
||||
* By default all input will be assumed to be UTF-8.
|
||||
* By default, all input will be assumed to be UTF-8.
|
||||
*
|
||||
* However, both iCalendar and vCard might be encoded using different
|
||||
* character sets. The character set is usually set in the mime-type.
|
||||
|
|
@ -48,17 +47,15 @@ class MimeDir extends Parser
|
|||
* If this is the case, use setEncoding to specify that a different
|
||||
* encoding will be used. If this is set, the parser will automatically
|
||||
* convert all incoming data to UTF-8.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $charset = 'UTF-8';
|
||||
protected string $charset = 'UTF-8';
|
||||
|
||||
/**
|
||||
* The list of character sets we support when decoding.
|
||||
*
|
||||
* This would be a const expression but for now we need to support PHP 5.5
|
||||
*/
|
||||
protected static $SUPPORTED_CHARSETS = [
|
||||
protected static array $SUPPORTED_CHARSETS = [
|
||||
'UTF-8',
|
||||
'ISO-8859-1',
|
||||
'Windows-1252',
|
||||
|
|
@ -71,15 +68,14 @@ class MimeDir extends Parser
|
|||
* used.
|
||||
*
|
||||
* @param string|resource|null $input
|
||||
* @param int $options
|
||||
*
|
||||
* @return \Sabre\VObject\Document
|
||||
* @throws ParseException
|
||||
*/
|
||||
public function parse($input = null, $options = 0)
|
||||
public function parse($input = null, int $options = 0): ?Document
|
||||
{
|
||||
$this->root = null;
|
||||
|
||||
if (!is_null($input)) {
|
||||
if (!\is_null($input)) {
|
||||
$this->setInput($input);
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +89,7 @@ class MimeDir extends Parser
|
|||
}
|
||||
|
||||
/**
|
||||
* By default all input will be assumed to be UTF-8.
|
||||
* By default, all input will be assumed to be UTF-8.
|
||||
*
|
||||
* However, both iCalendar and vCard might be encoded using different
|
||||
* character sets. The character set is usually set in the mime-type.
|
||||
|
|
@ -101,10 +97,8 @@ class MimeDir extends Parser
|
|||
* If this is the case, use setEncoding to specify that a different
|
||||
* encoding will be used. If this is set, the parser will automatically
|
||||
* convert all incoming data to UTF-8.
|
||||
*
|
||||
* @param string $charset
|
||||
*/
|
||||
public function setCharset($charset)
|
||||
public function setCharset(string $charset): void
|
||||
{
|
||||
if (!in_array($charset, self::$SUPPORTED_CHARSETS)) {
|
||||
throw new \InvalidArgumentException('Unsupported encoding. (Supported encodings: '.implode(', ', self::$SUPPORTED_CHARSETS).')');
|
||||
|
|
@ -116,6 +110,8 @@ class MimeDir extends Parser
|
|||
* Sets the input buffer. Must be a string or stream.
|
||||
*
|
||||
* @param resource|string $input
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setInput($input)
|
||||
{
|
||||
|
|
@ -138,18 +134,21 @@ class MimeDir extends Parser
|
|||
|
||||
/**
|
||||
* Parses an entire document.
|
||||
*
|
||||
* @throws EofException
|
||||
* @throws ParseException
|
||||
*/
|
||||
protected function parseDocument()
|
||||
protected function parseDocument(): void
|
||||
{
|
||||
$line = $this->readLine();
|
||||
|
||||
// BOM is ZERO WIDTH NO-BREAK SPACE (U+FEFF).
|
||||
// It's 0xEF 0xBB 0xBF in UTF-8 hex.
|
||||
if (3 <= strlen($line)
|
||||
&& 0xef === ord($line[0])
|
||||
&& 0xbb === ord($line[1])
|
||||
&& 0xbf === ord($line[2])) {
|
||||
$line = substr($line, 3);
|
||||
&& 0xEF === ord($line[0])
|
||||
&& 0xBB === ord($line[1])
|
||||
&& 0xBF === ord($line[2])) {
|
||||
$line = \substr($line, 3);
|
||||
}
|
||||
|
||||
switch (strtoupper($line)) {
|
||||
|
|
@ -172,7 +171,7 @@ class MimeDir extends Parser
|
|||
} catch (EofException $oEx) {
|
||||
$line = 'END:'.$this->root->name;
|
||||
}
|
||||
if ('END:' === strtoupper(substr($line, 0, 4))) {
|
||||
if ('END:' === strtoupper(\substr($line, 0, 4))) {
|
||||
break;
|
||||
}
|
||||
$result = $this->parseLine($line);
|
||||
|
|
@ -181,7 +180,7 @@ class MimeDir extends Parser
|
|||
}
|
||||
}
|
||||
|
||||
$name = strtoupper(substr($line, 4));
|
||||
$name = strtoupper(\substr($line, 4));
|
||||
if ($name !== $this->root->name) {
|
||||
throw new ParseException('Invalid MimeDir file. expected: "END:'.$this->root->name.'" got: "END:'.$name.'"');
|
||||
}
|
||||
|
|
@ -193,21 +192,24 @@ class MimeDir extends Parser
|
|||
*
|
||||
* @param string $line Unfolded line
|
||||
*
|
||||
* @return Node
|
||||
* @return Node|Property|false
|
||||
*
|
||||
* @throws EofException
|
||||
* @throws ParseException
|
||||
*/
|
||||
protected function parseLine($line)
|
||||
protected function parseLine(string $line)
|
||||
{
|
||||
// Start of a new component
|
||||
if ('BEGIN:' === strtoupper(substr($line, 0, 6))) {
|
||||
if (substr($line, 6) === $this->root->name) {
|
||||
if ('BEGIN:' === strtoupper(\substr($line, 0, 6))) {
|
||||
if (\substr($line, 6) === $this->root->name) {
|
||||
throw new ParseException('Invalid MimeDir file. Unexpected component: "'.$line.'" in document type '.$this->root->name);
|
||||
}
|
||||
$component = $this->root->createComponent(substr($line, 6), [], false);
|
||||
$component = $this->root->createComponent(\substr($line, 6), [], false);
|
||||
|
||||
while (true) {
|
||||
// Reading until we hit END:
|
||||
$line = $this->readLine();
|
||||
if ('END:' === strtoupper(substr($line, 0, 4))) {
|
||||
if ('END:' === strtoupper(\substr($line, 0, 4))) {
|
||||
break;
|
||||
}
|
||||
$result = $this->parseLine($line);
|
||||
|
|
@ -216,7 +218,7 @@ class MimeDir extends Parser
|
|||
}
|
||||
}
|
||||
|
||||
$name = strtoupper(substr($line, 4));
|
||||
$name = strtoupper(\substr($line, 4));
|
||||
if ($name !== $component->name) {
|
||||
throw new ParseException('Invalid MimeDir file. expected: "END:'.$component->name.'" got: "END:'.$name.'"');
|
||||
}
|
||||
|
|
@ -239,41 +241,33 @@ class MimeDir extends Parser
|
|||
* the next line.
|
||||
*
|
||||
* If that was not the case, we store it here.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $lineBuffer;
|
||||
protected ?string $lineBuffer = null;
|
||||
|
||||
/**
|
||||
* The real current line number.
|
||||
*/
|
||||
protected $lineIndex = 0;
|
||||
protected int $lineIndex = 0;
|
||||
|
||||
/**
|
||||
* In the case of unfolded lines, this property holds the line number for
|
||||
* the start of the line.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $startLine = 0;
|
||||
protected int $startLine = 0;
|
||||
|
||||
/**
|
||||
* Contains a 'raw' representation of the current line.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $rawLine;
|
||||
protected string $rawLine;
|
||||
|
||||
/**
|
||||
* Reads a single line from the buffer.
|
||||
*
|
||||
* This method strips any newlines and also takes care of unfolding.
|
||||
*
|
||||
* @throws \Sabre\VObject\EofException
|
||||
*
|
||||
* @return string
|
||||
* @throws EofException|ParseException
|
||||
*/
|
||||
protected function readLine()
|
||||
protected function readLine(): ?string
|
||||
{
|
||||
if (!\is_null($this->lineBuffer)) {
|
||||
$rawLine = $this->lineBuffer;
|
||||
|
|
@ -321,8 +315,12 @@ class MimeDir extends Parser
|
|||
|
||||
/**
|
||||
* Reads a property or component from a line.
|
||||
*
|
||||
* @return Property|false
|
||||
*
|
||||
* @throws ParseException|InvalidDataException
|
||||
*/
|
||||
protected function readProperty($line)
|
||||
protected function readProperty(string $line)
|
||||
{
|
||||
if ($this->options & self::OPTION_FORGIVING) {
|
||||
$propNameToken = 'A-Z0-9\-\._\\/';
|
||||
|
|
@ -347,7 +345,7 @@ class MimeDir extends Parser
|
|||
) (?=[;:,])
|
||||
/xi";
|
||||
|
||||
//echo $regex, "\n"; exit();
|
||||
// echo $regex, "\n"; exit();
|
||||
preg_match_all($regex, $line, $matches, PREG_SET_ORDER);
|
||||
|
||||
$property = [
|
||||
|
|
@ -368,14 +366,14 @@ class MimeDir extends Parser
|
|||
foreach ($matches as $match) {
|
||||
if (isset($match['paramValue'])) {
|
||||
if ($match['paramValue'] && '"' === $match['paramValue'][0]) {
|
||||
$value = substr($match['paramValue'], 1, -1);
|
||||
$value = \substr($match['paramValue'], 1, -1);
|
||||
} else {
|
||||
$value = $match['paramValue'];
|
||||
}
|
||||
|
||||
$value = $this->unescapeParam($value);
|
||||
|
||||
if (is_null($lastParam)) {
|
||||
if (\is_null($lastParam)) {
|
||||
if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
|
||||
// When the property can't be matched and the configuration
|
||||
// option is set to ignore invalid lines, we ignore this line
|
||||
|
|
@ -385,7 +383,7 @@ class MimeDir extends Parser
|
|||
}
|
||||
throw new ParseException('Invalid Mimedir file. Line starting at '.$this->startLine.' did not follow iCalendar/vCard conventions');
|
||||
}
|
||||
if (is_null($property['parameters'][$lastParam])) {
|
||||
if (\is_null($property['parameters'][$lastParam])) {
|
||||
$property['parameters'][$lastParam] = $value;
|
||||
} elseif (is_array($property['parameters'][$lastParam])) {
|
||||
$property['parameters'][$lastParam][] = $value;
|
||||
|
|
@ -421,7 +419,7 @@ class MimeDir extends Parser
|
|||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
if (is_null($property['value'])) {
|
||||
if (\is_null($property['value'])) {
|
||||
$property['value'] = '';
|
||||
}
|
||||
if (!$property['name']) {
|
||||
|
|
@ -440,7 +438,7 @@ class MimeDir extends Parser
|
|||
$namelessParameters = [];
|
||||
|
||||
foreach ($property['parameters'] as $name => $value) {
|
||||
if (!is_null($value)) {
|
||||
if (!\is_null($value)) {
|
||||
$namedParameters[$name] = $value;
|
||||
} else {
|
||||
$namelessParameters[] = $name;
|
||||
|
|
@ -454,6 +452,7 @@ class MimeDir extends Parser
|
|||
}
|
||||
|
||||
if (isset($propObj['ENCODING']) && 'QUOTED-PRINTABLE' === strtoupper($propObj['ENCODING'])) {
|
||||
/* @var Property\Text|Property\FlatText $propObj */
|
||||
$propObj->setQuotedPrintableValue($this->extractQuotedPrintableValue());
|
||||
} else {
|
||||
$charset = $this->charset;
|
||||
|
|
@ -464,8 +463,8 @@ class MimeDir extends Parser
|
|||
switch (strtolower($charset)) {
|
||||
case 'utf-8':
|
||||
break;
|
||||
case 'iso-8859-1':
|
||||
case 'windows-1252':
|
||||
case 'iso-8859-1':
|
||||
$property['value'] = mb_convert_encoding($property['value'], 'UTF-8', $charset);
|
||||
break;
|
||||
default:
|
||||
|
|
@ -483,7 +482,7 @@ class MimeDir extends Parser
|
|||
* vCard 2.1 says:
|
||||
* * Semi-colons must be escaped in some property values, specifically
|
||||
* ADR, ORG and N.
|
||||
* * Semi-colons must be escaped in parameter values, because semi-colons
|
||||
* * Semi-colons must be escaped in parameter values, because semicolons
|
||||
* are also use to separate values.
|
||||
* * No mention of escaping backslashes with another backslash.
|
||||
* * newlines are not escaped either, instead QUOTED-PRINTABLE is used to
|
||||
|
|
@ -491,10 +490,10 @@ class MimeDir extends Parser
|
|||
*
|
||||
* vCard 3.0 says:
|
||||
* * (rfc2425) Backslashes, newlines (\n or \N) and comma's must be
|
||||
* escaped, all time time.
|
||||
* * Comma's are used for delimiters in multiple values
|
||||
* * (rfc2426) Adds to to this that the semi-colon MUST also be escaped,
|
||||
* as in some properties semi-colon is used for separators.
|
||||
* escaped, all the time.
|
||||
* * Commas are used for delimiters in multiple values
|
||||
* * (rfc2426) Adds to this that the semicolon MUST also be escaped,
|
||||
* as in some properties semicolon is used for separators.
|
||||
* * Properties using semi-colons: N, ADR, GEO, ORG
|
||||
* * Both ADR and N's individual parts may be broken up further with a
|
||||
* comma.
|
||||
|
|
@ -502,12 +501,12 @@ class MimeDir extends Parser
|
|||
*
|
||||
* vCard 4.0 (rfc6350) says:
|
||||
* * Commas must be escaped.
|
||||
* * Semi-colons may be escaped, an unescaped semi-colon _may_ be a
|
||||
* * Semi-colons may be escaped, an unescaped semicolon _may_ be a
|
||||
* delimiter, depending on the property.
|
||||
* * Backslashes must be escaped
|
||||
* * Newlines must be escaped as either \N or \n.
|
||||
* * Some compound properties may contain multiple parts themselves, so a
|
||||
* comma within a semi-colon delimited property may also be unescaped
|
||||
* comma within a semicolon delimited property may also be unescaped
|
||||
* to denote multiple parts _within_ the compound property.
|
||||
* * Text-properties using semi-colons: N, ADR, ORG, CLIENTPIDMAP.
|
||||
* * Text-properties using commas: NICKNAME, RELATED, CATEGORIES, PID.
|
||||
|
|
@ -516,7 +515,7 @@ class MimeDir extends Parser
|
|||
* example for GEO in Section 6.5.2 seems to violate this.
|
||||
*
|
||||
* iCalendar 2.0 (rfc5545) says:
|
||||
* * Commas or semi-colons may be used as delimiters, depending on the
|
||||
* * Commas or semicolons may be used as delimiters, depending on the
|
||||
* property.
|
||||
* * Commas, semi-colons, backslashes, newline (\N or \n) are always
|
||||
* escaped, unless they are delimiters.
|
||||
|
|
@ -526,20 +525,17 @@ class MimeDir extends Parser
|
|||
* insignificant.
|
||||
* * Semi-colons are described as the delimiter for 'structured values'.
|
||||
* They are specifically used in Semi-colons are used as a delimiter in
|
||||
* REQUEST-STATUS, RRULE, GEO and EXRULE. EXRULE is deprecated however.
|
||||
* REQUEST-STATUS, RRULE, GEO and EXRULE. EXRULE is deprecated, however.
|
||||
*
|
||||
* Now for the parameters
|
||||
*
|
||||
* If delimiter is not set (empty string) this method will just return a string.
|
||||
* If it's a comma or a semi-colon the string will be split on those
|
||||
* If it's a comma or a semicolon the string will be split on those
|
||||
* characters, and always return an array.
|
||||
*
|
||||
* @param string $input
|
||||
* @param string $delimiter
|
||||
*
|
||||
* @return string|string[]
|
||||
*/
|
||||
public static function unescapeValue($input, $delimiter = ';')
|
||||
public static function unescapeValue(string $input, string $delimiter = ';')
|
||||
{
|
||||
$regex = '# (?: (\\\\ (?: \\\\ | N | n | ; | , ) )';
|
||||
if ($delimiter) {
|
||||
|
|
@ -589,11 +585,11 @@ class MimeDir extends Parser
|
|||
* * Does not mention a mechanism for this. In addition, double quotes
|
||||
* are never used to wrap values.
|
||||
* * This means that parameters can simply not contain colons or
|
||||
* semi-colons.
|
||||
* semicolons.
|
||||
*
|
||||
* vCard 3.0 (rfc2425, rfc2426):
|
||||
* * Parameters _may_ be surrounded by double quotes.
|
||||
* * If this is not the case, semi-colon, colon and comma may simply not
|
||||
* * If this is not the case, semicolon, colon and comma may simply not
|
||||
* occur (the comma used for multiple parameter values though).
|
||||
* * If it is surrounded by double-quotes, it may simply not contain
|
||||
* double-quotes.
|
||||
|
|
@ -611,10 +607,8 @@ class MimeDir extends Parser
|
|||
* * New-line is encoded as ^n
|
||||
* * ^ is encoded as ^^.
|
||||
* * " is encoded as ^'
|
||||
*
|
||||
* @param string $input
|
||||
*/
|
||||
private function unescapeParam($input)
|
||||
private function unescapeParam(string $input): ?string
|
||||
{
|
||||
return
|
||||
preg_replace_callback(
|
||||
|
|
@ -628,7 +622,7 @@ class MimeDir extends Parser
|
|||
case '\'':
|
||||
return '"';
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
// @codeCoverageIgnoreStart
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
},
|
||||
|
|
@ -644,9 +638,10 @@ class MimeDir extends Parser
|
|||
*
|
||||
* This method does not do any decoding.
|
||||
*
|
||||
* @return string
|
||||
* @throws EofException
|
||||
* @throws ParseException
|
||||
*/
|
||||
private function extractQuotedPrintableValue()
|
||||
private function extractQuotedPrintableValue(): string
|
||||
{
|
||||
// We need to parse the raw line again to get the start of the value.
|
||||
//
|
||||
|
|
@ -666,11 +661,11 @@ class MimeDir extends Parser
|
|||
// like unfolding, but we keep the newline.
|
||||
$value = str_replace("\n ", "\n", $value);
|
||||
|
||||
// Microsoft products don't always correctly fold lines, they may be
|
||||
// Microsoft's products don't always correctly fold lines, they may be
|
||||
// missing a whitespace. So if 'forgiving' is turned on, we will take
|
||||
// those as well.
|
||||
if ($this->options & self::OPTION_FORGIVING) {
|
||||
while ('=' === substr($value, -1) && $this->lineBuffer) {
|
||||
while ('=' === \substr($value, -1) && $this->lineBuffer) {
|
||||
// Reading the line
|
||||
$this->readLine();
|
||||
// Grabbing the raw form
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Sabre\VObject\Parser;
|
||||
|
||||
use Sabre\VObject\Document;
|
||||
|
||||
/**
|
||||
* Abstract parser.
|
||||
*
|
||||
|
|
@ -20,30 +22,27 @@ abstract class Parser
|
|||
* accept slashes and underscores in property names, and it will also
|
||||
* attempt to fix Microsoft vCard 2.1's broken line folding.
|
||||
*/
|
||||
const OPTION_FORGIVING = 1;
|
||||
public const OPTION_FORGIVING = 1;
|
||||
|
||||
/**
|
||||
* If this option is turned on, any lines we cannot parse will be ignored
|
||||
* by the reader.
|
||||
*/
|
||||
const OPTION_IGNORE_INVALID_LINES = 2;
|
||||
public const OPTION_IGNORE_INVALID_LINES = 2;
|
||||
|
||||
/**
|
||||
* Bitmask of parser options.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $options;
|
||||
protected int $options;
|
||||
|
||||
/**
|
||||
* Creates the parser.
|
||||
*
|
||||
* Optionally, it's possible to parse the input stream here.
|
||||
*
|
||||
* @param mixed $input
|
||||
* @param int $options any parser options (OPTION constants)
|
||||
* @param int $options any parser options (OPTION constants)
|
||||
*/
|
||||
public function __construct($input = null, $options = 0)
|
||||
public function __construct($input = null, int $options = 0)
|
||||
{
|
||||
if (!is_null($input)) {
|
||||
$this->setInput($input);
|
||||
|
|
@ -59,17 +58,14 @@ abstract class Parser
|
|||
*
|
||||
* If either input or options are not supplied, the defaults will be used.
|
||||
*
|
||||
* @param mixed $input
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
* @param resource|string|array|null $input
|
||||
*/
|
||||
abstract public function parse($input = null, $options = 0);
|
||||
abstract public function parse($input = null, int $options = 0): ?Document;
|
||||
|
||||
/**
|
||||
* Sets the input data.
|
||||
*
|
||||
* @param mixed $input
|
||||
* @param resource|string|array $input
|
||||
*/
|
||||
abstract public function setInput($input);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ namespace Sabre\VObject\Parser;
|
|||
use Sabre\VObject\Component;
|
||||
use Sabre\VObject\Component\VCalendar;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\Document;
|
||||
use Sabre\VObject\EofException;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
use Sabre\VObject\ParseException;
|
||||
use Sabre\Xml as SabreXml;
|
||||
|
||||
|
|
@ -20,39 +22,32 @@ use Sabre\Xml as SabreXml;
|
|||
*/
|
||||
class XML extends Parser
|
||||
{
|
||||
const XCAL_NAMESPACE = 'urn:ietf:params:xml:ns:icalendar-2.0';
|
||||
const XCARD_NAMESPACE = 'urn:ietf:params:xml:ns:vcard-4.0';
|
||||
public const XCAL_NAMESPACE = 'urn:ietf:params:xml:ns:icalendar-2.0';
|
||||
public const XCARD_NAMESPACE = 'urn:ietf:params:xml:ns:vcard-4.0';
|
||||
|
||||
/**
|
||||
* The input data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $input;
|
||||
protected ?array $input;
|
||||
|
||||
/**
|
||||
* A pointer/reference to the input.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $pointer;
|
||||
private ?array $pointer;
|
||||
|
||||
/**
|
||||
* Document, root component.
|
||||
*
|
||||
* @var \Sabre\VObject\Document
|
||||
*/
|
||||
protected $root;
|
||||
protected ?Document $root;
|
||||
|
||||
/**
|
||||
* Creates the parser.
|
||||
*
|
||||
* Optionally, it's possible to parse the input stream here.
|
||||
*
|
||||
* @param mixed $input
|
||||
* @param int $options any parser options (OPTION constants)
|
||||
* @param int $options any parser options (OPTION constants)
|
||||
*/
|
||||
public function __construct($input = null, $options = 0)
|
||||
public function __construct($input = null, int $options = 0)
|
||||
{
|
||||
if (0 === $options) {
|
||||
$options = parent::OPTION_FORGIVING;
|
||||
|
|
@ -64,14 +59,14 @@ class XML extends Parser
|
|||
/**
|
||||
* Parse xCal or xCard.
|
||||
*
|
||||
* @param resource|string $input
|
||||
* @param int $options
|
||||
* @param resource|string|null $input
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @return \Sabre\VObject\Document
|
||||
* @throws EofException
|
||||
* @throws InvalidDataException
|
||||
* @throws ParseException
|
||||
* @throws SabreXml\LibXMLException
|
||||
*/
|
||||
public function parse($input = null, $options = 0)
|
||||
public function parse($input = null, int $options = 0): ?Document
|
||||
{
|
||||
if (!is_null($input)) {
|
||||
$this->setInput($input);
|
||||
|
|
@ -112,8 +107,10 @@ class XML extends Parser
|
|||
|
||||
/**
|
||||
* Parse a xCalendar component.
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
protected function parseVCalendarComponents(Component $parentComponent)
|
||||
protected function parseVCalendarComponents(Component $parentComponent): void
|
||||
{
|
||||
foreach ($this->pointer['value'] ?: [] as $children) {
|
||||
switch (static::getTagName($children['name'])) {
|
||||
|
|
@ -132,8 +129,10 @@ class XML extends Parser
|
|||
|
||||
/**
|
||||
* Parse a xCard component.
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
protected function parseVCardComponents(Component $parentComponent)
|
||||
protected function parseVCardComponents(Component $parentComponent): void
|
||||
{
|
||||
$this->pointer = &$this->pointer['value'];
|
||||
$this->parseProperties($parentComponent);
|
||||
|
|
@ -142,9 +141,9 @@ class XML extends Parser
|
|||
/**
|
||||
* Parse xCalendar and xCard properties.
|
||||
*
|
||||
* @param string $propertyNamePrefix
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
protected function parseProperties(Component $parentComponent, $propertyNamePrefix = '')
|
||||
protected function parseProperties(Component $parentComponent, string $propertyNamePrefix = ''): void
|
||||
{
|
||||
foreach ($this->pointer ?: [] as $xmlProperty) {
|
||||
list($namespace, $tagName) = SabreXml\Service::parseClarkNotation($xmlProperty['name']);
|
||||
|
|
@ -318,8 +317,10 @@ class XML extends Parser
|
|||
|
||||
/**
|
||||
* Parse a component.
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
protected function parseComponent(Component $parentComponent)
|
||||
protected function parseComponent(Component $parentComponent): void
|
||||
{
|
||||
$components = $this->pointer['value'] ?: [];
|
||||
|
||||
|
|
@ -341,12 +342,9 @@ class XML extends Parser
|
|||
/**
|
||||
* Create a property.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $parameters
|
||||
* @param string $type
|
||||
* @param mixed $value
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
protected function createProperty(Component $parentComponent, $name, $parameters, $type, $value)
|
||||
protected function createProperty(Component $parentComponent, string $name, array $parameters, string $type, $value): void
|
||||
{
|
||||
$property = $this->root->createProperty(
|
||||
$name,
|
||||
|
|
@ -361,9 +359,11 @@ class XML extends Parser
|
|||
/**
|
||||
* Sets the input data.
|
||||
*
|
||||
* @param resource|string $input
|
||||
* @param resource|string|array $input
|
||||
*
|
||||
* @throws SabreXml\LibXMLException
|
||||
*/
|
||||
public function setInput($input)
|
||||
public function setInput($input): void
|
||||
{
|
||||
if (is_resource($input)) {
|
||||
$input = stream_get_contents($input);
|
||||
|
|
@ -384,12 +384,8 @@ class XML extends Parser
|
|||
|
||||
/**
|
||||
* Get tag name from a Clark notation.
|
||||
*
|
||||
* @param string $clarkedTagName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getTagName($clarkedTagName)
|
||||
protected static function getTagName(string $clarkedTagName): string
|
||||
{
|
||||
list(, $tagName) = SabreXml\Service::parseClarkNotation($clarkedTagName);
|
||||
|
||||
|
|
|
|||
|
|
@ -32,12 +32,8 @@ class KeyValue extends SabreXml\Element\KeyValue
|
|||
*
|
||||
* $reader->parseInnerTree() will parse the entire sub-tree, and advance to
|
||||
* the next element.
|
||||
*
|
||||
* @param XML\Reader $reader
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function xmlDeserialize(SabreXml\Reader $reader)
|
||||
public static function xmlDeserialize(SabreXml\Reader $reader): array
|
||||
{
|
||||
// If there's no children, we don't do anything.
|
||||
if ($reader->isEmptyElement) {
|
||||
|
|
|
|||
|
|
@ -16,45 +16,40 @@ use Sabre\Xml;
|
|||
*/
|
||||
abstract class Property extends Node
|
||||
{
|
||||
/**
|
||||
* The root document.
|
||||
*/
|
||||
public ?Component $root;
|
||||
|
||||
/**
|
||||
* Property name.
|
||||
*
|
||||
* This will contain a string such as DTSTART, SUMMARY, FN.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
public ?string $name;
|
||||
|
||||
/**
|
||||
* Property group.
|
||||
*
|
||||
* This is only used in vcards
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $group;
|
||||
public ?string $group;
|
||||
|
||||
/**
|
||||
* List of parameters.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $parameters = [];
|
||||
public array $parameters = [];
|
||||
|
||||
/**
|
||||
* Current value.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* In case this is a multi-value property. This string will be used as a
|
||||
* delimiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = ';';
|
||||
public string $delimiter = ';';
|
||||
|
||||
/**
|
||||
* Creates the generic property.
|
||||
|
|
@ -62,12 +57,11 @@ abstract class Property extends Node
|
|||
* Parameters must be specified in key=>value syntax.
|
||||
*
|
||||
* @param Component $root The root document
|
||||
* @param string $name
|
||||
* @param string|array|null $value
|
||||
* @param array $parameters List of parameters
|
||||
* @param string $group The vcard property group
|
||||
* @param string|null $group The vcard property group
|
||||
*/
|
||||
public function __construct(Component $root, $name, $value = null, array $parameters = [], $group = null)
|
||||
public function __construct(Component $root, ?string $name, $value = null, array $parameters = [], string $group = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->group = $group;
|
||||
|
|
@ -90,7 +84,7 @@ abstract class Property extends Node
|
|||
*
|
||||
* @param string|array $value
|
||||
*/
|
||||
public function setValue($value)
|
||||
public function setValue($value): void
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
|
@ -103,28 +97,26 @@ abstract class Property extends Node
|
|||
* it as a string.
|
||||
*
|
||||
* To get the correct multi-value version, use getParts.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
if (is_array($this->value)) {
|
||||
if (0 == count($this->value)) {
|
||||
return;
|
||||
return null;
|
||||
} elseif (1 === count($this->value)) {
|
||||
return $this->value[0];
|
||||
} else {
|
||||
return $this->getRawMimeDirValue();
|
||||
}
|
||||
} else {
|
||||
return $this->value;
|
||||
|
||||
return $this->getRawMimeDirValue();
|
||||
}
|
||||
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a multi-valued property.
|
||||
*/
|
||||
public function setParts(array $parts)
|
||||
public function setParts(array $parts): void
|
||||
{
|
||||
$this->value = $parts;
|
||||
}
|
||||
|
|
@ -134,10 +126,8 @@ abstract class Property extends Node
|
|||
*
|
||||
* This method always returns an array, if there was only a single value,
|
||||
* it will still be wrapped in an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getParts()
|
||||
public function getParts(): array
|
||||
{
|
||||
if (is_null($this->value)) {
|
||||
return [];
|
||||
|
|
@ -155,10 +145,9 @@ abstract class Property extends Node
|
|||
* combined.
|
||||
* If nameless parameter is added, we try to guess its name.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|array|null $value
|
||||
*/
|
||||
public function add($name, $value = null)
|
||||
public function add(?string $name, $value = null): void
|
||||
{
|
||||
$noName = false;
|
||||
if (null === $name) {
|
||||
|
|
@ -177,10 +166,8 @@ abstract class Property extends Node
|
|||
|
||||
/**
|
||||
* Returns an iterable list of children.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function parameters()
|
||||
public function parameters(): array
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
|
@ -190,34 +177,26 @@ abstract class Property extends Node
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getValueType();
|
||||
abstract public function getValueType(): string;
|
||||
|
||||
/**
|
||||
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||
*
|
||||
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||
* not yet done, but parameters are not included.
|
||||
*
|
||||
* @param string $val
|
||||
*/
|
||||
abstract public function setRawMimeDirValue($val);
|
||||
abstract public function setRawMimeDirValue(string $val): void;
|
||||
|
||||
/**
|
||||
* Returns a raw mime-dir representation of the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getRawMimeDirValue();
|
||||
abstract public function getRawMimeDirValue(): string;
|
||||
|
||||
/**
|
||||
* Turns the object back into a serialized blob.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function serialize()
|
||||
public function serialize(): string
|
||||
{
|
||||
$str = $this->name;
|
||||
if ($this->group) {
|
||||
|
|
@ -248,10 +227,8 @@ abstract class Property extends Node
|
|||
* Returns the value, in the format it should be encoded for JSON.
|
||||
*
|
||||
* This method must always return an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJsonValue()
|
||||
public function getJsonValue(): array
|
||||
{
|
||||
return $this->getParts();
|
||||
}
|
||||
|
|
@ -261,7 +238,7 @@ abstract class Property extends Node
|
|||
*
|
||||
* The value must always be an array.
|
||||
*/
|
||||
public function setJsonValue(array $value)
|
||||
public function setJsonValue(array $value): void
|
||||
{
|
||||
if (1 === count($value)) {
|
||||
$this->setValue(reset($value));
|
||||
|
|
@ -273,11 +250,9 @@ abstract class Property extends Node
|
|||
/**
|
||||
* This method returns an array, with the representation as it should be
|
||||
* encoded in JSON. This is used to create jCard or jCal documents.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$parameters = [];
|
||||
|
||||
|
|
@ -304,10 +279,12 @@ abstract class Property extends Node
|
|||
}
|
||||
|
||||
/**
|
||||
* Hydrate data from a XML subtree, as it would appear in a xCard or xCal
|
||||
* Hydrate data from an XML subtree, as it would appear in a xCard or xCal
|
||||
* object.
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function setXmlValue(array $value)
|
||||
public function setXmlValue(array $value): void
|
||||
{
|
||||
$this->setJsonValue($value);
|
||||
}
|
||||
|
|
@ -354,7 +331,7 @@ abstract class Property extends Node
|
|||
*
|
||||
* @param Xml\Writer $writer XML writer
|
||||
*/
|
||||
protected function xmlSerializeValue(Xml\Writer $writer)
|
||||
protected function xmlSerializeValue(Xml\Writer $writer): void
|
||||
{
|
||||
$valueType = strtolower($this->getValueType());
|
||||
|
||||
|
|
@ -370,11 +347,9 @@ abstract class Property extends Node
|
|||
*
|
||||
* If the property only had a single value, you will get just that. In the
|
||||
* case the property had multiple values, the contents will be escaped and
|
||||
* combined with ,.
|
||||
*
|
||||
* @return string
|
||||
* combined with comma.
|
||||
*/
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->getValue();
|
||||
}
|
||||
|
|
@ -383,22 +358,18 @@ abstract class Property extends Node
|
|||
|
||||
/**
|
||||
* Checks if an array element exists.
|
||||
*
|
||||
* @param mixed $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetExists($name)
|
||||
public function offsetExists($offset): bool
|
||||
{
|
||||
if (is_int($name)) {
|
||||
return parent::offsetExists($name);
|
||||
if (is_int($offset)) {
|
||||
return parent::offsetExists($offset);
|
||||
}
|
||||
|
||||
$name = strtoupper($name);
|
||||
$offset = strtoupper($offset);
|
||||
|
||||
foreach ($this->parameters as $parameter) {
|
||||
if ($parameter->name == $name) {
|
||||
if ($parameter->name == $offset) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -411,36 +382,34 @@ abstract class Property extends Node
|
|||
*
|
||||
* If the parameter does not exist, null is returned.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Node
|
||||
* @param string|int $offset
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetGet($name)
|
||||
public function offsetGet($offset): ?Node
|
||||
{
|
||||
if (is_int($name)) {
|
||||
return parent::offsetGet($name);
|
||||
if (is_int($offset)) {
|
||||
return parent::offsetGet($offset);
|
||||
}
|
||||
$name = strtoupper($name);
|
||||
$offset = strtoupper($offset);
|
||||
|
||||
if (!isset($this->parameters[$name])) {
|
||||
return;
|
||||
if (!isset($this->parameters[$offset])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->parameters[$name];
|
||||
return $this->parameters[$offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new parameter.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
* @param string|int $offset
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetSet($name, $value)
|
||||
public function offsetSet($offset, $value): void
|
||||
{
|
||||
if (is_int($name)) {
|
||||
parent::offsetSet($name, $value);
|
||||
if (is_int($offset)) {
|
||||
parent::offsetSet($offset, $value);
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
// This will never be reached, because an exception is always
|
||||
// thrown.
|
||||
|
|
@ -448,20 +417,21 @@ abstract class Property extends Node
|
|||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
$param = new Parameter($this->root, $name, $value);
|
||||
$param = new Parameter($this->root, $offset, $value);
|
||||
$this->parameters[$param->name] = $param;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes one or more parameters with the specified name.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|int $offset
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetUnset($name)
|
||||
public function offsetUnset($offset): void
|
||||
{
|
||||
if (is_int($name)) {
|
||||
parent::offsetUnset($name);
|
||||
if (is_int($offset)) {
|
||||
parent::offsetUnset($offset);
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
// This will never be reached, because an exception is always
|
||||
// thrown.
|
||||
|
|
@ -469,7 +439,7 @@ abstract class Property extends Node
|
|||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
unset($this->parameters[strtoupper($name)]);
|
||||
unset($this->parameters[strtoupper($offset)]);
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
|
@ -499,12 +469,8 @@ abstract class Property extends Node
|
|||
* * level - (number between 1 and 3 with severity information)
|
||||
* * message - (human readable message)
|
||||
* * node - (reference to the offending node)
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate($options = 0)
|
||||
public function validate(int $options = 0): array
|
||||
{
|
||||
$warnings = [];
|
||||
|
||||
|
|
@ -514,10 +480,8 @@ abstract class Property extends Node
|
|||
$level = 3;
|
||||
if ($options & self::REPAIR) {
|
||||
$newValue = StringUtil::convertToUTF8($oldValue);
|
||||
if (true || StringUtil::isUTF8($newValue)) {
|
||||
$this->setRawMimeDirValue($newValue);
|
||||
$level = 1;
|
||||
}
|
||||
$this->setRawMimeDirValue($newValue);
|
||||
$level = 1;
|
||||
}
|
||||
|
||||
if (preg_match('%([\x00-\x08\x0B-\x0C\x0E-\x1F\x7F])%', $oldValue, $matches)) {
|
||||
|
|
@ -533,11 +497,11 @@ abstract class Property extends Node
|
|||
];
|
||||
}
|
||||
|
||||
// Checking if the propertyname does not contain any invalid bytes.
|
||||
// Checking if the property name does not contain any invalid bytes.
|
||||
if (!preg_match('/^([A-Z0-9-]+)$/', $this->name)) {
|
||||
$warnings[] = [
|
||||
'level' => $options & self::REPAIR ? 1 : 3,
|
||||
'message' => 'The propertyname: '.$this->name.' contains invalid characters. Only A-Z, 0-9 and - are allowed',
|
||||
'message' => 'The property name: '.$this->name.' contains invalid characters. Only A-Z, 0-9 and - are allowed',
|
||||
'node' => $this,
|
||||
];
|
||||
if ($options & self::REPAIR) {
|
||||
|
|
@ -546,7 +510,7 @@ abstract class Property extends Node
|
|||
str_replace('_', '-', $this->name)
|
||||
);
|
||||
// Removing every other invalid character
|
||||
$this->name = preg_replace('/([^A-Z0-9-])/u', '', $this->name);
|
||||
$this->name = \preg_replace('/([^A-Z0-9-])/u', '', $this->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -558,6 +522,7 @@ abstract class Property extends Node
|
|||
'node' => $this,
|
||||
];
|
||||
} else {
|
||||
/** @var Property $encoding */
|
||||
$encoding = (string) $encoding;
|
||||
|
||||
$allowedEncoding = [];
|
||||
|
|
@ -571,7 +536,7 @@ abstract class Property extends Node
|
|||
break;
|
||||
case Document::VCARD30:
|
||||
$allowedEncoding = ['B'];
|
||||
//Repair vCard30 that use BASE64 encoding
|
||||
// Repair vCard30 that use BASE64 encoding
|
||||
if ($options & self::REPAIR) {
|
||||
if ('BASE64' === strtoupper($encoding)) {
|
||||
$encoding = 'B';
|
||||
|
|
@ -609,7 +574,7 @@ abstract class Property extends Node
|
|||
* It's intended to remove all circular references, so PHP can easily clean
|
||||
* it up.
|
||||
*/
|
||||
public function destroy()
|
||||
public function destroy(): void
|
||||
{
|
||||
parent::destroy();
|
||||
foreach ($this->parameters as $param) {
|
||||
|
|
|
|||
|
|
@ -23,10 +23,8 @@ class Binary extends Property
|
|||
/**
|
||||
* In case this is a multi-value property. This string will be used as a
|
||||
* delimiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = '';
|
||||
public string $delimiter = '';
|
||||
|
||||
/**
|
||||
* Updates the current value.
|
||||
|
|
@ -35,7 +33,7 @@ class Binary extends Property
|
|||
*
|
||||
* @param string|array $value
|
||||
*/
|
||||
public function setValue($value)
|
||||
public function setValue($value): void
|
||||
{
|
||||
if (is_array($value)) {
|
||||
if (1 === count($value)) {
|
||||
|
|
@ -53,20 +51,16 @@ class Binary extends Property
|
|||
*
|
||||
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||
* not yet done, but parameters are not included.
|
||||
*
|
||||
* @param string $val
|
||||
*/
|
||||
public function setRawMimeDirValue($val)
|
||||
public function setRawMimeDirValue(string $val): void
|
||||
{
|
||||
$this->value = base64_decode($val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a raw mime-dir representation of the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMimeDirValue()
|
||||
public function getRawMimeDirValue(): string
|
||||
{
|
||||
return base64_encode($this->value);
|
||||
}
|
||||
|
|
@ -76,10 +70,8 @@ class Binary extends Property
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'BINARY';
|
||||
}
|
||||
|
|
@ -88,10 +80,8 @@ class Binary extends Property
|
|||
* Returns the value, in the format it should be encoded for json.
|
||||
*
|
||||
* This method must always return an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJsonValue()
|
||||
public function getJsonValue(): array
|
||||
{
|
||||
return [base64_encode($this->getValue())];
|
||||
}
|
||||
|
|
@ -101,7 +91,7 @@ class Binary extends Property
|
|||
*
|
||||
* The value must always be an array.
|
||||
*/
|
||||
public function setJsonValue(array $value)
|
||||
public function setJsonValue(array $value): void
|
||||
{
|
||||
$value = array_map('base64_decode', $value);
|
||||
parent::setJsonValue($value);
|
||||
|
|
|
|||
|
|
@ -23,21 +23,17 @@ class Boolean extends Property
|
|||
*
|
||||
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||
* not yet done, but parameters are not included.
|
||||
*
|
||||
* @param string $val
|
||||
*/
|
||||
public function setRawMimeDirValue($val)
|
||||
public function setRawMimeDirValue(string $val): void
|
||||
{
|
||||
$val = 'TRUE' === strtoupper($val) ? true : false;
|
||||
$val = 'TRUE' === strtoupper($val);
|
||||
$this->setValue($val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a raw mime-dir representation of the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMimeDirValue()
|
||||
public function getRawMimeDirValue(): string
|
||||
{
|
||||
return $this->value ? 'TRUE' : 'FALSE';
|
||||
}
|
||||
|
|
@ -47,19 +43,17 @@ class Boolean extends Property
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'BOOLEAN';
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrate data from a XML subtree, as it would appear in a xCard or xCal
|
||||
* Hydrate data from an XML subtree, as it would appear in a xCard or xCal
|
||||
* object.
|
||||
*/
|
||||
public function setXmlValue(array $value)
|
||||
public function setXmlValue(array $value): void
|
||||
{
|
||||
$value = array_map(
|
||||
function ($value) {
|
||||
|
|
|
|||
|
|
@ -2,20 +2,22 @@
|
|||
|
||||
namespace Sabre\VObject\Property;
|
||||
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
|
||||
/**
|
||||
* FlatText property.
|
||||
*
|
||||
* This object represents certain TEXT values.
|
||||
*
|
||||
* Specifically, this property is used for text values where there is only 1
|
||||
* part. Semi-colons and colons will be de-escaped when deserializing, but if
|
||||
* any semi-colons or commas appear without a backslash, we will not assume
|
||||
* part. Semicolons and colons will be de-escaped when deserializing, but if
|
||||
* any semicolons or commas appear without a backslash, we will not assume
|
||||
* that they are delimiters.
|
||||
*
|
||||
* vCard 2.1 specifically has a whole bunch of properties where this may
|
||||
* vCard 2.1 specifically has a bunch of properties where this may
|
||||
* happen, as it only defines a delimiter for a few properties.
|
||||
*
|
||||
* vCard 4.0 states something similar. An unescaped semi-colon _may_ be a
|
||||
* vCard 4.0 states something similar. An unescaped semicolon _may_ be a
|
||||
* delimiter, depending on the property.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
|
|
@ -26,19 +28,17 @@ class FlatText extends Text
|
|||
{
|
||||
/**
|
||||
* Field separator.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = ',';
|
||||
public string $delimiter = ',';
|
||||
|
||||
/**
|
||||
* Sets the value as a quoted-printable encoded string.
|
||||
*
|
||||
* Overriding this so we're not splitting on a ; delimiter.
|
||||
* Overriding this so that we're not splitting on a semicolon delimiter.
|
||||
*
|
||||
* @param string $val
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function setQuotedPrintableValue($val)
|
||||
public function setQuotedPrintableValue(string $val): void
|
||||
{
|
||||
$val = quoted_printable_decode($val);
|
||||
$this->setValue($val);
|
||||
|
|
|
|||
|
|
@ -20,20 +20,16 @@ class FloatValue extends Property
|
|||
/**
|
||||
* In case this is a multi-value property. This string will be used as a
|
||||
* delimiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = ';';
|
||||
public string $delimiter = ';';
|
||||
|
||||
/**
|
||||
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||
*
|
||||
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||
* not yet done, but parameters are not included.
|
||||
*
|
||||
* @param string $val
|
||||
*/
|
||||
public function setRawMimeDirValue($val)
|
||||
public function setRawMimeDirValue(string $val): void
|
||||
{
|
||||
$val = explode($this->delimiter, $val);
|
||||
foreach ($val as &$item) {
|
||||
|
|
@ -44,10 +40,8 @@ class FloatValue extends Property
|
|||
|
||||
/**
|
||||
* Returns a raw mime-dir representation of the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMimeDirValue()
|
||||
public function getRawMimeDirValue(): string
|
||||
{
|
||||
return implode(
|
||||
$this->delimiter,
|
||||
|
|
@ -60,10 +54,8 @@ class FloatValue extends Property
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'FLOAT';
|
||||
}
|
||||
|
|
@ -72,10 +64,8 @@ class FloatValue extends Property
|
|||
* Returns the value, in the format it should be encoded for JSON.
|
||||
*
|
||||
* This method must always return an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJsonValue()
|
||||
public function getJsonValue(): array
|
||||
{
|
||||
$val = array_map('floatval', $this->getParts());
|
||||
|
||||
|
|
@ -91,10 +81,10 @@ class FloatValue extends Property
|
|||
}
|
||||
|
||||
/**
|
||||
* Hydrate data from a XML subtree, as it would appear in a xCard or xCal
|
||||
* Hydrate data from an XML subtree, as it would appear in a xCard or xCal
|
||||
* object.
|
||||
*/
|
||||
public function setXmlValue(array $value)
|
||||
public function setXmlValue(array $value): void
|
||||
{
|
||||
$value = array_map('floatval', $value);
|
||||
parent::setXmlValue($value);
|
||||
|
|
@ -103,10 +93,8 @@ class FloatValue extends Property
|
|||
/**
|
||||
* This method serializes only the value of a property. This is used to
|
||||
* create xCard or xCal documents.
|
||||
*
|
||||
* @param Xml\Writer $writer XML writer
|
||||
*/
|
||||
protected function xmlSerializeValue(Xml\Writer $writer)
|
||||
protected function xmlSerializeValue(Xml\Writer $writer): void
|
||||
{
|
||||
// Special-casing the GEO property.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -18,20 +18,16 @@ class CalAddress extends Text
|
|||
/**
|
||||
* In case this is a multi-value property. This string will be used as a
|
||||
* delimiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = '';
|
||||
public string $delimiter = '';
|
||||
|
||||
/**
|
||||
* Returns the type of value.
|
||||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'CAL-ADDRESS';
|
||||
}
|
||||
|
|
@ -43,10 +39,8 @@ class CalAddress extends Text
|
|||
* uris to lower-case.
|
||||
*
|
||||
* Evolution in particular tends to encode mailto: as MAILTO:.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNormalizedValue()
|
||||
public function getNormalizedValue(): string
|
||||
{
|
||||
$input = $this->getValue();
|
||||
if (!strpos($input, ':')) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject\Property\ICalendar;
|
||||
|
||||
use DateTimeInterface;
|
||||
use DateTimeZone;
|
||||
use Sabre\VObject\DateTimeParser;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
|
|
@ -32,16 +31,18 @@ class DateTime extends Property
|
|||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $delimiter = ',';
|
||||
public string $delimiter = ',';
|
||||
|
||||
/**
|
||||
* Sets a multi-valued property.
|
||||
*
|
||||
* You may also specify DateTime objects here.
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function setParts(array $parts)
|
||||
public function setParts(array $parts): void
|
||||
{
|
||||
if (isset($parts[0]) && $parts[0] instanceof DateTimeInterface) {
|
||||
if (isset($parts[0]) && $parts[0] instanceof \DateTimeInterface) {
|
||||
$this->setDateTimes($parts);
|
||||
} else {
|
||||
parent::setParts($parts);
|
||||
|
|
@ -55,13 +56,15 @@ class DateTime extends Property
|
|||
*
|
||||
* Instead of strings, you may also use DateTime here.
|
||||
*
|
||||
* @param string|array|DateTimeInterface $value
|
||||
* @param string|array|\DateTimeInterface $value
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function setValue($value)
|
||||
public function setValue($value): void
|
||||
{
|
||||
if (is_array($value) && isset($value[0]) && $value[0] instanceof DateTimeInterface) {
|
||||
if (is_array($value) && isset($value[0]) && $value[0] instanceof \DateTimeInterface) {
|
||||
$this->setDateTimes($value);
|
||||
} elseif ($value instanceof DateTimeInterface) {
|
||||
} elseif ($value instanceof \DateTimeInterface) {
|
||||
$this->setDateTimes([$value]);
|
||||
} else {
|
||||
parent::setValue($value);
|
||||
|
|
@ -74,29 +77,25 @@ class DateTime extends Property
|
|||
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||
* not yet done, but parameters are not included.
|
||||
*
|
||||
* @param string $val
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function setRawMimeDirValue($val)
|
||||
public function setRawMimeDirValue(string $val): void
|
||||
{
|
||||
$this->setValue(explode($this->delimiter, $val));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a raw mime-dir representation of the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMimeDirValue()
|
||||
public function getRawMimeDirValue(): string
|
||||
{
|
||||
return implode($this->delimiter, $this->getParts());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a DATE-TIME value, false if it's a DATE.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasTime()
|
||||
public function hasTime(): bool
|
||||
{
|
||||
return 'DATE' !== strtoupper((string) $this['VALUE']);
|
||||
}
|
||||
|
|
@ -106,13 +105,13 @@ class DateTime extends Property
|
|||
*
|
||||
* Note that DATE is always floating.
|
||||
*/
|
||||
public function isFloating()
|
||||
public function isFloating(): bool
|
||||
{
|
||||
return
|
||||
!$this->hasTime() ||
|
||||
(
|
||||
!isset($this['TZID']) &&
|
||||
false === strpos($this->getValue(), 'Z')
|
||||
!$this->hasTime()
|
||||
|| (
|
||||
!isset($this['TZID'])
|
||||
&& false === strpos($this->getValue(), 'Z')
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -127,15 +126,13 @@ class DateTime extends Property
|
|||
* property or floating time, we will use the DateTimeZone argument to
|
||||
* figure out the exact date.
|
||||
*
|
||||
* @param DateTimeZone $timeZone
|
||||
*
|
||||
* @return \DateTimeImmutable
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function getDateTime(DateTimeZone $timeZone = null)
|
||||
public function getDateTime(\DateTimeZone $timeZone = null): ?\DateTimeImmutable
|
||||
{
|
||||
$dt = $this->getDateTimes($timeZone);
|
||||
if (!$dt) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
return $dt[0];
|
||||
|
|
@ -148,14 +145,14 @@ class DateTime extends Property
|
|||
* property or floating time, we will use the DateTimeZone argument to
|
||||
* figure out the exact date.
|
||||
*
|
||||
* @param DateTimeZone $timeZone
|
||||
* @return \DateInterval[]|\DateTimeImmutable[]
|
||||
*
|
||||
* @return \DateTimeImmutable[]
|
||||
* @return \DateTime[]
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function getDateTimes(DateTimeZone $timeZone = null)
|
||||
public function getDateTimes(\DateTimeZone $timeZone = null): array
|
||||
{
|
||||
// Does the property have a TZID?
|
||||
/** @var Property\FlatText $tzid */
|
||||
$tzid = $this['TZID'];
|
||||
|
||||
if ($tzid) {
|
||||
|
|
@ -174,8 +171,10 @@ class DateTime extends Property
|
|||
* Sets the property as a DateTime object.
|
||||
*
|
||||
* @param bool isFloating If set to true, timezones will be ignored
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function setDateTime(DateTimeInterface $dt, $isFloating = false)
|
||||
public function setDateTime(\DateTimeInterface $dt, $isFloating = false): void
|
||||
{
|
||||
$this->setDateTimes([$dt], $isFloating);
|
||||
}
|
||||
|
|
@ -186,10 +185,12 @@ class DateTime extends Property
|
|||
* The first value will be used as a reference for the timezones, and all
|
||||
* the other values will be adjusted for that timezone
|
||||
*
|
||||
* @param DateTimeInterface[] $dt
|
||||
* @param \DateTimeInterface[] $dt
|
||||
* @param bool isFloating If set to true, timezones will be ignored
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function setDateTimes(array $dt, $isFloating = false)
|
||||
public function setDateTimes(array $dt, $isFloating = false): void
|
||||
{
|
||||
$values = [];
|
||||
|
||||
|
|
@ -236,10 +237,8 @@ class DateTime extends Property
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return $this->hasTime() ? 'DATE-TIME' : 'DATE';
|
||||
}
|
||||
|
|
@ -249,19 +248,19 @@ class DateTime extends Property
|
|||
*
|
||||
* This method must always return an array.
|
||||
*
|
||||
* @return array
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function getJsonValue()
|
||||
public function getJsonValue(): array
|
||||
{
|
||||
$dts = $this->getDateTimes();
|
||||
$hasTime = $this->hasTime();
|
||||
$isFloating = $this->isFloating();
|
||||
|
||||
$tz = $dts[0]->getTimeZone();
|
||||
$isUtc = $isFloating ? false : in_array($tz->getName(), ['UTC', 'GMT', 'Z']);
|
||||
$isUtc = !$isFloating && in_array($tz->getName(), ['UTC', 'GMT', 'Z']);
|
||||
|
||||
return array_map(
|
||||
function (DateTimeInterface $dt) use ($hasTime, $isUtc) {
|
||||
function (\DateTimeInterface $dt) use ($hasTime, $isUtc) {
|
||||
if ($hasTime) {
|
||||
return $dt->format('Y-m-d\\TH:i:s').($isUtc ? 'Z' : '');
|
||||
} else {
|
||||
|
|
@ -276,8 +275,10 @@ class DateTime extends Property
|
|||
* Sets the json value, as it would appear in a jCard or jCal object.
|
||||
*
|
||||
* The value must always be an array.
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function setJsonValue(array $value)
|
||||
public function setJsonValue(array $value): void
|
||||
{
|
||||
// dates and times in jCal have one difference to dates and times in
|
||||
// iCalendar. In jCal date-parts are separated by dashes, and
|
||||
|
|
@ -297,14 +298,15 @@ class DateTime extends Property
|
|||
* We need to intercept offsetSet, because it may be used to alter the
|
||||
* VALUE from DATE-TIME to DATE or vice-versa.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
* @param string|int $offset
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetSet($name, $value)
|
||||
public function offsetSet($offset, $value): void
|
||||
{
|
||||
parent::offsetSet($name, $value);
|
||||
if ('VALUE' !== strtoupper($name)) {
|
||||
parent::offsetSet($offset, $value);
|
||||
if ('VALUE' !== strtoupper($offset)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -329,12 +331,8 @@ class DateTime extends Property
|
|||
* 1 - The issue was repaired (only happens if REPAIR was turned on)
|
||||
* 2 - An inconsequential issue
|
||||
* 3 - A severe issue.
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate($options = 0)
|
||||
public function validate(int $options = 0): array
|
||||
{
|
||||
$messages = parent::validate($options);
|
||||
$valueType = $this->getValueType();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace Sabre\VObject\Property\ICalendar;
|
||||
|
||||
use DateInterval;
|
||||
use Sabre\VObject\DateTimeParser;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
use Sabre\VObject\Property;
|
||||
|
||||
/**
|
||||
|
|
@ -21,30 +23,24 @@ class Duration extends Property
|
|||
/**
|
||||
* In case this is a multi-value property. This string will be used as a
|
||||
* delimiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = ',';
|
||||
public string $delimiter = ',';
|
||||
|
||||
/**
|
||||
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||
*
|
||||
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||
* not yet done, but parameters are not included.
|
||||
*
|
||||
* @param string $val
|
||||
*/
|
||||
public function setRawMimeDirValue($val)
|
||||
public function setRawMimeDirValue(string $val): void
|
||||
{
|
||||
$this->setValue(explode($this->delimiter, $val));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a raw mime-dir representation of the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMimeDirValue()
|
||||
public function getRawMimeDirValue(): string
|
||||
{
|
||||
return implode($this->delimiter, $this->getParts());
|
||||
}
|
||||
|
|
@ -54,10 +50,8 @@ class Duration extends Property
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'DURATION';
|
||||
}
|
||||
|
|
@ -67,9 +61,9 @@ class Duration extends Property
|
|||
*
|
||||
* If the property has more than one value, only the first is returned.
|
||||
*
|
||||
* @return \DateInterval
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function getDateInterval()
|
||||
public function getDateInterval(): \DateInterval
|
||||
{
|
||||
$parts = $this->getParts();
|
||||
$value = $parts[0];
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Sabre\VObject\Property\ICalendar;
|
||||
|
||||
use Sabre\VObject\DateTimeParser;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
use Sabre\VObject\Property;
|
||||
use Sabre\Xml;
|
||||
|
||||
|
|
@ -22,30 +23,24 @@ class Period extends Property
|
|||
/**
|
||||
* In case this is a multi-value property. This string will be used as a
|
||||
* delimiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = ',';
|
||||
public string $delimiter = ',';
|
||||
|
||||
/**
|
||||
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||
*
|
||||
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||
* not yet done, but parameters are not included.
|
||||
*
|
||||
* @param string $val
|
||||
*/
|
||||
public function setRawMimeDirValue($val)
|
||||
public function setRawMimeDirValue(string $val): void
|
||||
{
|
||||
$this->setValue(explode($this->delimiter, $val));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a raw mime-dir representation of the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMimeDirValue()
|
||||
public function getRawMimeDirValue(): string
|
||||
{
|
||||
return implode($this->delimiter, $this->getParts());
|
||||
}
|
||||
|
|
@ -55,10 +50,8 @@ class Period extends Property
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'PERIOD';
|
||||
}
|
||||
|
|
@ -68,7 +61,7 @@ class Period extends Property
|
|||
*
|
||||
* The value must always be an array.
|
||||
*/
|
||||
public function setJsonValue(array $value)
|
||||
public function setJsonValue(array $value): void
|
||||
{
|
||||
$value = array_map(
|
||||
function ($item) {
|
||||
|
|
@ -84,9 +77,9 @@ class Period extends Property
|
|||
*
|
||||
* This method must always return an array.
|
||||
*
|
||||
* @return array
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function getJsonValue()
|
||||
public function getJsonValue(): array
|
||||
{
|
||||
$return = [];
|
||||
foreach ($this->getParts() as $item) {
|
||||
|
|
@ -116,9 +109,9 @@ class Period extends Property
|
|||
* This method serializes only the value of a property. This is used to
|
||||
* create xCard or xCal documents.
|
||||
*
|
||||
* @param Xml\Writer $writer XML writer
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
protected function xmlSerializeValue(Xml\Writer $writer)
|
||||
protected function xmlSerializeValue(Xml\Writer $writer): void
|
||||
{
|
||||
$writer->startElement(strtolower($this->getValueType()));
|
||||
$value = $this->getJsonValue();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Sabre\VObject\Property\ICalendar;
|
||||
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
use Sabre\VObject\Node;
|
||||
use Sabre\VObject\Property;
|
||||
use Sabre\Xml;
|
||||
|
||||
|
|
@ -24,6 +26,11 @@ use Sabre\Xml;
|
|||
*/
|
||||
class Recur extends Property
|
||||
{
|
||||
/**
|
||||
* Reference to the parent object, if this is not the top object.
|
||||
*/
|
||||
public ?Node $parent;
|
||||
|
||||
/**
|
||||
* Updates the current value.
|
||||
*
|
||||
|
|
@ -31,10 +38,10 @@ class Recur extends Property
|
|||
*
|
||||
* @param string|array $value
|
||||
*/
|
||||
public function setValue($value)
|
||||
public function setValue($value): void
|
||||
{
|
||||
// If we're getting the data from json, we'll be receiving an object
|
||||
if ($value instanceof \StdClass) {
|
||||
if ($value instanceof \stdClass) {
|
||||
$value = (array) $value;
|
||||
}
|
||||
|
||||
|
|
@ -73,10 +80,8 @@ class Recur extends Property
|
|||
* it as a string.
|
||||
*
|
||||
* To get the correct multi-value version, use getParts.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValue()
|
||||
public function getValue(): string
|
||||
{
|
||||
$out = [];
|
||||
foreach ($this->value as $key => $value) {
|
||||
|
|
@ -89,7 +94,7 @@ class Recur extends Property
|
|||
/**
|
||||
* Sets a multi-valued property.
|
||||
*/
|
||||
public function setParts(array $parts)
|
||||
public function setParts(array $parts): void
|
||||
{
|
||||
$this->setValue($parts);
|
||||
}
|
||||
|
|
@ -99,10 +104,8 @@ class Recur extends Property
|
|||
*
|
||||
* This method always returns an array, if there was only a single value,
|
||||
* it will still be wrapped in an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getParts()
|
||||
public function getParts(): array
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
|
@ -112,20 +115,16 @@ class Recur extends Property
|
|||
*
|
||||
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||
* not yet done, but parameters are not included.
|
||||
*
|
||||
* @param string $val
|
||||
*/
|
||||
public function setRawMimeDirValue($val)
|
||||
public function setRawMimeDirValue(string $val): void
|
||||
{
|
||||
$this->setValue($val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a raw mime-dir representation of the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMimeDirValue()
|
||||
public function getRawMimeDirValue(): string
|
||||
{
|
||||
return $this->getValue();
|
||||
}
|
||||
|
|
@ -135,10 +134,8 @@ class Recur extends Property
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'RECUR';
|
||||
}
|
||||
|
|
@ -148,9 +145,9 @@ class Recur extends Property
|
|||
*
|
||||
* This method must always return an array.
|
||||
*
|
||||
* @return array
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function getJsonValue()
|
||||
public function getJsonValue(): array
|
||||
{
|
||||
$values = [];
|
||||
foreach ($this->getParts() as $k => $v) {
|
||||
|
|
@ -170,10 +167,8 @@ class Recur extends Property
|
|||
/**
|
||||
* This method serializes only the value of a property. This is used to
|
||||
* create xCard or xCal documents.
|
||||
*
|
||||
* @param Xml\Writer $writer XML writer
|
||||
*/
|
||||
protected function xmlSerializeValue(Xml\Writer $writer)
|
||||
protected function xmlSerializeValue(Xml\Writer $writer): void
|
||||
{
|
||||
$valueType = strtolower($this->getValueType());
|
||||
|
||||
|
|
@ -184,12 +179,8 @@ class Recur extends Property
|
|||
|
||||
/**
|
||||
* Parses an RRULE value string, and turns it into a struct-ish array.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function stringToArray($value)
|
||||
public static function stringToArray(string $value): array
|
||||
{
|
||||
$value = strtoupper($value);
|
||||
$newValue = [];
|
||||
|
|
@ -227,12 +218,8 @@ class Recur extends Property
|
|||
* 1 - The issue was repaired (only happens if REPAIR was turned on)
|
||||
* 2 - An inconsequential issue
|
||||
* 3 - A severe issue.
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate($options = 0)
|
||||
public function validate(int $options = 0): array
|
||||
{
|
||||
$repair = ($options & self::REPAIR);
|
||||
|
||||
|
|
|
|||
|
|
@ -21,20 +21,16 @@ class IntegerValue extends Property
|
|||
*
|
||||
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||
* not yet done, but parameters are not included.
|
||||
*
|
||||
* @param string $val
|
||||
*/
|
||||
public function setRawMimeDirValue($val)
|
||||
public function setRawMimeDirValue(string $val): void
|
||||
{
|
||||
$this->setValue((int) $val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a raw mime-dir representation of the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMimeDirValue()
|
||||
public function getRawMimeDirValue(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
|
@ -44,10 +40,8 @@ class IntegerValue extends Property
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'INTEGER';
|
||||
}
|
||||
|
|
@ -56,19 +50,17 @@ class IntegerValue extends Property
|
|||
* Returns the value, in the format it should be encoded for json.
|
||||
*
|
||||
* This method must always return an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJsonValue()
|
||||
public function getJsonValue(): array
|
||||
{
|
||||
return [(int) $this->getValue()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrate data from a XML subtree, as it would appear in a xCard or xCal
|
||||
* Hydrate data from an XML subtree, as it would appear in a xCard or xCal
|
||||
* object.
|
||||
*/
|
||||
public function setXmlValue(array $value)
|
||||
public function setXmlValue(array $value): void
|
||||
{
|
||||
$value = array_map('intval', $value);
|
||||
parent::setXmlValue($value);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace Sabre\VObject\Property;
|
|||
|
||||
use Sabre\VObject\Component;
|
||||
use Sabre\VObject\Document;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
use Sabre\VObject\Parser\MimeDir;
|
||||
use Sabre\VObject\Property;
|
||||
use Sabre\Xml;
|
||||
|
|
@ -22,17 +23,13 @@ class Text extends Property
|
|||
/**
|
||||
* In case this is a multi-value property. This string will be used as a
|
||||
* delimiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = ',';
|
||||
public string $delimiter = ',';
|
||||
|
||||
/**
|
||||
* List of properties that are considered 'structured'.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $structuredValues = [
|
||||
protected array $structuredValues = [
|
||||
// vCard
|
||||
'N',
|
||||
'ADR',
|
||||
|
|
@ -49,10 +46,8 @@ class Text extends Property
|
|||
*
|
||||
* N must for instance be represented as 5 components, separated by ;, even
|
||||
* if the last few components are unused.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $minimumPropertyValues = [
|
||||
protected array $minimumPropertyValues = [
|
||||
'N' => 5,
|
||||
'ADR' => 7,
|
||||
];
|
||||
|
|
@ -65,18 +60,17 @@ class Text extends Property
|
|||
* Parameter objects.
|
||||
*
|
||||
* @param Component $root The root document
|
||||
* @param string $name
|
||||
* @param string|array|null $value
|
||||
* @param array $parameters List of parameters
|
||||
* @param string $group The vcard property group
|
||||
* @param string|null $group The vcard property group
|
||||
*/
|
||||
public function __construct(Component $root, $name, $value = null, array $parameters = [], $group = null)
|
||||
public function __construct(Component $root, string $name, $value = null, array $parameters = [], string $group = null)
|
||||
{
|
||||
// There's two types of multi-valued text properties:
|
||||
// 1. multivalue properties.
|
||||
// 2. structured value properties
|
||||
//
|
||||
// The former is always separated by a comma, the latter by semi-colon.
|
||||
// The former is always separated by a comma, the latter by semicolon.
|
||||
if (in_array($name, $this->structuredValues)) {
|
||||
$this->delimiter = ';';
|
||||
}
|
||||
|
|
@ -90,19 +84,17 @@ class Text extends Property
|
|||
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||
* not yet done, but parameters are not included.
|
||||
*
|
||||
* @param string $val
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function setRawMimeDirValue($val)
|
||||
public function setRawMimeDirValue(string $val): void
|
||||
{
|
||||
$this->setValue(MimeDir::unescapeValue($val, $this->delimiter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value as a quoted-printable encoded string.
|
||||
*
|
||||
* @param string $val
|
||||
*/
|
||||
public function setQuotedPrintableValue($val)
|
||||
public function setQuotedPrintableValue(string $val): void
|
||||
{
|
||||
$val = quoted_printable_decode($val);
|
||||
|
||||
|
|
@ -119,15 +111,13 @@ class Text extends Property
|
|||
|
||||
/**
|
||||
* Returns a raw mime-dir representation of the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMimeDirValue()
|
||||
public function getRawMimeDirValue(): string
|
||||
{
|
||||
$val = $this->getParts();
|
||||
|
||||
if (isset($this->minimumPropertyValues[$this->name])) {
|
||||
$val = array_pad($val, $this->minimumPropertyValues[$this->name], '');
|
||||
$val = \array_pad($val, $this->minimumPropertyValues[$this->name], '');
|
||||
}
|
||||
|
||||
foreach ($val as &$item) {
|
||||
|
|
@ -136,7 +126,7 @@ class Text extends Property
|
|||
}
|
||||
|
||||
foreach ($item as &$subItem) {
|
||||
if (!is_null($subItem)) {
|
||||
if (!\is_null($subItem)) {
|
||||
$subItem = strtr(
|
||||
$subItem,
|
||||
[
|
||||
|
|
@ -149,20 +139,18 @@ class Text extends Property
|
|||
);
|
||||
}
|
||||
}
|
||||
$item = implode(',', $item);
|
||||
$item = \implode(',', $item);
|
||||
}
|
||||
|
||||
return implode($this->delimiter, $val);
|
||||
return \implode($this->delimiter, $val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value, in the format it should be encoded for json.
|
||||
*
|
||||
* This method must always return an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJsonValue()
|
||||
public function getJsonValue(): array
|
||||
{
|
||||
// Structured text values should always be returned as a single
|
||||
// array-item. Multi-value text should be returned as multiple items in
|
||||
|
|
@ -179,20 +167,16 @@ class Text extends Property
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'TEXT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns the object back into a serialized blob.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function serialize()
|
||||
public function serialize(): string
|
||||
{
|
||||
// We need to kick in a special type of encoding, if it's a 2.1 vcard.
|
||||
if (Document::VCARD21 !== $this->root->getDocumentType()) {
|
||||
|
|
@ -232,7 +216,7 @@ class Text extends Property
|
|||
if (false !== \strpos($val, "\n")) {
|
||||
$str .= ';ENCODING=QUOTED-PRINTABLE:';
|
||||
$lastLine = $str;
|
||||
$out = null;
|
||||
$out = '';
|
||||
|
||||
// The PHP built-in quoted-printable-encode does not correctly
|
||||
// encode newlines for us. Specifically, the \r\n sequence must in
|
||||
|
|
@ -278,14 +262,12 @@ class Text extends Property
|
|||
/**
|
||||
* This method serializes only the value of a property. This is used to
|
||||
* create xCard or xCal documents.
|
||||
*
|
||||
* @param Xml\Writer $writer XML writer
|
||||
*/
|
||||
protected function xmlSerializeValue(Xml\Writer $writer)
|
||||
protected function xmlSerializeValue(Xml\Writer $writer): void
|
||||
{
|
||||
$values = $this->getParts();
|
||||
|
||||
$map = function ($items) use ($values, $writer) {
|
||||
$map = function (array $items) use ($values, $writer): void {
|
||||
foreach ($items as $i => $item) {
|
||||
$writer->writeElement(
|
||||
$item,
|
||||
|
|
@ -362,26 +344,22 @@ class Text extends Property
|
|||
* * level - (number between 1 and 3 with severity information)
|
||||
* * message - (human readable message)
|
||||
* * node - (reference to the offending node)
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate($options = 0)
|
||||
public function validate(int $options = 0): array
|
||||
{
|
||||
$warnings = parent::validate($options);
|
||||
|
||||
if (isset($this->minimumPropertyValues[$this->name])) {
|
||||
$minimum = $this->minimumPropertyValues[$this->name];
|
||||
$parts = $this->getParts();
|
||||
if (count($parts) < $minimum) {
|
||||
if (\count($parts) < $minimum) {
|
||||
$warnings[] = [
|
||||
'level' => $options & self::REPAIR ? 1 : 3,
|
||||
'message' => 'The '.$this->name.' property must have at least '.$minimum.' values. It only has '.count($parts),
|
||||
'message' => 'The '.$this->name.' property must have at least '.$minimum.' values. It only has '.\count($parts),
|
||||
'node' => $this,
|
||||
];
|
||||
if ($options & self::REPAIR) {
|
||||
$parts = array_pad($parts, $minimum, '');
|
||||
$parts = \array_pad($parts, $minimum, '');
|
||||
$this->setParts($parts);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Sabre\VObject\Property;
|
||||
|
||||
use Sabre\VObject\DateTimeParser;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
|
||||
/**
|
||||
* Time property.
|
||||
|
|
@ -18,20 +19,16 @@ class Time extends Text
|
|||
/**
|
||||
* In case this is a multi-value property. This string will be used as a
|
||||
* delimiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = '';
|
||||
public string $delimiter = '';
|
||||
|
||||
/**
|
||||
* Returns the type of value.
|
||||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'TIME';
|
||||
}
|
||||
|
|
@ -41,7 +38,7 @@ class Time extends Text
|
|||
*
|
||||
* The value must always be an array.
|
||||
*/
|
||||
public function setJsonValue(array $value)
|
||||
public function setJsonValue(array $value): void
|
||||
{
|
||||
// Removing colons from value.
|
||||
$value = str_replace(
|
||||
|
|
@ -62,9 +59,9 @@ class Time extends Text
|
|||
*
|
||||
* This method must always return an array.
|
||||
*
|
||||
* @return array
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function getJsonValue()
|
||||
public function getJsonValue(): array
|
||||
{
|
||||
$parts = DateTimeParser::parseVCardTime($this->getValue());
|
||||
$timeStr = '';
|
||||
|
|
@ -115,10 +112,10 @@ class Time extends Text
|
|||
}
|
||||
|
||||
/**
|
||||
* Hydrate data from a XML subtree, as it would appear in a xCard or xCal
|
||||
* Hydrate data from an XML subtree, as it would appear in a xCard or xCal
|
||||
* object.
|
||||
*/
|
||||
public function setXmlValue(array $value)
|
||||
public function setXmlValue(array $value): void
|
||||
{
|
||||
$value = array_map(
|
||||
function ($value) {
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@ class Unknown extends Text
|
|||
* Returns the value, in the format it should be encoded for json.
|
||||
*
|
||||
* This method must always return an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJsonValue()
|
||||
public function getJsonValue(): array
|
||||
{
|
||||
return [$this->getRawMimeDirValue()];
|
||||
}
|
||||
|
|
@ -31,10 +29,8 @@ class Unknown extends Text
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'UNKNOWN';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
namespace Sabre\VObject\Property;
|
||||
|
||||
use Sabre\VObject\Parameter;
|
||||
use Sabre\VObject\Property;
|
||||
|
||||
/**
|
||||
* URI property.
|
||||
|
|
@ -19,30 +18,24 @@ class Uri extends Text
|
|||
/**
|
||||
* In case this is a multi-value property. This string will be used as a
|
||||
* delimiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = '';
|
||||
public string $delimiter = '';
|
||||
|
||||
/**
|
||||
* Returns the type of value.
|
||||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'URI';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterable list of children.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function parameters()
|
||||
public function parameters(): array
|
||||
{
|
||||
$parameters = parent::parameters();
|
||||
if (!isset($parameters['VALUE']) && in_array($this->name, ['URL', 'PHOTO'])) {
|
||||
|
|
@ -65,13 +58,11 @@ class Uri extends Text
|
|||
*
|
||||
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||
* not yet done, but parameters are not included.
|
||||
*
|
||||
* @param string $val
|
||||
*/
|
||||
public function setRawMimeDirValue($val)
|
||||
public function setRawMimeDirValue(string $val): void
|
||||
{
|
||||
// Normally we don't need to do any type of unescaping for these
|
||||
// properties, however.. we've noticed that Google Contacts
|
||||
// properties, however, we've noticed that Google Contacts
|
||||
// specifically escapes the colon (:) with a backslash. While I have
|
||||
// no clue why they thought that was a good idea, I'm unescaping it
|
||||
// anyway.
|
||||
|
|
@ -100,10 +91,8 @@ class Uri extends Text
|
|||
|
||||
/**
|
||||
* Returns a raw mime-dir representation of the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMimeDirValue()
|
||||
public function getRawMimeDirValue(): string
|
||||
{
|
||||
if (is_array($this->value)) {
|
||||
$value = $this->value[0];
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Sabre\VObject\Property;
|
||||
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
|
||||
/**
|
||||
* UtcOffset property.
|
||||
*
|
||||
|
|
@ -16,20 +18,16 @@ class UtcOffset extends Text
|
|||
/**
|
||||
* In case this is a multi-value property. This string will be used as a
|
||||
* delimiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = '';
|
||||
public string $delimiter = '';
|
||||
|
||||
/**
|
||||
* Returns the type of value.
|
||||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'UTC-OFFSET';
|
||||
}
|
||||
|
|
@ -38,8 +36,10 @@ class UtcOffset extends Text
|
|||
* Sets the JSON value, as it would appear in a jCard or jCal object.
|
||||
*
|
||||
* The value must always be an array.
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function setJsonValue(array $value)
|
||||
public function setJsonValue(array $value): void
|
||||
{
|
||||
$value = array_map(
|
||||
function ($value) {
|
||||
|
|
@ -54,10 +54,8 @@ class UtcOffset extends Text
|
|||
* Returns the value, in the format it should be encoded for JSON.
|
||||
*
|
||||
* This method must always return an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJsonValue()
|
||||
public function getJsonValue(): array
|
||||
{
|
||||
return array_map(
|
||||
function ($value) {
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@ class Date extends DateAndOrTime
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'DATE';
|
||||
}
|
||||
|
|
@ -29,7 +27,7 @@ class Date extends DateAndOrTime
|
|||
/**
|
||||
* Sets the property as a DateTime object.
|
||||
*/
|
||||
public function setDateTime(\DateTimeInterface $dt)
|
||||
public function setDateTime(\DateTimeInterface $dt): void
|
||||
{
|
||||
$this->value = $dt->format('Ymd');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
namespace Sabre\VObject\Property\VCard;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Sabre\VObject\DateTimeParser;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
|
|
@ -23,20 +22,16 @@ class DateAndOrTime extends Property
|
|||
{
|
||||
/**
|
||||
* Field separator.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = '';
|
||||
public string $delimiter = '';
|
||||
|
||||
/**
|
||||
* Returns the type of value.
|
||||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'DATE-AND-OR-TIME';
|
||||
}
|
||||
|
|
@ -46,12 +41,12 @@ class DateAndOrTime extends Property
|
|||
*
|
||||
* You may also specify DateTimeInterface objects here.
|
||||
*/
|
||||
public function setParts(array $parts)
|
||||
public function setParts(array $parts): void
|
||||
{
|
||||
if (count($parts) > 1) {
|
||||
throw new \InvalidArgumentException('Only one value allowed');
|
||||
}
|
||||
if (isset($parts[0]) && $parts[0] instanceof DateTimeInterface) {
|
||||
if (isset($parts[0]) && $parts[0] instanceof \DateTimeInterface) {
|
||||
$this->setDateTime($parts[0]);
|
||||
} else {
|
||||
parent::setParts($parts);
|
||||
|
|
@ -65,11 +60,11 @@ class DateAndOrTime extends Property
|
|||
*
|
||||
* Instead of strings, you may also use DateTimeInterface here.
|
||||
*
|
||||
* @param string|array|DateTimeInterface $value
|
||||
* @param string|array|\DateTimeInterface $value
|
||||
*/
|
||||
public function setValue($value)
|
||||
public function setValue($value): void
|
||||
{
|
||||
if ($value instanceof DateTimeInterface) {
|
||||
if ($value instanceof \DateTimeInterface) {
|
||||
$this->setDateTime($value);
|
||||
} else {
|
||||
parent::setValue($value);
|
||||
|
|
@ -79,7 +74,7 @@ class DateAndOrTime extends Property
|
|||
/**
|
||||
* Sets the property as a DateTime object.
|
||||
*/
|
||||
public function setDateTime(DateTimeInterface $dt)
|
||||
public function setDateTime(\DateTimeInterface $dt): void
|
||||
{
|
||||
$tz = $dt->getTimeZone();
|
||||
$isUtc = in_array($tz->getName(), ['UTC', 'GMT', 'Z']);
|
||||
|
|
@ -108,11 +103,11 @@ class DateAndOrTime extends Property
|
|||
* current values for those. So at the time of writing, if the year was
|
||||
* omitted, we would have filled in 2014.
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function getDateTime()
|
||||
public function getDateTime(): \DateTimeImmutable
|
||||
{
|
||||
$now = new DateTime();
|
||||
$now = new \DateTime();
|
||||
|
||||
$tzFormat = 0 === $now->getTimezone()->getOffset($now) ? '\\Z' : 'O';
|
||||
$nowParts = DateTimeParser::parseVCardDateTime($now->format('Ymd\\This'.$tzFormat));
|
||||
|
|
@ -128,7 +123,7 @@ class DateAndOrTime extends Property
|
|||
}
|
||||
}
|
||||
|
||||
return new DateTimeImmutable("$dateParts[year]-$dateParts[month]-$dateParts[date] $dateParts[hour]:$dateParts[minute]:$dateParts[second] $dateParts[timezone]");
|
||||
return new \DateTimeImmutable("$dateParts[year]-$dateParts[month]-$dateParts[date] $dateParts[hour]:$dateParts[minute]:$dateParts[second] $dateParts[timezone]");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -136,9 +131,9 @@ class DateAndOrTime extends Property
|
|||
*
|
||||
* This method must always return an array.
|
||||
*
|
||||
* @return array
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function getJsonValue()
|
||||
public function getJsonValue(): array
|
||||
{
|
||||
$parts = DateTimeParser::parseVCardDateTime($this->getValue());
|
||||
|
||||
|
|
@ -228,16 +223,16 @@ class DateAndOrTime extends Property
|
|||
* This method serializes only the value of a property. This is used to
|
||||
* create xCard or xCal documents.
|
||||
*
|
||||
* @param Xml\Writer $writer XML writer
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
protected function xmlSerializeValue(Xml\Writer $writer)
|
||||
protected function xmlSerializeValue(Xml\Writer $writer): void
|
||||
{
|
||||
$valueType = strtolower($this->getValueType());
|
||||
$parts = DateTimeParser::parseVCardDateAndOrTime($this->getValue());
|
||||
$value = '';
|
||||
|
||||
// $d = defined
|
||||
$d = function ($part) use ($parts) {
|
||||
$d = function ($part) use ($parts): bool {
|
||||
return !is_null($parts[$part]);
|
||||
};
|
||||
|
||||
|
|
@ -264,7 +259,7 @@ class DateAndOrTime extends Property
|
|||
$value .= '---'.$r('date');
|
||||
}
|
||||
|
||||
// # 4.3.2
|
||||
// # 4.3.2
|
||||
// value-time = element time {
|
||||
// xsd:string { pattern = "(\d\d(\d\d(\d\d)?)?|-\d\d(\d\d?)|--\d\d)"
|
||||
// ~ "(Z|[+\-]\d\d(\d\d)?)?" }
|
||||
|
|
@ -307,20 +302,16 @@ class DateAndOrTime extends Property
|
|||
*
|
||||
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||
* not yet done, but parameters are not included.
|
||||
*
|
||||
* @param string $val
|
||||
*/
|
||||
public function setRawMimeDirValue($val)
|
||||
public function setRawMimeDirValue(string $val): void
|
||||
{
|
||||
$this->setValue($val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a raw mime-dir representation of the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMimeDirValue()
|
||||
public function getRawMimeDirValue(): string
|
||||
{
|
||||
return implode($this->delimiter, $this->getParts());
|
||||
}
|
||||
|
|
@ -342,12 +333,8 @@ class DateAndOrTime extends Property
|
|||
* 1 - The issue was repaired (only happens if REPAIR was turned on)
|
||||
* 2 - An inconsequential issue
|
||||
* 3 - A severe issue.
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate($options = 0)
|
||||
public function validate(int $options = 0): array
|
||||
{
|
||||
$messages = parent::validate($options);
|
||||
$value = $this->getValue();
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@ class DateTime extends DateAndOrTime
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'DATE-TIME';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,20 +20,16 @@ class LanguageTag extends Property
|
|||
*
|
||||
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||
* not yet done, but parameters are not included.
|
||||
*
|
||||
* @param string $val
|
||||
*/
|
||||
public function setRawMimeDirValue($val)
|
||||
public function setRawMimeDirValue(string $val): void
|
||||
{
|
||||
$this->setValue($val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a raw mime-dir representation of the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMimeDirValue()
|
||||
public function getRawMimeDirValue(): string
|
||||
{
|
||||
return $this->getValue();
|
||||
}
|
||||
|
|
@ -43,10 +39,8 @@ class LanguageTag extends Property
|
|||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'LANGUAGE-TAG';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,17 +13,15 @@ use Sabre\VObject\Property;
|
|||
*/
|
||||
class PhoneNumber extends Property\Text
|
||||
{
|
||||
protected $structuredValues = [];
|
||||
protected array $structuredValues = [];
|
||||
|
||||
/**
|
||||
* Returns the type of value.
|
||||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'PHONE-NUMBER';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Sabre\VObject\Property\VCard;
|
||||
|
||||
use Sabre\VObject\DateTimeParser;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
use Sabre\VObject\Property\Text;
|
||||
use Sabre\Xml;
|
||||
|
||||
|
|
@ -20,20 +21,16 @@ class TimeStamp extends Text
|
|||
/**
|
||||
* In case this is a multi-value property. This string will be used as a
|
||||
* delimiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = '';
|
||||
public string $delimiter = '';
|
||||
|
||||
/**
|
||||
* Returns the type of value.
|
||||
*
|
||||
* This corresponds to the VALUE= parameter. Every property also has a
|
||||
* 'default' valueType.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValueType()
|
||||
public function getValueType(): string
|
||||
{
|
||||
return 'TIMESTAMP';
|
||||
}
|
||||
|
|
@ -43,9 +40,9 @@ class TimeStamp extends Text
|
|||
*
|
||||
* This method must always return an array.
|
||||
*
|
||||
* @return array
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function getJsonValue()
|
||||
public function getJsonValue(): array
|
||||
{
|
||||
$parts = DateTimeParser::parseVCardDateTime($this->getValue());
|
||||
|
||||
|
|
@ -68,10 +65,8 @@ class TimeStamp extends Text
|
|||
/**
|
||||
* This method serializes only the value of a property. This is used to
|
||||
* create xCard or xCal documents.
|
||||
*
|
||||
* @param Xml\Writer $writer XML writer
|
||||
*/
|
||||
protected function xmlSerializeValue(Xml\Writer $writer)
|
||||
protected function xmlSerializeValue(Xml\Writer $writer): void
|
||||
{
|
||||
// xCard is the only XML and JSON format that has the same date and time
|
||||
// format than vCard.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
use Sabre\Xml\LibXMLException;
|
||||
|
||||
/**
|
||||
* iCalendar/vCard/jCal/jCard/xCal/xCard reader object.
|
||||
*
|
||||
|
|
@ -18,13 +20,13 @@ class Reader
|
|||
* If this option is passed to the reader, it will be less strict about the
|
||||
* validity of the lines.
|
||||
*/
|
||||
const OPTION_FORGIVING = 1;
|
||||
public const OPTION_FORGIVING = 1;
|
||||
|
||||
/**
|
||||
* If this option is turned on, any lines we cannot parse will be ignored
|
||||
* by the reader.
|
||||
*/
|
||||
const OPTION_IGNORE_INVALID_LINES = 2;
|
||||
public const OPTION_IGNORE_INVALID_LINES = 2;
|
||||
|
||||
/**
|
||||
* Parses a vCard or iCalendar object, and returns the top component.
|
||||
|
|
@ -35,18 +37,15 @@ class Reader
|
|||
* You can either supply a string, or a readable stream for input.
|
||||
*
|
||||
* @param string|resource $data
|
||||
* @param int $options
|
||||
* @param string $charset
|
||||
*
|
||||
* @return Document
|
||||
* @throws ParseException
|
||||
*/
|
||||
public static function read($data, $options = 0, $charset = 'UTF-8')
|
||||
public static function read($data, int $options = 0, string $charset = 'UTF-8'): ?Document
|
||||
{
|
||||
$parser = new Parser\MimeDir();
|
||||
$parser->setCharset($charset);
|
||||
$result = $parser->parse($data, $options);
|
||||
|
||||
return $result;
|
||||
return $parser->parse($data, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -60,16 +59,15 @@ class Reader
|
|||
* input.
|
||||
*
|
||||
* @param string|resource|array $data
|
||||
* @param int $options
|
||||
*
|
||||
* @return Document
|
||||
* @throws EofException
|
||||
* @throws ParseException|InvalidDataException
|
||||
*/
|
||||
public static function readJson($data, $options = 0)
|
||||
public static function readJson($data, int $options = 0): ?Document
|
||||
{
|
||||
$parser = new Parser\Json();
|
||||
$result = $parser->parse($data, $options);
|
||||
|
||||
return $result;
|
||||
return $parser->parse($data, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -81,15 +79,16 @@ class Reader
|
|||
* You can either supply a string, or a readable stream for input.
|
||||
*
|
||||
* @param string|resource $data
|
||||
* @param int $options
|
||||
*
|
||||
* @return Document
|
||||
* @throws EofException
|
||||
* @throws InvalidDataException
|
||||
* @throws ParseException
|
||||
* @throws LibXMLException
|
||||
*/
|
||||
public static function readXML($data, $options = 0)
|
||||
public static function readXML($data, int $options = 0): ?Document
|
||||
{
|
||||
$parser = new Parser\XML();
|
||||
$result = $parser->parse($data, $options);
|
||||
|
||||
return $result;
|
||||
return $parser->parse($data, $options);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@
|
|||
|
||||
namespace Sabre\VObject\Recur;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use DateTimeZone;
|
||||
use InvalidArgumentException;
|
||||
use Sabre\VObject\Component;
|
||||
use Sabre\VObject\Component\VEvent;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
use Sabre\VObject\Settings;
|
||||
|
||||
/**
|
||||
|
|
@ -62,17 +59,13 @@ class EventIterator implements \Iterator
|
|||
{
|
||||
/**
|
||||
* Reference timeZone for floating dates and times.
|
||||
*
|
||||
* @var DateTimeZone
|
||||
*/
|
||||
protected $timeZone;
|
||||
protected \DateTimeZone $timeZone;
|
||||
|
||||
/**
|
||||
* True if we're iterating an all-day event.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $allDay = false;
|
||||
protected bool $allDay = false;
|
||||
|
||||
/**
|
||||
* Creates the iterator.
|
||||
|
|
@ -88,15 +81,18 @@ class EventIterator implements \Iterator
|
|||
*
|
||||
* The $uid parameter is only required for the first method.
|
||||
*
|
||||
* @param Component|array $input
|
||||
* @param string|null $uid
|
||||
* @param DateTimeZone $timeZone reference timezone for floating dates and
|
||||
* times
|
||||
* @param Component|Component\VCalendar|array $input
|
||||
* @param \DateTimeZone|null $timeZone reference timezone for floating dates and
|
||||
* times
|
||||
*
|
||||
* @throws MaxInstancesExceededException
|
||||
* @throws NoInstancesException
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function __construct($input, $uid = null, DateTimeZone $timeZone = null)
|
||||
public function __construct($input, string $uid = null, \DateTimeZone $timeZone = null)
|
||||
{
|
||||
if (is_null($timeZone)) {
|
||||
$timeZone = new DateTimeZone('UTC');
|
||||
$timeZone = new \DateTimeZone('UTC');
|
||||
}
|
||||
$this->timeZone = $timeZone;
|
||||
|
||||
|
|
@ -107,16 +103,16 @@ class EventIterator implements \Iterator
|
|||
$events = [$input];
|
||||
} else {
|
||||
// Calendar + UID mode.
|
||||
$uid = (string) $uid;
|
||||
if (!$uid) {
|
||||
throw new InvalidArgumentException('The UID argument is required when a VCALENDAR is passed to this constructor');
|
||||
throw new \InvalidArgumentException('The UID argument is required when a VCALENDAR is passed to this constructor');
|
||||
}
|
||||
if (!isset($input->VEVENT)) {
|
||||
throw new InvalidArgumentException('No events found in this calendar');
|
||||
throw new \InvalidArgumentException('No events found in this calendar');
|
||||
}
|
||||
$events = $input->getByUID($uid);
|
||||
}
|
||||
|
||||
/** @var VEvent[] $events */
|
||||
foreach ($events as $vevent) {
|
||||
if (!isset($vevent->{'RECURRENCE-ID'})) {
|
||||
$this->masterEvent = $vevent;
|
||||
|
|
@ -136,7 +132,7 @@ class EventIterator implements \Iterator
|
|||
// event and use that instead. This may not always give the
|
||||
// desired result.
|
||||
if (!count($this->overriddenEvents)) {
|
||||
throw new InvalidArgumentException('This VCALENDAR did not have an event with UID: '.$uid);
|
||||
throw new \InvalidArgumentException('This VCALENDAR did not have an event with UID: '.$uid);
|
||||
}
|
||||
$this->masterEvent = array_shift($this->overriddenEvents);
|
||||
}
|
||||
|
|
@ -195,40 +191,40 @@ class EventIterator implements \Iterator
|
|||
|
||||
/**
|
||||
* Returns the date for the current position of the iterator.
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function current()
|
||||
public function current(): ?\DateTimeImmutable
|
||||
{
|
||||
if ($this->currentDate) {
|
||||
return clone $this->currentDate;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the start date for the current iteration of the
|
||||
* event.
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function getDtStart()
|
||||
public function getDtStart(): ?\DateTimeImmutable
|
||||
{
|
||||
if ($this->currentDate) {
|
||||
return clone $this->currentDate;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the end date for the current iteration of the
|
||||
* event.
|
||||
*
|
||||
* @return DateTimeImmutable
|
||||
* @throws MaxInstancesExceededException|InvalidDataException
|
||||
*/
|
||||
public function getDtEnd()
|
||||
public function getDtEnd(): ?\DateTimeImmutable
|
||||
{
|
||||
if (!$this->valid()) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
if ($this->currentOverriddenEvent && $this->currentOverriddenEvent->DTEND) {
|
||||
return $this->currentOverriddenEvent->DTEND->getDateTime($this->timeZone);
|
||||
|
|
@ -245,14 +241,16 @@ class EventIterator implements \Iterator
|
|||
* This VEVENT will have a recurrence id, and its DTSTART and DTEND
|
||||
* altered.
|
||||
*
|
||||
* @return VEvent
|
||||
* @throws MaxInstancesExceededException
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function getEventObject()
|
||||
public function getEventObject(): VEvent
|
||||
{
|
||||
if ($this->currentOverriddenEvent) {
|
||||
return $this->currentOverriddenEvent;
|
||||
}
|
||||
|
||||
/** @var VEvent $event */
|
||||
$event = clone $this->masterEvent;
|
||||
|
||||
// Ignoring the following block, because PHPUnit's code coverage
|
||||
|
|
@ -283,11 +281,9 @@ class EventIterator implements \Iterator
|
|||
* Returns the current position of the iterator.
|
||||
*
|
||||
* This is for us simply a 0-based index.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function key()
|
||||
public function key(): int
|
||||
{
|
||||
// The counter is always 1 ahead.
|
||||
return $this->counter - 1;
|
||||
|
|
@ -297,10 +293,10 @@ class EventIterator implements \Iterator
|
|||
* This is called after next, to see if the iterator is still at a valid
|
||||
* position, or if it's at the end.
|
||||
*
|
||||
* @return bool
|
||||
* @throws MaxInstancesExceededException
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function valid()
|
||||
public function valid(): bool
|
||||
{
|
||||
if ($this->counter > Settings::$maxRecurrences && -1 !== Settings::$maxRecurrences) {
|
||||
throw new MaxInstancesExceededException('Recurring events are only allowed to generate '.Settings::$maxRecurrences);
|
||||
|
|
@ -312,15 +308,16 @@ class EventIterator implements \Iterator
|
|||
/**
|
||||
* Sets the iterator back to the starting point.
|
||||
*
|
||||
* @return void
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function rewind()
|
||||
public function rewind(): void
|
||||
{
|
||||
$this->recurIterator->rewind();
|
||||
// re-creating overridden event index.
|
||||
$index = [];
|
||||
foreach ($this->overriddenEvents as $key => $event) {
|
||||
/** @var VEvent $event */
|
||||
$stamp = $event->DTSTART->getDateTime($this->timeZone)->getTimeStamp();
|
||||
$index[$stamp][] = $key;
|
||||
}
|
||||
|
|
@ -338,10 +335,10 @@ class EventIterator implements \Iterator
|
|||
/**
|
||||
* Advances the iterator with one step.
|
||||
*
|
||||
* @return void
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function next()
|
||||
public function next(): void
|
||||
{
|
||||
$this->currentOverriddenEvent = null;
|
||||
++$this->counter;
|
||||
|
|
@ -393,8 +390,10 @@ class EventIterator implements \Iterator
|
|||
|
||||
/**
|
||||
* Quickly jump to a date in the future.
|
||||
*
|
||||
* @throws MaxInstancesExceededException|InvalidDataException
|
||||
*/
|
||||
public function fastForward(DateTimeInterface $dateTime)
|
||||
public function fastForward(\DateTimeInterface $dateTime): void
|
||||
{
|
||||
while ($this->valid() && $this->getDtEnd() <= $dateTime) {
|
||||
$this->next();
|
||||
|
|
@ -403,10 +402,8 @@ class EventIterator implements \Iterator
|
|||
|
||||
/**
|
||||
* Returns true if this recurring event never ends.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isInfinite()
|
||||
public function isInfinite(): bool
|
||||
{
|
||||
return $this->recurIterator->isInfinite();
|
||||
}
|
||||
|
|
@ -414,9 +411,9 @@ class EventIterator implements \Iterator
|
|||
/**
|
||||
* RRULE parser.
|
||||
*
|
||||
* @var RRuleIterator
|
||||
* @var RRuleIterator|RDateIterator
|
||||
*/
|
||||
protected $recurIterator;
|
||||
protected \Iterator $recurIterator;
|
||||
|
||||
/**
|
||||
* The duration, in seconds, of the master event.
|
||||
|
|
@ -427,71 +424,53 @@ class EventIterator implements \Iterator
|
|||
|
||||
/**
|
||||
* A reference to the main (master) event.
|
||||
*
|
||||
* @var VEVENT
|
||||
*/
|
||||
protected $masterEvent;
|
||||
protected ?VEvent $masterEvent = null;
|
||||
|
||||
/**
|
||||
* List of overridden events.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $overriddenEvents = [];
|
||||
protected array $overriddenEvents = [];
|
||||
|
||||
/**
|
||||
* Overridden event index.
|
||||
*
|
||||
* Key is timestamp, value is the list of indexes of the item in the $overriddenEvent
|
||||
* property.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $overriddenEventsIndex;
|
||||
protected array $overriddenEventsIndex;
|
||||
|
||||
/**
|
||||
* A list of recurrence-id's that are either part of EXDATE, or are
|
||||
* overridden.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $exceptions = [];
|
||||
protected array $exceptions = [];
|
||||
|
||||
/**
|
||||
* Internal event counter.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $counter;
|
||||
protected int $counter = 0;
|
||||
|
||||
/**
|
||||
* The very start of the iteration process.
|
||||
*
|
||||
* @var DateTimeImmutable
|
||||
*/
|
||||
protected $startDate;
|
||||
protected ?\DateTimeImmutable $startDate;
|
||||
|
||||
/**
|
||||
* Where we are currently in the iteration process.
|
||||
*
|
||||
* @var DateTimeImmutable
|
||||
*/
|
||||
protected $currentDate;
|
||||
protected ?\DateTimeImmutable $currentDate = null;
|
||||
|
||||
/**
|
||||
* The next date from the rrule parser.
|
||||
*
|
||||
* Sometimes we need to temporary store the next date, because an
|
||||
* overridden event came before.
|
||||
*
|
||||
* @var DateTimeImmutable
|
||||
*/
|
||||
protected $nextDate;
|
||||
protected ?\DateTimeImmutable $nextDate = null;
|
||||
|
||||
/**
|
||||
* The event that overwrites the current iteration.
|
||||
*
|
||||
* @var VEVENT
|
||||
*/
|
||||
protected $currentOverriddenEvent;
|
||||
protected ?VEvent $currentOverriddenEvent = null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject\Recur;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* This exception will get thrown when a recurrence rule generated more than
|
||||
* the maximum number of instances.
|
||||
|
|
@ -12,6 +10,6 @@ use Exception;
|
|||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class MaxInstancesExceededException extends Exception
|
||||
class MaxInstancesExceededException extends \Exception
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject\Recur;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* This exception gets thrown when a recurrence iterator produces 0 instances.
|
||||
*
|
||||
|
|
@ -13,6 +11,6 @@ use Exception;
|
|||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class NoInstancesException extends Exception
|
||||
class NoInstancesException extends \Exception
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
namespace Sabre\VObject\Recur;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Iterator;
|
||||
use Sabre\VObject\DateTimeParser;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
|
||||
/**
|
||||
* RRuleParser.
|
||||
|
|
@ -19,14 +19,14 @@ use Sabre\VObject\DateTimeParser;
|
|||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class RDateIterator implements Iterator
|
||||
class RDateIterator implements \Iterator
|
||||
{
|
||||
/**
|
||||
* Creates the Iterator.
|
||||
*
|
||||
* @param string|array $rrule
|
||||
*/
|
||||
public function __construct($rrule, DateTimeInterface $start)
|
||||
public function __construct($rrule, \DateTimeInterface $start)
|
||||
{
|
||||
$this->startDate = $start;
|
||||
$this->parseRDate($rrule);
|
||||
|
|
@ -36,10 +36,10 @@ class RDateIterator implements Iterator
|
|||
/* Implementation of the Iterator interface {{{ */
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function current()
|
||||
public function current(): ?\DateTimeInterface
|
||||
{
|
||||
if (!$this->valid()) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
return clone $this->currentDate;
|
||||
|
|
@ -47,11 +47,9 @@ class RDateIterator implements Iterator
|
|||
|
||||
/**
|
||||
* Returns the current item number.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function key()
|
||||
public function key(): int
|
||||
{
|
||||
return $this->counter;
|
||||
}
|
||||
|
|
@ -59,22 +57,18 @@ class RDateIterator implements Iterator
|
|||
/**
|
||||
* Returns whether the current item is a valid item for the recurrence
|
||||
* iterator.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function valid()
|
||||
public function valid(): bool
|
||||
{
|
||||
return $this->counter <= count($this->dates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the iterator.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function rewind()
|
||||
public function rewind(): void
|
||||
{
|
||||
$this->currentDate = clone $this->startDate;
|
||||
$this->counter = 0;
|
||||
|
|
@ -83,10 +77,10 @@ class RDateIterator implements Iterator
|
|||
/**
|
||||
* Goes on to the next iteration.
|
||||
*
|
||||
* @return void
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function next()
|
||||
public function next(): void
|
||||
{
|
||||
++$this->counter;
|
||||
if (!$this->valid()) {
|
||||
|
|
@ -104,10 +98,8 @@ class RDateIterator implements Iterator
|
|||
|
||||
/**
|
||||
* Returns true if this recurring event never ends.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isInfinite()
|
||||
public function isInfinite(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -115,8 +107,10 @@ class RDateIterator implements Iterator
|
|||
/**
|
||||
* This method allows you to quickly go to the next occurrence after the
|
||||
* specified date.
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function fastForward(DateTimeInterface $dt)
|
||||
public function fastForward(\DateTimeInterface $dt): void
|
||||
{
|
||||
while ($this->valid() && $this->currentDate < $dt) {
|
||||
$this->next();
|
||||
|
|
@ -127,27 +121,21 @@ class RDateIterator implements Iterator
|
|||
* The reference start date/time for the rrule.
|
||||
*
|
||||
* All calculations are based on this initial date.
|
||||
*
|
||||
* @var DateTimeInterface
|
||||
*/
|
||||
protected $startDate;
|
||||
protected \DateTimeInterface $startDate;
|
||||
|
||||
/**
|
||||
* The date of the current iteration. You can get this by calling
|
||||
* ->current().
|
||||
*
|
||||
* @var DateTimeInterface
|
||||
*/
|
||||
protected $currentDate;
|
||||
protected \DateTimeInterface $currentDate;
|
||||
|
||||
/**
|
||||
* The current item in the list.
|
||||
*
|
||||
* You can get this number with the key() method.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $counter = 0;
|
||||
protected int $counter = 0;
|
||||
|
||||
/* }}} */
|
||||
|
||||
|
|
@ -155,9 +143,9 @@ class RDateIterator implements Iterator
|
|||
* This method receives a string from an RRULE property, and populates this
|
||||
* class with all the values.
|
||||
*
|
||||
* @param string|array $rrule
|
||||
* @param string|array $rdate
|
||||
*/
|
||||
protected function parseRDate($rdate)
|
||||
protected function parseRDate($rdate): void
|
||||
{
|
||||
if (is_string($rdate)) {
|
||||
$rdate = explode(',', $rdate);
|
||||
|
|
@ -168,8 +156,6 @@ class RDateIterator implements Iterator
|
|||
|
||||
/**
|
||||
* Array with the RRULE dates.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $dates = [];
|
||||
protected array $dates = [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
namespace Sabre\VObject\Recur;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Iterator;
|
||||
use Sabre\VObject\DateTimeParser;
|
||||
use Sabre\VObject\InvalidDataException;
|
||||
|
|
@ -22,21 +21,23 @@ use Sabre\VObject\Property;
|
|||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class RRuleIterator implements Iterator
|
||||
class RRuleIterator implements \Iterator
|
||||
{
|
||||
/**
|
||||
* Constant denoting the upper limit on how long into the future
|
||||
* we want to iterate. The value is a unix timestamp and currently
|
||||
* corresponds to the datetime 9999-12-31 11:59:59 UTC.
|
||||
*/
|
||||
const dateUpperLimit = 253402300799;
|
||||
public const dateUpperLimit = 253402300799;
|
||||
|
||||
/**
|
||||
* Creates the Iterator.
|
||||
*
|
||||
* @param string|array $rrule
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function __construct($rrule, DateTimeInterface $start)
|
||||
public function __construct($rrule, \DateTimeInterface $start)
|
||||
{
|
||||
$this->startDate = $start;
|
||||
$this->parseRRule($rrule);
|
||||
|
|
@ -46,10 +47,10 @@ class RRuleIterator implements Iterator
|
|||
/* Implementation of the Iterator interface {{{ */
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function current()
|
||||
public function current(): ?\DateTimeInterface
|
||||
{
|
||||
if (!$this->valid()) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
return clone $this->currentDate;
|
||||
|
|
@ -57,11 +58,9 @@ class RRuleIterator implements Iterator
|
|||
|
||||
/**
|
||||
* Returns the current item number.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function key()
|
||||
public function key(): int
|
||||
{
|
||||
return $this->counter;
|
||||
}
|
||||
|
|
@ -70,11 +69,9 @@ class RRuleIterator implements Iterator
|
|||
* Returns whether the current item is a valid item for the recurrence
|
||||
* iterator. This will return false if we've gone beyond the UNTIL or COUNT
|
||||
* statements.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function valid()
|
||||
public function valid(): bool
|
||||
{
|
||||
if (null === $this->currentDate) {
|
||||
return false;
|
||||
|
|
@ -88,11 +85,9 @@ class RRuleIterator implements Iterator
|
|||
|
||||
/**
|
||||
* Resets the iterator.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function rewind()
|
||||
public function rewind(): void
|
||||
{
|
||||
$this->currentDate = clone $this->startDate;
|
||||
$this->counter = 0;
|
||||
|
|
@ -100,11 +95,9 @@ class RRuleIterator implements Iterator
|
|||
|
||||
/**
|
||||
* Goes on to the next iteration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function next()
|
||||
public function next(): void
|
||||
{
|
||||
// Otherwise, we find the next event in the normal RRULE
|
||||
// sequence.
|
||||
|
|
@ -136,10 +129,8 @@ class RRuleIterator implements Iterator
|
|||
|
||||
/**
|
||||
* Returns true if this recurring event never ends.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isInfinite()
|
||||
public function isInfinite(): bool
|
||||
{
|
||||
return !$this->count && !$this->until;
|
||||
}
|
||||
|
|
@ -148,7 +139,7 @@ class RRuleIterator implements Iterator
|
|||
* This method allows you to quickly go to the next occurrence after the
|
||||
* specified date.
|
||||
*/
|
||||
public function fastForward(DateTimeInterface $dt)
|
||||
public function fastForward(\DateTimeInterface $dt): void
|
||||
{
|
||||
while ($this->valid() && $this->currentDate < $dt) {
|
||||
$this->next();
|
||||
|
|
@ -159,86 +150,66 @@ class RRuleIterator implements Iterator
|
|||
* The reference start date/time for the rrule.
|
||||
*
|
||||
* All calculations are based on this initial date.
|
||||
*
|
||||
* @var DateTimeInterface
|
||||
*/
|
||||
protected $startDate;
|
||||
protected \DateTimeInterface $startDate;
|
||||
|
||||
/**
|
||||
* The date of the current iteration. You can get this by calling
|
||||
* ->current().
|
||||
*
|
||||
* @var DateTimeInterface
|
||||
*/
|
||||
protected $currentDate;
|
||||
protected ?\DateTimeInterface $currentDate;
|
||||
|
||||
/**
|
||||
* Frequency is one of: secondly, minutely, hourly, daily, weekly, monthly,
|
||||
* yearly.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $frequency;
|
||||
protected string $frequency;
|
||||
|
||||
/**
|
||||
* The number of recurrences, or 'null' if infinitely recurring.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $count;
|
||||
protected ?int $count = null;
|
||||
|
||||
/**
|
||||
* The interval.
|
||||
*
|
||||
* If for example frequency is set to daily, interval = 2 would mean every
|
||||
* 2 days.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $interval = 1;
|
||||
protected int $interval = 1;
|
||||
|
||||
/**
|
||||
* The last instance of this recurrence, inclusively.
|
||||
*
|
||||
* @var DateTimeInterface|null
|
||||
*/
|
||||
protected $until;
|
||||
protected ?\DateTimeInterface $until = null;
|
||||
|
||||
/**
|
||||
* Which seconds to recur.
|
||||
*
|
||||
* This is an array of integers (between 0 and 60)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $bySecond;
|
||||
protected ?array $bySecond = null;
|
||||
|
||||
/**
|
||||
* Which minutes to recur.
|
||||
*
|
||||
* This is an array of integers (between 0 and 59)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $byMinute;
|
||||
protected ?array $byMinute = null;
|
||||
|
||||
/**
|
||||
* Which hours to recur.
|
||||
*
|
||||
* This is an array of integers (between 0 and 23)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $byHour;
|
||||
protected ?array $byHour = null;
|
||||
|
||||
/**
|
||||
* The current item in the list.
|
||||
*
|
||||
* You can get this number with the key() method.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $counter = 0;
|
||||
protected int $counter = 0;
|
||||
|
||||
/**
|
||||
* Which weekdays to recur.
|
||||
|
|
@ -249,20 +220,16 @@ class RRuleIterator implements Iterator
|
|||
* this indicates the nth occurrence of a specific day within the monthly or
|
||||
* yearly rrule. For instance, -2TU indicates the second-last tuesday of
|
||||
* the month, or year.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $byDay;
|
||||
protected ?array $byDay = null;
|
||||
|
||||
/**
|
||||
* Which days of the month to recur.
|
||||
*
|
||||
* This is an array of days of the months (1-31). The value can also be
|
||||
* negative. -5 for instance means the 5th last day of the month.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $byMonthDay;
|
||||
protected ?array $byMonthDay = null;
|
||||
|
||||
/**
|
||||
* Which days of the year to recur.
|
||||
|
|
@ -270,29 +237,23 @@ class RRuleIterator implements Iterator
|
|||
* This is an array with days of the year (1 to 366). The values can also
|
||||
* be negative. For instance, -1 will always represent the last day of the
|
||||
* year. (December 31st).
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $byYearDay;
|
||||
protected ?array $byYearDay = null;
|
||||
|
||||
/**
|
||||
* Which week numbers to recur.
|
||||
*
|
||||
* This is an array of integers from 1 to 53. The values can also be
|
||||
* negative. -1 will always refer to the last week of the year.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $byWeekNo;
|
||||
protected ?array $byWeekNo = null;
|
||||
|
||||
/**
|
||||
* Which months to recur.
|
||||
*
|
||||
* This is an array of integers from 1 to 12.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $byMonth;
|
||||
protected ?array $byMonth = null;
|
||||
|
||||
/**
|
||||
* Which items in an existing st to recur.
|
||||
|
|
@ -305,24 +266,20 @@ class RRuleIterator implements Iterator
|
|||
*
|
||||
* This would be done by setting frequency to 'monthly', byDay to
|
||||
* 'MO,TU,WE,TH,FR' and bySetPos to -1.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $bySetPos;
|
||||
protected ?array $bySetPos = null;
|
||||
|
||||
/**
|
||||
* When the week starts.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $weekStart = 'MO';
|
||||
protected string $weekStart = 'MO';
|
||||
|
||||
/* Functions that advance the iterator {{{ */
|
||||
|
||||
/**
|
||||
* Does the processing for advancing the iterator for hourly frequency.
|
||||
*/
|
||||
protected function nextHourly()
|
||||
protected function nextHourly(): void
|
||||
{
|
||||
$this->currentDate = $this->currentDate->modify('+'.$this->interval.' hours');
|
||||
}
|
||||
|
|
@ -330,7 +287,7 @@ class RRuleIterator implements Iterator
|
|||
/**
|
||||
* Does the processing for advancing the iterator for daily frequency.
|
||||
*/
|
||||
protected function nextDaily()
|
||||
protected function nextDaily(): void
|
||||
{
|
||||
if (!$this->byHour && !$this->byDay) {
|
||||
$this->currentDate = $this->currentDate->modify('+'.$this->interval.' days');
|
||||
|
|
@ -380,16 +337,16 @@ class RRuleIterator implements Iterator
|
|||
return;
|
||||
}
|
||||
} while (
|
||||
($this->byDay && !in_array($currentDay, $recurrenceDays)) ||
|
||||
($this->byHour && !in_array($currentHour, $recurrenceHours)) ||
|
||||
($this->byMonth && !in_array($currentMonth, $recurrenceMonths))
|
||||
($this->byDay && !in_array($currentDay, $recurrenceDays))
|
||||
|| ($this->byHour && !in_array($currentHour, $recurrenceHours))
|
||||
|| ($this->byMonth && !in_array($currentMonth, $recurrenceMonths))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the processing for advancing the iterator for weekly frequency.
|
||||
*/
|
||||
protected function nextWeekly()
|
||||
protected function nextWeekly(): void
|
||||
{
|
||||
if (!$this->byHour && !$this->byDay) {
|
||||
$this->currentDate = $this->currentDate->modify('+'.$this->interval.' weeks');
|
||||
|
|
@ -440,8 +397,10 @@ class RRuleIterator implements Iterator
|
|||
|
||||
/**
|
||||
* Does the processing for advancing the iterator for monthly frequency.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function nextMonthly()
|
||||
protected function nextMonthly(): void
|
||||
{
|
||||
$currentDayOfMonth = $this->currentDate->format('j');
|
||||
if (!$this->byMonthDay && !$this->byDay) {
|
||||
|
|
@ -468,7 +427,7 @@ class RRuleIterator implements Iterator
|
|||
$occurrences = $this->getMonthlyOccurrences();
|
||||
|
||||
foreach ($occurrences as $occurrence) {
|
||||
// The first occurrence thats higher than the current
|
||||
// The first occurrence that's higher than the current
|
||||
// day of the month wins.
|
||||
if ($occurrence > $currentDayOfMonth) {
|
||||
break 2;
|
||||
|
|
@ -482,7 +441,7 @@ class RRuleIterator implements Iterator
|
|||
// This line does not currently work in hhvm. Temporary workaround
|
||||
// follows:
|
||||
// $this->currentDate->modify('first day of this month');
|
||||
$this->currentDate = new DateTimeImmutable($this->currentDate->format('Y-m-1 H:i:s'), $this->currentDate->getTimezone());
|
||||
$this->currentDate = new \DateTimeImmutable($this->currentDate->format('Y-m-1 H:i:s'), $this->currentDate->getTimezone());
|
||||
// end of workaround
|
||||
$this->currentDate = $this->currentDate->modify('+ '.$this->interval.' months');
|
||||
|
||||
|
|
@ -491,7 +450,7 @@ class RRuleIterator implements Iterator
|
|||
$currentDayOfMonth = 0;
|
||||
|
||||
// For some reason the "until" parameter was not being used here,
|
||||
// that's why the workaround of the 10000 year bug was needed at all
|
||||
// that's why the workaround of the 10000-year bug was needed at all
|
||||
// let's stop it before the "until" parameter date
|
||||
if ($this->until && $this->currentDate->getTimestamp() >= $this->until->getTimestamp()) {
|
||||
return;
|
||||
|
|
@ -516,7 +475,7 @@ class RRuleIterator implements Iterator
|
|||
/**
|
||||
* Does the processing for advancing the iterator for yearly frequency.
|
||||
*/
|
||||
protected function nextYearly()
|
||||
protected function nextYearly(): void
|
||||
{
|
||||
$currentMonth = $this->currentDate->format('n');
|
||||
$currentYear = $this->currentDate->format('Y');
|
||||
|
|
@ -717,8 +676,10 @@ class RRuleIterator implements Iterator
|
|||
* class with all the values.
|
||||
*
|
||||
* @param string|array $rrule
|
||||
*
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
protected function parseRRule($rrule)
|
||||
protected function parseRRule($rrule): void
|
||||
{
|
||||
if (is_string($rrule)) {
|
||||
$rrule = Property\ICalendar\Recur::stringToArray($rrule);
|
||||
|
|
@ -833,10 +794,8 @@ class RRuleIterator implements Iterator
|
|||
|
||||
/**
|
||||
* Mappings between the day number and english day name.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $dayNames = [
|
||||
protected array $dayNames = [
|
||||
0 => 'Sunday',
|
||||
1 => 'Monday',
|
||||
2 => 'Tuesday',
|
||||
|
|
@ -852,9 +811,9 @@ class RRuleIterator implements Iterator
|
|||
*
|
||||
* The returned list is an array of integers with the day of month (1-31).
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getMonthlyOccurrences()
|
||||
protected function getMonthlyOccurrences(): array
|
||||
{
|
||||
$startDate = clone $this->currentDate;
|
||||
|
||||
|
|
@ -903,7 +862,7 @@ class RRuleIterator implements Iterator
|
|||
}
|
||||
} else {
|
||||
// There was no counter (first, second, last wednesdays), so we
|
||||
// just need to add the all to the list).
|
||||
// just need to add the all to the list.
|
||||
$byDayResults = array_merge($byDayResults, $dayHits);
|
||||
}
|
||||
}
|
||||
|
|
@ -913,8 +872,8 @@ class RRuleIterator implements Iterator
|
|||
if ($this->byMonthDay) {
|
||||
foreach ($this->byMonthDay as $monthDay) {
|
||||
// Removing values that are out of range for this month
|
||||
if ($monthDay > $startDate->format('t') ||
|
||||
$monthDay < 0 - $startDate->format('t')) {
|
||||
if ($monthDay > $startDate->format('t')
|
||||
|| $monthDay < 0 - $startDate->format('t')) {
|
||||
continue;
|
||||
}
|
||||
if ($monthDay > 0) {
|
||||
|
|
@ -962,10 +921,8 @@ class RRuleIterator implements Iterator
|
|||
|
||||
/**
|
||||
* Simple mapping from iCalendar day names to day numbers.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $dayMap = [
|
||||
protected array $dayMap = [
|
||||
'SU' => 0,
|
||||
'MO' => 1,
|
||||
'TU' => 2,
|
||||
|
|
@ -975,7 +932,7 @@ class RRuleIterator implements Iterator
|
|||
'SA' => 6,
|
||||
];
|
||||
|
||||
protected function getHours()
|
||||
protected function getHours(): array
|
||||
{
|
||||
$recurrenceHours = [];
|
||||
foreach ($this->byHour as $byHour) {
|
||||
|
|
@ -985,7 +942,7 @@ class RRuleIterator implements Iterator
|
|||
return $recurrenceHours;
|
||||
}
|
||||
|
||||
protected function getDays()
|
||||
protected function getDays(): array
|
||||
{
|
||||
$recurrenceDays = [];
|
||||
foreach ($this->byDay as $byDay) {
|
||||
|
|
@ -998,7 +955,7 @@ class RRuleIterator implements Iterator
|
|||
return $recurrenceDays;
|
||||
}
|
||||
|
||||
protected function getMonths()
|
||||
protected function getMonths(): array
|
||||
{
|
||||
$recurrenceMonths = [];
|
||||
foreach ($this->byMonth as $byMonth) {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class Settings
|
|||
* use-cases. In particular, it covers birthdates for virtually everyone
|
||||
* alive on earth, which is less than 5 people at the time of writing.
|
||||
*/
|
||||
public static $minDate = '1900-01-01';
|
||||
public static string $minDate = '1900-01-01';
|
||||
|
||||
/**
|
||||
* The maximum date we accept for various calculations with dates, such as
|
||||
|
|
@ -34,7 +34,7 @@ class Settings
|
|||
* The choice of 2100 is pretty arbitrary, but should cover most
|
||||
* appointments made for many years to come.
|
||||
*/
|
||||
public static $maxDate = '2100-01-01';
|
||||
public static string $maxDate = '2100-01-01';
|
||||
|
||||
/**
|
||||
* The maximum number of recurrences that will be generated.
|
||||
|
|
@ -51,5 +51,5 @@ class Settings
|
|||
*
|
||||
* Set this value to -1 to disable this control altogether.
|
||||
*/
|
||||
public static $maxRecurrences = 3500;
|
||||
public static int $maxRecurrences = 3500;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Sabre\VObject\Splitter;
|
||||
|
||||
use Sabre\VObject;
|
||||
use Sabre\VObject\Component;
|
||||
use Sabre\VObject\Component\VCalendar;
|
||||
|
||||
/**
|
||||
|
|
@ -23,27 +24,25 @@ class ICalendar implements SplitterInterface
|
|||
{
|
||||
/**
|
||||
* Timezones.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $vtimezones = [];
|
||||
protected array $vtimezones = [];
|
||||
|
||||
/**
|
||||
* iCalendar objects.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $objects = [];
|
||||
protected array $objects = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* The splitter should receive an readable file stream as its input.
|
||||
* The splitter should receive a readable file stream as its input.
|
||||
*
|
||||
* @param resource $input
|
||||
* @param int $options parser options, see the OPTIONS constants
|
||||
*
|
||||
* @throws VObject\ParseException
|
||||
*/
|
||||
public function __construct($input, $options = 0)
|
||||
public function __construct($input, int $options = 0)
|
||||
{
|
||||
$data = VObject\Reader::read($input, $options);
|
||||
|
||||
|
|
@ -52,7 +51,7 @@ class ICalendar implements SplitterInterface
|
|||
}
|
||||
|
||||
foreach ($data->children() as $component) {
|
||||
if (!$component instanceof VObject\Component) {
|
||||
if (!$component instanceof Component) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -82,10 +81,8 @@ class ICalendar implements SplitterInterface
|
|||
* hit the end of the stream.
|
||||
*
|
||||
* When the end is reached, null will be returned.
|
||||
*
|
||||
* @return \Sabre\VObject\Component|null
|
||||
*/
|
||||
public function getNext()
|
||||
public function getNext(): ?Component
|
||||
{
|
||||
if ($object = array_shift($this->objects)) {
|
||||
// create our baseobject
|
||||
|
|
@ -100,7 +97,7 @@ class ICalendar implements SplitterInterface
|
|||
|
||||
return $object;
|
||||
} else {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Sabre\VObject\Splitter;
|
||||
|
||||
use Sabre\VObject\Component;
|
||||
|
||||
/**
|
||||
* VObject splitter.
|
||||
*
|
||||
|
|
@ -20,7 +22,7 @@ interface SplitterInterface
|
|||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* The splitter should receive an readable file stream as its input.
|
||||
* The splitter should receive a readable file stream as its input.
|
||||
*
|
||||
* @param resource $input
|
||||
*/
|
||||
|
|
@ -31,8 +33,6 @@ interface SplitterInterface
|
|||
* hit the end of the stream.
|
||||
*
|
||||
* When the end is reached, null will be returned.
|
||||
*
|
||||
* @return \Sabre\VObject\Component|null
|
||||
*/
|
||||
public function getNext();
|
||||
public function getNext(): ?Component;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Sabre\VObject\Splitter;
|
||||
|
||||
use Sabre\VObject;
|
||||
use Sabre\VObject\Component;
|
||||
use Sabre\VObject\Parser\MimeDir;
|
||||
|
||||
/**
|
||||
|
|
@ -30,20 +31,18 @@ class VCard implements SplitterInterface
|
|||
|
||||
/**
|
||||
* Persistent parser.
|
||||
*
|
||||
* @var MimeDir
|
||||
*/
|
||||
protected $parser;
|
||||
protected MimeDir $parser;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* The splitter should receive an readable file stream as its input.
|
||||
* The splitter should receive a readable file stream as its input.
|
||||
*
|
||||
* @param resource $input
|
||||
* @param int $options parser options, see the OPTIONS constants
|
||||
*/
|
||||
public function __construct($input, $options = 0)
|
||||
public function __construct($input, int $options = 0)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->parser = new MimeDir($input, $options);
|
||||
|
|
@ -55,9 +54,9 @@ class VCard implements SplitterInterface
|
|||
*
|
||||
* When the end is reached, null will be returned.
|
||||
*
|
||||
* @return \Sabre\VObject\Component|null
|
||||
* @throws VObject\ParseException
|
||||
*/
|
||||
public function getNext()
|
||||
public function getNext(): ?Component
|
||||
{
|
||||
try {
|
||||
$object = $this->parser->parse();
|
||||
|
|
@ -66,7 +65,7 @@ class VCard implements SplitterInterface
|
|||
throw new VObject\ParseException('The supplied input contained non-VCARD data.');
|
||||
}
|
||||
} catch (VObject\EofException $e) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
return $object;
|
||||
|
|
|
|||
|
|
@ -13,12 +13,8 @@ class StringUtil
|
|||
{
|
||||
/**
|
||||
* Returns true or false depending on if a string is valid UTF-8.
|
||||
*
|
||||
* @param string $str
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isUTF8($str)
|
||||
public static function isUTF8(string $str): bool
|
||||
{
|
||||
// Control characters
|
||||
if (preg_match('%[\x00-\x08\x0B-\x0C\x0E\x0F]%', $str)) {
|
||||
|
|
@ -33,12 +29,8 @@ class StringUtil
|
|||
*
|
||||
* Currently only ISO-5991-1 input and UTF-8 input is supported, but this
|
||||
* may be expanded upon if we receive other examples.
|
||||
*
|
||||
* @param string $str
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function convertToUTF8($str)
|
||||
public static function convertToUTF8(string $str): string
|
||||
{
|
||||
if (!mb_check_encoding($str, 'UTF-8') && mb_check_encoding($str, 'ISO-8859-1')) {
|
||||
$str = mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1');
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
use DateTimeZone;
|
||||
use InvalidArgumentException;
|
||||
use Sabre\VObject\TimezoneGuesser\FindFromOffset;
|
||||
use Sabre\VObject\TimezoneGuesser\FindFromTimezoneIdentifier;
|
||||
use Sabre\VObject\TimezoneGuesser\FindFromTimezoneMap;
|
||||
|
|
@ -24,14 +22,13 @@ use Sabre\VObject\TimezoneGuesser\TimezoneGuesser;
|
|||
*/
|
||||
class TimeZoneUtil
|
||||
{
|
||||
/** @var self */
|
||||
private static $instance = null;
|
||||
private static ?TimeZoneUtil $instance = null;
|
||||
|
||||
/** @var TimezoneGuesser[] */
|
||||
private $timezoneGuessers = [];
|
||||
private array $timezoneGuessers = [];
|
||||
|
||||
/** @var TimezoneFinder[] */
|
||||
private $timezoneFinders = [];
|
||||
private array $timezoneFinders = [];
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
|
|
@ -75,11 +72,11 @@ class TimeZoneUtil
|
|||
* Alternatively, if $failIfUncertain is set to true, it will throw an
|
||||
* exception if we cannot accurately determine the timezone.
|
||||
*/
|
||||
private function findTimeZone(string $tzid, Component $vcalendar = null, bool $failIfUncertain = false): DateTimeZone
|
||||
private function findTimeZone(string $tzid, Component $vcalendar = null, bool $failIfUncertain = false): \DateTimeZone
|
||||
{
|
||||
foreach ($this->timezoneFinders as $timezoneFinder) {
|
||||
$timezone = $timezoneFinder->find($tzid, $failIfUncertain);
|
||||
if (!$timezone instanceof DateTimeZone) {
|
||||
if (!$timezone instanceof \DateTimeZone) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +89,7 @@ class TimeZoneUtil
|
|||
if ((string) $vtimezone->TZID === $tzid) {
|
||||
foreach ($this->timezoneGuessers as $timezoneGuesser) {
|
||||
$timezone = $timezoneGuesser->guess($vtimezone, $failIfUncertain);
|
||||
if (!$timezone instanceof DateTimeZone) {
|
||||
if (!$timezone instanceof \DateTimeZone) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -103,11 +100,11 @@ class TimeZoneUtil
|
|||
}
|
||||
|
||||
if ($failIfUncertain) {
|
||||
throw new InvalidArgumentException('We were unable to determine the correct PHP timezone for tzid: '.$tzid);
|
||||
throw new \InvalidArgumentException('We were unable to determine the correct PHP timezone for tzid: '.$tzid);
|
||||
}
|
||||
|
||||
// If we got all the way here, we default to whatever has been set as the PHP default timezone.
|
||||
return new DateTimeZone(date_default_timezone_get());
|
||||
return new \DateTimeZone(date_default_timezone_get());
|
||||
}
|
||||
|
||||
public static function addTimezoneGuesser(string $key, TimezoneGuesser $guesser): void
|
||||
|
|
@ -120,13 +117,7 @@ class TimeZoneUtil
|
|||
self::getInstance()->addFinder($key, $finder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tzid
|
||||
* @param false $failIfUncertain
|
||||
*
|
||||
* @return DateTimeZone
|
||||
*/
|
||||
public static function getTimeZone($tzid, Component $vcalendar = null, $failIfUncertain = false)
|
||||
public static function getTimeZone(string $tzid, Component $vcalendar = null, bool $failIfUncertain = false): \DateTimeZone
|
||||
{
|
||||
return self::getInstance()->findTimeZone($tzid, $vcalendar, $failIfUncertain);
|
||||
}
|
||||
|
|
@ -135,138 +126,4 @@ class TimeZoneUtil
|
|||
{
|
||||
self::$instance = null;
|
||||
}
|
||||
|
||||
// Keeping things for backwards compatibility
|
||||
/**
|
||||
* @var array|null
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public static $map = null;
|
||||
|
||||
/**
|
||||
* List of microsoft exchange timezone ids.
|
||||
*
|
||||
* Source: http://msdn.microsoft.com/en-us/library/aa563018(loband).aspx
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public static $microsoftExchangeMap = [
|
||||
0 => 'UTC',
|
||||
31 => 'Africa/Casablanca',
|
||||
// Insanely, id #2 is used for both Europe/Lisbon, and Europe/Sarajevo.
|
||||
// I'm not even kidding.. We handle this special case in the
|
||||
// getTimeZone method.
|
||||
2 => 'Europe/Lisbon',
|
||||
1 => 'Europe/London',
|
||||
4 => 'Europe/Berlin',
|
||||
6 => 'Europe/Prague',
|
||||
3 => 'Europe/Paris',
|
||||
69 => 'Africa/Luanda', // This was a best guess
|
||||
7 => 'Europe/Athens',
|
||||
5 => 'Europe/Bucharest',
|
||||
49 => 'Africa/Cairo',
|
||||
50 => 'Africa/Harare',
|
||||
59 => 'Europe/Helsinki',
|
||||
27 => 'Asia/Jerusalem',
|
||||
26 => 'Asia/Baghdad',
|
||||
74 => 'Asia/Kuwait',
|
||||
51 => 'Europe/Moscow',
|
||||
56 => 'Africa/Nairobi',
|
||||
25 => 'Asia/Tehran',
|
||||
24 => 'Asia/Muscat', // Best guess
|
||||
54 => 'Asia/Baku',
|
||||
48 => 'Asia/Kabul',
|
||||
58 => 'Asia/Yekaterinburg',
|
||||
47 => 'Asia/Karachi',
|
||||
23 => 'Asia/Calcutta',
|
||||
62 => 'Asia/Kathmandu',
|
||||
46 => 'Asia/Almaty',
|
||||
71 => 'Asia/Dhaka',
|
||||
66 => 'Asia/Colombo',
|
||||
61 => 'Asia/Rangoon',
|
||||
22 => 'Asia/Bangkok',
|
||||
64 => 'Asia/Krasnoyarsk',
|
||||
45 => 'Asia/Shanghai',
|
||||
63 => 'Asia/Irkutsk',
|
||||
21 => 'Asia/Singapore',
|
||||
73 => 'Australia/Perth',
|
||||
75 => 'Asia/Taipei',
|
||||
20 => 'Asia/Tokyo',
|
||||
72 => 'Asia/Seoul',
|
||||
70 => 'Asia/Yakutsk',
|
||||
19 => 'Australia/Adelaide',
|
||||
44 => 'Australia/Darwin',
|
||||
18 => 'Australia/Brisbane',
|
||||
76 => 'Australia/Sydney',
|
||||
43 => 'Pacific/Guam',
|
||||
42 => 'Australia/Hobart',
|
||||
68 => 'Asia/Vladivostok',
|
||||
41 => 'Asia/Magadan',
|
||||
17 => 'Pacific/Auckland',
|
||||
40 => 'Pacific/Fiji',
|
||||
67 => 'Pacific/Tongatapu',
|
||||
29 => 'Atlantic/Azores',
|
||||
53 => 'Atlantic/Cape_Verde',
|
||||
30 => 'America/Noronha',
|
||||
8 => 'America/Sao_Paulo', // Best guess
|
||||
32 => 'America/Argentina/Buenos_Aires',
|
||||
60 => 'America/Godthab',
|
||||
28 => 'America/St_Johns',
|
||||
9 => 'America/Halifax',
|
||||
33 => 'America/Caracas',
|
||||
65 => 'America/Santiago',
|
||||
35 => 'America/Bogota',
|
||||
10 => 'America/New_York',
|
||||
34 => 'America/Indiana/Indianapolis',
|
||||
55 => 'America/Guatemala',
|
||||
11 => 'America/Chicago',
|
||||
37 => 'America/Mexico_City',
|
||||
36 => 'America/Edmonton',
|
||||
38 => 'America/Phoenix',
|
||||
12 => 'America/Denver', // Best guess
|
||||
13 => 'America/Los_Angeles', // Best guess
|
||||
14 => 'America/Anchorage',
|
||||
15 => 'Pacific/Honolulu',
|
||||
16 => 'Pacific/Midway',
|
||||
39 => 'Pacific/Kwajalein',
|
||||
];
|
||||
|
||||
/**
|
||||
* This method will load in all the tz mapping information, if it's not yet
|
||||
* done.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public static function loadTzMaps()
|
||||
{
|
||||
if (!is_null(self::$map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$map = array_merge(
|
||||
include __DIR__.'/timezonedata/windowszones.php',
|
||||
include __DIR__.'/timezonedata/lotuszones.php',
|
||||
include __DIR__.'/timezonedata/exchangezones.php',
|
||||
include __DIR__.'/timezonedata/php-workaround.php'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns an array of timezone identifiers, that are supported
|
||||
* by DateTimeZone(), but not returned by DateTimeZone::listIdentifiers().
|
||||
*
|
||||
* We're not using DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC) because:
|
||||
* - It's not supported by some PHP versions as well as HHVM.
|
||||
* - It also returns identifiers, that are invalid values for new DateTimeZone() on some PHP versions.
|
||||
* (See timezonedata/php-bc.php and timezonedata php-workaround.php)
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public static function getIdentifiersBC()
|
||||
{
|
||||
return include __DIR__.'/timezonedata/php-bc.php';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace Sabre\VObject\TimezoneGuesser;
|
||||
|
||||
use DateTimeZone;
|
||||
|
||||
/**
|
||||
* Some clients add 'X-LIC-LOCATION' with the olson name.
|
||||
*/
|
||||
class FindFromOffset implements TimezoneFinder
|
||||
{
|
||||
public function find(string $tzid, bool $failIfUncertain = false): ?DateTimeZone
|
||||
public function find(string $tzid, ?bool $failIfUncertain = false): ?\DateTimeZone
|
||||
{
|
||||
// Maybe the author was hyper-lazy and just included an offset. We
|
||||
// support it, but we aren't happy about it.
|
||||
|
|
@ -22,7 +20,7 @@ class FindFromOffset implements TimezoneFinder
|
|||
// for versions under PHP 5.5.10, this bit can be taken out of the
|
||||
// source.
|
||||
// @codeCoverageIgnoreStart
|
||||
return new DateTimeZone('Etc/GMT'.$matches[1].ltrim(substr($matches[2], 0, 2), '0'));
|
||||
return new \DateTimeZone('Etc/GMT'.$matches[1].ltrim(substr($matches[2], 0, 2), '0'));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,13 @@ declare(strict_types=1);
|
|||
namespace Sabre\VObject\TimezoneGuesser;
|
||||
|
||||
use DateTimeZone;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Some clients add 'X-LIC-LOCATION' with the olson name.
|
||||
*/
|
||||
class FindFromTimezoneIdentifier implements TimezoneFinder
|
||||
{
|
||||
public function find(string $tzid, bool $failIfUncertain = false): ?DateTimeZone
|
||||
public function find(string $tzid, ?bool $failIfUncertain = false): ?\DateTimeZone
|
||||
{
|
||||
// First we will just see if the tzid is a support timezone identifier.
|
||||
//
|
||||
|
|
@ -35,19 +34,19 @@ class FindFromTimezoneIdentifier implements TimezoneFinder
|
|||
// https://bugs.php.net/bug.php?id=67881
|
||||
//
|
||||
// That's why we're checking if we'll be able to successfully instantiate
|
||||
// \DateTimeZone() before doing so. Otherwise we could simply instantiate
|
||||
// \DateTimeZone() before doing so. Otherwise, we could simply instantiate
|
||||
// and catch the exception.
|
||||
$tzIdentifiers = DateTimeZone::listIdentifiers();
|
||||
$tzIdentifiers = \DateTimeZone::listIdentifiers();
|
||||
|
||||
try {
|
||||
if (
|
||||
(in_array($tzid, $tzIdentifiers)) ||
|
||||
(preg_match('/^GMT(\+|-)([0-9]{4})$/', $tzid, $matches)) ||
|
||||
(in_array($tzid, $this->getIdentifiersBC()))
|
||||
in_array($tzid, $tzIdentifiers)
|
||||
|| preg_match('/^GMT(\+|-)([0-9]{4})$/', $tzid, $matches)
|
||||
|| in_array($tzid, $this->getIdentifiersBC())
|
||||
) {
|
||||
return new DateTimeZone($tzid);
|
||||
return new \DateTimeZone($tzid);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
@ -61,10 +60,8 @@ class FindFromTimezoneIdentifier implements TimezoneFinder
|
|||
* - It's not supported by some PHP versions as well as HHVM.
|
||||
* - It also returns identifiers, that are invalid values for new DateTimeZone() on some PHP versions.
|
||||
* (See timezonedata/php-bc.php and timezonedata php-workaround.php)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getIdentifiersBC()
|
||||
private function getIdentifiersBC(): array
|
||||
{
|
||||
return include __DIR__.'/../timezonedata/php-bc.php';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,18 +11,18 @@ use DateTimeZone;
|
|||
*/
|
||||
class FindFromTimezoneMap implements TimezoneFinder
|
||||
{
|
||||
private $map = [];
|
||||
private array $map = [];
|
||||
|
||||
private $patterns = [
|
||||
private array $patterns = [
|
||||
'/^\((UTC|GMT)(\+|\-)[\d]{2}\:[\d]{2}\) (.*)/',
|
||||
'/^\((UTC|GMT)(\+|\-)[\d]{2}\.[\d]{2}\) (.*)/',
|
||||
];
|
||||
|
||||
public function find(string $tzid, bool $failIfUncertain = false): ?DateTimeZone
|
||||
public function find(string $tzid, ?bool $failIfUncertain = false): ?\DateTimeZone
|
||||
{
|
||||
// Next, we check if the tzid is somewhere in our tzid map.
|
||||
if ($this->hasTzInMap($tzid)) {
|
||||
return new DateTimeZone($this->getTzFromMap($tzid));
|
||||
return new \DateTimeZone($this->getTzFromMap($tzid));
|
||||
}
|
||||
|
||||
// Some Microsoft products prefix the offset first, so let's strip that off
|
||||
|
|
@ -34,7 +34,7 @@ class FindFromTimezoneMap implements TimezoneFinder
|
|||
}
|
||||
$tzidAlternate = $matches[3];
|
||||
if ($this->hasTzInMap($tzidAlternate)) {
|
||||
return new DateTimeZone($this->getTzFromMap($tzidAlternate));
|
||||
return new \DateTimeZone($this->getTzFromMap($tzidAlternate));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -49,10 +49,8 @@ class FindFromTimezoneMap implements TimezoneFinder
|
|||
* - It's not supported by some PHP versions as well as HHVM.
|
||||
* - It also returns identifiers, that are invalid values for new DateTimeZone() on some PHP versions.
|
||||
* (See timezonedata/php-bc.php and timezonedata php-workaround.php)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTzMaps()
|
||||
private function getTzMaps(): array
|
||||
{
|
||||
if ([] === $this->map) {
|
||||
$this->map = array_merge(
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace Sabre\VObject\TimezoneGuesser;
|
||||
|
||||
use DateTimeZone;
|
||||
use Sabre\VObject\Component\VTimeZone;
|
||||
use Sabre\VObject\TimeZoneUtil;
|
||||
|
||||
|
|
@ -13,7 +12,7 @@ use Sabre\VObject\TimeZoneUtil;
|
|||
*/
|
||||
class GuessFromLicEntry implements TimezoneGuesser
|
||||
{
|
||||
public function guess(VTimeZone $vtimezone, bool $failIfUncertain = false): ?DateTimeZone
|
||||
public function guess(VTimeZone $vtimezone, ?bool $failIfUncertain = false): ?\DateTimeZone
|
||||
{
|
||||
if (!isset($vtimezone->{'X-LIC-LOCATION'})) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace Sabre\VObject\TimezoneGuesser;
|
||||
|
||||
use DateTimeZone;
|
||||
use Sabre\VObject\Component\VTimeZone;
|
||||
|
||||
class GuessFromMsTzId implements TimezoneGuesser
|
||||
|
|
@ -14,12 +13,12 @@ class GuessFromMsTzId implements TimezoneGuesser
|
|||
*
|
||||
* Source: http://msdn.microsoft.com/en-us/library/aa563018(loband).aspx
|
||||
*/
|
||||
public static $microsoftExchangeMap = [
|
||||
public static array $microsoftExchangeMap = [
|
||||
0 => 'UTC',
|
||||
31 => 'Africa/Casablanca',
|
||||
|
||||
// Insanely, id #2 is used for both Europe/Lisbon, and Europe/Sarajevo.
|
||||
// I'm not even kidding.. We handle this special case in the
|
||||
// I'm not even kidding. We handle this special case in the
|
||||
// getTimeZone method.
|
||||
2 => 'Europe/Lisbon',
|
||||
1 => 'Europe/London',
|
||||
|
|
@ -96,7 +95,7 @@ class GuessFromMsTzId implements TimezoneGuesser
|
|||
39 => 'Pacific/Kwajalein',
|
||||
];
|
||||
|
||||
public function guess(VTimeZone $vtimezone, bool $throwIfUnsure = false): ?DateTimeZone
|
||||
public function guess(VTimeZone $vtimezone, ?bool $failIfUncertain = false): ?\DateTimeZone
|
||||
{
|
||||
// Microsoft may add a magic number, which we also have an
|
||||
// answer for.
|
||||
|
|
@ -107,11 +106,11 @@ class GuessFromMsTzId implements TimezoneGuesser
|
|||
|
||||
// 2 can mean both Europe/Lisbon and Europe/Sarajevo.
|
||||
if (2 === $cdoId && false !== strpos((string) $vtimezone->TZID, 'Sarajevo')) {
|
||||
return new DateTimeZone('Europe/Sarajevo');
|
||||
return new \DateTimeZone('Europe/Sarajevo');
|
||||
}
|
||||
|
||||
if (isset(self::$microsoftExchangeMap[$cdoId])) {
|
||||
return new DateTimeZone(self::$microsoftExchangeMap[$cdoId]);
|
||||
return new \DateTimeZone(self::$microsoftExchangeMap[$cdoId]);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
namespace Sabre\VObject\TimezoneGuesser;
|
||||
|
||||
use DateTimeZone;
|
||||
|
||||
interface TimezoneFinder
|
||||
{
|
||||
public function find(string $tzid, bool $failIfUncertain = false): ?DateTimeZone;
|
||||
public function find(string $tzid, ?bool $failIfUncertain = false): ?\DateTimeZone;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
namespace Sabre\VObject\TimezoneGuesser;
|
||||
|
||||
use DateTimeZone;
|
||||
use Sabre\VObject\Component\VTimeZone;
|
||||
|
||||
interface TimezoneGuesser
|
||||
{
|
||||
public function guess(VTimeZone $vtimezone, bool $failIfUncertain = false): ?DateTimeZone;
|
||||
public function guess(VTimeZone $vtimezone, ?bool $failIfUncertain = false): ?\DateTimeZone;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,42 +21,36 @@ class UUIDUtil
|
|||
* This function is based on a comment by Andrew Moore on php.net
|
||||
*
|
||||
* @see http://www.php.net/manual/en/function.uniqid.php#94959
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getUUID()
|
||||
public static function getUUID(): string
|
||||
{
|
||||
return sprintf(
|
||||
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
|
||||
// 32 bits for "time_low"
|
||||
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xFFFF), mt_rand(0, 0xFFFF),
|
||||
|
||||
// 16 bits for "time_mid"
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xFFFF),
|
||||
|
||||
// 16 bits for "time_hi_and_version",
|
||||
// four most significant bits holds version number 4
|
||||
mt_rand(0, 0x0fff) | 0x4000,
|
||||
mt_rand(0, 0x0FFF) | 0x4000,
|
||||
|
||||
// 16 bits, 8 bits for "clk_seq_hi_res",
|
||||
// 8 bits for "clk_seq_low",
|
||||
// two most significant bits holds zero and one for variant DCE1.1
|
||||
mt_rand(0, 0x3fff) | 0x8000,
|
||||
mt_rand(0, 0x3FFF) | 0x8000,
|
||||
|
||||
// 48 bits for "node"
|
||||
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
|
||||
mt_rand(0, 0xFFFF), mt_rand(0, 0xFFFF), mt_rand(0, 0xFFFF)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a string is a valid UUID.
|
||||
*
|
||||
* @param string $uuid
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function validateUUID($uuid)
|
||||
public static function validateUUID(string $uuid): bool
|
||||
{
|
||||
return 0 !== preg_match(
|
||||
'/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i',
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
use Sabre\VObject\Property\Binary;
|
||||
use Sabre\VObject\Property\Uri;
|
||||
|
||||
/**
|
||||
* This utility converts vcards from one version to another.
|
||||
*
|
||||
|
|
@ -26,9 +29,9 @@ class VCardConverter
|
|||
*
|
||||
* If input and output version are identical, a clone is returned.
|
||||
*
|
||||
* @param int $targetVersion
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
public function convert(Component\VCard $input, $targetVersion)
|
||||
public function convert(Component\VCard $input, int $targetVersion): Component\VCard
|
||||
{
|
||||
$inputVersion = $input->getDocumentType();
|
||||
if ($inputVersion === $targetVersion) {
|
||||
|
|
@ -61,9 +64,9 @@ class VCardConverter
|
|||
/**
|
||||
* Handles conversion of a single property.
|
||||
*
|
||||
* @param int $targetVersion
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
protected function convertProperty(Component\VCard $input, Component\VCard $output, Property $property, $targetVersion)
|
||||
protected function convertProperty(Component\VCard $input, Component\VCard $output, Property $property, int $targetVersion): void
|
||||
{
|
||||
// Skipping these, those are automatically added.
|
||||
if (in_array($property->name, ['VERSION', 'PRODID'])) {
|
||||
|
|
@ -91,14 +94,15 @@ class VCardConverter
|
|||
|
||||
if (Document::VCARD30 === $targetVersion) {
|
||||
if ($property instanceof Property\Uri && in_array($property->name, ['PHOTO', 'LOGO', 'SOUND'])) {
|
||||
/** @var Property\Uri $newProperty */
|
||||
$newProperty = $this->convertUriToBinary($output, $newProperty);
|
||||
} elseif ($property instanceof Property\VCard\DateAndOrTime) {
|
||||
// In vCard 4, the birth year may be optional. This is not the
|
||||
// case for vCard 3. Apple has a workaround for this that
|
||||
// allows applications that support Apple's extension still
|
||||
// omit birthyears in vCard 3, but applications that do not
|
||||
// support this, will just use a random birthyear. We're
|
||||
// choosing 1604 for the birthyear, because that's what apple
|
||||
// omit birth years in vCard 3, but applications that do not
|
||||
// support this, will just use a random birth year. We're
|
||||
// choosing 1604 for the birth year, because that's what apple
|
||||
// uses.
|
||||
$parts = DateTimeParser::parseVCardDateTime($property->getValue());
|
||||
if (is_null($parts['year'])) {
|
||||
|
|
@ -150,6 +154,7 @@ class VCardConverter
|
|||
}
|
||||
|
||||
if ($property instanceof Property\Binary) {
|
||||
/** @var Property\Binary $newProperty */
|
||||
$newProperty = $this->convertBinaryToUri($output, $newProperty, $parameters);
|
||||
} elseif ($property instanceof Property\VCard\DateAndOrTime && isset($parameters['X-APPLE-OMIT-YEAR'])) {
|
||||
// If a property such as BDAY contained 'X-APPLE-OMIT-YEAR',
|
||||
|
|
@ -209,7 +214,7 @@ class VCardConverter
|
|||
}
|
||||
$newProperty->name = 'ANNIVERSARY';
|
||||
break;
|
||||
// Apple's per-property label system.
|
||||
// Apple's per-property label system.
|
||||
case 'X-ABLABEL':
|
||||
if ('_$!<Anniversary>!$_' === $newProperty->getValue()) {
|
||||
// We can safely remove these, as they are converted to
|
||||
|
|
@ -231,7 +236,7 @@ class VCardConverter
|
|||
|
||||
// Lastly, we need to see if there's a need for a VALUE parameter.
|
||||
//
|
||||
// We can do that by instantiating a empty property with that name, and
|
||||
// We can do that by instantiating an empty property with that name, and
|
||||
// seeing if the default valueType is identical to the current one.
|
||||
$tempProperty = $output->createProperty($newProperty->name);
|
||||
if ($tempProperty->getValueType() !== $newProperty->getValueType()) {
|
||||
|
|
@ -246,15 +251,15 @@ class VCardConverter
|
|||
*
|
||||
* vCard 4.0 no longer supports BINARY properties.
|
||||
*
|
||||
* @param Property\Uri $property the input property
|
||||
* @param $parameters list of parameters that will eventually be added to
|
||||
* the new property
|
||||
* @param array $parameters list of parameters that will eventually be added to
|
||||
* the new property
|
||||
*
|
||||
* @return Property\Uri
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
protected function convertBinaryToUri(Component\VCard $output, Property\Binary $newProperty, array &$parameters)
|
||||
protected function convertBinaryToUri(Component\VCard $output, Property\Binary $newProperty, array &$parameters): Uri
|
||||
{
|
||||
$value = $newProperty->getValue();
|
||||
/** @var Uri $newProperty */
|
||||
$newProperty = $output->createProperty(
|
||||
$newProperty->name,
|
||||
null, // no value
|
||||
|
|
@ -299,11 +304,11 @@ class VCardConverter
|
|||
* be valid in vCard 3.0 as well, we should convert those to BINARY if
|
||||
* possible, to improve compatibility.
|
||||
*
|
||||
* @param Property\Uri $property the input property
|
||||
* @return Property\Binary|Property\Uri|null
|
||||
*
|
||||
* @return Property\Binary|null
|
||||
* @throws InvalidDataException
|
||||
*/
|
||||
protected function convertUriToBinary(Component\VCard $output, Property\Uri $newProperty)
|
||||
protected function convertUriToBinary(Component\VCard $output, Property\Uri $newProperty): Property
|
||||
{
|
||||
$value = $newProperty->getValue();
|
||||
|
||||
|
|
@ -312,6 +317,7 @@ class VCardConverter
|
|||
return $newProperty;
|
||||
}
|
||||
|
||||
/** @var Binary $newProperty */
|
||||
$newProperty = $output->createProperty(
|
||||
$newProperty->name,
|
||||
null, // no value
|
||||
|
|
@ -347,7 +353,7 @@ class VCardConverter
|
|||
/**
|
||||
* Adds parameters to a new property for vCard 4.0.
|
||||
*/
|
||||
protected function convertParameters40(Property $newProperty, array $parameters)
|
||||
protected function convertParameters40(Property $newProperty, array $parameters): void
|
||||
{
|
||||
// Adding all parameters.
|
||||
foreach ($parameters as $param) {
|
||||
|
|
@ -368,7 +374,7 @@ class VCardConverter
|
|||
}
|
||||
}
|
||||
break;
|
||||
// These no longer exist in vCard 4
|
||||
// These no longer exist in vCard 4
|
||||
case 'ENCODING':
|
||||
case 'CHARSET':
|
||||
break;
|
||||
|
|
@ -383,7 +389,7 @@ class VCardConverter
|
|||
/**
|
||||
* Adds parameters to a new property for vCard 3.0.
|
||||
*/
|
||||
protected function convertParameters30(Property $newProperty, array $parameters)
|
||||
protected function convertParameters30(Property $newProperty, array $parameters): void
|
||||
{
|
||||
// Adding all parameters.
|
||||
foreach ($parameters as $param) {
|
||||
|
|
@ -401,11 +407,11 @@ class VCardConverter
|
|||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* Converting PREF=1 to TYPE=PREF.
|
||||
*
|
||||
* Any other PREF numbers we'll drop.
|
||||
*/
|
||||
/*
|
||||
* Converting PREF=1 to TYPE=PREF.
|
||||
*
|
||||
* Any other PREF numbers we'll drop.
|
||||
*/
|
||||
case 'PREF':
|
||||
if ('1' == $param->getValue()) {
|
||||
$newProperty->add('TYPE', 'PREF');
|
||||
|
|
|
|||
|
|
@ -14,5 +14,5 @@ class Version
|
|||
/**
|
||||
* Full version number.
|
||||
*/
|
||||
const VERSION = '4.5.0';
|
||||
public const VERSION = '4.5.2';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,32 +18,24 @@ class Writer
|
|||
{
|
||||
/**
|
||||
* Serializes a vCard or iCalendar object.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function write(Component $component)
|
||||
public static function write(Component $component): string
|
||||
{
|
||||
return $component->serialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes a jCal or jCard object.
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function writeJson(Component $component, $options = 0)
|
||||
public static function writeJson(Component $component, int $options = 0): string
|
||||
{
|
||||
return json_encode($component, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes a xCal or xCard object.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function writeXml(Component $component)
|
||||
public static function writeXml(Component $component): string
|
||||
{
|
||||
$writer = new Xml\Writer();
|
||||
$writer->openMemory();
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ return [
|
|||
// 'Mid-Atlantic' => 'Etc/GMT-2', // conflict with windows timezones.
|
||||
'Azores' => 'Atlantic/Azores',
|
||||
'Cape Verde' => 'Atlantic/Cape_Verde',
|
||||
'Greenwich' => 'Atlantic/Reykjavik', // No I'm serious.. Greenwich is not GMT.
|
||||
'Greenwich' => 'Atlantic/Reykjavik', // No I'm serious. Greenwich is not GMT.
|
||||
'Morocco' => 'Africa/Casablanca',
|
||||
'Central Europe' => 'Europe/Prague',
|
||||
'Central European' => 'Europe/Sarajevo',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue