Zum Inhalt

Plugins programmieren

-# 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 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 ortografí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 tienen 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 jpeg svg webp gif} - imagen de vista previa ----src/ - archivos fuente PHP (idealmente en una subestructura como en el directorio src de CCM19) ---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",
   -"type": "ccm19 plugin",
    "license": "proprietary",
    "authors": [
        {
            "name": "ExampleVendor GmbH",
            "role": "Fabricante"
        }
    ],
    "extra": {
        "copyright": "(c) Copyright...",
       --"activatePerDomain": true, // El plugin en la versión Agencia se puede activar 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 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 este propósito, $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 pueden leerse o establecerse con $event >get() y $event >set() y las plantillas de elementos de menú (subplantillas no incluidas) también pueden extenderse o reemplazarse.

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

-### Anotación @Menu

-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 pedido, 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": Navegación en el dominio.-Sólo visible para usuarios con acceso al dominio (no para administradores de agencia) - AdminController: En la navegación principal.--Sólo visible para admins en la Edición Agencia y usuarios en 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 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.-----Así que la navegación de 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 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 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 se 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 de menú a través de un listador de eventos en el evento App\Event\MenuGenerationEvent.

Reaccionar a rutas de otros controladores

El evento ccm19.controller.request., 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., 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.