/framework/vendor/zend/Zend/Pdf/ElementFactory.php
PHP | 436 lines | 179 code | 60 blank | 197 comment | 20 complexity | fb08aa25056e3f33d5e8d3b0bf2da85c MD5 | raw file
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 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) 18 * @license http://framework.zend.com/license/new-bsd New BSD License 19 * @version $Id: ElementFactory.php 20096 2010-01-06 02:05:09Z bkarwin $ 20 */ 21 22 23/** Zend_Pdf_ElementFactory_Interface */ 24require_once 'Zend/Pdf/ElementFactory/Interface.php'; 25 26/** 27 * PDF element factory. 28 * Responsibility is to log PDF changes 29 * 30 * @package Zend_Pdf 31 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) 32 * @license http://framework.zend.com/license/new-bsd New BSD License 33 */ 34class Zend_Pdf_ElementFactory implements Zend_Pdf_ElementFactory_Interface 35{ 36 /** 37 * List of the modified objects. 38 * Also contains new and removed objects 39 * 40 * Array: ojbectNumber => Zend_Pdf_Element_Object 41 * 42 * @var array 43 */ 44 private $_modifiedObjects = array(); 45 46 /** 47 * List of the removed objects 48 * 49 * Array: ojbectNumber => Zend_Pdf_Element_Object 50 * 51 * @var SplObjectStorage 52 */ 53 private $_removedObjects; 54 55 /** 56 * List of registered objects. 57 * Used for resources clean up when factory is destroyed. 58 * 59 * Array of Zend_Pdf_Element objects 60 * 61 * @var array 62 */ 63 private $_registeredObjects = array(); 64 65 /** 66 * PDF object counter. 67 * Actually it's an object number for new PDF object 68 * 69 * @var integer 70 */ 71 private $_objectCount; 72 73 74 /** 75 * List of the attached object factories. 76 * Array of Zend_Pdf_ElementFactory_Interface objects 77 * 78 * @var array 79 */ 80 private $_attachedFactories = array(); 81 82 83 /** 84 * Factory internal id 85 * 86 * @var integer 87 */ 88 private $_factoryId; 89 90 /** 91 * Identity, used for factory id generation 92 * 93 * @var integer 94 */ 95 private static $_identity = 0; 96 97 98 /** 99 * Internal cache to save calculated shifts 100 * 101 * @var array 102 */ 103 private $_shiftCalculationCache = array(); 104 105 106 /** 107 * Object constructor 108 * 109 * @param integer $objCount 110 */ 111 public function __construct($objCount) 112 { 113 $this->_objectCount = (int)$objCount; 114 $this->_factoryId = self::$_identity++; 115 $this->_removedObjects = new SplObjectStorage(); 116 } 117 118 119 /** 120 * Factory generator 121 * 122 * @param integer $objCount 123 * @return Zend_Pdf_ElementFactory_Interface 124 */ 125 static public function createFactory($objCount) 126 { 127 require_once 'Zend/Pdf/ElementFactory/Proxy.php'; 128 return new Zend_Pdf_ElementFactory_Proxy(new Zend_Pdf_ElementFactory($objCount)); 129 } 130 131 /** 132 * Close factory and clean-up resources 133 * 134 * @internal 135 */ 136 public function close() 137 { 138 $this->_modifiedObjects = null; 139 $this->_removedObjects = null; 140 $this->_attachedFactories = null; 141 142 foreach ($this->_registeredObjects as $obj) { 143 $obj->cleanUp(); 144 } 145 $this->_registeredObjects = null; 146 } 147 148 /** 149 * Get source factory object 150 * 151 * @return Zend_Pdf_ElementFactory 152 */ 153 public function resolve() 154 { 155 return $this; 156 } 157 158 /** 159 * Get factory ID 160 * 161 * @return integer 162 */ 163 public function getId() 164 { 165 return $this->_factoryId; 166 } 167 168 /** 169 * Set object counter 170 * 171 * @param integer $objCount 172 */ 173 public function setObjectCount($objCount) 174 { 175 $this->_objectCount = (int)$objCount; 176 } 177 178 /** 179 * Get object counter 180 * 181 * @return integer 182 */ 183 public function getObjectCount() 184 { 185 $count = $this->_objectCount; 186 187 foreach ($this->_attachedFactories as $attached) { 188 $count += $attached->getObjectCount() - 1; // -1 as "0" object is a special case and shared between factories 189 } 190 191 return $count; 192 } 193 194 195 /** 196 * Attach factory to the current; 197 * 198 * @param Zend_Pdf_ElementFactory_Interface $factory 199 */ 200 public function attach(Zend_Pdf_ElementFactory_Interface $factory) 201 { 202 if ( $factory === $this || isset($this->_attachedFactories[$factory->getId()])) { 203 /** 204 * Don't attach factory twice. 205 * We do not check recusively because of nature of attach operation 206 * (Pages are always attached to the Documents, Fonts are always attached 207 * to the pages even if pages already use Document level object factory and so on) 208 */ 209 return; 210 } 211 212 $this->_attachedFactories[$factory->getId()] = $factory; 213 } 214 215 216 /** 217 * Calculate object enumeration shift. 218 * 219 * @param Zend_Pdf_ElementFactory_Interface $factory 220 * @return integer 221 */ 222 public function calculateShift(Zend_Pdf_ElementFactory_Interface $factory) 223 { 224 if ($factory === $this) { 225 return 0; 226 } 227 228 if (isset($this->_shiftCalculationCache[$factory->_factoryId])) { 229 return $this->_shiftCalculationCache[$factory->_factoryId]; 230 } 231 232 $shift = $this->_objectCount - 1; 233 234 foreach ($this->_attachedFactories as $subFactory) { 235 $subFactoryShift = $subFactory->calculateShift($factory); 236 237 if ($subFactoryShift != -1) { 238 // context found 239 $this->_shiftCalculationCache[$factory->_factoryId] = $shift + $subFactoryShift; 240 return $shift + $subFactoryShift; 241 } else { 242 $shift += $subFactory->getObjectCount()-1; 243 } 244 } 245 246 $this->_shiftCalculationCache[$factory->_factoryId] = -1; 247 return -1; 248 } 249 250 /** 251 * Clean enumeration shift cache. 252 * Has to be used after PDF render operation to let followed updates be correct. 253 */ 254 public function cleanEnumerationShiftCache() 255 { 256 $this->_shiftCalculationCache = array(); 257 258 foreach ($this->_attachedFactories as $attached) { 259 $attached->cleanEnumerationShiftCache(); 260 } 261 } 262 263 /** 264 * Retrive object enumeration shift. 265 * 266 * @param Zend_Pdf_ElementFactory_Interface $factory 267 * @return integer 268 * @throws Zend_Pdf_Exception 269 */ 270 public function getEnumerationShift(Zend_Pdf_ElementFactory_Interface $factory) 271 { 272 if (($shift = $this->calculateShift($factory)) == -1) { 273 require_once 'Zend/Pdf/Exception.php'; 274 throw new Zend_Pdf_Exception('Wrong object context'); 275 } 276 277 return $shift; 278 } 279 280 /** 281 * Mark object as modified in context of current factory. 282 * 283 * @param Zend_Pdf_Element_Object $obj 284 * @throws Zend_Pdf_Exception 285 */ 286 public function markAsModified(Zend_Pdf_Element_Object $obj) 287 { 288 if ($obj->getFactory() !== $this) { 289 require_once 'Zend/Pdf/Exception.php'; 290 throw new Zend_Pdf_Exception('Object is not generated by this factory'); 291 } 292 293 $this->_modifiedObjects[$obj->getObjNum()] = $obj; 294 } 295 296 297 /** 298 * Remove object in context of current factory. 299 * 300 * @param Zend_Pdf_Element_Object $obj 301 * @throws Zend_Pdf_Exception 302 */ 303 public function remove(Zend_Pdf_Element_Object $obj) 304 { 305 if (!$obj->compareFactory($this)) { 306 require_once 'Zend/Pdf/Exception.php'; 307 throw new Zend_Pdf_Exception('Object is not generated by this factory'); 308 } 309 310 $this->_modifiedObjects[$obj->getObjNum()] = $obj; 311 $this->_removedObjects->attach($obj); 312 } 313 314 315 /** 316 * Generate new Zend_Pdf_Element_Object 317 * 318 * @todo Reusage of the freed object. It's not a support of new feature, but only improvement. 319 * 320 * @param Zend_Pdf_Element $objectValue 321 * @return Zend_Pdf_Element_Object 322 */ 323 public function newObject(Zend_Pdf_Element $objectValue) 324 { 325 require_once 'Zend/Pdf/Element/Object.php'; 326 $obj = new Zend_Pdf_Element_Object($objectValue, $this->_objectCount++, 0, $this); 327 $this->_modifiedObjects[$obj->getObjNum()] = $obj; 328 return $obj; 329 } 330 331 /** 332 * Generate new Zend_Pdf_Element_Object_Stream 333 * 334 * @todo Reusage of the freed object. It's not a support of new feature, but only improvement. 335 * 336 * @param mixed $objectValue 337 * @return Zend_Pdf_Element_Object_Stream 338 */ 339 public function newStreamObject($streamValue) 340 { 341 require_once 'Zend/Pdf/Element/Object/Stream.php'; 342 $obj = new Zend_Pdf_Element_Object_Stream($streamValue, $this->_objectCount++, 0, $this); 343 $this->_modifiedObjects[$obj->getObjNum()] = $obj; 344 return $obj; 345 } 346 347 348 /** 349 * Enumerate modified objects. 350 * Returns array of Zend_Pdf_UpdateInfoContainer 351 * 352 * @param Zend_Pdf_ElementFactory_Interface $rootFactory 353 * @return array 354 */ 355 public function listModifiedObjects($rootFactory = null) 356 { 357 if ($rootFactory == null) { 358 $rootFactory = $this; 359 $shift = 0; 360 } else { 361 $shift = $rootFactory->getEnumerationShift($this); 362 } 363 364 ksort($this->_modifiedObjects); 365 366 $result = array(); 367 require_once 'Zend/Pdf/UpdateInfoContainer.php'; 368 foreach ($this->_modifiedObjects as $objNum => $obj) { 369 if ($this->_removedObjects->contains($obj)) { 370 $result[$objNum+$shift] = new Zend_Pdf_UpdateInfoContainer($objNum + $shift, 371 $obj->getGenNum()+1, 372 true); 373 } else { 374 $result[$objNum+$shift] = new Zend_Pdf_UpdateInfoContainer($objNum + $shift, 375 $obj->getGenNum(), 376 false, 377 $obj->dump($rootFactory)); 378 } 379 } 380 381 foreach ($this->_attachedFactories as $factory) { 382 $result += $factory->listModifiedObjects($rootFactory); 383 } 384 385 return $result; 386 } 387 388 /** 389 * Register object in the factory 390 * 391 * It's used to clear "parent object" referencies when factory is closed and clean up resources 392 * 393 * @param string $refString 394 * @param Zend_Pdf_Element_Object $obj 395 */ 396 public function registerObject(Zend_Pdf_Element_Object $obj, $refString) 397 { 398 $this->_registeredObjects[$refString] = $obj; 399 } 400 401 /** 402 * Fetch object specified by reference 403 * 404 * @param string $refString 405 * @return Zend_Pdf_Element_Object|null 406 */ 407 public function fetchObject($refString) 408 { 409 if (!isset($this->_registeredObjects[$refString])) { 410 return null; 411 } 412 return $this->_registeredObjects[$refString]; 413 } 414 415 416 /** 417 * Check if PDF file was modified 418 * 419 * @return boolean 420 */ 421 public function isModified() 422 { 423 if (count($this->_modifiedObjects) != 0) { 424 return true; 425 } 426 427 foreach ($this->_attachedFactories as $subFactory) { 428 if ($subFactory->isModified()) { 429 return true; 430 } 431 } 432 433 return false; 434 } 435} 436