Pull to refresh

Comments 29

на сколько я понял — для того, чтобы добавить в шаблон еще один компонент (модуль, объект) — необходимо править код?
Это не очень удобно по двум причинам:
1 — ну собственно при изменении шаблона нужно лезть в код
2 — если вы хотите, чтобы можно было использовать одновременно несколько шаблонов сайта (например, обычный вид и версия для печати, ну или мобильная версия) — в некоторых шаблонах не понадобится одни модули, в других — другие — не понятно, как это реализовать в вашей модели.
Эта проблема решается конфигом, на основе которого создается нужное представление. А для правки такого конфига можно сделать визуальный редактор для обычного пользователя.
Если все-таки создать класс для простого отображения переменной, то можно избежать использование лишнего массива и метода… К тому же в такой класс можно добавить escape и другие функции для чистки вывода.
$page->fillings['title'] = new VariableView('greating');
Очень полезное замечание, спасибо.
У вас в коде по крайней мере одна очень большая проблема:

fillings не типизируются — код не может гарантировать, что в этом массиве будут объекты, реализующие метод draw. Вам нужно сделать fillings защищенным или приватным свойством и реализовать метод add для добавления View с указанием типа агрумента. Не очень хочется давать ссылку на википедию, но всё же посмотрите.

Думаю, вам нужно что-то вроде этого, если я не ошибаюсь, конечно ;):

abstract class AbstractView {

	/**
	 * @var AbstractView[]
	 */
	protected $views = array();

	abstract function draw();

	/**
	 * @param string $key
	 * @param AbstractView $view
	 */
	public function addView($key, AbstractView $view) {
		$this->views[(string)$key] = $view;
	}

	/**
	 * Рендерит отображение
	 *
	 * @param string $key
	 *
	 * @return string
	 * @throws InvalidArgumentException
	 */
	final public function render($key) {
		$key = (string)$key;
		if (!isset($this->views[$key]))
			throw new InvalidArgumentException('Представление по ключу '.$key.' не найдено');

		ob_start();
		$this->views[$key]->draw();
		return ob_get_clean();
	}
}

class LayoutView extends AbstractView {
	function draw() {
		/* ваш код */
	}
}

class SubView extends AbstractView {
	function draw() {
		/* ваш код */
	}
}

$view = new LayoutView();

$subView = new SubView();

$view->addView('content', $subView);

echo $view->render('content');
Да, вторая не очень хорошая на мой взгляд вещь:

if(isset($this->fillings[$filling_name])){
            $this->fillings[$filling_name]->draw();
}


А что будет, если вы случайно опечатались, вводя имя ключа? Правильно — ничего. Возможно вы или что-то еще будете долго дебажить код в поисках того, почему ваша программа не печатает вьюшку. Игнорирование ошибок — плохая практика.

К сожалению комментарий не поправить — пропустил модификаторы доступа к методам draw в наследниках.
Лучше выкладывать не код, а ссылку на код на пастбине или другом подобном сайте.
Вообще да, код длинноват — думал об этом. Но тут палка о двух концах. ;) Бывает в старый пост войдешь, а в комментах битые, а там-то суть коммента была. Вот так. Вот научился бы хабр хабракат в комментах ставить — было бы очень кстати.
Спойлер
<spoiler title="Заголовок">Содержимое</spoiler>
Вставка спойлера (разворачиваемый блок информации)
Спасибо. Да извиняюсь — не заметил в списке тегов, хотя честно искал.
Не так давно появился и как-то незаметно.
С замечанием относительно типовой небезопасности моего кода согласен. Не думаю, что стоит кидать исключение при отсутствии какого-либо объекта (нет — и не надо). То лично мне и удобно, что можно разметить фрагмент html кода в методе draw(), указав, где- что находится, а потом уже реализовывать постепенно эти днтали. Хотя это дело вкуса на мой взгляд.
Не понял вас:
echo $view->render('content');
Может вы имели ввиду:
echo $view->draw();?
echo $view->render('content'); это уже непосредственно вставка html — аналог вашего insert
Мне кажется вы не совсем меня поняли.
Вызов меня поняли: html-код выводится только в методе draw путем инклуда файла .phtml, который по сути является шаблоном, включающем вызовы метода insert('view_name'), который вызывает метод draw() для объекта типа AbstractView, содержащегося в масиве $fillings под ключем 'value name'.
извиняюсь за опечатку
Я все так и понял. Видимо вас смутило $view. echo $this->render('content'); пойдет?
Так, а у самого $view(который экземпляр LayoutView) draw() не вызовется же? или я что то не понял?
Я вас не совсем понял. Если вы про это:

