Means to implement full page cache with dynamic placeholders - php

I want to try create something like Zend's Server Pagecache. What I want to achieve is to store page output, so I guess it would be direct html, but with possibility to insert some dynamic data to page.

Output caching is a large subject. Do do it right, you need to think a bit on the design.
Here are 2 ways. The code sample is just for explanation, it's not a working solution.
Block cache and dynamic composition. Probably the best way. Divide your page into several bloks. Each block should be generated by separate function/class. You can use Zend_Cache_Frontend_* objects to cache those blocks. Once Your application know what to display, in the controller You can compose the output using cached blocks and the dynamic parts.
class CachedController extends Zend_Action_Controller
{
public function indexAction()
{
$this->_view->leftBlock = $this->leftBlock();
$this->_view->rightBlock = $this->rightBlock();
}
protected function leftBlock()
{
// prepare left block, can use Zend_View if you like
// use Zend_Cache to cache the block
}
protected function rightBlock()
{
// prepare left block, can use Zend_View if you like
// use Zend_Cache to cache the block
}
}
/* VIEW SCRIPT */
<html>
<body>
<div class="left">
Left cached block here
<?php echo $this->leftBlock; ?>
</div>
<div class="main">
Do Your dynamic part here
</div>
<div class="right">
Right cached block here
<?php echo $this->rightBlock; ?>
</div>
</body>
</html>
Whole page cache with substring substitution. If you do not wish do divide the page into blocks, You can cache whole page (Also using Zend_Cache_Frontend_*), and then use PHP str functions to substitute or insert the dynamic part. You will need to capture output of the View rather then having it sent by the framework automagically (refer to docs on how to change this).

You can always load dynamic data with ajax.
example:
if user logged and going to vote or something.

Related

Keeping dynamic navigation bar content separate from the controller code - Symfony2

