MVC и цепочка Actions

slego

Новичок
MVC и цепочка Actions

Честно изучил все треды по данной теме, но так и не увидел следующего:
итак, есть поступающий запрос

http:://site.ru/index.php?action=listUser&param1=...

который обрабатыется Request'ом на наличие ошибочных данных => далее изымается action => проверяется право юзера использовать его, и, если все в порядке, подключается необходимый класс, потомок от Action => выполняется его метод execute() => результат выполнения отдается _самому_главному_ контроллеру_ => контроллер передает управление представлению View => представление что-то там анализирует, и выплевыет html

Понятно, что это приблизительная схема. Т.е получается, что при таком подходе мы можем
обработать ну не знаю... одну модель, что ли...
В данном случае - у модели User вызываем метод listAll()... Комманда соответственно выглядит как

Код:
class ListUserAction extends Action
{
    public function execute()
    {
        ...
        $this->checkAccess();
        ...
        $user = new User()
        $this->xml .= $user->listAll();
        $this->log(...);
        ...
    }
}
А, если, допустим, надо еще обработать модель News и вызывать метод show() и еще кучу всякого?
Т.е. при одном запросе обрабатывать несколько, можно сказать, _независимых_ моделей.

Вижу два вариант - оба не нравятся :)
1. Прописывать подобную логику в каждый метод

Код:
class ListUserAction extends Action
{
    public function execute()
    {
        ...
        $this->checkAccess();
        ...
        $user = new User()
        $this->xml .= $user->list();
        $this->log(...);
        ...
        $news  = new News();
        $this->xml .= $news->show();
    }
}
беее

2. Передавать строкой запроса цепочку action's и потом их обрабатывать подряд

action1=listUser&param1=...action2=showNews...

Но это как-то тоже не по-взрослому..

Подскажите, пожалуйста, как подобное реализуете Вы?
Большое спасибо
 

kvf77

Red Devil
slego

а при каких обстоятельствах тебе может потребоваться одновременно управлять несколькими модулями?
 

slego

Новичок
Ну, банальный пример, обрабатывается основной модуль, в основной xml-поток сливаются все необходимые данные. К этим данным еще нужно добавить данные для каких-то новостей, какой-то статистики и т.д., которые будут выводиться на эту же страницу.
Ну может же такое быть? Ну, хотя бы гипотетично?

Мне интересно как правильно организовать систему для такого?
 

kvf77

Red Devil
slego
гм - URL с акшионами откуда у тебя возьмется? по идее узверь в один момент может управлять тока 1 объектом - следовательно, остальные в этот момент будут либо статичными, либо с заранее известными параметрами.
 

slego

Новичок
Ну хорошо. Пускай статичные. Ну тогда чем принципиально будут отличаться два случая:

1. Нужно показать только новости:
action=listNews
2. Нужно показать юзеров - основное действие. Сбоку показать новости, справа статистику..
Получается тут у нас будут задействованы 3 модели - cоответственно нужно вызывать 3 действия
action=listUsers ation=listNews actio=showStatistics

Получается, в первом случае действие listNews будет передаваться запросом - все внимание, так сказать, ему.
Во втором случае необходимость вызова дополнительных действий listNews и showStatistics должна быть зашита в шаблонах там или еще чем-нибудь.

не кузяво как-то... :/
 

kvf77

Red Devil
slego
то есть тебе хочется таскать все это в урле?
у тебя же по любому должна где-то храниться карта страницы - там в базе, в шаблоне, в XML - по любому без этого нельзя - так в чем проблема-то? ты не знаешь как обработать эту схему?
 

slego

Новичок
Да уже и сам не знаю. Голова кругом от этих всех паттернов, эксэмэлей и т.п. :)

Нет, таскать - ни в коем случае!
Пока есть структура хмл-файла. Для случая одного действия приблизительная схема:
Код:
	<actions>
		<action name="DoNothingAction">
			<forward commit="LoginView" action="LoginAction" view="login.xslt"/>
		</action>
	
		<action name="LoginAction">
			<forward commit="LoginSuccessView" action="..." />
			<forward rollback="LoginView" action="..."/>
		</action>

	<actions>
