компонентный подход, мвс и шаблоны

Духовность™

Продвинутый новичок
компонентный подход, мвс и шаблоны

Всётаки я решил так-нибудь начать пропробовать писать на основе компонентного подхода (http://dklab.ru/chicken/nablas/16.html, 4 параграф). Т.е. основная идеология - шаблон вызывает контроллер, шаблон первичен. Причиной такого решения стала либо моя некомпитенция, а именно - отсутствие понимания того, как сделать контроллер независимым от внешнего вида конечной страницы. Т.е. грубо говоря, на одной странице может быть сколь угодно много разных блоков данных и процесс получения этих данных невольно приходится организовывать в основном контроллере, что лишает контроллера универсальности. Об этом яуже спрашивал, но ответы уважаемой публики меня так и не просветили.

Вот что я надумал: При запросе /news.html (запрос идёт конечно же не напрямую в news.html, а перенаправляется в index.php) инстанцируется View - класс-"шаблонизатор"-обертка. View инклюдит шаблон, в котором и инстанцируются все необходимые классы контроллеров, которые в свою очередь обращаются к моделям. Цепочка последовательностей примерно такая:

Код:
Запрос: View [обращение к>>> Controller [обращение к>>> Model
Ответ:  View <<<отдает результат] Controller <<<отдает результат] Model
Как это возможно будет выглядеть на практике: активный шаблон news.html содержит примерно следующее:

PHP:
<html>
<body ....>
<?
// контроллер новостей
$nc = new News_Controller();
$nc->run('view_news'); // вызвали какой-то метод контроллера новостей
$this->addData($nc->getData()); // добавляем во внутренне представление данные, 
// сгенерированные контрллером News_Controller

// альтернативный вариант использования хелпера:
$this->addData( helper('News_Controller', 'view_news', $params=array()) );
?> 
<!-- тут выводим новость -->

<? foreach($this->news_data as $news): ?>
   <p><?=$news['content']?></p>
<? endforeach; ?>

<br><br><br><br>

<?
// контроллер чего-то ещё....
$oc = new Other_Controller();
$oc->run('other_action'); // вызвали какой-то метод контроллера новостей
$this->addData($oc->getData()); // добавляем во внутренне представление данные, 
// сгенерированные контрллером Other_Controller
?> 

<h1><?=$this->other_controller_data?></h1>

</html>
После инстанцирования View, данный шаблон инклюдится в класс view и включается буферизация вывода, что бы была возможность отправлят заголовки, кидать исключения и т.д.

Чего думаете?
 

findnext

Новичок
не знаю что и ответить. У тебя прямо в шаблоне идёт создание контроллера а не объекта новостей. Я бы разделил эту логику на 2 части.
PHP:
Class Index_Controller Extends Base_Controller{

  private function DoViewLogic($name = false){ 
     template::show($name); 
  }

  private function BusinessLogicController($name = false){
    $function_name    = 'Business_'.$name;
    if (method_exists(__CLASS__, $function_name)) call_user_func(array(__CLASS__, $function_name), $name);
  }

 public function News(){
   $this->BusinessLogicController('news');
   $this->DoViewLogic('news');
 }

 private function Business_news() {
    $this->news_data  = $this->content->get('news')->SelectWhateverYouWant($array);
  }

}
--и вот собственно шаблое news
<? foreach($this->news_data as $news): ?>
<p><?=$news['content']?></p>
<? endforeach; ?>
 

Духовность™

Продвинутый новичок
А где тут компонентный подход?

Я так понимаю что Index_Controller::News() как раз возвращает/показывает сгенерированный шаблон, а надо нароборот - что бы шаблон получал данные. Мы же натыкаемся на то, что пишем контроллеры под конкретный шаблон/страницу, а я хочу от этого уйти. В идеале никакого IndexController не должно существовать. Должен быть только шаблон и контроллеры сущьностей (новость, статья), которые отдают в шаблон конкретные переменые (содержание новости, статьи).
 

findnext

Новичок
triumvirat
смори, я код исправил, что теперь думаешь?

-~{}~ 09.04.09 16:43:

что бы шаблон получал данные
private function Business_news() {
$this->news_data = $this->content->get('news')->Select();
$this->other_data1 = $this->content->get('blogs')->Select();
$this->other_data2 = $this->content->get('archives')->Select();

}
 

findnext

Новичок
triumvirat
посмотри я исправил

-~{}~ 09.04.09 16:59:

т.е. данные можно получить впринципе вот так в любой части системы и данные не только news но и абсолютно любые данные $this->content->get('news')->Select();

-~{}~ 09.04.09 17:03:

$nc = new News_Controller();
тут ты должен вызвать объект новостей, никак не контроллер

-~{}~ 09.04.09 17:08:

triumvirat
Class Index_Controller является абстрактным, совсем забыл сказать
 

Духовность™

Продвинутый новичок
тут ты должен вызвать объект новостей, никак не контроллер
дело в том, что в реальности вызов того или иного объекта сопровождается ЛОГИКОЙ - зависимостью от условий. Её в объект новостей засовывать зачем? она должна быть в контроллере, который и будет получать данные.
 

findnext

Новичок
по сути это генеральный контроллер, универсальность определяется методами. Всё что public вызывается напрямую. Например пользователь зашёл на page.ru/news - автоматов вызывается $this->News() а до этого всё это дело проходит чере класс router где разбивается URL и определяется какую часть контроллера вызвать

-~{}~ 09.04.09 17:18:

triumvirat
я её не засовыввю в объект новостей. Объект новостей должен всего лишь содержать методы получения новостей из базы данных, формирование. Никакой особой логики там нет. Все эти данные должны обрабатываться в контроллере
 

iceman

говнокодер
PHP:
<html>
<head></head>
<body>
<table>
<tr>
  <td>{other::tags}</td>
  <td>{news::last_news}</td>
</tr>
</table>
</body>
</html>
вставки {...} - это так сказать мои компоненты
и сделал такой "стиль" для того чтобы не писать include, мне казалось, что так будет удобнее...

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

сам компонент, например news/last_news.php

имел такой вид:
PHP:
require_once 'Zend/View.php';

$userProfile = Shef_Registry::getInstance('userProfile');

$authView = new Zend_View();
$authView->userProfile = $userProfile;
$authView->strictVars(TRUE);
$authView->setScriptPath(PATH_VIEW);

if($userProfile->isAuth){
    echo $authView->render('groupware/auth_success.tpl');
} else {
    echo $authView->render('groupware/auth_form.tpl');
}
из выше приведенного кода видно, что все таки в нем опять же использовались шаблоны...

входе дальнейшего написания системы, понял что вставки {...} - неудобная вещь... )

