[comment]: # ({ed2f6c13-ed2f6c13})
# 20. Módulos

[comment]: # ({/ed2f6c13-ed2f6c13})

[comment]: # ({8c4f6bda-1060eddf})
#### Visão geral

É possível aprimorar a funcionalidade do frontend do Zabbix adicionando módulos de terceiros ou desenvolvendo seus próprios módulos, sem a necessidade de alterar o código-fonte do Zabbix.

Observe que o código do módulo será executado com os mesmos privilégios do código-fonte do Zabbix. Isso significa que:

-   módulos de terceiros podem ser prejudiciais. Você deve confiar nos módulos que está instalando;
-  Erros no código de um módulo de terceiros podem travar o frontend. Se isso acontecer, basta remover o código do módulo do frontend. Assim que você recarregar o frontend do Zabbix, verá uma mensagem informando que alguns módulos estão ausentes. Vá para [Module administration](/manual/web_interface/frontend_sections/administration/general#modules) (em *Administração* → *Geral* → *Módulos*) e clique em *Scan
 directory* novamente para remover módulos inexistentes do banco de dados.

[comment]: # ({/8c4f6bda-1060eddf})

[comment]: # ({485a0a1e-cffdc09c})

#### Instalação 

Leia sempre o manual de instalação de um módulo específico. Recomenda-se instalar novos módulos um por vez para identificar falhas facilmente.

Antes de instalar um módulo:

-   Certifique-se de que baixou o módulo de uma fonte confiável. A instalação de código prejudicial pode levar a consequências, como perda de dados.
-   Diferentes versões do mesmo módulo (com o mesmo ID) podem ser instaladas em paralelo, mas apenas uma versão pode ser ativada por vez.

Passos para instalar um módulo:

-   Descompacte o módulo dentro de sua própria pasta na pasta  `modules` do frontend do Zabbix
-   Certifique-se de que a pasta do módulo contenha pelo menos o arquivo manifest.json
-   Navegue até  [Module
    administration](/manual/web_interface/frontend_sections/administration/general#modules)
    e clique no botão *Scan directory*
-   O novo módulo aparecerá na lista, juntamente com sua versão, autor, descrição e status
-   Ative o módulo clicando em seu status

Troubleshooting:

|Problema|Solução|
|---------|----------------------------------------|
|*O módulo não apareceu na lista*|Certifique-se de que o arquivo manifest.json exista na pasta `modules/your-module/` do frontend do Zabbix. Se existir, significa que o módulo não é compatível com a versão atual do Zabbix. Se o arquivo manifest.json não existir, você provavelmente descompactou na pasta errada.|
|*O frontend travou*|O código do módulo não é compatível com a versão atual do Zabbix ou a configuração do servidor. Exclua os arquivos do módulo e recarregue o frontend. Você verá um aviso de que alguns módulos estão ausentes. Vá para [Module administration](/manual/web_interface/frontend_sections/administration/general#modules) e clique em *Scan directory* novamente para remover módulos inexistentes do banco de dados.|
|*Mensagem de erro sobre namespace, ID ou ações idênticas aparece*|O novo módulo tentou registrar um namespace, ID ou ações que já estão registrados por outros módulos ativados. Desative o módulo conflitante (mencionado na mensagem de erro) antes de ativar o novo.|
|*Mensagens de erro técnico aparecem*|Relate os erros ao desenvolvedor do módulo.|

[comment]: # ({/485a0a1e-cffdc09c})

[comment]: # ({26c922c0-26c922c0})
#### Desenvolvendo módulos

Os módulos são escritos em linguagem PHP. Controlador de visualização de modelo (MVC)
design de padrão de software é o preferido, pois também é usado no Zabbix
frontend e facilitará o desenvolvimento. A tipagem estrita do PHP também é
bem-vindo, mas não obrigatório.

Observe que com os módulos você pode adicionar facilmente novos itens de menu e
respectivas visualizações e ações para o frontend do Zabbix. Atualmente não é
possível registrar uma nova API ou criar novas tabelas de banco de dados através
módulos.

[comment]: # ({/26c922c0-26c922c0})

[comment]: # ({9c14363a-9c14363a})
##### Estrutura do módulo

Cada módulo é um diretório (colocado dentro do diretório `modules`) com
subdiretórios contendo controllers, views e qualquer outro código:

    example_module_directory/ (obrigatório)
        manifest.json (obrigatório) Metadados e definição de ação.
        Module.php Inicialização do módulo e manipulação de eventos.
        actions/Arquivos do controlador de ação.
            AlgoView.php
            AlgoCreate.php
            AlgoDelete.php
            data_export/
                ExportAsXml.php
                ExportAsExcel.php
        visualizações/Visualizar arquivos.
            exemplo.algo.view.php
            exemplo.algo.excluir.php
            js/ arquivos JavaScript usados ​​em views.
                exemplo.algo.view.js.php
        parciais/ Visualizar arquivos parciais.
            exemplo.algo.reutilizável.php
            js/ arquivos JavaScript usados ​​em parciais.
                exemplo.algo.reutilizável.js.php

Como você pode ver, o único arquivo obrigatório dentro do módulo personalizado
diretório é `manifest.json`. O módulo não será registrado sem isso
Arquivo. `Module.php` é responsável por registrar itens de menu e
processamento de eventos como 'onBeforeAction' e 'onTerminate'. O
Os diretórios *actions*, *views* e *partials* contêm PHP e JavaScript
código necessário para ações do módulo.

[comment]: # ({/9c14363a-9c14363a})

[comment]: # ({92e4fa47-92e4fa47})
##### Convenção de nomes

Antes de criar um módulo, é importante concordar com a nomenclatura
convenção para diferentes itens de módulo, como diretórios e arquivos,
que poderíamos manter as coisas bem organizadas. Você também pode encontrar exemplos
acima, na seção [Estrutura do módulo](#module_structure).

|Item|Regras de nomenclatura|Exemplo|
|----|------------|-------|
|*Diretório do módulo*|minúsculas \[a-z\], sublinhado e dígitos decimais|exemplo\_v2|
|*Subdiretórios de ação*|minúsculas \[a-z\] e caractere de sublinhado|dados\_export|
|*Arquivos de ação*|CamelCase, terminando com tipo de ação|SomethingView.php|
|*Visualização e arquivos parciais*|minúsculas \[az\]<br>Palavras separadas por ponto<br>Prefixado por `module.` seguido pelo nome do módulo<br>Terminando com tipo de ação e extensão de arquivo .php|module.example .algo.view.php|
|*Arquivos Javascript*|As mesmas regras se aplicam aos arquivos de visualização e parciais, exceto a extensão de arquivo .js.php.|module.example.something.view.js.php|

Observe que o prefixo 'módulo' e a inclusão do nome são obrigatórios para visualização
e nomes de arquivos parciais, a menos que você precise substituir as visualizações principais do Zabbix ou
parciais. Essa regra, no entanto, não se aplica a nomes de arquivos de ação.

[comment]: # ({/92e4fa47-92e4fa47})

[comment]: # ({9fafd42a-6b0430a7})

##### Preparação do manifesto

Cada módulo deve ter um arquivo manifest.jsoncom os seguintes campos no formato JSON:

|Parâmetro|Obrigatório|Tipo|Padrão|Descrição|
|---------|---|----|--|-------------------|
|manifest\_version|Sim|Double|\-|Versão do manifesto do módulo. A versão atualmente suportada é **1**.|
|id|Sim|String|\-|ID do módulo. Apenas um módulo com o ID fornecido pode ser ativado ao mesmo tempo.|
|name|Sim|String|\-|Nome do módulo conforme exibido na seção Administração.|
|version|Sim|String|\-|Versão do módulo conforme exibido na seção Administração.|
|namespace|Sim|String|\-|Namespace PHP para Module.php e classes de ação.|
|author|Não|String|""|Autor do módulo conforme exibido na seção Administração.|
|url|Não|String|""|URL do módulo conforme exibido na seção Administração.|
|description|Não|String|""|Descrição do módulo conforme exibido na seção Administração.|
|actions|Não|Objeto|{}|Ações a serem registradas com este módulo. Veja Ações.|
|config|Não|Objeto|{}|Configuração do módulo.|

Para referência, consulte um exemplo de manifest.json na seção 
[Reference](#reference).

[comment]: # ({/9fafd42a-6b0430a7})

[comment]: # ({59094baf-435502d9})

##### Ações

O módulo terá controle sobre as ações de frontend definidas no objeto
*actions* no arquivo manifest.json. Dessa forma, novas ações podem ser definidas. Da mesma maneira, você pode redefinir ações existentes. Cada chave de actions  deve representar o nome da ação, e o valor correspondente deve conter as chaves `class` e, opcionalmente, `layout` e `view`.

Uma ação é definida por quatro componentes: nome, controlador, visualização (_view_) e layout. A validação e preparação dos dados normalmente são feitas no controlador, o formato da saída é feito na visualização ou parciais (_partials_), e o layout é responsável por decorar a página com elementos como menu, cabeçalho, rodapé e outros.

As ações do módulo devem ser definidas no arquivo manifest.json como um objeto *actions*:

|Parâmetro|Obrigatório|Tipo|Padrão|Descrição|
|---------|---|----|--|-------------------|
|key|Sim|String|\-|Nome da ação, em letras minúsculas \[a-z\], separando palavras com ponto.|
|class|Sim|String|\-|Nome da classe da ação, incluindo o caminho do subdiretório (se usado) dentro do diretório `actions`.|
|layout|Não|String|"layout.htmlpage"|Layout da ação.|
|view|Não|String|null|Visualização da ação.|

Existem vários layouts predefinidos, como `layout.json` ou `layout.xml`. Estes são destinados para ações que produzem um resultado diferente de HTML. Você pode explorar os layouts predefinidos no diretório app/views/ ou até criar os seus próprios.

Às vezes, é necessário redefinir apenas a parte da visualização de alguma ação, mantendo o controlador intacto. Nesse caso, basta colocar os arquivos de visualização e/ou parciais necessários dentro do diretório `views` do módulo. 

Para referência, veja um exemplo de arquivo de controlador de ação na seção 
[Reference](#reference). Não hesite em explorar as ações atuais do código-fonte do Zabbix, localizado no diretório app/.

**Module.php**

Esse arquivo PHP opcional é responsável pela inicialização do módulo, bem como pelo tratamento de eventos. A classe 'Module' deve ser definida nesse arquivo, estendendo a classe base `\Core\CModule`. A classe Module deve ser definida dentro do namespace especificado no arquivo manifest.json.

``` {.php}
<?php

namespace Modules\Example;
use Core\CModule as BaseModule;

class Module extends BaseModule {
    ...
}
```

Para referência, veja um exemplo de Module.php na seção
[Reference](#reference).

[comment]: # ({/59094baf-435502d9})

[comment]: # ({2f2e3b5c-9a1772e3})
#### Referência

Esta seção contém versões básicas de diferentes elementos do módulo
introduzido nas seções anteriores.

**manifest.json**

``` {.java}
{
    "manifest_version": 1.0,
    "id": "example_module",
    "name": "Example module",
    "version": "1.0",
    "namespace": "Example",
    "author": "John Smith",
    "url": "http://module.example.com",
    "description": "Short description of the module.",
    "actions": {
        "example.something.view": {
            "class": "SomethingView",
            "view": "module.example.something.view"
        },
        "example.something.create": {
            "class": "SomethingCreate",
            "layout": null
        },
        "example.something.delete": {
            "class": "SomethingDelete",
            "layout": null
        },
        "example.something.export.xml": {
            "class": "data_export/ExportAsXml",
            "layout": null
        },
        "example.something.export.excel": {
            "class": "data_export/ExportAsExcel",
            "layout": null
        }
    },
    "config": {
        "username": "john_smith"
    }
}
```

**Módulo.php**

``` {.php}
<?php declare(strict_types = 1);

namespace Modules\Example;

use APP;
use CController as CAction;

/**
 * Please see Core\CModule class for additional reference.
 */
class Module extends \Core\CModule {

    /**
     * Initialize module.
     */
    public function init(): void {
        // Initialize main menu (CMenu class instance).
        APP::Component()->get('menu.main')
            ->findOrAdd(_('Reports'))
                ->getSubmenu()
                    ->add((new \CMenuItem(_('Example wide report')))
                        ->setAction('example.report.wide.php')
                    )
                    ->add((new \CMenuItem(_('Example narrow report')))
                        ->setAction('example.report.narrow.php')
                    );
    }

    /**
     * Event handler, triggered before executing the action.
     *
     * @param CAction $action  Action instance responsible for current request.
     */
    public function onBeforeAction(CAction $action): void {
    }

    /**
     * Event handler, triggered on application exit.
     *
     * @param CAction $action  Action instance responsible for current request.
     */
    public function onTerminate(CAction $action): void {
    }
}
```

**Controlador de ação**

``` {.php}
<?php declare(strict_types = 1);

namespace Modules\Example\Actions;

use CControllerResponseData;
use CControllerResponseFatal;
use CController as CAction;

/**
 * Example module action.
 */
class SomethingView extends CAction {

    /**
     * Initialize action. Method called by Zabbix core.
     *
     * @return void
     */
    public function init(): void {
        /**
         * Disable SID (Session ID) validation. Session ID validation should only be used for actions which involve data
         * modification, such as update or delete actions. In such case Session ID must be presented in the URL, so that
         * the URL would expire as soon as the session expired.
         */
        $this->disableSIDvalidation();
    }

    /**
     * Check and sanitize user input parameters. Method called by Zabbix core. Execution stops if false is returned.
     *
     * @return bool true on success, false on error.
     */
    protected function checkInput(): bool {
        $fields = [
            'name'  => 'required|string',
            'email' => 'required|string',
            'phone' => 'string'
        ];

        // Only validated data will further be available using $this->hasInput() and $this->getInput().
        $ret = $this->validateInput($fields);

        if (!$ret) {
            $this->setResponse(new CControllerResponseFatal());
        }

        return $ret;
    }

    /**
     * Check if the user has permission to execute this action. Method called by Zabbix core.
     * Execution stops if false is returned.
     *
     * @return bool
     */
    protected function checkPermissions(): bool {
        $permit_user_types = [USER_TYPE_ZABBIX_ADMIN, USER_TYPE_SUPER_ADMIN];

        return in_array($this->getUserType(), $permit_user_types);
    }

    /**
     * Prepare the response object for the view. Method called by Zabbix core.
     *
     * @return void
     */
    protected function doAction(): void {
        $contacts = $this->getInput('email');

        if ($this->hasInput('phone')) {
            $contacts .= ', '.$this->getInput('phone');
        }

        $data = [
            'name' => $this->getInput('name'),
            'contacts' => $contacts
        ];

        $response = new CControllerResponseData($data);

        $this->setResponse($response);
    }
}
```

**Visualização de ação**

``` {.php}
<?php declare(strict_types = 1);

/**
 * @var CView $this
 */

$this->includeJsFile('example.something.view.js.php');

(new CWidget())
    ->setTitle(_('Something view'))
    ->addItem(new CDiv($data['name']))
    ->addItem(new CPartial('module.example.something.reusable', [
        'contacts' => $data['contacts']
    ])
    ->show();
```

[comment]: # ({/2f2e3b5c-9a1772e3})
