Interfaz de línea de comandos


1Presentación

A menudo resulta útil escribir scripts que se ejecuten desde la línea de comandos. Esto es muy fácil de hacer en PHP puro, pero luego hay que inicializar manualmente el log, las fuentes de datos, el autoloader, la inyección de dependencias...

Por ello, Temma ofrece la funcionalidad Comma (COMmand-line MAnager), que realiza todas las inicializaciones necesarias antes de ejecutar el código solicitado.

Un script se ejecuta llamando al programa bin/comma, pasándole como parámetros el nombre del objeto y del método que se van a ejecutar, así como los parámetros adicionales que espera ese método.
La forma canónica es objeto/método, como una URL de Temma. El nombre del método también puede separarse del nombre del objeto con un espacio, dos puntos (:, como en los comandos de Symfony) o dos puntos dobles (::, como en las llamadas estáticas de PHP); estas formas son equivalentes.
El código que se ejecuta puede ser completamente autónomo (haciendo su trabajo a partir de las opciones proporcionadas), o entrar en comunicación interactiva con el usuario.

Algunos ejemplos imaginarios:

$ bin/comma CrmManager/pushData
Nuevos datos enviados al CRM
$ bin/comma Data/import --app=main
Introduce la ruta del archivo a importar: /tmp/import.json
Importación completada

Por defecto, los comandos ejecutables se almacenan en el directorio cli/ del proyecto. Sin embargo, puedes colocarlos donde quieras dentro de las rutas de inclusión, eventualmente usando un namespace.

Al usar un namespace, debes encerrar el nombre del objeto entre comillas o apóstrofos.
Por ejemplo:

$ bin/comma "\MyApp\Cli\CrmManager/pushData"
Nuevos datos enviados al CRM
$ bin/comma '\Cli\Managers\Data/import' --app=main
Introduce la ruta del archivo a importar: /tmp/import.json
Importación completada

Comandos proporcionados por Temma

Temma proporciona varios comandos, cuya documentación puede encontrarse en la sección "Helpers":

Cuando un nombre de controlador no empieza por una barra invertida y no corresponde a ninguna clase del proyecto, se busca automáticamente en el namespace \Temma\Cli. Así, es posible escribir bin/comma Cache/clear en lugar de bin/comma '\Temma\Cli\Cache' clear (una clase del proyecto con el mismo nombre tiene prioridad).


2Documentación

Al escribir bin/comma o bin/comma help, puedes ver la documentación general de Comma:

Si escribes bin/comma help seguido del nombre de un controlador, verás una lista de las acciones del controlador, con su documentación asociada:

Si añades el nombre de una acción, solo verás su documentación:


3Controladores

Los objetos ejecutados por Comma son controladores idénticos a los usados por Temma en respuesta a las peticiones HTTP, salvo que deben almacenarse en el directorio cli/ (y no en controllers/).

Hay muchas similitudes:

  • Las acciones pueden recibir un número variable de parámetros, con parámetros opcionales (con un valor por defecto).
  • Los métodos de inicialización __wakeup() y de finalización __sleep() se ejecutan respectivamente antes y después de la ejecución de la acción.
  • Si no se indica ningún nombre de método en la línea de comandos, se llama a la acción raíz __invoke(). Esta acción no puede recibir parámetros.
  • Si se define una acción por defecto __call() en el controlador, se ejecutará para todas las acciones solicitadas que no tengan un método equivalente.
  • Si se define una acción proxy __proxy() en el controlador, se ejecutará siempre, sea cual sea la acción llamada.
  • Los atributos definidos en controladores y acciones se ejecutan (siempre que puedan funcionar en un entorno de línea de comandos, y no en un entorno web).
  • El archivo de configuración etc/temma.php se lee y su contenido se pone a disposición mediante el objeto $this->_config.
  • El componente de inyección de dependencias se genera, y está disponible de la misma forma (escribiendo $this->_loader).
  • Las fuentes de datos se generan, y están disponibles ya sea escribiéndolas directamente (por ejemplo $this->db), o pasando por el componente de inyección de dependencias (por ejemplo $this->_loader->dataSources->db o $this->_loader->dataSources['db-read']).
  • También pueden usarse los DAO.

Pero también hay varias diferencias:

  • No existe sistema de rutas, ni siquiera simplificado (no es posible llamar a un controlador con un nombre distinto del suyo).
  • No se ejecuta ningún plugin.
  • No hay vistas.
  • El objeto $this->_request solo contiene los parámetros proporcionados en la línea de comandos.

