I've always thought about this and I can't decide what to do. Lets say I have a <div> and I want to echo specific links in it if the user is an admin or a just a member.
Would it be best to have the <div> in the HTML, and just do some if echos within it?
Or should you echo the whole entire div and everything inside it?
There is no possibilty of the div being empty.
You probably should go with code like (for simple application):
<div class="nav">
Index
Profile
<?php
if( $this->isAdmin()){
echo $this->getAdminLinks();
}
?>
</div>
Or rather something like this:
<?php
echo $this->getAdminLinks();
?>
and let that function care about whether to display or not function. For example Zend uses inline php in phtml templates (and I consider Zend great place where to learn).
If you're building complex application (multiple styles, complex navigation, many different types of pages and many conditions how to generate menu) or you use MVC framework, you should go with code:
<?php
echo $this->getNavigation();
?>
Code like this may get really hard to read (imagine 70 lines like this):
One
<?php echo $this->getSecond(); ?>
Third
<?php // some crazy stuff with 2 submenu levels
?>
Anyway, there's no one "good way" to do this, it's all based on what you need and how do you like your codes written.
Related
I am creating breadcrumbs on my simple site.
I have some helper classes. I use them like this (just example):
$Breadcrumbs = new Breadcrumbs();
$Breadcrumbs->add(new Breadcrumb("/", "page1"));
$Breadcrumbs->add(new Breadcrumb("/", "page2"));
$Breadcrumbs->add(new Breadcrumb("/", "page3"));
$breadcrumb->show(); returns this:
<ol class="breadcrumb">
<li>page1</li>
<li>page2</li>
<li class="active">page3</li>
</ol>
So, in my project I have some switch-case constructions in which I include some files.
In this files I am using $breadcrumbs->add(...). This code:
<div class="container body">
<? $Breadcrumbs->show();?>
<?
$page = isset($_GET['page']) ? $_GET['page'] : null;
switch($page):
case "suppliers":
require_once($DOCUMENT_ROOT."/modules/suppliers.php");
break;
default:
require_once($DOCUMENT_ROOT."/modules/default.php");
break;
endswitch;
?>
<? $Breadcrumbs->show();?>
</div>
gives me this result:
Well, it works like it must work. I am using $breadcrumbs->add(...) in require files after I called $breadcrumb->show() first time thats why 1st call returns blank result. 2nd call of show() is after all breadcrumbs are added, so it returns fine result.
The questions is how to output breadcrumbs before switch blocks but with right content. Maybe I need a buffer or idk?
This is a good example of why it is such a good idea to separate out logic from presentation: you have a nice abstraction for crumb links, but can't use it properly because your other code is outputting as it goes along, rather than working with abstract data.
Obviously, you could throw away your current structure and port both logic and display directly into a new framework, but assuming you want to migrate from where you are now, here's one approach:
Create an object or array that represents the "result" of whatever module is called. Replace all current use of echo or ?> with concatenation to a string called something like $results['generic_output']. This is effectively like buffering your output, and is enough to let you use your existing abstractions like $breadcrumbs at any time. At this stage, your "template" would consist mostly of echo $results['generic_output'], plus the boilerplate header and footer which is probably already gathered in one place.
Start breaking down the output into sections. Particularly look for sections which are similar on multiple pages. For instance, if you have a "sidebar" with different content on each page but similar styling, make a $results['sidebar_content'] with just the content of that sidebar; the boilerplate to lay it out can then go into your template, and you've reduced the amount of code duplication.
Make the data you pass to the template increasingly abstract, with the goal of eventually having no HTML outside of the template(s). For instance, maybe the sidebar is made up of panels; you might start with an array of HTML blocks, one for each panel, but then turn it into an array of objects based on the actual data being displayed (say, a special offer, or the customer's current basket), with a set of templates for handling different kinds of panel. Eventually, it should be theoretically possible to build a plain-text version of your site with no HTML, just by changing the template layer, and none of the original modules.
The final step is to separate decisions about what to show from decisions about what to do. Continuing with my imaginary sidebar, your template could always receive the current basket as a general variable for use somewhere on the page, rather than as "sidebar item 1". This allows you to completely separate the actions that led into a page from the output that eventually results.
I would like to stress that this is not the way to a perfect framework, or the definitive solution to your situation, but it's one way of organising existing code (and existing thinking) in the right direction.
In the above, the "templates" could just be a set of PHP files using ?> or echo to produce the output, or it could be a dedicated templating system such as Smarty or Twig. Indeed, the point of the separation is that you could change your mind on that front later, because the result of the code modules would be an array of data to be displayed, which is just what Smarty or Twig would need as input.
I have a custom CMS here entitled phpVMS, and I want to exclude a piece of code, a banner for a single page. phpVMS is steered using templates, for instance, the main template that codes the general layout for all pages is entitled layout.tpl. So, like I said, this displays whatever is in the template, on all of the pages. I have however created a special control panel, and therefore require to exclude the banner, because it slightly destroys the theme of it. Is there any PHP code that excludes a piece of code on a single site? I need to remove a single div...
<div id="slideshow"></div>
...on a single page.
Basically, I could create a new template but this is a very long winded and unefficient way within this CMS, and the final result isn't that great - because I can't reinclude the mainbox div which is the box defining the content on the centre white bit of the theme - it's already in the layout.tpl.
I hope you can somehow help me, hope I've included enough information there.
Thanks.
I don't think you can do what you're asking in PHP, but you might be able to do this on the client-side, by either hiding the div (CSS display:none) or by removing it with JavaScript. You might be able to do something like:
<?php
include("layout.tpi");
if (condition)
{
// Javascript:
echo "<script>document.getElementById('slideshow').style.display = 'none';</script>";
// OR jQuery:
echo "<script>$('#slideshow').hide();</script>";
}
?>
If you use a variable to determine you don't want to include the div, you could do this:
<?php if ($include) { ?>
<div id="slideshow"></div>
<?php } ?>
OR
<?php
if (!$include)
echo "<!--";
?>
<div id="slideshow"></div>
<?php
if (!$include)
echo "-->";
?>
EDIT: Obviously, there is no good reason to use the second method. The second method will only comment out the HTML so it will still show up in the source.
I'm not sure if this is what you are looking for, but seems simple
<?
$template = true;
if($template) {
?>
<div id="slideshow"></div>
<?
}
?>
On the template, you could have some code that reads:
if($_SERVER['PHP_SELF'] == /*control panel file*/) {
//exclude
}else{
//include
}
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.
Most HTML in a large website is duplicated across pages (the header, footer, navigation menus, etc.). How do you design your code so that all this duplicate HTML is not actually duplicated in your code? For example, if I want to change my navigation links from a <ul> to a <ol>, I'd like to make that change in just one file.
Here's how I've seen one particular codebase handle this problem. The code for every page looks like this:
print_top_html();
/* all the code/HTML for this particular page */
print_bottom_html();
But I feel uncomfortable with this approach (partially because opening tags aren't in the same file as their closing tags).
Is there a better way?
I mostly work with PHP sites, but I'd be interested in hearing solutions for other languages (I'm not sure if this question is language-agnostic).
I'm not a php programmer, but I know we can use a templating system called Smarty that it works with templates(views), something like asp.net mvc does with Razor.
look here http://www.smarty.net/
One solution at least in the case of PHP (and other programming languages) is templates. Instead of having two functions like you have above it would instead be a mix of HTML and PHP like this.
<html>
<head>
<title><?php print $page_title ?></title>
<?php print $styles ?>
<?php print $scripts ?>
</head>
<body>
<div id="nav">
<?php print $nav ?>
</div>
<div id="content">
<?php print $content ?>
</div>
</body>
</html>
Each variable within this template would contain HTML that was produced by another template, HTML produced by a function, or also content from a database. There are a number of PHP template engines which operate in more or less this manner.
You create a template for HTML that you would generally use over and over again. Then to use it would be something like this.
<?php
$vars['nav'] = _generate_nav();
$vars['content'] = "This is the page content."
extract($vars); // Extracts variables from an array, see php.net docs
include 'page_template.php'; // Or whatever you want to name your template
It's a pretty flexible way of doing things and one which a lot of frameworks and content management systems use.
Here's a really, really simplified version of a common method.
layout.php
<html>
<body>
<?php echo $content; ?>
</body>
</html>
Then
whatever_page.php
<?php
$content = "Hello World";
include( 'layout.php' );
Sounds like you need to use include() or require()
<?php
include("header.inc.php");
output html code for page
include("footer.inc.php");
?>
The header and footer files can hold all the common HTML for the site.
You asked for how other languages handle this, and I didn't see anything other than PHP, so I encourage you to check out Rails. Rails convention is elegant, and reflects #codeincarnate 's version in PHP.
In the MVC framework, the current view is rendered inside of a controller-specific layout file that encapsulates the current method's corresponding view. It uses a "yield" method to identify a section where view content should be inserted. A common layout file looks like this:
<html>
<head>
<% #stylesheet and js includes %>
<body>
<div id="header">Header content, menus, etc…</div>
<%= yield %>
<div id="footer">Footer content</div>
</body>
</html>
This enables the application to have a different look and feel or different navigation based on the controller. In practice, I haven't used different layout files for each controller, but instead rely on the default layout, which is named "application".
However, let's say you had a company website, with separate controllers for "information", "blog", and "admin". You could then change the navigation for each in a clean and unobtrusive manner by handling the different layout views in their respective layout files that correspond to their controllers.
You can always set a custom layout in the controller method by stating:
render :layout => 'custom_layout'
There are also great helper methods built into Rails so you don't have to rely on $global variables in PHP to ensure your CSS and Javascript paths are correct depending on your development environment (dev, staging, prod…). The most common are:
#looks in public/stylesheets and assumes it's a css file
stylesheet_link_tag "filename_without_extension"
#looks in public/javascripts and assumes it's a js file
javascript_include_tag "jquery"
Of course, each of these sections could be expounded upon in much greater detail and this is just brushing the surface. Check out the following for more detail:
http://guides.rubyonrails.org/layouts_and_rendering.html
What you suggested works OK. As long as print_top_html and print_bottom_html stay in sync (and you can use automated tests to check this), then you never need to worry about them again, leaving you to focus on the real content of the site -- the stuff in the middle.
Alternatively, you can combine print_top_html and print_bottom_html into a single call, and send it HTML code (or a callback) to place in the middle.
I use the partials system of Zend_View (very similar to Rails). A partial is essentially a small HTML template that has its own variable scope. It can be called from inside views like:
<?php echo $this->partial('my_partial.phtml', array( 'var1' => $myvar ));
The variables that get passed into the construct get bound to local variables inside the partial itself. Very handy for re-use.
You can also render a partial from inside normal code, if you're writing a helper object where you have more complex logic than you'd normally feel comfortable putting in a view.
public function helperFunction()
{
// complex logic here
$html = $this->getView()->partial('my_partial.phtml', array('var1' => $myvar ));
return $html;
}
Then in your view
<?php echo $this->myHelper()->helperFunction(); ?>
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.