1<?php
2/**
3 * Extension of the Horde_Share_Object class for storing share information in
4 * the Sqlng driver.
5 *
6 * @author  Jan Schneider <jan@horde.org>
7 * @package Share
8 */
9class Horde_Share_Object_Sqlng extends Horde_Share_Object_Sql
10{
11    /**
12     * Serializable version.
13     */
14    const VERSION = 1;
15
16    /**
17     * A list of available permission.
18     *
19     * This is necessary to unset certain permission when updating existing
20     * share objects.
21     *
22     * @param array
23     */
24    public $availablePermissions = array();
25
26    /**
27     * Constructor.
28     *
29     * @param array $data Share data array.
30     */
31    public function __construct($data)
32    {
33        parent::__construct($data);
34        $this->_setAvailablePermissions();
35    }
36
37    /**
38     * Serialize this object.
39     *
40     * @return string  The serialized data.
41     */
42    public function serialize()
43    {
44        return serialize(array(
45            self::VERSION,
46            $this->data,
47            $this->_shareCallback,
48            $this->availablePermissions,
49        ));
50    }
51
52    /**
53     * Reconstruct the object from serialized data.
54     *
55     * @param string $data  The serialized data.
56     */
57    public function unserialize($data)
58    {
59        $data = @unserialize($data);
60        if (!is_array($data) ||
61            !isset($data[0]) ||
62            ($data[0] != self::VERSION)) {
63            throw new Exception('Cache version change');
64        }
65
66        $this->data = $data[1];
67        if (empty($data[2])) {
68            throw new Exception('Missing callback for Horde_Share_Object unserializing');
69        }
70        $this->_shareCallback = $data[2];
71        $this->availablePermissions = $data[3];
72    }
73
74    /**
75     * Saves the current attribute values.
76     */
77    protected function _save()
78    {
79        $db = $this->getShareOb()->getStorage();
80        $table = $this->getShareOb()->getTable();
81
82        // Build the parameter arrays for the sql statement.
83        $fields = $params = array();
84        foreach ($this->getShareOb()->toDriverCharset($this->data) as $key => $value) {
85            if ($key != 'share_id' && $key != 'perm' && $key != 'share_flags') {
86                $fields[] = $key;
87                $params[] = $value;
88            }
89        }
90
91        $fields[] = 'share_flags';
92        $flags = 0;
93        if (!empty($this->data['perm']['users'])) {
94            $flags |= Horde_Share_Sql::SQL_FLAG_USERS;
95        }
96        if (!empty($this->data['perm']['groups'])) {
97            $flags |= Horde_Share_Sql::SQL_FLAG_GROUPS;
98        }
99        $params[] = $flags;
100
101        // Insert new share record, or update existing
102        if (empty($this->data['share_id'])) {
103            foreach ($this->data['perm'] as $base => $perms) {
104                if ($base == 'type' || $base == 'users' || $base == 'groups') {
105                    continue;
106                }
107                foreach (Horde_Share_Sqlng::convertBitmaskToArray($perms) as $perm) {
108                    $fields[] = 'perm_' . $base . '_' . $perm;
109                    $params[] = true;
110                }
111            }
112            $sql = 'INSERT INTO ' . $table . ' (' . implode(', ', $fields) . ') VALUES (?' . str_repeat(', ?', count($fields) - 1) . ')';
113            try {
114                $this->data['share_id'] = $db->insert($sql, $params);
115            } catch (Horde_Db_Exception $e) {
116                throw new Horde_Share_Exception($e);
117            }
118        } else {
119            foreach ($this->data['perm'] as $base => $perms) {
120                if ($base == 'type' || $base == 'users' || $base == 'groups') {
121                    continue;
122                }
123                $perms = array_flip(Horde_Share_Sqlng::convertBitmaskToArray($perms));
124                foreach ($this->availablePermissions as $perm) {
125                    $fields[] = 'perm_' . $base . '_' . $perm;
126                    $params[] = isset($perms[$perm]) ? true : false;
127                }
128            }
129            $sql = 'UPDATE ' . $table . ' SET ' . implode(' = ?, ', $fields) . ' = ? WHERE share_id = ?';
130            $params[] = $this->data['share_id'];
131            try {
132                $db->update($sql, $params);
133            } catch (Horde_Db_Exception $e) {
134                throw new Horde_Share_Exception($e);
135            }
136        }
137
138        // Update the share's user permissions
139        $db->delete('DELETE FROM ' . $table . '_users WHERE share_id = ?', array($this->data['share_id']));
140        if (!empty($this->data['perm']['users'])) {
141            $data = array();
142            foreach ($this->data['perm']['users'] as $user => $perms) {
143                $fields = $params = array();
144                foreach (Horde_Share_Sqlng::convertBitmaskToArray($perms) as $perm) {
145                    $fields[] = 'perm_' . $perm;
146                    $params[] = true;
147                }
148                if (!$fields) {
149                    continue;
150                }
151                array_unshift($params, $user);
152                array_unshift($params, $this->data['share_id']);
153                $db->insert('INSERT INTO ' . $table . '_users (share_id, user_uid, ' . implode(', ', $fields) . ') VALUES (?, ?' . str_repeat(', ?', count($fields)) . ')', $params);
154            }
155        }
156
157        // Update the share's group permissions
158        $db->delete('DELETE FROM ' . $table . '_groups WHERE share_id = ?', array($this->data['share_id']));
159        if (!empty($this->data['perm']['groups'])) {
160            $data = array();
161            foreach ($this->data['perm']['groups'] as $group => $perms) {
162                $fields = $params = array();
163                foreach (Horde_Share_Sqlng::convertBitmaskToArray($perms) as $perm) {
164                    $fields[] = 'perm_' . $perm;
165                    $params[] = true;
166                }
167                if (!$fields) {
168                    continue;
169                }
170                array_unshift($params, $group);
171                array_unshift($params, $this->data['share_id']);
172                $db->insert('INSERT INTO ' . $table . '_groups (share_id, group_uid, ' . implode(', ', $fields) . ') VALUES (?, ?' . str_repeat(', ?', count($fields)) . ')', $params);
173            }
174        }
175
176        return true;
177    }
178
179    /**
180     * Sets the permission of this share.
181     *
182     * @param Horde_Perms_Permission $perm  Permission object.
183     * @param boolean $update               Should the share be saved
184     *                                      after this operation?
185     */
186    public function setPermission($perm, $update = true)
187    {
188        parent::setPermission($perm, false);
189        $this->_setAvailablePermissions();
190        if ($update) {
191            $this->save();
192        }
193    }
194
195    /**
196     * Populates the $availablePermissions property with all seen permissions.
197     *
198     * This is necessary because the share tables might be extended with
199     * arbitrary permissions.
200     */
201    protected function _setAvailablePermissions()
202    {
203        $available = array();
204        foreach ($this->availablePermissions as $perm) {
205            $available[$perm] = true;
206        }
207        foreach ($this->data['perm'] as $base => $perms) {
208            if ($base == 'type') {
209                continue;
210            }
211            if ($base != 'users' && $base != 'groups') {
212                $perms = array($perms);
213            }
214            foreach ($perms as $subperms) {
215                foreach (Horde_Share_Sqlng::convertBitmaskToArray($subperms) as $perm) {
216                    $available[$perm] = true;
217                }
218            }
219        }
220        $this->availablePermissions = array_keys($available);
221    }
222}
223