Controller and View Question

View: New views
20 Messages — Rating Filter:   Alert me  

Controller and View Question

by Ralph Schindler :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hey group,
   I am curious how everyone implements common headers and footers
within a given application.  As I see it there are two methods:

a) include the header and footer in each view script via the
$this->render(..) routine.

b) use Zend_Controller Plugins to write to the view a standard header
and footer to the view body at preDispatch() postDispatch() /
preRouteStartup / postRouteStartup times.

Both methods have their pros and cons..

In method a) you are required to handle it in every script, which can be
tedious.  But it allows you flexibility to not include the common header
and footer blanketly on all requests when it makes sense not to include it.

Method b) writes headers and footers on all requests, unless I am
missing something.  The benefit is that you can write specific
controller/action scripts and they can be completely autonomous from the
rest of the application.

I like method b), but I wonder:  Are there ways to inject (or callback)
to write specific controller/action needed headers to the common header,
for example, adding a page specific JS script to a pages <head>.  Are
there ways that a specific controller/action can choose not to use a
header/footer dispatched previously?

Looking for best practices / ideas here..

Thanks,
Ralph


Re: Controller and View Question

by Ian Warner-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Ralph Schindler wrote:
> Hey group,
>   I am curious how everyone implements common headers and footers within
> a given application.  As I see it there are two methods:
>
> a) include the header and footer in each view script via the
> $this->render(..) routine.

I simply within the main site view call in the following files:

  <?php echo $this->render('../themes/' . $this->theme_template .
'/html/html_head.inc.php') ?>

  echo $this->render($this->actionTemplate);

This allows the view to specify the template and the template elements
are called via the theme.

>
> b) use Zend_Controller Plugins to write to the view a standard header
> and footer to the view body at preDispatch() postDispatch() /
> preRouteStartup / postRouteStartup times.
>
> Both methods have their pros and cons..
>
> In method a) you are required to handle it in every script, which can be
> tedious.  But it allows you flexibility to not include the common header
> and footer blanketly on all requests when it makes sense not to include it.
>
> Method b) writes headers and footers on all requests, unless I am
> missing something.  The benefit is that you can write specific
> controller/action scripts and they can be completely autonomous from the
> rest of the application.
>
> I like method b), but I wonder:  Are there ways to inject (or callback)
> to write specific controller/action needed headers to the common header,
> for example, adding a page specific JS script to a pages <head>.  Are
> there ways that a specific controller/action can choose not to use a
> header/footer dispatched previously?
>
> Looking for best practices / ideas here..
>
> Thanks,
> Ralph
>
>

RE: Controller and View Question

by Xavier Vidal :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi

We're using some different "views" to get a useful layout for each purpose.

We start using:

- portal-layout.php
- clean-layout.php

The first one has the header, footer, top menu, the main content and
optionally the left and right menus.
The clean layout only has the header and footer.

So, in our scripts we can do the following (extending the Zend_View
component):

$view = new TemplateView();
$view->tplMain  = 'articles/view.php';
$view->tplLeft  = 'articles/leftMenu.php';
$view->tplRight = 'articles/contextual.php';
$view->articles = $oArticles->get();
$view->render('portal-layout.php');

The "portal-layout.php" is constructed this way:

$this->render('header.php');
$this->render('topMenu.php');
if(isset($this->tplLeft))
    $this->render($this->tplLeft);
$this->render($this->tplMain);
if(isset($this->tplRight))
    $this->render($this->tplRight);
$this->render('footer.php');

More or less...

Xavier Vidal Piera
Enginyer Tècnic d'Informàtica de Gestió
Tècnic Especialista en Informàtica de Sistemes
xavividal@...
610 68 41 78
http://www.webpersonal.net/redness
http://www.myspace.com/xaviervidalmusic
 

> -----Mensaje original-----
> De: Ian Warner [mailto:iwarner@...]
> Enviado el: domingo, 25 de marzo de 2007 18:08
> Para: Ralph Schindler
> CC: Zend Framework General
> Asunto: Re: [fw-general] Controller and View Question
>
> Ralph Schindler wrote:
> > Hey group,
> >   I am curious how everyone implements common headers and footers
> > within a given application.  As I see it there are two methods:
> >
> > a) include the header and footer in each view script via the
> > $this->render(..) routine.
>
> I simply within the main site view call in the following files:
>
>   <?php echo $this->render('../themes/' . $this->theme_template .
> '/html/html_head.inc.php') ?>
>
>   echo $this->render($this->actionTemplate);
>
> This allows the view to specify the template and the template
> elements are called via the theme.
>
> >
> > b) use Zend_Controller Plugins to write to the view a
> standard header
> > and footer to the view body at preDispatch() postDispatch() /
> > preRouteStartup / postRouteStartup times.
> >
> > Both methods have their pros and cons..
> >
> > In method a) you are required to handle it in every script,
> which can
> > be tedious.  But it allows you flexibility to not include
> the common
> > header and footer blanketly on all requests when it makes
> sense not to include it.
> >
> > Method b) writes headers and footers on all requests, unless I am
> > missing something.  The benefit is that you can write specific
> > controller/action scripts and they can be completely
> autonomous from
> > the rest of the application.
> >
> > I like method b), but I wonder:  Are there ways to inject (or
> > callback) to write specific controller/action needed headers to the
> > common header, for example, adding a page specific JS script to a
> > pages <head>.  Are there ways that a specific controller/action can
> > choose not to use a header/footer dispatched previously?
> >
> > Looking for best practices / ideas here..
> >
> > Thanks,
> > Ralph
> >
> >
>
> --
> No virus found in this incoming message.
> Checked by AVG Free Edition.
> Version: 7.5.446 / Virus Database: 268.18.17/732 - Release
> Date: 24/03/2007 16:36
>  
>

--
No virus found in this outgoing message.
Checked by AVG Free Edition.
Version: 7.5.446 / Virus Database: 268.18.17/732 - Release Date: 24/03/2007
16:36
 


Re: Controller and View Question

by weierophinney :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

-- Ralph Schindler <ralph@...> wrote
(on Sunday, 25 March 2007, 09:37 AM -0500):

>   I am curious how everyone implements common headers and footers
> within a given application.  As I see it there are two methods:
>
> a) include the header and footer in each view script via the
> $this->render(..) routine.
>
> b) use Zend_Controller Plugins to write to the view a standard header
> and footer to the view body at preDispatch() postDispatch() /
> preRouteStartup / postRouteStartup times.
>
> Both methods have their pros and cons..
>
> In method a) you are required to handle it in every script, which can be
> tedious.  But it allows you flexibility to not include the common header
> and footer blanketly on all requests when it makes sense not to include it.
>
> Method b) writes headers and footers on all requests, unless I am
> missing something.  The benefit is that you can write specific
> controller/action scripts and they can be completely autonomous from the
> rest of the application.
>
> I like method b), but I wonder:  Are there ways to inject (or callback)
> to write specific controller/action needed headers to the common header,
> for example, adding a page specific JS script to a pages <head>.  Are
> there ways that a specific controller/action can choose not to use a
> header/footer dispatched previously?

I throw a Zend_View object in the registry, and then access this from my
controllers and plugins. The benefit of doing this is that the
controllers can set values in the view that are unused in their
individual view, but used later in the sitewide template.

Then, I use a dispatchLoopShutdown() plugin to inject any generated
content into a sitwide template:


    class SiteTemplatePlugin extends Zend_Controller_Plugin_Abstract
    {
        public function dispatchLoopShutdown()
        {
            $response = Zend_Controller_Front:;getInstance()->getResponse();
            $view = Zend_Registry::get('view');
            $view->content = $response->getBody();
            $response->setBody($view->render('site.phtml'));
        }
    }

Any other variables you've set in your template object to this point are
also available, not just $content. As a result, you could in your action
controllers specify additional values:

    public function formAction()
    {
        // Set the sitewide template's $pageTitle element
        $this->view->pageTitle = 'Login Form';

        $this->render();
    }

By doing the sitewide template at the end, instead of doing a header in
the preDispatch() and footer in the postDispatch(), you can affect the
entire layout of the page, and also chain together several actions to
build the final page.

--
Matthew Weier O'Phinney
PHP Developer            | matthew@...
Zend - The PHP Company   | http://www.zend.com/

Re: Controller and View Question

by fred wolf :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Matthew Weier O'Phinney a écrit :

> -- Ralph Schindler <ralph@...> wrote
> (on Sunday, 25 March 2007, 09:37 AM -0500):
>  
>>   I am curious how everyone implements common headers and footers
>> within a given application.  As I see it there are two methods:
>>
>> a) include the header and footer in each view script via the
>> $this->render(..) routine.
>>
>> b) use Zend_Controller Plugins to write to the view a standard header
>> and footer to the view body at preDispatch() postDispatch() /
>> preRouteStartup / postRouteStartup times.
>>
>> Both methods have their pros and cons..
>>
>> In method a) you are required to handle it in every script, which can be
>> tedious.  But it allows you flexibility to not include the common header
>> and footer blanketly on all requests when it makes sense not to include it.
>>
>> Method b) writes headers and footers on all requests, unless I am
>> missing something.  The benefit is that you can write specific
>> controller/action scripts and they can be completely autonomous from the
>> rest of the application.
>>
>> I like method b), but I wonder:  Are there ways to inject (or callback)
>> to write specific controller/action needed headers to the common header,
>> for example, adding a page specific JS script to a pages <head>.  Are
>> there ways that a specific controller/action can choose not to use a
>> header/footer dispatched previously?
>>    
>
> I throw a Zend_View object in the registry, and then access this from my
> controllers and plugins. The benefit of doing this is that the
> controllers can set values in the view that are unused in their
> individual view, but used later in the sitewide template.
>
> Then, I use a dispatchLoopShutdown() plugin to inject any generated
> content into a sitwide template:
>
>
>     class SiteTemplatePlugin extends Zend_Controller_Plugin_Abstract
>     {
>         public function dispatchLoopShutdown()
>         {
>             $response = Zend_Controller_Front:;getInstance()->getResponse();
>             $view = Zend_Registry::get('view');
>             $view->content = $response->getBody();
>             $response->setBody($view->render('site.phtml'));
>         }
>     }
>
> Any other variables you've set in your template object to this point are
> also available, not just $content. As a result, you could in your action
> controllers specify additional values:
>
>     public function formAction()
>     {
>         // Set the sitewide template's $pageTitle element
>         $this->view->pageTitle = 'Login Form';
>
>         $this->render();
>     }
>
> By doing the sitewide template at the end, instead of doing a header in
> the preDispatch() and footer in the postDispatch(), you can affect the
> entire layout of the page, and also chain together several actions to
> build the final page.
>
>  
Is it possible to imagine to throw a Zend_View object in the Response
object instead of the registry. The view object would still available in
the controllers.
What do you think ?
I don't even know why I would like to not throw the view object in the
registry, :) but may be it could be easier to combine data content,
vairaibles  and templates if  the view object and  the  response one
are  tied together.

