当前位置: 首页 > 工具软件 > Drupal Create > 使用案例 >

不要再打Drush命令了 告诉你Drupal Console強大的地方!

赵嘉悦
2023-12-01

 1. Drupal console简述

drupal console是一个能够生成代码样本与drupal交互并提供命令行接口CLI操作的工具。从重建缓存,到列出路由、服务以及模块。甚至还可以和配置管理进行交互。

 

2. Drupal console的诞生

一切都始于使Drupal 8更好的想法,每一项伟大的发明/创新都源于一个构想,而Drupal从7过渡到8伴随着对昨天基本操作程序的巨大改变。JesusDavid是Drupal Console项目的发起人,提出了将symfony控制台纳入Drupal核心的想法。将其他symfony组件包含到Drupal核心当中。但最初并没有被Drupal社区广泛接受,接受新的理念通常需要一段时间的市场证明,在几次尝试要求纳入并尝试合作进行不同的drupal项目之后,JesusDavid突然意识到,融合和协作将不会发生。于是在哥斯达黎加Drupal camp午餐时,JesusDavid随便讨论了他们试图将创新引入Drupal和相关项目时遇到的挫败感,而Larry Garfield则吹嘘说“有人需要创建一个包含Symfony Console和代码生成的单独项目” 。这句话催生了今天的Drupal Console项目。

 

3. Drupal console与Drush的区别

