Hi,
The new layout stuff works really well. I've just converted my app to using the
layouts, took a bit of getting used to it, but it wasn't to difficult. And now
I don't need to set up the decorator manually in the base view anymore. I've
made the default view have a method like this:
public function executeHtml(AgaviRequestDataHolder $rd)
{
$this->setupHtml($rd);
}
For simple views that just serve up a template without doing anyting else this
means I don't even need to override the executeHtml() method anymore.
I have set up the setupHtml method so that it takes as an optional parameter
the name of a layout, that way I can do setupHtml($rd, 'notDecorated') to have
a view that renders without decoration (e.g. a view that needs to be inserted
in some other slot) while the setupHtml($rd) automatically decorates with the
standard site template. And I have a third layout that just wraps some simple
layout around a template for pages like Unavailable.php.
The setting of slots for an inner layer is also very helpful. Something I've
been waiting for a long time.
I haven't encountered any problems so far. One thing I do keep on running into
is agavi telling me that a config file is not valid, but only giving back a
very general error-message (Element Content is invalid) that doesn't really
help in debugging. Maybe this is only a problem now because the config-file
format has changed a few times. Is it possible to have more specific errors? It
might also be useful to add the different parameters to xsd for validation
since right now you don't get a warning if you've used a wrong parameter.
Anyway, thanks again for all the hard work,
Koen
> -----Oorspronkelijk bericht-----
> Van: [EMAIL PROTECTED]
> [mailto:[EMAIL PROTECTED] Namens David Zülke
> Verzonden: dinsdag 30 januari 2007 10:32
> Aan: Agavi Users Mailing List
> CC: Agavi Dev Mailing List
> Onderwerp: Re: [Agavi-Users] Advanced Layout/Layers example
> (was: Re:IMPORTANT: Breaking changes in 0.11 branch: tons of
> new features!)
>
> As of http://trac.agavi.org/changeset/1609, the output of the
> inner layer is available via the variable $inner in
> templates. Also available are $container for the current
> execution container and $view for the template's view. Like
> with factories, the names of these assigns ("inner",
> "container" and "view") can be configured using the "assigns"
> parameter of a renderer.
>
> Since the wrapping template now does not have to know the
> inner layer's name anymore, the example can be simplified quite a bit.
>
> Master.php:
> <html>
> <head><title>logs!</title></head>
> <body>
> <?php echo $inner; ?>
> </body>
> </html>
>
> LiveSuccess.php:
> <tbody>
> <?php foreach($t['messages'] as $message): ?>
> <tr>
> <td class="name"><?php echo
> $message->getNick()->getNick(); ?></td>
> <td class="message"><?php echo
> $message->getMessage(); ?></td>
> <td class="time"><?php echo
> $message->getMessageDate(); ?></td>
> </tr>
> <?php endforeach; ?>
> </tbody>
>
> LiveSuccess.wrapper.php:
> <div id="roomTitle"><?php echo $t['topic']; ?></div> <table
> border="0" cellspacing="0" cellpadding="0"> <?php echo
> $inner; ?> </table>
>
> And the code that makes it happen:
> public function executeHtml(AgaviRequestDataHolder $rd) {
> // remember: first, you should have a base view and
> call a method on the parent to load the layout instead of
> doing it here.
> // second, loadLayout() would be enough since
> "standard" is the default layout
> $this->loadLayout('standard');
>
> // now we insert the wrapper template between the
> decorator and the actual content layer
> $i = $this->appendLayer($this->createLayer
> ('AgaviFileTemplateLayer', 'wrapper'), $this->getLayer('content'));
> $i->setTemplate('LiveSuccess.wrapper');
> }
>
>
> Cheers,
>
> David
>
>
>
> Am 29.01.2007 um 14:02 schrieb David Zülke:
>
> > Hi guys,
> >
> > I thought I'd give you a little example of what the new
> template layer
> > system can do.
> >
> > We participated in the PHP Throwdown
> (http://www.phpthrowdown.com) and
> > built an IRC bot using Agavi. It's called "Chuckwalla", contains a
> > fully fledged IRC library that doesn't suck, has live logs,
> cool web
> > interfaces etc and will be open sourced soon.
> >
> > One feature is the live logs. You click a channel, and it
> uses Ajax to
> > refresh the contents, so you can follow the discussion in a
> channel.
> > So for the first load, we need a full document, and for subsequent
> > XMLHttpRequest, we just want the new messages.
> >
> > Here is the layout's configuration for output type "html":
> > <layout name="standard">
> > <layers>
> > <layer name="content" class="AgaviFileTemplateLayer" />
> > <layer name="decorator" class="AgaviFileTemplateLayer">
> > <parameter name="template">Master</parameter>
> > </layer>
> > </layers>
> > </layout>
> >
> > Let's assume this is our decorator template:
> > <html>
> > <head><title>logs!</title></head>
> > <body>
> > <?php echo $slots['content']; ?>
> > </body>
> > </html>
> >
> > And here is the content template (LiveSuccess.php):
> > <div id="roomTitle"><?php echo $t['topic']; ?></div> <table
> border="0"
> > cellspacing="0" cellpadding="0">
> > <tbody>
> > <?php foreach($t['messages'] as $message): ?>
> > <tr>
> > <td class="name"><?php echo
> $message->getNick()->getNick(); ?></td>
> > <td class="message"><?php echo
> $message->getMessage(); ?></td>
> > <td class="time"><?php echo
> $message->getMessageDate(); ?></td>
> > </tr>
> > <?php endforeach; ?>
> > </tbody>
> > </table>
> >
> > Now we also have an output type for the AJAX calls, called "json".
> > It's configured like this:
> > <layout name="standard">
> > <layers>
> > <layer name="content" class="AgaviFileTemplateLayer" />
> > </layers>
> > </layout>
> >
> > But now we have a problem: If an AJAX call is made, we get back the
> > entire inner content template, complete with the <divs> and the
> > <table>, but we only want the <tbody> to append to the
> current table
> > (remember, tables can have multiple <tbody> elements).
> >
> > One approach would be to simply have two templates. The
> other approach
> > would be to split them up and include() the inner portion in the
> > non-ajax version, and set the templates differently per output type.
> >
> > However, there also is a third approach. Right now, we have these
> > layers:
> > +------------------------+
> > | <html> decorator |
> > | +--------------------+ |
> > | | <table> content | |
> > | | with <tbody>, <tr> | |
> > | +--------------------+ |
> > | </html> |
> > +------------------------+
> >
> > What we can do now is split up the template like we would with the
> > include() solution:
> > +------------------------+
> > | <html> decorator |
> > | +--------------------+ |
> > | | <table> wrapper | |
> > | | +----------------+ | |
> > | | | <tbody> inner | | |
> > | | | content | | |
> > | | +----------------+ | |
> > | | </table> | |
> > | +--------------------+ |
> > | </html> |
> > +------------------------+
> >
> >
> > First, the "wrapper" template (LiveSuccess.wrapper.php):
> > <div id="roomTitle"><?php echo $t['topic']; ?></div> <table
> border="0"
> > cellspacing="0" cellpadding="0"> <?php echo $slots['inner']; ?>
> > </table>
> >
> > And the actual "inner" content template (LiveSuccess.php):
> > <tbody>
> > <?php foreach($t['messages'] as $message): ?>
> > <tr>
> > <td class="name"><?php echo
> $message->getNick()->getNick(); ?></td>
> > <td class="message"><?php echo
> $message->getMessage(); ?></td>
> > <td class="time"><?php echo
> $message->getMessageDate(); ?></td>
> > </tr>
> > <?php endforeach; ?>
> > </tbody>
> >
> > For Ajax, everything is fine now. We'll get the <tbody>
> content. But
> > for output type "html", the result will be this:
> > <html>
> > <head><title>logs!</title></head>
> > <body>
> > <tbody>
> > <tr>
> > <td class="name">John McClane</td>
> > <td class="message">Yippie-kay-yay motherfucker</td>
> > <td class="time">03:27</td>
> > </tr>
> > </tbody>
> > </body>
> > </html>
> >
> > What we need now is insert the wrapper IN BETWEEN "decorator" and
> > "content" layer.
> >
> > Remember that the decorator template expects to output $slots
> > ['content']. Hence, we actually have to modify the
> "content" layer to
> > display the wrapper template (LiveSuccess.wrapper.php), and then
> > prepend another "inner" layer (LiveSuccess.php) to the
> layer list. We
> > do it like this, in the view:
> >
> > public function executeHtml(AgaviRequestDataHolder $rd) {
> > // remember: first, you should have a base view and
> call a method on
> > the parent to load the layout instead of doing it here.
> > // second, loadLayout() would be enough since "standard" is the
> > default layer
> > $this->loadLayout('standard');
> >
> > // we get the "content" layer and change the template
> to the wrapper
> > $c = $this->getLayer('content');
> > $c->setTemplate('LiveSuccess.wrapper');
> >
> > // and then prepend the actual "inner" content template
> to the list
> > $i = $this->prependLayer($this->createLayer
> > ('AgaviFileTemplateLayer', 'inner'));
> > $i->setTemplate('LiveSuccess');
> > }
> >
> > And that's it! Now we have the desired result:
> > <html>
> > <head><title>logs!</title></head>
> > <body>
> > <div id="roomTitle"><?php echo $t['topic']; ?></div> <table
> border="0"
> > cellspacing="0" cellpadding="0"> <tbody>
> > <tr>
> > <td class="name">John McClane</td>
> > <td class="message">Yippie-kay-yay motherfucker</td>
> > <td class="time">03:27</td>
> > </tr>
> > </tbody>
> > </table>
> > </body>
> > </html>
> >
> >
> > IMPORTANT: Some advice regarding base views. In the
> original email, I
> > recommended that you always have a base view you extend from where
> > execute() throws an exception. This view would also have
> base methods
> > you can call that load layers, maybe set dynamic slots, or do stuff
> > like:
> > $this->setAttribute('_contentType',
> $this->container->getOutputType()-
> >> getParameter('Content-Type'));
> >
> > However, there is a problem here. The whole point of having
> execute()
> > throw an exception is that if there is a request using, say, ajax,
> > that sets the output type to, say, "json" because of a routing rule
> > like this:
> > <route pattern="^XMLHttpRequest$" source="_SERVER
> > [HTTP_X_REQUESTED_WITH]" stop="false" output_type="json" />
> >
> > And you then implement a base executeJson() in the base
> view... all of
> > your views DO serve the json output type, and the normal
> execute() is
> > never called, not even for actions/views that don't implement ajax
> > features and should thus get an exception!
> >
> > To solve that problem, name these base methods differently.
> I suggest
> > you call them "setupHtml", "setupJson" and so on, and then
> call them
> > using $this->setupHtml($rd); etc inside your concrete view's
> > executeHtml() method.
> >
> > Again, if there are any questions, let me know.
> >
> > Cheers,
> >
> > David
> >
> > _______________________________________________
> > users mailing list
> > [email protected]
> > http://lists.agavi.org/mailman/listinfo/users
> >
>
>
> _______________________________________________
> users mailing list
> [email protected]
> http://lists.agavi.org/mailman/listinfo/users
>
_______________________________________________
users mailing list
[email protected]
http://lists.agavi.org/mailman/listinfo/users