Completed
Pull Request — master (#3)
by Valentin
09:28 queued 06:18
created

Extract::fillGaps()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 9.2
c 0
b 0
f 0
cc 3
eloc 14
nc 2
nop 4
1
<?php
2
3
namespace Spiral\Statistics;
4
5
use Spiral\Statistics\Database\Sources\StatisticsSource;
6
use Spiral\Statistics\Database\Statistics;
7
use Spiral\Statistics\Exceptions\EmptyExtractEventsException;
8
use Spiral\Statistics\Extract\Range;
9
use Spiral\Statistics\Extract\Events;
10
use Spiral\Statistics\Extract\RangeInterface;
11
12
class Extract
13
{
14
    /** @var StatisticsSource */
15
    protected $source;
16
17
    /** @var DatetimeConverter */
18
    protected $converter;
19
20
    /**
21
     * Extract constructor.
22
     *
23
     * @param DatetimeConverter $converter
24
     * @param StatisticsSource  $source
25
     */
26
    public function __construct(
27
        DatetimeConverter $converter,
28
        StatisticsSource $source
29
    ) {
30
        $this->source = $source;
31
        $this->converter = $converter;
32
    }
33
34
    /**
35
     * Extract listed events inside given timeframe.
36
     *
37
     * @param \DateTimeInterface $start
38
     * @param \DateTimeInterface $end
39
     * @param RangeInterface     $range
40
     * @param array              $eventsInput
41
     * @return Events
42
     */
43
    public function events(
44
        \DateTimeInterface $start,
45
        \DateTimeInterface $end,
46
        RangeInterface $range,
47
        array $eventsInput
48
    ): Events
49
    {
50
        if (empty($eventsInput)) {
51
            throw new EmptyExtractEventsException();
52
        }
53
54
        $start = $this->converter->immutable($start);
55
        $end = $this->converter->immutable($end);
56
57
        //Swap start and end dates if incorrect
58
        if ($start > $end) {
59
            list($start, $end) = [$end, $start];
60
        }
61
62
        $events = new Events($eventsInput);
63
64
        $queried = $this->source->findExtract($start, $end, $eventsInput);
65
        $lastDatetime = clone $start;
66
        $row = $events->addRow($start->format($range->getFormat()));
67
68
        /** @var Statistics $extracted */
69
        foreach ($queried as $extracted) {
70
            $row = $this->fillGaps($lastDatetime, $extracted->timestamp, $events, $range) ?? $row;
71
72
            $row->addEvent($extracted->name, $extracted->value);
73
        }
74
75
        $this->fillGaps($lastDatetime, $end, $events, $range);
76
77
        return $events;
78
    }
79
80
    /**
81
     * Add blank rows if between passed current datetime and passed end datetime can be placed
82
     * blank rows without any events occurred. Return result is last filled row if gaps were
83
     * filled or null.
84
     *
85
     * @param \DateTimeInterface|\DateTimeImmutable $current
86
     * @param \DateTimeInterface                    $end
87
     * @param Events                                $events
88
     * @param RangeInterface                        $range
89
     * @return Events\Row|null
90
     */
91
    protected function fillGaps(
92
        \DateTimeInterface &$current,
93
        \DateTimeInterface $end,
94
        Events $events,
95
        RangeInterface $range
96
    ) {
97
        $lastRow = null;
98
        $lastDatetimeConverted = $this->converter->convert($current, $range);
99
        $endDatetimeConverted = $this->converter->convert($end, $range);
100
101
        if ($lastDatetimeConverted < $endDatetimeConverted) {
102
            //one of next intervals, need to add blank rows;
103
            while ($lastDatetimeConverted < $endDatetimeConverted) {
104
                $current = $current->add($range->getInterval());
105
                $lastDatetimeConverted = $this->converter->convert($current, $range);
106
107
                $lastRow = $events->addRow($current->format($range->getFormat()));
108
            }
109
        }
110
111
        return $lastRow;
112
    }
113
}