diff --git a/composer.json b/composer.json index d4fa56a31..1e19e8474 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,8 @@ "require-dev" : { "friendsofphp/php-cs-fixer": "~2.16.1", "phpunit/phpunit" : "^7.5 || ^8.5 || ^9.0", - "phpstan/phpstan": "^0.12" + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12.6" }, "suggest" : { "hoa/bench" : "If you would like to run the benchmark scripts" diff --git a/lib/BirthdayCalendarGenerator.php b/lib/BirthdayCalendarGenerator.php index fade50e16..629263c69 100644 --- a/lib/BirthdayCalendarGenerator.php +++ b/lib/BirthdayCalendarGenerator.php @@ -16,7 +16,7 @@ class BirthdayCalendarGenerator /** * Input objects. * - * @var array + * @var Component\VCard[] */ protected $objects = []; @@ -39,7 +39,7 @@ class BirthdayCalendarGenerator * Check the setTimeRange and setObjects methods for details about the * arguments. * - * @param mixed $objects + * @param string[]|string|Component\VCard[]|Component\VCard|null $objects */ public function __construct($objects = null) { @@ -54,7 +54,7 @@ public function __construct($objects = null) * 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 + * @param string[]|string|Component\VCard[]|Component\VCard $objects */ public function setObjects($objects) { diff --git a/lib/Cli.php b/lib/Cli.php index f3e419b15..eea32806f 100644 --- a/lib/Cli.php +++ b/lib/Cli.php @@ -2,8 +2,7 @@ namespace Sabre\VObject; -use - InvalidArgumentException; +use InvalidArgumentException; /** * This is the CLI interface for sabre-vobject. @@ -314,17 +313,14 @@ protected function showHelp() * * @return int */ - protected function validate(Component $vObj) + protected function validate(Document $vObj) { $returnCode = 0; - switch ($vObj->name) { - case 'VCALENDAR': - $this->log('iCalendar: '.(string) $vObj->VERSION); - break; - case 'VCARD': - $this->log('vCard: '.(string) $vObj->VERSION); - break; + if ($vObj instanceof Component\VCalendar) { + $this->log('iCalendar: '.(string) $vObj->VERSION); + } elseif ($vObj instanceof Component\VCard) { + $this->log('vCard: '.(string) $vObj->VERSION); } $warnings = $vObj->validate(); @@ -354,17 +350,14 @@ protected function validate(Component $vObj) * * @return int */ - protected function repair(Component $vObj) + protected function repair(Document $vObj) { $returnCode = 0; - switch ($vObj->name) { - case 'VCALENDAR': - $this->log('iCalendar: '.(string) $vObj->VERSION); - break; - case 'VCARD': - $this->log('vCard: '.(string) $vObj->VERSION); - break; + if ($vObj instanceof Component\VCalendar) { + $this->log('iCalendar: '.(string) $vObj->VERSION); + } elseif ($vObj instanceof Component\VCard) { + $this->log('vCard: '.(string) $vObj->VERSION); } $warnings = $vObj->validate(Node::REPAIR); @@ -393,11 +386,11 @@ protected function repair(Component $vObj) /** * Converts a vObject file to a new format. * - * @param Component $vObj + * @param Component\VCard|Component\VCalendar $vObj * * @return int */ - protected function convert($vObj) + protected function convert(Document $vObj) { $json = false; $convertVersion = null; @@ -458,8 +451,6 @@ protected function convert($vObj) * Colorizes a file. * * @param Component $vObj - * - * @return int */ protected function color($vObj) { diff --git a/lib/Component.php b/lib/Component.php index 58594aec1..c18812501 100644 --- a/lib/Component.php +++ b/lib/Component.php @@ -16,15 +16,6 @@ */ class Component extends Node { - /** - * Component name. - * - * This will contain a string such as VEVENT, VTODO, VCALENDAR, VCARD. - * - * @var string - */ - public $name; - /** * A list of properties and/or sub-components. * @@ -169,7 +160,7 @@ public function remove($item) * Returns a flat list of all the properties and components in this * component. * - * @return array + * @return (Property|Component\VAlarm|Component\VAvailability|Component\VEvent|Component\VFreeBusy|Component\VJournal|Component\VTimeZone|Component\VTodo)[] */ public function children() { @@ -214,7 +205,7 @@ public function getComponents() * * @param string $name * - * @return array + * @return Node[] */ public function select($name) { @@ -431,7 +422,7 @@ protected function getDefaults() * * @param string $name * - * @return Property + * @return Property|Component|null */ public function __get($name) { @@ -441,10 +432,9 @@ public function __get($name) $matches = $this->select($name); if (0 === count($matches)) { - return; + return null; } else { $firstMatch = current($matches); - /* @var $firstMatch Property */ $firstMatch->setIterator(new ElementList(array_values($matches))); return $firstMatch; diff --git a/lib/Component/VAlarm.php b/lib/Component/VAlarm.php index bd00eb600..2e49d99ee 100644 --- a/lib/Component/VAlarm.php +++ b/lib/Component/VAlarm.php @@ -34,7 +34,7 @@ public function getEffectiveTriggerTime() $parentComponent = $this->parent; if ('START' === $related) { - if ('VTODO' === $parentComponent->name) { + if ($parentComponent instanceof VTodo) { $propName = 'DUE'; } else { $propName = 'DTSTART'; @@ -43,9 +43,9 @@ public function getEffectiveTriggerTime() $effectiveTrigger = $parentComponent->$propName->getDateTime(); $effectiveTrigger = $effectiveTrigger->add($triggerDuration); } else { - if ('VTODO' === $parentComponent->name) { + if ($parentComponent instanceof VTodo) { $endProp = 'DUE'; - } elseif ('VEVENT' === $parentComponent->name) { + } elseif ($parentComponent instanceof VEvent) { $endProp = 'DTEND'; } else { throw new InvalidDataException('time-range filters on VALARM components are only supported when they are a child of VTODO or VEVENT'); @@ -78,8 +78,8 @@ public function getEffectiveTriggerTime() * 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 + * @param \DateTime $start + * @param \DateTime $end * * @return bool */ diff --git a/lib/Component/VCalendar.php b/lib/Component/VCalendar.php index 40e09a1c0..94b9be1f0 100644 --- a/lib/Component/VCalendar.php +++ b/lib/Component/VCalendar.php @@ -315,7 +315,7 @@ public function expand(DateTimeInterface $start, DateTimeInterface $end, DateTim } elseif ($child instanceof Component && 'VTIMEZONE' !== $child->name) { // We're also stripping all VTIMEZONE objects because we're // converting everything to UTC. - if ('VEVENT' === $child->name && (isset($child->{'RECURRENCE-ID'}) || isset($child->RRULE) || isset($child->RDATE))) { + if ($child instanceof VEvent && (isset($child->{'RECURRENCE-ID'}) || isset($child->RRULE) || isset($child->RDATE))) { // Handle these a bit later. $uid = (string) $child->UID; if (!$uid) { @@ -326,7 +326,7 @@ public function expand(DateTimeInterface $start, DateTimeInterface $end, DateTim } else { $recurringEvents[$uid] = [clone $child]; } - } elseif ('VEVENT' === $child->name && $child->isInTimeRange($start, $end)) { + } elseif ($child instanceof VEvent && $child->isInTimeRange($start, $end)) { $newChildren[] = $stripTimezones(clone $child); } } @@ -440,7 +440,7 @@ public function validate($options = 0) if ($child instanceof Component) { ++$componentsFound; - if (!in_array($child->name, ['VEVENT', 'VTODO', 'VJOURNAL'])) { + if (!($child instanceof VEvent || $child instanceof VTodo || $child instanceof VJournal)) { continue; } $componentTypes[] = $child->name; diff --git a/lib/Component/VCard.php b/lib/Component/VCard.php index 51321949f..9c2459307 100644 --- a/lib/Component/VCard.php +++ b/lib/Component/VCard.php @@ -380,7 +380,7 @@ public function getValidationRules() * 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 + * @param string $propertyName * * @return VObject\Property|null */ @@ -423,6 +423,8 @@ public function getByType($propertyName, $type) return $field; } } + + return null; } /** diff --git a/lib/Document.php b/lib/Document.php index 14a77c911..569d3e95f 100644 --- a/lib/Document.php +++ b/lib/Document.php @@ -15,6 +15,9 @@ * @copyright Copyright (C) fruux GmbH (https://fruux.com/) * @author Evert Pot (http://evertpot.com/) * @license http://sabre.io/license/ Modified BSD License + * + * @method Component create(string $name, array $children = null, $defaults = true) + * @method Property create($name, $value = null, array $parameters = null, $valueType = null) */ abstract class Document extends Component { @@ -124,9 +127,8 @@ public function getDocumentType() * otherwise, we'll assume it's a property and call createProperty instead. * * @param string $name - * @param string $arg1,... Unlimited number of args * - * @return mixed + * @return Node */ public function create($name) { @@ -244,6 +246,8 @@ public function getClassNameForPropertyValue($valueParam) if (isset(static::$valueMap[$valueParam])) { return static::$valueMap[$valueParam]; } + + return null; } /** diff --git a/lib/FreeBusyGenerator.php b/lib/FreeBusyGenerator.php index a1c24044c..0bee6dbe0 100644 --- a/lib/FreeBusyGenerator.php +++ b/lib/FreeBusyGenerator.php @@ -49,7 +49,7 @@ class FreeBusyGenerator /** * VCALENDAR object. * - * @var Document + * @var VCalendar */ protected $baseObject; @@ -84,10 +84,10 @@ class FreeBusyGenerator * Check the setTimeRange and setObjects methods for details about the * arguments. * - * @param DateTimeInterface $start - * @param DateTimeInterface $end - * @param mixed $objects - * @param DateTimeZone $timeZone + * @param DateTimeInterface $start + * @param DateTimeInterface $end + * @param string[]|string|resource[]|resource|Component[]|Component|null $objects + * @param DateTimeZone $timeZone */ public function __construct(DateTimeInterface $start = null, DateTimeInterface $end = null, $objects = null, DateTimeZone $timeZone = null) { @@ -130,7 +130,7 @@ public function setVAvailability(Document $vcalendar) * Component. * It's also possible to specify multiple objects as an array. * - * @param mixed $objects + * @param string[]|string|resource[]|resource|Component[]|Component $objects */ public function setObjects($objects) { @@ -182,7 +182,7 @@ public function setTimeZone(DateTimeZone $timeZone) * Parses the input data and returns a correct VFREEBUSY object, wrapped in * a VCALENDAR. * - * @return Component + * @return VCalendar */ public function getResult() { @@ -360,129 +360,124 @@ protected function calculateBusy(FreeBusyData $fbData, array $objects) { foreach ($objects as $key => $object) { foreach ($object->getBaseComponents() as $component) { - switch ($component->name) { - case 'VEVENT': - - $FBTYPE = 'BUSY'; - if (isset($component->TRANSP) && ('TRANSPARENT' === strtoupper($component->TRANSP))) { + if ($component instanceof Component\VEvent) { + $FBTYPE = 'BUSY'; + if (isset($component->TRANSP) && ('TRANSPARENT' === strtoupper($component->TRANSP))) { + break; + } + if (isset($component->STATUS)) { + $status = strtoupper($component->STATUS); + if ('CANCELLED' === $status) { break; } - if (isset($component->STATUS)) { - $status = strtoupper($component->STATUS); - if ('CANCELLED' === $status) { - break; - } - if ('TENTATIVE' === $status) { - $FBTYPE = 'BUSY-TENTATIVE'; - } + if ('TENTATIVE' === $status) { + $FBTYPE = 'BUSY-TENTATIVE'; } + } - $times = []; + $times = []; - if ($component->RRULE) { - try { - $iterator = new EventIterator($object, (string) $component->UID, $this->timeZone); - } catch (NoInstancesException $e) { - // This event is recurring, but it doesn't have a single - // instance. We are skipping this event from the output - // entirely. - unset($this->objects[$key]); - break; - } - - if ($this->start) { - $iterator->fastForward($this->start); - } + if ($component->RRULE) { + try { + $iterator = new EventIterator($object, (string) $component->UID, $this->timeZone); + } catch (NoInstancesException $e) { + // This event is recurring, but it doesn't have a single + // instance. We are skipping this event from the output + // entirely. + unset($this->objects[$key]); + break; + } - $maxRecurrences = Settings::$maxRecurrences; + if ($this->start) { + $iterator->fastForward($this->start); + } - while ($iterator->valid() && --$maxRecurrences) { - $startTime = $iterator->getDTStart(); - if ($this->end && $startTime > $this->end) { - break; - } - $times[] = [ - $iterator->getDTStart(), - $iterator->getDTEnd(), - ]; + $maxRecurrences = Settings::$maxRecurrences; - $iterator->next(); - } - } else { - $startTime = $component->DTSTART->getDateTime($this->timeZone); + while ($iterator->valid() && --$maxRecurrences) { + $startTime = $iterator->getDTStart(); if ($this->end && $startTime > $this->end) { break; } - $endTime = null; - if (isset($component->DTEND)) { - $endTime = $component->DTEND->getDateTime($this->timeZone); - } elseif (isset($component->DURATION)) { - $duration = DateTimeParser::parseDuration((string) $component->DURATION); - $endTime = clone $startTime; - $endTime = $endTime->add($duration); - } elseif (!$component->DTSTART->hasTime()) { - $endTime = clone $startTime; - $endTime = $endTime->modify('+1 day'); - } else { - // The event had no duration (0 seconds) - break; - } + $times[] = [ + $iterator->getDTStart(), + $iterator->getDTEnd(), + ]; + + $iterator->next(); + } + } else { + $startTime = $component->DTSTART->getDateTime($this->timeZone); + if ($this->end && $startTime > $this->end) { + break; + } + $endTime = null; + if (isset($component->DTEND)) { + $endTime = $component->DTEND->getDateTime($this->timeZone); + } elseif (isset($component->DURATION)) { + $duration = DateTimeParser::parseDuration((string) $component->DURATION); + $endTime = clone $startTime; + $endTime = $endTime->add($duration); + } elseif (!$component->DTSTART->hasTime()) { + $endTime = clone $startTime; + $endTime = $endTime->modify('+1 day'); + } else { + // The event had no duration (0 seconds) + break; + } - $times[] = [$startTime, $endTime]; + $times[] = [$startTime, $endTime]; + } + + foreach ($times as $time) { + if ($this->end && $time[0] > $this->end) { + break; + } + if ($this->start && $time[1] < $this->start) { + break; } - foreach ($times as $time) { - if ($this->end && $time[0] > $this->end) { - break; - } - if ($this->start && $time[1] < $this->start) { - break; - } + $fbData->add( + $time[0]->getTimeStamp(), + $time[1]->getTimeStamp(), + $FBTYPE + ); + } + } elseif ($component instanceof Component\VFreeBusy) { + foreach ($component->FREEBUSY as $freebusy) { + $fbType = isset($freebusy['FBTYPE']) ? strtoupper($freebusy['FBTYPE']) : 'BUSY'; - $fbData->add( - $time[0]->getTimeStamp(), - $time[1]->getTimeStamp(), - $FBTYPE - ); + // Skipping intervals marked as 'free' + if ('FREE' === $fbType) { + continue; } - break; - case 'VFREEBUSY': - foreach ($component->FREEBUSY as $freebusy) { - $fbType = isset($freebusy['FBTYPE']) ? strtoupper($freebusy['FBTYPE']) : 'BUSY'; + $values = explode(',', $freebusy); + foreach ($values as $value) { + list($startTime, $endTime) = explode('/', $value); + $startTime = DateTimeParser::parseDateTime($startTime); - // Skipping intervals marked as 'free' - if ('FREE' === $fbType) { - continue; + if ('P' === substr($endTime, 0, 1) || '-P' === substr($endTime, 0, 2)) { + $duration = DateTimeParser::parseDuration($endTime); + $endTime = clone $startTime; + $endTime = $endTime->add($duration); + } else { + $endTime = DateTimeParser::parseDateTime($endTime); } - $values = explode(',', $freebusy); - foreach ($values as $value) { - list($startTime, $endTime) = explode('/', $value); - $startTime = DateTimeParser::parseDateTime($startTime); - - if ('P' === substr($endTime, 0, 1) || '-P' === substr($endTime, 0, 2)) { - $duration = DateTimeParser::parseDuration($endTime); - $endTime = clone $startTime; - $endTime = $endTime->add($duration); - } else { - $endTime = DateTimeParser::parseDateTime($endTime); - } - - if ($this->start && $this->start > $endTime) { - continue; - } - if ($this->end && $this->end < $startTime) { - continue; - } - $fbData->add( - $startTime->getTimeStamp(), - $endTime->getTimeStamp(), - $fbType - ); + if ($this->start && $this->start > $endTime) { + continue; + } + if ($this->end && $this->end < $startTime) { + continue; } + $fbData->add( + $startTime->getTimeStamp(), + $endTime->getTimeStamp(), + $fbType + ); } - break; + } } } } diff --git a/lib/ITip/Broker.php b/lib/ITip/Broker.php index c09cdf3be..fb01f1147 100644 --- a/lib/ITip/Broker.php +++ b/lib/ITip/Broker.php @@ -816,7 +816,7 @@ protected function parseEventInfo(VCalendar $calendar = null) $instances = []; $exdate = []; - foreach ($calendar->VEVENT as $vevent) { + foreach ($calendar->select('VEVENT') as $vevent) { $rrule = []; if (is_null($uid)) { diff --git a/lib/Node.php b/lib/Node.php index 4c0c04f72..2e449cf6d 100644 --- a/lib/Node.php +++ b/lib/Node.php @@ -56,10 +56,19 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable, \Js /** * The root document. * - * @var Component + * @var Document */ protected $root; + /** + * Node name. + * + * This will contain a string such as DTSTART, SUMMARY, FN, VEVENT, VTODO, VCALENDAR, VCARD + * + * @var string + */ + public $name; + /** * Serializes the node into a mimedir format. * diff --git a/lib/PHPStan/Component/AddDynamicMethodReturnTypeExtension.php b/lib/PHPStan/Component/AddDynamicMethodReturnTypeExtension.php new file mode 100644 index 000000000..5bd3c0c71 --- /dev/null +++ b/lib/PHPStan/Component/AddDynamicMethodReturnTypeExtension.php @@ -0,0 +1,58 @@ +getName(); + } + + public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type + { + if ($methodCall->args[0]->value instanceof \PhpParser\Node\Scalar\String_) { + if (array_key_exists($methodCall->args[0]->value->value, VCalendar::$componentMap)) { + return new ObjectType(VCalendar::$componentMap[$methodCall->args[0]->value->value]); + } + + if (array_key_exists($methodCall->args[0]->value->value, VCalendar::$propertyMap)) { + return new ObjectType(VCalendar::$propertyMap[$methodCall->args[0]->value->value]); + } + + if (array_key_exists($methodCall->args[0]->value->value, VCard::$componentMap)) { + return new ObjectType(VCard::$componentMap[$methodCall->args[0]->value->value]); + } + + if (array_key_exists($methodCall->args[0]->value->value, VCard::$propertyMap)) { + return new ObjectType(VCard::$propertyMap[$methodCall->args[0]->value->value]); + } + } + + if (2 === count($methodCall->args)) { + return new ObjectType(Component::class); + } + + if (3 === count($methodCall->args)) { + return new ObjectType(Property::class); + } + + return $scope->getType($methodCall->args[0]->value); + } +} diff --git a/lib/PHPStan/Component/SelectDynamicMethodReturnTypeExtension.php b/lib/PHPStan/Component/SelectDynamicMethodReturnTypeExtension.php new file mode 100644 index 000000000..fec4a922a --- /dev/null +++ b/lib/PHPStan/Component/SelectDynamicMethodReturnTypeExtension.php @@ -0,0 +1,75 @@ +getName(); + } + + public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type + { + if ($methodCall->args[0]->value instanceof \PhpParser\Node\Scalar\String_) { + if (array_key_exists($methodCall->args[0]->value->value, VCalendar::$propertyMap)) { + return $this->createArrayType( + VCalendar::$propertyMap[$methodCall->args[0]->value->value] + ); + } + + if (array_key_exists($methodCall->args[0]->value->value, VCalendar::$componentMap)) { + return $this->createArrayType( + VCalendar::$componentMap[$methodCall->args[0]->value->value] + ); + } + + if (array_key_exists($methodCall->args[0]->value->value, VCard::$propertyMap)) { + return $this->createArrayType( + VCard::$propertyMap[$methodCall->args[0]->value->value] + ); + } + + if (array_key_exists($methodCall->args[0]->value->value, VCard::$componentMap)) { + return $this->createArrayType( + VCard::$componentMap[$methodCall->args[0]->value->value] + ); + } + } + + return new ArrayType( + new IntegerType(), + new UnionType([ + new ObjectType(Component::class), + new ObjectType(Property::class), + ]) + ); + } + + private function createArrayType(string $class): ArrayType + { + return new ArrayType( + new IntegerType(), + new ObjectType($class) + ); + } +} diff --git a/lib/PHPStan/Component/VCalendar/CreateComponentDynamicMethodReturnTypeExtension.php b/lib/PHPStan/Component/VCalendar/CreateComponentDynamicMethodReturnTypeExtension.php new file mode 100644 index 000000000..4ba191ea4 --- /dev/null +++ b/lib/PHPStan/Component/VCalendar/CreateComponentDynamicMethodReturnTypeExtension.php @@ -0,0 +1,36 @@ +getName(); + } + + public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type + { + if ($methodCall->args[0]->value instanceof \PhpParser\Node\Scalar\String_) { + if (array_key_exists($methodCall->args[0]->value->value, VCalendar::$componentMap)) { + return new ObjectType(VCalendar::$componentMap[$methodCall->args[0]->value->value]); + } + } + + return new ObjectType(Component::class); + } +} diff --git a/lib/PHPStan/Component/VCalendar/CreatePropertyDynamicMethodReturnTypeExtension.php b/lib/PHPStan/Component/VCalendar/CreatePropertyDynamicMethodReturnTypeExtension.php new file mode 100644 index 000000000..dea194bf9 --- /dev/null +++ b/lib/PHPStan/Component/VCalendar/CreatePropertyDynamicMethodReturnTypeExtension.php @@ -0,0 +1,36 @@ +getName(); + } + + public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type + { + if ($methodCall->args[0]->value instanceof \PhpParser\Node\Scalar\String_) { + if (array_key_exists($methodCall->args[0]->value->value, VCalendar::$propertyMap)) { + return new ObjectType(VCalendar::$propertyMap[$methodCall->args[0]->value->value]); + } + } + + return new ObjectType(Property::class); + } +} diff --git a/lib/PHPStan/Component/VCard/CreateComponentDynamicMethodReturnTypeExtension.php b/lib/PHPStan/Component/VCard/CreateComponentDynamicMethodReturnTypeExtension.php new file mode 100644 index 000000000..959260f23 --- /dev/null +++ b/lib/PHPStan/Component/VCard/CreateComponentDynamicMethodReturnTypeExtension.php @@ -0,0 +1,36 @@ +getName(); + } + + public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type + { + if ($methodCall->args[0]->value instanceof \PhpParser\Node\Scalar\String_) { + if (array_key_exists($methodCall->args[0]->value->value, VCard::$componentMap)) { + return new ObjectType(VCard::$componentMap[$methodCall->args[0]->value->value]); + } + } + + return new ObjectType(Component::class); + } +} diff --git a/lib/PHPStan/Component/VCard/CreatePropertyDynamicMethodReturnTypeExtension.php b/lib/PHPStan/Component/VCard/CreatePropertyDynamicMethodReturnTypeExtension.php new file mode 100644 index 000000000..9f804c25a --- /dev/null +++ b/lib/PHPStan/Component/VCard/CreatePropertyDynamicMethodReturnTypeExtension.php @@ -0,0 +1,36 @@ +getName(); + } + + public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type + { + if ($methodCall->args[0]->value instanceof \PhpParser\Node\Scalar\String_) { + if (array_key_exists($methodCall->args[0]->value->value, VCard::$propertyMap)) { + return new ObjectType(VCard::$propertyMap[$methodCall->args[0]->value->value]); + } + } + + return new ObjectType(Property::class); + } +} diff --git a/lib/PHPStan/ComponentClassReflectionExtension.php b/lib/PHPStan/ComponentClassReflectionExtension.php new file mode 100644 index 000000000..18c8c1b83 --- /dev/null +++ b/lib/PHPStan/ComponentClassReflectionExtension.php @@ -0,0 +1,81 @@ +broker = $broker; + } + + public function hasProperty(ClassReflection $classReflection, string $propertyName): bool + { + if ($classReflection->isSubclassOf(Document::class)) { + return true; + } + + if ($classReflection->isSubclassOf(Component::class)) { + if (in_array($classReflection->getName(), VCalendar::$componentMap)) { + return $this->hasProperty( + $this->broker->getClass(VCalendar::class), + $propertyName + ); + } + } + + return false; + } + + public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection + { + if ($classReflection->isSubclassOf(Document::class) && ($property = $this->getMappedProperty($classReflection, $propertyName))) { + return $property; + } + + if (!$classReflection->isSubclassOf(Document::class) && $classReflection->isSubclassOf(Component::class)) { + if (in_array($classReflection->getName(), VCalendar::$componentMap)) { + return $this->getProperty( + $this->broker->getClass(VCalendar::class), + $propertyName + ); + } + } + + return new ComponentProperty($classReflection, Unknown::class); + } + + private function getMappedProperty(ClassReflection $classReflection, string $propertyName): ?PropertyReflection + { + $propertyName = strtoupper($propertyName); + + foreach (self::MAP_NAMES as $mapName) { + $map = $classReflection->getName()::$$mapName; + + if (isset($map[$propertyName])) { + return new ComponentProperty($classReflection, $map[$propertyName]); + } + } + + return null; + } +} diff --git a/lib/PHPStan/ComponentProperty.php b/lib/PHPStan/ComponentProperty.php new file mode 100644 index 000000000..58f3f9608 --- /dev/null +++ b/lib/PHPStan/ComponentProperty.php @@ -0,0 +1,99 @@ +declaringClass = $declaringClass; + $this->className = $className; + } + + public function getDeclaringClass(): ClassReflection + { + return $this->declaringClass; + } + + public function isStatic(): bool + { + return false; + } + + public function isPrivate(): bool + { + return false; + } + + public function isPublic(): bool + { + return true; + } + + public function getReadableType(): Type + { + if (Duration::class === $this->className) { + return new UnionType([ + new ObjectType($this->className), + new ObjectType(DateTime::class), + ]); + } + + return new ObjectType($this->className); + } + + public function getWritableType(): Type + { + return new ObjectType($this->className); + } + + public function canChangeTypeAfterAssignment(): bool + { + return false; + } + + public function isReadable(): bool + { + return true; + } + + public function isWritable(): bool + { + return true; + } + + public function isDeprecated(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + + public function getDeprecatedDescription(): ?string + { + return null; + } + + public function isInternal(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + + public function getDocComment(): ?string + { + return null; + } +} diff --git a/lib/PHPStan/extension.neon b/lib/PHPStan/extension.neon new file mode 100644 index 000000000..a515a2caf --- /dev/null +++ b/lib/PHPStan/extension.neon @@ -0,0 +1,29 @@ +services: + - + class: Sabre\VObject\PHPStan\ComponentClassReflectionExtension + tags: + - phpstan.broker.propertiesClassReflectionExtension + - + class: Sabre\VObject\PHPStan\Component\VCalendar\CreateComponentDynamicMethodReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: Sabre\VObject\PHPStan\Component\VCard\CreateComponentDynamicMethodReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: Sabre\VObject\PHPStan\Component\VCalendar\CreatePropertyDynamicMethodReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: Sabre\VObject\PHPStan\Component\VCard\CreatePropertyDynamicMethodReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: Sabre\VObject\PHPStan\Component\AddDynamicMethodReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: Sabre\VObject\PHPStan\Component\SelectDynamicMethodReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension diff --git a/lib/Parameter.php b/lib/Parameter.php index e39d320a1..719ccc361 100644 --- a/lib/Parameter.php +++ b/lib/Parameter.php @@ -19,13 +19,6 @@ */ class Parameter extends Node { - /** - * Parameter name. - * - * @var string - */ - public $name; - /** * vCard 2.1 allows parameters to be encoded without a name. * diff --git a/lib/Parser/MimeDir.php b/lib/Parser/MimeDir.php index ea5ac0326..d065e622d 100644 --- a/lib/Parser/MimeDir.php +++ b/lib/Parser/MimeDir.php @@ -9,6 +9,7 @@ use Sabre\VObject\EofException; use Sabre\VObject\Node; use Sabre\VObject\ParseException; +use Sabre\VObject\Property\Text; /** * MimeDir parser. @@ -35,7 +36,7 @@ class MimeDir extends Parser /** * Root component. * - * @var Component + * @var Document */ protected $root; @@ -439,7 +440,7 @@ protected function readProperty($line) $propObj->add(null, $namelessParameter); } - if ('QUOTED-PRINTABLE' === strtoupper($propObj['ENCODING'])) { + if ($propObj instanceof Text && 'QUOTED-PRINTABLE' === strtoupper($propObj['ENCODING'])) { $propObj->setQuotedPrintableValue($this->extractQuotedPrintableValue()); } else { $charset = $this->charset; diff --git a/lib/Parser/XML/Element/KeyValue.php b/lib/Parser/XML/Element/KeyValue.php index c0bbf0d9b..3a3c668c8 100644 --- a/lib/Parser/XML/Element/KeyValue.php +++ b/lib/Parser/XML/Element/KeyValue.php @@ -33,8 +33,6 @@ 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) diff --git a/lib/Property.php b/lib/Property.php index f9cf8e38e..9a2765869 100644 --- a/lib/Property.php +++ b/lib/Property.php @@ -16,15 +16,6 @@ */ abstract class Property extends Node { - /** - * Property name. - * - * This will contain a string such as DTSTART, SUMMARY, FN. - * - * @var string - */ - public $name; - /** * Property group. * @@ -56,6 +47,13 @@ abstract class Property extends Node */ public $delimiter = ';'; + /** + * Reference to the parent object, if this is not the top object. + * + * @var Component + */ + public $parent; + /** * Creates the generic property. * @@ -155,7 +153,7 @@ public function getParts() * combined. * If nameless parameter is added, we try to guess its name. * - * @param string $name + * @param string|null $name * @param string|array|null $value */ public function add($name, $value = null) @@ -411,7 +409,7 @@ public function offsetExists($name) * * @param string $name * - * @return Node + * @return Parameter|Property|null */ public function offsetGet($name) { @@ -421,7 +419,7 @@ public function offsetGet($name) $name = strtoupper($name); if (!isset($this->parameters[$name])) { - return; + return null; } return $this->parameters[$name]; diff --git a/lib/Property/ICalendar/DateTime.php b/lib/Property/ICalendar/DateTime.php index f2dbdeba3..d1da1d262 100644 --- a/lib/Property/ICalendar/DateTime.php +++ b/lib/Property/ICalendar/DateTime.php @@ -173,7 +173,7 @@ public function getDateTimes(DateTimeZone $timeZone = null) /** * Sets the property as a DateTime object. * - * @param bool isFloating If set to true, timezones will be ignored + * @param bool $isFloating If set to true, timezones will be ignored */ public function setDateTime(DateTimeInterface $dt, $isFloating = false) { @@ -186,8 +186,8 @@ public function setDateTime(DateTimeInterface $dt, $isFloating = false) * The first value will be used as a reference for the timezones, and all * the otehr values will be adjusted for that timezone * - * @param DateTimeInterface[] $dt - * @param bool isFloating If set to true, timezones will be ignored + * @param (\DateTime|\DateTimeImmutable)[] $dt + * @param bool $isFloating If set to true, timezones will be ignored */ public function setDateTimes(array $dt, $isFloating = false) { diff --git a/lib/Recur/EventIterator.php b/lib/Recur/EventIterator.php index fd904b383..44fb11e6b 100644 --- a/lib/Recur/EventIterator.php +++ b/lib/Recur/EventIterator.php @@ -88,10 +88,10 @@ 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 VEvent|VEvent[] $input + * @param string|null $uid + * @param DateTimeZone|null $timeZone reference timezone for floating dates and + * times */ public function __construct($input, $uid = null, DateTimeZone $timeZone = null) { diff --git a/lib/Recur/RDateIterator.php b/lib/Recur/RDateIterator.php index d117e152c..25911873c 100644 --- a/lib/Recur/RDateIterator.php +++ b/lib/Recur/RDateIterator.php @@ -146,7 +146,7 @@ public function fastForward(DateTimeInterface $dt) * 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) { diff --git a/lib/Recur/RRuleIterator.php b/lib/Recur/RRuleIterator.php index 55581e9ac..b61187582 100644 --- a/lib/Recur/RRuleIterator.php +++ b/lib/Recur/RRuleIterator.php @@ -2,6 +2,7 @@ namespace Sabre\VObject\Recur; +use DateTime; use DateTimeImmutable; use DateTimeInterface; use Iterator; @@ -152,7 +153,7 @@ public function fastForward(DateTimeInterface $dt) * The date of the current iteration. You can get this by calling * ->current(). * - * @var DateTimeInterface + * @var DateTime|DateTimeImmutable */ protected $currentDate; @@ -877,14 +878,14 @@ protected function getMonthlyOccurrences() 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')) { + $monthDay < 0 - (int) $startDate->format('t')) { continue; } if ($monthDay > 0) { $byMonthDayResults[] = $monthDay; } else { // Negative values - $byMonthDayResults[] = $startDate->format('t') + 1 + $monthDay; + $byMonthDayResults[] = (int) $startDate->format('t') + 1 + $monthDay; } } } diff --git a/lib/Splitter/ICalendar.php b/lib/Splitter/ICalendar.php index d42566194..14bf89eee 100644 --- a/lib/Splitter/ICalendar.php +++ b/lib/Splitter/ICalendar.php @@ -57,7 +57,7 @@ public function __construct($input, $options = 0) } // Get all timezones - if ('VTIMEZONE' === $component->name) { + if ($component instanceof VObject\Component\VTimeZone) { $this->vtimezones[(string) $component->TZID] = $component; continue; } diff --git a/lib/TimeZoneUtil.php b/lib/TimeZoneUtil.php index 2c407fee6..72074d1bc 100644 --- a/lib/TimeZoneUtil.php +++ b/lib/TimeZoneUtil.php @@ -117,12 +117,11 @@ class TimeZoneUtil * Alternatively, if $failIfUncertain is set to true, it will throw an * exception if we cannot accurately determine the timezone. * - * @param string $tzid - * @param Sabre\VObject\Component $vcalendar + * @param string $tzid * * @return \DateTimeZone */ - public static function getTimeZone($tzid, Component $vcalendar = null, $failIfUncertain = false) + public static function getTimeZone($tzid, Component\VCalendar $vcalendar = null, $failIfUncertain = false) { // First we will just see if the tzid is a support timezone identifier. // diff --git a/lib/VCardConverter.php b/lib/VCardConverter.php index 04932fe67..1b14d16c4 100644 --- a/lib/VCardConverter.php +++ b/lib/VCardConverter.php @@ -241,9 +241,8 @@ protected function convertProperty(Component\VCard $input, Component\VCard $outp * * 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 Parameter[] $parameters list of parameters that will eventually be added to + * the new property * * @return Property\Uri */ @@ -294,7 +293,7 @@ protected function convertBinaryToUri(Component\VCard $output, Property\Binary $ * 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 + * @param Property\Uri $newProperty the input property * * @return Property\Binary|null */ diff --git a/phpstan.neon b/phpstan.neon index c705178c9..3f7436107 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,4 +1,6 @@ parameters: - level: 1 - universalObjectCratesClasses: - - \Sabre\VObject\Component + level: 2 +includes: + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-phpunit/rules.neon + - lib/PHPStan/extension.neon diff --git a/tests/VObject/Component/AvailableTest.php b/tests/VObject/Component/AvailableTest.php index bf0a6716f..c52350308 100644 --- a/tests/VObject/Component/AvailableTest.php +++ b/tests/VObject/Component/AvailableTest.php @@ -21,6 +21,8 @@ public function testAvailableComponent() END:AVAILABLE END:VCALENDAR VCAL; + + /** @var VCalendar $document */ $document = Reader::read($vcal); $this->assertInstanceOf(Available::class, $document->AVAILABLE); } @@ -36,6 +38,7 @@ public function testGetEffectiveStartEnd() END:VCALENDAR VCAL; + /** @var VCalendar $document */ $document = Reader::read($vcal); $tz = new DateTimeZone('UTC'); $this->assertEquals( @@ -58,6 +61,7 @@ public function testGetEffectiveStartEndDuration() END:VCALENDAR VCAL; + /** @var VCalendar $document */ $document = Reader::read($vcal); $tz = new DateTimeZone('UTC'); $this->assertEquals( diff --git a/tests/VObject/Component/VAlarmTest.php b/tests/VObject/Component/VAlarmTest.php index 2823d16da..c231cb60b 100644 --- a/tests/VObject/Component/VAlarmTest.php +++ b/tests/VObject/Component/VAlarmTest.php @@ -164,6 +164,7 @@ public function testInTimeRangeBuggy() END:VCALENDAR BLA; + /** @var VCalendar $vobj */ $vobj = Reader::read($input); $this->assertTrue($vobj->VTODO->VALARM->isInTimeRange(new \DateTime('2012-10-01 00:00:00'), new \DateTime('2012-11-01 00:00:00'))); diff --git a/tests/VObject/Component/VAvailabilityTest.php b/tests/VObject/Component/VAvailabilityTest.php index 2fd9c0dde..3f771b104 100644 --- a/tests/VObject/Component/VAvailabilityTest.php +++ b/tests/VObject/Component/VAvailabilityTest.php @@ -22,6 +22,8 @@ public function testVAvailabilityComponent() END:VAVAILABILITY END:VCALENDAR VCAL; + + /** @var VCalendar $document */ $document = Reader::read($vcal); $this->assertInstanceOf(VAvailability::class, $document->VAVAILABILITY); @@ -38,6 +40,7 @@ public function testGetEffectiveStartEnd() END:VCALENDAR VCAL; + /** @var VCalendar $document */ $document = Reader::read($vcal); $tz = new DateTimeZone('UTC'); $this->assertEquals( @@ -60,6 +63,7 @@ public function testGetEffectiveStartDuration() END:VCALENDAR VCAL; + /** @var VCalendar $document */ $document = Reader::read($vcal); $tz = new DateTimeZone('UTC'); $this->assertEquals( @@ -80,6 +84,7 @@ public function testGetEffectiveStartEndUnbound() END:VCALENDAR VCAL; + /** @var VCalendar $document */ $document = Reader::read($vcal); $this->assertEquals( [ @@ -99,6 +104,7 @@ public function testIsInTimeRangeUnbound() END:VCALENDAR VCAL; + /** @var VCalendar $document */ $document = Reader::read($vcal); $this->assertTrue( $document->VAVAILABILITY->isInTimeRange(new DateTimeImmutable('2015-07-17'), new DateTimeImmutable('2015-07-18')) @@ -116,6 +122,7 @@ public function testIsInTimeRangeOutside() END:VCALENDAR VCAL; + /** @var VCalendar $document */ $document = Reader::read($vcal); $this->assertFalse( $document->VAVAILABILITY->isInTimeRange(new DateTimeImmutable('2015-07-17'), new DateTimeImmutable('2015-07-18')) @@ -234,6 +241,8 @@ public function testAvailableSubComponent() END:VAVAILABILITY END:VCALENDAR VCAL; + + /** @var VCalendar $document */ $document = Reader::read($vcal); $this->assertInstanceOf(Available::class, $document->VAVAILABILITY->AVAILABLE); @@ -375,33 +384,42 @@ public function testRFCxxxSection3_1_available_optional_once() public function testRFCxxxSection3_2() { + /** @var VCalendar $busy */ + $busy = Reader::read($this->templateAvailable([ + 'BUSYTYPE:BUSY', + ])); + $this->assertEquals( 'BUSY', - Reader::read($this->templateAvailable([ - 'BUSYTYPE:BUSY', - ])) + $busy ->VAVAILABILITY ->AVAILABLE ->BUSYTYPE ->getValue() ); + /** @var VCalendar $unavailable */ + $unavailable = Reader::read($this->templateAvailable([ + 'BUSYTYPE:BUSY-UNAVAILABLE', + ])); + $this->assertEquals( 'BUSY-UNAVAILABLE', - Reader::read($this->templateAvailable([ - 'BUSYTYPE:BUSY-UNAVAILABLE', - ])) + $unavailable ->VAVAILABILITY ->AVAILABLE ->BUSYTYPE ->getValue() ); + /** @var VCalendar $tentative */ + $tentative = Reader::read($this->templateAvailable([ + 'BUSYTYPE:BUSY-TENTATIVE', + ])); + $this->assertEquals( 'BUSY-TENTATIVE', - Reader::read($this->templateAvailable([ - 'BUSYTYPE:BUSY-TENTATIVE', - ])) + $tentative ->VAVAILABILITY ->AVAILABLE ->BUSYTYPE diff --git a/tests/VObject/Component/VCalendarTest.php b/tests/VObject/Component/VCalendarTest.php index c2f0ce978..050188b84 100644 --- a/tests/VObject/Component/VCalendarTest.php +++ b/tests/VObject/Component/VCalendarTest.php @@ -16,10 +16,12 @@ class VCalendarTest extends TestCase */ public function testExpand($input, $output, $timeZone = 'UTC', $start = '2011-12-01', $end = '2011-12-31') { + /** @var VCalendar $vcal */ $vcal = VObject\Reader::read($input); $timeZone = new DateTimeZone($timeZone); + /** @var VCalendar $vcal */ $vcal = $vcal->expand( new \DateTime($start), new \DateTime($end), @@ -343,6 +345,8 @@ public function testBrokenEventExpand() END:VEVENT END:VCALENDAR '; + + /** @var VCalendar $vcal */ $vcal = VObject\Reader::read($input); $vcal->expand( new \DateTime('2011-12-01'), @@ -533,8 +537,10 @@ public function testGetBaseComponent() END:VCALENDAR '; + /** @var VCalendar $vcal */ $vcal = VObject\Reader::read($input); + /** @var VEvent $result */ $result = $vcal->getBaseComponent(); $this->assertEquals('test', $result->SUMMARY->getValue()); } @@ -561,6 +567,7 @@ public function testGetBaseComponentNoResult() END:VCALENDAR '; + /** @var VCalendar $vcal */ $vcal = VObject\Reader::read($input); $result = $vcal->getBaseComponent(); @@ -588,8 +595,10 @@ public function testGetBaseComponentWithFilter() END:VCALENDAR '; + /** @var VCalendar $vcal */ $vcal = VObject\Reader::read($input); + /** @var VEvent $result */ $result = $vcal->getBaseComponent('VEVENT'); $this->assertEquals('test', $result->SUMMARY->getValue()); } @@ -608,6 +617,7 @@ public function testGetBaseComponentWithFilterNoResult() END:VCALENDAR '; + /** @var VCalendar $vcal */ $vcal = VObject\Reader::read($input); $result = $vcal->getBaseComponent('VEVENT'); diff --git a/tests/VObject/Component/VCardTest.php b/tests/VObject/Component/VCardTest.php index 3124fec84..d74c8579d 100644 --- a/tests/VObject/Component/VCardTest.php +++ b/tests/VObject/Component/VCardTest.php @@ -132,6 +132,7 @@ public function testGetByType() END:VCARD VCF; + /** @var VCard $vcard */ $vcard = VObject\Reader::read($vcard); $this->assertEquals('1@example.org', $vcard->getByType('EMAIL', 'home')->getValue()); $this->assertEquals('2@example.org', $vcard->getByType('EMAIL', 'work')->getValue()); @@ -149,6 +150,7 @@ public function testPreferredNoPref() END:VCARD VCF; + /** @var VCard $vcard */ $vcard = VObject\Reader::read($vcard); $this->assertEquals('1@example.org', $vcard->preferred('EMAIL')->getValue()); } @@ -163,6 +165,7 @@ public function testPreferredWithPref() END:VCARD VCF; + /** @var VCard $vcard */ $vcard = VObject\Reader::read($vcard); $this->assertEquals('2@example.org', $vcard->preferred('EMAIL')->getValue()); } @@ -178,6 +181,7 @@ public function testPreferredWith40Pref() END:VCARD VCF; + /** @var VCard $vcard */ $vcard = VObject\Reader::read($vcard); $this->assertEquals('3@example.org', $vcard->preferred('EMAIL')->getValue()); } @@ -190,6 +194,7 @@ public function testPreferredNotFound() END:VCARD VCF; + /** @var VCard $vcard */ $vcard = VObject\Reader::read($vcard); $this->assertNull($vcard->preferred('EMAIL')); } diff --git a/tests/VObject/Component/VFreeBusyTest.php b/tests/VObject/Component/VFreeBusyTest.php index 2aa4351ca..1cd595028 100644 --- a/tests/VObject/Component/VFreeBusyTest.php +++ b/tests/VObject/Component/VFreeBusyTest.php @@ -23,6 +23,7 @@ public function testIsFree() END:VCALENDAR BLA; + /** @var VCalendar $obj */ $obj = VObject\Reader::read($input); $vfb = $obj->VFREEBUSY; diff --git a/tests/VObject/Component/VTimeZoneTest.php b/tests/VObject/Component/VTimeZoneTest.php index ead22b81e..b95ceff78 100644 --- a/tests/VObject/Component/VTimeZoneTest.php +++ b/tests/VObject/Component/VTimeZoneTest.php @@ -42,6 +42,7 @@ public function testGetTimeZone() END:VCALENDAR HI; + /** @var VCalendar $obj */ $obj = Reader::read($input); $tz = new \DateTimeZone('America/Toronto'); diff --git a/tests/VObject/ComponentTest.php b/tests/VObject/ComponentTest.php index f56d55531..3781f9588 100644 --- a/tests/VObject/ComponentTest.php +++ b/tests/VObject/ComponentTest.php @@ -109,7 +109,7 @@ public function testMagicSetScalarTwice() public function testMagicSetArray() { - $comp = new VCalendar(); + $comp = new VCard(); $comp->ORG = ['Acme Inc', 'Section 9']; $this->assertInstanceOf(Property::class, $comp->ORG); @@ -155,7 +155,7 @@ public function testArrayAccessGet() $comp->add($event2); $this->assertEquals(2, count($comp->children())); - $this->assertTrue($comp->vevent[1] instanceof Component); + $this->assertInstanceOf(Component\VEvent::class, $comp->vevent[1]); $this->assertEquals('Event 2', (string) $comp->vevent[1]->summary); } @@ -520,6 +520,10 @@ public function ruleData() } } +/** + * @property Property $BAR + * @property Property $GIR + */ class FakeComponent extends Component { public function getValidationRules() diff --git a/tests/VObject/EmClientTest.php b/tests/VObject/EmClientTest.php index bb586ba97..49f67f101 100644 --- a/tests/VObject/EmClientTest.php +++ b/tests/VObject/EmClientTest.php @@ -48,6 +48,7 @@ public function testParseTz() END:VEVENT END:VCALENDAR'; + /** @var Component\VCalendar $vObject */ $vObject = Reader::read($str); $dt = $vObject->VEVENT->DTSTART->getDateTime(); $this->assertEquals(new DateTimeImmutable('2011-10-08 19:30:00', new \DateTimeZone('America/Chicago')), $dt); diff --git a/tests/VObject/EmptyParameterTest.php b/tests/VObject/EmptyParameterTest.php index 52fe878e2..b24a8caf2 100644 --- a/tests/VObject/EmptyParameterTest.php +++ b/tests/VObject/EmptyParameterTest.php @@ -24,6 +24,7 @@ public function testRead() $vcard = $vcard->convert(\Sabre\VObject\Document::VCARD30); $vcard = $vcard->serialize(); + /** @var Component\VCard $converted */ $converted = Reader::read($vcard); $converted->validate(); diff --git a/tests/VObject/EmptyValueIssueTest.php b/tests/VObject/EmptyValueIssueTest.php index 91a4d84f6..6c6d6a646 100644 --- a/tests/VObject/EmptyValueIssueTest.php +++ b/tests/VObject/EmptyValueIssueTest.php @@ -22,6 +22,7 @@ public function testDecodeValue() END:VCALENDAR ICS; + /** @var Component\VCalendar $vobj */ $vobj = Reader::read($input); // Before this bug was fixed, getValue() would return nothing. diff --git a/tests/VObject/GoogleColonEscapingTest.php b/tests/VObject/GoogleColonEscapingTest.php index 48bbde07b..320ec8cf7 100644 --- a/tests/VObject/GoogleColonEscapingTest.php +++ b/tests/VObject/GoogleColonEscapingTest.php @@ -25,6 +25,7 @@ public function testDecode() END:VCARD VCF; + /** @var Component\VCard $vobj */ $vobj = Reader::read($vcard); $this->assertEquals('http://www.rooftopsolutions.nl/', $vobj->URL->getValue()); } diff --git a/tests/VObject/ICalendar/AttachParseTest.php b/tests/VObject/ICalendar/AttachParseTest.php index e6e3d8685..9923b846c 100644 --- a/tests/VObject/ICalendar/AttachParseTest.php +++ b/tests/VObject/ICalendar/AttachParseTest.php @@ -21,6 +21,7 @@ public function testParseAttach() END:VCALENDAR ICS; + /** @var \Sabre\VObject\Component\VCalendar $vcal */ $vcal = Reader::read($vcal); $prop = $vcal->VEVENT->ATTACH; diff --git a/tests/VObject/ITip/BrokerTester.php b/tests/VObject/ITip/BrokerTester.php index 9e9956e03..01f1f826c 100644 --- a/tests/VObject/ITip/BrokerTester.php +++ b/tests/VObject/ITip/BrokerTester.php @@ -43,6 +43,7 @@ public function process($input, $existingObject = null, $expected = false) { $version = \Sabre\VObject\Version::VERSION; + /** @var \Sabre\VObject\Component\VCalendar $vcal */ $vcal = Reader::read($input); $mainComponent = new \Sabre\VObject\Component\VEvent($vcal, 'VEVENT'); diff --git a/tests/VObject/Issue153Test.php b/tests/VObject/Issue153Test.php index 309025041..0f6a3575f 100644 --- a/tests/VObject/Issue153Test.php +++ b/tests/VObject/Issue153Test.php @@ -8,6 +8,7 @@ class Issue153Test extends TestCase { public function testRead() { + /** @var Component\VCard $obj */ $obj = Reader::read(file_get_contents(dirname(__FILE__).'/issue153.vcf')); $this->assertEquals('Test Benutzer', (string) $obj->FN); } diff --git a/tests/VObject/Issue64Test.php b/tests/VObject/Issue64Test.php index 2e623baa8..2d0730aff 100644 --- a/tests/VObject/Issue64Test.php +++ b/tests/VObject/Issue64Test.php @@ -8,6 +8,7 @@ class Issue64Test extends TestCase { public function testRead() { + /** @var Component\VCard $vcard */ $vcard = Reader::read(file_get_contents(dirname(__FILE__).'/issue64.vcf')); $vcard = $vcard->convert(\Sabre\VObject\Document::VCARD30); $vcard = $vcard->serialize(); diff --git a/tests/VObject/Parser/JsonTest.php b/tests/VObject/Parser/JsonTest.php index e1c701489..5fe374309 100644 --- a/tests/VObject/Parser/JsonTest.php +++ b/tests/VObject/Parser/JsonTest.php @@ -368,6 +368,7 @@ public function testParseStreamArg() fwrite($stream, json_encode($input)); rewind($stream); + /** @var \Sabre\VObject\Component\VCard; $result */ $result = VObject\Reader::readJson($stream, 0); $this->assertEquals('foo', $result->FN->getValue()); } diff --git a/tests/VObject/Parser/MimeDirTest.php b/tests/VObject/Parser/MimeDirTest.php index 183c9ce4c..39f4ad5c9 100644 --- a/tests/VObject/Parser/MimeDirTest.php +++ b/tests/VObject/Parser/MimeDirTest.php @@ -29,6 +29,8 @@ public function testDecodeLatin1() $mimeDir = new MimeDir(); $mimeDir->setCharset('ISO-8859-1'); + + /** @var \Sabre\VObject\Component\VCard $vcard */ $vcard = $mimeDir->parse($vcard); $this->assertEquals("umlaut u - \xC3\xBC", $vcard->FN->getValue()); } @@ -43,6 +45,8 @@ public function testDecodeInlineLatin1() VCF; $mimeDir = new MimeDir(); + + /** @var \Sabre\VObject\Component\VCard $vcard */ $vcard = $mimeDir->parse($vcard); $this->assertEquals("umlaut u - \xC3\xBC", $vcard->FN->getValue()); } @@ -57,6 +61,8 @@ public function testIgnoreCharsetVCard30() VCF; $mimeDir = new MimeDir(); + + /** @var \Sabre\VObject\Component\VCard $vcard */ $vcard = $mimeDir->parse($vcard); $this->assertEquals("foo-bar - \xFC", $vcard->FN->getValue()); } @@ -71,6 +77,8 @@ public function testDontDecodeLatin1() VCF; $mimeDir = new MimeDir(); + + /** @var \Sabre\VObject\Component\VCard $vcard */ $vcard = $mimeDir->parse($vcard); // This basically tests that we don't touch the input string if // the encoding was set to UTF-8. The result is actually invalid @@ -111,6 +119,8 @@ public function testDecodeWindows1252() $mimeDir = new MimeDir(); $mimeDir->setCharset('Windows-1252'); + + /** @var \Sabre\VObject\Component\VCard $vcard */ $vcard = $mimeDir->parse($vcard); $this->assertEquals("Euro \xE2\x82\xAC", $vcard->FN->getValue()); } @@ -125,6 +135,8 @@ public function testDecodeWindows1252Inline() VCF; $mimeDir = new MimeDir(); + + /** @var \Sabre\VObject\Component\VCard $vcard */ $vcard = $mimeDir->parse($vcard); $this->assertEquals("Euro \xE2\x82\xAC", $vcard->FN->getValue()); } @@ -140,6 +152,8 @@ public function testCaseInsensitiveInlineCharset() VCF; $mimeDir = new MimeDir(); + + /** @var \Sabre\VObject\Component\VCard $vcard */ $vcard = $mimeDir->parse($vcard); // we can do a simple assertion here. As long as we don't get an exception, everything is thing $this->assertEquals('Euro', $vcard->FN->getValue()); diff --git a/tests/VObject/Parser/QuotedPrintableTest.php b/tests/VObject/Parser/QuotedPrintableTest.php index 7cadb46eb..c0051b627 100644 --- a/tests/VObject/Parser/QuotedPrintableTest.php +++ b/tests/VObject/Parser/QuotedPrintableTest.php @@ -3,7 +3,7 @@ namespace Sabre\VObject\Parser; use PHPUnit\Framework\TestCase; -use Sabre\VObject\Component; +use Sabre\VObject\Component\VCard; use Sabre\VObject\Reader; class QuotedPrintableTest extends TestCase @@ -14,10 +14,10 @@ public function testReadQuotedPrintableSimple() $result = Reader::read($data); - $this->assertInstanceOf(Component::class, $result); + $this->assertInstanceOf(VCard::class, $result); $this->assertEquals('VCARD', $result->name); $this->assertEquals(1, count($result->children())); - $this->assertEquals('Aachen', $this->getPropertyValue($result->LABEL)); + $this->assertEquals('Aachen', (string) $result->LABEL); } public function testReadQuotedPrintableNewlineSoft() @@ -25,10 +25,10 @@ public function testReadQuotedPrintableNewlineSoft() $data = "BEGIN:VCARD\r\nLABEL;ENCODING=QUOTED-PRINTABLE:Aa=\r\n ch=\r\n en\r\nEND:VCARD"; $result = Reader::read($data); - $this->assertInstanceOf(Component::class, $result); + $this->assertInstanceOf(VCard::class, $result); $this->assertEquals('VCARD', $result->name); $this->assertEquals(1, count($result->children())); - $this->assertEquals('Aachen', $this->getPropertyValue($result->LABEL)); + $this->assertEquals('Aachen', (string) $result->LABEL); } public function testReadQuotedPrintableNewlineHard() @@ -36,10 +36,10 @@ public function testReadQuotedPrintableNewlineHard() $data = "BEGIN:VCARD\r\nLABEL;ENCODING=QUOTED-PRINTABLE:Aachen=0D=0A=\r\n Germany\r\nEND:VCARD"; $result = Reader::read($data); - $this->assertInstanceOf(Component::class, $result); + $this->assertInstanceOf(VCard::class, $result); $this->assertEquals('VCARD', $result->name); $this->assertEquals(1, count($result->children())); - $this->assertEquals("Aachen\r\nGermany", $this->getPropertyValue($result->LABEL)); + $this->assertEquals("Aachen\r\nGermany", (string) $result->LABEL); } public function testReadQuotedPrintableCompatibilityMS() @@ -47,10 +47,10 @@ public function testReadQuotedPrintableCompatibilityMS() $data = "BEGIN:VCARD\r\nLABEL;ENCODING=QUOTED-PRINTABLE:Aachen=0D=0A=\r\nDeutschland:okay\r\nEND:VCARD"; $result = Reader::read($data, Reader::OPTION_FORGIVING); - $this->assertInstanceOf(Component::class, $result); + $this->assertInstanceOf(VCard::class, $result); $this->assertEquals('VCARD', $result->name); $this->assertEquals(1, count($result->children())); - $this->assertEquals("Aachen\r\nDeutschland:okay", $this->getPropertyValue($result->LABEL)); + $this->assertEquals("Aachen\r\nDeutschland:okay", (string) $result->LABEL); } public function testReadQuotesPrintableCompoundValues() @@ -65,38 +65,10 @@ public function testReadQuotesPrintableCompoundValues() END:VCARD VCF; + /** @var VCard $result */ $result = Reader::read($data, Reader::OPTION_FORGIVING); $this->assertEquals([ '', '', 'Münster Str. 1', 'Münster', '', '48143', 'Deutschland', ], $result->ADR->getParts()); } - - private function getPropertyValue(\Sabre\VObject\Property $property) - { - return (string) $property; - - /* - $param = $property['encoding']; - if ($param !== null) { - $encoding = strtoupper((string)$param); - if ($encoding === 'QUOTED-PRINTABLE') { - $value = quoted_printable_decode($value); - } else { - throw new Exception(); - } - } - - $param = $property['charset']; - if ($param !== null) { - $charset = strtoupper((string)$param); - if ($charset !== 'UTF-8') { - $value = mb_convert_encoding($value, 'UTF-8', $charset); - } - } else { - $value = StringUtil::convertToUTF8($value); - } - - return $value; - */ - } } diff --git a/tests/VObject/Property/ICalendar/CalAddressTest.php b/tests/VObject/Property/ICalendar/CalAddressTest.php index a907daf5c..b1d38de20 100644 --- a/tests/VObject/Property/ICalendar/CalAddressTest.php +++ b/tests/VObject/Property/ICalendar/CalAddressTest.php @@ -12,6 +12,8 @@ class CalAddressTest extends TestCase public function testGetNormalizedValue($expected, $input) { $vobj = new \Sabre\VObject\Component\VCalendar(); + + /** @var CalAddress $property */ $property = $vobj->add('ATTENDEE', $input); $this->assertEquals( diff --git a/tests/VObject/Property/ICalendar/RecurTest.php b/tests/VObject/Property/ICalendar/RecurTest.php index 3902a6e13..01492460a 100644 --- a/tests/VObject/Property/ICalendar/RecurTest.php +++ b/tests/VObject/Property/ICalendar/RecurTest.php @@ -55,6 +55,7 @@ public function testGetJSONWithCount() END:VCALENDAR '; + /** @var VCalendar $vcal */ $vcal = Reader::read($input); $rrule = $vcal->VEVENT->RRULE; $count = $rrule->getJsonValue()[0]['count']; @@ -89,6 +90,7 @@ public function testGetJSONWithUntil() END:VCALENDAR '; + /** @var VCalendar $vcal */ $vcal = Reader::read($input); $rrule = $vcal->VEVENT->RRULE; $untilJsonString = $rrule->getJsonValue()[0]['until']; diff --git a/tests/VObject/Property/TextTest.php b/tests/VObject/Property/TextTest.php index eea21b1ad..66275a7ba 100644 --- a/tests/VObject/Property/TextTest.php +++ b/tests/VObject/Property/TextTest.php @@ -75,6 +75,7 @@ public function testValidateMinimumPropValue() END:VCARD IN; + /** @var VCard $vcard */ $vcard = \Sabre\VObject\Reader::read($vcard); $this->assertEquals(1, count($vcard->validate())); diff --git a/tests/VObject/Property/VCard/DateAndOrTimeTest.php b/tests/VObject/Property/VCard/DateAndOrTimeTest.php index f21b408a1..3385eb694 100644 --- a/tests/VObject/Property/VCard/DateAndOrTimeTest.php +++ b/tests/VObject/Property/VCard/DateAndOrTimeTest.php @@ -213,6 +213,8 @@ public function testGetDateIncompleteFromVCard() BDAY:--0407 END:VCARD VCF; + + /** @var VObject\Component\VCard $vcard */ $vcard = Reader::read($vcard); $prop = $vcard->BDAY; diff --git a/tests/VObject/Property/VCard/LanguageTagTest.php b/tests/VObject/Property/VCard/LanguageTagTest.php index 54106ffe8..75a330aea 100644 --- a/tests/VObject/Property/VCard/LanguageTagTest.php +++ b/tests/VObject/Property/VCard/LanguageTagTest.php @@ -4,6 +4,7 @@ use PHPUnit\Framework\TestCase; use Sabre\VObject; +use Sabre\VObject\Component\VCard; class LanguageTagTest extends TestCase { @@ -12,6 +13,7 @@ public function testMimeDir() $input = "BEGIN:VCARD\r\nVERSION:4.0\r\nLANG:nl\r\nEND:VCARD\r\n"; $mimeDir = new VObject\Parser\MimeDir($input); + /** @var VCard $result */ $result = $mimeDir->parse($input); $this->assertInstanceOf(LanguageTag::class, $result->LANG); @@ -29,6 +31,7 @@ public function testChangeAndSerialize() $input = "BEGIN:VCARD\r\nVERSION:4.0\r\nLANG:nl\r\nEND:VCARD\r\n"; $mimeDir = new VObject\Parser\MimeDir($input); + /** @var VCard $result */ $result = $mimeDir->parse($input); $this->assertInstanceOf(LanguageTag::class, $result->LANG); diff --git a/tests/VObject/Property/VCard/PhoneNumberTest.php b/tests/VObject/Property/VCard/PhoneNumberTest.php index 668bc7e4c..5ea10489d 100644 --- a/tests/VObject/Property/VCard/PhoneNumberTest.php +++ b/tests/VObject/Property/VCard/PhoneNumberTest.php @@ -11,6 +11,7 @@ public function testParser() { $input = "BEGIN:VCARD\r\nVERSION:3.0\r\nTEL;TYPE=HOME;VALUE=PHONE-NUMBER:+1234\r\nEND:VCARD\r\n"; + /** @var \Sabre\VObject\Component\VCard $vCard */ $vCard = VObject\Reader::read($input); $this->assertInstanceOf(PhoneNumber::class, $vCard->TEL); $this->assertEquals('PHONE-NUMBER', $vCard->TEL->getValueType()); diff --git a/tests/VObject/ReaderTest.php b/tests/VObject/ReaderTest.php index 0992806be..c0b39f18d 100644 --- a/tests/VObject/ReaderTest.php +++ b/tests/VObject/ReaderTest.php @@ -12,7 +12,7 @@ public function testReadComponent() $result = Reader::read($data); - $this->assertInstanceOf(Component::class, $result); + $this->assertInstanceOf(Component\VCalendar::class, $result); $this->assertEquals('VCALENDAR', $result->name); $this->assertEquals(0, count($result->children())); } @@ -27,7 +27,7 @@ public function testReadStream() $result = Reader::read($stream); - $this->assertInstanceOf(Component::class, $result); + $this->assertInstanceOf(Component\VCalendar::class, $result); $this->assertEquals('VCALENDAR', $result->name); $this->assertEquals(0, count($result->children())); } @@ -38,7 +38,7 @@ public function testReadComponentUnixNewLine() $result = Reader::read($data); - $this->assertInstanceOf(Component::class, $result); + $this->assertInstanceOf(Component\VCalendar::class, $result); $this->assertEquals('VCALENDAR', $result->name); $this->assertEquals(0, count($result->children())); } @@ -49,7 +49,7 @@ public function testReadComponentLineFold() $result = Reader::read($data); - $this->assertInstanceOf(Component::class, $result); + $this->assertInstanceOf(Component\VCalendar::class, $result); $this->assertEquals('VCALENDAR', $result->name); $this->assertEquals(0, count($result->children())); } @@ -73,6 +73,8 @@ public function testReadCorruptSubComponent() public function testReadProperty() { $data = "BEGIN:VCALENDAR\r\nSUMMARY:propValue\r\nEND:VCALENDAR"; + + /** @var Component\VCalendar $result */ $result = Reader::read($data); $result = $result->SUMMARY; @@ -84,6 +86,8 @@ public function testReadProperty() public function testReadPropertyWithNewLine() { $data = "BEGIN:VCALENDAR\r\nSUMMARY:Line1\\nLine2\\NLine3\\\\Not the 4th line!\r\nEND:VCALENDAR"; + + /** @var Component\VCalendar $result */ $result = Reader::read($data); $result = $result->SUMMARY; @@ -95,6 +99,8 @@ public function testReadPropertyWithNewLine() public function testReadMappedProperty() { $data = "BEGIN:VCALENDAR\r\nDTSTART:20110529\r\nEND:VCALENDAR"; + + /** @var Component\VCalendar $result */ $result = Reader::read($data); $result = $result->DTSTART; @@ -106,6 +112,8 @@ public function testReadMappedProperty() public function testReadMappedPropertyGrouped() { $data = "BEGIN:VCALENDAR\r\nfoo.DTSTART:20110529\r\nEND:VCALENDAR"; + + /** @var Component\VCalendar $result */ $result = Reader::read($data); $result = $result->DTSTART; @@ -131,7 +139,7 @@ public function testReadPropertyInComponent() $result = Reader::read(implode("\r\n", $data)); - $this->assertInstanceOf(Component::class, $result); + $this->assertInstanceOf(Component\VCalendar::class, $result); $this->assertEquals('VCALENDAR', $result->name); $this->assertEquals(1, count($result->children())); $this->assertInstanceOf(Property::class, $result->children()[0]); @@ -152,7 +160,7 @@ public function testReadNestedComponent() $result = Reader::read(implode("\r\n", $data)); - $this->assertInstanceOf(Component::class, $result); + $this->assertInstanceOf(Component\VCalendar::class, $result); $this->assertEquals('VCALENDAR', $result->name); $this->assertEquals(1, count($result->children())); $this->assertInstanceOf(Component::class, $result->children()[0]); @@ -165,6 +173,8 @@ public function testReadNestedComponent() public function testReadPropertyParameter() { $data = "BEGIN:VCALENDAR\r\nPROPNAME;PARAMNAME=paramvalue:propValue\r\nEND:VCALENDAR"; + + /** @var Component\VCalendar $result */ $result = Reader::read($data); $result = $result->PROPNAME; @@ -180,6 +190,8 @@ public function testReadPropertyParameter() public function testReadPropertyRepeatingParameter() { $data = "BEGIN:VCALENDAR\r\nPROPNAME;N=1;N=2;N=3,4;N=\"5\",6;N=\"7,8\";N=9,10;N=^'11^':propValue\r\nEND:VCALENDAR"; + + /** @var Component\VCalendar $result */ $result = Reader::read($data); $result = $result->PROPNAME; @@ -196,6 +208,8 @@ public function testReadPropertyRepeatingParameter() public function testReadPropertyRepeatingNamelessGuessedParameter() { $data = "BEGIN:VCALENDAR\r\nPROPNAME;WORK;VOICE;PREF:propValue\r\nEND:VCALENDAR"; + + /** @var Component\VCalendar $result */ $result = Reader::read($data); $result = $result->PROPNAME; @@ -212,6 +226,8 @@ public function testReadPropertyRepeatingNamelessGuessedParameter() public function testReadPropertyNoName() { $data = "BEGIN:VCALENDAR\r\nPROPNAME;PRODIGY:propValue\r\nEND:VCALENDAR"; + + /** @var Component\VCalendar $result */ $result = Reader::read($data); $result = $result->PROPNAME; @@ -228,6 +244,8 @@ public function testReadPropertyNoName() public function testReadPropertyParameterExtraColon() { $data = "BEGIN:VCALENDAR\r\nPROPNAME;PARAMNAME=paramvalue:propValue:anotherrandomstring\r\nEND:VCALENDAR"; + + /** @var Component\VCalendar $result */ $result = Reader::read($data); $result = $result->PROPNAME; @@ -243,6 +261,8 @@ public function testReadPropertyParameterExtraColon() public function testReadProperty2Parameters() { $data = "BEGIN:VCALENDAR\r\nPROPNAME;PARAMNAME=paramvalue;PARAMNAME2=paramvalue2:propValue\r\nEND:VCALENDAR"; + + /** @var Component\VCalendar $result */ $result = Reader::read($data); $result = $result->PROPNAME; @@ -260,6 +280,8 @@ public function testReadProperty2Parameters() public function testReadPropertyParameterQuoted() { $data = "BEGIN:VCALENDAR\r\nPROPNAME;PARAMNAME=\"paramvalue\":propValue\r\nEND:VCALENDAR"; + + /** @var Component\VCalendar $result */ $result = Reader::read($data); $result = $result->PROPNAME; @@ -275,6 +297,8 @@ public function testReadPropertyParameterQuoted() public function testReadPropertyParameterNewLines() { $data = "BEGIN:VCALENDAR\r\nPROPNAME;PARAMNAME=paramvalue1^nvalue2^^nvalue3:propValue\r\nEND:VCALENDAR"; + + /** @var Component\VCalendar $result */ $result = Reader::read($data); $result = $result->PROPNAME; @@ -291,6 +315,8 @@ public function testReadPropertyParameterNewLines() public function testReadPropertyParameterQuotedColon() { $data = "BEGIN:VCALENDAR\r\nPROPNAME;PARAMNAME=\"param:value\":propValue\r\nEND:VCALENDAR"; + + /** @var Component\VCalendar $result */ $result = Reader::read($data); $result = $result->PROPNAME; @@ -319,6 +345,7 @@ public function testReadForgiving() $this->assertEquals(true, $caught); + /** @var Component\VCalendar $result */ $result = Reader::read(implode("\r\n", $data), Reader::OPTION_FORGIVING); $expected = implode("\r\n", [ @@ -349,6 +376,7 @@ public function testReadWithInvalidLine() $this->assertEquals(true, $caught); + /** @var Component\VCalendar $result */ $result = Reader::read(implode("\r\n", $data), Reader::OPTION_IGNORE_INVALID_LINES); $expected = implode("\r\n", [ @@ -408,7 +436,7 @@ public function testReadBOM() $data = chr(0xef).chr(0xbb).chr(0xbf)."BEGIN:VCALENDAR\r\nEND:VCALENDAR"; $result = Reader::read($data); - $this->assertInstanceOf(Component::class, $result); + $this->assertInstanceOf(Component\VCalendar::class, $result); $this->assertEquals('VCALENDAR', $result->name); $this->assertEquals(0, count($result->children())); } diff --git a/tests/VObject/Recur/EventIterator/FifthTuesdayProblemTest.php b/tests/VObject/Recur/EventIterator/FifthTuesdayProblemTest.php index 3db97ede2..53ecfbab6 100644 --- a/tests/VObject/Recur/EventIterator/FifthTuesdayProblemTest.php +++ b/tests/VObject/Recur/EventIterator/FifthTuesdayProblemTest.php @@ -3,6 +3,7 @@ namespace Sabre\VObject\Recur\EventIterator; use PHPUnit\Framework\TestCase; +use Sabre\VObject\Component\VCalendar; use Sabre\VObject\Reader; use Sabre\VObject\Recur; @@ -38,6 +39,7 @@ public function testGetDTEnd() END:VCALENDAR ICS; + /** @var VCalendar $vObject */ $vObject = Reader::read($ics); $it = new Recur\EventIterator($vObject, (string) $vObject->VEVENT->UID); diff --git a/tests/VObject/Recur/EventIterator/MaxInstancesTest.php b/tests/VObject/Recur/EventIterator/MaxInstancesTest.php index 6314b3b5a..b00f7c7de 100644 --- a/tests/VObject/Recur/EventIterator/MaxInstancesTest.php +++ b/tests/VObject/Recur/EventIterator/MaxInstancesTest.php @@ -4,6 +4,7 @@ use DateTime; use PHPUnit\Framework\TestCase; +use Sabre\VObject\Component\VCalendar; use Sabre\VObject\Reader; use Sabre\VObject\Recur\MaxInstancesExceededException; use Sabre\VObject\Settings; @@ -28,6 +29,7 @@ public function testExceedMaxRecurrences() $temp = Settings::$maxRecurrences; Settings::$maxRecurrences = 4; try { + /** @var VCalendar $vcal */ $vcal = Reader::read($input); $vcal->expand(new DateTime('2014-08-01'), new DateTime('2014-09-01')); } finally { diff --git a/tests/VObject/Recur/EventIterator/OverrideFirstEventTest.php b/tests/VObject/Recur/EventIterator/OverrideFirstEventTest.php index 150a13980..1861496b9 100644 --- a/tests/VObject/Recur/EventIterator/OverrideFirstEventTest.php +++ b/tests/VObject/Recur/EventIterator/OverrideFirstEventTest.php @@ -4,6 +4,7 @@ use DateTime; use PHPUnit\Framework\TestCase; +use Sabre\VObject\Component\VCalendar; use Sabre\VObject\Reader; class OverrideFirstEventTest extends TestCase @@ -30,6 +31,7 @@ public function testOverrideFirstEvent() END:VCALENDAR ICS; + /** @var VCalendar $vcal */ $vcal = Reader::read($input); $vcal = $vcal->expand(new DateTime('2014-08-01'), new DateTime('2014-09-01')); @@ -90,6 +92,7 @@ public function testRemoveFirstEvent() END:VCALENDAR ICS; + /** @var VCalendar $vcal */ $vcal = Reader::read($input); $vcal = $vcal->expand(new DateTime('2014-08-01'), new DateTime('2014-08-19')); diff --git a/tests/VObject/VCardConverterTest.php b/tests/VObject/VCardConverterTest.php index ae2b10bd5..1c557bc10 100644 --- a/tests/VObject/VCardConverterTest.php +++ b/tests/VObject/VCardConverterTest.php @@ -41,6 +41,7 @@ public function testConvert30to40() END:VCARD OUT; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD40); @@ -78,6 +79,7 @@ public function testConvert40to40() OUT; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD40); @@ -116,6 +118,7 @@ public function testConvert21to40() OUT; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD40); @@ -155,6 +158,7 @@ public function testConvert30to30() OUT; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD30); @@ -195,6 +199,7 @@ public function testConvert40to30() OUT; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD30); @@ -223,6 +228,7 @@ public function testConvertGroupCard() OUT; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD40); @@ -240,6 +246,7 @@ public function testConvertGroupCard() OUT; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD30); @@ -268,6 +275,7 @@ public function testBDAYConversion() OUT; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD40); @@ -285,6 +293,7 @@ public function testBDAYConversion() OUT; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD30); @@ -314,6 +323,7 @@ public function testUnknownSourceVCardVersion() IN; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard->convert(Document::VCARD40); } @@ -329,6 +339,7 @@ public function testUnknownTargetVCardVersion() IN; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard->convert(Document::VCARD21); } @@ -351,6 +362,7 @@ public function testConvertIndividualCard() OUT; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD30); @@ -367,6 +379,7 @@ public function testConvertIndividualCard() OUT; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD40); @@ -396,6 +409,7 @@ public function testAnniversary() OUT; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD30); @@ -413,6 +427,7 @@ public function testAnniversary() $input, ]; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD40); @@ -450,6 +465,7 @@ public function testMultipleAnniversaries() OUT; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD30); @@ -467,6 +483,7 @@ public function testMultipleAnniversaries() $input, ]; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD40); @@ -495,6 +512,7 @@ public function testNoLabel() $vcard = $vcard->convert(Document::VCARD40); $vcard = $vcard->serialize(); + /** @var Component\VCard $converted */ $converted = Reader::read($vcard); $converted->validate(); @@ -536,6 +554,7 @@ public function testPhoneNumberValueTypeGetsRemoved() END:VCARD VCF; + /** @var Component\VCard $vcard */ $vcard = Reader::read($input); $vcard = $vcard->convert(Document::VCARD40); diff --git a/tests/phpunit.xml b/tests/phpunit.xml index c0588d460..b23b0375f 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -16,6 +16,9 @@ ../lib/ + + ../lib/PHPStan +