565 votes

Comment un modèle doit-il être structuré en MVC ?

Je commence tout juste à comprendre le cadre MVC et je me demande souvent quelle quantité de code doit être placée dans le modèle. J'ai tendance à avoir une classe d'accès aux données qui a des méthodes comme celle-ci :

public function CheckUsername($connection, $username)
{
    try
    {
        $data = array();
        $data['Username'] = $username;

        //// SQL
        $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE Username = :Username";

        //// Execute statement
        return $this->ExecuteObject($connection, $sql, $data);
    }
    catch(Exception $e)
    {
        throw $e;
    }
}

Mes modèles ont tendance à être une classe d'entité qui est mappée à la table de la base de données.

L'objet modèle doit-il avoir toutes les propriétés liées à la base de données ainsi que le code ci-dessus ou est-il possible de séparer le code qui fait réellement fonctionner la base de données ?

Est-ce que je vais finir par avoir quatre couches ?

1 votes

136 votes

Pourquoi récupérez-vous les exceptions juste pour les relancer ?

9 votes

@Elias Van Ootegem : vous n'avez pas compris. Il est inutile de les attraper dans ce cas.

53voto

Rinzler Points 1459

Le paradigme MVC est un moyen de diviser une application, ou même simplement un élément de l'interface d'une application, en trois parties : le modèle, la vue et le contrôleur.

MVC a été développé à l'origine pour transposer les rôles traditionnels d'entrée, de traitement et de sortie dans le domaine des interfaces graphiques :

Veuillez vous référer : :
Zend Framework : Survivre aux profondeurs de l'océan

Pour plus d'informations sur le mvc en PHP, vous pouvez consulter les liens ci-dessous, qui sont particulièrement utiles pour les débutants.

  1. Modèle vue contrôleur (MVC) en PHP
  2. Implémentation de MVC en PHP : Le modèle
  3. MVC pour les novices
  4. Architecture MVC dans le développement PHP

Enter image description here

Modèle

Un modèle est un objet représentant des données ou même une activité, par exemple une table de base de données ou même un processus de machine de production dans l'usine.

Le modèle gère le comportement et les données du domaine d'application, répond aux demandes d'informations sur son état et répond aux instructions de changement d'état.

Le modèle représente les données de l'entreprise et les règles métier qui régissent l'accès à ces données et leur mise à jour. Souvent, le modèle sert d'approximation logicielle à un processus du monde réel, de sorte que des techniques simples de modélisation du monde réel s'appliquent lors de la définition du modèle.

Le modèle est la pièce qui représente l'état et le comportement de bas niveau du composant. Il gère l'état et effectue toutes les transformations sur cet état. Le modèle n'a aucune connaissance spécifique de ses contrôleurs ou de ses vues. La vue est la pièce qui gère l'affichage visuel de l'état représenté par le modèle. Un modèle peut avoir plus d'une vue.

Voir

Une vue est une forme de visualisation de l'état du modèle. La vue gère la sortie graphique et/ou textuelle sur la partie de l'affichage en mode point qui est allouée à son application. Au lieu d'un affichage en mode point, la vue peut générer une sortie HTML ou PDF.

La vue rend le contenu d'un modèle. Elle accède aux données de l'entreprise par le biais du modèle et spécifie comment ces données doivent être présentées.

La vue est responsable du mappage des graphiques sur un périphérique. Une vue a généralement une correspondance univoque avec une surface d'affichage et sait comment effectuer un rendu sur celle-ci. Une vue s'attache à un modèle et rend son contenu sur la surface d'affichage.

Contrôleur

Un contrôleur permet de modifier l'état du modèle. Le contrôleur interprète les entrées de la souris et du clavier de l'utilisateur, et commande le modèle et/ou la vue pour qu'ils changent comme il convient.

Un contrôleur est le moyen par lequel l'utilisateur interagit avec l'application. Il accepte les données de l'utilisateur et demande au modèle et à la vue d'effectuer des actions en fonction de ces données. En fait, le contrôleur est responsable de la correspondance entre l'action de l'utilisateur final et la réponse de l'application.

