|
View:
New views
20 Messages
—
Rating Filter:
Alert me
|
|
|
Controller and View QuestionHey 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 QuestionRalph 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 QuestionHi
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-- 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 QuestionMatthew 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. > > 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-- 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 QuestionMatthew 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 QuestionAnother 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-- 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 QuestionI 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.
|
|
|
Re: Controller and View QuestionI'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-- 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 |
|
|
Re: Controller and View QuestionThe 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 |
|
|
Re: 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 QuestionIsn'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-- 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 QuestionHello,
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 QuestionWhat 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.
|
|
|
|
| Free embeddable forum powered by Nabble | Forum Help |