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

Reply via email to