PluginProbe
UpStream: a Project Management Plugin for WordPress / 2.1.0
UpStream: a Project Management Plugin for WordPress v2.1.0
trunk 1.39.0 1.39.1 1.39.2 1.39.3 2.0.7 2.1.0
upstream / includes / class-upstream-report.php

class-upstream-report.php in UpStream: a Project Management Plugin for WordPress 2.1.0, at includes/class-upstream-report.php

684 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * UpStream_Report
4 *
5 * WordPress Coding Standart (WCS) note:
6 * Some camelCase methods and object properties on this file are not converted to snake_case,
7 * because it being used (heavily) on "upstream-reporting" add-on plugin.
8 *
9 * @package UpStream
10 */
11
12 if ( ! defined( 'ABSPATH' ) || class_exists( 'UpStream_Report' ) ) {
13 return;
14 }
15
16 /**
17 * Class UpStream_Report
18 */
19 class UpStream_Report {
20
21 /**
22 * Title
23 *
24 * @var string
25 */
26 public $title = '';
27
28 /**
29 * Id
30 *
31 * @var string
32 */
33 public $id = '';
34
35 /**
36 * UpStream_Report constructor.
37 */
38 public function __construct() { }
39
40 /**
41 * Get Display Options
42 */
43 public function getDisplayOptions() { // phpcs:ignore
44 return array(
45 'visualization_type' => 'Table',
46 );
47 }
48
49 /**
50 * Gets all of the parameter options to show when someone sets up a report. This is
51 * a form {
52 * ID : { type : project, task, etc,
53 * field1 : ...,
54 * field2 : ... }
55 * }
56 *
57 * @return array of all options to be used for the report parameters page
58 */
59 public function getAllFieldOptions() { // phpcs:ignore
60 return array();
61 }
62
63 /**
64 * Get Field Option
65 *
66 * @param mixed $section Section.
67 * @param mixed $key Key.
68 */
69 public function getFieldOption( $section, $key = null ) { // phpcs:ignore
70 $fo = $this->getAllFieldOptions();
71
72 if ( ! isset( $fo[ $section ] ) ) {
73 return null;
74 } else {
75 if ( $key ) {
76 return isset( $fo[ $section ][ $key ] ) ? $fo[ $section ][ $key ] : null;
77 } else {
78 return $fo[ $section ];
79 }
80 }
81 }
82
83 /**
84 * Array In
85 *
86 * @param mixed $needles Needles.
87 * @param mixed $haystack Haystack.
88 * @param mixed $comparator Comparator.
89 */
90 private function arrayIn( $needles, $haystack, $comparator = null ) { // phpcs:ignore
91 if ( ! $comparator ) {
92 $comparator = function( $a, $b ) {
93 return $a == $b;
94 };
95 }
96
97 if ( ! is_array( $haystack ) ) {
98 $haystack = array( $haystack );
99 }
100 if ( ! is_array( $needles ) ) {
101 $needles = array( $needles );
102 }
103
104 $haystack_count = count( $haystack );
105 for ( $j = 0; $j < $haystack_count; $j++ ) {
106 $needles_count = count( $needles );
107 for ( $i = 0; $i < $needles_count; $i++ ) {
108 if ( $comparator( $needles[ $i ], $haystack[ $j ] ) ) {
109 return true;
110 }
111 }
112 }
113
114 return false;
115 }
116
117 /**
118 * Combine Array
119 *
120 * @param mixed $arr Arr.
121 */
122 protected static function combineArray( $arr ) { // phpcs:ignore
123 if ( ! is_array( $arr ) ) {
124 return $arr;
125 } elseif ( count( $arr ) == 1 ) {
126 if ( ! isset( $arr[0] ) ) {
127 $arr[0] = null;
128 }
129 return $arr[0];
130 } else {
131 return implode( ', ', $arr );
132 }
133 }
134
135 /**
136 * Parse Project Params
137 *
138 * @param mixed $params Params.
139 * @param mixed $section_id Section Id.
140 */
141 protected function parseProjectParams( $params, $section_id ) { // phpcs:ignore
142 $prefix = $section_id . '_';
143 $field_options = $this->getAllFieldOptions();
144
145 $ids = $params[ $prefix . 'id' ];
146
147 $item_additional_check_callback = function( $item ) use ( $ids ) {
148
149 if ( ! $item instanceof UpStream_Model_Project ) {
150 return false;
151 }
152
153 if ( ! upstream_user_can_access_project( get_current_user_id(), $item->id ) ) {
154 return false;
155 }
156
157 return ( in_array( $item->id, $ids ) );
158 };
159
160 $options_info = $field_options[ $section_id ];
161 $items = $this->parseFields( $params, $prefix, $item_additional_check_callback );
162
163 return $items;
164 }
165
166 /**
167 * Parse Task Params
168 *
169 * @param mixed $params Params.
170 * @param mixed $section_id Section Id.
171 */
172 protected function parseTaskParams( $params, $section_id ) { // phpcs:ignore
173 $prefix = $section_id . '_';
174 $field_options = $this->getAllFieldOptions();
175
176 $ids = $params[ $prefix . 'id' ];
177
178 $item_additional_check_callback = function( $item ) use ( $ids ) {
179
180 if ( ! $item instanceof UpStream_Model_Task ) {
181 return false;
182 }
183
184 if ( ! upstream_override_access_object( true, UPSTREAM_ITEM_TYPE_TASK, $item->id, UPSTREAM_ITEM_TYPE_PROJECT, $item->parent->id, UPSTREAM_PERMISSIONS_ACTION_VIEW ) ) {
185 return false;
186 }
187
188 return ( in_array( $item->id, $ids ) );
189
190 };
191
192 $options_info = $field_options[ $section_id ];
193 $items = $this->parseFields( $params, $prefix, $item_additional_check_callback );
194
195 return $items;
196 }
197
198 /**
199 * Parse Bug Params
200 *
201 * @param mixed $params Params.
202 * @param mixed $section_id Section Id.
203 */
204 protected function parseBugParams( $params, $section_id ) { // phpcs:ignore
205 $prefix = $section_id . '_';
206 $field_options = $this->getAllFieldOptions();
207
208 $ids = $params[ $prefix . 'id' ];
209
210 $item_additional_check_callback = function( $item ) use ( $ids ) {
211
212 if ( ! $item instanceof UpStream_Model_Bug ) {
213 return false;
214 }
215
216 if ( ! upstream_override_access_object( true, UPSTREAM_ITEM_TYPE_BUG, $item->id, UPSTREAM_ITEM_TYPE_PROJECT, $item->parent->id, UPSTREAM_PERMISSIONS_ACTION_VIEW ) ) {
217 return false;
218 }
219
220 return ( in_array( $item->id, $ids ) );
221
222 };
223
224 $options_info = $field_options[ $section_id ];
225 $items = $this->parseFields( $params, $prefix, $item_additional_check_callback );
226
227 return $items;
228 }
229
230 /**
231 * Parse File Params
232 *
233 * @param mixed $params Params.
234 * @param mixed $section_id Section Id.
235 */
236 protected function parseFileParams( $params, $section_id ) { // phpcs:ignore
237 $prefix = $section_id . '_';
238 $field_options = $this->getAllFieldOptions();
239 $ids = $params[ $prefix . 'id' ];
240
241 $item_additional_check_callback = function( $item ) use ( $ids ) {
242 if ( ! $item instanceof UpStream_Model_File ) {
243 return false;
244 }
245
246 if ( ! upstream_override_access_object( true, UPSTREAM_ITEM_TYPE_FILE, $item->id, UPSTREAM_ITEM_TYPE_PROJECT, $item->parent->id, UPSTREAM_PERMISSIONS_ACTION_VIEW ) ) {
247 return false;
248 }
249
250 return ( in_array( $item->id, $ids ) );
251 };
252
253 $options_info = $field_options[ $section_id ];
254 $items = $this->parseFields( $params, $prefix, $item_additional_check_callback );
255
256 return $items;
257 }
258
259 /**
260 * Parse Milestone Params
261 *
262 * @param mixed $params Params.
263 * @param mixed $section_id Section Id.
264 */
265 protected function parseMilestoneParams( $params, $section_id ) { // phpcs:ignore
266 $prefix = $section_id . '_';
267 $field_options = $this->getAllFieldOptions();
268
269 $ids = $params[ $prefix . 'id' ];
270
271 $item_additional_check_callback = function( $item ) use ( $ids ) {
272
273 if ( ! $item instanceof UpStream_Model_Milestone ) {
274 return false;
275 }
276
277 if ( ! upstream_override_access_object( true, UPSTREAM_ITEM_TYPE_MILESTONE, $item->id, UPSTREAM_ITEM_TYPE_PROJECT, $item->parentId, UPSTREAM_PERMISSIONS_ACTION_VIEW ) ) { // phpcs:ignore
278 return false;
279 }
280
281 return ( in_array( $item->id, $ids ) );
282
283 };
284
285 $options_info = $field_options[ $section_id ];
286 $items = $this->parseFields( $params, $prefix, $item_additional_check_callback );
287
288 return $items;
289 }
290
291 /**
292 * Date Between
293 *
294 * @param mixed $lower_bound Lower Bound.
295 * @param mixed $upper_bound Upper Bound.
296 * @param mixed $val Val.
297 */
298 private static function dateBetween( $lower_bound, $upper_bound, $val ) { // phpcs:ignore
299 if ( empty( $upper_bound ) && empty( $lower_bound ) ) {
300 return true;
301 }
302 if ( ! $val ) {
303 return false;
304 }
305
306 try {
307 if ( empty( $lower_bound ) ) {
308 $lower_bound = new DateTime( '1970-01-01' );
309 } else {
310 $lower_bound = new DateTime( $lower_bound );
311 }
312 if ( empty( $upper_bound ) ) {
313 $upper_bound = new DateTime( '9999-01-01' );
314 } else {
315 $upper_bound = new DateTime( $upper_bound );
316 }
317
318 $val = new DateTime( $val );
319 $d1 = $lower_bound->diff( $val )->format( '%R%a' );
320 $d2 = $val->diff( $upper_bound )->format( '%R%a' );
321
322 if ( $d1 < 0 ) {
323 return false;
324 }
325 if ( $d2 < 0 ) {
326 return false;
327 }
328 return true;
329 } catch ( \Exception $e ) {
330 return true;
331 }
332 }
333
334 /**
335 * Number Between
336 *
337 * @param mixed $lower_bound Lower Bound.
338 * @param mixed $upper_bound Upper Bound.
339 * @param mixed $val Val.
340 */
341 private static function numberBetween( $lower_bound, $upper_bound, $val ) { // phpcs:ignore
342 if ( ( empty( $upper_bound ) && 0 != $upper_bound ) && ( empty( $lower_bound ) && 0 != $lower_bound ) ) {
343 return true;
344 }
345 if ( empty( $val ) ) {
346 $val = 0;
347 }
348
349 try {
350 if ( empty( $lower_bound ) || ! is_numeric( $lower_bound ) ) {
351 $lower_bound = -999999;
352 }
353 if ( empty( $upper_bound ) || ! is_numeric( $upper_bound ) ) {
354 $upper_bound = 999999;
355 }
356
357 if ( $val < $lower_bound ) {
358 return false;
359 }
360 if ( $val > $upper_bound ) {
361 return false;
362 }
363 return true;
364 } catch ( \Exception $e ) {
365 return true;
366 }
367 }
368
369 /**
370 * Check Item
371 *
372 * @param mixed $item Item.
373 * @param mixed $params Params.
374 * @param mixed $prefix Prefix.
375 * @param mixed $item_additional_check_callback Item Additional Check Callback.
376 */
377 protected function checkItem( $item, $params, $prefix, $item_additional_check_callback ) { // phpcs:ignore
378 $fields = $item->fields();
379 if ( $item_additional_check_callback && $item_additional_check_callback( $item ) == false ) {
380 return false;
381 }
382
383 foreach ( $fields as $field_name => $field ) {
384 if ( ! $field['search'] ) {
385 continue;
386 }
387
388 if ( ! isset( $params[ $prefix . $field_name ] ) || empty( $params[ $prefix . $field_name ] ) ) {
389 continue;
390 }
391
392 $value = $params[ $prefix . $field_name ];
393
394 if ( is_array( $value ) ) {
395 if ( 'user_id' === $field['type'] || 'select' === $field['type'] ) {
396 if ( ! $this->arrayIn( $value, $item->{$field_name} ) ) {
397 return false;
398 }
399 }
400 } else {
401 if ( 'string' === $field['type'] || 'text' === $field['type'] ) {
402 if ( ! stristr( $item->{$field_name}, $value ) ) {
403 return false;
404 }
405 } elseif ( 'color' === $field['type'] ) {
406 if ( ! stristr( $item->{$field_name}, $value ) ) {
407 return false;
408 }
409 } elseif ( 'date' === $field['type'] ) {
410 $value_start = $params[ $prefix . $field_name . '_start' ];
411 $value_end = $params[ $prefix . $field_name . '_end' ];
412 if ( ! self::dateBetween( $value_start, $value_end, $item->{$field_name} ) ) {
413 return false;
414 }
415 } elseif ( 'number' === $field['type'] ) {
416 $value_start = $params[ $prefix . $field_name . '_lower' ];
417 $value_end = $params[ $prefix . $field_name . '_upper' ];
418 if ( ! self::numberBetween( $value_start, $value_end, $item->{$field_name} ) ) {
419 return false;
420 }
421 }
422 // elseif ( $item->{$field_name} != $value ) {
423 // return false;
424 // }.
425 }
426 }
427
428 return true;
429 }
430
431 /**
432 * Parse Fields
433 *
434 * @param mixed $params Params.
435 * @param mixed $prefix Prefix.
436 * @param mixed $item_additional_check_callback Item Additional Check Callback.
437 */
438 protected function parseFields( $params, $prefix, $item_additional_check_callback ) { // phpcs:ignore
439 $mm = UpStream_Model_Manager::get_instance();
440
441 $items = $mm->findAllByCallback(
442 function( $item ) use ( $params, $prefix, $item_additional_check_callback ) {
443 return $this->checkItem( $item, $params, $prefix, $item_additional_check_callback );
444 }
445 );
446
447 return $items;
448 }
449
450 /**
451 * Make Cell
452 *
453 * @param mixed $val Val.
454 * @param mixed $field Field.
455 * @param mixed $users Users.
456 * @param mixed $override_f Override F.
457 */
458 public function makeCell( $val, &$field, &$users, $override_f = null ) { // phpcs:ignore
459 $f = null;
460
461 if ( ! is_array( $val ) ) {
462 $val = array( $val );
463 }
464 $val_count = count( $val );
465
466 for ( $j = 0; $j < $val_count; $j++ ) {
467 if ( ! empty( $field['options_cb'] ) ) {
468 $options = call_user_func( $field['options_cb'] );
469 if ( isset( $val[ $j ] ) && isset( $options[ $val[ $j ] ] ) ) {
470 $val[ $j ] = $options[ $val[ $j ] ];
471 }
472 } elseif ( isset( $val[ $j ] ) && 'user_id' === $field['type'] ) {
473 if ( isset( $users[ $val[ $j ] ] ) ) {
474 $val[ $j ] = $users[ $val[ $j ] ];
475 }
476 } elseif ( isset( $val[ $j ] ) && 'file' === $field['type'] ) {
477 if ( upstream_filesytem_enabled() ) {
478 $file = upstream_upfs_info( $val[ $j ] );
479 if ( $file ) {
480 $val[ $j ] = $file->orig_filename;
481 }
482 } else {
483 if ( $val[ $j ] ) {
484 $file = get_attached_file( $val[ $j ] );
485 $val[ $j ] = $file ? basename( $file ) : '';
486 } else {
487 $val[ $j ] = '';
488 }
489 }
490 } elseif ( isset( $val[ $j ] ) && 'date' === $field['type'] ) {
491 if ( $val[ $j ] ) {
492 $dp = explode( '-', $val[ $j ] );
493 $val[ $j ] = 'Date(' . $dp[0] . ',' . sprintf( '%02d', $dp[1] - 1 ) . ',' . $dp[2] . ')';
494 $f = null;
495 } else {
496 $val[ $j ] = '';
497 $f = '(empty)';
498 }
499 }
500 } // end for
501
502 if ( $override_f ) {
503 $f = $override_f;
504 }
505
506 if ( 'number' === $field['type'] ) {
507 $val[0] = (float) $val[0];
508 }
509
510 return $this->makeItem( $val, $f );
511 }
512
513 /**
514 * Execute Report
515 *
516 * @param mixed $params Params.
517 * @param mixed $row_callback Row Callback.
518 */
519 public function executeReport( $params, $row_callback = null ) { // phpcs:ignore
520 $display_fields = $params['display_fields'];
521 $items = $this->getIncludedItems( $params );
522 $data = array();
523 $users_info = upstream_get_viewable_users();
524 $users = $users_info['by_uid'];
525 $columns = array();
526 $items_count = count( $items );
527
528 for ( $i = 0; $i < $items_count; $i++ ) {
529
530 $item = $items[ $i ];
531 $fields = $items[ $i ]->fields();
532 $row = array();
533
534 foreach ( $display_fields as $field_name ) {
535 if ( isset( $fields[ $field_name ] ) && $fields[ $field_name ]['display'] ) {
536
537 $field = $fields[ $field_name ];
538 $columns[ $field_name ] = $field;
539
540 $parent_type = null;
541 $parent_id = 0;
542
543 if ( $item instanceof UpStream_Model_Meta_Object ) {
544 $parent_type = $item->parent->type;
545 $parent_id = $item->parent->id;
546 } elseif ( $item instanceof UpStream_Model_Milestone ) {
547 $parent_type = UPSTREAM_ITEM_TYPE_PROJECT;
548 $parent_id = $item->parentId; // phpcs:ignore
549 }
550
551 if ( upstream_override_access_field( true, $item->type, $item->id, $parent_type, $parent_id, $field_name, UPSTREAM_PERMISSIONS_ACTION_VIEW ) ) {
552 $val = $item->{$field_name};
553 $row[] = $this->makeCell( $val, $field, $users );
554 } else {
555 $val = null;
556 $row[] = $this->makeCell( $val, $field, $users, '(hidden)' );
557 }
558 }
559 } // end foreach
560
561 if ( null != $row_callback ) {
562 $row = call_user_func( $row_callback, $row );
563 }
564
565 if ( null != $row ) {
566 $data[] = array( 'c' => $row );
567 }
568 }
569
570 $column_info = $this->makeColumnInfo( $columns );
571
572 return array(
573 'cols' => $column_info,
574 'rows' => $data,
575 );
576 }
577
578 /**
579 * Make Item
580 *
581 * @param mixed $val Val.
582 * @param mixed $f F.
583 */
584 protected function makeItem( $val, $f = null ) { // phpcs:ignore
585 $r = array( 'v' => self::combineArray( $val ) );
586 if ( $f ) {
587 $r['f'] = $f;
588 }
589 return $r;
590 }
591
592 /**
593 * Get Included Items
594 *
595 * @param mixed $params Params.
596 */
597 public function getIncludedItems( $params ) { // phpcs:ignore
598 return array();
599 }
600
601 /**
602 * Make Column Info
603 *
604 * @param mixed $columns Columns.
605 */
606 protected function makeColumnInfo( &$columns ) { // phpcs:ignore
607 $column_info = array();
608
609 foreach ( $columns as $cid => $column ) {
610 $ci = array();
611 $ci['id'] = $cid;
612 $ci['label'] = $column['title'];
613
614 switch ( $column['type'] ) {
615
616 case 'date':
617 $ci['type'] = 'date';
618 break;
619
620 case 'number':
621 $ci['type'] = 'number';
622 break;
623
624 default:
625 $ci['type'] = 'string';
626 }
627 $column_info[] = $ci;
628 }
629
630 return $column_info;
631 }
632
633 }
634
635 /**
636 * Class UpStream_Report_Projects
637 */
638 class UpStream_Report_Projects extends UpStream_Report {
639
640 /**
641 * Id
642 *
643 * @var string
644 */
645 public $id = 'projects';
646
647 /**
648 * Construct
649 *
650 * @return void
651 */
652 public function __construct() {
653 $this->title = __( 'Project Table', 'upstream-reporting' );
654 }
655
656 /**
657 * Get Display Options
658 */
659 public function getDisplayOptions() {
660 return array(
661 'show_display_fields_box' => true,
662 'visualization_type' => 'Table',
663 );
664 }
665
666 /**
667 * Get All Field Options
668 */
669 public function getAllFieldOptions() {
670 return array( 'projects' => array( 'type' => 'project' ) );
671 }
672
673 /**
674 * Get Included Items
675 *
676 * @param mixed $params Params.
677 */
678 public function getIncludedItems( $params ) {
679 $items = self::parseProjectParams( $params, 'projects' );
680
681 return $items;
682 }
683 }
684