Completed
Pull Request — master (#475)
by
unknown
02:00
created

EventConfigurationUtility::hydrateCalendarize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.552
c 0
b 0
f 0
cc 1
nc 1
nop 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace HDNET\Calendarize\Utility;
6
7
use Exception;
8
use HDNET\Calendarize\Domain\Model\Configuration;
9
use HDNET\Calendarize\Ical\EventConfigurationInterface;
10
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
11
12
/**
13
 * Class EventConfigurationUtility.
14
 */
15
class EventConfigurationUtility
16
{
17
    /**
18
     * @param ObjectStorage<Configuration> $calendarize
0 ignored issues
show
Documentation introduced by
The doc-type ObjectStorage<Configuration> could not be parsed: Expected "|" or "end of type", but got "<" at position 13. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
19
     * @param EventConfigurationInterface  $event
20
     * @param string                       $importId
21
     * @param int                          $pid
22
     */
23
    public static function hydrateCalendarize(
24
        ObjectStorage $calendarize,
25
        EventConfigurationInterface $event,
26
        string $importId,
27
        int $pid
28
    ): void {
29
        $configuration = self::getOrCreateConfiguration($calendarize, $importId);
30
31
        $configuration->setImportId($importId);
32
        $configuration->setPid($pid);
33
34
        $configuration->setType(Configuration::TYPE_TIME);
35
        $configuration->setHandling(Configuration::HANDLING_INCLUDE);
36
        $configuration->setState($event->getState());
37
        $configuration->setAllDay($event->isAllDay());
38
39
        $configuration->setStartDate($event->getStartDate());
0 ignored issues
show
Bug introduced by
It seems like $event->getStartDate() can be null; however, setStartDate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
40
        $configuration->setEndDate($event->getEndDate());
0 ignored issues
show
Bug introduced by
It seems like $event->getEndDate() can be null; however, setEndDate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
41
        $configuration->setStartTime($event->getStartTime());
42
        $configuration->setEndTime($event->getEndTime());
43
44
        self::hydrateRecurringConfiguration($configuration, $event->getRRule());
45
    }
46
47
    /**
48
     * Get existing configuration with the matching import id or creates a new configuration and adds it to the store.
49
     *
50
     * @param ObjectStorage<Configuration> $calendarize
0 ignored issues
show
Documentation introduced by
The doc-type ObjectStorage<Configuration> could not be parsed: Expected "|" or "end of type", but got "<" at position 13. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
51
     * @param string                       $importId
52
     *
53
     * @return Configuration
54
     */
55
    protected static function getOrCreateConfiguration(ObjectStorage $calendarize, string $importId): Configuration
56
    {
57
        $configuration = false;
58
        // Get existing configuration if it matches the importId
59
        if (0 !== $calendarize->count()) {
60
            foreach ($calendarize as $item) {
61
                /** @var $item Configuration */
62
                if ($item->getImportId() === $importId) {
63
                    $configuration = $item;
64
                    break;
65
                }
66
            }
67
        }
68
        // Create configuration if not found / exists
69
        if (!$configuration) {
70
            $configuration = new Configuration();
71
            $configuration->setImportId($importId);
72
            $calendarize->attach($configuration);
73
        }
74
75
        return $configuration;
76
    }
77
78
    /**
79
     * Hydrates the configuration with recurrent configuration.
80
     *
81
     * @param Configuration $configuration
82
     * @param array         $rrule
83
     */
84
    protected static function hydrateRecurringConfiguration(Configuration $configuration, array $rrule): void
85
    {
86
        foreach ($rrule as $key => $value) {
87
            switch (strtoupper($key)) {
88
                case 'FREQ':
89
                    // The spelling of the frequency in RFC 5545 matches the constants in ConfigurationInterface.
90
                    // Currently only a subset of frequencies is implemented (missing "SECONDLY" / "MINUTELY" / "HOURLY")
91
                    $configuration->setFrequency(strtolower($value));
92
                    break;
93
                case 'UNTIL':
94
                    try {
95
                        $tillDate = new \DateTime($value);
96
                    } catch (Exception $e) {
97
                        break;
98
                    }
99
                    if ($tillDate <= $configuration->getStartDate()) {
100
                        break;
101
                    }
102
103
                    $configuration->setTillDate(DateTimeUtility::getDayStart($tillDate));
104
                    break;
105
                case 'INTERVAL':
106
                    $interval = (int)$value;
107
                    if ($interval < 1) {
108
                        break;
109
                    }
110
111
                    $configuration->setCounterInterval($interval);
112
                    break;
113
                case 'COUNT':
114
                    // RFC-5545 3.3.10:
115
                    // The COUNT rule part defines the number of occurrences at which to range-bound the recurrence.
116
                    // The "DTSTART" property value always counts as the first occurrence.
117
                    $count = (int)$value;
118
                    if ($count < 1) {
119
                        break;
120
                    }
121
122
                    // Since calendarize does not count the DTSTART as first occurrence, the count is decremented by one.
123
                    $configuration->setCounterAmount($count - 1);
124
                    break;
125
            }
126
        }
127
    }
128
}
129