I found a question on stack overflow about loading a template file in php, which was fine, but I wish to loop a template file of one line, many times instead.
The article I have read is here
[PHP Content Separation.
The best answer on that page was from prodigitalson with his function GetTemplate.
Now I wanted to use something like this, but if I put his function in a loop then it wouldn't be very efficient, as it would keep loading the same file many times.
So I tried this. I would get the html included. Then store it in a variable, before putting it in the loop. However it didn't work.
Here is my code. The data is already in an array called $result.
$salesTemp=$this->tempLine('salesTEM.php');
while($row = array_shift($result)):
echo $salesTemp;
endwhile;
private function tempLine($file){
ob_start();
require $file;
return ob_get_clean();
}
The problem is that my variable is not being updated in the template.
Here is my template
<li class="list-group-item"><?php echo $Customer;?><span class="label label-primary pull-right">SALES</span></li>
So is there a way of re-writing this so my $Customer variable is updated.
I am doing this to try to keep php and html separate.
The primary problem I see with the code as it stands is that when $salesTemp is declared and ran through the tempLine() method, a string is returned (due to ob_get_clean()). The variable within the template has been resolved, and when the string is echoed in the loop the variables in the template are not updated because they have already been resolved and processed into a string. To fix the situation I would:
while ($row = array_shift($result)) {
echo $this->tempLine('salesTEM.php', $Customer);
}
/**
* #return string
*/
private function tempLine($file, $Customer) {
ob_start();
require $file;
return ob_get_clean();
}
This would be the shortest path to getting what you want. If you wish to not include the template on each iteration, try:
$salesTEM = include 'salesTEM.php';
while ($row = array_shift($result)) {
echo sprintf($salesTEM, $Customer);
}
/**
* salesTEM.php
*/
<li class="list-group-item">
%s
<span class="label label-primary pull-right">SALES</span>
</li>
There are many frameworks available that provide this functionality out of the box and may be perused for additional information on templating techniques. Essentially, it is always good form to pass the information in via the function (file name and data) and expect the string back out. It will make it easy to unit test as well. Allowing it to pick up the information passively tends to make the code error prone, for example:
while ($row = array_shift($result)) {
echo include 'salesTEM.php';
}
/**
* salesTEM.php
*/
<li class="list-group-item">
<?php echo $Customer;?>
<span class="label label-primary pull-right">SALES</span>
</li>
You could accidentally include the file and have not declared the $Customer variable resulting in a difficult to find bug. Define everything going in and coming out and it will make it much more manageable down the road.
You should really move the loop to inside the template file, seeing as you've already used PHP as the templating language inside of it. This will make things a whole lot easier for you, and give you the best possible performance (without rewriting the entire templating system).
As for the statement about keeping the HTML and PHP separate: It is actually not quite accurate, as it's a subtle rewrite from the original goal. Namely keeping the business code and the presentation code separate.
Normally, the presentation code is pure HTML, but in the case of dynamic sites the presentation code also requires dynamic elements. Most of the time this is solved by using a template engine that provides its own template language, but PHP can also be used as one. Matter of fact, PHP started as a template langauge. :)
So, using PHP in your views is perfectly fine. Provided said PHP code only controls output, and not business operations.
I have an answer which works. However as ChristianF says it may not be the best answer, but this does solve my question.
Right instead of having an echo in the html I put the tag in %% like this
<li class="list-group-item">%CUSTOMER%<span class="label label-primary pull-right">SALES</span></li>
Then my loop in my class. I can build the object in the previous line for better readability or do it inline like I have.
$salesTemp=$this->tempLine('salesTEM.php');
while($row = array_shift($result)):
echo $this->replaceTemp($salesTemp, $obj=(object)array ( 'CUSTOMER' => $row['CustomerName'] ));
endwhile;
and a small function
private function replaceTemp($file, $obj){
return preg_replace('~%(\w+)%~e', '$obj->$1', $file);
}
private function tempLine($file){
ob_start();
require $file;
return ob_get_clean();
}
The function basically replaces everything in the html where there are %% symbols with whatever is in the object.
UPDATE
After posting this I have improved my answer, but I will leave the above there as it was my original answer. Below is a class which improves on the above answer. In the rTemplate function I can have one, or many tags that will be replaced in the template. For the example I only have one tag to replace, but you could add many. Running testLoad will list the array, grab the template and fill in the tags with what is in rTemplate.
class testlist{
private $myfile;
public function __construct(){
$this->myfile=$this->loadTemplate('salesTEM.php');
}
public function testload(){
// At this point the array is populated from a database, but I haven't shown this.
// You can populate the array anyway you like.
while($row = array_shift($result)):
echo $this->rTemplate($row['CustomerName']);
endwhile;
}
// This loads in a file into a string and then returns it.
private function loadTemplate($file){
ob_start();
require $file;
return ob_get_clean();
}
// This makes the object to replace keywords, then replaces them
private function rTemplate($customer)
{
$obj = (object) array(
'CUSTOMER' => $id
);
return preg_replace('~%(\w+)%~e', '$obj->$1', $this->myfile);
}
}
Related
I am building a website using php. I would want to separate the php from the html. Smarty engine, I guess does that, but right now its too complicated for me. Looking for a quick fix and easy to learn solution, one which is an accepted standard as well. Anyone helping please.
Consider frameworks or choose a template engine
Use a framework. Depending on your project, either a micro framework like Slim or something more complete like Laravel.
What I sometimes do when writing complex systems with quite much php code is separating it the following way (don't know your exact project, but it might work for you):
You create a php file with all the functions and variables you need. Then, you load every wepgage through the index.php file using .htaccess (so that a user actually always loads the index.php with a query string). Now, you can load the html page using file_get_contents (or similar) into a variable (I call this $body now); this variable can be modified using preg_replace.
An example: In the html file, you write {title} instead of <title>Sometext</title>
The replacement replaces {title} with the code you actually need:
$body = str_replace('{title}', $title, $body);
When all replacements are done, simply echo $body...
Just declare a lot of variables and use them in the template:
In your application:
function renderUserInformation($user)
{
$userName = $user->userName;
$userFullName = $user->fullName;
$userAge = $user->age;
include 'user.tpl.php';
}
In user.tpl.php:
User name: <?=$username?><br>
Full name: <?=userFullName?><br>
Age: <?=$userAge?>
By putting it in a function, you can limit the scope of the variables, so you won't pollute your global scope and/or accidentally overwrite existing variables.
This way, you can just 'prepare' the information needed to display and in a separate php file, all you need to do is output those variables.
Of course, if you must, you can still add more complex PHP code to the template, but try to do it as little as possible.
In the future, you might move this 'render' function to a separate class. In a way, this class is a view (a User View, in this case), and it is one step in creating a MVC structure. (But don't worry about that for now.)
Looking for a quick fix and easy to learn solution
METHOD 1 (the laziest; yet you preserve highlighting on editors like notepad++)
<?php
// my php
echo "foo";
$a = 4;
// now close the php tag -temporary-
// to render some html in the laziest of ways
?>
<!-- my html -->
<div></div>
<?php
// continue my php code
METHOD 2 (more organized; use template files, after you passed some values on it)
<?php
// my php
$var1 = "foo";
$title = "bar";
$v = array("var1"=>"foo","title"=>"bar"); // preferrable
include("template.php");
?>
template.php
<?php
// $var1, $var2 are known, also the array.
?>
<div>
<span> <?php echo $v["title"]; ?> </span>
</div>
Personally, i prefer method 2 and im using it in my own CMS which uses lots and lots of templates and arrays of data.
Another solution is of course advanced template engines like Smarty, PHPTemplate and the likes. You need a lot of time to learn them though and personally i dont like their approach (new language style)
function renderUserInformation($user)
{
$userName = $user->userName;
$userFullName = $user->fullName;
$userAge = $user->age;
include 'user.tpl.php';
}
is there anything wrong with using html inside a class function? I call it in the DOM so I don't need a string returned.
public function the_contact_table(){
?>
<div>
some html here
</div>
<?php
}
Also when I do need the string I use this method? Is there a better way or is this relatively standard?
public function get_single(){
ob_start();?>
<div class='staff-member single'>
<div class='col left'>
<div class='thumbnail'>
thumbnail
</div>
<?php $this->the_contact_table(); ?>
</div>
<div class='col right'>
</div>
</div>
<?php
$content = ob_get_contents();
ob_end_clean();
return $content;
}
UPDATE
I should have explained why i am doing this. I'm making a Wordpress plugin and want to control a post types output. So I am using a filter like below
public function filter_single($content){
global $post;
if ($post->post_type == 'staff-member') {
$sm = new JM_Staff_Member($post);
$content = $sm->get_single();
}
return $content;
}
So as you can see, I must return a string to the wordpress core
You should be using HEREDOC instead of output buffering if you want to store a long string into a variable. It looks like this:
$content = <<<EOD
content here
EOD;
EOD can be anything, but note two important things:
It can't have any whitespace in front of it and it must be on it's own line
It shouldn't be a string that could be found within your content
If you are using PHP >= 5.3, then you should use NOWDOC, which does not parse for variable inside the doc (unless you need this). The only different with the syntax of NOWDOC is that the sentinel is enclosed in quotes:
$content = <<<'EOD'
content here
EOD;
The reason why I'd stray away from output buffering is that it prevents the server from chunking the data sent to the client. This means that requests will seem slower because instead of the content being progressively sent to the client and displayed, it is forced to be sent all at once. Output buffering is a hack for situations when functions carelessly echo data instead of returning it or a tool for certain applications with the specific need for it. I'd also imagine that you'd take a hit on execution time if you used output buffering (because it involves function calls) versus HEREDOCing the string into a variable or including a view.
Now to answer the question about whether it is appropriate, I would say that in an MVC application all HTML and other content should be contained within its own view. Then a controller can call a view to display itself and doesn't have to worry about knowing the code involved in displaying the view. You can still pass information (like titles, authors, arrays of tags, etc.) to views, but the goal here is separating the content from the logic.
That said, Wordpress templates and code looks pretty sloppy to begin with and loosely if not at all implements MVC so if it's too much work to create a view for this, I'd say the sloppiness would fit in with WP's style.
It's not a good practice in regard to the fact that you alienate front-end developers by placing what are actually "Views" inside of PHP class files. This was one of my biggest issues when I first started using PHP in general, is that I wanted to dynamically create content within classes. It's a great idea, but you want to do it in a way that allows many members of your team to work together as smoothly as possible ;].
You should probably have the content inside of a separate file called "staff-member-single.php", which you then call in your function
public function get_single(){
ob_start();
require_once('views/staff-member-single.php');
$content = ob_get_contents();
ob_end_clean();
return $content;
}
You'd refactor that into a reusable method typically though, so it'd look a little bit like..
public function get_single()
{
$string = $this->render_view_as_string('satff-member-single');
return $string;
}
public function render_view($view)
{
require('views/'.$view.'.php');
}
public function render_view_as_string($view)
{
ob_start();
$this->render_view($view);
$content = ob_get_contents();
ob_end_clean();
return $content;
}
I think it is good practice to use PHP only for logic of application and transmission some data to view layer (template engine). In accordance with this there are some patterns like MVC.
I have the following dilemma. I have a complex CMS, and this CMS is to be themed by a graphic designer. The templates are plain HTML, with several nested inclusions. I'd like to make it easier for the designer to locate the file to be modified, by looking at the HTML of the page.
What I thought in the first place was to build something stupid like this:
function customInclude($what) {
print("<!-- Including $what -->");
include($what);
print("<!-- End of $what -->");
}
but, guess what? Variables obviously come out of scope in the included file :-) I can't declare them as global or as parameters, as I don't know how they are called and how many are there.
Is there any possibility to implement some kind of "macro expansion" in PHP? An alternative way to call it: I'd like to modify each call of the modify function, in an aspect-oriented style.
I have thought about eval(), is it the only way? Will it have a big impact on performance?
I know this is an old question, but I stumbled upon it and it reminds me of something I used to do it too.
how about if you create the function using a very weird variable?
<?php
function customInclude($___what___) {
echo '<!-- Including '.$___what___.' -->';
include($what);
echo '<!-- End of '.$___what___.' -->';
}
?>
I usually suggest to add a possible variable to display those tags only when necessary, you do not want other people to know...
<?php
function __printIncludeInfo($info, $dump = false){
//print only if the URL contains the parameter ?pii
//You can modify it to print only if coming from a certain IP
if(isset($_GET['pii'])){
if($dump){
var_dump($info);
} else {
echo $info;
}
}
}
function customInclude($___what___) {
__printIncludeInfo('<!-- Including '.$___what___.' -->');
include($what);
__printIncludeInfo('<!-- End of '.$___what___.' -->');
}
?>
in this way you can use the function to print any other information that you need
Not sure if I entirely understand the question, but if you're just trying to make life easier for the designer by showing them the underlying filename of the included file, then you can probably just use this within the template files:
echo '<!-- Start of '.__FILE__.' -->';
....content...
echo '<!-- End of '.__FILE__.' -->';
__FILE__ is just one of several Magic Constants.
Also there's the get_included_files() function that returns an array of all the included files, which might be of use (you could output a list of all the included files with 'tpl' in their name for example).
This is my 100% harcoded solution to custom include problem. It's about using a global var to point the next include filename and then include my custom proxy-include-file (wich replace your custom proxy-include-function)
1 - Add this code to a global include (wherever your customInclude function is defined)
$GLOBALS['next_include'] = "";
$GLOBALS['next_include_is_once'] = false;
function next_include($include_file) {
$GLOBALS['next_include_is_once'] = false;
$GLOBALS['next_include'] = $include_file;
}
function next_include_once($include_file) {
$GLOBALS['next_include_is_once'] = true;
$GLOBALS['next_include'] = $include_file;
}
2 - Create some include proxy-include-file, by example "debug_include.php"
<?php
if(empty($GLOBALS['next_include'])) die("Includes Problem");
// Pre-include code
// ....
if($GLOBALS['next_include_is_once']) {
include_once($GLOBALS['next_include']);
} else {
include($GLOBALS['next_include']);
}
// Post-include code
// ....
$GLOBALS['next_include'] = "";
3 - Perform a search and replace in all your files: (except debug_include.php)
search: 'include((.*));' as a reg.exp
replace with: '{next_include($1);include('debug_include.php');}'
and
search: 'include_once((.*)); as a reg.exp
replace with: '{next_include_once($1);include('debug_include.php');}'
Maybe you should need another search-and-replaces if you have some non-standard includes like
include (.... include (.... include (....
I think you can find some better search-and-replace patterns, but I'm not a regular expression user so I did it the hard way.
You should definitely use objects, namespaces and MVC model. Otherwise there is no pure and clean solution to your problem. And please, don't use eval, it's evil.
I have a function that loops through different types of listings pulled from MySQL and displays them as a Facebook-esque "feed". Each type of listing has a different appearance, and therefore requires a different template.
Here is the below function example might be called 100 times (if there are 100 listings):
function display_listing($id,$type) {
global $abs_path;
switch($type) {
case 'photo':
include($abs_path . '/templates/photo.php');
break;
case 'video':
include($abs_path . '/templates/video.php');
break;
}
}
Is there a better way to do this, where I don't potentially end up with 100 includes - which may slow my process down? Can I somehow save the include once on the page, and refer to it as many times as needed?
...or is this the best practice?
Also, I want to know how to do this on my own, without a template engine...
EDIT: The problem isn't solved just by include_once (I dont believe)...I need to be able to reuse the included file multiple times, replacing the variables each time.
Although a switch is not the most scalable way to write this code, I'm afraid that includes is the only way to keep your templates in separate files, here.
You could, conceivably, encapsulate each template's code in a function, however:
/*
photoTemplate.php
*/
<?php
function loadPhotoTemplate($id) {
?>
<div id="photo">
...
</div>
<?php
}
?>
/*
listing.php
*/
function display_listing($id,$type) {
global $abs_path;
switch($type) {
case 'photo':
include_once($abs_path . '/templates/photo.php');
loadPhotoTemplate($id);
break;
case 'video':
include_once($abs_path . '/templates/video.php');
loadVideoTemplate($id);
break;
}
}
This will load each template file at most once, and then just call the function each time you want to display the template with the specific data for that item.
Edit
It would probably be even better to include all template files at the beginning, then just call the appropriate function in the switch. PHP's *_once() functions are slow, as they must consult the list of previously included/required files every time they are called.
create an array of allowed templates. have you function look to see if the requested template is in the array. if it is, then use the $type variable to include the file. yes, in general you shouldn't use user-supplied data in an include file name, but since you've validated it against a known-good array of values, it's safe.
If your concern is performance, I personally wouldn't get into this loop at all.
Presuming that items in the list are viewed more frequently than they're created, I would generate the HTML as the items are created and store the output alongside the data in the database. (Or in memcache or files or somewhere else - but generate it and store it.)
In doing so you'd move this logic back into the creation process of the items so you're doing the same switch statement, but only for one item at a time - you're cutting out the loop.
Then at display time, instead of calling display_listing(), you just echo out the HTML you've already stored.
I think you ought to look at a few things. Firstly, is there even a possibility you will include the same "template" 100 times? That seems like a massive amount of content to put on a page.
If I'm using tiny "snippets" - say, a table row that's repeated many times - I tend to use a function that returns a string, like this:
/* snippets.php */
function tableRow( $row )
{
return
'<tr><td>' . $row['var1'] . '</td>' .
'<td>' . $row['var2'] . '</td></tr>';
}
/* main page/view */
foreach ( $data as $row )
echo tableRow( $row );
The main advantage here is you can have loops and all sorts in the function.
If you're looking for a straight variable-replacement, you could create your own mini-templates in an HTML file; something like:
<p>{name}<br />
Posted {date} by {author}</p>
Then read in the template, pass the whole string to your display_listing function, which runs str_replace on all the {variables}. I don't think there would be too much of a performance hit, but you'd have to try it to be sure.
You want to use the include_once function instead of include.
The include_once() statement includes
and evaluates the specified file
during the execution of the script.
This is a behavior similar to the
include() statement, with the only
difference being that if the code from
a file has already been included, it
will not be included again. As the
name suggests, it will be included
just once.
If you're going to be including templates using a switch for different keywords, then you should set a variable, say $template_filename, in the switch and then once you break out of the switch, do the include like so:
include_once("/templates/{$filename}.php");
If you don't want to use including at all, then you might as well use a templating engine...
This method seems reasonable to me however.
I've experienced first hand the extent of the horror and foot-shooting that the ugliness of PHP can cause. I'm onto my next project (you may be wondering why I'm not just switching languages but that's not why I'm here) and I've decided to try doing it right, or at least better, this time.
I've got some models defined, and I've started on a main controller. I'm at a fork in my decisions about how to implement the view. So far, the main controller can be given lists of display functions to call, and then it can spew out the whole page with one call. It looks like:
function Parse_Body()
{
foreach ($this->body_calls as $command)
{
$call = $command['call'];
if (isset($command['args'])) $call($command['args']);
else $call();
}
}
My dilemma is this:
Would it be better to have all of my display functions return the HTML they generate, so that the main controller can just echo $page; or should the display files use raw HTML outside of PHP, which gets output as soon as it's read?
With the former, the main app controller can precisely control when things get output, without just relinquishing complete control to the whim of the displays. Not to mention, all those lists of display functions to call (above) can't really be executed from a display file unless they got passed along. With the latter method, I get the benefit of doing HTML in actual HTML, instead of doing huge PHP string blocks. Plus I can just include the file to run it, instead of calling a function. So I guess with that method, a file is like a function.
Any input or advice please?
Would it be better to have all of my
display functions return the HTML they
generate, so that the main controller
can just echo $page; or should the
display files use raw HTML outside of
PHP, which gets output as soon as it's
read?
One of the advantages of php is that the processing is similar to the output:
So:
<h1> <?= $myHeading; ?> </h1>
Is more clear than:
echo "<h1>$myHeading</h1>";
An even more than:
echo heading1($myHeading); //heading1() being an hypothethical user defined function.
Based on that I consider that it is better to in the view to have HTML and and just print the appropriate dynamic fields using php.
In order to get finner control over the output you can use: ob_start as gurunu recommended.
You could of course use any of the several php MVC frameworks out there.
My prefered one, now is: Solarphp
but Zend Framework and Cakephp could help you too.
And finally if you don't want to use any framework
You could still use a pretty slim templating engine: phpSavant.
That will save you a few headaches in the development of your view.
th
You can get the benefit of both, obtaining a string of HTML while also embedding HTML within PHP code, by using the output control functions:
From the PHP manual # http://www.php.net/manual/en/ref.outcontrol.php:
<?php
function callback($buffer)
{
// replace all the apples with oranges
return (str_replace("apples", "oranges", $buffer));
}
ob_start("callback");
?>
<html>
<body>
<p>It's like comparing apples to oranges.</p>
</body>
</html>
<?php
ob_end_flush();
?>
First buffer everything. then replace tags using a parser at end of script.
<?php
$page_buffer = '';
function p($s){
global $page_buffer;
$page_buffer .= $s;
}
$page_buffer = str_replace(
array('<$content$>','<$title$>'),
array($pagecontent,$pagetitle),
$page_buffer);
echo $page_buffer;
?>
Samstyle PHP Framework implements output buffering and View model this way
And did I mention about benefits of buffering your output in a variable before "echo-ing"? http://thephpcode.blogspot.com/2009/02/php-output-buffering.html