JSON Config Files In Zend Framework

During a recent code review it was suggested that we should move from using an ini file to a JSON file for our Zend Framework application config file. The reason was to reduce duplication of data that can occur and instead move to a nicely nested file.

I wasn’t aware that JSON format config files were supported, but sure enough after a quick look at the Zend Framework documentation, there was the relevant class, Zend_Config_Json. It has only appeared in recent versions of the Zend Framework so that could be why I had missed it.

It’s easy to use in code, being almost a complete drop in for a the usual ini config.

$config = new Zend_Config_Json(
  './example_config.json',
  'production'
);

The first parameter is the location of the config file, the second is the section of the config file to use.

There is an optional third paramter that allows some addition configuration options to be specified such as changing the immutability of the config object once loaded, changing the behaviour of _extends, and the ability to ignore constants. More details can be found in options section of the Zend_Config_Json manual.

Here’s a quick example. Firstly the JSON configuration file.

{
  "production" : {
    "username" : "Robert Price",
    "beer" : [
      "Harveys Sussex Best",
      "Spitfire",
      "Asahi"
    ]
  },
  "testing" : {
    "_extends" : "production",
    "beer" : [
      "Harveys Star Of Eastbourne",
      "Schwaben Brau - Das Helle",
      "Brauhaus J.Albrect - Dunkel"
    ]
  }
}

OK, it’s a good real life example, but it has two sections, production and testing. Testing inherits from production by using the _extends parameter.
We can load and extract details using the following code.

$config = new Zend_Config_Json(
  './example_config.json',
  'production'
);
echo "Username is " . $config->username . "n";
echo "Favourite beers are...n";
foreach ($config->beer as $beer) {
  echo "* " . $beer . "n";
}

When you run this code you get the following results, assuming you saved the json config file from earlier as example_config.json

Username is Robert Price
Favourite beers are...
* Harveys Sussex Best
* Spitfire
* Asahi

Now change the code so instead of production when we load the config file, we use testing. Run the code and you’ll get the following…

Username is Robert Price
Favourite beers are...
* Harveys Star Of Eastbourne
* Schwaben Brau - Das Helle
* Brauhaus J.Albrect - Dunkel

As you can see my username has been inherited from the production block, but the list of beers has changed. This is a very powerful feature that lets you change a small section of data between environments in real code without having to repeat yourself and reduces the risk introducing errors in duplicated config options.

Adding Colour To A Mandelbrot Set

I was looking for a way to introduce some colour into my example Drawing A Mandelbrot Set With Zend PDF.

The method I settled upon was to use HSV – Hue, Saturation, Value.

I’m not an expert on colour theory, so I may not be the best person to describe how it works. The best way I can though, is to describe it as a cylinder, round the circumference is the hue, the radius is the saturation, and the height is the value. For a detailed definition, read the Wikipedia entry on HSL and HSV.

I can pick a hue and value, then just vary the saturation to give a nice graduated colour version of the earlier grayscale example.

Blue Mandelbrot

Alternatively I can pick a value and saturation, and vary the hue to give a vivid rainbow style fractal.

Vivid Mandelbrot

To achieve the first, we replace the code in the loop that prepared the grayscale colours, and instead generate our $colours array with the following…

list($red, $green, $blue) = hsvToRgb(0.5, $grayLevel, 1);
$colours[$i] = new Zend_Pdf_Color_Rgb($red, $green, $blue);

Firstly we get the values for $red, $green and $blue for a hue of 0.5 (blue), our varying $graylevel between 0 and 1, and a $value of 1 for the most vivid colours. After this we create a Zend_Pdf_Color and store it in the $colours array to use later.

To achieve the latter we just change how we call the hsvToRgb function.

list($red, $green, $blue) = hsvToRgb($grayLevel, 1, 1);
$colours[$i] = new Zend_Pdf_Color_Rgb($red, $green, $blue);

Now, you may have noticed that there isn’t a function called hsvToRgb available to PHP. Just drop in the following code.

