TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\Console;
|
||||
|
||||
use Symfony\Component\Console\Application as SymfonyConsoleApplication;
|
||||
use Symfony\Component\Console\Exception\ExceptionInterface;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
use TYPO3\CMS\Core\Adapter\EventDispatcherAdapter as SymfonyEventDispatcher;
|
||||
use TYPO3\CMS\Core\Authentication\CommandLineUserAuthentication;
|
||||
use TYPO3\CMS\Core\Configuration\ConfigurationManager;
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Context\DateTimeAspect;
|
||||
use TYPO3\CMS\Core\Context\UserAspect;
|
||||
use TYPO3\CMS\Core\Context\VisibilityAspect;
|
||||
use TYPO3\CMS\Core\Context\WorkspaceAspect;
|
||||
use TYPO3\CMS\Core\Core\ApplicationInterface;
|
||||
use TYPO3\CMS\Core\Core\BootService;
|
||||
use TYPO3\CMS\Core\Core\Bootstrap;
|
||||
use TYPO3\CMS\Core\Domain\DateTimeFactory;
|
||||
use TYPO3\CMS\Core\Information\Typo3Version;
|
||||
use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
|
||||
|
||||
/**
|
||||
* Entry point for the TYPO3 Command Line for Commands
|
||||
* In addition to a simple Symfony Command, this also sets up a CLI user
|
||||
*/
|
||||
class CommandApplication implements ApplicationInterface
|
||||
{
|
||||
protected Context $context;
|
||||
|
||||
protected CommandRegistry $commandRegistry;
|
||||
|
||||
protected ConfigurationManager $configurationManager;
|
||||
|
||||
protected BootService $bootService;
|
||||
|
||||
protected LanguageServiceFactory $languageServiceFactory;
|
||||
|
||||
protected SymfonyConsoleApplication $application;
|
||||
|
||||
public function __construct(
|
||||
Context $context,
|
||||
CommandRegistry $commandRegistry,
|
||||
EventDispatcherInterface $eventDispatcher,
|
||||
ConfigurationManager $configurationMananger,
|
||||
BootService $bootService,
|
||||
LanguageServiceFactory $languageServiceFactory
|
||||
) {
|
||||
$this->context = $context;
|
||||
$this->commandRegistry = $commandRegistry;
|
||||
$this->configurationManager = $configurationMananger;
|
||||
$this->bootService = $bootService;
|
||||
$this->languageServiceFactory = $languageServiceFactory;
|
||||
|
||||
$this->checkEnvironmentOrDie();
|
||||
$this->application = new Application('TYPO3 CMS', (new Typo3Version())->getVersion());
|
||||
$this->application->setAutoExit(false);
|
||||
$this->application->setDispatcher($eventDispatcher);
|
||||
$this->application->setCommandLoader($commandRegistry);
|
||||
// Replace default list command with TYPO3 override
|
||||
$this->application->addCommands([$commandRegistry->get('list')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the Symfony Console application in this TYPO3 application
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$input = new ArgvInput();
|
||||
$output = new ConsoleOutput();
|
||||
|
||||
$commandName = $this->getCommandName($input);
|
||||
if ($this->wantsFullBoot($commandName)) {
|
||||
// Do a full container boot if command is not a 1:1 matching low-level command
|
||||
$container = $this->bootService->getContainer();
|
||||
$eventDispatcher = $container->get(SymfonyEventDispatcher::class);
|
||||
$commandRegistry = $container->get(CommandRegistry::class);
|
||||
$this->application->setDispatcher($eventDispatcher);
|
||||
$this->application->setCommandLoader($commandRegistry);
|
||||
$this->context = $container->get(Context::class);
|
||||
|
||||
$realName = $this->resolveShortcut($commandName, $commandRegistry);
|
||||
$isLowLevelCommandShortcut = $realName !== null && !$this->wantsFullBoot($realName);
|
||||
// Load ext_localconf, except if a low level command shortcut was found
|
||||
// or if essential configuration is missing
|
||||
if (!$isLowLevelCommandShortcut && Bootstrap::checkIfEssentialConfigurationExists($this->configurationManager)) {
|
||||
$this->bootService->loadExtLocalconfDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure output is not buffered, so command-line output and interaction can take place.
|
||||
// Bootstrap does not open a buffer anymore, but third-party extension code may have done
|
||||
// so while ext_localconf.php files were loaded.
|
||||
while (ob_get_level()) {
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
$this->initializeContext();
|
||||
// create the BE_USER object (not logged in yet)
|
||||
Bootstrap::initializeBackendUser(CommandLineUserAuthentication::class);
|
||||
$GLOBALS['LANG'] = $this->languageServiceFactory->createFromUserPreferences($GLOBALS['BE_USER']);
|
||||
|
||||
$exitCode = $this->application->run($input, $output);
|
||||
// exit codes > 255 are not handled in UNIX
|
||||
if ($exitCode > 255) {
|
||||
$exitCode = 255;
|
||||
}
|
||||
|
||||
exit($exitCode);
|
||||
}
|
||||
|
||||
private function resolveShortcut(string $commandName, CommandRegistry $commandRegistry): ?string
|
||||
{
|
||||
if ($commandRegistry->has($commandName)) {
|
||||
return $commandName;
|
||||
}
|
||||
|
||||
$allCommands = $commandRegistry->getNames();
|
||||
$expr = implode('[^:]*:', array_map(preg_quote(...), explode(':', $commandName))) . '[^:]*';
|
||||
$commands = preg_grep('{^' . $expr . '}', $allCommands);
|
||||
|
||||
if ($commands === false || count($commands) === 0) {
|
||||
$commands = preg_grep('{^' . $expr . '}i', $allCommands);
|
||||
}
|
||||
|
||||
if ($commands === false || count($commands) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return reset($commands);
|
||||
}
|
||||
|
||||
protected function wantsFullBoot(string $commandName): bool
|
||||
{
|
||||
if ($commandName === 'help') {
|
||||
return true;
|
||||
}
|
||||
return !$this->commandRegistry->has($commandName);
|
||||
}
|
||||
|
||||
protected function getCommandName(ArgvInput $input): string
|
||||
{
|
||||
try {
|
||||
$input->bind($this->application->getDefinition());
|
||||
} catch (ExceptionInterface $e) {
|
||||
// Errors must be ignored, full binding/validation happens later when the console application runs.
|
||||
}
|
||||
|
||||
return $input->getFirstArgument() ?? 'list';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the script is called from a cli environment.
|
||||
*/
|
||||
protected function checkEnvironmentOrDie(): void
|
||||
{
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
die('Not called from a command line interface (e.g. a shell or scheduler).' . LF);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the Context used for accessing data and finding out the current state of the application
|
||||
*/
|
||||
protected function initializeContext(): void
|
||||
{
|
||||
$this->context->setAspect('date', new DateTimeAspect(DateTimeFactory::createFromTimestamp($GLOBALS['EXEC_TIME'])));
|
||||
$this->context->setAspect('visibility', new VisibilityAspect(true, true, false, true));
|
||||
$this->context->setAspect('workspace', new WorkspaceAspect(0));
|
||||
$this->context->setAspect('backend.user', new UserAspect(null));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user