Completed
Branch models-cleanup/model-relations (278059)
by
unknown
79:14 queued 69:54
created
core/db_models/EEM_Country.model.php 1 patch
Indentation   +97 added lines, -97 removed lines patch added patch discarded remove patch
@@ -12,114 +12,114 @@
 block discarded – undo
12 12
 class EEM_Country extends EEM_Base
13 13
 {
14 14
 
15
-    // private instance of the Attendee object
16
-    protected static $_instance = null;
17
-    // array of all countries
18
-    private static $_all_countries = false;
19
-    // array of all active countries
20
-    private static $_active_countries = false;
15
+	// private instance of the Attendee object
16
+	protected static $_instance = null;
17
+	// array of all countries
18
+	private static $_all_countries = false;
19
+	// array of all active countries
20
+	private static $_active_countries = false;
21 21
 
22 22
 
23 23
 
24
-    /**
25
-     * Resets the country
26
-     * @return EEM_Country
27
-     */
28
-    public static function reset($timezone = '')
29
-    {
30
-        self::$_active_countries = null;
31
-        self::$_all_countries = null;
32
-        return parent::reset($timezone);
33
-    }
24
+	/**
25
+	 * Resets the country
26
+	 * @return EEM_Country
27
+	 */
28
+	public static function reset($timezone = '')
29
+	{
30
+		self::$_active_countries = null;
31
+		self::$_all_countries = null;
32
+		return parent::reset($timezone);
33
+	}
34 34
 
35
-    protected function __construct($timezone = '')
36
-    {
37
-        $this->singular_item = esc_html__('Country', 'event_espresso');
38
-        $this->plural_item = esc_html__('Countries', 'event_espresso');
35
+	protected function __construct($timezone = '')
36
+	{
37
+		$this->singular_item = esc_html__('Country', 'event_espresso');
38
+		$this->plural_item = esc_html__('Countries', 'event_espresso');
39 39
 
40 40
 
41
-        $this->_tables = array(
42
-            'Country' => new EE_Primary_Table('esp_country', 'CNT_ISO')
43
-        );
44
-        $this->_fields = array(
45
-            'Country' => array(
46
-                'CNT_active' => new EE_Boolean_Field('CNT_active', esc_html__('Country Appears in Dropdown Select Lists', 'event_espresso'), false, true),
47
-                'CNT_ISO' => new EE_Primary_Key_String_Field('CNT_ISO', esc_html__('Country ISO Code', 'event_espresso')),
48
-                'CNT_ISO3' => new EE_All_Caps_Text_Field('CNT_ISO3', esc_html__('Country ISO3 Code', 'event_espresso'), false, ''),
49
-                'RGN_ID' => new EE_Integer_Field('RGN_ID', esc_html__('Region ID', 'event_espresso'), false, 0),// should be a foreign key, but no region table exists yet
50
-                'CNT_name' => new EE_Plain_Text_Field('CNT_name', esc_html__('Country Name', 'event_espresso'), false, ''),
51
-                'CNT_cur_code' => new EE_All_Caps_Text_Field('CNT_cur_code', esc_html__('Country Currency Code', 'event_espresso'), false),
52
-                'CNT_cur_single' => new EE_Plain_Text_Field('CNT_cur_single', esc_html__('Currency Name Singular', 'event_espresso'), false),
53
-                'CNT_cur_plural' => new EE_Plain_Text_Field('CNT_cur_plural', esc_html__('Currency Name Plural', 'event_espresso'), false),
54
-                'CNT_cur_sign' => new EE_Plain_Text_Field('CNT_cur_sign', esc_html__('Currency Sign', 'event_espresso'), false),
55
-                'CNT_cur_sign_b4' => new EE_Boolean_Field('CNT_cur_sign_b4', esc_html__('Currency Sign Before Number', 'event_espresso'), false, true),
56
-                'CNT_cur_dec_plc' => new EE_Integer_Field('CNT_cur_dec_plc', esc_html__('Currency Decimal Places', 'event_espresso'), false, 2),
57
-                'CNT_cur_dec_mrk' => new EE_Plain_Text_Field('CNT_cur_dec_mrk', esc_html__('Currency Decimal Mark', 'event_espresso'), false, '.'),
58
-                'CNT_cur_thsnds' => new EE_Plain_Text_Field('CNT_cur_thsnds', esc_html__('Currency Thousands Separator', 'event_espresso'), false, ','),
59
-                'CNT_tel_code' => new EE_Plain_Text_Field('CNT_tel_code', esc_html__('Country Telephone Code', 'event_espresso'), false, ''),
60
-                'CNT_is_EU' => new EE_Boolean_Field('CNT_is_EU', esc_html__('Country is Member of EU', 'event_espresso'), false, false)
61
-            ));
62
-        $this->_model_relations = array(
63
-            'Attendee' => new EE_Has_Many_Relation(),
64
-            'State' => new EE_Has_Many_Relation(),
65
-            'Venue' => new EE_Has_Many_Relation(),
66
-        );
67
-        // only anyone to view, but only those with the default role can do anything
68
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
41
+		$this->_tables = array(
42
+			'Country' => new EE_Primary_Table('esp_country', 'CNT_ISO')
43
+		);
44
+		$this->_fields = array(
45
+			'Country' => array(
46
+				'CNT_active' => new EE_Boolean_Field('CNT_active', esc_html__('Country Appears in Dropdown Select Lists', 'event_espresso'), false, true),
47
+				'CNT_ISO' => new EE_Primary_Key_String_Field('CNT_ISO', esc_html__('Country ISO Code', 'event_espresso')),
48
+				'CNT_ISO3' => new EE_All_Caps_Text_Field('CNT_ISO3', esc_html__('Country ISO3 Code', 'event_espresso'), false, ''),
49
+				'RGN_ID' => new EE_Integer_Field('RGN_ID', esc_html__('Region ID', 'event_espresso'), false, 0),// should be a foreign key, but no region table exists yet
50
+				'CNT_name' => new EE_Plain_Text_Field('CNT_name', esc_html__('Country Name', 'event_espresso'), false, ''),
51
+				'CNT_cur_code' => new EE_All_Caps_Text_Field('CNT_cur_code', esc_html__('Country Currency Code', 'event_espresso'), false),
52
+				'CNT_cur_single' => new EE_Plain_Text_Field('CNT_cur_single', esc_html__('Currency Name Singular', 'event_espresso'), false),
53
+				'CNT_cur_plural' => new EE_Plain_Text_Field('CNT_cur_plural', esc_html__('Currency Name Plural', 'event_espresso'), false),
54
+				'CNT_cur_sign' => new EE_Plain_Text_Field('CNT_cur_sign', esc_html__('Currency Sign', 'event_espresso'), false),
55
+				'CNT_cur_sign_b4' => new EE_Boolean_Field('CNT_cur_sign_b4', esc_html__('Currency Sign Before Number', 'event_espresso'), false, true),
56
+				'CNT_cur_dec_plc' => new EE_Integer_Field('CNT_cur_dec_plc', esc_html__('Currency Decimal Places', 'event_espresso'), false, 2),
57
+				'CNT_cur_dec_mrk' => new EE_Plain_Text_Field('CNT_cur_dec_mrk', esc_html__('Currency Decimal Mark', 'event_espresso'), false, '.'),
58
+				'CNT_cur_thsnds' => new EE_Plain_Text_Field('CNT_cur_thsnds', esc_html__('Currency Thousands Separator', 'event_espresso'), false, ','),
59
+				'CNT_tel_code' => new EE_Plain_Text_Field('CNT_tel_code', esc_html__('Country Telephone Code', 'event_espresso'), false, ''),
60
+				'CNT_is_EU' => new EE_Boolean_Field('CNT_is_EU', esc_html__('Country is Member of EU', 'event_espresso'), false, false)
61
+			));
62
+		$this->_model_relations = array(
63
+			'Attendee' => new EE_Has_Many_Relation(),
64
+			'State' => new EE_Has_Many_Relation(),
65
+			'Venue' => new EE_Has_Many_Relation(),
66
+		);
67
+		// only anyone to view, but only those with the default role can do anything
68
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
69 69
 
70
-        parent::__construct($timezone);
71
-    }
70
+		parent::__construct($timezone);
71
+	}
72 72
 
73 73
 
74 74
 
75 75
 
76
-    /**
77
-    *       _get_countries
78
-    *
79
-    *       @access     public
80
-    *       @return         array
81
-    */
82
-    public function get_all_countries()
83
-    {
84
-        if (! self::$_all_countries) {
85
-            self::$_all_countries = $this->get_all(array( 'order_by' => array('CNT_name' => 'ASC'), 'limit' => array( 0,99999 )));
86
-        }
87
-        return self::$_all_countries;
88
-    }
76
+	/**
77
+	 *       _get_countries
78
+	 *
79
+	 *       @access     public
80
+	 *       @return         array
81
+	 */
82
+	public function get_all_countries()
83
+	{
84
+		if (! self::$_all_countries) {
85
+			self::$_all_countries = $this->get_all(array( 'order_by' => array('CNT_name' => 'ASC'), 'limit' => array( 0,99999 )));
86
+		}
87
+		return self::$_all_countries;
88
+	}
89 89
 
90
-    /**
91
-    *       _get_countries
92
-    *       Gets and caches the list of active countries. If you know the list of active countries
93
-    *       has changed during this request, first use EEM_Country::reset() to flush the cache
94
-    *       @access     public
95
-    *       @return         array
96
-    */
97
-    public function get_all_active_countries()
98
-    {
99
-        if (! self::$_active_countries) {
100
-            self::$_active_countries =  $this->get_all(array( array( 'CNT_active' => true ), 'order_by' => array('CNT_name' => 'ASC'), 'limit' => array( 0, 99999 )));
101
-        }
102
-        return self::$_active_countries;
103
-    }
90
+	/**
91
+	 *       _get_countries
92
+	 *       Gets and caches the list of active countries. If you know the list of active countries
93
+	 *       has changed during this request, first use EEM_Country::reset() to flush the cache
94
+	 *       @access     public
95
+	 *       @return         array
96
+	 */
97
+	public function get_all_active_countries()
98
+	{
99
+		if (! self::$_active_countries) {
100
+			self::$_active_countries =  $this->get_all(array( array( 'CNT_active' => true ), 'order_by' => array('CNT_name' => 'ASC'), 'limit' => array( 0, 99999 )));
101
+		}
102
+		return self::$_active_countries;
103
+	}
104 104
 
105
-    /**
106
-     * Gets the country's name by its ISO
107
-     * @param string $country_ISO
108
-     * @return string
109
-     */
110
-    public function get_country_name_by_ISO($country_ISO)
111
-    {
112
-        if (
113
-            isset(self::$_all_countries[ $country_ISO ]) &&
114
-                self::$_all_countries[ $country_ISO ] instanceof EE_Country
115
-        ) {
116
-            return self::$_all_countries[ $country_ISO ]->name();
117
-        }
118
-        $names = $this->get_col(array( array( 'CNT_ISO' => $country_ISO ), 'limit' => 1), 'CNT_name');
119
-        if (is_array($names) && ! empty($names)) {
120
-            return reset($names);
121
-        } else {
122
-            return '';
123
-        }
124
-    }
105
+	/**
106
+	 * Gets the country's name by its ISO
107
+	 * @param string $country_ISO
108
+	 * @return string
109
+	 */
110
+	public function get_country_name_by_ISO($country_ISO)
111
+	{
112
+		if (
113
+			isset(self::$_all_countries[ $country_ISO ]) &&
114
+				self::$_all_countries[ $country_ISO ] instanceof EE_Country
115
+		) {
116
+			return self::$_all_countries[ $country_ISO ]->name();
117
+		}
118
+		$names = $this->get_col(array( array( 'CNT_ISO' => $country_ISO ), 'limit' => 1), 'CNT_name');
119
+		if (is_array($names) && ! empty($names)) {
120
+			return reset($names);
121
+		} else {
122
+			return '';
123
+		}
124
+	}
125 125
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Message_Template.model.php 1 patch
Indentation   +36 added lines, -36 removed lines patch added patch discarded remove patch
@@ -14,45 +14,45 @@
 block discarded – undo
14 14
  */
15 15
 class EEM_Message_Template extends EEM_Base
16 16
 {
17
-    // private instance of the EEM_Message_Template object
18
-    protected static $_instance = null;
17
+	// private instance of the EEM_Message_Template object
18
+	protected static $_instance = null;
19 19
 
20 20
 
21 21
 
22
-    /**
23
-     * private constructor to prevent direct creation
24
-     *
25
-     * @Constructor
26
-     * @access protected
27
-     * @param string $timezone
28
-     * @throws \EE_Error
29
-     */
30
-    protected function __construct($timezone = '')
31
-    {
32
-        $this->singular_item = __('Message Template', 'event_espresso');
33
-        $this->plural_item = __('Message Templates', 'event_espresso');
22
+	/**
23
+	 * private constructor to prevent direct creation
24
+	 *
25
+	 * @Constructor
26
+	 * @access protected
27
+	 * @param string $timezone
28
+	 * @throws \EE_Error
29
+	 */
30
+	protected function __construct($timezone = '')
31
+	{
32
+		$this->singular_item = __('Message Template', 'event_espresso');
33
+		$this->plural_item = __('Message Templates', 'event_espresso');
34 34
 
35
-        $this->_tables = array(
36
-            'Message_Template' => new EE_Primary_Table('esp_message_template', 'MTP_ID')
37
-        );
38
-        $this->_fields = array(
39
-            'Message_Template' => array(
40
-                'MTP_ID' => new EE_Primary_Key_Int_Field('MTP_ID', __('Message Template ID', 'event_espresso')),
41
-                'GRP_ID' => new EE_Foreign_Key_Int_Field('GRP_ID', __('Message Template Group ID', 'event_espresso'), false, 0, 'Message_Template_Group'),
42
-                'MTP_template_field' => new EE_Plain_Text_Field('MTP_template_field', __('Field Name for this Template', 'event_espresso'), false, 'default'),
43
-                'MTP_context' => new EE_Plain_Text_Field('MTP_context', __('Message Type Context for this field', 'event_espresso'), false, 'admin'),
44
-                'MTP_content' => new EE_Serialized_Text_Field('MTP_content', __('The field content for the template', 'event_espresso'), false, ''),
45
-            )
46
-        );
35
+		$this->_tables = array(
36
+			'Message_Template' => new EE_Primary_Table('esp_message_template', 'MTP_ID')
37
+		);
38
+		$this->_fields = array(
39
+			'Message_Template' => array(
40
+				'MTP_ID' => new EE_Primary_Key_Int_Field('MTP_ID', __('Message Template ID', 'event_espresso')),
41
+				'GRP_ID' => new EE_Foreign_Key_Int_Field('GRP_ID', __('Message Template Group ID', 'event_espresso'), false, 0, 'Message_Template_Group'),
42
+				'MTP_template_field' => new EE_Plain_Text_Field('MTP_template_field', __('Field Name for this Template', 'event_espresso'), false, 'default'),
43
+				'MTP_context' => new EE_Plain_Text_Field('MTP_context', __('Message Type Context for this field', 'event_espresso'), false, 'admin'),
44
+				'MTP_content' => new EE_Serialized_Text_Field('MTP_content', __('The field content for the template', 'event_espresso'), false, ''),
45
+			)
46
+		);
47 47
 
48
-        $this->_model_relations = array(
49
-            'Message_Template_Group' => new EE_Belongs_To_Relation()
50
-            );
51
-        $this->_model_chain_to_wp_user = 'Message_Template_Group';
52
-        foreach ($this->_cap_contexts_to_cap_action_map as $context => $action) {
53
-            $this->_cap_restriction_generators[ $context ] = new EE_Restriction_Generator_Global('Message_Template_Group.MTP_is_global');
54
-        }
55
-        $this->_caps_slug = 'messages';
56
-        parent::__construct($timezone);
57
-    }
48
+		$this->_model_relations = array(
49
+			'Message_Template_Group' => new EE_Belongs_To_Relation()
50
+			);
51
+		$this->_model_chain_to_wp_user = 'Message_Template_Group';
52
+		foreach ($this->_cap_contexts_to_cap_action_map as $context => $action) {
53
+			$this->_cap_restriction_generators[ $context ] = new EE_Restriction_Generator_Global('Message_Template_Group.MTP_is_global');
54
+		}
55
+		$this->_caps_slug = 'messages';
56
+		parent::__construct($timezone);
57
+	}
58 58
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Post_Meta.model.php 1 patch
Indentation   +49 added lines, -49 removed lines patch added patch discarded remove patch
@@ -19,56 +19,56 @@
 block discarded – undo
19 19
 class EEM_Post_Meta extends EEM_Base
20 20
 {
21 21
 
22
-    // private instance of the EE_Post_Meta object
23
-    protected static $_instance = null;
22
+	// private instance of the EE_Post_Meta object
23
+	protected static $_instance = null;
24 24
 
25 25
 
26 26
 
27
-    protected function __construct($timezone = '')
28
-    {
29
-        $this->singular_item = __('Post Meta', 'event_espresso');
30
-        $this->plural_item = __('Post Metas', 'event_espresso');
31
-        $this->_tables = array(
32
-            'Post_Meta' => new EE_Primary_Table('postmeta', 'meta_id'),
33
-        );
34
-        $models_this_can_attach_to = array_keys(EE_Registry::instance()->cpt_models());
35
-        $this->_fields = array(
36
-            'Post_Meta' => array(
37
-                'meta_id'    => new EE_Primary_Key_Int_Field(
38
-                    'meta_id',
39
-                    __("Meta ID", "event_espresso")
40
-                ),
41
-                'post_id'    => new EE_Foreign_Key_Int_Field(
42
-                    'post_id',
43
-                    __("Primary Key of Post", "event_espresso"),
44
-                    false,
45
-                    0,
46
-                    $models_this_can_attach_to
47
-                ),
48
-                'meta_key'   => new EE_Plain_Text_Field(
49
-                    'meta_key',
50
-                    __("Meta Key", "event_espresso"),
51
-                    false,
52
-                    ''
53
-                ),
54
-                'meta_value' => new EE_Maybe_Serialized_Text_Field(
55
-                    'meta_value',
56
-                    __("Meta Value", "event_espresso"),
57
-                    true
58
-                ),
59
-            ),
60
-        );
61
-        $this->_model_relations = array();
62
-        foreach ($models_this_can_attach_to as $model) {
63
-            $this->_model_relations[ $model ] = new EE_Belongs_To_Relation();
64
-        }
65
-        $this->_wp_core_model = true;
66
-        foreach ($this->cap_contexts_to_cap_action_map() as $cap_context => $action) {
67
-            $this->_cap_restriction_generators[ $cap_context ] = new EE_Restriction_Generator_Meta(
68
-                'meta_key',
69
-                'meta_value'
70
-            );
71
-        }
72
-        parent::__construct($timezone);
73
-    }
27
+	protected function __construct($timezone = '')
28
+	{
29
+		$this->singular_item = __('Post Meta', 'event_espresso');
30
+		$this->plural_item = __('Post Metas', 'event_espresso');
31
+		$this->_tables = array(
32
+			'Post_Meta' => new EE_Primary_Table('postmeta', 'meta_id'),
33
+		);
34
+		$models_this_can_attach_to = array_keys(EE_Registry::instance()->cpt_models());
35
+		$this->_fields = array(
36
+			'Post_Meta' => array(
37
+				'meta_id'    => new EE_Primary_Key_Int_Field(
38
+					'meta_id',
39
+					__("Meta ID", "event_espresso")
40
+				),
41
+				'post_id'    => new EE_Foreign_Key_Int_Field(
42
+					'post_id',
43
+					__("Primary Key of Post", "event_espresso"),
44
+					false,
45
+					0,
46
+					$models_this_can_attach_to
47
+				),
48
+				'meta_key'   => new EE_Plain_Text_Field(
49
+					'meta_key',
50
+					__("Meta Key", "event_espresso"),
51
+					false,
52
+					''
53
+				),
54
+				'meta_value' => new EE_Maybe_Serialized_Text_Field(
55
+					'meta_value',
56
+					__("Meta Value", "event_espresso"),
57
+					true
58
+				),
59
+			),
60
+		);
61
+		$this->_model_relations = array();
62
+		foreach ($models_this_can_attach_to as $model) {
63
+			$this->_model_relations[ $model ] = new EE_Belongs_To_Relation();
64
+		}
65
+		$this->_wp_core_model = true;
66
+		foreach ($this->cap_contexts_to_cap_action_map() as $cap_context => $action) {
67
+			$this->_cap_restriction_generators[ $cap_context ] = new EE_Restriction_Generator_Meta(
68
+				'meta_key',
69
+				'meta_value'
70
+			);
71
+		}
72
+		parent::__construct($timezone);
73
+	}
74 74
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Datetime.model.php 1 patch
Indentation   +830 added lines, -830 removed lines patch added patch discarded remove patch
@@ -13,834 +13,834 @@
 block discarded – undo
13 13
 class EEM_Datetime extends EEM_Soft_Delete_Base
14 14
 {
15 15
 
16
-    /**
17
-     * @var EEM_Datetime $_instance
18
-     */
19
-    protected static $_instance;
20
-
21
-
22
-    /**
23
-     * private constructor to prevent direct creation
24
-     *
25
-     * @param string $timezone A string representing the timezone we want to set for returned Date Time Strings
26
-     *                         (and any incoming timezone data that gets saved).
27
-     *                         Note this just sends the timezone info to the date time model field objects.
28
-     *                         Default is NULL
29
-     *                         (and will be assumed using the set timezone in the 'timezone_string' wp option)
30
-     * @throws EE_Error
31
-     * @throws InvalidArgumentException
32
-     * @throws InvalidArgumentException
33
-     */
34
-    protected function __construct($timezone = '')
35
-    {
36
-        $this->singular_item           = esc_html__('Datetime', 'event_espresso');
37
-        $this->plural_item             = esc_html__('Datetimes', 'event_espresso');
38
-        $this->_tables                 = [
39
-            'Datetime' => new EE_Primary_Table('esp_datetime', 'DTT_ID'),
40
-        ];
41
-        $this->_fields                 = [
42
-            'Datetime' => [
43
-                'DTT_ID'          => new EE_Primary_Key_Int_Field(
44
-                    'DTT_ID',
45
-                    esc_html__('Datetime ID', 'event_espresso')
46
-                ),
47
-                'EVT_ID'          => new EE_Foreign_Key_Int_Field(
48
-                    'EVT_ID',
49
-                    esc_html__('Event ID', 'event_espresso'),
50
-                    false,
51
-                    0,
52
-                    'Event'
53
-                ),
54
-                'DTT_name'        => new EE_Plain_Text_Field(
55
-                    'DTT_name',
56
-                    esc_html__('Datetime Name', 'event_espresso'),
57
-                    false,
58
-                    ''
59
-                ),
60
-                'DTT_description' => new EE_Post_Content_Field(
61
-                    'DTT_description',
62
-                    esc_html__('Description for Datetime', 'event_espresso'),
63
-                    false,
64
-                    ''
65
-                ),
66
-                'DTT_EVT_start'   => new EE_Datetime_Field(
67
-                    'DTT_EVT_start',
68
-                    esc_html__('Start time/date of Event', 'event_espresso'),
69
-                    false,
70
-                    EE_Datetime_Field::now,
71
-                    $timezone
72
-                ),
73
-                'DTT_EVT_end'     => new EE_Datetime_Field(
74
-                    'DTT_EVT_end',
75
-                    esc_html__('End time/date of Event', 'event_espresso'),
76
-                    false,
77
-                    EE_Datetime_Field::now,
78
-                    $timezone
79
-                ),
80
-                'DTT_reg_limit'   => new EE_Infinite_Integer_Field(
81
-                    'DTT_reg_limit',
82
-                    esc_html__('Registration Limit for this time', 'event_espresso'),
83
-                    true,
84
-                    EE_INF
85
-                ),
86
-                'DTT_sold'        => new EE_Integer_Field(
87
-                    'DTT_sold',
88
-                    esc_html__('How many sales for this Datetime that have occurred', 'event_espresso'),
89
-                    true,
90
-                    0
91
-                ),
92
-                'DTT_reserved'    => new EE_Integer_Field(
93
-                    'DTT_reserved',
94
-                    esc_html__('Quantity of tickets reserved, but not yet fully purchased', 'event_espresso'),
95
-                    false,
96
-                    0
97
-                ),
98
-                'DTT_is_primary'  => new EE_Boolean_Field(
99
-                    'DTT_is_primary',
100
-                    esc_html__('Flag indicating datetime is primary one for event', 'event_espresso'),
101
-                    false,
102
-                    false
103
-                ),
104
-                'DTT_order'       => new EE_Integer_Field(
105
-                    'DTT_order',
106
-                    esc_html__('The order in which the Datetime is displayed', 'event_espresso'),
107
-                    false,
108
-                    0
109
-                ),
110
-                'DTT_parent'      => new EE_Integer_Field(
111
-                    'DTT_parent',
112
-                    esc_html__('Indicates what DTT_ID is the parent of this DTT_ID', 'event_espresso'),
113
-                    true,
114
-                    0
115
-                ),
116
-                'DTT_deleted'     => new EE_Trashed_Flag_Field(
117
-                    'DTT_deleted',
118
-                    esc_html__('Flag indicating datetime is archived', 'event_espresso'),
119
-                    false,
120
-                    false
121
-                ),
122
-            ],
123
-        ];
124
-        $this->_model_relations        = [
125
-            'Ticket'          => new EE_HABTM_Relation('Datetime_Ticket'),
126
-            'Event'           => new EE_Belongs_To_Relation(),
127
-            'Checkin'         => new EE_Has_Many_Relation(),
128
-            'Datetime_Ticket' => new EE_Has_Many_Relation(),
129
-        ];
130
-        $path_to_event_model           = 'Event';
131
-        $this->model_chain_to_password = $path_to_event_model;
132
-        $this->_model_chain_to_wp_user = $path_to_event_model;
133
-        // this model is generally available for reading
134
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ]       =
135
-            new EE_Restriction_Generator_Event_Related_Public(
136
-                $path_to_event_model
137
-            );
138
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] =
139
-            new EE_Restriction_Generator_Event_Related_Protected(
140
-                $path_to_event_model
141
-            );
142
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ]       =
143
-            new EE_Restriction_Generator_Event_Related_Protected(
144
-                $path_to_event_model
145
-            );
146
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ]     =
147
-            new EE_Restriction_Generator_Event_Related_Protected(
148
-                $path_to_event_model,
149
-                EEM_Base::caps_edit
150
-            );
151
-        parent::__construct($timezone);
152
-    }
153
-
154
-
155
-    /**
156
-     * create new blank datetime
157
-     *
158
-     * @access public
159
-     * @return EE_Datetime[] array on success, FALSE on fail
160
-     * @throws EE_Error
161
-     * @throws InvalidArgumentException
162
-     * @throws InvalidDataTypeException
163
-     * @throws ReflectionException
164
-     * @throws InvalidInterfaceException
165
-     */
166
-    public function create_new_blank_datetime()
167
-    {
168
-        // makes sure timezone is always set.
169
-        $timezone_string = $this->get_timezone();
170
-        /**
171
-         * Filters the initial start date for the new datetime.
172
-         * Any time included in this value will be overridden later so use additional filters to modify the time.
173
-         *
174
-         * @param int $start_date Unix timestamp representing now + 30 days in seconds.
175
-         * @return int Unix timestamp
176
-         */
177
-        $start_date = apply_filters(
178
-            'FHEE__EEM_Datetime__create_new_blank_datetime__start_date',
179
-            $this->current_time_for_query('DTT_EVT_start', true) + MONTH_IN_SECONDS
180
-        );
181
-        /**
182
-         * Filters the initial end date for the new datetime.
183
-         * Any time included in this value will be overridden later so use additional filters to modify the time.
184
-         *
185
-         * @param int $end_data Unix timestamp representing now + 30 days in seconds.
186
-         * @return int Unix timestamp
187
-         */
188
-        $end_date       = apply_filters(
189
-            'FHEE__EEM_Datetime__create_new_blank_datetime__end_date',
190
-            $this->current_time_for_query('DTT_EVT_end', true) + MONTH_IN_SECONDS
191
-        );
192
-        $blank_datetime = EE_Datetime::new_instance(
193
-            [
194
-                'DTT_EVT_start' => $start_date,
195
-                'DTT_EVT_end'   => $end_date,
196
-                'DTT_order'     => 1,
197
-                'DTT_reg_limit' => EE_INF,
198
-            ],
199
-            $timezone_string
200
-        );
201
-        /**
202
-         * Filters the initial start time and format for the new EE_Datetime instance.
203
-         *
204
-         * @param array $start_time An array having size 2.  First element is the time, second element is the time
205
-         *                          format.
206
-         * @return array
207
-         */
208
-        $start_time = apply_filters(
209
-            'FHEE__EEM_Datetime__create_new_blank_datetime__start_time',
210
-            ['8am', 'ga']
211
-        );
212
-        /**
213
-         * Filters the initial end time and format for the new EE_Datetime instance.
214
-         *
215
-         * @param array $end_time An array having size 2.  First element is the time, second element is the time
216
-         *                        format
217
-         * @return array
218
-         */
219
-        $end_time = apply_filters(
220
-            'FHEE__EEM_Datetime__create_new_blank_datetime__end_time',
221
-            ['5pm', 'ga']
222
-        );
223
-        $this->validateStartAndEndTimeForBlankDate($start_time, $end_time);
224
-        $blank_datetime->set_start_time(
225
-            $this->convert_datetime_for_query(
226
-                'DTT_EVT_start',
227
-                $start_time[0],
228
-                $start_time[1],
229
-                $timezone_string
230
-            )
231
-        );
232
-        $blank_datetime->set_end_time(
233
-            $this->convert_datetime_for_query(
234
-                'DTT_EVT_end',
235
-                $end_time[0],
236
-                $end_time[1],
237
-                $timezone_string
238
-            )
239
-        );
240
-        return [$blank_datetime];
241
-    }
242
-
243
-
244
-    /**
245
-     * Validates whether the start_time and end_time are in the expected format.
246
-     *
247
-     * @param array $start_time
248
-     * @param array $end_time
249
-     * @throws InvalidArgumentException
250
-     * @throws InvalidDataTypeException
251
-     */
252
-    private function validateStartAndEndTimeForBlankDate(array $start_time, array $end_time)
253
-    {
254
-        if (! is_array($start_time)) {
255
-            throw new InvalidDataTypeException('start_time', $start_time, 'array');
256
-        }
257
-        if (! is_array($end_time)) {
258
-            throw new InvalidDataTypeException('end_time', $end_time, 'array');
259
-        }
260
-        if (count($start_time) !== 2) {
261
-            throw new InvalidArgumentException(
262
-                sprintf(
263
-                    'The variable %1$s is expected to be an array with two elements.  The first item in the '
264
-                    . 'array should be a valid time string, the second item in the array should be a valid time format',
265
-                    '$start_time'
266
-                )
267
-            );
268
-        }
269
-        if (count($end_time) !== 2) {
270
-            throw new InvalidArgumentException(
271
-                sprintf(
272
-                    'The variable %1$s is expected to be an array with two elements.  The first item in the '
273
-                    . 'array should be a valid time string, the second item in the array should be a valid time format',
274
-                    '$end_time'
275
-                )
276
-            );
277
-        }
278
-    }
279
-
280
-
281
-    /**
282
-     * get event start date from db
283
-     *
284
-     * @access public
285
-     * @param int $EVT_ID
286
-     * @return EE_Datetime[] array on success, FALSE on fail
287
-     * @throws EE_Error
288
-     * @throws ReflectionException
289
-     */
290
-    public function get_all_event_dates($EVT_ID = 0)
291
-    {
292
-        if (! $EVT_ID) { // on add_new_event event_id gets set to 0
293
-            return $this->create_new_blank_datetime();
294
-        }
295
-        $results = $this->get_datetimes_for_event_ordered_by_DTT_order($EVT_ID);
296
-        if (empty($results)) {
297
-            return $this->create_new_blank_datetime();
298
-        }
299
-        return $results;
300
-    }
301
-
302
-
303
-    /**
304
-     * get all datetimes attached to an event ordered by the DTT_order field
305
-     *
306
-     * @public
307
-     * @param int     $EVT_ID     event id
308
-     * @param boolean $include_expired
309
-     * @param boolean $include_deleted
310
-     * @param int     $limit      If included then limit the count of results by
311
-     *                            the given number
312
-     * @return EE_Datetime[]
313
-     * @throws EE_Error
314
-     */
315
-    public function get_datetimes_for_event_ordered_by_DTT_order(
316
-        int $EVT_ID,
317
-        bool $include_expired = true,
318
-        bool $include_deleted = true,
319
-        $limit = 0
320
-    ) {
321
-        $prev_data_prep_value = $this->prepModelForQuery();
322
-        $where_params         = ['Event.EVT_ID' => absint($EVT_ID)];
323
-        $query_params[0]      = $this->addDefaultWhereParams($where_params, $include_deleted, $include_expired);
324
-        $query_params         = $this->addDefaultWhereConditions($query_params);
325
-        $query_params         = $this->addDefaultQueryParams($query_params, $limit, 'DTT_order');
326
-        return $this->getDatetimesAndRestoreModel($query_params, $prev_data_prep_value);
327
-    }
328
-
329
-
330
-    /**
331
-     * Gets the datetimes for the event (with the given limit), and orders them by "importance".
332
-     * By importance, we mean that the primary datetimes are most important (DEPRECATED FOR NOW),
333
-     * and then the earlier datetimes are the most important.
334
-     * Maybe we'll want this to take into account datetimes that haven't already passed, but we don't yet.
335
-     *
336
-     * @param int $EVT_ID
337
-     * @param int $limit
338
-     * @return EE_Datetime[]|EE_Base_Class[]
339
-     * @throws EE_Error
340
-     */
341
-    public function get_datetimes_for_event_ordered_by_importance(int $EVT_ID, $limit = 0)
342
-    {
343
-        $query_params[0] = ['Event.EVT_ID' => absint($EVT_ID)];
344
-        $query_params    = $this->addDefaultWhereConditions($query_params);
345
-        $query_params    = $this->addDefaultQueryParams($query_params, $limit);
346
-        return $this->get_all($query_params);
347
-    }
348
-
349
-
350
-    /**
351
-     * @param int     $EVT_ID
352
-     * @param boolean $include_expired
353
-     * @param boolean $include_deleted
354
-     * @return EE_Datetime
355
-     * @throws EE_Error
356
-     */
357
-    public function get_oldest_datetime_for_event(
358
-        int $EVT_ID,
359
-        bool $include_expired = false,
360
-        bool $include_deleted = false
361
-    ) {
362
-        $results = $this->get_datetimes_for_event_ordered_by_start_time(
363
-            $EVT_ID,
364
-            $include_expired,
365
-            $include_deleted,
366
-            1
367
-        );
368
-        if ($results) {
369
-            return array_shift($results);
370
-        }
371
-        return null;
372
-    }
373
-
374
-
375
-    /**
376
-     * Gets the 'primary' datetime for an event.
377
-     *
378
-     * @param int  $EVT_ID
379
-     * @param bool $try_to_exclude_expired
380
-     * @param bool $try_to_exclude_deleted
381
-     * @return EE_Datetime
382
-     * @throws EE_Error
383
-     */
384
-    public function get_primary_datetime_for_event(
385
-        int $EVT_ID,
386
-        bool $try_to_exclude_expired = true,
387
-        bool $try_to_exclude_deleted = true
388
-    ) {
389
-        if ($try_to_exclude_expired) {
390
-            $non_expired = $this->get_oldest_datetime_for_event($EVT_ID, false, false);
391
-            if ($non_expired) {
392
-                return $non_expired;
393
-            }
394
-        }
395
-        if ($try_to_exclude_deleted) {
396
-            $expired_even = $this->get_oldest_datetime_for_event($EVT_ID, true);
397
-            if ($expired_even) {
398
-                return $expired_even;
399
-            }
400
-        }
401
-        return $this->get_oldest_datetime_for_event($EVT_ID, true, true);
402
-    }
403
-
404
-
405
-    /**
406
-     * Gets ALL the datetimes for an event (including trashed ones, for now), ordered
407
-     * only by start date
408
-     *
409
-     * @param int     $EVT_ID
410
-     * @param boolean $include_expired
411
-     * @param boolean $include_deleted
412
-     * @param int     $limit
413
-     * @return EE_Datetime[]
414
-     * @throws EE_Error
415
-     */
416
-    public function get_datetimes_for_event_ordered_by_start_time(
417
-        int $EVT_ID,
418
-        bool $include_expired = true,
419
-        bool $include_deleted = true,
420
-        $limit = 0
421
-    ) {
422
-        $prev_data_prep_value = $this->prepModelForQuery();
423
-        $where_params         = ['Event.EVT_ID' => absint($EVT_ID)];
424
-        $query_params[0]      = $this->addDefaultWhereParams($where_params, $include_deleted, $include_expired);
425
-        $query_params         = $this->addDefaultWhereConditions(
426
-            $query_params,
427
-            EEM_Base::default_where_conditions_this_only
428
-        );
429
-        $query_params         = $this->addDefaultQueryParams($query_params, $limit, 'DTT_order');
430
-        return $this->getDatetimesAndRestoreModel($query_params, $prev_data_prep_value);
431
-    }
432
-
433
-
434
-    /**
435
-     * Gets ALL the datetimes for an ticket (including trashed ones, for now), ordered
436
-     * only by start date
437
-     *
438
-     * @param int     $TKT_ID
439
-     * @param boolean $include_expired
440
-     * @param boolean $include_deleted
441
-     * @param int     $limit
442
-     * @return EE_Datetime[]
443
-     * @throws EE_Error
444
-     */
445
-    public function get_datetimes_for_ticket_ordered_by_start_time(
446
-        int $TKT_ID,
447
-        bool $include_expired = true,
448
-        bool $include_deleted = true,
449
-        $limit = 0
450
-    ) {
451
-        $prev_data_prep_value = $this->prepModelForQuery();
452
-        $where_params         = ['Ticket.TKT_ID' => absint($TKT_ID)];
453
-        $query_params[0]      = $this->addDefaultWhereParams($where_params, $include_deleted, $include_expired);
454
-        $query_params         = $this->addDefaultQueryParams($query_params, $limit);
455
-        return $this->getDatetimesAndRestoreModel($query_params, $prev_data_prep_value);
456
-    }
457
-
458
-
459
-    /**
460
-     * Gets all the datetimes for a ticket (including trashed ones, for now), ordered by the DTT_order for the
461
-     * datetimes.
462
-     *
463
-     * @param int      $TKT_ID           ID of ticket to retrieve the datetimes for
464
-     * @param boolean  $include_expired  whether to include expired datetimes or not
465
-     * @param boolean  $include_deleted  whether to include trashed datetimes or not.
466
-     * @param int|null $limit            if null, no limit, if int then limit results by
467
-     *                                   that number
468
-     * @return EE_Datetime[]
469
-     * @throws EE_Error
470
-     */
471
-    public function get_datetimes_for_ticket_ordered_by_DTT_order(
472
-        int $TKT_ID,
473
-        bool $include_expired = true,
474
-        bool $include_deleted = true,
475
-        $limit = 0
476
-    ) {
477
-        $prev_data_prep_value = $this->prepModelForQuery();
478
-        $where_params         = ['Ticket.TKT_ID' => absint($TKT_ID)];
479
-        $query_params[0]      = $this->addDefaultWhereParams($where_params, $include_deleted, $include_expired);
480
-        $query_params         = $this->addDefaultQueryParams($query_params, $limit, 'DTT_order');
481
-        return $this->getDatetimesAndRestoreModel($query_params, $prev_data_prep_value);
482
-    }
483
-
484
-
485
-    /**
486
-     * Gets the most important datetime for a particular event (ie, the primary event usually. But if for some WACK
487
-     * reason it doesn't exist, we consider the earliest event the most important)
488
-     *
489
-     * @param int $EVT_ID
490
-     * @return EE_Datetime
491
-     * @throws EE_Error
492
-     */
493
-    public function get_most_important_datetime_for_event(int $EVT_ID)
494
-    {
495
-        $results = $this->get_datetimes_for_event_ordered_by_importance($EVT_ID, 1);
496
-        if ($results) {
497
-            return array_shift($results);
498
-        }
499
-        return null;
500
-    }
501
-
502
-
503
-    /**
504
-     * This returns a wpdb->results        Array of all DTT month and years matching the incoming query params and
505
-     * grouped by month and year.
506
-     *
507
-     * @param array  $where_params       @see
508
-     *                                   https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
509
-     * @param string $evt_active_status  A string representing the evt active status to filter the months by.
510
-     *                                   Can be:
511
-     *                                   - '' = no filter
512
-     *                                   - upcoming = Published events with at least one upcoming datetime.
513
-     *                                   - expired = Events with all datetimes expired.
514
-     *                                   - active = Events that are published and have at least one datetime that
515
-     *                                   starts before now and ends after now.
516
-     *                                   - inactive = Events that are either not published.
517
-     * @return EE_Base_Class[]
518
-     * @throws EE_Error
519
-     * @throws InvalidArgumentException
520
-     * @throws InvalidArgumentException
521
-     */
522
-    public function get_dtt_months_and_years(array $where_params, $evt_active_status = '')
523
-    {
524
-        $current_time_for_DTT_EVT_start = $this->current_time_for_query('DTT_EVT_start');
525
-        $current_time_for_DTT_EVT_end   = $this->current_time_for_query('DTT_EVT_end');
526
-        switch ($evt_active_status) {
527
-            case 'upcoming':
528
-                $where_params['Event.status'] = 'publish';
529
-                // if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
530
-                if (isset($where_params['DTT_EVT_start'])) {
531
-                    $where_params['DTT_EVT_start*****'] = $where_params['DTT_EVT_start'];
532
-                }
533
-                $where_params['DTT_EVT_start'] = ['>', $current_time_for_DTT_EVT_start];
534
-                break;
535
-            case 'expired':
536
-                if (isset($where_params['Event.status'])) {
537
-                    unset($where_params['Event.status']);
538
-                }
539
-                // get events to exclude
540
-                $exclude_query[0] = array_merge(
541
-                    $where_params,
542
-                    ['DTT_EVT_end' => ['>', $current_time_for_DTT_EVT_end]]
543
-                );
544
-                // first get all events that have datetimes where its not expired.
545
-                $event_ids = $this->_get_all_wpdb_results(
546
-                    $exclude_query,
547
-                    OBJECT_K,
548
-                    'Datetime.EVT_ID'
549
-                );
550
-                $event_ids = array_keys($event_ids);
551
-                if (isset($where_params['DTT_EVT_end'])) {
552
-                    $where_params['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
553
-                }
554
-                $where_params['DTT_EVT_end']  = ['<', $current_time_for_DTT_EVT_end];
555
-                $where_params['Event.EVT_ID'] = ['NOT IN', $event_ids];
556
-                break;
557
-            case 'active':
558
-                $where_params['Event.status'] = 'publish';
559
-                if (isset($where_params['DTT_EVT_start'])) {
560
-                    $where_params['Datetime.DTT_EVT_start******'] = $where_params['DTT_EVT_start'];
561
-                }
562
-                if (isset($where_params['Datetime.DTT_EVT_end'])) {
563
-                    $where_params['Datetime.DTT_EVT_end*****'] = $where_params['DTT_EVT_end'];
564
-                }
565
-                $where_params['DTT_EVT_start'] = ['<', $current_time_for_DTT_EVT_start];
566
-                $where_params['DTT_EVT_end']   = ['>', $current_time_for_DTT_EVT_end];
567
-                break;
568
-            case 'inactive':
569
-                if (isset($where_params['Event.status'])) {
570
-                    unset($where_params['Event.status']);
571
-                }
572
-                if (isset($where_params['OR'])) {
573
-                    $where_params['AND']['OR'] = $where_params['OR'];
574
-                }
575
-                if (isset($where_params['DTT_EVT_end'])) {
576
-                    $where_params['AND']['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
577
-                    unset($where_params['DTT_EVT_end']);
578
-                }
579
-                if (isset($where_params['DTT_EVT_start'])) {
580
-                    $where_params['AND']['DTT_EVT_start'] = $where_params['DTT_EVT_start'];
581
-                    unset($where_params['DTT_EVT_start']);
582
-                }
583
-                $where_params['AND']['Event.status'] = ['!=', 'publish'];
584
-                break;
585
-        }
586
-        $query_params[0]          = $where_params;
587
-        $query_params['group_by'] = ['dtt_year', 'dtt_month'];
588
-        $query_params             = $this->addOrderByQueryParams($query_params, 'DTT_EVT_start', 'DESC');
589
-
590
-        $query_interval    = EEH_DTT_Helper::get_sql_query_interval_for_offset(
591
-            $this->get_timezone(),
592
-            'DTT_EVT_start'
593
-        );
594
-        $columns_to_select = [
595
-            'dtt_year'      => ['YEAR(' . $query_interval . ')', '%s'],
596
-            'dtt_month'     => ['MONTHNAME(' . $query_interval . ')', '%s'],
597
-            'dtt_month_num' => ['MONTH(' . $query_interval . ')', '%s'],
598
-        ];
599
-        return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select);
600
-    }
601
-
602
-
603
-    /**
604
-     * Updates the DTT_sold attribute on each datetime (based on the registrations
605
-     * for the tickets for each datetime)
606
-     *
607
-     * @param EE_Base_Class[]|EE_Datetime[] $datetimes
608
-     * @throws EE_Error
609
-     * @throws ReflectionException
610
-     */
611
-    public function update_sold(array $datetimes)
612
-    {
613
-        EE_Error::doing_it_wrong(
614
-            __FUNCTION__,
615
-            esc_html__(
616
-                'Please use \EEM_Ticket::update_tickets_sold() instead which will in turn correctly update both the Ticket AND Datetime counts.',
617
-                'event_espresso'
618
-            ),
619
-            '4.9.32.rc.005'
620
-        );
621
-        foreach ($datetimes as $datetime) {
622
-            $datetime->update_sold();
623
-        }
624
-    }
625
-
626
-
627
-    /**
628
-     *    Gets the total number of tickets available at a particular datetime
629
-     *    (does NOT take into account the datetime's spaces available)
630
-     *
631
-     * @param int   $DTT_ID
632
-     * @param array $query_params
633
-     * @return int of tickets available. If sold out, return less than 1. If infinite, returns EE_INF,  IF there are NO
634
-     *             tickets attached to datetime then FALSE is returned.
635
-     * @throws EE_Error
636
-     * @throws ReflectionException
637
-     */
638
-    public function sum_tickets_currently_available_at_datetime(int $DTT_ID, array $query_params = [])
639
-    {
640
-        $datetime = $this->get_one_by_ID($DTT_ID);
641
-        if ($datetime instanceof EE_Datetime) {
642
-            return $datetime->tickets_remaining($query_params);
643
-        }
644
-        return 0;
645
-    }
646
-
647
-
648
-    /**
649
-     * This returns an array of counts of datetimes in the database for each Datetime status that can be queried.
650
-     *
651
-     * @param array $stati_to_include  If included you can restrict the statuses we return counts for by including the
652
-     *                                 stati you want counts for as values in the array.  An empty array returns counts
653
-     *                                 for all valid stati.
654
-     * @param array $query_params      If included can be used to refine the conditions for returning the count (i.e.
655
-     *                                 only for Datetimes connected to a specific event, or specific ticket.
656
-     * @return array  The value returned is an array indexed by Datetime Status and the values are the counts.  The
657
-     * @throws EE_Error
658
-     *                                 stati used as index keys are: EE_Datetime::active EE_Datetime::upcoming
659
-     *                                 EE_Datetime::expired
660
-     */
661
-    public function get_datetime_counts_by_status(array $stati_to_include = [], array $query_params = [])
662
-    {
663
-        // only accept where conditions for this query.
664
-        $_where            = isset($query_params[0]) ? $query_params[0] : [];
665
-        $status_query_args = [
666
-            EE_Datetime::active   => array_merge(
667
-                $_where,
668
-                ['DTT_EVT_start' => ['<', time()], 'DTT_EVT_end' => ['>', time()]]
669
-            ),
670
-            EE_Datetime::upcoming => array_merge(
671
-                $_where,
672
-                ['DTT_EVT_start' => ['>', time()]]
673
-            ),
674
-            EE_Datetime::expired  => array_merge(
675
-                $_where,
676
-                ['DTT_EVT_end' => ['<', time()]]
677
-            ),
678
-        ];
679
-        if (! empty($stati_to_include)) {
680
-            foreach (array_keys($status_query_args) as $status) {
681
-                if (! in_array($status, $stati_to_include, true)) {
682
-                    unset($status_query_args[ $status ]);
683
-                }
684
-            }
685
-        }
686
-        // loop through and query counts for each stati.
687
-        $status_query_results = [];
688
-        foreach ($status_query_args as $status => $status_where_conditions) {
689
-            $status_query_results[ $status ] = EEM_Datetime::count(
690
-                [$status_where_conditions],
691
-                'DTT_ID',
692
-                true
693
-            );
694
-        }
695
-        return $status_query_results;
696
-    }
697
-
698
-
699
-    /**
700
-     * Returns the specific count for a given Datetime status matching any given query_params.
701
-     *
702
-     * @param string $status Valid string representation for Datetime status requested. (Defaults to Active).
703
-     * @param array  $query_params
704
-     * @return int
705
-     * @throws EE_Error
706
-     */
707
-    public function get_datetime_count_for_status($status = EE_Datetime::active, array $query_params = [])
708
-    {
709
-        $count = $this->get_datetime_counts_by_status([$status], $query_params);
710
-        return ! empty($count[ $status ]) ? $count[ $status ] : 0;
711
-    }
712
-
713
-
714
-    /**
715
-     * @return bool|int
716
-     * @since   $VID:$
717
-     */
718
-    private function prepModelForQuery()
719
-    {
720
-        $prev_data_prep_value = $this->get_assumption_concerning_values_already_prepared_by_model_object();
721
-        $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
722
-        return $prev_data_prep_value;
723
-    }
724
-
725
-
726
-    /**
727
-     * @param array    $query_params
728
-     * @param bool|int $prev_data_prep_value
729
-     * @return EE_Base_Class[]|EE_Datetime[]
730
-     * @throws EE_Error
731
-     * @since   $VID:$
732
-     */
733
-    private function getDatetimesAndRestoreModel(array $query_params, $prev_data_prep_value)
734
-    {
735
-        $result = $this->get_all($query_params);
736
-        $this->assume_values_already_prepared_by_model_object($prev_data_prep_value);
737
-        return $result;
738
-    }
739
-
740
-
741
-    /**
742
-     * @param array  $query_params
743
-     * @param int    $limit
744
-     * @param string $order_by
745
-     * @param string $order
746
-     * @return array
747
-     * @since   $VID:$
748
-     */
749
-    private function addDefaultQueryParams(array $query_params, $limit = 0, $order_by = 'DTT_EVT_start', $order = 'ASC')
750
-    {
751
-        $query_params = $this->addOrderByQueryParams($query_params, $order_by, $order);
752
-        $query_params = $this->addLimitQueryParams($query_params, $limit);
753
-        return $query_params;
754
-    }
755
-
756
-
757
-    /**
758
-     * @param array  $query_params
759
-     * @param string $default_where_conditions
760
-     * @return array
761
-     * @since   $VID:$
762
-     */
763
-    private function addDefaultWhereConditions(
764
-        array $query_params,
765
-        $default_where_conditions = EEM_Base::default_where_conditions_none
766
-    ) {
767
-        $query_params['default_where_conditions'] = $default_where_conditions;
768
-        return $query_params;
769
-    }
770
-
771
-
772
-    /**
773
-     * @param array $where_params
774
-     * @param bool  $include_deleted
775
-     * @param bool  $include_expired
776
-     * @return array
777
-     * @since   $VID:$
778
-     */
779
-    private function addDefaultWhereParams(array $where_params, bool $include_deleted = true, bool $include_expired = true)
780
-    {
781
-        $where_params = $this->addExpiredWhereParams($where_params, $include_expired);
782
-        $where_params = $this->addDeletedWhereParams($where_params, $include_deleted);
783
-        return $where_params;
784
-    }
785
-
786
-
787
-    /**
788
-     * @param array $where_params
789
-     * @param bool  $include_deleted
790
-     * @return array
791
-     * @since   $VID:$
792
-     */
793
-    private function addDeletedWhereParams(array $where_params, bool $include_deleted = true)
794
-    {
795
-        $deleted                     = $include_deleted ? [true, false] : [false];
796
-        $where_params['DTT_deleted'] = ['IN', $deleted];
797
-        return $where_params;
798
-    }
799
-
800
-
801
-    /**
802
-     * @param array $where_params
803
-     * @param bool  $include_expired
804
-     * @return array
805
-     * @since   $VID:$
806
-     */
807
-    private function addExpiredWhereParams(array $where_params, bool $include_expired = true)
808
-    {
809
-        if (! $include_expired) {
810
-            $where_params['DTT_EVT_end'] = ['>=', current_time('mysql', true)];
811
-        }
812
-        return $where_params;
813
-    }
814
-
815
-
816
-    /**
817
-     * @param array $query_params
818
-     * @param int   $limit
819
-     * @return array
820
-     * @since   $VID:$
821
-     */
822
-    private function addLimitQueryParams(array $query_params, $limit = 0)
823
-    {
824
-        if ($limit) {
825
-            $query_params['limit'] = $limit;
826
-        }
827
-        return $query_params;
828
-    }
829
-
830
-
831
-    /**
832
-     * @param array  $query_params
833
-     * @param string $order_by
834
-     * @param string $order
835
-     * @return array
836
-     * @since   $VID:$
837
-     */
838
-    private function addOrderByQueryParams(array $query_params, $order_by = 'DTT_EVT_start', $order = 'ASC')
839
-    {
840
-        $order                    = $order === 'ASC' ? 'ASC' : 'DESC';
841
-        $valid_order_columns      = ['DTT_ID', 'DTT_EVT_start', 'DTT_EVT_end', 'DTT_order'];
842
-        $order_by                 = in_array($order_by, $valid_order_columns, true) ? $order_by : 'DTT_EVT_start';
843
-        $query_params['order_by'] = [$order_by => $order];
844
-        return $query_params;
845
-    }
16
+	/**
17
+	 * @var EEM_Datetime $_instance
18
+	 */
19
+	protected static $_instance;
20
+
21
+
22
+	/**
23
+	 * private constructor to prevent direct creation
24
+	 *
25
+	 * @param string $timezone A string representing the timezone we want to set for returned Date Time Strings
26
+	 *                         (and any incoming timezone data that gets saved).
27
+	 *                         Note this just sends the timezone info to the date time model field objects.
28
+	 *                         Default is NULL
29
+	 *                         (and will be assumed using the set timezone in the 'timezone_string' wp option)
30
+	 * @throws EE_Error
31
+	 * @throws InvalidArgumentException
32
+	 * @throws InvalidArgumentException
33
+	 */
34
+	protected function __construct($timezone = '')
35
+	{
36
+		$this->singular_item           = esc_html__('Datetime', 'event_espresso');
37
+		$this->plural_item             = esc_html__('Datetimes', 'event_espresso');
38
+		$this->_tables                 = [
39
+			'Datetime' => new EE_Primary_Table('esp_datetime', 'DTT_ID'),
40
+		];
41
+		$this->_fields                 = [
42
+			'Datetime' => [
43
+				'DTT_ID'          => new EE_Primary_Key_Int_Field(
44
+					'DTT_ID',
45
+					esc_html__('Datetime ID', 'event_espresso')
46
+				),
47
+				'EVT_ID'          => new EE_Foreign_Key_Int_Field(
48
+					'EVT_ID',
49
+					esc_html__('Event ID', 'event_espresso'),
50
+					false,
51
+					0,
52
+					'Event'
53
+				),
54
+				'DTT_name'        => new EE_Plain_Text_Field(
55
+					'DTT_name',
56
+					esc_html__('Datetime Name', 'event_espresso'),
57
+					false,
58
+					''
59
+				),
60
+				'DTT_description' => new EE_Post_Content_Field(
61
+					'DTT_description',
62
+					esc_html__('Description for Datetime', 'event_espresso'),
63
+					false,
64
+					''
65
+				),
66
+				'DTT_EVT_start'   => new EE_Datetime_Field(
67
+					'DTT_EVT_start',
68
+					esc_html__('Start time/date of Event', 'event_espresso'),
69
+					false,
70
+					EE_Datetime_Field::now,
71
+					$timezone
72
+				),
73
+				'DTT_EVT_end'     => new EE_Datetime_Field(
74
+					'DTT_EVT_end',
75
+					esc_html__('End time/date of Event', 'event_espresso'),
76
+					false,
77
+					EE_Datetime_Field::now,
78
+					$timezone
79
+				),
80
+				'DTT_reg_limit'   => new EE_Infinite_Integer_Field(
81
+					'DTT_reg_limit',
82
+					esc_html__('Registration Limit for this time', 'event_espresso'),
83
+					true,
84
+					EE_INF
85
+				),
86
+				'DTT_sold'        => new EE_Integer_Field(
87
+					'DTT_sold',
88
+					esc_html__('How many sales for this Datetime that have occurred', 'event_espresso'),
89
+					true,
90
+					0
91
+				),
92
+				'DTT_reserved'    => new EE_Integer_Field(
93
+					'DTT_reserved',
94
+					esc_html__('Quantity of tickets reserved, but not yet fully purchased', 'event_espresso'),
95
+					false,
96
+					0
97
+				),
98
+				'DTT_is_primary'  => new EE_Boolean_Field(
99
+					'DTT_is_primary',
100
+					esc_html__('Flag indicating datetime is primary one for event', 'event_espresso'),
101
+					false,
102
+					false
103
+				),
104
+				'DTT_order'       => new EE_Integer_Field(
105
+					'DTT_order',
106
+					esc_html__('The order in which the Datetime is displayed', 'event_espresso'),
107
+					false,
108
+					0
109
+				),
110
+				'DTT_parent'      => new EE_Integer_Field(
111
+					'DTT_parent',
112
+					esc_html__('Indicates what DTT_ID is the parent of this DTT_ID', 'event_espresso'),
113
+					true,
114
+					0
115
+				),
116
+				'DTT_deleted'     => new EE_Trashed_Flag_Field(
117
+					'DTT_deleted',
118
+					esc_html__('Flag indicating datetime is archived', 'event_espresso'),
119
+					false,
120
+					false
121
+				),
122
+			],
123
+		];
124
+		$this->_model_relations        = [
125
+			'Ticket'          => new EE_HABTM_Relation('Datetime_Ticket'),
126
+			'Event'           => new EE_Belongs_To_Relation(),
127
+			'Checkin'         => new EE_Has_Many_Relation(),
128
+			'Datetime_Ticket' => new EE_Has_Many_Relation(),
129
+		];
130
+		$path_to_event_model           = 'Event';
131
+		$this->model_chain_to_password = $path_to_event_model;
132
+		$this->_model_chain_to_wp_user = $path_to_event_model;
133
+		// this model is generally available for reading
134
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ]       =
135
+			new EE_Restriction_Generator_Event_Related_Public(
136
+				$path_to_event_model
137
+			);
138
+		$this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] =
139
+			new EE_Restriction_Generator_Event_Related_Protected(
140
+				$path_to_event_model
141
+			);
142
+		$this->_cap_restriction_generators[ EEM_Base::caps_edit ]       =
143
+			new EE_Restriction_Generator_Event_Related_Protected(
144
+				$path_to_event_model
145
+			);
146
+		$this->_cap_restriction_generators[ EEM_Base::caps_delete ]     =
147
+			new EE_Restriction_Generator_Event_Related_Protected(
148
+				$path_to_event_model,
149
+				EEM_Base::caps_edit
150
+			);
151
+		parent::__construct($timezone);
152
+	}
153
+
154
+
155
+	/**
156
+	 * create new blank datetime
157
+	 *
158
+	 * @access public
159
+	 * @return EE_Datetime[] array on success, FALSE on fail
160
+	 * @throws EE_Error
161
+	 * @throws InvalidArgumentException
162
+	 * @throws InvalidDataTypeException
163
+	 * @throws ReflectionException
164
+	 * @throws InvalidInterfaceException
165
+	 */
166
+	public function create_new_blank_datetime()
167
+	{
168
+		// makes sure timezone is always set.
169
+		$timezone_string = $this->get_timezone();
170
+		/**
171
+		 * Filters the initial start date for the new datetime.
172
+		 * Any time included in this value will be overridden later so use additional filters to modify the time.
173
+		 *
174
+		 * @param int $start_date Unix timestamp representing now + 30 days in seconds.
175
+		 * @return int Unix timestamp
176
+		 */
177
+		$start_date = apply_filters(
178
+			'FHEE__EEM_Datetime__create_new_blank_datetime__start_date',
179
+			$this->current_time_for_query('DTT_EVT_start', true) + MONTH_IN_SECONDS
180
+		);
181
+		/**
182
+		 * Filters the initial end date for the new datetime.
183
+		 * Any time included in this value will be overridden later so use additional filters to modify the time.
184
+		 *
185
+		 * @param int $end_data Unix timestamp representing now + 30 days in seconds.
186
+		 * @return int Unix timestamp
187
+		 */
188
+		$end_date       = apply_filters(
189
+			'FHEE__EEM_Datetime__create_new_blank_datetime__end_date',
190
+			$this->current_time_for_query('DTT_EVT_end', true) + MONTH_IN_SECONDS
191
+		);
192
+		$blank_datetime = EE_Datetime::new_instance(
193
+			[
194
+				'DTT_EVT_start' => $start_date,
195
+				'DTT_EVT_end'   => $end_date,
196
+				'DTT_order'     => 1,
197
+				'DTT_reg_limit' => EE_INF,
198
+			],
199
+			$timezone_string
200
+		);
201
+		/**
202
+		 * Filters the initial start time and format for the new EE_Datetime instance.
203
+		 *
204
+		 * @param array $start_time An array having size 2.  First element is the time, second element is the time
205
+		 *                          format.
206
+		 * @return array
207
+		 */
208
+		$start_time = apply_filters(
209
+			'FHEE__EEM_Datetime__create_new_blank_datetime__start_time',
210
+			['8am', 'ga']
211
+		);
212
+		/**
213
+		 * Filters the initial end time and format for the new EE_Datetime instance.
214
+		 *
215
+		 * @param array $end_time An array having size 2.  First element is the time, second element is the time
216
+		 *                        format
217
+		 * @return array
218
+		 */
219
+		$end_time = apply_filters(
220
+			'FHEE__EEM_Datetime__create_new_blank_datetime__end_time',
221
+			['5pm', 'ga']
222
+		);
223
+		$this->validateStartAndEndTimeForBlankDate($start_time, $end_time);
224
+		$blank_datetime->set_start_time(
225
+			$this->convert_datetime_for_query(
226
+				'DTT_EVT_start',
227
+				$start_time[0],
228
+				$start_time[1],
229
+				$timezone_string
230
+			)
231
+		);
232
+		$blank_datetime->set_end_time(
233
+			$this->convert_datetime_for_query(
234
+				'DTT_EVT_end',
235
+				$end_time[0],
236
+				$end_time[1],
237
+				$timezone_string
238
+			)
239
+		);
240
+		return [$blank_datetime];
241
+	}
242
+
243
+
244
+	/**
245
+	 * Validates whether the start_time and end_time are in the expected format.
246
+	 *
247
+	 * @param array $start_time
248
+	 * @param array $end_time
249
+	 * @throws InvalidArgumentException
250
+	 * @throws InvalidDataTypeException
251
+	 */
252
+	private function validateStartAndEndTimeForBlankDate(array $start_time, array $end_time)
253
+	{
254
+		if (! is_array($start_time)) {
255
+			throw new InvalidDataTypeException('start_time', $start_time, 'array');
256
+		}
257
+		if (! is_array($end_time)) {
258
+			throw new InvalidDataTypeException('end_time', $end_time, 'array');
259
+		}
260
+		if (count($start_time) !== 2) {
261
+			throw new InvalidArgumentException(
262
+				sprintf(
263
+					'The variable %1$s is expected to be an array with two elements.  The first item in the '
264
+					. 'array should be a valid time string, the second item in the array should be a valid time format',
265
+					'$start_time'
266
+				)
267
+			);
268
+		}
269
+		if (count($end_time) !== 2) {
270
+			throw new InvalidArgumentException(
271
+				sprintf(
272
+					'The variable %1$s is expected to be an array with two elements.  The first item in the '
273
+					. 'array should be a valid time string, the second item in the array should be a valid time format',
274
+					'$end_time'
275
+				)
276
+			);
277
+		}
278
+	}
279
+
280
+
281
+	/**
282
+	 * get event start date from db
283
+	 *
284
+	 * @access public
285
+	 * @param int $EVT_ID
286
+	 * @return EE_Datetime[] array on success, FALSE on fail
287
+	 * @throws EE_Error
288
+	 * @throws ReflectionException
289
+	 */
290
+	public function get_all_event_dates($EVT_ID = 0)
291
+	{
292
+		if (! $EVT_ID) { // on add_new_event event_id gets set to 0
293
+			return $this->create_new_blank_datetime();
294
+		}
295
+		$results = $this->get_datetimes_for_event_ordered_by_DTT_order($EVT_ID);
296
+		if (empty($results)) {
297
+			return $this->create_new_blank_datetime();
298
+		}
299
+		return $results;
300
+	}
301
+
302
+
303
+	/**
304
+	 * get all datetimes attached to an event ordered by the DTT_order field
305
+	 *
306
+	 * @public
307
+	 * @param int     $EVT_ID     event id
308
+	 * @param boolean $include_expired
309
+	 * @param boolean $include_deleted
310
+	 * @param int     $limit      If included then limit the count of results by
311
+	 *                            the given number
312
+	 * @return EE_Datetime[]
313
+	 * @throws EE_Error
314
+	 */
315
+	public function get_datetimes_for_event_ordered_by_DTT_order(
316
+		int $EVT_ID,
317
+		bool $include_expired = true,
318
+		bool $include_deleted = true,
319
+		$limit = 0
320
+	) {
321
+		$prev_data_prep_value = $this->prepModelForQuery();
322
+		$where_params         = ['Event.EVT_ID' => absint($EVT_ID)];
323
+		$query_params[0]      = $this->addDefaultWhereParams($where_params, $include_deleted, $include_expired);
324
+		$query_params         = $this->addDefaultWhereConditions($query_params);
325
+		$query_params         = $this->addDefaultQueryParams($query_params, $limit, 'DTT_order');
326
+		return $this->getDatetimesAndRestoreModel($query_params, $prev_data_prep_value);
327
+	}
328
+
329
+
330
+	/**
331
+	 * Gets the datetimes for the event (with the given limit), and orders them by "importance".
332
+	 * By importance, we mean that the primary datetimes are most important (DEPRECATED FOR NOW),
333
+	 * and then the earlier datetimes are the most important.
334
+	 * Maybe we'll want this to take into account datetimes that haven't already passed, but we don't yet.
335
+	 *
336
+	 * @param int $EVT_ID
337
+	 * @param int $limit
338
+	 * @return EE_Datetime[]|EE_Base_Class[]
339
+	 * @throws EE_Error
340
+	 */
341
+	public function get_datetimes_for_event_ordered_by_importance(int $EVT_ID, $limit = 0)
342
+	{
343
+		$query_params[0] = ['Event.EVT_ID' => absint($EVT_ID)];
344
+		$query_params    = $this->addDefaultWhereConditions($query_params);
345
+		$query_params    = $this->addDefaultQueryParams($query_params, $limit);
346
+		return $this->get_all($query_params);
347
+	}
348
+
349
+
350
+	/**
351
+	 * @param int     $EVT_ID
352
+	 * @param boolean $include_expired
353
+	 * @param boolean $include_deleted
354
+	 * @return EE_Datetime
355
+	 * @throws EE_Error
356
+	 */
357
+	public function get_oldest_datetime_for_event(
358
+		int $EVT_ID,
359
+		bool $include_expired = false,
360
+		bool $include_deleted = false
361
+	) {
362
+		$results = $this->get_datetimes_for_event_ordered_by_start_time(
363
+			$EVT_ID,
364
+			$include_expired,
365
+			$include_deleted,
366
+			1
367
+		);
368
+		if ($results) {
369
+			return array_shift($results);
370
+		}
371
+		return null;
372
+	}
373
+
374
+
375
+	/**
376
+	 * Gets the 'primary' datetime for an event.
377
+	 *
378
+	 * @param int  $EVT_ID
379
+	 * @param bool $try_to_exclude_expired
380
+	 * @param bool $try_to_exclude_deleted
381
+	 * @return EE_Datetime
382
+	 * @throws EE_Error
383
+	 */
384
+	public function get_primary_datetime_for_event(
385
+		int $EVT_ID,
386
+		bool $try_to_exclude_expired = true,
387
+		bool $try_to_exclude_deleted = true
388
+	) {
389
+		if ($try_to_exclude_expired) {
390
+			$non_expired = $this->get_oldest_datetime_for_event($EVT_ID, false, false);
391
+			if ($non_expired) {
392
+				return $non_expired;
393
+			}
394
+		}
395
+		if ($try_to_exclude_deleted) {
396
+			$expired_even = $this->get_oldest_datetime_for_event($EVT_ID, true);
397
+			if ($expired_even) {
398
+				return $expired_even;
399
+			}
400
+		}
401
+		return $this->get_oldest_datetime_for_event($EVT_ID, true, true);
402
+	}
403
+
404
+
405
+	/**
406
+	 * Gets ALL the datetimes for an event (including trashed ones, for now), ordered
407
+	 * only by start date
408
+	 *
409
+	 * @param int     $EVT_ID
410
+	 * @param boolean $include_expired
411
+	 * @param boolean $include_deleted
412
+	 * @param int     $limit
413
+	 * @return EE_Datetime[]
414
+	 * @throws EE_Error
415
+	 */
416
+	public function get_datetimes_for_event_ordered_by_start_time(
417
+		int $EVT_ID,
418
+		bool $include_expired = true,
419
+		bool $include_deleted = true,
420
+		$limit = 0
421
+	) {
422
+		$prev_data_prep_value = $this->prepModelForQuery();
423
+		$where_params         = ['Event.EVT_ID' => absint($EVT_ID)];
424
+		$query_params[0]      = $this->addDefaultWhereParams($where_params, $include_deleted, $include_expired);
425
+		$query_params         = $this->addDefaultWhereConditions(
426
+			$query_params,
427
+			EEM_Base::default_where_conditions_this_only
428
+		);
429
+		$query_params         = $this->addDefaultQueryParams($query_params, $limit, 'DTT_order');
430
+		return $this->getDatetimesAndRestoreModel($query_params, $prev_data_prep_value);
431
+	}
432
+
433
+
434
+	/**
435
+	 * Gets ALL the datetimes for an ticket (including trashed ones, for now), ordered
436
+	 * only by start date
437
+	 *
438
+	 * @param int     $TKT_ID
439
+	 * @param boolean $include_expired
440
+	 * @param boolean $include_deleted
441
+	 * @param int     $limit
442
+	 * @return EE_Datetime[]
443
+	 * @throws EE_Error
444
+	 */
445
+	public function get_datetimes_for_ticket_ordered_by_start_time(
446
+		int $TKT_ID,
447
+		bool $include_expired = true,
448
+		bool $include_deleted = true,
449
+		$limit = 0
450
+	) {
451
+		$prev_data_prep_value = $this->prepModelForQuery();
452
+		$where_params         = ['Ticket.TKT_ID' => absint($TKT_ID)];
453
+		$query_params[0]      = $this->addDefaultWhereParams($where_params, $include_deleted, $include_expired);
454
+		$query_params         = $this->addDefaultQueryParams($query_params, $limit);
455
+		return $this->getDatetimesAndRestoreModel($query_params, $prev_data_prep_value);
456
+	}
457
+
458
+
459
+	/**
460
+	 * Gets all the datetimes for a ticket (including trashed ones, for now), ordered by the DTT_order for the
461
+	 * datetimes.
462
+	 *
463
+	 * @param int      $TKT_ID           ID of ticket to retrieve the datetimes for
464
+	 * @param boolean  $include_expired  whether to include expired datetimes or not
465
+	 * @param boolean  $include_deleted  whether to include trashed datetimes or not.
466
+	 * @param int|null $limit            if null, no limit, if int then limit results by
467
+	 *                                   that number
468
+	 * @return EE_Datetime[]
469
+	 * @throws EE_Error
470
+	 */
471
+	public function get_datetimes_for_ticket_ordered_by_DTT_order(
472
+		int $TKT_ID,
473
+		bool $include_expired = true,
474
+		bool $include_deleted = true,
475
+		$limit = 0
476
+	) {
477
+		$prev_data_prep_value = $this->prepModelForQuery();
478
+		$where_params         = ['Ticket.TKT_ID' => absint($TKT_ID)];
479
+		$query_params[0]      = $this->addDefaultWhereParams($where_params, $include_deleted, $include_expired);
480
+		$query_params         = $this->addDefaultQueryParams($query_params, $limit, 'DTT_order');
481
+		return $this->getDatetimesAndRestoreModel($query_params, $prev_data_prep_value);
482
+	}
483
+
484
+
485
+	/**
486
+	 * Gets the most important datetime for a particular event (ie, the primary event usually. But if for some WACK
487
+	 * reason it doesn't exist, we consider the earliest event the most important)
488
+	 *
489
+	 * @param int $EVT_ID
490
+	 * @return EE_Datetime
491
+	 * @throws EE_Error
492
+	 */
493
+	public function get_most_important_datetime_for_event(int $EVT_ID)
494
+	{
495
+		$results = $this->get_datetimes_for_event_ordered_by_importance($EVT_ID, 1);
496
+		if ($results) {
497
+			return array_shift($results);
498
+		}
499
+		return null;
500
+	}
501
+
502
+
503
+	/**
504
+	 * This returns a wpdb->results        Array of all DTT month and years matching the incoming query params and
505
+	 * grouped by month and year.
506
+	 *
507
+	 * @param array  $where_params       @see
508
+	 *                                   https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
509
+	 * @param string $evt_active_status  A string representing the evt active status to filter the months by.
510
+	 *                                   Can be:
511
+	 *                                   - '' = no filter
512
+	 *                                   - upcoming = Published events with at least one upcoming datetime.
513
+	 *                                   - expired = Events with all datetimes expired.
514
+	 *                                   - active = Events that are published and have at least one datetime that
515
+	 *                                   starts before now and ends after now.
516
+	 *                                   - inactive = Events that are either not published.
517
+	 * @return EE_Base_Class[]
518
+	 * @throws EE_Error
519
+	 * @throws InvalidArgumentException
520
+	 * @throws InvalidArgumentException
521
+	 */
522
+	public function get_dtt_months_and_years(array $where_params, $evt_active_status = '')
523
+	{
524
+		$current_time_for_DTT_EVT_start = $this->current_time_for_query('DTT_EVT_start');
525
+		$current_time_for_DTT_EVT_end   = $this->current_time_for_query('DTT_EVT_end');
526
+		switch ($evt_active_status) {
527
+			case 'upcoming':
528
+				$where_params['Event.status'] = 'publish';
529
+				// if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
530
+				if (isset($where_params['DTT_EVT_start'])) {
531
+					$where_params['DTT_EVT_start*****'] = $where_params['DTT_EVT_start'];
532
+				}
533
+				$where_params['DTT_EVT_start'] = ['>', $current_time_for_DTT_EVT_start];
534
+				break;
535
+			case 'expired':
536
+				if (isset($where_params['Event.status'])) {
537
+					unset($where_params['Event.status']);
538
+				}
539
+				// get events to exclude
540
+				$exclude_query[0] = array_merge(
541
+					$where_params,
542
+					['DTT_EVT_end' => ['>', $current_time_for_DTT_EVT_end]]
543
+				);
544
+				// first get all events that have datetimes where its not expired.
545
+				$event_ids = $this->_get_all_wpdb_results(
546
+					$exclude_query,
547
+					OBJECT_K,
548
+					'Datetime.EVT_ID'
549
+				);
550
+				$event_ids = array_keys($event_ids);
551
+				if (isset($where_params['DTT_EVT_end'])) {
552
+					$where_params['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
553
+				}
554
+				$where_params['DTT_EVT_end']  = ['<', $current_time_for_DTT_EVT_end];
555
+				$where_params['Event.EVT_ID'] = ['NOT IN', $event_ids];
556
+				break;
557
+			case 'active':
558
+				$where_params['Event.status'] = 'publish';
559
+				if (isset($where_params['DTT_EVT_start'])) {
560
+					$where_params['Datetime.DTT_EVT_start******'] = $where_params['DTT_EVT_start'];
561
+				}
562
+				if (isset($where_params['Datetime.DTT_EVT_end'])) {
563
+					$where_params['Datetime.DTT_EVT_end*****'] = $where_params['DTT_EVT_end'];
564
+				}
565
+				$where_params['DTT_EVT_start'] = ['<', $current_time_for_DTT_EVT_start];
566
+				$where_params['DTT_EVT_end']   = ['>', $current_time_for_DTT_EVT_end];
567
+				break;
568
+			case 'inactive':
569
+				if (isset($where_params['Event.status'])) {
570
+					unset($where_params['Event.status']);
571
+				}
572
+				if (isset($where_params['OR'])) {
573
+					$where_params['AND']['OR'] = $where_params['OR'];
574
+				}
575
+				if (isset($where_params['DTT_EVT_end'])) {
576
+					$where_params['AND']['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
577
+					unset($where_params['DTT_EVT_end']);
578
+				}
579
+				if (isset($where_params['DTT_EVT_start'])) {
580
+					$where_params['AND']['DTT_EVT_start'] = $where_params['DTT_EVT_start'];
581
+					unset($where_params['DTT_EVT_start']);
582
+				}
583
+				$where_params['AND']['Event.status'] = ['!=', 'publish'];
584
+				break;
585
+		}
586
+		$query_params[0]          = $where_params;
587
+		$query_params['group_by'] = ['dtt_year', 'dtt_month'];
588
+		$query_params             = $this->addOrderByQueryParams($query_params, 'DTT_EVT_start', 'DESC');
589
+
590
+		$query_interval    = EEH_DTT_Helper::get_sql_query_interval_for_offset(
591
+			$this->get_timezone(),
592
+			'DTT_EVT_start'
593
+		);
594
+		$columns_to_select = [
595
+			'dtt_year'      => ['YEAR(' . $query_interval . ')', '%s'],
596
+			'dtt_month'     => ['MONTHNAME(' . $query_interval . ')', '%s'],
597
+			'dtt_month_num' => ['MONTH(' . $query_interval . ')', '%s'],
598
+		];
599
+		return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select);
600
+	}
601
+
602
+
603
+	/**
604
+	 * Updates the DTT_sold attribute on each datetime (based on the registrations
605
+	 * for the tickets for each datetime)
606
+	 *
607
+	 * @param EE_Base_Class[]|EE_Datetime[] $datetimes
608
+	 * @throws EE_Error
609
+	 * @throws ReflectionException
610
+	 */
611
+	public function update_sold(array $datetimes)
612
+	{
613
+		EE_Error::doing_it_wrong(
614
+			__FUNCTION__,
615
+			esc_html__(
616
+				'Please use \EEM_Ticket::update_tickets_sold() instead which will in turn correctly update both the Ticket AND Datetime counts.',
617
+				'event_espresso'
618
+			),
619
+			'4.9.32.rc.005'
620
+		);
621
+		foreach ($datetimes as $datetime) {
622
+			$datetime->update_sold();
623
+		}
624
+	}
625
+
626
+
627
+	/**
628
+	 *    Gets the total number of tickets available at a particular datetime
629
+	 *    (does NOT take into account the datetime's spaces available)
630
+	 *
631
+	 * @param int   $DTT_ID
632
+	 * @param array $query_params
633
+	 * @return int of tickets available. If sold out, return less than 1. If infinite, returns EE_INF,  IF there are NO
634
+	 *             tickets attached to datetime then FALSE is returned.
635
+	 * @throws EE_Error
636
+	 * @throws ReflectionException
637
+	 */
638
+	public function sum_tickets_currently_available_at_datetime(int $DTT_ID, array $query_params = [])
639
+	{
640
+		$datetime = $this->get_one_by_ID($DTT_ID);
641
+		if ($datetime instanceof EE_Datetime) {
642
+			return $datetime->tickets_remaining($query_params);
643
+		}
644
+		return 0;
645
+	}
646
+
647
+
648
+	/**
649
+	 * This returns an array of counts of datetimes in the database for each Datetime status that can be queried.
650
+	 *
651
+	 * @param array $stati_to_include  If included you can restrict the statuses we return counts for by including the
652
+	 *                                 stati you want counts for as values in the array.  An empty array returns counts
653
+	 *                                 for all valid stati.
654
+	 * @param array $query_params      If included can be used to refine the conditions for returning the count (i.e.
655
+	 *                                 only for Datetimes connected to a specific event, or specific ticket.
656
+	 * @return array  The value returned is an array indexed by Datetime Status and the values are the counts.  The
657
+	 * @throws EE_Error
658
+	 *                                 stati used as index keys are: EE_Datetime::active EE_Datetime::upcoming
659
+	 *                                 EE_Datetime::expired
660
+	 */
661
+	public function get_datetime_counts_by_status(array $stati_to_include = [], array $query_params = [])
662
+	{
663
+		// only accept where conditions for this query.
664
+		$_where            = isset($query_params[0]) ? $query_params[0] : [];
665
+		$status_query_args = [
666
+			EE_Datetime::active   => array_merge(
667
+				$_where,
668
+				['DTT_EVT_start' => ['<', time()], 'DTT_EVT_end' => ['>', time()]]
669
+			),
670
+			EE_Datetime::upcoming => array_merge(
671
+				$_where,
672
+				['DTT_EVT_start' => ['>', time()]]
673
+			),
674
+			EE_Datetime::expired  => array_merge(
675
+				$_where,
676
+				['DTT_EVT_end' => ['<', time()]]
677
+			),
678
+		];
679
+		if (! empty($stati_to_include)) {
680
+			foreach (array_keys($status_query_args) as $status) {
681
+				if (! in_array($status, $stati_to_include, true)) {
682
+					unset($status_query_args[ $status ]);
683
+				}
684
+			}
685
+		}
686
+		// loop through and query counts for each stati.
687
+		$status_query_results = [];
688
+		foreach ($status_query_args as $status => $status_where_conditions) {
689
+			$status_query_results[ $status ] = EEM_Datetime::count(
690
+				[$status_where_conditions],
691
+				'DTT_ID',
692
+				true
693
+			);
694
+		}
695
+		return $status_query_results;
696
+	}
697
+
698
+
699
+	/**
700
+	 * Returns the specific count for a given Datetime status matching any given query_params.
701
+	 *
702
+	 * @param string $status Valid string representation for Datetime status requested. (Defaults to Active).
703
+	 * @param array  $query_params
704
+	 * @return int
705
+	 * @throws EE_Error
706
+	 */
707
+	public function get_datetime_count_for_status($status = EE_Datetime::active, array $query_params = [])
708
+	{
709
+		$count = $this->get_datetime_counts_by_status([$status], $query_params);
710
+		return ! empty($count[ $status ]) ? $count[ $status ] : 0;
711
+	}
712
+
713
+
714
+	/**
715
+	 * @return bool|int
716
+	 * @since   $VID:$
717
+	 */
718
+	private function prepModelForQuery()
719
+	{
720
+		$prev_data_prep_value = $this->get_assumption_concerning_values_already_prepared_by_model_object();
721
+		$this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
722
+		return $prev_data_prep_value;
723
+	}
724
+
725
+
726
+	/**
727
+	 * @param array    $query_params
728
+	 * @param bool|int $prev_data_prep_value
729
+	 * @return EE_Base_Class[]|EE_Datetime[]
730
+	 * @throws EE_Error
731
+	 * @since   $VID:$
732
+	 */
733
+	private function getDatetimesAndRestoreModel(array $query_params, $prev_data_prep_value)
734
+	{
735
+		$result = $this->get_all($query_params);
736
+		$this->assume_values_already_prepared_by_model_object($prev_data_prep_value);
737
+		return $result;
738
+	}
739
+
740
+
741
+	/**
742
+	 * @param array  $query_params
743
+	 * @param int    $limit
744
+	 * @param string $order_by
745
+	 * @param string $order
746
+	 * @return array
747
+	 * @since   $VID:$
748
+	 */
749
+	private function addDefaultQueryParams(array $query_params, $limit = 0, $order_by = 'DTT_EVT_start', $order = 'ASC')
750
+	{
751
+		$query_params = $this->addOrderByQueryParams($query_params, $order_by, $order);
752
+		$query_params = $this->addLimitQueryParams($query_params, $limit);
753
+		return $query_params;
754
+	}
755
+
756
+
757
+	/**
758
+	 * @param array  $query_params
759
+	 * @param string $default_where_conditions
760
+	 * @return array
761
+	 * @since   $VID:$
762
+	 */
763
+	private function addDefaultWhereConditions(
764
+		array $query_params,
765
+		$default_where_conditions = EEM_Base::default_where_conditions_none
766
+	) {
767
+		$query_params['default_where_conditions'] = $default_where_conditions;
768
+		return $query_params;
769
+	}
770
+
771
+
772
+	/**
773
+	 * @param array $where_params
774
+	 * @param bool  $include_deleted
775
+	 * @param bool  $include_expired
776
+	 * @return array
777
+	 * @since   $VID:$
778
+	 */
779
+	private function addDefaultWhereParams(array $where_params, bool $include_deleted = true, bool $include_expired = true)
780
+	{
781
+		$where_params = $this->addExpiredWhereParams($where_params, $include_expired);
782
+		$where_params = $this->addDeletedWhereParams($where_params, $include_deleted);
783
+		return $where_params;
784
+	}
785
+
786
+
787
+	/**
788
+	 * @param array $where_params
789
+	 * @param bool  $include_deleted
790
+	 * @return array
791
+	 * @since   $VID:$
792
+	 */
793
+	private function addDeletedWhereParams(array $where_params, bool $include_deleted = true)
794
+	{
795
+		$deleted                     = $include_deleted ? [true, false] : [false];
796
+		$where_params['DTT_deleted'] = ['IN', $deleted];
797
+		return $where_params;
798
+	}
799
+
800
+
801
+	/**
802
+	 * @param array $where_params
803
+	 * @param bool  $include_expired
804
+	 * @return array
805
+	 * @since   $VID:$
806
+	 */
807
+	private function addExpiredWhereParams(array $where_params, bool $include_expired = true)
808
+	{
809
+		if (! $include_expired) {
810
+			$where_params['DTT_EVT_end'] = ['>=', current_time('mysql', true)];
811
+		}
812
+		return $where_params;
813
+	}
814
+
815
+
816
+	/**
817
+	 * @param array $query_params
818
+	 * @param int   $limit
819
+	 * @return array
820
+	 * @since   $VID:$
821
+	 */
822
+	private function addLimitQueryParams(array $query_params, $limit = 0)
823
+	{
824
+		if ($limit) {
825
+			$query_params['limit'] = $limit;
826
+		}
827
+		return $query_params;
828
+	}
829
+
830
+
831
+	/**
832
+	 * @param array  $query_params
833
+	 * @param string $order_by
834
+	 * @param string $order
835
+	 * @return array
836
+	 * @since   $VID:$
837
+	 */
838
+	private function addOrderByQueryParams(array $query_params, $order_by = 'DTT_EVT_start', $order = 'ASC')
839
+	{
840
+		$order                    = $order === 'ASC' ? 'ASC' : 'DESC';
841
+		$valid_order_columns      = ['DTT_ID', 'DTT_EVT_start', 'DTT_EVT_end', 'DTT_order'];
842
+		$order_by                 = in_array($order_by, $valid_order_columns, true) ? $order_by : 'DTT_EVT_start';
843
+		$query_params['order_by'] = [$order_by => $order];
844
+		return $query_params;
845
+	}
846 846
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Term.model.php 1 patch
Indentation   +237 added lines, -237 removed lines patch added patch discarded remove patch
@@ -14,263 +14,263 @@
 block discarded – undo
14 14
 class EEM_Term extends EEM_Base
15 15
 {
16 16
 
17
-    // private instance of the Attendee object
18
-    protected static $_instance = null;
17
+	// private instance of the Attendee object
18
+	protected static $_instance = null;
19 19
 
20 20
 
21 21
 
22
-    /**
23
-     *__construct
24
-     *
25
-     * @param string $timezone
26
-     */
27
-    protected function __construct($timezone = '')
28
-    {
29
-        $this->singular_item = __('Term', 'event_espresso');
30
-        $this->plural_item = __('Terms', 'event_espresso');
31
-        $this->_tables = array(
32
-            'Term' => new EE_Primary_Table('terms', 'term_id'),
33
-        );
34
-        $this->_fields = array(
35
-            'Term' => array(
36
-                'term_id'    => new EE_Primary_Key_Int_Field('term_id', __('Term ID', 'event_espresso')),
37
-                'name'       => new EE_Plain_Text_Field('name', __('Term Name', 'event_espresso'), false, ''),
38
-                'slug'       => new EE_Slug_Field('slug', __('Term Slug', 'event_espresso'), false),
39
-                'term_group' => new EE_Integer_Field('term_group', __("Term Group", "event_espresso"), false, 0),
40
-            ),
41
-        );
42
-        $this->_model_relations = array(
43
-            'Term_Taxonomy' => new EE_Has_Many_Relation(),
44
-        );
45
-        $this->_wp_core_model = true;
46
-        $path_to_tax_model = 'Term_Taxonomy';
47
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
48
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Taxonomy_Protected(
49
-            $path_to_tax_model
50
-        );
51
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ] = false;
52
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ] = false;
53
-        $path_to_tax_model = $path_to_tax_model . '.';
54
-        // add cap restrictions for editing relating to the "ee_edit_*"
55
-        $this->_cap_restrictions[ EEM_Base::caps_edit ]['ee_edit_event_category'] = new EE_Default_Where_Conditions(
56
-            array(
57
-                $path_to_tax_model . 'taxonomy*ee_edit_event_category' => array('!=', 'espresso_event_categories'),
58
-            )
59
-        );
60
-        $this->_cap_restrictions[ EEM_Base::caps_edit ]['ee_edit_venue_category'] = new EE_Default_Where_Conditions(
61
-            array(
62
-                $path_to_tax_model . 'taxonomy*ee_edit_venue_category' => array('!=', 'espresso_venue_categories'),
63
-            )
64
-        );
65
-        $this->_cap_restrictions[ EEM_Base::caps_edit ]['ee_edit_event_type'] = new EE_Default_Where_Conditions(
66
-            array(
67
-                $path_to_tax_model . 'taxonomy*ee_edit_event_type' => array('!=', 'espresso_event_type'),
68
-            )
69
-        );
70
-        // add cap restrictions for deleting relating to the "ee_deleting_*"
71
-        $this->_cap_restrictions[ EEM_Base::caps_delete ]['ee_delete_event_category'] = new EE_Default_Where_Conditions(
72
-            array(
73
-                $path_to_tax_model . 'taxonomy*ee_delete_event_category' => array('!=', 'espresso_event_categories'),
74
-            )
75
-        );
76
-        $this->_cap_restrictions[ EEM_Base::caps_delete ]['ee_delete_venue_category'] = new EE_Default_Where_Conditions(
77
-            array(
78
-                $path_to_tax_model . 'taxonomy*ee_delete_venue_category' => array('!=', 'espresso_venue_categories'),
79
-            )
80
-        );
81
-        $this->_cap_restrictions[ EEM_Base::caps_delete ]['ee_delete_event_type'] = new EE_Default_Where_Conditions(
82
-            array(
83
-                $path_to_tax_model . 'taxonomy*ee_delete_event_type' => array('!=', 'espresso_event_type'),
84
-            )
85
-        );
86
-        parent::__construct($timezone);
87
-        add_filter('FHEE__Read__create_model_query_params', array('EEM_Term', 'rest_api_query_params'), 10, 3);
88
-    }
22
+	/**
23
+	 *__construct
24
+	 *
25
+	 * @param string $timezone
26
+	 */
27
+	protected function __construct($timezone = '')
28
+	{
29
+		$this->singular_item = __('Term', 'event_espresso');
30
+		$this->plural_item = __('Terms', 'event_espresso');
31
+		$this->_tables = array(
32
+			'Term' => new EE_Primary_Table('terms', 'term_id'),
33
+		);
34
+		$this->_fields = array(
35
+			'Term' => array(
36
+				'term_id'    => new EE_Primary_Key_Int_Field('term_id', __('Term ID', 'event_espresso')),
37
+				'name'       => new EE_Plain_Text_Field('name', __('Term Name', 'event_espresso'), false, ''),
38
+				'slug'       => new EE_Slug_Field('slug', __('Term Slug', 'event_espresso'), false),
39
+				'term_group' => new EE_Integer_Field('term_group', __("Term Group", "event_espresso"), false, 0),
40
+			),
41
+		);
42
+		$this->_model_relations = array(
43
+			'Term_Taxonomy' => new EE_Has_Many_Relation(),
44
+		);
45
+		$this->_wp_core_model = true;
46
+		$path_to_tax_model = 'Term_Taxonomy';
47
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
48
+		$this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Taxonomy_Protected(
49
+			$path_to_tax_model
50
+		);
51
+		$this->_cap_restriction_generators[ EEM_Base::caps_edit ] = false;
52
+		$this->_cap_restriction_generators[ EEM_Base::caps_delete ] = false;
53
+		$path_to_tax_model = $path_to_tax_model . '.';
54
+		// add cap restrictions for editing relating to the "ee_edit_*"
55
+		$this->_cap_restrictions[ EEM_Base::caps_edit ]['ee_edit_event_category'] = new EE_Default_Where_Conditions(
56
+			array(
57
+				$path_to_tax_model . 'taxonomy*ee_edit_event_category' => array('!=', 'espresso_event_categories'),
58
+			)
59
+		);
60
+		$this->_cap_restrictions[ EEM_Base::caps_edit ]['ee_edit_venue_category'] = new EE_Default_Where_Conditions(
61
+			array(
62
+				$path_to_tax_model . 'taxonomy*ee_edit_venue_category' => array('!=', 'espresso_venue_categories'),
63
+			)
64
+		);
65
+		$this->_cap_restrictions[ EEM_Base::caps_edit ]['ee_edit_event_type'] = new EE_Default_Where_Conditions(
66
+			array(
67
+				$path_to_tax_model . 'taxonomy*ee_edit_event_type' => array('!=', 'espresso_event_type'),
68
+			)
69
+		);
70
+		// add cap restrictions for deleting relating to the "ee_deleting_*"
71
+		$this->_cap_restrictions[ EEM_Base::caps_delete ]['ee_delete_event_category'] = new EE_Default_Where_Conditions(
72
+			array(
73
+				$path_to_tax_model . 'taxonomy*ee_delete_event_category' => array('!=', 'espresso_event_categories'),
74
+			)
75
+		);
76
+		$this->_cap_restrictions[ EEM_Base::caps_delete ]['ee_delete_venue_category'] = new EE_Default_Where_Conditions(
77
+			array(
78
+				$path_to_tax_model . 'taxonomy*ee_delete_venue_category' => array('!=', 'espresso_venue_categories'),
79
+			)
80
+		);
81
+		$this->_cap_restrictions[ EEM_Base::caps_delete ]['ee_delete_event_type'] = new EE_Default_Where_Conditions(
82
+			array(
83
+				$path_to_tax_model . 'taxonomy*ee_delete_event_type' => array('!=', 'espresso_event_type'),
84
+			)
85
+		);
86
+		parent::__construct($timezone);
87
+		add_filter('FHEE__Read__create_model_query_params', array('EEM_Term', 'rest_api_query_params'), 10, 3);
88
+	}
89 89
 
