Completed
Pull Request — develop (#11)
by Alexandr
01:57
created

Cron::parse()   F

Complexity

Conditions 18
Paths 3072

Size

Total Lines 78
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 78
rs 2.2173
cc 18
eloc 49
nc 3072
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace FOA\CronBundle\Manager;
4
5
use InvalidArgumentException;
6
7
/**
8
 * Cron represents a cron command. It holds:
9
 * - time data
10
 * - command
11
 * - comment
12
 * - log files
13
 * - cron execution status
14
 */
15
class Cron
16
{
17
    const ERROR_MINUTE = 1;
18
    const ERROR_HOUR = 2;
19
    const ERROR_DAY_OF_MONTH = 3;
20
    const ERROR_MONTH = 4;
21
    const ERROR_DAY_OF_WEEK = 5;
22
23
    /**
24
     * @var string
25
     */
26
    protected $minute = '*';
27
28
    /**
29
     * @var string
30
     */
31
    protected $hour = '*';
32
33
    /**
34
     * @var string
35
     */
36
    protected $dayOfMonth = '*';
37
38
    /**
39
     * @var string
40
     */
41
    protected $month = '*';
42
43
    /**
44
     * @var string
45
     */
46
    protected $dayOfWeek = '*';
47
48
    /**
49
     * @var string
50
     */
51
    protected $command;
52
53
    /**
54
     * @var string
55
     */
56
    protected $logFile = null;
57
58
    /**
59
     * The size of the log file
60
     *
61
     * @var string
62
     */
63
    protected $logSize = null;
64
65
    /**
66
     * @var string
67
     */
68
    protected $errorFile = null;
69
70
    /**
71
     * The size of the error file
72
     *
73
     * @var string
74
     */
75
    protected $errorSize = null;
76
77
    /**
78
     * The last run time based on when log files have been written
79
     *
80
     * @var int
81
     */
82
    protected $lastRunTime = null;
83
84
    /**
85
     * The status of the cron, based on the log files
86
     *
87
     * @var string
88
     */
89
    protected $status;
90
91
    /**
92
     * @var string
93
     */
94
    protected $comment;
95
96
    /**
97
     * isSuspended
98
     *
99
     * @var boolean
100
     * @access protected
101
     */
102
    protected $isSuspended = false;
103
104
    /**
105
     * Parses a cron line into a Cron instance
106
     *
107
     * @static
108
     *
109
     * @param $cron string The cron line
110
     *
111
     * @return Cron
112
     */
113
    public static function parse($cron)
114
    {
115
        if (substr($cron, 0, 12) == '#suspended: ') {
116
            $cron = substr($cron, 12);
117
            $isSuspended = true;
118
        }
119
120
        $parts = explode(' ', $cron);
121
122
        $command = implode(' ', array_slice($parts, 5));
123
124
        // extract comment
125
        if (strpos($command, '#')) {
126
            list($command, $comment) = explode('#', $command);
127
            $comment = trim($comment);
128
        }
129
130
        // extract error file
131
        if (strpos($command, '2>')) {
132
            list($command, $errorFile) = explode('2>', $command);
133
            $errorFile = trim($errorFile);
134
        }
135
136
        // extract log file
137
        if (strpos($command, '>')) {
138
            list($command, $logFile) = explode('>', $command);
139
            $logFile = trim($logFile);
140
        }
141
142
        // compute last run time, and file size
143
        $lastRunTime = null;
144
        $logSize = null;
145
        $errorSize = null;
146
        if (isset($logFile) && file_exists($logFile)) {
147
            $lastRunTime = filemtime($logFile);
148
            $logSize = filesize($logFile);
149
        }
150
        if (isset($errorFile) && file_exists($errorFile)) {
151
            $lastRunTime = max($lastRunTime ?: 0, filemtime($errorFile));
152
            $errorSize = filesize($errorFile);
153
        }
154
155
        // compute status
156
        $status = 'error';
157
        if (!$logSize && !$errorSize) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $logSize of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $errorSize of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
158
            $status = 'unknown';
159
        } elseif (!$errorSize || $errorSize == 0) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $errorSize of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
160
            $status = 'success';
161
        }
162
163
        // create cron instance
164
        $cron = new self();
165
        $cron->setMinute($parts[0])
166
            ->setHour($parts[1])
167
            ->setDayOfMonth($parts[2])
168
            ->setMonth($parts[3])
169
            ->setDayOfWeek($parts[4])
170
            ->setCommand(\trim($command))
171
            ->setLastRunTime($lastRunTime)
172
            ->setLogSize($logSize)
173
            ->setErrorSize($errorSize)
174
            ->setStatus($status);
175
176
        if (isset($isSuspended)) {
177
            $cron->setSuspended($isSuspended);
178
        }
179
        if (isset($comment)) {
180
            $cron->setComment($comment);
181
        }
182
        if (isset($logFile)) {
183
            $cron->setLogFile($logFile);
184
        }
185
        if (isset($errorFile)) {
186
            $cron->setErrorFile($errorFile);
187
        }
188
189
        return $cron;
190
    }
