Правильно вызывать базу данных из модели в приложении MVC?

Я строю крошечную структуру MVC для обучения / экспериментирования и небольших проектов. Мне нужно было выяснить основы внутренних компонентов Модели, так как полная структура MVC и ORM переполняют всего несколько запросов к базе данных.

Class Model { } 

Использование пустого класса, где я должен был бы вызвать new PDO объект new PDO для вызовов базы данных?

Что вызовет запрос, как внутри модели?

Кроме того, где я могу найти ресурс для начинающих / книжный ресурс для MVC (с большим количеством примеров кода)? Я слышал много терминов, таких как бизнес-логика и логика базы данных. Я помню, где-то читал, что вы должны отделить бизнес-логику и логику базы данных. Я могу понять концепцию несколько, мне просто интересно, как это выглядит или что они означают в самом коде. Я смущен тем, что логика бизнес-логики и логика базы данных должны быть разделены, но все еще находиться внутри модели.

В основном я ищу примеры кода / логики в качестве ответов, кроме, может быть, последнего абзаца.

Solutions Collecting From Web of "Правильно вызывать базу данных из модели в приложении MVC?"

Предупреждение:
Информация на этих постах крайне устарела . Он представляет мое понимание шаблона MVC, как это было более двух лет назад. Он будет обновляться, когда я подхожу к нему. Вероятно, в этом месяце (2013.09).

Черт возьми! (2017,11).

Сама Model не должна содержать SQL. Когда-либо. Он предназначен только для бизнес-логики домена.

Подход, который я бы рекомендовал, состоит в том, чтобы отделить обязанности, которые не являются строго «бизнес-логикой», на два других других набора конструктов: объекты домена и карты данных .

Например, если вы делаете блог, то модель не будет Post. Вместо этого, скорее всего, модель будет 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 в приложении использует одно и то же соединение с БД, не требуется Глобальное состояние (видео) .

файл /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 --- */ 
  • объект домена отвечает за проверку данных параметров
  • просмотр принимает и решает, как его представить
  • mapper берет объект и помещает в него всю необходимую информацию из хранилища (он не должен быть DB .. он может быть взят из некоторого файла или внешнего REST API)

Надеюсь, это поможет вам понять разницу между логикой БД и бизнес-логикой (и на самом деле, логикой представления тоже)


Несколько заметок

Модель никогда не должна расширять базу данных или 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 

Помимо очевидных логических проблем, если ваша модель тесно связана с базой данных, она делает код чрезвычайно трудным для тестирования (речь идет об тестировании устройств (видео) ).


Я лично считаю, что ОРМ бесполезны и в большом проекте – даже вредны. Проблема связана с тем, что ORM пытаются объединить два совершенно разных способа решения проблем: ООП и SQL.

Если вы начинаете проект с ORM, тогда, после короткой кривой обучения, вы можете быстро писать простые запросы. Но к тому времени, когда вы начнете сталкиваться с ограничениями и проблемами ORM, вы уже полностью инвестировали в использование ORM (возможно, даже новые люди были наняты, которые были действительно хороши в выбранном вами, но были втянуты в простой SQL). Вы попадаете в ситуацию, когда каждый новый вопрос, связанный с БД, занимает все больше времени для решения. И если вы используете ORM на основе шаблона ActiveRecord, то проблемы напрямую влияют на ваши модели.

Дядя Боб называет этот «технический долг».


Немногие книги

слабо связан с субъектом

  • Шаблоны архитектуры корпоративных приложений
  • Разработка, принципы, шаблоны и практика Agile Software
  • Ошибки SQL: устранение ошибок программирования баз данных
  • PHP-объектно-ориентированные решения
  • PHP в действии

По моему опыту различные структуры интерпретируют MVC несколько свободно и обычно с некоторыми отклонениями. Однако они обычно соглашаются, что MVC делится следующим образом:

  • Модель – Бизнес-логика + Хранение данных / ретрансляция / структурирование
  • Просмотр – представление данных
  • Контроллер – методы вызова по модели после анализа запроса

Я много использую Symfony и могу дать вам пару небольших примеров. Имейте в виду, что они чрезвычайно упрощены. :п

Модель:

 class MyUnitTable extends Doctrine_Table { // .. various other pieces of code added by Symfony ... // public function getForAccount( Account $_account ) { $q = $this ->createQuery('e') ->leftJoin('e.User u') ->leftJoin('u.Profile p') ->leftJoin('p.Account a') ->where('a.accountid = ?', $_account->getAccountid()); return $q->execute(); } } class myUnitActions extends sfActions { public function executeIndex(sfWebRequest $request) { $this->units = Doctrine_Core::getTable('MyUnit')->getForAccount($foo); } } 

Вид (просто показывая фрагмент):

 <div id="my-unit-list-container"> <ul> <?php foreach( $units as $unit ): ?> <li><?php echo $unit->getName(); ?></li> <?php endforeach; ?> </ul> </div> 

Контроллер:

Контроллер – это место, где обрабатывается запрос. Он проанализирует запрос и выяснит, какое действие (например, myUnitActions :: executeIndex () сверху) в модели, которая должна быть вызвана.

Последние примечания:

Я уверен, что вы можете видеть, что происходит в коде выше (много удобностей добавляется ORM). У вас есть диспетчер, отправляющий запрос модели, модель, работающая с вашей проблемной областью, и фактическое извлечение данных из базы данных и, наконец, представление, отображающее данные.

Это имеет много преимуществ для вас как разработчика, поскольку это позволяет, среди прочего, упростить и повысить надежность тестирования.

Превосходный читаемый для вас будет 21-й день с руководством Jobeet от людей, стоящих за Symfony. Это хорошая работа.

Вы также должны взглянуть на код как для Symfony, так и для Zend . Они оба превосходны. Также взгляните на пару ORM, таких как Doctrine и Propel .

Также см. Статью Википедии о MVC .

Вы могли бы взглянуть на подход модели карты данных, на который ссылается руководство по модели системы Zend

Затем у вас есть модель, содержащая свойства, и у нее есть сопоставитель, который выполняет фактическое взаимодействие с базой данных для заполнения модели.

Очевидно, что вы не хотите создавать новое соединение каждый раз при создании новой модели, поэтому вы хотите инициализировать объект PDO отдельно. (Я когда-то сталкивался с внутренней структурой MVC, когда модель расширила свой класс базы данных. Как вы можете себе представить, это было не быстро …)

Может, что-то подобное вам нужно?

 abstract class Model { protected $db = NULL; public function __construct (PDO $db) { $this -> db = $db; } } 

Пример использования

 class Article extends Model { public $props = array (); private function getPage ($id) { $q = $this -> db -> prepare ('select * from pages where pageId = :pageId'); $q -> execute (array ('pageId' => $id)); $ret = $res -> fetchAll (); return ($this -> props = $ret); } } $db = new PDO ('dsn goes here'); $page = new Article ($db); $page -> getPage (1234); 

Что касается поиска примеров? Попробуйте googling для «php mvc» и посмотрите на статьи, которые появляются