Completed
Push — master ( b1d09d...2e1b8b )
by Tim
26s queued 10s
created

EventConfigurationService::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\Service;
6
7
use Exception;
8
use HDNET\Calendarize\Domain\Model\Configuration;
9
use HDNET\Calendarize\Ical\EventConfigurationInterface;
10
use HDNET\Calendarize\Utility\DateTimeUtility;
11
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
12
13
/**
14
 * Class EventConfigurationService.
15
 */
16
class EventConfigurationService extends AbstractService
17
{
18
    /**
19
     * Hydrates the calendarize configurations with the information from an imported event.
20
     * This adds or updates (depending on the importId) the configurations in the store.
21
     *
22
     * @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...
23
     * @param EventConfigurationInterface  $event
24
     * @param string                       $importId
25
     * @param int                          $pid
26
     */
27
    public function hydrateCalendarize(
28
        ObjectStorage $calendarize,
29
        EventConfigurationInterface $event,
30
        string $importId,
31
        int $pid
32
    ): void {
33
        $configuration = $this->getOrCreateConfiguration($calendarize, $importId);
34
35
        $configuration->setImportId($importId);
36
        $configuration->setPid($pid);
37
38
        $configuration->setType(Configuration::TYPE_TIME);
39
        $configuration->setHandling(Configuration::HANDLING_INCLUDE);
40
        $configuration->setState($event->getState());
41
        $configuration->setAllDay($event->isAllDay());
42
43
        $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...
44
        $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...
45
        $configuration->setStartTime($event->getStartTime());
46
        $configuration->setEndTime($event->getEndTime());
47
48
        $this->hydrateRecurringConfiguration($configuration, $event->getRRule());
49
    }
50
51
    /**
52
     * Get existing configuration with the matching import id or creates a new configuration and adds it to the store.
53
     *
54
     * @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...
55
     * @param string                       $importId
56
     *
57
     * @return Configuration
58
     */
59
    protected function getOrCreateConfiguration(ObjectStorage $calendarize, string $importId): Configuration
60
    {
61
        $configuration = false;
62
        // Get existing configuration if it matches the importId
63
        if (0 !== $calendarize->count()) {
64
            foreach ($calendarize as $item) {
65
                /** @var $item Configuration */
66
                if ($item->getImportId() === $importId) {
67
                    $configuration = $item;
68
                    break;
69
                }
70
            }
71
        }
72
        // Create configuration if not found / exists
73
        if (!$configuration) {
74
            $configuration = new Configuration();
75
            $configuration->setImportId($importId);
76
            $calendarize->attach($configuration);
77
        }
78
79
        return $configuration;
80
    }
81
82
    /**
83
     * Hydrates the configuration with recurrent configuration.
84
     * Invalid values are skipped.
85
     *
86
     * @param Configuration $configuration
87
     * @param array         $rrule
88
     */
89
    protected function hydrateRecurringConfiguration(Configuration $configuration, array $rrule): void
90
    {
91
        foreach ($rrule as $key => $value) {
92
            switch (strtoupper($key)) {
93
                case 'FREQ':
94
                    // The spelling of the frequency in RFC 5545 matches the constants in ConfigurationInterface.
95
                    // Currently only a subset of frequencies is implemented (missing "SECONDLY" / "MINUTELY" / "HOURLY")
96
                    $configuration->setFrequency(strtolower($value));
97
                    break;
98
                case 'UNTIL':
99
                    try {
100
                        $tillDate = new \DateTime($value);
101
                    } catch (Exception $e) {
102
                        break;
103
                    }
104
                    if ($tillDate <= $configuration->getStartDate()) {
105
                        break;
106
                    }
107
108
                    $configuration->setTillDate(DateTimeUtility::getDayStart($tillDate));
109
                    break;
110
                case 'INTERVAL':
111
                    $interval = (int)$value;
112
                    if ($interval < 1) {
113
                        break;
114
                    }
115
116
                    $configuration->setCounterInterval($interval);
117
                    break;
118
                case 'COUNT':
119
                    // RFC-5545 3.3.10:
120
                    // The COUNT rule part defines the number of occurrences at which to range-bound the recurrence.
121
                    // The "DTSTART" property value always counts as the first occurrence.
122
                    $count = (int)$value;
123
                    if ($count < 1) {
124
                        break;
125
                    }
126
127
                    // Since calendarize does not count the DTSTART as first occurrence, the count is decremented by one.
128
                    $configuration->setCounterAmount($count - 1);
129
                    break;
130
            }
131
        }
132
    }
133
}
134