Ir para o conteúdo

PluginCreateRowOnEmptyTablePlugin

Resumo

Cria uma nova linha e a salva no objeto de dados se o evento Filter não retornar nenhuma linha.

Registro

O CreateRowOnEmptyTablePlugin é um plugin de ação para um evento de nível de tabela. Ele deve ser registrado para ser executado após o evento Filter. Como o plugin altera o comportamento do evento Filter intrínseco, ele deve ser registrado em um objeto de dados, não em uma tabela física.

Parâmetros

Nenhum

Observações

O CreateRowOnEmptyTablePlugin determina se o evento Filter retornou alguma linha. Se o evento Filter retornou uma ou mais linhas, o plugin sai sem processamento adicional. Caso contrário, o plugin cria uma nova linha e a persiste no objeto de dados.

O plugin cria uma linha invocando o evento New. O evento New é responsável por aplicar critérios de vinculação, bem como invocar as regras padrão do objeto de dados. No contexto de uma solicitação de página da web, os critérios de vinculação são derivados de parâmetros de string de consultar de URL. Em outras palavras, a nova linha será preenchida com quaisquer valores de parâmetro de string de consultar com nomes que correspondam aos nomes de coluna do objeto de dados.

Após invocar o evento New, o plugin invoca o evento Insert do objeto de dados, persistindo a linha na tabela de destino. Os desenvolvedores podem registrar ações no evento Insert para executar processamento adicional. Isso é importante porque o evento Filter é um evento de nível de tabela e, portanto, não oferece suporte a ações de nível de linha, como regras CRUD. Em contraste, o evento Insert é um evento de nível de linha. Eventos de nível de linha oferecem suporte à maioria das ações, incluindo regras CRUD.

Se o evento Insert não for bem-sucedido porque uma ou mais regras de validação falharam, o plugin sai sem processamento adicional. Caso contrário, o plugin verifica o escopo de alteração do evento Insert para determinar se a linha deve ser atualizada. Se o escopo de alteração for definido como um valor diferente de "None", o plugin atualiza a linha. A operação de atualização invoca o evento Filter na nova linha.

Nota

Os desenvolvedores devem considerar definir o escopo de alteração do evento Insert para disparar uma atualização se o objeto de dados contiver colunas computadas ou selecionar de várias tabelas. Esses valores são resolvidos apenas pelo evento Filter.

Finalmente, o plugin sai, retornando a linha recém-criada. Como tudo isso acontece dentro do contexto do evento Filter, o cliente web não sabe. No que diz respeito ao cliente web, a linha sempre existiu.

Uso

Imagine que um desenvolvedor queira criar um link que adicione automaticamente um produto ao carrinho de compras do usuário. O link pode ser parecido com este:

https://example.com/App Builder/app/Shop/AddToCart?ProductId=1234

Neste exemplo, o link abre a página AddToCart, passando ProductId como critério de vinculação.

Suponha que a fonte de dados contenha uma tabela Cart que se pareça com isto:

  • CartId - Identificador único, chave primária, gerado automaticamente.
  • ProductId - Inteiro, chave estrangeira para a tabela Product.
  • Quantidade - Inteiro.
  • SessionId - Identificador único, identifica a sessão do usuário.

O desenvolvedor começa criando um objeto de dados AddToCart que tem como alvo a tabela Cart. O objeto de dados AddToCart seleciona todas as colunas da tabela Cart. Embora não seja tecnicamente necessário, o desenvolvedor sinaliza o ProductId como uma coluna de ligação. Isso garante que o ProductId esteja presente antes de executar o evento. O objeto de dados AddToCart é restrito de modo que os usuários só podem visualizar itens do carrinho pertencentes à sua sessão atual. A instrução mvSQL resultante pode ser parecida com esta:

SELECT 
    C.CartId AS CartId,
    C.ProductId AS ProductId,
    C.Quantity AS Quantity,
    C.SessionId AS SessionId
FROM Cart AS C 
WHERE C.SessionId = session()

Observe que o CartId não precisa ser explicitamente padronizado, pois ele é gerado automaticamente. O ProductId não é padronizado porque ele será originado de critérios de vinculação.

