Lançado Adianti Framework 7.6!
Clique aqui para saber mais
Duvidas em Mapeamento objeto relacional classe Pessoa Olá amigos, boa noite! Estou caminhando na orientação a objetos e tenho uma dúvida com relação ao mapeamento de alguns dados para o modelo relacional. A minha principal dúvida no momento é sobre a classe pessoa que por herança servirá de base para outras classes como a cliente que também servirá de base para a cliente pessoa física e jurídica, nesse caso, terei campos como o CPF e...
GO
Duvidas em Mapeamento objeto relacional classe Pessoa  
Fechado
Olá amigos, boa noite!

Estou caminhando na orientação a objetos e tenho uma dúvida com relação ao mapeamento de alguns dados para o modelo relacional. A minha principal dúvida no momento é sobre a classe pessoa que por herança servirá de base para outras classes como a cliente que também servirá de base para a cliente pessoa física e jurídica, nesse caso, terei campos como o CPF e o CNPJ o RG e a IE, enfim, creio que essa situação não seja nova para a maioria dos amigos. Minha dúvida é com relação a melhor forma de mapear esses campos, hoje em meus sistemas eu crio um artifício de tela e armazeno a CPF e o CNPJ no mesmo campo na tabela no banco de dados, isso me facilita para a confecção dos relatórios e das pesquisas, mas tenho dúvidas se essa é a melhor forma de proceder.

Uma outra questão seria sobre um problema comum que me ocorre no sistema atual e que me acaba gerando uma redundância de dados. Um funcionário deseja realizar uma compra na loja e então preciso cadastra-lo na base de clientes, um caso semelhante seria o de um cliente de software passar a fornecer algum material para a empresa e então precisamos fazer um cadastro do mesmo na base de fornecedores.
Seria possível resolver esse caso com uma agregação entre a classe pessoa e uma classe de atribuições?

Exemplo:
Uma pessoa pode ser ao mesmo tempo cliente, fornecedor e funcionário?

Me desculpe pelo pouco conhecimento e já agradeço a quem possa me dar um retorno sobre como proceder da melhor forma.

Abraço e ótima noite!

Pacotão Dominando o Adianti Framework 7
O material mais completo de treinamento do Framework.
Curso em vídeo aulas + Livro completo + Códigos fontes do projeto ERPHouse.
Conteúdo Atualizado! Versão 7.4


Dominando o Adianti 7 Quero me inscrever agora!

Comentários (7)


PD

bem Geovani Oliveira eu uso uma class para dada um desses itens, mas nada impessa que trabalhe com nivel usando associação, ficaria mais organizado e iria suprir sua nescessidade
PD

Oi Geovani,

Eu particularmente prefiro criar um campo genérico (Ex: documento) e validar na aplicação. Além disso, também prefiro usar uma classe Pessoa, sendo que pessoa pode ser sim ora cliente, e ora fornecedor. Não vale a pena quebrar em coisas separadas, pois gera redundância. Prefiro criar uma outra tabela chamada Grupo , onde lá você cadastra os grupos (cliente, fornecedor, funcionário, etc), e faz uma agregação de Pessoa com Grupo (algo como um checkgroup). Assim, Pessoas marcadas como cliente poderão participar de vendas, e marcadas como fornecedor de compras, e de ambos caso estejam marcados como cliente e fornecedor. Deixe a aplicação validar ;-)

Espero ter ajudado.

Att,
Pablo
GO

Olá Pablo, bom dia!

E no caso da pessoa jurídica ou física, também cria somente uma classe e deixa a aplicação controlar?

Exemplo 1 : Pessoa -> Cliente->ClientePF
Pessoa -> Cliente->ClientePJ
Pessoa -> Funcionario
Pessoa -> Fornecedor

Exemplo 2 : Pessoa->PessoaF + (agregação com grupo de pessoas)
Pessoa->PessoaJ + (agregação com grupo de pessoas)

Exemplo 3: Pessoa + (agregação com grupo de pessoas)

Qual seria a situação que você trabalha Pablo?

Abraços!








GF

