Escribir un complemento GLPI para reabrir pedidos

Hola.



Hoy hablaremos sobre cómo escribí el complemento GLPI para que funcione con nuevos pedidos creados sobre la base de pedidos ya cerrados, o más bien reabrir pedidos cerrados, si se reciben solicitudes adicionales del usuario para ellos.

Antecedentes



Durante casi un mes he estado investigando el código fuente del sistema de asistencia técnica de GLPI. Y mientras estudiaba esta solución de código abierto, llamé la atención sobre la cantidad insignificante de información para los desarrolladores. La gran mayoría del material está relacionado con la configuración GLPI dentro de la interfaz. Un poco menos, pero aún puede encontrar información sobre cómo configurar el servidor. Y solo un artículo (y el que está en inglés) habla sobre el desarrollo de complementos para este sistema milagroso.



De los manuales oficiales: un par de recursos sobre readthedocs, además de un manual generado a partir de phpdoc.



De la comunidad: un chat en el telegrama y un foro extranjero.

Los parámetros de entrada son los siguientes.



Existe un sistema de asistencia técnica GLPI. Las aplicaciones de los usuarios se envían a un buzón dedicado conectado al sistema. La respuesta del servicio de soporte también llega por correo. En general, todas las notificaciones sobre el progreso de la aplicación desde la primera llamada hasta la decisión y el cierre se envían al correo.



Sin embargo, si el usuario considera que su problema no se ha resuelto correctamente y decide responder a la carta sobre el cierre de la solicitud, entonces en lugar de reabrir, se crea una nueva solicitud y simplemente se le adjunta el ticket anterior. En realidad, este problema tenía que resolverse.



Entonces vamos.



El primer paso es instalar el generador de complementos- Simplifica enormemente la vida al crear el esqueleto de nuestro futuro complemento. Esto se puede hacer usando el siguiente algoritmo:



  • (/path/to/glpi/plugins)
  • :



    $ ./plugin.sh YourPluginName 1.0


    YourPluginName — , 1.0 — .



Y eso es todo, el marco está listo.



Al ingresar al directorio del complemento que creó, verá un montón de archivos, de los cuales solo se necesitan setup.php y hook.php. Si planea usar bibliotecas adicionales, puede dejar composer.json. No los necesitaba, así que dejé solo 2 archivos necesarios.



Hay dos funciones requeridas en el archivo setup.php - plugin_init_yourpluginname y plugin_version_yourpluginname . El primero inicializa el complemento, el segundo devuelve información sobre él: nombre, autor, versión, etc.



Con el segundo, todo está más o menos claro. Por tanto, nos centraremos brevemente en la primera función. Funciona con la variable global $ PLUGIN_HOOKS... Seguramente todo el mundo sabe lo que son los ganchos, pero si alguien no lo sabe, entonces este es el llamado. ganchos del sistema que extrae el complemento. Puede leer más sobre los ganchos en el manual oficial .



Cada complemento debe registrar el gancho csrf_compliant ; de lo contrario, simplemente no podrá activarlo, habrá un error como este:





No sé qué es este parámetro, hasta que descubrí el sistema hasta el final. Si hay expertos en GLPI entre los lectores, escriba los comentarios.




Además del enlace obligatorio, puede registrar muchos otros, por ejemplo, establecer un enlace a la página de configuración:



$PLUGIN_HOOKS['config_page']['yourpluginname'] = 'config.php';


Las clases de complementos también se registran en esta función:

Plugin::registerClass(PluginYourpluginnameConfig::class);
, , , GLPI , . : Plugin + + . , , .



: PluginYourpluginnameConfig, config.class.php. inc ( , , , , — — , - ).



.

Volvamos a nuestros ganchos. Necesito realizar un seguimiento de la creación de un nuevo ticket de cancelación, así que registraré un controlador de gancho pre_item_add . Puede pasar parámetros al controlador, esto se hace usando una matriz asociativa, donde la clave es el objeto de la entidad deseada (en mi caso, Ticket), y el valor es el nombre de la función del controlador.



Como resultado, en mi caso, las dos funciones requeridas del archivo setup.php se ven así:



/**
 * Init hooks of the plugin.
 * REQUIRED
 *
 * @return void
 */