drupal console是面向oop 设计即drupal8含版本以上的模块,而drush除了向下兼容之外,drush9也基于Symfony和POO思想重新设计开发的。实际上这两者区别不大,接下来从源码上解析一下两者:

  • Drush的加载过程
  1.    // Set up environment  
  2. $environment = new Environment(Path::getHomeDirectory(), $cwd, $autoloadFile);  
  3. $environment->setConfigFileVariant(Drush::getMajorVersion());  
  4. $environment->setLoader($loader);  
  5. $environment->applyEnvironment();  
  6.   
  7. // Preflight and run  
  8. $preflight = new Preflight($environment);  
  9. $di = new DependencyInjection();  
  10. $di->desiredHandlers(['errorHandler''shutdownHandler']);  
  11. $runtime = new Runtime($preflight, $di);  
  12. $status_code = $runtime->run($_SERVER['argv']);  
  1. 首先是加载当前的站点环境变量
  2. 把当前环境变量与命令行输入和注入处理器放到当前容器上下文当中
  1. protected function addDrushServices(ContainerInterface $container, ClassLoader $loader, DrupalFinder $drupalFinder, SiteAliasManager $aliasManager, DrushConfig $config)  {
  2.  
  3.  // Override Robo's logger with our own  
  4.  $container->share('logger''Drush\Log\Logger')  
  5.    ->withArgument('output')  
  6.    ->withMethodCall('setLogOutputStyler', ['logStyler']);  
  7.   
  8.  $container->share('loader', $loader);  
  9.  $container->share('site.alias.manager', $aliasManager);  
  10.   
  11.  // Fetch the runtime config, where -D et. al. are stored, and  
  12.  // add a reference to it to the container.  
  13.  $container->share('config.runtime', $config->getContext(ConfigOverlay::PROCESS_CONTEXT));  
  14.   
  15.  // Override Robo's formatter manager with our own  
  16.  // @todo not sure that we'll use this. Maybe remove it.  
  17.  $container->share('formatterManager', \Drush\Formatters\DrushFormatterManager::class)  
  18.      ->withMethodCall('addDefaultFormatters', [])  
  19.      ->withMethodCall('addDefaultSimplifiers', []);  
  20.   
  21.  // Add some of our own objects to the container  
  22.  $container->share('bootstrap.drupal8''Drush\Boot\DrupalBoot8');  
  23.  $container->share('bootstrap.manager''Drush\Boot\BootstrapManager')  
  24.      ->withMethodCall('setDrupalFinder', [$drupalFinder]);  
  25.  // TODO: Can we somehow add these via discovery (e.g. backdrop extension?)  
  26.  $container->extend('bootstrap.manager')  
  27.      ->withMethodCall('add', ['bootstrap.drupal8']);  
  28.  $container->share('bootstrap.hook''Drush\Boot\BootstrapHook')  
  29.    ->withArgument('bootstrap.manager');  
  30.  $container->share('tildeExpansion.hook''Drush\Runtime\TildeExpansionHook');  
  31.  $container->share('process.manager', ProcessManager::class)  
  32.      ->withMethodCall('setConfig', ['config'])  
  33.      ->withMethodCall('setConfigRuntime', ['config.runtime']);  
  34.  $container->share('redispatch.hook''Drush\Runtime\RedispatchHook')  
  35.      ->withArgument('process.manager');  
  36.   
  37.  // Robo does not manage the command discovery object in the container,  
  38.  // but we will register and configure one for our use.  
  39.  // TODO: Some old adapter code uses this, but the Symfony dispatcher does not.  
  40.  // See Application::commandDiscovery().  
  41.  $container->share('commandDiscovery''Consolidation\AnnotatedCommand\CommandFileDiscovery')  
  42.      ->withMethodCall('addSearchLocation', ['CommandFiles'])  
  43.      ->withMethodCall('setSearchPattern', ['#.*(Commands|CommandFile).php$#']);  
  44.   
  45.  // Error and Shutdown handlers  
  46.  $container->share('errorHandler''Drush\Runtime\ErrorHandler');  
  47.  $container->share('shutdownHandler''Drush\Runtime\ShutdownHandler');  
  48.   
  49.  // Add inflectors. @see \Drush\Boot\BaseBoot::inflect  
  50.  $container->inflector(\Drush\Boot\AutoloaderAwareInterface::class)  
  51.      ->invokeMethod('setAutoloader', ['loader']);  
  52.  $container->inflector(\Consolidation\SiteAlias\SiteAliasManagerAwareInterface::class)  
  53.      ->invokeMethod('setSiteAliasManager', ['site.alias.manager']);  
  54.  $container->inflector(\Consolidation\SiteProcess\ProcessManagerAwareInterface::class)  
  55.      ->invokeMethod('setProcessManager', ['process.manager']);}  
  1. 之后获取容器runtime的上下文放入logger接收输出,实现ProcessManagerAwareInterface接口调起一个子进程反射执行方法
  1. protected function injectApplicationServices(ContainerInterface $container, Application $application)  
  2.   {
  3.  $application->setLogger($container->get('logger'));  
  4.  $application->setBootstrapManager($container->get('bootstrap.manager'));  
  5.  $application->setAliasManager($container->get('site.alias.manager'));  
  6.  $application->setRedispatchHook($container->get('redispatch.hook'));  
  7.  $application->setTildeExpansionHook($container->get('tildeExpansion.hook'));  
  8.  $application->setDispatcher($container->get('eventDispatcher'));  
  9.  $application->setConfig($container->get('config'));  }

 

  1. 最后将一系列的模组注入到当前的ApplicationServices里面通过Symfony Console component运行命令
  • Drupal console加载过程
  1.    $output = new ConsoleOutput();  
  2. $input = new ArrayInput([]);  
  3. $io = new DrupalStyle($input, $output);  
  4. $argvInputReader = new ArgvInputReader();  
  5. $root = $argvInputReader->get('root', getcwd());  
  6.   
  7. $drupalFinder = new DrupalFinder();  
  8. if (!$drupalFinder->locateRoot($root)) {  
  9.     $io->error('DrupalConsole must be executed within a Drupal Site.');  
  10.   
  11.     exit(1);  
  12. }  
  13.   
  14. chdir($drupalFinder->getDrupalRoot());  
  15. $configurationManager = new ConfigurationManager();  
  16. $configuration = $configurationManager  
  17.     ->loadConfiguration($drupalFinder->getComposerRoot())  
  18.     ->getConfiguration();  
  19. $debug = $argvInputReader->get('debug', false);  
  20. if ($configuration && $options = $configuration->get('application.options') ?: []) {  
  21.     $argvInputReader->setOptionsFromConfiguration($options);  
  22. }  
  23. $argvInputReader->setOptionsAsArgv();  
  24. if ($debug) {  
  25.     $io->writeln(  
  26.         sprintf(  
  27.             '<info>%s</info> version <comment>%s</comment>',  
  28.             Application::NAME,  
  29.             Application::VERSION  
  30.         )  
  31.     );  
  32. }  
  33. $drupal = new Drupal($autoload, $drupalFinder, $configurationManager);  
  34. $container = $drupal->boot();  
  35. if (!$container) {  
  36.     $io->error('Something was wrong. Drupal can not be bootstrap.');  
  37.   
  38.     exit(1);  
  39. }  
  40. $application = new Application($container);  
  41. $application->setDrupal($drupal);  
  42. $application->run();  

 

  1.    public function run(InputInterface $input = null, OutputInterface $output = null)  
  2. {  
  3.     putenv('LINES='.$this->terminal->getHeight());  
  4.     putenv('COLUMNS='.$this->terminal->getWidth());  
  5.     if (null === $input) {  
  6.         $input = new ArgvInput();  
  7.     }  
  8.     if (null === $output) {  
  9.         $output = new ConsoleOutput();  
  10.     }  
  11.     $renderException = function ($e) use ($output) {  
  12.         if (!$e instanceof \Exception) {  
  13.             $e = class_exists(FatalThrowableError::class) ? new FatalThrowableError($e) : new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());  
  14.         }  
  15.         if ($output instanceof ConsoleOutputInterface) {  
  16.             $this->renderException($e, $output->getErrorOutput());  
  17.         } else {  
  18.             $this->renderException($e, $output);  
  19.         }  
  20.     };  
  21.     if ($phpHandler = set_exception_handler($renderException)) {  
  22.         restore_exception_handler();  
  23.         if (!\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) {  
  24.             $debugHandler = true;  
  25.         } elseif ($debugHandler = $phpHandler[0]->setExceptionHandler($renderException)) {  
  26.             $phpHandler[0]->setExceptionHandler($debugHandler);  
  27.         }  
  28.     }  
  29.   
  30.     if (null !== $this->dispatcher && $this->dispatcher->hasListeners(ConsoleEvents::EXCEPTION)) {  
  31.         @trigger_error(sprintf('The "ConsoleEvents::EXCEPTION" event is deprecated since Symfony 3.3 and will be removed in 4.0. Listen to the "ConsoleEvents::ERROR" event instead.'), E_USER_DEPRECATED);  
  32.     }  
  33.   
  34.     $this->configureIO($input, $output);  
  35.     try {  
  36.         $exitCode = $this->doRun($input, $output);  
  37.     } catch (\Exception $e) {  
  38.         if (!$this->catchExceptions) {  
  39.             throw $e;  
  40.         }  
  41.         $renderException($e);  
  42.         $exitCode = $e->getCode();  
  43.         if (is_numeric($exitCode)) {  
  44.             $exitCode = (int) $exitCode;  
  45.             if (0 === $exitCode) {  
  46.                 $exitCode = 1;  
  47.             }  
  48.         } else {  
  49.             $exitCode = 1;  
  50.         }  
  51.     } finally {  
  52.         // if the exception handler changed, keep it  
  53.         // otherwise, unregister $renderException  
  54.         if (!$phpHandler) {  
  55.             if (set_exception_handler($renderException) === $renderException) {  
  56.                 restore_exception_handler();  
  57.             }  
  58.             restore_exception_handler();  
  59.         } elseif (!$debugHandler) {  
  60.             $finalHandler = $phpHandler[0]->setExceptionHandler(null);  
  61.             if ($finalHandler !== $renderException) {  
  62.                 $phpHandler[0]->setExceptionHandler($finalHandler);  
  63.             }  
  64.         }  
  65.     }  
  66.     if ($this->autoExit) {  
  67.         if ($exitCode > 255) {  
  68.             $exitCode = 255;  
  69.         }  
  70.         exit($exitCode);  
  71.     }  
  72.     return $exitCode;  
  73. }  

 

