Overview

Packages

  • Kolab
    • Storage

Classes

  • Horde_Kolab_Storage_Base
  • Horde_Kolab_Storage_Cache
  • Horde_Kolab_Storage_Cache_Data
  • Horde_Kolab_Storage_Cache_List
  • Horde_Kolab_Storage_Cached
  • Horde_Kolab_Storage_Data_Base
  • Horde_Kolab_Storage_Data_Cached
  • Horde_Kolab_Storage_Data_Decorator_Log
  • Horde_Kolab_Storage_Data_Format_Mime
  • Horde_Kolab_Storage_Data_Modifiable
  • Horde_Kolab_Storage_Data_Old
  • Horde_Kolab_Storage_Data_Parser_Structure
  • Horde_Kolab_Storage_Data_Query_History_Base
  • Horde_Kolab_Storage_Data_Query_History_Cache
  • Horde_Kolab_Storage_Data_Query_Preferences_Base
  • Horde_Kolab_Storage_Data_Query_Preferences_Cache
  • Horde_Kolab_Storage_Decorator_Synchronization
  • Horde_Kolab_Storage_Driver_Base
  • Horde_Kolab_Storage_Driver_Cclient
  • Horde_Kolab_Storage_Driver_Decorator_Base
  • Horde_Kolab_Storage_Driver_Decorator_Log
  • Horde_Kolab_Storage_Driver_Decorator_Timer
  • Horde_Kolab_Storage_Driver_Imap
  • Horde_Kolab_Storage_Driver_Mock
  • Horde_Kolab_Storage_Driver_Mock_Data
  • Horde_Kolab_Storage_Driver_Pear
  • Horde_Kolab_Storage_Driver_Rcube
  • Horde_Kolab_Storage_Exception
  • Horde_Kolab_Storage_Exception_Pear
  • Horde_Kolab_Storage_Factory
  • Horde_Kolab_Storage_Folder_Base
  • Horde_Kolab_Storage_Folder_Decorator_Base
  • Horde_Kolab_Storage_Folder_Decorator_Trigger
  • Horde_Kolab_Storage_Folder_Namespace
  • Horde_Kolab_Storage_Folder_Namespace_Config
  • Horde_Kolab_Storage_Folder_Namespace_Element
  • Horde_Kolab_Storage_Folder_Namespace_Element_Other
  • Horde_Kolab_Storage_Folder_Namespace_Element_Personal
  • Horde_Kolab_Storage_Folder_Namespace_Element_Shared
  • Horde_Kolab_Storage_Folder_Namespace_Element_SharedWithPrefix
  • Horde_Kolab_Storage_Folder_Namespace_Fixed
  • Horde_Kolab_Storage_Folder_Namespace_Imap
  • Horde_Kolab_Storage_Folder_Stamp_Uids
  • Horde_Kolab_Storage_Folder_Type
  • Horde_Kolab_Storage_List_Base
  • Horde_Kolab_Storage_List_Decorator_Cache
  • Horde_Kolab_Storage_List_Decorator_Log
  • Horde_Kolab_Storage_List_Query_Acl_Base
  • Horde_Kolab_Storage_List_Query_Acl_Cache
  • Horde_Kolab_Storage_List_Query_ActiveSync_Base
  • Horde_Kolab_Storage_List_Query_ActiveSync_Cache
  • Horde_Kolab_Storage_List_Query_List_Base
  • Horde_Kolab_Storage_List_Query_List_Cache
  • Horde_Kolab_Storage_List_Query_Share_Base
  • Horde_Kolab_Storage_List_Query_Share_Cache
  • Horde_Kolab_Storage_QuerySet_Base
  • Horde_Kolab_Storage_QuerySet_Cached
  • Horde_Kolab_Storage_QuerySet_Uncached
  • Horde_Kolab_Storage_Synchronization
  • Horde_Kolab_Storage_Translation
  • Horde_Kolab_Storage_Uncached