90 90
 
91 91
 
92
-    /**
93
-     * retrieves a list of all EE event categories
94
-     *
95
-     * @access public
96
-     * @param bool $show_uncategorized
97
-     * @return \EE_Base_Class[]
98
-     */
99
-    public function get_all_ee_categories($show_uncategorized = false)
100
-    {
101
-        $where_params = array(
102
-            'Term_Taxonomy.taxonomy' => 'espresso_event_categories',
103
-            'NOT'                    => array('name' => __('Uncategorized', 'event_espresso')),
104
-        );
105
-        if ($show_uncategorized) {
106
-            unset($where_params['NOT']);
107
-        }
108
-        return EEM_Term::instance()->get_all(
109
-            array(
110
-                $where_params,
111
-                'order_by' => array('name' => 'ASC'),
112
-            )
113
-        );
114
-    }
92
+	/**
93
+	 * retrieves a list of all EE event categories
94
+	 *
95
+	 * @access public
96
+	 * @param bool $show_uncategorized
97
+	 * @return \EE_Base_Class[]
98
+	 */
99
+	public function get_all_ee_categories($show_uncategorized = false)
100
+	{
101
+		$where_params = array(
102
+			'Term_Taxonomy.taxonomy' => 'espresso_event_categories',
103
+			'NOT'                    => array('name' => __('Uncategorized', 'event_espresso')),
104
+		);
105
+		if ($show_uncategorized) {
106
+			unset($where_params['NOT']);
107
+		}
108
+		return EEM_Term::instance()->get_all(
109
+			array(
110
+				$where_params,
111
+				'order_by' => array('name' => 'ASC'),
112
+			)
113
+		);
114
+	}
115 115
 