4Parámetros

Los parámetros esperados por las acciones pueden pasarse en la línea de comandos de dos maneras, que pueden combinarse: parámetros nombrados y parámetros posicionales.

Los parámetros nombrados se pasan añadiendo el prefijo --, seguido del signo igual (=) y del valor asociado. Se asocian a los parámetros del método según sus nombres.

Si el valor contiene espacios, puede encerrarse entre comillas (") o apóstrofos (').

Si un parámetro nombrado se pasa sin valor, se procesará como un booleano con valor true.

Los parámetros posicionales rellenan los parámetros del método de izquierda a derecha. Pueden escribirse como una URL de Temma (objeto/método/valor1/valor2, en cuyo caso los valores no pueden contener barras) o como simples argumentos de línea de comandos (objeto/método valor1 valor2).

Un valor posicional que empiece por un guion debe ir precedido del marcador estándar de fin de opciones --: bin/comma Math/add 3 -- -5


5Ejemplo

Por ejemplo, podrías crear un script para añadir un usuario a la base de datos.

Este script podría llamarse así:

$ bin/comma User/add --name="Luke Skywalker" --email=luke@rebellion.org

La misma llamada, con parámetros posicionales:

$ bin/comma User/add "Luke Skywalker" luke@rebellion.org

Podríamos imaginar un parámetro opcional, para indicar que el usuario es administrador:

$ bin/comma User/add --name=Yoda --email=yoda@rebellion.org --admin=1

En términos concretos, Comma instanciará el objeto User, y luego llamará a su método add(), pasándole los parámetros.

El objeto User debe almacenarse en un archivo llamado User.php, ubicado en el directorio cli/ del proyecto.
Este objeto debe heredar del objeto \Temma\Web\Controller.

El código de este objeto podría ser:

class User extends \Temma\Web\Controller {
    /** Creación de un Data Access Object automático. */
    protected $_temmaAutoDao = true;

    /**
     * Añadir usuario.
     * @param  string  $name   Nombre del usuario.
     * @param  string  $email  Dirección de correo electrónico del usuario.
     * @param  bool    $admin  (opcional) Permisos de administrador. Falso por defecto.
     */
    public function add(string $name, string $email, bool $admin=false) {
        // añade el usuario a la base de datos
        $id = $this->_dao->create([
            'name'  => $name,
            'email' => $email,
            'roles' => $admin ? 'admin' : '',
        ]);
        // mensaje
        print("Usuario creado con el identificador '$id'.\n");
    }
}

6Configuración

Por defecto, los scripts de línea de comandos cargan la configuración presente en el archivo etc/temma.php. Es posible indicar la ruta a otro archivo usando el parámetro conf.

Este parámetro debe colocarse antes del nombre del controlador.

Por ejemplo:

$ bin/comma conf=etc/temma-test.php User/add --name=Yoda --email=yoda@rebellion.org

Ten en cuenta que es posible indicar un archivo fuera del árbol del proyecto, pero eso no cambiará las rutas usadas hacia los distintos directorios. Por ejemplo, el plugin Language seguirá buscando sus archivos en etc/lang/.


7Rutas de inclusión

Los scripts ejecutados con Comma tienen el directorio lib/ del proyecto añadido a sus rutas de inclusión. Pueden añadirse rutas adicionales con el parámetro inc.

Al igual que con el parámetro conf, este parámetro debe colocarse antes del nombre del controlador.

Por ejemplo:

$ bin/comma inc=/other/project/src Deploy/start

8Log

Por defecto, los scripts de línea de comandos escriben sus logs en la salida de error.

Si así se indica en el archivo etc/temma.php, los logs también pueden escribirse en el archivo log/temma.log.

Para desactivar la escritura en la salida de error, usa el parámetro nostderr.

Al igual que con los parámetros conf e inc, este parámetro debe colocarse antes del nombre del controlador.

Ejemplo:

$ bin/comma nostderr User/list

9Interfaz

La interfaz de usuario es completamente distinta de la de los controladores web. Los scripts de línea de comandos interactúan escribiendo en su salida estándar, y recuperan lo que el usuario introduce leyendo desde su entrada estándar.

Temma proporciona dos helpers útiles en estas condiciones:

  • \Temma\Utils\Ansi: proporciona métodos para mejorar la visualización de la información escrita por tu código.
  • \Temma\Utils\Term: proporciona funcionalidades para interactuar más fácilmente con la terminal.