1<?php
2/**
3 * The base class representing Kolab objects stored in the server
4 * database.
5 *
6 * PHP version 5
7 *
8 * @category Kolab
9 * @package  Kolab_Server
10 * @author   Gunnar Wrobel <wrobel@pardus.de>
11 * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
12 * @link     http://pear.horde.org/index.php?package=Kolab_Server
13 */
14
15/**
16 * This class provides methods to deal with Kolab objects stored in
17 * the Kolab db.
18 *
19 * Copyright 2008-2016 Horde LLC (http://www.horde.org/)
20 *
21 * See the enclosed file COPYING for license information (LGPL). If you
22 * did not receive this file, see http://www.horde.org/licenses/lgpl21.
23 *
24 * @category Kolab
25 * @package  Kolab_Server
26 * @author   Gunnar Wrobel <wrobel@pardus.de>
27 * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
28 * @link     http://pear.horde.org/index.php?package=Kolab_Server
29 */
30abstract class Horde_Kolab_Server_Object_Base
31implements Horde_Kolab_Server_Object_Interface
32{
33    /**
34     * Link to the Kolab server.
35     *
36     * @var Horde_Kolab_Server_Composite
37     */
38    private $_composite;
39
40    /**
41     * GUID of this object on the Kolab server.
42     *
43     * @var string
44     */
45    protected $guid;
46
47    /**
48     * Initialize the Kolab Object. Provide either the GUID
49     *
50     * @param Horde_Kolab_Server_Composite $composite The link to the Kolab server.
51     * @param string                       $guid      GUID of the object.
52     */
53    public function __construct(
54        Horde_Kolab_Server_Composite $composite,
55        $guid = null
56    ) {
57        $this->_composite = $composite;
58        $this->guid       = $guid;
59    }
60
61    /**
62     * Get the GUID of this object
63     *
64     * @return string the GUID of this object
65     */
66    public function getGuid()
67    {
68        if ($this->guid === null) {
69            throw new Horde_Kolab_Server_Exception(
70                'Uninitialized object is missing GUID!'
71            );
72        }
73        return $this->guid;
74    }
75
76    /**
77     * Get the external attributes supported by this object.
78     *
79     * @return array The external attributes supported by this object. This is a
80     * list of abbreviated attribute class names.
81     */
82    public function getExternalAttributes()
83    {
84        return $this->_composite->structure->getExternalAttributes($this);
85    }
86
87    /**
88     * Get the internal attributes supported by this object.
89     *
90     * @return array The internal attributes supported by this object.
91     */
92    public function getInternalAttributes()
93    {
94        return $this->_composite->structure->getInternalAttributes($this);
95    }
96
97    /**
98     * Does the object exist?
99     *
100     * @return boolean True if the object exists, false otherwise.
101     */
102    public function exists()
103    {
104        try {
105            $this->readInternal();
106            return true;
107        } catch (Horde_Kolab_Server_Exception $e) {
108            return false;
109        }
110    }
111
112    /**
113     * Read the object data.
114     *
115     * @return array The read data.
116     */
117    public function readInternal()
118    {
119        return $this->_composite->server->readAttributes(
120            $this->getGuid(), $this->getInternalAttributes()
121        );
122    }
123
124    /**
125     * Get the specified internal attributes.
126     *
127     * @param array $attributes The internal attribute.
128     *
129     * @return array The value(s) of these attribute
130     */
131    public function getInternal(array $attributes)
132    {
133        $result = $this->readInternal();
134
135        $values = array();
136        foreach ($attributes as $attribute) {
137
138            if (!isset($result[$attribute])) {
139                throw new Horde_Kolab_Server_Exception_Novalue(
140                    sprintf(
141                        "No value for attribute \"%s\"!",
142                        $attribute
143                    )
144                );
145            }
146            $values[$attribute] = $result[$attribute];
147        }
148        return $values;
149    }
150
151    /**
152     * Get the specified attribute of this object.
153     *
154     * @param string $attr The attribute to read.
155     *
156     * @return mixed The value of this attribute.
157     */
158    public function getExternal($attr)
159    {
160        if (!in_array($attr, $this->getExternalAttributes())) {
161            throw new Horde_Kolab_Server_Exception(
162                sprintf("Attribute \"%s\" not supported!", $attr)
163            );
164        }
165        $attribute = $this->_composite->structure->getExternalAttribute(
166            $attr, $this
167        );
168        return $attribute->value();
169    }
170
171    /**
172     * Saves object information. This may either create a new entry or modify an
173     * existing entry.
174     *
175     * Please note that fields with multiple allowed values require the callee
176     * to provide the full set of values for the field. Any old values that are
177     * not resubmitted will be considered to be deleted.
178     *
179     * @param array $info The information about the object.
180     *
181     * @return NULL
182     *
183     * @throws Horde_Kolab_Server_Exception If saving the data failed.
184     */
185    public function save(array $info)
186    {
187        /** Handle all class specific transformations of the provided data */
188        $this->prepareObjectInformation($info);
189
190        $internal = $this->getNewInternal($info);
191
192        $guid = $this->_composite->structure->generateServerGuid(
193            get_class($this), $this->generateId($internal), $internal
194        );
195
196        if ($this->exists()) {
197            if ($guid != $this->guid) {
198                $this->_composite->server->rename($this->guid, $guid);
199                $this->guid = $guid;
200            }
201            $result = $this->_composite->server->save($this, $internal);
202        } else {
203            $this->guid = $guid;
204            $this->_composite->server->add($this, $internal);
205        }
206    }
207
208    /**
209     * Transform the given data array into the new internal dataset.
210     *
211     * @param array $info The information about the object.
212     *
213     * @return NULL
214     *
215     * @throws Horde_Kolab_Server_Exception If transforming the data failed.
216     */
217    protected function getNewInternal($info)
218    {
219        $internal   = array();
220        foreach ($info as $external => $value) {
221            $attribute = $this->_composite->structure->getExternalAttribute(
222                $external, $this
223            );
224            $internal = array_merge($internal, $attribute->update($info));
225        }
226        return $internal;
227    }
228
229    /**
230     * Delete this object.
231     *
232     * @return NULL
233     *
234     * @throws Horde_Kolab_Server_Exception If deleting the object failed.
235     */
236    public function delete()
237    {
238        $this->_composite->server->delete($this->getGuid());
239    }
240}
241