Created
April 4, 2012 11:27
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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