Besoin de vous pour une classe model

Eléphant du PHP | 451 Messages

15 août 2014, 17:32

Bonjour,

Alors voilà je suis en train de crée un petit framework en mvc pour un projet et je voulais faire une class model qui ressemble à celle de cakephp 3 car je trouve la façon de faire une requête pas mal.

Ils font:
$this->Model->find('all')->select('id')->where(['id' => 2])
J'ai essayé de voir comment ils ont fait mais je comprends pas trop, car c'est une classe table qui appel une classe query mais je ne comprend pas comment la requête de lance.

Voici ce que j'ai pour l'instant:
Model.php
<?php

class Model {

    public $database = 'default';

    public $table = false;
    public $alias = false;

    public function __construct() {
        if($this->table === false) {
            $this->table = strtolower(get_class($this));
        }

        if($this->alias === false) {
            $this->alias = get_class($this);
        }
    }

    public function find($type) {
        $query = $this->query();
        $query->select();

        return $this->callFinder($type, $query);
    }

    private function query() {
        return new Query($this);
    }

    public function callFinder($type, Query $query) {
        $finder = 'find' . ucfirst($type);

        if (method_exists($this, $finder)) {
            return $this->{$finder}($query);
        }
    }

    public function findAll(Query $query) {
        echo '<pre>';
        var_dump($query);
        echo '</pre>';

        return $query;
    }

}
Query.php
<?php

class Query {

    static $connect = [];

    private $model;
    private $pdo;
    private $sql;
    private $bind = [];



    public function __construct($model) {
        $this->model = $model;

        if(isset(self::$connect[$this->model->database])) {
            $this->pdo = self::$connect[$this->model->database];

            return true;
        }

        $conf = Conf::$database[$this->model->database];

        try {
            $pdo = new PDO('mysql:host='.$conf['host'].';dbname='.$conf['dbname'].';', $conf['user'], $conf['pass'], [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8']);

            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);

            self::$connect[$this->model->database] = $pdo;
            $this->pdo = $pdo;
        } catch(PDOException $e) {
            if(Config::$debug == 1) {
                die($e->getMessage());
            } else {
                die('Impossible de se connecter à la base de donnée');
            }
        }
    }

    public function select($fields = null) {
        if(!$fields) {
            return $this;
        }

        $this->sql .= "SELECT ";

        if(isset($fields)) {
            $sql = '';

            foreach ($fields as $field) {
                $sql .= $this->model->table.'.'.$field.', ';
            }

            $this->sql .= substr($sql, 0, -2);
        } else {
            $this->sql .= "*";
        }

        $this->sql .= " FROM ".$this->model->table." as ".$this->model->alias;

        return $this;
    }

    public function where($conditions) {
        $this->sql .= " WHERE ";

        $i = 0;
        $sql = '';

        foreach ($conditions as $key => $value) {
            $sql .= ($i != 0) ? " AND " : '';

            if(is_array($value)) {
                $this->bind[$key] = $value[1];
                $value = ' '.$value[0].' :'.$key;
            } else {
                $this->bind[$key] = $value;
                $value = ' = :'.$key;
            }

            $sql .= $key.$value;

            $i++;
        }

        $this->sql .= $sql;

        return $this;
    }

    public function exec() {
        var_dump($this->sql);
        $query = $this->pdo->prepare($this->sql);
        $query->execute($this->bind);
        $res = $query->fetchAll(PDO::FETCH_OBJ);

        return $res;
    }

}
Donc comment doit-je faire pour exécuter ma fonction exec de query dans la fonction find de model?

Merci d'avance....

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

15 août 2014, 18:02

salut,


il s'agit de l'utilisation d'n ORM comme
- doctrine
- propel
- celui de cake3 http://book.cakephp.org/3.0/fr/orm.html

Dans l'exemple
$this->Model->find('all')->select('id')->where(['id' => 2])
tu fait appel à un objet modèle qui retourne un objet avec une méthode select, qui retourne un objet avec une méthode where.

généralement c'est le même objet qui est retourné (return this) et qui permet de chaîner les méthodes.
La tes méthodes indique la table, les champs a utiliser et le prédicat, mais il te manque une méthode pour exécuter la requete (exec / query ?).

ce qui donnerais
$data = $this->Model->find('all')->select('id')->where(['id' => 2])->execute(); (pr exemple);

Je suppose que cette classe Modele sera héritée par les objet du modèle de l’application ?
Il faut penser que ta classe modèle est un générque qui va appeler appeler les tables associées (le nom est souvent figé par convention (par exemple article avec la table articles).

coté nom des méthodes, la méthode find retourne toutes la table, donc redondante avec select (qui devrait plutôt s'appeler columns a mon gout).

tu peux simplement reprendre un orm existant tu iras plus vite ;)

si tu souhaite prendre les temps de le refaire, il te faut étudier la chose plus en avant sur le papier avant ;)


@+
Il en faut peu pour être heureux ......

Eléphant du PHP | 451 Messages

15 août 2014, 19:46

Oui c'est tout as fait ça mais je préfère faire mon ORM que d'en prendre un tout fait car il sera plus léger et correspondra uniquement à mes besoins mais je bloque totalement pour que la requête se lance toute seule sans que je fasse un exec à la fin de l'exemple.

Si tu as des pistes ou un ptit exemple je suis preneur :wink:

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

18 août 2014, 23:01

avec ce que tu indique il faut la méthode
  • find : retourne un tableau avec tout les objets (qui correspondent a ce que tu passe en paramètre, ici all)
  • select($column) : utilise le premier tableau mais réduit à seulement aux colonnes passée en paramètre (dans un modèle je ne vois pas du tout l’intérêt d'une telle méthode ;) )
  • where(['id' => 2]) : réduit le tableau en appliquant le prédicat.


Perso je ne trouve pas ce type de fonctionnement correct, sauf si tu as un système de cache et encore je ne suis pas certain que cela soit plus performant qu'une requête.

Après je ne sais pas comment les ORM existant fonctionne, je sais qu'ils sont relativement performant.

Mais il est certain qu'il ne font pas une requête a chaque fois, je pense qu'ils travail comme je te l'ai indiqué avec le tri en php, sinon il faut exécuter la requête au moment ou l'on fetch la première fois et cela t'évite la méthode "execute".

donc en gros
$Methode->fetch() regarde s'il y un jeux de résultat, si absent exécute la demande et du coup les méthode précédente ne font que construire la requête.


@+
Il en faut peu pour être heureux ......

Eléphant du PHP | 451 Messages

19 août 2014, 22:23

Ok donc le mieux c'est de faire select()->where()->find() comme ça le find exécute la requête car la pour l'instant elle est vide dans mon find.

Car faire un tableau en php puis faire des tri dessus je crois que ça va être trop compliqué.

Mais je vais continué à étudié l'ORM de cakephp pour voir et comprendre comment ils font car je pense pas qu'ils fassent un tableau en php.