I've been struggling with the well-trodden issue of wanting stand-
alone elements to use requestAction() to isolate their data needs from
their hosting controllers, and the good vs evil of that approach.

I'm less concerned with the performance aspects than the architectural
aspects.

The Cake manual says that this is an acceptable use of requestAction.
I'm not so sure. I'd like to propose another solution pattern and see
what people think.

With the standard Cake flow, a controller gathers data from the models
and makes it available passively to the view. Once the view is
rendered, the controller doesn't gather any more data, or put another
way, it's a one-way waterfall process (action -> render) and the
action phase is already complete.

When elements call requestAction, we go back upstream so to speak, and
actively request/query new data from within the view rendering
function. Given the waterfall nature, we need to initiate a new action
since we can't leverage the existing completed one.

These are two different paradigms (passing data passively to the view
vs. the view actively querying data) and both are valid, but IMO
shouldn't be combined, since it reduces consistency and therefore
predictability. Note that I'm not calling into question the fidelity
to the MVC paradigm here...

So to go with the Cake passive paradigm, the action phase of the
controller should gather data for the elements along with the data for
the view, and present all data needed for everything on the returned
web page for the layout/view/elements to render.

But how to do this generically and avoid knowledge of the element's
data needs in every controller? Remember that elements are generally
distinct from entities, and certainly from the current controller's
entity (otherwise it'd be in the view)

The AD7six.com (Andy Dawson) mini-controller does this using
components, and uses the component startup hook to access models and
gather the data. This has two weaknesses I can see:

1. there's no convention linking the component to the element, like
there is in the rest of Cake. This limits scalability as things get
messy quickly without external discipline
2. the component gets called before the action function, rather than
afterwards. The fact that there needs to be a _continue() function to
allow the action to execute, then call the component explicitly once
the necessary context has been determined, is evidence of this. It
also forces the controller to know that the component exists, which is
a Bad Thing.

This smacks of Aspects. Elements and their controller-phase logic need
to exist orthogonally from the entity/model/controller/view
definitions. (Aspect is a very generic term, but then again so is
Component, Helper and Element)

So my thought is to promote element names to first-class citizens, and
create a new class in the controller linked to the element. it works
with the controllers, but without controller knowledge, like aspects.
I'll call this class Aspect.  So views/elements/sidebar.ctp could have
controllers/aspects/sidebar_aspect.php. Convention links them
together.

Now the hosting controller needs to specify the aspects. Or rather,
the controller is decorated with the aspects, since the controller
shouldn't be affected by them. Or whatever.

It would be cool if the controller could pre-parse the view and
automatically collect the referenced elements, but I don't see that
happening. Instead, use Helpers as a model. So if the controller has
the static:
var $aspects=Array("Sidebar");
then that aspect is available for all actions in that controller. If
the action instead has
$this->aspects[] = "Sidebar";
then it's available just for that action.

Now we can use the beforeRender hook to call all the aspects, and add
their variables to the viewvars space. This ensures any context has
been determined, and can be passed to the aspect within the $this-
>data->viewVars. Alternately there could be some sort of global
context object or dictionary. The aspects can then augment the
viewvars space, possibly using a primitive namespace like
$sidebar_variablename to avoid clashes (since elements don't
(shouldn't) know about the hosting controller or each other)

I honestly haven't had the time to prototype this up, but wanted to
run it past the community to see if either I missed something, or it's
been done before, or whatever. What do y'all think?

I wanted to bring up one more thing. Once a site starts depending on
these sorts of standalone elements, I believe that the controller
stops being associated heavily with an entity, and instead acts as a
FrontController from Sun's Model 2 pattern. That's certainly what
happened with my site. Entity controllers are given entity actions and
are usually ajax targets or requestAction() targets. The models have
become quite thick, and most of the controller action happens in a set
of controllers with no models, which act purely to coordinate the
gathering of data for all the elements on the screen. They concern
themselves instead with current user context, which they "publish" to
the elements using the global viewVars space.


Check out the new CakePHP Questions site http://cakeqs.org and help others with 
their CakePHP related questions.

You received this message because you are subscribed to the Google Groups 
"CakePHP" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected] For more options, visit this group at 
http://groups.google.com/group/cake-php?hl=en

Reply via email to