Передача данных из MVC-контроллера для просмотра в PHP
У меня есть собственная ручная фреймворк PHP MVC для некоторых проектов, над которыми я работаю. Когда я впервые создал фреймворк, это было в контексте создания админ-CMS. Поэтому между моделью, представлением и контроллером была очень приятная взаимно-однозначная взаимосвязь. У вас есть одна строка в БД, которая сопоставляется с одной моделью. Контроллер загружает модель и передает ее в визуализируемое представление (например, в форму редактирования). Хороший, чистый и легкий.
Однако теперь, когда я работаю над интерфейсом сайта, все становится липким. Страница не всегда представляет собой представление об одной модели. Это может быть список каталогов пользователей с 20 пользователями (каждая из моделей пользователей). Кроме того, могут быть метаданные о запросе, такие как разбиение на страницы (текущая страница, общие страницы, количество результатов) и/или поисковый запрос.
Мой вопрос: какой самый чистый способ передать все эти данные в представление?
Некоторые параметры, которые я рассматриваю:
-
Попросите контроллер создать массив и передать его в виде одного параметра:
class UserController{
public function renderView(){
// assume there some logic to create models, get pagination, etc.
$data = array()
$data['models'] = $models;
$data['currentPage'] = $current;
$data['totalPages'] = $total;
return $view->render($data);
}
}
class UserView{
public function render($data){
// render the data
}
}
-
Создайте свойства в классе представления и запишите их в контроллер:
class UserView{
public $models;
public $currentPage;
public $totalPages;
}
class UserController{
public function renderView(){
// assume there some logic to create models, get pagination, etc.
$view = new UserView();
$view->models = $models;
$view->currentPage = $current;
$view->totalPages = $total;
return $view->render();
}
}
-
Дайте представлению какой-то общий объект HashMap или Collection как контейнер, который может содержать произвольное число и имя данных.
class UserView{
public $collection = new Collection(); // works like a Java collection
}
class UserController{
public function renderView(){
// assume there some logic to create models, get pagination, etc.
$view = new UserView();
$view->collection->add($models,'models');
$view->collection->add($currentPage,'currentPage');
return $view->render();
}
}
Я знаю, что технически любой из них мог бы работать, но я не уверен в лучшем выборе, или если есть лучший или более обычный выбор, который мне не хватает.
Ответы
Ответ 1
Я порекомендую концепцию Fat Models, Skinny Controllers (или Тонкие контроллеры толстых моделей, если вы предпочитаете...)
В других словах ваша модель слишком строгая: привязка вашей модели к представлению только чего-то вроде RowDataGateway крайне ограничена.
На самом деле, я думаю, хорошие модели скрывают тот факт, что вы вообще читаете данные из базы данных. Потому что на самом деле ваши данные могут быть в текстовых файлах или из веб-службы или что-то еще. Если вы относитесь к своей модели как к прославленному DBAL, вы обрекаете себя на то, чтобы иметь жестко связанный код в ваших контроллерах, который просто не позволит вам оторваться от "мышления" только из базы данных.
Ответ 2
Я видел оба из первых двух методов, реализованных в популярных структурах MVC/templating.
django использует первый метод, переходя к просмотру словаря переменных, которые вид используется для заполнения шаблона.
smarty использует второй метод, создавая объект Smarty и присваивая значения каждому из свойств в контейнере.
Ваш третий метод, по-видимому, будет таким же, как второй, с незначительными различиями в архитектуре.
На самом деле, я думаю, я не сказал ничего, о чем вы уже не думали. В принципе, это все звуковые идеи, поэтому реализуйте все, что вы считаете наиболее комфортным.
Ответ 3
В том, что я использую, у него автоматически есть свойство вида в контроллере, которое позволяет получить доступ к методам и свойствам в представлении. Все общедоступные свойства затем доступны в представлении вида '$ this', так как представление визуализируется в контексте его собственных объектов.
В контроллере:
$this->view->myVar = 'test';
И в представлении:
$this->myVar; // 'test'
То же самое касается макета, так как оба экземпляра одного и того же объекта просмотра:
$this->layout->myVar = 'test';
И затем в макете:
$this->myVar; // 'test'
Рамка была собственностью, но должна быть выпущена для широкой публики. Я был бы рад выслать вам код, если вы думаете, что это поможет. Помните, что самый простой ответ - лучший ответ.