PageRenderTime 26ms CodeModel.GetById 13ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/framework/vendor/zend/Zend/Pdf/ElementFactory.php

http://zoop.googlecode.com/
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