Completed
Push — master ( bde134...8948a0 )
by Alexey
36:43
created

JobQueue::laterUnique()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 5
1
<?php
2
3
namespace yiicod\jobqueue;
4
5
use Illuminate\Queue\Capsule\Manager;
6
use Yii;
7
use yii\base\BootstrapInterface;
8
use yii\base\Component;
9
use yiicod\jobqueue\connectors\MongoThreadConnector;
10
11
/**
12
 * Yii component for laravel 5 queues to work with mongodb
13
 *
14
 * @author Orlov Alexey <[email protected]>
15
 * @author Virchenko Maksim <[email protected]>
16
 */
17
class JobQueue extends Component implements BootstrapInterface
18
{
19
    /**
20
     * Available connections
21
     *
22
     * @var array
23
     */
24
    public $connections = [
25
        'thread' => [
26
            'driver' => 'mongo-thread',
27
            'table' => 'yii_jobs_thread',
28
            'queue' => 'default',
29
            'expire' => 60,
30
            'limit' => 15, // Or 1
31
            'connectionName' => 'thread',
32
        ],
33
    ];
34
35
    /**
36
     * Encryption key
37
     *
38
     * @var string
39
     */
40
    public $privateKey = 'rc5lgpue80sr17nx';
41
42
    /**
43
     * Manager instance
44
     *
45
     * @var
46
     */
47
    private $manager = null;
48
49
    /**
50
     * Initialize
51
     *
52
     * @param \yii\base\Application $app
53
     */
54
    public function bootstrap($app)
55
    {
56
        $this->connect();
57
    }
58
59
    /**
60
     * Connect queue manager for mongo database
61
     *
62
     * @author Virchenko Maksim <[email protected]>
63
     *
64
     * @return Manager
65
     */
66
    protected function connect()
67
    {
68
        $this->manager = new Manager();
69
70
        $this->manager->addConnector('mongo-thread', function () {
71
            return new MongoThreadConnector(Yii::$app->mongodb);
72
        });
73
74
        foreach ($this->connections as $name => $params) {
75
            $this->manager->addConnection($params, $name);
76
        }
77
78
        //Set as global to access
79
        $this->manager->setAsGlobal();
80
    }
81
82
    /**
83
     * Get queue manager instance
84
     *
85
     * @return mixed
86
     */
87
    public function getQueueManager()
88
    {
89
        return $this->manager->getQueueManager();
90
    }
91
92
    /**
93
     * Push new job to queue
94
     *
95
     * @author Virchenko Maksim <[email protected]>
96
     *
97
     * @param mixed $job
98
     * @param array $data
99
     * @param string $queue
100
     * @param string $connection
101
     *
102
     * @return mixed
103
     */
104
    public static function push($job, $data = [], $queue = 'default', $connection = 'default')
105
    {
106
        return Manager::push($job, $data, $queue, $connection);
107
    }
108
109
    /**
110
     * Push new job to queue if this job is not exist
111
     *
112
     * @author Virchenko Maksim <[email protected]>
113
     *
114
     * @param mixed $job
115
     * @param array $data
116
     * @param string $queue
117
     * @param string $connection
118
     *
119
     * @return mixed
120
     */
121
    public static function pushUnique($job, $data = [], $queue = 'default', $connection = 'default')
122
    {
123
        if (false === Manager::connection($connection)->exists($job, $data, $queue)) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Illuminate\Contracts\Queue\Queue as the method exists() does only exist in the following implementations of said interface: yiicod\jobqueue\queues\MongoThreadQueue.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
124
            return Manager::push($job, $data, $queue, $connection);
125
        }
126
127
        return null;
128
    }
129
130
    /**
131
     * Push a new an array of jobs onto the queue.
132
     *
133
     * @param  array $jobs
134
     * @param  mixed $data
135
     * @param  string $queue
136
     * @param  string $connection
137
     *
138
     * @return mixed
139
     */
140
    public static function bulk($jobs, $data = '', $queue = null, $connection = null)
141
    {
142
        return Manager::bulk($jobs, $data, $queue, $connection);
143
    }
144
145
    /**
146
     * Push a new job onto the queue after a delay.
147
     *
148
     * @param  \DateTime|int $delay
149
     * @param  string $job
150
     * @param  mixed $data
151
     * @param  string $queue
152
     * @param  string $connection
153
     *
154
     * @return mixed
155
     */
156
    public static function later($delay, $job, $data = '', $queue = null, $connection = null)
157
    {
158
        return Manager::later($delay, $job, $data, $queue, $connection);
159
    }
160
161
    /**
162
     * Push a new job into the queue after a delay if job does not exist.
163
     *
164
     * @param  \DateTime|int $delay
165
     * @param  string $job
166
     * @param  mixed $data
167
     * @param  string $queue
168
     * @param  string $connection
169
     *
170
     * @return mixed
171
     */
172
    public static function laterUnique($delay, $job, $data = '', $queue = null, $connection = null)
173
    {
174
        if (false === Manager::connection($connection)->exists($job, $data, $queue)) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Illuminate\Contracts\Queue\Queue as the method exists() does only exist in the following implementations of said interface: yiicod\jobqueue\queues\MongoThreadQueue.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
175
            return Manager::later($delay, $job, $data, $queue, $connection);
176
        }
177
178
        return null;
179
    }
180
}
181