$view = new LayoutView();
$subView = new SubView();
$view->addView('content', $subView);
echo $view->render('content');


то это просто для примера вызова было дано.
Идея неплохая, но реализация слабовата. Здесь можно абстрагироваться полностью и ввести стандартное дерево HTML:

  • Root
    • Head
      • Link
      • Meta
  • Body
    • myheader
      • my menu
    • mycontent


  • Есть какая-то стандартная реализация элементов Root, Head, Body, которая слабо зависит от какой-то конкретной темы. В узел Head можно легко добавлять необходимые элементы, как и в любой другой. Элементы my* являются уже специфичными, но из них вполне можно выделить часто встречающиеся типы (такие как меню, заголовок, хлебные крошки), функционал которых можно вынести в отдельный класс, а представление — в конкретный, зависящий от каких-то условий.

    Самое интересное, что такую систему можно реализовать на основе паттерна Абстрактная фабрика и вообще абстрагироваться от HTML. Тогда можно будет легко перевести сайт с отображения на HTML5 в отображение XML.
Немного не в тему. Но я сделал проще используя шаблонизатор blitz унаследовался от него, создал метод call в итоге в любом месте на страничке я могу сделать {{ call('Class','method')}} ну и собственно все. Отдельный «пакет» Widgets реализует необходимый вывод в необходимых местах =) удобно и не надо заморачиваться с layouts. Впрочем у меня есть генератор страниц Page который выводит основной контент по умолчанию. За счет такой гибкости я могу быстро на разных страницах выводить разные виджеты, все что нужно сделать новый шаблон страницы и подключить его на этапе формирования View-а страницы.

Как-то так =)
Кстати эта идея у меня крутилась в голове, но в таком формате:
Есть результат выполнения затребованного пользователем действия Controller->action(), он вставляется в определенное место в шаблоне. Но в любой шабло, не важно, к какому классу View, он относится, можно вставлять виджеты, представленные вызовом метода какого либо класса виджетов. Это действительно удобно. Например я всегда хочу видеть справа чат. Вместо того, чтобы постоянно подключать его в layout, я могу вызывать метод класса виджета. Для этого надо описать еще один класс, методы которого, этим вызовом и будут заниматься. И в этом классе регистрировать список всех доступных виджетов. Назовем его WidgetMaster. Тогда в .phtml-шаблонах вставлять для виджетов, например метод WidgetMaster->call('name'). Но допустим, некоторые виджеты должны иметь средства для управления ими… было бы глупо перезагружать страницу из-за виджета. Это можно организовать через Ajax несложно и не нарушая архитектуры приложения. Ничего из этого еще не реализовывал, но могу написать отдельный топик, посвещенный этой теме, когда реализую.
Хочу понять вот что. Получается, что у вас в MVC появляется четвертый компонент?

Ну, то есть, теперь вид — не просто шаблон, а класс, который собирает HTML из шаблонов, так?

То есть, стандартным образом воспользоваться таким решением из MVC фреймверков не получится, точнее нужно будет заменить механизм видов на ваш механизм, правильно понимаю?

То есть, если например в CodeIgniter мы пишем что-то в стиле

$this->load->view('blogview', $data);

то тут эта конструкция будет заключена где-то в глубинах вашего объекта вида. Правильно?

Во многих фреймворках View — это класс. В зенде, например, вью вызывается в dispatch цикле после отработки контроллера. Цикл обработки zend. Это довольно гибкое решение, можно с легкостью менять типы ответа(xml,json) просто заменив один из элементов view.
Да, вы правильно понимаете. Но у меня и не было цели интегрировать мой механизм видов в какой-либо существующий фреймворк. Это механизм видов из моего простенького фреймворка. Прошу не кричать, что самописные фреймворки никто уже не пишет. Я его пишу по филосовским соображениям, дабы глубже понять идеи существующих.
Зачем нужно промежуточное преобразование?
Sign up to leave a comment.

Articles