Além do objeto de dados AddToCart, o desenvolvedor cria um objeto de dados chamado MyCart. Assim como o objeto de dados AddToCart, o objeto de dados MyCart tem como alvo e seleciona todas as colunas da tabela Cart. O objeto de dados MyCart também é restrito à sessão atual. No entanto, o objeto de dados MyCart não tem um evento Filter explícito. Ele não utiliza o plugin CreateRowOnEmptyTablePlugin.

O desenvolvedor então cria uma página chamada AddToCart, registrando o objeto de dados AddToCart como o objeto de dados da página. O desenvolvedor então adiciona um painel multi-linhas à página AddToCart. O painel multi-linhas seleciona do objeto de dados MyCart. Além disso, o painel multi-linhas é vinculado ao objeto de dados da página.

Nota

Vincular um painel à página garante que o painel não seja renderizado até que o evento Filter do objeto de dados da página seja executado.

O painel de várias linhas contém dois controles:

  • Product - List, vinculado à coluna ProductId. Seleciona da tabela Product usando ProductId como chave, ProductName como título.
  • Quantity - Numérico, vinculado à coluna Quantity.

Visualizar a página sem fornecer nenhum critério de vinculação resultará em erro.

Nota

No momento da escrita, exceções lançadas durante a execução do evento Filter do objeto de página não são exibidas na tela. No entanto, elas aparecerão no log.

Se a sequência de consultar contiver um parâmetro chamado ProductId com um valor válido, App Builder executará o evento Filter do objeto de dados AddToCart, que por sua vez executa o plugin CreateRowOnEmptyTablePlugin. O plugin criará uma nova linha, inserindo-a na tabela Cart. Após o evento Filter do objeto de dados AddToCart ser executado, App Builder executará o evento Filter do objeto de dados MyCart. Isso retornará a linha recém-criada, exibindo-a no painel multi-linhas.

O desenvolvedor pode executar ações adicionais quando a nova linha é inserida na tabela Cart. Por exemplo, o desenvolvedor pode registrar uma regra CRAM que insere uma linha na tabela Session se ela não existir. A instrução mvSQL pode ter esta aparência:

INSERT INTO Session
(
    SessionId,
    DateCreated
)
SELECT
    SessionId,
    DateCreated
FROM
(
    SELECT
    session() AS SessionId,
    now() AS DateCreated
) AS SOURCE
WHERE NOT EXISTS
(
    SELECT 1
    FROM Session
    WHERE
        Session.SessionId = SOURCE.SessionId
        AND Session.DateCreated = SOURCE.DateCreated
)

Isso permitiria ao desenvolvedor agendar um evento que exclui carrinhos pertencentes a sessões expiradas.

Erros

Loops Infinitos

Como o CreateRowOnEmptyTablePlugin invoca o evento Filter recursivamente, há uma chance de um loop infinito. Isso ocorreria se o desenvolvedor projetasse o objeto de dados de forma que ele não retornasse a linha recém-criada. Por exemplo:

SELECT *
FROM Table
WHERE 1 = 0 

App Builder protege contra essa situação. Se o evento Filter não encontrar a nova linha ao executar uma atualização, a seguinte exceção será lançada:

Loop infinito detectado ao criar uma linha em uma tabela vazia.

Segurança

Quando um navegador segue um link, ele faz uma solicitação HTTP GET. Como regra, uma solicitação HTTP GET deve ser segura e idempotente. Uma solicitação HTTP é segura se não tiver efeitos colaterais. Uma solicitação HTTP é idempotente se fazer a mesma solicitação uma segunda vez retornar o mesmo resultado.

O plugin CreateRowOnEmptyTablePlugin é idempotente: atualizar a janela do navegador não criará uma segunda linha. No entanto, o plugin CreateRowOnEmptyTablePlugin não é seguro: o plugin cria uma linha persistente no banco de dados. Isso é, por definição, um efeito colateral.

Os desenvolvedores devem ter isso em mente, pois uma solicitação GET insegura pode ser explorada em um ataque de falsificação de solicitação entre sites. Por esse motivo, os desenvolvedores devem evitar qualquer operação potencialmente destrutiva, como registrar uma regra de exclusão que é executada quando a página carrega. Os desenvolvedores também devem evitar registrar qualquer regra ou plug-in que interaja com sistemas externos, como enviar um email ou fazer um pagamento.