Interfaces

  • Horde_Kolab_Storage
  • Horde_Kolab_Storage_Data
  • Horde_Kolab_Storage_Data_Format
  • Horde_Kolab_Storage_Data_Parser
  • Horde_Kolab_Storage_Data_Query
  • Horde_Kolab_Storage_Data_Query_History
  • Horde_Kolab_Storage_Data_Query_Preferences
  • Horde_Kolab_Storage_Driver
  • Horde_Kolab_Storage_Folder
  • Horde_Kolab_Storage_Folder_Stamp
  • Horde_Kolab_Storage_List
  • Horde_Kolab_Storage_List_Query
  • Horde_Kolab_Storage_List_Query_Acl
  • Horde_Kolab_Storage_List_Query_ActiveSync
  • Horde_Kolab_Storage_List_Query_List
  • Horde_Kolab_Storage_List_Query_Share
  • Horde_Kolab_Storage_Queriable
  • Horde_Kolab_Storage_Query
  • Horde_Kolab_Storage_QuerySet
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * A cache backend for Kolab storage data handlers.
  4:  *
  5:  * PHP version 5
  6:  *
  7:  * @category Kolab
  8:  * @package  Kolab_Storage
  9:  * @author   Thomas Jarosch <thomas.jarosch@intra2net.com>
 10:  * @author   Gunnar Wrobel <wrobel@pardus.de>
 11:  * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
 12:  * @link     http://pear.horde.org/index.php?package=Kolab_Storage
 13:  */
 14: 
 15: /**
 16:  * A cache backend for Kolab storage data handlers.
 17:  *
 18:  * Copyright 2007-2012 Horde LLC (http://www.horde.org/)
 19:  *
 20:  * See the enclosed file COPYING for license information (LGPL). If you
 21:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
 22:  *
 23:  * @category Kolab
 24:  * @package  Kolab_Storage
 25:  * @author   Thomas Jarosch <thomas.jarosch@intra2net.com>
 26:  * @author   Gunnar Wrobel <wrobel@pardus.de>
 27:  * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
 28:  * @link     http://pear.horde.org/index.php?package=Kolab_Storage
 29:  */
 30: class Horde_Kolab_Storage_Cache_Data
 31: {
 32:     /** Key for the backend ID to object ID mapping. */
 33:     const B2O = 'M';
 34: 
 35:     /** Key for the object ID to backend ID mapping. */
 36:     const O2B = 'B';
 37: 
 38:     /** Key for the objects. */
 39:     const OBJECTS = 'O';
 40: 
 41:     /** Key for recording duplicate objects. */
 42:     const DUPLICATES = 'U';
 43: 
 44:     /** Key for recording error objects. */
 45:     const ERRORS = 'E';
 46: 
 47:     /** Key for the stamp. */
 48:     const STAMP = 'P';
 49: 
 50:     /** Key for the data format version. */
 51:     const DATA_VERSION = 'D';
 52: 
 53:     /** Key for the last time the data was synchronized. */
 54:     const SYNC = 'S';
 55: 
 56:     /** Key for the cache format version. */
 57:     const VERSION = 'V';
 58: 
 59:     /** Key for the data set parameters associated with this cache. */
 60:     const ID = 'I';
 61: 
 62:     /** Holds the version number of the cache format. */
 63:     const FORMAT_VERSION = '1';
 64: 
 65:     /** Holds query results. */
 66:     const QUERIES = 'Q';
 67: 
 68:     /**
 69:      * The core cache driver.
 70:      *
 71:      * @var Horde_Kolab_Storage_Cache
 72:      */
 73:     private $_cache;
 74: 
 75:     /**
 76:      * Data parameters that will be recorded in the cache.
 77:      *
 78:      * @var array
 79:      */
 80:     private $_parameters;
 81: 
 82:     /**
 83:      * Data ID.
 84:      *
 85:      * @var string
 86:      */
 87:     private $_data_id;
 88: 
 89:     /**
 90:      * The cache data.
 91:      *
 92:      * @var array
 93:      */
 94:     private $_data = false;
 95: 
 96:     /**
 97:      * Constructor.
 98:      *
 99:      * @param Horde_Kolab_Storage_Cache $cache      The core cache driver.
100: 
101:      * @param array                     $parameters Data set parameters that
102:      *                                              are only recorded and have
103:      *                                              no further impact.
104:      */
105:     public function __construct(Horde_Kolab_Storage_Cache $cache,
106:                                 $parameters = null)
107:     {
108:         $this->_cache = $cache;
109:         $this->_parameters = $parameters;
110:     }
111: 
112:     /**
113:      * The ID for the data cache.
114:      *
115:      * @param string $data_id The unique ID for the data used when caching it.
116:      *
117:      * @return NULL
118:      */
119:     public function setDataId($data_id)
120:     {
121:         $this->_data_id = $data_id;
122:     }
123: 
124:     /**
125:      * Return the ID for the data cache.
126:      *
127:      * @return string The unique ID for the data used when caching it.
128:      */
129:     public function getDataId()
130:     {
131:         if ($this->_data_id === null) {
132:             throw new Horde_Kolab_Storage_Exception(
133:                 'You must set the ID of the data cache!'
134:             );
135:         }
136:         return $this->_data_id;
137:     }
138: 
139:     /**
140:      * Retrieve the cached list data.
141:      *
142:      * @return mixed The data of the object.
143:      */
144:     private function _load()
145:     {
146:         if ($this->_data === false) {
147:             $this->_data = unserialize($this->_cache->loadData($this->getDataId()));
148:             if (!is_array($this->_data)
149:                 || !isset($this->_data[self::SYNC])
150:                 || !isset($this->_data[self::VERSION])
151:                 || $this->_data[self::VERSION] != self::FORMAT_VERSION) {
152:                 $this->_data = array();
153:             }
154:         }
155:     }
156: 
157:     /**
158:      * Cache the data.
159:      *
160:      * @return NULL
161:      */
162:     public function save()
163:     {
164:         $this->_cache->storeData($this->getDataId(), serialize($this->_data));
165:     }
166: 
167:     /**
168:      * Check if the cache has been initialized.
169:      *
170:      * @return boolean True if cache data is available.
171:      */
172:     public function isInitialized()
173:     {
174:         $this->_load();
175:         return !empty($this->_data);
176:     }
177: 
178:     /**
179:      * Retrieve the object list from the cache.
180:      *
181:      * @return array The list of objects.
182:      */
183:     public function getObjects()
184:     {
185:         return $this->_fetchCacheEntry(self::OBJECTS);
186:     }
187: 
188:     /**
189:      * Retrieve the specified object from the cache.
190:      *
191:      * @param string $obid The object ID to fetch.
192:      *
193:      * @return array The list of objects.
194:      */
195:     public function getObjectByBackendId($obid)
196:     {
197:         $obids = $this->getBackendToObject();
198:         if (isset($obids[$obid])) {
199:             $objects = $this->getObjects();
200:             return $objects[$obids[$obid]];
201:         } else {
202:             throw new Horde_Kolab_Storage_Exception(
203:                 sprintf ('No such object %s!', $obid)
204:             );
205:         }
206:     }
207: 
208:     /**
209:      * Return the object ID to backend ID mapping.
210:      *
211:      * @return array The mapping.
212:      */
213:     public function getObjectToBackend()
214:     {
215:         return $this->_fetchCacheEntry(self::O2B);
216:     }
217: 
218:     /**
219:      * Return the backend ID to object ID mapping.
220:      *
221:      * @return array The mapping.
222:      */
223:     public function getBackendToObject()
224:     {
225:         return $this->_fetchCacheEntry(self::B2O);
226:     }
227: 
228:     /**
229:      * Retrieve the last stamp.
230:      *
231:      * @return Horde_Kolab_Storage_Folder_Stamp The last recorded stamp.
232:      */
233:     public function getStamp()
234:     {
235:         $this->_checkInit(self::STAMP);
236:         return $this->_data[self::STAMP];
237:     }
238: 
239:     /**
240:      * Retrieve the data version.
241:      *
242:      * @return string The version of the stored data.
243:      */
244:     public function getVersion()
245:     {
246:         $this->_checkInit(self::DATA_VERSION);
247:         return $this->_data[self::DATA_VERSION];
248:     }
249: 
250:     /**
251:      * Retrieve the list of object duplicates.
252:      *
253:      * @since Horde_Kolab_Storage 1.1.0
254:      *
255:      * @return array The list of duplicates.
256:      */
257:     public function getDuplicates()
258:     {
259:         return $this->_fetchCacheEntry(self::DUPLICATES);
260:     }
261: 
262:     /**
263:      * Retrieve the list of object errors.
264:      *
265:      * @since Horde_Kolab_Storage 1.1.0
266:      *
267:      * @return array The list of errors.
268:      */
269:     public function getErrors()
270:     {
271:         return $this->_fetchCacheEntry(self::ERRORS);
272:     }
273: 
274:     /**
275:      * Retrieve an attachment.
276:      *
277:      * @param string $obid          Object backend id.
278:      * @param string $attachment_id Attachment ID.
279:      *
280:      * @return resource A stream opened to the attachement data.
281:      */
282:     public function getAttachment($obid, $attachment_id)
283:     {
284:         return $this->_cache->loadAttachment(
285:             $this->getDataId(), $obid, $attachment_id
286:         );
287:     }
288: 
289:     /**
290:      * Retrieve an attachment by name.
291:      *
292:      * @param string $obid          Object backend id.
293:      * @param string $attachment_id Attachment ID.
294:      *
295:      * @return array An array of attachment resources.
296:      */
297:     public function getAttachmentByName($obid, $name)
298:     {
299:         $object = $this->getObjectByBackendId($obid);
300:         if (!isset($object['_attachments']['name'][$name])) {
301:             throw new Horde_Kolab_Storage_Exception(
302:                 sprintf(
303:                     'No attachment named "%s" for object id %s!',
304:                     $name,
305:                     $obid
306:                 )
307:             );
308:         }
309:         $result = array();
310:         foreach ($object['_attachments']['name'][$name] as $attachment_id) {
311:             $result[$attachment_id] = $this->_cache->loadAttachment(
312:                 $this->getDataId(), $obid, $attachment_id
313:             );
314:         }
315:         return $result;
316:     }
317: 
318:     /**
319:      * Retrieve an attachment by name.
320:      *
321:      * @param string $obid          Object backend id.
322:      * @param string $attachment_id Attachment ID.
323:      *
324:      * @return array An array of attachment resources.
325:      */
326:     public function getAttachmentByType($obid, $type)
327:     {
328:         $object = $this->getObjectByBackendId($obid);
329:         if (!isset($object['_attachments']['type'][$type])) {
330:             throw new Horde_Kolab_Storage_Exception(
331:                 sprintf(
332:                     'No attachment with type "%s" for object id %s!',
333:                     $type,
334:                     $obid
335:                 )
336:             );
337:         }
338:         $result = array();
339:         foreach ($object['_attachments']['type'][$type] as $attachment_id) {
340:             $result[$attachment_id] = $this->_cache->loadAttachment(
341:                 $this->getDataId(), $obid, $attachment_id
342:             );
343:         }
344:         return $result;
345:     }
346: 
347:     /**
348:      * Return the timestamp of the last synchronization.
349:      *
350:      * @since Horde_Kolab_Storage 1.1.0
351:      *
352:      * @return int Timestamp of the last sync.
353:      */
354:     public function getLastSync()
355:     {
356:         $this->_load();
357:         return isset($this->_data[self::SYNC]) ? $this->_data[self::SYNC] : false;
358:     }
359: 
360:     /**
361:      * Is the specified query data available in the cache?
362:      *
363:      * @since Horde_Kolab_Storage 1.1.0
364:      *
365:      * @param string $key The query key.
366:      *
367:      * @return boolean True in case cached data is available.
368:      */
369:     public function hasQuery($key)
370:     {
371:         $this->_load();
372:         return isset($this->_data[self::QUERIES][$key]);
373:     }
374: 
375:     /**
376:      * Return query information.
377:      *
378:      * @since Horde_Kolab_Storage 1.1.0
379:      *
380:      * @param string $key The query key.
381:      *
382:      * @return mixed The query data.
383:      */
384:     public function getQuery($key)
385:     {
386:         if ($this->hasQuery($key)) {
387:             return $this->_data[self::QUERIES][$key];
388:         } else {
389:             throw new Horde_Kolab_Storage_Exception(
390:                 sprintf('Missing query cache data (Key: %s). Synchronize first!', $key)
391:             );
392:         }
393:     }
394: 
395:     /**
396:      * Set query information.
397:      *
398:      * @since Horde_Kolab_Storage 1.1.0
399:      *
400:      * @param string $key  The query key.
401:      * @param mixed  $data The query data.
402:      *
403:      * @return NULL
404:      */
405:     public function setQuery($key, $data)
406:     {
407:         $this->_load();
408:         $this->_data[self::QUERIES][$key] = $data;
409:     }
410: 
411:     /**
412:      * Fetch the specified cache entry in case it is present. Returns an empty
413:      * array otherwise.
414:      *
415:      * @param string $key The key in the cached data array.
416:      *
417:      * @return array The cache entry.
418:      */
419:     private function _fetchCacheEntry($key)
420:     {
421:         $this->_checkInit($key);
422:         if (isset($this->_data[$key])) {
423:             return $this->_data[$key];
424:         } else {
425:             return array();
426:         }
427:     }
428: 
429:     /**
430:      * Verify that the data cache is initialized.
431:      *
432:      * @param string $key The key in the cached data array.
433:      *
434:      * @return NULL
435:      *
436:      * @throws Horde_Kolab_Storage_Exception In case the cache has not been
437:      *                                       initialized.
438:      */
439:     private function _checkInit($key)
440:     {
441:         if (!$this->isInitialized()) {
442:             throw new Horde_Kolab_Storage_Exception(
443:                 sprintf('Missing cache data (Key: %s). Synchronize first!', $key)
444:             );
445:         }
446:     }
447: 
448:     /**
449:      * Map backend IDs to object ids.
450:      *
451:      * @since Horde_Kolab_Storage 1.1.0
452:      *
453:      * @param array $backend_ids The list of backend IDs
454:      *
455:      * @return array A list that associates object IDs (values) to backend IDs
456:      *               (keys).
457:      */
458:     public function backendMap($backend_ids)
459:     {
460:         if (empty($backend_ids)) {
461:             return array();
462:         }
463:         $map = array();
464:         foreach ($backend_ids as $item) {
465:             $map[$item] = $this->_data[self::B2O][$item];
466:         }
467:         return $map;
468:     }
469: 
470:     /**
471:      * Store the objects list in the cache.
472:      *
473:      * @param array                            $object  The object data to store.
474:      * @param Horde_Kolab_Storage_Folder_Stamp $stamp   The current stamp.
475:      * @param string                           $version The format version of
476:      *                                                  the provided data.
477:      * @param array                            $delete  Backend IDs that were removed.
478:      *
479:      * @return NULL
480:      */
481:     public function store(array $objects,
482:                           Horde_Kolab_Storage_Folder_Stamp $stamp,
483:                           $version,
484:                           array $delete = array())
485:     {
486:         $this->_load();
487:         if (!empty($delete)) {
488:             foreach ($delete as $obid => $object_id) {
489:                 $object = $this->_data[self::OBJECTS][$object_id];
490:                 if (isset($object['_attachments'])) {
491:                     foreach ($object['_attachments']['id'] as $id) {
492:                         $this->_cache->deleteAttachment(
493:                             $this->getDataId(), $obid, $id
494:                         );
495:                     }
496:                 }
497:                 unset($this->_data[self::O2B][$object_id]);
498:                 unset($this->_data[self::OBJECTS][$object_id]);
499:                 unset($this->_data[self::B2O][$obid]);
500:             }
501:         }
502:         foreach ($objects as $obid => $object) {
503:             if (!empty($object) && isset($object['uid'])) {
504:                 if (isset($this->_data[self::O2B][$object['uid']])) {
505:                     if (!isset($this->_data[self::DUPLICATES][$object['uid']])) {
506:                         $this->_data[self::DUPLICATES][$object['uid']][] = $this->_data[self::O2B][$object['uid']];
507:                     }
508:                     $this->_data[self::DUPLICATES][$object['uid']][] = $obid;
509:                 }
510:                 $this->_data[self::B2O][$obid] = $object['uid'];
511:                 $this->_data[self::O2B][$object['uid']] = $obid;
512:                 if (isset($object['_attachments'])) {
513:                     $attachments = array();
514:                     foreach ($object['_attachments'] as $id => $attachment) {
515:                         $attachments['id'][] = $id;
516:                         if (isset($attachment['name'])) {
517:                             $attachments['name'][$attachment['name']][] = $id;
518:                         }
519:                         if (isset($attachment['type'])) {
520:                             $attachments['type'][$attachment['type']][] = $id;
521:                         }
522:                         $this->_cache->storeAttachment($this->getDataId(), $obid, $id, $attachment['content']);
523:                     }
524:                     $object['_attachments'] = $attachments;
525:                 }
526:                 $this->_data[self::OBJECTS][$object['uid']] = $object;
527:             } else {
528:                 $this->_data[self::B2O][$obid] = false;
529:                 $this->_data[self::ERRORS][] = $obid;
530:             }
531:         }
532:         $this->_data[self::QUERIES] = array();
533:         $this->_data[self::STAMP] = serialize($stamp);
534:         $this->_data[self::DATA_VERSION] = $version;
535:         $this->_data[self::VERSION] = self::FORMAT_VERSION;
536:         $this->_data[self::ID] = serialize($this->_parameters);
537:         $this->_data[self::SYNC] = time();
538:     }
539: 
540:     /**
541:      * Initialize the cache structure.
542:      *
543:      * @return NULL
544:      */
545:     public function reset()
546:     {
547:         $this->_data = array();
548:     }
549: }
550: 
API documentation generated by ApiGen