116 116
 
117 117
 
118
-    /**
119
-     * retrieves a list of all post_tags associated with an EE CPT
120
-     *
121
-     * @access public
122
-     * @param string $post_type
123
-     * @return array
124
-     */
125
-    public function get_all_CPT_post_tags($post_type = '')
126
-    {
127
-        switch ($post_type) {
128
-            case 'espresso_events':
129
-                return $this->get_all_event_post_tags();
130
-                break;
131
-            case 'espresso_venues':
132
-                return $this->get_all_venue_post_tags();
133
-                break;
134
-            default:
135
-                $event_tags = $this->get_all_event_post_tags();
136
-                $venue_tags = $this->get_all_venue_post_tags();
137
-                return array_merge($event_tags, $venue_tags);
138
-        }
139
-    }
118
+	/**
119
+	 * retrieves a list of all post_tags associated with an EE CPT
120
+	 *
121
+	 * @access public
122
+	 * @param string $post_type
123
+	 * @return array
124
+	 */
125
+	public function get_all_CPT_post_tags($post_type = '')
126
+	{
127
+		switch ($post_type) {
128
+			case 'espresso_events':
129
+				return $this->get_all_event_post_tags();
130
+				break;
131
+			case 'espresso_venues':
132
+				return $this->get_all_venue_post_tags();
133
+				break;
134
+			default:
135
+				$event_tags = $this->get_all_event_post_tags();
136
+				$venue_tags = $this->get_all_venue_post_tags();
137
+				return array_merge($event_tags, $venue_tags);
138
+		}
139
+	}
140 140
 
