Timer::onTick()   B
last analyzed

Complexity

Conditions 5
Paths 9

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 13
nc 9
nop 0
1
<?php
2
3
/*
4
 * This file is part of the Cubiche package.
5
 *
6
 * Copyright (c) Cubiche
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Cubiche\Core\Async\Loop\Timer;
13
14
use Cubiche\Core\Async\Promise\Deferred;
15
use Cubiche\Core\Async\Promise\DeferredInterface;
16
use Cubiche\Core\Delegate\Delegate;
17
use React\EventLoop\LoopInterface;
18
use React\EventLoop\Timer\TimerInterface as BaseTimerInterface;
19
20
/**
21
 * Timer Class.
22
 *
23
 * @author Karel Osorio Ramírez <[email protected]>
24
 */
25
class Timer implements TimerInterface
26
{
27
    /**
28
     * @var int
29
     */
30
    protected $maxIterations;
31
32
    /**
33
     * @var int
34
     */
35
    protected $iterations;
36
37
    /**
38
     * @var BaseTimerInterface
39
     */
40
    private $timer;
41
42
    /**
43
     * @var Delegate
44
     */
45
    private $task;
46
47
    /**
48
     * @var DeferredInterface
49
     */
50
    private $deferred = null;
51
52
    /**
53
     * @var mixed
54
     */
55
    private $lastResult;
56
57
    /**
58
     * @param LoopInterface $loop
59
     * @param callable      $task
60
     * @param int|float     $interval
61
     * @param bool          $periodic
62
     * @param int           $count
63
     *
64
     * @throws \InvalidArgumentException
65
     */
66
    public function __construct(LoopInterface $loop, callable $task, $interval, $periodic = false, $count = null)
67
    {
68
        $this->maxIterations = $count !== null ? (int) $count : ($periodic ? null : 1);
69
        if ($this->maxIterations !== null && $this->maxIterations <= 0) {
70
            throw new \InvalidArgumentException('The count argument must be a positive integer value');
71
        }
72
73
        $this->task = new Delegate($task);
74
        $this->iterations = 0;
75
        $onTick = function () {
76
            $this->onTick();
77
        };
78
        if ($periodic) {
79
            $this->timer = $loop->addPeriodicTimer($interval, $onTick);
80
        } else {
81
            $this->timer = $loop->addTimer($interval, $onTick);
82
        }
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88
    public function interval()
89
    {
90
        return $this->timer->getInterval();
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    public function iterations()
97
    {
98
        return $this->iterations;
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104
    public function maxIterations()
105
    {
106
        return $this->maxIterations;
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112
    public function isActive()
113
    {
114
        return $this->timer->isActive();
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    public function cancel()
121
    {
122
        $this->timer->cancel();
123
        $this->deferred()->cancel();
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129
    public function then(callable $onSucceed = null, callable $onRejected = null, callable $onNotify = null)
130
    {
131
        return $this->deferred()->promise()->then($onSucceed, $onRejected, $onNotify);
132
    }
133
134
    /**
135
     * {@inheritdoc}
136
     */
137
    public function done(callable $onSucceed = null, callable $onRejected = null, callable $onNotify = null)
138
    {
139
        $this->deferred()->promise()->done($onSucceed, $onRejected, $onNotify);
140
    }
141
142
    /**
143
     * {@inheritdoc}
144
     */
145
    public function otherwise(callable $onRejected)
146
    {
147
        return $this->deferred()->promise()->otherwise($onRejected);
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153
    public function always(callable $onFulfilledOrRejected, callable $notify = null)
154
    {
155
        return $this->deferred()->promise()->always($onFulfilledOrRejected, $notify);
156
    }
157
158
    /**
159
     * {@inheritdoc}
160
     */
161
    public function state()
162
    {
163
        return $this->deferred()->promise()->state();
164
    }
165
166
    /**
167
     * @return \Cubiche\Core\Async\Promise\Deferred
168
     */
169
    protected function deferred()
170
    {
171
        if ($this->deferred === null) {
172
            $this->deferred = new Deferred();
173
        }
174
175
        return $this->deferred;
176
    }
177
178
    /**
179
     */
180
    private function onTick()
181
    {
182
        try {
183
            $this->lastResult = $this->task->__invoke($this);
184
            ++$this->iterations;
185
            if ($this->timer->isPeriodic()) {
186
                $this->deferred()->notify($this->lastResult);
187
                if ($this->maxIterations() !== null && $this->iterations() >= $this->maxIterations()) {
188
                    $this->cancel();
189
                }
190
            } else {
191
                $this->deferred()->resolve($this->lastResult);
192
            }
193
        } catch (\Exception $e) {
194
            $this->deferred()->reject($e);
195
            $this->timer->cancel();
196
        }
197
    }
198
}
199