Skip to content

Commit

Permalink
[#52] fix applying document-template and other preFormat elements whe…
Browse files Browse the repository at this point in the history
…n placeholders tag is missing
  • Loading branch information
psliwa committed Jun 1, 2014
1 parent 7dfba6b commit ccd7157
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 25 deletions.
1 change: 1 addition & 0 deletions .gitattributes
@@ -0,0 +1 @@
*.pdf binary
2 changes: 1 addition & 1 deletion CHANGELOG.markdown
Expand Up @@ -3,7 +3,7 @@ CHANGELOG

* 1.2.4-DEV (???)

* (nothing)
* [#52] fix document-template support

* 1.2.3 (2014-03-15)

Expand Down
2 changes: 1 addition & 1 deletion README-PL.markdown
Expand Up @@ -407,7 +407,7 @@ Istnieją tagi, które służą jedynie do określania wartości atrybutów, zbi
* stylesheet - style dla elementu nadrzędnego
* attribute - atrybut, bezpośredni element podrzędny dla "stylesheet". Wymagane atrybute tego elementu: name - nazwa atrybutu, value - wartość atrybutu
* complex-attribute - atrybut złożony, bezpośredni element podrzędny dla "stylesheet". Wymagany atrybut tego elementu: name - nazwa.
* placeholders - definiuje wartości "slotów" dla elementu podrzędnego. Elementy podrzędne "placeholders" są specyficzne dla tagu nadrzędnego.
* placeholders - definiuje wartości "slotów" dla elementu podrzędnego. Elementy podrzędne "placeholders" są specyficzne dla tagu nadrzędnego. Ten tag powinien być pierwszym tagiem w rodzicu.
* metadata - definiuje dane meta dla dokumentu pdf, bezpośredni element podrzędny korzenia dokumentu
* behaviours - definiuje zachowania dla elementu nadrzędnego. Obsługiwane zachowania: ref, href, bookmark, note (działanie takie samo jak dla atrybutów o tych samych nazwach)

Expand Down
2 changes: 1 addition & 1 deletion README.markdown
Expand Up @@ -469,7 +469,7 @@ There are tags that are only bags for attributes, a set of tags etc:
* stylesheet - stylesheet for parent
* attribute - simple attribute declaration, direct child of "stylesheet" tag. Required attributes of this element: name - attribute name, value - attribute value
* complex-attribute - complex attribute declaration, direct child of "stylesheet" tag. Required attributes of this element: name - complex attribute name
* placeholders - defines placeholders for parent tag. Children tags of placeholder are specyfic for every parent tag.
* placeholders - defines placeholders for parent tag. Children tags of placeholder are specyfic for every parent tag. **It should be first tag in parent**
* metadata - defines metadata of pdf document, direct child of document root
* behaviours - defines behaviours for a parent tag. Supported behaviours: href, ref, bookmark, note (action as same as for attributes with as same as name)

Expand Down
29 changes: 25 additions & 4 deletions lib/PHPPdf/Core/Node/Manager.php
Expand Up @@ -12,6 +12,7 @@

use PHPPdf\Core\Document;
use PHPPdf\Core\Parser\DocumentParserListener;
use PHPPdf\Core\Parser\DocumentParsingContext;
use PHPPdf\Core\Parser\Exception\DuplicatedIdException;

/**
Expand All @@ -26,6 +27,8 @@ class Manager implements DocumentParserListener

private $managedNodes = array();
private $behavioursTasks;

private $preFormatInvoked = array();

public function __construct()
{
Expand Down Expand Up @@ -76,24 +79,28 @@ public function clear()
$this->nodes = array();
}

public function onEndParsePlaceholders(Document $document, PageCollection $root, Node $node)
public function onEndParsePlaceholders(Document $document, PageCollection $root, Node $node, DocumentParsingContext $context)
{
if($this->isPage($node))
{
$node->preFormat($document);
$this->invokePreFormatIfItHasntInvokedYet($document, $node);
}
}

public function onStartParseNode(Document $document, PageCollection $root, Node $node)
public function onStartParseNode(Document $document, PageCollection $root, Node $node, DocumentParsingContext $context)
{
if(!$this->isPage($node) && $this->isPage($node->getParent()))
{
$this->invokePreFormatIfItHasntInvokedYet($document, $node->getParent());
}
}

private function isPage($node)
{
return $node instanceof \PHPPdf\Core\Node\Page;
}

public function onEndParseNode(Document $document, PageCollection $root, Node $node)
public function onEndParseNode(Document $document, PageCollection $root, Node $node, DocumentParsingContext $context)
{
if(!$this->isPage($node) && $this->isPage($node->getParent()))
{
Expand Down Expand Up @@ -175,4 +182,18 @@ public function onEndParsing(Document $document, PageCollection $root)
$document->invokeTasks($this->behavioursTasks);
$this->behavioursTasks = new DrawingTaskHeap();
}

private function invokePreFormatIfItHasntInvokedYet(Document $document, Node $node)
{
if(!$this->preFormatHasBeenInvoked($node))
{
$this->preFormatInvoked[spl_object_hash($node)] = true;
$node->preFormat($document);
}
}

private function preFormatHasBeenInvoked(Node $node)
{
return isset($this->preFormatInvoked[spl_object_hash($node)]);
}
}
6 changes: 3 additions & 3 deletions lib/PHPPdf/Core/Parser/DocumentParserListener.php
Expand Up @@ -17,8 +17,8 @@
*/
interface DocumentParserListener
{
public function onStartParseNode(Document $document, PageCollection $root, Node $node);
public function onEndParseNode(Document $document, PageCollection $root, Node $node);
public function onEndParsePlaceholders(Document $document, PageCollection $root, Node $node);
public function onStartParseNode(Document $document, PageCollection $root, Node $node, DocumentParsingContext $context);
public function onEndParseNode(Document $document, PageCollection $root, Node $node, DocumentParsingContext $context);
public function onEndParsePlaceholders(Document $document, PageCollection $root, Node $node, DocumentParsingContext $context);
public function onEndParsing(Document $document, PageCollection $root);
}
41 changes: 41 additions & 0 deletions lib/PHPPdf/Core/Parser/DocumentParsingContext.php
@@ -0,0 +1,41 @@
<?php


namespace PHPPdf\Core\Parser;


class DocumentParsingContext
{
private $inPlaceholder = false;
private $inBehaviour = false;

public function isInPlaceholder()
{
return $this->inPlaceholder;
}

public function isInBehaviour()
{
return $this->inBehaviour;
}

public function enterPlaceholder()
{
$this->inPlaceholder = true;
}

public function exitPlaceholder()
{
$this->inPlaceholder = false;
}

public function enterBehaviour()
{
$this->inBehaviour = true;
}

public function exitBehaviour()
{
$this->inBehaviour = false;
}
}
30 changes: 16 additions & 14 deletions lib/PHPPdf/Core/Parser/XmlDocumentParser.php
Expand Up @@ -46,8 +46,10 @@ class XmlDocumentParser extends XmlParser implements DocumentParser
private $ignoredTags = array('attribute', 'enhancement', 'complex-attribute');
private $tagStack = array();
private $innerParser = null;
private $inPlaceholder = false;
private $inBehaviour = false;
/**
* @var DocumentParsingContext
*/
private $context;
private $endTag = self::ROOT_TAG;
private $behaviourFactory = null;
private $nodeManager = null;
Expand Down Expand Up @@ -92,7 +94,7 @@ private function initialize()
$this->setStylesheetConstraint($stylesheetConstraint);
$this->isPreviousText = false;
$this->currentParagraph = null;
$this->inBehaviour = $this->inPlaceholder = false;
$this->context = new DocumentParsingContext();
$this->tagStack = array();
$this->prototypes = array();
$this->clearStack();
Expand Down Expand Up @@ -240,21 +242,21 @@ protected function parseElement(\XMLReader $reader)
$tag = $reader->name;
$parentNode = $this->getLastElementFromStack();

if($this->inPlaceholder)
if($this->context->isInPlaceholder())
{
$this->parsePlaceholder($reader, $parentNode);
}
elseif($this->inBehaviour)
elseif($this->context->isInBehaviour())
{
$this->parseBehaviour($reader, $parentNode);
}
elseif($tag === self::PLACEHOLDERS_TAG)
{
$this->inPlaceholder = true;
$this->context->enterPlaceholder();
}
elseif($tag === self::BEHAVIOURS_TAG)
{
$this->inBehaviour = true;
$this->context->enterBehaviour();
}
elseif($tag === self::STYLESHEET_TAG)
{
Expand Down Expand Up @@ -399,7 +401,7 @@ private function fireOnStartParseNode(Node $node)
{
foreach($this->listeners as $listener)
{
$listener->onStartParseNode($this->document, $this->getFirstElementFromStack(), $node);
$listener->onStartParseNode($this->document, $this->getFirstElementFromStack(), $node, $this->context);
}
}

Expand Down Expand Up @@ -489,15 +491,15 @@ protected function parseEndElement(\XMLReader $reader)
{
if($reader->name === self::PLACEHOLDERS_TAG)
{
$this->inPlaceholder = false;
$this->context->exitPlaceholder();
$node = $this->getLastElementFromStack();
$this->fireOnEndParsePlaceholders($node);
}
elseif($this->inBehaviour && $reader->name === self::BEHAVIOURS_TAG)
elseif($this->context->isInBehaviour() && $reader->name === self::BEHAVIOURS_TAG)
{
$this->inBehaviour = false;
$this->context->exitBehaviour();
}
elseif(!$this->inBehaviour)
elseif(!$this->context->isInBehaviour())
{
$node = $this->getLastElementFromStack();

Expand Down Expand Up @@ -526,15 +528,15 @@ private function fireOnEndParsePlaceholders(Node $node)
{
foreach($this->listeners as $listener)
{
$listener->onEndParsePlaceholders($this->document, $this->getFirstElementFromStack(), $node);
$listener->onEndParsePlaceholders($this->document, $this->getFirstElementFromStack(), $node, $this->context);
}
}

private function fireOnEndParseNode(Node $node)
{
foreach($this->listeners as $listener)
{
$listener->onEndParseNode($this->document, $this->getFirstElementFromStack(), $node);
$listener->onEndParseNode($this->document, $this->getFirstElementFromStack(), $node, $this->context);
}
}

Expand Down
65 changes: 64 additions & 1 deletion tests/PHPPdf/Test/Issue/Issue52Test.php
Expand Up @@ -8,6 +8,7 @@
use PHPPdf\Core\Engine\ZF\Engine;
use PHPPdf\Core\Node\DynamicPage;
use PHPPdf\PHPUnit\Framework\TestCase;
use ZendPdf\PdfDocument;

class Issue52Test extends TestCase
{
Expand All @@ -19,7 +20,7 @@ public function dynamicPageAndDocumentTemplate_setPrototypeSizeFromDocumentTempl
//given

$page = new DynamicPage();
$page->setAttribute('document-template', __DIR__.'/../../Resources/200x200.pdf');
$page->setAttribute('document-template', $this->get200x200DocumentTemplate());

//when

Expand All @@ -31,11 +32,73 @@ public function dynamicPageAndDocumentTemplate_setPrototypeSizeFromDocumentTempl
$this->assertEquals(200, $page->getPrototypePage()->getHeight());
}

/**
* @test
* @dataProvider booleanProvider
*/
public function dynamicPageAndDocumentTemplate_placeholdersMissing_useDocumentTemplateNonetheless($placeholdersExists)
{
//given

$placeholders = $placeholdersExists ? '<placeholders><header><div height="10">placeholders</div></header></placeholders>' : '';

$xml = <<<XML
<pdf>
<dynamic-page document-template="{$this->get200x200DocumentTemplate()}">
{$placeholders}
some text
</dynamic-page>
</pdf>
XML;

//when

$pdfContent = $this->createFacade()->render($xml);

//then

$document = new PdfDocument($pdfContent, null, false);

$this->assertEquals(200, $document->pages[0]->getWidth());
$this->assertEquals(200, $document->pages[0]->getHeight());

if($placeholders)
{
$this->assertContains('placeholders', $pdfContent);
}
}

public function booleanProvider()
{
return array(
array(true),
array(false),
);
}

/**
* @return Document
*/
private function createDocument()
{
return new Document(new Engine());
}

/**
* @return string
*/
private function get200x200DocumentTemplate()
{
return __DIR__ . '/../../Resources/200x200.pdf';
}

/**
* @return \PHPPdf\Core\Facade
*/
private function createFacade()
{
$facade = \PHPPdf\Core\FacadeBuilder::create()
->build();
return $facade;
}
}

0 comments on commit ccd7157

Please sign in to comment.