Je sais qu'en POO, vous voulez que chaque objet (d'une classe) soit une "chose", par exemple. utilisateur, validateur, etc.

Je connais les bases de MVC, comment les différentes parties interagissent les unes avec les autres.

Cependant, je me demande si les modèles dans MVC devraient être conçus selon la conception traditionnelle de la POO, c'est-à-dire, chaque modèle devrait-il être une base de données/table/ligne (solution 2) ?

Ou est-ce que l'intention est plutôt de collecter des méthodes qui affectent la même table ou un groupe de tables liées (solution 1).

Exemple pour un module de carnet d'adresses dans CodeIgniter, où je veux pouvoir "CRUD" un contact et l'ajouter/supprimer à/d'un groupe de contacts CRUD-able.

Solution des modèles 1 : regrouper toutes les méthodes associées (pas un objet réel, plutôt un "paquet")

class Contacts extends Model {

     function create_contact() {)
     function read_contact() {}
     function update_contact() {}
     function delete_contact() {}

     function add_contact_to_group() {}
     function delete_contact_from_group() {}

     function create_group() {}
     function read_group() {}
     function update_group() {}
     function delete_group() {}

}

Solution de modèles 2 : la méthode OOP (une classe par fichier)

class Contact extends Model {
     private $name = '';
     private $id = '';

     function create_contact() {)
     function read_contact() {}
     function update_contact() {}
     function delete_contact() {}

}

class ContactGroup extends Model {
     private $name = '';
     private $id = '';

     function add_contact_to_group() {}
     function delete_contact_from_group() {}

     function create_group() {}
     function read_group() {}
     function update_group() {}
     function delete_group() {}

}

Je ne sais pas comment penser quand je veux créer les modèles. et les exemples ci-dessus sont mes vraies tâches pour créer un carnet d'adresses. Dois-je simplement regrouper toutes les fonctions dans une seule classe. alors la classe contient une logique différente (contact et groupe), elle ne peut donc pas contenir de propriétés spécifiques à l'un ou l'autre.

La solution 2 fonctionne selon la POO. mais je ne sais pas pourquoi je devrais faire une telle division. quels seraient les avantages d'avoir un objet Contact par exemple. Ce n'est sûrement pas un objet User, alors pourquoi un contact devrait-il "vivre" avec son propre état (propriétés et méthodes). Parce que j'ai tendance à penser comme ceci : si quelque chose a besoin d'un état, alors je crée une classe OOP afin que les méthodes puissent affecter l'état ou d'autres choses basées sur l'état.

Les modèles devraient-ils donc aussi être « avec état » ? s'ils ne nécessitent aucun état, pourquoi devrais-je le créer selon le modèle OOP. alors je pourrais simplement tout regrouper comme la solution "package".