function plugin_init_advtickets() {
   global $PLUGIN_HOOKS;

   Plugin::registerClass(PluginAdvticketsEvent::class);

   $PLUGIN_HOOKS['csrf_compliant']['advtickets'] = true;

   $PLUGIN_HOOKS['pre_item_add']['advtickets'] = [
       Ticket::class => 'plugin_advtickets_pre_item_add'
   ];

}

/**
 * Get the name and the version of the plugin
 * REQUIRED
 *
 * @return array
 */
function plugin_version_advtickets() {
   return [
      'name'           => 'Adv Tickets',
      'version'        => PLUGIN_ADVTICKETS_VERSION,
      'author'         => 'Roman Gonyukov',
      'license'        => '',
      'homepage'       => 'https://github.com/stayfuneral/advtickets',
      'requirements'   => [
         'glpi' => [
            'min' => '9.2',
         ]
      ]
   ];
}


La documentación dice que es posible registrar métodos estáticos de clases como manejador, en cuyo caso deberían verse así (por cierto, no es en absoluto necesario pasar ningún parámetro al manejador):



/*     */

//call a function
$PLUGIN_HOOKS['hook_name']['plugin_name'] = 'function_name';
//call a static method from an object
$PLUGIN_HOOKS['other_hook']['plugin_name'] = ['ObjectName', 'methodName'];


Las propias funciones del controlador se almacenan en el archivo hook.php. Las funciones para instalar y desinstalar el complemento también se almacenan allí. Los mismos requisitos para los nombres de funciones son plugin_yourpluginname_function_name.



Por cierto, intenté registrar un método estático para manejar el gancho y pasar el objeto Ticket a los parámetros, pero por alguna razón, nada funcionó para mí. Pero con la función habitual, todo salió bien. Por lo tanto, para no ensuciar hook.php con código innecesario, registré una clase que contiene un método de manejo de gancho, y en la función requerida simplemente llamé a este método:



// hook.php

/**
 * @param Ticket $ticket
 *
 * @return bool
 */
function plugin_advtickets_pre_item_add(Ticket $ticket)
{
    return PluginAdvticketsEvent::pre_item_add_ticket($ticket);
}


Si necesita instalar tablas en una base de datos, la documentación oficial tiene un párrafo separado sobre este tema. No necesitaba las mesas, así que me salto este momento.



Bueno, hemos descubierto cómo instalar / desinstalar el complemento, registrar y llamar a los manejadores de enganches, ahora es el momento de averiguar cómo procesaremos una nueva solicitud.



Para hacer esto, como se mencionó anteriormente, registré la clase PluginAdvticketsEvent (archivo inc / event.php), que contiene un único método pre_item_add_ticket .



class PluginAdvticketsEvent extends CommonDBTM
{
    static function pre_item_add_ticket(Ticket $ticket)
    {
        global $DB;

// ..    ,      input
        $fields = $ticket->input;

//      ,       ( ) 
        if($fields['_link']['tickets_id_2']) {

            $relatedTicketId = $fields['_link']['tickets_id_2'];

            $relatedTicketParamsForUpdate = [
                'itemtype' => \Ticket::class, //  ,    
                'items_id' => $relatedTicketId, // id 
                'users_id' => $fields['_users_id_requester'], // id  
                'users_id_editor' => 0,
                'content' => $fields['content'],  
                'date' => date('c'),
                'date_mod' => date('c'),
                'date_creation' => date('c'),
                'is_private' => 0,
                'requesttypes_id' => $fields['requesttypes_id'], //  (helpdesk, email  ..)
                'timeline_position' => 4,
                'sourceitems_id' => 0,
                'sourceof_items_id' => 0
            ];

//           (    , ),        . ,        glpi_itilfollowups
            $DB->insert('glpi_itilfollowups', $relatedTicketParamsForUpdate);

//     ,    "".        glpi_tickets
            $DB->update('glpi_tickets', [
                'status' => 1
            ], [
                'id' => $relatedTicketId
            ]);

// ..     ,   input  false.       .
            $ticket->input = false;

            return $ticket->input;
        }
    }
}


Eso es todo. Gracias por su atención. Código fuente, como siempre en github .



Enlaces útiles:



Sitio web

oficial de GLPI Foros oficiales

Telegram Chat

Ejemplo de

documentación del complemento para

desarrolladores de APIDoc

Documentación sobre la creación de complementos

Artículo sobre la creación de complementos de GLPI



All Articles