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-milestone.php

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

1,218 lines 24.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class Milestone
4 *
5 * @package UpStream
6 */
7
8 namespace UpStream;
9
10 // Prevent direct access.
11
12 use UpStream\Traits\PostMetadata;
13
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 /**
19 * Class Milestone
20 *
21 * @since 1.24.0
22 */
23 class Milestone extends Struct {
24
25 use PostMetadata;
26
27 /**
28 * The Post Type for milestones.
29 */
30 const POST_TYPE = 'upst_milestone';
31
32 /**
33 * Project ID meta key.
34 */
35 const META_PROJECT_ID = 'upst_project_id';
36
37 /**
38 * Assigned To meta key.
39 */
40 const META_ASSIGNED_TO = 'upst_assigned_to';
41
42 /**
43 * Start date meta key.
44 */
45 const META_START_DATE = 'upst_start_date';
46
47 /**
48 * End date meta key.
49 */
50 const META_END_DATE = 'upst_end_date';
51
52 /**
53 * Order meta key.
54 */
55 const META_ORDER = 'upst_order';
56
57 /**
58 * Progress meta key.
59 */
60 const META_PROGRESS = 'upst_progress';
61
62 /**
63 * Color meta key.
64 */
65 const META_COLOR = 'upst_color';
66
67 /**
68 * Legacy ID meta key.
69 */
70 const META_LEGACY_ID = 'upst_legacy_id';
71
72 /**
73 * Legacy code used to link tasks to milestones.
74 */
75 const META_LEGACY_MILESTONE_CODE = 'upst_legacy_milestone_code';
76
77 /**
78 * Legacy flag for when the created time was set in UTC.
79 */
80 const META_CREATED_TIME_IN_UTC = 'upst_created_time_in_utc';
81
82 /**
83 * Task count meta key.
84 */
85 const META_TASK_COUNT = 'upst_task_count';
86
87 /**
88 * Task open meta key.
89 */
90 const META_TASK_OPEN = 'upst_task_open';
91
92 /**
93 * The default color.
94 */
95 const DEFAULT_COLOR = '#cccccc';
96
97 /**
98 * WP Post
99 *
100 * @var \WP_Post
101 */
102 protected $post;
103
104 /**
105 * Project ID
106 *
107 * @var int
108 */
109 protected $project_id;
110
111 /**
112 * Assigned to
113 *
114 * @var array
115 */
116 protected $assigned_to;
117
118 /**
119 * Start date in MySQL timestamp.
120 *
121 * @var string
122 */
123 protected $start_date;
124
125 /**
126 * End date in MySQL timestamp.
127 *
128 * @var string
129 */
130 protected $end_date;
131
132 /**
133 * Notes
134 *
135 * @var string
136 */
137 protected $notes;
138
139 /**
140 * Order
141 *
142 * @var int
143 */
144 protected $order;
145
146 /**
147 * Created By
148 *
149 * @var int
150 */
151 protected $created_date;
152
153 /**
154 * Created on date, in MySQL format
155 *
156 * @var string
157 */
158 protected $created_on;
159
160 /**
161 * Progress
162 *
163 * @var float
164 */
165 protected $progress;
166
167 /**
168 * Color
169 *
170 * @var string
171 */
172 protected $color;
173
174 /**
175 * Legacy ID
176 *
177 * @var string
178 */
179 protected $legacy_id;
180
181 /**
182 * Legacy_milestone_code
183 *
184 * @var string
185 */
186 protected $legacy_milestone_code;
187
188 /**
189 * Created Time In Utc
190 *
191 * @deprecated only for storing the legacy value from the old architecture.
192 *
193 * @var bool
194 */
195 protected $created_time_in_utc;
196
197 /**
198 * Task Count
199 *
200 * @var int
201 */
202 protected $task_count;
203
204 /**
205 * Task Open
206 *
207 * @var int
208 */
209 protected $task_open;
210
211 /**
212 * Categories
213 *
214 * @var array
215 */
216 protected $categories;
217
218 /**
219 * End date in YMD
220 *
221 * @var string
222 */
223 protected $end_date_ymd;
224
225 /**
226 * Start date in YMD
227 *
228 * @var string
229 */
230 protected $start_date_ymd;
231
232
233 /**
234 * Milestone constructor.
235 *
236 * @param int|\WP_Post|string $post Post object.
237 *
238 * @throws \Exception Exception.
239 */
240 public function __construct( $post ) {
241 if ( empty( $post ) ) {
242 throw new Exception( 'Invalid milestone post ID' );
243 }
244
245 if ( is_object( $post ) ) {
246 if ( self::POST_TYPE !== $post->post_type ) {
247 throw new Exception( __( 'Invalid Post Type for the given post.', 'upstream' ) );
248 }
249
250 $this->post_id = $post->ID;
251 $this->post = $post;
252 }
253
254 if ( is_numeric( $post ) ) {
255 $this->post_id = $post;
256 $this->post = $this->getPost();
257 }
258
259 // Are we filtering by the legacy ID?
260 if ( is_string( $post ) && ! is_numeric( $post ) ) {
261 $this->post = $this->getPost( $post );
262
263 if ( empty( $this->post ) ) {
264 throw new Exception( 'Milestone not found' );
265 }
266
267 $this->post_id = $this->post->ID;
268 }
269 }
270
271 /**
272 * Get Post data.
273 *
274 * @param string|null $legacy_id Legacy ID.
275 *
276 * @return \WP_Post|false Post data or false.
277 *
278 * @throws Exception Exception.
279 */
280 public function getPost( $legacy_id = null ) {
281 if ( empty( $this->post ) ) {
282 if ( empty( $this->post_id ) && empty( $legacy_id ) ) {
283 return false;
284 }
285
286 if ( empty( $legacy_id ) ) {
287 $this->post = get_post( $this->post_id );
288 } else {
289 $posts = get_posts(
290 array(
291 'post_type' => self::POST_TYPE,
292 'status' => 'publish',
293 'posts_per_page' => -1,
294 'meta_key' => self::META_LEGACY_ID,
295 'meta_value' => sanitize_text_field( $legacy_id ),
296 )
297 );
298
299 if ( ! empty( $posts ) ) {
300 $this->post = $posts[0];
301 } else {
302 throw new Exception( 'Milestone not found' );
303 }
304 }
305 }
306
307 return $this->post;
308 }
309
310 /**
311 * Set milestone name
312 *
313 * @param string $new_name New name.
314 *
315 * @return Milestone
316 */
317 public function setName( $new_name ) {
318 $this->post->post_title = $new_name;
319
320 $milestones = $this->getMilestonesInstance();
321
322 remove_action( 'save_post', array( $milestones, 'save_post' ) );
323 wp_update_post(
324 array(
325 'ID' => $this->post_id,
326 'post_title' => $new_name,
327 )
328 );
329 add_action( 'save_post', array( $milestones, 'save_post' ) );
330
331 return $this;
332 }
333
334 /**
335 * Get Milestones Instance
336 *
337 * @return \UpStream\Milestones
338 */
339 protected function getMilestonesInstance() {
340 return Milestones::getInstance();
341 }
342
343 /**
344 * Get Legacy Id
345 *
346 * @return string|null
347 */
348 public function getLegacyId() {
349 if ( ! empty( $this->legacy_id ) ) {
350 return $this->legacy_id;
351 }
352
353 $this->legacy_id = $this->get_metadata( self::META_LEGACY_ID, true );
354
355 return $this->legacy_id;
356 }
357
358 /**
359 * Set Legacy Id
360 *
361 * @param string $new_legacy_id New legacy ID.
362 *
363 * @return Milestone
364 */
365 public function setLegacyId( $new_legacy_id ) {
366 $this->legacy_id = sanitize_text_field( $new_legacy_id );
367
368 $this->update_metadata( array( self::META_LEGACY_ID => $new_legacy_id ) );
369
370 return $this;
371 }
372
373 /**
374 * Get Legacy Milestone Code
375 *
376 * @return string|null
377 */
378 public function getLegacyMilestoneCode() {
379 if ( ! empty( $this->legacy_milestone_code ) ) {
380 return $this->legacy_milestone_code;
381 }
382
383 $this->legacy_milestone_code = $this->get_metadata( self::META_LEGACY_MILESTONE_CODE, true );
384
385 return $this->legacy_milestone_code;
386 }
387
388 /**
389 * Set Legacy Milestone Code
390 *
391 * @param string $new_legacy_milestone_code New legacy milestone code.
392 *
393 * @return Milestone
394 */
395 public function setLegacyMilestoneCode( $new_legacy_milestone_code ) {
396 $this->legacy_milestone_code = sanitize_text_field( $new_legacy_milestone_code );
397
398 $this->update_metadata( array( self::META_LEGACY_MILESTONE_CODE => $new_legacy_milestone_code ) );
399
400 return $this;
401 }
402
403 /**
404 * GetCreatedTimeInUtc
405 *
406 * @return bool|null
407 */
408 public function getCreatedTimeInUtc() {
409 if ( ! empty( $this->created_time_in_utc ) ) {
410 return $this->created_time_in_utc;
411 }
412
413 $this->created_time_in_utc = $this->get_metadata( self::META_CREATED_TIME_IN_UTC, true );
414
415 return $this->created_time_in_utc;
416 }
417
418 /**
419 * SetCreatedTimeInUtc
420 *
421 * @param bool $new_created_time_in_utc New Created Time In Utc.
422 *
423 * @return Milestone
424 */
425 public function setCreatedTimeInUtc( $new_created_time_in_utc ) {
426 $this->created_time_in_utc = sanitize_text_field( $new_created_time_in_utc );
427
428 $this->update_metadata( array( self::META_CREATED_TIME_IN_UTC => $this->created_time_in_utc ) );
429
430 return $this;
431 }
432
433 /**
434 * Delete the milestone.
435 */
436 public function delete() {
437 global $wpdb;
438
439 try {
440 $wpdb->query( 'START TRANSACTION' );
441
442 $project_id = $this->getProjectId();
443
444 $tasks = (array) get_post_meta( $project_id, '_upstream_project_tasks', true );
445 if ( count( $tasks ) > 0 ) {
446 $updated = false;
447
448 foreach ( $tasks as &$task ) {
449 if ( isset( $task['milestone'] ) && $task['milestone'] === $this->getId() ) {
450 $task['milestone'] = '';
451
452 $updated = true;
453 }
454 }
455 unset( $task );
456
457 if ( $updated ) {
458 update_post_meta( $project_id, '_upstream_project_tasks', $tasks );
459 }
460 }
461
462 wp_trash_post( $this->getId() );
463
464 $activity = Factory::get_activity();
465 $activity->add_activity(
466 $project_id,
467 '_upstream_project_milestones',
468 'remove',
469 $this->convertToLegacyRowset()
470 );
471
472 $wpdb->query( 'COMMIT' );
473 } catch ( Exception $e ) {
474 $wpdb->query( 'ROLLBACK' );
475 }
476 }
477
478 /**
479 * GetProjectId
480 *
481 * @return int
482 */
483 public function getProjectId() {
484 if ( null === $this->project_id ) {
485 $this->project_id = (int) $this->get_metadata( self::META_PROJECT_ID, true );
486 }
487
488 return (int) $this->project_id;
489 }
490
491 /**
492 * SetProjectId
493 *
494 * @param int $project_id Project ID.
495 *
496 * @return Milestone
497 */
498 public function setProjectId( $project_id ) {
499 $this->project_id = (int) $project_id;
500
501 // Update the metadata.
502 $this->update_metadata( array( self::META_PROJECT_ID => $project_id ) );
503
504 $milestones = $this->getMilestonesInstance();
505
506 // Update the post parent so we can use it to filter and group project items.
507 $this->post->post_parent = $project_id;
508 remove_action( 'save_post', array( $milestones, 'save_post' ) );
509 wp_update_post(
510 array(
511 'ID' => $this->getId(),
512 'post_parent' => $project_id,
513 )
514 );
515 add_action( 'save_post', array( $milestones, 'save_post' ) );
516
517 return $this;
518 }
519
520 /**
521 * Get Id
522 *
523 * @return int
524 */
525 public function getId() {
526 return $this->post_id;
527 }
528
529 /**
530 * ConvertToLegacyRowset
531 *
532 * @return array
533 * @throws Exception Exception.
534 */
535 public function convertToLegacyRowset() {
536 $assignees = $this->getAssignedTo();
537 $categories = $this->getCategories();
538
539 if ( ! empty( $categories ) ) {
540 $categories_ids = array_map( array( $this, 'convertCategoryToLegacyRowset' ), $categories );
541 } else {
542 $categories_ids = array();
543 }
544
545 $row = array(
546 'id' => $this->getId(),
547 'milestone' => $this->getName(),
548 'milestone_order' => $this->getOrder(),
549 'created_by' => $this->getCreatedBy(),
550 'created_time' => $this->getCreatedOn( 'unix' ),
551 'assigned_to' => $assignees,
552 'progress' => $this->getProgress(),
553 'notes' => $this->getNotes(),
554 'start_date' => $this->getStartDate( 'unix' ),
555 'end_date' => $this->getEndDate( 'unix' ),
556 'start_date.YMD' => $this->getStartDate__YMD(),
557 'end_date.YMD' => $this->getEndDate__YMD(),
558 'task_count' => $this->getTaskCount(),
559 'task_open' => $this->getTaskOpen(),
560 'color' => $this->getColor(),
561 'categories' => $categories_ids,
562 'categories_order' => $this->getMilestonesInstance()->get_categories_names( $categories ),
563 );
564
565 if ( ! empty( $assignees ) ) {
566 // Get the name of assignees to fix ordering.
567 $row['assigned_to_order'] = upstream_get_users_display_name( $assignees );
568 }
569
570 $row = apply_filters( 'upstream_milestone_converting_legacy_rowset', $row );
571
572 return $row;
573 }
574
575 /**
576 * GetAssignedTo
577 *
578 * @return array
579 */
580 public function getAssignedTo() {
581 if ( null === $this->assigned_to ) {
582 $this->assigned_to = $this->get_metadata( self::META_ASSIGNED_TO, false );
583 }
584
585 return (array) $this->assigned_to;
586 }
587
588 /**
589 * SetAssignedTo
590 *
591 * @param array $assigned_to Assigned to.
592 *
593 * @return Milestone
594 */
595 public function setAssignedTo( $assigned_to ) {
596 if ( ! is_array( $assigned_to ) ) {
597 $assigned_to = array();
598 }
599
600 $this->assigned_to = $this->sanitizeArrayOfIds( $assigned_to );
601
602 $this->update_non_unique_metadata( self::META_ASSIGNED_TO, $this->assigned_to );
603
604 return $this;
605 }
606
607 /**
608 * GetCategories
609 *
610 * @param bool $only_keys Only keys boolean.
611 *
612 * @return array
613 */
614 public function getCategories( $only_keys = false ) {
615 if ( upstream_disable_milestone_categories() ) {
616 return array();
617 }
618
619 if ( ! isset( $this->categories ) ) {
620 $this->categories = wp_get_object_terms( $this->post_id, 'upst_milestone_category' );
621 }
622
623 if ( isset( $this->categories->errors ) ) {
624 return array();
625 }
626
627 if ( ! $only_keys ) {
628 $categories = $this->categories;
629 } else {
630 if ( empty( $this->categories ) ) {
631 $categories = array();
632 } else {
633 $categories = array_map( array( $this, 'convertCategoryToLegacyRowset' ), $this->categories );
634 }
635 }
636
637 return (array) $categories;
638 }
639
640 /**
641 * This method accepts array of integers (term_id) or instances of WP_Term.
642 *
643 * @param array $categories Milestone categories.
644 *
645 * @return Milestone
646 *
647 * @throws Exception Exception.
648 */
649 public function setCategories( $categories ) {
650 if ( ! is_array( $categories ) ) {
651 $categories = array();
652 }
653
654 $new_categories = array();
655
656 if ( ! empty( $categories ) ) {
657 foreach ( $categories as $category ) {
658 if ( is_object( $category ) && get_class( $category ) === 'WP_Term' ) {
659 $category = $category->term_id;
660 }
661
662 $new_categories[] = (int) $category;
663 }
664 }
665
666 wp_set_object_terms( $this->post_id, $new_categories, 'upst_milestone_category' );
667
668 return $this;
669 }
670
671 /**
672 * Get Name
673 *
674 * @return string
675 *
676 * @throws Exception Exception.
677 */
678 public function getName() {
679 if ( isset( $this->getPost()->post_title ) ) {
680 return $this->getPost()->post_title;
681 }
682 return '';
683 }
684
685 /**
686 * Get Order
687 *
688 * @return string|null
689 */
690 public function getOrder() {
691 if ( ! empty( $this->order ) ) {
692 return $this->order;
693 }
694
695 $this->order = $this->get_metadata( self::META_ORDER, true );
696
697 return $this->order;
698 }
699
700 /**
701 * SetOrder
702 *
703 * @param string $order Order.
704 *
705 * @return Milestone
706 * @throws Exception Exception.
707 */
708 public function setOrder( $order ) {
709 if ( empty( $order ) ) {
710 $order = $this->getName();
711 }
712
713 $this->order = $order;
714
715 // Assume it is on MySQL date format.
716 $this->update_metadata( array( self::META_ORDER => $order ) );
717
718 return $this;
719 }
720
721 /**
722 * GetCreatedBy
723 *
724 * @return int|null
725 *
726 * @throws Exception Exception.
727 */
728 public function getCreatedBy() {
729 if ( ! empty( $this->created_date ) ) {
730 return $this->created_date;
731 }
732
733 $this->created_date = (int) $this->getPost()->post_author;
734
735 return $this->created_date;
736 }
737
738 /**
739 * GetCreatedOn
740 *
741 * @param string $format Format data.
742 *
743 * @return int|null
744 */
745 public function getCreatedOn( $format = 'mysql' ) {
746 if ( ! empty( $this->created_on ) ) {
747 return $this->created_on;
748 }
749
750 $this->created_on = get_the_date( 'Y-m-d', $this->post_id );
751
752 return $this->getDateOnFormat( $this->created_on, $format );
753 }
754
755 /**
756 * GetDateOnFormat
757 *
758 * @param string $date Date.
759 * @param string $format Format.
760 *
761 * @return false|int|mixed
762 */
763 protected function getDateOnFormat( $date, $format ) {
764 if ( 'unix' === $format ) {
765 return strtotime( $date );
766 }
767
768 if ( 'upstream' === $format ) {
769 if ( ! preg_match( '/^\d+$/', $date ) ) {
770 $date = strtotime( $date );
771 }
772
773 return upstream_format_date( $date );
774 }
775
776 return $date;
777 }
778
779 /**
780 * GetProgress
781 *
782 * @return float|int
783 */
784 public function getProgress() {
785 if ( ! empty( $this->progress ) ) {
786 return $this->progress;
787 }
788
789 $this->progress = $this->get_metadata( self::META_PROGRESS, true );
790
791 if ( empty( $this->progress ) ) {
792 $this->progress = 0.00;
793 }
794
795 return (float) $this->progress;
796 }
797
798 /**
799 * SetProgress
800 *
801 * @param float $new_progress New progress.
802 *
803 * @return Milestone
804 */
805 public function setProgress( $new_progress ) {
806 $this->progress = (float) $new_progress;
807
808 $this->update_metadata( array( self::META_PROGRESS => $new_progress ) );
809
810 return $this;
811 }
812
813 /**
814 * GetNotes
815 *
816 * @return string|null
817 *
818 * @throws Exception Exception.
819 */
820 public function getNotes() {
821 if ( ! empty( $this->notes ) ) {
822 return $this->notes;
823 }
824
825 $this->notes = $this->getPost()->post_content;
826
827 return $this->notes;
828 }
829
830 /**
831 * SetNotes
832 *
833 * @param string $notes Notes.
834 *
835 * @return Milestone
836 */
837 public function setNotes( $notes ) {
838 $this->notes = $notes;
839
840 $milestones = $this->getMilestonesInstance();
841
842 remove_action( 'save_post', array( $milestones, 'save_post' ) );
843 wp_update_post(
844 array(
845 'ID' => $this->post_id,
846 'post_content' => $notes,
847 )
848 );
849 add_action( 'save_post', array( $milestones, 'save_post' ) );
850
851 return $this;
852 }
853
854 /**
855 * GetStartDate
856 *
857 * @param string $format mysql, unix, upstream.
858 *
859 * @return string
860 */
861 public function getStartDate( $format = 'mysql' ) {
862 if ( null === $this->start_date ) {
863 $this->start_date = $this->get_metadata( self::META_START_DATE, true );
864 }
865
866 return $this->getDateOnFormat( $this->start_date, $format );
867 }
868
869 /**
870 * SetStartDate
871 *
872 * @param int|string $start_date Start date.
873 *
874 * @return Milestone
875 */
876 public function setStartDate( $start_date ) {
877 $start_date = $this->getMySQLDate( $start_date );
878
879 $this->start_date = $start_date;
880
881 // Assume it is on MySQL date format.
882 $this->update_metadata( array( self::META_START_DATE => $start_date ) );
883
884 return $this;
885 }
886
887 /**
888 * SetStartDate__YMD
889 *
890 * @param string $start_date_ymd Start date ymd.
891 */
892 public function setStartDate__YMD( $start_date_ymd ) {
893 $this->update_metadata( array( 'upst_start_date.YMD' => $start_date_ymd ) );
894 return $this;
895 }
896
897 /**
898 * GetEndDate__YMD
899 */
900 public function getEndDate__YMD() {
901 if ( empty( $this->end_date_ymd ) && is_array( $this->get_metadata( 'upst_end_date.YMD' ) ) ) {
902 $r = $this->get_metadata( 'upst_end_date.YMD' );
903 if ( ! empty( $r ) && is_array( $r ) && count( $r ) > 0 ) {
904 $this->end_date_ymd = $r[0];
905 }
906 }
907 return $this->end_date_ymd;
908 }
909
910 /**
911 * GetStartDate__YMD
912 */
913 public function getStartDate__YMD() {
914 if ( empty( $this->start_date_ymd ) && is_array( $this->get_metadata( 'upst_start_date.YMD' ) ) ) {
915 $r = $this->get_metadata( 'upst_start_date.YMD' );
916 if ( ! empty( $r ) && is_array( $r ) && count( $r ) > 0 ) {
917 $this->start_date_ymd = $r[0];
918 }
919 }
920 return $this->start_date_ymd;
921 }
922
923 /**
924 * SetEndDate__YMD
925 *
926 * @param string $end_date_ymd End date ymd.
927 */
928 public function setEndDate__YMD( $end_date_ymd ) {
929 $this->update_metadata( array( 'upst_end_date.YMD' => $end_date_ymd ) );
930 return $this;
931 }
932
933 /**
934 * GetEndDate
935 *
936 * @param string $format mysql, unix, upstream.
937 *
938 * @return string
939 */
940 public function getEndDate( $format = 'mysql' ) {
941 if ( null === $this->end_date ) {
942 $this->end_date = $this->get_metadata( self::META_END_DATE, true );
943 }
944
945 return $this->getDateOnFormat( $this->end_date, $format );
946 }
947
948 /**
949 * SetEndDate
950 *
951 * @param int|string $end_date End date.
952 *
953 * @return Milestone
954 */
955 public function setEndDate( $end_date ) {
956 $end_date = $this->getMySQLDate( $end_date );
957
958 $this->end_date = $end_date;
959
960 // Assume it is on MySQL date format.
961 $this->update_metadata( array( self::META_END_DATE => $end_date ) );
962
963 return $this;
964 }
965
966 /**
967 * GetTaskCount
968 *
969 * @return int|null
970 */
971 public function getTaskCount() {
972 if ( ! empty( $this->task_count ) ) {
973 return $this->task_count;
974 }
975
976 $this->task_count = $this->get_metadata( self::META_TASK_COUNT, true );
977
978 return $this->task_count;
979 }
980
981 /**
982 * SetTaskCount
983 *
984 * @param int $new_task_count New Task Count.
985 *
986 * @return Milestone
987 */
988 public function setTaskCount( $new_task_count ) {
989 $this->task_count = sanitize_text_field( $new_task_count );
990
991 $this->update_metadata( array( self::META_TASK_COUNT => $new_task_count ) );
992
993 return $this;
994 }
995
996 /**
997 * GetTaskOpen
998 *
999 * @return int|null
1000 */
1001 public function getTaskOpen() {
1002 if ( ! empty( $this->task_open ) ) {
1003 return $this->task_open;
1004 }
1005
1006 $this->task_open = $this->get_metadata( self::META_TASK_OPEN, true );
1007
1008 return $this->task_open;
1009 }
1010
1011 /**
1012 * SetTaskOpen
1013 *
1014 * @param int $new_task_open New Task Open.
1015 *
1016 * @return Milestone
1017 */
1018 public function setTaskOpen( $new_task_open ) {
1019 $this->task_open = sanitize_text_field( $new_task_open );
1020
1021 $this->update_metadata( array( self::META_TASK_OPEN => $new_task_open ) );
1022
1023 return $this;
1024 }
1025
1026 /**
1027 * GetColor
1028 *
1029 * @return string|null
1030 */
1031 public function getColor() {
1032 if ( ! empty( $this->color ) ) {
1033 return $this->color;
1034 }
1035
1036 $this->color = $this->get_metadata( self::META_COLOR, true );
1037
1038 if ( empty( $this->color ) ) {
1039 // Check if the category (if set) has any default color.
1040 $categories = $this->getCategories();
1041 if ( ! empty( $categories ) ) {
1042 $first_category = $categories[0];
1043
1044 $category_default_color = get_term_meta( $first_category->term_id, 'color', true );
1045
1046 if ( ! empty( $category_default_color ) ) {
1047 $this->color = $category_default_color;
1048 }
1049 }
1050
1051 if ( empty( $this->color ) ) {
1052 $this->color = self::DEFAULT_COLOR;
1053 }
1054 }
1055
1056 return $this->color;
1057 }
1058
1059 /**
1060 * SetColor
1061 *
1062 * @param string $new_color New color.
1063 *
1064 * @return Milestone
1065 */
1066 public function setColor( $new_color ) {
1067 $this->color = sanitize_text_field( $new_color );
1068
1069 $this->update_metadata( array( self::META_COLOR => $new_color ) );
1070
1071 return $this;
1072 }
1073
1074 /**
1075 * SanitizeArrayOfIds
1076 *
1077 * @param array $array Array data.
1078 *
1079 * @return array array
1080 */
1081 protected function sanitizeArrayOfIds( $array ) {
1082 if ( ! empty( $array ) ) {
1083 $array = array_map( 'intval', $array );
1084
1085 $array = $this->removeEmptyValuesFromArray( $array );
1086 }
1087
1088 return $array;
1089 }
1090
1091 /**
1092 * RemoveEmptyValuesFromArray
1093 *
1094 * @param array $array Array data.
1095 *
1096 * @return array $array
1097 */
1098 protected function removeEmptyValuesFromArray( $array ) {
1099 if ( ! empty( $array ) ) {
1100 $array = array_unique( $array );
1101 $array = array_filter( $array );
1102 }
1103
1104 return $array;
1105 }
1106
1107 /**
1108 * GetMySQLDate
1109 *
1110 * @param mixed $date Date.
1111 *
1112 * @return false|mixed|string
1113 */
1114 protected function getMySQLDate( $date ) {
1115 if ( ! $this->dateIsMySQLDateFormat( $date ) ) {
1116 if ( ! $this->dateIsUnixTime( $date ) ) {
1117 // Convert to unix time.
1118 $date = upstream_date_unixtime( $date );
1119 }
1120
1121 // Assume it is in unix time format and convert to MySQL date format.
1122 if ( ! empty( $date ) ) {
1123 $date = gmdate( 'Y-m-d', $date );
1124 }
1125 }
1126
1127 return $date;
1128 }
1129
1130 /**
1131 * DateIsMySQLDateFormat
1132 *
1133 * @param int|string $date Date.
1134 *
1135 * @return bool
1136 */
1137 protected function dateIsMySQLDateFormat( $date ) {
1138 return preg_match( '/[0-9]{4}-[0-9]{2}-[0-9]{2}/', $date );
1139 }
1140
1141 /**
1142 * DateIsUnixTime
1143 *
1144 * @param string $date Date.
1145 *
1146 * @return bool
1147 */
1148 protected function dateIsUnixTime( $date ) {
1149 return preg_match( '/^\d+$/', $date );
1150 }
1151
1152 /**
1153 * ConvertCategoryToLegacyRowset
1154 *
1155 * @param string $category Category.
1156 */
1157 public function convertCategoryToLegacyRowset( $category ) {
1158 return $category->term_id;
1159 }
1160
1161 /**
1162 * GetComments
1163 *
1164 * @return array
1165 */
1166 public function getComments() {
1167 $comments = get_comments(
1168 array(
1169 'post_id' => $this->getProjectId(),
1170 'meta_query' => array(
1171 'relation' => 'AND',
1172 array(
1173 'key' => 'type',
1174 'value' => 'milestone',
1175 'compare' => '=',
1176 ),
1177 array(
1178 'key' => 'id',
1179 'value' => $this->getId(),
1180 'compare' => '=',
1181 ),
1182 ),
1183 )
1184 );
1185
1186 return $comments;
1187 }
1188
1189 /**
1190 * IsInProgress
1191 *
1192 * @return bool
1193 */
1194 public function isInProgress() {
1195 $progress = $this->getProgress();
1196
1197 return $progress > 0 && $progress < 100;
1198 }
1199
1200 /**
1201 * IsUpcoming
1202 *
1203 * @return bool
1204 */
1205 public function isUpcoming() {
1206 return ( $this->getStartDate( 'unix' ) < time() ) && ! $this->isCompleted();
1207 }
1208
1209 /**
1210 * IsCompleted
1211 *
1212 * @return bool
1213 */
1214 public function isCompleted() {
1215 return $this->getProgress() === 100;
1216 }
1217 }
1218