Zum Inhalt

CCM19-Plugins

CCM19 puede ampliarse con diversas funcionalidades mediante plugins.

Nombres

Cada plugin tiene un nombre único compuesto por 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 desarrollas plugins tú mismo, asegúrate de que el nombre sea lo más exclusivo posible para que no se produzcan colisiones con el prefijo del fabricante.

Para el directorio de plugins-, el nombre se compone con el prefijo del fabricante-en grafía CamelCase-.

Como ID de 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 extendido de iframe-" 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|jpeg|svg|webp|gif} - imagen de vista previa
  • src/ - archivos fuente PHP-(idealmente en una subestructura como en el directorio CCM19-src-)
  • src/Controller/ - Controlador-PHP-archivos (opcional)
  • config/ - Archivos Symfony-Config-(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",
    "type": "ccm19-plugin",
    "licencia": "propietario",
    "authors": [
        {
            "name": "ExampleVendor GmbH",
            "role": "Fabricante"
        }
    ],
    "extra": {
        "copyright": "(c) Copyright...",
        "activatePerDomain": true, // El plugin en la versión Agencia-puede activarse para dominios individuales (de-)
        "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 estándar antes mencionada-
    }
}

Si falta información traducible en un idioma, se utiliza la informació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 ejemplo anterior del plugin-, 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) se puede ampliar o sustituir por su propia plantilla. Para ello, $event->extendTemplate('@plugin:ExamplevendorReallySpecialPlugin/....twig') suele utilizarse para sustituir o complementar partes de la salida con bloques Twig-.

Con App\Event\TemplateRenderEvent, se pueden leer o establecer variables de plantilla-con $event->get() y $event->set() y también se pueden extender o reemplazar plantillas de elementos de menú-(no se incluyen subplantillas-).

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 las anotaciones @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;.

Las rutas-nombresdebencomenzar con plugin_manufacturer_pluginname_ para que la gestión de derechos tenga efecto y las rutas plugin-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).

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

Puede tener los siguientes parámetros:

  • primer parámetro o nombre: string El nombre que se utiliza para mostrar el elemento de menú. Se traduce utilizando el sistema de traducción normal.
  • grupo`: 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 del 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, de lo 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 del controlador-class).
  • 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": Navegación en el dominio-. Sólo visible para usuarios con acceso al dominio (no para administradores de la agencia-)
  • 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 los administradores de 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 la agencia-)
  • 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. Así, la navegación del dominio-para los usuarios de la Edición Básica-- y la navegación Meta/Usuario-para los clientes de la Agencia-. Para los administradores de la agencia-es de nuevo la navegación "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 de autocableado-también son posibles dentro de los plugins:

  • App\Model\PluginState devuelve el estado del plugin-modelo-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 el plugin se activa para el dominio (de-).

Los elementos de menú que no dependen del dominio se ocultan automáticamente en la versión de Agencia-si el plugin está bloqueado para un cliente.

Para requisitos más especializados, también es posible configurar manualmente los elementos del menú a través de un evento-listerner 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-, utilice siempre $pluginState->isActiveForCurrentDomain() o, dependiendo del contexto, $pluginState->isAllowedForCurrentUser() para comprobar si una acción del plugin es deseada en el contexto actual.