Skip to content

Instantly share code, notes, and snippets.

@jezhalford
Created April 4, 2012 11:27
Show Gist options
  • Save jezhalford/2300463 to your computer and use it in GitHub Desktop.
Save jezhalford/2300463 to your computer and use it in GitHub Desktop.
Zend Framework view helper to render a sheet of address labels as a PDF
<?php
/**
* A view helper to render a sheet of address labels as a PDF.
*/
class My_View_Helper_Labels extends Zend_View_Helper_Abstract {
/**
* @var int A page size constant from Zend_Pdf_Page
*/
private $_pageSize;
/**
* @var Array Associative array containing the height, width and
* padding values for each label
*/
private $_labelSize;
/**
* @var Array Associative array containing the top, bottom, left
* and right margins for the page
*/
private $_margins;
/**
* @var int The number of columns on each page
*/
private $_columns;
/**
* @var int The number of rows on each page
*/
private $_rows;
/**
* @var Array Associative array containing the horizontal and vertical
* spacing for each label
*/
private $_padding;
/**
* @var int The size of font to use
*/
private $_fontSize;
/**
* @var Array Two dimensional array containing starting x/y coordinates
* for each label on the page
*/
private $_cursors;
/**
* @var Zend_Pdf_Page The page we are working on
*/
private $_page;
/**
* @var Zend_Pdf The document we are working on
*/
private $_pdf;
/**
* Let's render some labels
*
* @param $spec array Associative array specifying the layout we want to use.
* Something like this (values in mm, font size in pts)
* array(
* 'pageSize' => 'A4',
* 'columns' => 3,
* 'rows' => 6,
* 'fontSize' => 12,
* 'margins' => array('top' => 5, 'bottom' => 5, 'left' => 5, 'right' => 5),
* 'padding' => array('horizontal' => 5, 'vertical' => 5),
* 'labels' => array('height' => 25, 'width' => 45)
* )
*
* @param $data array|string Array of things to print on each label, or one
* thing to print on all labels
*/
public function labels($spec, $data) {
$this->_parseSpec($spec);
$this->_pdf = new Zend_Pdf();
$labelsPerPage = $this->_rows * $this->_columns;
if(is_array($data)) {
$paginatedData = array_chunk($data, $labelsPerPage);
foreach($paginatedData as $pageData) {
$this->_renderPage($pageData);
}
}
else {
$this->_renderPage($data);
}
return $this->_pdf->render();
}
/**
* Render a single page of labels
*
* @param $data array|string Array of things to print on each label, or one
* thing to print on all labels
*/
protected function _renderPage($data) {
$this->_page = new Zend_Pdf_Page($this->_pageSize);
$this->_page->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA),
$this->_fontSize);
$this->_setCursorPositions();
$this->_pdf->pages[] = $this->_page;
$this->_renderLabels($data);
}
/**
* Render the labels for a single page, having populated $this->_cursors
*
* @param $data array|string Array of things to print on each label, or one
* thing to print on all labels
*/
protected function _renderLabels($data) {
if(is_array($data)) {
foreach($data as $i => $datum) {
$this->_writeLines($datum, $this->_cursors[$i]['x'], $this->_cursors[$i]['y']);
}
}
else {
foreach($this->_cursors as $cursor) {
$this->_writeLines($data, $cursor['x'], $cursor['y']);
}
}
}
/**
* Write some lines of text on the PDF
*
* @param $text string
* @param $x float The x coodinate to start at in points
* @param $y float The y coodinate to start at in points
*/
protected function _writeLines($text, $x, $y) {
$lines = explode("\n", $text);
foreach($lines as $i => $line) {
$this->_page->drawText($line, $x, $y - ($i *
$this->_getFontHeight($this->_page->getFont(), $this->_page->getFontSize())));
}
}
/**
* Sets up the view helper with info from the spec or suitable defaults.
*
* @param array $spec
*/
private function _parseSpec($spec) {
if(isset($spec['pageSize']) && $spec['pageSize'] == 'A4') {
$this->_pageSize = Zend_Pdf_Page::SIZE_A4;
}
else {
throw new Zend_View_Exception('No valid page size specified');
}
if(isset($spec['columns'])) {
$this->_columns = $spec['columns'];
}
else {
throw new Zend_View_Exception('No valid column count specified');
}
if(isset($spec['rows'])) {
$this->_rows = $spec['rows'];
}
else {
throw new Zend_View_Exception('No valid row count specified');
}
if(isset($spec['fontSize'])) {
$this->_fontSize = $spec['fontSize'];
}
else {
throw new Zend_View_Exception('No valid font size specified');
}
if(isset($spec['margins'])) {
$this->_margins = array('top' => 0, 'bottom' => 0, 'left' => 0, 'right' => 0);
foreach($spec['margins'] as $k => $v) {
if($k == 'top' || $k == 'bottom' || $k == 'left' || $k == 'right') {
$this->_margins[$k] = $this->_mmToPts($v);
}
}
}
else {
throw new Zend_View_Exception('No margins specified');
}
if(isset($spec['padding'])) {
$this->_padding = array('horizontal' => 0, 'vertical' => 0);
foreach($spec['padding'] as $k => $v) {
if($k == 'horizontal' || $k == 'vertical') {
$this->_padding[$k] = $this->_mmToPts($v);
}
}
}
else {
throw new Zend_View_Exception('No padding specified');
}
if(isset($spec['labels'])) {
$this->_labelSize = array('height' => 0, 'width' => 0, 'padding' => 0);
foreach($spec['labels'] as $k => $v) {
if($k == 'height' || $k == 'width') {
$this->_labelSize[$k] = $this->_mmToPts($v);
}
}
}
else {
throw new Zend_View_Exception('No label size specified');
}
}
/**
* Populates the _cursors variable with starting x/y coordinates for each label on the page.
*/
private function _setCursorPositions() {
$this->_cursors = array();
$startingY = $this->_page->getHeight();
$fontHeight = $this->_getFontHeight($this->_page->getFont(), $this->_page->getFontSize());
for($j = 0; $j < $this->_rows; $j++) { // rows...
$y = $startingY;
// we always need to add some top margin...
$y -= $this->_margins['top'];
if($j > 0) {
// if this isn't the first then we also need to add
// the vertical padding (i.e. the gap between rows) plus the height of the
// number of labels down we have got...
$y -= $this->_padding['vertical'] * ($j);
$y -= ($this->_labelSize['height'] + $this->_labelSize['padding']) * $j;
}
// shunt downwards by the height of the font - coordinates for fonts
// are set by their baseline.
$y -= $fontHeight;
for($i = 0; $i < $this->_columns; $i++) { // columns...
$x = 0;
// we always need to add some left margin...
$x += $this->_margins['left'];
if($i > 0) {
// if this isn't the first label in the row then we also need to add
// the horizontal padding (i.e. the gap between columns) plus the width of the
// number of labels across we have got...
$x += $this->_padding['horizontal'] * ($i);
$x += ($this->_labelSize['width'] + $this->_labelSize['padding']) * $i;
}
$this->_cursors[] = array(
'x' => $x,
'y' => $y
);
}
}
}
/**
* Find the height of a line of the font in points.
*
* @param Zend_Pdf_Resource_Font $font
* @param float $fontSize
* @return float
*/
private function _getFontHeight($font, $fontSize) {
return ($font->getLineHeight() / $font->getUnitsPerEm() * $fontSize);
}
/**
* Convert millimeters to points.
*
* @param float $mm
* @return float
*/
private function _mmToPts($mm) {
return $mm * 2.834645669;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment