2009年12月4日星期五

Re: [fw-mvc] PageController + ActionStack vs. Simple MVC

-- Christian Ehmig <ehmig@boerse-go.de> wrote
(on Friday, 04 December 2009, 05:15 AM -0800):
> weierophinney wrote:
> > -- Christian Ehmig <ehmig@boerse-go.de> wrote
> > (on Friday, 04 December 2009, 02:39 AM -0800):
> >> I've read some discussions about the "evil" ActionStack in this forum and
> >> specifically here:
> >> http://www.rmauger.co.uk/2009/03/why-the-zend-framework-actionstack-is-evil/
> >>
> >> I commented on that (#19).
> >>
> >> Now my question is - how do you setup Zend MVC for complex, highly
> >> configurable websites or portals (not only simple blog applications with
> >> basic CRUD operations). In particular, websites that consist of many
> >> conrete
> >> pages that make use of (hopefully) reusable components.
> >>
> >> For me the best solution is still:
> >>
> >> 1. Writing a Zend_Controller_Plugin that hooks into routeShutdown()
> >> 2. in routeShutdown() compile the set of actions, their parameters,
> >> templates and layout targets from a given page configuration (xml file,
> >> database) and the layout file to be used for that page
> >> 3. Push these actions to the ActionStack
> >> 4. done
> >>
> >> Any other approaches seem not reusable and "hard-coded" for me. I can
> >> give
> >> further details on my implementation if needed. I am just curious how
> >> others
> >> solve the issue "a page consists of several actions and their respective
> >> views".
> >
> > I've spoken and blogged a ton on this in the last year. The answer: this
> > stuff is typically either part of your domain model or part of your view
> > layer, but has nothing to do with your controllers.
> >
> > If the reason you're using ActionStack is to re-use business logic...
> > then that logic should be pushed into your models. If the reason you're
> > using ActionStack is to re-use view scripts, then simply consume those
> > view scripts. A judicious use of view placeholders and view helpers can
> > achieve some tremendous results.
>
> I tried to find some posts / blogs about this subject - I would be happy if
> you could provide me with some links to your posts.

Most recently, a talk at ZendCon:

http://www.slideshare.net/weierophinney/architecting-your-models

I've also blogged on the subject a few times, though most of the entries
are a bit dated in regards to how I actually code now:

http://weierophinney.net/matthew/plugin/tag/mvc

Paddy also has some great articles; browse his blog at:

http://blog.astrumfutura.com/

> About ActionStack - we are using it to re-use both business logic and view
> scripts. If working with only one action per request where is the point in
> having more than one action anyway? I am talking about sth like a
> "PageController" architecture. A request is handled by a PageController
> which knows (from configuration) how to render the page. This includes the
> layout, the actions + their parameters and templates. If you try to
> implement re-usable actions, a single page will always consist of several
> action calls.

The PageController pattern is different than the FrontController
pattern. Your description of PageController is spot on -- but it's not
how FrontController works. FrontController decomposes a request, and
from there determines what actions to take. The workflow is different,
in that there is not an assumption of a single course of action, or of a
specific handler for a given request. As such, a "controller" is merely
a group of related actions -- typically actions that operate on a common
resource. This is the rationale for multiple actions per controller.

Within the ZF FrontController implementation, there are several other
components where responsibility may be delegated: front controller
plugins, action helpers (which also can be used to automate, via init()
and pre/postDispatch() hooks), even bootstrap resources.

Another thing: view helpers can be aware of models, and make calls on
them. This provides some tremendous flexibility in regards to re-usable
presentation logic.

> Simple example:
>
> listArticlesAction() which lists a set of articles using a given template -
> the action itself queries it's data from the model: $model->getArticles() by
> passing parameters.
>
> Now, you like to display different sets of articles on different pages and
> it should be completely configurable - much like in a typical CMS with db
> backend.
>
> I cannot see any benefit from using view helpers or placeholders here
> instead of an ActionStack. Where would you effectively configure which set
> of articles to display on a given page. Also think of several different sets
> of articles per page. This sould easily be re-configurable in any point of
> time.

This is actually *trivial* to do with a well-defined model and a view
helper.

Consider this helper definition:

class Blog_View_Helper_Articles extends Zend_View_Helper_Abstract
{
protected $_model;

public function articles($set = null)
{
if (null === $set) {
return $this;
}

return $this->getModel()->fetchArticlesBySet($set);
}

public function setModel(Blog_Model_Article $model)
{
$this->_model = $model;
}

public function getModel()
{
if (null === $this->_model) {
$this->setModel(new Blog_Model_Article);
}
return $this->_model;
}
}

Within a view script, you would then do something like this:

<ul>
<?php foreach ($this->articles('zend_framework') as $article): ?>
<li>
<a href="<?php echo $this->url(array('id' => $article->id), 'blog-entry') ?>">
<?php echo $this->escape($article->title) ?>
</a>
</li>
<?php endforeach ?>
</ul>

Because the helper takes an argument, you can then re-use it several
times on the page. This takes less overhead than dispatching multiple
actions in the request, and pushes the business logic to an easily
_testable_ layer as well (view helpers and models are more easily tested
than controllers).

Hopefully this example and the above resources will give you some ideas
for how to accomplish these goals.

--
Matthew Weier O'Phinney
Project Lead | matthew@zend.com
Zend Framework | http://framework.zend.com/

没有评论: