Page 1 of 1

repetitive calls to template engine

Posted: Mon Sep 05, 2005 2:16 pm
by josh
I am going to need to make repetitive calls to my template engine, across several page and I am trying to figure out the best way to avoid calling each method one by one on each page, my average call will look like this:

Code: Select all

require_once('class.php');

$template = new template('main');

$template -> setTitle('Title of my web page');
// I'm still deciding how I want to send the menu items (as an array, one by one or have a default list hard coded into the class
// but I will most likely want to keep the template class generic, and have nothing hard coded in it except the methods needed
$template -> addMenuItem('Home');
$template -> addMenuItem('About');
$template -> addMenuItem('FAQ');
$template -> addMenuItem('Portfolio');

$template -> setLoginBox(
     (bool)$user -> validated()
);

$template -> header();

echo 'Hello world';

$template -> footer();

$template -> output();
I was thinking instead of putting all that on every page, I could increase readability and make it easier to make site wide changes by having all the repetitive calls done by some sort of abstraction. Like I said in the comment I don't really want defaults in the template class. I could perhaps have a class that extends the template class, and that class would make all those calls for me, but that might be headed in the wrong direction? Another thing I could possibly do is have a function defined in class.php (the file I include on every page, has database connection settings, includes common class definitions, starts the session, etc...) I could write a function in there and have it make all the calls for me, the problem with that is how the function would make the calls. Would it involve passing the $template object by reference? or should I access the $template object on the global scope? But if I do the global scope thing, that would involve relying on what I named my identifier, which is 'bad practice', as I plan on using a lot of this code for a great deal of many projects in the near future.


If anyone has done something like this could you tell me the methods in which you used? Thanks for your help, hopefully I find a 'clean' way to do what I want

Posted: Mon Sep 05, 2005 2:20 pm
by s.dot
Eh, if it's not broke, why fix it? Code readability shouldn't play too much of a factor, and if you comment the code, that should make the readability that much easier.

But as you noted in your comment, I think an array would look nice.

Code: Select all

$menus = array('item1','item2','item3','etc');
foreach($menu AS menu)
{
   addMenuItem($menu);
}

Posted: Mon Sep 05, 2005 2:25 pm
by josh
Yeah, I'll most likely go with an array for menu items, especially since I want to be able to pass a multi dimensional array, so I can have a menu where you expand an item to reveal 5 or 6 sub-items.

And the example I posted is just a few calls, some pages would need 100's of calls, and as I'm still writing the class itself I don't know my exact API, therefore I just posted a couple things for example's sake here, and code readability is a huge factor in a 10,000 line + script :D

What I'm most concerned with is wether I should use a function to make those calls, and if so pass object as reference, or use global scope
or, should I have a class extending the template class, with methods for default calls... which sounds like my best option

so I'd go:

$template -> sendDefaultMenu();

Then later I can add more menu items manually from each script


edit: eh, I guess I'll mention this is going to be a heavily javascript oriented site, so that is why I need so many methods, I need to be able control what javascript function definitions get sent in which files, among other things... right now I'm still drawing up my design plan, but while I'm doing that I figured I'd start designing the template engine's API

Posted: Mon Sep 05, 2005 4:40 pm
by nielsene
Yeah I think I'd make another class "PageLayout" or something similar that bundles most of the calls to the template class.

So you'd have something like

Code: Select all

$page =& new PageLayout("main","Title",$user);
echo "Hello World"; // Assume your using outbuffering to inject this when you call output?
$page->output();
Now the PageLayout class

Code: Select all

class PageLayout
   var $_template;
   function PageLayout($templateType,$title,$user) {
      $this->_template =& new template($templateType);
      $this->_template->setTitle($title);
      $this->_template->addMenuItem(...);
      $this->_template->sertLoginBox((bool)$user->validated());
      $this->_template->header();
      $this->_template->footer();
   }
   function output() {
     echo $this->_template->output();
  }
}
Or something like that, depending on your implementation.

Posted: Mon Sep 05, 2005 9:52 pm
by Christopher
You may want to specify your pages with an INI file or simply an array. PHP has some pretty good support for sturctured INI files that you could use. Then you could just have your central controller script read the appropriate INI file (or PHP file with an array defined) and feed the data to the controller. e.g.

Code: Select all

$page = array(
'template' => 'main',
'title' => 'Title of my web page',
'menu' => array('item1','item2','item3','etc'),
'content' => 'Hello world',
);
$controller = new PageController($page);
$controller->execute($Request);

Posted: Tue Sep 06, 2005 7:09 am
by McGruff
What would happen if you turn the Template class inside out ie rather than php code containing html, you'd have html (or etc) template files containing some php snippets?

My general view is that php is for manhandling data. Other tools are better at dealing with formatting.

