File indexing completed on 2024-12-22 05:36:56

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Pdf
0017  * @subpackage Actions
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 
0024 /** Internally used classes */
0025 // require_once 'Zend/Pdf/Element.php';
0026 // require_once 'Zend/Pdf/Element/Array.php';
0027 
0028 
0029 /** Zend_Pdf_Target */
0030 // require_once 'Zend/Pdf/Target.php';
0031 
0032 
0033 /**
0034  * Abstract PDF action representation class
0035  *
0036  * @package    Zend_Pdf
0037  * @subpackage Actions
0038  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0039  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0040  */
0041 abstract class Zend_Pdf_Action extends Zend_Pdf_Target implements RecursiveIterator, Countable
0042 {
0043     /**
0044      * Action dictionary
0045      *
0046      * @var Zend_Pdf_Element_Dictionary|Zend_Pdf_Element_Object|Zend_Pdf_Element_Reference
0047      */
0048     protected $_actionDictionary;
0049 
0050 
0051     /**
0052      * An original list of chained actions
0053      *
0054      * @var array  Array of Zend_Pdf_Action objects
0055      */
0056     protected $_originalNextList;
0057 
0058     /**
0059      * A list of next actions in actions tree (used for actions chaining)
0060      *
0061      * @var array  Array of Zend_Pdf_Action objects
0062      */
0063     public $next = array();
0064 
0065     /**
0066      * Object constructor
0067      *
0068      * @param Zend_Pdf_Element_Dictionary $dictionary
0069      * @param SplObjectStorage            $processedActions  list of already processed action dictionaries, used to avoid cyclic references
0070      * @throws Zend_Pdf_Exception
0071      */
0072     public function __construct(Zend_Pdf_Element $dictionary, SplObjectStorage $processedActions)
0073     {
0074         // require_once 'Zend/Pdf/Element.php';
0075         if ($dictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
0076             // require_once 'Zend/Pdf/Exception.php';
0077             throw new Zend_Pdf_Exception('$dictionary mast be a direct or an indirect dictionary object.');
0078         }
0079 
0080         $this->_actionDictionary = $dictionary;
0081 
0082         if ($dictionary->Next !== null) {
0083             if ($dictionary->Next instanceof Zend_Pdf_Element_Dictionary) {
0084                 // Check if dictionary object is not already processed
0085                 if (!$processedActions->contains($dictionary->Next)) {
0086                     $processedActions->attach($dictionary->Next);
0087                     $this->next[] = Zend_Pdf_Action::load($dictionary->Next, $processedActions);
0088                 }
0089             } else if ($dictionary->Next instanceof Zend_Pdf_Element_Array) {
0090                 foreach ($dictionary->Next->items as $chainedActionDictionary) {
0091                     // Check if dictionary object is not already processed
0092                     if (!$processedActions->contains($chainedActionDictionary)) {
0093                         $processedActions->attach($chainedActionDictionary);
0094                         $this->next[] = Zend_Pdf_Action::load($chainedActionDictionary, $processedActions);
0095                     }
0096                 }
0097             } else {
0098                 // require_once 'Zend/Pdf/Exception.php';
0099                 throw new Zend_Pdf_Exception('PDF Action dictionary Next entry must be a dictionary or an array.');
0100             }
0101         }
0102 
0103         $this->_originalNextList = $this->next;
0104     }
0105 
0106     /**
0107      * Load PDF action object using specified dictionary
0108      *
0109      * @internal
0110      * @param Zend_Pdf_Element $dictionary (It's actually Dictionary or Dictionary Object or Reference to a Dictionary Object)
0111      * @param SplObjectStorage $processedActions  list of already processed action dictionaries, used to avoid cyclic references
0112      * @return Zend_Pdf_Action
0113      * @throws Zend_Pdf_Exception
0114      */
0115     public static function load(Zend_Pdf_Element $dictionary, SplObjectStorage $processedActions = null)
0116     {
0117         if ($processedActions === null) {
0118             $processedActions = new SplObjectStorage();
0119         }
0120 
0121         // require_once 'Zend/Pdf/Element.php';
0122         if ($dictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
0123             // require_once 'Zend/Pdf/Exception.php';
0124             throw new Zend_Pdf_Exception('$dictionary mast be a direct or an indirect dictionary object.');
0125         }
0126         if (isset($dictionary->Type)  &&  $dictionary->Type->value != 'Action') {
0127             // require_once 'Zend/Pdf/Exception.php';
0128             throw new Zend_Pdf_Exception('Action dictionary Type entry must be set to \'Action\'.');
0129         }
0130 
0131         if ($dictionary->S === null) {
0132             // require_once 'Zend/Pdf/Exception.php';
0133             throw new Zend_Pdf_Exception('Action dictionary must contain S entry');
0134         }
0135 
0136         switch ($dictionary->S->value) {
0137             case 'GoTo':
0138                 // require_once 'Zend/Pdf/Action/GoTo.php';
0139                 return new Zend_Pdf_Action_GoTo($dictionary, $processedActions);
0140                 break;
0141 
0142             case 'GoToR':
0143                 // require_once 'Zend/Pdf/Action/GoToR.php';
0144                 return new Zend_Pdf_Action_GoToR($dictionary, $processedActions);
0145                 break;
0146 
0147             case 'GoToE':
0148                 // require_once 'Zend/Pdf/Action/GoToE.php';
0149                 return new Zend_Pdf_Action_GoToE($dictionary, $processedActions);
0150                 break;
0151 
0152             case 'Launch':
0153                 // require_once 'Zend/Pdf/Action/Launch.php';
0154                 return new Zend_Pdf_Action_Launch($dictionary, $processedActions);
0155                 break;
0156 
0157             case 'Thread':
0158                 // require_once 'Zend/Pdf/Action/Thread.php';
0159                 return new Zend_Pdf_Action_Thread($dictionary, $processedActions);
0160                 break;
0161 
0162             case 'URI':
0163                 // require_once 'Zend/Pdf/Action/URI.php';
0164                 return new Zend_Pdf_Action_URI($dictionary, $processedActions);
0165                 break;
0166 
0167             case 'Sound':
0168                 // require_once 'Zend/Pdf/Action/Sound.php';
0169                 return new Zend_Pdf_Action_Sound($dictionary, $processedActions);
0170                 break;
0171 
0172             case 'Movie':
0173                 // require_once 'Zend/Pdf/Action/Movie.php';
0174                 return new Zend_Pdf_Action_Movie($dictionary, $processedActions);
0175                 break;
0176 
0177             case 'Hide':
0178                 // require_once 'Zend/Pdf/Action/Hide.php';
0179                 return new Zend_Pdf_Action_Hide($dictionary, $processedActions);
0180                 break;
0181 
0182             case 'Named':
0183                 // require_once 'Zend/Pdf/Action/Named.php';
0184                 return new Zend_Pdf_Action_Named($dictionary, $processedActions);
0185                 break;
0186 
0187             case 'SubmitForm':
0188                 // require_once 'Zend/Pdf/Action/SubmitForm.php';
0189                 return new Zend_Pdf_Action_SubmitForm($dictionary, $processedActions);
0190                 break;
0191 
0192             case 'ResetForm':
0193                 // require_once 'Zend/Pdf/Action/ResetForm.php';
0194                 return new Zend_Pdf_Action_ResetForm($dictionary, $processedActions);
0195                 break;
0196 
0197             case 'ImportData':
0198                 // require_once 'Zend/Pdf/Action/ImportData.php';
0199                 return new Zend_Pdf_Action_ImportData($dictionary, $processedActions);
0200                 break;
0201 
0202             case 'JavaScript':
0203                 // require_once 'Zend/Pdf/Action/JavaScript.php';
0204                 return new Zend_Pdf_Action_JavaScript($dictionary, $processedActions);
0205                 break;
0206 
0207             case 'SetOCGState':
0208                 // require_once 'Zend/Pdf/Action/SetOCGState.php';
0209                 return new Zend_Pdf_Action_SetOCGState($dictionary, $processedActions);
0210                 break;
0211 
0212             case 'Rendition':
0213                 // require_once 'Zend/Pdf/Action/Rendition.php';
0214                 return new Zend_Pdf_Action_Rendition($dictionary, $processedActions);
0215                 break;
0216 
0217             case 'Trans':
0218                 // require_once 'Zend/Pdf/Action/Trans.php';
0219                 return new Zend_Pdf_Action_Trans($dictionary, $processedActions);
0220                 break;
0221 
0222             case 'GoTo3DView':
0223                 // require_once 'Zend/Pdf/Action/GoTo3DView.php';
0224                 return new Zend_Pdf_Action_GoTo3DView($dictionary, $processedActions);
0225                 break;
0226 
0227             default:
0228                 // require_once 'Zend/Pdf/Action/Unknown.php';
0229                 return new Zend_Pdf_Action_Unknown($dictionary, $processedActions);
0230                 break;
0231         }
0232     }
0233 
0234     /**
0235      * Get resource
0236      *
0237      * @internal
0238      * @return Zend_Pdf_Element
0239      */
0240     public function getResource()
0241     {
0242         return $this->_actionDictionary;
0243     }
0244 
0245     /**
0246      * Dump Action and its child actions into PDF structures
0247      *
0248      * Returns dictionary indirect object or reference
0249      *
0250      * @internal
0251      * @param Zend_Pdf_ElementFactory $factory   Object factory for newly created indirect objects
0252      * @param SplObjectStorage $processedActions  list of already processed actions (used to prevent infinity loop caused by cyclic references)
0253      * @return Zend_Pdf_Element_Object|Zend_Pdf_Element_Reference   Dictionary indirect object
0254      */
0255     public function dumpAction(Zend_Pdf_ElementFactory_Interface $factory, SplObjectStorage $processedActions = null)
0256     {
0257         if ($processedActions === null) {
0258             $processedActions = new SplObjectStorage();
0259         }
0260         if ($processedActions->contains($this)) {
0261             // require_once 'Zend/Pdf/Exception.php';
0262             throw new Zend_Pdf_Exception('Action chain cyclyc reference is detected.');
0263         }
0264         $processedActions->attach($this);
0265 
0266         $childListUpdated = false;
0267         if (count($this->_originalNextList) != count($this->next)) {
0268             // If original and current children arrays have different size then children list was updated
0269             $childListUpdated = true;
0270         } else if ( !(array_keys($this->_originalNextList) === array_keys($this->next)) ) {
0271             // If original and current children arrays have different keys (with a glance to an order) then children list was updated
0272             $childListUpdated = true;
0273         } else {
0274             foreach ($this->next as $key => $childAction) {
0275                 if ($this->_originalNextList[$key] !== $childAction) {
0276                     $childListUpdated = true;
0277                     break;
0278                 }
0279             }
0280         }
0281 
0282         if ($childListUpdated) {
0283             $this->_actionDictionary->touch();
0284             switch (count($this->next)) {
0285                 case 0:
0286                     $this->_actionDictionary->Next = null;
0287                     break;
0288 
0289                 case 1:
0290                     $child = reset($this->next);
0291                     $this->_actionDictionary->Next = $child->dumpAction($factory, $processedActions);
0292                     break;
0293 
0294                 default:
0295                     // require_once 'Zend/Pdf/Element/Array.php';
0296                     $pdfChildArray = new Zend_Pdf_Element_Array();
0297                     foreach ($this->next as $child) {
0298 
0299                         $pdfChildArray->items[] = $child->dumpAction($factory, $processedActions);
0300                     }
0301                     $this->_actionDictionary->Next = $pdfChildArray;
0302                     break;
0303             }
0304         } else {
0305             foreach ($this->next as $child) {
0306                 $child->dumpAction($factory, $processedActions);
0307             }
0308         }
0309 
0310         if ($this->_actionDictionary instanceof Zend_Pdf_Element_Dictionary) {
0311             // It's a newly created action. Register it within object factory and return indirect object
0312             return $factory->newObject($this->_actionDictionary);
0313         } else {
0314             // It's a loaded object
0315             return $this->_actionDictionary;
0316         }
0317     }
0318 
0319 
0320     ////////////////////////////////////////////////////////////////////////
0321     //  RecursiveIterator interface methods
0322     //////////////
0323 
0324     /**
0325      * Returns current child action.
0326      *
0327      * @return Zend_Pdf_Action
0328      */
0329     public function current()
0330     {
0331         return current($this->next);
0332     }
0333 
0334     /**
0335      * Returns current iterator key
0336      *
0337      * @return integer
0338      */
0339     public function key()
0340     {
0341         return key($this->next);
0342     }
0343 
0344     /**
0345      * Go to next child
0346      */
0347     public function next()
0348     {
0349         return next($this->next);
0350     }
0351 
0352     /**
0353      * Rewind children
0354      */
0355     public function rewind()
0356     {
0357         return reset($this->next);
0358     }
0359 
0360     /**
0361      * Check if current position is valid
0362      *
0363      * @return boolean
0364      */
0365     public function valid()
0366     {
0367         return current($this->next) !== false;
0368     }
0369 
0370     /**
0371      * Returns the child action.
0372      *
0373      * @return Zend_Pdf_Action|null
0374      */
0375     public function getChildren()
0376     {
0377         return current($this->next);
0378     }
0379 
0380     /**
0381      * Implements RecursiveIterator interface.
0382      *
0383      * @return bool  whether container has any pages
0384      */
0385     public function hasChildren()
0386     {
0387         return count($this->next) > 0;
0388     }
0389 
0390 
0391     ////////////////////////////////////////////////////////////////////////
0392     //  Countable interface methods
0393     //////////////
0394 
0395     /**
0396      * count()
0397      *
0398      * @return int
0399      */
0400     public function count()
0401     {
0402         return count($this->childOutlines);
0403     }
0404 }