Completed
Push — master ( fa4a59...67ceb7 )
by Benjamin
06:19 queued 03:50
created

CronRunCommand::runJob()   B

Complexity

Conditions 8
Paths 17

Size

Total Lines 54
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 54
rs 7.4119
cc 8
eloc 34
nc 17
nop 3

How to fix   Long Method   

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 Alpixel\Bundle\CronBundle\Command;
4
5
use Alpixel\Bundle\CronBundle\Entity\CronJob;
6
use Alpixel\Bundle\CronBundle\Entity\CronJobResult;
7
use Doctrine\ORM\EntityManager;
8
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
9
use Symfony\Component\Console\Input\ArgvInput;
10
use Symfony\Component\Console\Input\InputArgument;
11
use Symfony\Component\Console\Input\InputInterface;
12
use Symfony\Component\Console\Output\OutputInterface;
13
14
class CronRunCommand extends ContainerAwareCommand
15
{
16
    protected function configure()
17
    {
18
        $this->setName('cron:run')
19
             ->setDescription('Runs any currently schedule cron jobs')
20
             ->addArgument('job', InputArgument::OPTIONAL, 'Run only this job (if enabled)');
21
    }
22
23
    protected function execute(InputInterface $input, OutputInterface $output)
24
    {
25
        $start = microtime(true);
26
        $em = $this->getContainer()->get('doctrine.orm.entity_manager');
27
        $jobRepo = $em->getRepository('CronBundle:CronJob');
28
29
        $jobsToRun = [];
30
        if ($jobName = $input->getArgument('job')) {
31
            try {
32
                $jobObj = $jobRepo->findOneByCommand($jobName);
33
                if ($jobObj->getEnabled()) {
34
                    $jobsToRun = [$jobObj];
35
                }
36
            } catch (\Exception $e) {
37
                $output->writeln("Couldn't find a job by the name of $jobName");
38
39
                return CronJobResult::FAILED;
40
            }
41
        } else {
42
            $jobsToRun = $jobRepo->findDueTasks();
43
        }
44
45
        $jobCount = count($jobsToRun);
46
        $output->writeln("Running $jobCount jobs:");
47
48
        foreach ($jobsToRun as $job) {
49
            $this->runJob($job, $output, $em);
50
        }
51
52
        // Flush our results to the DB
53
        $em->flush();
54
55
        $end = microtime(true);
56
        $duration = sprintf('%0.2f', $end - $start);
57
        $output->writeln("Cron run completed in $duration seconds");
58
    }
59
60
    protected function runJob(CronJob $job, OutputInterface $output, EntityManager $em)
61
    {
62
        $output->write('Running '.$job->getCommand().': ');
63
64
        try {
65
            $commandToRun = $this->getApplication()->get($job->getCommand());
66
        } catch (InvalidArgumentException $ex) {
0 ignored issues
show
Bug introduced by
The class Alpixel\Bundle\CronBundl...nvalidArgumentException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
67
            $output->writeln(' skipped (command no longer exists)');
68
            $this->recordJobResult($em, $job, 0, 'Command no longer exists', CronJobResult::SKIPPED);
69
70
            // No need to reschedule non-existant commands
71
            return;
72
        }
73
74
        $emptyInput = new ArgvInput();
75
        $jobOutput = new MemoryWriter();
76
77
        $jobStart = microtime(true);
78
        try {
79
            $returnCode = $commandToRun->execute($emptyInput, $jobOutput);
80
        } catch (\Exception $ex) {
81
            $returnCode = CronJobResult::FAILED;
82
            $jobOutput->writeln('');
83
            $jobOutput->writeln('Job execution failed with exception '.get_class($ex).':');
84
            $jobOutput->writeln($ex->__toString());
85
        }
86
        $jobEnd = microtime(true);
87
88
        // Clamp the result to accepted values
89
        if ($returnCode < CronJobResult::RESULT_MIN || $returnCode > CronJobResult::RESULT_MAX) {
90
            $returnCode = CronJobResult::FAILED;
91
        }
92
93
        // Output the result
94
        $statusStr = 'unknown';
95
        if ($returnCode == CronJobResult::SKIPPED) {
96
            $statusStr = 'skipped';
97
        } elseif ($returnCode == CronJobResult::SUCCEEDED) {
98
            $statusStr = 'succeeded';
99
        } elseif ($returnCode == CronJobResult::FAILED) {
100
            $statusStr = 'failed';
101
        }
102
103
        $durationStr = sprintf('%0.2f', $jobEnd - $jobStart);
104
        $output->writeln("$statusStr in $durationStr seconds");
105
106
        // Record the result
107
        $this->recordJobResult($em, $job, $jobEnd - $jobStart, $jobOutput->getOutput(), $returnCode);
108
109
        // And update the job with it's next scheduled time
110
        $newTime = new \DateTime();
111
        $newTime = $newTime->add(new \DateInterval($job->getInterval()));
112
        $job->setNextRun($newTime);
0 ignored issues
show
Documentation introduced by
$newTime is of type object<DateTime>, but the function expects a object<Alpixel\Bundle\CronBundle\Entity\datetime>.

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...
113
    }
114
115
    protected function recordJobResult(EntityManager $em, CronJob $job, $timeTaken, $output, $resultCode)
116
    {
117
        // Create a new CronJobResult
118
        $result = new CronJobResult();
119
        $result->setJob($job);
120
        $result->setRunTime($timeTaken);
121
        $result->setOutput($output);
122
        $result->setResult($resultCode);
123
124
        // Then update associations and persist it
125
        $job->setMostRecentRun($result);
126
        $em->persist($result);
127
    }
128
}
129