Seguinte... não existe uma maneira certa de fazer. Existe sim, estratégias de fazer o mapeamento relacional.

Eu recomendo ler a documentação de frameworks como:

- Hibernate caso conheça java;
- NHibernate caso conheça o C#;
- Caso queira permanecer no PHP dê uma olhada no doctrine e no propel.

Conhecendo as técnicas de mapeamento, você vai esbarrar em técnicas que permitem utilizar uma única tabela para classes filhas e neste caso geralmente utiliza-se um campo identificador, ou você pode adicionar cada classe em uma tabela diferente. Abaixo, vou demostrar como utilizar as duas formas utilizando o Adianti Framework:
GF

Técnica que utiliza uma única tabela:

  1. <?php
  2. /**
  3.  * Pessoa Active Record
  4.  * @author  Guilherme Faht (GURUX)
  5.  */
  6. abstract class Pessoa extends TRecord
  7. {
  8.     const TABLENAME 'pessoa';
  9.     const PRIMARYKEY'id';
  10.     const IDPOLICY =  'serial'// {max, serial}
  11.     
  12.     /**
  13.      * Constructor method
  14.      */
  15.     public function __construct($id NULL$callObjectLoad TRUE)
  16.     {
  17.         parent::__construct($id$callObjectLoad);
  18.         parent::addAttribute('nome');
  19.     }
  20. }
  21. ?>


  1. <?php
  2. /**
  3.  * PessoaFisica Active Record
  4.  * @author  Guilherme Faht (GURUX)
  5.  */
  6. class PessoaFisica extends Pessoa
  7. {        
  8.     /**
  9.      * Constructor method
  10.      */
  11.     public function __construct($id NULL$callObjectLoad TRUE)
  12.     {
  13.         parent::__construct($id$callObjectLoad);
  14.         parent::addAttribute('cpf');
  15.         parent::addAttribute('dtNascimento');
  16.     }
  17. }
  18. ?>


  1. <?php
  2. /**
  3.  * PessoaJuridica Active Record
  4.  * @author  Guilherme Faht (GURUX)
  5.  */
  6. class PessoaJuridica extends Pessoa
  7. {        
  8.     /**
  9.      * Constructor method
  10.      */
  11.     public function __construct($id NULL$callObjectLoad TRUE)
  12.     {
  13.         parent::__construct($id$callObjectLoad);
  14.         parent::addAttribute('cnpj');
  15.     }
  16. }
  17. ?>


Caso você opte por essa técnica e manipule coleções através do TRepository, a diferenciação dos objetos terá que ser feita no TCriteria. Por exemplo, se for buscar objetos to tipo Pessoa Juridica você terá que retornar todos os objetos cujo cnpj é diferente de nulo.
GF