Posted: Tue Sep 06, 2005 12:17 pm
by josh
It would be easier for me to write a class to do what I'm doing then it would be for my php code to contain html, my site is going to be heavily javascript / flash and rely a lot on RPC, it would just be so much easier for me to serialize an object to the session to ensure the write javascript gets outputted on the right pages, I don't think the ini idea is the best idea for this project, because although most pages will be pretty consistent in whcih default settings they use, I might need to change a default depending on a setting that a user has set or something like that, I need something more dynamic. I'll most likely go with nielsen's recommendation, having a controller for the template class, but break down calls into differnet methods:

$template -> defaultMenuItems();
$template -> defaultHeaderData();

and then have a way to override defaults, say for instance I want every default menuitem excluding the login link:

$template -> defaultMenuItems( array('login') );

Thanks for all the suggestions

Posted: Wed Sep 07, 2005 2:28 am
by n00b Saibot
McGruff wrote:What would happen if you turn the Template class inside out ie rather than php code containing html, you'd have html (or etc) template files containing some php snippets?

My general view is that php is for manhandling data. Other tools are better at dealing with formatting.
Same Here. I also follow the same path... and I think this is the way it should be handled...

Posted: Wed Sep 07, 2005 9:26 am
by patrikG
using a template engine and not inline-PHP for the presentation layer can, to my mind, only be justified with two reasons:

1. you have designers who you do not want to be able to write PHP code
2. you want to minimise hits on the database

Template engines will become more or less a recreation of a scripting language (e.g. PHP) - so why not use PHP? Templates are only justifiable if they reduce complexity, more often than not they increase it, which is plain silly.

Posted: Wed Sep 07, 2005 8:54 pm
by edwardaux
I expressed a somewhat similar question here and was pointed to this discussion... I will preface my comments with the disclaimer that I am quite new to PHP, however, it seems to me that this is a problem that is suffered in any decent-size web application regardless of implementation language.

As I understand it jshpro2, your approach would be to create a PHP class that allows you to add various elements (titles, menus, etc), and then your template class would dynamically generate the eventual HTML (presumably the HTML fragments that make up the greater page would be stored as literal strings within your template class). Is that right? For the sake of this discussion I will refer to this approach as Solution A

An alternative approach, as suggested by McGruff, is to have a PHP file that contains most of the HTML markup with "markers" in the HTML. A separate (generic) PHP class then substitutes values into the appropriate spot. I will call this guy Solution B.

At the moment, I am tending towards the latter approach, but am keen to discuss in case I am missing something. One thing I particularly like about Solution B is that I can easily look at the layout file and get a feel for what it would look like in a browser, whereas in Solution A, the internal layout is not readily able to be visualised as it is not put together until runtime. Another plus for Solution B is that it supports as many wacky layouts as you like without having to make changes to the generic renderer.

The problem with Solution B, however, is how to embed the main body of the page. Consider if the template looks something like the following:

Code: Select all

<!-- This is the template layout PHP file - layout.php-->
<html>
<head><title>%%TITLE%%</title></head>
<body>
%%BANNER%%<br/>
%%BODY%%
</body>
</html>
<!-- I've chosen to use %%XX%% as markers, but it could be anything -->
<!-- It could also be something like <?php $renderer->get("XX") ?>  -->
The challenge is how to plug the main page body into %%BODY%%. A couple of possible approaches are shown below:

Code: Select all

<!-- shoppingCart.php -->
<?php
$renderer = new Renderer();
$renderer->startPage("/layout.php");
$renderer->setString("TITLE", "My title");
$renderer->setFile("BANNER", "/include/banner.php");
$renderer->setFile("BODY", "/bodies/shoppingCart.php");


<!-- bodies/shoppingCart.php -->
<ol>
  <li>item 1</li>
  <li>item 2</li>
</ol>

<!-- Lousy because for every page in my system, I have to have two pages -->
<!-- 1) the page the user requests (shoppingCart.php) and 2) the one that actually -->
<!-- contains the real data (bodies/shoppingCart.php) -->
?>

Code: Select all

<!-- shoppingCart.php -->
<?php
$renderer = new Renderer();
$renderer->startPage("/layout.php");
$renderer->setString("TITLE", "My title");
$renderer->setFile("BANNER", "/include/banner.php");

$body = "";
$body .= "<ol>\n";
$body .= "  <li>item 1</li>\n";
$body .= "  <li>item 2</li>\n";
$body .= "</ol>\n";

$renderer->setString("BODY", $body);

