Completed
Push — 14.2 ( 8a03b5...54a079 )
by Nathan
27:03
created

calendar_export_csv::get_selectors_etpl()   F

Complexity

Conditions 15
Paths 1600

Size

Total Lines 68
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 15
eloc 48
c 1
b 1
f 0
nc 1600
nop 1
dl 0
loc 68
rs 2.5815

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * eGroupWare
4
 *
5
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
6
 * @package calendar
7
 * @subpackage importexport
8
 * @link http://www.egroupware.org
9
 * @author Nathan Gray
10
 * @copyright Nathan Gray
11
 * @version $Id$
12
 */
13
14
/**
15
 * export CSV plugin of calendar
16
 */
17
class calendar_export_csv implements importexport_iface_export_plugin {
18
19
	public function __construct() {
20
		translation::add_app('calendar');
21
		$this->bo = new calendar_bo();
22
		$this->get_selects();
23
	}
24
25
	/**
26
	 * Exports records as defined in $_definition
27
	 *
28
	 * @param egw_record $_definition
29
	 */
30
	public function export( $_stream, importexport_definition $_definition) {
31
		$options = $_definition->plugin_options;
0 ignored issues
show
Documentation introduced by
The property plugin_options does not exist on object<importexport_definition>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
32
33
		$limit_exception = bo_merge::is_export_limit_excepted();
34
		if (!$limit_exception) $export_limit = bo_merge::getExportLimit('calendar');
35
		// Custom fields need to be specifically requested
36
		$cfs = array();
37
		foreach($options['mapping'] + (array)$_definition->filter as $key => $label) {
38
			if($key[0] == '#') $cfs[] = substr($key,1);
39
		}
40
41
		$query = array(
42
			'cfs'		=> $cfs, // Otherwise we shouldn't get any custom fields
43
			'num_rows'	=> -1,
44
			'csv_export'	=> true
45
		);
46
		switch($options['selection'])
47
		{
48
			case 'criteria':
49
				$query = array(
50
					'start' => $options['criteria']['start'],
51
					'end'   => strtotime('+1 day',$options['criteria']['end'])-1,
52
					'categories'	=> $options['categories'] ? $options['categories'] : $options['criteria']['categories'],
53
					//'enum_recuring' => false, // we want the recurring events enumerated for csv export
54
					'daywise'       => false,
55
					'users'         => $options['criteria']['owner'],
56
					'cfs'		=> $cfs // Otherwise we shouldn't get any custom fields
57
				);
58 View Code Duplication
				if(bo_merge::hasExportLimit($export_limit) && !$limit_exception) {
59
					$query['offset'] = 0;
60
					$query['num_rows'] = (int)$export_limit; // ! int of 'no' is 0
61
				}
62
				$events =& $this->bo->search($query);
63
				break;
64
			case 'search_results':
65
				$states = $GLOBALS['egw']->session->appsession('session_data','calendar');
66
				if($states['view'] == 'listview') {
67
					$query = $GLOBALS['egw']->session->appsession('calendar_list','calendar');
68
					$query['num_rows'] = -1;        // all
69
					$query['csv_export'] = true;	// so get_rows method _can_ produce different content or not store state in the session
70
					$query['start'] = 0;
71
					$query['cfs'] = $cfs;
72
73
					if(bo_merge::hasExportLimit($export_limit) && !$limit_exception) {
74
						$query['num_rows'] = (int)$export_limit; // ! int of 'no' is 0
75
					}
76
					$ui = new calendar_uilist();
77
					$ui->get_rows($query, $events, $unused);
78
				} else {
79
					$query = $GLOBALS['egw']->session->appsession('session_data','calendar');
80
					$query['users'] = explode(',', $query['owner']);
81
					$query['num_rows'] = -1;
82
					if(bo_merge::hasExportLimit($export_limit) && !$limit_exception) {
83
						$query['num_rows'] = (int)$export_limit;  // ! int of 'no' is 0
84
					}
85
86
					$events = array();
87
					switch($states['view']) {
88
						case 'month':
89
							$query += $this->get_query_month($states);
90
							break;
91
						case 'week':
92
						case 'weekN':
93
							$query += $this->get_query_week($states);
94
							break;
95
						case 'day':
96
							$query += $this->get_query_day($states);
97
							break;
98 View Code Duplication
						default:
99
							// Let UI set the date ranges
100
							$ui = new calendar_uiviews($query);
101
							if(method_exists($ui, $states['view']))
102
							{
103
								ob_start();
104
								$ui->$states['view']();
105
								ob_end_clean();
106
							}
107
							$query += array(
108
								'start' => is_array($ui->first) ? $this->bo->date2ts($ui->first) : $ui->first,
109
								'end' => is_array($ui->last) ? $this->bo->date2ts($ui->last) : $ui->last
110
							);
111
112
					}
113
					$boupdate = new calendar_boupdate();
114
					$events = $boupdate->search($query + array(
115
						'offset' => 0,
116
						'order' => 'cal_start',
117
					));
118
				}
119
				break;
120
			case 'filter':
121
				$fields = importexport_helper_functions::get_filter_fields($_definition->application, $this);
122
				$filter = $_definition->filter;
0 ignored issues
show
Documentation introduced by
The property filter does not exist on object<importexport_definition>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
123
124
				// Handle ranges
125 View Code Duplication
				foreach($filter as $field => $value)
126
				{
127
					if($field == 'filter' && $value)
128
					{
129
						$query['filter'] = $value;
130
						continue;
131
					}
132
					if(!is_array($value) || (!$value['from'] && !$value['to']))
133
					{
134
						$query['query']["cal_$field"] = $value;
135
						continue;
136
					}
137
138
					// Ranges are inclusive, so should be provided that way (from 2 to 10 includes 2 and 10)
139
					if($value['from']) $query['sql_filter'][] = "cal_$field >= " . (int)$value['from'];
140
					if($value['to']) $query['sql_filter'][] = "cal_$field <= " . (int)$value['to'];
141
142
				}
143
				if($query['sql_filter'] && is_array($query['sql_filter']))
144
				{
145
					// Set as an extra parameter
146
					$sql_filter = implode(' AND ',$query['sql_filter']);
147
				}
148
149
			case 'all':
150
				$events = $this->bo->search($query + array(
151
					'offset' => 0,
152
					'order' => 'cal_start',
153
				),$sql_filter);
154
				break;
155
		}
156
157
		$export_object = new importexport_export_csv($_stream, (array)$options);
158
		if (!$limit_exception) $export_object->export_limit = $export_limit;
159
		$export_object->set_mapping($options['mapping']);
160
		$convert_fields = calendar_egw_record::$types;
161
162
		$recurrence = $this->bo->recur_types;
163
164
		$record = new calendar_egw_record();
165
		foreach ($events as $event) {
166
			// the condition below (2 lines) may only work on enum_recuring=false and using the iterator to test an recurring event on the given timerange
167
			// Get rid of yearly recurring events that don't belong
168
			//if($options['selection']['select'] == 'criteria' && ($event['start'] > $query['end'] || $event['end'] < $query['start'])) continue;
169
			// Add in participants
170
			if($options['mapping']['participants']) {
171
				$event['participants'] = implode(", ",$this->bo->participants($event,true));
172
			}
173
			if (is_array($event))
174
			{
175
				$record->set_record($event);
176
				if($options['mapping']['recurrence']) {
177
					$record->recurrence = $recurrence[$record->recur_type];
0 ignored issues
show
Bug introduced by
Accessing recurrence on the interface importexport_iface_egw_record suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
Accessing recur_type on the interface importexport_iface_egw_record suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
178
					if($record->recur_type != MCAL_RECUR_NONE) $record->recurrence .= ' / '. $record->recur_interval;
0 ignored issues
show
Bug introduced by
Accessing recurrence on the interface importexport_iface_egw_record suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
Accessing recur_interval on the interface importexport_iface_egw_record suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
Accessing recur_type on the interface importexport_iface_egw_record suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
179
				}
180
181
				// Standard stuff
182
				if($options['convert']) {
183
					importexport_export_csv::convert($record, $convert_fields, 'calendar', $this->selects);
184
				} else {
185
					// Implode arrays, so they don't say 'Array'
186
					foreach($record->get_record_array() as $key => $value) {
187
						if(is_array($value)) $record->$key = implode(',', $value);
188
					}
189
	 			}
190
				$export_object->export_record($record);
191
			}
192
		}
193
		unset($record);
194
		return $export_object;
195
	}
196
197
	/**
198
	 * returns translated name of plugin
199
	 *
200
	 * @return string name
201
	 */
202
	public static function get_name() {
203
		return lang('Calendar CSV export');
204
	}
205
206
	/**
207
	 * returns translated (user) description of plugin
208
	 *
209
	 * @return string descriprion
210
	 */
211
	public static function get_description() {
212
		return lang("Exports events from your Calendar into a CSV File.");
213
	}
214
215
	/**
216
	 * retruns file suffix for exported file
217
	 *
218
	 * @return string suffix
219
	 */
220
	public static function get_filesuffix() {
221
		return 'csv';
222
	}
223
224
	public static function get_mimetype() {
225
		return 'text/csv';
226
	}
227
228
	/**
229
	 * return html for options.
230
	 *
231
	 */
232
	public function get_options_etpl($definition = null) {
233
	}
234
235
	/**
236
	 * returns selectors of this plugin
237
	 *
238
	 */
239
	public function get_selectors_etpl($definition = null) {
240
		$states = $GLOBALS['egw']->session->appsession('session_data','calendar');
241
		switch($states['view']) {
242
			case 'month':
243
				$query = $this->get_query_month($states);
244
				break;
245
			case 'week':
246
			case 'weekN':
247
				$query = $this->get_query_week($states);
248
				break;
249
			case 'day':
250
				$query = $this->get_query_day($states);
251
				break;
252
		}
253
		$start= new egw_time($query['start']);
254
		$end = new egw_time($query['end']);
255
		if ($states['view'] == 'listview')
256
		{
257
			$list = $GLOBALS['egw']->session->appsession('calendar_list','calendar');
258
259
			// Use UI to get dates
260
			$ui = new calendar_uilist();
261
			$list['csv_export'] = true;	// so get_rows method _can_ produce different content or not store state in the session
262
			$ui->get_rows($list,$rows,$readonlys);
263
			$start = $ui->first ? $ui->first : new egw_time($ui->date);
264
			$end = $ui->last;
265
266
			// Special handling
267
			if($list['filter'] == 'all') $start = $end = null;
268
			if($list['filter'] == 'before')
269
			{
270
				$end = $start;
271
				$start = null;
272
			}
273
			$ui = null;
274
		}
275
		elseif(!$end)
276
		{
277
			$end = '+1 ' . $states['view'];
278
			$end = strtotime($end, $start->format('ts'))-1;
279
		}
280
		$prefs = unserialize($GLOBALS['egw_info']['user']['preferences']['importexport'][$definition->definition_id]);
281
		$data = array(
282
			'name'		=> 'calendar.export_csv_select',
283
			'content'	=> array(
284
				'plugin_override' => true, // Plugin overrides preferences
285
				'selection'	=> $prefs['selection'] ? $prefs['selection'] : 'criteria',
286
				'criteria'	=> array(
287
					'start'		=> is_object($start) ? $start->format('ts') : $start,
288
					'end'		=> is_object($end) ? $end->format('ts') : $end,
289
					'owner'		=> is_array($states['owner']) ? $states['owner'] : explode(',',$states['owner'])
290
				)
291
			),
292
			'sel_options' => array(
293
				'owner' => array()
294
			)
295
		);
296
		// Pass current owner labels
297
		foreach($data['content']['criteria']['owner'] as $owner)
298
		{
299
			$data['sel_options']['owner'][] = array(
300
				'id' => $owner,
301
				'value' => $owner,
302
				'label' => $this->bo->participant_name($owner)
303
			);
304
		}
305
		return $data;
306
	}
307
308
	/**
309
	 * Get additional query parameters used when in various views
310
	 * This stuff copied out of calendar_uiviews
311
	 */
312
	public static function get_query_month($states)
313
	{
314
		$timespan = array(
315
			'start' => mktime(0,0,0,$states['month'],1,$states['year']),
316
			'end' => mktime(0,0,0,$states['month']+1,1,$states['year'])-1
317
		);
318
		return $timespan;
319
	}
320
321
	public static function get_query_week($states)
322
	{
323
		$query = array();
324
		$days = $states['days'];
325
		$ui = new calendar_uiviews($states);
326
		if (!$days)
327
                {
328
                        $days = isset($_GET['days']) ? $_GET['days'] : $ui->cal_prefs['days_in_weekview'];
329
                        if ($days != 5) $days = 7;
330
                }
331
		if ($states['view'] == 'week' && $days == 4)         // next 4 days view
332
                {
333
                        $query['start'] = $this->bo->date2ts($states['date']);
334
                        $query['end'] = strtotime("+$days days",$query['start']) - 1;
335
                }
336
                else
337
                {
338
			$query['start'] = $ui->datetime->get_weekday_start($states['year'],$states['month'],$states['day']);
339
			if ($days == 5)         // no weekend-days
340
			{
341
				switch($ui->cal_prefs['weekdaystarts'])
342
				{
343
					case 'Saturday':
344
						$query['start'] = strtotime("+2 days",$query['start']);
345
						break;
346
					case 'Sunday':
347
						$query['start'] = strtotime("+1 day",$query['start']);
348
						break;
349
				}
350
			}
351
			$query['end'] = strtotime($states['view'] == 'week' ? "+$days days" : "+{$ui->cal_prefs['multiple_weeks']} weeks",$query['start']) - 1;
352
		}
353
		return $query;
354
	}
355
356
	public static function get_query_day($states)
357
	{
358
		$query = array();
359
		$bo = new calendar_bo();
360
		$query['start'] = $bo->date2ts((string)$states['date']);
361
		$query['end'] = $query['start']+DAY_s-1;
362
		return $query;
363
	}
364
365
	/**
366
	 * Get select options for use in filter
367
	 */
368
	protected function get_selects()
369
	{
370
		$this->selects['priority'] = Array(
371
			0 => lang('None'),
372
			1 => lang('Low'),
373
			2 => lang('Normal'),
374
			3 => lang('High')
375
		);
376
		$this->selects['filter'] = array(
377
			'default'     => lang('Not rejected'),
378
			'accepted'    => lang('Accepted'),
379
			'unknown'     => lang('Invitations'),
380
			'tentative'   => lang('Tentative'),
381
			'delegated'   => lang('Delegated'),
382
			'rejected'    => lang('Rejected'),
383
			'owner'       => lang('Owner too'),
384
			'all'         => lang('All incl. rejected'),
385
			'hideprivate' => lang('Hide private infos'),
386
			'showonlypublic' =>  lang('Hide private events'),
387
			'no-enum-groups' => lang('only group-events'),
388
			'not-unknown' => lang('No meeting requests'),
389
		);
390
	}
391
392
	/**
393
	 * Adjust automatically generated field filters
394
	 */
395
	public function get_filter_fields(Array &$filters)
396
	{
397
398
		// Calendar SO doesn't support filtering by column, so we have to remove pretty much everything
399
		unset($filters['recur_date']);
400
401
		// Add in the status filter at the beginning
402
		$filters = array_reverse($filters, true);
403
		$filters['filter'] = array(
404
			'type'	=> 'select',
405
			'name'	=> 'filter',
406
			'label'	=> lang('Filter'),
407
		);
408
		$filters = array_reverse($filters, true);
409
410
		foreach($filters as $field_name => &$settings)
411
		{
412
			// Can't filter on a custom field
413
			if(strpos($field_name, '#') === 0)
414
			{
415
				unset($filters[$field_name]);
416
				continue;
417
			}
418
419
			// Pass on select options
420
			if($this->selects[$field_name]) $settings['values'] = $this->selects[$field_name];
421
		}
422
423
	}
424
	/**
425
	 * Get the class name for the egw_record to use while exporting
426
	 *
427
	 * @return string;
428
	 */
429
	public static function get_egw_record_class()
430
	{
431
		return 'calendar_egw_record';
432
	}
433
434
 }
435