Whenever I start a new project I find myself remaking and rethinking my self made template library. I use some influences from dom manipulation, but don't want to make too much functions so that it still loads fast.
This is how my current template system looks like:
This is a layout file:
<body>
<div id="content">
<block:content>This is a default text</block:content>
</div>
<div id="sidebar">
<widget:advertisement type="wide" />
<block:sidebar this_param="is_passed_on" />
</div>
</body>
As you can see I made 2 sort of "extra" tags that will be replaced when eventually publishing the template. I load this layout like this:
$this->template->load("layout");
I then can manipulate the block tags like this:
$this->template->content = "I'm overwriting the default text";
$this->template->content->prepend("I forgot something");
$this->template->sidebar->view("viewfile_1", array(/*data*/));
$this->template->sidebar->view("viewfile_2", array(/*data*/));
I can set text manually, I can load multiple views into 1 block, I can use a few dom-like manipulating functions like prepend, append, ...
I can even extend the template with more layout options like:
$this->template->content->extend("2columns");
This layout file might look like:
<div><block:left/></div>
<div><block:right/></div>
So that instead of the content block I now have an extra left and right block to put content in.
I have also created a widget tag that loads the specific widget class (/widgets/advertisement in this case). The optional parameters added in the tags are passed on to the views files and/or widget display function together with the direct passed data array.
In short, this is how my system now works. I haven't really found other systems like this to get inspiration from. Could you guys give me advice on anything so I can put together one decent system that I can keep using?
My approach is:
Create main layouts for each page type on a layouts/ folder (think Wordpress layouts for home, archive, single post, single page)
Create common bits of interface in a common/ folder (think header, footer, sidebar, widget_XX, widget_YY)
Use Phil Sturgeon's Template Library (or Spark!) to handle the views.
On each controller I load all the data needed for rendering in $this->data and I pass that object to the view
Hope this helps! Good luck.
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 Yii template that structure is:
Include CSS files in
echo $content right after
Include Javascript files (like JQPlot) after $content
What I would like to do is add custom mix of Javascript/PHP code after including all Javascript files. I know this can be done just adding the code to the template.
But I have many pages with custom JS/PHP code and I would like to include only the specific code for that page to avoid long load times.
Can I create new element that works like $content, but it would include for example "js.php" from the same View folder as "index.php"? The "js.php" would be in every view folder I need custom code and contain the js/php mix of code for that specific page.
Thanks for the help!
Clips are your best bet, as #jfrej suggests by pointing you to a forum topic where clips are discussed.
Under conventional circumstances, every controller has associated a folder where all its views are placed, and it is the case that you want to include at the end of the layout (this is how they are refered, rather than templates) some PHP+Javascript content that is common to all the actions in the controller.
I would override CController::afterRender() method to capture the content for you clip; lets call your clip controller_content:
afterRender(string $view, string &$output)
$this->beginClip('controller_content');
// output here any content you want to capture into your clip
// e.g. renderPartial, echo, etc.
...
$this->endClip();
parent::afterRender($view, $output);
}
Then, in your layout, you would render your clip after all the stuff that is always there, e.g.:
// register your CSSs
// output $content variable
// register Javascript
...
<?= $this->clips['controller_content'] ?>
Of course, there are various ways for you to generate your clip content. Here I overrode the CController::afterRender() method, but you could also use filters, behaviors or any other approach that best suits your needs.
You can try :
Yii::app()->clientScript->registerCssFile(Yii::app()->baseUrl.'/css/example.css');
Yii::app()->clientScript->registerScriptFile(Yii::app()->baseUrl.'/css/example.js');
You can call it from controller
I have a very dynamic (social networking) site running smarty that I want to enable caching for.
My Structure:
index.php display()s template.tpl
template.tpl include()s indexContent.tpl
Most of the content in template.tpl is static .. such as the scripts, banner, footer.. etc. How can I cache that but not specific parts which look different to depending on whose logged in (among other factors)?
I've discovered 3 methods:
{nocache} {include='indexContent.tpl'} {nocache}
{dynamic} {include ...
Set the cache_id for each page.
Unfortunately each has a problem:
Doesn't really seem to work? Dynamic content still gets cached..
Not sure how to implement or how it's different than (1)
How to identify uniquely? Some pages have the same "name" but different content for specific members... think "myProfile.php"
Any suggestions? Thanks!!
You can use reverse proxy, like Varnish to cache the static part of the page and to include your dynamic content as Server-Side Includes (for Varnishi it is ESI). Next you will need to setup the caching rules for your static and dynamic URLs so that the static one will be cached for a long time period while the dynamic one will not be cached at all.
To make it easier to understand the whole idea here is how your page HTML code could look like:
<html>
<head>...</head>
<body>
...some static layout...
<esi:include src="/esi/indexContent.php"/>
...some another static layout...
</body>
</html>
Where /esi/indexContent.php is the script that generates the dynamic content.
For Varnish: beware of the gzipped or deflated content with ESIs as it is described in the answer here
We have the same scenario. Our entire front page is cached except for a couple of dynamic elements (news, latest forum threads) and the easiest way I found to get around this is to add in a keyword to the cached template
NEWS_BLOCK
on your logic script you then load your news template and preg_replace it with the keyword.
$news_template = $smarty->fetch('news_template.smrt');
$page_body_raw = $smarty->fetch('frontpage.smrt');
$page_body = preg_replace('/NEWS_BLOCK/', $news_template, $page_body_raw);
in 3 way u can save cache file by this name:
myprofile_id for example a persone that registered and his id is 455 in user table u can save cache file for he with this name myprofile_455
after that u can include cached file in tpl file like this:
{include file="cache/myprofile`$smarty.get.userid`.html"}
I know the question is old my i am still proposing a solution to help someone else.
I seem to get into same trouble with a social networking site i am developing. Here is the solution that worked for me
Doesn't really seem to work? Dynamic content still gets cached..
Not sure how to implement or how it's different than (1)
Just remove the static part of your page like footer and header and put them in a different tpl file. Then include the tpl file as
{include file='head.html' cache_lifetime=5000}
or conversely remove the dynamic part of your page and put it in another template and include it as
{include file='head.html' nocache}
3.How to identify uniquely? Some pages have the same "name" but different content for specific members... think "myProfile.php"
for same page with different content like a profile page, you can pass profile Id as a parameter to cache call.
$my_cache_id = $_GET['profile_id'];
$smarty->display('index.tpl', $my_cache_id);
This will ensure that same page with different parameters are not treated as same page.
Hope this helps.
I am new to Code Igniter and I wish to know if there is anything that works like MasterPages do on .NET.
Also i was wondering where should i keep my public files, like scripts, styles and images.
Greetings, and Thank you in Advance
Master views aren't built into the framework. To get a similar effect you can load the subview and pass that to the master view.
Controller :
class Items extends Controller
{
function show($id)
{
$item = $this->item_model->get_item($id);
// Load the subview
$content = $this->load->view('item/show', array('item' => $item), true);
// Pass to the master view
$this->load->view('master_view', array('content' => $content));
}
}
Master view :
<div id="header">
</div>
<div id="content">
<?php echo $content; ?>
</div>
<div id="footer">
</div>
To answer your other question, I keep all Javascript scripts and CSS in directories in the root of my project.
I'm not sure that they have anything exactly like a master page. CodeIgniter is more of an MVC framework and uses views and controls to build up pages. If you're new to CodeIgniter, net.TutsPlus has a real good series of videos that goes into some depth about how to use the framework for different scenerios. Take a look under the section called "Catch Up" to see the list of videos.
Hope this helps out some and good luck in your project.
try this library
http://www.williamsconcepts.com/ci/codeigniter/libraries/template/?v141
I am not too familiar with .NET or CodeIgniter, but it appears the same functionality can be provided by judicious use of Views. The first sentence on that page says:
In fact, views can flexibly be embedded within other views (within other views, etc., etc.) if you need this type of hierarchy.
This seems like exactly what a MasterPage provides. And in fact, most PHP frameworks and templating systems provide the same features.
In answer to your second question, you may want to keep your scripts, styles, and images in separate folders off of the web root. I believe that URLs are relative to index.php, so keeping your resources near there would make them easier to refer to in your views. Another option is to take a look at the Asset Helper.
So I had a question on general organization of code for the Zend framework with regard to the layout.
My layout is basically this:
(LAYOUT.PHTML)
<div id='header'>
<?= $this->Layout()->header ?>
</div>
<div id='main'>
<?= $this->Layout()->main ?>
</div>
<div id='footer'>
<?= $this->Layout()->footer ?>
</div>
and so on and so forth. Now, in order to keep my code in my header separate from the code of my main and the code of my footer, I've created a folder for my view that holds header.phtml, main.phtml, footer.phtml. I then use this code to assign the content of header.phtml into $this->layout()->header:
(INDEX.PHTML)
$this->Layout()->header = file_get_contents('index/header.phtml');
$this->Layout()->main = file_get_contents('index/main.phtml');
$this->Layout()->footer = file_get_contents('index/footer.phtml');
That was working great, but I've hit a point where I don't want main to be static HTML anymore. I would like to be able to insert some values with PHP. So in my Controller in indexAction, I want to be able to load from my database and put values into index/main.phtml. Is there a way to do this without restructuring my site?
If not is there a way to do it so that I can have:
The ability to put code into different sections of my layout, such as Layout()->header, Layout->footer.
Separate these pieces into different files, so that they're easy to find and organize, like my index/footer.phtml, index/main.phtml etc.
Not have to put that code into quotes unnecessarily to turn it into a string to pass it to Layout()->header etc.
Thank you guys so much for your help.
-Ethan
Here is an idea:
Assign layout()->header the filename instead of the contents.
Put your code in this file
In your layout file, include() or require() the layout->header().
Since your layout headers/footers are now parsed, you can use them just like a view.
The ->header in $this->layout()->header is response segment. You can render parts of response using $this->_helper->viewRenderer->setResponseSegment('header'); in an action.
If you use
$this->layout()->header = $this->render('index/header.phtml');
It will even use the view, therefore keeping all your variables defined when rendering the header.
I would suggest using something like
<?php echo ($header = $this->layout()->header)?
$header : $this->render('headerDefault.phtml'); ?>
in your layout file - it will render a default header from the layout folder if the view script doesn't override it.
Have you tried looking at view helpers. They are a way of structuring view logic into reusable and modular code. In this case you would use a view helper to generate each of your required segments. So your example view script would look like
$this->Layout()->header = $this->header();
$this->Layout()->main = $this->main();
$this->Layout()->footer = $this->footer();
The benefit of using view helpers over include and require statements is that all of the file handling and name resolution is handled by the framework. The manual has more information on how to set up the paths and usage examples etc.
helpers are good. Another option is like the above, putting filenames in header/footer - put the template names and use $this->render($this->layout()->header)), etc etc. This is just like the include/require above, but more consistent.