141 141
 
142
-    /**
143
-     * returns an EE_Term object for the given tag
144
-     * if it has been utilized by any EE_Events or EE_Venues
145
-     *
146
-     * @param string $tag
147
-     * @return EE_Term|null
148
-     * @throws EE_Error
149
-     * @throws InvalidArgumentException
150
-     * @throws InvalidDataTypeException
151
-     * @throws InvalidInterfaceException
152
-     */
153
-    public function get_post_tag_for_event_or_venue($tag)
154
-    {
155
-        $post_tag_results = $this->get_all_wpdb_results(
156
-            array(
157
-                array(
158
-                    'slug' => $tag,
159
-                    'Term_Taxonomy.taxonomy' => 'post_tag',
160
-                    'OR' => array(
161
-                        'Term_Taxonomy.Venue.post_type' => 'espresso_venues',
162
-                        'Term_Taxonomy.Event.post_type' => 'espresso_events',
163
-                    ),
164
-                ),
165
-                'default_where_conditions' => 'none',
166
-                'extra_selects' => array(
167
-                    'event_post_type' => array('Term_Taxonomy___Event_CPT.post_type', '%s'),
168
-                    'venue_post_type' => array('Term_Taxonomy___Venue_CPT.post_type', '%s')
169
-                ),
170
-                'group_by' => array(
171
-                    'event_post_type',
172
-                    'venue_post_type',
173
-                ),
174
-                'limit' => 2
175
-            )
176
-        );
142
+	/**
143
+	 * returns an EE_Term object for the given tag
144
+	 * if it has been utilized by any EE_Events or EE_Venues
145
+	 *
146
+	 * @param string $tag
147
+	 * @return EE_Term|null
148
+	 * @throws EE_Error
149
+	 * @throws InvalidArgumentException
150
+	 * @throws InvalidDataTypeException
151
+	 * @throws InvalidInterfaceException
152
+	 */
153
+	public function get_post_tag_for_event_or_venue($tag)
154
+	{
155
+		$post_tag_results = $this->get_all_wpdb_results(
156
+			array(
157
+				array(
158
+					'slug' => $tag,
159
+					'Term_Taxonomy.taxonomy' => 'post_tag',
160
+					'OR' => array(
161
+						'Term_Taxonomy.Venue.post_type' => 'espresso_venues',
162
+						'Term_Taxonomy.Event.post_type' => 'espresso_events',
163
+					),
164
+				),
165
+				'default_where_conditions' => 'none',
166
+				'extra_selects' => array(
167
+					'event_post_type' => array('Term_Taxonomy___Event_CPT.post_type', '%s'),
168
+					'venue_post_type' => array('Term_Taxonomy___Venue_CPT.post_type', '%s')
169
+				),
170
+				'group_by' => array(
171
+					'event_post_type',
172
+					'venue_post_type',
173
+				),
174
+				'limit' => 2
175
+			)
176
+		);
177 177
 
178
-        $post_types = array();
179
-        foreach ((array) $post_tag_results as $row) {
180
-            if ($row['event_post_type'] === 'espresso_events') {
181
-                $post_types[] = EEM_Event::instance()->post_type();
182
-            } elseif ($row['venue_post_type'] === 'espresso_venues') {
183
-                $post_types[] = EEM_Venue::instance()->post_type();
184
-            }
185
-        }
186
-        $post_tag_row = reset($post_tag_results);
187
-        $post_tag = $this->instantiate_class_from_array_or_object($post_tag_row);
188
-        if (! $post_tag instanceof EE_Term) {
189
-            return null;
190
-        }
178
+		$post_types = array();
179
+		foreach ((array) $post_tag_results as $row) {
180
+			if ($row['event_post_type'] === 'espresso_events') {
181
+				$post_types[] = EEM_Event::instance()->post_type();
182
+			} elseif ($row['venue_post_type'] === 'espresso_venues') {
183
+				$post_types[] = EEM_Venue::instance()->post_type();
184
+			}
185
+		}
186
+		$post_tag_row = reset($post_tag_results);
187
+		$post_tag = $this->instantiate_class_from_array_or_object($post_tag_row);
188
+		if (! $post_tag instanceof EE_Term) {
189
+			return null;
190
+		}
191 191
 
192
-        if ($post_tag->post_type === null) {
193
-            $post_tag->post_type = array();
194
-        }
195
-        $post_tag->post_type = array_merge($post_tag->post_type, array_unique($post_types));
196
-        return $post_tag;
197
-    }
192
+		if ($post_tag->post_type === null) {
193
+			$post_tag->post_type = array();
194
+		}
195
+		$post_tag->post_type = array_merge($post_tag->post_type, array_unique($post_types));
196
+		return $post_tag;
197
+	}
198 198
 
199 199
 
200 200
 
201
-    /**
202
-     * get_all_event_post_tags
203
-     *
204
-     * @return EE_Base_Class[]
205
-     */
206
-    public function get_all_event_post_tags()
207
-    {
208
-        $post_tags = EEM_Term::instance()->get_all(
209
-            array(
210
-                array(
211
-                    'Term_Taxonomy.taxonomy'        => 'post_tag',
212
-                    'Term_Taxonomy.Event.post_type' => 'espresso_events',
213
-                ),
214
-                'order_by'   => array('name' => 'ASC'),
215
-                'force_join' => array('Term_Taxonomy.Event'),
216
-            )
217
-        );
218
-        foreach ($post_tags as $key => $post_tag) {
219
-            if (! isset($post_tags[ $key ]->post_type)) {
220
-                $post_tags[ $key ]->post_type = array();
221
-            }
222
-            $post_tags[ $key ]->post_type[] = 'espresso_events';
223
-        }
224
-        return $post_tags;
225
-    }
201
+	/**
202
+	 * get_all_event_post_tags
203
+	 *
204
+	 * @return EE_Base_Class[]
205
+	 */
206
+	public function get_all_event_post_tags()
207
+	{
208
+		$post_tags = EEM_Term::instance()->get_all(
209
+			array(
210
+				array(
211
+					'Term_Taxonomy.taxonomy'        => 'post_tag',
212
+					'Term_Taxonomy.Event.post_type' => 'espresso_events',
213
+				),
214
+				'order_by'   => array('name' => 'ASC'),
215
+				'force_join' => array('Term_Taxonomy.Event'),
216
+			)
217
+		);
218
+		foreach ($post_tags as $key => $post_tag) {
219
+			if (! isset($post_tags[ $key ]->post_type)) {
220
+				$post_tags[ $key ]->post_type = array();
221
+			}
222
+			$post_tags[ $key ]->post_type[] = 'espresso_events';
223
+		}
224
+		return $post_tags;
225
+	}
226 226
 
227 227
 
228 228
 
229
-    /**
230
-     * get_all_venue_post_tags
231
-     *
232
-     * @return EE_Base_Class[]
233
-     */
234
-    public function get_all_venue_post_tags()
235
-    {
236
-        $post_tags = EEM_Term::instance()->get_all(
237
-            array(
238
-                array(
239
-                    'Term_Taxonomy.taxonomy'        => 'post_tag',
240
-                    'Term_Taxonomy.Venue.post_type' => 'espresso_venues',
241
-                ),
242
-                'order_by'   => array('name' => 'ASC'),
243
-                'force_join' => array('Term_Taxonomy'),
244
-            )
245
-        );
246
-        foreach ($post_tags as $key => $post_tag) {
247
-            if (! isset($post_tags[ $key ]->post_type)) {
248
-                $post_tags[ $key ]->post_type = array();
249
-            }
250
-            $post_tags[ $key ]->post_type[] = 'espresso_venues';
251
-        }
252
-        return $post_tags;
253
-    }
229
+	/**
230
+	 * get_all_venue_post_tags
231
+	 *
232
+	 * @return EE_Base_Class[]
233
+	 */
234
+	public function get_all_venue_post_tags()
235
+	{
236
+		$post_tags = EEM_Term::instance()->get_all(
237
+			array(
238
+				array(
239
+					'Term_Taxonomy.taxonomy'        => 'post_tag',
240
+					'Term_Taxonomy.Venue.post_type' => 'espresso_venues',
241
+				),
242
+				'order_by'   => array('name' => 'ASC'),
243
+				'force_join' => array('Term_Taxonomy'),
244
+			)
245
+		);
246
+		foreach ($post_tags as $key => $post_tag) {
247
+			if (! isset($post_tags[ $key ]->post_type)) {
248
+				$post_tags[ $key ]->post_type = array();
249
+			}
250
+			$post_tags[ $key ]->post_type[] = 'espresso_venues';
251
+		}
252
+		return $post_tags;
253
+	}
254 254
 
255 255
 
256 256
 
257
-    /**
258
-     * Makes sure that during REST API queries, we only return terms
259
-     * for term taxonomies which should be shown in the rest api
260
-     *
261
-     * @param array    $model_query_params
262
-     * @param array    $querystring_query_params
263
-     * @param EEM_Base $model
264
-     * @return array
265
-     */
266
-    public static function rest_api_query_params($model_query_params, $querystring_query_params, $model)
267
-    {
268
-        if ($model === EEM_Term::instance()) {
269
-            $taxonomies = get_taxonomies(array('show_in_rest' => true));
270
-            if (! empty($taxonomies)) {
271
-                $model_query_params[0]['Term_Taxonomy.taxonomy'] = array('IN', $taxonomies);
272
-            }
273
-        }
274
-        return $model_query_params;
275
-    }
257
+	/**
258
+	 * Makes sure that during REST API queries, we only return terms
259
+	 * for term taxonomies which should be shown in the rest api
260
+	 *
261
+	 * @param array    $model_query_params
262
+	 * @param array    $querystring_query_params
263
+	 * @param EEM_Base $model
264
+	 * @return array
265
+	 */
266
+	public static function rest_api_query_params($model_query_params, $querystring_query_params, $model)
267
+	{
268
+		if ($model === EEM_Term::instance()) {
269
+			$taxonomies = get_taxonomies(array('show_in_rest' => true));
270
+			if (! empty($taxonomies)) {
271
+				$model_query_params[0]['Term_Taxonomy.taxonomy'] = array('IN', $taxonomies);
272
+			}
273
+		}
274
+		return $model_query_params;
275
+	}
276 276
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Message.model.php 1 patch
Indentation   +617 added lines, -617 removed lines patch added patch discarded remove patch
@@ -10,628 +10,628 @@
 block discarded – undo
10 10
 class EEM_Message extends EEM_Base implements EEI_Query_Filter
