Alternative to include() in a loop for DB row templating? - php

I'm writing a data provider class in PHP to help me speed up rendering of multiple-row SQL query results. Basically, the class has a bunch of SQL-related properties and methods to help with paginating, sorting and finally rendering the data. As for the latter, I want to be able to template the rows easily so I wrote a method called render() that can be called from a view file (in the MVC model) with a row template file as parameter. It looks similar to this:
public function render($row_template_file) {
if($result = mysql_query($this->query)) {
while($row = mysql_fetch_array($result)) {
include $row_template_file;
}
}
}
The actual method is more sophisticated than that (it checks whether the template file exists, uses data abstraction class rather than mysql_* functions etc.) but you get the general idea. The row template file is basically HTML that goes straight to the output, i.e.:
<div class="row">
<div class="foo"><?php echo $row['foo']; ?></div>
<div class="bar"><?php echo $row['bar']; ?></div>
</div>
This approach works fine, the only problem is include() in a loop is not a great idea performance-wise, especially when rendering a large number of rows. Is there anything I could replace it with while keeping the ability to template rows that way? There were few similar questions here, but all suggested solutions involved mixing logic with presentation which is what I want to avoid. I was thinking of creating an anonymous function during first iteration, then calling it in all subsequent iterations, but maybe I'm overthinking it or reinventing the wheel here. Any ideas?

Perhaps use php's printf() / sprintf() functions instead?
Thus your template file would contain code like:
<div class="row">
<div class="foo">%s</div>
<div class="bar">%s</div>
</div>
You only load it once into a variable, before the loop:
$tmpl = file_get_contents( $row_template_file);
Inside the loop you just put variables into the template:
printf( $tmpl, $row['foo'], $row['bar']);
See examples #3 and #4 in the link above for "Argument swapping" — way to use numbered positions in a template - to not worry about different order of arguments in different templates.
Hope that works for you.

The printf() / sprintf() solutions suggested are neat, but don't allow for including presentation-specific logic in the template, like, for instance:
<div class="gender">
<?php if($row['gender'] == 'f') : ?>
<img src="female_icon.gif" />
<?php else : ?>
<img src="male_icon.gif" />
<?php endif; ?>
</div>
I know, I shouldn't have written the template is "basically HTML" :-)
I've been playing with the anonymous function solution I mentioned in my question and even though it doesn't look very pretty, it works and is significantly faster than multiple includes, so I'm adding this as one of possible answers:
public function render($row_template_file) {
if($result = mysql_query($this->query)) {
$render_row = create_function('$row', '?>'.file_get_contents($row_template_file).'<?php ');
while($row = mysql_fetch_array($result)) {
$render_row($row);
}
}
}

This almost feels like a solution that's too easy, maybe I just don't get what the big problem is, but what about using a PHP-function?
function outputRow($row) {
echo '<div class="row">';
echo '<div class="foo">' . $row['foo'] . '</div>';
echo '<div class="bar">' . $row['bar'] . '</div>';
echo '</div>';
}
And instead of include, you call outputRow($row)

