Mantendo um modelo MVC fracamente acoplado ao DB?

9

Eu gosto de manter meu código testável e decidi seguir a estratégia de injeção de dependência para minha estrutura MVC atual, que definitivamente provou ser uma ótima maneira de garantir código, testabilidade e modularidade fracamente acoplados.

Mas, por estar longe de ser um mestre nos padrões de design, tenho dificuldade em descobrir uma boa maneira de manter meus modelos tão fracamente acoplados das classes de conectores do banco de dados quanto possível.

Como isso pode ser feito?
Como não forneci nenhum código físico junto com essa pergunta, eu realmente aprecio alguns exemplos ou informações de lógica / código que podem me indicar uma direção para entender o problema descrito acima.

Industrial
fonte
Essa pergunta pertence à engenharia de software , pois é mais sobre a estruturação e o pensamento em torno deste tópico, mais do que sobre implementá-lo no código.
Lasse V. Karlsen

Respostas:

6

Uma maneira é projetar seus modelos antes de projetar seu banco de dados. Ao projetar seus modelos, o foco é capturar a lógica e os significados do negócio no domínio do problema. Isso deve ser capturado de uma maneira que faça sentido para os negócios, incluindo mais do que apenas entidades e campos de dados. Alguns elementos de dados são interpretados por outros, outros dependem de outros etc. Além disso, você adicionaria a este modelo qualquer lógica básica necessária, como a forma como um objeto responde internamente quando um determinado elemento é definido com um determinado valor.

É bem provável que você termine com algo 90% mais idêntico ao de como você mantém os dados. Isso é bom. Pode ser completamente idêntico sem ser acoplado.

Observe também que modelar o domínio em meio a uma verdadeira ignorância de persistência é um pouco do santo graal para o design de software. Se você pode fazer isso, fantástico. Mas se o domínio do problema é significativo e tem alguma complexidade, ainda é uma boa idéia voltar da modelagem de domínio de tempos em tempos para fazer uma verificação de integridade na persistência dos dados para garantir que você não tenha pintado -se em um canto.

Lembre-se das funções reais dos vários componentes e mantenha-as separadas quando as projetar. Para qualquer decisão de design, pergunte-se se alguma dessas funções é violada:

  1. Banco de dados - armazene os dados, mantenha a integridade dos dados, mantenha os dados em repouso.
  2. Modelos - Conter a lógica de negócios, modelar o domínio do problema, manter os dados em movimento, responder a eventos em nível de negócios etc.
  3. Exibições - Apresente dados aos usuários, execute a lógica do lado do usuário (validação básica antes da validação verdadeira nos modelos, etc.).
  4. Controladores - responda a eventos do usuário, passe o controle para modelos, direcione solicitações e retorne respostas.
David
fonte
Olá David. Obrigado pela sua resposta extensa! Embora mantendo um alto nível de acoplamentos soltos, como você conectaria os modelos a um conector de banco de dados?
Industrial
11
@ Industrial: Existem várias maneiras de conectar modelos à persistência, mas até agora o único método que encontrei que realmente satisfaz meu desejo de separar preocupações é ter interfaces de repositório no domínio, implementadas externamente por um DAL. Os métodos do repositório aceitam e retornam modelos de domínio e convertem internamente entre esses e quaisquer entidades de banco de dados geradas. (Para ser sincero, não fiz muito isso em PHP.) Portanto, você pode usar uma estrutura DAL para gerar automaticamente todo o seu DB CRUD etc., e depois escrever seus repositórios como uma interface entre essas coisas e seus modelos.
David
@ Industrial: por exemplo, se você usar um ORM, esse ORM seria referenciado pelo seu DAL (isolado dos modelos de domínio) e transformaria seus modelos em acesso a dados de acordo. Ou, se você acessar diretamente o banco de dados com SQL manual, faça isso nos métodos de repositório do DAL e traduza os resultados das consultas SQL em modelos de domínio antes de retorná-las.
David
@ Industrial: Lembre-se também de que os métodos do repositório não precisam ser apenas CRUD. Muita inteligência pode ser inserida nesse código. Muitos dos mais complexos podem ter muito código interno que transforma dados do banco de dados. Ou, se os complexos envolvem muitas viagens ao banco de dados, para obter ganhos de desempenho, você pode colocar a lógica em um procedimento armazenado e o método DAL apenas passa para esse procedimento e traduz os resultados em modelos.
David
Olá David! Só queria agradecer novamente por esta resposta. Definitivamente, um dos melhores que recebi no StackExchange!
Industrial
2

Você quer ter duas coisas.

  1. Seus modelos (acessadores do DBAL e fazendo a maior parte da lógica do aplicativo).
  2. Seus "Modelos de Domínio", também conhecidos como Entidades de Dados, representam as entidades do seu sistema, como usuários, postagens, produtos etc.

    class PPI_Model_User {
    
        protected $_conn = null;
    
        function __construct(array $options = array()) {
            if(isset($options['dsnData'])) {
                $this->_conn = new PPI_DataSource_PDO($options['dsnData']);
            }
        }
    
        function getAll() {
            $rows = $this->_connect->query("SELECT .....")->fetchAll();
            $users = array();
            foreach($rows as $row) {
                $users[] = new PPI_Entity_User($row);
            }
            return $users;
        }
    
    }
    

Código de uso

    $model = new PPI_Model_User(array('dsnData' => $dsnData));
    $users = $model->getAll();
    foreach($users as $user) {
        echo $user->getFirstName();
    }

Aí está, é assim que você cria modelos de domínio (Entidades) e tem modelos MVC fazendo a conectividade do DB e a manipulação de dados.

Se você está se perguntando o que é PPI, pesquise no Google por "PPI Framework".

Boa sorte com sua pesquisa.

Atenciosamente, Paul Dragoonis.

Paul Dragoonis
fonte
1

Lembre-se, o MVC surgiu em smalltalk, que tem persistência automática para todos os objetos. Portanto, o padrão MVC não prescreve nenhuma solução para separação de modelo / persistência.

Minha preferência é fornecer um objeto "Repositório" que saiba como criar objetos Model a partir do banco de dados e armazenar objetos Model no banco de dados. Então o modelo não sabe nada sobre persistência. Algumas ações do usuário terão que ativar um salvamento, portanto, é provável que o Controlador conheça o Repositório. Normalmente, uso alguma forma de injeção de dependência para impedir que o controlador seja acoplado ao repositório.

Sean McMillan
fonte