Passed
Push — master ( 7e5c9a...4e2d24 )
by Valentin
03:59
created

Pheanstalk::create()   A

Complexity

Conditions 3
Paths 5

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 10
c 1
b 0
f 0
dl 0
loc 16
ccs 10
cts 10
cp 1
rs 9.9332
cc 3
nc 5
nop 2
crap 3
1
<?php
2
3
namespace Pheanstalk;
4
5
use Doctrine\Common\Collections\ArrayCollection;
6
use Pheanstalk\Command\CreateCommand;
7
use Pheanstalk\Command\CreateScheduleCommand;
8
use Pheanstalk\Command\CreateTubeCommand;
9
use Pheanstalk\Command\GetWorkflowCommand;
10
use Pheanstalk\Command\GetWorkflowInstancesCommand;
11
use Pheanstalk\Command\GetWorkflowInstancesDetailCommand;
12
use Pheanstalk\Command\ListWorkflowsCommand;
13
use Pheanstalk\Command\ReleaseCommand;
0 ignored issues
show
Bug introduced by
The type Pheanstalk\Command\ReleaseCommand was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
use Pheanstalk\Command\UpdateTubeCommand;
15
use Pheanstalk\Command\WorkflowExistsCommand;
16
use Pheanstalk\Exception\ServerDuplicateEntryException;
17
use Pheanstalk\Structure\Job;
18
use Pheanstalk\Structure\Schedule;
19
use Pheanstalk\Structure\Task;
20
use Pheanstalk\Structure\TaskInstance;
21
use Pheanstalk\Structure\TimeSchedule;
22
use Pheanstalk\Structure\Tube;
23
use Pheanstalk\Structure\Workflow;
24
use Pheanstalk\Structure\WorkflowInstance;
25
26
/**
27
 * Pheanstalk is a PHP client for the beanstalkd workqueue.
28
 *
29
 * The Pheanstalk class is a simple facade for the various underlying components.
30
 *
31
 * @see http://github.com/kr/beanstalkd
32
 * @see http://xph.us/software/beanstalkd/
33
 *
34
 * @author  Paul Annesley
35
 * @package Pheanstalk
36
 * @license http://www.opensource.org/licenses/mit-license.php
37
 */
38
class Pheanstalk implements PheanstalkInterface
39
{
40
41
    /** @var Connection $connection */
42
    private $connection;
43
44
    /** @var PheanstalkInterface $currentClass */
45
    private $currentClass;
46
47
    /**
48
     * @param string $host
49
     * @param string $user
50
     * @param string $password
51
     * @param int    $port
52
     * @param int    $connectTimeout
53
     * @param bool   $connectPersistent
54
     */
55 21
    public function __construct($host, $user = null, $password = null, $port = PheanstalkInterface::DEFAULT_PORT, $connectTimeout = null, $connectPersistent = false)
56
    {
57 21
        $this->setConnection(new Connection($host, $user, $password, $port, $connectTimeout, $connectPersistent));
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63 21
    public function setConnection(Connection $connection)
64
    {
65 21
        $this->connection = $connection;
66
67 21
        return $this;
68
    }
69
70
    /**
71
     * {@inheritdoc}
72
     */
73 2
    public function getConnection()
74
    {
75 2
        return $this->connection;
76
    }
77
78
    /**
79
     * @return PheanstalkInterface
80
     */
81 14
    public function getCurrentClass(): PheanstalkInterface
82
    {
83 14
        return $this->currentClass ?? $this;
84
    }
85
86
    /**
87
     * @param PheanstalkInterface $currentClass
88
     *
89
     * @return Pheanstalk
90
     */
91 1
    public function setCurrentClass(PheanstalkInterface $currentClass): PheanstalkInterface
92
    {
93 1
        $this->currentClass = $currentClass;
94 1
        return $this;
95
    }
96
97
    // ----------------------------------------
98
99
    /**
100
     * {@inheritdoc}
101
     */
102 1
    public function deleteSchedule(Schedule $schedule)
103
    {
104 1
        return $this->_dispatch(new Command\DeleteScheduleCommand($schedule));
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110 6
    public function delete(Workflow $workflow)
111
    {
112 6
        return $this->_dispatch(new Command\DeleteCommand($workflow));
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118 1
    public function deleteTube(Tube $tube)
119
    {
120 1
        return $this->_dispatch(new Command\DeleteTubeCommand($tube));
121
    }
122
123
    /**
124
     * {@inheritdoc}
125
     */
126 8
    public function workflowExists($name)
127
    {
128 8
        $workflow = $this->_dispatch(new Command\WorkflowExistsCommand($name));
129 7
        if ($workflow instanceof Workflow) {
130 7
            return $this->getCurrentClass()->getWorkflow($workflow);
131
        }
132 1
        return false;
133
    }
134
135
    /**
136
     * {@inheritdoc}
137
     */
138 1
    public function getSchedule(int $scheduleId)
139
    {
140 1
        return $this->_dispatch(new Command\GetScheduleCommand($scheduleId));
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146 1
    public function listSchedules()
147
    {
148 1
        return $this->_dispatch(new Command\ListSchedulesCommand());
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     */
154 7
    public function getWorkflow(Workflow $workflow)
155
    {
156 7
        return $this->_dispatch(new Command\GetWorkflowCommand($workflow));
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162 5
    public function getWorkflowInstances(?Workflow $workflow, string $status = null)
163
    {
164 5
        $paramsStatus = empty($status) ? GetWorkflowInstancesDetailCommand::FILTERS : [$status];
165 5
        $instances = new ArrayCollection([]);
166 5
        foreach ($paramsStatus as $stat) {
167 5
            $instances[strtolower($stat)] = $this->_dispatch(new Command\GetWorkflowInstancesCommand($workflow, $stat));
168
                /** @var ArrayCollection $workflowCollection */
169 5
                $workflowCollection = $instances[strtolower($stat)]->get('workflow_instances');
0 ignored issues
show
Bug introduced by
The method get() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

169
                /** @scrutinizer ignore-call */ 
170
                $workflowCollection = $instances[strtolower($stat)]->get('workflow_instances');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
170 5
            if (!empty($workflowCollection)) {
171 4
                foreach ($workflowCollection as $instance) {
172 4
                    $this->getCurrentClass()->getWorkflowInstancesDetails($instance);
173
                }
174
            }
175
        }
176 5
        if (!is_null($status)) {
177 3
            return $instances->get(strtolower($status))->get('workflow_instances');
178
        }
179
180 2
        return $instances;
181
    }
182
183
    /**
184
     * {@inheritdoc}
185
     */
186 4
    public function getWorkflowInstancesDetails(WorkflowInstance $workflowInstance)
187
    {
188 4
        return $this->_dispatch(new Command\GetWorkflowInstancesDetailCommand($workflowInstance));
189
    }
190
191
    /**
192
     * {@inheritdoc}
193
     */
194 9
    public function tubeExists($name)
195
    {
196 9
        return $this->_dispatch(new Command\TubeExistsCommand($name));
197
    }
198
199
    /**
200
     * {@inheritdoc}
201
     */
202 1
    public function listTubes()
203
    {
204 1
        return $this->_dispatch(new Command\ListTubesCommand());
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     */
210 1
    public function peek()
211
    {
212 1
        $response = $this->_dispatch(new Command\PeekCommand());
213
214 1
        return $response;
215
    }
216
217
    /**
218
     * {@inheritdoc}
219
     */
220 6
    public function put(Workflow $workflow)
221
    {
222 6
        $response = $this->_dispatch(new Command\PutCommand($workflow));
223
224 6
        return $response['workflow-instance-id'];
225
    }
226
227
    /**
228
     * {@inheritdoc}
229
     */
230 1
    public function statsTube(Tube $tube)
231
    {
232 1
        return $this->_dispatch(new Command\StatsTubeCommand($tube));
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_dispatch(...tatsTubeCommand($tube)) returns the type array which is incompatible with the return type mandated by Pheanstalk\PheanstalkInterface::statsTube() of object.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
233
    }
234
235
    /**
236
     * {@inheritdoc}
237
     */
238 1
    public function stats()
239
    {
240 1
        return $this->_dispatch(new Command\StatsCommand());
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_dispatch(...Command\StatsCommand()) returns the type array which is incompatible with the return type mandated by Pheanstalk\PheanstalkInterface::stats() of object.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
241
    }
242
243
    // ----------------------------------------
244
245
    /**
246
     * Dispatches the specified command to the connection object.
247
     *
248
     * If a SocketException occurs, the connection is reset, and the command is
249
     * re-attempted once.
250
     *
251
     * @throws Exception\ClientException
252
     * @param Command $command
253
     *
254
     * @return mixed
255
     */
256 18
    private function _dispatch($command)
257
    {
258 18
        return $this->connection->dispatchCommand($command);
259
    }
260
261
    /**
262
     * {@inheritdoc}
263
     */
264 6
    public function create(Workflow $workflow, $force = false): Workflow
265
    {
266
        try {
267 6
            $this->checkAndCreateTubes($workflow);
268 6
            $workflow = $this->_dispatch(new Command\CreateCommand($workflow));
269 3
        } catch (ServerDuplicateEntryException $e) {
270 3
            if ($force) {
271 3
                $workflowToDelete = $this->findWorkflow($workflow);
272 3
                $this->getCurrentClass()->delete($workflowToDelete);
0 ignored issues
show
Bug introduced by
It seems like $workflowToDelete can also be of type boolean; however, parameter $workflow of Pheanstalk\Pheanstalk::delete() does only seem to accept Pheanstalk\Structure\Workflow, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

272
                $this->getCurrentClass()->delete(/** @scrutinizer ignore-type */ $workflowToDelete);
Loading history...
273
274 3
                return $this->getCurrentClass()->create($workflow);
275
            }
276 1
            throw $e;
277
        }
278
279 6
        return $workflow;
280
    }
281
282
    /**
283
     * @param Workflow $workflow
284
     *
285
     * @return Workflow|bool
286
     * @throws Exception\ClientException
287
     */
288 3
    public function findWorkflow(Workflow $workflow)
289
    {
290 3
        $workflows = $this->_dispatch(new Command\ListWorkflowsCommand());
291
        return $workflows->filter(function(Workflow $listedWorkflow) use ($workflow) {
292 3
            return $listedWorkflow->getName() === $workflow->getName()
293 3
                && $listedWorkflow->getGroup() === $workflow->getGroup();
294 3
        })->first();
295
    }
296
297
    /**
298
     * @param Workflow $workflow
299
     *
300
     * @throws Exception\ClientException
301
     */
302 6
    public function checkAndCreateTubes(Workflow $workflow)
303
    {
304 6
        $tubes = [];
305
        /** @var Job $job */
306 6
        foreach ($workflow->getJobs() as $job) {
307
            /** @var Task $task */
308 6
            foreach ($job->getTasks() as $task) {
309 6
                $tubes = array_merge($tubes, [$task->getQueue()]);
310
            }
311
        }
312 6
        foreach ($tubes as $tube) {
313 6
            if (!$this->getCurrentClass()->tubeExists($tube)) {
314 1
                $this->getCurrentClass()->createTube(new Tube($tube, 1));
315
            };
316
        }
317
    }
318
319
    /**
320
     * {@inheritdoc}
321
     */
322 1
    public function update(Workflow $workflow): Workflow
323
    {
324 1
        $workflow = $this->_dispatch(new Command\UpdateCommand($workflow));
325 1
        return $workflow;
326
    }
327
328
    /**
329
     * {@inheritdoc}
330
     */
331 1
    public function updateSchedule(Schedule $schedule): Schedule
332
    {
333 1
        $schedule = $this->_dispatch(new Command\UpdateScheduleCommand($schedule));
334 1
        return $schedule;
335
    }
336
337
    /**
338
     * {@inheritdoc}
339
     */
340 1
    public function createSchedule(Schedule $schedule)
341
    {
342 1
        $workflowSchedule = $this->_dispatch(
343 1
            new Command\CreateScheduleCommand($schedule)
344
        );
345 1
        return $workflowSchedule;
346
    }
347
348
    /**
349
     * {@inheritdoc}
350
     */
351 5
    public function createTask(string $name, string $group, string $path, $queue = 'default', $useAgent = false, $user = null, $host = null, $comment = null): Workflow
352
    {
353 5
        $task = new Task($path, $queue, $useAgent, $user, $host);
354 5
        $job = new Job(new ArrayCollection([$task]));
355 5
        $workflow = new Workflow($name, $group, new ArrayCollection([$job]), $comment);
356
357 5
        return $this->getCurrentClass()->create($workflow, true);
358
    }
359
360
    /**
361
     * {@inheritDoc}
362
     */
363 1
    public function createTube(Tube $tube): Tube
364
    {
365 1
        return $this->_dispatch(new Command\CreateTubeCommand($tube));
366
    }
367
368
    /**
369
     * {@inheritdoc}
370
     */
371 1
    public function updateTube(Tube $tube): Tube
372
    {
373 1
        return $this->_dispatch(new Command\UpdateTubeCommand($tube));
374
    }
375
376
    /**
377
     * {@inheritdoc}
378
     */
379 1
    public function cancel(WorkflowInstance $workflowInstance)
380
    {
381 1
        return $this->_dispatch(new Command\CancelCommand($workflowInstance));
382
    }
383
384
    /**
385
     * {@inheritdoc}
386
     */
387 2
    public function kill(WorkflowInstance $workflowInstance, TaskInstance $taskInstance)
388
    {
389 2
        return $this->_dispatch(new Command\KillCommand($workflowInstance, $taskInstance));
390
    }
391
}
392