fa7a00c80776b3e8473ace2ca1dcfb4342102a38
[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-2013 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         
49         // use modern record resolving, if the model was configured using Tinebase_ModelConfiguration
50         // at first, resolve all single record fields
51         $this->_resolveSingleRecordFields($records);
52         // next step, resolve all multiple records fields
53         $this->_resolveMultipleRecordFields($records);
54         
55         // resolve the traditional way, if model hasn't been configured with Tinebase_ModelConfiguration
56         $this->_resolveMultipleIdFields($records);
57         
58         $_record = $records->getFirstRecord();
59         $_record->setTimezone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
60         $_record->bypassFilters = true;
61         
62         return $_record->toArray();
63     }
64
65     /**
66      * resolves single record fields (Tinebase_ModelConfiguration._recordsFields)
67      * 
68      * @param Tinebase_Record_RecordSet $_records the records
69      */
70     protected function _resolveSingleRecordFields(Tinebase_Record_RecordSet $_records)
71     {
72         $ownRecordClass = $_records->getRecordClassName();
73         
74         if (! $cfg = $ownRecordClass::getConfiguration()) {
75             return;
76         }
77         $resolveFields = $cfg->recordFields;
78         if ($resolveFields && is_array($resolveFields)) {
79             // don't search twice if the same recordClass gets resolved on multiple fields
80             foreach ($resolveFields as $fieldKey => $fieldConfig) {
81                 $resolveRecords[$fieldConfig['config']['recordClassName']][] = $fieldKey;
82             }
83             
84             foreach ($resolveRecords as $foreignRecordClassName => $fields) {
85                 $foreignIds = array();
86                 $fields = (array) $fields;
87                 
88                 foreach($fields as $field) {
89                     $foreignIds = array_unique(array_merge($foreignIds, $_records->{$field}));
90                 }
91                 
92                 if (! Tinebase_Core::getUser()->hasRight(substr($foreignRecordClassName, 0, strpos($foreignRecordClassName, "_")), Tinebase_Acl_Rights_Abstract::RUN)) {
93                     continue;
94                 }
95                 
96                 $cfg = $resolveFields[$fields[0]];
97                 
98                 if ($cfg['type'] == 'user') {
99                     $foreignRecords = Tinebase_User::getInstance()->getUsers();
100                 } elseif ($cfg['type'] == 'container') {
101                     $foreignRecords = new Tinebase_Record_RecordSet('Tinebase_Model_Container');
102                     $foreignRecords->addRecord(Tinebase_Container::getInstance()->get($_id));
103                 // TODO: resolve recursive records of records better in controller
104                 // TODO: resolve containers
105                 } else {
106                     $controller = array_key_exists('controllerClassName', $cfg['config']) ? $cfg['config']['controllerClassName']::getInstance() : Tinebase_Core::getApplicationInstance($foreignRecordClassName);
107                     $foreignRecords = $controller->getMultiple($foreignIds);
108                 }
109                 
110                 $foreignRecords->setTimezone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
111                 $foreignRecords->convertDates = true;
112                 Tinebase_Frontend_Json_Abstract::resolveContainerTagsUsers($foreignRecords);
113                 $fr = $foreignRecords->getFirstRecord();
114                 if ($fr && $fr->has('notes')) {
115                     Tinebase_Notes::getInstance()->getMultipleNotesOfRecords($foreignRecords);
116                 }
117                 
118                 if ($foreignRecords->count()) {
119                     foreach ($_records as $record) {
120                         foreach ($fields as $field) {
121                             $idx = $foreignRecords->getIndexById($record->{$field});
122                             if (isset($idx) && $idx !== FALSE) {
123                                 $record->{$field} = $foreignRecords[$idx];
124                             }
125                         }
126                     }
127                 }
128             }
129         }
130     }
131     
132     /**
133      * resolves multiple records (fallback)
134      * 
135      * @deprecated use Tinebase_ModelConfiguration to configure your models, so this won't be used anymore 
136      * @param Tinebase_Record_RecordSet $_records the records
137      */
138     protected function _resolveMultipleIdFields(Tinebase_Record_RecordSet $_records)
139     {
140         $ownRecordClass = $_records->getRecordClassName();
141         if (! $resolveFields = $ownRecordClass::getResolveForeignIdFields()) {
142             return;
143         }
144         
145         foreach ($resolveFields as $foreignRecordClassName => $fields) {
146             $foreignIds = array();
147             $fields = (array) $fields;
148     
149             foreach ($fields as $field) {
150                 $foreignIds = array_unique(array_merge($foreignIds, $_records->{$field}));
151             }
152     
153             if (! Tinebase_Core::getUser()->hasRight(substr($foreignRecordClassName, 0, strpos($foreignRecordClassName, "_")), Tinebase_Acl_Rights_Abstract::RUN))
154                 continue;
155     
156             $controller = Tinebase_Core::getApplicationInstance($foreignRecordClassName);
157     
158             if (method_exists($controller, 'modlogActive')) {
159                 $modlogActive = $controller->modlogActive(FALSE);
160             }
161             $foreignRecords = $controller->getMultiple($foreignIds);
162             $foreignRecords->setTimezone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
163             $foreignRecords->convertDates = true;
164             
165             if ($foreignRecords->count()) {
166                 foreach ($_records as $record) {
167                     foreach ($fields as $field) {
168                         $idx = $foreignRecords->getIndexById($record->{$field});
169                         if (isset($idx) && $idx !== FALSE) {
170                             $record->{$field} = $foreignRecords[$idx];
171                         }
172                     }
173                 }
174             }
175         }
176     }
177     
178     /**
179      * resolve multiple record fields (Tinebase_ModelConfiguration._recordsFields)
180      * 
181      * @param Tinebase_Record_RecordSet $_records
182      */
183     protected function _resolveMultipleRecordFields(Tinebase_Record_RecordSet $_records)
184     {
185         // show if there is something to resolve
186         $ownRecordClass = $_records->getRecordClassName();
187         
188         if (! $_records->count()) {
189             return;
190         }
191         
192         if (! (($config = $ownRecordClass::getConfiguration()) && ($resolveFields = $config->recordsFields))) {
193             return;
194         }
195         
196         $ownIds = $_records->{$config->idProperty};
197         
198         // iterate fields to resolve
199         foreach ($resolveFields as $fieldKey => $c) {
200             $config = $c['config'];
201             // fetch the fields by the refIfField
202             $controller = array_key_exists('controllerClassName', $config) ? $config['controllerClassName']::getInstance() : Tinebase_Core::getApplicationInstance($foreignRecordClassName);
203             $filterName = $config['filterClassName'];
204             
205             $filterArray = array();
206             
207             // addFilters can be added and must be added if the same model resides in more than one records fields
208             if (array_key_exists('addFilters', $config) && is_array($config['addFilters'])) {
209                 $useaddFilters = true;
210                 $filterArray = $config['addFilters'];
211             }
212             
213             $filter = new $filterName($filterArray);
214             $filter->addFilter(new Tinebase_Model_Filter_Id(array('field' => $config['refIdField'], 'operator' => 'in', 'value' => $ownIds)));
215             
216             $paging = NULL;
217             if (array_key_exists('paging', $config) && is_array($config['paging'])) {
218                 $paging = new Tinebase_Model_Pagination($config['paging']);
219             }
220             
221             $foreignRecords = $controller->search($filter, $paging);
222             $foreignRecords->setTimezone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
223             $foreignRecords->convertDates = true;
224             Tinebase_Frontend_Json_Abstract::resolveContainerTagsUsers($foreignRecords);
225             $fr = $foreignRecords->getFirstRecord();
226             if ($fr && $fr->has('notes')) {
227                 Tinebase_Notes::getInstance()->getMultipleNotesOfRecords($foreignRecords);
228             }
229             if ($foreignRecords->count() > 0) {
230                 foreach ($_records as $record) {
231                     $filtered = $foreignRecords->filter($config['refIdField'], $record->getId());
232                     $record->{$fieldKey} = $filtered->toArray();
233                 }
234             } else {
235                 $_records->{$fieldKey} = NULL;
236             }
237         }
238         
239     }
240     
241     /**
242      * converts Tinebase_Record_RecordSet to external format
243      * 
244      * @param  Tinebase_Record_RecordSet  $_records
245      * @param Tinebase_Model_Filter_FilterGroup $_filter
246      * @param Tinebase_Model_Pagination $_pagination
247      * 
248      * @return mixed
249      */
250     public function fromTine20RecordSet(Tinebase_Record_RecordSet $_records, $_filter = NULL, $_pagination = NULL)
251     {
252         if (count($_records) == 0) {
253             return array();
254         }
255         
256         Tinebase_Frontend_Json_Abstract::resolveContainerTagsUsers($_records);
257
258         $this->_resolveMultipleIdFields($_records);
259         $this->_resolveSingleRecordFields($_records);
260         $this->_resolveMultipleRecordFields($_records);
261
262         $_records->setTimezone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
263         $_records->convertDates = true;
264
265         $result = $_records->toArray();
266
267         return $result;
268     }
269 }