Merge branch '2013.10' into 2014.11
[tine20] / tine20 / Tinebase / Group / Sql.php
1 <?php
2 /**
3  * Tine 2.0
4  * 
5  * @package     Tinebase
6  * @subpackage  Group
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @copyright   Copyright (c) 2008-2015 Metaways Infosystems GmbH (http://www.metaways.de)
9  * @author      Lars Kneschke <l.kneschke@metaways.de>
10  */
11
12 /**
13  * sql implementation of the groups interface
14  * 
15  * @package     Tinebase
16  * @subpackage  Group
17  */
18 class Tinebase_Group_Sql extends Tinebase_Group_Abstract
19 {
20     /**
21      * @var Zend_Db_Adapter_Abstract
22      */
23     protected $_db;
24     
25     /**
26      * the groups table
27      *
28      * @var Tinebase_Db_Table
29      */
30     protected $groupsTable;
31     
32     /**
33      * the groupmembers table
34      *
35      * @var Tinebase_Db_Table
36      */
37     protected $groupMembersTable;
38     
39     /**
40      * Table name without prefix
41      *
42      * @var string
43      */
44     protected $_tableName = 'groups';
45     
46     /**
47      * set to true is addressbook table is found
48      * 
49      * @var boolean
50      */
51     protected $_addressBookInstalled = false;
52     
53     /**
54      * in class cache 
55      * 
56      * @var array
57      */
58     protected $_classCache = array (
59         'getGroupMemberships' => array()
60     );
61     
62     /**
63      * the constructor
64      */
65     public function __construct() 
66     {
67         $this->_db = Tinebase_Core::getDb();
68         
69         $this->groupsTable = new Tinebase_Db_Table(array('name' => SQL_TABLE_PREFIX . $this->_tableName));
70         $this->groupMembersTable = new Tinebase_Db_Table(array('name' => SQL_TABLE_PREFIX . 'group_members'));
71         
72         try {
73             // MySQL throws an exception         if the table does not exist
74             // PostgreSQL returns an empty array if the table does not exist
75             $adbSchema = Tinebase_Db_Table::getTableDescriptionFromCache(SQL_TABLE_PREFIX . 'addressbook');
76             $adbListsSchema = Tinebase_Db_Table::getTableDescriptionFromCache(SQL_TABLE_PREFIX . 'addressbook_lists');
77             if (! empty($adbSchema) && ! empty($adbListsSchema) ) {
78                 $this->_addressBookInstalled = TRUE;
79             }
80         } catch (Zend_Db_Statement_Exception $zdse) {
81             // nothing to do
82         }
83     }
84     
85     /**
86      * return all groups an account is member of
87      *
88      * @param mixed $_accountId the account as integer or Tinebase_Model_User
89      * @return array
90      */
91     public function getGroupMemberships($_accountId)
92     {
93         $accountId = Tinebase_Model_User::convertUserIdToInt($_accountId);
94         
95         $classCacheId = $accountId;
96         
97         if (isset($this->_classCache[__FUNCTION__][$classCacheId])) {
98             return $this->_classCache[__FUNCTION__][$classCacheId];
99         }
100         
101         $cacheId     = Tinebase_Helper::convertCacheId(__FUNCTION__ . $classCacheId);
102         $memberships = Tinebase_Core::getCache()->load($cacheId);
103         
104         if (! $memberships) {
105             $select = $this->_db->select()
106                 ->distinct()
107                 ->from(array('group_members' => SQL_TABLE_PREFIX . 'group_members'), array('group_id'))
108                 ->where($this->_db->quoteIdentifier('account_id') . ' = ?', $accountId);
109             
110             $stmt = $this->_db->query($select);
111             
112             $memberships = $stmt->fetchAll(Zend_Db::FETCH_COLUMN);
113             
114             Tinebase_Core::getCache()->save($memberships, $cacheId);
115         }
116         
117         $this->_classCache[__FUNCTION__][$classCacheId] = $memberships;
118         
119         return $memberships;
120     }
121     
122     /**
123      * get list of groupmembers
124      *
125      * @param int $_groupId
126      * @return array with account ids
127      */
128     public function getGroupMembers($_groupId)
129     {
130         $groupId = Tinebase_Model_Group::convertGroupIdToInt($_groupId);
131         
132         $cacheId = Tinebase_Helper::convertCacheId(__FUNCTION__ . $groupId);
133         $members = Tinebase_Core::getCache()->load($cacheId);
134
135         if (! $members) {
136             $members = array();
137
138             $select = $this->groupMembersTable->select();
139             $select->where($this->_db->quoteIdentifier('group_id') . ' = ?', $groupId);
140
141             $rows = $this->groupMembersTable->fetchAll($select);
142             
143             foreach($rows as $member) {
144                 $members[] = $member->account_id;
145             }
146
147             Tinebase_Core::getCache()->save($members, $cacheId);
148         }
149
150         return $members;
151     }
152     
153     /**
154      * replace all current groupmembers with the new groupmembers list
155      *
156      * @param  mixed  $_groupId
157      * @param  array  $_groupMembers
158      */
159     public function setGroupMembers($_groupId, $_groupMembers)
160     {
161         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
162             . ' Setting ' . count($_groupMembers) . ' new groupmembers for group ' . $_groupId);
163         
164         if ($this instanceof Tinebase_Group_Interface_SyncAble) {
165             $_groupMembers = $this->setGroupMembersInSyncBackend($_groupId, $_groupMembers);
166         }
167         
168         $this->setGroupMembersInSqlBackend($_groupId, $_groupMembers);
169     }
170      
171     /**
172      * replace all current groupmembers with the new groupmembers list
173      *
174      * @param  mixed  $_groupId
175      * @param  array  $_groupMembers
176      */
177     public function setGroupMembersInSqlBackend($_groupId, $_groupMembers)
178     {
179         $groupId = Tinebase_Model_Group::convertGroupIdToInt($_groupId);
180         
181         // remove old members
182         $where = $this->_db->quoteInto($this->_db->quoteIdentifier('group_id') . ' = ?', $groupId);
183         $this->groupMembersTable->delete($where);
184         
185         // check if users have accounts
186         $userIdsWithExistingAccounts = Tinebase_User::getInstance()->getMultiple($_groupMembers)->getArrayOfIds();
187         
188         if (count($_groupMembers) > 0) {
189             // add new members
190             foreach ($_groupMembers as $accountId) {
191                 $accountId = Tinebase_Model_User::convertUserIdToInt($accountId);
192                 if (in_array($accountId, $userIdsWithExistingAccounts)) {
193                     $this->_db->insert(SQL_TABLE_PREFIX . 'group_members', array(
194                         'group_id'    => $groupId,
195                         'account_id'  => $accountId
196                     ));
197                 } else {
198                     if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__
199                         . ' User with ID ' . $accountId . ' does not have an account!');
200                 }
201                 
202                 $this->_clearCache(array('getGroupMemberships' => $accountId));
203             }
204         }
205         
206         $this->_clearCache(array('getGroupMembers' => $groupId));
207     }
208     
209     /**
210      * invalidate cache by type/id
211      * 
212      * @param array $cacheIds
213      */
214     protected function _clearCache($cacheIds = array())
215     {
216         $cache = Tinebase_Core::getCache();
217         
218         foreach ($cacheIds as $type => $id) {
219             $cacheId = Tinebase_Helper::convertCacheId($type . $id);
220             $cache->remove($cacheId);
221         }
222         
223         $this->resetClassCache();
224     }
225     
226     /**
227      * set all groups an account is member of
228      *
229      * @param  mixed  $_userId    the userid as string or Tinebase_Model_User
230      * @param  mixed  $_groupIds
231      * 
232      * @return array
233      */
234     public function setGroupMemberships($_userId, $_groupIds)
235     {
236         if(count($_groupIds) === 0) {
237             throw new Tinebase_Exception_InvalidArgument('user must belong to at least one group');
238         }
239         
240         if($this instanceof Tinebase_Group_Interface_SyncAble) {
241             $this->setGroupMembershipsInSyncBackend($_userId, $_groupIds);
242         }
243         
244         return $this->setGroupMembershipsInSqlBackend($_userId, $_groupIds);
245     }
246     
247     /**
248      * set all groups an user is member of
249      *
250      * @param  mixed  $_usertId   the account as integer or Tinebase_Model_User
251      * @param  mixed  $_groupIds
252      * @return array
253      */
254     public function setGroupMembershipsInSqlBackend($_userId, $_groupIds)
255     {
256         if ($_groupIds instanceof Tinebase_Record_RecordSet) {
257             $_groupIds = $_groupIds->getArrayOfIds();
258         }
259         
260         if (count($_groupIds) === 0) {
261             throw new Tinebase_Exception_InvalidArgument('user must belong to at least one group');
262         }
263         
264         $userId = Tinebase_Model_user::convertUserIdToInt($_userId);
265         
266         $groupMemberships = $this->getGroupMemberships($userId);
267         
268         $removeGroupMemberships = array_diff($groupMemberships, $_groupIds);
269         $addGroupMemberships    = array_diff($_groupIds, $groupMemberships);
270         
271         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' current groupmemberships: ' . print_r($groupMemberships, true));
272         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' new groupmemberships: ' . print_r($_groupIds, true));
273         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' added groupmemberships: ' . print_r($addGroupMemberships, true));
274         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' removed groupmemberships: ' . print_r($removeGroupMemberships, true));
275         
276         foreach ($addGroupMemberships as $groupId) {
277             $this->addGroupMemberInSqlBackend($groupId, $userId);
278         }
279         
280         foreach ($removeGroupMemberships as $groupId) {
281             $this->removeGroupMemberFromSqlBackend($groupId, $userId);
282         }
283         
284         $event = new Tinebase_Group_Event_SetGroupMemberships(array(
285             'user'               => $_userId,
286             'addedMemberships'   => $addGroupMemberships,
287             'removedMemberships' => $removeGroupMemberships
288         ));
289         Tinebase_Event::fireEvent($event);
290         
291         return $this->getGroupMemberships($userId);
292     }
293     
294     /**
295      * add a new groupmember to a group
296      *
297      * @param  string  $_groupId
298      * @param  string  $_accountId
299      */
300     public function addGroupMember($_groupId, $_accountId)
301     {
302         if ($this instanceof Tinebase_Group_Interface_SyncAble) {
303             $this->addGroupMemberInSyncBackend($_groupId, $_accountId);
304         }
305         
306         $this->addGroupMemberInSqlBackend($_groupId, $_accountId);
307     }
308     
309     /**
310      * add a new groupmember to a group
311      *
312      * @param  string  $_groupId
313      * @param  string  $_accountId
314      */
315     public function addGroupMemberInSqlBackend($_groupId, $_accountId)
316     {
317         $groupId   = Tinebase_Model_Group::convertGroupIdToInt($_groupId);
318         $accountId = Tinebase_Model_User::convertUserIdToInt($_accountId);
319
320         $memberShips = $this->getGroupMemberships($accountId);
321         
322         if (!in_array($groupId, $memberShips)) {
323             $data = array(
324                 'group_id'      => $groupId,
325                 'account_id'    => $accountId
326             );
327         
328             $this->groupMembersTable->insert($data);
329             
330             $this->_clearCache(array(
331                 'getGroupMembers'     => $groupId,
332                 'getGroupMemberships' => $accountId,
333             ));
334         }
335         
336     }
337     
338     /**
339      * remove one groupmember from the group
340      *
341      * @param  mixed  $_groupId
342      * @param  mixed  $_accountId
343      */
344     public function removeGroupMember($_groupId, $_accountId)
345     {
346         if ($this instanceof Tinebase_Group_Interface_SyncAble) {
347             $this->removeGroupMemberInSyncBackend($_groupId, $_accountId);
348         }
349         
350         return $this->removeGroupMemberFromSqlBackend($_groupId, $_accountId);
351     }
352     
353     /**
354      * remove one groupmember from the group
355      *
356      * @param  mixed  $_groupId
357      * @param  mixed  $_accountId
358      */
359     public function removeGroupMemberFromSqlBackend($_groupId, $_accountId)
360     {
361         $groupId   = Tinebase_Model_Group::convertGroupIdToInt($_groupId);
362         $accountId = Tinebase_Model_User::convertUserIdToInt($_accountId);
363         
364         $where = array(
365             $this->_db->quoteInto($this->_db->quoteIdentifier('group_id') . '= ?', $groupId),
366             $this->_db->quoteInto($this->_db->quoteIdentifier('account_id') . '= ?', $accountId),
367         );
368          
369         $this->groupMembersTable->delete($where);
370         
371         $this->_clearCache(array(
372             'getGroupMembers'     => $groupId,
373             'getGroupMemberships' => $accountId,
374         ));
375     }
376     
377     /**
378      * create a new group
379      *
380      * @param   Tinebase_Model_Group  $_group
381      * 
382      * @return  Tinebase_Model_Group
383      * 
384      * @todo do not create group in sql if sync backend is readonly?
385      */
386     public function addGroup(Tinebase_Model_Group $_group)
387     {
388         if ($this instanceof Tinebase_Group_Interface_SyncAble) {
389             $groupFromSyncBackend = $this->addGroupInSyncBackend($_group);
390             
391             if (isset($groupFromSyncBackend->id)) {
392                 $_group->setId($groupFromSyncBackend->getId());
393             }
394         }
395         
396         return $this->addGroupInSqlBackend($_group);
397     }
398     
399     /**
400      * alias for addGroup
401      * 
402      * @param Tinebase_Model_Group $group
403      * @return Tinebase_Model_Group
404      */
405     public function create(Tinebase_Model_Group $group)
406     {
407         return $this->addGroup($group);
408     }
409     
410     /**
411      * create a new group in sql backend
412      *
413      * @param   Tinebase_Model_Group  $_group
414      * 
415      * @return  Tinebase_Model_Group
416      * @throws  Tinebase_Exception_Record_Validation
417      */
418     public function addGroupInSqlBackend(Tinebase_Model_Group $_group)
419     {
420         if(!$_group->isValid()) {
421             throw new Tinebase_Exception_Record_Validation('invalid group object');
422         }
423         
424         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ 
425             . ' Creating new group ' . $_group->name 
426             //. print_r($_group->toArray(), true)
427         );
428         
429         if(!isset($_group->id)) {
430             $groupId = $_group->generateUID();
431             $_group->setId($groupId);
432         }
433         
434         if (empty($_group->list_id)) {
435             $_group->visibility = 'hidden';
436             $_group->list_id    = null;
437         }
438         
439         $data = $_group->toArray();
440         
441         unset($data['members']);
442         unset($data['container_id']);
443         
444         $this->groupsTable->insert($data);
445         
446         return $_group;
447     }
448     
449     /**
450      * update a group
451      *
452      * @param  Tinebase_Model_Group  $_group
453      * 
454      * @return Tinebase_Model_Group
455      */
456     public function updateGroup(Tinebase_Model_Group $_group)
457     {
458         if ($this instanceof Tinebase_Group_Interface_SyncAble) {
459             $this->updateGroupInSyncBackend($_group);
460         }
461         
462         return $this->updateGroupInSqlBackend($_group);
463     }
464     
465     /**
466      * create a new group in sync backend
467      * 
468      * NOTE: sets visibility to HIDDEN if list_id is empty
469      *
470      * @param  Tinebase_Model_Group  $_group
471      * @return Tinebase_Model_Group
472      */
473     public function updateGroupInSqlBackend(Tinebase_Model_Group $_group)
474     {
475         $groupId = Tinebase_Model_Group::convertGroupIdToInt($_group);
476         
477         if (empty($_group->list_id)) {
478             $_group->visibility = Tinebase_Model_Group::VISIBILITY_HIDDEN;
479             $_group->list_id    = null;
480         }
481         
482         $data = array(
483             'name'          => $_group->name,
484             'description'   => $_group->description,
485             'visibility'    => $_group->visibility,
486             'email'         => $_group->email,
487             'list_id'       => $_group->list_id,
488             'created_by'            => $_group->created_by,
489             'creation_time'         => $_group->creation_time,
490             'last_modified_by'      => $_group->last_modified_by,
491             'last_modified_time'    => $_group->last_modified_time,
492             'is_deleted'            => $_group->is_deleted,
493             'deleted_time'          => $_group->deleted_time,
494             'deleted_by'            => $_group->deleted_by,
495             'seq'                   => $_group->seq,
496         );
497         
498         if (empty($data['seq'])) {
499             unset($data['seq']);
500         }
501         
502         $where = $this->_db->quoteInto($this->_db->quoteIdentifier('id') . ' = ?', $groupId);
503         
504         $this->groupsTable->update($data, $where);
505         
506         return $this->getGroupById($groupId);
507     }
508     
509     /**
510      * delete groups
511      *
512      * @param   mixed $_groupId
513
514      * @throws  Tinebase_Exception_Backend
515      */
516     public function deleteGroups($_groupId)
517     {
518         $groupIds = array();
519         
520         if (is_array($_groupId) or $_groupId instanceof Tinebase_Record_RecordSet) {
521             foreach ($_groupId as $groupId) {
522                 $groupIds[] = Tinebase_Model_Group::convertGroupIdToInt($groupId);
523             }
524         } else {
525             $groupIds[] = Tinebase_Model_Group::convertGroupIdToInt($_groupId);
526         }
527         
528         try {
529             $transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
530             
531             $this->_updatePrimaryGroupsOfUsers($groupIds);
532             
533             $this->deleteGroupsInSqlBackend($groupIds);
534             if ($this instanceof Tinebase_Group_Interface_SyncAble) {
535                 $this->deleteGroupsInSyncBackend($groupIds);
536             }
537             
538             Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
539             
540         } catch (Exception $e) {
541             Tinebase_TransactionManager::getInstance()->rollBack();
542             Tinebase_Exception::log($e);
543             throw new Tinebase_Exception_Backend($e->getMessage());
544         }
545     }
546     
547     /**
548      * set primary group for accounts with given primary group id
549      * 
550      * @param array $groupIds
551      * @param string $newPrimaryGroupId
552      * @throws Tinebase_Exception_Record_NotDefined
553      */
554     protected function _updatePrimaryGroupsOfUsers($groupIds, $newPrimaryGroupId = null)
555     {
556         if ($newPrimaryGroupId === null) {
557             $newPrimaryGroupId = $this->getDefaultGroup()->getId();
558         }
559         foreach ($groupIds as $groupId) {
560             $users = Tinebase_User::getInstance()->getUsersByPrimaryGroup($groupId);
561             $users->accountPrimaryGroup = $newPrimaryGroupId;
562             foreach ($users as $user) {
563                 Tinebase_User::getInstance()->updateUser($user);
564             }
565         }
566     }
567     
568     /**
569      * delete groups in sql backend
570      * 
571      * @param array $groupIds
572      */
573     public function deleteGroupsInSqlBackend($groupIds)
574     {
575         $where = $this->_db->quoteInto($this->_db->quoteIdentifier('group_id') . ' IN (?)', (array) $groupIds);
576         $this->groupMembersTable->delete($where);
577         $where = $this->_db->quoteInto($this->_db->quoteIdentifier('id') . ' IN (?)', (array) $groupIds);
578         $this->groupsTable->delete($where);
579     }
580     
581     /**
582      * Delete all groups returned by {@see getGroups()} using {@see deleteGroups()}
583      * @return void
584      */
585     public function deleteAllGroups()
586     {
587         $groups = $this->getGroups();
588         
589         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Deleting ' . count($groups) .' groups');
590         
591         if(count($groups) > 0) {
592             $this->deleteGroups($groups);
593         }
594     }
595     
596     /**
597      * get list of groups
598      *
599      * @param string $_filter
600      * @param string $_sort
601      * @param string $_dir
602      * @param int $_start
603      * @param int $_limit
604      * @return Tinebase_Record_RecordSet with record class Tinebase_Model_Group
605      */
606     public function getGroups($_filter = NULL, $_sort = 'name', $_dir = 'ASC', $_start = NULL, $_limit = NULL)
607     {
608         $select = $this->_getSelect();
609         
610         if($_filter !== NULL) {
611             $select->where($this->_db->quoteIdentifier($this->_tableName. '.name') . ' LIKE ?', '%' . $_filter . '%');
612         }
613         if($_sort !== NULL) {
614             $select->order($this->_tableName . '.' . $_sort . ' ' . $_dir);
615         }
616         if($_start !== NULL) {
617             $select->limit($_limit, $_start);
618         }
619         
620         $stmt = $this->_db->query($select);
621         $queryResult = $stmt->fetchAll();
622         $stmt->closeCursor();
623         
624         $result = new Tinebase_Record_RecordSet('Tinebase_Model_Group', $queryResult, TRUE);
625         
626         return $result;
627     }
628     
629     /**
630      * get group by name
631      *
632      * @param   string $_name
633      * @return  Tinebase_Model_Group
634      * @throws  Tinebase_Exception_Record_NotDefined
635      */
636     public function getGroupByName($_name)
637     {
638         $result = $this->getGroupByPropertyFromSqlBackend('name', $_name);
639         
640         return $result;
641     }
642     
643     /**
644      * get group by property
645      *
646      * @param   string  $_property      the key to filter
647      * @param   string  $_value         the value to search for
648      *
649      * @return  Tinebase_Model_Group
650      * @throws  Tinebase_Exception_Record_NotDefined
651      * @throws  Tinebase_Exception_InvalidArgument
652      */
653     public function getGroupByPropertyFromSqlBackend($_property, $_value)
654     {
655         if (! in_array($_property, array('id', 'name', 'description', 'list_id', 'email'))) {
656             throw new Tinebase_Exception_InvalidArgument('property not allowed');
657         }
658         
659         $select = $this->_getSelect();
660         
661         $select->where($this->_db->quoteIdentifier($this->_tableName . '.' . $_property) . ' = ?', $_value);
662         
663         $stmt = $this->_db->query($select);
664         $queryResult = $stmt->fetch();
665         $stmt->closeCursor();
666         
667         if (!$queryResult) {
668             throw new Tinebase_Exception_Record_NotDefined('Group not found.');
669         }
670         
671         $result = new Tinebase_Model_Group($queryResult, TRUE);
672         
673         return $result;
674     }
675     
676     
677     /**
678      * get group by id
679      *
680      * @param   string $_name
681      * @return  Tinebase_Model_Group
682      * @throws  Tinebase_Exception_Record_NotDefined
683      */
684     public function getGroupById($_groupId)
685     {
686         $groupdId = Tinebase_Model_Group::convertGroupIdToInt($_groupId);
687         
688         $result = $this->getGroupByPropertyFromSqlBackend('id', $groupdId);
689         
690         return $result;
691     }
692     
693     /**
694      * Get multiple groups
695      *
696      * @param string|array $_ids Ids
697      * @return Tinebase_Record_RecordSet
698      * 
699      * @todo this should return the container_id, too
700      */
701     public function getMultiple($_ids)
702     {
703         $result = new Tinebase_Record_RecordSet('Tinebase_Model_Group');
704         
705         if (! empty($_ids)) {
706             $select = $this->groupsTable->select();
707             $select->where($this->_db->quoteIdentifier('id') . ' IN (?)', array_unique((array) $_ids));
708             
709             $rows = $this->groupsTable->fetchAll($select);
710             foreach ($rows as $row) {
711                 $result->addRecord(new Tinebase_Model_Group($row->toArray(), TRUE));
712             }
713         }
714         
715         return $result;
716     }
717     
718     /**
719      * get the basic select object to fetch records from the database
720      * 
721      * NOTE: container_id is joined from addressbook lists table
722      *  
723      * @param array|string|Zend_Db_Expr $_cols columns to get, * per default
724      * @param boolean $_getDeleted get deleted records (if modlog is active)
725      * @return Zend_Db_Select
726      */
727     protected function _getSelect($_cols = '*', $_getDeleted = FALSE)
728     {
729         $select = $this->_db->select();
730         
731         $select->from(array($this->_tableName => SQL_TABLE_PREFIX . $this->_tableName), $_cols);
732         
733         if ($this->_addressBookInstalled === true) {
734             $select->joinLeft(
735                 array('addressbook_lists' => SQL_TABLE_PREFIX . 'addressbook_lists'),
736                 $this->_db->quoteIdentifier($this->_tableName . '.list_id') . ' = ' . $this->_db->quoteIdentifier('addressbook_lists.id'), 
737                 array('container_id')
738             );
739         }
740         
741         return $select;
742     }
743     
744     /**
745      * Method called by {@see Addressbook_Setup_Initialize::_initilaize()}
746      * 
747      * @param $_options
748      * @return unknown_type
749      */
750     public function __importGroupMembers($_options = null)
751     {
752         //nothing to do
753     }
754 }