При попытке смоделировать ваши бизнес-объекты нужно сделать много компромиссов.
Учитывая ваш пример, я могу вспомнить несколько подходов, которые в основном вращаются вокруг ленивых комментариев. Вот как бы я это сделал, если бы был уверен, что все не станет сложнее:
Сначала вы создаете сущности для Article и Comment, которые просто представляют данные в каждой таблице в вашей базе данных. Написать сеттеры и геттеры. Реализуйте метод loadComments () в статье.
Реализация одного или нескольких классов Collection, таких как ArticleCollection. У вас может быть класс обслуживания, который выбирает статьи, которые соответствуют некоторым критериям. ArticleService :: fetchArticles () будет возвращать статьи без загруженных комментариев. Затем реализуйте метод ArticleCollection loadComments (), который загружает все комментарии для всех статей в коллекции. Сначала это может просто перебирать статьи, вызывающие loadComments, но позже вы можете заменить его реализацией с одним запросом.
Вот начало статьи и коллекции статей. Если вы реализуете класс CommentCollection, вы можете использовать его внутри Article для хранения комментариев и т. Д.
<?php
/**
* Extends a base model class that provides database-related methods -- not ideal,
* but trying to stay focused here.
*/
class Article extends Model {
private $_data;
private $_fields = array('id','title','body','author');
/**
* Constructor can take an array of values to initialize.
*/
public function __construct($data=null){
if (is_array($data)){
foreach($this->_fields as $field){
$this->_data[$field] = $data[$field];
}
}
}
public function getId(){ return $this->_data['id']; }
// more getters, and setters, here.
public function loadComments(){
$result = $this->query('SELECT * FROM Comment WHERE article_id = ' . $this->getId());
$this->_comments = array();
foreach($result as $c){
//instantiate a new comment (imagine Comment's constructor is very similar to Article's
$this->_comments[] = new Comment($c);
}
}
}
class ArticleCollection extends Model {
/**
* An array of Articles, indexed by article_id
*/
private $_articles = array();
/**
* Naive implementation. A better one would grab all article IDs from $this->_articles, and
* do a single query for comments WHERE article_id IN ($ids), then attach them to the
* right articles.
*/
public function loadComments(){
foreach($this->_articles as $a){
$a->loadComments();
}
}
/**
* Add article to collection
*/
public function addArticle(Article $article){
if (empty($article->id)) throw new \Exception('Can\'t add non-persisted articles to articlecollection!');
$this->_articles[$article->id] = $article;
}
}
Вышеприведенное довольно простое - вы можете применять другие шаблоны проектирования для разграничения доступа к базе данных, чтобы он, например, не был так тесно связан. Но я просто пытаюсь описать стратегию ленивой загрузки ваших комментариев здесь в здравом уме.
Несколько заключительных советов: не попадитесь в ловушку, которую делают многие фреймворки, и подумайте, что существует некоторая божественная корреляция между таблицами в вашей базе данных и моделями. Модели - это просто объекты. Они могут делать разные вещи (представлять простую вещь, например, комментарий или пользователя), или представлять вещи, такие как сервис, который работает с такими простыми вещами, или они могут быть такими, как группы (коллекции) этих отдельных вещей. .
Одно забавное упражнение - просто написать классы и заполнить их фиктивными данными. Постарайтесь полностью забыть, что база данных будет задействована. Создавайте объекты, которые поддерживают нужные вам варианты использования. Затем, как только вы это сделаете, выясните, как сохранить и загрузить данные в / из БД.