Предупреждение:
Информация в этих сообщениях крайне устарела .Это представляет мое понимание шаблона MVC, как это было более 2 лет назад.Это будет обновлено, когда я доберусь до этого.Вероятно, в этом месяце (2013.09).
Черт возьми!(2017,11).
Model
сам по себе не должен содержать любой SQL.Когда-либо.Предполагается, что он содержит только бизнес-логику домена.
Подход, который я бы рекомендовал, состоит в том, чтобы разделить обязанности, которые не являются строго «бизнес-логикой», на два других набора конструкций: Объекты домена и Data Mappers .
Например, если вы ведете блог, то модель не будет опубликована.Вместо этого наиболее вероятно, что модель будет Blog, и эта модель будет работать с несколькими Domain Objects
: несколькими экземплярами Post, Comment, User и, возможно, другими объектами.
В вашей модели доменные объекты не должны знать, какхранить себя в базе данных.Или даже знать о существовании любой формы хранения.Это ответственность Data Mappers
.Все, что вам нужно сделать в модели, это позвонить $mapper->store( $comment );
.И преобразователь данных должен знать, как хранить один конкретный тип объектов домена, и выиграть, в какую таблицу помещать информацию (обычно хранение одного объекта домена фактически влияет на несколько таблиц).
Некоторый код
(только соответствующие фрагменты из файлов):
- Полагаю, вы знаете, как написать хороший конструктор .. если у вас есть сомнения, прочитайте эту статью
- в примере ничего не указано в пространстве имен, но должно быть
- все, что начинается с
_
в примере: protected
от /application/bootstrap.php
/* --- snip --- */
$connection = new PDO( 'sqlite::memory:' );
$model_factory = new ModelFactory( $connection );
$controller = new SomeController( $request , $model_factory );
/* --- snip --- */
$controller->{$action}();
/* --- snip --- */
- Контроллеру не нужно знать о подключении к базе данных.
- Если вы хотите изменить подключение к БД для всего приложения, вам нужно изменить одну строку
- чтобы изменить способ создания моделей, вы создаете другой класс, который реализует тот же интерфейс, что и ModelFactory
из /framework/classes/ModelFactory.php
/* --- snip --- */
class ModelFactory implements ModelBuilderInterface
{
/* --- snip --- */
protected function _prepare()
{
if ( $this->_object_factory === null )
{
$this->_object_factory = new DomainObjectFactory;
}
if ( $this->_mapper_factory === null )
{
$this->_mapper_factory = new DataMapperFactory( $this->_connection );
}
}
public function build( $name )
{
$this->_prepare();
return new {$name}( $this->_object_mapper , $this->_data_mapper );
}
/* --- snip --- */
}
- только картографы данныхбудет использовать базу данных, подключение требуется только фабрике картографических данных
- все зависимости модели вводятся в конструктор
- каждый экземпляр DataMapper в приложении использует одно и то же соединение с БД, нет Global State (видео) требуется.
файл /application/controllers/SomeController.php
/* --- snip --- */
public function get_foobar()
{
$factory = $this->_model_factory;
$view = $this->_view;
$foo = $factory->build( 'FooModel' );
$bar = $factory->build( 'BarModel' );
$bar->set_language( $this->_request->get('lang') );
$view->bind( 'ergo' , $foo );
/* --- snip --- */
}
/* --- snip --- */
- контроллер не знает подробностей создания модели
файл /application/models/FooModel.php
/* --- snip --- */
public function find_something( $param , $filter )
{
$something = $this->_object_factory('FooBar');
$mapper = $this->_mapper_factory('FooMapper');
$something->set_type( $param );
$mapper->use_filter( $filter )->fetch( $something );
return $something;
}
/* --- snip --- */
- объект доменаотвечает за проверку заданных параметров
- представление получает и решает, как его представить
- картограф берет объект и помещает в него всю необходимую информацию из хранилища (это не обязательно БД.. это может быть взято из некоторого файла или внешнего REST API)
Я надеюсь, что это поможет вам понять разделение между логикой БД и бизнес-логикой (и фактически, логикой представления вo)
Несколько замечаний
Модель никогда не должна расширять базу данных или ORM, поскольку модель не является их подмножеством.Расширяя класс, вы объявляете, что он обладает всеми характеристиками суперкласса, но с небольшими исключениями.
class Duck extends Bird{}
class ForestDuck extends Duck{}
// this is ok
class Table extends Database{}
class Person extends Table{}
// this is kinda stupid and a bit insulting
Помимо очевидных логических проблем, если ваша Модель тесно связана с лежащей в основе базой данных, она делаетКод чрезвычайно сложно протестировать (речь идет о Unit Testing (видео) ).
Лично я считаю, что ORM бесполезны, а в больших проектах - даже вредны.Проблема связана с тем, что ORM пытаются соединить два совершенно разных способа решения проблем: ООП и SQL.
Если вы начнете проект с ORM, то после короткого периода обучения вы сможете очень быстро писать простые запросы. Но к тому времени, когда вы начинаете сталкиваться с ограничениями и проблемами ORM, вы уже полностью инвестируете в использование ORM (может быть, даже были наняты новые люди, которые действительно хорошо разбирались в вашем избранном, но были поглощены простым SQL ). Вы попадаете в ситуацию, когда каждая проблема, связанная с БД, занимает все больше и больше времени. А если вы использовали ORM на основе шаблона ActiveRecord, то проблемы напрямую влияют на ваши модели.
Дядя Боб называет это "техническим долгом".
Несколько книг
слабо связанный с предметом