#5024: allow to attach external files to records
[tine20] / tine20 / Tinebase / Convert / Json.php
1 <?php
2 /**
3  * convert functions for records from/to json (array) format
4  * 
5  * @package     Tinebase
6  * @subpackage  Convert
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @author      Philipp Schüle <p.schuele@metaways.de>
9  * @copyright   Copyright (c) 2011-2012 Metaways Infosystems GmbH (http://www.metaways.de)
10  */
11
12 /**
13  * convert functions for records from/to json (array) format
14  *
15  * @package     Tinebase
16  * @subpackage  Convert
17  */
18 class Tinebase_Convert_Json implements Tinebase_Convert_Interface
19 {
20     /**
21      * converts external format to Tinebase_Record_Abstract
22      * 
23      * @param  mixed                     $_blob   the input data to parse
24      * @param  Tinebase_Record_Abstract  $_record  update existing record
25      * @return Tinebase_Record_Abstract
26      */
27     public function toTine20Model($_blob, Tinebase_Record_Abstract $_record = NULL)
28     {
29         throw new Tinebase_Exception_NotImplemented('From json to record is not implemented yet');
30     }
31     
32     /**
33      * converts Tinebase_Record_Abstract to external format
34      * 
35      * @param  Tinebase_Record_Abstract $_record
36      * @return mixed
37      */
38     public function fromTine20Model(Tinebase_Record_Abstract $_record)
39     {
40         if (! $_record) {
41             return array();
42         }
43         
44         // for resolving we'll use recordset
45         $records = new Tinebase_Record_RecordSet(get_class($_record), array($_record));
46         
47         Tinebase_Frontend_Json_Abstract::resolveContainerTagsUsers($records);
48         self::resolveMultipleIdFields($records);
49         
50         $_record = $records->getFirstRecord();
51         
52         $_record->setTimezone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
53         $_record->bypassFilters = true;
54         
55         return $_record->toArray();
56     }
57
58     /**
59      * resolves multiple records
60      * 
61      * @param Tinebase_Record_RecordSet $records the records
62      * @param array $resolveFields
63      */
64     public static function resolveMultipleIdFields($records, $resolveFields = NULL)
65     {
66         if (! $records instanceof Tinebase_Record_RecordSet) {
67             return;
68         }
69         
70         $ownRecordClass = $records->getRecordClassName();
71         if ($resolveFields === NULL) {
72             $resolveFields = $ownRecordClass::getResolveForeignIdFields();
73         }
74         
75         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ 
76             . ' Resolving ' . $ownRecordClass . ' fields: ' . print_r($resolveFields, TRUE));
77         
78         foreach ((array) $resolveFields as $foreignRecordClassName => $fields) {
79             if ($foreignRecordClassName === 'recursive') {
80                 foreach ($fields as $field => $model) {
81                     foreach ($records->$field as $subRecords) {
82                         self::resolveMultipleIdFields($subRecords);
83                     }
84                 }
85             } else {
86                 self::_resolveForeignIdFields($records, $foreignRecordClassName, (array) $fields);
87             }
88         }
89     }
90     
91     /**
92      * resolve foreign fields for records
93      * 
94      * @param Tinebase_Record_RecordSet $records
95      * @param string $foreignRecordClassName
96      * @param array $fields
97      */
98     protected static function _resolveForeignIdFields($records, $foreignRecordClassName, $fields)
99     {
100         $options = array_key_exists('options', $fields) ? $fields['options'] : array();
101         $fields = array_key_exists('fields', $fields) ? $fields['fields'] : $fields;
102         
103         $foreignIds = array();
104         foreach ($fields as $field) {
105             $foreignIds = array_unique(array_merge($foreignIds, $records->{$field}));
106         }
107         
108         if (! Tinebase_Core::getUser()->hasRight(substr($foreignRecordClassName, 0, strpos($foreignRecordClassName, "_")), Tinebase_Acl_Rights_Abstract::RUN)) {
109             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ 
110                 . ' Not resolving ' . $foreignRecordClassName . ' records because user has no right to run app.');
111             return;
112         }
113         
114         $controller = Tinebase_Core::getApplicationInstance($foreignRecordClassName);
115         
116         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ 
117             . ' Fetching ' . $foreignRecordClassName . ' by id: ' . print_r($foreignIds, TRUE));
118         
119         if (array_key_exists('ignoreAcl', $options) && $options['ignoreAcl']) {
120             // @todo make sure that second param of getMultiple() is $ignoreAcl
121             $foreignRecords = $controller->getMultiple($foreignIds, TRUE);
122         } else {
123             $foreignRecords = $controller->getMultiple($foreignIds);
124         }
125         
126         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ 
127             . ' Foreign records found: ' . print_r($foreignRecords->toArray(), TRUE));
128         
129         if (count($foreignRecords) === 0) {
130             return;
131         }
132         
133         foreach ($records as $record) {
134             foreach ($fields as $field) {
135                 if (is_scalar($record->{$field})) {
136                     $idx = $foreignRecords->getIndexById($record->{$field});
137                     if (isset($idx) && $idx !== FALSE) {
138                         $record->{$field} = $foreignRecords[$idx];
139                     } else {
140                         switch ($foreignRecordClassName) {
141                             case 'Tinebase_Model_User':
142                             case 'Tinebase_Model_FullUser':
143                                 $record->{$field} = Tinebase_User::getInstance()->getNonExistentUser();
144                                 break;
145                             default:
146                                 // skip
147                         }
148                     }
149                 }
150             }
151         }
152     }
153     
154     /**
155      * converts Tinebase_Record_RecordSet to external format
156      * 
157      * @param  Tinebase_Record_RecordSet  $_records
158      * @param Tinebase_Model_Filter_FilterGroup $_filter
159      * @param Tinebase_Model_Pagination $_pagination
160      * 
161      * @return mixed
162      */
163     public function fromTine20RecordSet(Tinebase_Record_RecordSet $_records, $_filter = NULL, $_pagination = NULL)
164     {
165         if (count($_records) == 0) {
166             return array();
167         }
168
169         Tinebase_Frontend_Json_Abstract::resolveContainerTagsUsers($_records);
170
171         self::resolveMultipleIdFields($_records);
172
173         $_records->setTimezone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
174         $_records->convertDates = true;
175
176         $result = $_records->toArray();
177
178         return $result;
179     }
180 }