# Criando Nova Tela

  • É possível criar uma tela totalmente do zero, adicionando componentes como um container, um card, um grid ou qualquer um que desejar.
  • Para facilitar, foram criados templates que encapsulam os componentes do Zeedhi. Podem ser encontrados aqui (opens new window).
  • Seu projeto já possui exemplos básicos de telas que utilizam os templates citados nessa seção. Utilize-os para sanar dúvidas sempre que necessário.
  • A documentação sobre o componente TekGrid, que está encapsulado no template utilizado nesse guia, pode ser encontrada aqui (opens new window).

Atenção!

  • Não altere a estrutura básica do seu projeto, o processo de build pode não funcionar corretamente. Além disso, durante o Deploy, serão feitas validações para garantir que os arquivos obrigatórios existam em seus devidos lugares.
  • Crie novas telas, controllers, serviços e afins nos devidos locais.

# Metadata


  • Todos seus arquivos de metadata das telas serão criados no diretório frontend/public/metadata.
  • É recomendável criar pastas para separação de metadatas de suas telas, como foi criada a example.
  • Nesse exemplo criaremos a pasta window e o arquivo da tela hello-world.json.
  • Adicione o código básico de uma tela de Grid:
{
	"name": "frame_page_hello_world",
	"component": "ZdFramePage",
	"path": "",
	"type": "post",
	"params": {
		"jsonPath": "templates/grid",
		"override": {
			"NAME": "grid_hello_world",
			"TITLE": "Hello World",
			"COLUMNS": []
		}
	}
}

Nota

É importante informar a propriedade name de forma coerente para cada componente. Posteriormente, será utilizada para obter a instância atual do componente para manuseio.


  • Em ambientes de desenvolvimento, é necessário criar um menu para acessar sua tela.
  • Abra o arquivo menu.json contido na raiz da sua aplicação.
  • Já existirá os menus Dashboard e Exemplos. Crie um novo ao final do arquivo com o código:
{
    "name": "hello-world",
    "component": "ZdMenuLink",
    "icon": "mdi-text-box",
    "label": "Hello World",
    "route": "/window/hello-world",
    "isVisible": true,
    "order": 30
}
  • A propriedade route deve apontar para o diretório da tela a partir da pasta metadata.
  • Todos os menus deverão possuir uma propriedade id, mas isso é gerado a partir de um comando. Em um terminal, entre no diretório do seu projeto, na pasta frontend e execute:
grunt zhIdGenerator

# Rota Frontend


  • É necessário configurar a rota de acesso à tela no arquivo frontend/src/router/routes.ts, na variável routes.
  • Adicione o código abaixo como as demais já existentes:
{
    path: '/window/hello-world',
    name: 'hello-world',
    component: ZdPage,
    props: () => ({
        path: 'window/hello-world',
        local: true,
    }),
}
  • A propriedade path deve apontar para o diretório da tela a partir da pasta metadata.
  • Após os passos acima, relogue na sua aplicação para que seu menu fique visível. Abra a tela e deverá aparecer um grid como na imagem abaixo.

hello-world-grid

# Colunas


  • Voltando no metadata da sua tela, adicione na propriedade COLUMNS algumas colunas para compor seu grid.
{
    "name": "ID",
    "label": "Código",
    "filterProps": {
        "component": "ZdTextInput",
        "grid": {
            "cols": 4
        }
    }
},
{
    "name": "NAME",
    "label": "Nome",
    "editable": true,
    "filterProps": {
        "component": "ZdTextInput",
        "grid": {
            "cols": 4
        }
    }
}

# Controller Frontend


  • Recomendamos que cada tela possua seu arquivo Controller.
  • Crie um novo no diretório frontend/src/controllers. Nesse exemplo, chamaremos de HelloWorldController.ts.
  • Adicione o código abaixo para já possuir o método Adicionar.
import { TextInput } from '@zeedhi/common';
import { IEventParam, Metadata } from '@zeedhi/core';
import { TekGrid } from '@zeedhi/teknisa-components-common';

export class HelloWorldController {
    public addGridRow({ component }: IEventParam<TekGrid>) {
        const newId = (component.datasource.total + 1).toString();
        component.addNewRow({ ID: newId }, 'start').then(() => {
            const nameInput = Metadata.getInstance<TextInput>(`NAME_editable_${newId}`);
            nameInput.setFocus();
        });
    }
}
  • No arquivo frontend/src/controllers/index.ts, registre seu novo controller para poder ser utilizado pelos componentes. Siga os exemplos já existentes e adicione o código abaixo.
(...)
import { HelloWorldController } from './HelloWorldController';

export default {
    (...)
    HelloWorldController,
}
  • Voltando ao seu metadata, dentro da propriedade override, adicione o evento EVENT_ADD_CLICK que fará com que o botão Adicionar execute o código do método addGridRow.
"EVENT_ADD_CLICK": "{{HelloWorldController.addGridRow}}",
  • Caso sua tela possuir regras de negócio que tratam os dados, é recomendável criar Serviços para uma melhor modularização. Nesse caso, crie uma pasta services dentro de frontend/src e crie seus arquivos.
  • O funcionamento/exemplos dos demais métodos CRUD podem ser consultados nos exemplos existentes no seu projeto.

# Rota Backend


  • No arquivo backend/config/routes.json crie uma nova rota para consultar os dados do seu Grid, como no exemplo abaixo:
{
    "uri": "/getHelloWorld",
    "controller": "helloWorldController",
    "controllerMethod": "getHelloWorld",
    "methods": ["GET"],
    "requestType": "Empty"
}

Nota

O método a ser executado não necessariamente deve possuir a mesma nomenclatura da rota, mas é uma boa prática que colabora com manutenções futuras.

  • É recomendável definir prioridades para modularizar sua aplicação. Seguimos o seguinte modelo:
    • Controller: Responsável por receber a requisição e retornar os dados no formato correto.
    • Service: Responsável por realizar as regras de negócio das rotinas.
    • Repository: Responsável por comunicar com o banco de dados (executando queries, por exemplo).

# Controller Backend


  • No diretório backend/src/Controllers crie um arquivo chamado HelloWorld.php para executar o início da sua rotina no backend.
<?php

namespace Controllers;

use Traits\TResponse;
use Zeedhi\Framework\DTO\Request;
use Zeedhi\Framework\DTO\Response;

class HelloWorld
{
    use TResponse;

    protected $helloWorldService;

    public function __construct(\Services\HelloWorld $helloWorldService) {
        $this->helloWorldService = $helloWorldService;
    }

    public function getHelloWorld(Request $request, Response $response) {
        try {
            $params = $request->getParameters();
            $data   = $this->helloWorldService->getHelloWorld();
            $this->sendResponse($data, 200);
        } catch(\Exception $ex) {
            $this->sendResponse(['error' => $ex->getMessage(), 'code' => $ex->getCode()], 500);
        }
    }
}

Nota

Seu projeto já possui a classe Traits\TResponse para enviar a resposta para o frontend no formato esperado.

  • Registre seu controller no arquivo backend/config/services.xml. Se baseie nos exemplos já criados.
<service id="helloWorldController" class="Controllers\HelloWorld">
    <argument type="service" id="helloWorldService"/>
</service>

Nota

  • O id definido nesse momento é o utilizado na propriedade controller de sua rota.
  • O argumento que foi recebido se trata da instância de um Serviço, que será definido logo abaixo. Seu controller o recebe como parâmetro do construtor.

# Service Backend


Crie um novo arquivo chamado HelloWorld.php dentro do diretório backend/src/Services.

<?php

namespace Services;

class HelloWorld {
    
    public function __construct(\Repositories\HelloWorld $helloWorldRepository) {
        $this->helloWorldRepository = $helloWorldRepository;
    }

    public function getHelloWorld() {
        $helloWorldData = $this->helloWorldRepository->findHelloWorld();
        return $helloWorldData;
    }
}
  • Registre seu serviço no arquivo backend/config/services.xml. Se baseie nos exemplos já criados.
<service id="helloWorldService" class="Services\HelloWorld">
    <argument type="service" id="helloWorldRepository"/>
</service>

Nota

  • O id definido nesse momento é o utilizado como argumento passado no registro do seu controller.
  • O argumento que foi recebido se trata da instância de um Repositório, que será definido logo abaixo. Seu serviço o recebe como parâmetro do construtor.

# Repository Backend


Crie um novo arquivo chamado HelloWorld.php dentro do diretório backend/src/Repositories.

<?php

namespace Repositories;

use Teknisa\Model\Traits\TQuery;
use Util\InstanceProvider;

class HelloWorld {

    Use TQuery;

    protected $entityManager;

    public function __construct()
    {
        $this->entityManager = InstanceProvider::getEntityManager();
    }

    public function findHelloWorld()
    {
        $query = <<<SQL
            SELECT 1 AS "ID", 'HELLO!' AS "NAME"
              FROM DUAL
             UNION
            SELECT 2 AS "ID", 'HI!' AS "NAME"
              FROM DUAL
SQL;
        $params = array();
        return $this->createAndExecuteQueryAndBuildResponseData($this->entityManager, $query, $params);
    }
}

Atenção!

Para que o framework consiga relacionar os dados da sua query com o grid, o nome das colunas retornadas deve ser igual à propriedade name das colunas do grid.

  • Registre seu repositório no arquivo backend/config/services.xml.
<service id="helloWorldRepository" class="Repositories\HelloWorld"/>

Nota

  • Criamos uma query com dados mockados para exemplificar.
  • Seu projeto já possui o arquivo Teknisa\Model\Traits\TQuery, vindo da dependência teknisa/entities, que possui a função createAndExecuteQueryAndBuildResponseData. Ela é responsável por executar a sua query, construir todos os filtros dinâmicos informados na tela e paginar os registros, caso necessário.
  • É possível informar filtros fixos na query a partir do array de parâmetros $params.

# DataSource


  • Voltando ao metadata no frontend, vamos definir o datasource da sua tela para utilizar a rotina que foi criada no backend. Adicione o código na propriedade override.
"DATASOURCE_UNIQUE_KEY": "ID",
"DATASOURCE_ROUTE": "getHelloWorld",
  • Caso tudo esteja correto, sua tela agora deverá aparecer os dados da sua query, como na imagem abaixo:

hello-world-data

Informação

Agora que já sabemos o fluxo completo, as demais operações CRUD de sua tela podem ser conferidas nos exemplos existentes. Não se preocupe em mantê-los em seu projeto, não ficarão visíveis no ambiente de produção.