/** * creates shared tas */ protected function _createSharedTimeaccounts() { // create 2 timeaccounts for each cc $taNumber = 1; $userGroup = Tinebase_Group::getInstance()->getGroupByName('Users'); $developmentString = self::$_de ? 'Entwicklung' : 'Development'; if (!$userGroup) { die('Could not find userGroup "Users", stopping.'); } $grants = array(array('account_id' => $userGroup->getId(), 'account_type' => 'group', 'bookOwnGrant' => TRUE, 'viewAllGrant' => TRUE, 'bookAllGrant' => TRUE, 'manageBillableGrant' => TRUE, 'exportGrant' => TRUE, 'adminGrant' => TRUE)); $contractsIndex = 0; foreach ($this->_costCenters as $costcenter) { $this->_timeAccounts[$costcenter->getId()] = new Tinebase_Record_RecordSet('Timetracker_Model_Timeaccount'); $i = 0; while ($i < 2) { $i++; $ta = new Timetracker_Model_Timeaccount(array('number' => $taNumber, 'title' => Tinebase_Record_Abstract::generateUID(3), 'grants' => $grants, 'status' => 'billed', 'cleared_at' => $this->_clearedDate, 'budget' => NULL, 'description' => 'Created By Tine 2.0 DEMO DATA')); if ($costcenter->remark == 'Marketing' || $costcenter->remark == $developmentString) { $contract = $costcenter->remark == 'Marketing' ? $this->_contractsMarketing->getByIndex(rand(0, $this->_contractsMarketing->count() - 1)) : $this->_contractsDevelopment->getByIndex(rand(0, $this->_contractsDevelopment->count() - 1)); $ta->budget = $costcenter->remark == 'Marketing' ? 100 : NULL; $ta->relations = array(array('own_model' => 'Timetracker_Model_Timeaccount', 'own_backend' => 'SQL', 'own_id' => NULL, 'related_degree' => Tinebase_Model_Relation::DEGREE_SIBLING, 'related_model' => 'Sales_Model_CostCenter', 'related_backend' => Tasks_Backend_Factory::SQL, 'related_id' => $costcenter->getId(), 'type' => 'COST_CENTER'), array('own_model' => 'Timetracker_Model_Timeaccount', 'own_backend' => 'SQL', 'own_id' => NULL, 'related_degree' => Tinebase_Model_Relation::DEGREE_SIBLING, 'related_model' => 'Sales_Model_Contract', 'related_backend' => Tasks_Backend_Factory::SQL, 'related_id' => $contract->getId(), 'type' => 'TIME_ACCOUNT')); $ta->title = (self::$_de ? 'Zeitkonto mit ' : 'Timeaccount for ') . $contract->getTitle(); } else { $ta->title = (self::$_de ? 'Zeitkonto mit KST ' : 'Timeaccount for CC ') . $costcenter->getTitle(); $ta->relations = array(array('own_model' => 'Timetracker_Model_Timeaccount', 'own_backend' => 'SQL', 'own_id' => NULL, 'related_degree' => Tinebase_Model_Relation::DEGREE_SIBLING, 'related_model' => 'Sales_Model_CostCenter', 'related_backend' => Tasks_Backend_Factory::SQL, 'related_id' => $costcenter->getId(), 'type' => 'COST_CENTER')); } $this->_timeAccounts[$costcenter->getId()]->addRecord($this->_taController->create($ta)); $taNumber++; } } }
/** * testCount(). */ public function testCount() { $before = $this->object->count(); $record = new Tinebase_Record_DummyRecord(array(), true); $this->object->addRecord($record); $this->assertEquals($this->object->count(), $before + 1); }
protected function _testFullFixtures() { $this->assertEquals(4, $this->_customerRecords->count()); $this->assertEquals(12, $this->_addressRecords->count()); $this->assertEquals(4, $this->_contractRecords->count()); $this->assertEquals(20, $this->_contactRecords->count()); }
/** * inspect creation of one record (before create) * * @param Tinebase_Record_Interface $_record * @return void */ protected function _inspectBeforeCreate(Tinebase_Record_Interface $_record) { $this->_freedaysToCreate = new Tinebase_Record_RecordSet('HumanResources_Model_FreeDay'); if (is_array($_record->employee_id)) { $_record->employee_id = $_record->employee_id['id']; } if ($_record->freedays && !empty($_record->freedays)) { foreach ($_record->freedays as $fd) { if (!$fd instanceof HumanResources_Model_FreeDay) { $fd = new HumanResources_Model_FreeDay($fd); } $this->_freedaysToCreate->addRecord($fd); } // normalize first-, last date and days_count $this->_freedaysToCreate->sort('date', 'ASC'); $_record->firstday_date = $this->_freedaysToCreate->getFirstRecord()->date; $this->_freedaysToCreate->sort('date', 'DESC'); $_record->lastday_date = $this->_freedaysToCreate->getFirstRecord()->date; $_record->days_count = $this->_freedaysToCreate->count(); } else { $_record->firstday_date = NULL; } }
/** * search tree nodes for search combo * * @param Tinebase_Model_Tree_Node_Filter $_filter * @param Tinebase_Record_Interface $_pagination * * @return Tinebase_Record_RecordSet of Tinebase_Model_Tree_Node */ protected function _searchNodesRecursive($_filter, $_pagination) { $files = new Tinebase_Record_RecordSet('Tinebase_Model_Tree_Node'); $ret = new Tinebase_Record_RecordSet('Tinebase_Model_Tree_Node'); $folders = $this->_getRootNodes(); $folders->merge($this->_getOtherUserNodes()); while ($folders->count()) { $node = $folders->getFirstRecord(); $filter = new Tinebase_Model_Tree_Node_Filter(array(array('field' => 'path', 'operator' => 'equals', 'value' => $node->path)), 'AND'); $result = $this->search($filter); $folders->merge($result->filter('type', Tinebase_Model_Tree_Node::TYPE_FOLDER)); if ($_filter->getFilter('query') && $_filter->getFilter('query')->getValue()) { $files->merge($result->filter('type', Tinebase_Model_Tree_Node::TYPE_FILE)->filter('name', '/^' . $_filter->getFilter('query')->getValue() . './i', true)); } else { $files->merge($result->filter('type', Tinebase_Model_Tree_Node::TYPE_FILE)); } $folders->removeRecord($node); } $this->_recursiveSearchTotalCount = $files->count(); $ret = $files->sortByPagination($_pagination)->limitByPagination($_pagination); return $ret; }
/** * Gets the phone id filter for the first record in the given recordset * * @param Tinebase_Record_RecordSet $userPhones * @return Tinebase_Model_Filter_Abstract */ protected function _getDefaultPhoneFilter($userPhones) { if ($userPhones->count()) { $filter = new Phone_Model_CallFilter(array('id' => 'defaultAdded', 'field' => 'phone_id', 'operator' => 'AND', 'value' => array(array('field' => ':id', 'operator' => 'in', 'value' => $userPhones->getId())))); } else { $filter = new Tinebase_Model_Filter_Text(array('id' => 'defaultAdded', 'field' => 'id', 'operator' => 'equals', 'value' => 'notexists')); } return $filter; }
/** * resolve multiple record fields (Tinebase_ModelConfiguration._recordsFields) * * @param Tinebase_Record_RecordSet $_records * @param Tinebase_ModelConfiguration $modelConfiguration * @param boolean $multiple * @throws Tinebase_Exception_UnexpectedValue */ protected function _resolveMultipleRecordFields(Tinebase_Record_RecordSet $_records, $modelConfiguration = NULL, $multiple = false) { if (!$modelConfiguration || !$_records->count()) { return; } if (!($resolveFields = $modelConfiguration->recordsFields)) { return; } $ownIds = $_records->{$modelConfiguration->idProperty}; // iterate fields to resolve foreach ($resolveFields as $fieldKey => $c) { $config = $c['config']; // resolve records, if omitOnSearch is definitively set to FALSE (by default they won't be resolved on search) if ($multiple && !(isset($config['omitOnSearch']) && $config['omitOnSearch'] === FALSE)) { continue; } if (!isset($config['controllerClassName'])) { throw new Tinebase_Exception_UnexpectedValue('Controller class name needed'); } // fetch the fields by the refIfField /** @var Tinebase_Controller_Record_Interface|Tinebase_Controller_SearchInterface $controller */ /** @noinspection PhpUndefinedMethodInspection */ $controller = $config['controllerClassName']::getInstance(); $filterName = $config['filterClassName']; $filterArray = array(); // addFilters can be added and must be added if the same model resides in more than one records fields if (isset($config['addFilters']) && is_array($config['addFilters'])) { $filterArray = $config['addFilters']; } /** @var Tinebase_Model_Filter_FilterGroup $filter */ $filter = new $filterName($filterArray); $filter->addFilter(new Tinebase_Model_Filter_Id(array('field' => $config['refIdField'], 'operator' => 'in', 'value' => $ownIds))); $paging = NULL; if (isset($config['paging']) && is_array($config['paging'])) { $paging = new Tinebase_Model_Pagination($config['paging']); } $foreignRecords = $controller->search($filter, $paging); /** @var Tinebase_Record_Interface $foreignRecordClass */ $foreignRecordClass = $foreignRecords->getRecordClassName(); $foreignRecordModelConfiguration = $foreignRecordClass::getConfiguration(); $foreignRecords->setTimezone(Tinebase_Core::getUserTimezone()); $foreignRecords->convertDates = true; $fr = $foreignRecords->getFirstRecord(); // @todo: resolve alarms? // @todo: use parts parameter? if ($foreignRecordModelConfiguration->resolveRelated && $fr) { if ($fr->has('notes')) { Tinebase_Notes::getInstance()->getMultipleNotesOfRecords($foreignRecords); } if ($fr->has('tags')) { Tinebase_Tags::getInstance()->getMultipleTagsOfRecords($foreignRecords); } if ($fr->has('relations')) { $relations = Tinebase_Relations::getInstance()->getMultipleRelations($foreignRecordClass, 'Sql', $foreignRecords->{$fr->getIdProperty()}); $foreignRecords->setByIndices('relations', $relations); } if ($fr->has('customfields')) { Tinebase_CustomField::getInstance()->resolveMultipleCustomfields($foreignRecords); } if ($fr->has('attachments') && Tinebase_Core::isFilesystemAvailable()) { Tinebase_FileSystem_RecordAttachments::getInstance()->getMultipleAttachmentsOfRecords($foreignRecords); } } if ($foreignRecords->count() > 0) { /** @var Tinebase_Record_Interface $record */ foreach ($_records as $record) { $filtered = $foreignRecords->filter($config['refIdField'], $record->getId())->toArray(); $filtered = $this->_resolveAfterToArray($filtered, $foreignRecordModelConfiguration, TRUE); $record->{$fieldKey} = $filtered; } } else { $_records->{$fieldKey} = NULL; } } }
/** * counts related records, gropued by Model, Type and Id but excludes relations which will be updated by $excludeCount * * @param string $ownModel * @param Tinebase_Record_RecordSet $relations * @return array */ public function countRelatedConstraints($ownModel, $relations, $excludeCount) { if ($relations->count() == 0) { return array(); } $adapter = $this->_dbTable->getAdapter(); $tableName = SQL_TABLE_PREFIX . 'relations'; $sql = 'SELECT ' . $this->_dbCommand->getConcat(array($this->_db->quoteIdentifier('related_model'), "'--'", $this->_db->quoteIdentifier('type'), "'--'", $this->_db->quoteIdentifier('own_id'))) . ' AS ' . $this->_db->quoteIdentifier('id') . ', ' . $this->_db->quoteIdentifier('related_model') . ', ' . $this->_db->quoteIdentifier('type') . ', ' . $this->_db->quoteIdentifier('own_model') . ', COUNT(*) AS ' . $this->_db->quoteIdentifier('count') . ' FROM ' . $this->_db->quoteIdentifier($tableName) . ' WHERE ' . $this->_db->quoteInto($this->_db->quoteIdentifier('own_id') . ' IN (?) ', $relations->related_id) . ' AND ' . $this->_db->quoteInto($this->_db->quoteIdentifier('related_model') . ' = ? ', $ownModel) . ' AND ' . $this->_db->quoteIdentifier('is_deleted') . ' = 0 '; if (!empty($excludeCount)) { $sql .= ' AND ' . $this->_db->quoteInto($this->_db->quoteIdentifier('id') . ' NOT IN (?) ', $excludeCount); } $sql .= 'GROUP BY ' . $this->_db->quoteIdentifier('own_id') . ',' . $this->_db->quoteIdentifier('related_model') . ', ' . $this->_db->quoteIdentifier('own_model') . ', ' . $this->_db->quoteIdentifier('type') . ', ' . $this->_db->quoteIdentifier('related_id'); $result = $adapter->fetchAssoc($sql); return $result; }
/** * validate constraints from the own and the other side. * this may be very expensive, if there are many constraints to check. * * @param string $ownModel * @param Tinebase_Record_RecordSet $relations * @throws Tinebase_Exception_InvalidRelationConstraints */ protected function _validateConstraintsConfig($ownModel, $relations, $toDelete = array(), $toUpdate = array()) { if (!$relations->count()) { return; } $relatedModels = array_unique($relations->related_model); $relatedIds = array_unique($relations->related_id); $toDelete = is_array($toDelete) ? $toDelete : array(); $toUpdate = is_array($toUpdate) ? $toUpdate : array(); $excludeCount = array_merge($toDelete, $toUpdate); $ownId = $relations->getFirstRecord()->own_id; // find out all models having a constraints config $allModels = $relatedModels; $allModels[] = $ownModel; $allModels = array_unique($allModels); $constraintsConfigs = self::getConstraintsConfigs($allModels); $relatedConstraints = $this->_backend->countRelatedConstraints($ownModel, $relations, $excludeCount); $groups = array(); foreach ($relations as $relation) { $groups[] = $relation->related_model . '--' . $relation->type . '--' . $relation->own_id; } $myConstraints = array_count_values($groups); $groups = array(); foreach ($relations as $relation) { if (!in_array($relation->getId(), $excludeCount)) { $groups[] = $relation->own_model . '--' . $relation->type . '--' . $relation->related_id; } } foreach ($relatedConstraints as $relC) { for ($i = 0; $i < $relC['count']; $i++) { $groups[] = $relC['id']; } } $allConstraints = array_count_values($groups); foreach ($constraintsConfigs as $cc) { foreach ($cc['config'] as $config) { $group = $cc['relatedRecordClassName'] . '--' . $config['type']; $idGroup = $group . '--' . $ownId; if (isset($myConstraints[$idGroup]) && ($config['max'] > 0 && $config['max'] < $myConstraints[$idGroup])) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Constraints validation failed from the own side! ' . print_r($cc, 1)); } throw new Tinebase_Exception_InvalidRelationConstraints(); } // TODO: if the other side gets the config reverted here, validating constrains failes here on multiple update foreach ($relatedIds as $relatedId) { $idGroup = $group . '--' . $relatedId; if (isset($allConstraints[$idGroup]) && ($config['max'] > 0 && $config['max'] < $allConstraints[$idGroup])) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Constraints validation failed from the other side! ' . print_r($cc, 1)); } throw new Tinebase_Exception_InvalidRelationConstraints(); } } } } }