Zum Inhalt

CCM19 plugins

CCM19 puede ampliarse con diversas funcionalidades mediante plugins.

Nombres

Cada plugin tiene un nombre único que consiste en un prefijo del fabricante y el nombre real del plugin. El nombre del plugin debe estar formado por palabras en inglés.

En el futuro, los prefijos de fabricante se asignarán de forma centralizada. Si usted mismo desarrolla los plugins, asegúrese de que el nombre sea lo más exclusivo posible para que no se produzcan colisiones con el prefijo del fabricante.

En el directorio de plugins, el nombre se combina con el prefijo del fabricante en notación CamelCase.

Como ID del plugin en el campo name de composer.json, el nombre se escribe como manufacturer/pluginname en snake_case.

Los plugins desarrollados por el equipo de desarrollo de CCM19 llevan el prefijo Ccm19.

Un plugin de CCM19 para "soporte iframe extendido" se llamaría por tanto ccm19/extended_iframe o Ccm19ExtendedIframe, un plugin del fabricante "Example Vendor" por ejemplo examplevendor/really_special_plugin o ExamplevendorReallySpecialPlugin.

Estructura básica

Un plugin se crea como una carpeta en el directorio plugins y contiene los siguientes archivos y carpetas:

  • composer.json - metadatos sobre el plugin
  • preview.{png``<nt>|</nt>jpeg<nt>|</nt>svg<nt>|</nt>webp<nt>|</nt>gif`} - imagen de vista previa
  • src/ - Archivos fuente PHP (idealmente en una subestructura como en el directorio CCM19-src)
  • src/Controller/ - Archivos PHP del controlador (opcional)
  • config/ - Archivos de configuración de Symfony (opcional)
  • templates/ - Plantillas Twig (opcional)
  • translations/ - archivos de traducción (opcional)

Composer.json

El composer.json tiene este aspecto:

{
    "name": "examplevendor/really_special_plugin",
    "description": "Este plugin hace algo realmente especial que debería describirse aquí",
    "version": "1.0",
    "tipo": "ccm19-plugin",
    "license": "proprietary",
    "authors": [
        {
            "name": "ExampleVendor GmbH",
            "role": "Fabricante"
        }
    ],
    "extra": {
        "copyright": "(c) Copyright...",
        "activatePerDomain": true, // El plugin se puede (des)activar para dominios individuales en la versión de agencia
        "label": {
            "es": "Plugin realmente especial", // Nombre para mostrar en la administración del plugin
            "de": "Plugin realmente especial",
            "fr": "Plugin vraiment spécial"
        },
        "description": {
            "de": "Este plugin hace algo muy especial que debería describirse aquí",
            "fr": "Ce plugin fait quelque chose de vraiment spécial qui devrait être décrit ici."
        },
        "manufacturerLink": {
            "es": "https://examplevendor.example",
            "es": "https://examplevendor.example"
        },
        "supportLink": {
            "es": "https://examplevendor.example/support_de/",
            "es": "https://examplevendor.example/support_en/"
        },
        "preview": "path/to/preview.png" // OPCIONAL: Si la imagen de previsualización no se encuentra en la ubicación por defecto mencionada anteriormente
    }
}

Si faltan especificaciones traducibles en un idioma, se utiliza la especificación en inglés como alternativa.

Los plugins también pueden proporcionar sus propias dependencias utilizando Composer. Para ello, el directorio composer.lock y el directorio vendor/ deben incluirse en el directorio principal del plugin. Las dependencias del plugin se cargan automáticamente cuando se activa el plugin.

Plantillas

Las plantillas del directorio templates/ del plugin se integran mediante espacios de nombres Twig según el esquema @plugin:PluginVerzeichnis/.

En el plugin de ejemplo anterior, templates/index.html.twig sería por tanto @plugin:ExamplevendorReallySpecialPlugin/index.html.twig.

Cambiar las plantillas del sistema principal

Para añadir o editar plantillas de elementos de menú que no sean las propias, se pueden utilizar los eventos App\Event\TemplateResolveEvent y App\Event\TemplateRenderEvent.

Con App\Event\TemplateResolveEvent, cualquier archivo de plantilla (incluidos los que se incluyen con {% include(...) %}, por ejemplo) puede ser ampliado o sustituido por su propia plantilla. Para ello, $event->extendTemplate('@plugin:ExamplevendorReallySpecialPlugin/....twig') se utiliza normalmente para reemplazar o complementar partes de la salida con bloques Twig.

Con App\Event\TemplateRenderEvent, las variables de plantilla se pueden leer o establecer con $event->get() y $event->set() y las plantillas de los elementos del menú (sin incluir las sub-plantillas) también se pueden extender o reemplazar.

class BackendTemplateListener implements EventSubscriberInterface
{
    privado $pluginState;

    public function __construct(PluginState $pluginState)
    {
        $this->pluginState = $pluginState;
    }

    /**
     * @return array
     */
    public static function getSubscribedEvents()
    {
        devuelve [
            TemplateRenderEvent::nameForView('domain/index.html.twig') => ['onRenderDomainIndex', 100],
        ];
    }

    /**
     * @return void
     */
    public function onRenderDomainIndex(TemplateRenderEvent $event)
    {
        if (!$this->pluginState->isActiveForCurrentDomain()) {
            return;
        }

        $event->extendTemplate('@plugin:ExamplevendorReallySpecialPlugin/domain_index.html.twig');
        $event->set('algunaVariable', ...);
    }
}

Rutas y elementos de menú

Las rutas y los elementos de menú se pueden crear a través de las anotaciones @Route y @Menu en los controladores en src/Controller/. Las dependencias para las anotaciones ya están importadas del sistema principal. En el plugin, por lo tanto, sólo es necesario importar las anotaciones con use SymfonyComponent\Routing\Annotation\Route; y use AppComponent\Menu\Annotation\Menu;.

Los nombres de las rutas**** deben empezar por plugin_manufacturer_pluginname_ para que la gestión de derechos tenga efecto y las rutas de los plugins se activen/desactiven dependiendo de si un plugin está activado para un usuario. El nombre del plugin y el prefijo del fabricante deben escribirse en la misma notación snake_case que en composer.json (sólo que con guión bajo en lugar de barra).

Anotación @menu

La anotación Menu crea un elemento de menú para una ruta.

Puede tener los siguientes parámetros:

  • parámetro o nombre: string El nombre utilizado para mostrar el elemento de menú. Se traduce utilizando el sistema de traducción normal.
  • group: string Grupo de menús en el que se mostrará el elemento de menú (opcional, por defecto en "Plugins")
  • icon: string Nombre del icono. Actualmente se soportan glyphicon-... y fa-....
  • order: integer ID de orden con el que se determina la posición en el menú
  • route: string Ruta a la que debe llevar el elemento del menú (por defecto: se lee de la anotación @route del método)
  • route_group: cadena Prefijo de todas las rutas que pertenecen al elemento de menú (por defecto: se lee de la anotación @route de la clase, si está disponible, en caso contrario es igual a route). Se utiliza para mostrar si el elemento de menú sigue activo.
  • access={...}: cadena[] Quién debe tener acceso al elemento de menú. Los valores posibles son "admin", "user" y "subuser". (Por defecto: se determina a partir de la superclase de la clase del controlador).
  • navegación string En qué navegación debe mostrarse el elemento del menú. Los valores posibles son main, domain y meta. Aquí, main corresponde a la navegación que se muestra al usuario cuando se registra. Por tanto, domain o meta, dependiendo de la edición y del tipo de usuario. (Por defecto: domain para DomainDependantControllern, en caso contrario main).
  • ediciones={...}: *cadena[]* Ediciones en las que debe mostrarse el elemento de menú. (Por defecto:paraHostingController`, en caso contrario todas las ediciones).
  • envs={...}: cadena[] Entornos en los que debe mostrarse el elemento de menú. Por ejemplo, {"dev"} para sólo en modo desarrollador. (por defecto: todos)