Re: Controller and View Question

by weierophinney :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

-- frederic wolf <fred.wolf@...> wrote
(on Sunday, 25 March 2007, 11:31 PM +0200):

> Matthew Weier O'Phinney a écrit :
> > -- Ralph Schindler <ralph@...> wrote
> > (on Sunday, 25 March 2007, 09:37 AM -0500):
> >  
> > >  I am curious how everyone implements common headers and footers
> > > within a given application.  As I see it there are two methods:
> > >
> > > a) include the header and footer in each view script via the
> > > $this->render(..) routine.
> > >
> > > b) use Zend_Controller Plugins to write to the view a standard header
> > > and footer to the view body at preDispatch() postDispatch() /
> > > preRouteStartup / postRouteStartup times.
> > >
> > > Both methods have their pros and cons..
> > >
> > > In method a) you are required to handle it in every script, which can be
> > > tedious.  But it allows you flexibility to not include the common header
> > > and footer blanketly on all requests when it makes sense not to include
> > > it.
> > >
> > > Method b) writes headers and footers on all requests, unless I am
> > > missing something.  The benefit is that you can write specific
> > > controller/action scripts and they can be completely autonomous from the
> > > rest of the application.
> > >
> > > I like method b), but I wonder:  Are there ways to inject (or callback)
> > > to write specific controller/action needed headers to the common header,
> > > for example, adding a page specific JS script to a pages <head> .  Are
> > > there ways that a specific controller/action can choose not to use a
> > > header/footer dispatched previously?
> > >    
> >
> > I throw a Zend_View object in the registry, and then access this from my
> > controllers and plugins. The benefit of doing this is that the
> > controllers can set values in the view that are unused in their
> > individual view, but used later in the sitewide template.
> >
> > Then, I use a dispatchLoopShutdown() plugin to inject any generated
> > content into a sitwide template:
> >
> >
> >    class SiteTemplatePlugin extends Zend_Controller_Plugin_Abstract
> >    {
> >        public function dispatchLoopShutdown()
> >        {
> >            $response =
> >            Zend_Controller_Front:;getInstance()->getResponse();
> >            $view = Zend_Registry::get('view');
> >            $view->content = $response->getBody();
> >            $response->setBody($view->render('site.phtml'));
> >        }
> >    }
> >
> > Any other variables you've set in your template object to this point are
> > also available, not just $content. As a result, you could in your action
> > controllers specify additional values:
> >
> >    public function formAction()
> >    {
> >        // Set the sitewide template's $pageTitle element
> >        $this->view->pageTitle = 'Login Form';
> >
> >        $this->render();
> >    }
> >
> > By doing the sitewide template at the end, instead of doing a header in
> > the preDispatch() and footer in the postDispatch(), you can affect the
> > entire layout of the page, and also chain together several actions to
> > build the final page.
> >
> >  
> Is it possible to imagine to throw a Zend_View object in the Response
> object instead of the registry. The view object would still available in
> the controllers.
> What do you think ?
> I don't even know why I would like to not throw the view object in the
> registry, :) but may be it could be easier to combine data content,
> vairaibles  and templates if  the view object and  the  response one
> are  tied together.

You're free to extend the response object to do exactly this. :-)

Truly, though -- I've done this in a project once already, and there are
some definite benefits to doing so -- the response object is already
available in the action controllers as well as in the plugins (plugins
have both the request and response objects registered within them), and
you can then do some fairly easy context switching.

The reason I haven't proposed doing so for the default response object
is that it typically also adds a ton of complexity to the response
object, and tightly couples the view and response objects.

Another alternative to using the registry is to pass the view object
through as a front controller param:

    $front->setParam('view', $view);

You can then access it in your action controllers:

    $view = $this->_getInvokeParam('view');

or via the front controller singleton:

    $view = Zend_Controller_Front::getInstance()->getParam('view');

Basically, there are a variety of mechanisms at your disposal -- choose
whatever works best for your project.

--
Matthew Weier O'Phinney
PHP Developer            | matthew@...
Zend - The PHP Company   | http://www.zend.com/

Re: Controller and View Question

by Arnaud Limbourg :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Matthew Weier O'Phinney wrote:

> I throw a Zend_View object in the registry, and then access this from my
> controllers and plugins. The benefit of doing this is that the
> controllers can set values in the view that are unused in their
> individual view, but used later in the sitewide template.
>
> Then, I use a dispatchLoopShutdown() plugin to inject any generated
> content into a sitwide template:
>
>
>     class SiteTemplatePlugin extends Zend_Controller_Plugin_Abstract
>     {
>         public function dispatchLoopShutdown()
>         {
>             $response = Zend_Controller_Front:;getInstance()->getResponse();
>             $view = Zend_Registry::get('view');
>             $view->content = $response->getBody();
>             $response->setBody($view->render('site.phtml'));
>         }
>     }

Which poses a problem when you want to send back json (or whatever) and
you don't want a site wide template :)

Arnaud.

Re: Controller and View Question

by Ian Warner-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Another method I use:

I extend the Zend_Controller_Action and put an Intermediate class there,
as you can see from this sample controller.

The inter class contains a toView method, I can then simply assign any
values.

I control all elements in my translation files so product can change
anything through POEdit works really well.

Please comment, would like to know from people within this thread what
is the best method ie speed wise with least overhead.

class Finances_InvoicesController extends Zend_Action
{
     // {{{ properties

     protected $_view = null;

     // }}}
     // {{{ __init()

     public function init()
     {
         // Maps to arg 'view' from: $frontController->setParam('view',
$view);
         $this->_view = $this->getInvokeArg('view');
     }

     // }}}
     // {{{ indexAction()

     /**
      * Basically this action acts as the home page.
      *
      * @access public
      * @return object
      */
     public function indexAction()
     {
         // Add items required from the registry
         $translate = Zend_Registry::get('translate');

         // Add items required from the registry
         $config = Zend_Registry::get('config');

         // Sort out the SMS Navigation
         $finances = new Modules_Finances_Classes_Finances();

         if (empty($this->getParam['selfbill'])) {
             $table = 'db_tbl_finances_invoices';
             $addon = 'invoices';
         } else {
             $table = 'db_tbl_finances_self_bills';
             $addon = 'selfbill';
         }

         // Add items required from the registry
         $db = Zend_Registry::get('DB');

         $string = '';

         for ($i = 1; $i <= 15; $i++) {
             $string .= 'IF (a.qty' . $i . ', a.qty' . $i . ' * a.unit'
. $i . ', 0) + ';
         }

         $string = rtrim($string, ' + ');

         // Query to get the invoices.
         $select = $db->select()
             ->from(array('a' => $config->$table), array('a.code',
'b.company',
               'a.sale_date', 'a.paid_date', 'total_net' => '@tn:=' .
$string,
               'output_vat' => '@ov:=FORMAT(IF (a.vat_exempt = "0",
(@tn) * 1.175 - @tn, 0), 2)',
               'total_gross' => 'FORMAT((@tn) + (@ov), 2)', 'a.status'))
             ->joinLeft(array('b' => $config->db_tbl_finances_debtors),
'a.debtor_id = b.debtor_id', array())
             ->order('a.code DESC');

         $result = $db->fetchAll($select);

         if ($result) {

             // Create the options
             $options['dataGrid'] = array('perPage' => '50', 'page' =>
$this->_getParam('page'));

             $options['fields'] = array(
               'code' => 'Code', 'company' => 'Company', 'sale_date' =>
'Sale Date',
               'paid_date' => 'Paid Date', 'total_net' => 'Total Net',
'output_vat' => 'Output VAT',
               'total_gross' => 'Total Gross', 'status' => 'Status'
              );

             $options['primary_key'] = array(
               'code'
              );

             // Render the table
             $rowSet = parent::tableRender($result, 'HTMLTable', $options);
         }

         if (is_null($this->_getParam('ajax'))) {

             // Render the view
             $this->_view->page_title    =
$translate->_('financesInvoices_page_title');
             $this->_view->h1            =
$translate->_('financesInvoices_h1');
             $this->_view->title         =
$translate->_('financesInvoices_title');
             $this->_view->navigation    =
$translate->_('financesInvoices_navigation');
             $this->_view->feature       = $finances->getHeader();
             $this->_view->text          =
$translate->_('financesInvoices_text') . $rowSet['string'];
             $this->_view->template      =
$translate->_('financesInvoices_template');
             $this->_view->template_span =
$translate->_('financesInvoices_template_span');

             // Render the view
             parent::toView($this->_view);

         } else {
             echo $rowSet['string'];
         }
     }

     // }}}
     // {{{ __call()

     /**
      * Method to redirect the page if a dodgy action is put into this
controller
      *
      * @param  string $action
      * @param  string $arguments
      * @return string
      */
     public function __call($action, $arguments)
     {
         $this->_redirect('/finances');
     }

     // }}}

}

Arnaud Limbourg wrote:

> Matthew Weier O'Phinney wrote:
>> I throw a Zend_View object in the registry, and then access this from my
>> controllers and plugins. The benefit of doing this is that the
>> controllers can set values in the view that are unused in their
>> individual view, but used later in the sitewide template.
>>
>> Then, I use a dispatchLoopShutdown() plugin to inject any generated
>> content into a sitwide template:
>>
>>
>>     class SiteTemplatePlugin extends Zend_Controller_Plugin_Abstract
>>     {
>>         public function dispatchLoopShutdown()
>>         {
>>             $response =
>> Zend_Controller_Front:;getInstance()->getResponse();
>>             $view = Zend_Registry::get('view');
>>             $view->content = $response->getBody();
>>             $response->setBody($view->render('site.phtml'));
>>         }
>>     }
>
> Which poses a problem when you want to send back json (or whatever) and
> you don't want a site wide template :)
>
> Arnaud.
>

Re: Controller and View Question

by weierophinney :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

-- Arnaud Limbourg <arnaud@...> wrote
(on Monday, 26 March 2007, 07:04 AM +0200):

> Matthew Weier O'Phinney wrote:
> > I throw a Zend_View object in the registry, and then access this from my
> > controllers and plugins. The benefit of doing this is that the
> > controllers can set values in the view that are unused in their
> > individual view, but used later in the sitewide template.
> >
> > Then, I use a dispatchLoopShutdown() plugin to inject any generated
> > content into a sitwide template:
> >
> >
> >    class SiteTemplatePlugin extends Zend_Controller_Plugin_Abstract
> >    {
> >        public function dispatchLoopShutdown()
> >        {
> >            $response = Zend_Controller_Front:;getInstance()->getResponse();
> >            $view = Zend_Registry::get('view');
> >            $view->content = $response->getBody();
> >            $response->setBody($view->render('site.phtml'));
> >        }
> >    }
>
> Which poses a problem when you want to send back json (or whatever) and
> you don't want a site wide template :)

This was a simple example. But it's actually really easy to return JSON:

    public function dispatchLoopShutdown()
    {
        // assume that we've already determined the request is ajax
        $request  = $this->getRequest();
        $response = $this->getResponse();
        $view     = Zend_Registry::get('view');

        if ($request->getParam('isAjax', false)) {
            // Ajax request detected
            // Get any variables set in the view
            $vars = get_object_vars($view);

            // Merge with named path segments in response
            $vars = array_merge($vars, $response->getBody(true));

            // Create a header and set the response body to a JSON value
            $resposne->setHeader('Content-Type', 'text/x-json');
            $response->setBody(Zend_Json::encode($vars));
            return;
        }

        // Otherwise, process as normal
        $view->content = $response->getBody();
        $response->setBody($view->render('site.phtml'));
    }

--
Matthew Weier O'Phinney
PHP Developer            | matthew@...
Zend - The PHP Company   | http://www.zend.com/

Re: Controller and View Question

by Art Hundiak :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I use method A and extend the View class to reduce the tedious code.
class Proj_View extends Zend_View
{
    protected $tplPage    = 'MasterPageTpl';  // Master layout
    protected $tplTitle   = 'Project View'; // Title set in individual view
    protected $tplContent = 'HomeIndexTpl'; // Content template
...
    function renderx()
    {
        $this->content = $this->render($this->tplContent); // Do content first
       
        return $this->render($this->tplPage); // The the master layout
    }
}
Simplistic but functional enough for me.

Ralph Schindler wrote:
Hey group,
   I am curious how everyone implements common headers and footers
within a given application.  As I see it there are two methods:

a) include the header and footer in each view script via the
$this->render(..) routine.

b) use Zend_Controller Plugins to write to the view a standard header
and footer to the view body at preDispatch() postDispatch() /
preRouteStartup / postRouteStartup times.

Re: Controller and View Question

by Dale McNeill :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I've got some CSS and javascript that I would like to dynamically add to
the HTML header depending on the controller/action.  I would like to be
able to append information like appending to the response body.  Then
use this information in a site wide template.  The only solution that
comes to mind is using a view variable and having each controller/action
get the variable, append it, and write it back to the view.  Is there
some functionality that I might be overlooking? - Thanks

Site wide template:
<html>
<head>
<title><?php echo $this->title; ?></title>
<?php echo $this->dynamic_header; ?>
</head>
<body>
...common header...
<?php echo $this->content; ?>
...common footer...
</body>
</html>

Matthew Weier O'Phinney wrote:

> -- Arnaud Limbourg <arnaud@...> wrote
> (on Monday, 26 March 2007, 07:04 AM +0200):
>  
>> Matthew Weier O'Phinney wrote:
>>    
>>> I throw a Zend_View object in the registry, and then access this from my
>>> controllers and plugins. The benefit of doing this is that the
>>> controllers can set values in the view that are unused in their
>>> individual view, but used later in the sitewide template.
>>>
>>> Then, I use a dispatchLoopShutdown() plugin to inject any generated
>>> content into a sitwide template:
>>>
>>>
>>>    class SiteTemplatePlugin extends Zend_Controller_Plugin_Abstract
>>>    {
>>>        public function dispatchLoopShutdown()
>>>        {
>>>            $response = Zend_Controller_Front:;getInstance()->getResponse();
>>>            $view = Zend_Registry::get('view');
>>>            $view->content = $response->getBody();
>>>            $response->setBody($view->render('site.phtml'));
>>>        }
>>>    }
>>>      
>> Which poses a problem when you want to send back json (or whatever) and
>> you don't want a site wide template :)
>>    
>
> This was a simple example. But it's actually really easy to return JSON:
>
>     public function dispatchLoopShutdown()
>     {
>         // assume that we've already determined the request is ajax
>         $request  = $this->getRequest();
>         $response = $this->getResponse();
>         $view     = Zend_Registry::get('view');
>
>         if ($request->getParam('isAjax', false)) {
>             // Ajax request detected
>             // Get any variables set in the view
>             $vars = get_object_vars($view);
>
>             // Merge with named path segments in response
>             $vars = array_merge($vars, $response->getBody(true));
>
>             // Create a header and set the response body to a JSON value
>             $resposne->setHeader('Content-Type', 'text/x-json');
>             $response->setBody(Zend_Json::encode($vars));
>             return;
>         }
>
>         // Otherwise, process as normal
>         $view->content = $response->getBody();
>         $response->setBody($view->render('site.phtml'));
>     }
>
>  

--
------------------------------------------------------------------------
Dale McNeill                  |
Alchemy Systems               | phone: (512) 532-8050
http://www.alchemysystems.com | email: dale.mcneill@...
------------------------------------------------------------------------


Re: Controller and View Question

by weierophinney :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

-- Dale McNeill <dale.mcneill@...> wrote
(on Tuesday, 27 March 2007, 09:19 AM -0500):

> I've got some CSS and javascript that I would like to dynamically add to
> the HTML header depending on the controller/action.  I would like to be
> able to append information like appending to the response body.  Then
> use this information in a site wide template.  The only solution that
> comes to mind is using a view variable and having each controller/action
> get the variable, append it, and write it back to the view.  Is there
> some functionality that I might be overlooking? - Thanks
>
> Site wide template:
> <html>
> <head>
> <title> <?php echo $this->title; ?> </title>
> <?php echo $this->dynamic_header; ?>

Define $dynamic_header as an array in the view object. When you first
initialize the view object, do something like this:

    $view = new Zend_View();
    $view->dynamic_header = array();

Then, whenever you want to add to it, just add a new element to the
array:

    $view->dynamic_header[] = '<meta name="keywords" value="zend framework zend_view" /> ';

Then, in the view script, iterate over the array:

    <?php foreach ($this->dynamic_header as $header):
            echo $header, "\n";
    endforeach; ?>

