Issues (83)

Command/DownloadCommand.php (1 issue)

Languages
Labels
Severity
1
<?php
2
3
/*
4
 * This file is part of the PHP Translation package.
5
 *
6
 * (c) PHP Translation team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Translation\Bundle\Command;
13
14
use Symfony\Component\Console\Command\Command;
15
use Symfony\Component\Console\Input\InputArgument;
16
use Symfony\Component\Console\Input\InputInterface;
17
use Symfony\Component\Console\Input\InputOption;
18
use Symfony\Component\Console\Output\OutputInterface;
19
use Symfony\Component\Console\Style\SymfonyStyle;
20
use Symfony\Component\Finder\Finder;
21
use Translation\Bundle\Catalogue\CatalogueWriter;
22
use Translation\Bundle\Service\CacheClearer;
23
use Translation\Bundle\Service\ConfigurationManager;
24
use Translation\Bundle\Service\StorageManager;
25
26
/**
27
 * @author Tobias Nyholm <[email protected]>
28
 */
29
class DownloadCommand extends Command
30
{
31
    use BundleTrait;
32
    use StorageTrait;
33
34
    protected static $defaultName = 'translation:download';
35
36
    private $configurationManager;
37
    private $cacheCleaner;
38
    private $catalogueWriter;
39
40
    public function __construct(
41
        StorageManager $storageManager,
42
        ConfigurationManager $configurationManager,
43
        CacheClearer $cacheCleaner,
44
        CatalogueWriter $catalogueWriter
45
    ) {
46
        $this->storageManager = $storageManager;
47
        $this->configurationManager = $configurationManager;
48
        $this->cacheCleaner = $cacheCleaner;
49
        $this->catalogueWriter = $catalogueWriter;
50
51
        parent::__construct();
52
    }
53
54
    protected function configure(): void
55
    {
56
        $this
57
            ->setName(self::$defaultName)
58
            ->setDescription('Replace local messages with messages from remote')
59
            ->setHelp(<<<EOT
60
The <info>%command.name%</info> will erase all your local translations and replace them with translations downloaded from the remote.
61
EOT
62
            )
63
            ->addArgument('configuration', InputArgument::OPTIONAL, 'The configuration to use', 'default')
64
            ->addOption('cache', null, InputOption::VALUE_NONE, '[DEPRECATED] Cache is now automatically cleared when translations have changed.')
65
            ->addOption('bundle', 'b', InputOption::VALUE_REQUIRED, 'The bundle you want update translations from.')
66
            ->addOption('export-config', 'exconf', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Options to send to the StorageInterface::export() function. Ie, when downloading. Example: --export-config foo:bar', [])
67
        ;
68
    }
69
70
    protected function execute(InputInterface $input, OutputInterface $output): int
71
    {
72
        $io = new SymfonyStyle($input, $output);
73
74
        if ($input->getOption('cache')) {
75
            $message = 'The --cache option is deprecated as it\'s now the default behaviour of this command.';
76
77
            $io->note($message);
78
            @\trigger_error($message, \E_USER_DEPRECATED);
79
        }
80
81
        $configName = $input->getArgument('configuration');
82
        $config = $this->configurationManager->getConfiguration($configName);
83
        $storage = $this->getStorage($configName);
84
85
        $this->configureBundleDirs($input, $config);
86
87
        $translationsDirectory = $config->getOutputDir();
88
        $md5BeforeDownload = $this->hashDirectory($translationsDirectory);
89
90
        $exportOptions = $this->cleanParameters($input->getOption('export-config'));
0 ignored issues
show
It seems like $input->getOption('export-config') can also be of type boolean and null and string; however, parameter $raw of Translation\Bundle\Comma...mand::cleanParameters() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

90
        $exportOptions = $this->cleanParameters(/** @scrutinizer ignore-type */ $input->getOption('export-config'));
Loading history...
91
        $catalogues = $storage->download($exportOptions);
92
        $this->catalogueWriter->writeCatalogues($config, $catalogues);
93
94
        $translationsCount = 0;
95
        foreach ($catalogues as $locale => $catalogue) {
96
            foreach ($catalogue->all() as $domain => $messages) {
97
                $translationsCount += \count($messages);
98
            }
99
        }
100
101
        $io->text("<info>$translationsCount</info> translations have been downloaded.");
102
103
        $md5AfterDownload = $this->hashDirectory($translationsDirectory);
104
105
        if ($md5BeforeDownload !== $md5AfterDownload) {
106
            $io->success('Translations updated successfully!');
107
            $this->cacheCleaner->clearAndWarmUp();
108
        } else {
109
            $io->success('All translations were up to date.');
110
        }
111
112
        return 0;
113
    }
114
115
    /**
116
     * @return bool|string
117
     */
118
    private function hashDirectory(string $directory)
119
    {
120
        if (!\is_dir($directory)) {
121
            return false;
122
        }
123
124
        $finder = new Finder();
125
        $finder->files()->in($directory)->notName('/~$/')->sortByName();
126
127
        $hash = \hash_init('md5');
128
        foreach ($finder as $file) {
129
            \hash_update_file($hash, $file->getRealPath());
130
        }
131
132
        return \hash_final($hash);
133
    }
134
135
    public function cleanParameters(array $raw)
136
    {
137
        $config = [];
138
139
        foreach ($raw as $string) {
140
            // Assert $string looks like "foo:bar"
141
            list($key, $value) = \explode(':', $string, 2);
142
            $config[$key][] = $value;
143
        }
144
145
        return $config;
146
    }
147
}
148