Может быть подскажете возможный вариант схемы для цепочки действий. Или где это лучше описать. Т.е. можно конечно придумать свое что-то, просто интересно на чужое тоже взглянуть :)
 

_RVK_

Новичок
У меня реализовано примерно так: Есть класс SuperAction (так уж назвал:)). Этот класс представляет сабой по сути маленький контроллер, и так же как и он может выполнять акшены. Но он имеет интерфейс обычного акшена, те у него есть метод exec. Например someurl/?action=display вызывает Superaction который, в свою очередь, выполняет другие акшены, например, DisplayContent, DosplayNews... и возвращает главному контроллеру либо данные модели либо уже готовый view(не суть важно) от каждого акшена.

Т.е., в случае с новостями на всех страницах, кусок повторяющегося кода, в методе exec всех объектов, SuperAction будет всего лишь:
$this->execAction(new DisplayNews(...));
 

_RVK_

Новичок
Приемущество еще и втом что в методе Superaction::exec конкретного объекта, можно задать любую логику исполнения акшенов.
 

su1d

Старожил PHPClubа
slego,
кажется, те ребята, что делают LIMB, реализовали там что-то подобное с помощью конечных автоматов.
 

BeGe

Вождь Апачей, блин (c)
Посмотри sybe.sf.net - хотя проект только начал возвращатся к жизни.... но идея акшинов уже реализована. А для общего развития и избежания писания велосипедов посмотри Apache Cocoon.
 

maxim

Новичок
У меня на каждый action (cart_view, info_id, info_id_list, ...) есть
карта страницы на которой есть набор таких конструкций Название файла совпадает с названием action.

Для примера страница со статьёй (info_id.php)

// последние 3 новости
$news = new NewsClass();
$list = $news->news_last_list(3);
... добавление $ list в основной xml страницы

//сама статья
$info = new infoClass();
$list = $info->info_content($info_id]);
... добавление $ list в основной xml страницы

и так почти для каждого action. Почти - так как есть action которые ничего не выводят(например добавление товара), а перенаправляются на другой action. В случае добавления товара это будет product_list - список товаров. Для такого перенапрвления у меня в каждом модуле есть файл parser.php,
который и переключает контроллер с одного action на другой.
 

slego

Новичок
всем большое спасибо...буду думать...до понедельника :)

-~{}~ 15.07.05 21:52:

Автор оригинала: BeGe
Посмотри sybe.sf.net
- там недвусмысленная фраза
This Project Has Not Released Any Files :(
А cocoon каких-то космических размеров... 44 метра... Это что туда насовали?

-~{}~ 15.07.05 23:39:

Так, понедельник отменяется.

Так все же, что же такое Action?
Это "мелкий" контроллер или все-таки часть бизнес-логики?

Или это что-то вроде дополнительного слоя между контроллером и моделью... хотя... получается, что и между контроллером и представлением тоже: многие используют action для визуализации, например, RenderViewAction extends Action.

2maxim Не очень понял. Т.е. у тебя для каждой страницы подключается php-файл, в котором последовательно обрабатываются нужные модели? Или еще используются какие-то конфигурационные файлы?

2_RVK_ а можешь какой-нибудь расширенный кусочичек кода привести? ;)
 

maxim

Новичок
У меня на каждый тип страницы (список новостей, подробная новость, раздел магазина, товар) есть свой action (news_list, news_id, shop_cat_id, product_id), и соответсвенно файл, который определяет какие ещё доп-е actions необходимо выполнить при поступлении в контроллер некоторого action.

Пример(упрощённый).
пусть после разбора УРЛ контроллер понял , что ему надо выполнить action news_list(выдать страницу со списком новостей).
контроллер подключает файл news_list.php (карта страницы)
выполняет action - news_list, затем action - internal_banner,
затем action - poll (голосование).
Результат всех этих action кидается в основное XML дерево страницы и затем в шаблонизатор.

Т.е. у меня на каждый action выполняется поток action'ов
 

slego

Новичок
Как в старом анекдоте про ожившего Ленина на небоскребе - именно так я себе все и представлял :)

А как насчет проверки доступа на выполнение action'а? Она (проверка) производится для каждого action'a, главного и всех вложенных или же, допустим, первый, самый главный action, проходит проверку, а доступ к остальным, вложенным, происходит автоматически?

