Итак, я прочитал некоторые уже существующие вопросы (например, this и this), а также я читаю книгу, но я все еще не могу решить. Извините за длинный пост, я разместил здесь достойное количество кода.Еще один проект php MVC
Работа по созданию маршрутизации, созданию контроллера и действиям прямо сейчас. До этого момента я только что прочитал простой текст в действии контроллера, чтобы узнать, работает ли он.
После этого я представил простой вид класс с функцией визуализации(), который возвращает «визуализируемый» HTML код:
public function render()
{
if (!isset($this->file)) {
return "";
}
if (!empty($this->data)) {
extract($this->data);
}
// dirty-hack: use output buffering so we can easily check if a file can be included
// if not, simply reject the output and throw an exception (let the caller handle it)
// if the inclusion was successfull then return with the buffered content
ob_start();
if (!include($this->file)) {
ob_end_clean();
throw new \Exception("View file \"{$this->file}\" not found");
}
return ob_get_clean();
}
Класса контроллера также есть рендер() и защищенная setView () функции
public function render()
{
if (isset($this->renderView)) {
echo $this->renderView->render();
}
}
protected function setView($view)
{
if (!is_object($view) || !($view instanceof View)) {
throw new \Exception("The \"view\" parameter have to be a View instance");
}
$this->renderView = $view;
}
пример, контроллер с примера действия:
public function viewHome()
{
$contentView = new Framework\View("HomeView.php");
// fill contentView with variables, using $contentView->setData("name", value)
$this->generateView($contentView);
}
protected function generateView($contentView)
{
if (!is_object($contentView) || !($contentView instanceof Framework\View)) {
throw new \Exception("Invalid \"contentView\" parameter");
}
$layout = new Framework\View("MainLayout.php");
$layout->setData("content", $contentView->render());
$this->setView($layout);
}
Фактически, действие контроллера присваивает данные представлению (Редактировать: На самом деле это не представление, больше похожее на шаблон, но это мое соглашение об именах), и представление просто использует данные. Это может быть «отменено», поэтому я мог бы создавать подклассы вида, которые получат ссылку на контроллер и используют контроллер для получения/установки данных в/из презентации. По какой-то причине я придерживаюсь первого (текущего) решения, но я могу изменить свое мнение. :)
Соответствующий тест MainLayout.php файл следующие
<div style="margin-left: auto; margin-right: auto; padding: 5px; width: 800px; border: 3px solid green;">
Main header <br />
<br />
Content: <br />
<?php
if (!isset($content)) {
die("The \"content\" variable is not available");
}
echo $content;
?>
</div>
Обратите внимание, что коды, которые я отправил служить целям тестирования, вещи могут быть различными в дальнейшем. Однако моя настоящая проблема связана с модельным слоем. Я читал два разных подхода к шаблону MVC:
Первое говорит, что модель является «глупым» слоем, простым представлением данных памяти/объекта. Реальная работа (так что доступ DAO, запросы, бизнес-логика) находится в контроллере.
Другой говорит, что контроллеры являются «глупыми» вещами, они всего лишь клей между моделью и представлением, работа выполнена моделью. Второй, кажется, проще, и он больше подходит для моего нынешнего дизайна. Как вы думаете, какой из них является предпочтительным?
И еще один: допустим, я выбрал второй подход (описанный выше), поэтому у меня есть класс модели, например. Пользователь. Этот класс имеет разные (статические) функции для запроса вещей, такие как «получить всех пользователей», «добавить нового пользователя» и т. Д. Однако я не хочу подключать модель к базе данных так сильно. Моя первая идея состоит в том, что я должен создать (по крайней мере) 3-х классов для одной модели:
- абстрактный класс/интерфейс, который определяет «модель» сама
- по крайней мере один подкласс (реализация) для каждого тип доступа к данным
- и завод для модели, которая создает подходящий класс. Если нам нужна макетная модель для тестирования, она вернет экземпляр UserMock вместо экземпляра UserDB.
У вас есть идеи?
Edit:
На основании принятого ответа, я решил использовать дизайн сервиса. Вот простой (образец) Класс:
abstract class UserService
{
private static $instance;
public static function setInstance($instance)
{
if (!is_object($instance) || !($instance instanceof UserService)) {
throw new \Exception("Invalid \"instance\" parameter");
}
self::$instance = $instance;
}
public static function get()
{
if (!isset(self::$instance)) {
throw new \Exception("Instance is not set");
}
return self::$instance;
}
public abstract function findAll();
public abstract function findById($id);
public function add($user)
{
if (!is_object($user) || !($user instanceof User)) {
throw new \Exception("Invalid \"user\" parameter");
}
$id = $this->addAndReturnId($user);
$user->setId($id);
}
protected abstract function addAndReturnId($user);
}
Таким образом я могу зарегистрировать реализацию сервиса (который использует базу данных или просто заполнен тестовые данные). Однако для каждой службы я должен скопировать-вставить код set/get. Я мог бы использовать базовый класс для этого, но проверка «instanceof» отличается для каждого подкласса.
Я знаю, что это немного не по теме, но есть ли у вас хорошая идея для этого? Или мне нужно скопировать-вставить две функции для каждой службы?
TL; DR. Является ли это более применимым к http://codereview.stackexchange.com/? –
@ JonStirling тоже может быть, но я не спрашиваю о размещенном коде, я спрашиваю о еще не реализованном коде. Я просто хотел показать, что (я думаю) у меня есть основная идея, и некоторые вещи работают, извините, если это вводит в заблуждение. – csisy