Preconfiguración de los derechos de acceso y el área de navegación

Si no se establece explícitamente con access y navigation, depende de la clase de la que deriva el controlador quién puede ver el elemento del menú y dónde.

  • domainDependantController": En la navegación del dominio. Sólo visible para usuarios con acceso al dominio (no para administradores de agencias)
  • adminController": En la navegación principal. Sólo visible para los administradores de la edición Agencia y los usuarios de la edición Básica.
  • hostingController": En la navegación principal. Sólo visible para administradores en la edición Agencia.
  • AbstractController: En la navegación principal. Sólo visible para los usuarios que pueden acceder al dominio (no para los administradores de agencias)
  • universalController": En la navegación principal. Visible para todos.
  • unrestrictedController": En la navegación principal. Visible para todos.

La navegación principal varía según la edición y el tipo de usuario. Siempre es la navegación que aparece después de iniciar sesión. Esto significa la navegación de dominio para los usuarios de la Edición Básica y la meta/navegación de usuario para los clientes de la Agencia. Para los Administradores de Agencia, es de nuevo la navegación de "Dominio" (incluso si no hay dominio).

Ejemplo:

namespace Plugins\ExamplevendorReallySpecialPlugin;

use App\Component\Menu\Annotation\Menu;
use App\Controller\DomainDependantController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @Route("/domains/{_domainId}/plugins/examplevendor/really_special/", name="plugin_examplevendor_really_special_plugin_")
 */
