Overview

Packages

  • Data

Classes

  • Horde_Data
  • Horde_Data_Base
  • Horde_Data_Csv
  • Horde_Data_Exception
  • Horde_Data_Icalendar
  • Horde_Data_Imc
  • Horde_Data_Outlookcsv
  • Horde_Data_Translation
  • Horde_Data_Tsv
  • Horde_Data_Vcard
  • Horde_Data_Vnote
  • Horde_Data_Vtodo
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Abstract class that Data drivers extend.
  4:  *
  5:  * Copyright 1999-2012 Horde LLC (http://www.horde.org/)
  6:  *
  7:  * See the enclosed file COPYING for license information (LGPL). If you
  8:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
  9:  *
 10:  * @author   Jan Schneider <jan@horde.org>
 11:  * @author   Chuck Hagenbuch <chuck@horde.org>
 12:  * @category Horde
 13:  * @package  Data
 14:  */
 15: abstract class Horde_Data_Base
 16: {
 17:     /**
 18:      * Browser object.
 19:      *
 20:      * @var Horde_Browser
 21:      */
 22:     protected $_browser;
 23: 
 24:     /**
 25:      * Cleanup callback function.
 26:      *
 27:      * @var callback
 28:      */
 29:     protected $_cleanupCallback;
 30: 
 31:     /**
 32:      * MIME content type.
 33:      *
 34:      * @var string
 35:      */
 36:     protected $_contentType = 'text/plain';
 37: 
 38:     /**
 39:      * File extension.
 40:      *
 41:      * @var string
 42:      */
 43:     protected $_extension = '';
 44: 
 45:     /**
 46:      * Variables object.
 47:      *
 48:      * @var Horde_Variables
 49:      */
 50:     protected $_vars;
 51: 
 52:     /**
 53:      * A list of warnings raised during the last operation.
 54:      *
 55:      * @var array
 56:      */
 57:     protected $_warnings = array();
 58: 
 59:     /**
 60:      * Constructor.
 61:      *
 62:      * @param array $params  Parameters:
 63:      * <pre>
 64:      * OPTIONAL:
 65:      * ---------
 66:      * browser - (Horde_Browser) A browser object.
 67:      * cleanup - (callback) A callback to call at cleanup time.
 68:      * vars - (Horde_Variables) Form data.
 69:      * </pre>
 70:      */
 71:     public function __construct(array $params = array())
 72:     {
 73:         if (isset($params['browser'])) {
 74:             $this->_browser = $params['browser'];
 75:         }
 76: 
 77:         if (isset($params['cleanup']) && is_callable($params['cleanup'])) {
 78:             $this->_cleanupCallback = $params['cleanup'];
 79:         }
 80: 
 81:         $this->_vars = isset($params['vars'])
 82:             ? $params['vars']
 83:             : Horde_Variables::getDefaultVariables();
 84:     }
 85: 
 86:     /**
 87:      * Stub to import passed data.
 88:      */
 89:     public function importData($text)
 90:     {
 91:     }
 92: 
 93:     /**
 94:      * Stub to return exported data.
 95:      */
 96:     abstract public function exportData($data, $method = 'REQUEST');
 97: 
 98:     /**
 99:      * Stub to import a file.
100:      */
101:     public function importFile($filename, $header = false)
102:     {
103:         $data = file_get_contents($filename);
104:         return $this->importData($data, $header);
105:     }
106: 
107:     /**
108:      * Stub to export data to a file.
109:      */
110:     abstract public function exportFile($filename, $data);
111: 
112:     /**
113:      * Tries to determine the expected newline character based on the
114:      * platform information passed by the browser's agent header.
115:      *
116:      * @return string  The guessed expected newline characters, either \n, \r
117:      *                 or \r\n.
118:      */
119:     public function getNewline()
120:     {
121:         if (!isset($this->_browser)) {
122:             throw new LogicException('Missing browser parameter.');
123:         }
124: 
125:         switch ($this->_browser->getPlatform()) {
126:         case 'win':
127:             return "\r\n";
128: 
129:         case 'mac':
130:             return "\r";
131: 
132:         case 'unix':
133:         default:
134:             return "\n";
135:         }
136:     }
137: 
138:     /**
139:      * Returns the full filename including the basename and extension.
140:      *
141:      * @param string $basename  Basename for the file.
142:      *
143:      * @return string  The file name.
144:      */
145:     public function getFilename($basename)
146:     {
147:         return $basename . '.' . $this->_extension;
148:     }
149: 
150:     /**
151:      * Returns the content type.
152:      *
153:      * @return string  The content type.
154:      */
155:     public function getContentType()
156:     {
157:         return $this->_contentType;
158:     }
159: 
160:     /**
161:      * Returns a list of warnings that have been raised during the last
162:      * operation.
163:      *
164:      * @return array  A (possibly empty) list of warnings.
165:      */
166:     public function warnings()
167:     {
168:         return $this->_warnings;
169:     }
170: 
171:     /**
172:      * Maps a date/time string to an associative array.
173:      *
174:      * @param string $date   The date.
175:      * @param string $type   One of 'date', 'time' or 'datetime'.
176:      * @param array $params  Two-dimensional array with additional information
177:      *                       about the formatting. Possible keys are:
178:      *                       - delimiter - The character that seperates the
179:      *                         different date/time parts.
180:      *                       - format - If 'ampm' and $date contains a time we
181:      *                         assume that it is in AM/PM format.
182:      *                       - order - If $type is 'datetime' the order of the
183:      *                         day and time parts: -1 (timestamp), 0
184:      *                         (day/time), 1 (time/day).
185:      * @param integer $key   The key to use for $params.
186:      *
187:      * @return string  The date or time in ISO format.
188:      */
189:     protected function _mapDate($date, $type, $params, $key)
190:     {
191:         switch ($type) {
192:         case 'date':
193:         case 'monthday':
194:         case 'monthdayyear':
195:             $dates = explode($params['delimiter'][$key], $date);
196:             if (count($dates) != 3) {
197:                 return $date;
198:             }
199:             $index = array_flip(explode('/', $params['format'][$key]));
200:             return $dates[$index['year']] . '-' . $dates[$index['month']] . '-' . $dates[$index['mday']];
201: 
202:         case 'time':
203:             $dates = explode($params['delimiter'][$key], $date);
204:             if (count($dates) < 2 || count($dates) > 3) {
205:                 return $date;
206:             }
207:             if ($params['format'][$key] == 'ampm') {
208:                 if (strpos(strtolower($dates[count($dates)-1]), 'pm') !== false) {
209:                     if ($dates[0] !== '12') {
210:                         $dates[0] += 12;
211:                     }
212:                 } elseif ($dates[0] == '12') {
213:                     $dates[0] = '0';
214:                 }
215:                 $dates[count($dates) - 1] = sprintf('%02d', $dates[count($dates)-1]);
216:             }
217:             return $dates[0] . ':' . $dates[1] . (count($dates) == 3 ? (':' . $dates[2]) : ':00');
218: 
219:         case 'datetime':
220:             switch ($params['order'][$key]) {
221:             case -1:
222:                 return (string)(int)$date == $date
223:                     ? date('Y-m-d H:i:s', $date)
224:                     : $date;
225:             case 0:
226:                 list($day, $time) = explode(' ', $date, 2);
227:                 break;
228:             case 1:
229:                list($time, $day) = explode(' ', $date, 2);
230:                break;
231:             }
232:             $date = $this->_mapDate($day, 'date',
233:                                    array('delimiter' => $params['day_delimiter'],
234:                                          'format' => $params['day_format']),
235:                                    $key);
236:             $time = $this->_mapDate($time, 'time',
237:                                    array('delimiter' => $params['time_delimiter'],
238:                                          'format' => $params['time_format']),
239:                                    $key);
240:             return $date . ' ' . $time;
241: 
242:         }
243:     }
244: 
245:     /**
246:      * Takes all necessary actions for the given import step, parameters and
247:      * form values and returns the next necessary step.
248:      *
249:      * @param integer $action  The current step. One of the IMPORT_* constants.
250:      * @param array $param     An associative array containing needed
251:      *                         parameters for the current step.
252:      *
253:      * @return mixed  Either the next step as an integer constant or imported
254:      *                data set after the final step.
255:      * @throws Horde_Data_Exception
256:      */
257:     public function nextStep($action, $param = array())
258:     {
259:         /* First step. */
260:         if (is_null($action)) {
261:             return Horde_Data::IMPORT_FILE;
262:         }
263: 
264:         // TODO - Must be injected
265:         $session = $GLOBALS['injector']->getInstance('Horde_Session');
266: 
267:         switch ($action) {
268:         case Horde_Data::IMPORT_FILE:
269:             if (!isset($this->_browser)) {
270:                 throw new LogicException('Missing browser parameter.');
271:             }
272:             /* Sanitize uploaded file. */
273:             try {
274:                 $this->_browser->wasFileUploaded('import_file', $param['file_types'][$this->_vars->import_format]);
275:             } catch (Horde_Exception $e) {
276:                 throw new Horde_Data_Exception($e);
277:             }
278:             if ($_FILES['import_file']['size'] <= 0) {
279:                 throw new Horde_Data_Exception(Horde_Data_Translation::t("The file contained no data."));
280:             }
281:             $session->set('horde', 'import_data/format', $this->_vars->import_format);
282:             break;
283: 
284:         case Horde_Data::IMPORT_MAPPED:
285:             if (!$this->_vars->dataKeys || !$this->_vars->appKeys) {
286:                 throw new Horde_Data_Exception(Horde_Data_Translation::t("You didn\'t map any fields from the imported file to the corresponding fields."));
287:             }
288:             $dataKeys = explode("\t", $this->_vars->dataKeys);
289:             $appKeys = explode("\t", $this->_vars->appKeys);
290:             $map = array();
291:             $dates = array();
292: 
293:             $import_data = $session->get('horde', 'import_data/data', Horde_Session::TYPE_ARRAY);
294: 
295:             foreach ($appKeys as $key => $app) {
296:                 $map[$dataKeys[$key]] = $app;
297:                 if (isset($param['time_fields']) &&
298:                     isset($param['time_fields'][$app])) {
299:                     $dates[$dataKeys[$key]]['type'] = $param['time_fields'][$app];
300:                     $dates[$dataKeys[$key]]['values'] = array();
301:                     $i = 0;
302:                     /* Build an example array of up to 10 date/time fields. */
303:                     while ($i < count($import_data) &&
304:                            count($dates[$dataKeys[$key]]['values']) < 10) {
305:                         if (!empty($import_data[$i][$dataKeys[$key]])) {
306:                             $dates[$dataKeys[$key]]['values'][] = $import_data[$i][$dataKeys[$key]];
307:                         }
308:                         ++$i;
309:                     }
310:                 }
311:             }
312: 
313:             $session->set('horde', 'import_data/map', $map);
314:             if (count($dates) > 0) {
315:                 foreach ($dates as $key => $data) {
316:                     if (count($data['values'])) {
317:                         $session->set('horde', 'import_data/dates', $dates);
318:                         return Horde_Data::IMPORT_DATETIME;
319:                     }
320:                 }
321:             }
322:             return $this->nextStep(Horde_Data::IMPORT_DATA, $param);
323: 
324:         case Horde_Data::IMPORT_DATETIME:
325:         case Horde_Data::IMPORT_DATA:
326:             if ($action == Horde_Data::IMPORT_DATETIME) {
327:                 $params = array(
328:                     'delimiter' => $this->_vars->delimiter,
329:                     'format' => $this->_vars->format,
330:                     'order' => $this->_vars->order,
331:                     'day_delimiter' => $this->_vars->day_delimiter,
332:                     'day_format' => $this->_vars->day_format,
333:                     'time_delimiter' => $this->_vars->time_delimiter,
334:                     'time_format' => $this->_vars->time_format
335:                 );
336:             }
337: 
338:             if (!$session->exists('horde', 'import_data/data')) {
339:                 throw new Horde_Data_Exception(Horde_Data_Translation::t("The uploaded data was lost since the previous step."));
340:             }
341: 
342:             /* Build the result data set as an associative array. */
343:             $data = array();
344:             $data_map = $session->get('horde', 'import_data/map', Horde_Session::TYPE_ARRAY);
345: 
346:             foreach ($session->get('horde', 'import_data/data') as $row) {
347:                 $data_row = array();
348:                 foreach ($row as $key => $val) {
349:                     if (isset($data_map[$key])) {
350:                         $mapped_key = $data_map[$key];
351:                         if ($action == Horde_Data::IMPORT_DATETIME &&
352:                             !empty($val) &&
353:                             isset($param['time_fields']) &&
354:                             isset($param['time_fields'][$mapped_key])) {
355:                             $val = $this->_mapDate($val, $param['time_fields'][$mapped_key], $params, $key);
356:                         }
357:                         $data_row[$mapped_key] = $val;
358:                     }
359:                 }
360:                 $data[] = $data_row;
361:             }
362: 
363:             return $data;
364:         }
365:     }
366: 
367:     /**
368:      * Cleans the session data up and removes any uploaded and moved
369:      * files.
370:      *
371:      * @return mixed  If callback called, the return value of this call.
372:      *                This should be the value of the first import step.
373:      */
374:     public function cleanup()
375:     {
376:         // TODO - Must be injected
377:         $session = $GLOBALS['injector']->getInstance('Horde_Session');
378: 
379:         if ($filename = $session->get('horde', 'import_data/file_name')) {
380:             @unlink($filename);
381:         }
382:         $session->remove('horde', 'import_data');
383: 
384:         if ($this->_cleanupCallback) {
385:             return call_user_func($this->_cleanupCallback);
386:         }
387:     }
388: 
389: }
390: 
API documentation generated by ApiGen