├── LICENSE
├── composer.json
└── src
├── Cache
├── Cleaners
│ ├── ApcCleaner.php
│ ├── ApcuCleaner.php
│ ├── ICleaner.php
│ ├── LocalFilesystemCleaner.php
│ ├── MemcachedCleaner.php
│ ├── NetteCachingStorageCleaner.php
│ └── OpcodeCleaner.php
└── Generators
│ ├── DiContainersCacheGenerator.php
│ ├── IGenerator.php
│ └── LatteTemplatesCacheGenerator.php
├── Command
├── AdvancedCache
│ ├── CacheCleanCommand.php
│ └── CacheGenerateCommand.php
├── Cache
│ └── CachePurgeCommand.php
├── Caching
│ └── CachingClearCommand.php
├── DI
│ └── DIPurgeCommand.php
├── Database
│ ├── BackupCommand.php
│ └── LoadCommand.php
├── Latte
│ ├── LattePurgeCommand.php
│ └── LatteWarmupCommand.php
├── Router
│ └── RouterDumpCommand.php
├── Security
│ └── SecurityPasswordCommand.php
└── Utils
│ └── UtilsRandomCommand.php
├── DI
├── AbstractCompilerExtension.php
├── AdvancedCacheConsoleExtension.php
├── CacheConsoleExtension.php
├── CachingConsoleExtension.php
├── ConsoleBridgesExtension.php
├── DIConsoleExtension.php
├── DatabaseConsoleExtension.php
├── LatteConsoleExtension.php
├── RouterConsoleExtension.php
├── SecurityConsoleExtension.php
└── UtilsConsoleExtension.php
├── Exception
├── LogicalException.php
└── RuntimeException.php
└── Utils
├── Database.php
├── Files.php
└── Utils.php
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Contributte
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "contributte/console-extra",
3 | "description": "Nette-based console commands for latte, DIC, security, utils and many others",
4 | "keywords": [
5 | "nette",
6 | "symfony",
7 | "console"
8 | ],
9 | "type": "library",
10 | "license": "MIT",
11 | "homepage": "https://github.com/contributte/console-extra",
12 | "authors": [
13 | {
14 | "name": "Milan Felix Šulc",
15 | "homepage": "https://f3l1x.io"
16 | }
17 | ],
18 | "require": {
19 | "php": ">=8.1",
20 | "nette/di": "^3.1.8",
21 | "symfony/console": "^6.4.2 || ^7.0.2"
22 | },
23 | "require-dev": {
24 | "contributte/console": "~0.10",
25 | "latte/latte": "^3.0.12",
26 | "nette/application": "^3.1.14",
27 | "nette/bootstrap": "^3.2.1",
28 | "nette/caching": "^3.2.3",
29 | "nette/security": "^3.1.8",
30 | "contributte/qa": "^0.4",
31 | "contributte/tester": "^0.4",
32 | "contributte/phpstan": "^0.1",
33 | "mockery/mockery": "^1.5.0"
34 | },
35 | "conflict": {
36 | "nette/schema": "<1.0.1"
37 | },
38 | "suggest": {
39 | "contributte/console": "Symfony\\Console for Nette"
40 | },
41 | "autoload": {
42 | "psr-4": {
43 | "Contributte\\Console\\Extra\\": "src"
44 | }
45 | },
46 | "autoload-dev": {
47 | "psr-4": {
48 | "Tests\\": "tests"
49 | }
50 | },
51 | "minimum-stability": "dev",
52 | "prefer-stable": true,
53 | "config": {
54 | "sort-packages": true,
55 | "allow-plugins": {
56 | "dealerdirect/phpcodesniffer-composer-installer": true
57 | }
58 | },
59 | "extra": {
60 | "branch-alias": {
61 | "dev-master": "0.9.x-dev"
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Cache/Cleaners/ApcCleaner.php:
--------------------------------------------------------------------------------
1 | writeln('Skipped APC cache cleaning, apc_clear_cache function is not available.');
20 |
21 | return false;
22 | }
23 |
24 | $output->writeln('Cleaning APC cache');
25 |
26 | $output->writeln('Cleaning APC system cache', OutputInterface::VERBOSITY_VERBOSE);
27 | apc_clear_cache();
28 |
29 | $output->writeln('Cleaning APC user cache', OutputInterface::VERBOSITY_VERBOSE);
30 | apc_clear_cache('user');
31 |
32 | $output->writeln('APC cache successfully cleaned.');
33 |
34 | return true;
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/Cache/Cleaners/ApcuCleaner.php:
--------------------------------------------------------------------------------
1 | writeln('Skipped APCu cache cleaning, apcu_clear_cache function is not available.');
20 |
21 | return false;
22 | }
23 |
24 | $output->writeln('Cleaning APCu cache');
25 |
26 | apcu_clear_cache();
27 |
28 | $output->writeln('APCu cache successfully cleaned.');
29 |
30 | return true;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/Cache/Cleaners/ICleaner.php:
--------------------------------------------------------------------------------
1 | directories = $directories;
25 | $this->ignored = $ignored;
26 | }
27 |
28 | public function getDescription(): string
29 | {
30 | return 'Local files';
31 | }
32 |
33 | public function clean(InputInterface $input, OutputInterface $output): bool
34 | {
35 | if ($this->directories === []) {
36 | $output->writeln('Skipped local filesystem cache cleaning, no directories defined.');
37 |
38 | return false;
39 | }
40 |
41 | $output->writeln('Cleaning local filesystem cache');
42 |
43 | foreach ($this->directories as $directory) {
44 | $output->writeln(sprintf('Cleaning directory %s', $directory), OutputInterface::VERBOSITY_VERBOSE);
45 | Files::purge($directory, $this->ignored);
46 | }
47 |
48 | $output->writeln('Local filesystem cache successfully cleaned.');
49 |
50 | return true;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/Cache/Cleaners/MemcachedCleaner.php:
--------------------------------------------------------------------------------
1 | memcaches = $memcaches;
22 | }
23 |
24 | public function getDescription(): string
25 | {
26 | return 'Memcached';
27 | }
28 |
29 | public function clean(InputInterface $input, OutputInterface $output): bool
30 | {
31 | if ($this->memcaches === []) {
32 | $output->writeln('Skipped Memcache(d) cleaning, no Memcache(d) services defined.');
33 |
34 | return false;
35 | }
36 |
37 | $output->writeln('Cleaning Memcache(d)');
38 |
39 | foreach ($this->memcaches as $name => $memcache) {
40 | $output->writeln(sprintf('Cleaning Memcache(d) instance %s', (string) $name), OutputInterface::VERBOSITY_VERBOSE);
41 | $memcache->flush();
42 | }
43 |
44 | $output->writeln('Memcache(d) successfully cleaned.');
45 |
46 | return true;
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/Cache/Cleaners/NetteCachingStorageCleaner.php:
--------------------------------------------------------------------------------
1 | storages = $storages;
22 | }
23 |
24 | public function getDescription(): string
25 | {
26 | return Storage::class;
27 | }
28 |
29 | public function clean(InputInterface $input, OutputInterface $output): bool
30 | {
31 | if ($this->storages === []) {
32 | $output->writeln(sprintf('Skipped %s cleaning, no IStorage services defined.', Storage::class));
33 |
34 | return false;
35 | }
36 |
37 | $output->writeln(sprintf('Cleaning %s', Storage::class));
38 |
39 | foreach ($this->storages as $name => $storage) {
40 | $output->writeln(sprintf('Cleaning storage instance %s', (string) $name), OutputInterface::VERBOSITY_VERBOSE);
41 | $storage->clean([
42 | Cache::All => true,
43 | ]);
44 | }
45 |
46 | $output->writeln(sprintf('%s successfully cleaned.', Storage::class));
47 |
48 | return true;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/Cache/Cleaners/OpcodeCleaner.php:
--------------------------------------------------------------------------------
1 | writeln('Skipped opcode cache cleaning, opcache_reset function is not available.');
20 |
21 | return false;
22 | }
23 |
24 | $output->writeln('Cleaning opcode cache cache');
25 | $success = @opcache_reset();
26 |
27 | if ($success) {
28 | $output->writeln('opcode cache successfully cleaned.');
29 |
30 | return true;
31 | } else {
32 | $output->writeln('opcode cache cannot be cleaned. It is probably restricted by "restrict_api" directive of OPcache API.');
33 |
34 | return false;
35 | }
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/Cache/Generators/DiContainersCacheGenerator.php:
--------------------------------------------------------------------------------
1 | config = $config;
23 | $this->configurator = $configurator;
24 | }
25 |
26 | public function getDescription(): string
27 | {
28 | return 'DI Containers cache';
29 | }
30 |
31 | public function generate(InputInterface $input, OutputInterface $output): bool
32 | {
33 | if ($this->config === []) {
34 | $output->writeln('Containers generating skipped, no containers configuration defined.');
35 |
36 | return false;
37 | }
38 |
39 | $output->writeln('Compiling DI containers');
40 |
41 | /** @var mixed[] $parameters */
42 | foreach ($this->config as $container => $parameters) {
43 | if (isset($parameters['debugMode'])) { // Nette BC
44 | $parameters['productionMode'] = !boolval($parameters['debugMode']);
45 | }
46 |
47 | $output->writeln(sprintf(
48 | 'Compiling container `%s`',
49 | (string) $container
50 | ));
51 |
52 | $configurator = clone $this->configurator;
53 | $configurator->addStaticParameters($parameters);
54 | $configurator->loadContainer();
55 | }
56 |
57 | $output->writeln('All containers successfully generated.');
58 |
59 | return true;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/Cache/Generators/IGenerator.php:
--------------------------------------------------------------------------------
1 | templateFactory = $templateFactory;
32 | $this->dirs = $dirs;
33 | $this->excludeDirs = $excludeDirs;
34 | $this->rootDir = $rootDir;
35 | }
36 |
37 | public function getDescription(): string
38 | {
39 | return 'Latte templates cache';
40 | }
41 |
42 | public function generate(InputInterface $input, OutputInterface $output): bool
43 | {
44 | if ($this->dirs === []) {
45 | $output->writeln('Latte templates compilation skipped, no directories defined.');
46 |
47 | return false;
48 | }
49 |
50 | $output->writeln('Compiling Latte templates');
51 |
52 | /** @var Template $template */
53 | $template = $this->templateFactory->createTemplate();
54 | $latte = $template->getLatte();
55 |
56 | $finder = Finder::findFiles('*.latte')->from($this->dirs);
57 |
58 | if ($this->excludeDirs !== []) {
59 | $finder->exclude($this->excludeDirs);
60 | }
61 |
62 | $successes = 0;
63 | $fails = 0;
64 |
65 | foreach ($finder as $path => $file) {
66 | $path = (string) realpath($path);
67 | $outputPath = $this->rootDir !== null && str_starts_with($path, $this->rootDir)
68 | ? substr($path, mb_strlen($this->rootDir))
69 | : $path;
70 |
71 | $output->writeln(sprintf('Compiling %s', $outputPath), OutputInterface::VERBOSITY_VERBOSE);
72 |
73 | try {
74 | $latte->warmupCache($path);
75 | $successes++;
76 | } catch (Throwable $e) {
77 | $output->writeln(sprintf('Failed %s compilation.', $outputPath), OutputInterface::VERBOSITY_VERBOSE);
78 | $fails++;
79 | }
80 | }
81 |
82 | if ($fails !== 0) {
83 | $output->writeln(sprintf('%d templates compiled, compilation of %d files failed.', $successes, $fails));
84 |
85 | return false;
86 | } else {
87 | $output->writeln('All templates successfully compiled.');
88 |
89 | return true;
90 | }
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/src/Command/AdvancedCache/CacheCleanCommand.php:
--------------------------------------------------------------------------------
1 | cleaners = $cleaners;
34 | }
35 |
36 | protected function configure(): void
37 | {
38 | $this->addOption('list', 'l', InputOption::VALUE_NONE, 'List all available cleaners');
39 | $this->addOption('cleaner', 'c', InputOption::VALUE_REQUIRED, 'Use only one cleaner');
40 | }
41 |
42 | protected function execute(InputInterface $input, OutputInterface $output): int
43 | {
44 | $style = new SymfonyStyle($input, $output);
45 |
46 | if ($input->getOption('list') === true) {
47 | $table = new Table($output);
48 | $table->setStyle('box');
49 | $table->setHeaders(['Name', 'Description']);
50 | $rows = [];
51 |
52 | foreach ($this->cleaners as $name => $cleaner) {
53 | $rows[] = [$name, $cleaner->getDescription()];
54 | }
55 |
56 | $table->setRows($rows);
57 | $table->render();
58 |
59 | return 0;
60 | }
61 |
62 | if (($cleanerName = $input->getOption('cleaner')) !== null) {
63 | if (!is_string($cleanerName) || !isset($this->cleaners[$cleanerName])) {
64 | throw new LogicalException(sprintf('Cannot run undefined cleaner "%s"', Utils::stringify($cleanerName)));
65 | }
66 |
67 | $this->cleaners[$cleanerName]->clean($input, $output);
68 |
69 | return 0;
70 | }
71 |
72 | if ($this->cleaners === []) {
73 | $style->error('Cache cleaning skipped, no cleaners defined.');
74 |
75 | return 0;
76 | }
77 |
78 | $stats = ['ok' => [], 'error' => []];
79 |
80 | foreach ($this->cleaners as $name => $cleaner) {
81 | $success = $cleaner->clean($input, $output);
82 |
83 | if ($success) {
84 | $stats['ok'][] = $name;
85 | } else {
86 | $stats['error'][] = $name;
87 | }
88 | }
89 |
90 | if ($stats['error'] !== []) {
91 | $style->warning(sprintf(
92 | 'Cache cleaning done. %d success / %d errors. Cleaner%s "%s" failed.',
93 | count($stats['ok']),
94 | count($stats['error']),
95 | (count($stats['error']) === 1) ? '' : 's',
96 | implode('", "', $stats['error'])
97 | ));
98 | } else {
99 | $style->success('Cache successfully cleaned.');
100 | }
101 |
102 | return 0;
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/src/Command/AdvancedCache/CacheGenerateCommand.php:
--------------------------------------------------------------------------------
1 | generators = $generators;
34 | }
35 |
36 | protected function configure(): void
37 | {
38 | $this->addOption('list', 'l', InputOption::VALUE_NONE, 'List all available generators');
39 | $this->addOption('generator', 'g', InputOption::VALUE_REQUIRED, 'Use only one generator');
40 | }
41 |
42 | protected function execute(InputInterface $input, OutputInterface $output): int
43 | {
44 | //todo - vypsat co failnulo a co se podařilo
45 | $style = new SymfonyStyle($input, $output);
46 |
47 | if ($input->getOption('list') === true) {
48 | $table = new Table($output);
49 | $table->setStyle('box');
50 | $table->setHeaders(['Name', 'Description']);
51 | $rows = [];
52 |
53 | foreach ($this->generators as $name => $generator) {
54 | $rows[] = [$name, $generator->getDescription()];
55 | }
56 |
57 | $table->setRows($rows);
58 | $table->render();
59 |
60 | return 0;
61 | }
62 |
63 | if (($generatorName = $input->getOption('generator')) !== null) {
64 | if (!is_string($generatorName) || !isset($this->generators[$generatorName])) {
65 | throw new LogicalException(sprintf('Cannot run undefined generator "%s"', Utils::stringify($generatorName)));
66 | }
67 |
68 | $this->generators[$generatorName]->generate($input, $output);
69 |
70 | return 0;
71 | }
72 |
73 | if ($this->generators === []) {
74 | $style->error('Cache generating skipped, no generators defined.');
75 |
76 | return 0;
77 | }
78 |
79 | $stats = ['ok' => [], 'error' => []];
80 |
81 | foreach ($this->generators as $name => $generator) {
82 | $success = $generator->generate($input, $output);
83 |
84 | if ($success) {
85 | $stats['ok'][] = $name;
86 | } else {
87 | $stats['error'][] = $name;
88 | }
89 | }
90 |
91 | if ($stats['error'] !== []) {
92 | $style->warning(sprintf(
93 | 'Cache generating done. %d success / %d errors. Generator%s "%s" failed.',
94 | count($stats['ok']),
95 | count($stats['error']),
96 | (count($stats['error']) === 1) ? '' : 's',
97 | implode('", "', $stats['error'])
98 | ));
99 | } else {
100 | $style->success('Cache successfully generated.');
101 | }
102 |
103 | return 0;
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/src/Command/Cache/CachePurgeCommand.php:
--------------------------------------------------------------------------------
1 | dirs = $dirs;
32 | }
33 |
34 | protected function configure(): void
35 | {
36 | $this->addOption('recreate', null, InputOption::VALUE_OPTIONAL, 'Recreate folders', false);
37 | }
38 |
39 | protected function execute(InputInterface $input, OutputInterface $output): int
40 | {
41 | $style = new SymfonyStyle($input, $output);
42 | $style->title('Cache Purge');
43 |
44 | foreach ($this->dirs as $directory) {
45 | $style->text(sprintf('Purging: %s', $directory));
46 | Files::purge($directory);
47 |
48 | if (Utils::boolenize($input->getOption('recreate'))) {
49 | $style->text(sprintf('Recreating: %s', $directory));
50 | Files::mkdir($directory);
51 | }
52 | }
53 |
54 | $style->success(sprintf('Purging done. Total %d folders purged.', count($this->dirs)));
55 |
56 | return 0;
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/Command/Caching/CachingClearCommand.php:
--------------------------------------------------------------------------------
1 | storage = $storage;
29 | }
30 |
31 | protected function configure(): void
32 | {
33 | $this->addOption('all', null, InputOption::VALUE_OPTIONAL, 'Clear whole storage', false);
34 | $this->addOption('tag', 't', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Clear by tag(s)', []);
35 | $this->addOption('priority', 'p', InputOption::VALUE_OPTIONAL, 'Clear by priority');
36 | }
37 |
38 | protected function execute(InputInterface $input, OutputInterface $output): int
39 | {
40 | $style = new SymfonyStyle($input, $output);
41 | $style->title('Caching Clear');
42 |
43 | if ($input->getOption('all') === null) {
44 | $this->storage->clean([Cache::All => true]);
45 | $style->success('Clearing whole storage done.');
46 | } elseif ($input->getOption('tag') !== null) {
47 | $this->storage->clean([Cache::Tags => $input->getOption('tag')]);
48 | $style->listing((array) $input->getOption('tag'));
49 | $style->success('Clearing by tags done.');
50 | } elseif ($input->getOption('priority') !== null) {
51 | $this->storage->clean([Cache::Priority => $input->getOption('priority')]);
52 | $style->comment(Utils::stringify($input->getOption('priority')));
53 | $style->success('Clearing by priority done.');
54 | } else {
55 | $style->warning('Specify clearing strategy.');
56 |
57 | return 1;
58 | }
59 |
60 | return 0;
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/Command/DI/DIPurgeCommand.php:
--------------------------------------------------------------------------------
1 | dirs = $dirs;
30 | }
31 |
32 | protected function execute(InputInterface $input, OutputInterface $output): int
33 | {
34 | $style = new SymfonyStyle($input, $output);
35 | $style->title('DI Purge');
36 |
37 | foreach ($this->dirs as $directory) {
38 | $style->text(sprintf('Purging: %s', $directory));
39 | Files::purge($directory);
40 | }
41 |
42 | $style->success(sprintf('Purging done. Total %d folders purged.', count($this->dirs)));
43 |
44 | return 0;
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/Command/Database/BackupCommand.php:
--------------------------------------------------------------------------------
1 | backupPath = $backupPath;
28 | }
29 |
30 | protected function configure(): void
31 | {
32 | $this->addArgument('platform', InputArgument::REQUIRED, 'mysql|postgresql')
33 | ->addArgument('host', InputArgument::REQUIRED, 'SQL server IP')
34 | ->addArgument('port', InputArgument::REQUIRED, 'SQL server port')
35 | ->addArgument('username', InputArgument::REQUIRED, 'SQL server username')
36 | ->addArgument('password', InputArgument::REQUIRED, 'SQL server password')
37 | ->addArgument('database', InputArgument::REQUIRED, 'Database name')
38 | ->addArgument('path', InputArgument::OPTIONAL, 'where save backup file (backup is saved to path defined in configuration if not defined)')
39 | ->addArgument('filename', InputArgument::OPTIONAL, 'backup filename (generated automatically if not defined)')
40 | ->addOption('no-gzip', 'g', InputOption::VALUE_NONE, 'do not gzip result')
41 | ->addOption('bin-path', 'b', InputOption::VALUE_OPTIONAL, 'path to mysqldump or pg_dump binary');
42 | }
43 |
44 | protected function isGzipEnabled(): bool
45 | {
46 | exec('which gzip > /dev/null', $retParams, $retVal);
47 |
48 | return $retVal === 0;
49 | }
50 |
51 | protected function execute(InputInterface $input, OutputInterface $output): int
52 | {
53 | // Gzip compression
54 | $gzip = !(bool) $input->getOption('no-gzip');
55 |
56 | if (!$gzip) {
57 | $output->writeln('Gzip compression is disabled');
58 | } elseif (!$this->isGzipEnabled()) {
59 | $output->writeln('Error: gzip binary not found, use "--no-gzip" option');
60 |
61 | return 1;
62 | }
63 |
64 | // FileName
65 | /** @var string|null $filename */
66 | $filename = $input->getArgument('filename');
67 | /** @var string $database */
68 | $database = $input->getArgument('database');
69 |
70 | if ($filename === null || $filename === '') {
71 | $filename = $database . '.backup.' . date('d-m-Y-h-i') . (!$gzip ? '.sql' : '.gz');
72 | } elseif ($gzip && !Database::isGz($filename)) {
73 | $output->writeln('Error: expected ".gz" filename extension');
74 |
75 | return 1;
76 | } elseif (!$gzip && !Database::isSql($filename)) {
77 | $output->writeln('Error: expected ".sql" filename extension');
78 |
79 | return 1;
80 | }
81 |
82 | // Path
83 | /** @var string|null $path */
84 | $path = $input->getArgument('path');
85 |
86 | if ($path === null || $path === '') {
87 | $path = $this->backupPath;
88 | } elseif (!is_dir($path)) {
89 | $output->writeln('Error: given path "' . $path . '" was not found');
90 |
91 | return 1;
92 | }
93 |
94 | $path = rtrim($path, DIRECTORY_SEPARATOR);
95 |
96 | // Destination
97 | $backupDestination = escapeshellarg($path . DIRECTORY_SEPARATOR . $filename);
98 |
99 | // Normalize bin-path
100 | $binPath = Utils::stringify($input->getOption('bin-path'));
101 | $binPath = Database::normalizeBinPath($binPath, ['mysqldump', 'pg_dump']);
102 |
103 | // Create command
104 | /** @var string $platform */
105 | $platform = $input->getArgument('platform');
106 | /** @var string $port */
107 | $port = $input->getArgument('port');
108 | /** @var string $username */
109 | $username = $input->getArgument('username');
110 | /** @var string $password */
111 | $password = $input->getArgument('password');
112 | /** @var string $host */
113 | $host = $input->getArgument('host');
114 |
115 | if ($platform === Database::PLATFORM_MYSQL) {
116 | $port = $port !== '' ? '--port ' . $port : '';
117 | $command = $binPath . sprintf(
118 | 'mysqldump --user %s --password=\'%s\' --host %s %s --opt %s',
119 | $username,
120 | $password,
121 | $host,
122 | $port,
123 | $database
124 | );
125 | } elseif ($platform === Database::PLATFORM_POSTGRES) {
126 | $port = $port !== '' ? ':' . $port : '';
127 | $command = $binPath . sprintf(
128 | 'pg_dump --dbname=postgresql://%s:%s@%s%s/%s --blobs --no-owner',
129 | $username,
130 | $password,
131 | $host,
132 | $port,
133 | $database
134 | );
135 | } else {
136 | $output->writeln('Error: unknown database connection type');
137 |
138 | return 1;
139 | }
140 |
141 | if ($gzip) {
142 | $command .= ' | gzip -c';
143 | }
144 |
145 | $command .= ' > ' . $backupDestination;
146 |
147 | // Execute
148 | $output->writeln('Backing up database "' . $database . '"...');
149 | exec($command, $retParams, $retVal);
150 |
151 | if ($retVal === 0) {
152 | if (file_exists($backupDestination)) {
153 | $output->writeln('Backup created, see "' . $backupDestination . '" for result');
154 |
155 | if (filesize($backupDestination) < 50) {
156 | $output->writeln('Warning: created backup is empty');
157 | }
158 |
159 | return 0;
160 | }
161 |
162 | $output->writeln('Error: backup was not created');
163 | }
164 |
165 | return 1;
166 | }
167 |
168 | }
169 |
--------------------------------------------------------------------------------
/src/Command/Database/LoadCommand.php:
--------------------------------------------------------------------------------
1 | addArgument('platform', InputArgument::REQUIRED, 'mysql|postgresql')
24 | ->addArgument('host', InputArgument::REQUIRED, 'SQL server IP')
25 | ->addArgument('port', InputArgument::REQUIRED, 'SQL server port')
26 | ->addArgument('username', InputArgument::REQUIRED, 'SQL server username')
27 | ->addArgument('password', InputArgument::REQUIRED, 'SQL server password')
28 | ->addArgument('database', InputArgument::REQUIRED, 'Database name')
29 | ->addArgument('filename', InputArgument::REQUIRED, 'Full path to imported file')
30 | ->addOption('bin-path', 'b', InputOption::VALUE_OPTIONAL, 'Path to mysql or psql binary');
31 | }
32 |
33 | protected function execute(InputInterface $input, OutputInterface $output): int
34 | {
35 | // Check given file
36 | /** @var string $filename */
37 | $filename = $input->getArgument('filename');
38 |
39 | if (!file_exists($filename)) {
40 | $output->writeln('Error: file "' . $filename . '" not found');
41 |
42 | return 1;
43 | }
44 |
45 | // Setup gunzip
46 | if (Database::isSql($filename)) {
47 | $packed = false;
48 | } elseif (Database::isGz($filename)) {
49 | $packed = true;
50 |
51 | if (!$this->isGunzipEnabled()) {
52 | $output->writeln('Error: gunzip binary not found');
53 |
54 | return 1;
55 | }
56 | } else {
57 | $output->writeln('Error: unsupported file format, expected .sql or .gz file');
58 |
59 | return 1;
60 | }
61 |
62 | // Destination
63 | $filename = escapeshellarg($filename);
64 |
65 | // Normalize binPath
66 | $binPath = Utils::stringify($input->getOption('bin-path'));
67 | $binPath = Database::normalizeBinPath($binPath, ['mysql', 'psql']);
68 |
69 | // Create command
70 | /** @var string $platform */
71 | $platform = $input->getArgument('platform');
72 | /** @var string $port */
73 | $port = $input->getArgument('port');
74 | /** @var string $username */
75 | $username = $input->getArgument('username');
76 | /** @var string $password */
77 | $password = $input->getArgument('password');
78 | /** @var string $database */
79 | $database = $input->getArgument('database');
80 | /** @var string $host */
81 | $host = $input->getArgument('host');
82 |
83 | if ($platform === Database::PLATFORM_MYSQL) {
84 | $port = $port !== '' ? '--port ' . $port : '';
85 | $command = $binPath . sprintf(
86 | 'mysql --user %s --password=\'%s\' --host %s %s %s',
87 | $username,
88 | $password,
89 | $host,
90 | $port,
91 | $database
92 | );
93 | } elseif ($platform === Database::PLATFORM_POSTGRES) {
94 | $port = $port !== '' ? ':' . $port : '';
95 | $command = $binPath . sprintf(
96 | 'psql --dbname=postgresql://%s:%s@%s%s/%s',
97 | $username,
98 | $password,
99 | $host,
100 | $port,
101 | $database
102 | );
103 | } else {
104 | $output->writeln('Error: unknown database connection type');
105 |
106 | return 1;
107 | }
108 |
109 | if ($packed) {
110 | $command = 'gunzip -c ' . $filename . ' | ' . $command;
111 | } else {
112 | $command .= ' < ' . $filename;
113 | }
114 |
115 | // Execute command
116 | $output->writeln('Importing data into database "' . $database . '"...');
117 | exec($command, $retParams, $retVal);
118 |
119 | if ($retVal === 0) {
120 | $output->writeln('Import finished');
121 |
122 | return 0;
123 | }
124 |
125 | return 1;
126 | }
127 |
128 | protected function isGunzipEnabled(): bool
129 | {
130 | exec('which gunzip > /dev/null', $retParams, $retVal);
131 |
132 | return $retVal === 0;
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/Command/Latte/LattePurgeCommand.php:
--------------------------------------------------------------------------------
1 | dirs = $dirs;
30 | }
31 |
32 | protected function execute(InputInterface $input, OutputInterface $output): int
33 | {
34 | $style = new SymfonyStyle($input, $output);
35 | $style->title('Latte Purge');
36 |
37 | foreach ($this->dirs as $directory) {
38 | $style->text(sprintf('Purging: %s', $directory));
39 | Files::purge($directory);
40 | }
41 |
42 | $style->success(sprintf('Purging done. Total %d folders purged.', count($this->dirs)));
43 |
44 | return 0;
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/Command/Latte/LatteWarmupCommand.php:
--------------------------------------------------------------------------------
1 | templateFactory = $templateFactory;
40 | $this->dirs = $dirs;
41 | $this->excludeDirs = $excludeDirs;
42 | }
43 |
44 | protected function execute(InputInterface $input, OutputInterface $output): int
45 | {
46 | $style = new SymfonyStyle($input, $output);
47 | $style->title('Latte Warmup');
48 |
49 | /** @var Template $template */
50 | $template = $this->templateFactory->createTemplate();
51 | $latte = $template->getLatte();
52 |
53 | $finder = Finder::findFiles('*.latte')->from($this->dirs);
54 |
55 | if ($this->excludeDirs !== []) {
56 | $finder->exclude($this->excludeDirs);
57 | }
58 |
59 | $stats = ['ok' => 0, 'error' => 0];
60 |
61 | /** @var SplFileInfo $file */
62 | foreach ($finder as $file) {
63 | try {
64 | $latte->warmupCache($file->getPathname());
65 | $stats['ok']++;
66 |
67 | if ($output->isVerbose()) {
68 | $style->text(sprintf('Warmuping: %s', $file->getPathname()));
69 | }
70 | } catch (Throwable $e) {
71 | $stats['error']++;
72 |
73 | if ($output->isVerbose()) {
74 | $style->caution(sprintf("Warmuping error: %s\nError: %s", $file->getPathname(), $e->getMessage()));
75 | }
76 | }
77 | }
78 |
79 | if ($stats['error'] > 0) {
80 | $style->warning(sprintf(
81 | 'Warmup partial done. %d success / %d errors. Total %d files.',
82 | $stats['ok'],
83 | $stats['error'],
84 | $stats['ok'] + $stats['error']
85 | ));
86 | } else {
87 | $style->success(sprintf('Warmup done. Total %d files.', $stats['ok']));
88 | }
89 |
90 | return 0;
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/src/Command/Router/RouterDumpCommand.php:
--------------------------------------------------------------------------------
1 | router = $router;
30 | }
31 |
32 | protected function execute(InputInterface $input, OutputInterface $output): int
33 | {
34 | $table = new Table($output);
35 | $table
36 | ->setHeaders(['Mask', 'Module', 'Defaults', 'Router'])
37 | ->setRows($this->createRows());
38 |
39 | $table->render();
40 |
41 | return 0;
42 | }
43 |
44 | /**
45 | * @return array
46 | */
47 | protected function createRows(): array
48 | {
49 | return $this->analyse($this->router);
50 | }
51 |
52 | /**
53 | * @return array
54 | */
55 | protected function analyse(Router $router, ?string $module = null): array
56 | {
57 | if ($router instanceof RouteList) {
58 | $routes = $this->analyseRouteList($router, $module);
59 | } elseif ($router instanceof Route) {
60 | $routes = [(array) $this->analyseRoute($router, $module)];
61 | } else {
62 | throw new LogicalException(sprintf('Router "%s" is not supported', $router::class));
63 | }
64 |
65 | return $routes;
66 | }
67 |
68 | /**
69 | * @return array
70 | */
71 | protected function analyseRouteList(RouteList $router, ?string $module = null): array
72 | {
73 | $routes = [];
74 |
75 | foreach ($router->getRouters() as $subRouter) {
76 | if ($subRouter instanceof RouteList) {
77 | $routes = array_merge(
78 | $routes,
79 | $this->analyseRouteList($subRouter, $module . $router->getModule())
80 | );
81 | } elseif ($subRouter instanceof Route) {
82 | $routes = array_merge(
83 | $routes,
84 | [(array) $this->analyseRoute($subRouter, $module . $router->getModule())]
85 | );
86 | } else {
87 | throw new LogicalException(sprintf('Router "%s" is not supported', $router::class));
88 | }
89 | }
90 |
91 | return $routes;
92 | }
93 |
94 | /**
95 | * @return stdClass
96 | */
97 | protected function analyseRoute(Route $router, ?string $module = null): object
98 | {
99 | return (object) [
100 | 'mask' => $router->getMask(),
101 | 'module' => rtrim((string) $module, ':'),
102 | 'defaults' => $this->analyseDefaults($router->getDefaults()),
103 | 'class' => $router::class,
104 | ];
105 | }
106 |
107 | /**
108 | * @param string[] $defaults
109 | */
110 | protected function analyseDefaults(array $defaults): string
111 | {
112 | $primary = [];
113 |
114 | if (isset($defaults['presenter'])) {
115 | $primary[] = $defaults['presenter'];
116 | unset($defaults['presenter']);
117 | }
118 |
119 | if (isset($defaults['action'])) {
120 | $primary[] = $defaults['action'];
121 | unset($defaults['action']);
122 | }
123 |
124 | if (isset($defaults['id'])) {
125 | $primary[] = $defaults['id'];
126 | unset($defaults['id']);
127 | }
128 |
129 | $secondary = [];
130 |
131 | foreach ($defaults as $key => $value) {
132 | $secondary[] = sprintf('%s=>%s', $key, $value);
133 | }
134 |
135 | if ($secondary !== []) {
136 | return implode(':', $primary) . ' [' . implode(',', $secondary) . ']';
137 | }
138 |
139 | return implode(':', $primary);
140 | }
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/src/Command/Security/SecurityPasswordCommand.php:
--------------------------------------------------------------------------------
1 | passwords = $passwords;
32 | }
33 |
34 | protected function configure(): void
35 | {
36 | $this->addArgument('password', InputArgument::OPTIONAL, 'Given password');
37 | $this->addOption('count', 'c', InputOption::VALUE_OPTIONAL, '', '10');
38 | }
39 |
40 | protected function execute(InputInterface $input, OutputInterface $output): int
41 | {
42 | $style = new SymfonyStyle($input, $output);
43 | $style->title('Security Password');
44 |
45 | if ($input->getArgument('password') !== null) {
46 | // Generate one password
47 | $password = Utils::stringify($input->getArgument('password'));
48 | $style->comment('Password given');
49 | $encrypted = $this->passwords->hash($password);
50 | $style->success(sprintf('Hashed password: %s', $encrypted));
51 |
52 | return 0;
53 | } else {
54 | // Generate more passwords
55 | $table = new Table($output);
56 | $table->setHeaders(['ID', 'Generated random password']);
57 | $count = Utils::numerize($input->getOption('count'));
58 |
59 | for ($i = 1; $i <= $count; $i++) {
60 | $table->addRow([$i, $this->passwords->hash(sha1(Random::generate(50) . time() . random_bytes(20)))]);
61 |
62 | if ($i !== $count) {
63 | $table->addRow(new TableSeparator());
64 | }
65 | }
66 |
67 | $table->render();
68 | $style->success(sprintf('Total generated and hashed passwords %d.', $count));
69 |
70 | return 0;
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/Command/Utils/UtilsRandomCommand.php:
--------------------------------------------------------------------------------
1 | addOption('count', 'c', InputOption::VALUE_OPTIONAL, '', '10');
26 | $this->addOption('length', 'l', InputOption::VALUE_OPTIONAL, '', '50');
27 | }
28 |
29 | protected function execute(InputInterface $input, OutputInterface $output): int
30 | {
31 | $style = new SymfonyStyle($input, $output);
32 | $style->title('Nette Random');
33 |
34 | $table = new Table($output);
35 | $table->setHeaders(['ID', 'Generated strings']);
36 |
37 | $count = max(Utils::numerize($input->getOption('count')), 1);
38 | $length = max(Utils::numerize($input->getOption('length')), 1);
39 | for ($i = 1; $i <= $count; $i++) {
40 | $table->addRow([$i, Random::generate($length)]);
41 |
42 | if ($i !== $count) {
43 | $table->addRow(new TableSeparator());
44 | }
45 | }
46 |
47 | $table->render();
48 | $style->success(sprintf('Total generated strings %d.', $count));
49 |
50 | return 0;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/DI/AbstractCompilerExtension.php:
--------------------------------------------------------------------------------
1 | cliMode = $cliMode;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/DI/AdvancedCacheConsoleExtension.php:
--------------------------------------------------------------------------------
1 | Expect::arrayOf(
18 | Expect::anyOf(Expect::string(), Expect::array(), Expect::type(Statement::class))
19 | ),
20 | 'generators' => Expect::arrayOf(
21 | Expect::anyOf(Expect::string(), Expect::array(), Expect::type(Statement::class))
22 | ),
23 | ]);
24 | }
25 |
26 | public function getConfigSchema(): Schema
27 | {
28 | return self::createSchema();
29 | }
30 |
31 | public function loadConfiguration(): void
32 | {
33 | // Skip if isn't CLI
34 | if ($this->cliMode !== true) {
35 | return;
36 | }
37 |
38 | $builder = $this->getContainerBuilder();
39 | $config = $this->getConfig();
40 |
41 | // Register generators
42 | $generatorDefinitions = [];
43 |
44 | foreach ($config->generators as $generatorName => $generatorConfig) {
45 | $generatorDef = $builder->addDefinition($this->prefix('generator.' . $generatorName))
46 | ->setFactory($generatorConfig)
47 | ->setAutowired(false);
48 |
49 | $generatorDefinitions[$generatorName] = $generatorDef;
50 | }
51 |
52 | $builder->addDefinition($this->prefix('generatorCommand'))
53 | ->setFactory(CacheGenerateCommand::class)
54 | ->setArguments([$generatorDefinitions]);
55 |
56 | // Register cleaners
57 | $cleanerDefinitions = [];
58 |
59 | foreach ($config->cleaners as $cleanerName => $cleanerConfig) {
60 | $cleanerDef = $builder->addDefinition($this->prefix('cleaner.' . $cleanerName))
61 | ->setFactory($cleanerConfig)
62 | ->setAutowired(false);
63 |
64 | $cleanerDefinitions[$cleanerName] = $cleanerDef;
65 | }
66 |
67 | $builder->addDefinition($this->prefix('cleanCommand'))
68 | ->setFactory(CacheCleanCommand::class)
69 | ->setArguments([$cleanerDefinitions]);
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/DI/CacheConsoleExtension.php:
--------------------------------------------------------------------------------
1 | Expect::listOf('string'),
17 | ]);
18 | }
19 |
20 | public function getConfigSchema(): Schema
21 | {
22 | return self::createSchema();
23 | }
24 |
25 | public function loadConfiguration(): void
26 | {
27 | // Skip if isn't CLI
28 | if ($this->cliMode !== true) {
29 | return;
30 | }
31 |
32 | $builder = $this->getContainerBuilder();
33 | $config = $this->getConfig();
34 |
35 | // Default values cannot be in schema, arrays are merged by keys
36 | if ($config->purge === []) {
37 | $config->purge = Helpers::expand(['%tempDir%/cache'], $builder->parameters);
38 | }
39 |
40 | $builder->addDefinition($this->prefix('purge'))
41 | ->setFactory(CachePurgeCommand::class, [$config->purge]);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/DI/CachingConsoleExtension.php:
--------------------------------------------------------------------------------
1 | cliMode !== true) {
14 | return;
15 | }
16 |
17 | $builder = $this->getContainerBuilder();
18 |
19 | $builder->addDefinition($this->prefix('clear'))
20 | ->setFactory(CachingClearCommand::class);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/DI/ConsoleBridgesExtension.php:
--------------------------------------------------------------------------------
1 | > */
14 | private array $map = [
15 | 'advancedCache' => AdvancedCacheConsoleExtension::class,
16 | 'cache' => CacheConsoleExtension::class,
17 | 'caching' => CachingConsoleExtension::class,
18 | 'di' => DIConsoleExtension::class,
19 | 'latte' => LatteConsoleExtension::class,
20 | 'router' => RouterConsoleExtension::class,
21 | 'security' => SecurityConsoleExtension::class,
22 | 'utils' => UtilsConsoleExtension::class,
23 | ];
24 |
25 | /** @var CompilerExtension[] */
26 | private array $passes = [];
27 |
28 | public function getConfigSchema(): Schema
29 | {
30 | $advancedCache = AdvancedCacheConsoleExtension::createSchema();
31 | $cache = CacheConsoleExtension::createSchema();
32 | $di = DIConsoleExtension::createSchema();
33 | $latte = LatteConsoleExtension::createSchema();
34 |
35 | return Expect::structure([
36 | 'advancedCache' => Expect::anyOf(false, $advancedCache)->default($advancedCache),
37 | 'cache' => Expect::anyOf(false, $cache)->default($cache),
38 | 'caching' => Expect::anyOf(false),
39 | 'di' => Expect::anyOf(false, $di)->default($di),
40 | 'latte' => Expect::anyOf(false, $latte)->default($latte),
41 | 'router' => Expect::anyOf(false),
42 | 'security' => Expect::anyOf(false),
43 | 'utils' => Expect::anyOf(false),
44 | ])->castTo('array');
45 | }
46 |
47 | public function loadConfiguration(): void
48 | {
49 | // Skip if isn't CLI
50 | if ($this->cliMode !== true) {
51 | return;
52 | }
53 |
54 | /** @var mixed[] $config */
55 | $config = $this->config;
56 |
57 | /** @var false|array|object|null $bridgeConfig */
58 | foreach ($config as $bridge => $bridgeConfig) {
59 | // Don't register sub extension
60 |
61 | if ($bridgeConfig === false) {
62 | continue;
63 | }
64 |
65 | /** @var CompilerExtension $pass */
66 | $pass = new $this->map[$bridge]($this->cliMode);
67 | $pass->setCompiler($this->compiler, $this->prefix($bridge));
68 |
69 | if ($bridgeConfig !== null) {
70 | $pass->setConfig($bridgeConfig);
71 | }
72 |
73 | $pass->loadConfiguration();
74 |
75 | // Register sub extension a.k.a CompilerPass
76 | $this->passes[$bridge] = $pass;
77 | }
78 | }
79 |
80 | public function beforeCompile(): void
81 | {
82 | // Skip if isn't CLI
83 | if ($this->cliMode !== true) {
84 | return;
85 | }
86 |
87 | foreach ($this->passes as $pass) {
88 | $pass->beforeCompile();
89 | }
90 | }
91 |
92 | public function afterCompile(ClassType $class): void
93 | {
94 | // Skip if isn't CLI
95 | if ($this->cliMode !== true) {
96 | return;
97 | }
98 |
99 | foreach ($this->passes as $pass) {
100 | $pass->afterCompile($class);
101 | }
102 | }
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/src/DI/DIConsoleExtension.php:
--------------------------------------------------------------------------------
1 | Expect::listOf('string'),
17 | ]);
18 | }
19 |
20 | public function getConfigSchema(): Schema
21 | {
22 | return self::createSchema();
23 | }
24 |
25 | public function loadConfiguration(): void
26 | {
27 | // Skip if isn't CLI
28 | if ($this->cliMode !== true) {
29 | return;
30 | }
31 |
32 | $builder = $this->getContainerBuilder();
33 | $config = $this->getConfig();
34 |
35 | // Default values cannot be in schema, arrays are merged by keys
36 | if ($config->purge === []) {
37 | $config->purge = Helpers::expand(['%tempDir%/cache/nette.configurator'], $builder->parameters);
38 | }
39 |
40 | $builder->addDefinition($this->prefix('purge'))
41 | ->setFactory(DIPurgeCommand::class, [$config->purge]);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/DI/DatabaseConsoleExtension.php:
--------------------------------------------------------------------------------
1 | Expect::string()->required(),
17 | 'consoleMode' => Expect::bool(false),
18 | ]);
19 | }
20 |
21 | public function loadConfiguration(): void
22 | {
23 | // Skip if isn't CLI
24 | if ($this->cliMode !== true) {
25 | return;
26 | }
27 |
28 | $builder = $this->getContainerBuilder();
29 | $config = $this->getConfig();
30 |
31 | $builder->addDefinition($this->prefix('backupCommand'))
32 | ->setFactory(BackupCommand::class, [$config->backupPath])
33 | ->setAutowired(false);
34 |
35 | $builder->addDefinition($this->prefix('loadCommand'))
36 | ->setFactory(LoadCommand::class)
37 | ->setAutowired(false);
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/DI/LatteConsoleExtension.php:
--------------------------------------------------------------------------------
1 | Expect::listOf('string'),
18 | 'warmupExclude' => Expect::listOf('string'),
19 | 'purge' => Expect::listOf('string'),
20 | ]);
21 | }
22 |
23 | public function getConfigSchema(): Schema
24 | {
25 | return self::createSchema();
26 | }
27 |
28 | public function loadConfiguration(): void
29 | {
30 | // Skip if isn't CLI
31 | if ($this->cliMode !== true) {
32 | return;
33 | }
34 |
35 | $builder = $this->getContainerBuilder();
36 | $config = $this->getConfig();
37 |
38 | // Default values cannot be in schema, arrays are merged by keys
39 | if ($config->warmup === []) {
40 | $config->warmup = Helpers::expand(['%appDir%'], $builder->parameters);
41 | }
42 |
43 | if ($config->purge === []) {
44 | $config->purge = Helpers::expand(['%tempDir%/cache/latte'], $builder->parameters);
45 | }
46 |
47 | $builder->addDefinition($this->prefix('warmup'))
48 | ->setFactory(LatteWarmupCommand::class, [
49 | 1 => $config->warmup,
50 | 2 => $config->warmupExclude,
51 | ]);
52 |
53 | $builder->addDefinition($this->prefix('purge'))
54 | ->setFactory(LattePurgeCommand::class, [$config->purge]);
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/DI/RouterConsoleExtension.php:
--------------------------------------------------------------------------------
1 | cliMode !== true) {
14 | return;
15 | }
16 |
17 | $builder = $this->getContainerBuilder();
18 |
19 | $builder->addDefinition($this->prefix('dump'))
20 | ->setFactory(RouterDumpCommand::class);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/DI/SecurityConsoleExtension.php:
--------------------------------------------------------------------------------
1 | cliMode !== true) {
14 | return;
15 | }
16 |
17 | $builder = $this->getContainerBuilder();
18 |
19 | $builder->addDefinition($this->prefix('password'))
20 | ->setFactory(SecurityPasswordCommand::class);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/DI/UtilsConsoleExtension.php:
--------------------------------------------------------------------------------
1 | cliMode !== true) {
14 | return;
15 | }
16 |
17 | $builder = $this->getContainerBuilder();
18 |
19 | $builder->addDefinition($this->prefix('random'))
20 | ->setFactory(UtilsRandomCommand::class);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/Exception/LogicalException.php:
--------------------------------------------------------------------------------
1 | realpath($path), $ignored);
36 |
37 | /** @var SplFileObject $entry */
38 | foreach ($iterator as $entry) {
39 | if (!in_array(str_replace('\\', '/', (string) $entry->getRealPath()), $ignored, true)) {
40 | if ($entry->isDir()) {
41 | rmdir((string) $entry->getRealPath());
42 | } else {
43 | unlink((string) $entry->getRealPath());
44 | }
45 | }
46 | }
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/Utils/Utils.php:
--------------------------------------------------------------------------------
1 |