Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
40.00% covered (danger)
40.00%
12 / 30
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
CronRunCommand
37.93% covered (danger)
37.93%
11 / 29
50.00% covered (danger)
50.00%
2 / 4
39.93
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 configure
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 execute
41.18% covered (danger)
41.18%
7 / 17
0.00% covered (danger)
0.00%
0 / 1
10.09
 resolveRunner
20.00% covered (danger)
20.00%
2 / 10
0.00% covered (danger)
0.00%
0 / 1
12.19
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Core\Console\Command;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use App\Core\Cron\CronRunner;
12use App\Core\Database\MultiDbRouter;
13use App\Shared\Infrastructure\Config\InstallerConfigLoader;
14use Symfony\Component\Console\Command\Command;
15use Symfony\Component\Console\Input\InputInterface;
16use Symfony\Component\Console\Output\OutputInterface;
17use Throwable;
18
19/**
20 * Cron Execution Console Command.
21 *
22 * @package App\Core\Console\Command
23 */
24final class CronRunCommand extends Command
25{
26    /**
27     * CronRunCommand constructor.
28     *
29     * @param CronRunner|null $cronRunner Optional runner instance.
30     */
31    public function __construct(private ?CronRunner $cronRunner = null)
32    {
33        parent::__construct('cron:run');
34    }
35
36    /** {@inheritdoc} */
37    protected function configure(): void
38    {
39        $this->setDescription('Executes all eligible scheduled background cron tasks.');
40    }
41
42    /** {@inheritdoc} */
43    protected function execute(InputInterface $input, OutputInterface $output): int
44    {
45        $output->writeln('<info>Starting scheduled task runner...</info>');
46        $runner = $this->resolveRunner();
47        if ($runner !== null) {
48            try {
49                $results = $runner->run();
50                foreach ($results as $res) {
51                    $statusStr = ($res['status'] ?? false) ? 'SUCCESS' : 'FAILED';
52                    $output->writeln(sprintf(
53                        '  [CRON] Job \'%s\' (ID: %d) completed with %s in %d ms.',
54                        (string) ($res['name'] ?? 'unknown'),
55                        (int) ($res['job_id'] ?? 0),
56                        $statusStr,
57                        (int) ($res['duration_ms'] ?? 0)
58                    ));
59                }
60            } catch (Throwable $e) {
61                $output->writeln(sprintf('<error>CRON execution failed: %s</error>', $e->getMessage()));
62            }
63        }
64        $output->writeln('<info>Cron execution cycle completed.</info>');
65
66        return Command::SUCCESS;
67    }
68
69    /**
70     * Resolves or instantiates default CronRunner from application configuration.
71     */
72    private function resolveRunner(): ?CronRunner
73    {
74        if ($this->cronRunner !== null) {
75            return $this->cronRunner;
76        }
77
78        try {
79            $dbConfig = InstallerConfigLoader::load();
80            $dbParams = is_array($dbConfig) ? ($dbConfig['db'] ?? []) : [];
81            $prefix = (string) ($dbParams['table_prefix'] ?? $dbParams['prefix'] ?? 'a_');
82
83            $router = new MultiDbRouter(['default' => $dbParams]);
84            $pdo = $router->getConnection('default');
85
86            return new CronRunner($pdo, $prefix);
87        } catch (Throwable) {
88            return null;
89        }
90    }
91}