11 11
 {
12 12
 
13
-    // private instance of the Message object
14
-    protected static $_instance = null;
13
+	// private instance of the Message object
14
+	protected static $_instance = null;
15 15
 
16 16
 
17
-    /**
18
-     * This priority indicates a message should be generated and sent ASAP
19
-     *
20
-     * @type int
21
-     */
22
-    const priority_high = 10;
23
-
24
-
25
-    /**
26
-     * This priority indicates a message should be generated ASAP and queued for sending.
27
-     *
28
-     * @type
29
-     */
30
-    const priority_medium = 20;
31
-
32
-
33
-    /**
34
-     * This priority indicates a message should be queued for generating.
35
-     *
36
-     * @type int
37
-     */
38
-    const priority_low = 30;
39
-
40
-
41
-    /**
42
-     * indicates this message was sent at the time modified
43
-     */
44
-    const status_sent = 'MSN';
45
-
46
-
47
-    /**
48
-     * indicates this message is waiting to be sent
49
-     */
50
-    const status_idle = 'MID';
51
-
52
-
53
-    /**
54
-     * indicates an attempt was a made to send this message
55
-     * at the scheduled time, but it failed at the time modified.  This differs from MDO status in that it will ALWAYS
56
-     * appear to the end user.
57
-     */
58
-    const status_failed = 'MFL';
59
-
60
-
61
-    /**
62
-     * indicates the message has been flagged for resending (at the time modified).
63
-     */
64
-    const status_resend = 'MRS';
65
-
66
-
67
-    /**
68
-     * indicates the message has been flagged for generation but has not been generated yet.  Messages always start as
69
-     * this status when added to the queue.
70
-     */
71
-    const status_incomplete = 'MIC';
72
-
73
-
74
-    /**
75
-     * Indicates everything was generated fine for the message, however, the messenger was unable to send.
76
-     * This status means that its possible to retry sending the message.
77
-     */
78
-    const status_retry = 'MRT';
79
-
80
-
81
-    /**
82
-     * This is used for more informational messages that may not indicate anything is broken but still cannot be
83
-     * generated or sent correctly. An example of a message that would get flagged this way would be when a not
84
-     * approved message was queued for generation, but at time of generation, the attached registration(s) are
85
-     * approved. So the message queued for generation is no longer valid.  Messages for this status will only persist
86
-     * in the db and be viewable in the message activity list table when the messages system is in debug mode.
87
-     *
88
-     * @see EEM_Message::debug()
89
-     */
90
-    const status_debug_only = 'MDO';
91
-
92
-
93
-    /**
94
-     * This status is given to messages it is processed by the messenger send method.
95
-     * Messages with this status should rarely be seen in the Message List table, but if they are, that's usually
96
-     * indicative of a PHP timeout or memory limit issue.
97
-     */
98
-    const status_messenger_executing = 'MEX';
99
-
100
-
101
-    /**
102
-     *    Private constructor to prevent direct creation.
103
-     *
104
-     * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and
105
-     *                         any incoming timezone data that gets saved).  Note this just sends the timezone info to
106
-     *                         the date time model field objects.  Default is null (and will be assumed using the set
107
-     *                         timezone in the 'timezone_string' wp option)
108
-     * @return EEM_Message
109
-     */
110
-    protected function __construct($timezone = '')
111
-    {
112
-        $this->singular_item = __('Message', 'event_espresso');
113
-        $this->plural_item   = __('Messages', 'event_espresso');
114
-
115
-        // used for token generator
116
-        EE_Registry::instance()->load_helper('URL');
117
-
118
-        $this->_tables = array(
119
-            'Message' => new EE_Primary_Table('esp_message', 'MSG_ID'),
120
-        );
121
-
122
-        $allowed_priority = array(
123
-            self::priority_high   => __('high', 'event_espresso'),
124
-            self::priority_medium => __('medium', 'event_espresso'),
125
-            self::priority_low    => __('low', 'event_espresso'),
126
-        );
127
-
128
-        $this->_fields          = array(
129
-            'Message' => array(
130
-                'MSG_ID'             => new EE_Primary_Key_Int_Field('MSG_ID', __('Message ID', 'event_espresso')),
131
-                'MSG_token'          => new EE_Plain_Text_Field(
132
-                    'MSG_token',
133
-                    __(
134
-                        'Unique Token used to represent this row in publicly viewable contexts (eg. a url).',
135
-                        'event_espresso'
136
-                    ),
137
-                    false,
138
-                    EEH_URL::generate_unique_token()
139
-                ),
140
-                'GRP_ID'             => new EE_Foreign_Key_Int_Field(
141
-                    'GRP_ID',
142
-                    __('Foreign key to the EEM_Message_Template_Group table.', 'event_espresso'),
143
-                    true,
144
-                    0,
145
-                    'Message_Template_Group'
146
-                ),
147
-                'TXN_ID'             => new EE_Foreign_Key_Int_Field(
148
-                    'TXN_ID',
149
-                    __(
150
-                        'Foreign key to the related EE_Transaction.  This is required to give context for regenerating the specific message',
151
-                        'event_espresso'
152
-                    ),
153
-                    true,
154
-                    0,
155
-                    'Transaction'
156
-                ),
157
-                'MSG_messenger'      => new EE_Plain_Text_Field(
158
-                    'MSG_messenger',
159
-                    __(
160
-                        'Corresponds to the EE_messenger::name used to send this message. This will also be used to attempt any resending of the message.',
161
-                        'event_espresso'
162
-                    ),
163
-                    false,
164
-                    'email'
165
-                ),
166
-                'MSG_message_type'   => new EE_Plain_Text_Field(
167
-                    'MSG_message_type',
168
-                    __('Corresponds to the EE_message_type::name used to generate this message.', 'event_espresso'),
169
-                    false,
170
-                    'receipt'
171
-                ),
172
-                'MSG_context'        => new EE_Plain_Text_Field('MSG_context', __('Context', 'event_espresso'), false),
173
-                'MSG_recipient_ID'   => new EE_Foreign_Key_Int_Field(
174
-                    'MSG_recipient_ID',
175
-                    __('Recipient ID', 'event_espresso'),
176
-                    true,
177
-                    null,
178
-                    array('Registration', 'Attendee', 'WP_User')
179
-                ),
180
-                'MSG_recipient_type' => new EE_Any_Foreign_Model_Name_Field(
181
-                    'MSG_recipient_type',
182
-                    __('Recipient Type', 'event_espresso'),
183
-                    true,
184
-                    null,
185
-                    array('Registration', 'Attendee', 'WP_User')
186
-                ),
187
-                'MSG_content'        => new EE_Maybe_Serialized_Text_Field(
188
-                    'MSG_content',
189
-                    __('Content', 'event_espresso'),
190
-                    true,
191
-                    ''
192
-                ),
193
-                'MSG_to'             => new EE_Maybe_Serialized_Text_Field(
194
-                    'MSG_to',
195
-                    __('Address To', 'event_espresso'),
196
-                    true
197
-                ),
198
-                'MSG_from'           => new EE_Maybe_Serialized_Text_Field(
199
-                    'MSG_from',
200
-                    __('Address From', 'event_espresso'),
201
-                    true
202
-                ),
203
-                'MSG_subject'        => new EE_Maybe_Serialized_Text_Field(
204
-                    'MSG_subject',
205
-                    __('Subject', 'event_espresso'),
206
-                    true,
207
-                    ''
208
-                ),
209
-                'MSG_priority'       => new EE_Enum_Integer_Field(
210
-                    'MSG_priority',
211
-                    __('Priority', 'event_espresso'),
212
-                    false,
213
-                    self::priority_low,
214
-                    $allowed_priority
215
-                ),
216
-                'STS_ID'             => new EE_Foreign_Key_String_Field(
217
-                    'STS_ID',
218
-                    __('Status', 'event_espresso'),
219
-                    false,
220
-                    self::status_incomplete,
221
-                    'Status'
222
-                ),
223
-                'MSG_created'        => new EE_Datetime_Field(
224
-                    'MSG_created',
225
-                    __('Created', 'event_espresso'),
226
-                    false,
227
-                    EE_Datetime_Field::now
228
-                ),
229
-                'MSG_modified'       => new EE_Datetime_Field(
230
-                    'MSG_modified',
231
-                    __('Modified', 'event_espresso'),
232
-                    true,
233
-                    EE_Datetime_Field::now
234
-                ),
235
-            ),
236
-        );
237
-        $this->_model_relations = array(
238
-            'Attendee'               => new EE_Belongs_To_Any_Relation(),
239
-            'Registration'           => new EE_Belongs_To_Any_Relation(),
240
-            'WP_User'                => new EE_Belongs_To_Any_Relation(),
241
-            'Message_Template_Group' => new EE_Belongs_To_Relation(),
242
-            'Transaction'            => new EE_Belongs_To_Relation(),
243
-        );
244
-        parent::__construct($timezone);
245
-    }
246
-
247
-
248
-    /**
249
-     * @return \EE_Message
250
-     */
251
-    public function create_default_object()
252
-    {
253
-        /** @type EE_Message $message */
254
-        $message = parent::create_default_object();
255
-        if ($message instanceof EE_Message) {
256
-            return EE_Message_Factory::set_messenger_and_message_type($message);
257
-        }
258
-        return null;
259
-    }
260
-
261
-
262
-    /**
263
-     * @param mixed $cols_n_values
264
-     * @return \EE_Message
265
-     */
266
-    public function instantiate_class_from_array_or_object($cols_n_values)
267
-    {
268
-        /** @type EE_Message $message */
269
-        $message = parent::instantiate_class_from_array_or_object($cols_n_values);
270
-        if ($message instanceof EE_Message) {
271
-            return EE_Message_Factory::set_messenger_and_message_type($message);
272
-        }
273
-        return null;
274
-    }
275
-
276
-
277
-    /**
278
-     * Returns whether or not a message of that type was sent for a given attendee.
279
-     *
280
-     * @param EE_Attendee|int $attendee
281
-     * @param string          $message_type the message type slug
282
-     * @return boolean
283
-     */
284
-    public function message_sent_for_attendee($attendee, $message_type)
285
-    {
286
-        $attendee_ID = EEM_Attendee::instance()->ensure_is_ID($attendee);
287
-        return $this->exists(array(
288
-            array(
289
-                'Attendee.ATT_ID'  => $attendee_ID,
290
-                'MSG_message_type' => $message_type,
291
-                'STS_ID'           => array('IN', $this->stati_indicating_sent()),
292
-            ),
293
-        ));
294
-    }
295
-
296
-
297
-    /**
298
-     * Returns whether or not a message of that type was sent for a given registration
299
-     *
300
-     * @param EE_Registration|int $registration
301
-     * @param string              $message_type the message type slug
302
-     * @return boolean
303
-     */
304
-    public function message_sent_for_registration($registration, $message_type)
305
-    {
306
-        $registrationID = EEM_Registration::instance()->ensure_is_ID($registration);
307
-        return $this->exists(array(
308
-            array(
309
-                'Registration.REG_ID' => $registrationID,
310
-                'MSG_message_type'    => $message_type,
311
-                'STS_ID'              => array('IN', $this->stati_indicating_sent()),
312
-            ),
313
-        ));
314
-    }
315
-
316
-
317
-    /**
318
-     * This retrieves an EE_Message object from the db matching the given token string.
319
-     *
320
-     * @param string $token
321
-     * @return EE_Message
322
-     */
323
-    public function get_one_by_token($token)
324
-    {
325
-        return $this->get_one(array(
326
-            array(
327
-                'MSG_token' => $token,
328
-            ),
329
-        ));
330
-    }
331
-
332
-
333
-    /**
334
-     * Returns stati that indicate the message HAS been sent
335
-     *
336
-     * @return array of strings for possible stati
337
-     */
338
-    public function stati_indicating_sent()
339
-    {
340
-        return apply_filters('FHEE__EEM_Message__stati_indicating_sent', array(self::status_sent));
341
-    }
342
-
343
-
344
-    /**
345
-     * Returns stati that indicate the message is waiting to be sent.
346
-     *
347
-     * @return array of strings for possible stati.
348
-     */
349
-    public function stati_indicating_to_send()
350
-    {
351
-        return apply_filters(
352
-            'FHEE__EEM_Message__stati_indicating_to_send',
353
-            array(self::status_idle, self::status_resend)
354
-        );
355
-    }
356
-
357
-
358
-    /**
359
-     * Returns stati that indicate the message has failed sending
360
-     *
361
-     * @return array  array of strings for possible stati.
362
-     */
363
-    public function stati_indicating_failed_sending()
364
-    {
365
-        $failed_stati = array(
366
-            self::status_failed,
367
-            self::status_retry,
368
-            self::status_messenger_executing,
369
-        );
370
-        // if WP_DEBUG is set, then let's include debug_only fails
371
-        if (WP_DEBUG) {
372
-            $failed_stati[] = self::status_debug_only;
373
-        }
374
-        return apply_filters('FHEE__EEM_Message__stati_indicating_failed_sending', $failed_stati);
375
-    }
376
-
377
-
378
-    /**
379
-     * Returns filterable array of all EEM_Message statuses.
380
-     *
381
-     * @return array
382
-     */
383
-    public function all_statuses()
384
-    {
385
-        return apply_filters(
386
-            'FHEE__EEM_Message__all_statuses',
387
-            array(
388
-                EEM_Message::status_sent,
389
-                EEM_Message::status_incomplete,
390
-                EEM_Message::status_idle,
391
-                EEM_Message::status_resend,
392
-                EEM_Message::status_retry,
393
-                EEM_Message::status_failed,
394
-                EEM_Message::status_messenger_executing,
395
-                EEM_Message::status_debug_only,
396
-            )
397
-        );
398
-    }
399
-
400
-    /**
401
-     * Detects any specific query variables in the request and uses those to setup appropriate
402
-     * filter for any queries.
403
-     *
404
-     * @return array
405
-     */
406
-    public function filter_by_query_params()
407
-    {
408
-        // expected possible query_vars, the key in this array matches an expected key in the request,
409
-        // the value, matches the corresponding EEM_Base child reference.
410
-        $expected_vars   = $this->_expected_vars_for_query_inject();
411
-        $query_params[0] = array();
412
-        foreach ($expected_vars as $request_key => $model_name) {
413
-            $request_value = EE_Registry::instance()->REQ->get($request_key);
414
-            if ($request_value) {
415
-                // special case
416
-                switch ($request_key) {
417
-                    case '_REG_ID':
418
-                        $query_params[0]['AND**filter_by']['OR**filter_by_REG_ID'] = array(
419
-                            'Transaction.Registration.REG_ID' => $request_value,
420
-                        );
421
-                        break;
422
-                    case 'EVT_ID':
423
-                        $query_params[0]['AND**filter_by']['OR**filter_by_EVT_ID'] = array(
424
-                            'Transaction.Registration.EVT_ID' => $request_value,
425
-                        );
426
-                        break;
427
-                    default:
428
-                        $query_params[0]['AND**filter_by'][ 'OR**filter_by_' . $request_key ][ $model_name . '.' . $request_key ] = $request_value;
429
-                        break;
430
-                }
431
-            }
432
-        }
433
-        return $query_params;
434
-    }
435
-
436
-
437
-    /**
438
-     * @return string
439
-     */
440
-    public function get_pretty_label_for_results()
441
-    {
442
-        $expected_vars = $this->_expected_vars_for_query_inject();
443
-        $pretty_label  = '';
444
-        $label_parts   = array();
445
-        foreach ($expected_vars as $request_key => $model_name) {
446
-            $model = EE_Registry::instance()->load_model($model_name);
447
-            if ($model_field_value = EE_Registry::instance()->REQ->get($request_key)) {
448
-                switch ($request_key) {
449
-                    case '_REG_ID':
450
-                        $label_parts[] = sprintf(
451
-                            esc_html__('Registration with the ID: %s', 'event_espresso'),
452
-                            $model_field_value
453
-                        );
454
-                        break;
455
-                    case 'ATT_ID':
456
-                        /** @var EE_Attendee $attendee */
457
-                        $attendee      = $model->get_one_by_ID($model_field_value);
458
-                        $label_parts[] = $attendee instanceof EE_Attendee
459
-                            ? sprintf(esc_html__('Attendee %s', 'event_espresso'), $attendee->full_name())
460
-                            : sprintf(esc_html__('Attendee ID: %s', 'event_espresso'), $model_field_value);
461
-                        break;
462
-                    case 'ID':
463
-                        /** @var EE_WP_User $wpUser */
464
-                        $wpUser        = $model->get_one_by_ID($model_field_value);
465
-                        $label_parts[] = $wpUser instanceof EE_WP_User
466
-                            ? sprintf(esc_html__('WP User: %s', 'event_espresso'), $wpUser->name())
467
-                            : sprintf(esc_html__('WP User ID: %s', 'event_espresso'), $model_field_value);
468
-                        break;
469
-                    case 'TXN_ID':
470
-                        $label_parts[] = sprintf(
471
-                            esc_html__('Transaction with the ID: %s', 'event_espresso'),
472
-                            $model_field_value
473
-                        );
474
-                        break;
475
-                    case 'EVT_ID':
476
-                        /** @var EE_Event $Event */
477
-                        $Event         = $model->get_one_by_ID($model_field_value);
478
-                        $label_parts[] = $Event instanceof EE_Event
479
-                            ? sprintf(esc_html__('for the Event: %s', 'event_espresso'), $Event->name())
480
-                            : sprintf(esc_html__('for the Event with ID: %s', 'event_espresso'), $model_field_value);
481
-                        break;
482
-                }
483
-            }
484
-        }
485
-
486
-        if ($label_parts) {
487
-            // prepend to the last element of $label_parts an "and".
488
-            if (count($label_parts) > 1) {
489
-                $label_parts_index_to_prepend               = count($label_parts) - 1;
490
-                $label_parts[ $label_parts_index_to_prepend ] = 'and' . $label_parts[ $label_parts_index_to_prepend ];
491
-            }
492
-
493
-            $pretty_label .= sprintf(
494
-                esc_html_x(
495
-                    'Showing messages for %s',
496
-                    'A label for the messages returned in a query that are filtered by items in the query. This could be Transaction, Event, Attendee, Registration, or WP_User.',
497
-                    'event_espresso'
498
-                ),
499
-                implode(', ', $label_parts)
500
-            );
501
-        }
502
-        return $pretty_label;
503
-    }
504
-
505
-
506
-    /**
507
-     * This returns the array of expected variables for the EEI_Query_Filter methods being implemented
508
-     * The array is in the format:
509
-     * array(
510
-     *  {$field_name} => {$model_name}
511
-     * );
512
-     *
513
-     * @since 4.9.0
514
-     * @return array
515
-     */
516
-    protected function _expected_vars_for_query_inject()
517
-    {
518
-        return array(
519
-            '_REG_ID' => 'Registration',
520
-            'ATT_ID'  => 'Attendee',
521
-            'ID'      => 'WP_User',
522
-            'TXN_ID'  => 'Transaction',
523
-            'EVT_ID'  => 'Event',
524
-        );
525
-    }
526
-
527
-
528
-    /**
529
-     * This returns whether EEM_Message is in debug mode or not.
530
-     * Currently "debug mode" is used to control the handling of the EEM_Message::debug_only status when
531
-     * generating/sending messages. Debug mode can be set by either:
532
-     * 1. Sending in a value for the $set_debug argument
533
-     * 2. Defining `EE_DEBUG_MESSAGES` constant in wp-config.php
534
-     * 3. Overriding the above via the provided filter.
535
-     *
536
-     * @param bool|null $set_debug      If provided, then the debug mode will be set internally until reset via the
537
-     *                                  provided boolean. When no argument is provided (default null) then the debug
538
-     *                                  mode will be returned.
539
-     * @return bool         true means Messages is in debug mode.  false means messages system is not in debug mode.
540
-     */
541
-    public static function debug($set_debug = null)
542
-    {
543
-        static $is_debugging = null;
544
-
545
-        // initialize (use constant if set).
546
-        if (is_null($set_debug) && is_null($is_debugging)) {
547
-            $is_debugging = defined('EE_DEBUG_MESSAGES') && EE_DEBUG_MESSAGES;
548
-        }
549
-
550
-        if (! is_null($set_debug)) {
551
-            $is_debugging = filter_var($set_debug, FILTER_VALIDATE_BOOLEAN);
552
-        }
553
-
554
-        // return filtered value
555
-        return apply_filters('FHEE__EEM_Message__debug', $is_debugging);
556
-    }
557
-
558
-
559
-    /**
560
-     * Deletes old messages meeting certain criteria for removal from the database.
561
-     * By default, this will delete messages that:
562
-     * - are older than the value of the delete_threshold in months.
563
-     * - have a STS_ID other than EEM_Message::status_idle
564
-     *
565
-     * @param int $delete_threshold  This integer will be used to set the boundary for what messages are deleted in months.
566
-     * @return bool|false|int Either the number of records affected or false if there was an error (you can call
567
-     *                         $wpdb->last_error to find out what the error was.
568
-     */
569
-    public function delete_old_messages($delete_threshold = 6)
570
-    {
571
-        $number_deleted = 0;
572
-        /**
573
-         * Allows code to change the boundary for what messages are kept.
574
-         * Uses the value of the `delete_threshold` variable by default.
575
-         *
576
-         * @param int $seconds seconds that will be subtracted from the timestamp for now.
577
-         * @return int
578
-         */
579
-        $time_to_leave_alone = absint(
580
-            apply_filters(
581
-                'FHEE__EEM_Message__delete_old_messages__time_to_leave_alone',
582
-                ((int) $delete_threshold) * MONTH_IN_SECONDS
583
-            )
584
-        );
585
-
586
-
587
-        /**
588
-         * Allows code to change what message stati are ignored when deleting.
589
-         * Defaults to only ignore EEM_Message::status_idle messages.
590
-         *
591
-         * @param string $message_stati_to_keep  An array of message statuses that will be ignored when deleting.
592
-         */
593
-        $message_stati_to_keep = (array) apply_filters(
594
-            'FHEE__EEM_Message__delete_old_messages__message_stati_to_keep',
595
-            array(
596
-                EEM_Message::status_idle
597
-            )
598
-        );
599
-
600
-        // first get all the ids of messages being deleted
601
-        $message_ids_to_delete = EEM_Message::instance()->get_col(
602
-            array(
603
-                0 => array(
604
-                    'STS_ID' => array('NOT_IN', $message_stati_to_keep),
605
-                    'MSG_modified' => array('<', time() - $time_to_leave_alone)
606
-                ),
607
-                'limit' => apply_filters(
608
-                    'EEM_Message__delete_old_messages__limit',
609
-                    2000,
610
-                    $delete_threshold
611
-                )
612
-            )
613
-        );
614
-
615
-        if (! empty($message_ids_to_delete) && is_array($message_ids_to_delete)) {
616
-            global $wpdb;
617
-            $number_deleted = $wpdb->query('
17
+	/**
18
+	 * This priority indicates a message should be generated and sent ASAP
19
+	 *
20
+	 * @type int
21
+	 */
22
+	const priority_high = 10;
23
+
24
+
25
+	/**
26
+	 * This priority indicates a message should be generated ASAP and queued for sending.
27
+	 *
28
+	 * @type
29
+	 */
30
+	const priority_medium = 20;
31
+
32
+
33
+	/**
34
+	 * This priority indicates a message should be queued for generating.
35
+	 *
36
+	 * @type int
37
+	 */
38
+	const priority_low = 30;
39
+
40
+
41
+	/**
42
+	 * indicates this message was sent at the time modified
43
+	 */
44
+	const status_sent = 'MSN';
45
+
46
+
47
+	/**
48
+	 * indicates this message is waiting to be sent
49
+	 */
50
+	const status_idle = 'MID';
51
+
52
+
53
+	/**
54
+	 * indicates an attempt was a made to send this message
55
+	 * at the scheduled time, but it failed at the time modified.  This differs from MDO status in that it will ALWAYS
56
+	 * appear to the end user.
57
+	 */
58
+	const status_failed = 'MFL';
59
+
60
+
61
+	/**
62
+	 * indicates the message has been flagged for resending (at the time modified).
63
+	 */
64
+	const status_resend = 'MRS';
65
+
66
+
67
+	/**
68
+	 * indicates the message has been flagged for generation but has not been generated yet.  Messages always start as
69
+	 * this status when added to the queue.
70
+	 */
71
+	const status_incomplete = 'MIC';
72
+
73
+
74
+	/**
75
+	 * Indicates everything was generated fine for the message, however, the messenger was unable to send.
76
+	 * This status means that its possible to retry sending the message.
77
+	 */
78
+	const status_retry = 'MRT';
79
+
80
+
81
+	/**
82
+	 * This is used for more informational messages that may not indicate anything is broken but still cannot be
83
+	 * generated or sent correctly. An example of a message that would get flagged this way would be when a not
84
+	 * approved message was queued for generation, but at time of generation, the attached registration(s) are
85
+	 * approved. So the message queued for generation is no longer valid.  Messages for this status will only persist
86
+	 * in the db and be viewable in the message activity list table when the messages system is in debug mode.
87
+	 *
88
+	 * @see EEM_Message::debug()
89
+	 */
90
+	const status_debug_only = 'MDO';
91
+
92
+
93
+	/**
94
+	 * This status is given to messages it is processed by the messenger send method.
95
+	 * Messages with this status should rarely be seen in the Message List table, but if they are, that's usually
96
+	 * indicative of a PHP timeout or memory limit issue.
97
+	 */
98
+	const status_messenger_executing = 'MEX';
99
+
100
+
101
+	/**
102
+	 *    Private constructor to prevent direct creation.
103
+	 *
104
+	 * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and
105
+	 *                         any incoming timezone data that gets saved).  Note this just sends the timezone info to
106
+	 *                         the date time model field objects.  Default is null (and will be assumed using the set
107
+	 *                         timezone in the 'timezone_string' wp option)
108
+	 * @return EEM_Message
109
+	 */
110
+	protected function __construct($timezone = '')
111
+	{
112
+		$this->singular_item = __('Message', 'event_espresso');
113
+		$this->plural_item   = __('Messages', 'event_espresso');
114
+
115
+		// used for token generator
116
+		EE_Registry::instance()->load_helper('URL');
117
+
118
+		$this->_tables = array(
119
+			'Message' => new EE_Primary_Table('esp_message', 'MSG_ID'),
120
+		);
121
+
122
+		$allowed_priority = array(
123
+			self::priority_high   => __('high', 'event_espresso'),
124
+			self::priority_medium => __('medium', 'event_espresso'),
125
+			self::priority_low    => __('low', 'event_espresso'),
126
+		);
127
+
128
+		$this->_fields          = array(
129
+			'Message' => array(
130
+				'MSG_ID'             => new EE_Primary_Key_Int_Field('MSG_ID', __('Message ID', 'event_espresso')),
131
+				'MSG_token'          => new EE_Plain_Text_Field(
132
+					'MSG_token',
133
+					__(
134
+						'Unique Token used to represent this row in publicly viewable contexts (eg. a url).',
135
+						'event_espresso'
136
+					),
137
+					false,
138
+					EEH_URL::generate_unique_token()
139
+				),
140
+				'GRP_ID'             => new EE_Foreign_Key_Int_Field(
141
+					'GRP_ID',
142
+					__('Foreign key to the EEM_Message_Template_Group table.', 'event_espresso'),
143
+					true,
144
+					0,
145
+					'Message_Template_Group'
146
+				),
147
+				'TXN_ID'             => new EE_Foreign_Key_Int_Field(
148
+					'TXN_ID',
149
+					__(
150
+						'Foreign key to the related EE_Transaction.  This is required to give context for regenerating the specific message',
151
+						'event_espresso'
152
+					),
153
+					true,
154
+					0,
155
+					'Transaction'
156
+				),
157
+				'MSG_messenger'      => new EE_Plain_Text_Field(
158
+					'MSG_messenger',
159
+					__(
160
+						'Corresponds to the EE_messenger::name used to send this message. This will also be used to attempt any resending of the message.',
161
+						'event_espresso'
162
+					),
163
+					false,
164
+					'email'
165
+				),
166
+				'MSG_message_type'   => new EE_Plain_Text_Field(
167
+					'MSG_message_type',
168
+					__('Corresponds to the EE_message_type::name used to generate this message.', 'event_espresso'),
169
+					false,
170
+					'receipt'
171
+				),
172
+				'MSG_context'        => new EE_Plain_Text_Field('MSG_context', __('Context', 'event_espresso'), false),
173
+				'MSG_recipient_ID'   => new EE_Foreign_Key_Int_Field(
174
+					'MSG_recipient_ID',
175
+					__('Recipient ID', 'event_espresso'),
176
+					true,
177
+					null,
178
+					array('Registration', 'Attendee', 'WP_User')
179
+				),
180
+				'MSG_recipient_type' => new EE_Any_Foreign_Model_Name_Field(
181
+					'MSG_recipient_type',
182
+					__('Recipient Type', 'event_espresso'),
183
+					true,
184
+					null,
185
+					array('Registration', 'Attendee', 'WP_User')
186
+				),
187
+				'MSG_content'        => new EE_Maybe_Serialized_Text_Field(
188
+					'MSG_content',
189
+					__('Content', 'event_espresso'),
190
+					true,
191
+					''
192
+				),
193
+				'MSG_to'             => new EE_Maybe_Serialized_Text_Field(
194
+					'MSG_to',
195
+					__('Address To', 'event_espresso'),
196
+					true
197
+				),
198
+				'MSG_from'           => new EE_Maybe_Serialized_Text_Field(
199
+					'MSG_from',
200
+					__('Address From', 'event_espresso'),
201
+					true
202
+				),
203
+				'MSG_subject'        => new EE_Maybe_Serialized_Text_Field(
204
+					'MSG_subject',
205
+					__('Subject', 'event_espresso'),
206
+					true,
207
+					''
208
+				),
209
+				'MSG_priority'       => new EE_Enum_Integer_Field(
210
+					'MSG_priority',
211
+					__('Priority', 'event_espresso'),
212
+					false,
213
+					self::priority_low,
214
+					$allowed_priority
215
+				),
216
+				'STS_ID'             => new EE_Foreign_Key_String_Field(
217
+					'STS_ID',
218
+					__('Status', 'event_espresso'),
219
+					false,
220
+					self::status_incomplete,
221
+					'Status'
222
+				),
223
+				'MSG_created'        => new EE_Datetime_Field(
224
+					'MSG_created',
225
+					__('Created', 'event_espresso'),
226
+					false,
227
+					EE_Datetime_Field::now
228
+				),
229
+				'MSG_modified'       => new EE_Datetime_Field(
230
+					'MSG_modified',
231
+					__('Modified', 'event_espresso'),
232
+					true,
233
+					EE_Datetime_Field::now
234
+				),
235
+			),
236
+		);
237
+		$this->_model_relations = array(
238
+			'Attendee'               => new EE_Belongs_To_Any_Relation(),
239
+			'Registration'           => new EE_Belongs_To_Any_Relation(),
240
+			'WP_User'                => new EE_Belongs_To_Any_Relation(),
241
+			'Message_Template_Group' => new EE_Belongs_To_Relation(),
242
+			'Transaction'            => new EE_Belongs_To_Relation(),
243
+		);
244
+		parent::__construct($timezone);
245
+	}
246
+
247
+
248
+	/**
249
+	 * @return \EE_Message
250
+	 */
251
+	public function create_default_object()
252
+	{
253
+		/** @type EE_Message $message */
254
+		$message = parent::create_default_object();
255
+		if ($message instanceof EE_Message) {
256
+			return EE_Message_Factory::set_messenger_and_message_type($message);
257
+		}
258
+		return null;
259
+	}
260
+
261
+
262
+	/**
263
+	 * @param mixed $cols_n_values
264
+	 * @return \EE_Message
265
+	 */
266
+	public function instantiate_class_from_array_or_object($cols_n_values)
267
+	{
268
+		/** @type EE_Message $message */
269
+		$message = parent::instantiate_class_from_array_or_object($cols_n_values);
270
+		if ($message instanceof EE_Message) {
271
+			return EE_Message_Factory::set_messenger_and_message_type($message);
272
+		}
273
+		return null;
274
+	}
275
+
276
+
277
+	/**
278
+	 * Returns whether or not a message of that type was sent for a given attendee.
279
+	 *
280
+	 * @param EE_Attendee|int $attendee
281
+	 * @param string          $message_type the message type slug
282
+	 * @return boolean
283
+	 */
284
+	public function message_sent_for_attendee($attendee, $message_type)
285
+	{
286
+		$attendee_ID = EEM_Attendee::instance()->ensure_is_ID($attendee);
287
+		return $this->exists(array(
288
+			array(
289
+				'Attendee.ATT_ID'  => $attendee_ID,
290
+				'MSG_message_type' => $message_type,
291
+				'STS_ID'           => array('IN', $this->stati_indicating_sent()),
292
+			),
293
+		));
294
+	}
295
+
296
+
297
+	/**
298
+	 * Returns whether or not a message of that type was sent for a given registration
299
+	 *
300
+	 * @param EE_Registration|int $registration
301
+	 * @param string              $message_type the message type slug
302
+	 * @return boolean
303
+	 */
304
+	public function message_sent_for_registration($registration, $message_type)
305
+	{
306
+		$registrationID = EEM_Registration::instance()->ensure_is_ID($registration);
307
+		return $this->exists(array(
308
+			array(
309
+				'Registration.REG_ID' => $registrationID,
310
+				'MSG_message_type'    => $message_type,
311
+				'STS_ID'              => array('IN', $this->stati_indicating_sent()),
312
+			),
313
+		));
314
+	}
315
+
316
+
317
+	/**
318
+	 * This retrieves an EE_Message object from the db matching the given token string.
319
+	 *
320
+	 * @param string $token
321
+	 * @return EE_Message
322
+	 */
323
+	public function get_one_by_token($token)
324
+	{
325
+		return $this->get_one(array(
326
+			array(
327
+				'MSG_token' => $token,
328
+			),
329
+		));
330
+	}
331
+
332
+
333
+	/**
334
+	 * Returns stati that indicate the message HAS been sent
335
+	 *
336
+	 * @return array of strings for possible stati
337
+	 */
338
+	public function stati_indicating_sent()
339
+	{
340
+		return apply_filters('FHEE__EEM_Message__stati_indicating_sent', array(self::status_sent));
341
+	}
342
+
343
+
344
+	/**
345
+	 * Returns stati that indicate the message is waiting to be sent.
346
+	 *
347
+	 * @return array of strings for possible stati.
348
+	 */
349
+	public function stati_indicating_to_send()
350
+	{
351
+		return apply_filters(
352
+			'FHEE__EEM_Message__stati_indicating_to_send',
353
+			array(self::status_idle, self::status_resend)
354
+		);
355
+	}
356
+
357
+
358
+	/**
359
+	 * Returns stati that indicate the message has failed sending
360
+	 *
361
+	 * @return array  array of strings for possible stati.
362
+	 */
363
+	public function stati_indicating_failed_sending()
364
+	{
365
+		$failed_stati = array(
366
+			self::status_failed,
367
+			self::status_retry,
368
+			self::status_messenger_executing,
369
+		);
370
+		// if WP_DEBUG is set, then let's include debug_only fails
371
+		if (WP_DEBUG) {
372
+			$failed_stati[] = self::status_debug_only;
373
+		}
374
+		return apply_filters('FHEE__EEM_Message__stati_indicating_failed_sending', $failed_stati);
375
+	}
376
+
377
+
378
+	/**
379
+	 * Returns filterable array of all EEM_Message statuses.
380
+	 *
381
+	 * @return array
382
+	 */
383
+	public function all_statuses()
384
+	{
385
+		return apply_filters(
386
+			'FHEE__EEM_Message__all_statuses',
387
+			array(
388
+				EEM_Message::status_sent,
389
+				EEM_Message::status_incomplete,
390
+				EEM_Message::status_idle,
391
+				EEM_Message::status_resend,
392
+				EEM_Message::status_retry,
393
+				EEM_Message::status_failed,
394
+				EEM_Message::status_messenger_executing,
395
+				EEM_Message::status_debug_only,
396
+			)
397
+		);
398
+	}
399
+
400
+	/**
401
+	 * Detects any specific query variables in the request and uses those to setup appropriate
402
+	 * filter for any queries.
403
+	 *
404
+	 * @return array
405
+	 */
406
+	public function filter_by_query_params()
407
+	{
408
+		// expected possible query_vars, the key in this array matches an expected key in the request,
409
+		// the value, matches the corresponding EEM_Base child reference.
410
+		$expected_vars   = $this->_expected_vars_for_query_inject();
411
+		$query_params[0] = array();
412
+		foreach ($expected_vars as $request_key => $model_name) {
413
+			$request_value = EE_Registry::instance()->REQ->get($request_key);
414
+			if ($request_value) {
415
+				// special case
416
+				switch ($request_key) {
417
+					case '_REG_ID':
418
+						$query_params[0]['AND**filter_by']['OR**filter_by_REG_ID'] = array(
419
+							'Transaction.Registration.REG_ID' => $request_value,
420
+						);
421
+						break;
422
+					case 'EVT_ID':
423
+						$query_params[0]['AND**filter_by']['OR**filter_by_EVT_ID'] = array(
424
+							'Transaction.Registration.EVT_ID' => $request_value,
425
+						);
426
+						break;
427
+					default:
428
+						$query_params[0]['AND**filter_by'][ 'OR**filter_by_' . $request_key ][ $model_name . '.' . $request_key ] = $request_value;
429
+						break;
430
+				}
431
+			}
432
+		}
433
+		return $query_params;
434
+	}
435
+
436
+
437
+	/**
438
+	 * @return string
439
+	 */
440
+	public function get_pretty_label_for_results()
441
+	{
442
+		$expected_vars = $this->_expected_vars_for_query_inject();
443
+		$pretty_label  = '';
444
+		$label_parts   = array();
445
+		foreach ($expected_vars as $request_key => $model_name) {
446
+			$model = EE_Registry::instance()->load_model($model_name);
447
+			if ($model_field_value = EE_Registry::instance()->REQ->get($request_key)) {
448
+				switch ($request_key) {
449
+					case '_REG_ID':
450
+						$label_parts[] = sprintf(
451
+							esc_html__('Registration with the ID: %s', 'event_espresso'),
452
+							$model_field_value
453
+						);
454
+						break;
455
+					case 'ATT_ID':
456
+						/** @var EE_Attendee $attendee */
457
+						$attendee      = $model->get_one_by_ID($model_field_value);
458
+						$label_parts[] = $attendee instanceof EE_Attendee
459
+							? sprintf(esc_html__('Attendee %s', 'event_espresso'), $attendee->full_name())
460
+							: sprintf(esc_html__('Attendee ID: %s', 'event_espresso'), $model_field_value);
461
+						break;
462
+					case 'ID':
463
+						/** @var EE_WP_User $wpUser */
464
+						$wpUser        = $model->get_one_by_ID($model_field_value);
465
+						$label_parts[] = $wpUser instanceof EE_WP_User
466
+							? sprintf(esc_html__('WP User: %s', 'event_espresso'), $wpUser->name())
467
+							: sprintf(esc_html__('WP User ID: %s', 'event_espresso'), $model_field_value);
468
+						break;
469
+					case 'TXN_ID':
470
+						$label_parts[] = sprintf(
471
+							esc_html__('Transaction with the ID: %s', 'event_espresso'),
472
+							$model_field_value
473
+						);
474
+						break;
475
+					case 'EVT_ID':
476
+						/** @var EE_Event $Event */
477
+						$Event         = $model->get_one_by_ID($model_field_value);
478
+						$label_parts[] = $Event instanceof EE_Event
479
+							? sprintf(esc_html__('for the Event: %s', 'event_espresso'), $Event->name())
480
+							: sprintf(esc_html__('for the Event with ID: %s', 'event_espresso'), $model_field_value);
481
+						break;
482
+				}
483
+			}
484
+		}
485
+
486
+		if ($label_parts) {
487
+			// prepend to the last element of $label_parts an "and".
488
+			if (count($label_parts) > 1) {
489
+				$label_parts_index_to_prepend               = count($label_parts) - 1;
490
+				$label_parts[ $label_parts_index_to_prepend ] = 'and' . $label_parts[ $label_parts_index_to_prepend ];
491
+			}
492
+
493
+			$pretty_label .= sprintf(
494
+				esc_html_x(
495
+					'Showing messages for %s',
496
+					'A label for the messages returned in a query that are filtered by items in the query. This could be Transaction, Event, Attendee, Registration, or WP_User.',
497
+					'event_espresso'
498
+				),
499
+				implode(', ', $label_parts)
500
+			);
501
+		}
502
+		return $pretty_label;
503
+	}
504
+
505
+
506
+	/**
507
+	 * This returns the array of expected variables for the EEI_Query_Filter methods being implemented
508
+	 * The array is in the format:
509
+	 * array(
510
+	 *  {$field_name} => {$model_name}
511
+	 * );
512
+	 *
513
+	 * @since 4.9.0
514
+	 * @return array
515
+	 */
516
+	protected function _expected_vars_for_query_inject()
517
+	{
518
+		return array(
519
+			'_REG_ID' => 'Registration',
520
+			'ATT_ID'  => 'Attendee',
521
+			'ID'      => 'WP_User',
522
+			'TXN_ID'  => 'Transaction',
523
+			'EVT_ID'  => 'Event',
524
+		);
525
+	}
526
+
527
+
528
+	/**
529
+	 * This returns whether EEM_Message is in debug mode or not.
530
+	 * Currently "debug mode" is used to control the handling of the EEM_Message::debug_only status when
531
+	 * generating/sending messages. Debug mode can be set by either:
532
+	 * 1. Sending in a value for the $set_debug argument
533
+	 * 2. Defining `EE_DEBUG_MESSAGES` constant in wp-config.php
534
+	 * 3. Overriding the above via the provided filter.
535
+	 *
536
+	 * @param bool|null $set_debug      If provided, then the debug mode will be set internally until reset via the
537
+	 *                                  provided boolean. When no argument is provided (default null) then the debug
538
+	 *                                  mode will be returned.
539
+	 * @return bool         true means Messages is in debug mode.  false means messages system is not in debug mode.
540
+	 */
541
+	public static function debug($set_debug = null)
542
+	{
543
+		static $is_debugging = null;
544
+
545
+		// initialize (use constant if set).
546
+		if (is_null($set_debug) && is_null($is_debugging)) {
547
+			$is_debugging = defined('EE_DEBUG_MESSAGES') && EE_DEBUG_MESSAGES;
548
+		}
549
+
550
+		if (! is_null($set_debug)) {
551
+			$is_debugging = filter_var($set_debug, FILTER_VALIDATE_BOOLEAN);
552
+		}
553
+
554
+		// return filtered value
555
+		return apply_filters('FHEE__EEM_Message__debug', $is_debugging);
556
+	}
557
+
558
+
559
+	/**
560
+	 * Deletes old messages meeting certain criteria for removal from the database.
561
+	 * By default, this will delete messages that:
562
+	 * - are older than the value of the delete_threshold in months.
563
+	 * - have a STS_ID other than EEM_Message::status_idle
564
+	 *
565
+	 * @param int $delete_threshold  This integer will be used to set the boundary for what messages are deleted in months.
566
+	 * @return bool|false|int Either the number of records affected or false if there was an error (you can call
567
+	 *                         $wpdb->last_error to find out what the error was.
568
+	 */
569
+	public function delete_old_messages($delete_threshold = 6)
570
+	{
571
+		$number_deleted = 0;
572
+		/**
573
+		 * Allows code to change the boundary for what messages are kept.
574
+		 * Uses the value of the `delete_threshold` variable by default.
575
+		 *
576
+		 * @param int $seconds seconds that will be subtracted from the timestamp for now.
577
+		 * @return int
578
+		 */
579
+		$time_to_leave_alone = absint(
580
+			apply_filters(
581
+				'FHEE__EEM_Message__delete_old_messages__time_to_leave_alone',
582
+				((int) $delete_threshold) * MONTH_IN_SECONDS
583
+			)
584
+		);
585
+
586
+
587
+		/**
588
+		 * Allows code to change what message stati are ignored when deleting.
589
+		 * Defaults to only ignore EEM_Message::status_idle messages.
590
+		 *
591
+		 * @param string $message_stati_to_keep  An array of message statuses that will be ignored when deleting.
592
+		 */
593
+		$message_stati_to_keep = (array) apply_filters(
594
+			'FHEE__EEM_Message__delete_old_messages__message_stati_to_keep',
595
+			array(
596
+				EEM_Message::status_idle
597
+			)
598
+		);
599
+
600
+		// first get all the ids of messages being deleted
601
+		$message_ids_to_delete = EEM_Message::instance()->get_col(
602
+			array(
603
+				0 => array(
604
+					'STS_ID' => array('NOT_IN', $message_stati_to_keep),
605
+					'MSG_modified' => array('<', time() - $time_to_leave_alone)
606
+				),
607
+				'limit' => apply_filters(
608
+					'EEM_Message__delete_old_messages__limit',
609
+					2000,
610
+					$delete_threshold
611
+				)
612
+			)
613
+		);
614
+
615
+		if (! empty($message_ids_to_delete) && is_array($message_ids_to_delete)) {
616
+			global $wpdb;
617
+			$number_deleted = $wpdb->query('
618 618
                 DELETE
619 619
                 FROM ' . $this->table() . '
620 620
                 WHERE
621 621
                     MSG_ID IN (' . implode(",", $message_ids_to_delete) . ')
622 622
             ');
623
-        }
624
-
625
-        /**
626
-         * This will get called if the number of records deleted 0 or greater.  So a successful deletion is one where
627
-         * there were no errors.  An unsuccessful deletion is where there were errors.  Keep that in mind for the actions
628
-         * below.
629
-         */
630
-        if ($number_deleted !== false) {
631
-            do_action('AHEE__EEM_Message__delete_old_messages__after_successful_deletion', $message_ids_to_delete, $number_deleted);
632
-        } else {
633
-            do_action('AHEE__EEM_Message__delete_old_messages__after_deletion_fail', $message_ids_to_delete, $number_deleted);
634
-        }
635
-        return $number_deleted;
636
-    }
623
+		}
624
+
625
+		/**
626
+		 * This will get called if the number of records deleted 0 or greater.  So a successful deletion is one where
627
+		 * there were no errors.  An unsuccessful deletion is where there were errors.  Keep that in mind for the actions
628
+		 * below.
629
+		 */
630
+		if ($number_deleted !== false) {
631
+			do_action('AHEE__EEM_Message__delete_old_messages__after_successful_deletion', $message_ids_to_delete, $number_deleted);
632
+		} else {
633
+			do_action('AHEE__EEM_Message__delete_old_messages__after_deletion_fail', $message_ids_to_delete, $number_deleted);
634
+		}
635
+		return $number_deleted;
636
+	}
637 637
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Question_Option.model.php 1 patch
Indentation   +70 added lines, -70 removed lines patch added patch discarded remove patch
@@ -10,80 +10,80 @@
 block discarded – undo
10 10
 class EEM_Question_Option extends EEM_Soft_Delete_Base
11 11
 {
12 12
 
13
-    // private instance of the Attendee object
14
-    protected static $_instance = null;
13
+	// private instance of the Attendee object
14
+	protected static $_instance = null;
15 15
 
16 16
 
17
-    protected function __construct($timezone = '')
18
-    {
19
-        $this->singular_item = esc_html__('Question Option', 'event_espresso');
20
-        $this->plural_item   = esc_html__('Question Options', 'event_espresso');
17
+	protected function __construct($timezone = '')
18
+	{
19
+		$this->singular_item = esc_html__('Question Option', 'event_espresso');
20
+		$this->plural_item   = esc_html__('Question Options', 'event_espresso');
21 21
 
22
-        $this->_tables          = [
23
-            'Question_Option' => new EE_Primary_Table('esp_question_option', 'QSO_ID'),
24
-        ];
25
-        $this->_fields          = [
26
-            'Question_Option' => [
27
-                'QSO_ID'      => new EE_Primary_Key_Int_Field(
28
-                    'QSO_ID',
29
-                    esc_html__('Question Option ID', 'event_espresso')
30
-                ),
31
-                'QST_ID'      => new EE_Foreign_Key_Int_Field(
32
-                    'QST_ID',
33
-                    esc_html__('Question ID', 'event_espresso'),
34
-                    false,
35
-                    0,
36
-                    'Question'
37
-                ),
38
-                'QSO_deleted' => new EE_Trashed_Flag_Field(
39
-                    'QSO_deleted',
40
-                    esc_html__('Flag indicating Option was trashed', 'event_espresso'),
41
-                    false,
42
-                    false
43
-                ),
44
-                'QSO_desc'    => new EE_Post_Content_Field(
45
-                    'QSO_desc',
46
-                    esc_html__('Question Option Description', 'event_espresso'),
47
-                    false,
48
-                    ''
49
-                ),
50
-                'QSO_order'   => new EE_Integer_Field(
51
-                    'QSO_order',
52
-                    esc_html__('Question Option Order', 'event_espresso'),
53
-                    false,
54
-                    0
55
-                ),
56
-                'QSO_system'  => new EE_Plain_Text_Field(
57
-                    'QSO_system',
58
-                    esc_html__('Internal string ID for question option', 'event_espresso'),
59
-                    true,
60
-                    null
61
-                ),
62
-                'QSO_value'   => new EE_Plain_Text_Field(
63
-                    'QSO_value',
64
-                    esc_html__("Question Option Value", "event_espresso"),
65
-                    false,
66
-                    ''
67
-                ),
68
-            ],
69
-        ];
70
-        $this->_model_relations = [
71
-            'Question' => new EE_Belongs_To_Relation(),
72
-        ];
22
+		$this->_tables          = [
23
+			'Question_Option' => new EE_Primary_Table('esp_question_option', 'QSO_ID'),
24
+		];
25
+		$this->_fields          = [
26
+			'Question_Option' => [
27
+				'QSO_ID'      => new EE_Primary_Key_Int_Field(
28
+					'QSO_ID',
29
+					esc_html__('Question Option ID', 'event_espresso')
30
+				),
31
+				'QST_ID'      => new EE_Foreign_Key_Int_Field(
32
+					'QST_ID',
33
+					esc_html__('Question ID', 'event_espresso'),
34
+					false,
35
+					0,
36
+					'Question'
37
+				),
38
+				'QSO_deleted' => new EE_Trashed_Flag_Field(
39
+					'QSO_deleted',
40
+					esc_html__('Flag indicating Option was trashed', 'event_espresso'),
41
+					false,
42
+					false
43
+				),
44
+				'QSO_desc'    => new EE_Post_Content_Field(
45
+					'QSO_desc',
46
+					esc_html__('Question Option Description', 'event_espresso'),
47
+					false,
48
+					''
49
+				),
50
+				'QSO_order'   => new EE_Integer_Field(
51
+					'QSO_order',
52
+					esc_html__('Question Option Order', 'event_espresso'),
53
+					false,
54
+					0
55
+				),
56
+				'QSO_system'  => new EE_Plain_Text_Field(
57
+					'QSO_system',
58
+					esc_html__('Internal string ID for question option', 'event_espresso'),
59
+					true,
60
+					null
61
+				),
62
+				'QSO_value'   => new EE_Plain_Text_Field(
63
+					'QSO_value',
64
+					esc_html__("Question Option Value", "event_espresso"),
65
+					false,
66
+					''
67
+				),
68
+			],
69
+		];
70
+		$this->_model_relations = [
71
+			'Question' => new EE_Belongs_To_Relation(),
72
+		];
73 73
 
74
-        $this->_caps_slug              = 'questions';
75
-        $this->_model_chain_to_wp_user = 'Question';
74
+		$this->_caps_slug              = 'questions';
75
+		$this->_model_chain_to_wp_user = 'Question';
76 76
 
77
-        // this model is generally available for reading
78
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ]       =
79
-            new EE_Restriction_Generator_Public();
80
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] =
81
-            new EE_Restriction_Generator_Reg_Form('QSO_system');
82
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ]       =
83
-            new EE_Restriction_Generator_Reg_Form('QSO_system');
84
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ]     =
85
-            new EE_Restriction_Generator_Reg_Form('QSO_system');
77
+		// this model is generally available for reading
78
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ]       =
79
+			new EE_Restriction_Generator_Public();
80
+		$this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] =
81
+			new EE_Restriction_Generator_Reg_Form('QSO_system');
82
+		$this->_cap_restriction_generators[ EEM_Base::caps_edit ]       =
83
+			new EE_Restriction_Generator_Reg_Form('QSO_system');
84
+		$this->_cap_restriction_generators[ EEM_Base::caps_delete ]     =
85
+			new EE_Restriction_Generator_Reg_Form('QSO_system');
86 86
 
