1 | <?php |
||
20 | class CalculateAnalyticsCommand extends ContainerAwareCommand implements CronCommandInterface |
||
21 | { |
||
22 | const BATCH_SIZE = 200; |
||
23 | const COMMAND_NAME = 'oro:cron:analytic:calculate'; |
||
24 | |||
25 | /** |
||
26 | * {@inheritdoc} |
||
27 | */ |
||
28 | public function getDefaultDefinition() |
||
32 | |||
33 | /** |
||
34 | * {@inheritdoc} |
||
35 | */ |
||
36 | protected function configure() |
||
37 | { |
||
38 | $this |
||
39 | ->setName(self::COMMAND_NAME) |
||
40 | ->setDescription('Calculate all registered analytic metrics') |
||
41 | ->addOption('channel', null, InputOption::VALUE_OPTIONAL, 'Data Channel id to process') |
||
42 | ->addOption( |
||
43 | 'ids', |
||
44 | null, |
||
45 | InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, |
||
46 | 'Customer identity ids for given channel' |
||
47 | ); |
||
48 | } |
||
49 | |||
50 | /** |
||
51 | * {@inheritdoc} |
||
52 | */ |
||
53 | public function execute(InputInterface $input, OutputInterface $output) |
||
54 | { |
||
55 | /** @var FormatterHelper $formatter */ |
||
56 | $formatter = $this->getHelper('formatter'); |
||
57 | /** @var ProgressHelper $progress */ |
||
58 | $progress = $this->getHelper('progress'); |
||
59 | |||
60 | $channel = $input->getOption('channel'); |
||
61 | $ids = $input->getOption('ids'); |
||
62 | |||
63 | if (!$channel && $ids) { |
||
64 | $output->writeln('<error>Option "ids" does not work without "channel"</error>'); |
||
65 | |||
66 | return; |
||
67 | } |
||
68 | |||
69 | if ($this->getStateManager()->isJobRunning()) { |
||
70 | $output->writeln('<error>Job already running. Terminating....</error>'); |
||
71 | |||
72 | return; |
||
73 | } |
||
74 | |||
75 | if ($channel && !$ids && $this->getStateManager()->isJobRunning(sprintf('--channel=%s', $channel))) { |
||
76 | $output->writeln('<error>Job already running. Terminating....</error>'); |
||
77 | |||
78 | return; |
||
79 | } |
||
80 | |||
81 | $channels = $this->getChannels($channel); |
||
82 | foreach ($channels as $channel) { |
||
83 | $output->writeln($formatter->formatSection('Process', sprintf('Channel: %s', $channel->getName()))); |
||
84 | |||
85 | $entities = $this->getEntitiesByChannel($channel, $ids); |
||
86 | |||
87 | if ($input->isInteractive()) { |
||
88 | $progress->start($output, $entities->count()); |
||
89 | } |
||
90 | |||
91 | $count = $this->processChannel($channel, $entities, $input, $progress); |
||
92 | |||
93 | if ($input->isInteractive()) { |
||
94 | $progress->finish(); |
||
95 | } |
||
96 | $output->writeln($formatter->formatSection('Done', sprintf('%s/%s updated.', $count, $entities->count()))); |
||
97 | } |
||
98 | } |
||
99 | |||
100 | /** |
||
101 | * @param Channel $channel |
||
102 | * @param BufferedQueryResultIterator $entities |
||
103 | * @param InputInterface $input |
||
104 | * @param ProgressHelper $progress |
||
105 | * |
||
106 | * @return int |
||
107 | */ |
||
108 | protected function processChannel( |
||
109 | $channel, |
||
110 | BufferedQueryResultIterator $entities, |
||
111 | InputInterface $input, |
||
112 | ProgressHelper $progress |
||
113 | ) { |
||
114 | $count = 0; |
||
115 | $identityFQCN = $channel->getCustomerIdentity(); |
||
116 | |||
117 | $em = $this->getDoctrineHelper()->getEntityManager($identityFQCN); |
||
118 | |||
119 | foreach ($entities as $k => $entity) { |
||
120 | if ($input->isInteractive()) { |
||
121 | $progress->advance(); |
||
122 | } |
||
123 | |||
124 | if ($this->getAnalyticBuilder()->build($entity)) { |
||
125 | $count++; |
||
126 | } |
||
127 | |||
128 | if (($k + 1) % self::BATCH_SIZE === 0) { |
||
129 | $em->flush(); |
||
130 | $em->clear(); |
||
131 | } |
||
132 | } |
||
133 | |||
134 | $em->flush(); |
||
135 | $em->clear(); |
||
136 | |||
137 | return $count; |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * @param int $channelId |
||
142 | * |
||
143 | * @return BufferedQueryResultIterator|Channel[] |
||
144 | */ |
||
145 | protected function getChannels($channelId = null) |
||
146 | { |
||
147 | $className = $this->getContainer()->getParameter('orocrm_channel.entity.class'); |
||
148 | $qb = $this->getDoctrineHelper()->getEntityRepository($className) |
||
149 | ->createQueryBuilder('c'); |
||
150 | |||
151 | $qb->orderBy('c.id'); |
||
152 | $qb->andWhere('c.status = :status'); |
||
153 | $qb->setParameter('status', Channel::STATUS_ACTIVE); |
||
154 | |||
155 | if ($channelId) { |
||
|
|||
156 | $qb->andWhere('c.id = :id'); |
||
157 | $qb->setParameter('id', $channelId); |
||
158 | } |
||
159 | |||
160 | $analyticsInterface = $this->getContainer()->getParameter('orocrm_analytics.model.analytics_aware_interface'); |
||
161 | |||
162 | return new \CallbackFilterIterator( |
||
163 | new BufferedQueryResultIterator($qb), |
||
164 | function (Channel $channel) use ($analyticsInterface) { |
||
165 | $identityFQCN = $channel->getCustomerIdentity(); |
||
166 | |||
167 | return is_a($identityFQCN, $analyticsInterface, true); |
||
168 | } |
||
169 | ); |
||
170 | } |
||
171 | |||
172 | /** |
||
173 | * @param Channel $channel |
||
174 | * @param array $ids |
||
175 | * |
||
176 | * @return BufferedQueryResultIterator|CustomerIdentity[] |
||
177 | */ |
||
178 | protected function getEntitiesByChannel(Channel $channel, array $ids = []) |
||
200 | |||
201 | /** |
||
202 | * @return AnalyticsBuilder |
||
203 | */ |
||
204 | protected function getAnalyticBuilder() |
||
208 | |||
209 | /** |
||
210 | * @return DoctrineHelper |
||
211 | */ |
||
212 | protected function getDoctrineHelper() |
||
216 | |||
217 | /** |
||
218 | * @return StateManager |
||
219 | */ |
||
220 | protected function getStateManager() |
||
224 | } |
||
225 |
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
integer
values, zero is a special case, in particular the following results might be unexpected: