Scn Esi Widget

Zend Framework 2 in the Fast Lane


A leading online media and services company obsessed with gaming, entertainment, and everything you enjoy!


Dynamic scripting languages are great to develop in, but if you have to scale, the first thing to do is make sure you're not doing repetitive work.

Let's speed up our Zend Framework 2 web application by putting Varnish Cache in front of it!

Typical Scaled Web App Stack

Web App Stack w/ Varnish

Zend Framework 2

  • Modular
  • Secure
  • Extensible
  • Community
  • High Performing
  • Enterprise Ready

Varnish Cache

Varnish Cache is a web application accelerator also known as a caching HTTP reverse proxy. You install it in front of any server that speaks HTTP and configure it to cache the contents. Varnish Cache is really, really fast. It typically speeds up delivery with a factor of 300 - 1000x, depending on your architecture.

- www.varnish-cache.org

But I have User Info!

  1. Configure Varnish to never cache "private" parts of the page
  2. Configure Varnish to add the UUID to the hash key
  3. Do all user specific stuff in the client

But I have Dynamic Content!

  1. Probably not as much as you think
  2. Layout? Published blog post?
  3. Blog Comments? Can still cache for short time
  4. At 500 req/s, caching for 1s alleviates a tremendous load from origin servers
  5. Let's face it...as soon as the data leaves your DC, it's already old

Edge Side Includes (ESI)

Edge Side Includes is a simple markup language for edge level dynamic web content assembly. The purpose is to tackle the problem of web infrastructure scaling and is an application of edge computing.

<esi:include src="http://example.com/1.html" alt="http://bak.example.com/2.html" onerror="continue"/>

Scn Esi Widget Components

  • EsiWidget Controller Plugin
  • EsiRenderer
  • EsiStrategy

That's It!

Esi Widget Controller Plugin

  • Wrapper around the ZF2 Forward Plugin
  • Sets up a clone of the MVC event with it's own Request / Response
  • Uses application routes to forward to proper controller / action
  • Injects the resulting View Model into the parent with required params

Esi Renderer

  • Only chosen when client announces surrogate capability
  • Wrapper around the ZF2 PhpRenderer
  • Replaces actual view content with ESI tag

Esi Strategy

  • Chooses EsiRenderer when client announces surrogate capability
  • Adds a response header announcing "Surrogate-Control", i.e. the HTML may contain ESI tags that need to be replaced



Composer is a tool for dependency management in PHP. It allows you to declare the dependent libraries your project needs and it will install them in your project for you.

- getcomposer.org

Composer Configuration

"minimum-stability": "dev",
"require": {
    "php": ">=5.3.3",
    "zendframework/zendframework": "2.*",
    "socalnick/scn-esi-widget": "1.*"

ZF2 Application Configuration

return array(
    'modules' => array(

Varnish Configuration

backend default {
    .host = "";
    .port = "10088";

sub vcl_recv {
    # Set a header announcing Surrogate Capability to the origin
    # ScnEsiWidget sees this header and emits ESI tag for widgets
    set req.http.Surrogate-Capability = "varnish=ESI/1.0";

sub vcl_fetch {
    # Unset the Surrogate Control header and do ESI
    if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
        unset beresp.http.Surrogate-Control;
        set beresp.do_esi = true;


Call Esi Widget Controller Plugin

public function esiAction()
    $viewModel = new ViewModel();
    $this->esiWidget()->addToViewModel($viewModel, '/application/index/recent-tweets', 'recentTweets');

    $headers = $this->getResponse()->getHeaders();
    $cacheControl = new \Zend\Http\Header\CacheControl();
    $cacheControl->addDirective('s-maxage', '60');

    return $viewModel;

Echo Widget in View Script

<div><?php echo $this->recentTweets ?></div>

Action for Esi Widget

public function recentTweetsAction()
    $headers = $this->getResponse()->getHeaders();
    $cacheControl = new \Zend\Http\Header\CacheControl();
    $cacheControl->addDirective('s-maxage', '10');

    $viewModel = new ViewModel();
    return $viewModel;

View Script for Esi Widget

    <li><?php echo date('h:i:s')?> @SocalNick: This is a recent tweet!</li>
    <li><?php echo date('h:i:s', time() - 10)?> @ZendCon: @SocalNick is giving his EsiWidget talk!</li>


  • Zend Skeleton Index
  • Zend Skeleton Index w/ESI (it works w/o Varnish!)
  • Recent Tweets Action (reacheable on it's own)
  • Zend Skeleton Index w/ESI behind Varnish

That's all folks!

Nicholas Calugar

Senior Software Engineer @ IGN Entertainment



Code: https://github.com/SocalNick/ScnEsiWidget

Slides: http://socalnick.github.com/talks/2012/10/24/zf2-fast-lane/

joind.in: https://joind.in/7024