first commit
This commit is contained in:
commit
1218dd1517
12716 files changed
+989233
No files matched your search
@@ -0,0 +1,289 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Mvc\Cli;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Extbase\Reflection\ClassSchema;
|
||||
|
||||
/**
|
||||
* Represents a Command
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Use symfony/console commands instead.
|
||||
*/
|
||||
class Command
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $controllerClassName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $controllerCommandName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $commandIdentifier;
|
||||
|
||||
/**
|
||||
* Name of the extension to which this command belongs
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $extensionName;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
|
||||
*/
|
||||
protected $reflectionService;
|
||||
|
||||
/**
|
||||
* @var ClassSchema
|
||||
*/
|
||||
protected $classSchema;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $controllerCommandMethod;
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService
|
||||
*/
|
||||
public function injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
|
||||
{
|
||||
$this->reflectionService = $reflectionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $controllerClassName Class name of the controller providing the command
|
||||
* @param string $controllerCommandName Command name, i.e. the method name of the command, without the "Command" suffix
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct($controllerClassName, $controllerCommandName)
|
||||
{
|
||||
$this->controllerClassName = $controllerClassName;
|
||||
$this->controllerCommandName = $controllerCommandName;
|
||||
$this->controllerCommandMethod = $this->controllerCommandName . 'Command';
|
||||
$classNameParts = explode('\\', $controllerClassName);
|
||||
if (isset($classNameParts[0]) && $classNameParts[0] === 'TYPO3' && isset($classNameParts[1]) && $classNameParts[1] === 'CMS') {
|
||||
$classNameParts[0] .= '\\' . $classNameParts[1];
|
||||
unset($classNameParts[1]);
|
||||
$classNameParts = array_values($classNameParts);
|
||||
}
|
||||
$numberOfClassNameParts = count($classNameParts);
|
||||
if ($numberOfClassNameParts < 3) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Controller class names must at least consist of three parts: vendor, extension name and path.',
|
||||
1438782187
|
||||
);
|
||||
}
|
||||
if (strpos($classNameParts[$numberOfClassNameParts - 1], 'CommandController') === false) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid controller class name "' . $controllerClassName . '". Class name must end with "CommandController".',
|
||||
1305100019
|
||||
);
|
||||
}
|
||||
|
||||
$this->extensionName = $classNameParts[1];
|
||||
$extensionKey = \TYPO3\CMS\Core\Utility\GeneralUtility::camelCaseToLowerCaseUnderscored($this->extensionName);
|
||||
$this->commandIdentifier = strtolower($extensionKey . ':' . substr($classNameParts[$numberOfClassNameParts - 1], 0, -17) . ':' . $controllerCommandName);
|
||||
}
|
||||
|
||||
public function initializeObject()
|
||||
{
|
||||
$this->classSchema = $this->reflectionService->getClassSchema($this->controllerClassName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getControllerClassName()
|
||||
{
|
||||
return $this->controllerClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getControllerCommandName()
|
||||
{
|
||||
return $this->controllerCommandName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command identifier for this command
|
||||
*
|
||||
* @return string The command identifier for this command, following the pattern extensionname:controllername:commandname
|
||||
*/
|
||||
public function getCommandIdentifier()
|
||||
{
|
||||
return $this->commandIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the extension to which this command belongs
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getExtensionName()
|
||||
{
|
||||
return $this->extensionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a short description of this command
|
||||
*
|
||||
* @return string A short description
|
||||
*/
|
||||
public function getShortDescription()
|
||||
{
|
||||
$lines = explode(LF, $this->classSchema->getMethod($this->controllerCommandMethod)['description']);
|
||||
return !empty($lines) ? trim($lines[0]) : '<no description available>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a longer description of this command
|
||||
* This is the complete method description except for the first line which can be retrieved via getShortDescription()
|
||||
* If The command description only consists of one line, an empty string is returned
|
||||
*
|
||||
* @return string A longer description of this command
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
$lines = explode(LF, $this->classSchema->getMethod($this->controllerCommandMethod)['description']);
|
||||
array_shift($lines);
|
||||
$descriptionLines = [];
|
||||
foreach ($lines as $line) {
|
||||
$trimmedLine = trim($line);
|
||||
if ($descriptionLines !== [] || $trimmedLine !== '') {
|
||||
$descriptionLines[] = $trimmedLine;
|
||||
}
|
||||
}
|
||||
return implode(LF, $descriptionLines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if this command expects required and/or optional arguments, otherwise FALSE
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasArguments()
|
||||
{
|
||||
return !empty($this->classSchema->getMethod($this->controllerCommandMethod)['params']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of \TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition that contains
|
||||
* information about required/optional arguments of this command.
|
||||
* If the command does not expect any arguments, an empty array is returned
|
||||
*
|
||||
* @return array<\TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition>
|
||||
*/
|
||||
public function getArgumentDefinitions()
|
||||
{
|
||||
if (!$this->hasArguments()) {
|
||||
return [];
|
||||
}
|
||||
$commandArgumentDefinitions = [];
|
||||
$commandParameters = $this->classSchema->getMethod($this->controllerCommandMethod)['params'];
|
||||
$commandParameterTags = $this->classSchema->getMethod($this->controllerCommandMethod)['tags']['param'];
|
||||
$i = 0;
|
||||
foreach ($commandParameters as $commandParameterName => $commandParameterDefinition) {
|
||||
$explodedAnnotation = preg_split('/\s+/', $commandParameterTags[$i], 3);
|
||||
$description = !empty($explodedAnnotation[2]) ? $explodedAnnotation[2] : '';
|
||||
$required = $commandParameterDefinition['optional'] !== true;
|
||||
$commandArgumentDefinitions[] = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition::class, $commandParameterName, $required, $description);
|
||||
$i++;
|
||||
}
|
||||
return $commandArgumentDefinitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this command is internal and thus should not be exposed through help texts, user documentation etc.
|
||||
* Internall commands are still accessible through the regular command line interface, but should not be used
|
||||
* by users.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isInternal()
|
||||
{
|
||||
return isset($this->classSchema->getMethod($this->controllerCommandMethod)['tags']['internal']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this command is meant to be used on CLI only.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isCliOnly()
|
||||
{
|
||||
return isset($this->classSchema->getMethod($this->controllerCommandMethod)['tags']['cli']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this command flushes all caches and thus needs special attention in the interactive shell.
|
||||
*
|
||||
* Note that neither this method nor the @flushesCaches annotation is currently part of the official API.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @deprecated will be removed in TYPO3 v10.0.
|
||||
*/
|
||||
public function isFlushingCaches()
|
||||
{
|
||||
trigger_error(
|
||||
'Method isFlushingCaches() will be removed in TYPO3 v10.0. Do not call from other extension.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
return isset($this->classSchema->getMethod($this->controllerCommandMethod)['tags']['flushesCaches']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of command identifiers which were specified in the "@see"
|
||||
* annotation of a command method.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRelatedCommandIdentifiers()
|
||||
{
|
||||
if (!isset($this->classSchema->getMethod($this->controllerCommandMethod)['tags']['see'])) {
|
||||
return [];
|
||||
}
|
||||
$relatedCommandIdentifiers = [];
|
||||
foreach ($this->classSchema->getMethod($this->controllerCommandMethod)['tags']['see'] as $tagValue) {
|
||||
if (preg_match('/^[\\w\\d\\.]+:[\\w\\d]+:[\\w\\d]+$/', $tagValue) === 1) {
|
||||
$relatedCommandIdentifiers[] = $tagValue;
|
||||
}
|
||||
}
|
||||
return $relatedCommandIdentifiers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Mvc\Cli;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a CommandArgumentDefinition
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Use symfony/console commands instead.
|
||||
*/
|
||||
class CommandArgumentDefinition
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name = '';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $required = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $name name of the command argument (= parameter name)
|
||||
* @param bool $required defines whether this argument is required or optional
|
||||
* @param string $description description of the argument
|
||||
*/
|
||||
public function __construct($name, $required, $description)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->required = $required;
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lowercased name with dashes as word separator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDashedName()
|
||||
{
|
||||
$dashedName = ucfirst($this->name);
|
||||
$dashedName = preg_replace('/([A-Z][a-z0-9]+)/', '$1-', $dashedName);
|
||||
return '--' . strtolower(substr($dashedName, 0, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function isRequired()
|
||||
{
|
||||
return $this->required;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Mvc\Cli;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* A helper for CLI commands
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Use symfony/console commands instead.
|
||||
*/
|
||||
class CommandManager implements \TYPO3\CMS\Core\SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @var array<\TYPO3\CMS\Extbase\Mvc\Cli\Command>
|
||||
*/
|
||||
protected $availableCommands;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $shortCommandIdentifiers;
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all commands
|
||||
*
|
||||
* @return Command[]
|
||||
*/
|
||||
public function getAvailableCommands()
|
||||
{
|
||||
if ($this->availableCommands === null) {
|
||||
$this->availableCommands = [];
|
||||
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'] ?? [] as $className) {
|
||||
if (!class_exists($className)) {
|
||||
continue;
|
||||
}
|
||||
foreach (get_class_methods($className) as $methodName) {
|
||||
if (substr($methodName, -7, 7) === 'Command') {
|
||||
$this->availableCommands[] = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Cli\Command::class, $className, substr($methodName, 0, -7));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->availableCommands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Command that matches the given identifier.
|
||||
* If no Command could be found a CommandNotFoundException is thrown
|
||||
* If more than one Command matches an AmbiguousCommandIdentifierException is thrown that contains the matched Commands
|
||||
*
|
||||
* @param string $commandIdentifier command identifier in the format foo:bar:baz
|
||||
* @return Command
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchCommandException if no matching command is available
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\AmbiguousCommandIdentifierException if more than one Command matches the identifier (the exception contains the matched commands)
|
||||
*/
|
||||
public function getCommandByIdentifier($commandIdentifier)
|
||||
{
|
||||
$commandIdentifier = strtolower(trim($commandIdentifier));
|
||||
if ($commandIdentifier === 'help') {
|
||||
$commandIdentifier = 'extbase:help:help';
|
||||
}
|
||||
$matchedCommands = [];
|
||||
$availableCommands = $this->getAvailableCommands();
|
||||
foreach ($availableCommands as $command) {
|
||||
if ($this->commandMatchesIdentifier($command, $commandIdentifier)) {
|
||||
$matchedCommands[] = $command;
|
||||
}
|
||||
}
|
||||
if (empty($matchedCommands)) {
|
||||
throw new \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchCommandException('No command could be found that matches the command identifier "' . $commandIdentifier . '".', 1310556663);
|
||||
}
|
||||
if (count($matchedCommands) > 1) {
|
||||
throw new \TYPO3\CMS\Extbase\Mvc\Exception\AmbiguousCommandIdentifierException('More than one command matches the command identifier "' . $commandIdentifier . '"', 1310557169, null, $matchedCommands);
|
||||
}
|
||||
return current($matchedCommands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shortest, non-ambiguous command identifier for the given command
|
||||
*
|
||||
* @param Command $command The command
|
||||
* @return string The shortest possible command identifier
|
||||
*/
|
||||
public function getShortestIdentifierForCommand(Command $command)
|
||||
{
|
||||
if ($command->getCommandIdentifier() === 'extbase:help:help') {
|
||||
return 'help';
|
||||
}
|
||||
$shortCommandIdentifiers = $this->getShortCommandIdentifiers();
|
||||
if (!isset($shortCommandIdentifiers[$command->getCommandIdentifier()])) {
|
||||
$command->getCommandIdentifier();
|
||||
}
|
||||
return $shortCommandIdentifiers[$command->getCommandIdentifier()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array that contains all available command identifiers and their shortest non-ambiguous alias
|
||||
*
|
||||
* @return array in the format array('full.command:identifier1' => 'alias1', 'full.command:identifier2' => 'alias2')
|
||||
*/
|
||||
protected function getShortCommandIdentifiers()
|
||||
{
|
||||
if ($this->shortCommandIdentifiers === null) {
|
||||
$commandsByCommandName = [];
|
||||
foreach ($this->getAvailableCommands() as $availableCommand) {
|
||||
list($extensionKey, $controllerName, $commandName) = explode(':', $availableCommand->getCommandIdentifier());
|
||||
if (!isset($commandsByCommandName[$commandName])) {
|
||||
$commandsByCommandName[$commandName] = [];
|
||||
}
|
||||
if (!isset($commandsByCommandName[$commandName][$controllerName])) {
|
||||
$commandsByCommandName[$commandName][$controllerName] = [];
|
||||
}
|
||||
$commandsByCommandName[$commandName][$controllerName][] = $extensionKey;
|
||||
}
|
||||
foreach ($this->getAvailableCommands() as $availableCommand) {
|
||||
list($extensionKey, $controllerName, $commandName) = explode(':', $availableCommand->getCommandIdentifier());
|
||||
if (count($commandsByCommandName[$commandName][$controllerName]) > 1) {
|
||||
$this->shortCommandIdentifiers[$availableCommand->getCommandIdentifier()] = sprintf('%s:%s:%s', $extensionKey, $controllerName, $commandName);
|
||||
} else {
|
||||
$this->shortCommandIdentifiers[$availableCommand->getCommandIdentifier()] = sprintf('%s:%s', $controllerName, $commandName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->shortCommandIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if the specified command identifier matches the identifier of the specified command.
|
||||
* This is the case, if the identifiers are the same or if at least the last two command parts match (case sensitive).
|
||||
*
|
||||
* @param Command $command
|
||||
* @param string $commandIdentifier command identifier in the format foo:bar:baz (all lower case)
|
||||
* @return bool TRUE if the specified command identifier matches this commands identifier
|
||||
*/
|
||||
protected function commandMatchesIdentifier(Command $command, $commandIdentifier)
|
||||
{
|
||||
$commandIdentifierParts = explode(':', $command->getCommandIdentifier());
|
||||
$searchedCommandIdentifierParts = explode(':', $commandIdentifier);
|
||||
$extensionKey = array_shift($commandIdentifierParts);
|
||||
if (count($searchedCommandIdentifierParts) === 3) {
|
||||
$searchedExtensionKey = array_shift($searchedCommandIdentifierParts);
|
||||
if ($searchedExtensionKey !== $extensionKey) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (count($searchedCommandIdentifierParts) !== 2) {
|
||||
return false;
|
||||
}
|
||||
return $searchedCommandIdentifierParts === $commandIdentifierParts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Mvc\Cli;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Helper\FormatterHelper;
|
||||
use Symfony\Component\Console\Helper\HelperSet;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput as SymfonyConsoleOutput;
|
||||
use Symfony\Component\Console\Question\ChoiceQuestion;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
|
||||
/**
|
||||
* A wrapper for Symfony ConsoleOutput and related helpers
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Use symfony/console commands instead.
|
||||
*/
|
||||
class ConsoleOutput
|
||||
{
|
||||
/**
|
||||
* @var ArgvInput
|
||||
*/
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* @var SymfonyConsoleOutput
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* @var QuestionHelper
|
||||
*/
|
||||
protected $questionHelper;
|
||||
|
||||
/**
|
||||
* @var ProgressBar
|
||||
*/
|
||||
protected $progressBar;
|
||||
|
||||
/**
|
||||
* @var Table
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* Creates and initializes the Symfony I/O instances
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->output = new SymfonyConsoleOutput();
|
||||
$this->output->getFormatter()->setStyle('b', new OutputFormatterStyle(null, null, ['bold']));
|
||||
$this->output->getFormatter()->setStyle('i', new OutputFormatterStyle('black', 'white'));
|
||||
$this->output->getFormatter()->setStyle('u', new OutputFormatterStyle(null, null, ['underscore']));
|
||||
$this->output->getFormatter()->setStyle('em', new OutputFormatterStyle(null, null, ['reverse']));
|
||||
$this->output->getFormatter()->setStyle('strike', new OutputFormatterStyle(null, null, ['conceal']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the desired maximum line length for console output.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getMaximumLineLength()
|
||||
{
|
||||
return 79;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs specified text to the console window
|
||||
* You can specify arguments that will be passed to the text via sprintf
|
||||
* @see http://www.php.net/sprintf
|
||||
*
|
||||
* @param string $text Text to output
|
||||
* @param array $arguments Optional arguments to use for sprintf
|
||||
*/
|
||||
public function output($text, array $arguments = [])
|
||||
{
|
||||
if ($arguments !== []) {
|
||||
$text = vsprintf($text, $arguments);
|
||||
}
|
||||
$this->output->write($text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs specified text to the console window and appends a line break
|
||||
*
|
||||
* @param string $text Text to output
|
||||
* @param array $arguments Optional arguments to use for sprintf
|
||||
* @see output()
|
||||
* @see outputLines()
|
||||
*/
|
||||
public function outputLine($text = '', array $arguments = [])
|
||||
{
|
||||
$this->output($text . PHP_EOL, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given text to fit into the maximum line length and outputs it to the
|
||||
* console window
|
||||
*
|
||||
* @param string $text Text to output
|
||||
* @param array $arguments Optional arguments to use for sprintf
|
||||
* @param int $leftPadding The number of spaces to use for indentation
|
||||
* @see outputLine()
|
||||
*/
|
||||
public function outputFormatted($text = '', array $arguments = [], $leftPadding = 0)
|
||||
{
|
||||
$lines = explode(PHP_EOL, $text);
|
||||
foreach ($lines as $line) {
|
||||
$formattedText = str_repeat(' ', $leftPadding) . wordwrap($line, $this->getMaximumLineLength() - $leftPadding, PHP_EOL . str_repeat(' ', $leftPadding), true);
|
||||
$this->outputLine($formattedText, $arguments);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a table like output of the given $rows
|
||||
*
|
||||
* @param array $rows
|
||||
* @param array $headers
|
||||
*/
|
||||
public function outputTable($rows, $headers = null)
|
||||
{
|
||||
$table = $this->getTable();
|
||||
if ($headers !== null) {
|
||||
$table->setHeaders($headers);
|
||||
}
|
||||
$table->setRows($rows);
|
||||
$table->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the user to select a value
|
||||
*
|
||||
* @param string|array $question The question to ask. If an array each array item is turned into one line of a multi-line question
|
||||
* @param array $choices List of choices to pick from
|
||||
* @param bool $default The default answer if the user enters nothing
|
||||
* @param bool $multiSelect If TRUE the result will be an array with the selected options. Multiple options can be given separated by commas
|
||||
* @param int|null $attempts Max number of times to ask before giving up (null by default, which means infinite)
|
||||
* @return int|string|array The selected value or values (the key of the choices array)
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function select($question, $choices, $default = null, $multiSelect = false, $attempts = null)
|
||||
{
|
||||
$question = (new ChoiceQuestion($question, $choices, $default))
|
||||
->setMultiselect($multiSelect)
|
||||
->setMaxAttempts($attempts)
|
||||
->setErrorMessage('Value "%s" is invalid');
|
||||
|
||||
return $this->getQuestionHelper()->ask($this->getInput(), $this->output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks a question to the user
|
||||
*
|
||||
* @param string|array $question The question to ask. If an array each array item is turned into one line of a multi-line question
|
||||
* @param string $default The default answer if none is given by the user
|
||||
* @param array $autocomplete List of values to autocomplete. This only works if "stty" is installed
|
||||
* @return string The user answer
|
||||
* @throws \RuntimeException If there is no data to read in the input stream
|
||||
*/
|
||||
public function ask($question, $default = null, array $autocomplete = null)
|
||||
{
|
||||
$question = (new Question($question, $default))
|
||||
->setAutocompleterValues($autocomplete);
|
||||
|
||||
return $this->getQuestionHelper()->ask($this->getInput(), $this->output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks a confirmation to the user.
|
||||
*
|
||||
* The question will be asked until the user answers by nothing, yes, or no.
|
||||
*
|
||||
* @param string|array $question The question to ask. If an array each array item is turned into one line of a multi-line question
|
||||
* @param bool $default The default answer if the user enters nothing
|
||||
* @return bool true if the user has confirmed, false otherwise
|
||||
*/
|
||||
public function askConfirmation($question, $default = true)
|
||||
{
|
||||
$question = new ConfirmationQuestion($question, $default);
|
||||
|
||||
return $this->getQuestionHelper()->ask($this->getInput(), $this->output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks a question to the user, the response is hidden
|
||||
*
|
||||
* @param string|array $question The question. If an array each array item is turned into one line of a multi-line question
|
||||
* @param bool $fallback In case the response can not be hidden, whether to fallback on non-hidden question or not
|
||||
* @return string The answer
|
||||
* @throws \RuntimeException In case the fallback is deactivated and the response can not be hidden
|
||||
*/
|
||||
public function askHiddenResponse($question, $fallback = true)
|
||||
{
|
||||
$question = (new Question($question))
|
||||
->setHidden(true)
|
||||
->setHiddenFallback($fallback);
|
||||
|
||||
return $this->getQuestionHelper()->ask($this->getInput(), $this->output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks for a value and validates the response
|
||||
*
|
||||
* The validator receives the data to validate. It must return the
|
||||
* validated data when the data is valid and throw an exception
|
||||
* otherwise.
|
||||
*
|
||||
* @param string|array $question The question to ask. If an array each array item is turned into one line of a multi-line question
|
||||
* @param callable $validator A PHP callback that gets a value and is expected to return the (transformed) value or throw an exception if it wasn't valid
|
||||
* @param int|null $attempts Max number of times to ask before giving up (null by default, which means infinite)
|
||||
* @param string $default The default answer if none is given by the user
|
||||
* @param array $autocomplete List of values to autocomplete. This only works if "stty" is installed
|
||||
* @return mixed
|
||||
* @throws \Exception When any of the validators return an error
|
||||
*/
|
||||
public function askAndValidate($question, $validator, $attempts = null, $default = null, array $autocomplete = null)
|
||||
{
|
||||
$question = (new Question($question, $default))
|
||||
->setValidator($validator)
|
||||
->setMaxAttempts($attempts)
|
||||
->setAutocompleterValues($autocomplete);
|
||||
|
||||
return $this->getQuestionHelper()->ask($this->getInput(), $this->output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks for a value, hide and validates the response
|
||||
*
|
||||
* The validator receives the data to validate. It must return the
|
||||
* validated data when the data is valid and throw an exception
|
||||
* otherwise.
|
||||
*
|
||||
* @param string|array $question The question to ask. If an array each array item is turned into one line of a multi-line question
|
||||
* @param callable $validator A PHP callback that gets a value and is expected to return the (transformed) value or throw an exception if it wasn't valid
|
||||
* @param int|bool $attempts Max number of times to ask before giving up (false by default, which means infinite)
|
||||
* @param bool $fallback In case the response can not be hidden, whether to fallback on non-hidden question or not
|
||||
* @return string The response
|
||||
* @throws \Exception When any of the validators return an error
|
||||
* @throws \RuntimeException In case the fallback is deactivated and the response can not be hidden
|
||||
*/
|
||||
public function askHiddenResponseAndValidate($question, $validator, $attempts = false, $fallback = true)
|
||||
{
|
||||
$question = (new Question($question))
|
||||
->setValidator($validator)
|
||||
->setMaxAttempts($attempts)
|
||||
->setHidden(true)
|
||||
->setHiddenFallback($fallback);
|
||||
|
||||
return $this->getQuestionHelper()->ask($this->getInput(), $this->output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the progress output
|
||||
*
|
||||
* @param int $max Maximum steps. If NULL an indeterminate progress bar is rendered
|
||||
*/
|
||||
public function progressStart($max = null)
|
||||
{
|
||||
$this->getProgressBar()->start($max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the progress output X steps
|
||||
*
|
||||
* @param int $step Number of steps to advance
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function progressAdvance($step = 1)
|
||||
{
|
||||
$this->getProgressBar()->advance($step);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current progress
|
||||
*
|
||||
* @param int $current The current progress
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function progressSet($current)
|
||||
{
|
||||
$this->getProgressBar()->setProgress($current);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes the progress output
|
||||
*/
|
||||
public function progressFinish()
|
||||
{
|
||||
$this->getProgressBar()->finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArgvInput
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getInput()
|
||||
{
|
||||
if ($this->input === null) {
|
||||
if (!isset($_SERVER['argv'])) {
|
||||
throw new \RuntimeException('Cannot initialize ArgvInput object without CLI context.', 1456914444);
|
||||
}
|
||||
$this->input = new ArgvInput();
|
||||
}
|
||||
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns or initializes the symfony/console QuestionHelper
|
||||
*
|
||||
* @return QuestionHelper
|
||||
*/
|
||||
protected function getQuestionHelper()
|
||||
{
|
||||
if ($this->questionHelper === null) {
|
||||
$this->questionHelper = new QuestionHelper();
|
||||
$helperSet = new HelperSet([new FormatterHelper()]);
|
||||
$this->questionHelper->setHelperSet($helperSet);
|
||||
}
|
||||
return $this->questionHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns or initializes the symfony/console ProgressBar
|
||||
*
|
||||
* @return ProgressBar
|
||||
*/
|
||||
protected function getProgressBar()
|
||||
{
|
||||
if ($this->progressBar === null) {
|
||||
$this->progressBar = new ProgressBar($this->output);
|
||||
}
|
||||
return $this->progressBar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns or initializes the symfony/console Table
|
||||
*
|
||||
* @return Table
|
||||
*/
|
||||
protected function getTable()
|
||||
{
|
||||
if ($this->table === null) {
|
||||
$this->table = new Table($this->output);
|
||||
}
|
||||
return $this->table;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Mvc\Cli;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a CLI request.
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Use symfony/console commands instead.
|
||||
*/
|
||||
class Request implements \TYPO3\CMS\Extbase\Mvc\RequestInterface
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $controllerObjectName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $controllerCommandName = 'default';
|
||||
|
||||
/**
|
||||
* @var string Name of the extension which is supposed to handle this request.
|
||||
*/
|
||||
protected $controllerExtensionName;
|
||||
|
||||
/**
|
||||
* The arguments for this request
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $arguments = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $exceedingArguments = [];
|
||||
|
||||
/**
|
||||
* If this request has been changed and needs to be dispatched again
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $dispatched = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $commandLineArguments;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Mvc\Cli\Command | NULL
|
||||
*/
|
||||
protected $command;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $callingScript;
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $callingScript
|
||||
*/
|
||||
public function setCallingScript($callingScript)
|
||||
{
|
||||
$this->callingScript = $callingScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCallingScript()
|
||||
{
|
||||
return $this->callingScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dispatched flag
|
||||
*
|
||||
* @param bool $flag If this request has been dispatched
|
||||
*/
|
||||
public function setDispatched($flag)
|
||||
{
|
||||
$this->dispatched = (bool)$flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this request has been dispatched and addressed by the responsible
|
||||
* controller and the response is ready to be sent.
|
||||
*
|
||||
* The dispatcher will try to dispatch the request again if it has not been
|
||||
* addressed yet.
|
||||
*
|
||||
* @return bool TRUE if this request has been disptached successfully
|
||||
*/
|
||||
public function isDispatched()
|
||||
{
|
||||
return $this->dispatched;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the object name of the controller
|
||||
*
|
||||
* @param string $controllerObjectName The fully qualified controller object name
|
||||
*/
|
||||
public function setControllerObjectName($controllerObjectName)
|
||||
{
|
||||
$nameParts = \TYPO3\CMS\Core\Utility\ClassNamingUtility::explodeObjectControllerName($controllerObjectName);
|
||||
|
||||
$this->controllerExtensionName = $nameParts['extensionName'];
|
||||
$this->controllerObjectName = $controllerObjectName;
|
||||
$this->command = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object name of the controller
|
||||
*
|
||||
* @return string The controller's object name
|
||||
*/
|
||||
public function getControllerObjectName()
|
||||
{
|
||||
return $this->controllerObjectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extension name of the specified controller.
|
||||
*
|
||||
* @return string The extension name
|
||||
*/
|
||||
public function getControllerExtensionName()
|
||||
{
|
||||
return $this->controllerExtensionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the command contained in this request.
|
||||
*
|
||||
* Note that the command name must start with a lower case letter and is case sensitive.
|
||||
*
|
||||
* @param string $commandName Name of the command to execute by the controller
|
||||
*/
|
||||
public function setControllerCommandName($commandName)
|
||||
{
|
||||
$this->controllerCommandName = $commandName;
|
||||
$this->command = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the command the controller is supposed to execute.
|
||||
*
|
||||
* @return string Command name
|
||||
*/
|
||||
public function getControllerCommandName()
|
||||
{
|
||||
return $this->controllerCommandName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command object for this request
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Mvc\Cli\Command
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
if ($this->command === null) {
|
||||
$this->command = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Cli\Command::class, $this->controllerObjectName, $this->controllerCommandName);
|
||||
}
|
||||
return $this->command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the specified argument
|
||||
*
|
||||
* @param string $argumentName Name of the argument to set
|
||||
* @param mixed $value The new value
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException
|
||||
*/
|
||||
public function setArgument($argumentName, $value)
|
||||
{
|
||||
if (!is_string($argumentName) || $argumentName === '') {
|
||||
throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException('Invalid argument name.', 1300893885);
|
||||
}
|
||||
$this->arguments[$argumentName] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the whole arguments ArrayObject and therefore replaces any arguments
|
||||
* which existed before.
|
||||
*
|
||||
* @param array $arguments An array of argument names and their values
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the specified argument
|
||||
*
|
||||
* @param string $argumentName Name of the argument
|
||||
* @return string Value of the argument
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException if such an argument does not exist
|
||||
*/
|
||||
public function getArgument($argumentName)
|
||||
{
|
||||
if (!isset($this->arguments[$argumentName])) {
|
||||
throw new \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException('An argument "' . $argumentName . '" does not exist for this request.', 1300893886);
|
||||
}
|
||||
return $this->arguments[$argumentName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an argument of the given name exists (is set)
|
||||
*
|
||||
* @param string $argumentName Name of the argument to check
|
||||
* @return bool TRUE if the argument is set, otherwise FALSE
|
||||
*/
|
||||
public function hasArgument($argumentName)
|
||||
{
|
||||
return isset($this->arguments[$argumentName]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ArrayObject of arguments and their values
|
||||
*
|
||||
* @return array Array of arguments and their values (which may be arguments and values as well)
|
||||
*/
|
||||
public function getArguments()
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the exceeding arguments
|
||||
*
|
||||
* @param array $exceedingArguments Numeric array of exceeding arguments
|
||||
*/
|
||||
public function setExceedingArguments(array $exceedingArguments)
|
||||
{
|
||||
$this->exceedingArguments = $exceedingArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns additional unnamed arguments (if any) which have been passed through the command line after all
|
||||
* required arguments (if any) have been specified.
|
||||
*
|
||||
* For a command method with the signature ($argument1, $argument2) and for the command line
|
||||
* typo3/sysext/core/bin/typo3 acme:foo --argument1 Foo --argument2 Bar baz quux
|
||||
* this method would return array(0 => 'baz', 1 => 'quux')
|
||||
*
|
||||
* @return array Numeric array of exceeding argument values
|
||||
*/
|
||||
public function getExceedingArguments()
|
||||
{
|
||||
return $this->exceedingArguments;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Mvc\Cli;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Builds a CLI request object from the raw command call
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Use symfony/console commands instead.
|
||||
*/
|
||||
class RequestBuilder implements \TYPO3\CMS\Core\SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
|
||||
*/
|
||||
protected $reflectionService;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Mvc\Cli\CommandManager
|
||||
*/
|
||||
protected $commandManager;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
|
||||
*/
|
||||
protected $configurationManager;
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService
|
||||
*/
|
||||
public function injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
|
||||
{
|
||||
$this->reflectionService = $reflectionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Mvc\Cli\CommandManager $commandManager
|
||||
*/
|
||||
public function injectCommandManager(\TYPO3\CMS\Extbase\Mvc\Cli\CommandManager $commandManager)
|
||||
{
|
||||
$this->commandManager = $commandManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
|
||||
*/
|
||||
public function injectConfigurationManager(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager)
|
||||
{
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a CLI request object from a command line.
|
||||
*
|
||||
* The given command line may be a string (e.g. "myextension:foo do-that-thing --force") or
|
||||
* an array consisting of the individual parts. The array must not include the script
|
||||
* name (like in $argv) but start with command right away.
|
||||
*
|
||||
* @param mixed $commandLine The command line, either as a string or as an array
|
||||
* @param string $callingScript The calling script (usually ./typo3/sysext/core/bin/typo3)
|
||||
* @return \TYPO3\CMS\Extbase\Mvc\Cli\Request The CLI request as an object
|
||||
*/
|
||||
public function build($commandLine = '', $callingScript = './typo3/sysext/core/bin/typo3')
|
||||
{
|
||||
$request = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Cli\Request::class);
|
||||
$request->setCallingScript($callingScript);
|
||||
$request->setControllerObjectName(\TYPO3\CMS\Extbase\Command\HelpCommandController::class);
|
||||
$rawCommandLineArguments = is_array($commandLine) ? $commandLine : explode(' ', $commandLine);
|
||||
if (empty($rawCommandLineArguments)) {
|
||||
$request->setControllerCommandName('helpStub');
|
||||
return $request;
|
||||
}
|
||||
$commandIdentifier = trim(array_shift($rawCommandLineArguments));
|
||||
try {
|
||||
$command = $this->commandManager->getCommandByIdentifier($commandIdentifier);
|
||||
$this->configurationManager->setConfiguration(['extensionName' => $command->getExtensionName()]);
|
||||
} catch (\TYPO3\CMS\Extbase\Mvc\Exception\CommandException $exception) {
|
||||
$request->setArgument('exception', $exception);
|
||||
$request->setControllerCommandName('error');
|
||||
return $request;
|
||||
}
|
||||
$controllerObjectName = $command->getControllerClassName();
|
||||
$controllerCommandName = $command->getControllerCommandName();
|
||||
$request->setControllerObjectName($controllerObjectName);
|
||||
$request->setControllerCommandName($controllerCommandName);
|
||||
list($commandLineArguments, $exceedingCommandLineArguments) = $this->parseRawCommandLineArguments($rawCommandLineArguments, $controllerObjectName, $controllerCommandName);
|
||||
$request->setArguments($commandLineArguments);
|
||||
$request->setExceedingArguments($exceedingCommandLineArguments);
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an array of unparsed command line arguments and options and converts it separated
|
||||
* by named arguments, options and unnamed arguments.
|
||||
*
|
||||
* @param array $rawCommandLineArguments The unparsed command parts (such as "--foo") as an array
|
||||
* @param string $controllerObjectName Object name of the designated command controller
|
||||
* @param string $controllerCommandName Command name of the recognized command (ie. method name without "Command" suffix)
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentMixingException
|
||||
* @return array All and exceeding command line arguments
|
||||
*/
|
||||
protected function parseRawCommandLineArguments(array $rawCommandLineArguments, $controllerObjectName, $controllerCommandName)
|
||||
{
|
||||
$commandLineArguments = [];
|
||||
$exceedingArguments = [];
|
||||
$commandMethodName = $controllerCommandName . 'Command';
|
||||
$commandMethodParameters = $this->reflectionService
|
||||
->getClassSchema($controllerObjectName)
|
||||
->getMethod($commandMethodName)['params'] ?? [];
|
||||
$requiredArguments = [];
|
||||
$optionalArguments = [];
|
||||
$argumentNames = [];
|
||||
foreach ($commandMethodParameters as $parameterName => $parameterInfo) {
|
||||
$argumentNames[] = $parameterName;
|
||||
if ($parameterInfo['optional'] === false) {
|
||||
$requiredArguments[strtolower($parameterName)] = ['parameterName' => $parameterName, 'type' => $parameterInfo['type']];
|
||||
} else {
|
||||
$optionalArguments[strtolower($parameterName)] = ['parameterName' => $parameterName, 'type' => $parameterInfo['type']];
|
||||
}
|
||||
}
|
||||
$decidedToUseNamedArguments = false;
|
||||
$decidedToUseUnnamedArguments = false;
|
||||
$argumentIndex = 0;
|
||||
while (!empty($rawCommandLineArguments)) {
|
||||
$rawArgument = array_shift($rawCommandLineArguments);
|
||||
if ($rawArgument[0] === '-') {
|
||||
if ($rawArgument[1] === '-') {
|
||||
$rawArgument = substr($rawArgument, 2);
|
||||
} else {
|
||||
$rawArgument = substr($rawArgument, 1);
|
||||
}
|
||||
$argumentName = $this->extractArgumentNameFromCommandLinePart($rawArgument);
|
||||
if (isset($optionalArguments[$argumentName])) {
|
||||
$argumentValue = $this->getValueOfCurrentCommandLineOption($rawArgument, $rawCommandLineArguments, $optionalArguments[$argumentName]['type']);
|
||||
$commandLineArguments[$optionalArguments[$argumentName]['parameterName']] = $argumentValue;
|
||||
} elseif (isset($requiredArguments[$argumentName])) {
|
||||
if ($decidedToUseUnnamedArguments) {
|
||||
throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentMixingException(sprintf('Unexpected named argument "%s". If you use unnamed arguments, all required arguments must be passed without a name.', $argumentName), 1309971821);
|
||||
}
|
||||
$decidedToUseNamedArguments = true;
|
||||
$argumentValue = $this->getValueOfCurrentCommandLineOption($rawArgument, $rawCommandLineArguments, $requiredArguments[$argumentName]['type']);
|
||||
$commandLineArguments[$requiredArguments[$argumentName]['parameterName']] = $argumentValue;
|
||||
unset($requiredArguments[$argumentName]);
|
||||
}
|
||||
} else {
|
||||
if (!empty($requiredArguments)) {
|
||||
if ($decidedToUseNamedArguments) {
|
||||
throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentMixingException(sprintf('Unexpected unnamed argument "%s". If you use named arguments, all required arguments must be passed named.', $rawArgument), 1309971820);
|
||||
}
|
||||
$argument = array_shift($requiredArguments);
|
||||
$commandLineArguments[$argument['parameterName']] = $rawArgument;
|
||||
$decidedToUseUnnamedArguments = true;
|
||||
} else {
|
||||
if ($argumentIndex < count($argumentNames)) {
|
||||
$commandLineArguments[$argumentNames[$argumentIndex]] = $rawArgument;
|
||||
} else {
|
||||
$exceedingArguments[] = $rawArgument;
|
||||
}
|
||||
}
|
||||
}
|
||||
$argumentIndex++;
|
||||
}
|
||||
return [$commandLineArguments, $exceedingArguments];
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the option or argument name from the name / value pair of a command line.
|
||||
*
|
||||
* @param string $commandLinePart Part of the command line, e.g. "my-important-option=SomeInterestingValue
|
||||
* @return string The lowercased argument name, e.g. "myimportantoption
|
||||
*/
|
||||
protected function extractArgumentNameFromCommandLinePart($commandLinePart)
|
||||
{
|
||||
$nameAndValue = explode('=', $commandLinePart, 2);
|
||||
return strtolower(str_replace('-', '', $nameAndValue[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the first argument of the given input array. Shifts the parsed argument off the array.
|
||||
*
|
||||
* @param string $currentArgument The current argument
|
||||
* @param array &$rawCommandLineArguments Array of the remaining command line arguments
|
||||
* @param string $expectedArgumentType The expected type of the current argument, because booleans get special attention
|
||||
* @return string The value of the first argument
|
||||
*/
|
||||
protected function getValueOfCurrentCommandLineOption($currentArgument, array &$rawCommandLineArguments, $expectedArgumentType)
|
||||
{
|
||||
if (!isset($rawCommandLineArguments[0]) && strpos($currentArgument, '=') === false || isset($rawCommandLineArguments[0]) && $rawCommandLineArguments[0][0] === '-' && strpos($currentArgument, '=') === false) {
|
||||
return true;
|
||||
}
|
||||
if (strpos($currentArgument, '=') === false) {
|
||||
$possibleValue = trim(array_shift($rawCommandLineArguments));
|
||||
if (strpos($possibleValue, '=') === false) {
|
||||
if ($expectedArgumentType !== 'boolean') {
|
||||
return $possibleValue;
|
||||
}
|
||||
if (in_array($possibleValue, ['on', '1', 'y', 'yes', 'true', 'TRUE'], true)) {
|
||||
return true;
|
||||
}
|
||||
if (in_array($possibleValue, ['off', '0', 'n', 'no', 'false', 'FALSE'], true)) {
|
||||
return false;
|
||||
}
|
||||
array_unshift($rawCommandLineArguments, $possibleValue);
|
||||
return true;
|
||||
}
|
||||
$currentArgument .= $possibleValue;
|
||||
}
|
||||
$splitArgument = explode('=', $currentArgument, 2);
|
||||
while ((!isset($splitArgument[1]) || trim($splitArgument[1]) === '') && !empty($rawCommandLineArguments)) {
|
||||
$currentArgument .= array_shift($rawCommandLineArguments);
|
||||
$splitArgument = explode('=', $currentArgument);
|
||||
}
|
||||
$value = $splitArgument[1] ?? '';
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Mvc\Cli;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
|
||||
/**
|
||||
* The generic command line interface request handler for the MVC framework.
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Use symfony/console commands instead.
|
||||
*/
|
||||
class RequestHandler implements \TYPO3\CMS\Extbase\Mvc\RequestHandlerInterface
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Mvc\Dispatcher
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Mvc\Cli\RequestBuilder
|
||||
*/
|
||||
protected $requestBuilder;
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Mvc\Dispatcher $dispatcher
|
||||
*/
|
||||
public function injectDispatcher(\TYPO3\CMS\Extbase\Mvc\Dispatcher $dispatcher)
|
||||
{
|
||||
$this->dispatcher = $dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Mvc\Cli\RequestBuilder $requestBuilder
|
||||
*/
|
||||
public function injectRequestBuilder(\TYPO3\CMS\Extbase\Mvc\Cli\RequestBuilder $requestBuilder)
|
||||
{
|
||||
$this->requestBuilder = $requestBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Mvc\ResponseInterface
|
||||
*/
|
||||
public function handleRequest()
|
||||
{
|
||||
$commandLine = $_SERVER['argv'] ?? [];
|
||||
$callingScript = array_shift($commandLine);
|
||||
if ($callingScript !== $_SERVER['_']) {
|
||||
$callingScript = $_SERVER['_'] . ' ' . $callingScript;
|
||||
}
|
||||
|
||||
$request = $this->requestBuilder->build($commandLine, $callingScript);
|
||||
/** @var \TYPO3\CMS\Extbase\Mvc\Cli\Response $response */
|
||||
$response = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Cli\Response::class);
|
||||
$this->dispatcher->dispatch($request, $response);
|
||||
$response->send();
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* This request handler can handle any command line request.
|
||||
*
|
||||
* @return bool If the request is a command line request, TRUE otherwise FALSE
|
||||
*/
|
||||
public function canHandleRequest()
|
||||
{
|
||||
return Environment::isCli();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the priority - how eager the handler is to actually handle the
|
||||
* request.
|
||||
*
|
||||
* @return int The priority of the request handler.
|
||||
*/
|
||||
public function getPriority()
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Mvc\Cli;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* A CLI specific response implementation
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Use symfony/console commands instead.
|
||||
*/
|
||||
class Response extends \TYPO3\CMS\Extbase\Mvc\Response
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $exitCode = 0;
|
||||
|
||||
/**
|
||||
* Sets the numerical exit code which should be returned when exiting this application.
|
||||
*
|
||||
* @param int $exitCode
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setExitCode($exitCode)
|
||||
{
|
||||
if (!is_int($exitCode)) {
|
||||
throw new \InvalidArgumentException(sprintf('Tried to set invalid exit code. The value must be integer, %s given.', gettype($exitCode)), 1312222064);
|
||||
}
|
||||
$this->exitCode = $exitCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rets the numerical exit code which should be returned when exiting this application.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getExitCode()
|
||||
{
|
||||
return $this->exitCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders and sends the whole web response
|
||||
*/
|
||||
public function send()
|
||||
{
|
||||
if ($this->content !== null) {
|
||||
echo $this->shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user