This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Oro\Bundle\BatchBundle\Command; |
||
4 | |||
5 | use Akeneo\Bundle\BatchBundle\Job\BatchStatus; |
||
6 | |||
7 | use Doctrine\ORM\AbstractQuery; |
||
8 | use Doctrine\ORM\EntityManager; |
||
9 | use Doctrine\ORM\QueryBuilder; |
||
10 | |||
11 | use Symfony\Component\Console\Input\InputOption; |
||
12 | use Symfony\Component\Console\Input\InputInterface; |
||
13 | use Symfony\Component\Console\Output\OutputInterface; |
||
14 | use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; |
||
15 | |||
16 | use Oro\Bundle\CronBundle\Command\CronCommandInterface; |
||
17 | use Oro\Bundle\BatchBundle\ORM\Query\DeletionQueryResultIterator; |
||
18 | |||
19 | /** |
||
20 | * Command to clean up old batch job records |
||
21 | */ |
||
22 | class CleanupCommand extends ContainerAwareCommand implements CronCommandInterface |
||
23 | { |
||
24 | const FLUSH_BATCH_SIZE = 100; |
||
25 | |||
26 | /** |
||
27 | * {@inheritdoc} |
||
28 | */ |
||
29 | public function getDefaultDefinition() |
||
30 | { |
||
31 | return '0 1 * * *'; |
||
32 | } |
||
33 | |||
34 | /** |
||
35 | * {@inheritdoc} |
||
36 | */ |
||
37 | protected function configure() |
||
38 | { |
||
39 | $this |
||
40 | ->setName('oro:cron:batch:cleanup') |
||
41 | ->setDescription('Clean up batch history') |
||
42 | ->addOption( |
||
43 | 'interval', |
||
44 | 'i', |
||
45 | InputOption::VALUE_OPTIONAL, |
||
46 | 'Time interval to keep the batch records. Example "2 weeks"' |
||
47 | ); |
||
48 | } |
||
49 | |||
50 | /** |
||
51 | * {@inheritdoc} |
||
52 | */ |
||
53 | protected function execute(InputInterface $input, OutputInterface $output) |
||
54 | { |
||
55 | $interval = $input->getOption('interval'); |
||
56 | |||
57 | $batchJobs = $this->getObsoleteBatchJobsQueryBuilder($this->prepareDateInterval($interval)); |
||
58 | $batchJobsIterator = new DeletionQueryResultIterator($batchJobs); |
||
59 | $batchJobsIterator->setBufferSize(self::FLUSH_BATCH_SIZE); |
||
60 | $batchJobsIterator->setHydrationMode(AbstractQuery::HYDRATE_SCALAR); |
||
61 | |||
62 | if (!count($batchJobsIterator)) { |
||
63 | $output->writeln('<info>There are no jobs eligible for clean up</info>'); |
||
64 | |||
65 | return; |
||
66 | } |
||
67 | $output->writeln(sprintf('<comment>Batch jobs will be deleted:</comment> %d', count($batchJobsIterator))); |
||
68 | |||
69 | $this->deleteRecords($batchJobsIterator, 'AkeneoBatchBundle:JobExecution'); |
||
70 | |||
71 | $jobExecutions = $this->getObsoleteJobInstancesQueryBuilder(); |
||
72 | $jobInstanceIterator = new DeletionQueryResultIterator($jobExecutions); |
||
73 | $jobInstanceIterator->setBufferSize(self::FLUSH_BATCH_SIZE); |
||
74 | $jobInstanceIterator->setHydrationMode(AbstractQuery::HYDRATE_SCALAR); |
||
75 | $this->deleteRecords($jobInstanceIterator, 'AkeneoBatchBundle:JobInstance'); |
||
76 | |||
77 | $output->writeln('<info>Batch job history cleanup complete</info>'); |
||
78 | } |
||
79 | |||
80 | /** |
||
81 | * Subtract given interval from current date time |
||
82 | * |
||
83 | * @param string $intervalString |
||
84 | * |
||
85 | * @return \DateTime |
||
86 | */ |
||
87 | protected function prepareDateInterval($intervalString = null) |
||
88 | { |
||
89 | $date = new \DateTime('now', new \DateTimeZone('UTC')); |
||
90 | $intervalString = $intervalString ?: $this->getContainer()->getParameter('oro_batch.cleanup_interval'); |
||
91 | $date->sub(\DateInterval::createFromDateString($intervalString)); |
||
92 | |||
93 | return $date; |
||
94 | } |
||
95 | |||
96 | /** |
||
97 | * Delete records using iterator |
||
98 | * |
||
99 | * @param DeletionQueryResultIterator $iterator |
||
100 | * |
||
101 | * @param string $className Entity FQCN |
||
102 | * |
||
103 | * @throws \Exception |
||
104 | */ |
||
105 | protected function deleteRecords(DeletionQueryResultIterator $iterator, $className) |
||
106 | { |
||
107 | $iteration = 0; |
||
108 | $em = $this->getEntityManager(); |
||
109 | |||
110 | foreach ($iterator as $row) { |
||
111 | $id = reset($row); |
||
112 | $em->remove($em->getReference($className, $id)); |
||
0 ignored issues
–
show
|
|||
113 | |||
114 | $iteration++; |
||
115 | if ($iteration % self::FLUSH_BATCH_SIZE == 0) { |
||
116 | $this->finishBatch(); |
||
117 | } |
||
118 | } |
||
119 | if ($iteration % self::FLUSH_BATCH_SIZE > 0) { |
||
120 | $this->finishBatch(); |
||
121 | } |
||
122 | } |
||
123 | |||
124 | /** |
||
125 | * Finish processed batch |
||
126 | */ |
||
127 | protected function finishBatch() |
||
128 | { |
||
129 | $this->getEntityManager()->flush(); |
||
130 | $this->getEntityManager()->clear(); |
||
131 | } |
||
132 | |||
133 | /** |
||
134 | * Find job executions created before the given date time |
||
135 | * |
||
136 | * @param $endTime |
||
137 | * |
||
138 | * @return QueryBuilder |
||
139 | */ |
||
140 | protected function getObsoleteBatchJobsQueryBuilder($endTime) |
||
141 | { |
||
142 | $repository = $this->getEntityManager()->getRepository('AkeneoBatchBundle:JobExecution'); |
||
143 | |||
144 | return $repository->createQueryBuilder('je') |
||
145 | ->resetDQLPart('select') |
||
146 | ->select('je.id') |
||
147 | ->where('je.status NOT IN (:statuses)') |
||
148 | ->andWhere('je.createTime < (:endTime)') |
||
149 | ->setParameter( |
||
150 | 'statuses', |
||
151 | [BatchStatus::STARTING, BatchStatus::STARTED] |
||
152 | ) |
||
153 | ->setParameter('endTime', $endTime); |
||
154 | } |
||
155 | |||
156 | |||
157 | /** |
||
158 | * Find job instances that don't have any job executions associated to them |
||
159 | * |
||
160 | * @return QueryBuilder |
||
161 | */ |
||
162 | protected function getObsoleteJobInstancesQueryBuilder() |
||
163 | { |
||
164 | $repository = $this->getEntityManager()->getRepository('AkeneoBatchBundle:JobInstance'); |
||
165 | |||
166 | return $repository->createQueryBuilder('ji') |
||
167 | ->resetDQLPart('select') |
||
168 | ->select('ji.id') |
||
169 | ->leftJoin('ji.jobExecutions', 'je') |
||
170 | ->where('je.id IS NULL'); |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * @return EntityManager |
||
175 | */ |
||
176 | protected function getEntityManager() |
||
177 | { |
||
178 | return $this->getContainer()->get('doctrine')->getManager(); |
||
179 | } |
||
180 | } |
||
181 |
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.