I'm new to Symfony2 and I've been thinking of the best way to generate navigation bar HTML that is used on every page request - especially with regards to caching.
So imagine if every page request shows the logged in user and a number indicating how many messages are unread (in fact like stackoverflow for that). I'm guessing that could be generated in every controller to ensure the info is up-to-date (using a function or something of course) - but I'm also looking at caching the whole controller output, and think it might be good to keep this dynamic part separate.
Would creating a controller extension for all this kind of stuff be a good way to go? So this way the controller only deals with that specific function (e.g. getting blog posts from a DB etc.) and the controller extension adds all the dynamic content. That way I can cache the controller result and speed up pages without caching the full page (which can't really be done due to lots of dynamic HTML content).
Something like this maybe:
class ControllerExtension extends Controller
{
public function render($view, array $parameters = array(), Response $response = null)
{
//get number of messages for this user
$parameters['messages'] =
//are they logged in
$parameters['logged_in'] =
// render as normal
return parent::render($view, $parameters, $response);
}
}
For this I want to ignore use of JS. I know some of these things could be populated with JS, but I would prefer not for this.
You can solve this by caching the navbar fragment separably from the page html with ESI or Hinclude and can be simply and elegantly solved with Symfony2.
Embed a controller inside a template
You can render a controller inside a template:
<div id="sidebar">
{% render url('latest_articles', { 'max': 3 }) %}
</div>
This will render the controller with the route "latest_articles", inside your html.
This can be done in you controller template, or in the global layout template (where you define the header, footer, js, css ecc of all your pages, see Template Inheritance)
Cache the embedded fragment separately from the page html:
You can use a reverse proxy (like Varnish, or the AppCache), to cache the two part of the html separately:
<div id="sidebar">
{% render url('latest_articles', { 'max': 3 }, {'standalone': true}) %}
</div>
That's it, just add {'standalone': true}
You'll need an external program on front of your web server (like Varnish, or Nginx with a mod), but this is the fastest way.
Load the fragment with javascript:
You can also tell symfony to asynchronously load the fragment in javascript:
<div id="sidebar">
{% render url('latest_articles', { 'max': 3 }, {'standalone': 'js'}) %}
</div>
This is a nice approach, since you can cache the entire html in a CDN (for example with Amazon CDN CloudFront), and still show user specific content.
For info see: http://symfony.com/doc/2.1/book/templating.html#asynchronous-content-with-hinclude-js

Is it a bad idea to store html in a DB so that users can edit it?

I just wanted to get your opinions on how I plan to handle a situation.
Situation: I am developing a school's website where strict Board of Education policies will not allow anyone BUT me FTP access to the site. However, the school will have a group of six students in a "webpage" class to manage 10-12 pages that need frequent updating.
The pages all look pretty identical: header, navigation, side navigation (for that specific section (sports, academics, etc)), and the main content.
The main content is served by the div "content", so what I'm thinking to do is just to load all of #content's content from a Mysql db that is edited with another file (I pretty promise to use prepared statements).
Do you have any opinions on this, or maybe a better method? Thank you!
When you kepp your markup in a database, in order to get that one you need:
Parse config file(if any) and establish a connection
Do query and fetch the data
Append the results
When you keep your markup in a file, all you need to do is include that markup via require() language construct
EDIT
To be very specific - No. it's not a bad idea to store dynamic HTML content in a table. This is a common practise. But if you also store static content like header, navigation in a table for each page, it merely leads to data duplication.
I personaly would store the parts I never change in a file. The parts that tend to be "dynamic" I'd store in a table. I would add/edit them via TinyMCE using jquery-ajax.
An example of how I do that:
File: page_view.php
<?php
class Page_View // <- This isn't MVC
{
private $data = array();
public function render()
{
include('page_template.phtml');
exit();
}
private function getTitle()
{
return $this->data['title'];
}
private function getBody()
{
return $this->data['body'];
}
private function getStaticBlock($file)
{
include($file);
}
public function setBody($body)
{
$this->data['body'] = $body;
}
public function setTitle($title)
{
$this->data['title'] = $title;
}
}
File: page_template.phtml
?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo $this->getTitle(); ?></title>
<?php $this->getStaticBlock('/templates/blocks/header.phtml'); ?>
<body>
<div id="navigation">
<?php $this->getStaticBlock('/templates/blocks/navigation.phtml'); ?>
</div>
<div id="content"><?php echo $this->getBody(); ?></div>
</body>
</head>
</html>
Example of usage:
<?php
// $data is what you got from a table
$page = new Page_View();
$page->setTitle($data['title']);
$page->setBody($data['body']);
$page->render();
Yes, storing arbitrary HTML in a database is a nightmare to maintain and secure. I'd look more closely at what you are trying to accomplish before engineering a new solution.
I'd strongly recommend a content management system. They're equipped to deal with this sort of work and there's no sense in rebuilding one from scratch.
If the selected students are going to be frequently updating the website, consider separating out that part of the site.
For example, if the main website is static but the frequently updated parts are a blog, set up a static site and either a subdomain or a sub-directory with a wordpress blog in it.
If the students are going to be editing the actual content of the page, a CMS like Drupal is far more effective for the task.

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.

PHP placement problem

I am calling this function halfway down the page:
<div id="leftArea">
<?php
if (isset($id)){
single($id);
}
?>
</div>
The problem is i want use some of the output in the meta tags in the <head>, whats the best way to approach this?
EDIT:
The single function, takes the $id and echo's the data straight to the page, exactly where it is. In the DIV leftArea. But i want to take one of the rows from the DB and insert it into the META tags at the top
Copy the code into the <head> section.
Redesign your System
The best method is to create a class that manages your html page for you, example:
$Page = new HTMLPage("My Page",HTMLPage::Strict);
$Page->addScript("....");
$Page->addScript("....");
$Page->addScript("....");
$Page->addStyle("....");
$Page->addStyle("....");
$Page->addStyle("....");
$Page->SetBody($MyTemplate);
$Page->send();
this way though out your functions you can do
function myfunc()
{
global $Page;
$Page->addScript("....");
}
the main point here is you should build your document up before sending it to the browser, this way you still have control over the content no matter where your code is executing from.
on the final send method you build your content up, and then push the content via echo, and then exit directly. (all processing should be done prior to output to manage errors)

Zend organization question

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.

Categories