Drupal console 加载过程更为简洁,直接加载环境配置和drupal的bootstrap kernel然后全部交给Symfony Console component运行命令。

在9版本之前drush跟drupal console相比,确实没有代码生成器功能,实际上drush 在9版本开始就已经拥有跟drupal console同样的功能了即代码生成器,在创建模块的时候会有一些细微的交互区别,例如drush会询问要创建library.yml,Permissions.yml,block,controller等。

 

 

 

  1. Drupal consoleDrush的安装方法
  1. Drupal console:
  1. Curl

curl https://drupalconsole.com/installer -L -o drupal.phar

然后mv drupal.phar  /usr/bin/drupal;chmod +x /usr/bin/drupal 变成全局变量

 

  1. php 内置库请求安装

php -r "readfile('https://drupalconsole.com/installer');" > drupal.phar

然后mv drupal.phar  /usr/bin/drupal;chmod +x /usr/bin/drupal 变成全局变量

最后去到网站根目录执行 drupal site:status 或者用别名drupal ss就能验证是否安装好了

 

  1. Composer为了不污染环境没有使用全局,容器内安装,不用global

composer require drupal/console:@stable

当前用户变量别名添加~/.bashrc

alias drupal=’<网站根目录>/vendor/drupal/console/bin/’

然后就可以用了例如生成reset api模块

