Tinebase_Export_Xls - clone row styles too
[tine20] / tine20 / Calendar / Export / GenericTrait.php
1 <?php
2 /**
3  * calendar export generic trait
4  *
5  * @package     Calendar
6  * @subpackage  Export
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @author      Cornelius Weiss <c.weiss@metaways.de>
9  * @copyright   Copyright (c) 2014-2017 Metaways Infosystems GmbH (http://www.metaways.de)
10  *
11  */
12
13 /**
14  * generic calendar export trait
15  *
16  * @package     Calendar
17  * @subpackage  Export
18  *
19  * @property Tinebase_Controller_Record_Abstract    $_controller
20  * @property Tinebase_Model_Filter_FilterGroup      $_filter
21  * @property boolen                                 $_getRelations
22  * @property Zend_Config_Xml                        $_config
23  *
24  * TODO rename trait to hint functionality? GenericTrait is not a good name ;)
25  */
26 trait Calendar_Export_GenericTrait
27 {
28     /**
29      * @var Tinebase_DateTime
30      */
31     protected $_from = NULL;
32
33     /**
34      * @var Tinebase_DateTime
35      */
36     protected $_until = NULL;
37
38     /**
39      * contains the original dtstart and dtend of events that are splitted multi day whole day events ($id => array('dtstart' => dt, 'dtend' => dt))
40      *
41      * @var array
42      */
43     protected $_multiDayWholDayEvents = array();
44
45     /**
46      * the constructor
47      *
48      * @param Tinebase_Model_Filter_FilterGroup $_filter
49      * @param Tinebase_Controller_Record_Interface $_controller (optional)
50      * @param array $_additionalOptions (optional) additional options
51      */
52     public function init(Tinebase_Model_Filter_FilterGroup $_filter, Tinebase_Controller_Record_Interface $_controller = NULL, $_additionalOptions = array())
53     {
54         $periodFilter = $_filter->getFilter('period', false, true);
55
56         if ($periodFilter) {
57             $this->_from = $periodFilter->getFrom();
58             $this->_until = $periodFilter->getUntil()->subSecond(1);
59         }
60
61         parent::__construct($_filter, $_controller, $_additionalOptions);
62     }
63
64     /**
65      * export records
66      */
67     protected function _exportRecords()
68     {
69         // to support rrule & sorting we can't do pagination in calendar exports
70         $records = $this->_controller->search($this->_filter, NULL, $this->_getRelations, false, 'export');
71         Calendar_Model_Rrule::mergeAndRemoveNonMatchingRecurrences($records, $this->_filter);
72
73         // explode multiday whole day events to multiple, one day whole day events
74         $multiDayConfig = $this->_config->get('multiDay', NULL);
75         if (null !== $multiDayConfig && mb_strtolower($multiDayConfig) === 'daily') {
76             $newEvents = new Tinebase_Record_RecordSet('Calendar_Model_Event');
77             $removeIds = array();
78
79             /** @var Calendar_Model_Event $record */
80             foreach($records as $record) {
81                 if ($record->is_all_day_event) {
82
83                     $orgDtStart = clone $record->dtstart;
84                     $orgDtEnd = clone $record->dtend;
85                     $dtstart = clone $record->dtstart;
86                     $dtstart->addDay(1);
87
88                     $isSplitted = false;
89
90                     while ($record->dtend->isLater($dtstart)) {
91                         $isSplitted = true;
92                         $newEvent = clone $record;
93                         $newEvent->setId(Tinebase_Record_Abstract::generateUID());
94                         $newEvent->dtend = clone $newEvent->dtstart;
95                         $newEvent->dtend->setTime(23, 59, 59);
96
97                         if ($newEvent->dtend->isLater($this->_from) && $newEvent->dtstart->isEarlier($this->_until)) {
98                             $newEvents->addRecord($newEvent);
99                             $this->_multiDayWholDayEvents[$newEvent->getId()] = array(
100                                 'dtstart' => $orgDtStart,
101                                 'dtend'   => $orgDtEnd
102                             );
103                         }
104
105                         $record->dtstart = clone $dtstart;
106                         $dtstart->addDay(1);
107                     }
108
109                     if (!$record->dtend->isLater($this->_from) || !$record->dtstart->isEarlier($this->_until)) {
110                         $removeIds[] = $record->getId();
111                     } elseif(true === $isSplitted) {
112                         $this->_multiDayWholDayEvents[$record->getId()] = array(
113                             'dtstart' => $orgDtStart,
114                             'dtend'   => $orgDtEnd
115                         );
116                     }
117                 }
118             }
119             if (count($removeIds) > 0) {
120                 foreach($removeIds as $id) {
121                     $records->removeById($id);
122                 }
123             }
124             $records->merge($newEvents);
125         }
126
127         $this->_sortRecords($records);
128
129         if ($this instanceof Tinebase_Export_Abstract) {
130             $this->_records = $records;
131             $this->_groupByProperty = 'dtstart';
132             $this->_groupByProcessor = function(&$val) {
133                 $val = $val->format('Y-m-d');
134             };
135             parent::_exportRecords();
136         } else {
137             $this->_resolveRecords($records);
138             foreach ($records as $idx => $record) {
139                 $this->processRecord($record, $idx);
140             }
141
142             $result = array();
143
144             $this->_onAfterExportRecords($result);
145         }
146     }
147
148     protected function _sortRecords(&$records)
149     {
150         $records->sort(function($r1, $r2) {
151             return $r1->dtstart > $r2->dtstart;
152         });
153     }
154
155     /**
156      * resolve records and prepare for export (set user timezone, ...)
157      *
158      * @param Tinebase_Record_RecordSet $_records
159      */
160     protected function _resolveRecords(Tinebase_Record_RecordSet $_records)
161     {
162         parent::_resolveRecords($_records);
163
164         Calendar_Model_Attender::resolveAttendee($_records->attendee, false, $_records);
165
166         foreach($_records as $record) {
167             $attendee = $record->attendee->getName();
168             $record->attendee = implode('& ', $attendee);
169
170             $organizer = $record->resolveOrganizer();
171             if ($organizer) {
172                 $record->organizer = $organizer->n_fileas;
173             }
174         }
175     }
176 }