<!-- Lousy because I am having to fool around with string manipulation -->
?>
Another alternative is to use a generic controller (http://www.blah.com/controller.php?page=shoppingCart) that reads an INI file (or some other configuration) and then plugs them into the layout. This is pretty much how Struts does it (but it introduces the extra level of indirection of the INI file). For example:

Code: Select all

<!-- config.ini -->
page.shoppingCart.template=layout.php
page.shoppingCart.title=My title
page.shoppingCart.banner=/include/banner.php
page.shoppingCart.body=shoppingCart.php
Now the point of all this waffle (yes, there is one :)) is that although I prefer Solution B, it is by no means wrinkle free. I can also see many benefits through using Solution A. Perhaps there is a happy medium between Solution A and Solution B... I am curious as to the thoughts of those with more PHP experience than I. Anyway, apologies for the long-winded post... and I also apologise if I have hijacked your thread. Feel free to tell me to sod off and I will start another thread :)

--
Edwardaux

Posted: Thu Sep 08, 2005 12:30 am
by josh
patrikG wrote:using a template engine and not inline-PHP for the presentation layer can, to my mind, only be justified with two reasons:

1. you have designers who you do not want to be able to write PHP code
2. you want to minimise hits on the database

Template engines will become more or less a recreation of a scripting language (e.g. PHP) - so why not use PHP? Templates are only justifiable if they reduce complexity, more often than not they increase it, which is plain silly.
3. portions of the template will change depending on what page you're on, but you still need to keep the main template file consistent across pages.
4. when an item is activated (div layer's visibility toggled, menu item added via javascript, etc..) it's state needs to be maintained between page views.


... I'm going to be adding menu items, using javascript when certain events are triggered, and once a menu item is added, an RPC call is made to alert PHP of the new menu item, which is then serialized into the template class, and stored into the session, so now every page has that menu item activated.

I have about 10 other problems besides that which the easiest solution for me was a templating class. I created this thread not to debate the use of templates, but to ask how I should implement the setting of defaults, which nielsene answered very well.

Don't get me wrong you all have legitimate points, they just do not apply to my specific project..

and to further clarify the reason I'm not just doing

Code: Select all

$user = unserialize($_SESSION['user']);
if ( $user -> validate() ) {
   // output welcome msg
} else {
   // output login box
}
is because when a user logs in, the welcome message appears through javascript RPC's, I cannot have the page refresh between tasks such as logging in, or clicking menu items, the site has a lot of flash content and for example my login box is in flash, when they login it will fade from the login form to the welcome message..

also simply because not all the states I'm maintaining are booleans, sometimes I may need to trasfer the contents of a div layer from page to page, while all of this can be acheived through mixed html/php documents, that's just silly to me... just like the use of a templating class is silly to you I guess..

Anyways I have my issue solved and I don't think it needs to be discussed further, I really do appreciate everyone taking the time to come up with their suggestions but really the only one that helped much was nielsene's.





----------------------------------------------------

edwardaux:

What I would do in your situation is first come up with all the data I need to build the page, then I would include a template file looking something like this:

Code: Select all

<html>
  <head>
     <title><?=$title?></title>
  </head>
  <body>
     <h3><?=title?></h3>
     You have <?=count($product_array)?> items in your shopping cart:
     <table>
        <tr>
           <td></td>
           <td></td>
        </tr>
        <?
        while(list($name,$price)=explode("-", each($product_array)) {
         <tr>
           <td><?=$name?></td>
           <td><?=price?></td>
        </tr>
         }
         ?>
     </table>
  </body>
<html>
just basically embed all your data right into the template, you can keep the code that's actually getting the data seperate though. In your scenario I would have to agree with mcgruff, you shouldn't really go overboard with the templating, if you're going to have customizeable elements of the page, for example the user can set the page's background color or something like that, you're best off using CSS and just telling the browser which CSS to use for which pages.

Posted: Thu Sep 08, 2005 12:59 am
by edwardaux
just basically embed all your data right into the template, you can keep the code that's actually getting the data seperate though. In your scenario I would have to agree with mcgruff, you shouldn't really go overboard with the templating, if you're going to have customizeable elements of the page, for example the user can set the page's background color or something like that, you're best off using CSS and just telling the browser which CSS to use for which pages.
I guess I didn't articulate my thoughts clearly... I've no problems using the technique(s) you mention for populating specific page details such as a list of shopping cart items. However, that's not quite my problem... what I am trying to find is a solution to providing a generic framework for defining and including "structural" elements across the whole web site.

Things like the inclusion - in each page - of common headers, footers, breadcrumbs, menus, sub-menus, and so on. For example, shoppingCart.php should have headerA, menuA, breadcrumbs and a body containing the list of items; checkout.php should have headerA, menuB, no breadcrumbs and a body containing the checkout details; latestNews.php should use headerB, menuA and a body containing a bunch of news items.

CSS helps me determine what they look like (once they are included), but it doesn't help in determining which ones should be included. Anyway, I'm pleased you found what are looking for... I guess I will just keep searching. I appreciate your feedback.

--
Edwardaux

Posted: Thu Sep 08, 2005 3:14 pm
by josh
Just include headera.php, and embed all your data right in headera.php, if you want header B include headerb.php