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 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 0023 /** Zend_Pdf_ElementFactory_Interface */ 0024 // require_once 'Zend/Pdf/ElementFactory/Interface.php'; 0025 0026 /** 0027 * PDF element factory. 0028 * Responsibility is to log PDF changes 0029 * 0030 * @package Zend_Pdf 0031 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0032 * @license http://framework.zend.com/license/new-bsd New BSD License 0033 */ 0034 class Zend_Pdf_ElementFactory implements Zend_Pdf_ElementFactory_Interface 0035 { 0036 /** 0037 * List of the modified objects. 0038 * Also contains new and removed objects 0039 * 0040 * Array: ojbectNumber => Zend_Pdf_Element_Object 0041 * 0042 * @var array 0043 */ 0044 private $_modifiedObjects = array(); 0045 0046 /** 0047 * List of the removed objects 0048 * 0049 * Array: ojbectNumber => Zend_Pdf_Element_Object 0050 * 0051 * @var SplObjectStorage 0052 */ 0053 private $_removedObjects; 0054 0055 /** 0056 * List of registered objects. 0057 * Used for resources clean up when factory is destroyed. 0058 * 0059 * Array of Zend_Pdf_Element objects 0060 * 0061 * @var array 0062 */ 0063 private $_registeredObjects = array(); 0064 0065 /** 0066 * PDF object counter. 0067 * Actually it's an object number for new PDF object 0068 * 0069 * @var integer 0070 */ 0071 private $_objectCount; 0072 0073 0074 /** 0075 * List of the attached object factories. 0076 * Array of Zend_Pdf_ElementFactory_Interface objects 0077 * 0078 * @var array 0079 */ 0080 private $_attachedFactories = array(); 0081 0082 0083 /** 0084 * Factory internal id 0085 * 0086 * @var integer 0087 */ 0088 private $_factoryId; 0089 0090 /** 0091 * Identity, used for factory id generation 0092 * 0093 * @var integer 0094 */ 0095 private static $_identity = 0; 0096 0097 0098 /** 0099 * Internal cache to save calculated shifts 0100 * 0101 * @var array 0102 */ 0103 private $_shiftCalculationCache = array(); 0104 0105 0106 /** 0107 * Object constructor 0108 * 0109 * @param integer $objCount 0110 */ 0111 public function __construct($objCount) 0112 { 0113 $this->_objectCount = (int)$objCount; 0114 $this->_factoryId = self::$_identity++; 0115 $this->_removedObjects = new SplObjectStorage(); 0116 } 0117 0118 0119 /** 0120 * Get factory 0121 * 0122 * @return Zend_Pdf_ElementFactory_Interface 0123 */ 0124 public function getFactory() 0125 { 0126 return $this; 0127 } 0128 0129 /** 0130 * Factory generator 0131 * 0132 * @param integer $objCount 0133 * @return Zend_Pdf_ElementFactory_Interface 0134 */ 0135 static public function createFactory($objCount) 0136 { 0137 // require_once 'Zend/Pdf/ElementFactory/Proxy.php'; 0138 return new Zend_Pdf_ElementFactory_Proxy(new Zend_Pdf_ElementFactory($objCount)); 0139 } 0140 0141 /** 0142 * Close factory and clean-up resources 0143 * 0144 * @internal 0145 */ 0146 public function close() 0147 { 0148 $this->_modifiedObjects = null; 0149 $this->_removedObjects = null; 0150 $this->_attachedFactories = null; 0151 0152 foreach ($this->_registeredObjects as $obj) { 0153 $obj->cleanUp(); 0154 } 0155 $this->_registeredObjects = null; 0156 } 0157 0158 /** 0159 * Get source factory object 0160 * 0161 * @return Zend_Pdf_ElementFactory 0162 */ 0163 public function resolve() 0164 { 0165 return $this; 0166 } 0167 0168 /** 0169 * Get factory ID 0170 * 0171 * @return integer 0172 */ 0173 public function getId() 0174 { 0175 return $this->_factoryId; 0176 } 0177 0178 /** 0179 * Set object counter 0180 * 0181 * @param integer $objCount 0182 */ 0183 public function setObjectCount($objCount) 0184 { 0185 $this->_objectCount = (int)$objCount; 0186 } 0187 0188 /** 0189 * Get object counter 0190 * 0191 * @return integer 0192 */ 0193 public function getObjectCount() 0194 { 0195 $count = $this->_objectCount; 0196 0197 foreach ($this->_attachedFactories as $attached) { 0198 $count += $attached->getObjectCount() - 1; // -1 as "0" object is a special case and shared between factories 0199 } 0200 0201 return $count; 0202 } 0203 0204 0205 /** 0206 * Attach factory to the current; 0207 * 0208 * @param Zend_Pdf_ElementFactory_Interface $factory 0209 */ 0210 public function attach(Zend_Pdf_ElementFactory_Interface $factory) 0211 { 0212 if ( $factory === $this || isset($this->_attachedFactories[$factory->getId()])) { 0213 /** 0214 * Don't attach factory twice. 0215 * We do not check recusively because of nature of attach operation 0216 * (Pages are always attached to the Documents, Fonts are always attached 0217 * to the pages even if pages already use Document level object factory and so on) 0218 */ 0219 return; 0220 } 0221 0222 $this->_attachedFactories[$factory->getId()] = $factory; 0223 } 0224 0225 0226 /** 0227 * Calculate object enumeration shift. 0228 * 0229 * @param Zend_Pdf_ElementFactory_Interface $factory 0230 * @return integer 0231 */ 0232 public function calculateShift(Zend_Pdf_ElementFactory_Interface $factory) 0233 { 0234 if ($factory === $this) { 0235 return 0; 0236 } 0237 0238 if (isset($this->_shiftCalculationCache[$factory->_factoryId])) { 0239 return $this->_shiftCalculationCache[$factory->_factoryId]; 0240 } 0241 0242 $shift = $this->_objectCount - 1; 0243 0244 foreach ($this->_attachedFactories as $subFactory) { 0245 $subFactoryShift = $subFactory->calculateShift($factory); 0246 0247 if ($subFactoryShift != -1) { 0248 // context found 0249 $this->_shiftCalculationCache[$factory->_factoryId] = $shift + $subFactoryShift; 0250 return $shift + $subFactoryShift; 0251 } else { 0252 $shift += $subFactory->getObjectCount()-1; 0253 } 0254 } 0255 0256 $this->_shiftCalculationCache[$factory->_factoryId] = -1; 0257 return -1; 0258 } 0259 0260 /** 0261 * Clean enumeration shift cache. 0262 * Has to be used after PDF render operation to let followed updates be correct. 0263 */ 0264 public function cleanEnumerationShiftCache() 0265 { 0266 $this->_shiftCalculationCache = array(); 0267 0268 foreach ($this->_attachedFactories as $attached) { 0269 $attached->cleanEnumerationShiftCache(); 0270 } 0271 } 0272 0273 /** 0274 * Retrive object enumeration shift. 0275 * 0276 * @param Zend_Pdf_ElementFactory_Interface $factory 0277 * @return integer 0278 * @throws Zend_Pdf_Exception 0279 */ 0280 public function getEnumerationShift(Zend_Pdf_ElementFactory_Interface $factory) 0281 { 0282 if (($shift = $this->calculateShift($factory)) == -1) { 0283 // require_once 'Zend/Pdf/Exception.php'; 0284 throw new Zend_Pdf_Exception('Wrong object context'); 0285 } 0286 0287 return $shift; 0288 } 0289 0290 /** 0291 * Mark object as modified in context of current factory. 0292 * 0293 * @param Zend_Pdf_Element_Object $obj 0294 * @throws Zend_Pdf_Exception 0295 */ 0296 public function markAsModified(Zend_Pdf_Element_Object $obj) 0297 { 0298 if ($obj->getFactory() !== $this) { 0299 // require_once 'Zend/Pdf/Exception.php'; 0300 throw new Zend_Pdf_Exception('Object is not generated by this factory'); 0301 } 0302 0303 $this->_modifiedObjects[$obj->getObjNum()] = $obj; 0304 } 0305 0306 0307 /** 0308 * Remove object in context of current factory. 0309 * 0310 * @param Zend_Pdf_Element_Object $obj 0311 * @throws Zend_Pdf_Exception 0312 */ 0313 public function remove(Zend_Pdf_Element_Object $obj) 0314 { 0315 if (!$obj->compareFactory($this)) { 0316 // require_once 'Zend/Pdf/Exception.php'; 0317 throw new Zend_Pdf_Exception('Object is not generated by this factory'); 0318 } 0319 0320 $this->_modifiedObjects[$obj->getObjNum()] = $obj; 0321 $this->_removedObjects->attach($obj); 0322 } 0323 0324 0325 /** 0326 * Generate new Zend_Pdf_Element_Object 0327 * 0328 * @todo Reusage of the freed object. It's not a support of new feature, but only improvement. 0329 * 0330 * @param Zend_Pdf_Element $objectValue 0331 * @return Zend_Pdf_Element_Object 0332 */ 0333 public function newObject(Zend_Pdf_Element $objectValue) 0334 { 0335 // require_once 'Zend/Pdf/Element/Object.php'; 0336 $obj = new Zend_Pdf_Element_Object($objectValue, $this->_objectCount++, 0, $this); 0337 $this->_modifiedObjects[$obj->getObjNum()] = $obj; 0338 return $obj; 0339 } 0340 0341 /** 0342 * Generate new Zend_Pdf_Element_Object_Stream 0343 * 0344 * @todo Reusage of the freed object. It's not a support of new feature, but only improvement. 0345 * 0346 * @param mixed $objectValue 0347 * @return Zend_Pdf_Element_Object_Stream 0348 */ 0349 public function newStreamObject($streamValue) 0350 { 0351 // require_once 'Zend/Pdf/Element/Object/Stream.php'; 0352 $obj = new Zend_Pdf_Element_Object_Stream($streamValue, $this->_objectCount++, 0, $this); 0353 $this->_modifiedObjects[$obj->getObjNum()] = $obj; 0354 return $obj; 0355 } 0356 0357 0358 /** 0359 * Enumerate modified objects. 0360 * Returns array of Zend_Pdf_UpdateInfoContainer 0361 * 0362 * @param Zend_Pdf_ElementFactory_Interface $rootFactory 0363 * @return array 0364 */ 0365 public function listModifiedObjects($rootFactory = null) 0366 { 0367 if ($rootFactory == null) { 0368 $rootFactory = $this; 0369 $shift = 0; 0370 } else { 0371 $shift = $rootFactory->getEnumerationShift($this); 0372 } 0373 0374 ksort($this->_modifiedObjects); 0375 0376 $result = array(); 0377 // require_once 'Zend/Pdf/UpdateInfoContainer.php'; 0378 foreach ($this->_modifiedObjects as $objNum => $obj) { 0379 if ($this->_removedObjects->contains($obj)) { 0380 $result[$objNum+$shift] = new Zend_Pdf_UpdateInfoContainer($objNum + $shift, 0381 $obj->getGenNum()+1, 0382 true); 0383 } else { 0384 $result[$objNum+$shift] = new Zend_Pdf_UpdateInfoContainer($objNum + $shift, 0385 $obj->getGenNum(), 0386 false, 0387 $obj->dump($rootFactory)); 0388 } 0389 } 0390 0391 foreach ($this->_attachedFactories as $factory) { 0392 $result += $factory->listModifiedObjects($rootFactory); 0393 } 0394 0395 return $result; 0396 } 0397 0398 /** 0399 * Register object in the factory 0400 * 0401 * It's used to clear "parent object" referencies when factory is closed and clean up resources 0402 * 0403 * @param string $refString 0404 * @param Zend_Pdf_Element_Object $obj 0405 */ 0406 public function registerObject(Zend_Pdf_Element_Object $obj, $refString) 0407 { 0408 $this->_registeredObjects[$refString] = $obj; 0409 } 0410 0411 /** 0412 * Fetch object specified by reference 0413 * 0414 * @param string $refString 0415 * @return Zend_Pdf_Element_Object|null 0416 */ 0417 public function fetchObject($refString) 0418 { 0419 if (!isset($this->_registeredObjects[$refString])) { 0420 return null; 0421 } 0422 return $this->_registeredObjects[$refString]; 0423 } 0424 0425 0426 /** 0427 * Check if PDF file was modified 0428 * 0429 * @return boolean 0430 */ 0431 public function isModified() 0432 { 0433 if (count($this->_modifiedObjects) != 0) { 0434 return true; 0435 } 0436 0437 foreach ($this->_attachedFactories as $subFactory) { 0438 if ($subFactory->isModified()) { 0439 return true; 0440 } 0441 } 0442 0443 return false; 0444 } 0445 } 0446