# Criando Nova Tela
- É possível criar uma tela totalmente do zero, adicionando componentes como um
container
, umcard
, umgrid
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 telahello-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.
# Menu
- 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 pastametadata
. - 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 pastafrontend
e execute:
grunt zhIdGenerator
# Rota Frontend
- É necessário configurar a rota de acesso à tela no arquivo
frontend/src/router/routes.ts
, na variávelroutes
. - 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 pastametadata
. - 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.
# 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 deHelloWorldController.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 eventoEVENT_ADD_CLICK
que fará com que o botão Adicionar execute o código do métodoaddGridRow
.
"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 defrontend/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 chamadoHelloWorld.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 propriedadecontroller
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ênciateknisa/entities
, que possui a funçãocreateAndExecuteQueryAndBuildResponseData
. 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 propriedadeoverride
.
"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:
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.