Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]Wzorzec MVC - model
Forum PHP.pl > Forum > Przedszkole
Evinek
Chodzi o model, który pobiera newsy.
Mam na przykład takie coś:
  1. class News extends Model {
  2. public function getAll() {
  3. return $this->db->query('SELECT * FROM `news`')->fetchAll();
  4. }
  5. }

Muszę również pobierać newsy:
a) tylko 5 najnowszych
b) tylko usunięte (delete = 1)
c) tylko te, które mają datę publikacji mniejszą niż aktualna (publish < time())
d) tylko widoczne (visible = 1)

e) połączenie a + b, a + c, b + c, a + b + c + d i tak dalej, i tak dalej.

I pytanie, jak rozwiązać to aby nie tworzyć wielu metod, a najlepiej żeby była jedna czy dwie?

Klasa bazy danych
  1. class Database {
  2.  
  3. protected $pdo;
  4. protected $stmt;
  5.  
  6. public function __construct($type, $host, $name, $user, $pass) {
  7. $this->pdo = new PDO($type . ':host=' . $host . ';dbname=' . $name, $user, $pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
  8. }
  9.  
  10. public function query($sql, $data = array()) {
  11. $this->stmt = $this->pdo->prepare($sql);
  12. $this->stmt->setFetchMode(PDO::FETCH_ASSOC);
  13. foreach($data as $key=>$value) {
  14. if(is_int($value))
  15. $this->stmt->bindValue(':' . $key, $value, PDO::PARAM_INT);
  16. else
  17. $this->stmt->bindValue(':' . $key, $value);
  18. }
  19. $this->stmt->execute();
  20. return $this;
  21. }
  22.  
  23. public function fetch() {
  24. return $this->stmt->fetch();
  25. }
  26.  
  27. public function fetchAll() {
  28. return $this->stmt->fetchAll();
  29. }
  30.  
  31. public function rowCount() {
  32. return $this->stmt->rowCount();
  33. }
  34.  
  35. public function lastId() {
  36. return $this->pdo->lastInsertId();
  37. }
  38.  
  39. public function pdo() {
  40. return $this->pdo;
  41. }
  42. }
Turson
Najprostsze rozwiązanie jakie mi teraz przychodzi do głowy to przekazywanie warunku w parametrze
  1. $model->getData("WHERE delete=1");

  1. public function getData($query=null){
  2. return $this->db->query('SELECT * FROM `news` '.$query)->fetchAll();
  3. }


ale czy rozsądne, wątpię...
vonski
Może coś w tym stylu:

  1. public function getMany($fields = null, $cond = null, $limit = null, $orderBy = null)
  2. {
  3. $query = "SELECT ";
  4. if(!is_null($fields)) {
  5. $query .= ... // doklejasz listę pól do zapytania
  6. } else {
  7. $query .= "* ";
  8. }
  9.  
  10. $query .= "FROM " . $this->tableName . ' ';
  11.  
  12. if(!is_null($cond)) {
  13. $query .= ... // doklejasz $cond
  14. }
  15.  
  16. // ...sprawdzasz resztę zmiennych i ewentualnie doklejasz
  17.  
  18. return $this->db->query($query);
  19. }


Użycie:

  1.  
  2. getMany('*', null, 5, "date DESC");
  3. getMany('*', "delete = 1");
  4. getMany('*', "publish < " . time());
  5. getMany('*', 'visible = 1');


Do prostych zastosowań wystarczy, do bardziej zaawansowanych zainteresowałbym się Doctrine 2, zamiast pisał coś swojego smile.gif
Pyton_000
Zrób sobie metodę np. whereBuilder z parametrami który buduje WHERE, potem w get... doklejasz to co zostało wygenerowane
Turson
Cytat(Pyton_000 @ 19.02.2014, 23:29:40 ) *
Zrób sobie metodę np. whereBuilder z parametrami który buduje WHERE, potem w get... doklejasz to co zostało wygenerowane

A czy nie napisałem tego samego?
Evinek
Czyli ogólnie nic nowego czego bym nie wiedział. Myślałem nad tym, ale jakoś źle mi to wygląda. Nie wiem czy ktoś zauważył, ale używam bindowania więc wasze przykłady mi się nie przydadzą.
A kod w stylu:
  1. $where = array('delete = :delete', 'visible = :visible', 'publish > :publish');
  2. $data = array('delete' => $_POST['delete'], 'visible' => $_POST['visible'], 'publish' => time());
  3. $model->getMany($where, $data, 5); // $model->getMany(where, dane_do_bindowania, limit);

wydaje mi się zbyt mocno przesadzony.
Miałem i nadal mam nadzieje na inny sposób na to.
vonski
To może napisz chociaż jak byś chciał żeby to wyglądało. Bo "innych sposobów na to" istnieje mnóstwo, tylko ciężko wyczuć jaki Tobie się będzie podobał. Możesz np. napisać klasę, powiedzmy Query i użyć jej mniej więcej w ten sposób:

  1. $query = new Query('news');
  2. $query->fields('title, created_at')
  3. ->where('delete', array('eq' => '1'))
  4. ->where('visible', array('eq' => '1'), 'and')
  5. ->where('publish', array('eq' > time()), 'and')
  6. ->limit(10)
  7. ->orderBy('title');
  8. $query->build();


I powiedzmy, że build() zbuduje takie zapytanie: "SELECT title, created_at FROM news WHERE delete = :delete AND visible = :visible AND publish > :publish ORDER BY title ASC LIMIT 10".
Możesz potem ten obiekt $query przekazać do metody query() z Twojej klasy Database i niech już ona sobie z nim radzi - wszystkie informacje - czyli samo zapytanie jak i parametry do zbindowania - tam siedzą.
To jest jeden z wielu sposobów.. ale też może Ci się wydać mocno przesadzony... Możesz też użyć już wspomnianego Doctrine - integruje się szalenie łatwo, za pomocą composera smile.gif
memory
chyba za bardzo chcesz dobrze
vonski
chyba nie rozumiem smile.gif
memory
pisałem do Evinek smile.gif
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.