1: <?php
2: /**
3: * Parses an object by relying on the MIME capabilities of the backend.
4: *
5: * PHP version 5
6: *
7: * @category Kolab
8: * @package Kolab_Storage
9: * @author Gunnar Wrobel <wrobel@pardus.de>
10: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
11: * @link http://pear.horde.org/index.php?package=Kolab_Storage
12: */
13:
14: /**
15: * Parses an object by relying on the MIME capabilities of the backend.
16: er.
17: *
18: * Copyright 2011-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 Gunnar Wrobel <wrobel@pardus.de>
26: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
27: * @link http://pear.horde.org/index.php?package=Kolab_Storage
28: */
29: class Horde_Kolab_Storage_Data_Parser_Structure
30: implements Horde_Kolab_Storage_Data_Parser
31: {
32: /**
33: * The backend driver.
34: *
35: * @param Horde_Kolab_Storage_Driver
36: */
37: private $_driver;
38:
39: /**
40: * The bridge between the backend object and the format parser.
41: *
42: * @param Horde_Kolab_Storage_Data_Format
43: */
44: private $_format;
45:
46: /**
47: * A log handler.
48: *
49: * @param mixed
50: */
51: private $_logger;
52:
53: /**
54: * Constructor
55: *
56: * @param Horde_Kolab_Storage_Driver $driver The backend driver.
57: */
58: public function __construct(Horde_Kolab_Storage_Driver $driver)
59: {
60: $this->_driver = $driver;
61: }
62:
63: /**
64: * Set the logger.
65: *
66: * @param mixed $logger The log handler (must provide the warn() method).
67: *
68: * @return NULL
69: */
70: public function setLogger($logger)
71: {
72: $this->_logger = $logger;
73: }
74:
75: /**
76: * Indicate a problem in the log.
77: *
78: * @param Exception $message The warn message.
79: */
80: private function _warn($message)
81: {
82: if ($this->_logger === null) {
83: throw $message;
84: } else if ($this->_logger === false) {
85: return;
86: }
87: $this->_logger->warn($message->getMessage());
88: }
89:
90: /**
91: * Set the format handler.
92: *
93: * @param Horde_Kolab_Storage_Data_Format $format The data object <-> format
94: * bridge.
95: *
96: * @return NULL
97: */
98: public function setFormat(Horde_Kolab_Storage_Data_Format $format)
99: {
100: $this->_format = $format;
101: }
102:
103: /**
104: * Return the format handler.
105: *
106: * @return Horde_Kolab_Storage_Data_Format The data object <-> format
107: * bridge.
108: */
109: public function getFormat()
110: {
111: if ($this->_format === null) {
112: throw new Horde_Kolab_Storage_Exception(
113: 'The format handler has been left undefined!'
114: );
115: }
116: return $this->_format;
117: }
118:
119: /**
120: * Fetches the objects for the specified backend IDs.
121: *
122: * @param string $folder The folder to access.
123: * @param array $obids The object backend IDs to fetch.
124: * @param array $options Additional options for fetching.
125: * <pre>
126: * 'type' - Required argument specifying the object type that should be
127: * parsed.
128: * 'version' - Optional argument specifying the version of the object
129: * format.
130: * </pre>
131: *
132: * @return array The objects.
133: */
134: public function fetch($folder, $obids, $options = array())
135: {
136: $objects = array();
137: $this->_completeOptions($options);
138: $structures = $this->_driver->fetchStructure($folder, $obids);
139: foreach ($structures as $obid => $structure) {
140: if (!isset($structure['structure'])) {
141: throw new Horde_Kolab_Storage_Exception(
142: 'Backend returned a structure without the expected "structure" element.'
143: );
144: }
145: try {
146: $objects[$obid] = $this->getFormat()->parse($folder, $obid, $structure['structure'], $options);
147: } catch (Horde_Kolab_Storage_Exception $e) {
148: $objects[$obid] = false;
149: $this->_warn($e);
150: }
151: if ($this->_driver->hasCatenateSupport()) {
152: $objects[$obid]['__structure'] = $structure['structure'];
153: }
154: $this->_fetchAttachments($objects[$obid], $folder, $obid, $options);
155: }
156: return $objects;
157: }
158:
159: /**
160: * Completes the given object with any required attachments.
161: *
162: * @param array $object The object to fetch attachments for.
163: * @param string $folder The folder to access.
164: * @param array $obid The object backend ID.
165: * @param array $options Additional options for fetching.
166: *
167: * @return NULL
168: */
169: private function _fetchAttachments(&$object, $folder, $obid, $options = array())
170: {
171: //@todo: implement
172: }
173:
174: /**
175: * Fetch the specified mime part.
176: *
177: * @param string $folder The folder to access.
178: * @param string $obid The backend ID to parse from.
179: * @param string $mime_id The ID of the part that should be fetched.
180: *
181: * @return resource A stream for the specified body part.
182: */
183: public function fetchId($folder, $obid, $mime_id)
184: {
185: return $this->_driver->fetchBodypart($folder, $obid, $mime_id);
186: }
187:
188: /**
189: * Complete the options.
190: *
191: * @param array $options Options.
192: * <pre>
193: * 'type' - Required argument specifying the object type.
194: * 'version' - Optional argument specifying the version of the object
195: * format.
196: * </pre>
197: *
198: * @return NULL
199: */
200: private function _completeOptions(&$options)
201: {
202: if (!isset($options['type'])) {
203: throw new Horde_Kolab_Storage_Exception(
204: 'The object type must be specified!'
205: );
206: }
207: if (!isset($options['version'])) {
208: $options['version'] = 1;
209: }
210: }
211:
212: /**
213: * Create a new object in the specified folder.
214: *
215: * @param string $folder The folder to use.
216: * @param array $object The object.
217: * @param array $options Additional options for storing.
218: * <pre>
219: * 'type' - Required argument specifying the object type that should be
220: * stored.
221: * 'version' - Optional argument specifying the version of the object
222: * format.
223: * </pre>
224: *
225: * @return string The ID of the new object or true in case the backend does
226: * not support this return value.
227: */
228: public function create($folder, $object, $options = array())
229: {
230: return $this->_driver->appendMessage(
231: $folder,
232: $this->createObject($object, $options)
233: );
234: }
235:
236: /**
237: * Modify an existing object in the specified folder.
238: *
239: * @param string $folder The folder to use.
240: * @param array $object The object.
241: * @param string $obid The object ID in the backend.
242: * @param array $options Additional options for storing.
243: * <pre>
244: * 'type' - Required argument specifying the object type that should be
245: * stored.
246: * 'version' - Optional argument specifying the version of the object
247: * format.
248: * </pre>
249: *
250: * @return string The ID of the modified object or true in case the backend
251: * does not support this return value.
252: */
253: public function modify($folder, $object, $obid, $options = array())
254: {
255: $modifiable = $this->_driver->getModifiable($folder, $obid, $object);
256: $new_uid = $this->_format->modify($modifiable, $object, $options);
257: $this->_driver->deleteMessages($folder, array($obid));
258: $this->_driver->expunge($folder);
259: return $new_uid;
260: }
261:
262: /**
263: * Create a new MIME representation for the object.
264: *
265: * @param array $object The object.
266: * @param array $options Additional options for storing.
267: * <pre>
268: * 'type' - Required argument specifying the object type that should be
269: * stored.
270: * 'version' - Optional argument specifying the version of the object
271: * format.
272: * </pre>
273: *
274: * @return resource The MIME message representing the object.
275: */
276: public function createObject($object, $options = array())
277: {
278: $this->_completeOptions($options);
279: $envelope = $this->_format->createEnvelope();
280: $envelope->addPart($this->_format->createKolabPart($object, $options));
281: return $envelope->toString(
282: array(
283: 'canonical' => true,
284: 'stream' => true,
285: 'headers' => $this->_format->createEnvelopeHeaders(
286: $object['uid'],
287: $this->_driver->getAuth(),
288: $options['type']
289: )
290: )
291: );
292: }
293: }
294: