Okay, after much asking for it I guess I’ll share my snippet
It works like this:
http://nimja.com/frozen-youth
That is a dynamic PDF file with the background and copyright automatically added for each page. My whole story is in there automatically and is always up to date.
Current version: 0.8
Version history:
v0.8 - Added Title and Author support to the snippet call
v0.7 - Fixed the ’deprecated’ error that prevented PDFs from being proper.
v0.6 - Added multiple parents support.
v0.5 - Italic font support, limited to whole lines/paragraphs.
v0.4 - Optimizations for 100+ pages.
v0.3 - Added header and footer.
v0.2 - Numerous fixes
v0.1 - Basic work.
Libraries used:
modified FPDI - Added setTemplate function. - included in the download of this post.
original available at:
http://www.setasign.de/products/pdf-php-solutions/fpdi/
Install:
Download the files at the bottom of this post and upload them to your server so the files reside in YOUR_SITE/assets/snippets/makepdf/
Create the snippet with the name
MakePDF from the code below. There is an error when trying to upload the zip file to this thread:
The attachments upload directory is not writable. Your attachment or avatar cannot be saved.
Add
application/pdf to the Custom content types: (in Tools -> Configuration)
Sorry, while the file upload doesn’t work, download the file here: makepdf.zip
Usage:
Create an new document:
set "Uses template" to
(blank)
set "Document’s alias" to
something.pdf
set "Content Type" to
application/pdf
Call the snippet:
[!MakePDF? &parent=`1` !]
(see the snippet for more options)
Notes:
I’ve used several PHP->PDF libraries but only FPDF (and FPDI) has good enough performance and can handle documents over 50 pages. Do note that using a template uses more memory and I had to abandon templates over about 300 pages.
Please note that this is very much a work in progress and supposed to be educational. It works, but that’s about it. Please feel free to point out any/all obvious mistakes I’ve made.
Snippet Code:
For the curious or the lazy.
<?php
/* MakePDF snippet:
v0.8 - Added Title and Author support to the snippet call and fixed the filename not working.
v0.7 - Fixed the 'deprecated' error that prevented PDFs from being proper.
v0.6 - Added multiple parents support.
v0.5 - Italic font support, limited to whole lines/paragraphs.
v0.4 - Optimizations for 100+ pages.
v0.3 - Added header and footer.
v0.2 - Numerous fixes
v0.1 - Basic work.
By Nimja - nimja.com
Usage:
[!MakePDF? &parent=`1` !] -- Basic example
[!MakePDF? &parent=`1,2,3` !] -- Multiple parents
[!MakePDF? &parent=`1,2,3` &sortBy=`pub_date` $sortDir=`asc` &where=`template=1` &filename=`Frozen_Youth.pdf` &title=`Frozen Youth` $author=`Nimja.com` &limit=`10`!] -- Additional settings.
*/
/* ------------------------------------------
Basic settings
------------------------------------------- */
if (isset($parent)) {
//Title, above each page.
$pdfTitle = (!empty($title)) ? $title : 'Frozen Youth';
//Author, below each page with copyright.
$pdfAuthor = (!empty($author)) ? $author : 'Nimja';
// &sortBY, field to sort by, defaults to pub_date.
$sortBy = (!empty($sortBy) ) ? $sortBy : 'menuindex';
// &sortHow, sort direction, defaults to ASC(ending).
// Options are: ASC, DESC
$sortHow = (!empty($sortHow) ) ? $sortHow : 'ASC';
//Additional 'filters'
$where = (!empty($where) ) ? $where : '';
//&filename - The filename of the PDF people will download.
$filename = (!empty($filename) ) ? $filename : 'Download.pdf';
//&limit - Max number of pages we will retrieve. Leave empty or 0 for all.
$limit = (!empty($limit) ) ? $limit : '';
//Fields we use.
$fields = 'longtitle,description,content';
$basepath = $modx->config['base_path']."assets/snippets/makepdf/";
$classpath = $basepath.'class/';
//Use MODX function to get children.
$parents = split(',', $parent);
$pages = Array();
foreach($parents as $par) {
$pages = array_merge($pages,$modx->getDocumentChildren($par, 1, 0, $fields, $where, $sortBy, $sortHow, $limit));
}
require_once($classpath.'fpdi.php');
/* ------------------------------------------
Header and Footer to class
------------------------------------------- */
class PDF extends FPDI {
function Header() {
$this->SetFont('Arial','I',11);
//Position at 1.5 cm from bottom
$this->SetY(5);
//Page number
$this->Cell(0,10,$this->title,0,1,'R');
}
function Footer() {
$this->SetFont('Arial','I',8);
//Position at 1.5 cm from bottom
$this->SetY(-15);
//Copyright based on year and author.
$this->Cell(0,10,'Copyright '.date("Y").' '.$this->author,0,0,'L');
//Position at 1.5 cm from bottom
$this->SetY(-15);
//Page number
$this->Cell(0,10,$this->PageNo(),0,0,'R');
}
}
/* ------------------------------------------
Start PDF and set the settings.
------------------------------------------- */
// initiate FPDI
$pdf = new PDF();
// add a page
$pdf->AddPage();
// set the sourcefile
$pdf->setSourceFile($basepath.'Page.pdf');
$pdf->SetAuthor($pdfAuthor);
$pdf->SetCreator($pdfAuthor);
$pdf->SetTitle($pdfTitle);
// import page 1
$templatePage = $pdf->importPage(1);
// use the imported page and place it on the first page. After this it will be added to every page.
$pdf->useTemplate($templatePage);
// set the template to be applied automatically.
$pdf->setTemplate($templatePage);
$pdf->SetFont('Arial');
$pdf->SetTextColor(0,0,0);
$pdf->SetLineWidth(.25);
$pdf->SetDrawColor(0,0,0);
$pdf->SetMargins(10,10);
$newpage = false;
$remove = Array("\r", '<b>', '</b>');
$clean = Array('<i>', '</i>');
/* ------------------------------------------
Start content.
------------------------------------------- */
$c = 0; //MODx Page counter, not PDF page!
$italic = false;
foreach ($pages as $page) {
//echo $page['longtitle'].' - '.$page['introtext'].'<br />';
$chapter = $page['longtitle'];
$title = $page['description'];
$content = str_replace($remove, '', $page['content']);
//Start at the top of a page after 10 chapters. Because I'm base-10 addicted.
if ($c > 9) {
$pdf->AddPage();
$c=0;
}
//Set the title.
$pdf->SetX(10);
$pdf->SetFont('Arial','',18);
$pdf->Cell(0,7,$chapter.' - '.$title,'B',1,'L');
//Add some space between the title and the content.
$pdf->Ln(3);
$content = split("\n", $content);
//Handle content per line/block.
foreach ($content as $par) {
$line = trim($par);
//Space between paragraphs (a little less than a whole line, looks nicer).
if (empty($line) ) {
$pdf->Ln(3);
} else {
if (strpos($line, '<i>') > -1) $italic = true;
//Switch between italic and normal. Only usable for whole paragraphs/lines for now.
if ($italic) {
$pdf->SetFont('Arial','i',11);
} else {
$pdf->SetFont('Arial','',11);
}
if (strpos($line, '</i>')) $italic = false;
$line = str_replace($clean, '', $line);
$pdf->MultiCell(0,4.5,$line,0,1,'L');
}
}
$pdf->Ln(10);
$italic = false;
$c++;
}
$pdf->Output($filename, 'd');
} else {
//Output error message because of missing parent ID
echo 'Parent ID missing!';
}
?>