Completed
Pull Request — master (#284)
by Alex
03:09 queued 01:41
created

UpdateStats::getTimestamp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php declare(strict_types=1);
2
/*
3
 * This file is part of the feed-io package.
4
 *
5
 * (c) Alexandre Debril <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace FeedIo\Reader\Result;
12
13
use FeedIo\Feed\ItemInterface;
14
use FeedIo\FeedInterface;
15
16
class UpdateStats
17
{
18
    const DEFAULT_MIN_DELAY = 3600;
19
20
    const DEFAULT_STALLED_DELAY = 86400;
21
22
    const DEFAULT_MARGIN_RATIO = 0.1;
23
24
    /**
25
     * @var FeedInterface
26
     */
27
    protected $feed;
28
29
    /**
30
     * @var array
31
     */
32
    protected $intervals;
33
34
    /**
35
     * UpdateStats constructor.
36
     * @param FeedInterface $feed
37
     */
38 2
    public function __construct(FeedInterface $feed)
39
    {
40 2
        $this->feed = $feed;
41 2
        $this->intervals = $this->computeIntervals($this->extractDates($feed));
42 2
    }
43
44
    /**
45
     * @param int $minDelay
46
     * @param int $stalledDelay
47
     * @param float $marginRatio
48
     * @return \DateTime
49
     */
50 2
    public function computeNextUpdate(
51
        int $minDelay = self::DEFAULT_MIN_DELAY,
52
        int $stalledDelay = self::DEFAULT_STALLED_DELAY,
53
        float $marginRatio = self::DEFAULT_MARGIN_RATIO
54
    ): \DateTime {
55 2
        if ($this->isStalled($marginRatio)) {
56 1
            return (new \DateTime())->setTimestamp(time() + $stalledDelay);
57
        }
58 1
        $feedTimeStamp = $this->getFeedTimestamp();
59 1
        $now = time();
60
        $intervals = [
61 1
            $this->getMinInterval(),
62 1
            $this->getAverageInterval(),
63 1
            $this->getMedianInterval(),
64
        ];
65 1
        sort($intervals);
66 1
        $newTimestamp = $now + $minDelay;
67 1
        foreach ($intervals as $interval) {
68 1
            $computedTimestamp = $this->addInterval($feedTimeStamp, $interval, $marginRatio);
69 1
            if ($computedTimestamp > $now) {
70 1
                $newTimestamp = $computedTimestamp;
71 1
                break;
72
            }
73
        }
74 1
        return (new \DateTime())->setTimestamp($newTimestamp);
75
    }
76
77 2
    public function isStalled(float $marginRatio): bool
78
    {
79 2
        return time() > $this->addInterval($this->getFeedTimestamp(), $this->getMaxInterval(), $marginRatio);
80
    }
81
82 2
    public function addInterval(int $ts, int $interval, float $marginRatio): int
83
    {
84 2
        return $ts + intval($interval + $marginRatio * $interval);
85
    }
86
87
    /**
88
     * @return array
89
     */
90 2
    public function getIntervals(): array
91
    {
92 2
        return $this->intervals;
93
    }
94
95
    /**
96
     * @return int
97
     */
98 1
    public function getMinInterval(): int
99
    {
100 1
        return min($this->intervals);
101
    }
102
103
    /**
104
     * @return int
105
     */
106 2
    public function getMaxInterval(): int
107
    {
108 2
        return max($this->intervals);
109
    }
110
111
    /**
112
     * @return int
113
     */
114 1
    public function getAverageInterval(): int
115
    {
116 1
        $total = array_sum($this->intervals);
117
118 1
        return intval(floor($total / count($this->intervals)));
119
    }
120
121
    /**
122
     * @return int
123
     */
124 1
    public function getMedianInterval(): int
125
    {
126 1
        sort($this->intervals);
127 1
        $num = floor(count($this->intervals) / 2);
128
129 1
        return $this->intervals[$num];
130
    }
131
132 2
    private function computeIntervals(array $dates): array
133
    {
134 2
        rsort($dates);
135 2
        $intervals = [];
136 2
        $current = 0;
137 2
        foreach ($dates as $date) {
138 2
            if ($current > 0) {
139 2
                $intervals[] = $current - $date;
140
            }
141 2
            $current = $date;
142
        }
143 2
        return $intervals;
144
    }
145
146 2
    private function extractDates(FeedInterface $feed): array
147
    {
148 2
        $dates = [];
149 2
        foreach ($feed as $item) {
150 2
            $dates[] = $this->getTimestamp($item);
151
        }
152 2
        return $dates;
153
    }
154
155 2
    private function getTimestamp(ItemInterface $item): ? int
156
    {
157 2
        return $item->getLastModified()->getTimestamp();
158
    }
159
160 2
    private function getFeedTimestamp(): int
161
    {
162 2
        return !! $this->feed->getLastModified() ? $this->feed->getLastModified()->getTimestamp():time();
163
    }
164
}
165