Garder un modèle MVC faiblement couplé à la base de données?

9

J'aime garder mon code testable et j'ai décidé de suivre la stratégie d'injection de dépendances pour mon framework MVC actuel, qui s'est certainement avérée être un excellent moyen d'assurer un code couplé de manière lâche, la testabilité et la modularité.

Mais étant loin d'être un maître dans les modèles de conception, j'ai du mal à trouver un bon moyen de garder mes modèles aussi faiblement couplés des classes de connecteurs de base de données, que possible.

Comment est-ce possible?
Comme je n'ai pas fourni de code physique avec cette question, j'apprécierais vraiment quelques exemples ou informations de logique / code qui pourraient m'orienter dans une direction pour comprendre le problème décrit ci-dessus.

Industriel
la source
Cette question appartient au génie logiciel , car elle concerne davantage la structuration et la réflexion autour de ce sujet, plus que sa mise en œuvre dans le code.
Lasse V. Karlsen

Réponses:

6

Une façon consiste à concevoir vos modèles avant de concevoir votre base de données. Lors de la conception de vos modèles, l'accent est mis sur la capture de la logique métier et des significations au sein du domaine problématique. Cela doit être capturé d'une manière qui a du sens pour l'entreprise, y compris plus que des entités et des champs de données. Certains éléments de données sont interprétés par d'autres, certains dépendent d'autres, etc. De plus, vous ajouteriez à ce modèle toute logique de base dont vous avez besoin, comme la façon dont un objet répond en interne lorsqu'un certain élément est défini sur une certaine valeur.

Il est fort probable que vous vous retrouviez avec quelque chose qui est identique à 90% à la façon dont vous finissez par persister dans les données. C'est très bien. Il peut être complètement identique sans être couplé.

Notez également que la modélisation du domaine dans un brouillard de véritable ignorance de la persistance est un peu un Saint Graal pour la conception de logiciels. Si vous pouvez le faire, fantastique. Mais si le domaine problématique est important et a une complexité, c'est toujours une bonne idée de prendre de temps en temps un peu de recul par rapport à la modélisation de domaine afin de faire un contrôle de cohérence sur la persistance des données pour vous assurer que vous n'avez pas peint vous dans un coin.

N'oubliez pas les rôles réels des différents composants et gardez ces rôles séparés lorsque vous les concevez. Pour toute décision de conception donnée, demandez-vous si l'un de ces rôles est violé:

  1. Base de données - Stockez les données, maintenez l'intégrité des données, maintenez les données au repos.
  2. Modèles - Contenez la logique métier, modélisez le domaine problématique, maintenez les données en mouvement, répondez aux événements de niveau métier, etc.
  3. Vues - Présentez les données aux utilisateurs, effectuez une logique côté utilisateur (validation de base avant qu'une véritable validation soit effectuée dans les modèles, etc.).
  4. Contrôleurs - Répondez aux événements des utilisateurs, passez le contrôle aux modèles, routez les demandes et renvoyez les réponses.
David
la source
Salut David. Merci pour votre réponse détaillée! Tout en maintenant un niveau élevé de couplages desserrés, comment connecteriez-vous les modèles avec un connecteur de base de données?
Industrial
1
@Industrial: Il existe un certain nombre de façons de connecter les modèles à la persistance, mais jusqu'à présent, la seule méthode que j'ai trouvée qui satisfait vraiment mon désir de séparer les préoccupations est d'avoir des interfaces de référentiel dans le domaine qui sont implémentées en externe par un DAL. Les méthodes de référentiel acceptent et renvoient des modèles de domaine et convertissent en interne entre ceux-ci et toutes les entités de base de données générées. (Pour être honnête, je n'ai pas fait beaucoup de choses en PHP.) Vous pouvez donc utiliser un cadre DAL pour générer automatiquement tous vos DB CRUD, etc., puis écrire vos référentiels comme interface entre ce truc et vos modèles.
David
@Industrial: Par exemple, si vous utilisez un ORM, alors cet ORM serait référencé par votre DAL (qui est isolé des modèles de domaine) et transformerait vos modèles en accès aux données en conséquence. Ou si vous effectuez un accès direct à la base de données avec SQL manuel, vous le feriez dans les méthodes de référentiel de votre DAL et traduisez les résultats des requêtes SQL en modèles de domaine avant de les renvoyer.
David
@Industrial: Gardez également à l'esprit que les méthodes de référentiel ne doivent pas simplement être CRUD. Beaucoup d'intelligence peut être intégrée dans ce code. Beaucoup des plus complexes peuvent avoir beaucoup de code interne qui transforme les données de la base de données. Ou, si les problèmes complexes impliquent de nombreux déplacements dans la base de données, pour des gains de performances, vous pouvez placer la logique dans une procédure stockée et la méthode DAL passe simplement à cette procédure et traduit les résultats en modèles.
David
Salut David! Je voulais juste vous remercier encore pour cette réponse. Certainement l'un des meilleurs que j'ai reçus sur StackExchange!
Industrial
2

Vous voulez avoir deux choses.

  1. Vos modèles (accesseurs du DBAL et exécutant la majeure partie de la logique de l'application).
  2. Vos "modèles de domaine" alias entités de données, elles représentent les entités de votre système telles que les utilisateurs, les publications, les produits, 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;
        }
    
    }
    

Code d'utilisation

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

Voilà, c'est ainsi que vous créez des modèles de domaine (Entités) et que les modèles MVC effectuent la connectivité DB et la manipulation des données.

Si vous vous demandez ce qu'est un PPI, recherchez «PPI Framework» sur Google.

Bonne chance dans vos recherches.

Cordialement, Paul Dragoonis.

Paul Dragoonis
la source
1

Rappelez-vous, MVC est apparu dans smalltalk, qui a une persistance automatique pour tous les objets. Ainsi, le modèle MVC ne prescrit aucune solution pour la séparation modèle / persistance.

Ma préférence est de fournir un objet "Repository" qui sait comment créer des objets Model à partir de la base de données et stocker des objets Model dans la base de données. Ensuite, le modèle ne sait rien de la persistance. Cependant, certaines actions de l'utilisateur devront déclencher une sauvegarde, il est donc probable que le contrôleur connaîtra le référentiel. J'utilise généralement une certaine forme d'injection de dépendance pour empêcher le contrôleur d'être couplé au référentiel.

Sean McMillan
la source