Como chamar um behavior dentro do arquivo 'tables.php'

23 views
Skip to first unread message

Hermiro Carvalho

unread,
Oct 26, 2020, 12:59:22 PM10/26/20
to CakePHP Tuga
Boa tarde.

Eu procurei aqui no fórum, porém os posts que falam de behavior estão muito desatualizados.
O que eu preciso é o seguinte... ANTES de salvar um registro... eu preciso calcular o valor de um campo em função de outro... a minha idéia seria usar um behavior porém eu não entendi a documentação do cakephp...

É possível chamar um behavior dentro de uma função beforeMarshall? 
Algo assim por exemplo?

// Na classe da sua table ou behavior
public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options)
{

$SkillTaxaHora = null;
$Valor_taxa = null;


    if (!isset($data['valor'])) {
        
       //Behavior para recuperar o valor da SKILL
        $SkillTaxaHora = $this->BEHAVIOR->METODO_NO_BEHAVIOR($data['id_skill']);

        $data['valor'] = $SkillTaxaHora * $data['tempo];

    }

Cauan Cabral

unread,
Oct 26, 2020, 1:13:15 PM10/26/20
to CakePHP Tuga
Boa tarde,

Você precisa do Behavior exatamente por que?

A partir do CakePHP 3, com a divisão do ORM em Entities e Tables, boa parte dos casos de uso para behaviors passaram a ser atendidos por uma ou outra.
Como regra básica eu costumo fazer:

 - Se o campo que vai ser calculado não precisa de acesso a outra tabela/registro, defino um mutator/getter na minha entidade
 - Se precisa consultar outro registro, uso na table
 - Se precisa de acesso a outra tabela, daí eu parto para um behavior.

Quanto ao callback para uso, você está pensando em definir o beforeMarshal da tabela pra chamar um método do behavior? Porque você pode fazer isso de forma transparente definindo no Behavior
o método beforeMarshal, e nele você faz as rotinas necessárias.


--
--
CakePHP Tuga (cakephp-pt)
 
Utilize http://bin.cakephp.org para códigos
Cookbook: http://book.cakephp.org
 
Website do CakePHP: http://cakephp.org/
Website do grupo: http://groups.google.com/group/cakephp-pt?hl=pt-PT
---
Recebeu esta mensagem porque subscreveu ao grupo "CakePHP Tuga" do Grupos do Google.
Para anular a subscrição deste grupo e parar de receber emails do mesmo, envie um email para cakephp-pt+...@googlegroups.com.
Para ver este debate na Web, visite https://groups.google.com/d/msgid/cakephp-pt/30175d61-48c1-4747-9976-97ae4e8e5880n%40googlegroups.com.


--
Cauan Cabral
----------------
Onde me encontrar: https://cauancabral.net

Hermiro Carvalho

unread,
Oct 26, 2020, 1:27:13 PM10/26/20
to CakePHP Tuga
Cauan.

Se eu entendi o que voce disse seria o seguinte:
No código que eu postei, o valor da variável  $SkillTaxaHora depende de um outro campo de que está numa tabela diferente...
dependendo da opção que o usuário coloca no formulário esse valor pode mudar.
Eu pensei no Marshall porque eu já tenho ele pronto e eu pensei que chamando o behavior aqui eu conseguiria calcular esse valor como eu seu estivesse preenchendo manualmente este campo do formulário... porém a documentação não me ajuda muito... por isso eu coloquei esse código porque eu pensei que o jeito de usar um behavior fosse parecido com o jeito de usar um componente de controller por exemplo.
Outro ponto importante é que eu posso reutilizar esse código em outro ponto da minha aplicação...
Existe outra forma de fazer isso sem usar o behavior? 

Cauan Cabral

unread,
Oct 26, 2020, 2:00:23 PM10/26/20
to CakePHP Tuga
Entendi, nesse seu caso faz sentido o uso do behavior sim.

Na sua Table, você pode fazer algo assim:

public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options)
{
    $SkillTaxaHora = null;
    $Valor_taxa = null;

    if (!isset($data['valor'])) {
       
       //Behavior para recuperar o valor da SKILL
        $SkillTaxaHora = $this->getBehavior('NOME_DO_SEU_BEHAVIOR')->METODO_NO_BEHAVIOR($data['id_skill']);

Hermiro Carvalho

unread,
Oct 26, 2020, 3:09:54 PM10/26/20
to CakePHP Tuga
Erro.

Criei meu behavior utilizando o bake e ao tentar inserir dentro da minha table deu o seguinte erro:


Não entendi bem o porque, pois no início da minha table eu fiz:
    public function initialize(array $config): void
    {
     
        //Adiciona o behavior 'OnSaveBehavior' para tratamento de campos.
        $this->addBehavior('OnSave');
 }

Esse é o código da minha função dentro do Behavior:
public function ConfiguraTempoTotal ($id_skill = null, $horas = null){
        //Declaração de variáveis.
        $valor_skill = null;

        //Valida id da skill
        if (empty($id_skill)) {
            return false;
        }

        //Valida quantidade de horas
        if (empty($horas)) {
            return false;
        }

        /*
        ** Se todos os parâmetros forem informados tenta calcular o valor baseado
        ** na quantidade de horas pela skill.
        */
        $valor_skill = $this->Skill->find('all', ['conditions' => ['Skill.id' => $id_skill]]);
        debug($valor_skill);
        die("OnSave Behavior");
    }

O código do Marshal ficou assim:
public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options)
{
    $SkillTaxaHora = null;

    if (!isset($data['valor'])) {        

        $valor = $this->OnSave->ConfiguraTempoTotal($data['id_skill'], $data['tempo']);
        die("Hermiro Marshal");
        $SkillTaxa_hora = $data['tempo'] * $valor['valor'];

    }

Alguém sabe me explica porque ele não está aceitando? 

Hermiro Carvalho

unread,
Oct 26, 2020, 3:14:58 PM10/26/20
to CakePHP Tuga

Anexando um print do erro.
Erro_Behavior.jpg

Cauan Cabral

unread,
Oct 26, 2020, 3:25:19 PM10/26/20
to CakePHP Tuga
Você está chamando seu Behavior como se fosse uma Table relacionada, olha novamente como eu tinha sugerido o código para chamar o behavior:

$SkillTaxaHora = $this->getBehavior('NOME_DO_SEU_BEHAVIOR')->METODO_NO_BEHAVIOR($data['id_skill']);

Hermiro Carvalho

unread,
Oct 26, 2020, 3:52:47 PM10/26/20
to CakePHP Tuga
Boa Cauan... Funcionou...

Segue abaixo o código do meu behavior e do Marshall...

Marshall
public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options)
{

    $SkillTaxaHora = null;

    if (!isset($data['valor'])) {        

        $SkillTaxaHora = $this->getBehavior('OnSave')->ConfiguraTempoTotal($data['id_skill'], $data['tempo']);//Chama o behavior
        $data['valor'] = $data['tempo'] * $SkillTaxaHora['0']['valor'];//Calcula o custo pela relação SKILL e tempo gasto.
    }
}

Behavior (código completo)
<?php
declare(strict_types=1);

namespace App\Model\Behavior;

use Cake\ORM\Behavior;
use Cake\ORM\Table;
use Cake\ORM\TableRegistry;
/**
 * OnSave behavior
 * Autor: Hermiro Carvalho
 * Objetivo: Padronizar neste behavior, todas as operações de configurar campos ANTES do evento
 *           de salvar.
 */
class OnSaveBehavior extends Behavior
{
    /**
     * Default configuration.
     *
     * @var array
     */
    protected $_defaultConfig = [];
    /**
     * Função: Configura o valor do campo tempototal
     * Objetivo: Através do ID (ID do atendimento), soma os valores de todos os atendimentos e 
     *           retorna o valor.
     */
    public function ConfiguraTempoTotal ($id_skill = null, $horas = null){
        //Declaração de variáveis.
        $valor_skill = null;
        $this->table = TableRegistry::get('Skills');
        $this->table = TableRegistry::getTableLocator()->get('Skills');
        $data = null;
        //Valida id da skill
        if (empty($id_skill)) {
            return false;
        }

        //Valida quantidade de horas
        if (empty($horas)) {
            return false;
        }

        /*
        ** Se todos os parâmetros forem informados tenta calcular o valor baseado
        ** na quantidade de horas pela skill.
        */
        $valor_skill = $this->table->find('all', ['conditions' => ['Skills.id' => $id_skill], 'fields' => ['Skills.valor']]);
        if (!empty($valor_skill)) {
            $data = $valor_skill->toArray();
            return $data;
        }

    }
}

Reply all
Reply to author
Forward
0 new messages