даже вышеприведенный код, можно отнести к контроллеру...

но все таки можно убрать "шаблонную" часть, и сделать так чтобы компонент отдавал массив, который использовать как нужно уже в самом шаблоне "верхнего уровня" и опять же вставлять вверху шаблона вставки
PHP:
<?php include 'news/last_news.php'; ?>
p.s. история одного извращенца... +)
 

AmdY

Пью пиво
Команда форума
triumvirat
мне нравится в каком ты направлении двигаешься.
только у тебя много хрени в шаблоне получается
делай так
<!-- создаёт массив с новостями $this->news_data -->
$this->forward('news/controller/view/');
<? foreach($this->news_data as $news): ?>

либо $this->forward('news/controller/view/toVar/news_data/');
<? foreach($this->news_data as $news): ?>

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

-~{}~ 09.04.09 20:34:

посмотри фреймворк zerkms - mzz.ru
 

pilot911

Новичок
насколько же это криво... сплошная ручная писанина под каждую страницу

все-таки идея моей цмски отлично решает эту проблему
 

Alexandre

PHPПенсионер
подход "активные шаблоны" - очень спорный
чем?
по этому поводу много противоречивых суждений
одно из последних детищ, которые мне приходилось рефакторить - использовало активные шаблоны. Очень долго въезжал в архитектуру...Очень много магии...

Есть общепринятая архитектура:Контроллер-Модель-Представление
Не нужно мешать мух с котлетами...если есть Представление - то оно и должно отвеать за логику представления, а не брать на себя еще и функции контроллера
 

Духовность™

Продвинутый новичок
Alexandre
Есть общепринятая архитектура:Контроллер-Модель-Представление
Не нужно мешать мух с котлетами...
а где в компонентном подходе смешение? Парадигме MVC это не противоречит, ИМХО - мы же не мешаем логику и вид. Мы просто даем право виду вызывать контроллеры.