87
-        parent::__construct($timezone);
88
-    }
87
+		parent::__construct($timezone);
88
+	}
89 89
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Extra_Meta.model.php 1 patch
Indentation   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -17,33 +17,33 @@
 block discarded – undo
17 17
 class EEM_Extra_Meta extends EEM_Base
18 18
 {
19 19
 
20
-    // private instance of the Attendee object
21
-    protected static $_instance = null;
20
+	// private instance of the Attendee object
21
+	protected static $_instance = null;
22 22
 
23
-    protected function __construct($timezone = '')
24
-    {
25
-        $this->singular_item = __('Extra Meta', 'event_espresso');
26
-        $this->plural_item = __('Extra Metas', 'event_espresso');
27
-        $this->_tables = array(
28
-            'Extra_Meta' => new EE_Primary_Table('esp_extra_meta', 'EXM_ID')
29
-        );
30
-        $models_this_can_attach_to = array_keys(EE_Registry::instance()->non_abstract_db_models);
31
-        $this->_fields = array(
32
-            'Extra_Meta' => array(
33
-                'EXM_ID' => new EE_Primary_Key_Int_Field('EXM_ID', __("Extra Meta ID", "event_espresso")),
34
-                'OBJ_ID' => new EE_Foreign_Key_Int_Field('OBJ_ID', __("Primary Key of Attached Thing", "event_espresso"), false, 0, $models_this_can_attach_to),
35
-                'EXM_type' => new EE_Any_Foreign_Model_Name_Field('EXM_type', __("Model of Attached Thing", "event_espresso"), false, 'Transaction', $models_this_can_attach_to),
36
-                'EXM_key' => new EE_Plain_Text_Field('EXM_key', __("Meta Key", "event_espresso"), false, ''),
37
-                'EXM_value' => new EE_Maybe_Serialized_Text_Field('EXM_value', __("Meta Value", "event_espresso"), true)
23
+	protected function __construct($timezone = '')
24
+	{
25
+		$this->singular_item = __('Extra Meta', 'event_espresso');
26
+		$this->plural_item = __('Extra Metas', 'event_espresso');
27
+		$this->_tables = array(
28
+			'Extra_Meta' => new EE_Primary_Table('esp_extra_meta', 'EXM_ID')
29
+		);
30
+		$models_this_can_attach_to = array_keys(EE_Registry::instance()->non_abstract_db_models);
31
+		$this->_fields = array(
32
+			'Extra_Meta' => array(
33
+				'EXM_ID' => new EE_Primary_Key_Int_Field('EXM_ID', __("Extra Meta ID", "event_espresso")),
34
+				'OBJ_ID' => new EE_Foreign_Key_Int_Field('OBJ_ID', __("Primary Key of Attached Thing", "event_espresso"), false, 0, $models_this_can_attach_to),
35
+				'EXM_type' => new EE_Any_Foreign_Model_Name_Field('EXM_type', __("Model of Attached Thing", "event_espresso"), false, 'Transaction', $models_this_can_attach_to),
36
+				'EXM_key' => new EE_Plain_Text_Field('EXM_key', __("Meta Key", "event_espresso"), false, ''),
37
+				'EXM_value' => new EE_Maybe_Serialized_Text_Field('EXM_value', __("Meta Value", "event_espresso"), true)
38 38
 
39
-            ));
40
-        $this->_model_relations = array();
41
-        foreach ($models_this_can_attach_to as $model) {
42
-            $this->_model_relations[ $model ] = new EE_Belongs_To_Any_Relation();
43
-        }
44
-        foreach ($this->cap_contexts_to_cap_action_map() as $cap_context => $action) {
45
-            $this->_cap_restriction_generators[ $cap_context ] = new EE_Restriction_Generator_Meta('EXM_key', 'EXM_value');
46
-        }
47
-        parent::__construct($timezone);
48
-    }
39
+			));
40
+		$this->_model_relations = array();
41
+		foreach ($models_this_can_attach_to as $model) {
42
+			$this->_model_relations[ $model ] = new EE_Belongs_To_Any_Relation();
43
+		}
44
+		foreach ($this->cap_contexts_to_cap_action_map() as $cap_context => $action) {
45
+			$this->_cap_restriction_generators[ $cap_context ] = new EE_Restriction_Generator_Meta('EXM_key', 'EXM_value');
46
+		}
47
+		parent::__construct($timezone);
48
+	}
49 49
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Registration.model.php 1 patch
Indentation   +868 added lines, -868 removed lines patch added patch discarded remove patch
@@ -14,817 +14,817 @@  discard block
 block discarded – undo
14 14
 class EEM_Registration extends EEM_Soft_Delete_Base
15 15
 {
16 16
 
17
-    /**
18
-     * @var EEM_Registration $_instance
19
-     */
20
-    protected static $_instance;
21
-
22
-    /**
23
-     * Keys are the status IDs for registrations (eg, RAP, RCN, etc), and the values
24
-     * are status codes (eg, approved, cancelled, etc)
25
-     *
26
-     * @var array
27
-     */
28
-    private static $_reg_status;
29
-
30
-    /**
31
-     * The value of REG_count for a primary registrant
32
-     */
33
-    const PRIMARY_REGISTRANT_COUNT = 1;
34
-
35
-    /**
36
-     * Status ID (STS_ID on esp_status table) to indicate an INCOMPLETE registration.
37
-     * Initial status for registrations when they are first created
38
-     * Payments are NOT allowed.
39
-     * Automatically toggled to whatever the default Event registration status is upon completion of the attendee
40
-     * information reg step NO space reserved. Registration is NOT active
41
-     */
42
-    const status_id_incomplete = 'RIC';
43
-
44
-    /**
45
-     * Status ID (STS_ID on esp_status table) to indicate an UNAPPROVED registration.
46
-     * Payments are NOT allowed.
47
-     * Event Admin must manually toggle STS_ID for it to change
48
-     * No space reserved.
49
-     * Registration is active
50
-     */
51
-    const status_id_not_approved = 'RNA';
52
-
53
-    /**
54
-     * Status ID (STS_ID on esp_status table) to indicate registration is PENDING_PAYMENT .
55
-     * Payments are allowed.
56
-     * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee
57
-     * No space reserved.
58
-     * Registration is active
59
-     */
60
-    const status_id_pending_payment = 'RPP';
61
-
62
-    /**
63
-     * Status ID (STS_ID on esp_status table) to indicate registration is on the WAIT_LIST .
64
-     * Payments are allowed.
65
-     * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee
66
-     * No space reserved.
67
-     * Registration is active
68
-     */
69
-    const status_id_wait_list = 'RWL';
70
-
71
-    /**
72
-     * Status ID (STS_ID on esp_status table) to indicate an APPROVED registration.
73
-     * the TXN may or may not be completed ( paid in full )
74
-     * Payments are allowed.
75
-     * A space IS reserved.
76
-     * Registration is active
77
-     */
78
-    const status_id_approved = 'RAP';
79
-
80
-    /**
81
-     * Status ID (STS_ID on esp_status table) to indicate a registration was CANCELLED by the attendee.
82
-     * Payments are NOT allowed.
83
-     * NO space reserved.
84
-     * Registration is NOT active
85
-     */
86
-    const status_id_cancelled = 'RCN';
87
-
88
-    /**
89
-     * Status ID (STS_ID on esp_status table) to indicate a registration was DECLINED by the Event Admin
90
-     * Payments are NOT allowed.
91
-     * No space reserved.
92
-     * Registration is NOT active
93
-     */
94
-    const status_id_declined = 'RDC';
95
-
96
-    /**
97
-     * @var TableAnalysis $table_analysis
98
-     */
99
-    protected $_table_analysis;
100
-
101
-
102
-    /**
103
-     *    private constructor to prevent direct creation
104
-     *
105
-     * @Constructor
106
-     * @access protected
107
-     * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any
108
-     *                         incoming timezone data that gets saved). Note this just sends the timezone info to the
109
-     *                         date time model field objects.  Default is NULL (and will be assumed using the set
110
-     *                         timezone in the 'timezone_string' wp option)
111
-     * @throws EE_Error
112
-     */
113
-    protected function __construct($timezone = '')
114
-    {
115
-        $this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
116
-        $this->singular_item = esc_html__('Registration', 'event_espresso');
117
-        $this->plural_item = esc_html__('Registrations', 'event_espresso');
118
-        $this->_tables = array(
119
-            'Registration' => new EE_Primary_Table('esp_registration', 'REG_ID'),
120
-        );
121
-        $this->_fields = array(
122
-            'Registration' => array(
123
-                'REG_ID' => new EE_Primary_Key_Int_Field(
124
-                    'REG_ID',
125
-                    esc_html__('Registration ID', 'event_espresso')
126
-                ),
127
-                'EVT_ID' => new EE_Foreign_Key_Int_Field(
128
-                    'EVT_ID',
129
-                    esc_html__('Event ID', 'event_espresso'),
130
-                    false,
131
-                    0,
132
-                    'Event'
133
-                ),
134
-                'ATT_ID' => new EE_Foreign_Key_Int_Field(
135
-                    'ATT_ID',
136
-                    esc_html__('Attendee ID', 'event_espresso'),
137
-                    false,
138
-                    0,
139
-                    'Attendee'
140
-                ),
141
-                'TXN_ID' => new EE_Foreign_Key_Int_Field(
142
-                    'TXN_ID',
143
-                    esc_html__('Transaction ID', 'event_espresso'),
144
-                    false,
145
-                    0,
146
-                    'Transaction'
147
-                ),
148
-                'TKT_ID' => new EE_Foreign_Key_Int_Field(
149
-                    'TKT_ID',
150
-                    esc_html__('Ticket ID', 'event_espresso'),
151
-                    false,
152
-                    0,
153
-                    'Ticket'
154
-                ),
155
-                'STS_ID' => new EE_Foreign_Key_String_Field(
156
-                    'STS_ID',
157
-                    esc_html__('Status ID', 'event_espresso'),
158
-                    false,
159
-                    EEM_Registration::status_id_incomplete,
160
-                    'Status'
161
-                ),
162
-                'REG_date' => new EE_Datetime_Field(
163
-                    'REG_date',
164
-                    esc_html__('Time registration occurred', 'event_espresso'),
165
-                    false,
166
-                    EE_Datetime_Field::now,
167
-                    $timezone
168
-                ),
169
-                'REG_final_price' => new EE_Money_Field(
170
-                    'REG_final_price',
171
-                    esc_html__('Registration\'s share of the transaction total', 'event_espresso'),
172
-                    false,
173
-                    0
174
-                ),
175
-                'REG_paid' => new EE_Money_Field(
176
-                    'REG_paid',
177
-                    esc_html__('Amount paid to date towards registration', 'event_espresso'),
178
-                    false,
179
-                    0
180
-                ),
181
-                'REG_session' => new EE_Plain_Text_Field(
182
-                    'REG_session',
183
-                    esc_html__('Session ID of registration', 'event_espresso'),
184
-                    false,
185
-                    ''
186
-                ),
187
-                'REG_code' => new EE_Plain_Text_Field(
188
-                    'REG_code',
189
-                    esc_html__('Unique Code for this registration', 'event_espresso'),
190
-                    false,
191
-                    ''
192
-                ),
193
-                'REG_url_link' => new EE_Plain_Text_Field(
194
-                    'REG_url_link',
195
-                    esc_html__('String to be used in URL for identifying registration', 'event_espresso'),
196
-                    false,
197
-                    ''
198
-                ),
199
-                'REG_count' => new EE_Integer_Field(
200
-                    'REG_count',
201
-                    esc_html__('Count of this registration in the group registration ', 'event_espresso'),
202
-                    true,
203
-                    1
204
-                ),
205
-                'REG_group_size' => new EE_Integer_Field(
206
-                    'REG_group_size',
207
-                    esc_html__('Number of registrations on this group', 'event_espresso'),
208
-                    false,
209
-                    1
210
-                ),
211
-                'REG_att_is_going' => new EE_Boolean_Field(
212
-                    'REG_att_is_going',
213
-                    esc_html__('Flag indicating the registrant plans on attending', 'event_espresso'),
214
-                    false,
215
-                    false
216
-                ),
217
-                'REG_deleted' => new EE_Trashed_Flag_Field(
218
-                    'REG_deleted',
219
-                    esc_html__('Flag indicating if registration has been archived or not.', 'event_espresso'),
220
-                    false,
221
-                    false
222
-                ),
223
-            ),
224
-        );
225
-        $this->_model_relations = array(
226
-            'Event' => new EE_Belongs_To_Relation(),
227
-            'Attendee' => new EE_Belongs_To_Relation(),
228
-            'Transaction' => new EE_Belongs_To_Relation(),
229
-            'Ticket' => new EE_Belongs_To_Relation(),
230
-            'Status' => new EE_Belongs_To_Relation(),
231
-            'Answer' => new EE_Has_Many_Relation(),
232
-            'Checkin' => new EE_Has_Many_Relation(),
233
-            'Registration_Payment' => new EE_Has_Many_Relation(),
234
-            'Payment' => new EE_HABTM_Relation('Registration_Payment'),
235
-            'Message' => new EE_Has_Many_Any_Relation(false)
236
-            // allow deletes even if there are messages in the queue related
237
-        );
238
-        $this->_model_chain_to_wp_user = 'Event';
239
-        parent::__construct($timezone);
240
-    }
241
-
242
-
243
-    /**
244
-     * a list of ALL valid registration statuses currently in use within the system
245
-     * generated by combining the filterable active and inactive reg status arrays
246
-     *
247
-     * @return array
248
-     */
249
-    public static function reg_statuses()
250
-    {
251
-        return array_unique(
252
-            array_merge(
253
-                EEM_Registration::active_reg_statuses(),
254
-                EEM_Registration::inactive_reg_statuses()
255
-            )
256
-        );
257
-    }
258
-
259
-
260
-    /**
261
-     * reg_statuses_that_allow_payment
262
-     * a filterable list of registration statuses that allow a registrant to make a payment
263
-     *
264
-     * @access public
265
-     * @return array
266
-     */
267
-    public static function reg_statuses_that_allow_payment()
268
-    {
269
-        return apply_filters(
270
-            'FHEE__EEM_Registration__reg_statuses_that_allow_payment',
271
-            array(
272
-                EEM_Registration::status_id_approved,
273
-                EEM_Registration::status_id_pending_payment,
274
-            )
275
-        );
276
-    }
277
-
278
-
279
-    /**
280
-     * active_reg_statuses
281
-     * a filterable list of registration statuses that are considered active
282
-     *
283
-     * @access public
284
-     * @return array
285
-     */
286
-    public static function active_reg_statuses()
287
-    {
288
-        return apply_filters(
289
-            'FHEE__EEM_Registration__active_reg_statuses',
290
-            array(
291
-                EEM_Registration::status_id_approved,
292
-                EEM_Registration::status_id_pending_payment,
293
-                EEM_Registration::status_id_wait_list,
294
-                EEM_Registration::status_id_not_approved,
295
-            )
296
-        );
297
-    }
298
-
299
-
300
-    /**
301
-     * inactive_reg_statuses
302
-     * a filterable list of registration statuses that are not considered active
303
-     *
304
-     * @access public
305
-     * @return array
306
-     */
307
-    public static function inactive_reg_statuses()
308
-    {
309
-        return apply_filters(
310
-            'FHEE__EEM_Registration__inactive_reg_statuses',
311
-            array(
312
-                EEM_Registration::status_id_incomplete,
313
-                EEM_Registration::status_id_cancelled,
314
-                EEM_Registration::status_id_declined,
315
-            )
316
-        );
317
-    }
318
-
319
-
320
-    /**
321
-     *    closed_reg_statuses
322
-     *    a filterable list of registration statuses that are considered "closed"
323
-     * meaning they should not be considered in any calculations involving monies owing
324
-     *
325
-     * @access public
326
-     * @return array
327
-     */
328
-    public static function closed_reg_statuses()
329
-    {
330
-        return apply_filters(
331
-            'FHEE__EEM_Registration__closed_reg_statuses',
332
-            array(
333
-                EEM_Registration::status_id_cancelled,
334
-                EEM_Registration::status_id_declined,
335
-                EEM_Registration::status_id_wait_list,
336
-            )
337
-        );
338
-    }
339
-
340
-
341
-    /**
342
-     *        get list of registration statuses
343
-     *
344
-     * @access public
345
-     * @param array $exclude The status ids to exclude from the returned results
346
-     * @param bool $translated If true will return the values as singular localized strings
347
-     * @return array
348
-     * @throws EE_Error
349
-     */
350
-    public static function reg_status_array($exclude = array(), $translated = false)
351
-    {
352
-        EEM_Registration::instance()->_get_registration_status_array($exclude);
353
-        return $translated
354
-            ? EEM_Status::instance()->localized_status(self::$_reg_status, false, 'sentence')
355
-            : self::$_reg_status;
356
-    }
357
-
358
-
359
-    /**
360
-     *    get list of registration statuses
361
-     *
362
-     * @access private
363
-     * @param array $exclude
364
-     * @return void
365
-     * @throws EE_Error
366
-     */
367
-    private function _get_registration_status_array($exclude = array())
368
-    {
369
-        // in the very rare circumstance that we are deleting a model's table's data
370
-        // and the table hasn't actually been created, this could have an error
371
-        /** @type WPDB $wpdb */
372
-        global $wpdb;
373
-        if ($this->_get_table_analysis()->tableExists($wpdb->prefix . 'esp_status')) {
374
-            $results = $wpdb->get_results(
375
-                "SELECT STS_ID, STS_code FROM {$wpdb->prefix}esp_status WHERE STS_type = 'registration'"
376
-            );
377
-            self::$_reg_status = array();
378
-            foreach ($results as $status) {
379
-                if (!in_array($status->STS_ID, $exclude, true)) {
380
-                    self::$_reg_status[ $status->STS_ID ] = $status->STS_code;
381
-                }
382
-            }
383
-        }
384
-    }
385
-
386
-
387
-    /**
388
-     * Gets the injected table analyzer, or throws an exception
389
-     *
390
-     * @return TableAnalysis
391
-     * @throws EE_Error
392
-     */
393
-    protected function _get_table_analysis()
394
-    {
395
-        if ($this->_table_analysis instanceof TableAnalysis) {
396
-            return $this->_table_analysis;
397
-        }
398
-        throw new EE_Error(
399
-            sprintf(
400
-                esc_html__('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
401
-                get_class($this)
402
-            )
403
-        );
404
-    }
405
-
406
-
407
-    /**
408
-     * This returns a wpdb->results array of all registration date month and years matching the incoming query params
409
-     * and grouped by month and year.
410
-     *
411
-     * @param  array $where_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
412
-     * @return array
413
-     * @throws EE_Error
414
-     */
415
-    public function get_reg_months_and_years($where_params)
416
-    {
417
-        $query_params[0] = $where_params;
418
-        $query_params['group_by'] = array('reg_year', 'reg_month');
419
-        $query_params['order_by'] = array('REG_date' => 'DESC');
420
-        $columns_to_select = array(
421
-            'reg_year' => array('YEAR(REG_date)', '%s'),
422
-            'reg_month' => array('MONTHNAME(REG_date)', '%s'),
423
-        );
424
-        return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select);
425
-    }
426
-
427
-
428
-    /**
429
-     * retrieve ALL registrations for a particular Attendee from db
430
-     *
431
-     * @param int $ATT_ID
432
-     * @return EE_Base_Class[]|EE_Registration[]|null
433
-     * @throws EE_Error
434
-     */
435
-    public function get_all_registrations_for_attendee($ATT_ID = 0)
436
-    {
437
-        if (!$ATT_ID) {
438
-            return null;
439
-        }
440
-        return $this->get_all(array(array('ATT_ID' => $ATT_ID)));
441
-    }
442
-
443
-
444
-    /**
445
-     * Gets a registration given their REG_url_link. Yes, this should usually
446
-     * be passed via a GET parameter.
447
-     *
448
-     * @param string $REG_url_link
449
-     * @return EE_Base_Class|EE_Registration|null
450
-     * @throws EE_Error
451
-     */
452
-    public function get_registration_for_reg_url_link($REG_url_link)
453
-    {
454
-        if (!$REG_url_link) {
455
-            return null;
456
-        }
457
-        return $this->get_one(array(array('REG_url_link' => $REG_url_link)));
458
-    }
459
-
460
-
461
-    /**
462
-     *        retrieve registration for a specific transaction attendee from db
463
-     *
464
-     * @access        public
465
-     * @param    int $TXN_ID
466
-     * @param    int $ATT_ID
467
-     * @param    int $att_nmbr in case the ATT_ID is the same for multiple registrations (same details used) then the
468
-     *                         attendee number is required
469
-     * @return        mixed        array on success, FALSE on fail
470
-     * @throws EE_Error
471
-     */
472
-    public function get_registration_for_transaction_attendee($TXN_ID = 0, $ATT_ID = 0, $att_nmbr = 0)
473
-    {
474
-        return $this->get_one(array(
475
-            array(
476
-                'TXN_ID' => $TXN_ID,
477
-                'ATT_ID' => $ATT_ID,
478
-            ),
479
-            'limit' => array(min($att_nmbr - 1, 0), 1),
480
-        ));
481
-    }
482
-
483
-
484
-    /**
485
-     *        get the number of registrations per day  for the Registration Admin page Reports Tab.
486
-     *        (doesn't utilize models because it's a fairly specialized query)
487
-     *
488
-     * @access        public
489
-     * @param $period string which can be passed to php's strtotime function (eg "-1 month")
490
-     * @return stdClass[] with properties regDate and total
491
-     * @throws EE_Error
492
-     */
493
-    public function get_registrations_per_day_report($period = '-1 month')
494
-    {
495
-        $sql_date = $this->convert_datetime_for_query(
496
-            'REG_date',
497
-            date('Y-m-d H:i:s', strtotime($period)),
498
-            'Y-m-d H:i:s',
499
-            'UTC'
500
-        );
501
-        $where = array(
502
-            'REG_date' => array('>=', $sql_date),
503
-            'STS_ID' => array('!=', EEM_Registration::status_id_incomplete),
504
-        );
505
-        if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_day_report')) {
506
-            $where['Event.EVT_wp_user'] = get_current_user_id();
507
-        }
508
-        $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'REG_date');
509
-        $results = $this->_get_all_wpdb_results(
510
-            array(
511
-                $where,
512
-                'group_by' => 'regDate',
513
-                'order_by' => array('REG_date' => 'ASC'),
514
-            ),
515
-            OBJECT,
516
-            array(
517
-                'regDate' => array('DATE(' . $query_interval . ')', '%s'),
518
-                'total' => array('count(REG_ID)', '%d'),
519
-            )
520
-        );
521
-        return $results;
522
-    }
523
-
524
-
525
-    /**
526
-     * Get the number of registrations per day including the count of registrations for each Registration Status.
527
-     * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results.
528
-     *
529
-     * @param string $period
530
-     * @return stdClass[] with properties Registration_REG_date and a column for each registration status as the STS_ID
531
-     * @throws EE_Error
532
-     *                    (i.e. RAP)
533
-     */
534
-    public function get_registrations_per_day_and_per_status_report($period = '-1 month')
535
-    {
536
-        global $wpdb;
537
-        $registration_table = $wpdb->prefix . 'esp_registration';
538
-        $event_table = $wpdb->posts;
539
-        $sql_date = date('Y-m-d H:i:s', strtotime($period));
540
-        // prepare the query interval for displaying offset
541
-        $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'dates.REG_date');
542
-        // inner date query
543
-        $inner_date_query = "SELECT DISTINCT REG_date from {$registration_table} ";
544
-        $inner_where = ' WHERE';
545
-        // exclude events not authored by user if permissions in effect
546
-        if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
547
-            $inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID";
548
-            $inner_where .= ' post_author = ' . get_current_user_id() . ' AND';
549
-        }
550
-        $inner_where .= " REG_date >= '{$sql_date}'";
551
-        $inner_date_query .= $inner_where;
552
-        // start main query
553
-        $select = "SELECT DATE({$query_interval}) as Registration_REG_date, ";
554
-        $join = '';
555
-        $join_parts = array();
556
-        $select_parts = array();
557
-        // loop through registration stati to do parts for each status.
558
-        foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) {
559
-            if ($STS_ID === EEM_Registration::status_id_incomplete) {
560
-                continue;
561
-            }
562
-            $select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}";
563
-            $join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.REG_date = dates.REG_date AND {$STS_code}.STS_ID = '{$STS_ID}'";
564
-        }
565
-        // setup the selects
566
-        $select .= implode(', ', $select_parts);
567
-        $select .= " FROM ($inner_date_query) AS dates LEFT JOIN ";
568
-        // setup the joins
569
-        $join .= implode(' LEFT JOIN ', $join_parts);
570
-        // now let's put it all together
571
-        $query = $select . $join . ' GROUP BY Registration_REG_date';
572
-        // and execute it
573
-        return $wpdb->get_results($query, ARRAY_A);
574
-    }
575
-
576
-
577
-    /**
578
-     *        get the number of registrations per event  for the Registration Admin page Reports Tab
579
-     *
580
-     * @access        public
581
-     * @param $period string which can be passed to php's strtotime function (eg "-1 month")
582
-     * @return stdClass[] each with properties event_name, reg_limit, and total
583
-     * @throws EE_Error
584
-     */
585
-    public function get_registrations_per_event_report($period = '-1 month')
586
-    {
587
-        $date_sql = $this->convert_datetime_for_query(
588
-            'REG_date',
589
-            date('Y-m-d H:i:s', strtotime($period)),
590
-            'Y-m-d H:i:s',
591
-            'UTC'
592
-        );
593
-        $where = array(
594
-            'REG_date' => array('>=', $date_sql),
595
-            'STS_ID' => array('!=', EEM_Registration::status_id_incomplete),
596
-        );
597
-        if (
598
-            !EE_Registry::instance()->CAP->current_user_can(
599
-                'ee_read_others_registrations',
600
-                'reg_per_event_report'
601
-            )
602
-        ) {
603
-            $where['Event.EVT_wp_user'] = get_current_user_id();
604
-        }
605
-        $results = $this->_get_all_wpdb_results(
606
-            array(
607
-            $where,
608
-            'group_by' => 'Event.EVT_name',
609
-            'order_by' => 'Event.EVT_name',
610
-            'limit' => array(0, 24),
611
-            ),
612
-            OBJECT,
613
-            array(
614
-                'event_name' => array('Event_CPT.post_title', '%s'),
615
-                'total' => array('COUNT(REG_ID)', '%s'),
616
-            )
617
-        );
618
-        return $results;
619
-    }
620
-
621
-
622
-    /**
623
-     * Get the number of registrations per event grouped by registration status.
624
-     * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results.
625
-     *
626
-     * @param string $period
627
-     * @return stdClass[] with properties `Registration_Event` and a column for each registration status as the STS_ID
628
-     * @throws EE_Error
629
-     *                    (i.e. RAP)
630
-     */
631
-    public function get_registrations_per_event_and_per_status_report($period = '-1 month')
632
-    {
633
-        global $wpdb;
634
-        $registration_table = $wpdb->prefix . 'esp_registration';
635
-        $event_table = $wpdb->posts;
636
-        $sql_date = date('Y-m-d H:i:s', strtotime($period));
637
-        // inner date query
638
-        $inner_date_query = "SELECT DISTINCT EVT_ID, REG_date from $registration_table ";
639
-        $inner_where = ' WHERE';
640
-        // exclude events not authored by user if permissions in effect
641
-        if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
642
-            $inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID";
643
-            $inner_where .= ' post_author = ' . get_current_user_id() . ' AND';
644
-        }
645
-        $inner_where .= " REG_date >= '{$sql_date}'";
646
-        $inner_date_query .= $inner_where;
647
-        // build main query
648
-        $select = 'SELECT Event.post_title as Registration_Event, ';
649
-        $join = '';
650
-        $join_parts = array();
651
-        $select_parts = array();
652
-        // loop through registration stati to do parts for each status.
653
-        foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) {
654
-            if ($STS_ID === EEM_Registration::status_id_incomplete) {
655
-                continue;
656
-            }
657
-            $select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}";
658
-            $join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.EVT_ID = dates.EVT_ID AND {$STS_code}.STS_ID = '{$STS_ID}' AND {$STS_code}.REG_date = dates.REG_date";
659
-        }
660
-        // setup the selects
661
-        $select .= implode(', ', $select_parts);
662
-        $select .= " FROM ($inner_date_query) AS dates LEFT JOIN $event_table as Event ON Event.ID = dates.EVT_ID LEFT JOIN ";
663
-        // setup remaining joins
664
-        $join .= implode(' LEFT JOIN ', $join_parts);
665
-        // now put it all together
666
-        $query = $select . $join . ' GROUP BY Registration_Event';
667
-        // and execute
668
-        return $wpdb->get_results($query, ARRAY_A);
669
-    }
670
-
671
-
672
-    /**
673
-     * Returns the EE_Registration of the primary attendee on the transaction id provided
674
-     *
675
-     * @param int $TXN_ID
676
-     * @return EE_Base_Class|EE_Registration|null
677
-     * @throws EE_Error
678
-     */
679
-    public function get_primary_registration_for_transaction_ID($TXN_ID = 0)
680
-    {
681
-        if (!$TXN_ID) {
682
-            return null;
683
-        }
684
-        return $this->get_one(array(
685
-            array(
686
-                'TXN_ID' => $TXN_ID,
687
-                'REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT,
688
-            ),
689
-        ));
690
-    }
691
-
692
-
693
-    /**
694
-     *        get_event_registration_count
695
-     *
696
-     * @access public
697
-     * @param int $EVT_ID
698
-     * @param boolean $for_incomplete_payments
699
-     * @return int
700
-     * @throws EE_Error
701
-     */
702
-    public function get_event_registration_count($EVT_ID, $for_incomplete_payments = false)
703
-    {
704
-        // we only count approved registrations towards registration limits
705
-        $query_params = array(array('EVT_ID' => $EVT_ID, 'STS_ID' => self::status_id_approved));
706
-        if ($for_incomplete_payments) {
707
-            $query_params[0]['Transaction.STS_ID'] = array('!=', EEM_Transaction::complete_status_code);
708
-        }
709
-        return $this->count($query_params);
710
-    }
711
-
712
-
713
-    /**
714
-     * Deletes all registrations with no transactions. Note that this needs to be very efficient
715
-     * and so it uses wpdb directly. Also, we can't put a limit on this because MySQL doesn't allow a limit on a delete
716
-     * when joining tables like this.
717
-     *
718
-     * @global WPDB $wpdb
719
-     * @return int number deleted
720
-     * @throws EE_Error
721
-     */
722
-    public function delete_registrations_with_no_transaction()
723
-    {
724
-        /** @type WPDB $wpdb */
725
-        global $wpdb;
726
-        return $wpdb->query(
727
-            'DELETE r FROM '
728
-            . $this->table()
729
-            . ' r LEFT JOIN '
730
-            . EEM_Transaction::instance()->table()
731
-            . ' t ON r.TXN_ID = t.TXN_ID WHERE t.TXN_ID IS NULL'
732
-        );
733
-    }
734
-
735
-
736
-    /**
737
-     *  Count registrations checked into (or out of) a datetime
738
-     *
739
-     * @param int $DTT_ID datetime ID
740
-     * @param boolean $checked_in whether to count registrations checked IN or OUT
741
-     * @return int
742
-     * @throws EE_Error
743
-     */
744
-    public function count_registrations_checked_into_datetime($DTT_ID, $checked_in = true)
745
-    {
746
-        global $wpdb;
747
-        // subquery to get latest checkin
748
-        $query = $wpdb->prepare(
749
-            'SELECT '
750
-            . 'COUNT( DISTINCT checkins.REG_ID ) '
751
-            . 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN'
752
-            . '( SELECT '
753
-            . 'max( CHK_timestamp ) AS latest_checkin, '
754
-            . 'REG_ID AS REG_ID '
755
-            . 'FROM ' . EEM_Checkin::instance()->table() . ' '
756
-            . 'WHERE DTT_ID=%d '
757
-            . 'GROUP BY REG_ID'
758
-            . ') AS most_recent_checkin_per_reg '
759
-            . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID '
760
-            . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin '
761
-            . 'WHERE '
762
-            . 'checkins.CHK_in=%d',
763
-            $DTT_ID,
764
-            $checked_in
765
-        );
766
-        return (int) $wpdb->get_var($query);
767
-    }
768
-
769
-
770
-    /**
771
-     *  Count registrations checked into (or out of) an event.
772
-     *
773
-     * @param int $EVT_ID event ID
774
-     * @param boolean $checked_in whether to count registrations checked IN or OUT
775
-     * @return int
776
-     * @throws EE_Error
777
-     */
778
-    public function count_registrations_checked_into_event($EVT_ID, $checked_in = true)
779
-    {
780
-        global $wpdb;
781
-        // subquery to get latest checkin
782
-        $query = $wpdb->prepare(
783
-            'SELECT '
784
-            . 'COUNT( DISTINCT checkins.REG_ID ) '
785
-            . 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN'
786
-            . '( SELECT '
787
-            . 'max( CHK_timestamp ) AS latest_checkin, '
788
-            . 'REG_ID AS REG_ID '
789
-            . 'FROM ' . EEM_Checkin::instance()->table() . ' AS c '
790
-            . 'INNER JOIN ' . EEM_Datetime::instance()->table() . ' AS d '
791
-            . 'ON c.DTT_ID=d.DTT_ID '
792
-            . 'WHERE d.EVT_ID=%d '
793
-            . 'GROUP BY REG_ID'
794
-            . ') AS most_recent_checkin_per_reg '
795
-            . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID '
796
-            . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin '
797
-            . 'WHERE '
798
-            . 'checkins.CHK_in=%d',
799
-            $EVT_ID,
800
-            $checked_in
801
-        );
802
-        return (int) $wpdb->get_var($query);
803
-    }
804
-
805
-
806
-    /**
807
-     * The purpose of this method is to retrieve an array of
808
-     * EE_Registration objects that represent the latest registration
809
-     * for each ATT_ID given in the function argument.
810
-     *
811
-     * @param array $attendee_ids
812
-     * @return EE_Base_Class[]|EE_Registration[]
813
-     * @throws EE_Error
814
-     */
815
-    public function get_latest_registration_for_each_of_given_contacts($attendee_ids = array())
816
-    {
817
-        // first do a native wp_query to get the latest REG_ID's matching these attendees.
818
-        global $wpdb;
819
-        $registration_table = $wpdb->prefix . 'esp_registration';
820
-        $attendee_table = $wpdb->posts;
821
-        $attendee_ids = is_array($attendee_ids)
822
-            ? array_map('absint', $attendee_ids)
823
-            : array((int) $attendee_ids);
824
-        $ATT_IDs = implode(',', $attendee_ids);
825
-        // first we do a query to get the registration ids
826
-        // (because a group by before order by causes the order by to be ignored.)
827
-        $registration_id_query = "
17
+	/**
18
+	 * @var EEM_Registration $_instance
19
+	 */
20
+	protected static $_instance;
21
+
22
+	/**
23
+	 * Keys are the status IDs for registrations (eg, RAP, RCN, etc), and the values
24
+	 * are status codes (eg, approved, cancelled, etc)
25
+	 *
26
+	 * @var array
27
+	 */
28
+	private static $_reg_status;
29
+
30
+	/**
31
+	 * The value of REG_count for a primary registrant
32
+	 */
33
+	const PRIMARY_REGISTRANT_COUNT = 1;
34
+
35
+	/**
36
+	 * Status ID (STS_ID on esp_status table) to indicate an INCOMPLETE registration.
37
+	 * Initial status for registrations when they are first created
38
+	 * Payments are NOT allowed.
39
+	 * Automatically toggled to whatever the default Event registration status is upon completion of the attendee
40
+	 * information reg step NO space reserved. Registration is NOT active
41
+	 */
42
+	const status_id_incomplete = 'RIC';
43
+
44
+	/**
45
+	 * Status ID (STS_ID on esp_status table) to indicate an UNAPPROVED registration.
46
+	 * Payments are NOT allowed.
47
+	 * Event Admin must manually toggle STS_ID for it to change
48
+	 * No space reserved.
49
+	 * Registration is active
50
+	 */
51
+	const status_id_not_approved = 'RNA';
52
+
53
+	/**
54
+	 * Status ID (STS_ID on esp_status table) to indicate registration is PENDING_PAYMENT .
55
+	 * Payments are allowed.
56
+	 * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee
57
+	 * No space reserved.
58
+	 * Registration is active
59
+	 */
60
+	const status_id_pending_payment = 'RPP';
61
+
62
+	/**
63
+	 * Status ID (STS_ID on esp_status table) to indicate registration is on the WAIT_LIST .
64
+	 * Payments are allowed.
65
+	 * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee
66
+	 * No space reserved.
67
+	 * Registration is active
68
+	 */
69
+	const status_id_wait_list = 'RWL';
70
+
71
+	/**
72
+	 * Status ID (STS_ID on esp_status table) to indicate an APPROVED registration.
73
+	 * the TXN may or may not be completed ( paid in full )
74
+	 * Payments are allowed.
75
+	 * A space IS reserved.
76
+	 * Registration is active
77
+	 */
78
+	const status_id_approved = 'RAP';
79
+
80
+	/**
81
+	 * Status ID (STS_ID on esp_status table) to indicate a registration was CANCELLED by the attendee.
82
+	 * Payments are NOT allowed.
83
+	 * NO space reserved.
84
+	 * Registration is NOT active
85
+	 */
86
+	const status_id_cancelled = 'RCN';
87
+
88
+	/**
89
+	 * Status ID (STS_ID on esp_status table) to indicate a registration was DECLINED by the Event Admin
90
+	 * Payments are NOT allowed.
91
+	 * No space reserved.
92
+	 * Registration is NOT active
93
+	 */
94
+	const status_id_declined = 'RDC';
95
+
96
+	/**
97
+	 * @var TableAnalysis $table_analysis
98
+	 */
99
+	protected $_table_analysis;
100
+
101
+
102
+	/**
103
+	 *    private constructor to prevent direct creation
104
+	 *
105
+	 * @Constructor
106
+	 * @access protected
107
+	 * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any
108
+	 *                         incoming timezone data that gets saved). Note this just sends the timezone info to the
109
+	 *                         date time model field objects.  Default is NULL (and will be assumed using the set
110
+	 *                         timezone in the 'timezone_string' wp option)
111
+	 * @throws EE_Error
112
+	 */
113
+	protected function __construct($timezone = '')
114
+	{
115
+		$this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
116
+		$this->singular_item = esc_html__('Registration', 'event_espresso');
117
+		$this->plural_item = esc_html__('Registrations', 'event_espresso');
118
+		$this->_tables = array(
119
+			'Registration' => new EE_Primary_Table('esp_registration', 'REG_ID'),
120
+		);
121
+		$this->_fields = array(
122
+			'Registration' => array(
123
+				'REG_ID' => new EE_Primary_Key_Int_Field(
124
+					'REG_ID',
125
+					esc_html__('Registration ID', 'event_espresso')
126
+				),
127
+				'EVT_ID' => new EE_Foreign_Key_Int_Field(
128
+					'EVT_ID',
129
+					esc_html__('Event ID', 'event_espresso'),
130
+					false,
131
+					0,
132
+					'Event'
133
+				),
134
+				'ATT_ID' => new EE_Foreign_Key_Int_Field(
135
+					'ATT_ID',
136
+					esc_html__('Attendee ID', 'event_espresso'),
137
+					false,
138
+					0,
139
+					'Attendee'
140
+				),
141
+				'TXN_ID' => new EE_Foreign_Key_Int_Field(
142
+					'TXN_ID',
143
+					esc_html__('Transaction ID', 'event_espresso'),
144
+					false,
145
+					0,
146
+					'Transaction'
147
+				),
148
+				'TKT_ID' => new EE_Foreign_Key_Int_Field(
149
+					'TKT_ID',
150
+					esc_html__('Ticket ID', 'event_espresso'),
151
+					false,
152
+					0,
153
+					'Ticket'
154
+				),
155
+				'STS_ID' => new EE_Foreign_Key_String_Field(
156
+					'STS_ID',
157
+					esc_html__('Status ID', 'event_espresso'),
158
+					false,
159
+					EEM_Registration::status_id_incomplete,
160
+					'Status'
161
+				),
162
+				'REG_date' => new EE_Datetime_Field(
163
+					'REG_date',
164
+					esc_html__('Time registration occurred', 'event_espresso'),
165
+					false,
166
+					EE_Datetime_Field::now,
167
+					$timezone
168
+				),
169
+				'REG_final_price' => new EE_Money_Field(
170
+					'REG_final_price',
171
+					esc_html__('Registration\'s share of the transaction total', 'event_espresso'),
172
+					false,
173
+					0
174
+				),
175
+				'REG_paid' => new EE_Money_Field(
176
+					'REG_paid',
177
+					esc_html__('Amount paid to date towards registration', 'event_espresso'),
178
+					false,
179
+					0
180
+				),
181
+				'REG_session' => new EE_Plain_Text_Field(
182
+					'REG_session',
183
+					esc_html__('Session ID of registration', 'event_espresso'),
184
+					false,
185
+					''
186
+				),
187
+				'REG_code' => new EE_Plain_Text_Field(
188
+					'REG_code',
189
+					esc_html__('Unique Code for this registration', 'event_espresso'),
190
+					false,
191
+					''
192
+				),
193
+				'REG_url_link' => new EE_Plain_Text_Field(
194
+					'REG_url_link',
195
+					esc_html__('String to be used in URL for identifying registration', 'event_espresso'),
196
+					false,
197
+					''
198
+				),
199
+				'REG_count' => new EE_Integer_Field(
200
+					'REG_count',
201
+					esc_html__('Count of this registration in the group registration ', 'event_espresso'),
202
+					true,
203
+					1
204
+				),
205
+				'REG_group_size' => new EE_Integer_Field(
206
+					'REG_group_size',
207
+					esc_html__('Number of registrations on this group', 'event_espresso'),
208
+					false,
209
+					1
210
+				),
211
+				'REG_att_is_going' => new EE_Boolean_Field(
212
+					'REG_att_is_going',
213
+					esc_html__('Flag indicating the registrant plans on attending', 'event_espresso'),
214
+					false,
215
+					false
216
+				),
217
+				'REG_deleted' => new EE_Trashed_Flag_Field(
218
+					'REG_deleted',
219
+					esc_html__('Flag indicating if registration has been archived or not.', 'event_espresso'),
220
+					false,
221
+					false
222
+				),
223
+			),
224
+		);
225
+		$this->_model_relations = array(
226
+			'Event' => new EE_Belongs_To_Relation(),
227
+			'Attendee' => new EE_Belongs_To_Relation(),
228
+			'Transaction' => new EE_Belongs_To_Relation(),
229
+			'Ticket' => new EE_Belongs_To_Relation(),
230
+			'Status' => new EE_Belongs_To_Relation(),
231
+			'Answer' => new EE_Has_Many_Relation(),
232
+			'Checkin' => new EE_Has_Many_Relation(),
233
+			'Registration_Payment' => new EE_Has_Many_Relation(),
234
+			'Payment' => new EE_HABTM_Relation('Registration_Payment'),
235
+			'Message' => new EE_Has_Many_Any_Relation(false)
236
+			// allow deletes even if there are messages in the queue related
237
+		);
238
+		$this->_model_chain_to_wp_user = 'Event';
239
+		parent::__construct($timezone);
240
+	}
241
+
242
+
243
+	/**
244
+	 * a list of ALL valid registration statuses currently in use within the system
245
+	 * generated by combining the filterable active and inactive reg status arrays
246
+	 *
247
+	 * @return array
248
+	 */
249
+	public static function reg_statuses()
250
+	{
251
+		return array_unique(
252
+			array_merge(
253
+				EEM_Registration::active_reg_statuses(),
254
+				EEM_Registration::inactive_reg_statuses()
255
+			)
256
+		);
257
+	}
258
+
259
+
260
+	/**
261
+	 * reg_statuses_that_allow_payment
262
+	 * a filterable list of registration statuses that allow a registrant to make a payment
263
+	 *
264
+	 * @access public
265
+	 * @return array
266
+	 */
267
+	public static function reg_statuses_that_allow_payment()
268
+	{
269
+		return apply_filters(
270
+			'FHEE__EEM_Registration__reg_statuses_that_allow_payment',
271
+			array(
272
+				EEM_Registration::status_id_approved,
273
+				EEM_Registration::status_id_pending_payment,
274
+			)
275
+		);
276
+	}
277
+
278
+
279
+	/**
280
+	 * active_reg_statuses
281
+	 * a filterable list of registration statuses that are considered active
282
+	 *
283
+	 * @access public
284
+	 * @return array
285
+	 */
286
+	public static function active_reg_statuses()
287
+	{
288
+		return apply_filters(
289
+			'FHEE__EEM_Registration__active_reg_statuses',
290
+			array(
291
+				EEM_Registration::status_id_approved,
292
+				EEM_Registration::status_id_pending_payment,
293
+				EEM_Registration::status_id_wait_list,
294
+				EEM_Registration::status_id_not_approved,
295
+			)
296
+		);
297
+	}
298
+
299
+
300
+	/**
301
+	 * inactive_reg_statuses
302
+	 * a filterable list of registration statuses that are not considered active
303
+	 *
304
+	 * @access public
305
+	 * @return array
306
+	 */
307
+	public static function inactive_reg_statuses()
308
+	{
309
+		return apply_filters(
310
+			'FHEE__EEM_Registration__inactive_reg_statuses',
311
+			array(
312
+				EEM_Registration::status_id_incomplete,
313
+				EEM_Registration::status_id_cancelled,
314
+				EEM_Registration::status_id_declined,
315
+			)
316
+		);
317
+	}
318
+
319
+
320
+	/**
321
+	 *    closed_reg_statuses
322
+	 *    a filterable list of registration statuses that are considered "closed"
323
+	 * meaning they should not be considered in any calculations involving monies owing
324
+	 *
325
+	 * @access public
326
+	 * @return array
327
+	 */
328
+	public static function closed_reg_statuses()
329
+	{
330
+		return apply_filters(
331
+			'FHEE__EEM_Registration__closed_reg_statuses',
332
+			array(
333
+				EEM_Registration::status_id_cancelled,
334
+				EEM_Registration::status_id_declined,
335
+				EEM_Registration::status_id_wait_list,
336
+			)
337
+		);
338
+	}
339
+
340
+
341
+	/**
342
+	 *        get list of registration statuses
343
+	 *
344
+	 * @access public
345
+	 * @param array $exclude The status ids to exclude from the returned results
346
+	 * @param bool $translated If true will return the values as singular localized strings
347
+	 * @return array
348
+	 * @throws EE_Error
349
+	 */
350
+	public static function reg_status_array($exclude = array(), $translated = false)
351
+	{
352
+		EEM_Registration::instance()->_get_registration_status_array($exclude);
353
+		return $translated
354
+			? EEM_Status::instance()->localized_status(self::$_reg_status, false, 'sentence')
355
+			: self::$_reg_status;
356
+	}
357
+
358
+
359
+	/**
360
+	 *    get list of registration statuses
361
+	 *
362
+	 * @access private
363
+	 * @param array $exclude
364
+	 * @return void
365
+	 * @throws EE_Error
366
+	 */
367
+	private function _get_registration_status_array($exclude = array())
368
+	{
369
+		// in the very rare circumstance that we are deleting a model's table's data
370
+		// and the table hasn't actually been created, this could have an error
371
+		/** @type WPDB $wpdb */
372
+		global $wpdb;
373
+		if ($this->_get_table_analysis()->tableExists($wpdb->prefix . 'esp_status')) {
374
+			$results = $wpdb->get_results(
375
+				"SELECT STS_ID, STS_code FROM {$wpdb->prefix}esp_status WHERE STS_type = 'registration'"
376
+			);
377
+			self::$_reg_status = array();
378
+			foreach ($results as $status) {
379
+				if (!in_array($status->STS_ID, $exclude, true)) {
380
+					self::$_reg_status[ $status->STS_ID ] = $status->STS_code;
381
+				}
382
+			}
383
+		}
384
+	}
385
+
386
+
387
+	/**
388
+	 * Gets the injected table analyzer, or throws an exception
389
+	 *
390
+	 * @return TableAnalysis
391
+	 * @throws EE_Error
392
+	 */
393
+	protected function _get_table_analysis()
394
+	{
395
+		if ($this->_table_analysis instanceof TableAnalysis) {
396
+			return $this->_table_analysis;
397
+		}
398
+		throw new EE_Error(
399
+			sprintf(
400
+				esc_html__('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
401
+				get_class($this)
402
+			)
403
+		);
404
+	}
405
+
406
+
407
+	/**
408
+	 * This returns a wpdb->results array of all registration date month and years matching the incoming query params
409
+	 * and grouped by month and year.
410
+	 *
411
+	 * @param  array $where_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
412
+	 * @return array
413
+	 * @throws EE_Error
414
+	 */
415
+	public function get_reg_months_and_years($where_params)
416
+	{
417
+		$query_params[0] = $where_params;
418
+		$query_params['group_by'] = array('reg_year', 'reg_month');
419
+		$query_params['order_by'] = array('REG_date' => 'DESC');
420
+		$columns_to_select = array(
421
+			'reg_year' => array('YEAR(REG_date)', '%s'),
422
+			'reg_month' => array('MONTHNAME(REG_date)', '%s'),
423
+		);
424
+		return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select);
425
+	}
426
+
427
+
428
+	/**
429
+	 * retrieve ALL registrations for a particular Attendee from db
430
+	 *
431
+	 * @param int $ATT_ID
432
+	 * @return EE_Base_Class[]|EE_Registration[]|null
433
+	 * @throws EE_Error
434
+	 */
435
+	public function get_all_registrations_for_attendee($ATT_ID = 0)
436
+	{
437
+		if (!$ATT_ID) {
438
+			return null;
439
+		}
440
+		return $this->get_all(array(array('ATT_ID' => $ATT_ID)));
441
+	}
442
+
443
+
444
+	/**
445
+	 * Gets a registration given their REG_url_link. Yes, this should usually
446
+	 * be passed via a GET parameter.
447
+	 *
448
+	 * @param string $REG_url_link
449
+	 * @return EE_Base_Class|EE_Registration|null
450
+	 * @throws EE_Error
451
+	 */
452
+	public function get_registration_for_reg_url_link($REG_url_link)
453
+	{
454
+		if (!$REG_url_link) {
455
+			return null;
456
+		}
457
+		return $this->get_one(array(array('REG_url_link' => $REG_url_link)));
458
+	}
459
+
460
+
461
+	/**
462
+	 *        retrieve registration for a specific transaction attendee from db
463
+	 *
464
+	 * @access        public
465
+	 * @param    int $TXN_ID
466
+	 * @param    int $ATT_ID
467
+	 * @param    int $att_nmbr in case the ATT_ID is the same for multiple registrations (same details used) then the
468
+	 *                         attendee number is required
469
+	 * @return        mixed        array on success, FALSE on fail
470
+	 * @throws EE_Error
471
+	 */
472
+	public function get_registration_for_transaction_attendee($TXN_ID = 0, $ATT_ID = 0, $att_nmbr = 0)
473
+	{
474
+		return $this->get_one(array(
475
+			array(
476
+				'TXN_ID' => $TXN_ID,
477
+				'ATT_ID' => $ATT_ID,
478
+			),
479
+			'limit' => array(min($att_nmbr - 1, 0), 1),
480
+		));
481
+	}
482
+
483
+
484
+	/**
485
+	 *        get the number of registrations per day  for the Registration Admin page Reports Tab.
486
+	 *        (doesn't utilize models because it's a fairly specialized query)
487
+	 *
488
+	 * @access        public
489
+	 * @param $period string which can be passed to php's strtotime function (eg "-1 month")
490
+	 * @return stdClass[] with properties regDate and total
491
+	 * @throws EE_Error
492
+	 */
493
+	public function get_registrations_per_day_report($period = '-1 month')
494
+	{
495
+		$sql_date = $this->convert_datetime_for_query(
496
+			'REG_date',
497
+			date('Y-m-d H:i:s', strtotime($period)),
498
+			'Y-m-d H:i:s',
499
+			'UTC'
500
+		);
501
+		$where = array(
502
+			'REG_date' => array('>=', $sql_date),
503
+			'STS_ID' => array('!=', EEM_Registration::status_id_incomplete),
504
+		);
505
+		if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_day_report')) {
506
+			$where['Event.EVT_wp_user'] = get_current_user_id();
507
+		}
508
+		$query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'REG_date');
509
+		$results = $this->_get_all_wpdb_results(
510
+			array(
511
+				$where,
512
+				'group_by' => 'regDate',
513
+				'order_by' => array('REG_date' => 'ASC'),
514
+			),
515
+			OBJECT,
516
+			array(
517
+				'regDate' => array('DATE(' . $query_interval . ')', '%s'),
518
+				'total' => array('count(REG_ID)', '%d'),
519
+			)
520
+		);
521
+		return $results;
522
+	}
523
+
524
+
525
+	/**
526
+	 * Get the number of registrations per day including the count of registrations for each Registration Status.
527
+	 * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results.
528
+	 *
529
+	 * @param string $period
530
+	 * @return stdClass[] with properties Registration_REG_date and a column for each registration status as the STS_ID
531
+	 * @throws EE_Error
532
+	 *                    (i.e. RAP)
533
+	 */
534
+	public function get_registrations_per_day_and_per_status_report($period = '-1 month')
535
+	{
536
+		global $wpdb;
537
+		$registration_table = $wpdb->prefix . 'esp_registration';
538
+		$event_table = $wpdb->posts;
539
+		$sql_date = date('Y-m-d H:i:s', strtotime($period));
540
+		// prepare the query interval for displaying offset
541
+		$query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'dates.REG_date');
542
+		// inner date query
543
+		$inner_date_query = "SELECT DISTINCT REG_date from {$registration_table} ";
544
+		$inner_where = ' WHERE';
545
+		// exclude events not authored by user if permissions in effect
546
+		if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
547
+			$inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID";
548
+			$inner_where .= ' post_author = ' . get_current_user_id() . ' AND';
549
+		}
550
+		$inner_where .= " REG_date >= '{$sql_date}'";
551
+		$inner_date_query .= $inner_where;
552
+		// start main query
553
+		$select = "SELECT DATE({$query_interval}) as Registration_REG_date, ";
554
+		$join = '';
555
+		$join_parts = array();
556
+		$select_parts = array();
557
+		// loop through registration stati to do parts for each status.
558
+		foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) {
559
+			if ($STS_ID === EEM_Registration::status_id_incomplete) {
560
+				continue;
561
+			}
562
+			$select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}";
563
+			$join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.REG_date = dates.REG_date AND {$STS_code}.STS_ID = '{$STS_ID}'";
564
+		}
565
+		// setup the selects
566
+		$select .= implode(', ', $select_parts);
567
+		$select .= " FROM ($inner_date_query) AS dates LEFT JOIN ";
568
+		// setup the joins
569
+		$join .= implode(' LEFT JOIN ', $join_parts);
570
+		// now let's put it all together
571
+		$query = $select . $join . ' GROUP BY Registration_REG_date';
572
+		// and execute it
573
+		return $wpdb->get_results($query, ARRAY_A);
574
+	}
575
+
576
+
577
+	/**
578
+	 *        get the number of registrations per event  for the Registration Admin page Reports Tab
579
+	 *
580
+	 * @access        public
581
+	 * @param $period string which can be passed to php's strtotime function (eg "-1 month")
582
+	 * @return stdClass[] each with properties event_name, reg_limit, and total
583
+	 * @throws EE_Error
584
+	 */
585
+	public function get_registrations_per_event_report($period = '-1 month')
586
+	{
587
+		$date_sql = $this->convert_datetime_for_query(
588
+			'REG_date',
589
+			date('Y-m-d H:i:s', strtotime($period)),
590
+			'Y-m-d H:i:s',
591
+			'UTC'
592
+		);
593
+		$where = array(
594
+			'REG_date' => array('>=', $date_sql),
595
+			'STS_ID' => array('!=', EEM_Registration::status_id_incomplete),
596
+		);
597
+		if (
598
+			!EE_Registry::instance()->CAP->current_user_can(
599
+				'ee_read_others_registrations',
600
+				'reg_per_event_report'
601
+			)
602
+		) {
603
+			$where['Event.EVT_wp_user'] = get_current_user_id();
604
+		}
605
+		$results = $this->_get_all_wpdb_results(
606
+			array(
607
+			$where,
608
+			'group_by' => 'Event.EVT_name',
609
+			'order_by' => 'Event.EVT_name',
610
+			'limit' => array(0, 24),
611
+			),
612
+			OBJECT,
613
+			array(
614
+				'event_name' => array('Event_CPT.post_title', '%s'),
615
+				'total' => array('COUNT(REG_ID)', '%s'),
616
+			)
617
+		);
618
+		return $results;
619
+	}
620
+
621
+
622
+	/**
623
+	 * Get the number of registrations per event grouped by registration status.
624
+	 * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results.
625
+	 *
626
+	 * @param string $period
627
+	 * @return stdClass[] with properties `Registration_Event` and a column for each registration status as the STS_ID
628
+	 * @throws EE_Error
629
+	 *                    (i.e. RAP)
630
+	 */
631
+	public function get_registrations_per_event_and_per_status_report($period = '-1 month')
632
+	{
633
+		global $wpdb;
634
+		$registration_table = $wpdb->prefix . 'esp_registration';
635
+		$event_table = $wpdb->posts;
636
+		$sql_date = date('Y-m-d H:i:s', strtotime($period));
637
+		// inner date query
638
+		$inner_date_query = "SELECT DISTINCT EVT_ID, REG_date from $registration_table ";
639
+		$inner_where = ' WHERE';
640
+		// exclude events not authored by user if permissions in effect
641
+		if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
642
+			$inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID";
643
+			$inner_where .= ' post_author = ' . get_current_user_id() . ' AND';
644
+		}
645
+		$inner_where .= " REG_date >= '{$sql_date}'";
646
+		$inner_date_query .= $inner_where;
647
+		// build main query
648
+		$select = 'SELECT Event.post_title as Registration_Event, ';
649
+		$join = '';
650
+		$join_parts = array();
651
+		$select_parts = array();
652
+		// loop through registration stati to do parts for each status.
653
+		foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) {
654
+			if ($STS_ID === EEM_Registration::status_id_incomplete) {
655
+				continue;
656
+			}
657
+			$select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}";
658
+			$join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.EVT_ID = dates.EVT_ID AND {$STS_code}.STS_ID = '{$STS_ID}' AND {$STS_code}.REG_date = dates.REG_date";
659
+		}
660
+		// setup the selects
661
+		$select .= implode(', ', $select_parts);
662
+		$select .= " FROM ($inner_date_query) AS dates LEFT JOIN $event_table as Event ON Event.ID = dates.EVT_ID LEFT JOIN ";
663
+		// setup remaining joins
664
+		$join .= implode(' LEFT JOIN ', $join_parts);
665
+		// now put it all together
666
+		$query = $select . $join . ' GROUP BY Registration_Event';
667
+		// and execute
668
+		return $wpdb->get_results($query, ARRAY_A);
669
+	}
670
+
671
+
672
+	/**
673
+	 * Returns the EE_Registration of the primary attendee on the transaction id provided
674
+	 *
675
+	 * @param int $TXN_ID
676
+	 * @return EE_Base_Class|EE_Registration|null
677
+	 * @throws EE_Error
678
+	 */
679
+	public function get_primary_registration_for_transaction_ID($TXN_ID = 0)
680
+	{
681
+		if (!$TXN_ID) {
682
+			return null;
683
+		}
684
+		return $this->get_one(array(
685
+			array(
686
+				'TXN_ID' => $TXN_ID,
687
+				'REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT,
688
+			),
689
+		));
690
+	}
691
+
692
+
693
+	/**
694
+	 *        get_event_registration_count
695
+	 *
696
+	 * @access public
697
+	 * @param int $EVT_ID
698
+	 * @param boolean $for_incomplete_payments
699
+	 * @return int
700
+	 * @throws EE_Error
701
+	 */
702
+	public function get_event_registration_count($EVT_ID, $for_incomplete_payments = false)
703
+	{
704
+		// we only count approved registrations towards registration limits
705
+		$query_params = array(array('EVT_ID' => $EVT_ID, 'STS_ID' => self::status_id_approved));
706
+		if ($for_incomplete_payments) {
707
+			$query_params[0]['Transaction.STS_ID'] = array('!=', EEM_Transaction::complete_status_code);
708
+		}
709
+		return $this->count($query_params);
710
+	}
711
+
712
+
713
+	/**
714
+	 * Deletes all registrations with no transactions. Note that this needs to be very efficient
715
+	 * and so it uses wpdb directly. Also, we can't put a limit on this because MySQL doesn't allow a limit on a delete
716
+	 * when joining tables like this.
717
+	 *
718
+	 * @global WPDB $wpdb
719
+	 * @return int number deleted
720
+	 * @throws EE_Error
721
+	 */
722
+	public function delete_registrations_with_no_transaction()
723
+	{
724
+		/** @type WPDB $wpdb */
725
+		global $wpdb;
726
+		return $wpdb->query(
727
+			'DELETE r FROM '
728
+			. $this->table()
729
+			. ' r LEFT JOIN '
730
+			. EEM_Transaction::instance()->table()
731
+			. ' t ON r.TXN_ID = t.TXN_ID WHERE t.TXN_ID IS NULL'
732
+		);
733
+	}
734
+
735
+
736
+	/**
737
+	 *  Count registrations checked into (or out of) a datetime
738
+	 *
739
+	 * @param int $DTT_ID datetime ID
740
+	 * @param boolean $checked_in whether to count registrations checked IN or OUT
741
+	 * @return int
742
+	 * @throws EE_Error
743
+	 */
744
+	public function count_registrations_checked_into_datetime($DTT_ID, $checked_in = true)
745
+	{
746
+		global $wpdb;
747
+		// subquery to get latest checkin
748
+		$query = $wpdb->prepare(
749
+			'SELECT '
750
+			. 'COUNT( DISTINCT checkins.REG_ID ) '
751
+			. 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN'
752
+			. '( SELECT '
753
+			. 'max( CHK_timestamp ) AS latest_checkin, '
754
+			. 'REG_ID AS REG_ID '
755
+			. 'FROM ' . EEM_Checkin::instance()->table() . ' '
756
+			. 'WHERE DTT_ID=%d '
757
+			. 'GROUP BY REG_ID'
758
+			. ') AS most_recent_checkin_per_reg '
759
+			. 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID '
760
+			. 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin '
761
+			. 'WHERE '
762
+			. 'checkins.CHK_in=%d',
763
+			$DTT_ID,
764
+			$checked_in
765
+		);
766
+		return (int) $wpdb->get_var($query);
767
+	}
768
+
769
+
770
+	/**
771
+	 *  Count registrations checked into (or out of) an event.
772
+	 *
773
+	 * @param int $EVT_ID event ID
774
+	 * @param boolean $checked_in whether to count registrations checked IN or OUT
775
+	 * @return int
776
+	 * @throws EE_Error
777
+	 */
778
+	public function count_registrations_checked_into_event($EVT_ID, $checked_in = true)
779
+	{
780
+		global $wpdb;
781
+		// subquery to get latest checkin
782
+		$query = $wpdb->prepare(
783
+			'SELECT '
784
+			. 'COUNT( DISTINCT checkins.REG_ID ) '
785
+			. 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN'
786
+			. '( SELECT '
787
+			. 'max( CHK_timestamp ) AS latest_checkin, '
788
+			. 'REG_ID AS REG_ID '
789
+			. 'FROM ' . EEM_Checkin::instance()->table() . ' AS c '
790
+			. 'INNER JOIN ' . EEM_Datetime::instance()->table() . ' AS d '
791
+			. 'ON c.DTT_ID=d.DTT_ID '
792
+			. 'WHERE d.EVT_ID=%d '
793
+			. 'GROUP BY REG_ID'
794
+			. ') AS most_recent_checkin_per_reg '
795
+			. 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID '
796
+			. 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin '
797
+			. 'WHERE '
798
+			. 'checkins.CHK_in=%d',
799
+			$EVT_ID,
800
+			$checked_in
801
+		);
802
+		return (int) $wpdb->get_var($query);
803
+	}
804
+
805
+
806
+	/**
807
+	 * The purpose of this method is to retrieve an array of
808
+	 * EE_Registration objects that represent the latest registration
809
+	 * for each ATT_ID given in the function argument.
810
+	 *
811
+	 * @param array $attendee_ids
812
+	 * @return EE_Base_Class[]|EE_Registration[]
813
+	 * @throws EE_Error
814
+	 */
815
+	public function get_latest_registration_for_each_of_given_contacts($attendee_ids = array())
816
+	{
817
+		// first do a native wp_query to get the latest REG_ID's matching these attendees.
818
+		global $wpdb;
819
+		$registration_table = $wpdb->prefix . 'esp_registration';
820
+		$attendee_table = $wpdb->posts;
821
+		$attendee_ids = is_array($attendee_ids)
822
+			? array_map('absint', $attendee_ids)
823
+			: array((int) $attendee_ids);
824
+		$ATT_IDs = implode(',', $attendee_ids);
825
+		// first we do a query to get the registration ids
826
+		// (because a group by before order by causes the order by to be ignored.)
827
+		$registration_id_query = "
828 828
 			SELECT registrations.registration_ids as registration_id
829 829
 			FROM (
830 830
 				SELECT
@@ -838,61 +838,61 @@  discard block
 block discarded – undo
838 838
 			  ) AS registrations
839 839
 			  GROUP BY registrations.attendee_ids
840 840
 		";
841
-        $registration_ids = $wpdb->get_results($registration_id_query, ARRAY_A);
842
-        if (empty($registration_ids)) {
843
-            return array();
844
-        }
845
-        $ids_for_model_query = array();
846
-        // let's flatten the ids so they can be used in the model query.
847
-        foreach ($registration_ids as $registration_id) {
848
-            if (isset($registration_id['registration_id'])) {
849
-                $ids_for_model_query[] = $registration_id['registration_id'];
850
-            }
851
-        }
852
-        // construct query
853
-        $_where = array(
854
-            'REG_ID' => array('IN', $ids_for_model_query),
855
-        );
856
-        return $this->get_all(array($_where));
857
-    }
858
-
859
-
860
-
861
-    /**
862
-     * returns a count of registrations for the supplied event having the status as specified
863
-     *
864
-     * @param int $EVT_ID
865
-     * @param array $statuses
866
-     * @return int
867
-     * @throws InvalidArgumentException
868
-     * @throws InvalidStatusException
869
-     * @throws EE_Error
870
-     */
871
-    public function event_reg_count_for_statuses($EVT_ID, $statuses = array())
872
-    {
873
-        $EVT_ID = absint($EVT_ID);
874
-        if (! $EVT_ID) {
875
-            throw new InvalidArgumentException(
876
-                esc_html__('An invalid Event ID was supplied.', 'event_espresso')
877
-            );
878
-        }
879
-        $statuses = is_array($statuses) ? $statuses : array($statuses);
880
-        $statuses = ! empty($statuses) ? $statuses : array(EEM_Registration::status_id_approved);
881
-        $valid_reg_statuses = EEM_Registration::reg_statuses();
882
-        foreach ($statuses as $status) {
883
-            if (! in_array($status, $valid_reg_statuses, true)) {
884
-                throw new InvalidStatusException($status, esc_html__('Registration', 'event_espresso'));
885
-            }
886
-        }
887
-        return $this->count(
888
-            array(
889
-                array(
890
-                    'EVT_ID' => $EVT_ID,
891
-                    'STS_ID' => array('IN', $statuses),
892
-                ),
893
-            ),
894
-            'REG_ID',
895
-            true
896
-        );
897
-    }
841
+		$registration_ids = $wpdb->get_results($registration_id_query, ARRAY_A);
842
+		if (empty($registration_ids)) {
843
+			return array();
844
+		}
845
+		$ids_for_model_query = array();
846
+		// let's flatten the ids so they can be used in the model query.
847
+		foreach ($registration_ids as $registration_id) {
848
+			if (isset($registration_id['registration_id'])) {
849
+				$ids_for_model_query[] = $registration_id['registration_id'];
850
+			}
851
+		}
852
+		// construct query
853
+		$_where = array(
854
+			'REG_ID' => array('IN', $ids_for_model_query),
855
+		);
856
+		return $this->get_all(array($_where));
857
+	}
858
+
859
+
860
+
861
+	/**
862
+	 * returns a count of registrations for the supplied event having the status as specified
863
+	 *
864
+	 * @param int $EVT_ID
865
+	 * @param array $statuses
866
+	 * @return int
867
+	 * @throws InvalidArgumentException
868
+	 * @throws InvalidStatusException
869
+	 * @throws EE_Error
870
+	 */
871
+	public function event_reg_count_for_statuses($EVT_ID, $statuses = array())
872
+	{
873
+		$EVT_ID = absint($EVT_ID);
874
+		if (! $EVT_ID) {
875
+			throw new InvalidArgumentException(
876
+				esc_html__('An invalid Event ID was supplied.', 'event_espresso')
877
+			);
878
+		}
879
+		$statuses = is_array($statuses) ? $statuses : array($statuses);
880
+		$statuses = ! empty($statuses) ? $statuses : array(EEM_Registration::status_id_approved);
881
+		$valid_reg_statuses = EEM_Registration::reg_statuses();
882
+		foreach ($statuses as $status) {
883
+			if (! in_array($status, $valid_reg_statuses, true)) {
884
+				throw new InvalidStatusException($status, esc_html__('Registration', 'event_espresso'));
885
+			}
886
+		}
887
+		return $this->count(
888
+			array(
889
+				array(
890
+					'EVT_ID' => $EVT_ID,
891
+					'STS_ID' => array('IN', $statuses),
892
+				),
893
+			),
894
+			'REG_ID',
895
+			true
896
+		);
897
+	}
898 898
 }
Please login to merge, or discard this patch.