Action.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Pdf
  17. * @subpackage Actions
  18. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id$
  21. */
  22. /** Zend_Pdf_ElementFactory */
  23. require_once 'Zend/Pdf/ElementFactory.php';
  24. /**
  25. * Abstract PDF action representation class
  26. *
  27. * @package Zend_Pdf
  28. * @subpackage Actions
  29. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  30. * @license http://framework.zend.com/license/new-bsd New BSD License
  31. */
  32. abstract class Zend_Pdf_Action
  33. {
  34. /**
  35. * Action dictionary
  36. *
  37. * @var Zend_Pdf_Element_Dictionary|Zend_Pdf_Element_Object|Zend_Pdf_Element_Reference
  38. */
  39. protected $_actionDictionary;
  40. /**
  41. * A list of next actions in actions tree (used for actions chaining)
  42. *
  43. * @var SplObjectStorage Contains Zend_Pdf_Action objects
  44. */
  45. protected $_next;
  46. /**
  47. * Parent object in Actions tree (or null if it's a root object)
  48. *
  49. * @var Zend_Pdf_Action
  50. */
  51. protected $_parent;
  52. /**
  53. * Object constructor
  54. *
  55. * @param Zend_Pdf_Element_Dictionary $dictionary
  56. * @param Zend_Pdf_Action|null $parentAction
  57. * @param SplObjectStorage $processedActions list of already processed action dictionaries, used to avoid cyclic references
  58. * @throws Zend_Pdf_Exception
  59. */
  60. public function __construct(Zend_Pdf_Element $dictionary, $parentAction, SplObjectStorage $processedActions)
  61. {
  62. if ($dictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
  63. require_once 'Zend/Pdf/Exception.php';
  64. throw new Zend_Pdf_Exception('$dictionary mast be a direct or an indirect dictionary object.');
  65. }
  66. if ($parentAction !== null && !$parentAction instanceof Zend_Pdf_Action) {
  67. require_once 'Zend/Pdf/Exception.php';
  68. throw new Zend_Pdf_Exception('Zend_Pdf_Action constructor $parentAction parameter must be a Zend_Pdf_Action object.');
  69. }
  70. $this->_actionDictionary = $dictionary;
  71. $this->_parent = $parentAction;
  72. $this->_next = new SplObjectStorage();
  73. if ($dictionary->Next !== null) {
  74. if ($dictionary->Next instanceof Zend_Pdf_Element_Dictionary) {
  75. // Check if dictionary object is not already processed
  76. if (!$processedActions->contains($dictionary->Next)) {
  77. $processedActions->attach($dictionary->Next);
  78. $this->_next->attach(Zend_Pdf_Action::load($dictionary->Next, $this, $processedActions));
  79. }
  80. } else if ($dictionary->Next instanceof Zend_Pdf_Element_Array) {
  81. foreach ($dictionary->Next->items as $chainedActionDictionary) {
  82. // Check if dictionary object is not already processed
  83. if (!$processedActions->contains($chainedActionDictionary)) {
  84. $processedActions->attach($chainedActionDictionary);
  85. $this->_next->attach(Zend_Pdf_Action::load($chainedActionDictionary, $this, $processedActions));
  86. }
  87. }
  88. } else {
  89. require_once 'Zend/Pdf/Exception.php';
  90. throw new Zend_Pdf_Exception('PDF Action dictionary Next entry must be a dictionary or an array.');
  91. }
  92. }
  93. }
  94. /**
  95. * Load PDF action object using specified dictionary
  96. *
  97. * @param Zend_Pdf_Element $dictionary (It's actually Dictionary or Dictionary Object or Reference to a Dictionary Object)
  98. * @param Zend_Pdf_Action $parentAction
  99. * @param SplObjectStorage $processedActions list of already processed action dictionaries, used to avoid cyclic references
  100. * @return Zend_Pdf_Action
  101. * @throws Zend_Pdf_Exception
  102. */
  103. public static function load(Zend_Pdf_Element $dictionary, $parentAction = null, $processedActions = null)
  104. {
  105. if ($processedActions === null) {
  106. $processedActions = new SplObjectStorage();
  107. } else if (!$processedActions instanceof SplObjectStorage) {
  108. require_once 'Zend/Pdf/Exception.php';
  109. throw new Zend_Pdf_Exception('$processedActions parameter must be a SplObjectStorage object or null.');
  110. }
  111. if ($dictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
  112. require_once 'Zend/Pdf/Exception.php';
  113. throw new Zend_Pdf_Exception('$dictionary mast be a direct or an indirect dictionary object.');
  114. }
  115. if (isset($dictionary->Type) && $dictionary->Type->value != 'Action') {
  116. require_once 'Zend/Pdf/Exception.php';
  117. throw new Zend_Pdf_Exception('Action dictionary Type entry must be set to \'Action\'.');
  118. }
  119. if ($dictionary->S === null) {
  120. require_once 'Zend/Pdf/Exception.php';
  121. throw new Zend_Pdf_Exception('Action dictionary must have S entry');
  122. }
  123. switch ($dictionary->S->value) {
  124. case 'GoTo':
  125. require_once 'Zend/Pdf/Action/GoTo.php';
  126. return new Zend_Pdf_Action_GoTo($dictionary, $parentAction, $processedActions);
  127. brake;
  128. case 'GoToR':
  129. require_once 'Zend/Pdf/Action/GoToR.php';
  130. return new Zend_Pdf_Action_GoToR($dictionary, $parentAction, $processedActions);
  131. brake;
  132. case 'GoToE':
  133. require_once 'Zend/Pdf/Action/GoToE.php';
  134. return new Zend_Pdf_Action_GoToE($dictionary, $parentAction, $processedActions);
  135. brake;
  136. case 'Launch':
  137. require_once 'Zend/Pdf/Action/Launch.php';
  138. return new Zend_Pdf_Action_Launch($dictionary, $parentAction, $processedActions);
  139. brake;
  140. case 'Thread':
  141. require_once 'Zend/Pdf/Action/Thread.php';
  142. return new Zend_Pdf_Action_Thread($dictionary, $parentAction, $processedActions);
  143. brake;
  144. case 'URI':
  145. require_once 'Zend/Pdf/Action/URI.php';
  146. return new Zend_Pdf_Action_URI($dictionary, $parentAction, $processedActions);
  147. brake;
  148. case 'Sound':
  149. require_once 'Zend/Pdf/Action/Sound.php';
  150. return new Zend_Pdf_Action_Sound($dictionary, $parentAction, $processedActions);
  151. brake;
  152. case 'Movie':
  153. require_once 'Zend/Pdf/Action/Movie.php';
  154. return new Zend_Pdf_Action_Movie($dictionary, $parentAction, $processedActions);
  155. brake;
  156. case 'Hide':
  157. require_once 'Zend/Pdf/Action/Hide.php';
  158. return new Zend_Pdf_Action_Hide($dictionary, $parentAction, $processedActions);
  159. brake;
  160. case 'Named':
  161. require_once 'Zend/Pdf/Action/Named.php';
  162. return new Zend_Pdf_Action_Named($dictionary, $parentAction, $processedActions);
  163. brake;
  164. case 'SubmitForm':
  165. require_once 'Zend/Pdf/Action/SubmitForm.php';
  166. return new Zend_Pdf_Action_SubmitForm($dictionary, $parentAction, $processedActions);
  167. brake;
  168. case 'ResetForm':
  169. require_once 'Zend/Pdf/Action/ResetForm.php';
  170. return new Zend_Pdf_Action_ResetForm($dictionary, $parentAction, $processedActions);
  171. brake;
  172. case 'ImportData':
  173. require_once 'Zend/Pdf/Action/ImportData.php';
  174. return new Zend_Pdf_Action_ImportData($dictionary, $parentAction, $processedActions);
  175. brake;
  176. case 'JavaScript':
  177. require_once 'Zend/Pdf/Action/JavaScript.php';
  178. return new Zend_Pdf_Action_JavaScript($dictionary, $parentAction, $processedActions);
  179. brake;
  180. case 'SetOCGState':
  181. require_once 'Zend/Pdf/Action/SetOCGState.php';
  182. return new Zend_Pdf_Action_SetOCGState($dictionary, $parentAction, $processedActions);
  183. brake;
  184. case 'Rendition':
  185. require_once 'Zend/Pdf/Action/Rendition.php';
  186. return new Zend_Pdf_Action_Rendition($dictionary, $parentAction, $processedActions);
  187. brake;
  188. case 'Trans':
  189. require_once 'Zend/Pdf/Action/Trans.php';
  190. return new Zend_Pdf_Action_Trans($dictionary, $parentAction, $processedActions);
  191. brake;
  192. case 'GoTo3DView':
  193. require_once 'Zend/Pdf/Action/GoTo3DView.php';
  194. return new Zend_Pdf_Action_GoTo3DView($dictionary, $parentAction, $processedActions);
  195. brake;
  196. default:
  197. require_once 'Zend/Pdf/Action/Unknown.php';
  198. return new Zend_Pdf_Action_Unknown($dictionary, $parentAction, $processedActions);
  199. brake;
  200. }
  201. }
  202. /**
  203. * Extract action from the chain
  204. *
  205. * Returns root of the updated actions tree
  206. *
  207. * @return Zend_Pdf_Action
  208. */
  209. public function extract()
  210. {
  211. if (($parent = $this->_parent) !== null) {
  212. $parent->_next->detach($this);
  213. foreach ($this->_next as $chainedAction) {
  214. $parent->_next->attach($chainedAction);
  215. $chainedAction->_parent = $parent;
  216. }
  217. $this->_parent = null;
  218. $this->_next = new SplObjectStorage();
  219. return $parent->getRoot();
  220. } else {
  221. // This is a root node. Treat first subaction as a new root
  222. if ($this->_next->count() == 0) {
  223. // There is no any action in a tree now
  224. return null;
  225. }
  226. $this->_next->rewind();
  227. $root = $this->_next->current();
  228. $this->_next->detach($root);
  229. $root->_parent = null;
  230. foreach ($this->_next as $chainedAction) {
  231. $root->_next->attach($chainedAction);
  232. $chainedAction->_parent = $root;
  233. }
  234. $this->_next = new SplObjectStorage();
  235. return $root;
  236. }
  237. }
  238. /**
  239. * Destroy actions subtree
  240. *
  241. * Method has to be used to clean up resources after actions tree usage
  242. * since PHP doesn't do it automatically for objects with cyclic references
  243. */
  244. public function clean()
  245. {
  246. $this->_parent = null;
  247. foreach ($this->_next as $chainedAction) {
  248. $chainedAction->clean();
  249. }
  250. $this->_next = new SplObjectStorage();
  251. }
  252. /**
  253. * Get root of actions tree
  254. *
  255. * @return Zend_Pdf_Action
  256. */
  257. public function getRoot()
  258. {
  259. $root = $this;
  260. while ($root->_parent !== null) {
  261. $root = $root->_parent;
  262. }
  263. return $root;
  264. }
  265. /**
  266. * Return all subactions including this one
  267. *
  268. * @return SplObjectStorage
  269. */
  270. public function getAllActions()
  271. {
  272. $actions = new SplObjectStorage();
  273. $actions->attach($this);
  274. foreach ($this->_next as $chainedAction) {
  275. /** @todo Change to $actions->addAll($subAction->allActions()) when PHP 5.3.0+ is required for ZF */
  276. foreach ($chainedAction->getAllActions() as $action) {
  277. $actions->attach($action);
  278. }
  279. }
  280. return $actions;
  281. }
  282. /**
  283. * Get handler
  284. *
  285. * @param string $property
  286. * @return Zend_Pdf_Element | null
  287. */
  288. public function __get($property)
  289. {
  290. return $this->_actionDictionary->$property;
  291. }
  292. /**
  293. * Set handler
  294. *
  295. * @param string $property
  296. * @param mixed $value
  297. */
  298. public function __set($item, $value)
  299. {
  300. $this->_actionDictionary->$property = $value;
  301. }
  302. /**
  303. * Attach chained action
  304. *
  305. * @param Zend_Pdf_Action $action
  306. */
  307. public function attach(Zend_Pdf_Action $action)
  308. {
  309. $this->_next->attach($action);
  310. $action->_parent = $this;
  311. }
  312. /**
  313. * Rebuild PDF dictionaries corresponding to the current tree structure
  314. */
  315. public function rebuildSubtree()
  316. {
  317. switch (count($this->_next)) {
  318. case 0:
  319. $this->_actionDictionary->Next = null;
  320. break;
  321. case 1:
  322. $this->_next->rewind();
  323. $chainedAction = $this->_next->current();
  324. $chainedAction->rebuildSubtree();
  325. $this->_actionDictionary->Next = $chainedAction->_actionDictionary;
  326. break;
  327. default:
  328. $nextArray = new Zend_Pdf_Element_Array();
  329. foreach ($this->_next as $chainedAction) {
  330. $chainedAction->rebuildSubtree();
  331. $nextArray->items[] = $chainedAction->_actionDictionary;
  332. }
  333. $this->_actionDictionary->Next = $nextArray;
  334. break;
  335. }
  336. }
  337. /**
  338. * Get Action dictionary
  339. *
  340. * @internal
  341. * @return Zend_Pdf_Element_Dictionary|Zend_Pdf_Element_Object|Zend_Pdf_Element_Reference
  342. */
  343. public function getDictionary()
  344. {
  345. return $this->_actionDictionary;
  346. }
  347. }