Le contrôleur traduit les interactions avec la vue en actions à exécuter par le modèle. Dans un client GUI autonome, les interactions de l'utilisateur peuvent être des clics de bouton ou des sélections de menu, alors que dans une application Web, elles se présentent sous la forme de requêtes HTTP GET et POST. Les actions réalisées par le modèle comprennent l'activation de processus métier ou la modification de l'état du modèle. En fonction des interactions de l'utilisateur et du résultat des actions du modèle, le contrôleur répond en sélectionnant une vue appropriée.

Le contrôleur est la pièce qui gère l'interaction de l'utilisateur avec le modèle. Il fournit le mécanisme par lequel les changements sont apportés à l'état du modèle.

Un exemple de modèle en Zend Framework dans lequel je travaille .

<?php
    class Default_Model_Check extends Zend_Db_Table {
        protected $_name = 'Check';  // This is the Table which is defined here since we have already defined our working database.
        public function CheckUsername($username) {    // Which just need to pass the username to check the condition
            $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE Username = :Username";  // Our query

            // Exception handling here
            try{
                $result = $this->getDefaultAdapter()->fetchAll($sql);
                if (count($result)>0){
                    return $result;
                }
            }
            catch(Exception $e){
                $errlog = Zend_Controller_Action_HelperBroker::getStaticHelper('errorlog');
                $errlog->direct("Check.CheckUsername : " . $e->getMessage());
            }
            return false;
        }
    }
?>

39voto

netcoder Points 31874

Tout ce qui est logique d'entreprise appartient à un modèle, qu'il s'agisse d'une requête de base de données, de calculs, d'un appel REST, etc.

Vous pouvez avoir l'accès aux données dans le modèle lui-même, le modèle MVC ne vous en empêche pas. Vous pouvez l'enrober de services, de mappeurs et autres, mais la définition réelle d'un modèle est une couche qui gère la logique métier, rien de plus, rien de moins. Il peut s'agir d'une classe, d'une fonction ou d'un module complet avec des milliards d'objets si c'est ce que vous voulez.

Il est toujours plus facile d'avoir un objet séparé qui exécute réellement les requêtes de la base de données plutôt que de les exécuter directement dans le modèle : cela sera particulièrement utile lors des tests unitaires (en raison de la facilité d'injecter une dépendance de base de données fictive dans votre modèle) :

class Database {
   protected $_conn;

   public function __construct($connection) {
       $this->_conn = $connection;
   }

   public function ExecuteObject($sql, $data) {
       // stuff
   }
}

abstract class Model {
   protected $_db;

   public function __construct(Database $db) {
       $this->_db = $db;
   }
}

class User extends Model {
   public function CheckUsername($username) {
       // ...
       $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE ...";
       return $this->_db->ExecuteObject($sql, $data);
   }
}

$db = new Database($conn);
$model = new User($db);
$model->CheckUsername('foo');

De plus, en PHP, il est rarement nécessaire d'attraper/renvoyer les exceptions car le backtrace est préservé, surtout dans un cas comme votre exemple. Laissez simplement l'exception être levée et attrapez-la dans le contrôleur à la place.

0 votes

Ma structure est très similaire, je pense que je la sépare juste un peu plus. La raison pour laquelle je faisais circuler la connexion était que j'avais besoin que les morceaux soient exécutés dans des transactions. Je voulais ajouter un utilisateur, puis ajouter l'utilisateur à un rôle, mais revenir au rôle si l'une des transactions échouait. La seule façon de résoudre ce problème était de passer la connexion.

10 votes

-1 : il se trouve aussi qu'il est complètement faux. Un modèle n'est pas une abstraction pour une table.

1 votes

En User étend fondamentalement le modèle, mais ce n'est pas un objet. L'utilisateur devrait être un objet et avoir des propriétés comme : id, nom ... Vous déployez User est une aide.

20voto

mario Points 76989

En Web-"MVC", vous pouvez faire ce que vous voulez.

Le concept original (1) a décrit le modèle comme la logique de l'entreprise. Il doit représenter l'état de l'application et assurer une certaine cohérence des données. Cette approche est souvent décrite comme un "gros modèle".