AmdY
но большая проблема в том, что есть контроллеры которые не только выплёвывают данные, но и выполняют логику, влияющую на остальные модули. допустим конторллер формы входа, голосование и т.д.
да, об этом я ещё не думал. Есть какие идеи? :)
 

AmdY

Пью пиво
Команда форума
Alexandre
вот я и говорю, что документирование становится сверхважной задачой. меня этому самого недавно надоумили. как же хорошо работать в команде.

triumvirat
основная запарка в разработке диспетчиризации, тебе приходит основной запрос, ты его сохраняешь, дальше выполняются пре акшин, здесь впринципе могут уже начать вызываться другие контроллеры, затем основной экшин, который может вообще нихрена не делать, кроме как вызывать шаблон, в шаблоне так же вызываются контроллеры, для каждого контроллера свой объект Request, только с _учётом основного_ запроса, вдруг понадобится значение пэйджинга или узнать какой пункт менб выбран.
ах, ещё советую создать в шаблонизаторе метод селект для выборки из БД.
<? foreach( $this->select()->from('News')->method('getNewsFromCategory')->fetchArray($this->category_id) AS $news) : ?>

зато в плане кеширования тебя ждёт рай, так как сейчас у тебя извлечение данных и их рендеринг в одной точке и ты можешь кешировать сразу всё. очень удобно использовать клас Hrakk-а, он когда-то его вылаживал, т.к. в нём есть методы для работы с переменными и выводом, а не разнесено как в Zend_Cache, который я использую.
 

rotoZOOM

ACM maniac
Полностью поддерживаю Alexandre. Считаю, что все данные для шаблона должны быть подготовлены контроллером ДО вызова шаблона. Почему бы не сделать мастер контроллер (для каждого типа страницы, тот же newsMasterController), который в свою очередь знает какие именно secondary контроллеры необходимо инстанцировать (forecastSecondaryController, paginatorSecondaryController, тот же newsSecondaryController и т.д.). Все секондари контроллеры подготавливают необходимую информацию для вью, засовывая ее в единый dataCenter. И уже из этого dataCenter будут брать СВОИ данные вьюшки для шаблонов.
В основном же шаблоне останутся только строчки вида:
<?php echo $this->outputForecastBlock(); ?>
<?php echo $this->outputNewsBlock(); ?>
и т.д.
P.S. this - это вью, который подключает шаблон и который знает где в dataCenter лежит нужная информация.
 

pilot911

Новичок
вообще, triumvirat говорит об одном контроллере для всей системы

на его месте я бы создал конфигурационный массив для конкретных урлов, который был бы доступен диспетчеру

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

очень простой пример такого массива

PHP:
array(

	'урл для роутера, например :language/news/:year/:month/:day'	=>
			array(
					'controller_config'	=>	array(
									'controller' 	=> 'index',
									'function' 		=> 'main',
									'template' 		=> 'template/index.tpl',
					),
 					
				 	'метка_1' 	=> 	array(
									'view' 			=> 'news_list',
 									'template' 		=> 'template/news_list.tpl',
 									'limit' 		=> '2,10',
 								),
								
				 	'метка_2' 	=> 	array(
									'view' 	=> 'user_profile',
									'template' 		=> 'template/user_profile.tpl',
 								),
			
			)
)
 

atv

Новичок
А ведь в чём основная проблема? В том что многомерный мир программирования пытаются всунуть в трёхмерное измерение MVC.

И кто сказал, что контроллер должен быть универсальным? На уровне приложения ВСЕГДА будет код, специфичный для данной страницы, и только для неё. Избавиться от него НЕЛЬЗЯ, можно только тягать его туда сюда, из шаблона в контроллер и обратно, выдумывая преимущества вроде удобства дизайнеру.

И ещё один момент. Если меняется содержание или функциональность страницы, то должен привлекаться программист. Если меняется оформление страницы, то привлекается дизайнер.

Мифические истории про то, как код уволившегося программиста дизайнер заюзал сам, сэкономив заказчику пару баксов, на практике встречаются НИКОГДА.

P.S. Советую поглядывать в сторону событийно-ориентированного программирования. Такой подход позволяет оперировать в приложении столькими уровнями, сколько необходимо для обеспечения гибкости, маштабируемости и повторного использования кода, а не замыкаться на трёх уровнях MVC. С появлением удобного синтаксиса анонимных функций в PHP, событийно-ориентированный подход программирования станет ещё эффективнее.
 
Сверху