Vous avez connu des gars avec la POO/MVC, veuillez nous éclairer sur la façon dont il faut penser ici dans cette tâche très concrète (et en général lors de la création d'un modèle)

EDIT : pensez aux contrôleurs dans MVC. ils sont créés selon la solution « package ». Ça me fait penser...

4
never_had_a_name 12 avril 2010 à 07:34

3 réponses

Meilleure réponse

chaque modèle devrait-il être une base de données/table/ligne (solution 2) ?

Non. Ne liez pas la définition d'un modèle à sa méthode de persistance. Bien que pour des applications simples, vous puissiez étendre un modèle à partir d'un objet de ligne de base de données, vous devez les garder au moins mentalement séparés.

Les modèles sont simplement des représentations d'entités dans votre domaine, donc par nécessité, ils ont un état. Là où vous parlez d'un modèle de contact, vous parlez en réalité d'un mappeur ou d'une passerelle, c'est-à-dire de l'objet récupérant votre modèle du magasin de données. Il est regrettable que tant d'implémentations ad hoc d'Active Record aient brouillé les pistes à ce sujet.

Les mappeurs peuvent être implémentés en tant que collection de fonctions statiques ou en tant qu'objet - cependant, la collection est moins flexible si vous souhaitez étendre ou modifier le comportement pour une raison quelconque (comme la moquerie pour les tests unitaires).

Le modèle lui-même doit simplement être une collection de données, soit stockées en tant que propriétés publiques, soit de préférence avec des setters et getters appropriés (veuillez ne pas simplement définir une paire de fonctions get/set pour chaque variable ou vous pourriez aussi laissez-les simplement publics), ainsi que d'autres méthodes qui fonctionnent sur les données. Il ne doit pas avoir de concept ni de dépendance vis-à-vis du magasin de données. Il est de la responsabilité du mappeur d'instancier et d'initialiser le modèle via son interface. Cela vous donnera une flexibilité dans la façon dont vous pouvez créer et enregistrer vos modèles. Vous pouvez le faire à partir de la base de données, d'un fichier XML, dans le code, à partir d'un flux sérialisé envoyé sur le réseau, tout ce qui flotte vraiment sur votre bateau, le tout en substituant un mappeur différent, et le modèle reste complètement inconscient.

2
Duncan 12 avril 2010 à 10:00
Je pense que je comprends votre point. mais le code SQL permet-il de récupérer/insérer des lignes de/vers la base de données dans le mapper_model ou les data_models ? pourquoi devrais-je récupérer les données de mysql et les mettre dans le data_model (chaque objet représentant un contact) via un mappeur ? à quoi ça sert? ou ai-je mal compris le flux ? CONTROLLER appelle MAPPER_MODEL qui récupère les données de MYSQL et les met dans DATA_MODEL ? Je pense que je me trompe. pourriez-vous m'expliquer le flux.
 – 
never_had_a_name
12 avril 2010 à 10:27
Vous avez raison. Le contrôleur appelle le mappeur (généralement indirectement via un service ou en invoquant un autre modèle en fonction de la distance que vous souhaitez atteindre) et demande un modèle. Le mappeur crée le modèle, le remplit et le renvoie. Le but est l'abstraction ; il protège le modèle des modifications apportées au magasin de données. Le code MySQL appartient au mappeur, le modèle ne doit rien en savoir. Si vous décidez ultérieurement de stocker vos données dans un format différent, disons XML, vous écrivez un mappeur qui analyse les fichiers XML et renvoie le modèle. De cette façon, toute la logique de persistance est encapsulée.
 – 
Duncan
12 avril 2010 à 11:28
Ça a tellement de sens pour moi maintenant! Donc, fondamentalement, je devrais nommer mes mappeurs à la couche de données qu'ils utilisent, par exemple. "xml_mapper_model", "mysql_mapper_model". de cette manière particulière, je pourrais utiliser le stockage de données que je préfère. et les modèles de données sont le "contact_model" et le "contact_group_model". c'est comme la matrice..chaque programme est un "être humain" responsable d'une seule tâche. nous avons le "gardien", le "fabricant de clés", les "agents de sécurité" et ainsi de suite. donc une application entière n'est qu'un tas de ces objets qui communiquent/déléguent à des tâches les uns avec les autres. aussi comme un gouvernement militaire =)
 – 
never_had_a_name
13 avril 2010 à 06:52
Mais j'ai entendu des gens dire que souvent un moyen de coder est de créer un modèle pour chaque table. puis avoir un contrôleur avec le même nom. donc users_controller -> users_model -> users_table. c'est la manière RoR de le faire qu'ils déclarent. quelles sont vos opinions à ce sujet? et comment cela a-t-il un impact avec les "mapper_models" et les "data_models". Ce serait génial si vous pouviez utiliser mon exemple pour cela aussi.
 – 
never_had_a_name
13 avril 2010 à 07:15

Je ne sais pas s'il existe une meilleure méthode, mais je vais partager ma façon de procéder...

J'ai une passerelle de table, par ex. ContactTableGateway qui contient tout le SQL pour traiter les contacts. J'aime que tout le SQL soit au même endroit.

class ContactTableGateway extends Model {

    function saveContact( Contact $contact )
    function getContact ( $contact_id )
    function createContact ( Contact $contact )

}

Ensuite, j'ai une classe de contact qui n'a essentiellement que des getters et des setters (ou des propriétés publiques). Les objets de cette classe sont utilisés comme arguments pour que la passerelle de table enregistre/crée

class Contact extends Model {

    function getName()
    function getAddress()
    function getEmail()
    ....

}

Voici un exemple simplifié

if ( isset( $_POST ) ) {

    // some validation here
    $contact = new Contact;
    $contact->name = $_POST['name'];
    $contact->email = $_POST['email']
    $contactTableGateway = new ContactTableGateway;

    if ( $contactTableGateway->createContact( $contact ) ) {
        echo "YAY";
    }
}
2
Galen 12 avril 2010 à 07:49
Merci d'avoir partagé! il semble que vous optiez pour la solution POO :) et cela a l'air assez élégant. qu'en est-il de vos contrôleurs, sont-ils plutôt des packages, ou également orientés objet ?
 – 
never_had_a_name
12 avril 2010 à 07:53
Je ne suis pas sûr de ce que vous voulez dire. site.com/contact/create = créer une méthode sur le contrôleur de contact. site.com/contact/view/3/ = méthode d'affichage sur le contrôleur de contact, affichage du contact avec l'identifiant : 3
 – 
Galen
12 avril 2010 à 08:46
Oh tant pis avec les contrôleurs :) vous avez les propriétés publiques dans la classe Contact ? sinon, ContactTableGateway NE PEUT PAS y accéder. mais je ne veux jamais que mes propriétés soient directement accessibles mais privées afin qu'elles ne soient accessibles que via les setters/getters. complication.
 – 
never_had_a_name
12 avril 2010 à 10:32
1
Rendez-les tous privés et ajoutez des getters/setters =)
 – 
Galen
13 avril 2010 à 00:21
Donc, fondamentalement, ContactTableGateway est chargé de communiquer avec la base de données et Contact est un objet ? Pourquoi tous doivent-ils étendre la classe Model ? Pour utiliser l'objet $db ?
 – 
TomSawyer
2 déc. 2016 à 23:06

Je pense que votre solution n°2 est supérieure car elle est plus moléculaire/modulaire, donc plus compréhensible, flexible et extensible (dans le domaine de la POO). Il est également plus convivial en ressources car il pourrait vous permettre de n'avoir à charger la classe Contact que lorsqu'aucune fonctionnalité de groupe de contacts n'est requise et vice-versa. C'est l'avantage de la division.

Si les modèles n'ont pas besoin d'état, cela ne signifie pas que OOP/MVC ne s'applique pas. Les modèles de table peuvent n'avoir aucun état dans leur conception, mais c'est pourquoi nous avons des méthodes/membres statiques, c'est-à-dire Contact::read($id).

1
webbiedave 12 avril 2010 à 09:32