source: trunk/zpush/lib/syncobjects/syncobject.php @ 7589

Revision 7589, 20.0 KB checked in by douglas, 11 years ago (diff)

Ticket #3209 - Integrar módulo de sincronização Z-push ao Expresso

Line 
1<?php
2/***********************************************
3* File      :   syncobjects.php
4* Project   :   Z-Push
5* Descr     :   Defines general behavoir of sub-WBXML
6*               entities (Sync* objects) that can be parsed
7*               directly (as a stream) from WBXML.
8*               They are automatically decoded
9*               according to $mapping by the Streamer,
10*               and the Sync WBXML mappings.
11*
12* Created   :   01.10.2007
13*
14* Copyright 2007 - 2012 Zarafa Deutschland GmbH
15*
16* This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU Affero General Public License, version 3,
18* as published by the Free Software Foundation with the following additional
19* term according to sec. 7:
20*
21* According to sec. 7 of the GNU Affero General Public License, version 3,
22* the terms of the AGPL are supplemented with the following terms:
23*
24* "Zarafa" is a registered trademark of Zarafa B.V.
25* "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
26* The licensing of the Program under the AGPL does not imply a trademark license.
27* Therefore any rights, title and interest in our trademarks remain entirely with us.
28*
29* However, if you propagate an unmodified version of the Program you are
30* allowed to use the term "Z-Push" to indicate that you distribute the Program.
31* Furthermore you may use our trademarks where it is necessary to indicate
32* the intended purpose of a product or service provided you use it in accordance
33* with honest practices in industrial or commercial matters.
34* If you want to propagate modified versions of the Program under the name "Z-Push",
35* you may only do so if you have a written permission by Zarafa Deutschland GmbH
36* (to acquire a permission please contact Zarafa at trademark@zarafa.com).
37*
38* This program is distributed in the hope that it will be useful,
39* but WITHOUT ANY WARRANTY; without even the implied warranty of
40* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41* GNU Affero General Public License for more details.
42*
43* You should have received a copy of the GNU Affero General Public License
44* along with this program.  If not, see <http://www.gnu.org/licenses/>.
45*
46* Consult LICENSE file for details
47************************************************/
48
49
50abstract class SyncObject extends Streamer {
51    const STREAMER_CHECKS = 6;
52    const STREAMER_CHECK_REQUIRED = 7;
53    const STREAMER_CHECK_ZEROORONE = 8;
54    const STREAMER_CHECK_NOTALLOWED = 9;
55    const STREAMER_CHECK_ONEVALUEOF = 10;
56    const STREAMER_CHECK_SETZERO = "setToValue0";
57    const STREAMER_CHECK_SETONE = "setToValue1";
58    const STREAMER_CHECK_SETTWO = "setToValue2";
59    const STREAMER_CHECK_SETEMPTY = "setToValueEmpty";
60    const STREAMER_CHECK_CMPLOWER = 13;
61    const STREAMER_CHECK_CMPHIGHER = 14;
62    const STREAMER_CHECK_LENGTHMAX = 15;
63    const STREAMER_CHECK_EMAIL   = 16;
64
65    protected $unsetVars;
66
67
68    public function SyncObject($mapping) {
69        $this->unsetVars = array();
70        parent::Streamer($mapping);
71    }
72
73    /**
74     * Sets all supported but not transmitted variables
75     * of this SyncObject to an "empty" value, so they are deleted when being saved
76     *
77     * @param array     $supportedFields        array with all supported fields, if available
78     *
79     * @access public
80     * @return boolean
81     */
82    public function emptySupported($supportedFields) {
83        if ($supportedFields === false || !is_array($supportedFields))
84            return false;
85
86        foreach ($supportedFields as $field) {
87            if (!isset($this->mapping[$field])) {
88                ZLog::Write(LOGLEVEL_WARN, sprintf("Field '%s' is supposed to be emptied but is not defined for '%s'", $field, get_class($this)));
89                continue;
90            }
91            $var = $this->mapping[$field][self::STREAMER_VAR];
92            // add var to $this->unsetVars if $var is not set
93            if (!isset($this->$var))
94                $this->unsetVars[] = $var;
95        }
96        ZLog::Write(LOGLEVEL_DEBUG, sprintf("Supported variables to be unset: %s", implode(',', $this->unsetVars)));
97        return true;
98    }
99
100
101    /**
102     * Compares this a SyncObject to another.
103     * In case that all available mapped fields are exactly EQUAL, it returns true
104     *
105     * @see SyncObject
106     * @param SyncObject $odo other SyncObject
107     * @return boolean
108     */
109    public function equals($odo, $log = false) {
110        if ($odo === false)
111            return false;
112
113        // check objecttype
114        if (! ($odo instanceof SyncObject)) {
115            ZLog::Write(LOGLEVEL_DEBUG, "SyncObject->equals() the target object is not a SyncObject");
116            return false;
117        }
118
119        // check for mapped fields
120        foreach ($this->mapping as $v) {
121            $val = $v[self::STREAMER_VAR];
122            // array of values?
123            if (isset($v[self::STREAMER_ARRAY])) {
124                // seek for differences in the arrays
125                if (is_array($this->$val) && is_array($odo->$val)) {
126                    if (count(array_diff($this->$val, $odo->$val)) + count(array_diff($odo->$val, $this->$val)) > 0) {
127                        ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncObject->equals() items in array '%s' differ", $val));
128                        return false;
129                    }
130                }
131                else {
132                    ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncObject->equals() array '%s' is set in one but not the other object", $val));
133                    return false;
134                }
135            }
136            else {
137                if (isset($this->$val) && isset($odo->$val)) {
138                    if ($this->$val != $odo->$val){
139                        ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncObject->equals() false on field '%s': '%s' != '%s'", $val, Utils::PrintAsString($this->$val), Utils::PrintAsString($odo->$val)));
140                        return false;
141                    }
142                }
143                else if (!isset($this->$val) && !isset($odo->$val)) {
144                    continue;
145                }
146                else {
147                    ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncObject->equals() false because field '%s' is only defined at one obj: '%s' != '%s'", $val, Utils::PrintAsString(isset($this->$val)), Utils::PrintAsString(isset($odo->$val))));
148                    return false;
149                }
150            }
151        }
152
153        return true;
154    }
155
156    /**
157     * String representation of the object
158     *
159     * @return String
160     */
161    public function __toString() {
162        $str = get_class($this) . " (\n";
163
164        $streamerVars = array();
165        foreach ($this->mapping as $k=>$v)
166            $streamerVars[$v[self::STREAMER_VAR]] = (isset($v[self::STREAMER_TYPE]))?$v[self::STREAMER_TYPE]:false;
167
168        foreach (get_object_vars($this) as $k=>$v) {
169            if ($k == "mapping") continue;
170
171            if (array_key_exists($k, $streamerVars))
172                $strV = "(S) ";
173            else
174                $strV = "";
175
176            // self::STREAMER_ARRAY ?
177            if (is_array($v)) {
178                $str .= "\t". $strV . $k ."(Array) size: " . count($v) ."\n";
179                foreach ($v as $value) $str .= "\t\t". Utils::PrintAsString($value) ."\n";
180            }
181            else if ($v instanceof SyncObject) {
182                $str .= "\t". $strV .$k ." => ". str_replace("\n", "\n\t\t\t", $v->__toString()) . "\n";
183            }
184            else
185                $str .= "\t". $strV .$k ." => " . (isset($this->$k)? Utils::PrintAsString($this->$k) :"null") . "\n";
186        }
187        $str .= ")";
188
189        return $str;
190    }
191
192    /**
193     * Returns the properties which have to be unset on the server
194     *
195     * @access public
196     * @return array
197     */
198    public function getUnsetVars() {
199        return $this->unsetVars;
200    }
201
202    /**
203     * Method checks if the object has the minimum of required parameters
204     * and fullfills semantic dependencies
205     *
206     * General checks:
207     *     STREAMER_CHECK_REQUIRED      may have as value false (do not fix, ignore object!) or set-to-values: STREAMER_CHECK_SETZERO/ONE/TWO, STREAMER_CHECK_SETEMPTY
208     *     STREAMER_CHECK_ZEROORONE     may be 0 or 1, if none of these, set-to-values: STREAMER_CHECK_SETZERO or STREAMER_CHECK_SETONE
209     *     STREAMER_CHECK_NOTALLOWED    fails if is set
210     *     STREAMER_CHECK_ONEVALUEOF    expects an array with accepted values, fails if value is not in array
211     *
212     * Comparison:
213     *     STREAMER_CHECK_CMPLOWER      compares if the current parameter is lower as a literal or another parameter of the same object
214     *     STREAMER_CHECK_CMPHIGHER     compares if the current parameter is higher as a literal or another parameter of the same object
215     *
216     * @param boolean   $logAsDebug     (opt) default is false, so messages are logged in WARN log level
217     *
218     * @access public
219     * @return boolean
220     */
221    public function Check($logAsDebug = false) {
222        // semantic checks general "turn off switch"
223        if (defined("DO_SEMANTIC_CHECKS") && DO_SEMANTIC_CHECKS === false) {
224            ZLog::Write(LOGLEVEL_DEBUG, "SyncObject->Check(): semantic checks disabled. Check your config for 'DO_SEMANTIC_CHECKS'.");
225            return true;
226        }
227
228        $defaultLogLevel = LOGLEVEL_WARN;
229
230        // in some cases non-false checks should not provoke a WARN log but only a DEBUG log
231        if ($logAsDebug)
232            $defaultLogLevel = LOGLEVEL_DEBUG;
233
234        $objClass = get_class($this);
235        foreach ($this->mapping as $k=>$v) {
236
237            // check sub-objects recursively
238            if (isset($v[self::STREAMER_TYPE]) && isset($this->$v[self::STREAMER_VAR])) {
239                if ($this->$v[self::STREAMER_VAR] instanceof SyncObject) {
240                    if (! $this->$v[self::STREAMER_VAR]->Check($logAsDebug))
241                        return false;
242                }
243                else if (is_array($this->$v[self::STREAMER_VAR])) {
244                    foreach ($this->$v[self::STREAMER_VAR] as $subobj)
245                        if ($subobj instanceof SyncObject && !$subobj->Check($logAsDebug))
246                            return false;
247                }
248            }
249
250            if (isset($v[self::STREAMER_CHECKS])) {
251                foreach ($v[self::STREAMER_CHECKS] as $rule => $condition) {
252                    // check REQUIRED settings
253                    if ($rule === self::STREAMER_CHECK_REQUIRED && (!isset($this->$v[self::STREAMER_VAR]) || $this->$v[self::STREAMER_VAR] === '' ) ) {
254                        // parameter is not set but ..
255                        // requested to set to 0
256                        if ($condition === self::STREAMER_CHECK_SETZERO) {
257                            $this->$v[self::STREAMER_VAR] = 0;
258                            ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Fixed object from type %s: parameter '%s' is set to 0", $objClass, $v[self::STREAMER_VAR]));
259                        }
260                        // requested to be set to 1
261                        else if ($condition === self::STREAMER_CHECK_SETONE) {
262                            $this->$v[self::STREAMER_VAR] = 1;
263                            ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Fixed object from type %s: parameter '%s' is set to 1", $objClass, $v[self::STREAMER_VAR]));
264                        }
265                        // requested to be set to 2
266                        else if ($condition === self::STREAMER_CHECK_SETTWO) {
267                            $this->$v[self::STREAMER_VAR] = 2;
268                            ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Fixed object from type %s: parameter '%s' is set to 2", $objClass, $v[self::STREAMER_VAR]));
269                        }
270                        // requested to be set to ''
271                        else if ($condition === self::STREAMER_CHECK_SETEMPTY) {
272                            if (!isset($this->$v[self::STREAMER_VAR])) {
273                                $this->$v[self::STREAMER_VAR] = '';
274                                ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Fixed object from type %s: parameter '%s' is set to ''", $objClass, $v[self::STREAMER_VAR]));
275                            }
276                        }
277                        // there is another value !== false
278                        else if ($condition !== false) {
279                            $this->$v[self::STREAMER_VAR] = $condition;
280                            ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Fixed object from type %s: parameter '%s' is set to '%s'", $objClass, $v[self::STREAMER_VAR], $condition));
281
282                        }
283                        // no fix available!
284                        else {
285                            ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Unmet condition in object from type %s: parameter '%s' is required but not set. Check failed!", $objClass, $v[self::STREAMER_VAR]));
286                            return false;
287                        }
288                    } // end STREAMER_CHECK_REQUIRED
289
290
291                    // check STREAMER_CHECK_ZEROORONE
292                    if ($rule === self::STREAMER_CHECK_ZEROORONE && isset($this->$v[self::STREAMER_VAR])) {
293                        if ($this->$v[self::STREAMER_VAR] != 0 && $this->$v[self::STREAMER_VAR] != 1) {
294                            $newval = $condition === self::STREAMER_CHECK_SETZERO ? 0:1;
295                            $this->$v[self::STREAMER_VAR] = $newval;
296                            ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Fixed object from type %s: parameter '%s' is set to '%s' as it was not 0 or 1", $objClass, $v[self::STREAMER_VAR], $newval));
297                        }
298                    }// end STREAMER_CHECK_ZEROORONE
299
300
301                    // check STREAMER_CHECK_ONEVALUEOF
302                    if ($rule === self::STREAMER_CHECK_ONEVALUEOF && isset($this->$v[self::STREAMER_VAR])) {
303                        if (!in_array($this->$v[self::STREAMER_VAR], $condition)) {
304                            ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): object from type %s: parameter '%s'->'%s' is not in the range of allowed values.", $objClass, $v[self::STREAMER_VAR], $this->$v[self::STREAMER_VAR]));
305                            return false;
306                        }
307                    }// end STREAMER_CHECK_ONEVALUEOF
308
309
310                    // Check value compared to other value or literal
311                    if ($rule === self::STREAMER_CHECK_CMPHIGHER || $rule === self::STREAMER_CHECK_CMPLOWER) {
312                        if (isset($this->$v[self::STREAMER_VAR])) {
313                            $cmp = false;
314                            // directly compare against literals
315                            if (is_int($condition)) {
316                                $cmp = $condition;
317                            }
318                            // check for invalid compare-to
319                            else if (!isset($this->mapping[$condition])) {
320                                ZLog::Write(LOGLEVEL_ERROR, sprintf("SyncObject->Check(): Can not compare parameter '%s' against the other value '%s' as it is not defined object from type %s. Please report this! Check skipped!", $objClass, $v[self::STREAMER_VAR], $condition));
321                                continue;
322                            }
323                            else {
324                                $cmpPar = $this->mapping[$condition][self::STREAMER_VAR];
325                                if (isset($this->$cmpPar))
326                                    $cmp = $this->$cmpPar;
327                            }
328
329                            if ($cmp === false) {
330                                ZLog::Write(LOGLEVEL_WARN, sprintf("SyncObject->Check(): Unmet condition in object from type %s: parameter '%s' can not be compared, as the comparable is not set. Check failed!", $objClass, $v[self::STREAMER_VAR]));
331                                return false;
332                            }
333                            if ( ($rule == self::STREAMER_CHECK_CMPHIGHER && $this->$v[self::STREAMER_VAR] < $cmp) ||
334                                 ($rule == self::STREAMER_CHECK_CMPLOWER  && $this->$v[self::STREAMER_VAR] > $cmp)
335                                ) {
336
337                                ZLog::Write(LOGLEVEL_WARN, sprintf("SyncObject->Check(): Unmet condition in object from type %s: parameter '%s' is %s than '%s'. Check failed!",
338                                                                    $objClass,
339                                                                    $v[self::STREAMER_VAR],
340                                                                    (($rule === self::STREAMER_CHECK_CMPHIGHER)?'LOWER':'HIGHER'),
341                                                                    ((isset($cmpPar)?$cmpPar:$condition))  ));
342                                return false;
343                            }
344                        }
345                    } // STREAMER_CHECK_CMP*
346
347
348                    // check STREAMER_CHECK_LENGTHMAX
349                    if ($rule === self::STREAMER_CHECK_LENGTHMAX && isset($this->$v[self::STREAMER_VAR])) {
350
351                        if (is_array($this->$v[self::STREAMER_VAR])) {
352                            // implosion takes 2bytes, so we just assume ", " here
353                            $chkstr = implode(", ", $this->$v[self::STREAMER_VAR]);
354                        }
355                        else
356                            $chkstr = $this->$v[self::STREAMER_VAR];
357
358                        if (strlen($chkstr) > $condition) {
359                            ZLog::Write(LOGLEVEL_WARN, sprintf("SyncObject->Check(): object from type %s: parameter '%s' is longer than %d. Check failed", $objClass, $v[self::STREAMER_VAR], $condition));
360                            return false;
361                        }
362                    }// end STREAMER_CHECK_LENGTHMAX
363
364
365                    // check STREAMER_CHECK_EMAIL
366                    // if $condition is false then the check really fails. Otherwise invalid emails are removed.
367                    // if nothing is left (all emails were false), the parameter is set to condition
368                    if ($rule === self::STREAMER_CHECK_EMAIL && isset($this->$v[self::STREAMER_VAR])) {
369                        if ($condition === false && ( (is_array($this->$v[self::STREAMER_VAR]) && empty($this->$v[self::STREAMER_VAR])) || strlen($this->$v[self::STREAMER_VAR]) == 0) )
370                            continue;
371
372                        $as_array = false;
373
374                        if (is_array($this->$v[self::STREAMER_VAR])) {
375                            $mails = $this->$v[self::STREAMER_VAR];
376                            $as_array = true;
377                        }
378                        else {
379                            $mails = array( $this->$v[self::STREAMER_VAR] );
380                        }
381
382                        $output = array();
383                        foreach ($mails as $mail) {
384                            if (! Utils::CheckEmail($mail)) {
385                                ZLog::Write(LOGLEVEL_WARN, sprintf("SyncObject->Check(): object from type %s: parameter '%s' contains an invalid email address '%s'. Address is removed.", $objClass, $v[self::STREAMER_VAR], $mail));
386                            }
387                            else
388                                $output[] = $mail;
389                        }
390                        if (count($mails) != count($output)) {
391                            if ($condition === false)
392                                return false;
393
394                            // nothing left, use $condition as new value
395                            if (count($output) == 0)
396                                $output[] = $condition;
397
398                            // if we are allowed to rewrite the attribute, we do that
399                            if ($as_array)
400                                $this->$v[self::STREAMER_VAR] = $output;
401                            else
402                                $this->$v[self::STREAMER_VAR] = $output[0];
403                        }
404                    }// end STREAMER_CHECK_EMAIL
405
406
407                } // foreach CHECKS
408            } // isset CHECKS
409        } // foreach mapping
410
411        return true;
412    }
413}
414
415?>
Note: See TracBrowser for help on using the repository browser.