Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,22 @@ jobs:
strategy:
fail-fast: false
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3', '8.4']
php-versions: ['8.3', '8.4']
coverage: ['pcov']
code-style: ['no']
code-analysis: ['no']
rector-check: ['no']
include:
- php-versions: '7.4'
- php-versions: '8.2'
coverage: 'pcov'
code-style: 'yes'
code-analysis: 'yes'
rector-check: 'no'
- php-versions: '8.5'
coverage: 'pcov'
code-style: 'no'
code-analysis: 'yes'
rector-check: 'yes'
steps:
- name: Checkout
uses: actions/checkout@v6
Expand Down Expand Up @@ -61,6 +64,10 @@ jobs:
if: matrix.code-analysis == 'yes'
run: composer phpstan

- name: Code Refactoring (rector)
if: matrix.rector-check == 'yes'
run: composer rector-check

- name: Test with phpunit
run: vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-clover clover.xml

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ vendor/
composer.lock
tests/cov/
tests/temp
tests/.phpunit.cache
tests/.phpunit.result.cache

# Development stuff
Expand Down
28 changes: 23 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,20 @@
"homepage" : "http://sabre.io/vobject/",
"license" : "BSD-3-Clause",
"require" : {
"php" : "^7.4 || ^8.0",
"php" : "^8.2",
"ext-mbstring" : "*",
"ext-json" : "*",
"sabre/xml" : "^3.0 || ^4.0"
},
"require-dev" : {
"friendsofphp/php-cs-fixer": "^3.94",
"phpunit/phpunit" : "^9.6",
"phpunit/php-invoker" : "^2.0 || ^3.1",
"phpstan/phpstan": "^2.1"
"friendsofphp/php-cs-fixer": "^3.95",
"phpstan/phpstan": "^2.2",
"phpstan/phpstan-phpunit": "^2.0",
"phpstan/phpstan-strict-rules": "^2.0",
"phpstan/extension-installer": "^1.4",
"phpunit/phpunit": "^11.5",
"phpunit/php-invoker" : "^5.0",
"rector/rector": "^2.4"
},
"suggest" : {
"hoa/bench" : "If you would like to run the benchmark scripts"
Expand Down Expand Up @@ -96,6 +100,12 @@
"cs-fixer": [
"PHP_CS_FIXER_IGNORE_ENV=true php-cs-fixer fix"
],
"rector-check": [
"rector process --dry-run"
],
"rector-fix": [
"rector process"
],
"phpunit": [
"phpunit --configuration tests/phpunit.xml"
],
Expand All @@ -104,5 +114,13 @@
"composer cs-fixer",
"composer phpunit"
]
},
"config": {
"allow-plugins": {
"phpstan/extension-installer": true
},
"platform": {
"php": "8.2"
}
}
}
4 changes: 2 additions & 2 deletions lib/BirthdayCalendarGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public function getResult(): VCalendar
// We've seen clients (ez-vcard) putting "BDAY:" properties
// without a value into vCards. If we come across those, we'll
// skip them.
if (empty($object->BDAY->getValue())) {
if ('' === $object->BDAY->getValue()) {
continue;
}

Expand All @@ -116,7 +116,7 @@ public function getResult(): VCalendar
// Skip if we can't parse the BDAY value.
try {
$dateParts = DateTimeParser::parseVCardDateTime($object->BDAY->getValue());
} catch (InvalidDataException $e) {
} catch (InvalidDataException) {
continue;
}

Expand Down
80 changes: 25 additions & 55 deletions lib/Cli.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public function main(array $argv): int
// @codeCoverageIgnoreEnd

try {
list($options, $positional) = $this->parseArguments($argv);
[$options, $positional] = $this->parseArguments($argv);

if (isset($options['q'])) {
$this->quiet = true;
Expand All @@ -110,27 +110,10 @@ public function main(array $argv): int

return 0;
case 'format':
switch ($value) {
// jcard/jcal documents
case 'jcard':
case 'jcal':
// specific document versions
case 'vcard21':
case 'vcard30':
case 'vcard40':
case 'icalendar20':
// specific formats
case 'json':
case 'mimedir':
// icalendar/vcard
case 'icalendar':
case 'vcard':
$this->format = $value;
break;

default:
throw new \InvalidArgumentException('Unknown format: '.$value);
}
$this->format = match ($value) {
'jcard', 'jcal', 'vcard21', 'vcard30', 'vcard40', 'icalendar20', 'json', 'mimedir', 'icalendar', 'vcard' => $value,
default => throw new \InvalidArgumentException('Unknown format: '.$value),
};
break;
case 'pretty':
$this->pretty = true;
Expand All @@ -139,28 +122,11 @@ public function main(array $argv): int
$this->forgiving = true;
break;
case 'inputformat':
switch ($value) {
// json formats
case 'jcard':
case 'jcal':
case 'json':
$this->inputFormat = 'json';
break;

// mimedir formats
case 'mimedir':
case 'icalendar':
case 'vcard':
case 'vcard21':
case 'vcard30':
case 'vcard40':
case 'icalendar20':
$this->inputFormat = 'mimedir';
break;

default:
throw new \InvalidArgumentException('Unknown format: '.$value);
}
$this->inputFormat = match ($value) {
'jcard', 'jcal', 'json' => 'json',
'mimedir', 'icalendar', 'vcard', 'vcard21', 'vcard30', 'vcard40', 'icalendar20' => 'mimedir',
default => throw new \InvalidArgumentException('Unknown format: '.$value),
};
break;
default:
throw new \InvalidArgumentException('Unknown option: '.$name);
Expand All @@ -181,7 +147,7 @@ public function main(array $argv): int
throw new \InvalidArgumentException('Too many arguments');
}

if (!in_array($positional[0], ['validate', 'repair', 'convert', 'color'])) {
if (!in_array($positional[0], ['validate', 'repair', 'convert', 'color'], true)) {
throw new \InvalidArgumentException('Unknown command: '.$positional[0]);
}
} catch (\InvalidArgumentException $e) {
Expand All @@ -201,14 +167,14 @@ public function main(array $argv): int
}

if (null === $this->inputFormat) {
if ('.json' === substr($this->inputPath, -5)) {
if (str_ends_with($this->inputPath, '.json')) {
$this->inputFormat = 'json';
} else {
$this->inputFormat = 'mimedir';
}
}
if (null === $this->format) {
if ('.json' === substr($this->outputPath, -5)) {
if (str_ends_with($this->outputPath, '.json')) {
$this->format = 'json';
} else {
$this->format = 'mimedir';
Expand All @@ -219,12 +185,13 @@ public function main(array $argv): int

try {
while ($input = $this->readInput()) {
// @phpstan-ignore method.dynamicName
$returnCode = $this->$command($input);
if (0 !== $returnCode) {
$realCode = $returnCode;
}
}
} catch (EofException $e) {
} catch (EofException) {
// end of file
} catch (\Exception $e) {
$this->log('Error: '.$e->getMessage(), 'red');
Expand Down Expand Up @@ -408,7 +375,7 @@ protected function convert(Component $vObj): int
}
fwrite($this->stdout, json_encode($vObj->jsonSerialize(), $jsonOptions));
} else {
fwrite($this->stdout, $vObj->serialize());
fwrite($this->stdout, (string) $vObj->serialize());
}

return 0;
Expand Down Expand Up @@ -538,7 +505,7 @@ protected function serializeProperty(Property $property): void
$this->cWrite('red', ':');

if ($property instanceof Property\Binary) {
$this->cWrite('default', 'embedded binary stripped. ('.strlen($property->getValue()).' bytes)');
$this->cWrite('default', 'embedded binary stripped. ('.strlen((string) $property->getValue()).' bytes)');
} else {
$parts = $property->getParts();
$first1 = true;
Expand Down Expand Up @@ -593,17 +560,17 @@ protected function parseArguments(array $argv): array

$v = $argv[$ii];

if ('--' === substr($v, 0, 2)) {
if (str_starts_with((string) $v, '--')) {
// This is a long-form option.
$optionName = substr($v, 2);
$optionName = substr((string) $v, 2);
$optionValue = true;
if (strpos($optionName, '=')) {
list($optionName, $optionValue) = explode('=', $optionName);
[$optionName, $optionValue] = explode('=', $optionName);
}
$options[$optionName] = $optionValue;
} elseif ('-' === substr($v, 0, 1) && strlen($v) > 1) {
} elseif (str_starts_with((string) $v, '-') && strlen((string) $v) > 1) {
// This is a short-form option.
foreach (str_split(substr($v, 1)) as $option) {
foreach (str_split(substr((string) $v, 1)) as $option) {
$options[$option] = true;
}
} else {
Expand All @@ -628,6 +595,9 @@ protected function readInput(): ?Document
if (!$this->parser) {
if ('-' !== $this->inputPath) {
$this->stdin = fopen($this->inputPath, 'r');
if (false === $this->stdin) {
throw new InvalidDataException('Cannot open "'.$this->inputPath);
}
}

if ('mimedir' === $this->inputFormat) {
Expand Down
16 changes: 7 additions & 9 deletions lib/Component.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public function remove($item): void
// 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, '.')) {
if (!str_contains($item, '.')) {
unset($this->children[strtoupper($item)]);

return;
Expand Down Expand Up @@ -210,8 +210,8 @@ public function select(string $name): array
{
$group = null;
$name = strtoupper($name);
if (false !== strpos($name, '.')) {
list($group, $name) = explode('.', $name, 2);
if (str_contains($name, '.')) {
[$group, $name] = explode('.', $name, 2);
}
if ('' === $name) {
$name = null;
Expand All @@ -228,9 +228,7 @@ public function select(string $name): array
// more.
return array_filter(
$result,
function ($child) use ($group) {
return $child instanceof Property && (null !== $child->group ? strtoupper($child->group) : '') === $group;
}
fn ($child) => $child instanceof Property && (null !== $child->group ? strtoupper($child->group) : '') === $group
);
}

Expand Down Expand Up @@ -368,7 +366,7 @@ public function xmlSerialize(Xml\Writer $writer): void

$writer->startElement(strtolower($this->name));

if (!empty($properties)) {
if ([] !== $properties) {
$writer->startElement('properties');

foreach ($properties as $property) {
Expand All @@ -378,7 +376,7 @@ public function xmlSerialize(Xml\Writer $writer): void
$writer->endElement();
}

if (!empty($components)) {
if ([] !== $components) {
$writer->startElement('components');

foreach ($components as $component) {
Expand Down Expand Up @@ -541,7 +539,7 @@ public function validate(int $options = 0): array
$messages = [];

foreach ($this->children() as $child) {
$name = strtoupper($child->name);
$name = strtoupper((string) $child->name);
if (!isset($propertyCounters[$name])) {
$propertyCounters[$name] = 1;
} else {
Expand Down
4 changes: 2 additions & 2 deletions lib/Component/VAlarm.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ class VAlarm extends VObject\Component
public function getEffectiveTriggerTime(): \DateTimeImmutable
{
$trigger = $this->TRIGGER;
if (!isset($trigger['VALUE']) || ($trigger['VALUE'] && 'DURATION' === strtoupper($trigger['VALUE']))) {
if (!isset($trigger['VALUE']) || ($trigger['VALUE'] && 'DURATION' === strtoupper((string) $trigger['VALUE']))) {
$triggerDuration = VObject\DateTimeParser::parseDuration($this->TRIGGER);
$related = (isset($trigger['RELATED']) && 'END' == strtoupper($trigger['RELATED'])) ? 'END' : 'START';
$related = (isset($trigger['RELATED']) && 'END' === strtoupper($trigger['RELATED'])) ? 'END' : 'START';

/** @var VEvent|VTodo $parentComponent */
$parentComponent = $this->parent;
Expand Down
2 changes: 1 addition & 1 deletion lib/Component/VAvailability.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class VAvailability extends VObject\Component
*/
public function isInTimeRange(\DateTimeInterface $start, \DateTimeInterface $end): bool
{
list($effectiveStart, $effectiveEnd) = $this->getEffectiveStartEnd();
[$effectiveStart, $effectiveEnd] = $this->getEffectiveStartEnd();

return
(is_null($effectiveStart) || $start < $effectiveEnd)
Expand Down
4 changes: 2 additions & 2 deletions lib/Component/VCalendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ public function expand(\DateTimeInterface $start, \DateTimeInterface $end, ?\Dat
foreach ($recurringEvents as $events) {
try {
$it = new EventIterator($events, null, $timeZone);
} catch (NoInstancesException $e) {
} catch (NoInstancesException) {
// This event is recurring, but it doesn't have a single
// instance. We are skipping this event from the output
// entirely.
Expand Down Expand Up @@ -424,7 +424,7 @@ public function validate(int $options = 0): array
if ($child instanceof Component) {
++$componentsFound;

if (!in_array($child->name, ['VEVENT', 'VTODO', 'VJOURNAL'])) {
if (!in_array($child->name, ['VEVENT', 'VTODO', 'VJOURNAL'], true)) {
continue;
}
$componentTypes[] = $child->name;
Expand Down
Loading