Create the template as a string with placeholders and replace values into it. Pass it in to the render() method.
Then, you'd just have to decide on how it's best to How you obtain the string - via file_get_contents (i'd go for this) or simply have it hard-coded into some "template" class, extract an interface out of it - and pass it around.

May be try to play with eval function. This comment on php.net might help you:
http://www.php.net/manual/ru/function.eval.php#108091

Related

If I don't use a template engine with my PHP, what should my code look like?

I don't want to use an MVC framework. I don't want to use a template engine. I am a few man shop where the developers where all the hats, no graphic artists. We do it all (all layers). I do not want code mixed with presentation, like I have with Classic ASP.
But, I do not know what my code is suppose to look like between server side and the actual presentation.
If I'm not emitting HTML in my server side code, how does it get to the HTML page so I can do things like <span><?= $myvar ?></span>? and put loops in the html page?
Thank you for any advice.
For using loops and all, I use the alternative syntax for the control structures.
An example:
<div id="messages"<?php if(!(isset($messages) && count($messages))): ?> class="hidden"<?php endif; ?>>
<?php if(isset($messages)): ?>
<?php foreach($messages as $message): ?>
<div class="message"><?php echo $message; ?></div>
<?php endforeach; ?>
<?php endif; ?>
</div>
For more information, see this: http://php.net/manual/en/control-structures.alternative-syntax.php
Oh also, I use a semi-MVC structure, where I have a class that handles templates (views), basically it's just a class that I create an instance of, pass a set of variables, then render the template when the instance get destroyed. I have an array of variables in that class, and then use extract to pass all variables in the include, like so:
extract($this->variables, EXTR_SKIP);
include($this->file);
EDIT: Here is the same example in Smarty:
<div id="messages"{if isset($messages) && !count($messages)} class="hidden"{/if}>
{if isset($messages)}
{foreach from=$messages item=message}
<div class="message">{$message}</div>
{/foreach}
{/if}
</div>
Simple PHP projects usually generate the full HTML in-place instead of populating templates, so you'd just echo it out in your PHP code.
This gets messy, so you WILL end up coding some kind of templating system for any moderately complex website.
A possible alternative is to serve your page as completely static HTML/CSS and use AJAX to fetch the actual contents dynamically (JSON would be a good transport format, it's native to JS and can easily be generated from PHP). This gets you rid of all the HTML littered across your PHP code. Whether this is a viable alternative or not depends on the case.
<span><?= $myvar ?></span> works.
A loop would look like:
<html>
<body>
<?php
for ($i=1; $i<=5; $i++)
{
echo "The number is " . $i . "<br />";
}
?>
</body>
</html>
Example taken from here.
I really recommend that you use the php Template Inheritance system. (Don't let it scare you, it's only one file.) This is a simple set of functions that helps you to build extensible PHP views without the problems and limitations of manual includes.
It's still Pure PHP, so you don't need to learn some strange template language. It may not look like much, but it's really powerful once you start using it.
To be sure, you can do it all by yourself - but what you want is still MVC pattern, or separation of concerns ("I do not want code mixed with presentation"). Or at least MV, for very simple applications (although it's still dirty, having models directly influence the view).
The easiest way to achieve this is to first collect and process all data, then just print them. No complex code allowed in the php files directly exposed to the web.
<?php
require('model.inc');
process_capuchin_monkey_order_form();
?>
...
<h1>Thank you for your order of <?php echo $order->num_monkeys; ?> monkeys.</h1>
...
typically you would want to just make sure you have as little PHP in your HTML as possible. This means doing all of the data processing before hand, and simply passing a set of variables in one way or another to a method or function that includes the HTML.
Any HTML with PHP intermixed could be considered a template. Here's a simplified example:
// view class
class View {
public function render($html_template) {
include('view_path/' . $html_template . '.php');
}
}
// html template file 'view_path/main.php'
<html>
<body>
<h1><?= $this->title ?></h1>
</body>
</html>
// usage
$view = new View();
$view->title = 'Some Title';
$view->render('main');
You should use an MVC-like separation of concerns no matter what you do. This means:
At least one file is all html and is given a handful of variables. (view/template)
At least one file is all php and only talks to the database. (model)
At least one file processes the http request, pulls data from database, and executes the view.
The core of every php templating language is the use of extract() and include inside a function:
function render_template($___filename, $___data) {
extract($___data, EXTR_SKIP);
include $__filename;
}
You can pretty this up with a class interface (view objects) or with output buffering, but this is the core of every template system. Your controller's responsibility is simply to assemble that $__data argument (usually with data from a database) for a given view.

Best way to store widgets, XTHML snippets and containers in PHP

I have a a few XHTML widgets and containers that have static or mostly static content. When I say mostly static, I mean a widget which is using one or more variables passed to it from a DB or a configuration. These are all used in more than one frontend page. Currently, I have stored them as PHP functions that return a XHTML string, and these functions are stored in a singular "functions" file that is "included" on every page. Where applicable, I either pass these functions configuration values or do some DB calls from within.
Is there another better way to store these in PHP code? Or is what I am doing pretty standard?
(I am not using Smarty or another template system and I'd rather not add another layer of abstraction.)
That's pretty standard, most you can do is separate them into files for each and then have a "includes" files that includes each one of them.
This way you would only have to load what you need per script / page.
(I am not using Smarty or another template system and I'd rather not add another layer of abstraction.)
I know this isnt what you want but this is exacly what id do. I wouldnt necessarily use a template engine with its wone grammar but i would use php and make seperate snippet templates containing the structural markup and then pass in what i need for example:
function get_partial($path, $args = array())
{
ob_start();
include($path);
return ob_get_clean();
}
function include_partial($path, $args = array())
{
echo get_partial($path, $args);
}
Then in your template:
<div class="<?php echo $args['classname']?>">
<h4><?php echo $args['title'] ?></h4>
<?php echo $args['content'] ?>
</div>

How much code should be in a CodeIgniter view?

First steps are done, some pages are coded. And after looking to the result I've got the question... how much code is there should be in templates (View)?
For example, here is a template file:
<?php $this->load->view('header'); ?>
<?php $this->load->view('banner'); ?>
<div id="items">
<?php
for($i=0; $i<count($main); $i++) {
echo '<div class="item">
<div class="name">'.$main[$i]['name'].'</div>';
if($main[$i]['icq']=='') { }
else { echo '<div class="phone">'.$main[$i]['phone'].'</div>'; }
echo '</div>';
}
?>
</div>
<?php $this->load->view('footer'); ?>
Do you think there is too much code in this template or it is normal?
The first answer was actually spot on, but the user deleted it (probably due to peer pressure). Basically, you do not want any logic in your template. In an ideal world, you had a tag for all the model data, but since we are in an HTML world, there isn't, so you either have to use XSLT or use ViewHelpers.
Let's focus on the ViewHelper approach.
This is hard to maintain:
<div id="items">
<?php
for($i=0; $i<count($main); $i++) {
echo '<div class="item">
<div class="name">'.$main[$i]['name'].'</div>';
if($main[$i]['icq']=='') { }
else { echo '<div class="phone">'.$main[$i]['phone'].'</div>'; }
echo '</div>';
}
?>
</div>
And it won't get any better if you replace the PHP with Smarty. This is easy to maintain:
<div id="items">
<?php echo itemlist($items, 'template.htm') ?>;
</div>
Below the now deleted question, there was a commentor objecting this "code isn't easy to maintain for non-coders because now they don't know where itemlist is defined and what it does." but that's complete gibberish. Think about it for a second.
On the one hand, they claim non-coders will have issues with a simple function call but on the other hand they expect them to understand the mishmash of PHP code mixed with HTML. A designer does not care about the presentation logic, but just the actual presentation. The output.
A single function call clearly says: "here be an item list", which is much easier to grasp than "here is a for that echoes a div and maybe something else if icq is given". A function call is as good as a tag. It has clearly defined input and output. How it achieves that output is irrelevant to anyone but the developer.
Your ViewHelper encapsulates the presentation logic. It's a snippet you can reuse across all of your Views. That is much more maintainable than copy and pasting all that logic over and over again when needed. In the example above, there is two arguments to the helper:
$items is an array or other traversable type holding your actual item data
'template.htm' is the filename of the template used to render the data
I'll make the second one optional, because I'd assume it's always the same template anyway. But since the commentor complained the non-coder wouldn't know where to look, I felt it necessary to show how easy it is to tell the non-coder where to look.
function itemlist($items, $template = './templates/itemlist.htm') {
ob_start();
foreach($items as $item) {
include $template;
}
return ob_get_flush();
}
There might be more efficient approaches to solve the inclusion of the template. The main idea should be clear though. Hide the presentation logic from the actual template. Your "template.htm" would then look like this:
<div class="item">
<div class="name"><?php echo $item['name'] ?></div>
<?php echo contact($item, 'icq' 'phone'); ?>
</div>
No if and elses. No string concatenations or curly braces. The logic to decide how to the user can be contacted is hidden in a ViewHelper as well. All the non-coder has to know now is the arguments to the ViewHelpers and that's as easy as knowing which attribute to write to a tag. Give them a cheat sheet if necessary.
Related information:
http://martinfowler.com/eaaCatalog/templateView.html
EDIT
Due to the two comments below I decided to expand on this answer. The above is not abstraction for abstraction's sake. It is for reusability and maintainability. I've already pointed that out above but let me explain that here again.
Actually, I find it odd to object to using ViewHelpers because you'll have "have presentation in two places" but not complain about separating header, banner and footer. It's the same thing. You isolate parts that are reusable and put them into their own templates. Separating the logic from the template in that step is just the natural next step to achive even more maintainability.
A view template that contains logic is effectively a script and not a template. Any view template that contains the logic to assemble itself is doomed to repeat itself. This might not be an issue with small sites but if you are working on a site with a couple dozen or even hundreds of view and widgets, not abstracting these parts will lead to code duplication. Put all the logic into the template and it will quickly become a tangled mess of c&p'ed markup mixed with conditionals. For any duplication, you'll double the time it takes to change it. Add inline styles and obtrusive Javascript and you are in maintenance hell.¹
If you use OOP for the other parts of your application, then why would you go procedural in your view? If you understood that you should separate Javascript and CSS from your HTML, why would you mix PHP into your template? It doesn't make sense. The OP's code snippet is a script and not a template. As such, it is the domain of the developer. And because of that you apply all the good practise you apply to other parts of your application as well. And that includes isolating logic into functions and/or classes.
Granted, a designer looking into a script might not immediately know what's going on. But then again, she might not know that either once you start to add in native PHP functions. What's mb_strimwidth doing? And substr? What's that ?: construct? The more actual PHP you add, the harder it will be to read for non-developers.
If you want to have designers work on templates, don't give them scripts. Give them templates. And if you do, isolate the logic from it and replace it with easy to grasp function calls. Use function names that clearly communicate what the function does. So the designer only needs to know if "I use this with that input, I will always get that output. I don't care how that output comes to be. I'll leave that to the developer".
Isolating the logic into functions (or classes) also gives you the immediate advantage of being able to test the logic used to render specific parts on that page in isolation. You don't have to setup the entire environment required to create a page, but just pass in the required input and assert it's output (that's why the function buffers the string instead of outputting it btw).
¹For those of you who think this is not an issue, I strongly suggest to find yourself a legacy application that truly keeps all the logic in the view template. Try to change a few things. Once you have had the pleasure of eating through 2500 lines of spaghetti code with at least 500 chars each and containing a mix of repeated PHP, HTML, CSS and JavaScript you'll know what I am talking about.
I don't think what you're trying to achieve in the view is too much logic, but I think it should be cleaned up somewhat.
Something like:
<?php foreach($main as $item): ?>
<div class="item">
<div class="name"><?php echo $item['name']; ?></div>
<?php if($item['icq']): ?>
<div class="phone"><?php echo $item['phone']; ?></div>
<?php endif; ?>
</div>
<?php endforeach; ?>
I find that a lot easier to read, and it does the same job. I also don't think it would be hard for a non-coder to modify, which is ultimately the goal of a view.
When the templates need a lot of logic is could be useful to introduce the ViewModel pattern
The logic that determines when a certain block is shown is placed in the view model.
Example
A template snippet:
<?php if($item['show_phone_number']): ?>
<div class="phone"><?php echo $item['phone_number']; ?></div>
<?php endif; ?>
A view model snippet:
$item['show_phone_number'] = $item["icq"] == '';
short answer:
As little as is viably possible.
View is no a template.
Or at least - it should not be a template. Views are generally instance of classes, which are responsible for dealing with presentational logic. They juggle multiple templates and decide which one to use and what data pass into them.
But CI has none of this. You are basically stuck with a template, which pretends to be "View" , and and instances of ActiveRecord, which they tell you are "Models". Hell .. in proper MVC the Model isn't even a specific class but an application layer.
In long term, this situation will force both presentation logic and business logic into the controller, while at the same time, producing hard-to-maintain templates and activerecord classes.
I think as James, too much code, but you can add an array variable to the get_items() function, to control the prefix and suffix of each item, something like:
$options = Array('item_prefix' => '<div class="item">', 'item_suffix' => '</div>'...)
echo get_items();
Your views should definitely contain most of the html tags, so I do not think that a function get_items should be placed somewhere else. Just clean up your templates a little bit and work with the alternative loop syntax as suggested by Karpie. You could also think about using some existing templating engine like Twig but with that the views have to contain some references to your data as well...
What you want to achieve is that non-coders can edit your html files without having to understand too much scripting logic.

Whats the best way to output data from a database using php?

I'm relatively new to php, and I'm working on a project using a mysql database. The project consists of users being able to write posts, which are then shown in a list format. The problem is, the posts are shown in different locations on the site, like the index (main) page, and the users profile page. Similar to twitter if you're confused. My question is, what is the best way to display the posts? Currently I'm using a class that I created. It has functions to retrieve posts from the database, save them all in a multidimensional array. Then another function in the class formats the entire list using foreach, and then returns the formatted HTML list of posts. All I have to do is echo what is returned. But I read somewhere that it's bad practice to write functions (especially class functions) that output HTML. What would be the best way to do this, without having to rewrite the same code on every page the posts are shown. Is it really bad practice to use HTML in functions?
Example...
a profile page looks something like this.
<
require('class.php');
require('header.php');
$profile = new Profile();
$userProfile = $profile->GetUserProfile($userID);
echo $userProfile;
$class = new Posts();
$posts = $class->GetUserPosts($userID);
echo $posts;
require('footer.php');
?>
And the main page looks something like this
<
$class = new Posts();
$posts = $class->GetAllPosts();
echo $posts;
?>
where the profile class would take a user id and output the users profile, already formatted in HTML.
And the posts class has functions to return a determined number of posts already formatted in an HTML list.
Should I keep everything in the class, or is there a better way?
Thanks
Well, if you're not using an MVC framework of some kind, then I would say that having functions that output HTML isn't going to kill anyone.
Generally however, it's helpful to separate HTML from logic, and this is usually done by creating an HTML template and template fragments with interspersed PHP. Something like this:
<div>
<h1><?php echo $title; ?></h1>
</div>
You could then set up a $title variable (and others), and include('title_fragment.php') to output that bit of HTML. You can extend this to work with entire pages, making it so that your code only has to deal with small amounts of data that get passed to the template.
When it comes time to make changes to the page layout or look, you don't have to go hunting through the code to find the bits of generated HTML... you can go straight to the template files.
This is important for maintainable design as well as code, and it makes it easier to produce other output types later on.
With PHP, one of the simplest libraries for separating the two is Smarty templates. Using Smarty (or any other templating library), you can write an HTML file with the layout and some simple loops or other constructs, and then render that template using a data structure. At the very least, I would suggest altering your class to utilize a template and produce output that way, rather than a mish-mash of print or echo statements with a bunch of HTML in them.
I'd even shy away from #zombat's solution of echo statements in HTML fragments, they quickly become ugly.
Example Smarty template to achieve something like what you want:
{section name=i loop=$posts}
<li>{$posts[i].author} — {$post[i].text}</li>
{/section}
And some PHP supporting code:
// Instantiate Smarty object
$smarty = new Smarty();
// Assign a hash of data
$smarty->assign('posts', array(
array('author' => 'Jim', 'text' => 'Hi this is my post!'),
array('author' => 'Sally', 'text' => 'My first post to the system')
)
);
// Use the file with the above template in it
$smarty->display('posts.html');
The part where you assign data to the template should probably be done via some programmatic means to convert your list of class objects into a list of hashes.
This way you can easily change the way the output looks just by editing the HTML template and you don't have to worry about touching any code to change the output.
Your class should ideally provide the data only. Use another PHP file or generic class to output HTML, so later you could output e.g. XML, JSON, etc from the same data class. This separates your data processing (model/controller) from your data representation (view).
I would disagree with using a template engine like Smarty. PHP is a template engine.
You can use output buffering. It's helping to build your templates and not be forced to process data in the display order.
<?php
$posts = take_data_from_class();
ob_start();
require_once('path/to/posts.php');
$html_posts = ob_get_clean();
// you can do the same with other parts like header or footer
ob_start();
require_once('path/to/header.php');
$header = ob_get_clean();
ob_start();
require_once('path/to/footer.php');
$footer = ob_get_clean();
?>
In posts.php you can display the posts:
<? foreach ($posts as $p) { ?>
<div class="...">
post data here
</div>
<? } ?>
Now, to display the whole thing:
<?php echo $header . $html_posts . $footer; ?>
More at http://us3.php.net/manual/en/book.outcontrol.php
Enjoy!
Im not familiar with Smarty at all...how exactly does that work, and what are the benefits of using a smarty vs. just creating functions to take large amounts of data and return html containing that data just to be echoed later?

Whats the best way to create templates using php?

I have a class that gathers templates and displays the final output after connecting all the templates.
class Template{
$private $output = '';
public function Load_Template($template, $data = null){
ob_start();
include($template);
$this->output .= ob_get_clean();
}
public function Display($add_footer = true){
echo $this->output;
}
}
Now, Currently my templates look something like this.
<h1><?php echo $data['name']; ?></h1>
or the more complex ones that involve loops look more like
<ul>
<li>
<?php foreach($data as $user){ ?>
<h1><?php echo $user['name']; ?></h1>
<?php } ?>
</li>
</ul>
Actually theres way more data than that in them, but im sure you guys get the point.
Now, I have heard people say thats it better to have templates like this
<h1>{name}</h1>
or
<ul>
<li>
<h1>{name}</h1>
</li>
</ul>
and then use a str_replace function... Now, if im using a foreach loop, how would I accomplish something like this... should i alter my class, and if so can i get some ideas as to how... And do you guys suggest using templates with
Smarty is too redundant! Your class with the function of cutting a page is enough.
For these "{tags}" type template you have a very popular engine: Smarty
Every template language has its own way of approaching the problem. You could, instead of writing your own template language from scratch, use one of the standard ones out there like Smarty.
If you are writing your own, you'll need at a minimum a construct that will let you express loops and conditionals. One simple approach that I've seen used before is something like:
<!-- BEGIN conditional_or_looped_block_named_foo -->
Stuff that may appear zero or more times
<!-- END conditional_or_looped_block_named_foo -->
The syntax varies widely, of course, from one language to another, but the basic approach is the same: have some markup that surrounds the portion of code you want to isolate and repeat (or omit).
This should give you an idea:
http://www.handyphp.com/index.php/PHP-Resources/Handy-PHP-Tutorials/Creating-Your-First-Template-Driven-PHP-Website-Part-2.html
I found it by doing a quick search, it has code to do what you are asking, it does search and replace with simply variables that you have created.
So your foreach() call would not echo but store in a variable, then you replace that variable with {users} in the template.

Categories