drupal gprr

 

  1. Drush

 

根据drush官方文档安装对应兼容drupal的版本

Drush Version

Drush Branch

PHP

Compatible Drupal versions

Code Status

Drush 9

master

5.5+

D7, D8

 

Drush 8

8.x

5.4.5+

D6, D7, D8

 

Drush 7

7.x

5.3.0+

D6, D7

 

Drush 6

6.x

5.3.0+

D6, D7

Unsupported

Drush 5

5.x

5.2.0+

D6, D7

Unsupported

Drush 4

4.x

5.2.0+

D5, D6, D7

Unsupported

Drush 3

3.x

5.2.0+

D5, D6

Unsupported

 

例如我用D8版本

  1. Composer 同理为了不污染环境,容器内安装,不用global

composer require drush/drush:dev-master

当前用户变量别名添加~/.bashrc

alias drupal=’<网站根目录>vendor/drush/drush/drush’

然后就可以用了例如drush cr 清缓存

 

2.源码包安装

git clone https://github.com/drush-ops/drush/releases,找到drush.phar

mv drush.phar drush && chmod +x drush;mv drush /usr/bin/;drush init

接下来初始化一路看到ok让你选择安装目录y后都成功的话那就是安装成功了

 

 

#常用操作命令只能在<网站根目录>下使用

  1. Drupal console
  2. 维护模式开/关

drupal site:maintenance on/off

     3.开发/生产模式切换

drupal site:mode dev/prod

     4.创建Node/Users/Terms测试数据

drupal create:nodes

drupal create:users

drupal create:terms

      5.创建模块

  1.     drupal generate:modulename  
  2.  // Welcome to the Drupal module generator  
  3.  Enter the new module name:  
  4.  > hello  
  5.  Enter the module machine name [hello]:  
  6.  >  
  7.  Enter the module Path [/modules/custom]:  
  8.  >  
  9.  Enter module description [My Awesome Module]:  
  10.  > ttt.  
  11.  Enter package name [Custom]:  
  12.  > test  
  13.  Enter Drupal Core version [8.x]:  
  14.  >  
  15.  Do you want to generate a .module file (yes/no) [yes]:  
  16.  >  
  17.  Define module as feature (yes/no) [no]:  
  18.  >  
  19.  Do you want to add a composer.json file to your module (yes/no) [yes]:  
  20.  >  
  21.  Would you like to add module dependencies (yes/no) [no]:  
  22.  >  
  23.  Do you want to generate a unit test class (yes/no) [yes]:  
  24.  >  
  25.  Do you want to generate a themeable template (yes/no) [yes]:  
  26.  >  
  27.  Do you confirm generation? (yes/no) [yes]:  
  28.  >  
  29. Generated or updated files  
  30.  1 - /var/www/html/drupal8/web/modules/custom/hello/hello.info.yml  
  31.  2 - /var/www/html/drupal8/web/modules/custom/hello/hello.module  
  32.  3 - /var/www/html/drupal8/web/modules/custom/hello/composer.json  
  33.  4 - /var/www/html/drupal8/web/modules/custom/hello/tests/src/Functional/LoadTest.php  
  34.  5 - /var/www/html/drupal8/web/modules/custom/hello/hello.module  
  35.  6 - /var/www/html/drupal8/web/modules/custom/hello/templates/hello.html.twig  

 

