-- Vincent de Lau <[email protected]> wrote
(on Saturday, 14 March 2009, 10:16 PM +0100):
> > -----Original Message-----
> > From: Matthew Weier O'Phinney [mailto:[email protected]]
> > Sent: Saturday, March 14, 2009 3:30 PM
> > 
> > -- Vincent de Lau <[email protected]> wrote
> > (on Saturday, 14 March 2009, 12:52 PM +0100):

<snip> 

> > In this case, we're pulling from a model we've injected into the view,
> > and then creating an unordered list which we return. In your view
> > script, you then simply echo the results:
> > 
> >     <?php echo $this->recentEnties() ?>
> 
> And that is where the catch is in my case. I don't want a viewscript to
> decide what content to display; I want that to be dynamic. 

Um.. I fail to see the contradiction here. :)

Your view script is responsible for display logic -- i.e., what to
display, and where.

> How do I get my models in the view when I don't know beforehand what
> helpers are going to be called and what model access they need? I
> would argue that that is a controller task, but you lose that part
> when using sole helpers.

I have two responses to this. First, one job of controllers is to push
the relevant models into the view. One can certainly argue that if your
controller doesn't already know what models to push... then you're
coding your model wrong.

Second, you can also code your view helpers such that they actually
instantiate the models themselves -- this is a technique I've done
often. For example, I could have modified the previous example to
instantiate the model if it's not been injected into the view (lazily,
and keeping a copy in case it were to be used later):

    class My_View_Helper_RecentEntries extends Zend_View_Helper_Abstract
    {
        protected $_entriesModel;

        public function getEntriesModel()
        {
            if (null === $this->_entriesModel) {
                if ($this->view->entriesModel) {
                    $this->_entriesModel = $this->view->entriesModel;
                } else {
                    $this->_entriesModel = new Entries();
                }
            }
            return $this->_entriesModel;
        }

        public function recentEntries()
        {
            $model = $this->getEntriesModel();
            // ...
        }
    }

This allows for both dependency injection (via the view) as well as
on-demand lazy-loading.


> Part of the problem could be handled by adding a view helper that calls
> other helpers (the dynamic part) and passes parameters to them, but I
> suppose that doesn't solve the problem of which model to access.
> 
> I also find it a problem that for large parts of my system, I would not be
> using view scripts for output, making such components harder to reuse. 

Ummm... again, I'm finding this to be contradictory. View helpers are
inherently designed _for_ re-use. Not only that, but because they are
part of a plugin architecture, you can extend them and provide alternate
behavior. Finally, view helpers give you the ability to unit test
discrete behavior -- "if I call this view helper with these arguments, I
will get this return value". This is the core of re-use.

Additionally, you are *still* using view scripts for your output, as you
would be calling your view helpers *within* your view scripts.

> The current controllers that I'm building, can be used on other sites
> without modification. I only need to change my view scripts if
> required. Some controllers even made it into our library, leaving only
> an empty extending class in the application. (For instance: class
> ErrorController extends My_Error_ActionController {} )

And view helpers work exactly the same. Drop them (and any dependencies)
into another project, and they just work. Change your view scripts if
necessary, or extend your view helpers to modify the output -- but the
core functionality remains the same.

View helpers are just classes, after all.

> > and that's it. This tactic provides better encapsulation, provides
> > behavior that is easily testable, and is much more performant as there
> > is no need to lookup the controller and dispatch it.
> > 
> > Your suggestion that if performance is an issue with action(), effort
> > might go into improving the dispatcher or creating a lightweight
> > version
> > makes sense in theory... but to do so actually exposes an important
> > point: modifying how the dispatch sequence works would actually
> > potentially break action().
> >
> > Ironically, the method of using view helpers instead of action() makes
> > it *easier* to replace elements of Zend_Controller with your own
> > implementations, as you no longer need to worry that changing the
> > implementation will break the functionality.
> 
> I totally understand your point and would never suggest to alter the
> behavior of the current dispatcher or action(). I specifically mentioned
> 'secondary' content because it might warrant a far less complex way of
> 'dispatching'. 

Actually, the dispatcher is not terribly complicated. But if you create
an alternate dispatcher using different rules, action() then will act
differently -- potentially resulting in unexpected behavior. That's what
I was getting at.

> Wrapping all my earlier comments and experience up, I can see
> a helper that can load other 'helpers' 

Any helper can already load any other helper via the registered view
object:

    class My_View_Helper_Foo extends Zend_View_Helper_Abstract
    {
        public function foo()
        {
            $this->view->headTitle('Foo!');
            return $this->view->formText('foo', 'foo');
        }
    }

> or 'mini-controllers'. Those 'helpers' might even use view scripts to
> control their output.

Again, helpers can already utilize view scripts via the view object:

    return $this->view->render('partials/foo.phtml');


> However, I could also understand that this would part to far from the
> (traditional) MVC pattern. That would however get me thinking if MVC is
> really the way to do this type of web applications.

What I've been trying to get at is that too many people are doing too
much business and display logic via their action controllers, instead of
properly separating the various areas of responsibility. Your controller
should be determining what models and views to use. Your views should be
doing display related logic, and pulling information from models
necessary to those ends. Your models should encapsulate all your
business logic.

-- 
Matthew Weier O'Phinney
Software Architect       | [email protected]
Zend Framework           | http://framework.zend.com/

Reply via email to