191
192
    /**
193
     * @param string $command
194
     *
195
     * @return $this
196
     */
197
    public function setCommand($command)
198
    {
199
        $this->command = $command;
200
201
        return $this;
202
    }
203
204
    /**
205
     * @return string
206
     */
207
    public function getCommand()
208
    {
209
        return $this->command;
210
    }
211
212
    /**
213
     * @param string $dayOfMonth
214
     *
215
     * @return $this
216
     * @throws InvalidArgumentException
217
     */
218
    public function setDayOfMonth($dayOfMonth)
219
    {
220
        if (is_numeric($dayOfMonth) &&
221
            $dayOfMonth < 1 || $dayOfMonth > 31
222
        ) {
223
            throw new InvalidArgumentException('Invalid day of month format', self::ERROR_DAY_OF_MONTH);
224
        }
225
226
        $this->dayOfMonth = $dayOfMonth;
0 ignored issues
show
Documentation Bug introduced by
It seems like $dayOfMonth can also be of type integer or double. However, the property $dayOfMonth is declared as type string. 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...
227
228
        return $this;
229
    }
230
231
    /**
232
     * @return string
233
     */
234
    public function getDayOfMonth()
235
    {
236
        return $this->dayOfMonth;
237
    }
238
239
    /**
240
     * @param string $dayOfWeek
241
     *
242
     * @return $this
243
     * @throws InvalidArgumentException
244
     */
245
    public function setDayOfWeek($dayOfWeek)
246
    {
247
        if (is_numeric($dayOfWeek) &&
248
            $dayOfWeek < 0 || $dayOfWeek > 7
249
        ) {
250
            throw new InvalidArgumentException('Invalid day of week format', self::ERROR_DAY_OF_WEEK);
251
        }
252
253
        $this->dayOfWeek = $dayOfWeek;
0 ignored issues
show
Documentation Bug introduced by
It seems like $dayOfWeek can also be of type integer or double. However, the property $dayOfWeek is declared as type string. 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...
254
255
        return $this;
256
    }
257
258
    /**
259
     * @return string
260
     */
261
    public function getDayOfWeek()
262
    {
263
        return $this->dayOfWeek;
264
    }
265
266
    /**
267
     * @param string $hour
268
     *
269
     * @return $this
270
     * @throws InvalidArgumentException
271
     */
272 View Code Duplication
    public function setHour($hour)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
273
    {
274
        if (is_numeric($hour) &&
275
            $hour < 0 || $hour > 23
276
        ) {
277
            throw new InvalidArgumentException('Invalid hour format', self::ERROR_HOUR);
278
        }
279
280
        $this->hour = $hour;
0 ignored issues
show
Documentation Bug introduced by
It seems like $hour can also be of type integer or double. However, the property $hour is declared as type string. 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...
281
282
        return $this;
283
    }
284
285
    /**
286
     * @return string
287
     */
288
    public function getHour()
289
    {
290
        return $this->hour;
291
    }
292
293
    /**
294
     * @param string $minute
295
     *
296
     * @return $this
297
     * @throws InvalidArgumentException
298
     */
299 View Code Duplication
    public function setMinute($minute)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
300
    {
301
        if (is_numeric($minute) &&
302
            $minute < 0 || $minute > 59
303
        ) {
304
            throw new InvalidArgumentException('Invalid minute format', self::ERROR_MINUTE);
305
        }
306
307
        $this->minute = $minute;
0 ignored issues
show
Documentation Bug introduced by
It seems like $minute can also be of type integer or double. However, the property $minute is declared as type string. 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...
308
309
        return $this;
310
    }
311
312
    /**
313
     * @return string
314
     */
315
    public function getMinute()
316
    {
317
        return $this->minute;
318
    }
319
320
    /**
321
     * @param string $month
322
     *
323
     * @return $this
324
     * @throws InvalidArgumentException
325
     */
326 View Code Duplication
    public function setMonth($month)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
327
    {
328
        if (is_numeric($month) &&
329
            $month < 1 || $month > 12
330
        ) {
331
            throw new InvalidArgumentException('Invalid month format', self::ERROR_MONTH);
332
        }
333
334
        $this->month = $month;
0 ignored issues
show
Documentation Bug introduced by
It seems like $month can also be of type integer or double. However, the property $month is declared as type string. 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...
335
336
        return $this;
337
    }
