/** * import helper * * @param array $_options * @param string|Tinebase_Model_ImportExportDefinition $_definition * @param Tinebase_Model_Filter_FilterGroup $_exportFilter * @throws Tinebase_Exception_NotFound * @return array */ protected function _doImport(array $_options, $_definition, Tinebase_Model_Filter_FilterGroup $_exportFilter = NULL) { if (!$this->_importerClassName || !$this->_modelName) { throw new Tinebase_Exception_NotFound('No import class or model name given'); } $definition = $_definition instanceof Tinebase_Model_ImportExportDefinition ? $_definition : Tinebase_ImportExportDefinition::getInstance()->getByName($_definition); $this->_instance = call_user_func_array($this->_importerClassName . '::createFromDefinition', array($definition, $_options)); // export first if ($_exportFilter !== NULL && $this->_exporterClassName) { $exporter = new $this->_exporterClassName($_exportFilter, Tinebase_Core::getApplicationInstance($this->_modelName)); $this->_filename = $exporter->generate(); } // then import $result = $this->_instance->importFile($this->_filename); return $result; }
/** * append relation filter * * @param Crm_Model_LeadFilter $filter */ protected function _appendRelationFilter($filter) { if (!Tinebase_Core::getPreference()->getValue(Tinebase_Preference::ADVANCED_SEARCH, false)) { return; } $relationsToSearchIn = array('Addressbook_Model_Contact', 'Sales_Model_Product', 'Tasks_Model_Task'); $leadIds = array(); foreach ($relationsToSearchIn as $relatedModel) { $filterModel = $relatedModel . 'Filter'; $relatedFilter = new $filterModel(array(array('field' => 'query', 'operator' => 'contains', 'value' => $this->_value))); $relatedIds = Tinebase_Core::getApplicationInstance($relatedModel)->search($relatedFilter, NULL, FALSE, TRUE); $relationFilter = new Tinebase_Model_RelationFilter(array(array('field' => 'own_model', 'operator' => 'equals', 'value' => 'Crm_Model_Lead'), array('field' => 'related_model', 'operator' => 'equals', 'value' => $relatedModel), array('field' => 'related_id', 'operator' => 'in', 'value' => $relatedIds))); $leadIds = array_merge($leadIds, Tinebase_Relations::getInstance()->search($relationFilter, NULL)->own_id); } $filter->addFilter(new Tinebase_Model_Filter_Id('id', 'in', $leadIds)); }
/** * the constructor * * @param string $_path * @throws Sabre\DAV\Exception\NotFound */ public function __construct($path) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Record path: ' . $path); } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . print_r(Sabre\DAV\URLUtil::splitPath($path), true)); } try { list($appModel, $id) = Sabre\DAV\URLUtil::splitPath($path); list($appName, $records, $model) = explode('/', $appModel); $this->_record = Tinebase_Core::getApplicationInstance($appName, $model)->get($id); } catch (Tinebase_Exception_NotFound $tenf) { throw new Sabre\DAV\Exception\NotFound('Record ' . $path . ' not found'); } $this->_appName = $appName; $this->_path = $path; }
/** * calls the handleEvent function in the controller of all enabled applications * * @param Tinebase_Event_Object $_eventObject the event object */ public static function fireEvent(Tinebase_Event_Abstract $_eventObject) { self::$events[get_class($_eventObject)][$_eventObject->getId()] = $_eventObject; if (self::isDuplicateEvent($_eventObject)) { // do nothing return; } foreach (Tinebase_Application::getInstance()->getApplicationsByState(Tinebase_Application::ENABLED) as $application) { try { $controller = Tinebase_Core::getApplicationInstance($application, NULL, TRUE); } catch (Tinebase_Exception_NotFound $e) { // application has no controller or is not useable at all continue; } if ($controller instanceof Tinebase_Event_Interface) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . ' (' . __LINE__ . ') calling eventhandler for event ' . get_class($_eventObject) . ' of application ' . (string) $application); } try { $controller->handleEvent($_eventObject); } catch (Exception $e) { if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) { Tinebase_Core::getLogger()->notice(__METHOD__ . ' (' . __LINE__ . ') ' . (string) $application . ' threw an exception: ' . $e->getMessage()); } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . ' (' . __LINE__ . ') ' . $e->getTraceAsString()); } } } } // try custom user defined listeners try { if (@class_exists('CustomEventHooks')) { $methods = get_class_methods('CustomEventHooks'); if (in_array('handleEvent', (array) $methods)) { Tinebase_Core::getLogger()->info(__METHOD__ . ' (' . __LINE__ . ') ' . ' about to process user defined event hook for ' . get_class($_eventObject)); CustomEventHooks::handleEvent($_eventObject); } } } catch (Exception $e) { Tinebase_Core::getLogger()->info(__METHOD__ . ' (' . __LINE__ . ') ' . ' failed to process user defined event hook with message: ' . $e); } unset(self::$events[get_class($_eventObject)][$_eventObject->getId()]); }
/** * send pending alarms * * @param mixed $_eventName * @return void * * @todo sort alarms (by model/...)? * @todo what to do about Tinebase_Model_Alarm::STATUS_FAILURE alarms? */ public function sendPendingAlarms($_eventName) { $eventName = is_array($_eventName) ? $_eventName['eventName'] : $_eventName; $job = Tinebase_AsyncJob::getInstance()->startJob($eventName); if (!$job) { return; } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' No ' . $eventName . ' is running. Starting new one.'); } try { // get all pending alarms $filter = new Tinebase_Model_AlarmFilter(array(array('field' => 'alarm_time', 'operator' => 'before', 'value' => Tinebase_DateTime::now()->subMinute(1)->get(Tinebase_Record_Abstract::ISO8601LONG)), array('field' => 'sent_status', 'operator' => 'equals', 'value' => Tinebase_Model_Alarm::STATUS_PENDING))); $limit = Tinebase_Config::getInstance()->get(Tinebase_Config::ALARMS_EACH_JOB, 100); $pagination = $limit > 0 ? new Tinebase_Model_Pagination(array('limit' => $limit)) : null; $alarms = $this->_backend->search($filter, $pagination); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Sending ' . count($alarms) . ' alarms (limit: ' . $limit . ').'); } // loop alarms and call sendAlarm in controllers foreach ($alarms as $alarm) { list($appName, $i, $itemName) = explode('_', $alarm->model); $appController = Tinebase_Core::getApplicationInstance($appName, $itemName); if ($appController instanceof Tinebase_Controller_Alarm_Interface) { $alarm->sent_time = Tinebase_DateTime::now(); try { // NOTE: we set the status here, so controller can adopt the status itself $alarm->sent_status = Tinebase_Model_Alarm::STATUS_SUCCESS; $appController->sendAlarm($alarm); } catch (Exception $e) { Tinebase_Exception::log($e); $alarm->sent_message = $e->getMessage(); $alarm->sent_status = Tinebase_Model_Alarm::STATUS_FAILURE; } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Updating alarm status: ' . $alarm->sent_status); } $this->update($alarm); } } $job = Tinebase_AsyncJob::getInstance()->finishJob($job); } catch (Exception $e) { // save new status 'failure' $job = Tinebase_AsyncJob::getInstance()->finishJob($job, Tinebase_Model_AsyncJob::STATUS_FAILURE, $e->getMessage()); if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Job failed: ' . $e->getMessage()); } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $e->getTraceAsString()); } } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Job ' . $eventName . ' finished.'); } }
/** * get default modelconfig methods * * @return array of Zend_Server_Method_Definition */ protected static function _getModelConfigMethods() { // get all apps user has RUN right for $userApplications = Tinebase_Core::getUser()->getApplications(); $definitions = array(); foreach ($userApplications as $application) { try { $controller = Tinebase_Core::getApplicationInstance($application->name); $models = $controller->getModels(); if (!$models) { continue; } } catch (Exception $e) { Tinebase_Exception::log($e); continue; } foreach ($models as $model) { $config = $model::getConfiguration(); if ($config && $config->exposeJsonApi) { // TODO replace this with generic method $simpleModelName = str_replace($application->name . '_Model_', '', $model); $commonJsonApiMethods = array('get' => array('params' => array(new Zend_Server_Method_Parameter(array('type' => 'string', 'name' => 'id'))), 'help' => 'get one ' . $simpleModelName . ' identified by $id', 'plural' => false), 'search' => array('params' => array(new Zend_Server_Method_Parameter(array('type' => 'array', 'name' => 'filter')), new Zend_Server_Method_Parameter(array('type' => 'array', 'name' => 'paging'))), 'help' => 'Search for ' . $simpleModelName . 's matching given arguments', 'plural' => true), 'save' => array('params' => array(new Zend_Server_Method_Parameter(array('type' => 'array', 'name' => 'recordData'))), 'help' => 'Save ' . $simpleModelName . '', 'plural' => false), 'delete' => array('params' => array(new Zend_Server_Method_Parameter(array('type' => 'array', 'name' => 'ids'))), 'help' => 'Delete multiple ' . $simpleModelName . 's', 'plural' => true)); foreach ($commonJsonApiMethods as $name => $method) { $key = $application->name . '.' . $name . $simpleModelName . ($method['plural'] ? 's' : ''); $appJsonFrontendClass = $application->name . '_Frontend_Json'; if (class_exists($appJsonFrontendClass)) { $class = $appJsonFrontendClass; $object = null; } else { $class = 'Tinebase_Frontend_Json_Generic'; $object = new Tinebase_Frontend_Json_Generic($application->name); } $definitions[$key] = new Zend_Server_Method_Definition(array('name' => $key, 'prototypes' => array(array('returnType' => 'array', 'parameters' => $method['params'])), 'methodHelp' => $method['help'], 'invokeArguments' => array(), 'object' => $object, 'callback' => array('type' => 'instance', 'class' => $class, 'method' => $name . $simpleModelName . ($method['plural'] ? 's' : '')))); } } } } if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Got MC definitions: ' . print_r(array_keys($definitions), true)); } return $definitions; }
/** * move records to container * * @param string $targetContainerId * @param array $filterData * @param string $applicationName * @param string $model * @return array */ public function moveRecordsToContainer($targetContainerId, $filterData, $applicationName, $model) { $filterModel = $applicationName . '_Model_' . $model . 'Filter'; $filter = new $filterModel(array()); $filter->setFromArrayInUsersTimezone($filterData); $this->_longRunningRequest(); $recordController = Tinebase_Core::getApplicationInstance($applicationName, $model); $result = $recordController->move($filter, $targetContainerId); return array('status' => 'success', 'results' => $result); }
/** * resolve foreign fields for records like user ids to users, etc. * * @param Tinebase_Record_RecordSet $records * @param string $foreignRecordClassName * @param array $fields */ protected static function _resolveForeignIdFields($records, $foreignRecordClassName, $fields) { $options = isset($fields['options']) || array_key_exists('options', $fields) ? $fields['options'] : array(); $fields = isset($fields['fields']) || array_key_exists('fields', $fields) ? $fields['fields'] : $fields; $foreignIds = array(); foreach ($fields as $field) { $foreignIds = array_unique(array_merge($foreignIds, $records->{$field})); } try { $controller = Tinebase_Core::getApplicationInstance($foreignRecordClassName); } catch (Tinebase_Exception_AccessDenied $tead) { if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) { Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' No right to access application of record ' . $foreignRecordClassName); } return; } if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Fetching ' . $foreignRecordClassName . ' by id: ' . print_r($foreignIds, TRUE)); } if ((isset($options['ignoreAcl']) || array_key_exists('ignoreAcl', $options)) && $options['ignoreAcl']) { // @todo make sure that second param of getMultiple() is $ignoreAcl $foreignRecords = $controller->getMultiple($foreignIds, TRUE); } else { $foreignRecords = $controller->getMultiple($foreignIds); } if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Foreign records found: ' . print_r($foreignRecords->toArray(), TRUE)); } if (count($foreignRecords) === 0) { return; } foreach ($records as $record) { foreach ($fields as $field) { if (is_scalar($record->{$field})) { $idx = $foreignRecords->getIndexById($record->{$field}); if (isset($idx) && $idx !== FALSE) { $record->{$field} = $foreignRecords[$idx]; } else { switch ($foreignRecordClassName) { case 'Tinebase_Model_User': case 'Tinebase_Model_FullUser': $record->{$field} = Tinebase_User::getInstance()->getNonExistentUser(); break; default: // skip } } } } } }
/** * get option setting string * * @deprecated * @param Tinebase_Record_Interface $_record * @param string $_id * @param string $_label * @return string */ public static function getOptionString($_record, $_label) { $controller = Tinebase_Core::getApplicationInstance($_record->getApplication()); $settings = $controller->getConfigSettings(); $idField = $_label . '_id'; $option = $settings->getOptionById($_record->{$idField}, $_label . 's'); $result = isset($option[$_label]) ? $option[$_label] : ''; return $result; }
/** * @param Sales_Model_ProductAggregate $productAggregate * @return null|Tinebase_Record_RecordSet * @throws Tinebase_Exception_AccessDenied * @throws Tinebase_Exception_NotFound */ protected function _getProductAccountables(Sales_Model_ProductAggregate $productAggregate) { $json_attributes = $productAggregate->json_attributes; if (!is_array($json_attributes) || !isset($json_attributes['assignedAccountables'])) { return null; } $product = Sales_Controller_Product::getInstance()->get($productAggregate->product_id); if ($product->accountable == '') { return null; } $app = Tinebase_Core::getApplicationInstance($product->accountable, ''); return $app->getMultiple($json_attributes['assignedAccountables']); }
/** * gets image info and data * * @param string $_application application which manages the image * @param string $_identifier identifier of image/record * @param string $_location optional additional identifier * @return Tinebase_Model_Image * @throws Tinebase_Exception_NotFound * @throws Tinebase_Exception_UnexpectedValue */ public function getImage($_application, $_identifier, $_location = '') { $appController = Tinebase_Core::getApplicationInstance($_application); if (!method_exists($appController, 'getImage')) { throw new Tinebase_Exception_NotFound("{$_application} has no getImage function."); } $image = $appController->getImage($_identifier, $_location); if (!$image instanceof Tinebase_Model_Image) { throw new Tinebase_Exception_UnexpectedValue("{$_application} returned invalid image."); } return $image; }
/** * creates a new container * * @todo allow to create personal folders only when in currents users own path * * @param array $properties properties for new container * @throws \Sabre\DAV\Exception\Forbidden * @return Tinebase_Model_Container */ protected function _createContainer(array $properties) { if (count($this->_getPathParts()) !== 2) { throw new \Sabre\DAV\Exception\Forbidden('Permission denied to create directory ' . $properties['name']); } $containerType = Tinebase_Helper::array_value(1, $this->_getPathParts()) == Tinebase_Model_Container::TYPE_SHARED ? Tinebase_Model_Container::TYPE_SHARED : Tinebase_Model_Container::TYPE_PERSONAL; $newContainer = new Tinebase_Model_Container(array_merge($properties, array('type' => $containerType, 'backend' => 'Sql', 'application_id' => $this->_getApplication()->getId(), 'model' => Tinebase_Core::getApplicationInstance($this->_applicationName)->getDefaultModel()))); try { $container = Tinebase_Container::getInstance()->addContainer($newContainer); } catch (Tinebase_Exception_AccessDenied $tead) { throw new \Sabre\DAV\Exception\Forbidden('Permission denied to create directory ' . $properties['name']); } return $container; }
/** * generates path for the record * * @param Tinebase_Record_Abstract $record * @param boolean $rebuildRecursively * @return Tinebase_Record_RecordSet * * TODO what about acl? the account who creates the path probably does not see all relations ... */ public function generatePathForRecord(Tinebase_Record_Abstract $record, $rebuildRecursively = false) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Generate path for ' . get_class($record) . ' record with id ' . $record->getId()); } $recordController = Tinebase_Core::getApplicationInstance(get_class($record)); // if we rebuild recursively, dont do any tree operation, just rebuild the paths for the record and be done with it if (false === $rebuildRecursively) { // fetch full record + check acl $record = $recordController->get($record->getId()); $currentPaths = Tinebase_Record_Path::getInstance()->getPathsForRecords($record); } $newPaths = new Tinebase_Record_RecordSet('Tinebase_Model_Path'); // fetch all parent -> child relations and add to path $newPaths->merge($this->_getPathsOfRecord($record, $rebuildRecursively)); if (method_exists($recordController, 'generatePathForRecord')) { $newPaths->merge($recordController->generatePathForRecord($record)); } // if we rebuild recursively, dont do any tree operation, just rebuild the paths for the record and be done with it if (false === $rebuildRecursively) { //compare currentPaths with newPaths to find out if we need to make subtree updates //we should do this before the new paths of the current record have been persisted to DB! $currentShadowPathOffset = array(); foreach ($currentPaths as $offset => $path) { $currentShadowPathOffset[$path->shadow_path] = $offset; } $newShadowPathOffset = array(); foreach ($newPaths as $offset => $path) { $newShadowPathOffset[$path->shadow_path] = $offset; } $toDelete = array(); $anyOldOffset = null; foreach ($currentShadowPathOffset as $shadowPath => $offset) { $anyOldOffset = $offset; // parent path has been deleted! if (false === isset($newShadowPathOffset[$shadowPath])) { $toDelete[] = $shadowPath; continue; } $currentPath = $currentPaths[$offset]; $newPath = $newPaths[$newShadowPathOffset[$shadowPath]]; // path changed (a title was updated or similar) if ($currentPath->path !== $newPath->path) { // update ... set path = REPLACE(path, $currentPath->path, $newPath->path) where shadow_path LIKE '$shadowPath/%' $this->_backend->replacePathForShadowPathTree($shadowPath, $currentPath->path, $newPath->path); } unset($newShadowPathOffset[$shadowPath]); } // new parents if (count($newShadowPathOffset) > 0 && null !== $anyOldOffset) { $anyPath = $currentPaths[$anyOldOffset]; $newParents = array_values($newShadowPathOffset); foreach ($newParents as $newParentOffset) { $newParent = $newPaths[$newParentOffset]; // insert into ... select // REPLACE(path, $anyPath->path, $newParent->path) as path, // REPLACE(shadow_path, $anyPath->shadow_path, $newParent->shadow_path) as shadow_path // from ... where shadow_path LIKE '$anyPath->shadow_path/%' $this->_backend->copyTreeByShadowPath($anyPath->shadow_path, $newParent->path, $anyPath->path, $newParent->shadow_path, $anyPath->shadow_path); } } //execute deletes only now, important to make 100% sure "new parents" just above still has data to work on! foreach ($toDelete as $delete) { // delete where shadow_path LIKE '$delete/%' $this->_backend->deleteForShadowPathTree($delete); } } // delete current paths of this record $this->deletePathsForRecord($record); // recreate new paths of this record foreach ($newPaths as $path) { $this->_backend->create($path); } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Created ' . count($newPaths) . ' paths.'); } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . print_r($newPaths->toArray(), true)); } return $newPaths; }
/** * create a new system container * - by default user group gets READ grant * - by default admin group gets all grants * * NOTE: this should never be called in user land and only in admin/setup contexts * * @param Tinebase_Model_Application|string $application app record, app id or app name * @param string $name * @param string $idConfig save id in config if given * @param Tinebase_Record_RecordSet $grants use this to overwrite default grants * @param string $model the model the container contains * @return Tinebase_Model_Container */ public function createSystemContainer($application, $name, $configId = NULL, Tinebase_Record_RecordSet $grants = NULL, $model = NULL) { $application = $application instanceof Tinebase_Model_Application ? $application : Tinebase_Application::getInstance()->getApplicationById($application); if ($model === null) { $controller = Tinebase_Core::getApplicationInstance($application->name, '', true); $model = $controller->getDefaultModel(); } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Creating system container for model ' . $model); } $newContainer = new Tinebase_Model_Container(array('name' => $name, 'type' => Tinebase_Model_Container::TYPE_SHARED, 'backend' => 'Sql', 'application_id' => $application->getId(), 'model' => $model)); $groupsBackend = Tinebase_Group::getInstance(); $grants = $grants ? $grants : new Tinebase_Record_RecordSet('Tinebase_Model_Grants', array(array('account_id' => $groupsBackend->getDefaultGroup()->getId(), 'account_type' => Tinebase_Acl_Rights::ACCOUNT_TYPE_GROUP, Tinebase_Model_Grants::GRANT_READ => true, Tinebase_Model_Grants::GRANT_EXPORT => true, Tinebase_Model_Grants::GRANT_SYNC => true), array('account_id' => $groupsBackend->getDefaultAdminGroup()->getId(), 'account_type' => Tinebase_Acl_Rights::ACCOUNT_TYPE_GROUP, Tinebase_Model_Grants::GRANT_READ => true, Tinebase_Model_Grants::GRANT_ADD => true, Tinebase_Model_Grants::GRANT_EDIT => true, Tinebase_Model_Grants::GRANT_DELETE => true, Tinebase_Model_Grants::GRANT_ADMIN => true, Tinebase_Model_Grants::GRANT_EXPORT => true, Tinebase_Model_Grants::GRANT_SYNC => true)), TRUE); $newContainer = Tinebase_Container::getInstance()->addContainer($newContainer, $grants, TRUE); if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Created new system container ' . $name . ' for application ' . $application->name); } if ($configId !== NULL) { $configClass = $application->name . '_Config'; if (@class_exists($configClass)) { $config = call_user_func(array($configClass, 'getInstance')); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Setting system container config "' . $configId . '" = ' . $newContainer->getId()); } $config->set($configId, $newContainer->getId()); } else { if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) { Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' Could not find preferences class ' . $configClass); } } } $this->resetClassCache(); return $newContainer; }
/** * delete linked objects (notes, relations, ...) of record * * @param Tinebase_Record_Interface $_record */ protected function _deleteLinkedObjects(Tinebase_Record_Interface $_record) { // delete notes & relations if ($_record->has('notes')) { Tinebase_Notes::getInstance()->deleteNotesOfRecord($this->_modelName, $this->_backend->getType(), $_record->getId()); } if ($_record->has('relations')) { $relations = Tinebase_Relations::getInstance()->getRelations($this->_modelName, $this->_backend->getType(), $_record->getId()); if (!empty($relations)) { // remove relations Tinebase_Relations::getInstance()->setRelations($this->_modelName, $this->_backend->getType(), $_record->getId(), array()); // remove related objects if (!empty($this->_relatedObjectsToDelete)) { foreach ($relations as $relation) { if (in_array($relation->related_model, $this->_relatedObjectsToDelete)) { list($appName, $i, $itemName) = explode('_', $relation->related_model); $appController = Tinebase_Core::getApplicationInstance($appName, $itemName); $appController->delete($relation->related_id); } } } } } }
/** * set controller */ protected function _setController() { $this->_controller = Tinebase_Core::getApplicationInstance($this->_options['model']); }
/** * merge duplicate shared tags * * @param string $model record model for which tags should be merged * @param boolean $deleteObsoleteTags * @param boolean $ignoreAcl * * @see 0007354: function for merging duplicate tags */ public function mergeDuplicateSharedTags($model, $deleteObsoleteTags = TRUE, $ignoreAcl = FALSE) { $select = $this->_db->select()->from(array('tags' => SQL_TABLE_PREFIX . 'tags'), 'name')->where($this->_db->quoteIdentifier('type') . ' = ?', Tinebase_Model_Tag::TYPE_SHARED)->where($this->_db->quoteIdentifier('is_deleted') . ' = 0')->group('name')->having('COUNT(' . $this->_db->quoteIdentifier('name') . ') > 1'); $queryResult = $this->_db->fetchAll($select); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Found ' . count($queryResult) . ' duplicate tag names.'); } $controller = Tinebase_Core::getApplicationInstance($model); if ($ignoreAcl) { $containerChecks = $controller->doContainerACLChecks(FALSE); } $recordFilterModel = $model . 'Filter'; foreach ($queryResult as $duplicateTag) { $filter = new Tinebase_Model_TagFilter(array('name' => $duplicateTag['name'], 'type' => Tinebase_Model_Tag::TYPE_SHARED)); $paging = new Tinebase_Model_Pagination(array('sort' => 'creation_time')); $tagsWithSameName = $this->searchTags($filter, $paging); $targetTag = $tagsWithSameName->getFirstRecord(); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Merging tag ' . $duplicateTag['name'] . '. Found ' . count($tagsWithSameName) . ' tags with this name.'); } foreach ($tagsWithSameName as $tag) { if ($tag->getId() === $targetTag->getId()) { // skip target (oldest) tag continue; } $recordFilter = new $recordFilterModel(array(array('field' => 'tag', 'operator' => 'in', 'value' => array($tag->getId())))); $recordIdsWithTagToMerge = $controller->search($recordFilter, NULL, FALSE, TRUE); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Found ' . count($recordIdsWithTagToMerge) . ' ' . $model . '(s) with tags to be merged.'); } if (!empty($recordIdsWithTagToMerge)) { $recordFilter = new $recordFilterModel(array(array('field' => 'id', 'operator' => 'in', 'value' => $recordIdsWithTagToMerge))); $this->attachTagToMultipleRecords($recordFilter, $targetTag); $this->detachTagsFromMultipleRecords($recordFilter, $tag->getId()); } // check occurrence of the merged tag and remove it if obsolete $tag = $this->get($tag); if ($deleteObsoleteTags && $tag->occurrence == 0) { $this->deleteTags($tag->getId(), $ignoreAcl); } } } if ($ignoreAcl) { /** @noinspection PhpUndefinedVariableInspection */ $controller->doContainerACLChecks($containerChecks); } }
/** * returns the personal container of a given account accessible by a another given account * * @param string|Tinebase_Model_User $_accountId * @param string $_application * @param int|Tinebase_Model_User $_owner * @param array|string $_grant * @param bool $_ignoreACL * @return Tinebase_Record_RecordSet of subtype Tinebase_Model_Container * @throws Tinebase_Exception_NotFound */ public function getPersonalContainer($_accountId, $_application, $_owner, $_grant, $_ignoreACL = false) { $accountId = Tinebase_Model_User::convertUserIdToInt($_accountId); $ownerId = Tinebase_Model_User::convertUserIdToInt($_owner); $grant = $_ignoreACL ? '*' : $_grant; $application = Tinebase_Application::getInstance()->getApplicationByName($_application); $select = $this->_db->select()->from(array('owner' => SQL_TABLE_PREFIX . 'container_acl'), array())->join(array('user' => SQL_TABLE_PREFIX . 'container_acl'), "{$this->_db->quoteIdentifier('owner.container_id')} = {$this->_db->quoteIdentifier('user.container_id')}", array())->join(array('container' => SQL_TABLE_PREFIX . 'container'), "{$this->_db->quoteIdentifier('owner.container_id')} = {$this->_db->quoteIdentifier('container.id')}")->where("{$this->_db->quoteIdentifier('owner.account_id')} = ?", $ownerId)->where("{$this->_db->quoteIdentifier('owner.account_grant')} = ?", Tinebase_Model_Grants::GRANT_ADMIN)->where("{$this->_db->quoteIdentifier('container.application_id')} = ?", $application->getId())->where("{$this->_db->quoteIdentifier('container.type')} = ?", Tinebase_Model_Container::TYPE_PERSONAL)->where("{$this->_db->quoteIdentifier('container.is_deleted')} = ?", 0, Zend_Db::INT_TYPE)->group('container.id')->order('container.name'); $this->addGrantsSql($select, $accountId, $grant, 'user'); $select = Tinebase_Backend_Sql_Abstract::traitGroup($this->_db, $this->_tablePrefix, $select); $stmt = $this->_db->query($select); $containersData = $stmt->fetchAll(Zend_Db::FETCH_ASSOC); // if no containers where found, maybe something went wrong when creating the initial folder // let's check if the controller of the application has a function to create the needed folders if (empty($containersData) and $accountId === $ownerId) { $application = Tinebase_Core::getApplicationInstance($application->name); if ($application instanceof Tinebase_Container_Interface) { return $application->createPersonalFolder($accountId); } } $containers = new Tinebase_Record_RecordSet('Tinebase_Model_Container', $containersData, TRUE); return $containers; }
/** * magic method for json api * * @param string $method * @param array $args */ public function __call($method, array $args) { // provides api for default application methods if (preg_match('/^(get|save|search|delete)([a-z0-9]+)/i', $method, $matches)) { $apiMethod = $matches[1]; $model = in_array($apiMethod, array('search', 'delete')) ? substr($matches[2], 0, -1) : $matches[2]; $modelController = Tinebase_Core::getApplicationInstance($this->_applicationName, $model); switch ($apiMethod) { case 'get': return $this->_get($args[0], $modelController); break; case 'save': return $this->_save($args[0], $modelController, $model); break; case 'search': $filterName = $this->_applicationName . '_Model_' . $model . 'Filter'; return $this->_search($args[0], $args[1], $modelController, $filterName, true); break; case 'delete': return $this->_delete($args[0], $modelController); break; } } // call plugin method (see Tinebase_Pluggable_Abstract) return parent::__call($method, $args); }
/** * execute action defined in queue message * * @param array $message action * @return mixed */ public function executeAction($message) { if (!is_array($message) || !(isset($message['action']) || array_key_exists('action', $message)) || strpos($message['action'], '.') === FALSE) { throw new Tinebase_Exception_NotFound('Could not execute action, invalid message/action param'); } if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " executing action: '{$message['action']}'"); } list($appName, $actionName) = explode('.', $message['action']); $controller = Tinebase_Core::getApplicationInstance($appName); if (!method_exists($controller, $actionName)) { throw new Tinebase_Exception_NotFound('Could not execute action, requested action does not exist'); } return call_user_func_array(array($controller, $actionName), $message['params']); }
/** * returns array with the filter settings of this filter * * @param bool $valueToJson resolve value for json api? * @return array */ public function toArray($valueToJson = false) { $result = parent::toArray($valueToJson); if (strtolower($this->_cfRecord->definition['type']) == 'record') { try { $modelParts = explode('.', $this->_cfRecord->definition['recordConfig']['value']['records']); // get model parts from saved record class e.g. Tine.Admin.Model.Group $controller = Tinebase_Core::getApplicationInstance($modelParts[1], $modelParts[3]); $result['value']['value'] = $controller->get($result['value']['value'])->toArray(); } catch (Exception $e) { if (Tinebase_Core::isLogLevel(Zend_Log::ERR)) { Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' Error resolving custom field record: ' . $e->getMessage()); } $result['value']['value'] = $customField->value; } } return $result; }
/** * get controller * * @return Tinebase_Controller_Record_Abstract|null */ protected function _getController() { if ($this->_controller === null) { if (isset($this->_options['controller'])) { $cname = $this->_options['controller']; $this->_controller = $cname::getInstance(); } elseif (isset($this->_options['modelName'])) { $this->_controller = Tinebase_Core::getApplicationInstance($this->_options['modelName']); } else { Tinebase_Core::getLogger()->INFO(__METHOD__ . '::' . __LINE__ . ' No modelName or controller defined in filter options, can not resolve record.'); return null; } } return $this->_controller; }
/** * download file attachment * * @param string $nodeId * @param string $recordId * @param string $modelName */ public function downloadRecordAttachment($nodeId, $recordId, $modelName) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Downloading attachment of ' . $modelName . ' record with id ' . $recordId); } $recordController = Tinebase_Core::getApplicationInstance($modelName); $record = $recordController->get($recordId); $node = Tinebase_FileSystem::getInstance()->get($nodeId); $path = Tinebase_Model_Tree_Node_Path::STREAMWRAPPERPREFIX . Tinebase_FileSystem_RecordAttachments::getInstance()->getRecordAttachmentPath($record) . '/' . $node->name; $this->_downloadFileNode($node, $path); exit; }
/** * * @return Tinebase_Controller_Record_Interface */ protected function _getController() { if ($this->_controller === null) { $this->_controller = Tinebase_Core::getApplicationInstance($this->_application->name, $this->_model); } return $this->_controller; }
/** * clean relations, set relation to deleted if at least one of the ends has been set to deleted or pruned */ public function cleanRelations() { $relations = Tinebase_Relations::getInstance(); $filter = new Tinebase_Model_Filter_FilterGroup(); $pagination = new Tinebase_Model_Pagination(); $pagination->limit = 10000; $pagination->sort = 'id'; $totalCount = 0; $date = Tinebase_DateTime::now()->subYear(1); while (($recordSet = $relations->search($filter, $pagination)) && $recordSet->count() > 0) { $filter = new Tinebase_Model_Filter_FilterGroup(); $pagination->start += $pagination->limit; $models = array(); foreach ($recordSet as $relation) { $models[$relation->own_model][$relation->own_id][] = $relation->id; $models[$relation->related_model][$relation->related_id][] = $relation->id; } foreach ($models as $model => &$ids) { $doAll = false; try { $app = Tinebase_Core::getApplicationInstance($model, '', true); } catch (Tinebase_Exception_NotFound $tenf) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' model: ' . $model . ' no application found for it'); } $doAll = true; } if (!$doAll) { if ($app instanceof Tinebase_Container) { $backend = $app; } else { if (!$app instanceof Tinebase_Controller_Record_Abstract) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' model: ' . $model . ' controller: ' . get_class($app) . ' not an instance of Tinebase_Controller_Record_Abstract'); } continue; } $backend = $app->getBackend(); } if (!$backend instanceof Tinebase_Backend_Interface) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' model: ' . $model . ' backend: ' . get_class($backend) . ' not an instance of Tinebase_Backend_Interface'); } continue; } $record = new $model(null, true); $modelFilter = $model . 'Filter'; $idFilter = new $modelFilter(array(), '', array('ignoreAcl' => true)); $idFilter->addFilter(new Tinebase_Model_Filter_Id(array('field' => $record->getIdProperty(), 'operator' => 'in', 'value' => array_keys($ids)))); $existingIds = $backend->search($idFilter, null, true); if (!is_array($existingIds)) { throw new Exception('search for model: ' . $model . ' returned not an array!'); } foreach ($existingIds as $id) { unset($ids[$id]); } } if (count($ids) > 0) { $toDelete = array(); foreach ($ids as $idArrays) { foreach ($idArrays as $id) { $toDelete[$id] = true; } } $toDelete = array_keys($toDelete); foreach ($toDelete as $id) { if ($recordSet->getById($id)->creation_time && $recordSet->getById($id)->creation_time->isLater($date)) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' relation is about to get deleted that is younger than 1 year: ' . print_r($recordSet->getById($id)->toArray(false), true)); } } $relations->delete($toDelete); $totalCount += count($toDelete); } } } $message = 'Deleted ' . $totalCount . ' relations in total'; if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ' . $message); } echo $message . "\n"; }
/** * delete linked relations * * @param Tinebase_Record_Interface $_record * * TODO check if this needs to be done, as we might already deleting this "from the other side" */ protected function _deleteLinkedRelations(Tinebase_Record_Interface $_record) { $relations = Tinebase_Relations::getInstance()->getRelations($this->_modelName, $this->_getBackendType(), $_record->getId()); if (empty($relations)) { return; } // remove relations Tinebase_Relations::getInstance()->setRelations($this->_modelName, $this->_getBackendType(), $_record->getId(), array()); if (empty($this->_relatedObjectsToDelete)) { return; } // remove related objects Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Deleting all ' . implode(',', $this->_relatedObjectsToDelete) . ' relations.'); foreach ($relations as $relation) { if (in_array($relation->related_model, $this->_relatedObjectsToDelete)) { list($appName, $i, $itemName) = explode('_', $relation->related_model); $appController = Tinebase_Core::getApplicationInstance($appName, $itemName); try { $appController->delete($relation->related_id); } catch (Exception $e) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Error deleting: ' . $e->getMessage()); } } } }
/** * return autocomplete suggestions for a given recordclass, the property and value * * @param string $appName * @param string $modelName * @param string $property * @param string $startswith * * @return array */ public function autoComplete($appName, $modelName, $property, $startswith) { $recordClassName = $appName . '_Model_' . $modelName; $controller = Tinebase_Core::getApplicationInstance($appName, $modelName); $filterClassName = $recordClassName . 'Filter'; if (!class_exists($recordClassName)) { throw new Tinebase_Exception_InvalidArgument('A record class for the given appName and modelName does not exist!'); } if (!$controller) { throw new Tinebase_Exception_InvalidArgument('A controller for the given appName and modelName does not exist!'); } if (!class_exists($filterClassName)) { throw new Tinebase_Exception_InvalidArgument('A filter for the given appName and modelName does not exist!'); } if (!in_array($property, $recordClassName::getAutocompleteFields())) { throw new Tinebase_Exception_UnexpectedValue('bad property name'); } $filter = new $filterClassName(array(array('field' => $property, 'operator' => 'startswith', 'value' => $startswith))); $paging = new Tinebase_Model_Pagination(array('sort' => $property)); $values = array_unique($controller->search($filter, $paging)->{$property}); $result = array('results' => array(), 'totalcount' => count($values)); foreach ($values as $value) { $result['results'][] = array($property => $value); } return $result; }
/** * gets image info and data * * @param string $application application which manages the image * @param string $identifier identifier of image/record * @param string $location optional additional identifier * @return Tinebase_Model_Image * @throws Tinebase_Exception_NotFound * @throws Tinebase_Exception_UnexpectedValue */ public function getImage($application, $identifier, $location = '') { if ($location === 'vfs') { $node = Tinebase_FileSystem::getInstance()->get($identifier); $path = Tinebase_Model_Tree_Node_Path::STREAMWRAPPERPREFIX . Tinebase_FileSystem::getInstance()->getPathOfNode($node, true); $image = Tinebase_ImageHelper::getImageInfoFromBlob(file_get_contents($path)); } else { if ($application == 'Tinebase' && $location == 'tempFile') { $tempFile = Tinebase_TempFile::getInstance()->getTempFile($identifier); $image = Tinebase_ImageHelper::getImageInfoFromBlob(file_get_contents($tempFile->path)); } else { $appController = Tinebase_Core::getApplicationInstance($application); if (!method_exists($appController, 'getImage')) { throw new Tinebase_Exception_NotFound("{$application} has no getImage function."); } $image = $appController->getImage($identifier, $location); } } if (!$image instanceof Tinebase_Model_Image) { if (is_array($image)) { $image = new Tinebase_Model_Image($image + array('application' => $application, 'id' => $identifier, 'location' => $location)); } else { throw new Tinebase_Exception_UnexpectedValue('broken image'); } } return $image; }
/** * Used for updating multiple records * * @param string $appName * @param string $modelName * @param array $changes * @param array $filter */ public function updateMultipleRecords($appName, $modelName, $changes, $filter) { $filterModel = $appName . '_Model_' . $modelName . 'Filter'; foreach ($changes as $f) { $data[preg_replace('/^customfield_/', '#', $f['name'])] = $f['value']; } return $this->_updateMultiple($filter, $data, Tinebase_Core::getApplicationInstance($appName, $modelName), $filterModel); }
/** * append relation filter * * @param string $ownModel * @param array $relationsToSearchIn * @return Tinebase_Model_Filter_Id */ protected function _getAdvancedSearchFilter($ownModel = null, $relationsToSearchIn = null) { if (Tinebase_Core::get('ADVANCED_SEARCHING') || !Tinebase_Core::getPreference()->getValue(Tinebase_Preference::ADVANCED_SEARCH, false) || empty($relationsToSearchIn)) { return null; } if (0 === strpos($this->_operator, 'not')) { $not = true; $operator = substr($this->_operator, 3); } else { $not = false; $operator = $this->_operator; } $ownIds = array(); foreach ((array) $relationsToSearchIn as $relatedModel) { $filterModel = $relatedModel . 'Filter'; // prevent recursion here // TODO find a better way for this, maybe we could pass this an option to all filters in filter model Tinebase_Core::set('ADVANCED_SEARCHING', true); $relatedFilter = new $filterModel(array(array('field' => 'query', 'operator' => $operator, 'value' => $this->_value))); $relatedIds = Tinebase_Core::getApplicationInstance($relatedModel)->search($relatedFilter, NULL, FALSE, TRUE); Tinebase_Core::set('ADVANCED_SEARCHING', false); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Found ' . count($relatedIds) . ' related ids'); } $relationFilter = new Tinebase_Model_RelationFilter(array(array('field' => 'own_model', 'operator' => 'equals', 'value' => $ownModel), array('field' => 'related_model', 'operator' => 'equals', 'value' => $relatedModel), array('field' => 'related_id', 'operator' => 'in', 'value' => $relatedIds))); $ownIds = array_merge($ownIds, Tinebase_Relations::getInstance()->search($relationFilter, NULL)->own_id); } return new Tinebase_Model_Filter_Id('id', $not ? 'notin' : 'in', $ownIds); }