[FEATURE] Add annotation for CLI only commands 68/43268/5
authorMathias Brodala <mbrodala@pagemachine.de>
Sun, 13 Sep 2015 11:30:05 +0000 (13:30 +0200)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Mon, 14 Sep 2015 13:15:44 +0000 (15:15 +0200)
This adds the annotation "@cli" to declare Extbase CommandController
commands to be usable on CLI only and is used to remove these commands
from the Scheduler task list.

Also annotate the following commands as CLI only:

- help:help
- extension:install
- extension:uninstall
- extension:dumpclassloadinginformation

Resolves: #68746
Releases: master
Change-Id: Ifb55def33c11e4a10510433f03ddc9279ee56898
Reviewed-on: http://review.typo3.org/43268
Reviewed-by: Nicole Cordes <typo3@cordes.co>
Tested-by: Nicole Cordes <typo3@cordes.co>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Tested-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
typo3/sysext/core/Documentation/Changelog/master/Feature-68746-AddAnnotationForCLIOnlyCommands.rst [new file with mode: 0644]
typo3/sysext/extbase/Classes/Command/HelpCommandController.php
typo3/sysext/extbase/Classes/Mvc/Cli/Command.php
typo3/sysext/extbase/Classes/Scheduler/FieldProvider.php
typo3/sysext/extbase/Tests/Unit/Scheduler/FieldProviderTest.php
typo3/sysext/extensionmanager/Classes/Command/ExtensionCommandController.php

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-68746-AddAnnotationForCLIOnlyCommands.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-68746-AddAnnotationForCLIOnlyCommands.rst
new file mode 100644 (file)
index 0000000..0eb08cd
--- /dev/null
@@ -0,0 +1,17 @@
+======================================================
+Feature: #68746 - Add annotation for CLI only commands
+======================================================
+
+Description
+===========
+
+The PHPDoc annotation ``@cli`` was added to declare Extbase CommandController commands to be usable on CLI only.
+In general each defined CommandController can be selected within the Extbase CommandController Task in the scheduler.
+For some commands like ``extbase:help:help`` running in a scheduler task is not wanted or needed. Now those commands can
+be excluded from the scheduler command selection.
+
+
+Impact
+======
+
+Extbase ``CommandController`` commands annotated with ``@cli`` are not shown as command in the scheduler task.
\ No newline at end of file
index 1a9e728..34240fa 100644 (file)
@@ -62,7 +62,7 @@ class HelpCommandController extends \TYPO3\CMS\Extbase\Mvc\Controller\CommandCon
         * ./cli_dispatch.phpsh extbase help <command identifier>
         *
         * @param string $commandIdentifier Identifier of a command for more details
