Completed
Push — master ( 298e09...565401 )
by Ivannis Suárez
02:36
created

Timer   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 166
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 22
c 1
b 0
f 0
lcom 1
cbo 3
dl 0
loc 166
rs 10

12 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 18 6
A interval() 0 4 1
A iterations() 0 4 1
A maxIterations() 0 4 1
A isActive() 0 4 1
A cancel() 0 5 1
A then() 0 4 1
A otherwise() 0 4 1
A always() 0 4 1
A state() 0 4 1
A deferred() 0 8 2
B onTick() 0 18 5
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 ? $periodic : 1);
0 ignored issues
show
Documentation Bug introduced by
It seems like $count !== null ? (int) ...riodic ? $periodic : 1) can also be of type boolean. However, the property $maxIterations is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
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 otherwise(callable $catch)
138
    {
139
        return $this->deferred()->promise()->otherwise($catch);
140
    }
141
142
    /**
143
     * {@inheritdoc}
144
     */
145
    public function always(callable $finally, callable $notify = null)
146
    {
147
        return $this->deferred()->promise()->always($finally, $notify);
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153
    public function state()
154
    {
155
        return $this->deferred()->promise()->state();
156
    }
157
158
    /**
159
     * @return \Cubiche\Core\Async\Promise\Deferred
160
     */
161
    protected function deferred()
162
    {
163
        if ($this->deferred === null) {
164
            $this->deferred = new Deferred();
165
        }
166
167
        return $this->deferred;
168
    }
169
170
    /**
171
     */
172
    private function onTick()
173
    {
174
        try {
175
            ++$this->iterations;
176
            $this->lastResult = $this->task->__invoke();
177
            if ($this->timer->isPeriodic()) {
178
                $this->deferred()->notify($this->lastResult);
179
                if ($this->maxIterations() !== null && $this->iterations() >= $this->maxIterations()) {
180
                    $this->cancel();
181
                }
182
            } else {
183
                $this->deferred()->resolve($this->lastResult);
184
            }
185
        } catch (\Exception $e) {
186
            $this->deferred()->reject($e);
187
            $this->timer->cancel();
188
        }
189
    }
190
}
191