Controlando la salida de comandos de Drush

cli
Solucionex
21
Ago 24

La mayoría de comandos de drush que emiten datos (como por ejemplo, el comando status), permiten controlar cómo se presenta la información e incluso elegir los campos a mostrar.

Ejemplo con el comando drush status (pueden comprobarse las opciones con el comando "drush help status"):

--format[=FORMAT] Format the result data. Available formats:                                                                 
                  csv,json,list,null,php,print-r,string,table,tsv,var_dump,var_export,xml,yaml [default: table]              
--fields=FIELDS   Available fields: Drupal version (drupal-version), Site URI (uri), DB driver (db-driver)...

Formatos

Por ejemplo, puede cambiarse del formato por defecto (drush status):

Drupal version   : 10.3.1                                     
Site URI         : https://project.ddev.site                      
DB driver        : mysql                                      
DB hostname      : db                                         
DB port          : 3306                                       
DB username      : db                                         
DB name          : db                                         
Database         : Connected                                  
Drupal bootstrap : Successful                                 
Default theme    : wingsuit                                   
Admin theme      : gin                                        
PHP binary       : /usr/bin/php8.3                            
PHP config       : /etc/php/8.3/cli/php.ini                   
PHP OS           : Linux                                      
PHP version      : 8.3.2-1+0~20240120.16+debian11~1.gbpb43448 
Drush script     : /var/www/html/vendor/bin/drush             
Drush version    : 13.0.0.0                                   
Drush temp       : /tmp                                       
Drush configs    : /var/www/html/vendor/drush/drush/drush.yml 
                  /var/www/html/drush/drush.yml              
Install profile  :                                            
Drupal root      : /var/www/html/web                          
Site path        : sites/default                              
Files, Public    : sites/default/files                        
Files, Private   : /var/www/html/web/../private_files         
Files, Temp      : /tmp

a JSON (drush status --format=json):

{
   "drupal-version": "10.3.1",
   "uri": "https://project.ddev.site",
   "db-driver": "mysql",
   "db-hostname": "db",
   "db-port": "3306",
   "db-username": "db",
   "db-password": "db",
   "db-name": "db",
   "db-status": "Connected",
   "bootstrap": "Successful",
   "theme": "wingsuit",
   "admin-theme": "gin",
   "php-bin": "/usr/bin/php8.3",
   "php-conf": [
       "/etc/php/8.3/cli/php.ini"
   ],
   "php-os": "Linux",
   "php-version": "8.3.2-1+0~20240120.16+debian11~1.gbpb43448",
   "drush-script": "/var/www/html/vendor/bin/drush",
   "drush-version": "13.0.0.0",
   "drush-temp": "/tmp",
   "drush-conf": [
       "/var/www/html/vendor/drush/drush/drush.yml",
       "/var/www/html/drush/drush.yml"
   ],
   "drush-alias-files": [
       "/var/www/html/drush/sites/pre.site.yml",
       "/var/www/html/drush/sites/prod.site.yml"
   ],
   "alias-searchpaths": [
       "/var/www/html/drush/sites"
   ],
   "install-profile": false,
   "root": "/var/www/html/web",
   "drupal-settings-file": "sites/default/settings.php",
   "site": "sites/default",
   "themes": "sites/all/themes",
   "modules": "sites/all/modules",
   "files": "sites/default/files",
   "private": "/var/www/html/web/../private_files",
   "temp": "/tmp",
   "config-sync": "../config/sync",
   "%paths": {
       "%root": "/var/www/html/web",
       "%site": "sites/default",
       "%modules": "sites/all/modules",
       "%themes": "sites/all/themes",
       "%config-sync": "../config/sync",
       "%files": "sites/default/files",
       "%temp": "/tmp",
       "%private": "/var/www/html/private_files"
   }
}

o a yaml (drush status --format=yaml):

drupal-version: 10.3.1
uri: 'https://project.ddev.site'
db-driver: mysql
db-hostname: db
db-port: '3306'
db-username: db
db-password: db
db-name: db
db-status: Connected
bootstrap: Successful
theme: wingsuit
admin-theme: gin
php-bin: /usr/bin/php8.3
php-conf:
 - /etc/php/8.3/cli/php.ini
php-os: Linux
php-version: 8.3.2-1+0~20240120.16+debian11~1.gbpb43448
drush-script: /var/www/html/vendor/bin/drush
drush-version: 13.0.0.0
drush-temp: /tmp
drush-conf:
 - /var/www/html/vendor/drush/drush/drush.yml
 - /var/www/html/drush/drush.yml