338
339
    /**
340
     * @return string
341
     */
342
    public function getMonth()
343
    {
344
        return $this->month;
345
    }
346
347
    /**
348
     * @param string $comment
349
     *
350
     * @return $this
351
     */
352
    public function setComment($comment)
353
    {
354
        $this->comment = $comment;
355
356
        return $this;
357
    }
358
359
    /**
360
     * @return string
361
     */
362
    public function getComment()
363
    {
364
        return $this->comment;
365
    }
366
367
    /**
368
     * @param string $logFile
369
     *
370
     * @return $this
371
     */
372
    public function setLogFile($logFile)
373
    {
374
        $this->logFile = $logFile;
375
376
        return $this;
377
    }
378
379
    /**
380
     * @return string
381
     */
382
    public function getLogFile()
383
    {
384
        return $this->logFile;
385
    }
386
387
    /**
388
     * @param string $errorFile
389
     *
390
     * @return $this
391
     */
392
    public function setErrorFile($errorFile)
393
    {
394
        $this->errorFile = $errorFile;
395
396
        return $this;
397
    }
398
399
    /**
400
     * @return string
401
     */
402
    public function getErrorFile()
403
    {
404
        return $this->errorFile;
405
    }
406
407
    /**
408
     * @param int $lastRunTime
409
     *
410
     * @return $this
411
     */
412
    public function setLastRunTime($lastRunTime)
413
    {
414
        $this->lastRunTime = $lastRunTime;
415
416
        return $this;
417
    }
418
419
    /**
420
     * @return int
421
     */
422
    public function getLastRunTime()
423
    {
424
        return $this->lastRunTime;
425
    }
426
427
    /**
428
     * @param string $errorSize
429
     *
430
     * @return $this
431
     */
432
    public function setErrorSize($errorSize)
433
    {
434
        $this->errorSize = $errorSize;
435
436
        return $this;
437
    }
438
439
    /**
440
     * @return string
441
     */
442
    public function getErrorSize()
443
    {
444
        return $this->errorSize;
445
    }
446
447
    /**
448
     * @param string $logSize
449
     *
450
     * @return $this
451
     */
452
    public function setLogSize($logSize)
453
    {
454
        $this->logSize = $logSize;
455
456
        return $this;
457
    }
458
459
    /**
460
     * @return string
461
     */
462
    public function getLogSize()
463
    {
464
        return $this->logSize;
465
    }
466
467
    /**
468
     * @param string $status
469
     *
470
     * @return $this
471
     */
472
    public function setStatus($status)
473
    {
474
        $this->status = $status;
475
476
        return $this;
477
    }
478
479
    /**
480
     * @return string
481
     */
482
    public function getStatus()
483
    {
484
        return $this->status;
485
    }
486
487
    /**
488
     * Concatenate time data to get the time expression
489
     *
490
     * @return string
491
     */
492
    public function getExpression()
493
    {
494
        return sprintf('%s %s %s %s %s', $this->minute, $this->hour, $this->dayOfMonth, $this->month, $this->dayOfWeek);
495
    }
496
497
    /**
498
     * Gets the value of isSuspended
499
     *
500
     * @return boolean
501
     */
502
    public function isSuspended()
503
    {
504
        return $this->isSuspended;
505
    }
506
507
    /**
508
     * Sets the value of isSuspended
509
     *
510
     * @param boolean $isSuspended status
511
     *
512
     * @return Cron
513
     */
514
    public function setSuspended($isSuspended = true)
515
    {
516
        if ($this->isSuspended != $isSuspended) {
517
            $this->isSuspended = $isSuspended;
518
        }
519
520
        return $this;
521
    }
522
523
    /**
524
     * Transforms the cron instance into a cron line
525
     *
526
     * @return string
527
     */
528
    public function __toString()
529
    {
530
        $cronLine = '';
531
        if ($this->isSuspended()) {
532
            $cronLine .= '#suspended: ';
533
        }
534
535
        $cronLine .= $this->getExpression() . ' ' . $this->command;
536
        if ('' != $this->logFile) {
537
            $cronLine .= ' > ' . $this->logFile;
538
        }
539
        if ('' != $this->errorFile) {
540
            $cronLine .= ' 2> ' . $this->errorFile;
541
        }
542
        if ('' != $this->comment) {
543
            $cronLine .= ' #' . $this->comment;
544
        }
545
546
        return $cronLine;
547
    }
548
}
549