La plupart des frameworks PHP suivent une approche plus superficielle, où le modèle n'est qu'une interface de base de données. Mais ces modèles doivent au moins valider les données et les relations entrantes.

Quoi qu'il en soit, vous n'êtes pas très loin si vous séparez les éléments SQL ou les appels de base de données dans une autre couche. De cette façon, vous n'avez à vous préoccuper que des données/comportement réels, et non de l'API de stockage proprement dite. (Il n'est toutefois pas raisonnable d'en faire trop. Vous ne pourrez jamais, par exemple, remplacer un backend de base de données par un stockage de fichiers si cela n'a pas été conçu à l'avance).

8 votes

Le lien n'est pas valide (404)

1 votes

Cela fonctionne à partir de WebArchive : web.archive.org/web/20101229204648/https://stackoverflow.com/

7voto

Le plus souvent, la plupart des applications ont des parties données, affichage et traitement et nous les mettons toutes dans les lettres. M , V y C .

Modèle( M ) -->Il a les attributs qui contiennent l'état de l'application et il ne sait rien à ce sujet. V y C .

Voir( V ) -->Dispose d'un format d'affichage pour l'application et ne connaît que la façon de digérer le modèle sur celui-ci et ne se soucie pas de C .

Contrôleur( C ) ---->Partie intégrante de l'application, elle agit comme un lien entre M et V et dépend des deux. M , V contrairement à M y V .

Dans l'ensemble, il y a une séparation des préoccupations entre chacun. À l'avenir, toute modification ou amélioration pourra être ajoutée très facilement.

0voto

Ibu Points 17457

Dans mon cas, j'ai une classe de base de données qui gère toute l'interaction directe avec la base de données, comme l'interrogation, la récupération, etc. Donc si je devais changer ma base de données de MySQL a PostgreSQL il n'y aura pas de problème. Il peut donc être utile d'ajouter cette couche supplémentaire.

Chaque table peut avoir sa propre classe et ses méthodes spécifiques, mais pour obtenir réellement les données, elle laisse la classe de base de données s'en charger :

Fichier Database.php

class Database {
    private static $connection;
    private static $current_query;
    ...

    public static function query($sql) {
        if (!self::$connection){
            self::open_connection();
        }
        self::$current_query = $sql;
        $result = mysql_query($sql,self::$connection);

        if (!$result){
            self::close_connection();
            // throw custom error
            // The query failed for some reason. here is query :: self::$current_query
            $error = new Error(2,"There is an Error in the query.\n<b>Query:</b>\n{$sql}\n");
            $error->handleError();
        }
        return $result;
    }
 ....

    public static function find_by_sql($sql){
        if (!is_string($sql))
            return false;

        $result_set = self::query($sql);
        $obj_arr = array();
        while ($row = self::fetch_array($result_set))
        {
            $obj_arr[] = self::instantiate($row);
        }
        return $obj_arr;
    }
}

Objet de table classeL

class DomainPeer extends Database {

    public static function getDomainInfoList() {
        $sql = 'SELECT ';
        $sql .='d.`id`,';
        $sql .='d.`name`,';
        $sql .='d.`shortName`,';
        $sql .='d.`created_at`,';
        $sql .='d.`updated_at`,';
        $sql .='count(q.id) as queries ';
        $sql .='FROM `domains` d ';
        $sql .='LEFT JOIN queries q on q.domainId = d.id ';
        $sql .='GROUP BY d.id';
        return self::find_by_sql($sql);
    }

    ....
}

J'espère que cet exemple vous aidera à créer une bonne structure.

12 votes

"Donc si je devais changer ma base de données de MySQL à PostgreSQL, il n'y aura pas de problème." Uhhhmmm avec le code ci-dessus vous auriez un énorme problème pour changer quoi que ce soit imo.

0 votes

Je vois que ma réponse a de moins en moins de sens après édition, et au fur et à mesure que le temps passe. Mais elle devrait rester ici

2 votes

Database dans l'exemple n'est pas une classe. C'est juste une enveloppe pour les fonctions. De plus, comment pouvez-vous avoir une "classe d'objets de table" sans objet ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X