Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Refatoração das fabricas de entidades

Fala mestre,

Antes de assistir essa última aula sobre fail fast eu havia refatorado a minha fábrica de especialidades e de médicos por que notei que podia abstrair algumas coisas com template method, não sei se faz muito sentido após ter visto essa ultima aula, mas está ai para quem tiver curiosidade e ache que faça sentido, muita coisa pode ser melhorada também.

Eu fiz basicamente três coisas:

1 - Criei uma abstract class FabricaDeEntidades para juntar coisas em comum em todas as fábricas. Essa fábrica de entidades recebe dois parâmetros para ser construído:

Primeiro parâmetro: Um objeto que implementa a interface DadosNormalizaveis(nome péssimo), que vai me garantir que os dados passados serão transformado em um array. Assim eu posso receber tanto um json, quanto qualquer outro tipo de dado vindo da web pq sei que será formatado para um array.

Segundo parâmetro: Um array que contém os nomes das propriedades que serão obrigatórios para construção da entidade.

2 - Criei uma interface chamada DadosNormalizaveis que contém o método normalize($dados): array. Esse método deve me garantir que os dados de alguma forma serão transformados em um array e assim posso padronizar a construção de diferentes entidades.

3 - Criei uma trait chamada Entidade Helper que pode possuir alguns métodos auxiliares para a minha fábrica de entidades.

abstract class FabricaDeEntidades
{    
    use EntidadeHelper;

    protected $tipoDeDado;
    protected $propriedades;

    public function __construct(DadosNormalizaveis $tipoDeDado, array $propriedades)
    {
        $this->tipoDeDado = $tipoDeDado;
        $this->propriedades = $propriedades;
    }

    public function tipoDeDado(DadosNormalizaveis $tipoDeDado):  void
    {
        $this->tipoDeDado = $tipoDeDado;
    }

    public function propriedades(array $propriedades):  void
    {
        $this->propriedades = $propriedades;
    }

    public function criarCom($dados)
    {    
        $dados = $this->tipoDeDado->normalize($dados);
        if($erro = $this->naoExistemPropriedades($dados, $this->propriedades)){

            $msg = sprintf("Faltam as propriedades: %s", implode(', ', $erro));
            throw new EntityFactoryException($msg);            
        }

        return $this->comoCriarEntidade($dados);
    }

    abstract function comoCriarEntidade(array $dados);
}
trait EntidadeHelper
{
    public function naoExistemPropriedades(array $dados, array $propriedades)
    {
        return array_filter($propriedades, fn($prop) => !isset($dados[$prop]));
    }
}

class JsonParaArray implements DadosNormalizaveis
{
    public function normalize($data): array
    {
        return (array) json_decode($data);
    }
}

Agora para criar qualquer classe do tipo FabricaDeEntidades preciso somente dizer como o objeto é setado/construido e quais propriedades eu desejo receber nos dados:


class FabricaDeEspecialidades extends FabricaDeEntidades
{
    public function __construct(DadosNormalizaveis $tipoDeDado)
    {
        $propriedades = ['descricao'];
        parent::__construct($tipoDeDado, $propriedades);
    }

    public function comoCriarEntidade(array $dados): Especialidade
    {
        $especialidade = new Especialidade();
        $especialidade->setDescricao($dados['descricao']);

        return $especialidade;
    }
}
2 respostas
solução!

Cara, sensacional! Eu tô no celular então fica um pouco ruim de acompanhar o código, mas parece estar sensacional. Coloca esse projeto no GitHub, man.

Dica rápida: a função json_encode tem um segundo parâmetro pra retornar um array, aí vc não precisa desse cast. :-D

Valeu mestre <3

Realmente comi grama com o json_decode, esqueci que podia passar esse parametro extra hahaha. Acho que o ponto forte da implementação foi abstrair o formato de dado recebido, assim posso reaproveitar em projeto que não seja com json, basta implementar uma classe com a interface DadosNormalizaveis.