写完模块当然是安装了

drupal module:install hello

上面只有sample code 想要渲染一些东西到页面还得生成一个controller

  1.   $ drupal generate:controller  
  2. // Welcome to the Drupal Controller generator  
  3. Enter the module name [hello]:  
  4. >  
  5. Enter the Controller class name [DefaultController]:  
  6. >  
  7. Enter the Controller method title (to stop adding more methods, leave this empty) [ ]:  
  8. > Hello  Awesome  
  9. Enter the action method name [hello]:  
  10. > hello  
  11. Enter the route path [/hello/Hello]:  
  12. > /hello/example  
  13. Enter the Controller method title (to stop adding more methods, leave this empty) [ ]:  
  14. >  
  15. Do you want to generate a unit test class (yes/no) [yes]:  
  16. >  
  17. Do you want to load services from the container (yes/no) [no]:  
  18. >  
  19. Do you confirm generation? (yes/no) [yes]:  
  20. >  

 

之后访问http://localhost/hello/example,就可以看到页面了

  1. 创建一个block layout
  1.    $ drupal generate:plugin:block   
  2.   
  3.  // Welcome to the Drupal Plugin Block generator  
  4.  Enter the module name [hellosanta]:  
  5.  > hello  
  6.  Enter the plugin class name [DefaultBlock]:  
  7.  > testblock  
  8.  Enter the plugin label [testblock]:  
  9.  >  
  10.  Enter the plugin id [testblock]:  
  11.  > hello-block-1  
  12.  Enter the theme region to render the Plugin Block. [ ]:  
  13.  >  
  14.  Do you want to load services from the container (yes/no) [no]:  
  15.  >  
  16. You can add input fields to create special configurations in the block.  
  17. This is optional, press enter to continue  
  18.  Do you want to generate a form structure? (yes/no) [yes]:  
  19.  >  
  20.  New field type (press <return> to stop adding fields) [ ]:  
  21.  > textfield  
  22.  Input label:  
  23.  > Name  
  24.  Input machine name [name]:  
  25.  >  
  26.  Maximum amount of characters [64]:  
  27.  > 10  
  28.  Width of the textfield (in characters) [64]:  
  29.  > 30  
  30.  Description [ ]:  
  31.  > Please leave your name  
  32.  Default value [ ]:  
  33.  > Test  
  34.  Weight for input item [0]:  
  35.  >  
  36.  New field type (press <return> to stop adding fields) [ ]:  
  37.  > email  
  38.  Input label:  
  39.  > Email  
  40.  Input machine name [email]:  
  41.  >  
  42.  Description [ ]:  
  43.  > Please leave your Email  
  44.  Default value [ ]:  
  45.  > jin@126.com  
  46.  Weight for input item [0]:  
  47.  > 1  
  48.  New field type (press <return> to stop adding fields) [ ]:  
  49.  >  
  50.  Do you confirm generation? (yes/no) [yes]:  
  51.  >  

默认region是放在content里的所以只要访问上一步的url就能看见这个block了

 

 

  1. Drush
  1. 改账号密码

drush upwd admin 123456

  1. 清除超过5次登陆错误锁定账号

drush php-eval 'db_query("DELETE FROM `flood`");'

drush user-unblock  <user>

  1. 清缓存

选择类型缓存drush cc

Enter a number to choose which cache to clear.

 [0]   :  Cancel        

 [1]   :  all           

 [2]   :  drush         

 [3]   :  theme-registry

 [4]   :  menu          

 [5]   :  css-js        

 [6]   :  block         

 [7]   :  module-list   

 [8]   :  theme-list    

 [9]   :  registry      

 [10]  :  token         

 [11]  :  views

全局类型清缓存drush cr

  1. 模块下载/启用/更新

下载:drush en 模块名 -y

启用:drush en admin-menu -y

更新:drush upc

刷新数据库:drush updatedb

     2.数据库备份

drush cr all && drush sql-dump --result-file=../19.sql 或者压缩 drush sql-dump --gzip --result-file=../19.sql

 

 

 

 

 

 

 类似资料: