Atributos


1Presentación

Temma ofrece atributos PHP opcionales para controlar el acceso a los controladores y las acciones.

Estos atributos pueden combinarse entre sí, por lo que puedes añadir varios atributos distintos (y a veces el mismo atributo varias veces, con parámetros diferentes) al mismo controlador o acción.

Además, puedes crear tus propios atributos para gestionar el acceso a controladores y acciones.

Atributos proporcionados por Temma

Temma proporciona varios atributos, cuya documentación está disponible en la sección "Helpers":

  • Auth: Para restringir el acceso a los usuarios autenticados.
  • Check: Para validar los datos de entrada (parámetros URL/GET/POST, payload, archivos) y los datos de salida.
  • View: Para gestionar las vistas de controladores y acciones.
  • Template: Para definir la ruta del archivo de plantilla.
  • Method: Para gestionar los métodos HTTP autorizados.
  • Referer: Para filtrar el acceso según el HTTP REFERER.
  • Redirect: Para redirigir automáticamente las peticiones.

2Escribe tus propios atributos

Puedes crear tus propios atributos para gestionar el acceso a controladores y acciones.

En Temma, los atributos son activos: el framework reacciona a su presencia; ejecuta los atributos, les proporciona una API, y son los propios atributos los que controlan el comportamiento del framework.
En comparación con otros frameworks, esto hace que Temma sea más simple. Se pueden añadir nuevos atributos sin necesidad de modificar el núcleo del framework.


2.1Principio

Tus atributos deben extender la clase \Temma\Web\Attribute y solo pueden aplicarse a controladores y acciones.

Un atributo debe definir un constructor, que puede recibir los parámetros necesarios para el atributo. El constructor no debe realizar ninguna lógica y solo debe almacenar los parámetros recibidos.
El procesamiento real del atributo debe implementarse en un método apply(), que recibe como parámetro un objeto que implementa la interfaz Reflector, indicando el contexto en el que se ejecuta el atributo. Puede ser un objeto ReflectionClass (a nivel de controlador) o un objeto ReflectionMethod (a nivel de acción).

Gracias a la herencia, tus atributos tienen acceso a funcionalidades muy similares a las disponibles para los controladores:

  • Acceso a las variables de plantilla mediante notación de corchetes.
    Por ejemplo: $this['var'] = 'value'; para definir una variable, y $var = $this['var']; para leer el valor de una variable.
  • Acceso a las fuentes de datos en forma de propiedades directas del objeto.
    Por ejemplo: $this->db para acceder a una base de datos llamada db.
  • Los métodos $this->_httpCode() y $this->_httpError() para definir el código de retorno HTTP, o el código de error HTTP.
    Los métodos $this->_getHttpCode() y $this->_getHttpError() para recuperar el código HTTP previamente definido.
  • Los métodos $this->_redirect() y $this->_redirect301() para definir órdenes de redirección.
  • Los métodos $this->_view() para definir la vista, $this->_template() para definir la plantilla, y $this->_templatePrefix() para definir el prefijo de plantilla.

Además, hay propiedades para acceder a los objetos internos de Temma:

Todos estos elementos permiten manipular el flujo de ejecución del mismo modo que los plugins.


2.2Flujo de ejecución

Para modificar el flujo de ejecución, un atributo debe lanzar una excepción específica:

  • \Temma\Exceptions\FlowHalt: Detiene el flujo de ejecución. No se ejecutará ningún otro plugin ni controlador, y el framework pasa directamente al procesamiento de la vista o de la redirección.
  • \Temma\Exceptions\FlowRestart: Reinicia el procesamiento de la fase actual (pre-plugins, controlador o post-plugins).
  • \Temma\Exceptions\FlowReboot: Reinicia toda la cadena de procesamiento (pre-plugins + controlador + post-plugins).
  • \Temma\Exceptions\FlowQuit: Detiene la ejecución del framework. No se ejecutará ningún otro plugin ni controlador. La vista no se ejecutará y las peticiones de redirección se ignoran.

2.3Ejemplo

Aquí tienes un ejemplo de un atributo llamado MyLog, que escribe en un archivo justo antes de que un controlador sea instanciado o una acción sea ejecutada. Se escriben el nombre del objeto o del método, junto con el nombre del archivo y el número de línea.

<?php

use \Temma\Base\Log as TµLog;

/**
 * Atributo usado para escribir en un log el flujo de ejecución
 * de los controladores y las acciones.
 */
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
class MyLog extends \Temma\Web\Attribute {
    /**
     * Constructor.
     * @param   string  $message  (opcional) Mensaje que se añade a la línea de log.
     */
    public function __construct(private ?string $message=null) {
    }

    /**
     * Ejecución del atributo.
     * @param   \Reflector  $context  Contexto de ejecución (clase o método).
     */
    public function apply(\Reflector $context) : void {
        // recuperar la información
        $name = $context->getName();
        $file = $context->getFileName();
        $line = $context->getStartLine();

        // determinar el tipo de contexto
        if ($context instanceof \ReflectionClass) {
            $type = 'Controller';
            // $name ya contiene el nombre completo de la clase
        } elseif ($context instanceof \ReflectionMethod) {
            $type = 'Action';
            // $name contiene el nombre del método; se le añade el nombre de la clase
            $name = $context->getDeclaringClass()->getName() . '::' . $name;
        } else {
            return;
        }

        // construir la cadena de log
        $logString = "[$type] $name ($file:$line)";
        if ($this->message)
            $logString .= ' : ' . $this->message;

        // escribir en el log
        TµLog::l($logString);
    }
}
  • Línea 9 : El objeto se declara como un atributo que puede aplicarse a clases y métodos.
  • Línea 10 : Definición del objeto, que extiende \Temma\Web\Attribute.
  • Línea 15 : Constructor del atributo, que recibe un parámetro promovido a propiedad privada.
  • Línea 22 : Método de ejecución, que recibe el contexto de ejecución como parámetro.
  • Líneas 23 a 38 : Recuperación de la información necesaria para construir el mensaje de log.
  • Líneas 40 a 43 : Construcción del mensaje de log.
  • Línea 46 : Escritura de la cadena mediante el objeto \Temma\Base\Log.

Y aquí tienes un ejemplo de cómo se puede usar este atributo:

<?php

/** Controlador. */
#[MyLog]
class Article extends \Temma\Web\Controller {
    /** Acción que muestra la lista de artículos. */
    #[MyLog('Article list')]
    public function list() {
        // ...
    }

    /**
     * Acción que muestra un artículo.
     * @param int  $id  Identificador del artículo.
     */
    #[MyLog('Display article')]
    public function view(int $id) {
        // ...
    }
}
  • Línea 4 : El atributo MyLog se aplica al controlador.
    Esto añadirá la siguiente línea al log: [Controller] Article (Article.php:4)
  • Línea 7 : El atributo se aplica a la acción list().
    Esto añadirá la siguiente línea al log: [Action] Article::list (Article.php:7) : Article list
  • Línea 16 : El atributo se aplica a la acción view().
    Esto añadirá la siguiente línea al log: [Action] Article::view (Article.php:16) : Display article