Ну возьмем твой пример:

+-action - news_list
|
+-----action - internal_banner,
|
+---- action - poll

Допустим, на выполнение первого action'а имеет право любой пользователь, а на action=poll - только зарегистрированный.

Не возникает неоднозначностей доступа? Или все продумывается заранее?

-~{}~ 18.07.05 10:36:

Я так понял, то у тебя реализовано на подобе struts. Типа
Код:
<action name="news_list"...>
     <forward name="success" path="news_list.php">
     <forward name="failure" path="std_error.php">
</action>
?

-~{}~ 18.07.05 10:51:

вот только я как-то внутренне против такого :(

<forward name="success" path="news_list.php">

Хотелось бы что-нибудь эдакое забабахать
PHP:
<action name="doSmthAction"...>
     <success view="main.xslt">
              <subaction name="showNewsAction" view="news.xslt"/>
              <subaction name="showBannerAction" view="banner.xslt"/>
              <subaction name="showCopyRightAction" view="banner.xslt"/>
     </success>
     <failure>
              <subaction name="showErrorBodyAction" view="error.xslt"/>
              <subaction name="showBannerAction" view="banner.xslt"/>
              <subaction name="showCopyRightAction" view="banner.xslt"/>
     </failure>
</action>
...но, получается, тут смешивается все на свете - и логика поведения скрипта и логика отображения...

:(
 

_RVK_

Новичок
Хотелось бы что-нибудь эдакое забабахать
Этакое не позволит включать акшены на основе какой-то логики. Например какой-то акшен вернул ошибку, следовательно не нужно выпонять никакие другие екшены, а выполнить акшен LocationAction для перехода на сраницу вывода сообщений об ошибках. Мой вариант позволяет задать любую логику выполнения акшенов.
можешь какой-нибудь расширенный кусочичек кода привести
PHP:
В суперакшене:
class DisplayAction extends SuperAction {

    function exec() {
        $this->execAction(new MenuAction());
        $this->execAction(new GoodsAction());
        $this->ctrl->addGlobalViewData('sel.id',$this->ViewData['Goods']['parent']);
        return true;
    }
}
Акшен отображающий пункты меню.
PHP:
class MenuAction extends Action {

    function exec() {
        //$this->foo();
        $this->ViewData[1] = 'DVD';
        $this->ViewData[2] = 'CD';
        $this->ViewData[3] = 'BOOKS';
        return true;
    }
}
Экшен отображающий список товаров.
PHP:
<?php
 class GoodsAction extends Action {

    protected $VieData;

    function __construct() {
    }

    function exec() {
        //$this->foo();
        $model = new GoodsModel();
        $model->select_goods($this->getRequest()->get('id'));
        $model->init();
        $this->ViewData = $model->getModelData();
        return true;
    }
}
?>
А это инициализация главного контроллера:
PHP:
<?php
include_once 'config.inc.php';

$Request = new Request();
$app = new Application(APP_NAME,'catalog',NULL,$Request);

$ctrl = new Controller($app);

$ctrl->setView(new SmartyView('main.tpl',APP_ROOT.'/tpls/'));
$ctrl->addAction(new DefaultAction());
$ctrl->addAction(new DisplayAction());
$ctrl->exec();

print $ctrl->getViewResult();

?>
Вообще движок еще немного сырой и будет дорабатываться, но общий смысл должен быть понятен.
Еще у контроллкра есть методы
addPreDeffAction(...) и addPostDeffAction(...) которые позваляют добавлять акшены которые должны быть выполнены полюбому. Например отображение меню здесь для премера засунуто в суперашен. На самом деле можно сделать и так:
PHP:
$ctrl->addPreDeffAction(new MenuAction());
-~{}~ 18.07.05 12:00:

Могу показать ТЗ к этому фреймверку. Там кое что расписано.
 

slego

Новичок
Большое спасибо за столь подробное разжевывание.
Буду разбираться....

Автор оригинала: _RVK_
Могу показать ТЗ к этому фреймверку. Там кое что расписано.
Самое интересное, что этот файл уже выкачал эдак пару месяцев назад и уже раз 10 его перечитывал, каждый раз "постигая" что-то новое.
 
Сверху