class ControladorPrincipal extends ControladorDependienteDominio
{
    /**
     * @Menu("Realmente especial", icon="fa-plug")
     * @Route("", name="index", methods={"HEAD", "GET"})
     */
    función pública index(...): Respuesta
    {
        ...
    }

    /**
     * @Route("", name="guardar")
     */
    función pública indexSave(...): Respuesta
    {
        ...
    }
}

Se puede utilizar el autowiring de Symfony. Dos argumentos especiales adicionales de autocableado son posibles dentro de los plugins:

  • App\Model\PluginState devuelve el modelo de estado del plugin para el plugin actual, que se puede utilizar, por ejemplo, para comprobar si el plugin debe estar activo.
  • string $PLUGINPATH devuelve la ruta completa al directorio del plugin.

Los elementos del menú del dominio (es decir, aquellos cuyo controlador deriva de DomainDependantController) se muestran/ocultan automáticamente cuando se (des)activa el plugin para el dominio.

Los elementos de menú que no dependen del dominio se ocultan automáticamente en la versión de agencia cuando el plugin se bloquea para un cliente.

Para requisitos más especializados, también es posible configurar manualmente los elementos de menú a través de un registro de eventos en el evento App\Event\MenuGenerationEvent.

Reaccionar a rutas de otros controladores

El evento ccm19.controller.request.<route_name>, por ejemplo ccm19.controller.request.app_dashboard, puede utilizarse para reaccionar a una ruta antes de que se ejecute el controlador correspondiente.

El objeto evento es un Symfony\Component\HttpKernel\Event\ControllerEvent. La petición también puede ser redirigida a otro controlador utilizando el método setController().

El evento ccm19.controller.response.<route_name>, por otro lado, permite ejecutar código después de que el controlador se haya ejecutado.

Ambos eventos no se activan en caso de acceso no autorizado, por ejemplo, si se llama a una ruta que requiere un usuario conectado sin una sesión válida.

Importante:Para todos los manejadores de eventos, siempre se debe comprobar con $pluginState->isActiveForCurrentDomain() o, dependiendo del contexto, $pluginState->isAllowedForCurrentUser() si se desea una acción del plugin en el contexto actual.