drush-alias-files:
 - /var/www/html/drush/sites/pre.site.yml
 - /var/www/html/drush/sites/prod.site.yml
alias-searchpaths:
 - /var/www/html/drush/sites
install-profile: false
root: /var/www/html/web
drupal-settings-file: sites/default/settings.php
site: sites/default
themes: sites/all/themes
modules: sites/all/modules
files: sites/default/files
private: /var/www/html/web/../private_files
temp: /tmp
config-sync: ../config/sync
'%paths':
 '%root': /var/www/html/web
 '%site': sites/default
 '%modules': sites/all/modules
 '%themes': sites/all/themes
 '%config-sync': ../config/sync
 '%files': sites/default/files
 '%temp': /tmp
 '%private': /var/www/html/private_files

Campos

También puede filtrarse qué campos se quieren mostrar. Por ejemplo, para mostrar solamente los campos de php (drush status --fields=php-bin,php-conf,php-os,php-version):

PHP binary  : /usr/bin/php8.3                            
PHP config  : /etc/php/8.3/cli/php.ini                   
PHP OS      : Linux                                      
PHP version : 8.3.2-1+0~20240120.16+debian11~1.gbpb43448

También pueden combinarse ambas opciones (formato y campos), para obtener solamente los campos que se quieran en un formato determinado (drush status --format=json --fields=php-bin,php-conf,php-os,php-version):

{
   "php-bin": "/usr/bin/php8.3",
   "php-conf": [
       "/etc/php/8.3/cli/php.ini"
   ],
   "php-os": "Linux",
   "php-version": "8.3.2-1+0~20240120.16+debian11~1.gbpb43448"
}

Ejemplo en comando personalizado

Se usa como ejemplo la siguiente clase de comandos de drush, que contiene un comando que muestra información sobre los tipos de contenido de la web y cuántos nodos hay de cada tipo:

<?php
declare(strict_types=1);

namespace Drupal\slx\Drush\Commands;

use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\node\NodeTypeInterface;
use Drush\Attributes as CLI;
use Drush\Commands\AutowireTrait;
use Drush\Commands\DrushCommands;

/**
* Example commands.
*/
final class PostCommands extends DrushCommands {

 use AutowireTrait;
 
 /**
  * The current entity storage.
  *
  * @var \Drupal\Core\Entity\EntityStorageInterface
  */
 protected $storage;
 
 public function __construct(
   private EntityTypeManagerInterface $entityTypeManager,
 ) {
 }
 
 /**
  * Gets the content types of this web.
  */
 #[CLI\Command(name: 'slx-content-types', aliases: ['slxct'])]
 public function getContentTypes(array $options = ['format' => 'table', 'delimiter' => ';']): RowsOfFields {
   $this->storage = $this->entityTypeManager->getStorage('node');
   $content_types = $this->entityTypeManager->getStorage('node_type')->loadMultiple();
   
   $rows = array_map(fn (NodeTypeInterface $content_type) => [
     'label' => $content_type->label(),
     'machine name' => $content_type->id(),
     'total' => $this->count(['type' => $content_type->id()]),
     'published' => $this->count(['type' => $content_type->id(), 'status' => 1]),
     'unpublished' => $this->count(['type' => $content_type->id(), 'status' => 0]),
   ], $content_types);
   
   return new RowsOfFields($rows);
 }
 
 /**
  * Gets the content count for a specific entity type and conditions.
  */
 private function count(array $conditions): int {
   $query = $this->storage->getQuery()
     ->accessCheck(FALSE)
     ->count();
   foreach ($conditions as $field => $value) {
     $query->condition($field, $value);
   }
   
   return $query->execute();
 }
 
}

Solamente hay que tener en cuenta dos cosas:

  • Poner que la función del comando tenga como argumento la variable $options, donde se puede especificar el formato por defecto (y el delimitador para cuando se use el formateador "csv"):
public function getContentTypes(array $options = ['format' => 'table', 'delimiter' => ';']): RowsOfFields {
  • Retornar los datos como un objeto RowsOfFields. Los datos a retornar son un array cuyos valores son un array asociativo con [Nombre del campo => Valor del campo]

En caso de no retornar un array con múltiples valores y solamente querer mostrar una lista de datos sin repetición (ejemplo: ['content type' => 'Página básica', 'total nodes' => 57]), puede usarse un objeto PopertyList como valor de retorno de la función.

Drush