Completed
Push — 1.9 ( 5c3e2e...1529fd )
by
unknown
60:20
created

CalculateAnalyticsCommand::execute()   C

Complexity

Conditions 8
Paths 5

Size

Total Lines 35
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 2 Features 0
Metric Value
dl 0
loc 35
rs 5.3846
c 5
b 2
f 0
cc 8
eloc 18
nc 5
nop 2
1
<?php
2
3
namespace OroCRM\Bundle\AnalyticsBundle\Command;
4
5
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
6
use Symfony\Component\Console\Helper\FormatterHelper;
7
use Symfony\Component\Console\Input\InputInterface;
8
use Symfony\Component\Console\Input\InputOption;
9
use Symfony\Component\Console\Output\OutputInterface;
10
11
use Oro\Bundle\BatchBundle\ORM\Query\BufferedQueryResultIterator;
12
use Oro\Bundle\CronBundle\Command\CronCommandInterface;
13
use Oro\Bundle\EntityBundle\ORM\DoctrineHelper;
14
use OroCRM\Bundle\AnalyticsBundle\Builder\AnalyticsBuilder;
15
use OroCRM\Bundle\ChannelBundle\Entity\Channel;
16
use OroCRM\Bundle\AnalyticsBundle\Model\StateManager;
17
18
class CalculateAnalyticsCommand extends ContainerAwareCommand implements CronCommandInterface
19
{
20
    const BATCH_SIZE   = 200;
21
    const COMMAND_NAME = 'oro:cron:analytic:calculate';
22
23
    /**
24
     * {@inheritdoc}
25
     */
26
    public function getDefaultDefinition()
27
    {
28
        return '0 0 * * *';
29
    }
30
31
    /**
32
     * {@inheritdoc}
33
     */
34
    protected function configure()
35
    {
36
        $this
37
            ->setName(self::COMMAND_NAME)
38
            ->setDescription('Calculate all registered analytic metrics')
39
            ->addOption('channel', null, InputOption::VALUE_OPTIONAL, 'Data Channel id to process')
40
            ->addOption(
41
                'ids',
42
                null,
43
                InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
44
                'Customer identity ids for given channel'
45
            );
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51
    public function execute(InputInterface $input, OutputInterface $output)
52
    {
53
        /** @var FormatterHelper $formatter */
54
        $formatter = $this->getHelper('formatter');
55
56
        $channel = $input->getOption('channel');
57
        $ids = $input->getOption('ids');
58
59
        if (!$channel && $ids) {
60
            $output->writeln('<error>Option "ids" does not work without "channel"</error>');
61
62
            return;
63
        }
64
65
        if ($this->getStateManager()->isJobRunning()) {
66
            $output->writeln('<error>Job already running. Terminating....</error>');
67
68
            return;
69
        }
70
71
        if ($channel && !$ids && $this->getStateManager()->isJobRunning(sprintf('--channel=%s', $channel))) {
72
            $output->writeln('<error>Job already running. Terminating....</error>');
73
74
            return;
75
        }
76
77
        $channels = $this->getChannels($channel);
78
        foreach ($channels as $channel) {
79
            $output->writeln($formatter->formatSection('Process', sprintf('Channel: %s', $channel->getName())));
80
81
            $this->getAnalyticBuilder()->build($channel, $ids);
82
83
            $output->writeln($formatter->formatSection('Done', sprintf('Channel: %s updated.', $channel->getName())));
84
        }
85
    }
86
87
    /**
88
     * @param int $channelId
89
     *
90
     * @return BufferedQueryResultIterator|Channel[]
91
     */
92
    protected function getChannels($channelId = null)
93
    {
94
        $className = $this->getContainer()->getParameter('orocrm_channel.entity.class');
95
        $qb = $this->getDoctrineHelper()->getEntityRepository($className)->createQueryBuilder('c');
96
97
        $qb->orderBy($qb->expr()->asc('c.id'));
98
        $qb->andWhere('c.status = :status');
99
        $qb->setParameter('status', Channel::STATUS_ACTIVE);
100
101
        if ($channelId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $channelId of type integer|null is loosely compared to true; 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...
102
            $qb->andWhere('c.id = :id');
103
            $qb->setParameter('id', $channelId);
104
        }
105
106
        $analyticsInterface = $this->getContainer()->getParameter('orocrm_analytics.model.analytics_aware_interface');
107
108
        return new \CallbackFilterIterator(
109
            new BufferedQueryResultIterator($qb),
110
            function (Channel $channel) use ($analyticsInterface) {
111
                $identityFQCN = $channel->getCustomerIdentity();
112
113
                return is_a($identityFQCN, $analyticsInterface, true);
114
            }
115
        );
116
    }
117
118
    /**
119
     * @return AnalyticsBuilder
120
     */
121
    protected function getAnalyticBuilder()
122
    {
123
        return $this->getContainer()->get('orocrm_analytics.builder');
124
    }
125
126
    /**
127
     * @return DoctrineHelper
128
     */
129
    protected function getDoctrineHelper()
130
    {
131
        return $this->getContainer()->get('oro_entity.doctrine_helper');
132
    }
133
134
    /**
135
     * @return StateManager
136
     */
137
    protected function getStateManager()
138
    {
139
        return $this->getContainer()->get('orocrm_analytics.model.state_manager');
140
    }
141
}
142