5546354e687366b6d03cd17e50e5eea009fd8b05
[tine20] / tine20 / Addressbook / Backend / List.php
1 <?php
2 /**
3  * Tine 2.0
4  *
5  * @package     Addressbook
6  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
7  * @author      Lars Kneschke <l.kneschke@metaways.de>
8  * @copyright   Copyright (c) 2007-2010 Metaways Infosystems GmbH (http://www.metaways.de)
9  * 
10  * @todo        move visibility='displayed' check from getSelect to contact filter
11  */
12
13 /**
14  * sql backend class for the addressbook
15  *
16  * @package     Addressbook
17  */
18 class Addressbook_Backend_List extends Tinebase_Backend_Sql_Abstract
19 {
20     /**
21      * Table name without prefix
22      *
23      * @var string
24      */
25     protected $_tableName = 'addressbook_lists';
26     
27     /**
28      * Model name
29      *
30      * @var string
31      */
32     protected $_modelName = 'Addressbook_Model_List';
33
34     /**
35      * if modlog is active, we add 'is_deleted = 0' to select object in _getSelect()
36      *
37      * @var boolean
38      */
39     protected $_modlogActive = TRUE;
40
41     /**
42      * default column(s) for count
43      *
44      * @var string
45      */
46     protected $_defaultCountCol = 'id';
47
48     /**
49      * foreign tables 
50      * name => array(table, joinOn, field)
51      *
52      * @var array
53      */
54     protected $_foreignTables = array(
55         'members'    => array(
56             'table'  => 'addressbook_list_members',
57             'field'  => 'contact_id',
58             'joinOn' => 'list_id',
59         ),
60         'group_id'    => array(
61             'table'        => 'groups',
62             'field'        => 'id',
63             'joinOn'       => 'list_id',
64         // use first element of result array
65             'singleValue'  => TRUE,
66         )
67     );
68
69     /**
70      * the constructor
71      * 
72      * allowed options:
73      *  - modelName
74      *  - tableName
75      *  - tablePrefix
76      *  - modlogActive
77      *  
78      * @param Zend_Db_Adapter_Abstract $_db (optional)
79      * @param array $_options (optional)
80      * @throws Tinebase_Exception_Backend_Database
81      */
82     public function __construct($_dbAdapter = NULL, $_options = array())
83     {
84         parent::__construct($_dbAdapter, $_options);
85
86         if (Addressbook_Config::getInstance()->featureEnabled(Addressbook_Config::FEATURE_LIST_VIEW)) {
87             $this->_additionalColumns['emails'] = new Zend_Db_Expr('(' .
88                 $this->_db->select()
89                     ->from($this->_tablePrefix . 'addressbook', array($this->_dbCommand->getAggregate('email')))
90                     ->where($this->_db->quoteIdentifier('id') . ' IN ?', $this->_db->select()
91                         ->from(array('addressbook_list_members' => $this->_tablePrefix . 'addressbook_list_members'), array('contact_id'))
92                         ->where($this->_db->quoteIdentifier('addressbook_list_members.list_id') . ' = ' . $this->_db->quoteIdentifier('addressbook_lists.id'))
93                     ) .
94                 ')');
95         }
96     }
97
98     /**
99      * converts record into raw data for adapter
100      *
101      * @param  Tinebase_Record_Abstract $_record
102      * @return array
103      */
104     protected function _recordToRawData($_record)
105     {
106         $result = parent::_recordToRawData($_record);
107         
108         // stored in foreign key
109         unset($result['members']);
110         unset($result['group_id']);
111
112         return $result;
113     }
114
115     /**
116      * add new members to list
117      * 
118      * @param  mixed  $_listId
119      * @param  mixed  $_newMembers
120      * @return Addressbook_Model_List
121      */
122     public function addListMember($_listId, $_newMembers)
123     {
124         $list = $this->get($_listId);
125         
126         if (empty($_newMembers)) {
127             return $list;
128         }
129         
130         $newMembers = $this->_getIdsFromMixed($_newMembers);
131         $idsToAdd   = array_diff($newMembers, $list->members);
132         
133         $listId     = Tinebase_Record_Abstract::convertId($_listId, $this->_modelName);
134         
135         $transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
136         
137         foreach ($idsToAdd as $id) {
138             $recordArray = array (
139                 $this->_foreignTables['members']['joinOn'] => $listId,
140                 $this->_foreignTables['members']['field']  => $id
141             );
142             $this->_db->insert($this->_tablePrefix . $this->_foreignTables['members']['table'], $recordArray);
143         }
144         
145         Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
146         
147         return $this->get($_listId);
148     }
149     
150     /**
151      * Delete all lists returned by {@see getAll()} using {@see delete()}
152      * @return void
153      */
154     public function deleteAllLists()
155     {
156         $lists = $this->getAll();
157         
158         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Deleting ' . count($lists) .' lists');
159         
160         if(count($lists) > 0) {
161             $this->delete($lists->getArrayOfIds());
162         }
163     }
164     
165     /**
166      * remove members from list
167      * 
168      * @param  mixed  $_listId
169      * @param  mixed  $_newMembers
170      * @return Addressbook_Model_List
171      */
172     public function removeListMember($_listId, $_oldMembers)
173     {
174         $list = $this->get($_listId);
175         
176         if (empty($_oldMembers)) {
177             return $list;
178         }
179         
180         $oldMembers  = $this->_getIdsFromMixed($_oldMembers);
181         $idsToRemove = array_intersect($list->members, $oldMembers);
182         $listId      = Tinebase_Record_Abstract::convertId($_listId, $this->_modelName);
183         
184         $transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
185         
186         if (!empty($idsToRemove)) {
187             $where = '(' . 
188                 $this->_db->quoteInto($this->_db->quoteIdentifier($this->_tablePrefix . $this->_foreignTables['members']['table'] . '.' . $this->_foreignTables['members']['joinOn']) . ' = ?', $listId) .
189                 ' AND ' .
190                 $this->_db->quoteInto($this->_db->quoteIdentifier($this->_tablePrefix . $this->_foreignTables['members']['table'] . '.' . $this->_foreignTables['members']['field']) . ' IN (?)', $idsToRemove) .
191             ')';
192                 
193             $this->_db->delete($this->_tablePrefix . $this->_foreignTables['members']['table'], $where);
194         }
195         
196         Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
197         
198         return $this->get($_listId);
199     }
200     
201     /**
202     * set all lists an user is member of
203     *
204     * @param  string  $contactId
205     * @param  mixed  $listIds
206     * @return array
207     */
208     public function setMemberships($contactId, $listIds)
209     {
210         $contactId = Tinebase_Record_Abstract::convertId($contactId, 'Addressbook_Model_Contact');
211         
212         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
213             . ' Set ' . count($listIds) . ' list memberships for contact ' . $contactId);
214         
215         if ($listIds instanceof Tinebase_Record_RecordSet) {
216             $listIds = $listIds->getArrayOfIds();
217         }
218     
219         $listMemberships = $this->getMemberships($contactId);
220     
221         $removeListMemberships = array_diff($listMemberships, $listIds);
222         $addListMemberships    = array_diff($listIds, $listMemberships);
223     
224         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' current memberships: ' . print_r($listMemberships, true));
225         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' new memberships: ' . print_r($listIds, true));
226         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' added memberships: ' . print_r($addListMemberships, true));
227         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' removed memberships: ' . print_r($removeListMemberships, true));
228     
229         foreach ($addListMemberships as $listId) {
230             $this->addListMember($listId, $contactId);
231         }
232     
233         foreach ($removeListMemberships as $listId) {
234             $this->removeListMember($listId, $contactId);
235         }
236     
237         return $this->getMemberships($contactId);
238     }
239     
240     /**
241      * get group memberships of contact id
242      * 
243      * @param mixed $contactId
244      * @return array
245      */
246     public function getMemberships($contactId)
247     {
248         $contactId = Tinebase_Record_Abstract::convertId($contactId, 'Addressbook_Model_Contact');
249         
250         $select = $this->_db->select()
251             ->from($this->_tablePrefix . $this->_foreignTables['members']['table'], 'list_id')
252             ->where($this->_db->quoteIdentifier('contact_id') . ' = ?', $contactId);
253         
254         $stmt = $this->_db->query($select);
255         $rows = (array) $stmt->fetchAll(Zend_Db::FETCH_ASSOC);
256         
257         $result = array();
258         foreach ($rows as $membership) {
259             $result[] = $membership['list_id'];
260         }
261         
262         return $result;
263     }
264     
265     /**
266      * get list by group name
267      * 
268      * @param string $groupName
269      * @return NULL|Addressbook_Model_List
270      */
271     public function getByGroupName($groupName)
272     {
273         $filter = new Addressbook_Model_ListFilter(array(
274             array('field' => 'name', 'operator' => 'equals', 'value' => $groupName),
275             array('field' => 'type', 'operator' => 'equals', 'value' => Addressbook_Model_List::LISTTYPE_GROUP)
276         ));
277         
278         $existingLists = $this->search($filter);
279         
280         return $existingLists->getFirstRecord();
281     }
282 }