6 * @subpackage Controller
7 * @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
8 * @author Lars Kneschke <l.kneschke@metaways.de>
9 * @copyright Copyright (c) 2010-2012 Metaways Infosystems GmbH (http://www.metaways.de)
14 * contact controller for Addressbook
16 * @package Addressbook
17 * @subpackage Controller
19 class Addressbook_Controller_List extends Tinebase_Controller_Record_Abstract
22 * application name (is needed in checkRight())
26 protected $_applicationName = 'Addressbook';
33 protected $_modelName = 'Addressbook_Model_List';
36 * @var null|Tinebase_Backend_Sql
38 protected $_memberRolesBackend = null;
43 * don't use the constructor. use the singleton
45 private function __construct()
47 $this->_resolveCustomFields = true;
48 $this->_backend = new Addressbook_Backend_List();
52 * don't clone. Use the singleton.
55 private function __clone()
60 * holds the instance of the singleton
62 * @var Addressbook_Controller_List
64 private static $_instance = NULL;
66 protected function _getMemberRolesBackend()
68 if ($this->_memberRolesBackend === null) {
69 $this->_memberRolesBackend = new Tinebase_Backend_Sql(array(
70 'tableName' => 'adb_list_m_role',
71 'modelName' => 'Addressbook_Model_ListMemberRole',
75 return $this->_memberRolesBackend;
79 * the singleton pattern
81 * @return Addressbook_Controller_List
83 public static function getInstance()
85 if (self::$_instance === NULL) {
86 self::$_instance = new Addressbook_Controller_List();
89 return self::$_instance;
95 * @see Tinebase_Controller_Record_Abstract::get()
97 public function get($_id, $_containerId = NULL)
99 $result = new Tinebase_Record_RecordSet('Addressbook_Model_List', array(parent::get($_id, $_containerId)));
100 $this->_removeHiddenListMembers($result);
101 return $result->getFirstRecord();
105 * use contact search to remove hidden list members
107 * @param Tinebase_Record_RecordSet $lists
109 protected function _removeHiddenListMembers($lists)
111 if (count($lists) === 0) {
115 $allMemberIds = array();
116 foreach ($lists as $list) {
117 $allMemberIds = array_merge($list->members, $allMemberIds);
119 $allMemberIds = array_unique($allMemberIds);
121 if (empty($allMemberIds)) {
122 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
123 . ' No members found.');
127 $allVisibleMemberIds = Addressbook_Controller_Contact::getInstance()->search(new Addressbook_Model_ContactFilter(array(array(
130 'value' => $allMemberIds
131 ))), NULL, FALSE, TRUE);
133 $hiddenMemberids = array_diff($allMemberIds, $allVisibleMemberIds);
135 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
136 . ' Found ' . count($hiddenMemberids) . ' hidden members, removing them');
137 if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
138 . print_r($hiddenMemberids, TRUE));
140 foreach ($lists as $list) {
141 $list->members = array_diff($list->members, $hiddenMemberids);
148 * @see Tinebase_Controller_Record_Abstract::search()
150 public function search(Tinebase_Model_Filter_FilterGroup $_filter = NULL, Tinebase_Record_Interface $_pagination = NULL, $_getRelations = FALSE, $_onlyIds = FALSE, $_action = 'get')
152 $result = parent::search($_filter, $_pagination, $_getRelations, $_onlyIds, $_action);
154 if ($_onlyIds !== true) {
155 $this->_removeHiddenListMembers($result);
164 * @see Tinebase_Controller_Record_Abstract::getMultiple()
166 public function getMultiple($_ids, $_ignoreACL = FALSE)
168 $result = parent::getMultiple($_ids, $_ignoreACL);
169 $this->_removeHiddenListMembers($result);
174 * add new members to list
176 * @param mixed $_listId
177 * @param mixed $_newMembers
178 * @return Addressbook_Model_List
180 public function addListMember($_listId, $_newMembers)
183 $list = $this->get($_listId);
184 } catch (Tinebase_Exception_AccessDenied $tead) {
185 $list = $this->_fixEmptyContainerId($_listId);
186 $list = $this->get($_listId);
189 $this->_checkGrant($list, 'update', TRUE, 'No permission to add list member.');
191 $list = $this->_backend->addListMember($_listId, $_newMembers);
193 return $this->get($list->getId());
197 * fixes empty container ids / perhaps this can be removed later as all lists should have a container id!
199 * @param mixed $_listId
200 * @return Addressbook_Model_List
202 protected function _fixEmptyContainerId($_listId)
204 $list = $this->_backend->get($_listId);
206 if (empty($list->container_id)) {
207 $list->container_id = $this->_getDefaultInternalAddressbook();
208 $list = $this->_backend->update($list);
215 * get default internal adb id
219 protected function _getDefaultInternalAddressbook()
221 $appConfigDefaults = Admin_Controller::getInstance()->getConfigSettings();
222 $result = (isset($appConfigDefaults[Admin_Model_Config::DEFAULTINTERNALADDRESSBOOK])) ? $appConfigDefaults[Admin_Model_Config::DEFAULTINTERNALADDRESSBOOK] : NULL;
224 if (empty($result)) {
225 if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__
226 . ' Default internal addressbook not found. Creating new config setting.');
227 $result = Addressbook_Setup_Initialize::setDefaultInternalAddressbook()->getId();
233 * remove members from list
235 * @param mixed $_listId
236 * @param mixed $_newMembers
237 * @return Addressbook_Model_List
239 public function removeListMember($_listId, $_newMembers)
241 $list = $this->get($_listId);
243 $this->_checkGrant($list, 'update', TRUE, 'No permission to remove list member.');
244 $list = $this->_backend->removeListMember($_listId, $_newMembers);
246 return $this->get($list->getId());
250 * inspect creation of one record
252 * @param Tinebase_Record_Interface $_record
255 protected function _inspectBeforeCreate(Tinebase_Record_Interface $_record)
257 if (isset($record->type) && $record->type == Addressbook_Model_List::LISTTYPE_GROUP) {
258 throw new Addressbook_Exception_InvalidArgument('can not add list of type ' . Addressbook_Model_List::LISTTYPE_GROUP);
263 * inspect creation of one record (after create)
265 * @param Tinebase_Record_Interface $_createdRecord
266 * @param Tinebase_Record_Interface $_record
269 protected function _inspectAfterCreate($_createdRecord, Tinebase_Record_Interface $_record)
271 $this->_fireChangeListeEvent($_createdRecord);
275 * inspect update of one record
277 * @param Tinebase_Record_Interface $_record the update record
278 * @param Tinebase_Record_Interface $_oldRecord the current persistent record
281 protected function _inspectBeforeUpdate($_record, $_oldRecord)
283 if (isset($record->type) && $record->type == Addressbook_Model_List::LISTTYPE_GROUP) {
284 throw new Addressbook_Exception_InvalidArgument('can not update list of type ' . Addressbook_Model_List::LISTTYPE_GROUP);
289 * inspect update of one record (after update)
291 * @param Tinebase_Record_Interface $updatedRecord the just updated record
292 * @param Tinebase_Record_Interface $record the update record
293 * @param Tinebase_Record_Interface $currentRecord the current record (before update)
296 protected function _inspectAfterUpdate($updatedRecord, $record, $currentRecord)
298 $this->_fireChangeListeEvent($updatedRecord);
302 * fireChangeListeEvent
304 * @param Addressbook_Model_List $list
306 protected function _fireChangeListeEvent(Addressbook_Model_List $list)
308 $event = new Addressbook_Event_ChangeList();
309 $event->list = $list;
310 Tinebase_Event::fireEvent($event);
314 * inspects delete action
317 * @return array of ids to actually delete
319 protected function _inspectDelete(array $_ids)
321 $lists = $this->getMultiple($_ids);
322 foreach ($lists as $list) {
323 $event = new Addressbook_Event_DeleteList();
324 $event->list = $list;
325 Tinebase_Event::fireEvent($event);
332 * create or update list in addressbook sql backend
334 * @param Tinebase_Model_Group $group
335 * @return Addressbook_Model_List
337 public function createOrUpdateByGroup(Tinebase_Model_Group $group)
339 if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($group->toArray(), TRUE));
342 if (empty($group->list_id)) {
343 $list = $this->_backend->getByGroupName($group->name);
345 // jump to catch block => no list_id provided and no existing list for group found
346 throw new Tinebase_Exception_NotFound('list_id is empty');
348 $group->list_id = $list->getId();
350 $list = $this->_backend->get($group->list_id);
353 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
354 . ' Update list ' . $group->name);
356 $list->name = $group->name;
357 $list->description = $group->description;
358 $list->email = $group->email;
359 $list->type = Addressbook_Model_List::LISTTYPE_GROUP;
360 $list->container_id = (empty($group->container_id)) ? $this->_getDefaultInternalAddressbook() : $group->container_id;
361 $list->members = (isset($group->members)) ? $this->_getContactIds($group->members) : array();
364 Tinebase_Timemachine_ModificationLog::setRecordMetaData($list, 'update');
366 $list = $this->_backend->update($list);
367 $list = $this->get($list->getId());
369 } catch (Tinebase_Exception_NotFound $tenf) {
370 $list = $this->createByGroup($group);
377 * create new list by group
379 * @param Tinebase_Model_Group $group
380 * @return Addressbook_Model_List
382 public function createByGroup($group)
384 $list = new Addressbook_Model_List(array(
385 'name' => $group->name,
386 'description' => $group->description,
387 'email' => $group->email,
388 'type' => Addressbook_Model_List::LISTTYPE_GROUP,
389 'container_id' => (empty($group->container_id)) ? $this->_getDefaultInternalAddressbook() : $group->container_id,
390 'members' => (isset($group->members)) ? $this->_getContactIds($group->members) : array(),
394 Tinebase_Timemachine_ModificationLog::setRecordMetaData($list, 'create');
396 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
397 . ' Add new list ' . $group->name);
398 if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
399 . ' ' . print_r($list->toArray(), TRUE));
401 $list = $this->_backend->create($list);
407 * get contact_ids of users
409 * @param array $_userIds
412 protected function _getContactIds($_userIds)
414 $contactIds = array();
416 if (empty($_userIds)) {
420 foreach ($_userIds as $userId) {
421 $user = Tinebase_User::getInstance()->getUserByPropertyFromSqlBackend('accountId', $userId);
422 if (!empty($user->contact_id)) {
423 $contactIds[] = $user->contact_id;
431 * you can define default filters here
433 * @param Tinebase_Model_Filter_FilterGroup $_filter
435 protected function _addDefaultFilter(Tinebase_Model_Filter_FilterGroup $_filter = NULL)
437 if (!$_filter->isFilterSet('showHidden')) {
438 $hiddenFilter = $_filter->createFilter('showHidden', 'equals', FALSE);
439 $hiddenFilter->setIsImplicit(TRUE);
440 $_filter->addFilter($hiddenFilter);
445 * set relations / tags / alarms
447 * @param Tinebase_Record_Interface $updatedRecord the just updated record
448 * @param Tinebase_Record_Interface $record the update record
449 * @param Tinebase_Record_Interface $currentRecord the original record if one exists
450 * @param boolean $returnUpdatedRelatedData
451 * @return Tinebase_Record_Interface
453 protected function _setRelatedData(Tinebase_Record_Interface $updatedRecord, Tinebase_Record_Interface $record, Tinebase_Record_Interface $currentRecord = null, $returnUpdatedRelatedData = FALSE)
455 if (isset($record->memberroles)) {
457 // TODO add generic helper fn for this?
458 $memberrolesToSet = (!$record->memberroles instanceof Tinebase_Record_RecordSet)
459 ? new Tinebase_Record_RecordSet(
460 'Addressbook_Model_ListMemberRole',
461 $record->memberroles,
462 /* $_bypassFilters */ true
463 ) : $record->memberroles;
465 foreach ($memberrolesToSet as $memberrole) {
466 foreach (array('contact_id', 'list_role_id', 'list_id') as $field) {
467 if (isset($memberrole[$field]['id'])) {
468 $memberrole[$field] = $memberrole[$field]['id'];
473 $currentMemberroles = $this->_getMemberRoles($record);
474 $diff = $currentMemberroles->diff($memberrolesToSet);
475 if (count($diff['added']) > 0) {
476 $diff['added']->list_id = $updatedRecord->getId();
477 foreach ($diff['added'] as $memberrole) {
478 $this->_getMemberRolesBackend()->create($memberrole);
481 if (count($diff['removed']) > 0) {
482 $this->_getMemberRolesBackend()->delete($diff['removed']->getArrayOfIds());
486 $result = parent::_setRelatedData($updatedRecord, $record, $currentRecord, $returnUpdatedRelatedData);
492 * add related data to record
494 * @param Tinebase_Record_Interface $record
496 protected function _getRelatedData($record)
498 $memberRoles = $this->_getMemberRoles($record);
499 if (count($memberRoles) > 0) {
500 $record->memberroles = $memberRoles;
502 parent::_getRelatedData($record);
505 protected function _getMemberRoles($record)
507 $result = $this->_getMemberRolesBackend()->getMultipleByProperty($record->getId(), 'list_id');
512 * get all lists given contact is member of
517 public function getMemberships($contact)
519 return $this->_backend->getMemberships($contact);