Finally, use a Two Step View as I've outlined previously in this thread
-- use a dispatchLoopShutdown() plugin to throw the response body into a
sitewide template (which it looks like you're doing here).

> </head>
> <body>
> ...common header...
> <?php echo $this->content; ?>
> ...common footer...
> </body>
> </html>
>
> Matthew Weier O'Phinney wrote:
> > -- Arnaud Limbourg <arnaud@...> wrote
> > (on Monday, 26 March 2007, 07:04 AM +0200):
> >  
> > > Matthew Weier O'Phinney wrote:
> > >    
> > > > I throw a Zend_View object in the registry, and then access this from my
> > > > controllers and plugins. The benefit of doing this is that the
> > > > controllers can set values in the view that are unused in their
> > > > individual view, but used later in the sitewide template.
> > > >
> > > > Then, I use a dispatchLoopShutdown() plugin to inject any generated
> > > > content into a sitwide template:
> > > >
> > > >
> > > >   class SiteTemplatePlugin extends Zend_Controller_Plugin_Abstract
> > > >   {
> > > >       public function dispatchLoopShutdown()
> > > >       {
> > > >           $response =
> > > >           Zend_Controller_Front:;getInstance()->getResponse();
> > > >           $view = Zend_Registry::get('view');
> > > >           $view->content = $response->getBody();
> > > >           $response->setBody($view->render('site.phtml'));
> > > >       }
> > > >   }
> > > >      
> > > Which poses a problem when you want to send back json (or whatever) and
> > > you don't want a site wide template :)
> > >    
> >
> > This was a simple example. But it's actually really easy to return JSON:
> >
> >    public function dispatchLoopShutdown()
> >    {
> >        // assume that we've already determined the request is ajax
> >        $request  = $this->getRequest();
> >        $response = $this->getResponse();
> >        $view     = Zend_Registry::get('view');
> >
> >        if ($request->getParam('isAjax', false)) {
> >            // Ajax request detected
> >            // Get any variables set in the view
> >            $vars = get_object_vars($view);
> >
> >            // Merge with named path segments in response
> >            $vars = array_merge($vars, $response->getBody(true));
> >
> >            // Create a header and set the response body to a JSON value
> >            $resposne->setHeader('Content-Type', 'text/x-json');
> >            $response->setBody(Zend_Json::encode($vars));
> >            return;
> >        }
> >
> >        // Otherwise, process as normal
> >        $view->content = $response->getBody();
> >        $response->setBody($view->render('site.phtml'));
> >    }
--
Matthew Weier O'Phinney
PHP Developer            | matthew@...
Zend - The PHP Company   | http://www.zend.com/

Re: Controller and View Question

by Ivan Shumkov :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Re: Controller and View Question

by gneustaetter :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

The problem I see with an approach like this is that the view is tied very closely with the controller.  Should the controller have any idea about which javascript files need to be included on a particular page?  Finding a solution that minimizes the amount of common code that has to be placed in the view but still provides the view with the ability to inject javascript, css, page titles, meta tags, etc to header seems to be a problem I haven't seen answered well in any framework.  The template may include a couple javascript or css files by default in every page, but even then, the page may choose to remove the default files if it chooses. 

Thoughts?

On 3/27/07, Matthew Weier O'Phinney <matthew@...> wrote:
-- Dale McNeill <dale.mcneill@...> wrote
(on Tuesday, 27 March 2007, 09:19 AM -0500):

> I've got some CSS and javascript that I would like to dynamically add to
> the HTML header depending on the controller/action.  I would like to be
> able to append information like appending to the response body.  Then
> use this information in a site wide template.  The only solution that
> comes to mind is using a view variable and having each controller/action
> get the variable, append it, and write it back to the view.  Is there
> some functionality that I might be overlooking? - Thanks
>
> Site wide template:
> <html>
> <head>
> <title> <?php echo $this->title; ?> </title>
> <?php echo $this->dynamic_header; ?>

Define $dynamic_header as an array in the view object. When you first
initialize the view object, do something like this:

    $view = new Zend_View();
    $view->dynamic_header = array();

Then, whenever you want to add to it, just add a new element to the
array:

    $view->dynamic_header[] = '<meta name="keywords" value="zend framework zend_view" /> ';

Then, in the view script, iterate over the array:

    <?php foreach ($this->dynamic_header as $header):
            echo $header, "\n";
    endforeach; ?>

Finally, use a Two Step View as I've outlined previously in this thread
-- use a dispatchLoopShutdown() plugin to throw the response body into a
sitewide template (which it looks like you're doing here).

> </head>
> <body>
> ...common header...
> <?php echo $this->content; ?>
> ...common footer...
> </body>
> </html>
>
> Matthew Weier O'Phinney wrote:
> > -- Arnaud Limbourg <arnaud@...> wrote
> > (on Monday, 26 March 2007, 07:04 AM +0200):
> >
> > > Matthew Weier O'Phinney wrote:
> > >
> > > > I throw a Zend_View object in the registry, and then access this from my
> > > > controllers and plugins. The benefit of doing this is that the
> > > > controllers can set values in the view that are unused in their
> > > > individual view, but used later in the sitewide template.
> > > >
> > > > Then, I use a dispatchLoopShutdown() plugin to inject any generated
> > > > content into a sitwide template:
> > > >
> > > >
> > > >   class SiteTemplatePlugin extends Zend_Controller_Plugin_Abstract
> > > >   {
> > > >       public function dispatchLoopShutdown()

> > > >       {
> > > >           $response =
> > > >           Zend_Controller_Front:;getInstance()->getResponse();
> > > >           $view = Zend_Registry::get('view');
> > > >           $view->content = $response->getBody();
> > > >           $response->setBody($view->render(' site.phtml'));
> > > >       }
> > > >   }
> > > >
> > > Which poses a problem when you want to send back json (or whatever) and
> > > you don't want a site wide template :)
> > >
> >
> > This was a simple example. But it's actually really easy to return JSON:
> >
> >    public function dispatchLoopShutdown()
> >    {
> >        // assume that we've already determined the request is ajax
> >        $request  = $this->getRequest();
> >        $response = $this->getResponse();
> >        $view     = Zend_Registry::get('view');
> >
> >        if ($request->getParam('isAjax', false)) {
> >            // Ajax request detected
> >            // Get any variables set in the view
> >            $vars = get_object_vars($view);
> >
> >            // Merge with named path segments in response
> >            $vars = array_merge($vars, $response->getBody(true));
> >
> >            // Create a header and set the response body to a JSON value
> >            $resposne->setHeader('Content-Type', 'text/x-json');
> >            $response->setBody(Zend_Json::encode($vars));
> >            return;
> >        }
> >
> >        // Otherwise, process as normal
> >        $view->content = $response->getBody();
> >        $response->setBody($view->render('site.phtml'));
> >    }
--
Matthew Weier O'Phinney
PHP Developer            | matthew@...
Zend - The PHP Company   | http://www.zend.com/


Re: Controller and View Question

by weierophinney :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

-- Greg Neustaetter <gneustaetter@...> wrote
(on Tuesday, 27 March 2007, 08:14 AM -0700):

> The problem I see with an approach like this is that the view is tied very
> closely with the controller.  Should the controller have any idea about which
> javascript files need to be included on a particular page?  Finding a solution
> that minimizes the amount of common code that has to be placed in the view but
> still provides the view with the ability to inject javascript, css, page
> titles, meta tags, etc to header seems to be a problem I haven't seen answered
> well in any framework.  The template may include a couple javascript or css
> files by default in every page, but even then, the page may choose to remove
> the default files if it chooses.
>
> Thoughts?

A few.

One is to do something similar to how Zend_Controller_Action::render()
works, only with your css/js. So, in your sitewide template view script,
have some logic like this:

    <?php
    $request     = Zend_Controller_Front::getInstance()->getRequest();
    $module      = $request->getModuleName();
    $controller  = $request->getControllerName();
    ?>
    <html>
    <head>
        <title><?= $this->escape($this->title) ?></title>
        <link rel="stylesheet" type="text/css" href="/styles/site.css" />
        <link rel="stylesheet" type="text/css" href="/styles/<?= $module ?>/<?= $controller ?>.css" />

In this example, sitewide styles are kept under the /styles/ root in the
webroot, and then segregated by module and controller:

    /styles/
        news/
            list.css
            item.css
        blog/
            archive.css

In this way, you'd have some automation in how CSS (and you can extend
the idea to JS scripts, too) is injected into the page. The problem is
that you'd have to ensure that these files existed for each module and
controller -- which could lead to a ton of empty, unused files on your
machine.

Another approach is to use set view variables from within component
views. For example, if I have a view script for the NewsController, I
could do this:

    <?php
    $this->dynamic_header[] = '<link rel="stylesheet" type="text/css" href="/styles/news.css" />';
    ?>

Then, assuming the sitewide template uses the same view object, it now
has an additional header. This satisfies the requirement you had of
keeping this logic out of the controller and in the view. It's a bit
unwieldy, but it also solves the issue presented above of not needing to
create a CSS file for every controller.
       
I'm sure others have ideas as well.

> On 3/27/07, Matthew Weier O'Phinney <matthew@...> wrote:
>
>     -- Dale McNeill <dale.mcneill@...> wrote
>     (on Tuesday, 27 March 2007, 09:19 AM -0500):
>     > I've got some CSS and javascript that I would like to dynamically add to
>     > the HTML header depending on the controller/action.  I would like to be
>     > able to append information like appending to the response body.  Then
>     > use this information in a site wide template.  The only solution that
>     > comes to mind is using a view variable and having each controller/action
>     > get the variable, append it, and write it back to the view.  Is there
>     > some functionality that I might be overlooking? - Thanks
>     >
>     > Site wide template:
>     > <html>
>     > <head>
>     > <title> <?php echo $this->title; ?> </title>
>     > <?php echo $this->dynamic_header; ?>
>
>     Define $dynamic_header as an array in the view object. When you first
>     initialize the view object, do something like this:
>
>         $view = new Zend_View();
>         $view->dynamic_header = array();
>
>     Then, whenever you want to add to it, just add a new element to the
>     array:
>
>         $view->dynamic_header[] = '<meta name="keywords" value="zend framework
>     zend_view" /> ';
>
>     Then, in the view script, iterate over the array:
>
>         <?php foreach ($this->dynamic_header as $header):
>                 echo $header, "\n";
>         endforeach; ?>
>
>     Finally, use a Two Step View as I've outlined previously in this thread
>     -- use a dispatchLoopShutdown() plugin to throw the response body into a
>     sitewide template (which it looks like you're doing here).
>
>     > </head>
>     > <body>
>     > ...common header...
>     > <?php echo $this->content; ?>
>     > ...common footer...
>     > </body>
>     > </html>
>     >
>     > Matthew Weier O'Phinney wrote:
>     > > -- Arnaud Limbourg <arnaud@...> wrote
>     > > (on Monday, 26 March 2007, 07:04 AM +0200):
>     > >
>     > > > Matthew Weier O'Phinney wrote:
>     > > >
>     > > > > I throw a Zend_View object in the registry, and then access this
>     from my
>     > > > > controllers and plugins. The benefit of doing this is that the
>     > > > > controllers can set values in the view that are unused in their
>     > > > > individual view, but used later in the sitewide template.
>     > > > >
>     > > > > Then, I use a dispatchLoopShutdown() plugin to inject any generated
>     > > > > content into a sitwide template:
>     > > > >
>     > > > >
>     > > > >   class SiteTemplatePlugin extends Zend_Controller_Plugin_Abstract
>     > > > >   {
>     > > > >       public function dispatchLoopShutdown()
>     > > > >       {
>     > > > >           $response =
>     > > > >           Zend_Controller_Front:;getInstance()->getResponse();
>     > > > >           $view = Zend_Registry::get('view');
>     > > > >           $view->content = $response->getBody();
>     > > > >           $response->setBody($view->render(' site.phtml'));
>     > > > >       }
>     > > > >   }
>     > > > >
>     > > > Which poses a problem when you want to send back json (or whatever)
>     and
>     > > > you don't want a site wide template :)
>     > > >
>     > >
>     > > This was a simple example. But it's actually really easy to return
>     JSON:
>     > >
>     > >    public function dispatchLoopShutdown()
>     > >    {
>     > >        // assume that we've already determined the request is ajax
>     > >        $request  = $this->getRequest();
>     > >        $response = $this->getResponse();
>     > >        $view     = Zend_Registry::get('view');
>     > >
>     > >        if ($request->getParam('isAjax', false)) {
>     > >            // Ajax request detected
>     > >            // Get any variables set in the view
>     > >            $vars = get_object_vars($view);
>     > >
>     > >            // Merge with named path segments in response
>     > >            $vars = array_merge($vars, $response->getBody(true));
>     > >
>     > >            // Create a header and set the response body to a JSON value
>     > >            $resposne->setHeader('Content-Type', 'text/x-json');
>     > >            $response->setBody(Zend_Json::encode($vars));
>     > >            return;
>     > >        }
>     > >
>     > >        // Otherwise, process as normal
>     > >        $view->content = $response->getBody();
>     > >        $response->setBody($view->render('site.phtml'));
>     > >    }
>     --
>     Matthew Weier O'Phinney
>     PHP Developer            | matthew@...
>     Zend - The PHP Company   | http://www.zend.com/
>
>

--
Matthew Weier O'Phinney
PHP Developer            | matthew@...
Zend - The PHP Company   | http://www.zend.com/

Re: Controller and View Question

by Kevin McArthur-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Isn't that crossing the view/controller relationship boundary a bit. Would
it not be more correct to subclass Zend_View to provide $this->module and
$this->controller if you were going to take that approach?

If you're going to create an engine view, maybe create an engine model to
interact with it the way you want to. I'd just be nervous about putting in
controller logic in templates and view html in controllers as it might make
for some fun debugging later.

If you were to subclass, you could create two arrays $this->stylesheets and
$this->scripts and iterate them in the engine. If there were 0 entries, then
no output would result (and no empty files would be needed). Similarly you
can set the current title, page breadcrumbs etc.

You could also subclass Zend_Controller_Action instead and provide an init()
method to setup a view object the way you want it, then store it as
$this->view or such.

Theres lots of options

Kevin McArthur

----- Original Message -----
From: "Matthew Weier O'Phinney" <matthew@...>
To: <fw-general@...>
Sent: Tuesday, March 27, 2007 8:42 AM
Subject: Re: [fw-general] Controller and View Question


> -- Greg Neustaetter <gneustaetter@...> wrote
> (on Tuesday, 27 March 2007, 08:14 AM -0700):
>> The problem I see with an approach like this is that the view is tied
>> very
>> closely with the controller.  Should the controller have any idea about
>> which
>> javascript files need to be included on a particular page?  Finding a
>> solution
>> that minimizes the amount of common code that has to be placed in the
>> view but
>> still provides the view with the ability to inject javascript, css, page
>> titles, meta tags, etc to header seems to be a problem I haven't seen
>> answered
>> well in any framework.  The template may include a couple javascript or
>> css
>> files by default in every page, but even then, the page may choose to
>> remove
>> the default files if it chooses.
>>
>> Thoughts?
>
> A few.
>
> One is to do something similar to how Zend_Controller_Action::render()
> works, only with your css/js. So, in your sitewide template view script,
> have some logic like this:
>
>    <?php
>    $request     = Zend_Controller_Front::getInstance()->getRequest();
>    $module      = $request->getModuleName();
>    $controller  = $request->getControllerName();
>    ?>
>    <html>
>    <head>
>        <title><?= $this->escape($this->title) ?></title>
>        <link rel="stylesheet" type="text/css" href="/styles/site.css" />
>        <link rel="stylesheet" type="text/css" href="/styles/<?= $module
> ?>/<?= $controller ?>.css" />
>
> In this example, sitewide styles are kept under the /styles/ root in the
> webroot, and then segregated by module and controller:
>
>    /styles/
>        news/
>            list.css
>            item.css
>        blog/
>            archive.css
>
> In this way, you'd have some automation in how CSS (and you can extend
> the idea to JS scripts, too) is injected into the page. The problem is
> that you'd have to ensure that these files existed for each module and
> controller -- which could lead to a ton of empty, unused files on your
> machine.
>
> Another approach is to use set view variables from within component
> views. For example, if I have a view script for the NewsController, I
> could do this:
>
>    <?php
>    $this->dynamic_header[] = '<link rel="stylesheet" type="text/css"
> href="/styles/news.css" />';
>    ?>
>
> Then, assuming the sitewide template uses the same view object, it now
> has an additional header. This satisfies the requirement you had of
> keeping this logic out of the controller and in the view. It's a bit
> unwieldy, but it also solves the issue presented above of not needing to
> create a CSS file for every controller.
>
> I'm sure others have ideas as well.
>
>> On 3/27/07, Matthew Weier O'Phinney <matthew@...> wrote:
>>
>>     -- Dale McNeill <dale.mcneill@...> wrote
>>     (on Tuesday, 27 March 2007, 09:19 AM -0500):
>>     > I've got some CSS and javascript that I would like to dynamically
>> add to
>>     > the HTML header depending on the controller/action.  I would like
>> to be
>>     > able to append information like appending to the response body.
>> Then
>>     > use this information in a site wide template.  The only solution
>> that
>>     > comes to mind is using a view variable and having each
>> controller/action
>>     > get the variable, append it, and write it back to the view.  Is
>> there
>>     > some functionality that I might be overlooking? - Thanks
>>     >
>>     > Site wide template:
>>     > <html>
>>     > <head>
>>     > <title> <?php echo $this->title; ?> </title>
>>     > <?php echo $this->dynamic_header; ?>
>>
>>     Define $dynamic_header as an array in the view object. When you first
>>     initialize the view object, do something like this:
>>
>>         $view = new Zend_View();
>>         $view->dynamic_header = array();
>>
>>     Then, whenever you want to add to it, just add a new element to the
>>     array:
>>
>>         $view->dynamic_header[] = '<meta name="keywords" value="zend
>> framework
>>     zend_view" /> ';
>>
>>     Then, in the view script, iterate over the array:
>>
>>         <?php foreach ($this->dynamic_header as $header):
>>                 echo $header, "\n";
>>         endforeach; ?>
>>
>>     Finally, use a Two Step View as I've outlined previously in this
>> thread
>>     -- use a dispatchLoopShutdown() plugin to throw the response body
>> into a
>>     sitewide template (which it looks like you're doing here).
>>
>>     > </head>
>>     > <body>
>>     > ...common header...
>>     > <?php echo $this->content; ?>
>>     > ...common footer...
>>     > </body>
>>     > </html>
>>     >
>>     > Matthew Weier O'Phinney wrote:
>>     > > -- Arnaud Limbourg <arnaud@...> wrote
>>     > > (on Monday, 26 March 2007, 07:04 AM +0200):
>>     > >
>>     > > > Matthew Weier O'Phinney wrote:
>>     > > >
>>     > > > > I throw a Zend_View object in the registry, and then access
>> this
>>     from my
>>     > > > > controllers and plugins. The benefit of doing this is that
>> the
>>     > > > > controllers can set values in the view that are unused in
>> their
>>     > > > > individual view, but used later in the sitewide template.
>>     > > > >
>>     > > > > Then, I use a dispatchLoopShutdown() plugin to inject any
>> generated
>>     > > > > content into a sitwide template:
>>     > > > >
>>     > > > >
>>     > > > >   class SiteTemplatePlugin extends
>> Zend_Controller_Plugin_Abstract
>>     > > > >   {
>>     > > > >       public function dispatchLoopShutdown()
>>     > > > >       {
>>     > > > >           $response =
>>     > > > >
>> Zend_Controller_Front:;getInstance()->getResponse();
>>     > > > >           $view = Zend_Registry::get('view');
>>     > > > >           $view->content = $response->getBody();
>>     > > > >           $response->setBody($view->render(' site.phtml'));
>>     > > > >       }
>>     > > > >   }
>>     > > > >
>>     > > > Which poses a problem when you want to send back json (or
>> whatever)
>>     and
>>     > > > you don't want a site wide template :)
>>     > > >
>>     > >
>>     > > This was a simple example. But it's actually really easy to
>> return
>>     JSON:
>>     > >
>>     > >    public function dispatchLoopShutdown()
>>     > >    {
>>     > >        // assume that we've already determined the request is
>> ajax
>>     > >        $request  = $this->getRequest();
>>     > >        $response = $this->getResponse();
>>     > >        $view     = Zend_Registry::get('view');
>>     > >
>>     > >        if ($request->getParam('isAjax', false)) {
>>     > >            // Ajax request detected
>>     > >            // Get any variables set in the view
>>     > >            $vars = get_object_vars($view);
>>     > >
>>     > >            // Merge with named path segments in response
>>     > >            $vars = array_merge($vars, $response->getBody(true));
>>     > >
>>     > >            // Create a header and set the response body to a JSON
>> value
>>     > >            $resposne->setHeader('Content-Type', 'text/x-json');
>>     > >            $response->setBody(Zend_Json::encode($vars));
>>     > >            return;
>>     > >        }
>>     > >
>>     > >        // Otherwise, process as normal
>>     > >        $view->content = $response->getBody();
>>     > >        $response->setBody($view->render('site.phtml'));
>>     > >    }
>>     --
>>     Matthew Weier O'Phinney
>>     PHP Developer            | matthew@...
>>     Zend - The PHP Company   | http://www.zend.com/
>>
>>
>
> --
> Matthew Weier O'Phinney
> PHP Developer            | matthew@...
> Zend - The PHP Company   | http://www.zend.com/ 


Re: Controller and View Question

by weierophinney :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

-- Kevin McArthur <kevin@...> wrote
(on Tuesday, 27 March 2007, 10:22 AM -0700):

> Isn't that crossing the view/controller relationship boundary a bit. Would
> it not be more correct to subclass Zend_View to provide $this->module and
> $this->controller if you were going to take that approach?
>
> If you're going to create an engine view, maybe create an engine model to
> interact with it the way you want to. I'd just be nervous about putting in
> controller logic in templates and view html in controllers as it might make
> for some fun debugging later.
>
> If you were to subclass, you could create two arrays $this->stylesheets and
> $this->scripts and iterate them in the engine. If there were 0 entries,
> then no output would result (and no empty files would be needed). Similarly
> you can set the current title, page breadcrumbs etc.
>
> You could also subclass Zend_Controller_Action instead and provide an
> init() method to setup a view object the way you want it, then store it as
> $this->view or such.
>
> Theres lots of options

I've provided three now, one of which had no reliance on the controllers
(have the component view set variables to be used by the sitewide view).
This built on the original method I suggested of using array variables
in the view script -- just setting them from individual views instead of
the controller.

There are many ways to do this, some involving injections from the
controller (and remember, such interactions are part of the MVC pattern,
as are interactions between the view and model -- the controller may
provide hints to the view as to what should or should not be displayed;
the view may pull data directly from the model to display, etc), some
using the values already in the view (or the location of the view
itself) to determine what data to pull, etc.

You say "theres lots of options" -- post them to the list so we can see
how *you* tackle the issue. The more concrete solutions, the better!


> ----- Original Message -----
> From: "Matthew Weier O'Phinney" <matthew@...>
> To: <fw-general@...>
> Sent: Tuesday, March 27, 2007 8:42 AM
> Subject: Re: [fw-general] Controller and View Question
>
>
> >-- Greg Neustaetter <gneustaetter@...> wrote
> >(on Tuesday, 27 March 2007, 08:14 AM -0700):
> >>The problem I see with an approach like this is that the view is tied
> >>very
> >>closely with the controller.  Should the controller have any idea about
> >>which
> >>javascript files need to be included on a particular page?  Finding a
> >>solution
> >>that minimizes the amount of common code that has to be placed in the
> >>view but
> >>still provides the view with the ability to inject javascript, css, page
> >>titles, meta tags, etc to header seems to be a problem I haven't seen
> >>answered
> >>well in any framework.  The template may include a couple javascript or
> >>css
> >>files by default in every page, but even then, the page may choose to
> >>remove
> >>the default files if it chooses.
> >>
> >>Thoughts?
> >
> >A few.
> >
> >One is to do something similar to how Zend_Controller_Action::render()
> >works, only with your css/js. So, in your sitewide template view script,
> >have some logic like this:
> >
> >   <?php
> >   $request     = Zend_Controller_Front::getInstance()->getRequest();
> >   $module      = $request->getModuleName();
> >   $controller  = $request->getControllerName();
> >   ?>
> >   <html>
> >   <head>
> >       <title><?= $this->escape($this->title) ?></title>
> >       <link rel="stylesheet" type="text/css" href="/styles/site.css" />
> >       <link rel="stylesheet" type="text/css" href="/styles/<?= $module
> >?>/<?= $controller ?>.css" />
> >
> >In this example, sitewide styles are kept under the /styles/ root in the
> >webroot, and then segregated by module and controller:
> >
> >   /styles/
> >       news/
> >           list.css
> >           item.css
> >       blog/
> >           archive.css
> >
> >In this way, you'd have some automation in how CSS (and you can extend
> >the idea to JS scripts, too) is injected into the page. The problem is
> >that you'd have to ensure that these files existed for each module and
> >controller -- which could lead to a ton of empty, unused files on your
> >machine.
> >
> >Another approach is to use set view variables from within component
> >views. For example, if I have a view script for the NewsController, I
> >could do this:
> >
> >   <?php
> >   $this->dynamic_header[] = '<link rel="stylesheet" type="text/css"
> >href="/styles/news.css" />';
> >   ?>
> >
> >Then, assuming the sitewide template uses the same view object, it now
> >has an additional header. This satisfies the requirement you had of
> >keeping this logic out of the controller and in the view. It's a bit
> >unwieldy, but it also solves the issue presented above of not needing to
> >create a CSS file for every controller.
> >
> >I'm sure others have ideas as well.
> >
> >>On 3/27/07, Matthew Weier O'Phinney <matthew@...> wrote:
> >>
> >>    -- Dale McNeill <dale.mcneill@...> wrote
> >>    (on Tuesday, 27 March 2007, 09:19 AM -0500):
> >>    > I've got some CSS and javascript that I would like to dynamically
> >>add to
> >>    > the HTML header depending on the controller/action.  I would like
> >>to be
> >>    > able to append information like appending to the response body.
> >>Then
> >>    > use this information in a site wide template.  The only solution
> >>that
> >>    > comes to mind is using a view variable and having each
> >>controller/action
> >>    > get the variable, append it, and write it back to the view.  Is
> >>there
> >>    > some functionality that I might be overlooking? - Thanks
> >>    >
> >>    > Site wide template:
> >>    > <html>
> >>    > <head>
> >>    > <title> <?php echo $this->title; ?> </title>
> >>    > <?php echo $this->dynamic_header; ?>
> >>
> >>    Define $dynamic_header as an array in the view object. When you first
> >>    initialize the view object, do something like this:
> >>
> >>        $view = new Zend_View();
> >>        $view->dynamic_header = array();
> >>
> >>    Then, whenever you want to add to it, just add a new element to the
> >>    array:
> >>
> >>        $view->dynamic_header[] = '<meta name="keywords" value="zend
> >>framework
> >>    zend_view" /> ';
> >>
> >>    Then, in the view script, iterate over the array:
> >>
> >>        <?php foreach ($this->dynamic_header as $header):
> >>                echo $header, "\n";
> >>        endforeach; ?>
> >>
> >>    Finally, use a Two Step View as I've outlined previously in this
> >>thread
> >>    -- use a dispatchLoopShutdown() plugin to throw the response body
> >>into a
> >>    sitewide template (which it looks like you're doing here).
> >>
> >>    > </head>
> >>    > <body>
> >>    > ...common header...
> >>    > <?php echo $this->content; ?>
> >>    > ...common footer...
> >>    > </body>
> >>    > </html>
> >>    >
> >>    > Matthew Weier O'Phinney wrote:
> >>    > > -- Arnaud Limbourg <arnaud@...> wrote
> >>    > > (on Monday, 26 March 2007, 07:04 AM +0200):
> >>    > >
> >>    > > > Matthew Weier O'Phinney wrote:
> >>    > > >
> >>    > > > > I throw a Zend_View object in the registry, and then access
> >>this
> >>    from my
> >>    > > > > controllers and plugins. The benefit of doing this is that
> >>the
> >>    > > > > controllers can set values in the view that are unused in
> >>their
> >>    > > > > individual view, but used later in the sitewide template.
> >>    > > > >
> >>    > > > > Then, I use a dispatchLoopShutdown() plugin to inject any
> >>generated
> >>    > > > > content into a sitwide template:
> >>    > > > >
> >>    > > > >
> >>    > > > >   class SiteTemplatePlugin extends
> >>Zend_Controller_Plugin_Abstract
> >>    > > > >   {
> >>    > > > >       public function dispatchLoopShutdown()
> >>    > > > >       {
> >>    > > > >           $response =
> >>    > > > >
> >>Zend_Controller_Front:;getInstance()->getResponse();
> >>    > > > >           $view = Zend_Registry::get('view');
> >>    > > > >           $view->content = $response->getBody();
> >>    > > > >           $response->setBody($view->render(' site.phtml'));
> >>    > > > >       }
> >>    > > > >   }
> >>    > > > >
> >>    > > > Which poses a problem when you want to send back json (or
> >>whatever)
> >>    and
> >>    > > > you don't want a site wide template :)
> >>    > > >
> >>    > >
> >>    > > This was a simple example. But it's actually really easy to
> >>return
> >>    JSON:
> >>    > >
> >>    > >    public function dispatchLoopShutdown()
> >>    > >    {
> >>    > >        // assume that we've already determined the request is
> >>ajax
> >>    > >        $request  = $this->getRequest();
> >>    > >        $response = $this->getResponse();
> >>    > >        $view     = Zend_Registry::get('view');
> >>    > >
> >>    > >        if ($request->getParam('isAjax', false)) {
> >>    > >            // Ajax request detected
> >>    > >            // Get any variables set in the view
> >>    > >            $vars = get_object_vars($view);
> >>    > >
> >>    > >            // Merge with named path segments in response
> >>    > >            $vars = array_merge($vars, $response->getBody(true));
> >>    > >
> >>    > >            // Create a header and set the response body to a JSON
> >>value
> >>    > >            $resposne->setHeader('Content-Type', 'text/x-json');
> >>    > >            $response->setBody(Zend_Json::encode($vars));
> >>    > >            return;
> >>    > >        }
> >>    > >
> >>    > >        // Otherwise, process as normal
> >>    > >        $view->content = $response->getBody();
> >>    > >        $response->setBody($view->render('site.phtml'));
> >>    > >    }
> >>    --
> >>    Matthew Weier O'Phinney
> >>    PHP Developer            | matthew@...
> >>    Zend - The PHP Company   | http://www.zend.com/
> >>
> >>
> >
> >--
> >Matthew Weier O'Phinney
> >PHP Developer            | matthew@...
> >Zend - The PHP Company   | http://www.zend.com/ 
>

--
Matthew Weier O'Phinney
PHP Developer            | matthew@...
Zend - The PHP Company   | http://www.zend.com/

Re: Controller and View Question

by Andries Seutens :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello,

I have chosen to override Zend_Controller_Action. My template structure
is as follows:

/templates
   /default
     /blog
       archive.html
       post.html
       ...
     /news
       archive.html
       post.html
       ...
     blog.html
     news.html
     template.html

When i call *_Action::render() i first check if there is a "main
template" available for a certain module. In the example above those
would be "blog.html" and "news.html".

These templates will then be used as the "main" template for this
module, and will have the parsed content of the "action script" assigned
to them (archive.html, post.html, ...), eventually the parsed content
will be loaded into the sitewide template "template.html"

If the "main template" for a specified module doesn't exist, then the
parsed content of the "action script" will directly be assigned to the
sitewide template.

Here's an example:
http://andries.systray.be/Action.phps

Best,

Andriesss

Matthew Weier O'Phinney schreef:

> -- Kevin McArthur <kevin@...> wrote
> (on Tuesday, 27 March 2007, 10:22 AM -0700):
>> Isn't that crossing the view/controller relationship boundary a bit. Would
>> it not be more correct to subclass Zend_View to provide $this->module and
>> $this->controller if you were going to take that approach?
>>
>> If you're going to create an engine view, maybe create an engine model to
>> interact with it the way you want to. I'd just be nervous about putting in
>> controller logic in templates and view html in controllers as it might make
>> for some fun debugging later.
>>
>> If you were to subclass, you could create two arrays $this->stylesheets and
>> $this->scripts and iterate them in the engine. If there were 0 entries,
>> then no output would result (and no empty files would be needed). Similarly
>> you can set the current title, page breadcrumbs etc.
>>
>> You could also subclass Zend_Controller_Action instead and provide an
>> init() method to setup a view object the way you want it, then store it as
>> $this->view or such.
>>
>> Theres lots of options
>
> I've provided three now, one of which had no reliance on the controllers
> (have the component view set variables to be used by the sitewide view).
> This built on the original method I suggested of using array variables
> in the view script -- just setting them from individual views instead of
> the controller.
>
> There are many ways to do this, some involving injections from the
> controller (and remember, such interactions are part of the MVC pattern,
> as are interactions between the view and model -- the controller may
> provide hints to the view as to what should or should not be displayed;
> the view may pull data directly from the model to display, etc), some
> using the values already in the view (or the location of the view
> itself) to determine what data to pull, etc.
>
> You say "theres lots of options" -- post them to the list so we can see
> how *you* tackle the issue. The more concrete solutions, the better!
>
>
>> ----- Original Message -----
>> From: "Matthew Weier O'Phinney" <matthew@...>
>> To: <fw-general@...>
>> Sent: Tuesday, March 27, 2007 8:42 AM
>> Subject: Re: [fw-general] Controller and View Question
>>
>>
>>> -- Greg Neustaetter <gneustaetter@...> wrote
>>> (on Tuesday, 27 March 2007, 08:14 AM -0700):
>>>> The problem I see with an approach like this is that the view is tied
>>>> very
>>>> closely with the controller.  Should the controller have any idea about
>>>> which
>>>> javascript files need to be included on a particular page?  Finding a
>>>> solution
>>>> that minimizes the amount of common code that has to be placed in the
>>>> view but
>>>> still provides the view with the ability to inject javascript, css, page
>>>> titles, meta tags, etc to header seems to be a problem I haven't seen
>>>> answered
>>>> well in any framework.  The template may include a couple javascript or
>>>> css
>>>> files by default in every page, but even then, the page may choose to
>>>> remove
>>>> the default files if it chooses.
>>>>
>>>> Thoughts?
>>> A few.
>>>
>>> One is to do something similar to how Zend_Controller_Action::render()
>>> works, only with your css/js. So, in your sitewide template view script,
>>> have some logic like this:
>>>
>>>   <?php
>>>   $request     = Zend_Controller_Front::getInstance()->getRequest();
>>>   $module      = $request->getModuleName();
>>>   $controller  = $request->getControllerName();
>>>   ?>
>>>   <html>
>>>   <head>
>>>       <title><?= $this->escape($this->title) ?></title>
>>>       <link rel="stylesheet" type="text/css" href="/styles/site.css" />
>>>       <link rel="stylesheet" type="text/css" href="/styles/<?= $module
>>> ?>/<?= $controller ?>.css" />
>>>
>>> In this example, sitewide styles are kept under the /styles/ root in the
>>> webroot, and then segregated by module and controller:
>>>
>>>   /styles/
>>>       news/
>>>           list.css
>>>           item.css
>>>       blog/
>>>           archive.css
>>>
>>> In this way, you'd have some automation in how CSS (and you can extend
>>> the idea to JS scripts, too) is injected into the page. The problem is
>>> that you'd have to ensure that these files existed for each module and
>>> controller -- which could lead to a ton of empty, unused files on your
>>> machine.
>>>
>>> Another approach is to use set view variables from within component
>>> views. For example, if I have a view script for the NewsController, I
>>> could do this:
>>>
>>>   <?php
>>>   $this->dynamic_header[] = '<link rel="stylesheet" type="text/css"
>>> href="/styles/news.css" />';
>>>   ?>
>>>
>>> Then, assuming the sitewide template uses the same view object, it now
>>> has an additional header. This satisfies the requirement you had of
>>> keeping this logic out of the controller and in the view. It's a bit
>>> unwieldy, but it also solves the issue presented above of not needing to
>>> create a CSS file for every controller.
>>>
>>> I'm sure others have ideas as well.
>>>
>>>> On 3/27/07, Matthew Weier O'Phinney <matthew@...> wrote:
>>>>
>>>>    -- Dale McNeill <dale.mcneill@...> wrote
>>>>    (on Tuesday, 27 March 2007, 09:19 AM -0500):
>>>>    > I've got some CSS and javascript that I would like to dynamically
>>>> add to
>>>>    > the HTML header depending on the controller/action.  I would like
>>>> to be
>>>>    > able to append information like appending to the response body.
>>>> Then
>>>>    > use this information in a site wide template.  The only solution
>>>> that
>>>>    > comes to mind is using a view variable and having each
>>>> controller/action
>>>>    > get the variable, append it, and write it back to the view.  Is
>>>> there
>>>>    > some functionality that I might be overlooking? - Thanks
>>>>    >
>>>>    > Site wide template:
>>>>    > <html>
>>>>    > <head>
>>>>    > <title> <?php echo $this->title; ?> </title>
>>>>    > <?php echo $this->dynamic_header; ?>
>>>>
>>>>    Define $dynamic_header as an array in the view object. When you first
>>>>    initialize the view object, do something like this:
>>>>
>>>>        $view = new Zend_View();
>>>>        $view->dynamic_header = array();
>>>>
>>>>    Then, whenever you want to add to it, just add a new element to the
>>>>    array:
>>>>
>>>>        $view->dynamic_header[] = '<meta name="keywords" value="zend
>>>> framework
>>>>    zend_view" /> ';
>>>>
>>>>    Then, in the view script, iterate over the array:
>>>>
>>>>        <?php foreach ($this->dynamic_header as $header):
>>>>                echo $header, "\n";
>>>>        endforeach; ?>
>>>>
>>>>    Finally, use a Two Step View as I've outlined previously in this
>>>> thread
>>>>    -- use a dispatchLoopShutdown() plugin to throw the response body
>>>> into a
>>>>    sitewide template (which it looks like you're doing here).
>>>>
>>>>    > </head>
>>>>    > <body>
>>>>    > ...common header...
>>>>    > <?php echo $this->content; ?>
>>>>    > ...common footer...
>>>>    > </body>
>>>>    > </html>
>>>>    >
>>>>    > Matthew Weier O'Phinney wrote:
>>>>    > > -- Arnaud Limbourg <arnaud@...> wrote
>>>>    > > (on Monday, 26 March 2007, 07:04 AM +0200):
>>>>    > >
>>>>    > > > Matthew Weier O'Phinney wrote:
>>>>    > > >
>>>>    > > > > I throw a Zend_View object in the registry, and then access
>>>> this
>>>>    from my
>>>>    > > > > controllers and plugins. The benefit of doing this is that
>>>> the
>>>>    > > > > controllers can set values in the view that are unused in
>>>> their
>>>>    > > > > individual view, but used later in the sitewide template.
>>>>    > > > >
>>>>    > > > > Then, I use a dispatchLoopShutdown() plugin to inject any
>>>> generated
>>>>    > > > > content into a sitwide template:
>>>>    > > > >
>>>>    > > > >
>>>>    > > > >   class SiteTemplatePlugin extends
>>>> Zend_Controller_Plugin_Abstract
>>>>    > > > >   {
>>>>    > > > >       public function dispatchLoopShutdown()
>>>>    > > > >       {
>>>>    > > > >           $response =
>>>>    > > > >
>>>> Zend_Controller_Front:;getInstance()->getResponse();
>>>>    > > > >           $view = Zend_Registry::get('view');
>>>>    > > > >           $view->content = $response->getBody();
>>>>    > > > >           $response->setBody($view->render(' site.phtml'));
>>>>    > > > >       }
>>>>    > > > >   }
>>>>    > > > >
>>>>    > > > Which poses a problem when you want to send back json (or
>>>> whatever)
>>>>    and
>>>>    > > > you don't want a site wide template :)
>>>>    > > >
>>>>    > >
>>>>    > > This was a simple example. But it's actually really easy to
>>>> return
>>>>    JSON:
>>>>    > >
>>>>    > >    public function dispatchLoopShutdown()
>>>>    > >    {
>>>>    > >        // assume that we've already determined the request is
>>>> ajax
>>>>    > >        $request  = $this->getRequest();
>>>>    > >        $response = $this->getResponse();
>>>>    > >        $view     = Zend_Registry::get('view');
>>>>    > >
>>>>    > >        if ($request->getParam('isAjax', false)) {
>>>>    > >            // Ajax request detected
>>>>    > >            // Get any variables set in the view
>>>>    > >            $vars = get_object_vars($view);
>>>>    > >
>>>>    > >            // Merge with named path segments in response
>>>>    > >            $vars = array_merge($vars, $response->getBody(true));
>>>>    > >
>>>>    > >            // Create a header and set the response body to a JSON
>>>> value
>>>>    > >            $resposne->setHeader('Content-Type', 'text/x-json');
>>>>    > >            $response->setBody(Zend_Json::encode($vars));
>>>>    > >            return;
>>>>    > >        }
>>>>    > >
>>>>    > >        // Otherwise, process as normal
>>>>    > >        $view->content = $response->getBody();
>>>>    > >        $response->setBody($view->render('site.phtml'));
>>>>    > >    }
>>>>    --
>>>>    Matthew Weier O'Phinney
>>>>    PHP Developer            | matthew@...
>>>>    Zend - The PHP Company   | http://www.zend.com/
>>>>
>>>>
>>> --
>>> Matthew Weier O'Phinney
>>> PHP Developer            | matthew@...
>>> Zend - The PHP Company   | http://www.zend.com/ 
>


Re: Controller and View Question

by Dr Livingston :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

What I do is to treat the HEAD as a separate View in it's self, so you can use either a common template for site wide, or a more specific template for any given request.

Thus, I can add Javascript, Meta Tags etc on demand, without effecting the rest of the system. On another note, I think it's a bad idea, architecturally, to be dependent on using plugins to aid in your output generation.

The functionality and facilities should already be there, available in a lower layer.

Matthew Weier O'Phinney-3 wrote:
-- Dale McNeill <dale.mcneill@alchemysystems.com> wrote
(on Tuesday, 27 March 2007, 09:19 AM -0500):
> I've got some CSS and javascript that I would like to dynamically add to
> the HTML header depending on the controller/action.  I would like to be
> able to append information like appending to the response body.  Then
> use this information in a site wide template.  The only solution that
> comes to mind is using a view variable and having each controller/action
> get the variable, append it, and write it back to the view.  Is there
> some functionality that I might be overlooking? - Thanks
>
> Site wide template:
> <html>
> <head>
> <title> <?php echo $this->title; ?> </title>
> <?php echo $this->dynamic_header; ?>

Define $dynamic_header as an array in the view object. When you first
initialize the view object, do something like this:

    $view = new Zend_View();
    $view->dynamic_header = array();

Then, whenever you want to add to it, just add a new element to the
array:

    $view->dynamic_header[] = '<meta name="keywords" value="zend framework zend_view" /> ';

Then, in the view script, iterate over the array:

    <?php foreach ($this->dynamic_header as $header):
            echo $header, "\n";
    endforeach; ?>

Finally, use a Two Step View as I've outlined previously in this thread
-- use a dispatchLoopShutdown() plugin to throw the response body into a
sitewide template (which it looks like you're doing here).

> </head>
> <body>
> ...common header...
> <?php echo $this->content; ?>
> ...common footer...
> </body>
> </html>
>
> Matthew Weier O'Phinney wrote:
> > -- Arnaud Limbourg <arnaud@limbourg.com> wrote
> > (on Monday, 26 March 2007, 07:04 AM +0200):
> >  
> > > Matthew Weier O'Phinney wrote:
> > >    
> > > > I throw a Zend_View object in the registry, and then access this from my
> > > > controllers and plugins. The benefit of doing this is that the
> > > > controllers can set values in the view that are unused in their
> > > > individual view, but used later in the sitewide template.
> > > >
> > > > Then, I use a dispatchLoopShutdown() plugin to inject any generated
> > > > content into a sitwide template:
> > > >
> > > >
> > > >   class SiteTemplatePlugin extends Zend_Controller_Plugin_Abstract
> > > >   {
> > > >       public function dispatchLoopShutdown()
> > > >       {
> > > >           $response =
> > > >           Zend_Controller_Front:;getInstance()->getResponse();
> > > >           $view = Zend_Registry::get('view');
> > > >           $view->content = $response->getBody();
> > > >           $response->setBody($view->render('site.phtml'));
> > > >       }
> > > >   }
> > > >      
> > > Which poses a problem when you want to send back json (or whatever) and
> > > you don't want a site wide template :)
> > >    
> >
> > This was a simple example. But it's actually really easy to return JSON:
> >
> >    public function dispatchLoopShutdown()
> >    {
> >        // assume that we've already determined the request is ajax
> >        $request  = $this->getRequest();
> >        $response = $this->getResponse();
> >        $view     = Zend_Registry::get('view');
> >
> >        if ($request->getParam('isAjax', false)) {
> >            // Ajax request detected
> >            // Get any variables set in the view
> >            $vars = get_object_vars($view);
> >
> >            // Merge with named path segments in response
> >            $vars = array_merge($vars, $response->getBody(true));
> >
> >            // Create a header and set the response body to a JSON value
> >            $resposne->setHeader('Content-Type', 'text/x-json');
> >            $response->setBody(Zend_Json::encode($vars));
> >            return;
> >        }
> >
> >        // Otherwise, process as normal
> >        $view->content = $response->getBody();
> >        $response->setBody($view->render('site.phtml'));
> >    }
--
Matthew Weier O'Phinney
PHP Developer            | matthew@zend.com
Zend - The PHP Company   | http://www.zend.com/

Parent Message unknown Re: Controller and View Question

by Pádraic Brady :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

The way the Zend_View Enhanced proposal  (and also the Zend_View_Helper_* proposal) address this is to setup a centrally registered data store all View templates can access. Then any sub-templates which compose the end View can dynamically add/append/remove items. Both proposals add specific helpers for each of scripts, styles, title, etc. in the HEAD section.

Alternatively, if defining template by template seems confusing, one could use the same system in a more Java-esque way (think the Tiles tag library plugin for Struts) and define such upfront in a set of site specific template files which are included by the base View template only, or included by some other means into the sitewide layout template (if using the ZVE approach). These can then be injected in the layout template holding the HEAD section using simple echo's (all these helpers inplement __toString() and allow for very specific element ordering which is sometimes important for script inclusion).

<head>
<?php echo $this->headTitle() ?>
<?php echo $this->headStyle() ?>
<?php echo $this->headScript() ?>
</head>

The upfront configuration method is also useful in the case that you define which configuration to utilise as a View variable set by the base Controller. It would just need to be included early into the base View object so it's not overwriting any subtemplate alterations (which a user may choose to enforce since they can't be completely determined upfront for some reason).

Regards,
Pádraic
 
Pádraic Brady
http://blog.astrumfutura.com
http://www.patternsforphp.com



----- Original Message ----
From: Dr Livingston <nukebaghdad@...>
To: fw-general@...
Sent: Saturday, July 14, 2007 9:07:50 PM
Subject: Re: [fw-general] Controller and View Question


What I do is to treat the HEAD as a separate View in it's self, so you can
use either a common template for site wide, or a more specific template for
any given request.

Thus, I can add Javascript, Meta Tags etc on demand, without effecting the
rest of the system. On another note, I think it's a bad idea,
architecturally, to be dependent on using plugins to aid in your output
generation.

The functionality and facilities should already be there, available in a
lower layer.


Matthew Weier O'Phinney-3 wrote:

>
> -- Dale McNeill <dale.mcneill@...> wrote
> (on Tuesday, 27 March 2007, 09:19 AM -0500):
>> I've got some CSS and javascript that I would like to dynamically add to
>> the HTML header depending on the controller/action.  I would like to be
>> able to append information like appending to the response body.  Then
>> use this information in a site wide template.  The only solution that
>> comes to mind is using a view variable and having each controller/action
>> get the variable, append it, and write it back to the view.  Is there
>> some functionality that I might be overlooking? - Thanks
>>
>> Site wide template:
>> <html>
>> <head>
>> <title> <?php echo $this->title; ?> </title>
>> <?php echo $this->dynamic_header; ?>
>
> Define $dynamic_header as an array in the view object. When you first
> initialize the view object, do something like this:
>
>     $view = new Zend_View();
>     $view->dynamic_header = array();
>
> Then, whenever you want to add to it, just add a new element to the
> array:
>
>     $view->dynamic_header[] = '<meta name="keywords" value="zend framework
> zend_view" /> ';
>
> Then, in the view script, iterate over the array:
>
>     <?php foreach ($this->dynamic_header as $header):
>             echo $header, "\n";
>     endforeach; ?>
>
> Finally, use a Two Step View as I've outlined previously in this thread
> -- use a dispatchLoopShutdown() plugin to throw the response body into a
> sitewide template (which it looks like you're doing here).
>
>> </head>
>> <body>
>> ...common header...
>> <?php echo $this->content; ?>
>> ...common footer...
>> </body>
>> </html>
>>
>> Matthew Weier O'Phinney wrote:
>> > -- Arnaud Limbourg <arnaud@...> wrote
>> > (on Monday, 26 March 2007, 07:04 AM +0200):
>> >  
>> > > Matthew Weier O'Phinney wrote:
>> > >    
>> > > > I throw a Zend_View object in the registry, and then access this
>> from my
>> > > > controllers and plugins. The benefit of doing this is that the
>> > > > controllers can set values in the view that are unused in their
>> > > > individual view, but used later in the sitewide template.
>> > > >
>> > > > Then, I use a dispatchLoopShutdown() plugin to inject any generated
>> > > > content into a sitwide template:
>> > > >
>> > > >
>> > > >   class SiteTemplatePlugin extends Zend_Controller_Plugin_Abstract
>> > > >   {
>> > > >       public function dispatchLoopShutdown()
>> > > >       {
>> > > >           $response =
>> > > >           Zend_Controller_Front:;getInstance()->getResponse();
>> > > >           $view = Zend_Registry::get('view');
>> > > >           $view->content = $response->getBody();
>> > > >           $response->setBody($view->render('site.phtml'));
>> > > >       }
>> > > >   }
>> > > >      
>> > > Which poses a problem when you want to send back json (or whatever)
>> and
>> > > you don't want a site wide template :)
>> > >    
>> >
>> > This was a simple example. But it's actually really easy to return
>> JSON:
>> >
>> >    public function dispatchLoopShutdown()
>> >    {
>> >        // assume that we've already determined the request is ajax
>> >        $request  = $this->getRequest();
>> >        $response = $this->getResponse();
>> >        $view     = Zend_Registry::get('view');
>> >
>> >        if ($request->getParam('isAjax', false)) {
>> >            // Ajax request detected
>> >            // Get any variables set in the view
>> >            $vars = get_object_vars($view);
>> >
>> >            // Merge with named path segments in response
>> >            $vars = array_merge($vars, $response->getBody(true));
>> >
>> >            // Create a header and set the response body to a JSON value
>> >            $resposne->setHeader('Content-Type', 'text/x-json');
>> >            $response->setBody(Zend_Json::encode($vars));
>> >            return;
>> >        }
>> >
>> >        // Otherwise, process as normal
>> >        $view->content = $response->getBody();
>> >        $response->setBody($view->render('site.phtml'));
>> >    }
> --
> Matthew Weier O'Phinney
> PHP Developer            | matthew@...
> Zend - The PHP Company   | http://www.zend.com/
>
>

--
View this message in context: http://www.nabble.com/Controller-and-View-Question-tf3462561s16154.html#a11596858
Sent from the Zend Framework mailing list archive at Nabble.com.




Sucker-punch spam with award-winning protection.
Try the free Yahoo! Mail Beta.
Pádraic Brady

Blog: http://blog.astrumfutura.com
Free Zend Framework Book: http://www.survivethedeepend.com
OpenID Europe Foundation - Irish Representative