function hsvToRgb ($hue, $saturation, $value)
{
  $rgb = array($value, $value, $value);
  if ($saturation != 0) {
    $varH = $hue * 6;
    $varI = floor($varH);
    $var1 = $value * ( 1 - $saturation );
    $var2 = $value * ( 1 - $saturation * ( $varH - $varI ) );
    $var3 = $value * ( 1 - $saturation * (1 - ( $varH - $varI ) ) );
    if ($varI == 0) {
      $rgb = array($value, $var3, $var1);
    } else if ($varI == 1) {
      $rgb = array($var2, $value, $var1);
    } else if ($varI == 2) {
      $rgb = array($var1, $value, $var3);
    } else if ($varI == 3) {
      $rgb = array($var1, $var2, $value);
    } else if ($varI == 4) {
      $rgb = array($var3, $var1, $value);
    } else {
      $rgb = array($value, $var1, $var2);
    }
  }
  return $rgb;
}

Drawing A Mandelbrot Set With Zend PDF

As you may know from some of my previous posts, I’ve been looking at Zend Framework’s PDF support.

As a bit of fun on the train home from work, I wondered if it would be possible to draw out a Mandelbrot Set using the PDF drawing functions in Zend_Pdf.

For those who don’t know what the Mandelbrot Set is, it is a fractal shape, and one of those projects every developer plays with at some point. It looks like my time has come here.

There is a reasonably simple formula for generating the image, we just need to iterate between a maximum and minimum x and y co-ordinate set and draw a pixel at each point when the number of iterations of the formula has reached a pre-defined number. In my example, I’m using 20 iterations, though you can go higher for greater accuracy. I won’t go over the formula, as it is explained in far greater depth than I have time for elsewhere on the internet.

In this code example, I’m using variables similar to those used in Mandelbrots formula, so they do trigger warnings with Zend Framework’s coding standards, but I think they make sense.

// load the Zend Framework Autoloader.
ini_set('include_path', './library');
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
$maxIterations = 20;
$minX = -2;
$maxX = 1;
$minY = -1;
$maxY = 1;
try {
  // create a new PDF document.
  $pdf = new Zend_Pdf();
  // create a new A4 sized page.
  $page = new Zend_Pdf_Page(Zend_Pdf_Page::SIZE_A4);
  // calculate the width and height of the image to generate.
  $width = $page->getWidth();
  $height = $page->getHeight();
  if ($width > $height) {
    $width = $height;
  } else {
    $height = $width;
  }
  // prepare a black colour we can reuse when we draw the mandelbrot set.
  $black = new Zend_Pdf_Color_Html('#000000');
  // iterate over the mandelbrot set and draw it out.
  for ($x=0; $x<=$width; $x++) {
    for ($y=0; $y<=$height; $y++) {
      $c1 = $minX + ($maxX - $minX) / $width * $x;
      $c2 = $minY + ($maxY - $minY) / $height * $y;
      $z1 = 0;
      $z2 = 0;
      for ($i=0; $i<$maxIterations; $i++) {
        $newZ1 = $z1 * $z1 - $z2 * $z2 + $c1;
        $newZ2 = 2 * $z1 * $z2 + $c2;
        $z1 = $newZ1;
        $z2 = $newZ2;
        if ($z1 * $z1 + $z2 * $z2 >= 4) {
          break;
        }
      }
      // if we reach max iterations, draw a black pixel
      if ($i >= $maxIterations) {
        $page->setFillColor($black)
             ->setLineColor($black)
             ->drawRectangle(
               $x,
               $y,
               $x+1,
               $y+1,
               Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE
             );
      }
    }
  }
  // add the page to the pdf document.
  $pdf->pages[] = $page;
  // save the finished PDF to a file
  $pdf->save('fractal.pdf');
  // catch any errors
} catch (Zend_Pdf_Exception $e) {
  die('PDF error: ' . $e->getMessage());
} catch (Exception $e) {
  die ('Error: ' . $e->getMessage());
}

