7 * @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
8 * @copyright Copyright (c) 2007-2013 Metaways Infosystems GmbH (http://www.metaways.de)
9 * @author Alexander Stintzing <a.stintzing@metaways.de>
14 * Abstract class for DemoData
19 abstract class Tinebase_Setup_DemoData_Abstract
23 * the models to create demodata for
26 protected $_models = NULL;
29 * the application name to work on
33 protected $_appName = NULL;
36 * the name of the model currently worked on
40 protected $_modelName = NULL;
42 * default ip for the fake session
45 protected $_defaultCliIp = '127.0.0.1';
48 * holds the costcenter for "marketing"
50 * @var Sales_Model_CostCenter
52 protected $_marketingCostCenter;
55 * holds names of required applications to create demo data before this app
59 protected static $_requiredApplications;
62 * holds the costcenter for "development"
64 * @var Sales_Model_CostCenter
66 protected $_developmentCostCenter;
69 * creates soo many records, if set to true
73 protected static $_createFullData = FALSE;
76 * the personas to create demodata for
77 * http://www.tine20.org/wiki/index.php/Personas
78 * will be resolved to array of accounts
82 protected $_personas = array(
83 'pwulf' => 'Paul Wulf',
84 'jsmith' => 'John Smith',
85 'sclever' => 'Susan Clever',
86 'jmcblack' => 'James McBlack',
87 'rwright' => 'Roberta Wright',
91 * the groups to create
93 protected $_groups = array(
96 'visibility' => 'displayed', 'name' => 'Managers', 'description' => 'Managers of the company'
98 'groupMembers' => array('pwulf')
101 'groupData' => array(
102 'visibility' => 'displayed', 'name' => 'HumanResources', 'description' => 'Human Resources Managment'
105 array('sclever', 'pwulf')
108 'groupData' => array(
109 'visibility' => 'displayed', 'name' => 'Secretary', 'description' => 'Secretarys of the company'
111 'groupMembers' => array('sclever', 'pwulf')
114 'groupData' => array(
115 'visibility' => 'displayed', 'name' => 'Controllers', 'description' => 'Controllers of the company'
117 'groupMembers' => array('rwright', 'pwulf')
122 * the roles to create for each group
124 protected $_roles = array(
126 'roleData' => array('name' => 'manager role'),
127 'roleMembers' => array(
128 array('type' => Tinebase_Acl_Rights::ACCOUNT_TYPE_GROUP, 'name' => 'Managers')
130 'roleRights' => array(
132 'view_accounts','run','view_apps','manage_shared_tags','view_access_log'
134 'Addressbook' => array(
135 'manage_shared_contact_favorites','manage_shared_folders','run'
138 'manage_shared_task_favorites','manage_shared_folders','run'
141 'manage_shared_lead_favorites','manage_shared_folders','manage_leads','run'
143 'Filemanager' => array(
144 'manage_shared_folders','run'
147 'manage_shared_event_favorites','manage_shared_folders','manage_resources','run'
150 'add_existing_user','add_new_user','run'
152 'HumanResources' => array(
156 'manage_shared_project_favorites','run'
159 'manage_products','run'
162 'manage_private_accounts','manage_shared_accounts','sync_lines','manage_accounts','run'
164 'RequestTracker' => array(
167 'Inventory' => array(
170 'SimpleFAQ' => array(
173 'ExampleApplication' => array(
176 'Felamimail' => array(
179 'ActiveSync' => array(
183 'run','manage_own_profile','check_version'
185 'Timetracker' => array(
186 'manage_timeaccounts','add_timeaccounts','manage_shared_timeaccount_favorites','manage_shared_timesheet_favorites','run'
191 'roleData' => array('name' => 'administrative management role'),
192 'roleMembers' => array(
193 array('type' => Tinebase_Acl_Rights::ACCOUNT_TYPE_GROUP, 'name' => 'HumanResources'),
194 array('type' => Tinebase_Acl_Rights::ACCOUNT_TYPE_GROUP, 'name' => 'Controllers')
196 'roleRights' => array(
198 'manage_shared_task_favorites','manage_shared_folders','run'
201 'manage_shared_lead_favorites','manage_shared_folders','run','manage_leads'
204 'manage_shared_event_favorites','manage_shared_folders','run','manage_resources'
206 'HumanResources' => array(
210 'run','manage_private_accounts','manage_shared_accounts','manage_accounts','sync_lines'
213 'run','manage_products'
215 'RequestTracker' => array(
219 'run','manage_shared_project_favorites'
222 'run','add_existing_user','add_new_user'
224 'Inventory' => array(
227 'SimpleFAQ' => array(
230 'ExampleApplication' => array(
233 'Felamimail' => array(
236 'Filemanager' => array(
237 'run','manage_shared_folders'
239 'Addressbook' => array(
240 'run','manage_shared_folders','manage_shared_contact_favorites'
242 'ActiveSync' => array(
248 'Timetracker' => array(
249 'manage_shared_timeaccount_favorites','manage_shared_timesheet_favorites','run','add_timeaccounts','manage_timeaccounts'
252 'manage_accounts','view_accounts','run'
257 'roleData' => array('name' => 'secretary role'),
258 'roleMembers' => array(
259 array('type' => Tinebase_Acl_Rights::ACCOUNT_TYPE_GROUP, 'name' => 'Secretary'),
261 'roleRights' => array(
262 'Addressbook' => array(
263 'manage_shared_contact_favorites','manage_shared_folders','run'
266 'manage_shared_task_favorites','manage_shared_folders','run'
269 'manage_shared_lead_favorites','manage_shared_folders','run'
272 'manage_shared_event_favorites','manage_shared_folders','run','manage_resources'
274 'HumanResources' => array(
283 'RequestTracker' => array(
290 'run','add_existing_user','add_new_user'
292 'Inventory' => array(
295 'SimpleFAQ' => array(
298 'ExampleApplication' => array(
301 'Felamimail' => array(
304 'Filemanager' => array(
307 'ActiveSync' => array(
313 'Timetracker' => array(
314 'manage_shared_timeaccount_favorites','manage_shared_timesheet_favorites','run'
321 * the reference date for data in aggregates/invoices...
323 * @var Tinebase_DateTime
325 protected $_referenceDate = NULL;
328 * holds an array containing the last day of each month for last year
332 protected $_lastMonthDays = NULL;
335 * if the last year was a leap year, this is set to true
339 protected $_isLeapYear = FALSE;
342 protected $_monday = NULL;
343 protected $_tuesday = NULL;
344 protected $_wednesday = NULL;
345 protected $_thursday = NULL;
346 protected $_friday = NULL;
347 protected $_saturday = NULL;
348 protected $_sunday = NULL;
351 protected $_lastMonday = NULL;
352 protected $_lastFriday = NULL;
353 protected $_lastSaturday = NULL;
354 protected $_lastSunday = NULL;
357 protected $_nextMonday = NULL;
358 protected $_nextWednesday = NULL;
359 protected $_nextFriday = NULL;
361 protected $_wednesday2week = NULL;
362 protected $_friday2week = NULL;
365 * shall shared data be created?
368 protected $_createShared = NULL;
371 * shall user data be created?
374 protected $_createUsers = NULL;
379 protected $_adminUser;
382 * the contact of the admin user
384 protected $_adminUserContact;
390 protected $_adminGrants = array('readGrant','addGrant','editGrant','deleteGrant','privateGrant','exportGrant','syncGrant','adminGrant','freebusyGrant');
392 * Grants for Secretary on private calendars
395 protected $_secretaryGrants = array('readGrant','freebusyGrant','addGrant');
397 * Grants for Controller
400 protected $_controllerGrants = array('readGrant','exportGrant');
405 protected $_userGrants = array('readGrant','addGrant','editGrant','deleteGrant');
408 * RecordSet with all sales.costcenter, loaded by this._loadCostCenters
410 * @var Tinebase_Record_RecordSet
412 protected $_costCenters;
415 * the ids of all costcenters in an array, loaded by this._loadCostCenters
419 protected $_costCenterKeys;
422 * the locale, the demodata should created with
425 protected static $_locale = 'en';
428 * shortcut for locale
430 protected static $_de = true;
433 * defaults to NULL, a random password will be generated and shown on the cli output
434 * prevent this by adding a 'login' array containing 'username' and 'password' to the config
436 protected static $_defaultPassword = NULL;
439 * shortcut for locale
441 protected static $_en = false;
444 * sets $this->_referenceDate to the first january of last year
446 protected function _setReferenceDate()
448 // set reference date to the 1st january of last year
449 $this->_referenceDate = Tinebase_DateTime::now();
450 $this->_referenceDate->setTimezone(Tinebase_Core::getUserTimezone());
451 $this->_referenceDate->subYear(1);
452 $this->_referenceDate->setDate($this->_referenceDate->format('Y'), 1 ,1);
453 $this->_referenceDate->setTime(0,0,0);
455 $this->_referenceYear = $this->_referenceDate->format('Y');
456 $this->_lastMonthDays = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
458 // find out if year is a leap year
459 if (($this->_referenceYear % 400) == 0 || (($this->_referenceYear % 4) == 0 && ($this->_referenceYear % 100) != 0)) {
460 $this->_isLeapYear = TRUE;
461 $this->_lastMonthDays[1] = 29;
467 * @param Tinebase_DateTime $now
469 protected function _getDays(Tinebase_DateTime $now = NULL)
471 // find out where we are
473 $now = new Tinebase_DateTime();
475 $weekday = $now->format('w');
477 $subdaysLastMonday = 6 + $weekday; // Monday last Week
478 $subdaysLastFriday = 2 + $weekday; // Friday last Week
481 $this->_monday = new Tinebase_DateTime();
482 $this->_monday->sub(date_interval_create_from_date_string(($weekday - 1) . ' days'));
483 $this->_tuesday = new Tinebase_DateTime();
484 $this->_tuesday->sub(date_interval_create_from_date_string(($weekday - 2) . ' days'));
485 $this->_wednesday = new Tinebase_DateTime();
486 $this->_wednesday->sub(date_interval_create_from_date_string(($weekday - 3) . ' days'));
487 $this->_thursday = new Tinebase_DateTime();
488 $this->_thursday->sub(date_interval_create_from_date_string(($weekday - 4) . ' days'));
489 $this->_friday = new Tinebase_DateTime();
490 $this->_friday->sub(date_interval_create_from_date_string(($weekday - 5) . ' days'));
491 $this->_saturday = clone $this->_friday;
492 $this->_saturday->add(date_interval_create_from_date_string('1 day'));
493 $this->_sunday = clone $this->_friday;
494 $this->_sunday->add(date_interval_create_from_date_string('2 days'));
497 $this->_lastMonday = clone $this->_monday;
498 $this->_lastMonday->subWeek(1);
499 $this->_lastWednesday = clone $this->_wednesday;
500 $this->_lastWednesday->subWeek(1);
501 $this->_lastFriday = clone $this->_friday;
502 $this->_lastFriday->subWeek(1);
503 $this->_lastThursday = clone $this->_thursday;
504 $this->_lastThursday->subWeek(1);
505 $this->_lastSaturday = clone $this->_saturday;
506 $this->_lastSaturday->subWeek(1);
507 $this->_lastSunday = clone $this->_sunday;
508 $this->_lastSunday->subWeek(1);
510 $this->_nextMonday = clone $this->_monday;
511 $this->_nextMonday->addWeek(1);
512 $this->_nextTuesday = clone $this->_tuesday;
513 $this->_nextTuesday->addWeek(1);
514 $this->_nextWednesday = clone $this->_wednesday;
515 $this->_nextWednesday->addWeek(1);
516 $this->_nextThursday = clone $this->_thursday;
517 $this->_nextThursday->addWeek(1);
518 $this->_nextFriday = clone $this->_friday;
519 $this->_nextFriday->addWeek(1);
521 $this->_wednesday2week = clone $this->_nextWednesday;
522 $this->_wednesday2week->addWeek(1);
523 $this->_friday2week = clone $this->_nextFriday;
524 $this->_friday2week->addWeek(1);
530 * loads all costcenters to this._costCenters property
532 * @return Tinebase_Record_RecordSet
534 protected function _loadCostCentersAndDivisions()
536 $filter = new Sales_Model_CostCenterFilter(array());
537 $this->_costCenters = Sales_Controller_CostCenter::getInstance()->search($filter)->sort('number');
538 $this->_costCenterKeys[] = array();
540 foreach($this->_costCenters as $cc) {
541 if ($cc->remark == 'Marketing') {
542 $this->_marketingCostCenter = $cc;
544 if ($cc->remark == 'Development' || $cc->remark == 'Entwicklung') {
545 $this->_developmentCostCenter = $cc;
547 $this->_costCenterKeys[] = $cc->getId();
550 $filter = new Sales_Model_DivisionFilter(array());
551 $this->_divisions = Sales_Controller_Division::getInstance()->search($filter)->sort('number');
553 return $this->_costCenters;
558 * @return multitype:array|null
560 public static function getRequiredApplications()
562 return static::$_requiredApplications ? static::$_requiredApplications : array();
566 * this is required for other applications needing demo data of this application
567 * if this returns true, this demodata has been run already
571 public static function hasBeenRun()
577 * creates the demo data and is called from the Frontend_Cli
579 * @param array $options
582 public function createDemoData(array $options)
584 static::$_createFullData = (isset($options['full']) || array_key_exists('full', $options)) ? TRUE : FALSE;
586 $this->_createShared = (isset($options['createShared']) || array_key_exists('createShared', $options)) ? $options['createShared'] : TRUE;
587 $this->_createUsers = (isset($options['createUsers']) || array_key_exists('createUsers', $options)) ? $options['createUsers'] : TRUE;
589 if ((isset($options['locale']) || array_key_exists('locale', $options))) {
590 static::$_locale = $options['locale'];
593 static::$_de = (static::$_locale == 'de') ? true : false;
594 static::$_en = ! static::$_de;
595 static::$_defaultPassword = (isset($options['password']) || array_key_exists('password', $options)) ? $options['password'] : '';
596 $this->_beforeCreate();
598 // look for defined models
599 if ((isset($options['models']) || array_key_exists('models', $options)) && is_array($options['models'])) {
600 foreach ($options['models'] as $model) {
601 if (! in_array($model, $this->_models)) {
602 echo 'Model ' . $model . ' is not defined for demo data creation!' . chr(10);
606 $this->_models = array_intersect($options['models'], $this->_models);
610 if ((isset($options['users']) || array_key_exists('users', $options)) && is_array($options['users'])) {
611 foreach ($options['users'] as $user) {
612 if (! (isset($this->_personas[$user]) || array_key_exists($user, $this->_personas))) {
613 echo 'User ' . $user . ' is not defined for demo data creation!' . chr(10);
616 $users[$user] = $this->_personas[$user];
620 $users = $this->_personas;
623 $this->_personas = array();
625 foreach($users as $loginName => $name) {
627 $this->_personas[$loginName] = Tinebase_User::getInstance()->getFullUserByLoginName($loginName);
628 } catch (Tinebase_Exception_NotFound $e) {
629 echo 'Persona with login name ' . $loginName . ' does not exist or no demo data is defined!' . chr(10);
630 echo 'Have you called Admin.createDemoDate already?' . PHP_EOL;
631 echo 'If not, do this!' . PHP_EOL;
637 $this->_adminUser = Tinebase_Core::getUser();
638 $this->_adminUserContact = Addressbook_Controller_Contact::getInstance()->getContactByUserId($this->_adminUser->getId());
642 $callQueue = array();
643 $callQueueShared = array();
645 if (is_array($this->_models)) {
646 foreach ($this->_models as $model) {
647 $mname = ucfirst($model);
649 if ($this->_createShared) {
650 $methodName = '_createShared' . $mname . 's';
651 if(method_exists($this, $methodName)) {
652 $callQueueShared[] = array('methodName' => $methodName, 'modelName' => $mname);
657 if ($this->_createUsers) {
658 foreach ($users as $userLogin => $userRecord) {
659 $uname = ucfirst($userLogin);
660 $methodName = '_create' . $mname . 'sFor' . $uname;
661 if (method_exists($this, $methodName)) {
662 $callQueue[$userLogin] = array('methodName' => $methodName, 'userName' => $uname, 'modelName' => $mname);
669 // call create shared method
670 foreach ($callQueueShared as $info) {
671 echo 'Creating shared ' . $info['modelName'] . 's...' . PHP_EOL;
672 $this->_modelName = $info['modelName'];
673 $this->{$info['methodName']}();
676 // call create methods as the user itself
677 foreach ($callQueue as $loginName => $info) {
678 Tinebase_Core::set(Tinebase_Core::USER, $this->_personas[$loginName]);
679 echo 'Creating personal ' . $info['modelName'] . 's for ' . $info['userName'] . '...' . PHP_EOL;
680 $this->{$info['methodName']}();
683 Tinebase_Core::set(Tinebase_Core::USER, $this->_adminUser);
685 $this->_afterCreate();
691 * returns a relation array by records
693 * @param Tinebase_Record_Abstract $ownRecord
694 * @param Tinebase_Record_Abstract $foreignRecord
695 * @param string $ownDegree
696 * @param string $type
699 protected function _getRelationArray($ownRecord, $foreignRecord, $ownDegree = Tinebase_Model_Relation::DEGREE_SIBLING, $type = NULL)
701 $ownModel = get_class($ownRecord);
702 $foreignModel = get_class($foreignRecord);
705 $split = explode('_Model_', $foreignModel);
706 $type = strtoupper($split[1]);
710 'own_model' => $ownModel,
711 'own_backend' => 'Sql',
712 'own_id' => $ownRecord->getId(),
713 'related_degree' => $ownDegree,
714 'related_model' => $foreignModel,
715 'related_backend' => 'Sql',
716 'related_id' => $foreignRecord->getId(),
721 protected function _createContainer()
726 * creates a shared container by name and data, if given
728 protected function _createSharedContainer($containerName, $data = array(), $setAsThisSharedContainer = true)
730 // create shared calendar
731 $container = Tinebase_Container::getInstance()->addContainer(
732 new Tinebase_Model_Container(array_merge(
734 'name' => $containerName,
735 'type' => Tinebase_Model_Container::TYPE_SHARED,
736 'owner_id' => Tinebase_Core::getUser(),
738 'application_id' => Tinebase_Application::getInstance()->getApplicationByName($this->_appName)->getId(),
739 'model' => $this->_appName . '_Model_' . $this->_modelName,
745 $group = Tinebase_Group::getInstance()->getDefaultGroup();
746 Tinebase_Container::getInstance()->addGrants($container->getId(), 'group', $group->getId(), $this->_userGrants, true);
747 if (isset($this->_personas['sclever'])) {
748 Tinebase_Container::getInstance()->addGrants($container->getId(), 'user', $this->_personas['sclever']->getId(), $this->_secretaryGrants, true);
750 if (isset($this->_personas['pwulf'])) {
751 Tinebase_Container::getInstance()->addGrants($container->getId(), 'user', $this->_personas['pwulf']->getId(), $this->_adminGrants, true);
754 if ($setAsThisSharedContainer) {
755 $this->_sharedContainer = $container;
762 * returns an existing contact by its full name or by an account login name
764 * array('user' => 'pwulf')
765 * returns the contact of paul wulf
766 * array('contact' => 'Carolynn Hinsdale')
767 * returns the contact of Mrs. Hinsdale
769 * @param array $_data
772 protected function _getContact($_data)
775 if ((isset($_data['user']) || array_key_exists('user', $_data))) {
776 $account = $this->_personas[$_data['user']];
777 $contact = Addressbook_Controller_Contact::getInstance()->get($account->contact_id);
778 } else { // handle contact
779 $filter = new Addressbook_Model_ContactFilter(array(
780 array('field' => 'query', 'operator' => 'contains', 'value' => $_data['contact'])
782 $contact = Addressbook_Controller_Contact::getInstance()->search($filter)->getFirstRecord();
788 * is called on createDemoData before finding out which models and users to build
790 protected function _beforeCreate()
795 * is called on createDemoData after finding out which models
796 * and users to build and before calling the demo data class methods
798 protected function _onCreate()
803 * is called on createDemoData after all demo data has been created
805 protected function _afterCreate()