-        * @return void
+        * @cli
         */
        public function helpCommand($commandIdentifier = NULL) {
                if ($commandIdentifier === NULL) {
index 8add314..0e83583 100644 (file)
@@ -217,6 +217,15 @@ class Command {
        }
 
        /**
+        * Tells if this command is meant to be used on CLI only.
+        *
+        * @return bool
+        */
+       public function isCliOnly() {
+               return $this->getCommandMethodReflection()->isTaggedWith('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.
index c61876e..c977ca3 100644 (file)
@@ -124,27 +124,28 @@ class FieldProvider implements \TYPO3\CMS\Scheduler\AdditionalFieldProviderInter
                $commands = $this->commandManager->getAvailableCommands();
                $options = array();
                foreach ($commands as $command) {
-                       if ($command->isInternal() === FALSE) {
-                               $className = $command->getControllerClassName();
-                               if (strpos($className, '\\')) {
-                                       $classNameParts = explode('\\', $className);
-                                       // Skip vendor and product name for core classes
-                                       if (strpos($className, 'TYPO3\\CMS\\') === 0) {
-                                               $classPartsToSkip = 2;
-                                       } else {
-                                               $classPartsToSkip = 1;
-                                       }
-                                       $classNameParts = array_slice($classNameParts, $classPartsToSkip);
-                                       $extensionName = $classNameParts[0];
-                                       $controllerName = $classNameParts[2];
+                       if ($command->isInternal() === TRUE || $command->isCliOnly() === TRUE) {
+                               continue;
+                       }
+                       $className = $command->getControllerClassName();
+                       if (strpos($className, '\\')) {
+                               $classNameParts = explode('\\', $className);
+                               // Skip vendor and product name for core classes
+                               if (strpos($className, 'TYPO3\\CMS\\') === 0) {
+                                       $classPartsToSkip = 2;
                                } else {
-                                       $classNameParts = explode('_', $className);
-                                       $extensionName = $classNameParts[1];
-                                       $controllerName = $classNameParts[3];
+                                       $classPartsToSkip = 1;
                                }
-                               $identifier = $command->getCommandIdentifier();
-                               $options[$identifier] = $extensionName . ' ' . str_replace('CommandController', '', $controllerName) . ': ' . $command->getControllerCommandName();
+                               $classNameParts = array_slice($classNameParts, $classPartsToSkip);
+                               $extensionName = $classNameParts[0];
+                               $controllerName = $classNameParts[2];
+                       } else {
+                               $classNameParts = explode('_', $className);
+                               $extensionName = $classNameParts[1];
+                               $controllerName = $classNameParts[3];
                        }
+                       $identifier = $command->getCommandIdentifier();
+                       $options[$identifier] = $extensionName . ' ' . str_replace('CommandController', '', $controllerName) . ': ' . $command->getControllerCommandName();
                }
                $name = 'action';
                $currentlySelectedCommand = $this->task !== NULL ? $this->task->getCommandIdentifier() : NULL;
index eb8cd2c..8cd92d3 100644 (file)
@@ -36,6 +36,7 @@ class FieldProviderTest extends UnitTestCase {
                /** @var Command|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $command1 */
                $command1 = $this->getAccessibleMock(Command::class, array(), array(), '', FALSE);
                $command1->expects($this->once())->method('isInternal')->will($this->returnValue(FALSE));
+               $command1->expects($this->once())->method('isCliOnly')->will($this->returnValue(FALSE));
                $command1->expects($this->once())->method('getControllerClassName')->will($this->returnValue(MockACommandController::class));
                $command1->expects($this->once())->method('getControllerCommandName')->will($this->returnValue('FuncA'));
                $command1->expects($this->once())->method('getCommandIdentifier')->will($this->returnValue('extbase:mocka:funca'));
@@ -43,6 +44,7 @@ class FieldProviderTest extends UnitTestCase {
                /** @var Command|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $command2 */
                $command2 = $this->getAccessibleMock(Command::class, array(), array(), '', FALSE);
                $command2->expects($this->once())->method('isInternal')->will($this->returnValue(FALSE));
+               $command2->expects($this->once())->method('isCliOnly')->will($this->returnValue(FALSE));
                $command2->expects($this->once())->method('getControllerClassName')->will($this->returnValue('Acme\\Mypkg\\Command\\MockBCommandController'));
                $command2->expects($this->once())->method('getControllerCommandName')->will($this->returnValue('FuncB'));
                $command2->expects($this->once())->method('getCommandIdentifier')->will($this->returnValue('mypkg:mockb:funcb'));
@@ -50,6 +52,7 @@ class FieldProviderTest extends UnitTestCase {
                /** @var Command|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $command3 */
                $command3 = $this->getAccessibleMock(Command::class, array(), array(), '', FALSE);
                $command3->expects($this->once())->method('isInternal')->will($this->returnValue(FALSE));
+               $command3->expects($this->once())->method('isCliOnly')->will($this->returnValue(FALSE));
                $command3->expects($this->once())->method('getControllerClassName')->will($this->returnValue('Tx_Extbase_Command_MockCCommandController'));
                $command3->expects($this->once())->method('getControllerCommandName')->will($this->returnValue('FuncC'));
                $command3->expects($this->once())->method('getCommandIdentifier')->will($this->returnValue('extbase:mockc:funcc'));
@@ -77,6 +80,66 @@ class FieldProviderTest extends UnitTestCase {
        /**
         * @test
         */
+       public function getCommandControllerActionFieldSkipsInternalCommands() {
+               /** @var Command|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $command1 */
+               $command = $this->getAccessibleMock(Command::class, array(), array(), '', FALSE);
+               $command->method('isInternal')->will($this->returnValue(TRUE));
+               $command->method('isCliOnly')->will($this->returnValue(FALSE));
+               $command->method('getControllerClassName')->will($this->returnValue(MockACommandController::class));
+               $command->method('getControllerCommandName')->will($this->returnValue('FuncA'));
+               $command->method('getCommandIdentifier')->will($this->returnValue('extbase:mocka:funca'));
+
+               /** @var CommandManager|\PHPUnit_Framework_MockObject_MockObject $commandManager */
+               $commandManager = $this->getMock(CommandManager::class, array('getAvailableCommands'));
+               $commandManager->expects($this->any())->method('getAvailableCommands')->will($this->returnValue(array($command)));
+
+               /** @var FieldProvider|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $fieldProvider */
+               $fieldProvider = $this->getAccessibleMock(
+                       FieldProvider::class,
+                       array('getActionLabel'),
+                       array(),
+                       '',
+                       FALSE
+               );
+               $fieldProvider->_set('commandManager', $commandManager);
+               $fieldProvider->expects($this->once())->method('getActionLabel')->will($this->returnValue('some label'));
+               $actualResult = $fieldProvider->_call('getCommandControllerActionField', array());
+               $this->assertNotContains('<option title="test" value="extbase:mocka:funca">Extbase MockA: FuncA</option>', $actualResult['code']);
+       }
+
+       /**
+        * @test
+        */
+       public function getCommandControllerActionFieldSkipsCliOnlyCommands() {
+               /** @var Command|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $command1 */
+               $command = $this->getAccessibleMock(Command::class, array(), array(), '', FALSE);
+               $command->method('isInternal')->will($this->returnValue(FALSE));
+               $command->method('isCliOnly')->will($this->returnValue(TRUE));
+               $command->method('getControllerClassName')->will($this->returnValue(MockACommandController::class));
+               $command->method('getControllerCommandName')->will($this->returnValue('FuncA'));
+               $command->method('getCommandIdentifier')->will($this->returnValue('extbase:mocka:funca'));
+
+               /** @var CommandManager|\PHPUnit_Framework_MockObject_MockObject $commandManager */
+               $commandManager = $this->getMock(CommandManager::class, array('getAvailableCommands'));
+               $commandManager->expects($this->any())->method('getAvailableCommands')->will($this->returnValue(array($command)));
+
+               /** @var FieldProvider|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $fieldProvider */
+               $fieldProvider = $this->getAccessibleMock(
+                       FieldProvider::class,
+                       array('getActionLabel'),
+                       array(),
+                       '',
+                       FALSE
+               );
+               $fieldProvider->_set('commandManager', $commandManager);
+               $fieldProvider->expects($this->once())->method('getActionLabel')->will($this->returnValue('some label'));
+               $actualResult = $fieldProvider->_call('getCommandControllerActionField', array());
+               $this->assertNotContains('<option title="test" value="extbase:mocka:funca">Extbase MockA: FuncA</option>', $actualResult['code']);
+       }
+
+       /**
+        * @test
+        */
        public function constructResolvesExtensionNameFromNamespaced() {
                $mockController = new DummyController();
                $expectedResult = 'Extbase';
index c77851b..211d072 100644 (file)
@@ -48,6 +48,7 @@ class ExtensionCommandController extends CommandController {
         *
         * @param string $extensionKey
         * @return void
+        * @cli
         */
        public function installCommand($extensionKey) {
                $this->emitPackagesMayHaveChangedSignal();
@@ -65,6 +66,7 @@ class ExtensionCommandController extends CommandController {
         *
         * @param string $extensionKey
         * @return void
+        * @cli
         */
        public function uninstallCommand($extensionKey) {
                /** @var $service \TYPO3\CMS\Extensionmanager\Utility\InstallUtility */
@@ -79,6 +81,7 @@ class ExtensionCommandController extends CommandController {
         * creating or updating this info properly during extension (de-)activation.
         *
         * @return void
+        * @cli
         */
        public function dumpClassLoadingInformationCommand() {
                if (Bootstrap::usesComposerClassLoading()) {