Técnica que utiliza uma tabela para cada classe (padrão Adianti):

  1. <?php
  2. /**
  3.  * Pessoa Active Record
  4.  * @author  Guilherme Faht (GURUX)
  5.  */
  6. class Pessoa extends TRecord
  7. {
  8.     const TABLENAME 'pessoa';
  9.     const PRIMARYKEY'id';
  10.     const IDPOLICY =  'serial'// {max, serial}
  11.     
  12.     
  13.     /**
  14.      * Constructor method
  15.      */
  16.     public function __construct($id NULL$callObjectLoad TRUE)
  17.     {
  18.         parent::__construct($id$callObjectLoad);
  19.         parent::addAttribute('nome');
  20.     }
  21.     
  22.     /**
  23.      * Method getPessoaFisicas
  24.      */
  25.     public function getPessoaFisicas()
  26.     {
  27.         $criteria = new TCriteria;
  28.         $criteria->add(new TFilter('pessoa_id''='$this->id));
  29.         return PessoaFisica::getObjects$criteria );
  30.     }
  31.     
  32.     
  33.     /**
  34.      * Method getPessoaJuridicas
  35.      */
  36.     public function getPessoaJuridicas()
  37.     {
  38.         $criteria = new TCriteria;
  39.         $criteria->add(new TFilter('pessoa_id''='$this->id));
  40.         return PessoaJuridica::getObjects$criteria );
  41.     }
  42.     
  43. }
  44. ?>


  1. <?php
  2. /**
  3.  * PessoaFisica Active Record
  4.  * @author  Guilherme Faht (GURUX)
  5.  */
  6. class PessoaFisica extends TRecord
  7. {
  8.     const TABLENAME 'pessoa_fisica';
  9.     const PRIMARYKEY'id';
  10.     const IDPOLICY =  'serial'// {max, serial}
  11.     
  12.     
  13.     private $pessoa;
  14.     /**
  15.      * Constructor method
  16.      */
  17.     public function __construct($id NULL$callObjectLoad TRUE)
  18.     {
  19.         parent::__construct($id$callObjectLoad);
  20.         parent::addAttribute('cpf');
  21.         parent::addAttribute('dtNascimento');
  22.         parent::addAttribute('pessoa_id');
  23.     }
  24.     
  25.     /**
  26.      * Method set_pessoa
  27.      * Sample of usage: $pessoa_fisica->pessoa = $object;
  28.      * @param $object Instance of Pessoa
  29.      */
  30.     public function set_pessoa(Pessoa $object)
  31.     {
  32.         $this->pessoa $object;
  33.         $this->pessoa_id $object->id;
  34.     }
  35.     
  36.     /**
  37.      * Method get_pessoa
  38.      * Sample of usage: $pessoa_fisica->pessoa->attribute;
  39.      * @returns Pessoa instance
  40.      */
  41.     public function get_pessoa()
  42.     {
  43.         // loads the associated object
  44.         if (empty($this->pessoa))
  45.             $this->pessoa = new Pessoa($this->pessoa_id);
  46.     
  47.         // returns the associated object
  48.         return $this->pessoa;
  49.     }
  50.     
  51. }
  52. ?>


  1. <?php
  2. /**
  3.  * PessoaJuridica Active Record
  4.  * @author  Guilherme Faht (GURUX)
  5.  */
  6. class PessoaJuridica extends TRecord
  7. {
  8.     const TABLENAME 'pessoa_juridica';
  9.     const PRIMARYKEY'id';
  10.     const IDPOLICY =  'serial'// {max, serial}
  11.     
  12.     
  13.     private $pessoa;
  14.     /**
  15.      * Constructor method
  16.      */
  17.     public function __construct($id NULL$callObjectLoad TRUE)
  18.     {
  19.         parent::__construct($id$callObjectLoad);
  20.         parent::addAttribute('cnpj');
  21.         parent::addAttribute('pessoa_id');
  22.     }
  23.     
  24.     /**
  25.      * Method set_pessoa
  26.      * Sample of usage: $pessoa_juridica->pessoa = $object;
  27.      * @param $object Instance of Pessoa
  28.      */
  29.     public function set_pessoa(Pessoa $object)
  30.     {
  31.         $this->pessoa $object;
  32.         $this->pessoa_id $object->id;
  33.     }
  34.     
  35.     /**
  36.      * Method get_pessoa
  37.      * Sample of usage: $pessoa_juridica->pessoa->attribute;
  38.      * @returns Pessoa instance
  39.      */
  40.     public function get_pessoa()
  41.     {
  42.         // loads the associated object
  43.         if (empty($this->pessoa))
  44.             $this->pessoa = new Pessoa($this->pessoa_id);
  45.     
  46.         // returns the associated object
  47.         return $this->pessoa;
  48.     }
  49.     
  50. }
  51. ?>


Nessa técnica o único cuidado que você deverá tomar é o de manipular corretamente a persistência de Pessoa juntamente com a PessoaFisica ou PessoaJuridica. Sendo assim, não existe uma maneira melhor ou pior, pois vai depender da sua preferência. A maior vantagem dessa técnica é que as tabelas do banco de dados ficam menos "esburacadas". Porém, você terá que fazer um número maior de consultas.

Então são essas as minhas sugestões. Espero ter ajudado. Abraço!
GO

Olá Guilherme, bom dia!

Agradeço muito pelo retorno, suas explicações e as do Pablo foram de suma importância para o meu aprendizado.

Abração!