Completed
Push — master ( 849ee3...e6cfd0 )
by Vuong
04:11 queued 02:54
created

Async::batchRun()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 3
nc 3
nop 1
1
<?php
2
/**
3
 * @link https://github.com/vuongxuongminh/laravel-async
4
 *
5
 * @copyright (c) Vuong Xuong Minh
6
 * @license [MIT](https://opensource.org/licenses/MIT)
7
 */
8
9
namespace VXM\Async;
10
11
use Closure;
12
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
13
use Illuminate\Support\Str;
14
use Spatie\Async\Process\Runnable;
15
use VXM\Async\Runtime\ParentRuntime;
16
17
/**
18
 * @author Vuong Minh <[email protected]>
19
 * @since  1.0.0
20
 */
21
class Async
22
{
23
    /**
24
     * A pool manage async processes.
25
     *
26
     * @var Pool
27
     */
28
    protected $pool;
29
30
    /**
31
     * Event dispatcher manage async events.
32
     *
33
     * @var EventDispatcher
34
     */
35
    protected $events;
36
37
    /**
38
     * Create a new Async instance.
39
     *
40
     * @param \VXM\Async\Pool $pool
41
     * @param \Illuminate\Contracts\Events\Dispatcher $events
42
     */
43
    public function __construct(Pool $pool, EventDispatcher $events)
44
    {
45
        $this->pool = $pool;
46
        $this->events = $events;
47
    }
48
49
    /**
50
     * Execute async job.
51
     *
52
     * @param callable|string|object $job need to execute.
53
     * @param array $events event. Have key is an event name, value is a callable triggered when event
54
     *                                       happen, have three events `error`, `success`, `timeout`.
55
     *
56
     * @return static
57
     */
58
    public function run($job, array $events = []): self
59
    {
60
        $process = $this->createProcess($this->makeJob($job));
0 ignored issues
show
Documentation introduced by
$this->makeJob($job) is of type *, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
61
        $process->then($this->makeProcessListener('success', $process));
62
        $process->catch($this->makeProcessListener('error', $process));
63
        $process->timeout($this->makeProcessListener('timeout', $process));
64
        $this->addProcessListeners($events, $process);
65
        $this->pool->add($process);
0 ignored issues
show
Documentation introduced by
$process is of type object<Spatie\Async\Process\Runnable>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
66
67
        return $this;
68
    }
69
70
    /**
71
     * Batch execute async jobs.
72
     *
73
     * @param array $jobs
74
     * @return static
75
     * @see run()
76
     * @since 2.0.0
77
     */
78
    public function batchRun(...$jobs): self
79
    {
80
        foreach ($jobs as $job) {
81
            if (is_array($job)) {
82
                [$job, $events] = $job;
0 ignored issues
show
Bug introduced by
The variable $events does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
83
            } else {
84
                $events = [];
85
            }
86
87
            $this->run($job, $events);
88
        }
89
90
        return $this;
91
    }
92
93
    /**
94
     * Wait until all async jobs done and return job results.
95
     *
96
     * @return array
97
     */
98
    public function wait()
99
    {
100
        $results = $this->pool->wait();
101
        $this->pool->flush();
102
103
        return $results;
104
    }
105
106
    /**
107
     * Make async job.
108
     *
109
     * @param $job
110
     *
111
     * @return mixed
112
     */
113
    protected function makeJob($job)
114
    {
115
        if (is_string($job)) {
116
            return $this->createClassJob($job);
117
        }
118
119
        return $job;
120
    }
121
122
    /**
123
     * Create class and method job.
124
     *
125
     * @param string $job
126
     *
127
     * @return Closure
128
     */
129
    protected function createClassJob(string $job): Closure
130
    {
131
        [$class, $method] = Str::parseCallback($job, 'handle');
0 ignored issues
show
Bug introduced by
The variable $class does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $method does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
132
133
        return function () use ($class, $method) {
134
            return app()->call($class.'@'.$method);
135
        };
136
    }
137
138
    /**
139
     * Listen events of process given.
140
     *
141
     * @param array $events
142
     * @param Runnable $process
143
     */
144
    protected function addProcessListeners(array $events, Runnable $process): void
145
    {
146
        foreach ($events as $event => $callable) {
147
            $this->events->listen("async.{$event}_{$process->getId()}", $callable);
148
        }
149
    }
150
151
    /**
152
     * Make a base listener for integration with [[EventDispatcher]].
153
     *
154
     * @param string $event
155
     * @param Runnable $process
156
     *
157
     * @return callable
158
     */
159
    protected function makeProcessListener(string $event, Runnable $process): callable
160
    {
161
        return function (...$args) use ($event, $process) {
162
            $event = "async.{$event}_{$process->getId()}";
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $event, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
163
            $this->events->dispatch($event, $args);
164
            $this->events->forget($event);
165
        };
166
    }
167
168
    /**
169
     * Create a new process for run a job.
170
     *
171
     * @param callable $job need to execute.
172
     *
173
     * @return Runnable process.
174
     */
175
    protected function createProcess($job): Runnable
176
    {
177
        return ParentRuntime::createProcess($job);
178
    }
179
}
180