399 lines
13 KiB
PHP
399 lines
13 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* Zend Framework
|
||
|
*
|
||
|
* LICENSE
|
||
|
*
|
||
|
* This source file is subject to the new BSD license that is bundled
|
||
|
* with this package in the file LICENSE.txt.
|
||
|
* It is also available through the world-wide-web at this URL:
|
||
|
* http://framework.zend.com/license/new-bsd
|
||
|
* If you did not receive a copy of the license and are unable to
|
||
|
* obtain it through the world-wide-web, please send an email
|
||
|
* to license@zend.com so we can send you a copy immediately.
|
||
|
*
|
||
|
* @category Zend
|
||
|
* @package Zend_Pdf
|
||
|
* @subpackage Actions
|
||
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||
|
* @version $Id: Action.php 17182 2009-07-27 13:54:11Z alexander $
|
||
|
*/
|
||
|
|
||
|
/** Zend_Pdf_ElementFactory */
|
||
|
require_once 'Zend/Pdf/ElementFactory.php';
|
||
|
|
||
|
/** Zend_Pdf_Target */
|
||
|
require_once 'Zend/Pdf/Target.php';
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Abstract PDF action representation class
|
||
|
*
|
||
|
* @package Zend_Pdf
|
||
|
* @subpackage Actions
|
||
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||
|
*/
|
||
|
abstract class Zend_Pdf_Action extends Zend_Pdf_Target implements RecursiveIterator, Countable
|
||
|
{
|
||
|
/**
|
||
|
* Action dictionary
|
||
|
*
|
||
|
* @var Zend_Pdf_Element_Dictionary|Zend_Pdf_Element_Object|Zend_Pdf_Element_Reference
|
||
|
*/
|
||
|
protected $_actionDictionary;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* An original list of chained actions
|
||
|
*
|
||
|
* @var array Array of Zend_Pdf_Action objects
|
||
|
*/
|
||
|
protected $_originalNextList;
|
||
|
|
||
|
/**
|
||
|
* A list of next actions in actions tree (used for actions chaining)
|
||
|
*
|
||
|
* @var array Array of Zend_Pdf_Action objects
|
||
|
*/
|
||
|
public $next = array();
|
||
|
|
||
|
/**
|
||
|
* Object constructor
|
||
|
*
|
||
|
* @param Zend_Pdf_Element_Dictionary $dictionary
|
||
|
* @param SplObjectStorage $processedActions list of already processed action dictionaries, used to avoid cyclic references
|
||
|
* @throws Zend_Pdf_Exception
|
||
|
*/
|
||
|
public function __construct(Zend_Pdf_Element $dictionary, SplObjectStorage $processedActions)
|
||
|
{
|
||
|
if ($dictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
|
||
|
require_once 'Zend/Pdf/Exception.php';
|
||
|
throw new Zend_Pdf_Exception('$dictionary mast be a direct or an indirect dictionary object.');
|
||
|
}
|
||
|
|
||
|
$this->_actionDictionary = $dictionary;
|
||
|
|
||
|
if ($dictionary->Next !== null) {
|
||
|
if ($dictionary->Next instanceof Zend_Pdf_Element_Dictionary) {
|
||
|
// Check if dictionary object is not already processed
|
||
|
if (!$processedActions->contains($dictionary->Next)) {
|
||
|
$processedActions->attach($dictionary->Next);
|
||
|
$this->next[] = Zend_Pdf_Action::load($dictionary->Next, $processedActions);
|
||
|
}
|
||
|
} else if ($dictionary->Next instanceof Zend_Pdf_Element_Array) {
|
||
|
foreach ($dictionary->Next->items as $chainedActionDictionary) {
|
||
|
// Check if dictionary object is not already processed
|
||
|
if (!$processedActions->contains($chainedActionDictionary)) {
|
||
|
$processedActions->attach($chainedActionDictionary);
|
||
|
$this->next[] = Zend_Pdf_Action::load($chainedActionDictionary, $processedActions);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
require_once 'Zend/Pdf/Exception.php';
|
||
|
throw new Zend_Pdf_Exception('PDF Action dictionary Next entry must be a dictionary or an array.');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$this->_originalNextList = $this->next;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Load PDF action object using specified dictionary
|
||
|
*
|
||
|
* @internal
|
||
|
* @param Zend_Pdf_Element $dictionary (It's actually Dictionary or Dictionary Object or Reference to a Dictionary Object)
|
||
|
* @param SplObjectStorage $processedActions list of already processed action dictionaries, used to avoid cyclic references
|
||
|
* @return Zend_Pdf_Action
|
||
|
* @throws Zend_Pdf_Exception
|
||
|
*/
|
||
|
public static function load(Zend_Pdf_Element $dictionary, SplObjectStorage $processedActions = null)
|
||
|
{
|
||
|
if ($processedActions === null) {
|
||
|
$processedActions = new SplObjectStorage();
|
||
|
}
|
||
|
|
||
|
if ($dictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
|
||
|
require_once 'Zend/Pdf/Exception.php';
|
||
|
throw new Zend_Pdf_Exception('$dictionary mast be a direct or an indirect dictionary object.');
|
||
|
}
|
||
|
if (isset($dictionary->Type) && $dictionary->Type->value != 'Action') {
|
||
|
require_once 'Zend/Pdf/Exception.php';
|
||
|
throw new Zend_Pdf_Exception('Action dictionary Type entry must be set to \'Action\'.');
|
||
|
}
|
||
|
|
||
|
if ($dictionary->S === null) {
|
||
|
require_once 'Zend/Pdf/Exception.php';
|
||
|
throw new Zend_Pdf_Exception('Action dictionary must contain S entry');
|
||
|
}
|
||
|
|
||
|
switch ($dictionary->S->value) {
|
||
|
case 'GoTo':
|
||
|
require_once 'Zend/Pdf/Action/GoTo.php';
|
||
|
return new Zend_Pdf_Action_GoTo($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'GoToR':
|
||
|
require_once 'Zend/Pdf/Action/GoToR.php';
|
||
|
return new Zend_Pdf_Action_GoToR($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'GoToE':
|
||
|
require_once 'Zend/Pdf/Action/GoToE.php';
|
||
|
return new Zend_Pdf_Action_GoToE($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'Launch':
|
||
|
require_once 'Zend/Pdf/Action/Launch.php';
|
||
|
return new Zend_Pdf_Action_Launch($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'Thread':
|
||
|
require_once 'Zend/Pdf/Action/Thread.php';
|
||
|
return new Zend_Pdf_Action_Thread($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'URI':
|
||
|
require_once 'Zend/Pdf/Action/URI.php';
|
||
|
return new Zend_Pdf_Action_URI($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'Sound':
|
||
|
require_once 'Zend/Pdf/Action/Sound.php';
|
||
|
return new Zend_Pdf_Action_Sound($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'Movie':
|
||
|
require_once 'Zend/Pdf/Action/Movie.php';
|
||
|
return new Zend_Pdf_Action_Movie($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'Hide':
|
||
|
require_once 'Zend/Pdf/Action/Hide.php';
|
||
|
return new Zend_Pdf_Action_Hide($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'Named':
|
||
|
require_once 'Zend/Pdf/Action/Named.php';
|
||
|
return new Zend_Pdf_Action_Named($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'SubmitForm':
|
||
|
require_once 'Zend/Pdf/Action/SubmitForm.php';
|
||
|
return new Zend_Pdf_Action_SubmitForm($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'ResetForm':
|
||
|
require_once 'Zend/Pdf/Action/ResetForm.php';
|
||
|
return new Zend_Pdf_Action_ResetForm($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'ImportData':
|
||
|
require_once 'Zend/Pdf/Action/ImportData.php';
|
||
|
return new Zend_Pdf_Action_ImportData($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'JavaScript':
|
||
|
require_once 'Zend/Pdf/Action/JavaScript.php';
|
||
|
return new Zend_Pdf_Action_JavaScript($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'SetOCGState':
|
||
|
require_once 'Zend/Pdf/Action/SetOCGState.php';
|
||
|
return new Zend_Pdf_Action_SetOCGState($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'Rendition':
|
||
|
require_once 'Zend/Pdf/Action/Rendition.php';
|
||
|
return new Zend_Pdf_Action_Rendition($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'Trans':
|
||
|
require_once 'Zend/Pdf/Action/Trans.php';
|
||
|
return new Zend_Pdf_Action_Trans($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
case 'GoTo3DView':
|
||
|
require_once 'Zend/Pdf/Action/GoTo3DView.php';
|
||
|
return new Zend_Pdf_Action_GoTo3DView($dictionary, $processedActions);
|
||
|
brake;
|
||
|
|
||
|
default:
|
||
|
require_once 'Zend/Pdf/Action/Unknown.php';
|
||
|
return new Zend_Pdf_Action_Unknown($dictionary, $processedActions);
|
||
|
brake;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get resource
|
||
|
*
|
||
|
* @internal
|
||
|
* @return Zend_Pdf_Element
|
||
|
*/
|
||
|
public function getResource()
|
||
|
{
|
||
|
return $this->_actionDictionary;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Dump Action and its child actions into PDF structures
|
||
|
*
|
||
|
* Returns dictionary indirect object or reference
|
||
|
*
|
||
|
* @internal
|
||
|
* @param Zend_Pdf_ElementFactory $factory Object factory for newly created indirect objects
|
||
|
* @param SplObjectStorage $processedActions list of already processed actions (used to prevent infinity loop caused by cyclic references)
|
||
|
* @return Zend_Pdf_Element_Object|Zend_Pdf_Element_Reference Dictionary indirect object
|
||
|
*/
|
||
|
public function dumpAction(Zend_Pdf_ElementFactory_Interface $factory, SplObjectStorage $processedActions = null)
|
||
|
{
|
||
|
if ($processedActions === null) {
|
||
|
$processedActions = new SplObjectStorage();
|
||
|
}
|
||
|
if ($processedActions->contains($this)) {
|
||
|
require_once 'Zend/Pdf/Exception.php';
|
||
|
throw new Zend_Pdf_Exception('Action chain cyclyc reference is detected.');
|
||
|
}
|
||
|
$processedActions->attach($this);
|
||
|
|
||
|
$childListUpdated = false;
|
||
|
if (count($this->_originalNextList) != count($this->next)) {
|
||
|
// If original and current children arrays have different size then children list was updated
|
||
|
$childListUpdated = true;
|
||
|
} else if ( !(array_keys($this->_originalNextList) === array_keys($this->next)) ) {
|
||
|
// If original and current children arrays have different keys (with a glance to an order) then children list was updated
|
||
|
$childListUpdated = true;
|
||
|
} else {
|
||
|
foreach ($this->next as $key => $childAction) {
|
||
|
if ($this->_originalNextList[$key] !== $childAction) {
|
||
|
$childListUpdated = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($childListUpdated) {
|
||
|
$this->_actionDictionary->touch();
|
||
|
switch (count($this->next)) {
|
||
|
case 0:
|
||
|
$this->_actionDictionary->Next = null;
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
$child = reset($this->next);
|
||
|
$this->_actionDictionary->Next = $child->dumpAction($factory, $processedActions);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
$pdfChildArray = new Zend_Pdf_Element_Array();
|
||
|
foreach ($this->next as $child) {
|
||
|
|
||
|
$pdfChildArray->items[] = $child->dumpAction($factory, $processedActions);
|
||
|
}
|
||
|
$this->_actionDictionary->Next = $pdfChildArray;
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
foreach ($this->next as $child) {
|
||
|
$child->dumpAction($factory, $processedActions);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($this->_actionDictionary instanceof Zend_Pdf_Element_Dictionary) {
|
||
|
// It's a newly created action. Register it within object factory and return indirect object
|
||
|
return $factory->newObject($this->_actionDictionary);
|
||
|
} else {
|
||
|
// It's a loaded object
|
||
|
return $this->_actionDictionary;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// RecursiveIterator interface methods
|
||
|
//////////////
|
||
|
|
||
|
/**
|
||
|
* Returns current child action.
|
||
|
*
|
||
|
* @return Zend_Pdf_Action
|
||
|
*/
|
||
|
public function current()
|
||
|
{
|
||
|
return current($this->next);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns current iterator key
|
||
|
*
|
||
|
* @return integer
|
||
|
*/
|
||
|
public function key()
|
||
|
{
|
||
|
return key($this->next);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Go to next child
|
||
|
*/
|
||
|
public function next()
|
||
|
{
|
||
|
return next($this->next);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Rewind children
|
||
|
*/
|
||
|
public function rewind()
|
||
|
{
|
||
|
return reset($this->next);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if current position is valid
|
||
|
*
|
||
|
* @return boolean
|
||
|
*/
|
||
|
public function valid()
|
||
|
{
|
||
|
return current($this->next) !== false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the child action.
|
||
|
*
|
||
|
* @return Zend_Pdf_Outline|null
|
||
|
*/
|
||
|
public function getChildren()
|
||
|
{
|
||
|
return current($this->next);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implements RecursiveIterator interface.
|
||
|
*
|
||
|
* @return bool whether container has any pages
|
||
|
*/
|
||
|
public function hasChildren()
|
||
|
{
|
||
|
return count($this->next) > 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// Countable interface methods
|
||
|
//////////////
|
||
|
|
||
|
/**
|
||
|
* count()
|
||
|
*
|
||
|
* @return int
|
||
|
*/
|
||
|
public function count()
|
||
|
{
|
||
|
return count($this->childOutlines);
|
||
|
}
|
||
|
}
|