You will need to run this code on the command line, and it will take a few seconds to execute. When complete, you will have a PDF document with the following image.

Mandelbrot set rendered from a PDF

We can refine this slightly to get a prettier picture if we show the number of iterations used in a different colour, instead of just showing black if we go over our limit of maximum iterations.

To do this, we’d need to prepare an associative array with a colour for each iteration. The easiest option is to use grayscale and Zend_Pdf_Color_GrayScale. After we work out the max width and height, insert the following code.

// prepare colours
for ($i=0; $i >= $maxIterations; $i++) {
  $grayLevel = $i / $maxIterations;
  $colours[$i] = new Zend_Pdf_Color_GrayScale($grayLevel);
}

Now we have an associative array to look up a different shade of gray from 0 to $maxIterations.

Instead of the code that checks if $maxIterations has been reached and then draw a black pixel, we can replace it with the following

$page->setLineColor($colours[$i])
     ->setFillColor($colours[$i])
     ->drawRectangle($x, $y, $x+1, $y+1, Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE);

Run this modified script on the command line, and you’ll generate a PDF with the following image.

Mandelbrot set rendered from a PDF in grayscale

That image looks great, but not very colourful. I’ll cover how to get some colour in there another time.

Drawing A Image In A PDF With Zend Framework

I recently wrote about Creating A Simple PDF With The Zend Framework, and so I thought I’d take a quick look at Zend_PDF’s Drawing Methods.

As you may know I work for a company called Bauer and we have a very simple logo. It’s basically a blue square, with a gray triangle in the top right hand corner and the name BAUER in white at the bottom. This sounds like an ideal image to try to recreate using Zend_PDF.

Bauer Media Logo

Take a look at my previous article on PDF’s and Zend Framework for an explanation of setting up a document and page to draw on. I will assume this page has been setup and is available in the $page variable.

Firstly we need to prepare a font for use. I don’t know the font Bauer use, so I’ll just use Helvetica Bold in this example.

$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA_BOLD);

The background is a blue square, so I need to set the fill colour to the shade of blue Bauer use, then draw the square using this colour.

$page->setFillColor(new Zend_Pdf_Color_Html('#014495'))
     ->drawRectangle(0, 0, 200, 200, Zend_Pdf_Page::SHAPE_DRAW_FILL);

As you can see, I’ve decided to make the logo 200×200 in size.

Now it’s time to write BAUER at the bottom in white using the font we prepared earlier.

$page->setFillColor(new Zend_Pdf_Color_Html('#ffffff'))
     ->setFont($font, 52)
     ->drawText('BAUER', 7, 10);

Firstly I set the fill colour to white. Next I select the font and set it’s size. Finally I write the word BAUER at co-ordinates 7,10, which happens to be at the bottom of the blue square.

Finally it’s time to draw the gray triangle in the top right corner of the blue square.

$page->setFillColor(new Zend_Pdf_Color_Html('#dddddd'))
     ->drawPolygon(array(70, 190, 190),
                   array(190, 190, 70),
                   Zend_Pdf_Page::SHAPE_DRAW_FILL);

As before, I set the fill colour, this time to gray. Now I use the drawPolygon method to draw the triangle. As you can see there are two arrays there, the first are the x co-ordinates of the triangle, the second are the y co-ordinates of the triangle. The fill method is the last parameter, it’s the same as the one we used when drawing the blue square.

We should now have our Bauer logo on the page!

generated copy of the Bauer Media logo

I don’t think that Bauer will be sacking their design team in a hurry, but it’s quite a close approximation of the logo.

Here’s a copy of the finished code.

// load the Zend Framework Autoloader.
ini_set("include_path","./library");
require_once 'Zend/Loader/Autoloader.php';

$loader = Zend_Loader_Autoloader::getInstance();

try {
  // create a new PDF document.
  $pdf = new Zend_Pdf();

  // create a new A4 sized page.
  $page = new Zend_Pdf_Page(Zend_Pdf_Page::SIZE_A4);

  // prepare the Helvetica Bold font.
  $font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA_BOLD);

  // draw the blue square background.
  $page->setFillColor(new Zend_Pdf_Color_Html('#014495'))
       ->drawRectangle(0, 0, 200, 200, Zend_Pdf_Page::SHAPE_DRAW_FILL);

  // draw the white BAUER text at the bottom of the square.
  $page->setFillColor(new Zend_Pdf_Color_Html('#ffffff'))
       ->setFont($font, 52)
       ->drawText('BAUER', 7, 10);

  // draw the grey triangle in the top right corner of the square.
  $page->setFillColor(new Zend_Pdf_Color_Html('#dddddd'))
       ->drawPolygon(array(70, 190, 190),
                     array(190, 190, 70),
                     Zend_Pdf_Page::SHAPE_DRAW_FILL);

  // add the page to the pdf document.
  $pdf->pages[] = $page;

  // save the finished PDF to a file
  $pdf->save('bauer.pdf');

// catch any errors
} catch (Zend_Pdf_Exception $e) {
  die('PDF error: ' . $e->getMessage());
} catch (Exception $e) {
  die ('Error: ' . $e->getMessage());
}

Creating A Simple PDF With The Zend Framework

I’ve recently been playing with creating PDF documents for a project I’ve been working on.

I thought I’d share some of the knowledge I’ve gained in the hope it will help others.

I’ve been using the excellent Zend Framework as usual, and the Zend_Pdf component in particular. This is a pure PHP implementation of the PDF standard and it doesn’t require any other libraries to be installed to work.

A PDF document is text document that has been been designed by Adobe a way to create and share printable documents across multiple platforms. If you open a PDF document in a text editor, you can see the markup for yourself, however it’s not very user friendly. This is where Zend_Pdf comes to our aid.

Let’s create a simple A4 document, and say Hello World!.


<?php
// load the Zend Framework Autoloader.
ini_set("include_path","./library");
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
try {
// create a new PDF document.
$pdf = new Zend_Pdf();
// create the Helvetica font.
$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA);
// create a new A4 sized page.
$page = new Zend_Pdf_Page(Zend_Pdf_Page::SIZE_A4);
// draw the text Hello World! to position 0,0 with the Helvetica font.
$page->setFont($font, 16)
->drawText('Hello World!',0,0);
// add the page to the pdf document.
$pdf->pages[] = $page;
// save the finished PDF to a file
$pdf->save('helloworld.pdf');
// catch any errors
} catch (Zend_Pdf_Exception $e) {
die('PDF error: ' . $e->getMessage());
} catch (Exception $e) {
die ('Error: ' . $e->getMessage());
}
?>

What’s going on? Well firstly I take advantage of Zend Frameworks autoloader to load in the required components.

Next I create an empty PDF document. A copy of the Helvetica font is prepared for use. We’ll need to add pages to this document, so after this we create a new A4 sized page. I’ve used A4 as that is the common paper size in Europe, but in the US letter size is the standard. This can be changed by using Zend_Pdf_Page::SIZE_LETTER instead of Zend_Pdf_Page::SIZE_A4.

Now I have a page, I want to add some text to it. This is easily achieved using the drawText method. This takes the text, and an X and Y position to draw it at. We do need to set the font first, let’s use the Helvetica font we defined earlier, and use size 16. I chose position 0,0 to write the text, this is the bottom left hand side of the page.

Finally, I add the page to PDF document, and save it.

If an error occurs, I catch this with my exception handlers.

Of course, in reality you’ll want o do a lot more than just write one line of text. Zend_Pdf allows you to do a lot more, such as adding images, drawing graphics, adding meta data. I’ll cover this in another post.

Adding A Trailing Slash To A Zend Framework URL

“We need all our URL’s to have a trailing slash”, was a request I had in recently.

This sounds easy enough, a quick rewrite rule will do the trick, and that is what I added.

RewriteRule ^(.*[^/])$ /$1/ [R=301,L]

I look at the start of the URL, grab every character to the end of the URL, making sure the last one isn’t a slash already, then rewrite that with slashes around it, issuing a 301 redirect and informing Apache not to process any more rules.

This works great for pages already on the server, for example /guestbook becomes /guestbook/. However, what if we wanted to load /logo.gif, this would rewrite to /logo.gif/ and cause a error.

OK, so we need not to match every character in the URL, but only if it doesn’t have a dot in there. The site in question was a Zend Framework application, and this caused it’s own problems.

Zend Framework applications have their own rewriting rules…

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

This checks if the requested resource is actually a real object Apache can serve, if not it passes it over to the Zend Framework to handle internally via the index.php script.

So what happens if /guestbook is actually a Zend Framework application?

Well, the URL would be rewritten to /index.php/.

Why? Well the first rewrite we added a slash, this caused the page to re-requested, this then passed to the Zend Framework rewrites, this saw it needed to rewrite to index.php, this caused the page to be re-requested again internally, which added a slash to the end, and redirected again. Finally this request was /index.php/ which doesn’t exist and failed.

Wow, that was a mouthful, let’s look at that as a sequence diagram.

sequence diagram showing apache rewrites and Zend Framework working incorrectly

What we need is to only rewrite the requested URL if it doesn’t have a trailing slash and if it doesn’t have a dot in the request and if it isn’t an internal Apache redirect. We also only want to rewrite if the request is a GET, POSTs (DELETE’s and PUT’s too) don’t support rewriting in the browser.

This indicates a series a conditions that need to be met, so tells me we should be using Apache’s RewriteCond directive.

Let’s check for a GET request first…

RewriteCond %{REQUEST_METHOD} GET [NC]

The %{REQUEST_METHOD} variable in a rewrite rule tells us the HTTP method used to make the request, so we just need to check if that is GET. The [NC] makes the check case insensitive so matches GET, get, Get, etc…

Next we need to see if the request already has a trailing slash.

RewriteCond %{REQUEST_URI} !/$

This checks the requested URI and sees if the last character isn’t a slash.

Now we need to check if there are any dots in the request.

RewriteCond %{REQUEST_URI} !.

This just checks that there isn’t a dot in the requested URI. As dot normally matches any character, we need to escape this with a clash first.

If all these conditions match, we can issue our RewriteRule.

RewriteRule ^.*$ %{REQUEST_URI}/ [R=301,L]

This takes the requested URI, adds a slash and issues a 301 status code to force the browser to re-request the page and change the URL shown in the address bar. We add the L to tell Apache not to process any more rules.

Let’s put this all together, and insert it above the normal Zend Framework rewrites, but after RewriteEngine On.

RewriteCond %{REQUEST_METHOD} GET [NC]
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{REQUEST_URI} !.
RewriteRule ^.*$ %{REQUEST_URI}/ [R=301,L]

Let’s request /guestbook again, and see what happens.

sequence diagram showing apache rewrites and Zend Framework

Disabling The Zend Framework ViewRenderer

There are times when using the Zend Framework that you don’t want a view to render.

For example, you may be generating a feed programaticaly, or you may be using a templating engine such as Twig for some or all paths.

By default, the front controller enables the ViewRenderer action helper. It is the job of the ViewRenderer to inject the view object into the controller and to automatically render the view. The idea is that you don’t need to worry about manually instantiating view objects in your controller, the helper does it for you.

It’s actually very simple to disable this behaviour, and there are several ways to do it.

Firstly, if you want to disable this functionality across your application, you could use the following in the application.ini file…

resources.frontController.noViewRenderer = true

This can also be set programatically…

Zend_Controller_Front::getInstance()-&gt;setParam('noViewRenderer', true);

A better approach would be to simply remove the ViewRenderer helper.

$this->_helper->removeHelper('viewRenderer');

If you don’t want the ViewRenderer disabled across your entire application, you can set it locally in a controller…

$this->_helper->viewRenderer->setNoRender(true);