Completed
Branch Gutenberg/switch-eventespresso... (7adb18)
by
unknown
16:22 queued 14:31
created
core/db_classes/EE_Price.class.php 2 patches
Indentation   +286 added lines, -286 removed lines patch added patch discarded remove patch
@@ -10,290 +10,290 @@
 block discarded – undo
10 10
 class EE_Price extends EE_Soft_Delete_Base_Class
11 11
 {
12 12
 
13
-    /**
14
-     *
15
-     * @param array  $props_n_values          incoming values
16
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
17
-     *                                        used.)
18
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
19
-     *                                        date_format and the second value is the time format
20
-     * @return EE_Attendee
21
-     */
22
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
23
-    {
24
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
25
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
26
-    }
27
-
28
-
29
-    /**
30
-     * @param array  $props_n_values  incoming values from the database
31
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
32
-     *                                the website will be used.
33
-     * @return EE_Attendee
34
-     */
35
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
36
-    {
37
-        return new self($props_n_values, true, $timezone);
38
-    }
39
-
40
-
41
-    /**
42
-     *        Set Price type ID
43
-     *
44
-     * @access        public
45
-     * @param        int $PRT_ID
46
-     */
47
-    public function set_type($PRT_ID = 0)
48
-    {
49
-        $this->set('PRT_ID', $PRT_ID);
50
-    }
51
-
52
-
53
-    /**
54
-     *        Set Price Amount
55
-     *
56
-     * @access        public
57
-     * @param        float $PRC_amount
58
-     */
59
-    public function set_amount($PRC_amount = 0.00)
60
-    {
61
-        $this->set('PRC_amount', $PRC_amount);
62
-    }
63
-
64
-
65
-    /**
66
-     *        Set Price Name
67
-     *
68
-     * @access        public
69
-     * @param        string $PRC_name
70
-     */
71
-    public function set_name($PRC_name = '')
72
-    {
73
-        $this->set('PRC_name', $PRC_name);
74
-    }
75
-
76
-
77
-    /**
78
-     *        Set Price Description
79
-     *
80
-     * @access        public
81
-     * @param        string $PRC_desc
82
-     */
83
-    public function set_description($PRC_desc = '')
84
-    {
85
-        $this->Set('PRC_desc', $PRC_desc);
86
-    }
87
-
88
-
89
-    /**
90
-     *        set is_default
91
-     *
92
-     * @access        public
93
-     * @param        bool $PRC_is_default
94
-     */
95
-    public function set_is_default($PRC_is_default = false)
96
-    {
97
-        $this->set('PRC_is_default', $PRC_is_default);
98
-    }
99
-
100
-
101
-    /**
102
-     *        set deleted
103
-     *
104
-     * @access        public
105
-     * @param        bool $PRC_deleted
106
-     */
107
-    public function set_deleted($PRC_deleted = null)
108
-    {
109
-        $this->set('PRC_deleted', $PRC_deleted);
110
-    }
111
-
112
-
113
-    /**
114
-     *    get Price type
115
-     *
116
-     * @access        public
117
-     * @return        int
118
-     */
119
-    public function type()
120
-    {
121
-        return $this->get('PRT_ID');
122
-    }
123
-
124
-
125
-    /**
126
-     *    get Price Amount
127
-     *
128
-     * @access        public
129
-     * @return        float
130
-     */
131
-    public function amount()
132
-    {
133
-        return $this->get('PRC_amount');
134
-    }
135
-
136
-
137
-    /**
138
-     *    get Price Name
139
-     *
140
-     * @access        public
141
-     * @return        string
142
-     */
143
-    public function name()
144
-    {
145
-        return $this->get('PRC_name');
146
-    }
147
-
148
-
149
-    /**
150
-     *    get Price description
151
-     *
152
-     * @access        public
153
-     * @return        string
154
-     */
155
-    public function desc()
156
-    {
157
-        return $this->get('PRC_desc');
158
-    }
159
-
160
-
161
-    /**
162
-     *    get overrides
163
-     *
164
-     * @access        public
165
-     * @return        int
166
-     */
167
-    public function overrides()
168
-    {
169
-        return $this->get('PRC_overrides');
170
-    }
171
-
172
-
173
-    /**
174
-     *    get order
175
-     *
176
-     * @access        public
177
-     * @return        int
178
-     */
179
-    public function order()
180
-    {
181
-        return $this->get('PRC_order');
182
-    }
183
-
184
-
185
-    /**
186
-     * get the author of the price
187
-     *
188
-     * @since 4.5.0
189
-     *
190
-     * @return int
191
-     */
192
-    public function wp_user()
193
-    {
194
-        return $this->get('PRC_wp_user');
195
-    }
196
-
197
-
198
-    /**
199
-     *    get is_default
200
-     *
201
-     * @access        public
202
-     * @return        bool
203
-     */
204
-    public function is_default()
205
-    {
206
-        return $this->get('PRC_is_default');
207
-    }
208
-
209
-
210
-    /**
211
-     *    get deleted
212
-     *
213
-     * @access        public
214
-     * @return        bool
215
-     */
216
-    public function deleted()
217
-    {
218
-        return $this->get('PRC_deleted');
219
-    }
220
-
221
-
222
-    /**
223
-     * @return bool
224
-     */
225
-    public function parent()
226
-    {
227
-        return $this->get('PRC_parent');
228
-    }
229
-
230
-
231
-    // some helper methods for getting info on the price_type for this price
232
-
233
-    /**
234
-     * return whether the price is a base price or not
235
-     *
236
-     * @return boolean
237
-     */
238
-    public function is_base_price()
239
-    {
240
-        $price_type = $this->type_obj();
241
-        return $price_type->base_type() === 1;
242
-    }
243
-
244
-
245
-    /**
246
-     *
247
-     * @return EE_Price_Type
248
-     */
249
-    public function type_obj()
250
-    {
251
-        return $this->get_first_related('Price_Type');
252
-    }
253
-
254
-
255
-    /**
256
-     * Simply indicates whether this price increases or decreases the total
257
-     *
258
-     * @return boolean true = discount, otherwise adds to the total
259
-     */
260
-    public function is_discount()
261
-    {
262
-        $price_type = $this->type_obj();
263
-        return $price_type->is_discount();
264
-    }
265
-
266
-
267
-    /**
268
-     * whether the price is a percentage or not
269
-     *
270
-     * @return boolean
271
-     */
272
-    public function is_percent()
273
-    {
274
-        $price_type = $this->type_obj();
275
-        return $price_type->get('PRT_is_percent');
276
-    }
277
-
278
-
279
-    /**
280
-     * return pretty price dependant on whether its a dollar or percent.
281
-     *
282
-     * @since 4.4.0
283
-     *
284
-     * @return string
285
-     */
286
-    public function pretty_price()
287
-    {
288
-        return ! $this->is_percent() ? $this->get_pretty('PRC_amount') : $this->get('PRC_amount') . '%';
289
-    }
290
-
291
-
292
-    /**
293
-     * @return mixed
294
-     */
295
-    public function get_price_without_currency_symbol()
296
-    {
297
-        return str_replace(EE_Registry::instance()->CFG->currency->sign, '', $this->get_pretty('PRC_amount'));
298
-    }
13
+	/**
14
+	 *
15
+	 * @param array  $props_n_values          incoming values
16
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
17
+	 *                                        used.)
18
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
19
+	 *                                        date_format and the second value is the time format
20
+	 * @return EE_Attendee
21
+	 */
22
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
23
+	{
24
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
25
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
26
+	}
27
+
28
+
29
+	/**
30
+	 * @param array  $props_n_values  incoming values from the database
31
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
32
+	 *                                the website will be used.
33
+	 * @return EE_Attendee
34
+	 */
35
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
36
+	{
37
+		return new self($props_n_values, true, $timezone);
38
+	}
39
+
40
+
41
+	/**
42
+	 *        Set Price type ID
43
+	 *
44
+	 * @access        public
45
+	 * @param        int $PRT_ID
46
+	 */
47
+	public function set_type($PRT_ID = 0)
48
+	{
49
+		$this->set('PRT_ID', $PRT_ID);
50
+	}
51
+
52
+
53
+	/**
54
+	 *        Set Price Amount
55
+	 *
56
+	 * @access        public
57
+	 * @param        float $PRC_amount
58
+	 */
59
+	public function set_amount($PRC_amount = 0.00)
60
+	{
61
+		$this->set('PRC_amount', $PRC_amount);
62
+	}
63
+
64
+
65
+	/**
66
+	 *        Set Price Name
67
+	 *
68
+	 * @access        public
69
+	 * @param        string $PRC_name
70
+	 */
71
+	public function set_name($PRC_name = '')
72
+	{
73
+		$this->set('PRC_name', $PRC_name);
74
+	}
75
+
76
+
77
+	/**
78
+	 *        Set Price Description
79
+	 *
80
+	 * @access        public
81
+	 * @param        string $PRC_desc
82
+	 */
83
+	public function set_description($PRC_desc = '')
84
+	{
85
+		$this->Set('PRC_desc', $PRC_desc);
86
+	}
87
+
88
+
89
+	/**
90
+	 *        set is_default
91
+	 *
92
+	 * @access        public
93
+	 * @param        bool $PRC_is_default
94
+	 */
95
+	public function set_is_default($PRC_is_default = false)
96
+	{
97
+		$this->set('PRC_is_default', $PRC_is_default);
98
+	}
99
+
100
+
101
+	/**
102
+	 *        set deleted
103
+	 *
104
+	 * @access        public
105
+	 * @param        bool $PRC_deleted
106
+	 */
107
+	public function set_deleted($PRC_deleted = null)
108
+	{
109
+		$this->set('PRC_deleted', $PRC_deleted);
110
+	}
111
+
112
+
113
+	/**
114
+	 *    get Price type
115
+	 *
116
+	 * @access        public
117
+	 * @return        int
118
+	 */
119
+	public function type()
120
+	{
121
+		return $this->get('PRT_ID');
122
+	}
123
+
124
+
125
+	/**
126
+	 *    get Price Amount
127
+	 *
128
+	 * @access        public
129
+	 * @return        float
130
+	 */
131
+	public function amount()
132
+	{
133
+		return $this->get('PRC_amount');
134
+	}
135
+
136
+
137
+	/**
138
+	 *    get Price Name
139
+	 *
140
+	 * @access        public
141
+	 * @return        string
142
+	 */
143
+	public function name()
144
+	{
145
+		return $this->get('PRC_name');
146
+	}
147
+
148
+
149
+	/**
150
+	 *    get Price description
151
+	 *
152
+	 * @access        public
153
+	 * @return        string
154
+	 */
155
+	public function desc()
156
+	{
157
+		return $this->get('PRC_desc');
158
+	}
159
+
160
+
161
+	/**
162
+	 *    get overrides
163
+	 *
164
+	 * @access        public
165
+	 * @return        int
166
+	 */
167
+	public function overrides()
168
+	{
169
+		return $this->get('PRC_overrides');
170
+	}
171
+
172
+
173
+	/**
174
+	 *    get order
175
+	 *
176
+	 * @access        public
177
+	 * @return        int
178
+	 */
179
+	public function order()
180
+	{
181
+		return $this->get('PRC_order');
182
+	}
183
+
184
+
185
+	/**
186
+	 * get the author of the price
187
+	 *
188
+	 * @since 4.5.0
189
+	 *
190
+	 * @return int
191
+	 */
192
+	public function wp_user()
193
+	{
194
+		return $this->get('PRC_wp_user');
195
+	}
196
+
197
+
198
+	/**
199
+	 *    get is_default
200
+	 *
201
+	 * @access        public
202
+	 * @return        bool
203
+	 */
204
+	public function is_default()
205
+	{
206
+		return $this->get('PRC_is_default');
207
+	}
208
+
209
+
210
+	/**
211
+	 *    get deleted
212
+	 *
213
+	 * @access        public
214
+	 * @return        bool
215
+	 */
216
+	public function deleted()
217
+	{
218
+		return $this->get('PRC_deleted');
219
+	}
220
+
221
+
222
+	/**
223
+	 * @return bool
224
+	 */
225
+	public function parent()
226
+	{
227
+		return $this->get('PRC_parent');
228
+	}
229
+
230
+
231
+	// some helper methods for getting info on the price_type for this price
232
+
233
+	/**
234
+	 * return whether the price is a base price or not
235
+	 *
236
+	 * @return boolean
237
+	 */
238
+	public function is_base_price()
239
+	{
240
+		$price_type = $this->type_obj();
241
+		return $price_type->base_type() === 1;
242
+	}
243
+
244
+
245
+	/**
246
+	 *
247
+	 * @return EE_Price_Type
248
+	 */
249
+	public function type_obj()
250
+	{
251
+		return $this->get_first_related('Price_Type');
252
+	}
253
+
254
+
255
+	/**
256
+	 * Simply indicates whether this price increases or decreases the total
257
+	 *
258
+	 * @return boolean true = discount, otherwise adds to the total
259
+	 */
260
+	public function is_discount()
261
+	{
262
+		$price_type = $this->type_obj();
263
+		return $price_type->is_discount();
264
+	}
265
+
266
+
267
+	/**
268
+	 * whether the price is a percentage or not
269
+	 *
270
+	 * @return boolean
271
+	 */
272
+	public function is_percent()
273
+	{
274
+		$price_type = $this->type_obj();
275
+		return $price_type->get('PRT_is_percent');
276
+	}
277
+
278
+
279
+	/**
280
+	 * return pretty price dependant on whether its a dollar or percent.
281
+	 *
282
+	 * @since 4.4.0
283
+	 *
284
+	 * @return string
285
+	 */
286
+	public function pretty_price()
287
+	{
288
+		return ! $this->is_percent() ? $this->get_pretty('PRC_amount') : $this->get('PRC_amount') . '%';
289
+	}
290
+
291
+
292
+	/**
293
+	 * @return mixed
294
+	 */
295
+	public function get_price_without_currency_symbol()
296
+	{
297
+		return str_replace(EE_Registry::instance()->CFG->currency->sign, '', $this->get_pretty('PRC_amount'));
298
+	}
299 299
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -285,7 +285,7 @@
 block discarded – undo
285 285
      */
286 286
     public function pretty_price()
287 287
     {
288
-        return ! $this->is_percent() ? $this->get_pretty('PRC_amount') : $this->get('PRC_amount') . '%';
288
+        return ! $this->is_percent() ? $this->get_pretty('PRC_amount') : $this->get('PRC_amount').'%';
289 289
     }
290 290
 
291 291
 
Please login to merge, or discard this patch.
core/db_classes/EE_Import.class.php 2 patches
Indentation   +950 added lines, -950 removed lines patch added patch discarded remove patch
@@ -14,91 +14,91 @@  discard block
 block discarded – undo
14 14
 class EE_Import implements ResettableInterface
15 15
 {
16 16
 
17
-    const do_insert = 'insert';
18
-    const do_update = 'update';
19
-    const do_nothing = 'nothing';
20
-
21
-
22
-    // instance of the EE_Import object
23
-    private static $_instance = null;
24
-
25
-    private static $_csv_array = array();
26
-
27
-    /**
28
-     *
29
-     * @var array of model names
30
-     */
31
-    private static $_model_list = array();
32
-
33
-    private static $_columns_to_save = array();
34
-
35
-    protected $_total_inserts = 0;
36
-    protected $_total_updates = 0;
37
-    protected $_total_insert_errors = 0;
38
-    protected $_total_update_errors = 0;
39
-
40
-
41
-    /**
42
-     *        private constructor to prevent direct creation
43
-     *
44
-     * @Constructor
45
-     * @access private
46
-     * @return void
47
-     */
48
-    private function __construct()
49
-    {
50
-        $this->_total_inserts = 0;
51
-        $this->_total_updates = 0;
52
-        $this->_total_insert_errors = 0;
53
-        $this->_total_update_errors = 0;
54
-    }
55
-
56
-
57
-    /**
58
-     *    @ singleton method used to instantiate class object
59
-     *    @ access public
60
-     *
61
-     * @return EE_Import
62
-     */
63
-    public static function instance()
64
-    {
65
-        // check if class object is instantiated
66
-        if (self::$_instance === null or ! is_object(self::$_instance) or ! (self::$_instance instanceof EE_Import)) {
67
-            self::$_instance = new self();
68
-        }
69
-        return self::$_instance;
70
-    }
71
-
72
-    /**
73
-     * Resets the importer
74
-     *
75
-     * @return EE_Import
76
-     */
77
-    public static function reset()
78
-    {
79
-        self::$_instance = null;
80
-        return self::instance();
81
-    }
82
-
83
-
84
-    /**
85
-     *    @ generates HTML for a file upload input and form
86
-     *    @ access    public
87
-     *
88
-     * @param    string $title  - heading for the form
89
-     * @param    string $intro  - additional text explaing what to do
90
-     * @param    string $page   - EE Admin page to direct form to - in the form "espresso_{pageslug}"
91
-     * @param    string $action - EE Admin page route array "action" that form will direct to
92
-     * @param    string $type   - type of file to import
93
-     *                          @ return    string
94
-     */
95
-    public function upload_form($title, $intro, $form_url, $action, $type)
96
-    {
97
-
98
-        $form_url = EE_Admin_Page::add_query_args_and_nonce(array('action' => $action), $form_url);
99
-
100
-        ob_start();
101
-        ?>
17
+	const do_insert = 'insert';
18
+	const do_update = 'update';
19
+	const do_nothing = 'nothing';
20
+
21
+
22
+	// instance of the EE_Import object
23
+	private static $_instance = null;
24
+
25
+	private static $_csv_array = array();
26
+
27
+	/**
28
+	 *
29
+	 * @var array of model names
30
+	 */
31
+	private static $_model_list = array();
32
+
33
+	private static $_columns_to_save = array();
34
+
35
+	protected $_total_inserts = 0;
36
+	protected $_total_updates = 0;
37
+	protected $_total_insert_errors = 0;
38
+	protected $_total_update_errors = 0;
39
+
40
+
41
+	/**
42
+	 *        private constructor to prevent direct creation
43
+	 *
44
+	 * @Constructor
45
+	 * @access private
46
+	 * @return void
47
+	 */
48
+	private function __construct()
49
+	{
50
+		$this->_total_inserts = 0;
51
+		$this->_total_updates = 0;
52
+		$this->_total_insert_errors = 0;
53
+		$this->_total_update_errors = 0;
54
+	}
55
+
56
+
57
+	/**
58
+	 *    @ singleton method used to instantiate class object
59
+	 *    @ access public
60
+	 *
61
+	 * @return EE_Import
62
+	 */
63
+	public static function instance()
64
+	{
65
+		// check if class object is instantiated
66
+		if (self::$_instance === null or ! is_object(self::$_instance) or ! (self::$_instance instanceof EE_Import)) {
67
+			self::$_instance = new self();
68
+		}
69
+		return self::$_instance;
70
+	}
71
+
72
+	/**
73
+	 * Resets the importer
74
+	 *
75
+	 * @return EE_Import
76
+	 */
77
+	public static function reset()
78
+	{
79
+		self::$_instance = null;
80
+		return self::instance();
81
+	}
82
+
83
+
84
+	/**
85
+	 *    @ generates HTML for a file upload input and form
86
+	 *    @ access    public
87
+	 *
88
+	 * @param    string $title  - heading for the form
89
+	 * @param    string $intro  - additional text explaing what to do
90
+	 * @param    string $page   - EE Admin page to direct form to - in the form "espresso_{pageslug}"
91
+	 * @param    string $action - EE Admin page route array "action" that form will direct to
92
+	 * @param    string $type   - type of file to import
93
+	 *                          @ return    string
94
+	 */
95
+	public function upload_form($title, $intro, $form_url, $action, $type)
96
+	{
97
+
98
+		$form_url = EE_Admin_Page::add_query_args_and_nonce(array('action' => $action), $form_url);
99
+
100
+		ob_start();
101
+		?>
102 102
         <div class="ee-upload-form-dv">
103 103
             <h3><?php echo $title; ?></h3>
104 104
             <p><?php echo $intro; ?></p>
@@ -114,874 +114,874 @@  discard block
 block discarded – undo
114 114
                 <b><?php _e('Attention', 'event_espresso'); ?></b><br/>
115 115
                 <?php echo sprintf(__('Accepts .%s file types only.', 'event_espresso'), $type); ?>
116 116
                 <?php echo __(
117
-                    'Please only import CSV files exported from Event Espresso, or compatible 3rd-party software.',
118
-                    'event_espresso'
119
-                ); ?>
117
+					'Please only import CSV files exported from Event Espresso, or compatible 3rd-party software.',
118
+					'event_espresso'
119
+				); ?>
120 120
             </p>
121 121
 
122 122
         </div>
123 123
 
124 124
         <?php
125
-        $uploader = ob_get_clean();
126
-        return $uploader;
127
-    }
128
-
129
-
130
-    /**
131
-     * @Import Event Espresso data - some code "borrowed" from event espresso csv_import.php
132
-     * @access public
133
-     * @return boolean success
134
-     */
135
-    public function import()
136
-    {
137
-
138
-        require_once(EE_CLASSES . 'EE_CSV.class.php');
139
-        $this->EE_CSV = EE_CSV::instance();
140
-
141
-        if (isset($_REQUEST['import'])) {
142
-            if (isset($_POST['csv_submitted'])) {
143
-                switch ($_FILES['file']['error'][0]) {
144
-                    case UPLOAD_ERR_OK:
145
-                        $error_msg = false;
146
-                        break;
147
-                    case UPLOAD_ERR_INI_SIZE:
148
-                        $error_msg = __(
149
-                            "'The uploaded file exceeds the upload_max_filesize directive in php.ini.'",
150
-                            "event_espresso"
151
-                        );
152
-                        break;
153
-                    case UPLOAD_ERR_FORM_SIZE:
154
-                        $error_msg = __(
155
-                            'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.',
156
-                            "event_espresso"
157
-                        );
158
-                        break;
159
-                    case UPLOAD_ERR_PARTIAL:
160
-                        $error_msg = __('The uploaded file was only partially uploaded.', "event_espresso");
161
-                        break;
162
-                    case UPLOAD_ERR_NO_FILE:
163
-                        $error_msg = __('No file was uploaded.', "event_espresso");
164
-                        break;
165
-                    case UPLOAD_ERR_NO_TMP_DIR:
166
-                        $error_msg = __('Missing a temporary folder.', "event_espresso");
167
-                        break;
168
-                    case UPLOAD_ERR_CANT_WRITE:
169
-                        $error_msg = __('Failed to write file to disk.', "event_espresso");
170
-                        break;
171
-                    case UPLOAD_ERR_EXTENSION:
172
-                        $error_msg = __('File upload stopped by extension.', "event_espresso");
173
-                        break;
174
-                    default:
175
-                        $error_msg = __(
176
-                            'An unknown error occurred and the file could not be uploaded',
177
-                            "event_espresso"
178
-                        );
179
-                        break;
180
-                }
181
-
182
-                if (! $error_msg) {
183
-                    $filename = $_FILES['file']['name'][0];
184
-                    $file_ext = substr(strrchr($filename, '.'), 1);
185
-                    $file_type = $_FILES['file']['type'][0];
186
-                    $temp_file = $_FILES['file']['tmp_name'][0];
187
-                    $filesize = $_FILES['file']['size'][0] / 1024;// convert from bytes to KB
188
-
189
-                    if ($file_ext == 'csv') {
190
-                        $max_upload = $this->EE_CSV->get_max_upload_size();// max upload size in KB
191
-                        if ($filesize < $max_upload || true) {
192
-                            $wp_upload_dir = str_replace(array('\\', '/'), DS, wp_upload_dir());
193
-                            $path_to_file = $wp_upload_dir['basedir'] . DS . 'espresso' . DS . $filename;
194
-
195
-                            if (move_uploaded_file($temp_file, $path_to_file)) {
196
-                                // convert csv to array
197
-                                $this->csv_array = $this->EE_CSV->import_csv_to_model_data_array($path_to_file);
198
-
199
-                                // was data successfully stored in an array?
200
-                                if (is_array($this->csv_array)) {
201
-                                    $import_what = str_replace('csv_import_', '', $_REQUEST['action']);
202
-                                    $import_what = str_replace('_', ' ', ucwords($import_what));
203
-                                    $processed_data = $this->csv_array;
204
-                                    $this->columns_to_save = false;
205
-
206
-                                    // if any imports require funcky processing, we'll catch them in the switch
207
-                                    switch ($_REQUEST['action']) {
208
-                                        case "import_events":
209
-                                        case "event_list":
210
-                                            $import_what = 'Event Details';
211
-                                            break;
212
-
213
-                                        case 'groupon_import_csv':
214
-                                            $import_what = 'Groupon Codes';
215
-                                            $processed_data = $this->process_groupon_codes();
216
-                                            break;
217
-                                    }
218
-                                    // save processed codes to db
219
-                                    if ($this->save_csv_data_array_to_db($processed_data, $this->columns_to_save)) {
220
-                                        return true;
221
-                                    }
222
-                                } else {
223
-                                    // no array? must be an error
224
-                                    EE_Error::add_error(
225
-                                        sprintf(__("No file seems to have been uploaded", "event_espresso")),
226
-                                        __FILE__,
227
-                                        __FUNCTION__,
228
-                                        __LINE__
229
-                                    );
230
-                                    return false;
231
-                                }
232
-                            } else {
233
-                                EE_Error::add_error(
234
-                                    sprintf(__("%s was not successfully uploaded", "event_espresso"), $filename),
235
-                                    __FILE__,
236
-                                    __FUNCTION__,
237
-                                    __LINE__
238
-                                );
239
-                                return false;
240
-                            }
241
-                        } else {
242
-                            EE_Error::add_error(
243
-                                sprintf(
244
-                                    __(
245
-                                        "%s was too large of a file and could not be uploaded. The max filesize is %s' KB.",
246
-                                        "event_espresso"
247
-                                    ),
248
-                                    $filename,
249
-                                    $max_upload
250
-                                ),
251
-                                __FILE__,
252
-                                __FUNCTION__,
253
-                                __LINE__
254
-                            );
255
-                            return false;
256
-                        }
257
-                    } else {
258
-                        EE_Error::add_error(
259
-                            sprintf(__("%s  had an invalid file extension, not uploaded", "event_espresso"), $filename),
260
-                            __FILE__,
261
-                            __FUNCTION__,
262
-                            __LINE__
263
-                        );
264
-                        return false;
265
-                    }
266
-                } else {
267
-                    EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
268
-                    return false;
269
-                }
270
-            }
271
-        }
272
-        return;
273
-    }
274
-
275
-
276
-    /**
277
-     *    Given an array of data (usually from a CSV import) attempts to save that data to the db.
278
-     *    If $model_name ISN'T provided, assumes that this is a 3d array, with toplevel keys being model names,
279
-     *    next level being numeric indexes adn each value representing a model object, and the last layer down
280
-     *    being keys of model fields and their proposed values.
281
-     *    If $model_name IS provided, assumes a 2d array of the bottom two layers previously mentioned.
282
-     *    If the CSV data says (in the metadata row) that it's from the SAME database,
283
-     *    we treat the IDs in the CSV as the normal IDs, and try to update those records. However, if those
284
-     *    IDs DON'T exist in the database, they're treated as temporary IDs,
285
-     *    which can used elsewhere to refer to the same object. Once an item
286
-     *    with a temporary ID gets inserted, we record its mapping from temporary
287
-     *    ID to real ID, and use the real ID in place of the temporary ID
288
-     *    when that temporary ID was used as a foreign key.
289
-     *    If the CSV data says (in the metadata again) that it's from a DIFFERENT database,
290
-     *    we treat all the IDs in the CSV as temporary ID- eg, if the CSV specifies an event with
291
-     *    ID 1, and the database already has an event with ID 1, we assume that's just a coincidence,
292
-     *    and insert a new event, and map it's temporary ID of 1 over to its new real ID.
293
-     *    An important exception are non-auto-increment primary keys. If one entry in the
294
-     *    CSV file has the same ID as one in the DB, we assume they are meant to be
295
-     *    the same item, and instead update the item in the DB with that same ID.
296
-     *    Also note, we remember the mappings permanently. So the 2nd, 3rd, and 10000th
297
-     *    time you import a CSV from a different site, we remember their mappings, and
298
-     * will try to update the item in the DB instead of inserting another item (eg
299
-     * if we previously imported an event with temporary ID 1, and then it got a
300
-     * real ID of 123, we remember that. So the next time we import an event with
301
-     * temporary ID, from the same site, we know that it's real ID is 123, and will
302
-     * update that event, instead of adding a new event).
303
-     *
304
-     * @access public
305
-     * @param array $csv_data_array - the array containing the csv data produced from
306
-     *                              EE_CSV::import_csv_to_model_data_array()
307
-     * @param array $fields_to_save - an array containing the csv column names as keys with the corresponding db table
308
-     *                              fields they will be saved to
309
-     * @return TRUE on success, FALSE on fail
310
-     * @throws \EE_Error
311
-     */
312
-    public function save_csv_data_array_to_db($csv_data_array, $model_name = false)
313
-    {
314
-        $success = false;
315
-        $error = false;
316
-        // whther to treat this import as if it's data froma different database or not
317
-        // ie, if it IS from a different database, ignore foreign keys whihf
318
-        $export_from_site_a_to_b = true;
319
-        // first level of array is not table information but a table name was passed to the function
320
-        // array is only two levels deep, so let's fix that by adding a level, else the next steps will fail
321
-        if ($model_name) {
322
-            $csv_data_array = array($csv_data_array);
323
-        }
324
-        // begin looking through the $csv_data_array, expecting the toplevel key to be the model's name...
325
-        $old_site_url = 'none-specified';
326
-        // hanlde metadata
327
-        if (isset($csv_data_array[ EE_CSV::metadata_header ])) {
328
-            $csv_metadata = array_shift($csv_data_array[ EE_CSV::metadata_header ]);
329
-            // ok so its metadata, dont try to save it to ehte db obviously...
330
-            if (isset($csv_metadata['site_url']) && $csv_metadata['site_url'] == site_url()) {
331
-                EE_Error::add_attention(
332
-                    sprintf(
333
-                        __(
334
-                            "CSV Data appears to be from the same database, so attempting to update data",
335
-                            "event_espresso"
336
-                        )
337
-                    )
338
-                );
339
-                $export_from_site_a_to_b = false;
340
-            } else {
341
-                $old_site_url = isset($csv_metadata['site_url']) ? $csv_metadata['site_url'] : $old_site_url;
342
-                EE_Error::add_attention(
343
-                    sprintf(
344
-                        __(
345
-                            "CSV Data appears to be from a different database (%s instead of %s), so we assume IDs in the CSV data DO NOT correspond to IDs in this database",
346
-                            "event_espresso"
347
-                        ),
348
-                        $old_site_url,
349
-                        site_url()
350
-                    )
351
-                );
352
-            };
353
-            unset($csv_data_array[ EE_CSV::metadata_header ]);
354
-        }
355
-        /**
356
-         * @var $old_db_to_new_db_mapping 2d array: toplevel keys being model names, bottom-level keys being the original key, and
357
-         * the value will be the newly-inserted ID.
358
-         * If we have already imported data from the same website via CSV, it shoudl be kept in this wp option
359
-         */
360
-        $old_db_to_new_db_mapping = get_option('ee_id_mapping_from' . sanitize_title($old_site_url), array());
361
-        if ($old_db_to_new_db_mapping) {
362
-            EE_Error::add_attention(
363
-                sprintf(
364
-                    __(
365
-                        "We noticed you have imported data via CSV from %s before. Because of this, IDs in your CSV have been mapped to their new IDs in %s",
366
-                        "event_espresso"
367
-                    ),
368
-                    $old_site_url,
369
-                    site_url()
370
-                )
371
-            );
372
-        }
373
-        $old_db_to_new_db_mapping = $this->save_data_rows_to_db(
374
-            $csv_data_array,
375
-            $export_from_site_a_to_b,
376
-            $old_db_to_new_db_mapping
377
-        );
378
-
379
-        // save the mapping from old db to new db in case they try re-importing the same data from the same website again
380
-        update_option('ee_id_mapping_from' . sanitize_title($old_site_url), $old_db_to_new_db_mapping);
381
-
382
-        if ($this->_total_updates > 0) {
383
-            EE_Error::add_success(
384
-                sprintf(
385
-                    __("%s existing records in the database were updated.", "event_espresso"),
386
-                    $this->_total_updates
387
-                )
388
-            );
389
-            $success = true;
390
-        }
391
-        if ($this->_total_inserts > 0) {
392
-            EE_Error::add_success(
393
-                sprintf(__("%s new records were added to the database.", "event_espresso"), $this->_total_inserts)
394
-            );
395
-            $success = true;
396
-        }
397
-
398
-        if ($this->_total_update_errors > 0) {
399
-            EE_Error::add_error(
400
-                sprintf(
401
-                    __(
402
-                        "'One or more errors occurred, and a total of %s existing records in the database were <strong>not</strong> updated.'",
403
-                        "event_espresso"
404
-                    ),
405
-                    $this->_total_update_errors
406
-                ),
407
-                __FILE__,
408
-                __FUNCTION__,
409
-                __LINE__
410
-            );
411
-            $error = true;
412
-        }
413
-        if ($this->_total_insert_errors > 0) {
414
-            EE_Error::add_error(
415
-                sprintf(
416
-                    __(
417
-                        "One or more errors occurred, and a total of %s new records were <strong>not</strong> added to the database.'",
418
-                        "event_espresso"
419
-                    ),
420
-                    $this->_total_insert_errors
421
-                ),
422
-                __FILE__,
423
-                __FUNCTION__,
424
-                __LINE__
425
-            );
426
-            $error = true;
427
-        }
428
-
429
-        // lastly, we need to update the datetime and ticket sold amounts
430
-        // as those may have been affected by this
431
-        EEM_Ticket::instance()->update_tickets_sold(EEM_Ticket::instance()->get_all());
432
-
433
-        // if there was at least one success and absolutely no errors
434
-        if ($success && ! $error) {
435
-            return true;
436
-        } else {
437
-            return false;
438
-        }
439
-    }
440
-
441
-
442
-    /**
443
-     * Processes the array of data, given the knowledge that it's from the same database or a different one,
444
-     * and the mapping from temporary IDs to real IDs.
445
-     * If the data is from a different database, we treat the primary keys and their corresponding
446
-     * foreign keys as "temp Ids", basically identifiers that get mapped to real primary keys
447
-     * in the real target database. As items are inserted, their temporary primary keys
448
-     * are mapped to the real IDs in the target database. Also, before doing any update or
449
-     * insert, we replace all the temp ID which are foreign keys with their mapped real IDs.
450
-     * An exception: string primary keys are treated as real IDs, or else we'd need to
451
-     * dynamically generate new string primary keys which would be very awkard for the country table etc.
452
-     * Also, models with no primary key are strange too. We combine use their primar key INDEX (a
453
-     * combination of fields) to create a unique string identifying the row and store
454
-     * those in the mapping.
455
-     *
456
-     * If the data is from the same database, we usually treat primary keys as real IDs.
457
-     * An exception is if there is nothing in the database for that ID. If that's the case,
458
-     * we need to insert a new row for that ID, and then map from the non-existent ID
459
-     * to the newly-inserted real ID.
460
-     *
461
-     * @param type $csv_data_array
462
-     * @param type $export_from_site_a_to_b
463
-     * @param type $old_db_to_new_db_mapping
464
-     * @return array updated $old_db_to_new_db_mapping
465
-     */
466
-    public function save_data_rows_to_db($csv_data_array, $export_from_site_a_to_b, $old_db_to_new_db_mapping)
467
-    {
468
-        foreach ($csv_data_array as $model_name_in_csv_data => $model_data_from_import) {
469
-            // now check that assumption was correct. If
470
-            if (EE_Registry::instance()->is_model_name($model_name_in_csv_data)) {
471
-                $model_name = $model_name_in_csv_data;
472
-            } else {
473
-                // no table info in the array and no table name passed to the function?? FAIL
474
-                EE_Error::add_error(
475
-                    __(
476
-                        'No table information was specified and/or found, therefore the import could not be completed',
477
-                        'event_espresso'
478
-                    ),
479
-                    __FILE__,
480
-                    __FUNCTION__,
481
-                    __LINE__
482
-                );
483
-                return false;
484
-            }
485
-            /* @var $model EEM_Base */
486
-            $model = EE_Registry::instance()->load_model($model_name);
487
-
488
-            // so without further ado, scanning all the data provided for primary keys and their inital values
489
-            foreach ($model_data_from_import as $model_object_data) {
490
-                // before we do ANYTHING, make sure the csv row wasn't just completely blank
491
-                $row_is_completely_empty = true;
492
-                foreach ($model_object_data as $field) {
493
-                    if ($field) {
494
-                        $row_is_completely_empty = false;
495
-                    }
496
-                }
497
-                if ($row_is_completely_empty) {
498
-                    continue;
499
-                }
500
-                // find the PK in the row of data (or a combined key if
501
-                // there is no primary key)
502
-                if ($model->has_primary_key_field()) {
503
-                    $id_in_csv = $model_object_data[ $model->primary_key_name() ];
504
-                } else {
505
-                    $id_in_csv = $model->get_index_primary_key_string($model_object_data);
506
-                }
507
-
508
-
509
-                $model_object_data = $this->_replace_temp_ids_with_mappings(
510
-                    $model_object_data,
511
-                    $model,
512
-                    $old_db_to_new_db_mapping,
513
-                    $export_from_site_a_to_b
514
-                );
515
-                // now we need to decide if we're going to add a new model object given the $model_object_data,
516
-                // or just update.
517
-                if ($export_from_site_a_to_b) {
518
-                    $what_to_do = $this->_decide_whether_to_insert_or_update_given_data_from_other_db(
519
-                        $id_in_csv,
520
-                        $model_object_data,
521
-                        $model,
522
-                        $old_db_to_new_db_mapping
523
-                    );
524
-                } else {// this is just a re-import
525
-                    $what_to_do = $this->_decide_whether_to_insert_or_update_given_data_from_same_db(
526
-                        $id_in_csv,
527
-                        $model_object_data,
528
-                        $model,
529
-                        $old_db_to_new_db_mapping
530
-                    );
531
-                }
532
-                if ($what_to_do == self::do_nothing) {
533
-                    continue;
534
-                }
535
-
536
-                // double-check we actually want to insert, if that's what we're planning
537
-                // based on whether this item would be unique in the DB or not
538
-                if ($what_to_do == self::do_insert) {
539
-                    // we're supposed to be inserting. But wait, will this thing
540
-                    // be acceptable if inserted?
541
-                    $conflicting = $model->get_one_conflicting($model_object_data, false);
542
-                    if ($conflicting) {
543
-                        // ok, this item would conflict if inserted. Just update the item that it conflicts with.
544
-                        $what_to_do = self::do_update;
545
-                        // and if this model has a primary key, remember its mapping
546
-                        if ($model->has_primary_key_field()) {
547
-                            $old_db_to_new_db_mapping[ $model_name ][ $id_in_csv ] = $conflicting->ID();
548
-                            $model_object_data[ $model->primary_key_name() ] = $conflicting->ID();
549
-                        } else {
550
-                            // we want to update this conflicting item, instead of inserting a conflicting item
551
-                            // so we need to make sure they match entirely (its possible that they only conflicted on one field, but we need them to match on other fields
552
-                            // for the WHERE conditions in the update). At the time of this comment, there were no models like this
553
-                            foreach ($model->get_combined_primary_key_fields() as $key_field) {
554
-                                $model_object_data[ $key_field->get_name() ] = $conflicting->get(
555
-                                    $key_field->get_name()
556
-                                );
557
-                            }
558
-                        }
559
-                    }
560
-                }
561
-                if ($what_to_do == self::do_insert) {
562
-                    $old_db_to_new_db_mapping = $this->_insert_from_data_array(
563
-                        $id_in_csv,
564
-                        $model_object_data,
565
-                        $model,
566
-                        $old_db_to_new_db_mapping
567
-                    );
568
-                } elseif ($what_to_do == self::do_update) {
569
-                    $old_db_to_new_db_mapping = $this->_update_from_data_array(
570
-                        $id_in_csv,
571
-                        $model_object_data,
572
-                        $model,
573
-                        $old_db_to_new_db_mapping
574
-                    );
575
-                } else {
576
-                    throw new EE_Error(
577
-                        sprintf(
578
-                            __(
579
-                                'Programming error. We shoudl be inserting or updating, but instead we are being told to "%s", whifh is invalid',
580
-                                'event_espresso'
581
-                            ),
582
-                            $what_to_do
583
-                        )
584
-                    );
585
-                }
586
-            }
587
-        }
588
-        return $old_db_to_new_db_mapping;
589
-    }
590
-
591
-
592
-    /**
593
-     * Decides whether or not to insert, given that this data is from another database.
594
-     * So, if the primary key of this $model_object_data already exists in the database,
595
-     * it's just a coincidence and we should still insert. The only time we should
596
-     * update is when we know what it maps to, or there's something that would
597
-     * conflict (and we should instead just update that conflicting thing)
598
-     *
599
-     * @param string   $id_in_csv
600
-     * @param array    $model_object_data        by reference so it can be modified
601
-     * @param EEM_Base $model
602
-     * @param array    $old_db_to_new_db_mapping by reference so it can be modified
603
-     * @return string one of the consts on this class that starts with do_*
604
-     */
605
-    protected function _decide_whether_to_insert_or_update_given_data_from_other_db(
606
-        $id_in_csv,
607
-        $model_object_data,
608
-        $model,
609
-        $old_db_to_new_db_mapping
610
-    ) {
611
-        $model_name = $model->get_this_model_name();
612
-        // if it's a site-to-site export-and-import, see if this modelobject's id
613
-        // in the old data that we know of
614
-        if (isset($old_db_to_new_db_mapping[ $model_name ][ $id_in_csv ])) {
615
-            return self::do_update;
616
-        } else {
617
-            return self::do_insert;
618
-        }
619
-    }
620
-
621
-    /**
622
-     * If this thing basically already exists in the database, we want to update it;
623
-     * otherwise insert it (ie, someone tweaked the CSV file, or the item was
624
-     * deleted in the database so it should be re-inserted)
625
-     *
626
-     * @param type     $id_in_csv
627
-     * @param type     $model_object_data
628
-     * @param EEM_Base $model
629
-     * @param type     $old_db_to_new_db_mapping
630
-     * @return
631
-     */
632
-    protected function _decide_whether_to_insert_or_update_given_data_from_same_db(
633
-        $id_in_csv,
634
-        $model_object_data,
635
-        $model
636
-    ) {
637
-        // in this case, check if this thing ACTUALLY exists in the database
638
-        if ($model->get_one_conflicting($model_object_data)) {
639
-            return self::do_update;
640
-        } else {
641
-            return self::do_insert;
642
-        }
643
-    }
644
-
645
-    /**
646
-     * Using the $old_db_to_new_db_mapping array, replaces all the temporary IDs
647
-     * with their mapped real IDs. Eg, if importing from site A to B, the mapping
648
-     * file may indicate that the ID "my_event_id" maps to an actual event ID of 123.
649
-     * So this function searches for any event temp Ids called "my_event_id" and
650
-     * replaces them with 123.
651
-     * Also, if there is no temp ID for the INT foreign keys from another database,
652
-     * replaces them with 0 or the field's default.
653
-     *
654
-     * @param type     $model_object_data
655
-     * @param EEM_Base $model
656
-     * @param type     $old_db_to_new_db_mapping
657
-     * @param boolean  $export_from_site_a_to_b
658
-     * @return array updated model object data with temp IDs removed
659
-     */
660
-    protected function _replace_temp_ids_with_mappings(
661
-        $model_object_data,
662
-        $model,
663
-        $old_db_to_new_db_mapping,
664
-        $export_from_site_a_to_b
665
-    ) {
666
-        // if this model object's primary key is in the mapping, replace it
667
-        if ($model->has_primary_key_field() &&
668
-            $model->get_primary_key_field()->is_auto_increment() &&
669
-            isset($old_db_to_new_db_mapping[ $model->get_this_model_name() ]) &&
670
-            isset(
671
-                $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $model_object_data[ $model->primary_key_name() ] ]
672
-            )) {
673
-            $model_object_data[ $model->primary_key_name() ] = $old_db_to_new_db_mapping[ $model->get_this_model_name(
674
-            ) ][ $model_object_data[ $model->primary_key_name() ] ];
675
-        }
676
-
677
-        try {
678
-            $model_name_field = $model->get_field_containing_related_model_name();
679
-            $models_pointed_to_by_model_name_field = $model_name_field->get_model_names_pointed_to();
680
-        } catch (EE_Error $e) {
681
-            $model_name_field = null;
682
-            $models_pointed_to_by_model_name_field = array();
683
-        }
684
-        foreach ($model->field_settings(true) as $field_obj) {
685
-            if ($field_obj instanceof EE_Foreign_Key_Int_Field) {
686
-                $models_pointed_to = $field_obj->get_model_names_pointed_to();
687
-                $found_a_mapping = false;
688
-                foreach ($models_pointed_to as $model_pointed_to_by_fk) {
689
-                    if ($model_name_field) {
690
-                        $value_of_model_name_field = $model_object_data[ $model_name_field->get_name() ];
691
-                        if ($value_of_model_name_field == $model_pointed_to_by_fk) {
692
-                            $model_object_data[ $field_obj->get_name() ] = $this->_find_mapping_in(
693
-                                $model_object_data[ $field_obj->get_name() ],
694
-                                $model_pointed_to_by_fk,
695
-                                $old_db_to_new_db_mapping,
696
-                                $export_from_site_a_to_b
697
-                            );
698
-                            $found_a_mapping = true;
699
-                            break;
700
-                        }
701
-                    } else {
702
-                        $model_object_data[ $field_obj->get_name() ] = $this->_find_mapping_in(
703
-                            $model_object_data[ $field_obj->get_name() ],
704
-                            $model_pointed_to_by_fk,
705
-                            $old_db_to_new_db_mapping,
706
-                            $export_from_site_a_to_b
707
-                        );
708
-                        $found_a_mapping = true;
709
-                    }
710
-                    // once we've found a mapping for this field no need to continue
711
-                    if ($found_a_mapping) {
712
-                        break;
713
-                    }
714
-                }
715
-            } else {
716
-                // it's a string foreign key (which we leave alone, because those are things
717
-                // like country names, which we'd really rather not make 2 USAs etc (we'd actually
718
-                // prefer to just update one)
719
-                // or it's just a regular value that ought to be replaced
720
-            }
721
-        }
722
-        //
723
-        if ($model instanceof EEM_Term_Taxonomy) {
724
-            $model_object_data = $this->_handle_split_term_ids($model_object_data);
725
-        }
726
-        return $model_object_data;
727
-    }
728
-
729
-    /**
730
-     * If the data was exported PRE-4.2, but then imported POST-4.2, then the term_id
731
-     * this term-taxonomy refers to may be out-of-date so we need to update it.
732
-     * see https://make.wordpress.org/core/2015/02/16/taxonomy-term-splitting-in-4-2-a-developer-guide/
733
-     *
734
-     * @param type $model_object_data
735
-     * @return array new model object data
736
-     */
737
-    protected function _handle_split_term_ids($model_object_data)
738
-    {
739
-        if (isset($model_object_data['term_id'])
740
-            && isset($model_object_data['taxonomy'])
741
-            && apply_filters(
742
-                'FHEE__EE_Import__handle_split_term_ids__function_exists',
743
-                function_exists('wp_get_split_term'),
744
-                $model_object_data
745
-            )) {
746
-            $new_term_id = wp_get_split_term($model_object_data['term_id'], $model_object_data['taxonomy']);
747
-            if ($new_term_id) {
748
-                $model_object_data['term_id'] = $new_term_id;
749
-            }
750
-        }
751
-        return $model_object_data;
752
-    }
753
-
754
-    /**
755
-     * Given the object's ID and its model's name, find it int he mapping data,
756
-     * bearing in mind where it came from
757
-     *
758
-     * @param type   $object_id
759
-     * @param string $model_name
760
-     * @param array  $old_db_to_new_db_mapping
761
-     * @param type   $export_from_site_a_to_b
762
-     * @return int
763
-     */
764
-    protected function _find_mapping_in($object_id, $model_name, $old_db_to_new_db_mapping, $export_from_site_a_to_b)
765
-    {
766
-        if (isset($old_db_to_new_db_mapping[ $model_name ][ $object_id ])) {
767
-            return $old_db_to_new_db_mapping[ $model_name ][ $object_id ];
768
-        } elseif ($object_id == '0' || $object_id == '') {
769
-            // leave as-is
770
-            return $object_id;
771
-        } elseif ($export_from_site_a_to_b) {
772
-            // we couldn't find a mapping for this, and it's from a different site,
773
-            // so blank it out
774
-            return null;
775
-        } elseif (! $export_from_site_a_to_b) {
776
-            // we coudln't find a mapping for this, but it's from thsi DB anyway
777
-            // so let's just leave it as-is
778
-            return $object_id;
779
-        }
780
-    }
781
-
782
-    /**
783
-     *
784
-     * @param type     $id_in_csv
785
-     * @param type     $model_object_data
786
-     * @param EEM_Base $model
787
-     * @param type     $old_db_to_new_db_mapping
788
-     * @return array updated $old_db_to_new_db_mapping
789
-     */
790
-    protected function _insert_from_data_array($id_in_csv, $model_object_data, $model, $old_db_to_new_db_mapping)
791
-    {
792
-        // remove the primary key, if there is one (we don't want it for inserts OR updates)
793
-        // we'll put it back in if we need it
794
-        if ($model->has_primary_key_field() && $model->get_primary_key_field()->is_auto_increment()) {
795
-            $effective_id = $model_object_data[ $model->primary_key_name() ];
796
-            unset($model_object_data[ $model->primary_key_name() ]);
797
-        } else {
798
-            $effective_id = $model->get_index_primary_key_string($model_object_data);
799
-        }
800
-        // the model takes care of validating the CSV's input
801
-        try {
802
-            $new_id = $model->insert($model_object_data);
803
-            if ($new_id) {
804
-                $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $id_in_csv ] = $new_id;
805
-                $this->_total_inserts++;
806
-                EE_Error::add_success(
807
-                    sprintf(
808
-                        __("Successfully added new %s (with id %s) with csv data %s", "event_espresso"),
809
-                        $model->get_this_model_name(),
810
-                        $new_id,
811
-                        implode(",", $model_object_data)
812
-                    )
813
-                );
814
-            } else {
815
-                $this->_total_insert_errors++;
816
-                // put the ID used back in there for the error message
817
-                if ($model->has_primary_key_field()) {
818
-                    $model_object_data[ $model->primary_key_name() ] = $effective_id;
819
-                }
820
-                EE_Error::add_error(
821
-                    sprintf(
822
-                        __("Could not insert new %s with the csv data: %s", "event_espresso"),
823
-                        $model->get_this_model_name(),
824
-                        http_build_query($model_object_data)
825
-                    ),
826
-                    __FILE__,
827
-                    __FUNCTION__,
828
-                    __LINE__
829
-                );
830
-            }
831
-        } catch (EE_Error $e) {
832
-            $this->_total_insert_errors++;
833
-            if ($model->has_primary_key_field()) {
834
-                $model_object_data[ $model->primary_key_name() ] = $effective_id;
835
-            }
836
-            EE_Error::add_error(
837
-                sprintf(
838
-                    __("Could not insert new %s with the csv data: %s because %s", "event_espresso"),
839
-                    $model->get_this_model_name(),
840
-                    implode(",", $model_object_data),
841
-                    $e->getMessage()
842
-                ),
843
-                __FILE__,
844
-                __FUNCTION__,
845
-                __LINE__
846
-            );
847
-        }
848
-        return $old_db_to_new_db_mapping;
849
-    }
850
-
851
-    /**
852
-     * Given the model object data, finds the row to update and updates it
853
-     *
854
-     * @param string|int $id_in_csv
855
-     * @param array      $model_object_data
856
-     * @param EEM_Base   $model
857
-     * @param array      $old_db_to_new_db_mapping
858
-     * @return array updated $old_db_to_new_db_mapping
859
-     */
860
-    protected function _update_from_data_array($id_in_csv, $model_object_data, $model, $old_db_to_new_db_mapping)
861
-    {
862
-        try {
863
-            // let's keep two copies of the model object data:
864
-            // one for performing an update, one for everthing else
865
-            $model_object_data_for_update = $model_object_data;
866
-            if ($model->has_primary_key_field()) {
867
-                $conditions = array($model->primary_key_name() => $model_object_data[ $model->primary_key_name() ]);
868
-                // remove the primary key because we shouldn't use it for updating
869
-                unset($model_object_data_for_update[ $model->primary_key_name() ]);
870
-            } elseif ($model->get_combined_primary_key_fields() > 1) {
871
-                $conditions = array();
872
-                foreach ($model->get_combined_primary_key_fields() as $key_field) {
873
-                    $conditions[ $key_field->get_name() ] = $model_object_data[ $key_field->get_name() ];
874
-                }
875
-            } else {
876
-                $model->primary_key_name(
877
-                );// this shoudl just throw an exception, explaining that we dont have a primary key (or a combine dkey)
878
-            }
879
-
880
-            $success = $model->update($model_object_data_for_update, array($conditions));
881
-            if ($success) {
882
-                $this->_total_updates++;
883
-                EE_Error::add_success(
884
-                    sprintf(
885
-                        __("Successfully updated %s with csv data %s", "event_espresso"),
886
-                        $model->get_this_model_name(),
887
-                        implode(",", $model_object_data_for_update)
888
-                    )
889
-                );
890
-                // we should still record the mapping even though it was an update
891
-                // because if we were going to insert somethign but it was going to conflict
892
-                // we would have last-minute decided to update. So we'd like to know what we updated
893
-                // and so we record what record ended up being updated using the mapping
894
-                if ($model->has_primary_key_field()) {
895
-                    $new_key_for_mapping = $model_object_data[ $model->primary_key_name() ];
896
-                } else {
897
-                    // no primary key just a combined key
898
-                    $new_key_for_mapping = $model->get_index_primary_key_string($model_object_data);
899
-                }
900
-                $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $id_in_csv ] = $new_key_for_mapping;
901
-            } else {
902
-                $matched_items = $model->get_all(array($conditions));
903
-                if (! $matched_items) {
904
-                    // no items were matched (so we shouldn't have updated)... but then we should have inserted? what the heck?
905
-                    $this->_total_update_errors++;
906
-                    EE_Error::add_error(
907
-                        sprintf(
908
-                            __(
909
-                                "Could not update %s with the csv data: '%s' for an unknown reason (using WHERE conditions %s)",
910
-                                "event_espresso"
911
-                            ),
912
-                            $model->get_this_model_name(),
913
-                            http_build_query($model_object_data),
914
-                            http_build_query($conditions)
915
-                        ),
916
-                        __FILE__,
917
-                        __FUNCTION__,
918
-                        __LINE__
919
-                    );
920
-                } else {
921
-                    $this->_total_updates++;
922
-                    EE_Error::add_success(
923
-                        sprintf(
924
-                            __(
925
-                                "%s with csv data '%s' was found in the database and didn't need updating because all the data is identical.",
926
-                                "event_espresso"
927
-                            ),
928
-                            $model->get_this_model_name(),
929
-                            implode(",", $model_object_data)
930
-                        )
931
-                    );
932
-                }
933
-            }
934
-        } catch (EE_Error $e) {
935
-            $this->_total_update_errors++;
936
-            $basic_message = sprintf(
937
-                __("Could not update %s with the csv data: %s because %s", "event_espresso"),
938
-                $model->get_this_model_name(),
939
-                implode(",", $model_object_data),
940
-                $e->getMessage()
941
-            );
942
-            $debug_message = $basic_message . ' Stack trace: ' . $e->getTraceAsString();
943
-            EE_Error::add_error("$basic_message | $debug_message", __FILE__, __FUNCTION__, __LINE__);
944
-        }
945
-        return $old_db_to_new_db_mapping;
946
-    }
947
-
948
-    /**
949
-     * Gets the number of inserts performed since importer was instantiated or reset
950
-     *
951
-     * @return int
952
-     */
953
-    public function get_total_inserts()
954
-    {
955
-        return $this->_total_inserts;
956
-    }
957
-
958
-    /**
959
-     *  Gets the number of insert errors since importer was instantiated or reset
960
-     *
961
-     * @return int
962
-     */
963
-    public function get_total_insert_errors()
964
-    {
965
-        return $this->_total_insert_errors;
966
-    }
967
-
968
-    /**
969
-     *  Gets the number of updates performed since importer was instantiated or reset
970
-     *
971
-     * @return int
972
-     */
973
-    public function get_total_updates()
974
-    {
975
-        return $this->_total_updates;
976
-    }
977
-
978
-    /**
979
-     *  Gets the number of update errors since importer was instantiated or reset
980
-     *
981
-     * @return int
982
-     */
983
-    public function get_total_update_errors()
984
-    {
985
-        return $this->_total_update_errors;
986
-    }
125
+		$uploader = ob_get_clean();
126
+		return $uploader;
127
+	}
128
+
129
+
130
+	/**
131
+	 * @Import Event Espresso data - some code "borrowed" from event espresso csv_import.php
132
+	 * @access public
133
+	 * @return boolean success
134
+	 */
135
+	public function import()
136
+	{
137
+
138
+		require_once(EE_CLASSES . 'EE_CSV.class.php');
139
+		$this->EE_CSV = EE_CSV::instance();
140
+
141
+		if (isset($_REQUEST['import'])) {
142
+			if (isset($_POST['csv_submitted'])) {
143
+				switch ($_FILES['file']['error'][0]) {
144
+					case UPLOAD_ERR_OK:
145
+						$error_msg = false;
146
+						break;
147
+					case UPLOAD_ERR_INI_SIZE:
148
+						$error_msg = __(
149
+							"'The uploaded file exceeds the upload_max_filesize directive in php.ini.'",
150
+							"event_espresso"
151
+						);
152
+						break;
153
+					case UPLOAD_ERR_FORM_SIZE:
154
+						$error_msg = __(
155
+							'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.',
156
+							"event_espresso"
157
+						);
158
+						break;
159
+					case UPLOAD_ERR_PARTIAL:
160
+						$error_msg = __('The uploaded file was only partially uploaded.', "event_espresso");
161
+						break;
162
+					case UPLOAD_ERR_NO_FILE:
163
+						$error_msg = __('No file was uploaded.', "event_espresso");
164
+						break;
165
+					case UPLOAD_ERR_NO_TMP_DIR:
166
+						$error_msg = __('Missing a temporary folder.', "event_espresso");
167
+						break;
168
+					case UPLOAD_ERR_CANT_WRITE:
169
+						$error_msg = __('Failed to write file to disk.', "event_espresso");
170
+						break;
171
+					case UPLOAD_ERR_EXTENSION:
172
+						$error_msg = __('File upload stopped by extension.', "event_espresso");
173
+						break;
174
+					default:
175
+						$error_msg = __(
176
+							'An unknown error occurred and the file could not be uploaded',
177
+							"event_espresso"
178
+						);
179
+						break;
180
+				}
181
+
182
+				if (! $error_msg) {
183
+					$filename = $_FILES['file']['name'][0];
184
+					$file_ext = substr(strrchr($filename, '.'), 1);
185
+					$file_type = $_FILES['file']['type'][0];
186
+					$temp_file = $_FILES['file']['tmp_name'][0];
187
+					$filesize = $_FILES['file']['size'][0] / 1024;// convert from bytes to KB
188
+
189
+					if ($file_ext == 'csv') {
190
+						$max_upload = $this->EE_CSV->get_max_upload_size();// max upload size in KB
191
+						if ($filesize < $max_upload || true) {
192
+							$wp_upload_dir = str_replace(array('\\', '/'), DS, wp_upload_dir());
193
+							$path_to_file = $wp_upload_dir['basedir'] . DS . 'espresso' . DS . $filename;
194
+
195
+							if (move_uploaded_file($temp_file, $path_to_file)) {
196
+								// convert csv to array
197
+								$this->csv_array = $this->EE_CSV->import_csv_to_model_data_array($path_to_file);
198
+
199
+								// was data successfully stored in an array?
200
+								if (is_array($this->csv_array)) {
201
+									$import_what = str_replace('csv_import_', '', $_REQUEST['action']);
202
+									$import_what = str_replace('_', ' ', ucwords($import_what));
203
+									$processed_data = $this->csv_array;
204
+									$this->columns_to_save = false;
205
+
206
+									// if any imports require funcky processing, we'll catch them in the switch
207
+									switch ($_REQUEST['action']) {
208
+										case "import_events":
209
+										case "event_list":
210
+											$import_what = 'Event Details';
211
+											break;
212
+
213
+										case 'groupon_import_csv':
214
+											$import_what = 'Groupon Codes';
215
+											$processed_data = $this->process_groupon_codes();
216
+											break;
217
+									}
218
+									// save processed codes to db
219
+									if ($this->save_csv_data_array_to_db($processed_data, $this->columns_to_save)) {
220
+										return true;
221
+									}
222
+								} else {
223
+									// no array? must be an error
224
+									EE_Error::add_error(
225
+										sprintf(__("No file seems to have been uploaded", "event_espresso")),
226
+										__FILE__,
227
+										__FUNCTION__,
228
+										__LINE__
229
+									);
230
+									return false;
231
+								}
232
+							} else {
233
+								EE_Error::add_error(
234
+									sprintf(__("%s was not successfully uploaded", "event_espresso"), $filename),
235
+									__FILE__,
236
+									__FUNCTION__,
237
+									__LINE__
238
+								);
239
+								return false;
240
+							}
241
+						} else {
242
+							EE_Error::add_error(
243
+								sprintf(
244
+									__(
245
+										"%s was too large of a file and could not be uploaded. The max filesize is %s' KB.",
246
+										"event_espresso"
247
+									),
248
+									$filename,
249
+									$max_upload
250
+								),
251
+								__FILE__,
252
+								__FUNCTION__,
253
+								__LINE__
254
+							);
255
+							return false;
256
+						}
257
+					} else {
258
+						EE_Error::add_error(
259
+							sprintf(__("%s  had an invalid file extension, not uploaded", "event_espresso"), $filename),
260
+							__FILE__,
261
+							__FUNCTION__,
262
+							__LINE__
263
+						);
264
+						return false;
265
+					}
266
+				} else {
267
+					EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
268
+					return false;
269
+				}
270
+			}
271
+		}
272
+		return;
273
+	}
274
+
275
+
276
+	/**
277
+	 *    Given an array of data (usually from a CSV import) attempts to save that data to the db.
278
+	 *    If $model_name ISN'T provided, assumes that this is a 3d array, with toplevel keys being model names,
279
+	 *    next level being numeric indexes adn each value representing a model object, and the last layer down
280
+	 *    being keys of model fields and their proposed values.
281
+	 *    If $model_name IS provided, assumes a 2d array of the bottom two layers previously mentioned.
282
+	 *    If the CSV data says (in the metadata row) that it's from the SAME database,
283
+	 *    we treat the IDs in the CSV as the normal IDs, and try to update those records. However, if those
284
+	 *    IDs DON'T exist in the database, they're treated as temporary IDs,
285
+	 *    which can used elsewhere to refer to the same object. Once an item
286
+	 *    with a temporary ID gets inserted, we record its mapping from temporary
287
+	 *    ID to real ID, and use the real ID in place of the temporary ID
288
+	 *    when that temporary ID was used as a foreign key.
289
+	 *    If the CSV data says (in the metadata again) that it's from a DIFFERENT database,
290
+	 *    we treat all the IDs in the CSV as temporary ID- eg, if the CSV specifies an event with
291
+	 *    ID 1, and the database already has an event with ID 1, we assume that's just a coincidence,
292
+	 *    and insert a new event, and map it's temporary ID of 1 over to its new real ID.
293
+	 *    An important exception are non-auto-increment primary keys. If one entry in the
294
+	 *    CSV file has the same ID as one in the DB, we assume they are meant to be
295
+	 *    the same item, and instead update the item in the DB with that same ID.
296
+	 *    Also note, we remember the mappings permanently. So the 2nd, 3rd, and 10000th
297
+	 *    time you import a CSV from a different site, we remember their mappings, and
298
+	 * will try to update the item in the DB instead of inserting another item (eg
299
+	 * if we previously imported an event with temporary ID 1, and then it got a
300
+	 * real ID of 123, we remember that. So the next time we import an event with
301
+	 * temporary ID, from the same site, we know that it's real ID is 123, and will
302
+	 * update that event, instead of adding a new event).
303
+	 *
304
+	 * @access public
305
+	 * @param array $csv_data_array - the array containing the csv data produced from
306
+	 *                              EE_CSV::import_csv_to_model_data_array()
307
+	 * @param array $fields_to_save - an array containing the csv column names as keys with the corresponding db table
308
+	 *                              fields they will be saved to
309
+	 * @return TRUE on success, FALSE on fail
310
+	 * @throws \EE_Error
311
+	 */
312
+	public function save_csv_data_array_to_db($csv_data_array, $model_name = false)
313
+	{
314
+		$success = false;
315
+		$error = false;
316
+		// whther to treat this import as if it's data froma different database or not
317
+		// ie, if it IS from a different database, ignore foreign keys whihf
318
+		$export_from_site_a_to_b = true;
319
+		// first level of array is not table information but a table name was passed to the function
320
+		// array is only two levels deep, so let's fix that by adding a level, else the next steps will fail
321
+		if ($model_name) {
322
+			$csv_data_array = array($csv_data_array);
323
+		}
324
+		// begin looking through the $csv_data_array, expecting the toplevel key to be the model's name...
325
+		$old_site_url = 'none-specified';
326
+		// hanlde metadata
327
+		if (isset($csv_data_array[ EE_CSV::metadata_header ])) {
328
+			$csv_metadata = array_shift($csv_data_array[ EE_CSV::metadata_header ]);
329
+			// ok so its metadata, dont try to save it to ehte db obviously...
330
+			if (isset($csv_metadata['site_url']) && $csv_metadata['site_url'] == site_url()) {
331
+				EE_Error::add_attention(
332
+					sprintf(
333
+						__(
334
+							"CSV Data appears to be from the same database, so attempting to update data",
335
+							"event_espresso"
336
+						)
337
+					)
338
+				);
339
+				$export_from_site_a_to_b = false;
340
+			} else {
341
+				$old_site_url = isset($csv_metadata['site_url']) ? $csv_metadata['site_url'] : $old_site_url;
342
+				EE_Error::add_attention(
343
+					sprintf(
344
+						__(
345
+							"CSV Data appears to be from a different database (%s instead of %s), so we assume IDs in the CSV data DO NOT correspond to IDs in this database",
346
+							"event_espresso"
347
+						),
348
+						$old_site_url,
349
+						site_url()
350
+					)
351
+				);
352
+			};
353
+			unset($csv_data_array[ EE_CSV::metadata_header ]);
354
+		}
355
+		/**
356
+		 * @var $old_db_to_new_db_mapping 2d array: toplevel keys being model names, bottom-level keys being the original key, and
357
+		 * the value will be the newly-inserted ID.
358
+		 * If we have already imported data from the same website via CSV, it shoudl be kept in this wp option
359
+		 */
360
+		$old_db_to_new_db_mapping = get_option('ee_id_mapping_from' . sanitize_title($old_site_url), array());
361
+		if ($old_db_to_new_db_mapping) {
362
+			EE_Error::add_attention(
363
+				sprintf(
364
+					__(
365
+						"We noticed you have imported data via CSV from %s before. Because of this, IDs in your CSV have been mapped to their new IDs in %s",
366
+						"event_espresso"
367
+					),
368
+					$old_site_url,
369
+					site_url()
370
+				)
371
+			);
372
+		}
373
+		$old_db_to_new_db_mapping = $this->save_data_rows_to_db(
374
+			$csv_data_array,
375
+			$export_from_site_a_to_b,
376
+			$old_db_to_new_db_mapping
377
+		);
378
+
379
+		// save the mapping from old db to new db in case they try re-importing the same data from the same website again
380
+		update_option('ee_id_mapping_from' . sanitize_title($old_site_url), $old_db_to_new_db_mapping);
381
+
382
+		if ($this->_total_updates > 0) {
383
+			EE_Error::add_success(
384
+				sprintf(
385
+					__("%s existing records in the database were updated.", "event_espresso"),
386
+					$this->_total_updates
387
+				)
388
+			);
389
+			$success = true;
390
+		}
391
+		if ($this->_total_inserts > 0) {
392
+			EE_Error::add_success(
393
+				sprintf(__("%s new records were added to the database.", "event_espresso"), $this->_total_inserts)
394
+			);
395
+			$success = true;
396
+		}
397
+
398
+		if ($this->_total_update_errors > 0) {
399
+			EE_Error::add_error(
400
+				sprintf(
401
+					__(
402
+						"'One or more errors occurred, and a total of %s existing records in the database were <strong>not</strong> updated.'",
403
+						"event_espresso"
404
+					),
405
+					$this->_total_update_errors
406
+				),
407
+				__FILE__,
408
+				__FUNCTION__,
409
+				__LINE__
410
+			);
411
+			$error = true;
412
+		}
413
+		if ($this->_total_insert_errors > 0) {
414
+			EE_Error::add_error(
415
+				sprintf(
416
+					__(
417
+						"One or more errors occurred, and a total of %s new records were <strong>not</strong> added to the database.'",
418
+						"event_espresso"
419
+					),
420
+					$this->_total_insert_errors
421
+				),
422
+				__FILE__,
423
+				__FUNCTION__,
424
+				__LINE__
425
+			);
426
+			$error = true;
427
+		}
428
+
429
+		// lastly, we need to update the datetime and ticket sold amounts
430
+		// as those may have been affected by this
431
+		EEM_Ticket::instance()->update_tickets_sold(EEM_Ticket::instance()->get_all());
432
+
433
+		// if there was at least one success and absolutely no errors
434
+		if ($success && ! $error) {
435
+			return true;
436
+		} else {
437
+			return false;
438
+		}
439
+	}
440
+
441
+
442
+	/**
443
+	 * Processes the array of data, given the knowledge that it's from the same database or a different one,
444
+	 * and the mapping from temporary IDs to real IDs.
445
+	 * If the data is from a different database, we treat the primary keys and their corresponding
446
+	 * foreign keys as "temp Ids", basically identifiers that get mapped to real primary keys
447
+	 * in the real target database. As items are inserted, their temporary primary keys
448
+	 * are mapped to the real IDs in the target database. Also, before doing any update or
449
+	 * insert, we replace all the temp ID which are foreign keys with their mapped real IDs.
450
+	 * An exception: string primary keys are treated as real IDs, or else we'd need to
451
+	 * dynamically generate new string primary keys which would be very awkard for the country table etc.
452
+	 * Also, models with no primary key are strange too. We combine use their primar key INDEX (a
453
+	 * combination of fields) to create a unique string identifying the row and store
454
+	 * those in the mapping.
455
+	 *
456
+	 * If the data is from the same database, we usually treat primary keys as real IDs.
457
+	 * An exception is if there is nothing in the database for that ID. If that's the case,
458
+	 * we need to insert a new row for that ID, and then map from the non-existent ID
459
+	 * to the newly-inserted real ID.
460
+	 *
461
+	 * @param type $csv_data_array
462
+	 * @param type $export_from_site_a_to_b
463
+	 * @param type $old_db_to_new_db_mapping
464
+	 * @return array updated $old_db_to_new_db_mapping
465
+	 */
466
+	public function save_data_rows_to_db($csv_data_array, $export_from_site_a_to_b, $old_db_to_new_db_mapping)
467
+	{
468
+		foreach ($csv_data_array as $model_name_in_csv_data => $model_data_from_import) {
469
+			// now check that assumption was correct. If
470
+			if (EE_Registry::instance()->is_model_name($model_name_in_csv_data)) {
471
+				$model_name = $model_name_in_csv_data;
472
+			} else {
473
+				// no table info in the array and no table name passed to the function?? FAIL
474
+				EE_Error::add_error(
475
+					__(
476
+						'No table information was specified and/or found, therefore the import could not be completed',
477
+						'event_espresso'
478
+					),
479
+					__FILE__,
480
+					__FUNCTION__,
481
+					__LINE__
482
+				);
483
+				return false;
484
+			}
485
+			/* @var $model EEM_Base */
486
+			$model = EE_Registry::instance()->load_model($model_name);
487
+
488
+			// so without further ado, scanning all the data provided for primary keys and their inital values
489
+			foreach ($model_data_from_import as $model_object_data) {
490
+				// before we do ANYTHING, make sure the csv row wasn't just completely blank
491
+				$row_is_completely_empty = true;
492
+				foreach ($model_object_data as $field) {
493
+					if ($field) {
494
+						$row_is_completely_empty = false;
495
+					}
496
+				}
497
+				if ($row_is_completely_empty) {
498
+					continue;
499
+				}
500
+				// find the PK in the row of data (or a combined key if
501
+				// there is no primary key)
502
+				if ($model->has_primary_key_field()) {
503
+					$id_in_csv = $model_object_data[ $model->primary_key_name() ];
504
+				} else {
505
+					$id_in_csv = $model->get_index_primary_key_string($model_object_data);
506
+				}
507
+
508
+
509
+				$model_object_data = $this->_replace_temp_ids_with_mappings(
510
+					$model_object_data,
511
+					$model,
512
+					$old_db_to_new_db_mapping,
513
+					$export_from_site_a_to_b
514
+				);
515
+				// now we need to decide if we're going to add a new model object given the $model_object_data,
516
+				// or just update.
517
+				if ($export_from_site_a_to_b) {
518
+					$what_to_do = $this->_decide_whether_to_insert_or_update_given_data_from_other_db(
519
+						$id_in_csv,
520
+						$model_object_data,
521
+						$model,
522
+						$old_db_to_new_db_mapping
523
+					);
524
+				} else {// this is just a re-import
525
+					$what_to_do = $this->_decide_whether_to_insert_or_update_given_data_from_same_db(
526
+						$id_in_csv,
527
+						$model_object_data,
528
+						$model,
529
+						$old_db_to_new_db_mapping
530
+					);
531
+				}
532
+				if ($what_to_do == self::do_nothing) {
533
+					continue;
534
+				}
535
+
536
+				// double-check we actually want to insert, if that's what we're planning
537
+				// based on whether this item would be unique in the DB or not
538
+				if ($what_to_do == self::do_insert) {
539
+					// we're supposed to be inserting. But wait, will this thing
540
+					// be acceptable if inserted?
541
+					$conflicting = $model->get_one_conflicting($model_object_data, false);
542
+					if ($conflicting) {
543
+						// ok, this item would conflict if inserted. Just update the item that it conflicts with.
544
+						$what_to_do = self::do_update;
545
+						// and if this model has a primary key, remember its mapping
546
+						if ($model->has_primary_key_field()) {
547
+							$old_db_to_new_db_mapping[ $model_name ][ $id_in_csv ] = $conflicting->ID();
548
+							$model_object_data[ $model->primary_key_name() ] = $conflicting->ID();
549
+						} else {
550
+							// we want to update this conflicting item, instead of inserting a conflicting item
551
+							// so we need to make sure they match entirely (its possible that they only conflicted on one field, but we need them to match on other fields
552
+							// for the WHERE conditions in the update). At the time of this comment, there were no models like this
553
+							foreach ($model->get_combined_primary_key_fields() as $key_field) {
554
+								$model_object_data[ $key_field->get_name() ] = $conflicting->get(
555
+									$key_field->get_name()
556
+								);
557
+							}
558
+						}
559
+					}
560
+				}
561
+				if ($what_to_do == self::do_insert) {
562
+					$old_db_to_new_db_mapping = $this->_insert_from_data_array(
563
+						$id_in_csv,
564
+						$model_object_data,
565
+						$model,
566
+						$old_db_to_new_db_mapping
567
+					);
568
+				} elseif ($what_to_do == self::do_update) {
569
+					$old_db_to_new_db_mapping = $this->_update_from_data_array(
570
+						$id_in_csv,
571
+						$model_object_data,
572
+						$model,
573
+						$old_db_to_new_db_mapping
574
+					);
575
+				} else {
576
+					throw new EE_Error(
577
+						sprintf(
578
+							__(
579
+								'Programming error. We shoudl be inserting or updating, but instead we are being told to "%s", whifh is invalid',
580
+								'event_espresso'
581
+							),
582
+							$what_to_do
583
+						)
584
+					);
585
+				}
586
+			}
587
+		}
588
+		return $old_db_to_new_db_mapping;
589
+	}
590
+
591
+
592
+	/**
593
+	 * Decides whether or not to insert, given that this data is from another database.
594
+	 * So, if the primary key of this $model_object_data already exists in the database,
595
+	 * it's just a coincidence and we should still insert. The only time we should
596
+	 * update is when we know what it maps to, or there's something that would
597
+	 * conflict (and we should instead just update that conflicting thing)
598
+	 *
599
+	 * @param string   $id_in_csv
600
+	 * @param array    $model_object_data        by reference so it can be modified
601
+	 * @param EEM_Base $model
602
+	 * @param array    $old_db_to_new_db_mapping by reference so it can be modified
603
+	 * @return string one of the consts on this class that starts with do_*
604
+	 */
605
+	protected function _decide_whether_to_insert_or_update_given_data_from_other_db(
606
+		$id_in_csv,
607
+		$model_object_data,
608
+		$model,
609
+		$old_db_to_new_db_mapping
610
+	) {
611
+		$model_name = $model->get_this_model_name();
612
+		// if it's a site-to-site export-and-import, see if this modelobject's id
613
+		// in the old data that we know of
614
+		if (isset($old_db_to_new_db_mapping[ $model_name ][ $id_in_csv ])) {
615
+			return self::do_update;
616
+		} else {
617
+			return self::do_insert;
618
+		}
619
+	}
620
+
621
+	/**
622
+	 * If this thing basically already exists in the database, we want to update it;
623
+	 * otherwise insert it (ie, someone tweaked the CSV file, or the item was
624
+	 * deleted in the database so it should be re-inserted)
625
+	 *
626
+	 * @param type     $id_in_csv
627
+	 * @param type     $model_object_data
628
+	 * @param EEM_Base $model
629
+	 * @param type     $old_db_to_new_db_mapping
630
+	 * @return
631
+	 */
632
+	protected function _decide_whether_to_insert_or_update_given_data_from_same_db(
633
+		$id_in_csv,
634
+		$model_object_data,
635
+		$model
636
+	) {
637
+		// in this case, check if this thing ACTUALLY exists in the database
638
+		if ($model->get_one_conflicting($model_object_data)) {
639
+			return self::do_update;
640
+		} else {
641
+			return self::do_insert;
642
+		}
643
+	}
644
+
645
+	/**
646
+	 * Using the $old_db_to_new_db_mapping array, replaces all the temporary IDs
647
+	 * with their mapped real IDs. Eg, if importing from site A to B, the mapping
648
+	 * file may indicate that the ID "my_event_id" maps to an actual event ID of 123.
649
+	 * So this function searches for any event temp Ids called "my_event_id" and
650
+	 * replaces them with 123.
651
+	 * Also, if there is no temp ID for the INT foreign keys from another database,
652
+	 * replaces them with 0 or the field's default.
653
+	 *
654
+	 * @param type     $model_object_data
655
+	 * @param EEM_Base $model
656
+	 * @param type     $old_db_to_new_db_mapping
657
+	 * @param boolean  $export_from_site_a_to_b
658
+	 * @return array updated model object data with temp IDs removed
659
+	 */
660
+	protected function _replace_temp_ids_with_mappings(
661
+		$model_object_data,
662
+		$model,
663
+		$old_db_to_new_db_mapping,
664
+		$export_from_site_a_to_b
665
+	) {
666
+		// if this model object's primary key is in the mapping, replace it
667
+		if ($model->has_primary_key_field() &&
668
+			$model->get_primary_key_field()->is_auto_increment() &&
669
+			isset($old_db_to_new_db_mapping[ $model->get_this_model_name() ]) &&
670
+			isset(
671
+				$old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $model_object_data[ $model->primary_key_name() ] ]
672
+			)) {
673
+			$model_object_data[ $model->primary_key_name() ] = $old_db_to_new_db_mapping[ $model->get_this_model_name(
674
+			) ][ $model_object_data[ $model->primary_key_name() ] ];
675
+		}
676
+
677
+		try {
678
+			$model_name_field = $model->get_field_containing_related_model_name();
679
+			$models_pointed_to_by_model_name_field = $model_name_field->get_model_names_pointed_to();
680
+		} catch (EE_Error $e) {
681
+			$model_name_field = null;
682
+			$models_pointed_to_by_model_name_field = array();
683
+		}
684
+		foreach ($model->field_settings(true) as $field_obj) {
685
+			if ($field_obj instanceof EE_Foreign_Key_Int_Field) {
686
+				$models_pointed_to = $field_obj->get_model_names_pointed_to();
687
+				$found_a_mapping = false;
688
+				foreach ($models_pointed_to as $model_pointed_to_by_fk) {
689
+					if ($model_name_field) {
690
+						$value_of_model_name_field = $model_object_data[ $model_name_field->get_name() ];
691
+						if ($value_of_model_name_field == $model_pointed_to_by_fk) {
692
+							$model_object_data[ $field_obj->get_name() ] = $this->_find_mapping_in(
693
+								$model_object_data[ $field_obj->get_name() ],
694
+								$model_pointed_to_by_fk,
695
+								$old_db_to_new_db_mapping,
696
+								$export_from_site_a_to_b
697
+							);
698
+							$found_a_mapping = true;
699
+							break;
700
+						}
701
+					} else {
702
+						$model_object_data[ $field_obj->get_name() ] = $this->_find_mapping_in(
703
+							$model_object_data[ $field_obj->get_name() ],
704
+							$model_pointed_to_by_fk,
705
+							$old_db_to_new_db_mapping,
706
+							$export_from_site_a_to_b
707
+						);
708
+						$found_a_mapping = true;
709
+					}
710
+					// once we've found a mapping for this field no need to continue
711
+					if ($found_a_mapping) {
712
+						break;
713
+					}
714
+				}
715
+			} else {
716
+				// it's a string foreign key (which we leave alone, because those are things
717
+				// like country names, which we'd really rather not make 2 USAs etc (we'd actually
718
+				// prefer to just update one)
719
+				// or it's just a regular value that ought to be replaced
720
+			}
721
+		}
722
+		//
723
+		if ($model instanceof EEM_Term_Taxonomy) {
724
+			$model_object_data = $this->_handle_split_term_ids($model_object_data);
725
+		}
726
+		return $model_object_data;
727
+	}
728
+
729
+	/**
730
+	 * If the data was exported PRE-4.2, but then imported POST-4.2, then the term_id
731
+	 * this term-taxonomy refers to may be out-of-date so we need to update it.
732
+	 * see https://make.wordpress.org/core/2015/02/16/taxonomy-term-splitting-in-4-2-a-developer-guide/
733
+	 *
734
+	 * @param type $model_object_data
735
+	 * @return array new model object data
736
+	 */
737
+	protected function _handle_split_term_ids($model_object_data)
738
+	{
739
+		if (isset($model_object_data['term_id'])
740
+			&& isset($model_object_data['taxonomy'])
741
+			&& apply_filters(
742
+				'FHEE__EE_Import__handle_split_term_ids__function_exists',
743
+				function_exists('wp_get_split_term'),
744
+				$model_object_data
745
+			)) {
746
+			$new_term_id = wp_get_split_term($model_object_data['term_id'], $model_object_data['taxonomy']);
747
+			if ($new_term_id) {
748
+				$model_object_data['term_id'] = $new_term_id;
749
+			}
750
+		}
751
+		return $model_object_data;
752
+	}
753
+
754
+	/**
755
+	 * Given the object's ID and its model's name, find it int he mapping data,
756
+	 * bearing in mind where it came from
757
+	 *
758
+	 * @param type   $object_id
759
+	 * @param string $model_name
760
+	 * @param array  $old_db_to_new_db_mapping
761
+	 * @param type   $export_from_site_a_to_b
762
+	 * @return int
763
+	 */
764
+	protected function _find_mapping_in($object_id, $model_name, $old_db_to_new_db_mapping, $export_from_site_a_to_b)
765
+	{
766
+		if (isset($old_db_to_new_db_mapping[ $model_name ][ $object_id ])) {
767
+			return $old_db_to_new_db_mapping[ $model_name ][ $object_id ];
768
+		} elseif ($object_id == '0' || $object_id == '') {
769
+			// leave as-is
770
+			return $object_id;
771
+		} elseif ($export_from_site_a_to_b) {
772
+			// we couldn't find a mapping for this, and it's from a different site,
773
+			// so blank it out
774
+			return null;
775
+		} elseif (! $export_from_site_a_to_b) {
776
+			// we coudln't find a mapping for this, but it's from thsi DB anyway
777
+			// so let's just leave it as-is
778
+			return $object_id;
779
+		}
780
+	}
781
+
782
+	/**
783
+	 *
784
+	 * @param type     $id_in_csv
785
+	 * @param type     $model_object_data
786
+	 * @param EEM_Base $model
787
+	 * @param type     $old_db_to_new_db_mapping
788
+	 * @return array updated $old_db_to_new_db_mapping
789
+	 */
790
+	protected function _insert_from_data_array($id_in_csv, $model_object_data, $model, $old_db_to_new_db_mapping)
791
+	{
792
+		// remove the primary key, if there is one (we don't want it for inserts OR updates)
793
+		// we'll put it back in if we need it
794
+		if ($model->has_primary_key_field() && $model->get_primary_key_field()->is_auto_increment()) {
795
+			$effective_id = $model_object_data[ $model->primary_key_name() ];
796
+			unset($model_object_data[ $model->primary_key_name() ]);
797
+		} else {
798
+			$effective_id = $model->get_index_primary_key_string($model_object_data);
799
+		}
800
+		// the model takes care of validating the CSV's input
801
+		try {
802
+			$new_id = $model->insert($model_object_data);
803
+			if ($new_id) {
804
+				$old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $id_in_csv ] = $new_id;
805
+				$this->_total_inserts++;
806
+				EE_Error::add_success(
807
+					sprintf(
808
+						__("Successfully added new %s (with id %s) with csv data %s", "event_espresso"),
809
+						$model->get_this_model_name(),
810
+						$new_id,
811
+						implode(",", $model_object_data)
812
+					)
813
+				);
814
+			} else {
815
+				$this->_total_insert_errors++;
816
+				// put the ID used back in there for the error message
817
+				if ($model->has_primary_key_field()) {
818
+					$model_object_data[ $model->primary_key_name() ] = $effective_id;
819
+				}
820
+				EE_Error::add_error(
821
+					sprintf(
822
+						__("Could not insert new %s with the csv data: %s", "event_espresso"),
823
+						$model->get_this_model_name(),
824
+						http_build_query($model_object_data)
825
+					),
826
+					__FILE__,
827
+					__FUNCTION__,
828
+					__LINE__
829
+				);
830
+			}
831
+		} catch (EE_Error $e) {
832
+			$this->_total_insert_errors++;
833
+			if ($model->has_primary_key_field()) {
834
+				$model_object_data[ $model->primary_key_name() ] = $effective_id;
835
+			}
836
+			EE_Error::add_error(
837
+				sprintf(
838
+					__("Could not insert new %s with the csv data: %s because %s", "event_espresso"),
839
+					$model->get_this_model_name(),
840
+					implode(",", $model_object_data),
841
+					$e->getMessage()
842
+				),
843
+				__FILE__,
844
+				__FUNCTION__,
845
+				__LINE__
846
+			);
847
+		}
848
+		return $old_db_to_new_db_mapping;
849
+	}
850
+
851
+	/**
852
+	 * Given the model object data, finds the row to update and updates it
853
+	 *
854
+	 * @param string|int $id_in_csv
855
+	 * @param array      $model_object_data
856
+	 * @param EEM_Base   $model
857
+	 * @param array      $old_db_to_new_db_mapping
858
+	 * @return array updated $old_db_to_new_db_mapping
859
+	 */
860
+	protected function _update_from_data_array($id_in_csv, $model_object_data, $model, $old_db_to_new_db_mapping)
861
+	{
862
+		try {
863
+			// let's keep two copies of the model object data:
864
+			// one for performing an update, one for everthing else
865
+			$model_object_data_for_update = $model_object_data;
866
+			if ($model->has_primary_key_field()) {
867
+				$conditions = array($model->primary_key_name() => $model_object_data[ $model->primary_key_name() ]);
868
+				// remove the primary key because we shouldn't use it for updating
869
+				unset($model_object_data_for_update[ $model->primary_key_name() ]);
870
+			} elseif ($model->get_combined_primary_key_fields() > 1) {
871
+				$conditions = array();
872
+				foreach ($model->get_combined_primary_key_fields() as $key_field) {
873
+					$conditions[ $key_field->get_name() ] = $model_object_data[ $key_field->get_name() ];
874
+				}
875
+			} else {
876
+				$model->primary_key_name(
877
+				);// this shoudl just throw an exception, explaining that we dont have a primary key (or a combine dkey)
878
+			}
879
+
880
+			$success = $model->update($model_object_data_for_update, array($conditions));
881
+			if ($success) {
882
+				$this->_total_updates++;
883
+				EE_Error::add_success(
884
+					sprintf(
885
+						__("Successfully updated %s with csv data %s", "event_espresso"),
886
+						$model->get_this_model_name(),
887
+						implode(",", $model_object_data_for_update)
888
+					)
889
+				);
890
+				// we should still record the mapping even though it was an update
891
+				// because if we were going to insert somethign but it was going to conflict
892
+				// we would have last-minute decided to update. So we'd like to know what we updated
893
+				// and so we record what record ended up being updated using the mapping
894
+				if ($model->has_primary_key_field()) {
895
+					$new_key_for_mapping = $model_object_data[ $model->primary_key_name() ];
896
+				} else {
897
+					// no primary key just a combined key
898
+					$new_key_for_mapping = $model->get_index_primary_key_string($model_object_data);
899
+				}
900
+				$old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $id_in_csv ] = $new_key_for_mapping;
901
+			} else {
902
+				$matched_items = $model->get_all(array($conditions));
903
+				if (! $matched_items) {
904
+					// no items were matched (so we shouldn't have updated)... but then we should have inserted? what the heck?
905
+					$this->_total_update_errors++;
906
+					EE_Error::add_error(
907
+						sprintf(
908
+							__(
909
+								"Could not update %s with the csv data: '%s' for an unknown reason (using WHERE conditions %s)",
910
+								"event_espresso"
911
+							),
912
+							$model->get_this_model_name(),
913
+							http_build_query($model_object_data),
914
+							http_build_query($conditions)
915
+						),
916
+						__FILE__,
917
+						__FUNCTION__,
918
+						__LINE__
919
+					);
920
+				} else {
921
+					$this->_total_updates++;
922
+					EE_Error::add_success(
923
+						sprintf(
924
+							__(
925
+								"%s with csv data '%s' was found in the database and didn't need updating because all the data is identical.",
926
+								"event_espresso"
927
+							),
928
+							$model->get_this_model_name(),
929
+							implode(",", $model_object_data)
930
+						)
931
+					);
932
+				}
933
+			}
934
+		} catch (EE_Error $e) {
935
+			$this->_total_update_errors++;
936
+			$basic_message = sprintf(
937
+				__("Could not update %s with the csv data: %s because %s", "event_espresso"),
938
+				$model->get_this_model_name(),
939
+				implode(",", $model_object_data),
940
+				$e->getMessage()
941
+			);
942
+			$debug_message = $basic_message . ' Stack trace: ' . $e->getTraceAsString();
943
+			EE_Error::add_error("$basic_message | $debug_message", __FILE__, __FUNCTION__, __LINE__);
944
+		}
945
+		return $old_db_to_new_db_mapping;
946
+	}
947
+
948
+	/**
949
+	 * Gets the number of inserts performed since importer was instantiated or reset
950
+	 *
951
+	 * @return int
952
+	 */
953
+	public function get_total_inserts()
954
+	{
955
+		return $this->_total_inserts;
956
+	}
957
+
958
+	/**
959
+	 *  Gets the number of insert errors since importer was instantiated or reset
960
+	 *
961
+	 * @return int
962
+	 */
963
+	public function get_total_insert_errors()
964
+	{
965
+		return $this->_total_insert_errors;
966
+	}
967
+
968
+	/**
969
+	 *  Gets the number of updates performed since importer was instantiated or reset
970
+	 *
971
+	 * @return int
972
+	 */
973
+	public function get_total_updates()
974
+	{
975
+		return $this->_total_updates;
976
+	}
977
+
978
+	/**
979
+	 *  Gets the number of update errors since importer was instantiated or reset
980
+	 *
981
+	 * @return int
982
+	 */
983
+	public function get_total_update_errors()
984
+	{
985
+		return $this->_total_update_errors;
986
+	}
987 987
 }
Please login to merge, or discard this patch.
Spacing   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -135,7 +135,7 @@  discard block
 block discarded – undo
135 135
     public function import()
136 136
     {
137 137
 
138
-        require_once(EE_CLASSES . 'EE_CSV.class.php');
138
+        require_once(EE_CLASSES.'EE_CSV.class.php');
139 139
         $this->EE_CSV = EE_CSV::instance();
140 140
 
141 141
         if (isset($_REQUEST['import'])) {
@@ -179,18 +179,18 @@  discard block
 block discarded – undo
179 179
                         break;
180 180
                 }
181 181
 
182
-                if (! $error_msg) {
182
+                if ( ! $error_msg) {
183 183
                     $filename = $_FILES['file']['name'][0];
184 184
                     $file_ext = substr(strrchr($filename, '.'), 1);
185 185
                     $file_type = $_FILES['file']['type'][0];
186 186
                     $temp_file = $_FILES['file']['tmp_name'][0];
187
-                    $filesize = $_FILES['file']['size'][0] / 1024;// convert from bytes to KB
187
+                    $filesize = $_FILES['file']['size'][0] / 1024; // convert from bytes to KB
188 188
 
189 189
                     if ($file_ext == 'csv') {
190
-                        $max_upload = $this->EE_CSV->get_max_upload_size();// max upload size in KB
190
+                        $max_upload = $this->EE_CSV->get_max_upload_size(); // max upload size in KB
191 191
                         if ($filesize < $max_upload || true) {
192 192
                             $wp_upload_dir = str_replace(array('\\', '/'), DS, wp_upload_dir());
193
-                            $path_to_file = $wp_upload_dir['basedir'] . DS . 'espresso' . DS . $filename;
193
+                            $path_to_file = $wp_upload_dir['basedir'].DS.'espresso'.DS.$filename;
194 194
 
195 195
                             if (move_uploaded_file($temp_file, $path_to_file)) {
196 196
                                 // convert csv to array
@@ -324,8 +324,8 @@  discard block
 block discarded – undo
324 324
         // begin looking through the $csv_data_array, expecting the toplevel key to be the model's name...
325 325
         $old_site_url = 'none-specified';
326 326
         // hanlde metadata
327
-        if (isset($csv_data_array[ EE_CSV::metadata_header ])) {
328
-            $csv_metadata = array_shift($csv_data_array[ EE_CSV::metadata_header ]);
327
+        if (isset($csv_data_array[EE_CSV::metadata_header])) {
328
+            $csv_metadata = array_shift($csv_data_array[EE_CSV::metadata_header]);
329 329
             // ok so its metadata, dont try to save it to ehte db obviously...
330 330
             if (isset($csv_metadata['site_url']) && $csv_metadata['site_url'] == site_url()) {
331 331
                 EE_Error::add_attention(
@@ -350,14 +350,14 @@  discard block
 block discarded – undo
350 350
                     )
351 351
                 );
352 352
             };
353
-            unset($csv_data_array[ EE_CSV::metadata_header ]);
353
+            unset($csv_data_array[EE_CSV::metadata_header]);
354 354
         }
355 355
         /**
356 356
          * @var $old_db_to_new_db_mapping 2d array: toplevel keys being model names, bottom-level keys being the original key, and
357 357
          * the value will be the newly-inserted ID.
358 358
          * If we have already imported data from the same website via CSV, it shoudl be kept in this wp option
359 359
          */
360
-        $old_db_to_new_db_mapping = get_option('ee_id_mapping_from' . sanitize_title($old_site_url), array());
360
+        $old_db_to_new_db_mapping = get_option('ee_id_mapping_from'.sanitize_title($old_site_url), array());
361 361
         if ($old_db_to_new_db_mapping) {
362 362
             EE_Error::add_attention(
363 363
                 sprintf(
@@ -377,7 +377,7 @@  discard block
 block discarded – undo
377 377
         );
378 378
 
379 379
         // save the mapping from old db to new db in case they try re-importing the same data from the same website again
380
-        update_option('ee_id_mapping_from' . sanitize_title($old_site_url), $old_db_to_new_db_mapping);
380
+        update_option('ee_id_mapping_from'.sanitize_title($old_site_url), $old_db_to_new_db_mapping);
381 381
 
382 382
         if ($this->_total_updates > 0) {
383 383
             EE_Error::add_success(
@@ -500,7 +500,7 @@  discard block
 block discarded – undo
500 500
                 // find the PK in the row of data (or a combined key if
501 501
                 // there is no primary key)
502 502
                 if ($model->has_primary_key_field()) {
503
-                    $id_in_csv = $model_object_data[ $model->primary_key_name() ];
503
+                    $id_in_csv = $model_object_data[$model->primary_key_name()];
504 504
                 } else {
505 505
                     $id_in_csv = $model->get_index_primary_key_string($model_object_data);
506 506
                 }
@@ -544,14 +544,14 @@  discard block
 block discarded – undo
544 544
                         $what_to_do = self::do_update;
545 545
                         // and if this model has a primary key, remember its mapping
546 546
                         if ($model->has_primary_key_field()) {
547
-                            $old_db_to_new_db_mapping[ $model_name ][ $id_in_csv ] = $conflicting->ID();
548
-                            $model_object_data[ $model->primary_key_name() ] = $conflicting->ID();
547
+                            $old_db_to_new_db_mapping[$model_name][$id_in_csv] = $conflicting->ID();
548
+                            $model_object_data[$model->primary_key_name()] = $conflicting->ID();
549 549
                         } else {
550 550
                             // we want to update this conflicting item, instead of inserting a conflicting item
551 551
                             // so we need to make sure they match entirely (its possible that they only conflicted on one field, but we need them to match on other fields
552 552
                             // for the WHERE conditions in the update). At the time of this comment, there were no models like this
553 553
                             foreach ($model->get_combined_primary_key_fields() as $key_field) {
554
-                                $model_object_data[ $key_field->get_name() ] = $conflicting->get(
554
+                                $model_object_data[$key_field->get_name()] = $conflicting->get(
555 555
                                     $key_field->get_name()
556 556
                                 );
557 557
                             }
@@ -611,7 +611,7 @@  discard block
 block discarded – undo
611 611
         $model_name = $model->get_this_model_name();
612 612
         // if it's a site-to-site export-and-import, see if this modelobject's id
613 613
         // in the old data that we know of
614
-        if (isset($old_db_to_new_db_mapping[ $model_name ][ $id_in_csv ])) {
614
+        if (isset($old_db_to_new_db_mapping[$model_name][$id_in_csv])) {
615 615
             return self::do_update;
616 616
         } else {
617 617
             return self::do_insert;
@@ -666,12 +666,12 @@  discard block
 block discarded – undo
666 666
         // if this model object's primary key is in the mapping, replace it
667 667
         if ($model->has_primary_key_field() &&
668 668
             $model->get_primary_key_field()->is_auto_increment() &&
669
-            isset($old_db_to_new_db_mapping[ $model->get_this_model_name() ]) &&
669
+            isset($old_db_to_new_db_mapping[$model->get_this_model_name()]) &&
670 670
             isset(
671
-                $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $model_object_data[ $model->primary_key_name() ] ]
671
+                $old_db_to_new_db_mapping[$model->get_this_model_name()][$model_object_data[$model->primary_key_name()]]
672 672
             )) {
673
-            $model_object_data[ $model->primary_key_name() ] = $old_db_to_new_db_mapping[ $model->get_this_model_name(
674
-            ) ][ $model_object_data[ $model->primary_key_name() ] ];
673
+            $model_object_data[$model->primary_key_name()] = $old_db_to_new_db_mapping[$model->get_this_model_name(
674
+            )][$model_object_data[$model->primary_key_name()]];
675 675
         }
676 676
 
677 677
         try {
@@ -687,10 +687,10 @@  discard block
 block discarded – undo
687 687
                 $found_a_mapping = false;
688 688
                 foreach ($models_pointed_to as $model_pointed_to_by_fk) {
689 689
                     if ($model_name_field) {
690
-                        $value_of_model_name_field = $model_object_data[ $model_name_field->get_name() ];
690
+                        $value_of_model_name_field = $model_object_data[$model_name_field->get_name()];
691 691
                         if ($value_of_model_name_field == $model_pointed_to_by_fk) {
692
-                            $model_object_data[ $field_obj->get_name() ] = $this->_find_mapping_in(
693
-                                $model_object_data[ $field_obj->get_name() ],
692
+                            $model_object_data[$field_obj->get_name()] = $this->_find_mapping_in(
693
+                                $model_object_data[$field_obj->get_name()],
694 694
                                 $model_pointed_to_by_fk,
695 695
                                 $old_db_to_new_db_mapping,
696 696
                                 $export_from_site_a_to_b
@@ -699,8 +699,8 @@  discard block
 block discarded – undo
699 699
                             break;
700 700
                         }
701 701
                     } else {
702
-                        $model_object_data[ $field_obj->get_name() ] = $this->_find_mapping_in(
703
-                            $model_object_data[ $field_obj->get_name() ],
702
+                        $model_object_data[$field_obj->get_name()] = $this->_find_mapping_in(
703
+                            $model_object_data[$field_obj->get_name()],
704 704
                             $model_pointed_to_by_fk,
705 705
                             $old_db_to_new_db_mapping,
706 706
                             $export_from_site_a_to_b
@@ -763,8 +763,8 @@  discard block
 block discarded – undo
763 763
      */
764 764
     protected function _find_mapping_in($object_id, $model_name, $old_db_to_new_db_mapping, $export_from_site_a_to_b)
765 765
     {
766
-        if (isset($old_db_to_new_db_mapping[ $model_name ][ $object_id ])) {
767
-            return $old_db_to_new_db_mapping[ $model_name ][ $object_id ];
766
+        if (isset($old_db_to_new_db_mapping[$model_name][$object_id])) {
767
+            return $old_db_to_new_db_mapping[$model_name][$object_id];
768 768
         } elseif ($object_id == '0' || $object_id == '') {
769 769
             // leave as-is
770 770
             return $object_id;
@@ -772,7 +772,7 @@  discard block
 block discarded – undo
772 772
             // we couldn't find a mapping for this, and it's from a different site,
773 773
             // so blank it out
774 774
             return null;
775
-        } elseif (! $export_from_site_a_to_b) {
775
+        } elseif ( ! $export_from_site_a_to_b) {
776 776
             // we coudln't find a mapping for this, but it's from thsi DB anyway
777 777
             // so let's just leave it as-is
778 778
             return $object_id;
@@ -792,8 +792,8 @@  discard block
 block discarded – undo
792 792
         // remove the primary key, if there is one (we don't want it for inserts OR updates)
793 793
         // we'll put it back in if we need it
794 794
         if ($model->has_primary_key_field() && $model->get_primary_key_field()->is_auto_increment()) {
795
-            $effective_id = $model_object_data[ $model->primary_key_name() ];
796
-            unset($model_object_data[ $model->primary_key_name() ]);
795
+            $effective_id = $model_object_data[$model->primary_key_name()];
796
+            unset($model_object_data[$model->primary_key_name()]);
797 797
         } else {
798 798
             $effective_id = $model->get_index_primary_key_string($model_object_data);
799 799
         }
@@ -801,7 +801,7 @@  discard block
 block discarded – undo
801 801
         try {
802 802
             $new_id = $model->insert($model_object_data);
803 803
             if ($new_id) {
804
-                $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $id_in_csv ] = $new_id;
804
+                $old_db_to_new_db_mapping[$model->get_this_model_name()][$id_in_csv] = $new_id;
805 805
                 $this->_total_inserts++;
806 806
                 EE_Error::add_success(
807 807
                     sprintf(
@@ -815,7 +815,7 @@  discard block
 block discarded – undo
815 815
                 $this->_total_insert_errors++;
816 816
                 // put the ID used back in there for the error message
817 817
                 if ($model->has_primary_key_field()) {
818
-                    $model_object_data[ $model->primary_key_name() ] = $effective_id;
818
+                    $model_object_data[$model->primary_key_name()] = $effective_id;
819 819
                 }
820 820
                 EE_Error::add_error(
821 821
                     sprintf(
@@ -831,7 +831,7 @@  discard block
 block discarded – undo
831 831
         } catch (EE_Error $e) {
832 832
             $this->_total_insert_errors++;
833 833
             if ($model->has_primary_key_field()) {
834
-                $model_object_data[ $model->primary_key_name() ] = $effective_id;
834
+                $model_object_data[$model->primary_key_name()] = $effective_id;
835 835
             }
836 836
             EE_Error::add_error(
837 837
                 sprintf(
@@ -864,17 +864,17 @@  discard block
 block discarded – undo
864 864
             // one for performing an update, one for everthing else
865 865
             $model_object_data_for_update = $model_object_data;
866 866
             if ($model->has_primary_key_field()) {
867
-                $conditions = array($model->primary_key_name() => $model_object_data[ $model->primary_key_name() ]);
867
+                $conditions = array($model->primary_key_name() => $model_object_data[$model->primary_key_name()]);
868 868
                 // remove the primary key because we shouldn't use it for updating
869
-                unset($model_object_data_for_update[ $model->primary_key_name() ]);
869
+                unset($model_object_data_for_update[$model->primary_key_name()]);
870 870
             } elseif ($model->get_combined_primary_key_fields() > 1) {
871 871
                 $conditions = array();
872 872
                 foreach ($model->get_combined_primary_key_fields() as $key_field) {
873
-                    $conditions[ $key_field->get_name() ] = $model_object_data[ $key_field->get_name() ];
873
+                    $conditions[$key_field->get_name()] = $model_object_data[$key_field->get_name()];
874 874
                 }
875 875
             } else {
876 876
                 $model->primary_key_name(
877
-                );// this shoudl just throw an exception, explaining that we dont have a primary key (or a combine dkey)
877
+                ); // this shoudl just throw an exception, explaining that we dont have a primary key (or a combine dkey)
878 878
             }
879 879
 
880 880
             $success = $model->update($model_object_data_for_update, array($conditions));
@@ -892,15 +892,15 @@  discard block
 block discarded – undo
892 892
                 // we would have last-minute decided to update. So we'd like to know what we updated
893 893
                 // and so we record what record ended up being updated using the mapping
894 894
                 if ($model->has_primary_key_field()) {
895
-                    $new_key_for_mapping = $model_object_data[ $model->primary_key_name() ];
895
+                    $new_key_for_mapping = $model_object_data[$model->primary_key_name()];
896 896
                 } else {
897 897
                     // no primary key just a combined key
898 898
                     $new_key_for_mapping = $model->get_index_primary_key_string($model_object_data);
899 899
                 }
900
-                $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $id_in_csv ] = $new_key_for_mapping;
900
+                $old_db_to_new_db_mapping[$model->get_this_model_name()][$id_in_csv] = $new_key_for_mapping;
901 901
             } else {
902 902
                 $matched_items = $model->get_all(array($conditions));
903
-                if (! $matched_items) {
903
+                if ( ! $matched_items) {
904 904
                     // no items were matched (so we shouldn't have updated)... but then we should have inserted? what the heck?
905 905
                     $this->_total_update_errors++;
906 906
                     EE_Error::add_error(
@@ -939,7 +939,7 @@  discard block
 block discarded – undo
939 939
                 implode(",", $model_object_data),
940 940
                 $e->getMessage()
941 941
             );
942
-            $debug_message = $basic_message . ' Stack trace: ' . $e->getTraceAsString();
942
+            $debug_message = $basic_message.' Stack trace: '.$e->getTraceAsString();
943 943
             EE_Error::add_error("$basic_message | $debug_message", __FILE__, __FUNCTION__, __LINE__);
944 944
         }
945 945
         return $old_db_to_new_db_mapping;
Please login to merge, or discard this patch.
core/db_classes/EE_Line_Item.class.php 2 patches
Indentation   +1426 added lines, -1426 removed lines patch added patch discarded remove patch
@@ -14,1430 +14,1430 @@
 block discarded – undo
14 14
 class EE_Line_Item extends EE_Base_Class implements EEI_Line_Item
15 15
 {
16 16
 
17
-    /**
18
-     * for children line items (currently not a normal relation)
19
-     *
20
-     * @type EE_Line_Item[]
21
-     */
22
-    protected $_children = array();
23
-
24
-    /**
25
-     * for the parent line item
26
-     *
27
-     * @var EE_Line_Item
28
-     */
29
-    protected $_parent;
30
-
31
-
32
-    /**
33
-     *
34
-     * @param array  $props_n_values          incoming values
35
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
36
-     *                                        used.)
37
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
38
-     *                                        date_format and the second value is the time format
39
-     * @return EE_Line_Item
40
-     * @throws EE_Error
41
-     */
42
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
43
-    {
44
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
45
-        return $has_object
46
-            ? $has_object
47
-            : new self($props_n_values, false, $timezone);
48
-    }
49
-
50
-
51
-    /**
52
-     * @param array  $props_n_values  incoming values from the database
53
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
54
-     *                                the website will be used.
55
-     * @return EE_Line_Item
56
-     * @throws EE_Error
57
-     */
58
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
59
-    {
60
-        return new self($props_n_values, true, $timezone);
61
-    }
62
-
63
-
64
-    /**
65
-     * Adds some defaults if they're not specified
66
-     *
67
-     * @param array  $fieldValues
68
-     * @param bool   $bydb
69
-     * @param string $timezone
70
-     * @throws EE_Error
71
-     */
72
-    protected function __construct($fieldValues = array(), $bydb = false, $timezone = '')
73
-    {
74
-        parent::__construct($fieldValues, $bydb, $timezone);
75
-        if (! $this->get('LIN_code')) {
76
-            $this->set_code($this->generate_code());
77
-        }
78
-    }
79
-
80
-
81
-    /**
82
-     * Gets ID
83
-     *
84
-     * @return int
85
-     * @throws EE_Error
86
-     */
87
-    public function ID()
88
-    {
89
-        return $this->get('LIN_ID');
90
-    }
91
-
92
-
93
-    /**
94
-     * Gets TXN_ID
95
-     *
96
-     * @return int
97
-     * @throws EE_Error
98
-     */
99
-    public function TXN_ID()
100
-    {
101
-        return $this->get('TXN_ID');
102
-    }
103
-
104
-
105
-    /**
106
-     * Sets TXN_ID
107
-     *
108
-     * @param int $TXN_ID
109
-     * @throws EE_Error
110
-     */
111
-    public function set_TXN_ID($TXN_ID)
112
-    {
113
-        $this->set('TXN_ID', $TXN_ID);
114
-    }
115
-
116
-
117
-    /**
118
-     * Gets name
119
-     *
120
-     * @return string
121
-     * @throws EE_Error
122
-     */
123
-    public function name()
124
-    {
125
-        $name = $this->get('LIN_name');
126
-        if (! $name) {
127
-            $name = ucwords(str_replace('-', ' ', $this->type()));
128
-        }
129
-        return $name;
130
-    }
131
-
132
-
133
-    /**
134
-     * Sets name
135
-     *
136
-     * @param string $name
137
-     * @throws EE_Error
138
-     */
139
-    public function set_name($name)
140
-    {
141
-        $this->set('LIN_name', $name);
142
-    }
143
-
144
-
145
-    /**
146
-     * Gets desc
147
-     *
148
-     * @return string
149
-     * @throws EE_Error
150
-     */
151
-    public function desc()
152
-    {
153
-        return $this->get('LIN_desc');
154
-    }
155
-
156
-
157
-    /**
158
-     * Sets desc
159
-     *
160
-     * @param string $desc
161
-     * @throws EE_Error
162
-     */
163
-    public function set_desc($desc)
164
-    {
165
-        $this->set('LIN_desc', $desc);
166
-    }
167
-
168
-
169
-    /**
170
-     * Gets quantity
171
-     *
172
-     * @return int
173
-     * @throws EE_Error
174
-     */
175
-    public function quantity()
176
-    {
177
-        return $this->get('LIN_quantity');
178
-    }
179
-
180
-
181
-    /**
182
-     * Sets quantity
183
-     *
184
-     * @param int $quantity
185
-     * @throws EE_Error
186
-     */
187
-    public function set_quantity($quantity)
188
-    {
189
-        $this->set('LIN_quantity', max($quantity, 0));
190
-    }
191
-
192
-
193
-    /**
194
-     * Gets item_id
195
-     *
196
-     * @return string
197
-     * @throws EE_Error
198
-     */
199
-    public function OBJ_ID()
200
-    {
201
-        return $this->get('OBJ_ID');
202
-    }
203
-
204
-
205
-    /**
206
-     * Sets item_id
207
-     *
208
-     * @param string $item_id
209
-     * @throws EE_Error
210
-     */
211
-    public function set_OBJ_ID($item_id)
212
-    {
213
-        $this->set('OBJ_ID', $item_id);
214
-    }
215
-
216
-
217
-    /**
218
-     * Gets item_type
219
-     *
220
-     * @return string
221
-     * @throws EE_Error
222
-     */
223
-    public function OBJ_type()
224
-    {
225
-        return $this->get('OBJ_type');
226
-    }
227
-
228
-
229
-    /**
230
-     * Gets item_type
231
-     *
232
-     * @return string
233
-     * @throws EE_Error
234
-     */
235
-    public function OBJ_type_i18n()
236
-    {
237
-        $obj_type = $this->OBJ_type();
238
-        switch ($obj_type) {
239
-            case 'Event':
240
-                $obj_type = __('Event', 'event_espresso');
241
-                break;
242
-            case 'Price':
243
-                $obj_type = __('Price', 'event_espresso');
244
-                break;
245
-            case 'Promotion':
246
-                $obj_type = __('Promotion', 'event_espresso');
247
-                break;
248
-            case 'Ticket':
249
-                $obj_type = __('Ticket', 'event_espresso');
250
-                break;
251
-            case 'Transaction':
252
-                $obj_type = __('Transaction', 'event_espresso');
253
-                break;
254
-        }
255
-        return apply_filters('FHEE__EE_Line_Item__OBJ_type_i18n', $obj_type, $this);
256
-    }
257
-
258
-
259
-    /**
260
-     * Sets item_type
261
-     *
262
-     * @param string $OBJ_type
263
-     * @throws EE_Error
264
-     */
265
-    public function set_OBJ_type($OBJ_type)
266
-    {
267
-        $this->set('OBJ_type', $OBJ_type);
268
-    }
269
-
270
-
271
-    /**
272
-     * Gets unit_price
273
-     *
274
-     * @return float
275
-     * @throws EE_Error
276
-     */
277
-    public function unit_price()
278
-    {
279
-        return $this->get('LIN_unit_price');
280
-    }
281
-
282
-
283
-    /**
284
-     * Sets unit_price
285
-     *
286
-     * @param float $unit_price
287
-     * @throws EE_Error
288
-     */
289
-    public function set_unit_price($unit_price)
290
-    {
291
-        $this->set('LIN_unit_price', $unit_price);
292
-    }
293
-
294
-
295
-    /**
296
-     * Checks if this item is a percentage modifier or not
297
-     *
298
-     * @return boolean
299
-     * @throws EE_Error
300
-     */
301
-    public function is_percent()
302
-    {
303
-        if ($this->is_tax_sub_total()) {
304
-            // tax subtotals HAVE a percent on them, that percentage only applies
305
-            // to taxable items, so its' an exception. Treat it like a flat line item
306
-            return false;
307
-        }
308
-        $unit_price = abs($this->get('LIN_unit_price'));
309
-        $percent = abs($this->get('LIN_percent'));
310
-        if ($unit_price < .001 && $percent) {
311
-            return true;
312
-        }
313
-        if ($unit_price >= .001 && ! $percent) {
314
-            return false;
315
-        }
316
-        if ($unit_price >= .001 && $percent) {
317
-            throw new EE_Error(
318
-                sprintf(
319
-                    esc_html__('A Line Item can not have a unit price of (%s) AND a percent (%s)!', 'event_espresso'),
320
-                    $unit_price,
321
-                    $percent
322
-                )
323
-            );
324
-        }
325
-        // if they're both 0, assume its not a percent item
326
-        return false;
327
-    }
328
-
329
-
330
-    /**
331
-     * Gets percent (between 100-.001)
332
-     *
333
-     * @return float
334
-     * @throws EE_Error
335
-     */
336
-    public function percent()
337
-    {
338
-        return $this->get('LIN_percent');
339
-    }
340
-
341
-
342
-    /**
343
-     * Sets percent (between 100-0.01)
344
-     *
345
-     * @param float $percent
346
-     * @throws EE_Error
347
-     */
348
-    public function set_percent($percent)
349
-    {
350
-        $this->set('LIN_percent', $percent);
351
-    }
352
-
353
-
354
-    /**
355
-     * Gets total
356
-     *
357
-     * @return float
358
-     * @throws EE_Error
359
-     */
360
-    public function total()
361
-    {
362
-        return $this->get('LIN_total');
363
-    }
364
-
365
-
366
-    /**
367
-     * Sets total
368
-     *
369
-     * @param float $total
370
-     * @throws EE_Error
371
-     */
372
-    public function set_total($total)
373
-    {
374
-        $this->set('LIN_total', $total);
375
-    }
376
-
377
-
378
-    /**
379
-     * Gets order
380
-     *
381
-     * @return int
382
-     * @throws EE_Error
383
-     */
384
-    public function order()
385
-    {
386
-        return $this->get('LIN_order');
387
-    }
388
-
389
-
390
-    /**
391
-     * Sets order
392
-     *
393
-     * @param int $order
394
-     * @throws EE_Error
395
-     */
396
-    public function set_order($order)
397
-    {
398
-        $this->set('LIN_order', $order);
399
-    }
400
-
401
-
402
-    /**
403
-     * Gets parent
404
-     *
405
-     * @return int
406
-     * @throws EE_Error
407
-     */
408
-    public function parent_ID()
409
-    {
410
-        return $this->get('LIN_parent');
411
-    }
412
-
413
-
414
-    /**
415
-     * Sets parent
416
-     *
417
-     * @param int $parent
418
-     * @throws EE_Error
419
-     */
420
-    public function set_parent_ID($parent)
421
-    {
422
-        $this->set('LIN_parent', $parent);
423
-    }
424
-
425
-
426
-    /**
427
-     * Gets type
428
-     *
429
-     * @return string
430
-     * @throws EE_Error
431
-     */
432
-    public function type()
433
-    {
434
-        return $this->get('LIN_type');
435
-    }
436
-
437
-
438
-    /**
439
-     * Sets type
440
-     *
441
-     * @param string $type
442
-     * @throws EE_Error
443
-     */
444
-    public function set_type($type)
445
-    {
446
-        $this->set('LIN_type', $type);
447
-    }
448
-
449
-
450
-    /**
451
-     * Gets the line item of which this item is a composite. Eg, if this is a subtotal, the parent might be a total\
452
-     * If this line item is saved to the DB, fetches the parent from the DB. However, if this line item isn't in the DB
453
-     * it uses its cached reference to its parent line item (which would have been set by `EE_Line_Item::set_parent()`
454
-     * or indirectly by `EE_Line_item::add_child_line_item()`)
455
-     *
456
-     * @return EE_Base_Class|EE_Line_Item
457
-     * @throws EE_Error
458
-     */
459
-    public function parent()
460
-    {
461
-        return $this->ID()
462
-            ? $this->get_model()->get_one_by_ID($this->parent_ID())
463
-            : $this->_parent;
464
-    }
465
-
466
-
467
-    /**
468
-     * Gets ALL the children of this line item (ie, all the parts that contribute towards this total).
469
-     *
470
-     * @return EE_Base_Class[]|EE_Line_Item[]
471
-     * @throws EE_Error
472
-     */
473
-    public function children()
474
-    {
475
-        if ($this->ID()) {
476
-            return $this->get_model()->get_all(
477
-                array(
478
-                    array('LIN_parent' => $this->ID()),
479
-                    'order_by' => array('LIN_order' => 'ASC'),
480
-                )
481
-            );
482
-        }
483
-        if (! is_array($this->_children)) {
484
-            $this->_children = array();
485
-        }
486
-        return $this->_children;
487
-    }
488
-
489
-
490
-    /**
491
-     * Gets code
492
-     *
493
-     * @return string
494
-     * @throws EE_Error
495
-     */
496
-    public function code()
497
-    {
498
-        return $this->get('LIN_code');
499
-    }
500
-
501
-
502
-    /**
503
-     * Sets code
504
-     *
505
-     * @param string $code
506
-     * @throws EE_Error
507
-     */
508
-    public function set_code($code)
509
-    {
510
-        $this->set('LIN_code', $code);
511
-    }
512
-
513
-
514
-    /**
515
-     * Gets is_taxable
516
-     *
517
-     * @return boolean
518
-     * @throws EE_Error
519
-     */
520
-    public function is_taxable()
521
-    {
522
-        return $this->get('LIN_is_taxable');
523
-    }
524
-
525
-
526
-    /**
527
-     * Sets is_taxable
528
-     *
529
-     * @param boolean $is_taxable
530
-     * @throws EE_Error
531
-     */
532
-    public function set_is_taxable($is_taxable)
533
-    {
534
-        $this->set('LIN_is_taxable', $is_taxable);
535
-    }
536
-
537
-
538
-    /**
539
-     * Gets the object that this model-joins-to.
540
-     * returns one of the model objects that the field OBJ_ID can point to... see the 'OBJ_ID' field on
541
-     * EEM_Promotion_Object
542
-     *
543
-     *        Eg, if this line item join model object is for a ticket, this will return the EE_Ticket object
544
-     *
545
-     * @return EE_Base_Class | NULL
546
-     * @throws EE_Error
547
-     */
548
-    public function get_object()
549
-    {
550
-        $model_name_of_related_obj = $this->OBJ_type();
551
-        return $this->get_model()->has_relation($model_name_of_related_obj)
552
-            ? $this->get_first_related($model_name_of_related_obj)
553
-            : null;
554
-    }
555
-
556
-
557
-    /**
558
-     * Like EE_Line_Item::get_object(), but can only ever actually return an EE_Ticket.
559
-     * (IE, if this line item is for a price or something else, will return NULL)
560
-     *
561
-     * @param array $query_params
562
-     * @return EE_Base_Class|EE_Ticket
563
-     * @throws EE_Error
564
-     */
565
-    public function ticket($query_params = array())
566
-    {
567
-        // we're going to assume that when this method is called we always want to receive the attached ticket EVEN if that ticket is archived.  This can be overridden via the incoming $query_params argument
568
-        $remove_defaults = array('default_where_conditions' => 'none');
569
-        $query_params = array_merge($remove_defaults, $query_params);
570
-        return $this->get_first_related('Ticket', $query_params);
571
-    }
572
-
573
-
574
-    /**
575
-     * Gets the EE_Datetime that's related to the ticket, IF this is for a ticket
576
-     *
577
-     * @return EE_Datetime | NULL
578
-     * @throws EE_Error
579
-     */
580
-    public function get_ticket_datetime()
581
-    {
582
-        if ($this->OBJ_type() === 'Ticket') {
583
-            $ticket = $this->ticket();
584
-            if ($ticket instanceof EE_Ticket) {
585
-                $datetime = $ticket->first_datetime();
586
-                if ($datetime instanceof EE_Datetime) {
587
-                    return $datetime;
588
-                }
589
-            }
590
-        }
591
-        return null;
592
-    }
593
-
594
-
595
-    /**
596
-     * Gets the event's name that's related to the ticket, if this is for
597
-     * a ticket
598
-     *
599
-     * @return string
600
-     * @throws EE_Error
601
-     */
602
-    public function ticket_event_name()
603
-    {
604
-        $event_name = esc_html__('Unknown', 'event_espresso');
605
-        $event = $this->ticket_event();
606
-        if ($event instanceof EE_Event) {
607
-            $event_name = $event->name();
608
-        }
609
-        return $event_name;
610
-    }
611
-
612
-
613
-    /**
614
-     * Gets the event that's related to the ticket, if this line item represents a ticket.
615
-     *
616
-     * @return EE_Event|null
617
-     * @throws EE_Error
618
-     */
619
-    public function ticket_event()
620
-    {
621
-        $event = null;
622
-        $ticket = $this->ticket();
623
-        if ($ticket instanceof EE_Ticket) {
624
-            $datetime = $ticket->first_datetime();
625
-            if ($datetime instanceof EE_Datetime) {
626
-                $event = $datetime->event();
627
-            }
628
-        }
629
-        return $event;
630
-    }
631
-
632
-
633
-    /**
634
-     * Gets the first datetime for this lien item, assuming it's for a ticket
635
-     *
636
-     * @param string $date_format
637
-     * @param string $time_format
638
-     * @return string
639
-     * @throws EE_Error
640
-     */
641
-    public function ticket_datetime_start($date_format = '', $time_format = '')
642
-    {
643
-        $first_datetime_string = esc_html__('Unknown', 'event_espresso');
644
-        $datetime = $this->get_ticket_datetime();
645
-        if ($datetime) {
646
-            $first_datetime_string = $datetime->start_date_and_time($date_format, $time_format);
647
-        }
648
-        return $first_datetime_string;
649
-    }
650
-
651
-
652
-    /**
653
-     * Adds the line item as a child to this line item. If there is another child line
654
-     * item with the same LIN_code, it is overwritten by this new one
655
-     *
656
-     * @param EEI_Line_Item $line_item
657
-     * @param bool          $set_order
658
-     * @return bool success
659
-     * @throws EE_Error
660
-     */
661
-    public function add_child_line_item(EEI_Line_Item $line_item, $set_order = true)
662
-    {
663
-        // should we calculate the LIN_order for this line item ?
664
-        if ($set_order || $line_item->order() === null) {
665
-            $line_item->set_order(count($this->children()));
666
-        }
667
-        if ($this->ID()) {
668
-            // check for any duplicate line items (with the same code), if so, this replaces it
669
-            $line_item_with_same_code = $this->get_child_line_item($line_item->code());
670
-            if ($line_item_with_same_code instanceof EE_Line_Item && $line_item_with_same_code !== $line_item) {
671
-                $this->delete_child_line_item($line_item_with_same_code->code());
672
-            }
673
-            $line_item->set_parent_ID($this->ID());
674
-            if ($this->TXN_ID()) {
675
-                $line_item->set_TXN_ID($this->TXN_ID());
676
-            }
677
-            return $line_item->save();
678
-        }
679
-        $this->_children[ $line_item->code() ] = $line_item;
680
-        if ($line_item->parent() !== $this) {
681
-            $line_item->set_parent($this);
682
-        }
683
-        return true;
684
-    }
685
-
686
-
687
-    /**
688
-     * Similar to EE_Base_Class::_add_relation_to, except this isn't a normal relation.
689
-     * If this line item is saved to the DB, this is just a wrapper for set_parent_ID() and save()
690
-     * However, if this line item is NOT saved to the DB, this just caches the parent on
691
-     * the EE_Line_Item::_parent property.
692
-     *
693
-     * @param EE_Line_Item $line_item
694
-     * @throws EE_Error
695
-     */
696
-    public function set_parent($line_item)
697
-    {
698
-        if ($this->ID()) {
699
-            if (! $line_item->ID()) {
700
-                $line_item->save();
701
-            }
702
-            $this->set_parent_ID($line_item->ID());
703
-            $this->save();
704
-        } else {
705
-            $this->_parent = $line_item;
706
-            $this->set_parent_ID($line_item->ID());
707
-        }
708
-    }
709
-
710
-
711
-    /**
712
-     * Gets the child line item as specified by its code. Because this returns an object (by reference)
713
-     * you can modify this child line item and the parent (this object) can know about them
714
-     * because it also has a reference to that line item
715
-     *
716
-     * @param string $code
717
-     * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL
718
-     * @throws EE_Error
719
-     */
720
-    public function get_child_line_item($code)
721
-    {
722
-        if ($this->ID()) {
723
-            return $this->get_model()->get_one(
724
-                array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code))
725
-            );
726
-        }
727
-        return isset($this->_children[ $code ])
728
-            ? $this->_children[ $code ]
729
-            : null;
730
-    }
731
-
732
-
733
-    /**
734
-     * Returns how many items are deleted (or, if this item has not been saved ot the DB yet, just how many it HAD
735
-     * cached on it)
736
-     *
737
-     * @return int
738
-     * @throws EE_Error
739
-     */
740
-    public function delete_children_line_items()
741
-    {
742
-        if ($this->ID()) {
743
-            return $this->get_model()->delete(array(array('LIN_parent' => $this->ID())));
744
-        }
745
-        $count = count($this->_children);
746
-        $this->_children = array();
747
-        return $count;
748
-    }
749
-
750
-
751
-    /**
752
-     * If this line item has been saved to the DB, deletes its child with LIN_code == $code. If this line
753
-     * HAS NOT been saved to the DB, removes the child line item with index $code.
754
-     * Also searches through the child's children for a matching line item. However, once a line item has been found
755
-     * and deleted, stops searching (so if there are line items with duplicate codes, only the first one found will be
756
-     * deleted)
757
-     *
758
-     * @param string $code
759
-     * @param bool   $stop_search_once_found
760
-     * @return int count of items deleted (or simply removed from the line item's cache, if not has not been saved to
761
-     *             the DB yet)
762
-     * @throws EE_Error
763
-     */
764
-    public function delete_child_line_item($code, $stop_search_once_found = true)
765
-    {
766
-        if ($this->ID()) {
767
-            $items_deleted = 0;
768
-            if ($this->code() === $code) {
769
-                $items_deleted += EEH_Line_Item::delete_all_child_items($this);
770
-                $items_deleted += (int) $this->delete();
771
-                if ($stop_search_once_found) {
772
-                    return $items_deleted;
773
-                }
774
-            }
775
-            foreach ($this->children() as $child_line_item) {
776
-                $items_deleted += $child_line_item->delete_child_line_item($code, $stop_search_once_found);
777
-            }
778
-            return $items_deleted;
779
-        }
780
-        if (isset($this->_children[ $code ])) {
781
-            unset($this->_children[ $code ]);
782
-            return 1;
783
-        }
784
-        return 0;
785
-    }
786
-
787
-
788
-    /**
789
-     * If this line item is in the database, is of the type subtotal, and
790
-     * has no children, why do we have it? It should be deleted so this function
791
-     * does that
792
-     *
793
-     * @return boolean
794
-     * @throws EE_Error
795
-     */
796
-    public function delete_if_childless_subtotal()
797
-    {
798
-        if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && ! $this->children()) {
799
-            return $this->delete();
800
-        }
801
-        return false;
802
-    }
803
-
804
-
805
-    /**
806
-     * Creates a code and returns a string. doesn't assign the code to this model object
807
-     *
808
-     * @return string
809
-     * @throws EE_Error
810
-     */
811
-    public function generate_code()
812
-    {
813
-        // each line item in the cart requires a unique identifier
814
-        return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime());
815
-    }
816
-
817
-
818
-    /**
819
-     * @return bool
820
-     * @throws EE_Error
821
-     */
822
-    public function is_tax()
823
-    {
824
-        return $this->type() === EEM_Line_Item::type_tax;
825
-    }
826
-
827
-
828
-    /**
829
-     * @return bool
830
-     * @throws EE_Error
831
-     */
832
-    public function is_tax_sub_total()
833
-    {
834
-        return $this->type() === EEM_Line_Item::type_tax_sub_total;
835
-    }
836
-
837
-
838
-    /**
839
-     * @return bool
840
-     * @throws EE_Error
841
-     */
842
-    public function is_line_item()
843
-    {
844
-        return $this->type() === EEM_Line_Item::type_line_item;
845
-    }
846
-
847
-
848
-    /**
849
-     * @return bool
850
-     * @throws EE_Error
851
-     */
852
-    public function is_sub_line_item()
853
-    {
854
-        return $this->type() === EEM_Line_Item::type_sub_line_item;
855
-    }
856
-
857
-
858
-    /**
859
-     * @return bool
860
-     * @throws EE_Error
861
-     */
862
-    public function is_sub_total()
863
-    {
864
-        return $this->type() === EEM_Line_Item::type_sub_total;
865
-    }
866
-
867
-
868
-    /**
869
-     * Whether or not this line item is a cancellation line item
870
-     *
871
-     * @return boolean
872
-     * @throws EE_Error
873
-     */
874
-    public function is_cancellation()
875
-    {
876
-        return EEM_Line_Item::type_cancellation === $this->type();
877
-    }
878
-
879
-
880
-    /**
881
-     * @return bool
882
-     * @throws EE_Error
883
-     */
884
-    public function is_total()
885
-    {
886
-        return $this->type() === EEM_Line_Item::type_total;
887
-    }
888
-
889
-
890
-    /**
891
-     * @return bool
892
-     * @throws EE_Error
893
-     */
894
-    public function is_cancelled()
895
-    {
896
-        return $this->type() === EEM_Line_Item::type_cancellation;
897
-    }
898
-
899
-
900
-    /**
901
-     * @return string like '2, 004.00', formatted according to the localized currency
902
-     * @throws EE_Error
903
-     */
904
-    public function unit_price_no_code()
905
-    {
906
-        return $this->get_pretty('LIN_unit_price', 'no_currency_code');
907
-    }
908
-
909
-
910
-    /**
911
-     * @return string like '2, 004.00', formatted according to the localized currency
912
-     * @throws EE_Error
913
-     */
914
-    public function total_no_code()
915
-    {
916
-        return $this->get_pretty('LIN_total', 'no_currency_code');
917
-    }
918
-
919
-
920
-    /**
921
-     * Gets the final total on this item, taking taxes into account.
922
-     * Has the side-effect of setting the sub-total as it was just calculated.
923
-     * If this is used on a grand-total line item, also updates the transaction's
924
-     * TXN_total (provided this line item is allowed to persist, otherwise we don't
925
-     * want to change a persistable transaction with info from a non-persistent line item)
926
-     *
927
-     * @return float
928
-     * @throws EE_Error
929
-     * @throws InvalidArgumentException
930
-     * @throws InvalidInterfaceException
931
-     * @throws InvalidDataTypeException
932
-     */
933
-    public function recalculate_total_including_taxes()
934
-    {
935
-        $pre_tax_total = $this->recalculate_pre_tax_total();
936
-        $tax_total = $this->recalculate_taxes_and_tax_total();
937
-        $total = $pre_tax_total + $tax_total;
938
-        // no negative totals plz
939
-        $total = max($total, 0);
940
-        $this->set_total($total);
941
-        // only update the related transaction's total
942
-        // if we intend to save this line item and its a grand total
943
-        if ($this->allow_persist() && $this->type() === EEM_Line_Item::type_total
944
-            && $this->transaction()
945
-               instanceof
946
-               EE_Transaction
947
-        ) {
948
-            $this->transaction()->set_total($total);
949
-            if ($this->transaction()->ID()) {
950
-                $this->transaction()->save();
951
-            }
952
-        }
953
-        $this->maybe_save();
954
-        return $total;
955
-    }
956
-
957
-
958
-    /**
959
-     * Recursively goes through all the children and recalculates sub-totals EXCEPT for
960
-     * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its
961
-     * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and
962
-     * when this is called on the grand total
963
-     *
964
-     * @return float
965
-     * @throws InvalidArgumentException
966
-     * @throws InvalidInterfaceException
967
-     * @throws InvalidDataTypeException
968
-     * @throws EE_Error
969
-     */
970
-    public function recalculate_pre_tax_total()
971
-    {
972
-        $total = 0;
973
-        $my_children = $this->children();
974
-        $has_children = ! empty($my_children);
975
-        if ($has_children && $this->is_line_item()) {
976
-            $total = $this->_recalculate_pretax_total_for_line_item($total, $my_children);
977
-        } elseif (! $has_children && ($this->is_sub_line_item() || $this->is_line_item())) {
978
-            $total = $this->unit_price() * $this->quantity();
979
-        } elseif ($this->is_sub_total() || $this->is_total()) {
980
-            $total = $this->_recalculate_pretax_total_for_subtotal($total, $my_children);
981
-        } elseif ($this->is_tax_sub_total() || $this->is_tax() || $this->is_cancelled()) {
982
-            // completely ignore tax totals, tax sub-totals, and cancelled line items, when calculating the pre-tax-total
983
-            return 0;
984
-        }
985
-        // ensure all non-line items and non-sub-line-items have a quantity of 1 (except for Events)
986
-        if (! $this->is_line_item() && ! $this->is_sub_line_item() && ! $this->is_cancellation()
987
-        ) {
988
-            if ($this->OBJ_type() !== 'Event') {
989
-                $this->set_quantity(1);
990
-            }
991
-            if (! $this->is_percent()) {
992
-                $this->set_unit_price($total);
993
-            }
994
-        }
995
-        // we don't want to bother saving grand totals, because that needs to factor in taxes anyways
996
-        // so it ought to be
997
-        if (! $this->is_total()) {
998
-            $this->set_total($total);
999
-            // if not a percent line item, make sure we keep the unit price in sync
1000
-            if ($has_children
1001
-                && $this->is_line_item()
1002
-                && ! $this->is_percent()
1003
-            ) {
1004
-                if ($this->quantity() === 0) {
1005
-                    $new_unit_price = 0;
1006
-                } else {
1007
-                    $new_unit_price = $this->total() / $this->quantity();
1008
-                }
1009
-                $this->set_unit_price($new_unit_price);
1010
-            }
1011
-            $this->maybe_save();
1012
-        }
1013
-        return $total;
1014
-    }
1015
-
1016
-
1017
-    /**
1018
-     * Calculates the pretax total when this line item is a subtotal or total line item.
1019
-     * Basically does a sum-then-round approach (ie, any percent line item that are children
1020
-     * will calculate their total based on the un-rounded total we're working with so far, and
1021
-     * THEN round the result; instead of rounding as we go like with sub-line-items)
1022
-     *
1023
-     * @param float          $calculated_total_so_far
1024
-     * @param EE_Line_Item[] $my_children
1025
-     * @return float
1026
-     * @throws InvalidArgumentException
1027
-     * @throws InvalidInterfaceException
1028
-     * @throws InvalidDataTypeException
1029
-     * @throws EE_Error
1030
-     */
1031
-    protected function _recalculate_pretax_total_for_subtotal($calculated_total_so_far, $my_children = null)
1032
-    {
1033
-        if ($my_children === null) {
1034
-            $my_children = $this->children();
1035
-        }
1036
-        $subtotal_quantity = 0;
1037
-        // get the total of all its children
1038
-        foreach ($my_children as $child_line_item) {
1039
-            if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) {
1040
-                // percentage line items are based on total so far
1041
-                if ($child_line_item->is_percent()) {
1042
-                    // round as we go so that the line items add up ok
1043
-                    $percent_total = round(
1044
-                        $calculated_total_so_far * $child_line_item->percent() / 100,
1045
-                        EE_Registry::instance()->CFG->currency->dec_plc
1046
-                    );
1047
-                    $child_line_item->set_total($percent_total);
1048
-                    // so far all percent line items should have a quantity of 1
1049
-                    // (ie, no double percent discounts. Although that might be requested someday)
1050
-                    $child_line_item->set_quantity(1);
1051
-                    $child_line_item->maybe_save();
1052
-                    $calculated_total_so_far += $percent_total;
1053
-                } else {
1054
-                    // verify flat sub-line-item quantities match their parent
1055
-                    if ($child_line_item->is_sub_line_item()) {
1056
-                        $child_line_item->set_quantity($this->quantity());
1057
-                    }
1058
-                    $calculated_total_so_far += $child_line_item->recalculate_pre_tax_total();
1059
-                    $subtotal_quantity += $child_line_item->quantity();
1060
-                }
1061
-            }
1062
-        }
1063
-        if ($this->is_sub_total()) {
1064
-            // no negative totals plz
1065
-            $calculated_total_so_far = max($calculated_total_so_far, 0);
1066
-            $subtotal_quantity = $subtotal_quantity > 0 ? 1 : 0;
1067
-            $this->set_quantity($subtotal_quantity);
1068
-            $this->maybe_save();
1069
-        }
1070
-        return $calculated_total_so_far;
1071
-    }
1072
-
1073
-
1074
-    /**
1075
-     * Calculates the pretax total for a normal line item, in a round-then-sum approach
1076
-     * (where each sub-line-item is applied to the base price for the line item
1077
-     * and the result is immediately rounded, rather than summing all the sub-line-items
1078
-     * then rounding, like we do when recalculating pretax totals on totals and subtotals).
1079
-     *
1080
-     * @param float          $calculated_total_so_far
1081
-     * @param EE_Line_Item[] $my_children
1082
-     * @return float
1083
-     * @throws InvalidArgumentException
1084
-     * @throws InvalidInterfaceException
1085
-     * @throws InvalidDataTypeException
1086
-     * @throws EE_Error
1087
-     */
1088
-    protected function _recalculate_pretax_total_for_line_item($calculated_total_so_far, $my_children = null)
1089
-    {
1090
-        if ($my_children === null) {
1091
-            $my_children = $this->children();
1092
-        }
1093
-        // we need to keep track of the running total for a single item,
1094
-        // because we need to round as we go
1095
-        $unit_price_for_total = 0;
1096
-        $quantity_for_total = 1;
1097
-        // get the total of all its children
1098
-        foreach ($my_children as $child_line_item) {
1099
-            if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) {
1100
-                if ($child_line_item->is_percent()) {
1101
-                    // it should be the unit-price-so-far multiplied by teh percent multiplied by the quantity
1102
-                    // not total multiplied by percent, because that ignores rounding along-the-way
1103
-                    $percent_unit_price = round(
1104
-                        $unit_price_for_total * $child_line_item->percent() / 100,
1105
-                        EE_Registry::instance()->CFG->currency->dec_plc
1106
-                    );
1107
-                    $percent_total = $percent_unit_price * $quantity_for_total;
1108
-                    $child_line_item->set_total($percent_total);
1109
-                    // so far all percent line items should have a quantity of 1
1110
-                    // (ie, no double percent discounts. Although that might be requested someday)
1111
-                    $child_line_item->set_quantity(1);
1112
-                    $child_line_item->maybe_save();
1113
-                    $calculated_total_so_far += $percent_total;
1114
-                    $unit_price_for_total += $percent_unit_price;
1115
-                } else {
1116
-                    // verify flat sub-line-item quantities match their parent
1117
-                    if ($child_line_item->is_sub_line_item()) {
1118
-                        $child_line_item->set_quantity($this->quantity());
1119
-                    }
1120
-                    $quantity_for_total = $child_line_item->quantity();
1121
-                    $calculated_total_so_far += $child_line_item->recalculate_pre_tax_total();
1122
-                    $unit_price_for_total += $child_line_item->unit_price();
1123
-                }
1124
-            }
1125
-        }
1126
-        return $calculated_total_so_far;
1127
-    }
1128
-
1129
-
1130
-    /**
1131
-     * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets
1132
-     * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items
1133
-     * and tax sub-total if already in the DB
1134
-     *
1135
-     * @return float
1136
-     * @throws EE_Error
1137
-     */
1138
-    public function recalculate_taxes_and_tax_total()
1139
-    {
1140
-        // get all taxes
1141
-        $taxes = $this->tax_descendants();
1142
-        // calculate the pretax total
1143
-        $taxable_total = $this->taxable_total();
1144
-        $tax_total = 0;
1145
-        foreach ($taxes as $tax) {
1146
-            $total_on_this_tax = $taxable_total * $tax->percent() / 100;
1147
-            // remember the total on this line item
1148
-            $tax->set_total($total_on_this_tax);
1149
-            $tax->maybe_save();
1150
-            $tax_total += $tax->total();
1151
-        }
1152
-        $this->_recalculate_tax_sub_total();
1153
-        return $tax_total;
1154
-    }
1155
-
1156
-
1157
-    /**
1158
-     * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated
1159
-     *
1160
-     * @return void
1161
-     * @throws EE_Error
1162
-     */
1163
-    private function _recalculate_tax_sub_total()
1164
-    {
1165
-        if ($this->is_tax_sub_total()) {
1166
-            $total = 0;
1167
-            $total_percent = 0;
1168
-            // simply loop through all its children (which should be taxes) and sum their total
1169
-            foreach ($this->children() as $child_tax) {
1170
-                if ($child_tax instanceof EE_Line_Item) {
1171
-                    $total += $child_tax->total();
1172
-                    $total_percent += $child_tax->percent();
1173
-                }
1174
-            }
1175
-            $this->set_total($total);
1176
-            $this->set_percent($total_percent);
1177
-            $this->maybe_save();
1178
-        } elseif ($this->is_total()) {
1179
-            foreach ($this->children() as $maybe_tax_subtotal) {
1180
-                if ($maybe_tax_subtotal instanceof EE_Line_Item) {
1181
-                    $maybe_tax_subtotal->_recalculate_tax_sub_total();
1182
-                }
1183
-            }
1184
-        }
1185
-    }
1186
-
1187
-
1188
-    /**
1189
-     * Gets the total tax on this line item. Assumes taxes have already been calculated using
1190
-     * recalculate_taxes_and_total
1191
-     *
1192
-     * @return float
1193
-     * @throws EE_Error
1194
-     */
1195
-    public function get_total_tax()
1196
-    {
1197
-        $this->_recalculate_tax_sub_total();
1198
-        $total = 0;
1199
-        foreach ($this->tax_descendants() as $tax_line_item) {
1200
-            if ($tax_line_item instanceof EE_Line_Item) {
1201
-                $total += $tax_line_item->total();
1202
-            }
1203
-        }
1204
-        return $total;
1205
-    }
1206
-
1207
-
1208
-    /**
1209
-     * Gets the total for all the items purchased only
1210
-     *
1211
-     * @return float
1212
-     * @throws EE_Error
1213
-     */
1214
-    public function get_items_total()
1215
-    {
1216
-        // by default, let's make sure we're consistent with the existing line item
1217
-        if ($this->is_total()) {
1218
-            $pretax_subtotal_li = EEH_Line_Item::get_pre_tax_subtotal($this);
1219
-            if ($pretax_subtotal_li instanceof EE_Line_Item) {
1220
-                return $pretax_subtotal_li->total();
1221
-            }
1222
-        }
1223
-        $total = 0;
1224
-        foreach ($this->get_items() as $item) {
1225
-            if ($item instanceof EE_Line_Item) {
1226
-                $total += $item->total();
1227
-            }
1228
-        }
1229
-        return $total;
1230
-    }
1231
-
1232
-
1233
-    /**
1234
-     * Gets all the descendants (ie, children or children of children etc) that
1235
-     * are of the type 'tax'
1236
-     *
1237
-     * @return EE_Line_Item[]
1238
-     */
1239
-    public function tax_descendants()
1240
-    {
1241
-        return EEH_Line_Item::get_tax_descendants($this);
1242
-    }
1243
-
1244
-
1245
-    /**
1246
-     * Gets all the real items purchased which are children of this item
1247
-     *
1248
-     * @return EE_Line_Item[]
1249
-     */
1250
-    public function get_items()
1251
-    {
1252
-        return EEH_Line_Item::get_line_item_descendants($this);
1253
-    }
1254
-
1255
-
1256
-    /**
1257
-     * Returns the amount taxable among this line item's children (or if it has no children,
1258
-     * how much of it is taxable). Does not recalculate totals or subtotals.
1259
-     * If the taxable total is negative, (eg, if none of the tickets were taxable,
1260
-     * but there is a "Taxable" discount), returns 0.
1261
-     *
1262
-     * @return float
1263
-     * @throws EE_Error
1264
-     */
1265
-    public function taxable_total()
1266
-    {
1267
-        $total = 0;
1268
-        if ($this->children()) {
1269
-            foreach ($this->children() as $child_line_item) {
1270
-                if ($child_line_item->type() === EEM_Line_Item::type_line_item && $child_line_item->is_taxable()) {
1271
-                    // if it's a percent item, only take into account the percent
1272
-                    // that's taxable too (the taxable total so far)
1273
-                    if ($child_line_item->is_percent()) {
1274
-                        $total += ($total * $child_line_item->percent() / 100);
1275
-                    } else {
1276
-                        $total += $child_line_item->total();
1277
-                    }
1278
-                } elseif ($child_line_item->type() === EEM_Line_Item::type_sub_total) {
1279
-                    $total += $child_line_item->taxable_total();
1280
-                }
1281
-            }
1282
-        }
1283
-        return max($total, 0);
1284
-    }
1285
-
1286
-
1287
-    /**
1288
-     * Gets the transaction for this line item
1289
-     *
1290
-     * @return EE_Base_Class|EE_Transaction
1291
-     * @throws EE_Error
1292
-     */
1293
-    public function transaction()
1294
-    {
1295
-        return $this->get_first_related('Transaction');
1296
-    }
1297
-
1298
-
1299
-    /**
1300
-     * Saves this line item to the DB, and recursively saves its descendants.
1301
-     * Because there currently is no proper parent-child relation on the model,
1302
-     * save_this_and_cached() will NOT save the descendants.
1303
-     * Also sets the transaction on this line item and all its descendants before saving
1304
-     *
1305
-     * @param int $txn_id if none is provided, assumes $this->TXN_ID()
1306
-     * @return int count of items saved
1307
-     * @throws EE_Error
1308
-     */
1309
-    public function save_this_and_descendants_to_txn($txn_id = null)
1310
-    {
1311
-        $count = 0;
1312
-        if (! $txn_id) {
1313
-            $txn_id = $this->TXN_ID();
1314
-        }
1315
-        $this->set_TXN_ID($txn_id);
1316
-        $children = $this->children();
1317
-        $count += $this->save()
1318
-            ? 1
1319
-            : 0;
1320
-        foreach ($children as $child_line_item) {
1321
-            if ($child_line_item instanceof EE_Line_Item) {
1322
-                $child_line_item->set_parent_ID($this->ID());
1323
-                $count += $child_line_item->save_this_and_descendants_to_txn($txn_id);
1324
-            }
1325
-        }
1326
-        return $count;
1327
-    }
1328
-
1329
-
1330
-    /**
1331
-     * Saves this line item to the DB, and recursively saves its descendants.
1332
-     *
1333
-     * @return int count of items saved
1334
-     * @throws EE_Error
1335
-     */
1336
-    public function save_this_and_descendants()
1337
-    {
1338
-        $count = 0;
1339
-        $children = $this->children();
1340
-        $count += $this->save()
1341
-            ? 1
1342
-            : 0;
1343
-        foreach ($children as $child_line_item) {
1344
-            if ($child_line_item instanceof EE_Line_Item) {
1345
-                $child_line_item->set_parent_ID($this->ID());
1346
-                $count += $child_line_item->save_this_and_descendants();
1347
-            }
1348
-        }
1349
-        return $count;
1350
-    }
1351
-
1352
-
1353
-    /**
1354
-     * returns the cancellation line item if this item was cancelled
1355
-     *
1356
-     * @return EE_Line_Item[]
1357
-     * @throws InvalidArgumentException
1358
-     * @throws InvalidInterfaceException
1359
-     * @throws InvalidDataTypeException
1360
-     * @throws ReflectionException
1361
-     * @throws EE_Error
1362
-     */
1363
-    public function get_cancellations()
1364
-    {
1365
-        EE_Registry::instance()->load_helper('Line_Item');
1366
-        return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_cancellation);
1367
-    }
1368
-
1369
-
1370
-    /**
1371
-     * If this item has an ID, then this saves it again to update the db
1372
-     *
1373
-     * @return int count of items saved
1374
-     * @throws EE_Error
1375
-     */
1376
-    public function maybe_save()
1377
-    {
1378
-        if ($this->ID()) {
1379
-            return $this->save();
1380
-        }
1381
-        return false;
1382
-    }
1383
-
1384
-
1385
-    /**
1386
-     * clears the cached children and parent from the line item
1387
-     *
1388
-     * @return void
1389
-     */
1390
-    public function clear_related_line_item_cache()
1391
-    {
1392
-        $this->_children = array();
1393
-        $this->_parent = null;
1394
-    }
1395
-
1396
-
1397
-    /**
1398
-     * @param bool $raw
1399
-     * @return int
1400
-     * @throws EE_Error
1401
-     */
1402
-    public function timestamp($raw = false)
1403
-    {
1404
-        return $raw
1405
-            ? $this->get_raw('LIN_timestamp')
1406
-            : $this->get('LIN_timestamp');
1407
-    }
1408
-
1409
-
1410
-
1411
-
1412
-    /************************* DEPRECATED *************************/
1413
-    /**
1414
-     * @deprecated 4.6.0
1415
-     * @param string $type one of the constants on EEM_Line_Item
1416
-     * @return EE_Line_Item[]
1417
-     */
1418
-    protected function _get_descendants_of_type($type)
1419
-    {
1420
-        EE_Error::doing_it_wrong(
1421
-            'EE_Line_Item::_get_descendants_of_type()',
1422
-            __('Method replaced with EEH_Line_Item::get_descendants_of_type()', 'event_espresso'),
1423
-            '4.6.0'
1424
-        );
1425
-        return EEH_Line_Item::get_descendants_of_type($this, $type);
1426
-    }
1427
-
1428
-
1429
-    /**
1430
-     * @deprecated 4.6.0
1431
-     * @param string $type like one of the EEM_Line_Item::type_*
1432
-     * @return EE_Line_Item
1433
-     */
1434
-    public function get_nearest_descendant_of_type($type)
1435
-    {
1436
-        EE_Error::doing_it_wrong(
1437
-            'EE_Line_Item::get_nearest_descendant_of_type()',
1438
-            __('Method replaced with EEH_Line_Item::get_nearest_descendant_of_type()', 'event_espresso'),
1439
-            '4.6.0'
1440
-        );
1441
-        return EEH_Line_Item::get_nearest_descendant_of_type($this, $type);
1442
-    }
17
+	/**
18
+	 * for children line items (currently not a normal relation)
19
+	 *
20
+	 * @type EE_Line_Item[]
21
+	 */
22
+	protected $_children = array();
23
+
24
+	/**
25
+	 * for the parent line item
26
+	 *
27
+	 * @var EE_Line_Item
28
+	 */
29
+	protected $_parent;
30
+
31
+
32
+	/**
33
+	 *
34
+	 * @param array  $props_n_values          incoming values
35
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
36
+	 *                                        used.)
37
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
38
+	 *                                        date_format and the second value is the time format
39
+	 * @return EE_Line_Item
40
+	 * @throws EE_Error
41
+	 */
42
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
43
+	{
44
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
45
+		return $has_object
46
+			? $has_object
47
+			: new self($props_n_values, false, $timezone);
48
+	}
49
+
50
+
51
+	/**
52
+	 * @param array  $props_n_values  incoming values from the database
53
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
54
+	 *                                the website will be used.
55
+	 * @return EE_Line_Item
56
+	 * @throws EE_Error
57
+	 */
58
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
59
+	{
60
+		return new self($props_n_values, true, $timezone);
61
+	}
62
+
63
+
64
+	/**
65
+	 * Adds some defaults if they're not specified
66
+	 *
67
+	 * @param array  $fieldValues
68
+	 * @param bool   $bydb
69
+	 * @param string $timezone
70
+	 * @throws EE_Error
71
+	 */
72
+	protected function __construct($fieldValues = array(), $bydb = false, $timezone = '')
73
+	{
74
+		parent::__construct($fieldValues, $bydb, $timezone);
75
+		if (! $this->get('LIN_code')) {
76
+			$this->set_code($this->generate_code());
77
+		}
78
+	}
79
+
80
+
81
+	/**
82
+	 * Gets ID
83
+	 *
84
+	 * @return int
85
+	 * @throws EE_Error
86
+	 */
87
+	public function ID()
88
+	{
89
+		return $this->get('LIN_ID');
90
+	}
91
+
92
+
93
+	/**
94
+	 * Gets TXN_ID
95
+	 *
96
+	 * @return int
97
+	 * @throws EE_Error
98
+	 */
99
+	public function TXN_ID()
100
+	{
101
+		return $this->get('TXN_ID');
102
+	}
103
+
104
+
105
+	/**
106
+	 * Sets TXN_ID
107
+	 *
108
+	 * @param int $TXN_ID
109
+	 * @throws EE_Error
110
+	 */
111
+	public function set_TXN_ID($TXN_ID)
112
+	{
113
+		$this->set('TXN_ID', $TXN_ID);
114
+	}
115
+
116
+
117
+	/**
118
+	 * Gets name
119
+	 *
120
+	 * @return string
121
+	 * @throws EE_Error
122
+	 */
123
+	public function name()
124
+	{
125
+		$name = $this->get('LIN_name');
126
+		if (! $name) {
127
+			$name = ucwords(str_replace('-', ' ', $this->type()));
128
+		}
129
+		return $name;
130
+	}
131
+
132
+
133
+	/**
134
+	 * Sets name
135
+	 *
136
+	 * @param string $name
137
+	 * @throws EE_Error
138
+	 */
139
+	public function set_name($name)
140
+	{
141
+		$this->set('LIN_name', $name);
142
+	}
143
+
144
+
145
+	/**
146
+	 * Gets desc
147
+	 *
148
+	 * @return string
149
+	 * @throws EE_Error
150
+	 */
151
+	public function desc()
152
+	{
153
+		return $this->get('LIN_desc');
154
+	}
155
+
156
+
157
+	/**
158
+	 * Sets desc
159
+	 *
160
+	 * @param string $desc
161
+	 * @throws EE_Error
162
+	 */
163
+	public function set_desc($desc)
164
+	{
165
+		$this->set('LIN_desc', $desc);
166
+	}
167
+
168
+
169
+	/**
170
+	 * Gets quantity
171
+	 *
172
+	 * @return int
173
+	 * @throws EE_Error
174
+	 */
175
+	public function quantity()
176
+	{
177
+		return $this->get('LIN_quantity');
178
+	}
179
+
180
+
181
+	/**
182
+	 * Sets quantity
183
+	 *
184
+	 * @param int $quantity
185
+	 * @throws EE_Error
186
+	 */
187
+	public function set_quantity($quantity)
188
+	{
189
+		$this->set('LIN_quantity', max($quantity, 0));
190
+	}
191
+
192
+
193
+	/**
194
+	 * Gets item_id
195
+	 *
196
+	 * @return string
197
+	 * @throws EE_Error
198
+	 */
199
+	public function OBJ_ID()
200
+	{
201
+		return $this->get('OBJ_ID');
202
+	}
203
+
204
+
205
+	/**
206
+	 * Sets item_id
207
+	 *
208
+	 * @param string $item_id
209
+	 * @throws EE_Error
210
+	 */
211
+	public function set_OBJ_ID($item_id)
212
+	{
213
+		$this->set('OBJ_ID', $item_id);
214
+	}
215
+
216
+
217
+	/**
218
+	 * Gets item_type
219
+	 *
220
+	 * @return string
221
+	 * @throws EE_Error
222
+	 */
223
+	public function OBJ_type()
224
+	{
225
+		return $this->get('OBJ_type');
226
+	}
227
+
228
+
229
+	/**
230
+	 * Gets item_type
231
+	 *
232
+	 * @return string
233
+	 * @throws EE_Error
234
+	 */
235
+	public function OBJ_type_i18n()
236
+	{
237
+		$obj_type = $this->OBJ_type();
238
+		switch ($obj_type) {
239
+			case 'Event':
240
+				$obj_type = __('Event', 'event_espresso');
241
+				break;
242
+			case 'Price':
243
+				$obj_type = __('Price', 'event_espresso');
244
+				break;
245
+			case 'Promotion':
246
+				$obj_type = __('Promotion', 'event_espresso');
247
+				break;
248
+			case 'Ticket':
249
+				$obj_type = __('Ticket', 'event_espresso');
250
+				break;
251
+			case 'Transaction':
252
+				$obj_type = __('Transaction', 'event_espresso');
253
+				break;
254
+		}
255
+		return apply_filters('FHEE__EE_Line_Item__OBJ_type_i18n', $obj_type, $this);
256
+	}
257
+
258
+
259
+	/**
260
+	 * Sets item_type
261
+	 *
262
+	 * @param string $OBJ_type
263
+	 * @throws EE_Error
264
+	 */
265
+	public function set_OBJ_type($OBJ_type)
266
+	{
267
+		$this->set('OBJ_type', $OBJ_type);
268
+	}
269
+
270
+
271
+	/**
272
+	 * Gets unit_price
273
+	 *
274
+	 * @return float
275
+	 * @throws EE_Error
276
+	 */
277
+	public function unit_price()
278
+	{
279
+		return $this->get('LIN_unit_price');
280
+	}
281
+
282
+
283
+	/**
284
+	 * Sets unit_price
285
+	 *
286
+	 * @param float $unit_price
287
+	 * @throws EE_Error
288
+	 */
289
+	public function set_unit_price($unit_price)
290
+	{
291
+		$this->set('LIN_unit_price', $unit_price);
292
+	}
293
+
294
+
295
+	/**
296
+	 * Checks if this item is a percentage modifier or not
297
+	 *
298
+	 * @return boolean
299
+	 * @throws EE_Error
300
+	 */
301
+	public function is_percent()
302
+	{
303
+		if ($this->is_tax_sub_total()) {
304
+			// tax subtotals HAVE a percent on them, that percentage only applies
305
+			// to taxable items, so its' an exception. Treat it like a flat line item
306
+			return false;
307
+		}
308
+		$unit_price = abs($this->get('LIN_unit_price'));
309
+		$percent = abs($this->get('LIN_percent'));
310
+		if ($unit_price < .001 && $percent) {
311
+			return true;
312
+		}
313
+		if ($unit_price >= .001 && ! $percent) {
314
+			return false;
315
+		}
316
+		if ($unit_price >= .001 && $percent) {
317
+			throw new EE_Error(
318
+				sprintf(
319
+					esc_html__('A Line Item can not have a unit price of (%s) AND a percent (%s)!', 'event_espresso'),
320
+					$unit_price,
321
+					$percent
322
+				)
323
+			);
324
+		}
325
+		// if they're both 0, assume its not a percent item
326
+		return false;
327
+	}
328
+
329
+
330
+	/**
331
+	 * Gets percent (between 100-.001)
332
+	 *
333
+	 * @return float
334
+	 * @throws EE_Error
335
+	 */
336
+	public function percent()
337
+	{
338
+		return $this->get('LIN_percent');
339
+	}
340
+
341
+
342
+	/**
343
+	 * Sets percent (between 100-0.01)
344
+	 *
345
+	 * @param float $percent
346
+	 * @throws EE_Error
347
+	 */
348
+	public function set_percent($percent)
349
+	{
350
+		$this->set('LIN_percent', $percent);
351
+	}
352
+
353
+
354
+	/**
355
+	 * Gets total
356
+	 *
357
+	 * @return float
358
+	 * @throws EE_Error
359
+	 */
360
+	public function total()
361
+	{
362
+		return $this->get('LIN_total');
363
+	}
364
+
365
+
366
+	/**
367
+	 * Sets total
368
+	 *
369
+	 * @param float $total
370
+	 * @throws EE_Error
371
+	 */
372
+	public function set_total($total)
373
+	{
374
+		$this->set('LIN_total', $total);
375
+	}
376
+
377
+
378
+	/**
379
+	 * Gets order
380
+	 *
381
+	 * @return int
382
+	 * @throws EE_Error
383
+	 */
384
+	public function order()
385
+	{
386
+		return $this->get('LIN_order');
387
+	}
388
+
389
+
390
+	/**
391
+	 * Sets order
392
+	 *
393
+	 * @param int $order
394
+	 * @throws EE_Error
395
+	 */
396
+	public function set_order($order)
397
+	{
398
+		$this->set('LIN_order', $order);
399
+	}
400
+
401
+
402
+	/**
403
+	 * Gets parent
404
+	 *
405
+	 * @return int
406
+	 * @throws EE_Error
407
+	 */
408
+	public function parent_ID()
409
+	{
410
+		return $this->get('LIN_parent');
411
+	}
412
+
413
+
414
+	/**
415
+	 * Sets parent
416
+	 *
417
+	 * @param int $parent
418
+	 * @throws EE_Error
419
+	 */
420
+	public function set_parent_ID($parent)
421
+	{
422
+		$this->set('LIN_parent', $parent);
423
+	}
424
+
425
+
426
+	/**
427
+	 * Gets type
428
+	 *
429
+	 * @return string
430
+	 * @throws EE_Error
431
+	 */
432
+	public function type()
433
+	{
434
+		return $this->get('LIN_type');
435
+	}
436
+
437
+
438
+	/**
439
+	 * Sets type
440
+	 *
441
+	 * @param string $type
442
+	 * @throws EE_Error
443
+	 */
444
+	public function set_type($type)
445
+	{
446
+		$this->set('LIN_type', $type);
447
+	}
448
+
449
+
450
+	/**
451
+	 * Gets the line item of which this item is a composite. Eg, if this is a subtotal, the parent might be a total\
452
+	 * If this line item is saved to the DB, fetches the parent from the DB. However, if this line item isn't in the DB
453
+	 * it uses its cached reference to its parent line item (which would have been set by `EE_Line_Item::set_parent()`
454
+	 * or indirectly by `EE_Line_item::add_child_line_item()`)
455
+	 *
456
+	 * @return EE_Base_Class|EE_Line_Item
457
+	 * @throws EE_Error
458
+	 */
459
+	public function parent()
460
+	{
461
+		return $this->ID()
462
+			? $this->get_model()->get_one_by_ID($this->parent_ID())
463
+			: $this->_parent;
464
+	}
465
+
466
+
467
+	/**
468
+	 * Gets ALL the children of this line item (ie, all the parts that contribute towards this total).
469
+	 *
470
+	 * @return EE_Base_Class[]|EE_Line_Item[]
471
+	 * @throws EE_Error
472
+	 */
473
+	public function children()
474
+	{
475
+		if ($this->ID()) {
476
+			return $this->get_model()->get_all(
477
+				array(
478
+					array('LIN_parent' => $this->ID()),
479
+					'order_by' => array('LIN_order' => 'ASC'),
480
+				)
481
+			);
482
+		}
483
+		if (! is_array($this->_children)) {
484
+			$this->_children = array();
485
+		}
486
+		return $this->_children;
487
+	}
488
+
489
+
490
+	/**
491
+	 * Gets code
492
+	 *
493
+	 * @return string
494
+	 * @throws EE_Error
495
+	 */
496
+	public function code()
497
+	{
498
+		return $this->get('LIN_code');
499
+	}
500
+
501
+
502
+	/**
503
+	 * Sets code
504
+	 *
505
+	 * @param string $code
506
+	 * @throws EE_Error
507
+	 */
508
+	public function set_code($code)
509
+	{
510
+		$this->set('LIN_code', $code);
511
+	}
512
+
513
+
514
+	/**
515
+	 * Gets is_taxable
516
+	 *
517
+	 * @return boolean
518
+	 * @throws EE_Error
519
+	 */
520
+	public function is_taxable()
521
+	{
522
+		return $this->get('LIN_is_taxable');
523
+	}
524
+
525
+
526
+	/**
527
+	 * Sets is_taxable
528
+	 *
529
+	 * @param boolean $is_taxable
530
+	 * @throws EE_Error
531
+	 */
532
+	public function set_is_taxable($is_taxable)
533
+	{
534
+		$this->set('LIN_is_taxable', $is_taxable);
535
+	}
536
+
537
+
538
+	/**
539
+	 * Gets the object that this model-joins-to.
540
+	 * returns one of the model objects that the field OBJ_ID can point to... see the 'OBJ_ID' field on
541
+	 * EEM_Promotion_Object
542
+	 *
543
+	 *        Eg, if this line item join model object is for a ticket, this will return the EE_Ticket object
544
+	 *
545
+	 * @return EE_Base_Class | NULL
546
+	 * @throws EE_Error
547
+	 */
548
+	public function get_object()
549
+	{
550
+		$model_name_of_related_obj = $this->OBJ_type();
551
+		return $this->get_model()->has_relation($model_name_of_related_obj)
552
+			? $this->get_first_related($model_name_of_related_obj)
553
+			: null;
554
+	}
555
+
556
+
557
+	/**
558
+	 * Like EE_Line_Item::get_object(), but can only ever actually return an EE_Ticket.
559
+	 * (IE, if this line item is for a price or something else, will return NULL)
560
+	 *
561
+	 * @param array $query_params
562
+	 * @return EE_Base_Class|EE_Ticket
563
+	 * @throws EE_Error
564
+	 */
565
+	public function ticket($query_params = array())
566
+	{
567
+		// we're going to assume that when this method is called we always want to receive the attached ticket EVEN if that ticket is archived.  This can be overridden via the incoming $query_params argument
568
+		$remove_defaults = array('default_where_conditions' => 'none');
569
+		$query_params = array_merge($remove_defaults, $query_params);
570
+		return $this->get_first_related('Ticket', $query_params);
571
+	}
572
+
573
+
574
+	/**
575
+	 * Gets the EE_Datetime that's related to the ticket, IF this is for a ticket
576
+	 *
577
+	 * @return EE_Datetime | NULL
578
+	 * @throws EE_Error
579
+	 */
580
+	public function get_ticket_datetime()
581
+	{
582
+		if ($this->OBJ_type() === 'Ticket') {
583
+			$ticket = $this->ticket();
584
+			if ($ticket instanceof EE_Ticket) {
585
+				$datetime = $ticket->first_datetime();
586
+				if ($datetime instanceof EE_Datetime) {
587
+					return $datetime;
588
+				}
589
+			}
590
+		}
591
+		return null;
592
+	}
593
+
594
+
595
+	/**
596
+	 * Gets the event's name that's related to the ticket, if this is for
597
+	 * a ticket
598
+	 *
599
+	 * @return string
600
+	 * @throws EE_Error
601
+	 */
602
+	public function ticket_event_name()
603
+	{
604
+		$event_name = esc_html__('Unknown', 'event_espresso');
605
+		$event = $this->ticket_event();
606
+		if ($event instanceof EE_Event) {
607
+			$event_name = $event->name();
608
+		}
609
+		return $event_name;
610
+	}
611
+
612
+
613
+	/**
614
+	 * Gets the event that's related to the ticket, if this line item represents a ticket.
615
+	 *
616
+	 * @return EE_Event|null
617
+	 * @throws EE_Error
618
+	 */
619
+	public function ticket_event()
620
+	{
621
+		$event = null;
622
+		$ticket = $this->ticket();
623
+		if ($ticket instanceof EE_Ticket) {
624
+			$datetime = $ticket->first_datetime();
625
+			if ($datetime instanceof EE_Datetime) {
626
+				$event = $datetime->event();
627
+			}
628
+		}
629
+		return $event;
630
+	}
631
+
632
+
633
+	/**
634
+	 * Gets the first datetime for this lien item, assuming it's for a ticket
635
+	 *
636
+	 * @param string $date_format
637
+	 * @param string $time_format
638
+	 * @return string
639
+	 * @throws EE_Error
640
+	 */
641
+	public function ticket_datetime_start($date_format = '', $time_format = '')
642
+	{
643
+		$first_datetime_string = esc_html__('Unknown', 'event_espresso');
644
+		$datetime = $this->get_ticket_datetime();
645
+		if ($datetime) {
646
+			$first_datetime_string = $datetime->start_date_and_time($date_format, $time_format);
647
+		}
648
+		return $first_datetime_string;
649
+	}
650
+
651
+
652
+	/**
653
+	 * Adds the line item as a child to this line item. If there is another child line
654
+	 * item with the same LIN_code, it is overwritten by this new one
655
+	 *
656
+	 * @param EEI_Line_Item $line_item
657
+	 * @param bool          $set_order
658
+	 * @return bool success
659
+	 * @throws EE_Error
660
+	 */
661
+	public function add_child_line_item(EEI_Line_Item $line_item, $set_order = true)
662
+	{
663
+		// should we calculate the LIN_order for this line item ?
664
+		if ($set_order || $line_item->order() === null) {
665
+			$line_item->set_order(count($this->children()));
666
+		}
667
+		if ($this->ID()) {
668
+			// check for any duplicate line items (with the same code), if so, this replaces it
669
+			$line_item_with_same_code = $this->get_child_line_item($line_item->code());
670
+			if ($line_item_with_same_code instanceof EE_Line_Item && $line_item_with_same_code !== $line_item) {
671
+				$this->delete_child_line_item($line_item_with_same_code->code());
672
+			}
673
+			$line_item->set_parent_ID($this->ID());
674
+			if ($this->TXN_ID()) {
675
+				$line_item->set_TXN_ID($this->TXN_ID());
676
+			}
677
+			return $line_item->save();
678
+		}
679
+		$this->_children[ $line_item->code() ] = $line_item;
680
+		if ($line_item->parent() !== $this) {
681
+			$line_item->set_parent($this);
682
+		}
683
+		return true;
684
+	}
685
+
686
+
687
+	/**
688
+	 * Similar to EE_Base_Class::_add_relation_to, except this isn't a normal relation.
689
+	 * If this line item is saved to the DB, this is just a wrapper for set_parent_ID() and save()
690
+	 * However, if this line item is NOT saved to the DB, this just caches the parent on
691
+	 * the EE_Line_Item::_parent property.
692
+	 *
693
+	 * @param EE_Line_Item $line_item
694
+	 * @throws EE_Error
695
+	 */
696
+	public function set_parent($line_item)
697
+	{
698
+		if ($this->ID()) {
699
+			if (! $line_item->ID()) {
700
+				$line_item->save();
701
+			}
702
+			$this->set_parent_ID($line_item->ID());
703
+			$this->save();
704
+		} else {
705
+			$this->_parent = $line_item;
706
+			$this->set_parent_ID($line_item->ID());
707
+		}
708
+	}
709
+
710
+
711
+	/**
712
+	 * Gets the child line item as specified by its code. Because this returns an object (by reference)
713
+	 * you can modify this child line item and the parent (this object) can know about them
714
+	 * because it also has a reference to that line item
715
+	 *
716
+	 * @param string $code
717
+	 * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL
718
+	 * @throws EE_Error
719
+	 */
720
+	public function get_child_line_item($code)
721
+	{
722
+		if ($this->ID()) {
723
+			return $this->get_model()->get_one(
724
+				array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code))
725
+			);
726
+		}
727
+		return isset($this->_children[ $code ])
728
+			? $this->_children[ $code ]
729
+			: null;
730
+	}
731
+
732
+
733
+	/**
734
+	 * Returns how many items are deleted (or, if this item has not been saved ot the DB yet, just how many it HAD
735
+	 * cached on it)
736
+	 *
737
+	 * @return int
738
+	 * @throws EE_Error
739
+	 */
740
+	public function delete_children_line_items()
741
+	{
742
+		if ($this->ID()) {
743
+			return $this->get_model()->delete(array(array('LIN_parent' => $this->ID())));
744
+		}
745
+		$count = count($this->_children);
746
+		$this->_children = array();
747
+		return $count;
748
+	}
749
+
750
+
751
+	/**
752
+	 * If this line item has been saved to the DB, deletes its child with LIN_code == $code. If this line
753
+	 * HAS NOT been saved to the DB, removes the child line item with index $code.
754
+	 * Also searches through the child's children for a matching line item. However, once a line item has been found
755
+	 * and deleted, stops searching (so if there are line items with duplicate codes, only the first one found will be
756
+	 * deleted)
757
+	 *
758
+	 * @param string $code
759
+	 * @param bool   $stop_search_once_found
760
+	 * @return int count of items deleted (or simply removed from the line item's cache, if not has not been saved to
761
+	 *             the DB yet)
762
+	 * @throws EE_Error
763
+	 */
764
+	public function delete_child_line_item($code, $stop_search_once_found = true)
765
+	{
766
+		if ($this->ID()) {
767
+			$items_deleted = 0;
768
+			if ($this->code() === $code) {
769
+				$items_deleted += EEH_Line_Item::delete_all_child_items($this);
770
+				$items_deleted += (int) $this->delete();
771
+				if ($stop_search_once_found) {
772
+					return $items_deleted;
773
+				}
774
+			}
775
+			foreach ($this->children() as $child_line_item) {
776
+				$items_deleted += $child_line_item->delete_child_line_item($code, $stop_search_once_found);
777
+			}
778
+			return $items_deleted;
779
+		}
780
+		if (isset($this->_children[ $code ])) {
781
+			unset($this->_children[ $code ]);
782
+			return 1;
783
+		}
784
+		return 0;
785
+	}
786
+
787
+
788
+	/**
789
+	 * If this line item is in the database, is of the type subtotal, and
790
+	 * has no children, why do we have it? It should be deleted so this function
791
+	 * does that
792
+	 *
793
+	 * @return boolean
794
+	 * @throws EE_Error
795
+	 */
796
+	public function delete_if_childless_subtotal()
797
+	{
798
+		if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && ! $this->children()) {
799
+			return $this->delete();
800
+		}
801
+		return false;
802
+	}
803
+
804
+
805
+	/**
806
+	 * Creates a code and returns a string. doesn't assign the code to this model object
807
+	 *
808
+	 * @return string
809
+	 * @throws EE_Error
810
+	 */
811
+	public function generate_code()
812
+	{
813
+		// each line item in the cart requires a unique identifier
814
+		return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime());
815
+	}
816
+
817
+
818
+	/**
819
+	 * @return bool
820
+	 * @throws EE_Error
821
+	 */
822
+	public function is_tax()
823
+	{
824
+		return $this->type() === EEM_Line_Item::type_tax;
825
+	}
826
+
827
+
828
+	/**
829
+	 * @return bool
830
+	 * @throws EE_Error
831
+	 */
832
+	public function is_tax_sub_total()
833
+	{
834
+		return $this->type() === EEM_Line_Item::type_tax_sub_total;
835
+	}
836
+
837
+
838
+	/**
839
+	 * @return bool
840
+	 * @throws EE_Error
841
+	 */
842
+	public function is_line_item()
843
+	{
844
+		return $this->type() === EEM_Line_Item::type_line_item;
845
+	}
846
+
847
+
848
+	/**
849
+	 * @return bool
850
+	 * @throws EE_Error
851
+	 */
852
+	public function is_sub_line_item()
853
+	{
854
+		return $this->type() === EEM_Line_Item::type_sub_line_item;
855
+	}
856
+
857
+
858
+	/**
859
+	 * @return bool
860
+	 * @throws EE_Error
861
+	 */
862
+	public function is_sub_total()
863
+	{
864
+		return $this->type() === EEM_Line_Item::type_sub_total;
865
+	}
866
+
867
+
868
+	/**
869
+	 * Whether or not this line item is a cancellation line item
870
+	 *
871
+	 * @return boolean
872
+	 * @throws EE_Error
873
+	 */
874
+	public function is_cancellation()
875
+	{
876
+		return EEM_Line_Item::type_cancellation === $this->type();
877
+	}
878
+
879
+
880
+	/**
881
+	 * @return bool
882
+	 * @throws EE_Error
883
+	 */
884
+	public function is_total()
885
+	{
886
+		return $this->type() === EEM_Line_Item::type_total;
887
+	}
888
+
889
+
890
+	/**
891
+	 * @return bool
892
+	 * @throws EE_Error
893
+	 */
894
+	public function is_cancelled()
895
+	{
896
+		return $this->type() === EEM_Line_Item::type_cancellation;
897
+	}
898
+
899
+
900
+	/**
901
+	 * @return string like '2, 004.00', formatted according to the localized currency
902
+	 * @throws EE_Error
903
+	 */
904
+	public function unit_price_no_code()
905
+	{
906
+		return $this->get_pretty('LIN_unit_price', 'no_currency_code');
907
+	}
908
+
909
+
910
+	/**
911
+	 * @return string like '2, 004.00', formatted according to the localized currency
912
+	 * @throws EE_Error
913
+	 */
914
+	public function total_no_code()
915
+	{
916
+		return $this->get_pretty('LIN_total', 'no_currency_code');
917
+	}
918
+
919
+
920
+	/**
921
+	 * Gets the final total on this item, taking taxes into account.
922
+	 * Has the side-effect of setting the sub-total as it was just calculated.
923
+	 * If this is used on a grand-total line item, also updates the transaction's
924
+	 * TXN_total (provided this line item is allowed to persist, otherwise we don't
925
+	 * want to change a persistable transaction with info from a non-persistent line item)
926
+	 *
927
+	 * @return float
928
+	 * @throws EE_Error
929
+	 * @throws InvalidArgumentException
930
+	 * @throws InvalidInterfaceException
931
+	 * @throws InvalidDataTypeException
932
+	 */
933
+	public function recalculate_total_including_taxes()
934
+	{
935
+		$pre_tax_total = $this->recalculate_pre_tax_total();
936
+		$tax_total = $this->recalculate_taxes_and_tax_total();
937
+		$total = $pre_tax_total + $tax_total;
938
+		// no negative totals plz
939
+		$total = max($total, 0);
940
+		$this->set_total($total);
941
+		// only update the related transaction's total
942
+		// if we intend to save this line item and its a grand total
943
+		if ($this->allow_persist() && $this->type() === EEM_Line_Item::type_total
944
+			&& $this->transaction()
945
+			   instanceof
946
+			   EE_Transaction
947
+		) {
948
+			$this->transaction()->set_total($total);
949
+			if ($this->transaction()->ID()) {
950
+				$this->transaction()->save();
951
+			}
952
+		}
953
+		$this->maybe_save();
954
+		return $total;
955
+	}
956
+
957
+
958
+	/**
959
+	 * Recursively goes through all the children and recalculates sub-totals EXCEPT for
960
+	 * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its
961
+	 * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and
962
+	 * when this is called on the grand total
963
+	 *
964
+	 * @return float
965
+	 * @throws InvalidArgumentException
966
+	 * @throws InvalidInterfaceException
967
+	 * @throws InvalidDataTypeException
968
+	 * @throws EE_Error
969
+	 */
970
+	public function recalculate_pre_tax_total()
971
+	{
972
+		$total = 0;
973
+		$my_children = $this->children();
974
+		$has_children = ! empty($my_children);
975
+		if ($has_children && $this->is_line_item()) {
976
+			$total = $this->_recalculate_pretax_total_for_line_item($total, $my_children);
977
+		} elseif (! $has_children && ($this->is_sub_line_item() || $this->is_line_item())) {
978
+			$total = $this->unit_price() * $this->quantity();
979
+		} elseif ($this->is_sub_total() || $this->is_total()) {
980
+			$total = $this->_recalculate_pretax_total_for_subtotal($total, $my_children);
981
+		} elseif ($this->is_tax_sub_total() || $this->is_tax() || $this->is_cancelled()) {
982
+			// completely ignore tax totals, tax sub-totals, and cancelled line items, when calculating the pre-tax-total
983
+			return 0;
984
+		}
985
+		// ensure all non-line items and non-sub-line-items have a quantity of 1 (except for Events)
986
+		if (! $this->is_line_item() && ! $this->is_sub_line_item() && ! $this->is_cancellation()
987
+		) {
988
+			if ($this->OBJ_type() !== 'Event') {
989
+				$this->set_quantity(1);
990
+			}
991
+			if (! $this->is_percent()) {
992
+				$this->set_unit_price($total);
993
+			}
994
+		}
995
+		// we don't want to bother saving grand totals, because that needs to factor in taxes anyways
996
+		// so it ought to be
997
+		if (! $this->is_total()) {
998
+			$this->set_total($total);
999
+			// if not a percent line item, make sure we keep the unit price in sync
1000
+			if ($has_children
1001
+				&& $this->is_line_item()
1002
+				&& ! $this->is_percent()
1003
+			) {
1004
+				if ($this->quantity() === 0) {
1005
+					$new_unit_price = 0;
1006
+				} else {
1007
+					$new_unit_price = $this->total() / $this->quantity();
1008
+				}
1009
+				$this->set_unit_price($new_unit_price);
1010
+			}
1011
+			$this->maybe_save();
1012
+		}
1013
+		return $total;
1014
+	}
1015
+
1016
+
1017
+	/**
1018
+	 * Calculates the pretax total when this line item is a subtotal or total line item.
1019
+	 * Basically does a sum-then-round approach (ie, any percent line item that are children
1020
+	 * will calculate their total based on the un-rounded total we're working with so far, and
1021
+	 * THEN round the result; instead of rounding as we go like with sub-line-items)
1022
+	 *
1023
+	 * @param float          $calculated_total_so_far
1024
+	 * @param EE_Line_Item[] $my_children
1025
+	 * @return float
1026
+	 * @throws InvalidArgumentException
1027
+	 * @throws InvalidInterfaceException
1028
+	 * @throws InvalidDataTypeException
1029
+	 * @throws EE_Error
1030
+	 */
1031
+	protected function _recalculate_pretax_total_for_subtotal($calculated_total_so_far, $my_children = null)
1032
+	{
1033
+		if ($my_children === null) {
1034
+			$my_children = $this->children();
1035
+		}
1036
+		$subtotal_quantity = 0;
1037
+		// get the total of all its children
1038
+		foreach ($my_children as $child_line_item) {
1039
+			if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) {
1040
+				// percentage line items are based on total so far
1041
+				if ($child_line_item->is_percent()) {
1042
+					// round as we go so that the line items add up ok
1043
+					$percent_total = round(
1044
+						$calculated_total_so_far * $child_line_item->percent() / 100,
1045
+						EE_Registry::instance()->CFG->currency->dec_plc
1046
+					);
1047
+					$child_line_item->set_total($percent_total);
1048
+					// so far all percent line items should have a quantity of 1
1049
+					// (ie, no double percent discounts. Although that might be requested someday)
1050
+					$child_line_item->set_quantity(1);
1051
+					$child_line_item->maybe_save();
1052
+					$calculated_total_so_far += $percent_total;
1053
+				} else {
1054
+					// verify flat sub-line-item quantities match their parent
1055
+					if ($child_line_item->is_sub_line_item()) {
1056
+						$child_line_item->set_quantity($this->quantity());
1057
+					}
1058
+					$calculated_total_so_far += $child_line_item->recalculate_pre_tax_total();
1059
+					$subtotal_quantity += $child_line_item->quantity();
1060
+				}
1061
+			}
1062
+		}
1063
+		if ($this->is_sub_total()) {
1064
+			// no negative totals plz
1065
+			$calculated_total_so_far = max($calculated_total_so_far, 0);
1066
+			$subtotal_quantity = $subtotal_quantity > 0 ? 1 : 0;
1067
+			$this->set_quantity($subtotal_quantity);
1068
+			$this->maybe_save();
1069
+		}
1070
+		return $calculated_total_so_far;
1071
+	}
1072
+
1073
+
1074
+	/**
1075
+	 * Calculates the pretax total for a normal line item, in a round-then-sum approach
1076
+	 * (where each sub-line-item is applied to the base price for the line item
1077
+	 * and the result is immediately rounded, rather than summing all the sub-line-items
1078
+	 * then rounding, like we do when recalculating pretax totals on totals and subtotals).
1079
+	 *
1080
+	 * @param float          $calculated_total_so_far
1081
+	 * @param EE_Line_Item[] $my_children
1082
+	 * @return float
1083
+	 * @throws InvalidArgumentException
1084
+	 * @throws InvalidInterfaceException
1085
+	 * @throws InvalidDataTypeException
1086
+	 * @throws EE_Error
1087
+	 */
1088
+	protected function _recalculate_pretax_total_for_line_item($calculated_total_so_far, $my_children = null)
1089
+	{
1090
+		if ($my_children === null) {
1091
+			$my_children = $this->children();
1092
+		}
1093
+		// we need to keep track of the running total for a single item,
1094
+		// because we need to round as we go
1095
+		$unit_price_for_total = 0;
1096
+		$quantity_for_total = 1;
1097
+		// get the total of all its children
1098
+		foreach ($my_children as $child_line_item) {
1099
+			if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) {
1100
+				if ($child_line_item->is_percent()) {
1101
+					// it should be the unit-price-so-far multiplied by teh percent multiplied by the quantity
1102
+					// not total multiplied by percent, because that ignores rounding along-the-way
1103
+					$percent_unit_price = round(
1104
+						$unit_price_for_total * $child_line_item->percent() / 100,
1105
+						EE_Registry::instance()->CFG->currency->dec_plc
1106
+					);
1107
+					$percent_total = $percent_unit_price * $quantity_for_total;
1108
+					$child_line_item->set_total($percent_total);
1109
+					// so far all percent line items should have a quantity of 1
1110
+					// (ie, no double percent discounts. Although that might be requested someday)
1111
+					$child_line_item->set_quantity(1);
1112
+					$child_line_item->maybe_save();
1113
+					$calculated_total_so_far += $percent_total;
1114
+					$unit_price_for_total += $percent_unit_price;
1115
+				} else {
1116
+					// verify flat sub-line-item quantities match their parent
1117
+					if ($child_line_item->is_sub_line_item()) {
1118
+						$child_line_item->set_quantity($this->quantity());
1119
+					}
1120
+					$quantity_for_total = $child_line_item->quantity();
1121
+					$calculated_total_so_far += $child_line_item->recalculate_pre_tax_total();
1122
+					$unit_price_for_total += $child_line_item->unit_price();
1123
+				}
1124
+			}
1125
+		}
1126
+		return $calculated_total_so_far;
1127
+	}
1128
+
1129
+
1130
+	/**
1131
+	 * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets
1132
+	 * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items
1133
+	 * and tax sub-total if already in the DB
1134
+	 *
1135
+	 * @return float
1136
+	 * @throws EE_Error
1137
+	 */
1138
+	public function recalculate_taxes_and_tax_total()
1139
+	{
1140
+		// get all taxes
1141
+		$taxes = $this->tax_descendants();
1142
+		// calculate the pretax total
1143
+		$taxable_total = $this->taxable_total();
1144
+		$tax_total = 0;
1145
+		foreach ($taxes as $tax) {
1146
+			$total_on_this_tax = $taxable_total * $tax->percent() / 100;
1147
+			// remember the total on this line item
1148
+			$tax->set_total($total_on_this_tax);
1149
+			$tax->maybe_save();
1150
+			$tax_total += $tax->total();
1151
+		}
1152
+		$this->_recalculate_tax_sub_total();
1153
+		return $tax_total;
1154
+	}
1155
+
1156
+
1157
+	/**
1158
+	 * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated
1159
+	 *
1160
+	 * @return void
1161
+	 * @throws EE_Error
1162
+	 */
1163
+	private function _recalculate_tax_sub_total()
1164
+	{
1165
+		if ($this->is_tax_sub_total()) {
1166
+			$total = 0;
1167
+			$total_percent = 0;
1168
+			// simply loop through all its children (which should be taxes) and sum their total
1169
+			foreach ($this->children() as $child_tax) {
1170
+				if ($child_tax instanceof EE_Line_Item) {
1171
+					$total += $child_tax->total();
1172
+					$total_percent += $child_tax->percent();
1173
+				}
1174
+			}
1175
+			$this->set_total($total);
1176
+			$this->set_percent($total_percent);
1177
+			$this->maybe_save();
1178
+		} elseif ($this->is_total()) {
1179
+			foreach ($this->children() as $maybe_tax_subtotal) {
1180
+				if ($maybe_tax_subtotal instanceof EE_Line_Item) {
1181
+					$maybe_tax_subtotal->_recalculate_tax_sub_total();
1182
+				}
1183
+			}
1184
+		}
1185
+	}
1186
+
1187
+
1188
+	/**
1189
+	 * Gets the total tax on this line item. Assumes taxes have already been calculated using
1190
+	 * recalculate_taxes_and_total
1191
+	 *
1192
+	 * @return float
1193
+	 * @throws EE_Error
1194
+	 */
1195
+	public function get_total_tax()
1196
+	{
1197
+		$this->_recalculate_tax_sub_total();
1198
+		$total = 0;
1199
+		foreach ($this->tax_descendants() as $tax_line_item) {
1200
+			if ($tax_line_item instanceof EE_Line_Item) {
1201
+				$total += $tax_line_item->total();
1202
+			}
1203
+		}
1204
+		return $total;
1205
+	}
1206
+
1207
+
1208
+	/**
1209
+	 * Gets the total for all the items purchased only
1210
+	 *
1211
+	 * @return float
1212
+	 * @throws EE_Error
1213
+	 */
1214
+	public function get_items_total()
1215
+	{
1216
+		// by default, let's make sure we're consistent with the existing line item
1217
+		if ($this->is_total()) {
1218
+			$pretax_subtotal_li = EEH_Line_Item::get_pre_tax_subtotal($this);
1219
+			if ($pretax_subtotal_li instanceof EE_Line_Item) {
1220
+				return $pretax_subtotal_li->total();
1221
+			}
1222
+		}
1223
+		$total = 0;
1224
+		foreach ($this->get_items() as $item) {
1225
+			if ($item instanceof EE_Line_Item) {
1226
+				$total += $item->total();
1227
+			}
1228
+		}
1229
+		return $total;
1230
+	}
1231
+
1232
+
1233
+	/**
1234
+	 * Gets all the descendants (ie, children or children of children etc) that
1235
+	 * are of the type 'tax'
1236
+	 *
1237
+	 * @return EE_Line_Item[]
1238
+	 */
1239
+	public function tax_descendants()
1240
+	{
1241
+		return EEH_Line_Item::get_tax_descendants($this);
1242
+	}
1243
+
1244
+
1245
+	/**
1246
+	 * Gets all the real items purchased which are children of this item
1247
+	 *
1248
+	 * @return EE_Line_Item[]
1249
+	 */
1250
+	public function get_items()
1251
+	{
1252
+		return EEH_Line_Item::get_line_item_descendants($this);
1253
+	}
1254
+
1255
+
1256
+	/**
1257
+	 * Returns the amount taxable among this line item's children (or if it has no children,
1258
+	 * how much of it is taxable). Does not recalculate totals or subtotals.
1259
+	 * If the taxable total is negative, (eg, if none of the tickets were taxable,
1260
+	 * but there is a "Taxable" discount), returns 0.
1261
+	 *
1262
+	 * @return float
1263
+	 * @throws EE_Error
1264
+	 */
1265
+	public function taxable_total()
1266
+	{
1267
+		$total = 0;
1268
+		if ($this->children()) {
1269
+			foreach ($this->children() as $child_line_item) {
1270
+				if ($child_line_item->type() === EEM_Line_Item::type_line_item && $child_line_item->is_taxable()) {
1271
+					// if it's a percent item, only take into account the percent
1272
+					// that's taxable too (the taxable total so far)
1273
+					if ($child_line_item->is_percent()) {
1274
+						$total += ($total * $child_line_item->percent() / 100);
1275
+					} else {
1276
+						$total += $child_line_item->total();
1277
+					}
1278
+				} elseif ($child_line_item->type() === EEM_Line_Item::type_sub_total) {
1279
+					$total += $child_line_item->taxable_total();
1280
+				}
1281
+			}
1282
+		}
1283
+		return max($total, 0);
1284
+	}
1285
+
1286
+
1287
+	/**
1288
+	 * Gets the transaction for this line item
1289
+	 *
1290
+	 * @return EE_Base_Class|EE_Transaction
1291
+	 * @throws EE_Error
1292
+	 */
1293
+	public function transaction()
1294
+	{
1295
+		return $this->get_first_related('Transaction');
1296
+	}
1297
+
1298
+
1299
+	/**
1300
+	 * Saves this line item to the DB, and recursively saves its descendants.
1301
+	 * Because there currently is no proper parent-child relation on the model,
1302
+	 * save_this_and_cached() will NOT save the descendants.
1303
+	 * Also sets the transaction on this line item and all its descendants before saving
1304
+	 *
1305
+	 * @param int $txn_id if none is provided, assumes $this->TXN_ID()
1306
+	 * @return int count of items saved
1307
+	 * @throws EE_Error
1308
+	 */
1309
+	public function save_this_and_descendants_to_txn($txn_id = null)
1310
+	{
1311
+		$count = 0;
1312
+		if (! $txn_id) {
1313
+			$txn_id = $this->TXN_ID();
1314
+		}
1315
+		$this->set_TXN_ID($txn_id);
1316
+		$children = $this->children();
1317
+		$count += $this->save()
1318
+			? 1
1319
+			: 0;
1320
+		foreach ($children as $child_line_item) {
1321
+			if ($child_line_item instanceof EE_Line_Item) {
1322
+				$child_line_item->set_parent_ID($this->ID());
1323
+				$count += $child_line_item->save_this_and_descendants_to_txn($txn_id);
1324
+			}
1325
+		}
1326
+		return $count;
1327
+	}
1328
+
1329
+
1330
+	/**
1331
+	 * Saves this line item to the DB, and recursively saves its descendants.
1332
+	 *
1333
+	 * @return int count of items saved
1334
+	 * @throws EE_Error
1335
+	 */
1336
+	public function save_this_and_descendants()
1337
+	{
1338
+		$count = 0;
1339
+		$children = $this->children();
1340
+		$count += $this->save()
1341
+			? 1
1342
+			: 0;
1343
+		foreach ($children as $child_line_item) {
1344
+			if ($child_line_item instanceof EE_Line_Item) {
1345
+				$child_line_item->set_parent_ID($this->ID());
1346
+				$count += $child_line_item->save_this_and_descendants();
1347
+			}
1348
+		}
1349
+		return $count;
1350
+	}
1351
+
1352
+
1353
+	/**
1354
+	 * returns the cancellation line item if this item was cancelled
1355
+	 *
1356
+	 * @return EE_Line_Item[]
1357
+	 * @throws InvalidArgumentException
1358
+	 * @throws InvalidInterfaceException
1359
+	 * @throws InvalidDataTypeException
1360
+	 * @throws ReflectionException
1361
+	 * @throws EE_Error
1362
+	 */
1363
+	public function get_cancellations()
1364
+	{
1365
+		EE_Registry::instance()->load_helper('Line_Item');
1366
+		return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_cancellation);
1367
+	}
1368
+
1369
+
1370
+	/**
1371
+	 * If this item has an ID, then this saves it again to update the db
1372
+	 *
1373
+	 * @return int count of items saved
1374
+	 * @throws EE_Error
1375
+	 */
1376
+	public function maybe_save()
1377
+	{
1378
+		if ($this->ID()) {
1379
+			return $this->save();
1380
+		}
1381
+		return false;
1382
+	}
1383
+
1384
+
1385
+	/**
1386
+	 * clears the cached children and parent from the line item
1387
+	 *
1388
+	 * @return void
1389
+	 */
1390
+	public function clear_related_line_item_cache()
1391
+	{
1392
+		$this->_children = array();
1393
+		$this->_parent = null;
1394
+	}
1395
+
1396
+
1397
+	/**
1398
+	 * @param bool $raw
1399
+	 * @return int
1400
+	 * @throws EE_Error
1401
+	 */
1402
+	public function timestamp($raw = false)
1403
+	{
1404
+		return $raw
1405
+			? $this->get_raw('LIN_timestamp')
1406
+			: $this->get('LIN_timestamp');
1407
+	}
1408
+
1409
+
1410
+
1411
+
1412
+	/************************* DEPRECATED *************************/
1413
+	/**
1414
+	 * @deprecated 4.6.0
1415
+	 * @param string $type one of the constants on EEM_Line_Item
1416
+	 * @return EE_Line_Item[]
1417
+	 */
1418
+	protected function _get_descendants_of_type($type)
1419
+	{
1420
+		EE_Error::doing_it_wrong(
1421
+			'EE_Line_Item::_get_descendants_of_type()',
1422
+			__('Method replaced with EEH_Line_Item::get_descendants_of_type()', 'event_espresso'),
1423
+			'4.6.0'
1424
+		);
1425
+		return EEH_Line_Item::get_descendants_of_type($this, $type);
1426
+	}
1427
+
1428
+
1429
+	/**
1430
+	 * @deprecated 4.6.0
1431
+	 * @param string $type like one of the EEM_Line_Item::type_*
1432
+	 * @return EE_Line_Item
1433
+	 */
1434
+	public function get_nearest_descendant_of_type($type)
1435
+	{
1436
+		EE_Error::doing_it_wrong(
1437
+			'EE_Line_Item::get_nearest_descendant_of_type()',
1438
+			__('Method replaced with EEH_Line_Item::get_nearest_descendant_of_type()', 'event_espresso'),
1439
+			'4.6.0'
1440
+		);
1441
+		return EEH_Line_Item::get_nearest_descendant_of_type($this, $type);
1442
+	}
1443 1443
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -72,7 +72,7 @@  discard block
 block discarded – undo
72 72
     protected function __construct($fieldValues = array(), $bydb = false, $timezone = '')
73 73
     {
74 74
         parent::__construct($fieldValues, $bydb, $timezone);
75
-        if (! $this->get('LIN_code')) {
75
+        if ( ! $this->get('LIN_code')) {
76 76
             $this->set_code($this->generate_code());
77 77
         }
78 78
     }
@@ -123,7 +123,7 @@  discard block
 block discarded – undo
123 123
     public function name()
124 124
     {
125 125
         $name = $this->get('LIN_name');
126
-        if (! $name) {
126
+        if ( ! $name) {
127 127
             $name = ucwords(str_replace('-', ' ', $this->type()));
128 128
         }
129 129
         return $name;
@@ -480,7 +480,7 @@  discard block
 block discarded – undo
480 480
                 )
481 481
             );
482 482
         }
483
-        if (! is_array($this->_children)) {
483
+        if ( ! is_array($this->_children)) {
484 484
             $this->_children = array();
485 485
         }
486 486
         return $this->_children;
@@ -676,7 +676,7 @@  discard block
 block discarded – undo
676 676
             }
677 677
             return $line_item->save();
678 678
         }
679
-        $this->_children[ $line_item->code() ] = $line_item;
679
+        $this->_children[$line_item->code()] = $line_item;
680 680
         if ($line_item->parent() !== $this) {
681 681
             $line_item->set_parent($this);
682 682
         }
@@ -696,7 +696,7 @@  discard block
 block discarded – undo
696 696
     public function set_parent($line_item)
697 697
     {
698 698
         if ($this->ID()) {
699
-            if (! $line_item->ID()) {
699
+            if ( ! $line_item->ID()) {
700 700
                 $line_item->save();
701 701
             }
702 702
             $this->set_parent_ID($line_item->ID());
@@ -724,8 +724,8 @@  discard block
 block discarded – undo
724 724
                 array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code))
725 725
             );
726 726
         }
727
-        return isset($this->_children[ $code ])
728
-            ? $this->_children[ $code ]
727
+        return isset($this->_children[$code])
728
+            ? $this->_children[$code]
729 729
             : null;
730 730
     }
731 731
 
@@ -777,8 +777,8 @@  discard block
 block discarded – undo
777 777
             }
778 778
             return $items_deleted;
779 779
         }
780
-        if (isset($this->_children[ $code ])) {
781
-            unset($this->_children[ $code ]);
780
+        if (isset($this->_children[$code])) {
781
+            unset($this->_children[$code]);
782 782
             return 1;
783 783
         }
784 784
         return 0;
@@ -811,7 +811,7 @@  discard block
 block discarded – undo
811 811
     public function generate_code()
812 812
     {
813 813
         // each line item in the cart requires a unique identifier
814
-        return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime());
814
+        return md5($this->get('OBJ_type').$this->get('OBJ_ID').microtime());
815 815
     }
816 816
 
817 817
 
@@ -974,7 +974,7 @@  discard block
 block discarded – undo
974 974
         $has_children = ! empty($my_children);
975 975
         if ($has_children && $this->is_line_item()) {
976 976
             $total = $this->_recalculate_pretax_total_for_line_item($total, $my_children);
977
-        } elseif (! $has_children && ($this->is_sub_line_item() || $this->is_line_item())) {
977
+        } elseif ( ! $has_children && ($this->is_sub_line_item() || $this->is_line_item())) {
978 978
             $total = $this->unit_price() * $this->quantity();
979 979
         } elseif ($this->is_sub_total() || $this->is_total()) {
980 980
             $total = $this->_recalculate_pretax_total_for_subtotal($total, $my_children);
@@ -983,18 +983,18 @@  discard block
 block discarded – undo
983 983
             return 0;
984 984
         }
985 985
         // ensure all non-line items and non-sub-line-items have a quantity of 1 (except for Events)
986
-        if (! $this->is_line_item() && ! $this->is_sub_line_item() && ! $this->is_cancellation()
986
+        if ( ! $this->is_line_item() && ! $this->is_sub_line_item() && ! $this->is_cancellation()
987 987
         ) {
988 988
             if ($this->OBJ_type() !== 'Event') {
989 989
                 $this->set_quantity(1);
990 990
             }
991
-            if (! $this->is_percent()) {
991
+            if ( ! $this->is_percent()) {
992 992
                 $this->set_unit_price($total);
993 993
             }
994 994
         }
995 995
         // we don't want to bother saving grand totals, because that needs to factor in taxes anyways
996 996
         // so it ought to be
997
-        if (! $this->is_total()) {
997
+        if ( ! $this->is_total()) {
998 998
             $this->set_total($total);
999 999
             // if not a percent line item, make sure we keep the unit price in sync
1000 1000
             if ($has_children
@@ -1309,7 +1309,7 @@  discard block
 block discarded – undo
1309 1309
     public function save_this_and_descendants_to_txn($txn_id = null)
1310 1310
     {
1311 1311
         $count = 0;
1312
-        if (! $txn_id) {
1312
+        if ( ! $txn_id) {
1313 1313
             $txn_id = $this->TXN_ID();
1314 1314
         }
1315 1315
         $this->set_TXN_ID($txn_id);
Please login to merge, or discard this patch.
core/db_classes/EE_Term_Relationship.class.php 1 patch
Indentation   +17 added lines, -17 removed lines patch added patch discarded remove patch
@@ -10,23 +10,23 @@
 block discarded – undo
10 10
 class EE_Term_Relationship extends EE_Base_Class
11 11
 {
12 12
 
13
-    /**
14
-     * @param array $props_n_values
15
-     * @return EE_Term_Relationship
16
-     */
17
-    public static function new_instance($props_n_values = array())
18
-    {
19
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__);
20
-        return $has_object ? $has_object : new self($props_n_values);
21
-    }
13
+	/**
14
+	 * @param array $props_n_values
15
+	 * @return EE_Term_Relationship
16
+	 */
17
+	public static function new_instance($props_n_values = array())
18
+	{
19
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__);
20
+		return $has_object ? $has_object : new self($props_n_values);
21
+	}
22 22
 
23 23
 
24
-    /**
25
-     * @param array $props_n_values
26
-     * @return EE_Term_Relationship
27
-     */
28
-    public static function new_instance_from_db($props_n_values = array())
29
-    {
30
-        return new self($props_n_values, true);
31
-    }
24
+	/**
25
+	 * @param array $props_n_values
26
+	 * @return EE_Term_Relationship
27
+	 */
28
+	public static function new_instance_from_db($props_n_values = array())
29
+	{
30
+		return new self($props_n_values, true);
31
+	}
32 32
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Export.class.php 2 patches
Indentation   +773 added lines, -773 removed lines patch added patch discarded remove patch
@@ -16,777 +16,777 @@
 block discarded – undo
16 16
 class EE_Export
17 17
 {
18 18
 
19
-    const option_prefix = 'ee_report_job_';
20
-
21
-
22
-    // instance of the EE_Export object
23
-    private static $_instance = null;
24
-
25
-    // instance of the EE_CSV object
26
-    /**
27
-     *
28
-     * @var EE_CSV
29
-     */
30
-    public $EE_CSV = null;
31
-
32
-
33
-    private $_req_data = array();
34
-
35
-
36
-    /**
37
-     *        private constructor to prevent direct creation
38
-     *
39
-     * @Constructor
40
-     * @access private
41
-     * @param array $request_data
42
-     */
43
-    private function __construct($request_data = array())
44
-    {
45
-        $this->_req_data = $request_data;
46
-        $this->today = date("Y-m-d", time());
47
-        require_once(EE_CLASSES . 'EE_CSV.class.php');
48
-        $this->EE_CSV = EE_CSV::instance();
49
-    }
50
-
51
-
52
-    /**
53
-     *        @ singleton method used to instantiate class object
54
-     *        @ access public
55
-     *
56
-     * @param array $request_data
57
-     * @return \EE_Export
58
-     */
59
-    public static function instance($request_data = array())
60
-    {
61
-        // check if class object is instantiated
62
-        if (self::$_instance === null or ! is_object(self::$_instance) or ! (self::$_instance instanceof EE_Export)) {
63
-            self::$_instance = new self($request_data);
64
-        }
65
-        return self::$_instance;
66
-    }
67
-
68
-
69
-    /**
70
-     * @Export Event Espresso data - routes export requests
71
-     * @access public
72
-     * @return void | bool
73
-     */
74
-    public function export()
75
-    {
76
-        // in case of bulk exports, the "actual" action will be in action2, but first check regular action for "export" keyword
77
-        if (isset($this->_req_data['action']) && strpos($this->_req_data['action'], 'export') === false) {
78
-            // check if action2 has export action
79
-            if (isset($this->_req_data['action2']) && strpos($this->_req_data['action2'], 'export') !== false) {
80
-                // whoop! there it is!
81
-                $this->_req_data['action'] = $this->_req_data['action2'];
82
-            }
83
-        }
84
-
85
-        $this->_req_data['export'] = isset($this->_req_data['export']) ? $this->_req_data['export'] : '';
86
-
87
-        switch ($this->_req_data['export']) {
88
-            case 'report':
89
-                switch ($this->_req_data['action']) {
90
-                    case "event":
91
-                    case "export_events":
92
-                    case 'all_event_data':
93
-                        $this->export_all_event_data();
94
-                        break;
95
-
96
-                    case 'registrations_report_for_event':
97
-                        $this->report_registrations_for_event($this->_req_data['EVT_ID']);
98
-                        break;
99
-
100
-                    case 'attendees':
101
-                        $this->export_attendees();
102
-                        break;
103
-
104
-                    case 'categories':
105
-                        $this->export_categories();
106
-                        break;
107
-
108
-                    default:
109
-                        EE_Error::add_error(
110
-                            __('An error occurred! The requested export report could not be found.', 'event_espresso'),
111
-                            __FILE__,
112
-                            __FUNCTION__,
113
-                            __LINE__
114
-                        );
115
-                        return false;
116
-                        break;
117
-                }
118
-                break; // end of switch export : report
119
-            default:
120
-                break;
121
-        } // end of switch export
122
-
123
-        exit;
124
-    }
125
-
126
-    /**
127
-     * Downloads a CSV file with all the columns, but no data. This should be used for importing
128
-     *
129
-     * @return null kills execution
130
-     */
131
-    public function export_sample()
132
-    {
133
-        $event = EEM_Event::instance()->get_one();
134
-        $this->_req_data['EVT_ID'] = $event->ID();
135
-        $this->export_all_event_data();
136
-    }
137
-
138
-
139
-    /**
140
-     * @Export data for ALL events
141
-     * @access public
142
-     * @return void
143
-     */
144
-    public function export_all_event_data()
145
-    {
146
-        // are any Event IDs set?
147
-        $event_query_params = array();
148
-        $related_models_query_params = array();
149
-        $related_through_reg_query_params = array();
150
-        $datetime_ticket_query_params = array();
151
-        $price_query_params = array();
152
-        $price_type_query_params = array();
153
-        $term_query_params = array();
154
-        $state_country_query_params = array();
155
-        $question_group_query_params = array();
156
-        $question_query_params = array();
157
-        if (isset($this->_req_data['EVT_ID'])) {
158
-            // do we have an array of IDs ?
159
-
160
-            if (is_array($this->_req_data['EVT_ID'])) {
161
-                $EVT_IDs = array_map('sanitize_text_field', $this->_req_data['EVT_ID']);
162
-                $value_to_equal = array('IN', $EVT_IDs);
163
-                $filename = 'events';
164
-            } else {
165
-                // generate regular where = clause
166
-                $EVT_ID = absint($this->_req_data['EVT_ID']);
167
-                $value_to_equal = $EVT_ID;
168
-                $event = EE_Registry::instance()->load_model('Event')->get_one_by_ID($EVT_ID);
169
-
170
-                $filename = 'event-' . ($event instanceof EE_Event ? $event->slug() : __('unknown', 'event_espresso'));
171
-            }
172
-            $event_query_params[0]['EVT_ID'] = $value_to_equal;
173
-            $related_models_query_params[0]['Event.EVT_ID'] = $value_to_equal;
174
-            $related_through_reg_query_params[0]['Registration.EVT_ID'] = $value_to_equal;
175
-            $datetime_ticket_query_params[0]['Datetime.EVT_ID'] = $value_to_equal;
176
-            $price_query_params[0]['Ticket.Datetime.EVT_ID'] = $value_to_equal;
177
-            $price_type_query_params[0]['Price.Ticket.Datetime.EVT_ID'] = $value_to_equal;
178
-            $term_query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $value_to_equal;
179
-            $state_country_query_params[0]['Venue.Event.EVT_ID'] = $value_to_equal;
180
-            $question_group_query_params[0]['Event.EVT_ID'] = $value_to_equal;
181
-            $question_query_params[0]['Question_Group.Event.EVT_ID'] = $value_to_equal;
182
-        } else {
183
-            $filename = 'all-events';
184
-        }
185
-
186
-
187
-        // array in the format:  table name =>  query where clause
188
-        $models_to_export = array(
189
-            'Event'                   => $event_query_params,
190
-            'Datetime'                => $related_models_query_params,
191
-            'Ticket_Template'         => $price_query_params,
192
-            'Ticket'                  => $datetime_ticket_query_params,
193
-            'Datetime_Ticket'         => $datetime_ticket_query_params,
194
-            'Price_Type'              => $price_type_query_params,
195
-            'Price'                   => $price_query_params,
196
-            'Ticket_Price'            => $price_query_params,
197
-            'Term'                    => $term_query_params,
198
-            'Term_Taxonomy'           => $related_models_query_params,
199
-            'Term_Relationship'       => $related_models_query_params, // model has NO primary key...
200
-            'Country'                 => $state_country_query_params,
201
-            'State'                   => $state_country_query_params,
202
-            'Venue'                   => $related_models_query_params,
203
-            'Event_Venue'             => $related_models_query_params,
204
-            'Question_Group'          => $question_group_query_params,
205
-            'Event_Question_Group'    => $question_group_query_params,
206
-            'Question'                => $question_query_params,
207
-            'Question_Group_Question' => $question_query_params,
208
-            // 'Transaction'=>$related_through_reg_query_params,
209
-            // 'Registration'=>$related_models_query_params,
210
-            // 'Attendee'=>$related_through_reg_query_params,
211
-            // 'Line_Item'=>
212
-
213
-        );
214
-
215
-        $model_data = $this->_get_export_data_for_models($models_to_export);
216
-
217
-        $filename = $this->generate_filename($filename);
218
-
219
-        if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $model_data)) {
220
-            EE_Error::add_error(
221
-                __(
222
-                    "'An error occurred and the Event details could not be exported from the database.'",
223
-                    "event_espresso"
224
-                ),
225
-                __FILE__,
226
-                __FUNCTION__,
227
-                __LINE__
228
-            );
229
-        }
230
-    }
231
-
232
-    public function report_attendees()
233
-    {
234
-        $attendee_rows = EEM_Attendee::instance()->get_all_wpdb_results(
235
-            array(
236
-                'force_join' => array('State', 'Country'),
237
-                'caps'       => EEM_Base::caps_read_admin,
238
-            )
239
-        );
240
-        $csv_data = array();
241
-        foreach ($attendee_rows as $attendee_row) {
242
-            $csv_row = array();
243
-            foreach (EEM_Attendee::instance()->field_settings() as $field_name => $field_obj) {
244
-                if ($field_name == 'STA_ID') {
245
-                    $state_name_field = EEM_State::instance()->field_settings_for('STA_name');
246
-                    $csv_row[ __('State', 'event_espresso') ] = $attendee_row[ $state_name_field->get_qualified_column(
247
-                    ) ];
248
-                } elseif ($field_name == 'CNT_ISO') {
249
-                    $country_name_field = EEM_Country::instance()->field_settings_for('CNT_name');
250
-                    $csv_row[ __(
251
-                        'Country',
252
-                        'event_espresso'
253
-                    ) ] = $attendee_row[ $country_name_field->get_qualified_column() ];
254
-                } else {
255
-                    $csv_row[ $field_obj->get_nicename() ] = $attendee_row[ $field_obj->get_qualified_column() ];
256
-                }
257
-            }
258
-            $csv_data[] = $csv_row;
259
-        }
260
-
261
-        $filename = $this->generate_filename('contact-list-report');
262
-
263
-        $handle = $this->EE_CSV->begin_sending_csv($filename);
264
-        $this->EE_CSV->write_data_array_to_csv($handle, $csv_data);
265
-        $this->EE_CSV->end_sending_csv($handle);
266
-    }
267
-
268
-
269
-    /**
270
-     * @Export data for ALL attendees
271
-     * @access public
272
-     * @return void
273
-     */
274
-    public function export_attendees()
275
-    {
276
-
277
-        $states_that_have_an_attendee = EEM_State::instance()->get_all(
278
-            array(0 => array('Attendee.ATT_ID' => array('IS NOT NULL')))
279
-        );
280
-        $countries_that_have_an_attendee = EEM_Country::instance()->get_all(
281
-            array(0 => array('Attendee.ATT_ID' => array('IS NOT NULL')))
282
-        );
283
-        // $states_to_export_query_params
284
-        $models_to_export = array(
285
-            'Country'  => array(array('CNT_ISO' => array('IN', array_keys($countries_that_have_an_attendee)))),
286
-            'State'    => array(array('STA_ID' => array('IN', array_keys($states_that_have_an_attendee)))),
287
-            'Attendee' => array(),
288
-        );
289
-
290
-
291
-        $model_data = $this->_get_export_data_for_models($models_to_export);
292
-        $filename = $this->generate_filename('all-attendees');
293
-
294
-        if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $model_data)) {
295
-            EE_Error::add_error(
296
-                __(
297
-                    'An error occurred and the Attendee data could not be exported from the database.',
298
-                    'event_espresso'
299
-                ),
300
-                __FILE__,
301
-                __FUNCTION__,
302
-                __LINE__
303
-            );
304
-        }
305
-    }
306
-
307
-    /**
308
-     * Shortcut for preparing a database result for display
309
-     *
310
-     * @param EEM_Base       $model
311
-     * @param string         $field_name
312
-     * @param string         $raw_db_value
313
-     * @param boolean|string $pretty_schema true to display pretty, a string to use a specific "Schema", or false to
314
-     *                                      NOT display pretty
315
-     * @return string
316
-     */
317
-    protected function _prepare_value_from_db_for_display($model, $field_name, $raw_db_value, $pretty_schema = true)
318
-    {
319
-        $field_obj = $model->field_settings_for($field_name);
320
-        $value_on_model_obj = $field_obj->prepare_for_set_from_db($raw_db_value);
321
-        if ($field_obj instanceof EE_Datetime_Field) {
322
-            $field_obj->set_date_format(
323
-                EE_CSV::instance()->get_date_format_for_csv($field_obj->get_date_format($pretty_schema)),
324
-                $pretty_schema
325
-            );
326
-            $field_obj->set_time_format(
327
-                EE_CSV::instance()->get_time_format_for_csv($field_obj->get_time_format($pretty_schema)),
328
-                $pretty_schema
329
-            );
330
-        }
331
-        if ($pretty_schema === true) {
332
-            return $field_obj->prepare_for_pretty_echoing($value_on_model_obj);
333
-        } elseif (is_string($pretty_schema)) {
334
-            return $field_obj->prepare_for_pretty_echoing($value_on_model_obj, $pretty_schema);
335
-        } else {
336
-            return $field_obj->prepare_for_get($value_on_model_obj);
337
-        }
338
-    }
339
-
340
-    /**
341
-     * Export a custom CSV of registration info including: A bunch of the reg fields, the time of the event, the price
342
-     * name, and the questions associated with the registrations
343
-     *
344
-     * @param int $event_id
345
-     */
346
-    public function report_registrations_for_event($event_id = null)
347
-    {
348
-        $reg_fields_to_include = array(
349
-            'TXN_ID',
350
-            'ATT_ID',
351
-            'REG_ID',
352
-            'REG_date',
353
-            'REG_code',
354
-            'REG_count',
355
-            'REG_final_price',
356
-
357
-        );
358
-        $att_fields_to_include = array(
359
-            'ATT_fname',
360
-            'ATT_lname',
361
-            'ATT_email',
362
-            'ATT_address',
363
-            'ATT_address2',
364
-            'ATT_city',
365
-            'STA_ID',
366
-            'CNT_ISO',
367
-            'ATT_zip',
368
-            'ATT_phone',
369
-        );
370
-
371
-        $registrations_csv_ready_array = array();
372
-        $reg_model = EE_Registry::instance()->load_model('Registration');
373
-        $query_params = apply_filters(
374
-            'FHEE__EE_Export__report_registration_for_event',
375
-            array(
376
-                array(
377
-                    'OR'                 => array(
378
-                        // don't include registrations from failed or abandoned transactions...
379
-                        'Transaction.STS_ID' => array(
380
-                            'NOT IN',
381
-                            array(EEM_Transaction::failed_status_code, EEM_Transaction::abandoned_status_code),
382
-                        ),
383
-                        // unless the registration is approved, in which case include it regardless of transaction status
384
-                        'STS_ID'             => EEM_Registration::status_id_approved,
385
-                    ),
386
-                    'Ticket.TKT_deleted' => array('IN', array(true, false)),
387
-                ),
388
-                'order_by'   => array('Transaction.TXN_ID' => 'asc', 'REG_count' => 'asc'),
389
-                'force_join' => array('Transaction', 'Ticket', 'Attendee'),
390
-                'caps'       => EEM_Base::caps_read_admin,
391
-            ),
392
-            $event_id
393
-        );
394
-        if ($event_id) {
395
-            $query_params[0]['EVT_ID'] = $event_id;
396
-        } else {
397
-            $query_params['force_join'][] = 'Event';
398
-        }
399
-        $registration_rows = $reg_model->get_all_wpdb_results($query_params);
400
-        // get all questions which relate to someone in this group
401
-        $registration_ids = array();
402
-        foreach ($registration_rows as $reg_row) {
403
-            $registration_ids[] = intval($reg_row['Registration.REG_ID']);
404
-        }
405
-        // EEM_Question::instance()->show_next_x_db_queries();
406
-        $questions_for_these_regs_rows = EEM_Question::instance()->get_all_wpdb_results(
407
-            array(array('Answer.REG_ID' => array('IN', $registration_ids)))
408
-        );
409
-        foreach ($registration_rows as $reg_row) {
410
-            if (is_array($reg_row)) {
411
-                $reg_csv_array = array();
412
-                if (! $event_id) {
413
-                    // get the event's name and Id
414
-                    $reg_csv_array[ __('Event', 'event_espresso') ] = sprintf(
415
-                        __('%1$s (%2$s)', 'event_espresso'),
416
-                        $this->_prepare_value_from_db_for_display(
417
-                            EEM_Event::instance(),
418
-                            'EVT_name',
419
-                            $reg_row['Event_CPT.post_title']
420
-                        ),
421
-                        $reg_row['Event_CPT.ID']
422
-                    );
423
-                }
424
-                $is_primary_reg = $reg_row['Registration.REG_count'] == '1' ? true : false;
425
-                /*@var $reg_row EE_Registration */
426
-                foreach ($reg_fields_to_include as $field_name) {
427
-                    $field = $reg_model->field_settings_for($field_name);
428
-                    if ($field_name == 'REG_final_price') {
429
-                        $value = $this->_prepare_value_from_db_for_display(
430
-                            $reg_model,
431
-                            $field_name,
432
-                            $reg_row['Registration.REG_final_price'],
433
-                            'localized_float'
434
-                        );
435
-                    } elseif ($field_name == 'REG_count') {
436
-                        $value = sprintf(
437
-                            __('%s of %s', 'event_espresso'),
438
-                            $this->_prepare_value_from_db_for_display(
439
-                                $reg_model,
440
-                                'REG_count',
441
-                                $reg_row['Registration.REG_count']
442
-                            ),
443
-                            $this->_prepare_value_from_db_for_display(
444
-                                $reg_model,
445
-                                'REG_group_size',
446
-                                $reg_row['Registration.REG_group_size']
447
-                            )
448
-                        );
449
-                    } elseif ($field_name == 'REG_date') {
450
-                        $value = $this->_prepare_value_from_db_for_display(
451
-                            $reg_model,
452
-                            $field_name,
453
-                            $reg_row['Registration.REG_date'],
454
-                            'no_html'
455
-                        );
456
-                    } else {
457
-                        $value = $this->_prepare_value_from_db_for_display(
458
-                            $reg_model,
459
-                            $field_name,
460
-                            $reg_row[ $field->get_qualified_column() ]
461
-                        );
462
-                    }
463
-                    $reg_csv_array[ $this->_get_column_name_for_field($field) ] = $value;
464
-                    if ($field_name == 'REG_final_price') {
465
-                        // add a column named Currency after the final price
466
-                        $reg_csv_array[ __("Currency", "event_espresso") ] = EE_Config::instance()->currency->code;
467
-                    }
468
-                }
469
-                // get pretty status
470
-                $stati = EEM_Status::instance()->localized_status(
471
-                    array(
472
-                        $reg_row['Registration.STS_ID']     => __('unknown', 'event_espresso'),
473
-                        $reg_row['TransactionTable.STS_ID'] => __('unknown', 'event_espresso'),
474
-                    ),
475
-                    false,
476
-                    'sentence'
477
-                );
478
-                $reg_csv_array[ __(
479
-                    "Registration Status",
480
-                    'event_espresso'
481
-                ) ] = $stati[ $reg_row['Registration.STS_ID'] ];
482
-                // get pretty trnasaction status
483
-                $reg_csv_array[ __(
484
-                    "Transaction Status",
485
-                    'event_espresso'
486
-                ) ] = $stati[ $reg_row['TransactionTable.STS_ID'] ];
487
-                $reg_csv_array[ __('Transaction Amount Due', 'event_espresso') ] = $is_primary_reg
488
-                    ? $this->_prepare_value_from_db_for_display(
489
-                        EEM_Transaction::instance(),
490
-                        'TXN_total',
491
-                        $reg_row['TransactionTable.TXN_total'],
492
-                        'localized_float'
493
-                    ) : '0.00';
494
-                $reg_csv_array[ __('Amount Paid', 'event_espresso') ] = $is_primary_reg
495
-                    ? $this->_prepare_value_from_db_for_display(
496
-                        EEM_Transaction::instance(),
497
-                        'TXN_paid',
498
-                        $reg_row['TransactionTable.TXN_paid'],
499
-                        'localized_float'
500
-                    ) : '0.00';
501
-                $payment_methods = array();
502
-                $gateway_txn_ids_etc = array();
503
-                $payment_times = array();
504
-                if ($is_primary_reg && $reg_row['TransactionTable.TXN_ID']) {
505
-                    $payments_info = EEM_Payment::instance()->get_all_wpdb_results(
506
-                        array(
507
-                            array(
508
-                                'TXN_ID' => $reg_row['TransactionTable.TXN_ID'],
509
-                                'STS_ID' => EEM_Payment::status_id_approved,
510
-                            ),
511
-                            'force_join' => array('Payment_Method'),
512
-                        ),
513
-                        ARRAY_A,
514
-                        'Payment_Method.PMD_admin_name as name, Payment.PAY_txn_id_chq_nmbr as gateway_txn_id, Payment.PAY_timestamp as payment_time'
515
-                    );
516
-
517
-                    foreach ($payments_info as $payment_method_and_gateway_txn_id) {
518
-                        $payment_methods[] = isset($payment_method_and_gateway_txn_id['name'])
519
-                            ? $payment_method_and_gateway_txn_id['name'] : __('Unknown', 'event_espresso');
520
-                        $gateway_txn_ids_etc[] = isset($payment_method_and_gateway_txn_id['gateway_txn_id'])
521
-                            ? $payment_method_and_gateway_txn_id['gateway_txn_id'] : '';
522
-                        $payment_times[] = isset($payment_method_and_gateway_txn_id['payment_time'])
523
-                            ? $payment_method_and_gateway_txn_id['payment_time'] : '';
524
-                    }
525
-                }
526
-                $reg_csv_array[ __('Payment Date(s)', 'event_espresso') ] = implode(',', $payment_times);
527
-                $reg_csv_array[ __('Payment Method(s)', 'event_espresso') ] = implode(",", $payment_methods);
528
-                $reg_csv_array[ __('Gateway Transaction ID(s)', 'event_espresso') ] = implode(
529
-                    ',',
530
-                    $gateway_txn_ids_etc
531
-                );
532
-
533
-                // get whether or not the user has checked in
534
-                $reg_csv_array[ __("Check-Ins", "event_espresso") ] = $reg_model->count_related(
535
-                    $reg_row['Registration.REG_ID'],
536
-                    'Checkin'
537
-                );
538
-                // get ticket of registration and its price
539
-                $ticket_model = EE_Registry::instance()->load_model('Ticket');
540
-                if ($reg_row['Ticket.TKT_ID']) {
541
-                    $ticket_name = $this->_prepare_value_from_db_for_display(
542
-                        $ticket_model,
543
-                        'TKT_name',
544
-                        $reg_row['Ticket.TKT_name']
545
-                    );
546
-                    $datetimes_strings = array();
547
-                    foreach (EEM_Datetime::instance()->get_all_wpdb_results(
548
-                        array(
549
-                            array('Ticket.TKT_ID' => $reg_row['Ticket.TKT_ID']),
550
-                            'order_by'                 => array('DTT_EVT_start' => 'ASC'),
551
-                            'default_where_conditions' => 'none',
552
-                        )
553
-                    ) as $datetime) {
554
-                        $datetimes_strings[] = $this->_prepare_value_from_db_for_display(
555
-                            EEM_Datetime::instance(),
556
-                            'DTT_EVT_start',
557
-                            $datetime['Datetime.DTT_EVT_start']
558
-                        );
559
-                    }
560
-                } else {
561
-                    $ticket_name = __('Unknown', 'event_espresso');
562
-                    $datetimes_strings = array(__('Unknown', 'event_espresso'));
563
-                }
564
-                $reg_csv_array[ $ticket_model->field_settings_for('TKT_name')->get_nicename() ] = $ticket_name;
565
-                $reg_csv_array[ __("Datetimes of Ticket", "event_espresso") ] = implode(", ", $datetimes_strings);
566
-                // get datetime(s) of registration
567
-
568
-                // add attendee columns
569
-                foreach ($att_fields_to_include as $att_field_name) {
570
-                    $field_obj = EEM_Attendee::instance()->field_settings_for($att_field_name);
571
-                    if ($reg_row['Attendee_CPT.ID']) {
572
-                        if ($att_field_name == 'STA_ID') {
573
-                            $value = EEM_State::instance()->get_var(
574
-                                array(array('STA_ID' => $reg_row['Attendee_Meta.STA_ID'])),
575
-                                'STA_name'
576
-                            );
577
-                        } elseif ($att_field_name == 'CNT_ISO') {
578
-                            $value = EEM_Country::instance()->get_var(
579
-                                array(array('CNT_ISO' => $reg_row['Attendee_Meta.CNT_ISO'])),
580
-                                'CNT_name'
581
-                            );
582
-                        } else {
583
-                            $value = $this->_prepare_value_from_db_for_display(
584
-                                EEM_Attendee::instance(),
585
-                                $att_field_name,
586
-                                $reg_row[ $field_obj->get_qualified_column() ]
587
-                            );
588
-                        }
589
-                    } else {
590
-                        $value = '';
591
-                    }
592
-
593
-                    $reg_csv_array[ $this->_get_column_name_for_field($field_obj) ] = $value;
594
-                }
595
-
596
-                // make sure each registration has the same questions in the same order
597
-                foreach ($questions_for_these_regs_rows as $question_row) {
598
-                    if (! isset($reg_csv_array[ $question_row['Question.QST_admin_label'] ])) {
599
-                        $reg_csv_array[ $question_row['Question.QST_admin_label'] ] = null;
600
-                    }
601
-                }
602
-                // now fill out the questions THEY answered
603
-                foreach (EEM_Answer::instance()->get_all_wpdb_results(
604
-                    array(array('REG_ID' => $reg_row['Registration.REG_ID']), 'force_join' => array('Question'))
605
-                ) as $answer_row) {
606
-                    /* @var $answer EE_Answer */
607
-                    if ($answer_row['Question.QST_ID']) {
608
-                        $question_label = $this->_prepare_value_from_db_for_display(
609
-                            EEM_Question::instance(),
610
-                            'QST_admin_label',
611
-                            $answer_row['Question.QST_admin_label']
612
-                        );
613
-                    } else {
614
-                        $question_label = sprintf(__('Question $s', 'event_espresso'), $answer_row['Answer.QST_ID']);
615
-                    }
616
-                    if (isset($answer_row['Question.QST_type']) && $answer_row['Question.QST_type'] == EEM_Question::QST_type_state) {
617
-                        $reg_csv_array[ $question_label ] = EEM_State::instance()->get_state_name_by_ID(
618
-                            $answer_row['Answer.ANS_value']
619
-                        );
620
-                    } else {
621
-                        $reg_csv_array[ $question_label ] = $this->_prepare_value_from_db_for_display(
622
-                            EEM_Answer::instance(),
623
-                            'ANS_value',
624
-                            $answer_row['Answer.ANS_value']
625
-                        );
626
-                    }
627
-                }
628
-                $registrations_csv_ready_array[] = apply_filters(
629
-                    'FHEE__EE_Export__report_registrations__reg_csv_array',
630
-                    $reg_csv_array,
631
-                    $reg_row
632
-                );
633
-            }
634
-        }
635
-
636
-        // if we couldn't export anything, we want to at least show the column headers
637
-        if (empty($registrations_csv_ready_array)) {
638
-            $reg_csv_array = array();
639
-            $model_and_fields_to_include = array(
640
-                'Registration' => $reg_fields_to_include,
641
-                'Attendee'     => $att_fields_to_include,
642
-            );
643
-            foreach ($model_and_fields_to_include as $model_name => $field_list) {
644
-                $model = EE_Registry::instance()->load_model($model_name);
645
-                foreach ($field_list as $field_name) {
646
-                    $field = $model->field_settings_for($field_name);
647
-                    $reg_csv_array[ $this->_get_column_name_for_field(
648
-                        $field
649
-                    ) ] = null;// $registration->get($field->get_name());
650
-                }
651
-            }
652
-            $registrations_csv_ready_array [] = $reg_csv_array;
653
-        }
654
-        if ($event_id) {
655
-            $event_slug = EEM_Event::instance()->get_var(array(array('EVT_ID' => $event_id)), 'EVT_slug');
656
-            if (! $event_slug) {
657
-                $event_slug = __('unknown', 'event_espresso');
658
-            }
659
-        } else {
660
-            $event_slug = __('all', 'event_espresso');
661
-        }
662
-        $filename = sprintf("registrations-for-%s", $event_slug);
663
-
664
-        $handle = $this->EE_CSV->begin_sending_csv($filename);
665
-        $this->EE_CSV->write_data_array_to_csv($handle, $registrations_csv_ready_array);
666
-        $this->EE_CSV->end_sending_csv($handle);
667
-    }
668
-
669
-    /**
670
-     * Gets the 'normal' column named for fields
671
-     *
672
-     * @param EE_Model_Field_Base $field
673
-     * @return string
674
-     */
675
-    protected function _get_column_name_for_field(EE_Model_Field_Base $field)
676
-    {
677
-        return $field->get_nicename() . "[" . $field->get_name() . "]";
678
-    }
679
-
680
-
681
-    /**
682
-     * @Export data for ALL events
683
-     * @access public
684
-     * @return void
685
-     */
686
-    public function export_categories()
687
-    {
688
-        // are any Event IDs set?
689
-        $query_params = array();
690
-        if (isset($this->_req_data['EVT_CAT_ID'])) {
691
-            // do we have an array of IDs ?
692
-            if (is_array($this->_req_data['EVT_CAT_ID'])) {
693
-                // generate an "IN (CSV)" where clause
694
-                $EVT_CAT_IDs = array_map('sanitize_text_field', $this->_req_data['EVT_CAT_ID']);
695
-                $filename = 'event-categories';
696
-                $query_params[0]['term_taxonomy_id'] = array('IN', $EVT_CAT_IDs);
697
-            } else {
698
-                // generate regular where = clause
699
-                $EVT_CAT_ID = absint($this->_req_data['EVT_CAT_ID']);
700
-                $filename = 'event-category#' . $EVT_CAT_ID;
701
-                $query_params[0]['term_taxonomy_id'] = $EVT_CAT_ID;
702
-            }
703
-        } else {
704
-            // no IDs means we will d/l the entire table
705
-            $filename = 'all-categories';
706
-        }
707
-
708
-        $tables_to_export = array(
709
-            'Term_Taxonomy' => $query_params,
710
-        );
711
-
712
-        $table_data = $this->_get_export_data_for_models($tables_to_export);
713
-        $filename = $this->generate_filename($filename);
714
-
715
-        if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $table_data)) {
716
-            EE_Error::add_error(
717
-                __(
718
-                    'An error occurred and the Category details could not be exported from the database.',
719
-                    'event_espresso'
720
-                ),
721
-                __FILE__,
722
-                __FUNCTION__,
723
-                __LINE__
724
-            );
725
-        }
726
-    }
727
-
728
-
729
-    /**
730
-     * @process export name to create a suitable filename
731
-     * @access  private
732
-     * @param string - export_name
733
-     * @return string on success, FALSE on fail
734
-     */
735
-    private function generate_filename($export_name = '')
736
-    {
737
-        if ($export_name != '') {
738
-            $filename = get_bloginfo('name') . '-' . $export_name;
739
-            $filename = sanitize_key($filename) . '-' . $this->today;
740
-            return $filename;
741
-        } else {
742
-            EE_Error::add_error(__("No filename was provided", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
743
-        }
744
-        return false;
745
-    }
746
-
747
-
748
-    /**
749
-     * @recursive function for exporting table data and merging the results with the next results
750
-     * @access    private
751
-     * @param array $models_to_export keys are model names (eg 'Event', 'Attendee', etc.) and values are arrays of
752
-     *                                query params like on EEM_Base::get_all
753
-     * @return array on success, FALSE on fail
754
-     */
755
-    private function _get_export_data_for_models($models_to_export = array())
756
-    {
757
-        $table_data = false;
758
-        if (is_array($models_to_export)) {
759
-            foreach ($models_to_export as $model_name => $query_params) {
760
-                // check for a numerically-indexed array. in that case, $model_name is the value!!
761
-                if (is_int($model_name)) {
762
-                    $model_name = $query_params;
763
-                    $query_params = array();
764
-                }
765
-                $model = EE_Registry::instance()->load_model($model_name);
766
-                $model_objects = $model->get_all($query_params);
767
-
768
-                $table_data[ $model_name ] = array();
769
-                foreach ($model_objects as $model_object) {
770
-                    $model_data_array = array();
771
-                    $fields = $model->field_settings();
772
-                    foreach ($fields as $field) {
773
-                        $column_name = $field->get_nicename() . "[" . $field->get_name() . "]";
774
-                        if ($field instanceof EE_Datetime_Field) {
775
-                            // $field->set_date_format('Y-m-d');
776
-                            // $field->set_time_format('H:i:s');
777
-                            $model_data_array[ $column_name ] = $model_object->get_datetime(
778
-                                $field->get_name(),
779
-                                'Y-m-d',
780
-                                'H:i:s'
781
-                            );
782
-                        } else {
783
-                            $model_data_array[ $column_name ] = $model_object->get($field->get_name());
784
-                        }
785
-                    }
786
-                    $table_data[ $model_name ][] = $model_data_array;
787
-                }
788
-            }
789
-        }
790
-        return $table_data;
791
-    }
19
+	const option_prefix = 'ee_report_job_';
20
+
21
+
22
+	// instance of the EE_Export object
23
+	private static $_instance = null;
24
+
25
+	// instance of the EE_CSV object
26
+	/**
27
+	 *
28
+	 * @var EE_CSV
29
+	 */
30
+	public $EE_CSV = null;
31
+
32
+
33
+	private $_req_data = array();
34
+
35
+
36
+	/**
37
+	 *        private constructor to prevent direct creation
38
+	 *
39
+	 * @Constructor
40
+	 * @access private
41
+	 * @param array $request_data
42
+	 */
43
+	private function __construct($request_data = array())
44
+	{
45
+		$this->_req_data = $request_data;
46
+		$this->today = date("Y-m-d", time());
47
+		require_once(EE_CLASSES . 'EE_CSV.class.php');
48
+		$this->EE_CSV = EE_CSV::instance();
49
+	}
50
+
51
+
52
+	/**
53
+	 *        @ singleton method used to instantiate class object
54
+	 *        @ access public
55
+	 *
56
+	 * @param array $request_data
57
+	 * @return \EE_Export
58
+	 */
59
+	public static function instance($request_data = array())
60
+	{
61
+		// check if class object is instantiated
62
+		if (self::$_instance === null or ! is_object(self::$_instance) or ! (self::$_instance instanceof EE_Export)) {
63
+			self::$_instance = new self($request_data);
64
+		}
65
+		return self::$_instance;
66
+	}
67
+
68
+
69
+	/**
70
+	 * @Export Event Espresso data - routes export requests
71
+	 * @access public
72
+	 * @return void | bool
73
+	 */
74
+	public function export()
75
+	{
76
+		// in case of bulk exports, the "actual" action will be in action2, but first check regular action for "export" keyword
77
+		if (isset($this->_req_data['action']) && strpos($this->_req_data['action'], 'export') === false) {
78
+			// check if action2 has export action
79
+			if (isset($this->_req_data['action2']) && strpos($this->_req_data['action2'], 'export') !== false) {
80
+				// whoop! there it is!
81
+				$this->_req_data['action'] = $this->_req_data['action2'];
82
+			}
83
+		}
84
+
85
+		$this->_req_data['export'] = isset($this->_req_data['export']) ? $this->_req_data['export'] : '';
86
+
87
+		switch ($this->_req_data['export']) {
88
+			case 'report':
89
+				switch ($this->_req_data['action']) {
90
+					case "event":
91
+					case "export_events":
92
+					case 'all_event_data':
93
+						$this->export_all_event_data();
94
+						break;
95
+
96
+					case 'registrations_report_for_event':
97
+						$this->report_registrations_for_event($this->_req_data['EVT_ID']);
98
+						break;
99
+
100
+					case 'attendees':
101
+						$this->export_attendees();
102
+						break;
103
+
104
+					case 'categories':
105
+						$this->export_categories();
106
+						break;
107
+
108
+					default:
109
+						EE_Error::add_error(
110
+							__('An error occurred! The requested export report could not be found.', 'event_espresso'),
111
+							__FILE__,
112
+							__FUNCTION__,
113
+							__LINE__
114
+						);
115
+						return false;
116
+						break;
117
+				}
118
+				break; // end of switch export : report
119
+			default:
120
+				break;
121
+		} // end of switch export
122
+
123
+		exit;
124
+	}
125
+
126
+	/**
127
+	 * Downloads a CSV file with all the columns, but no data. This should be used for importing
128
+	 *
129
+	 * @return null kills execution
130
+	 */
131
+	public function export_sample()
132
+	{
133
+		$event = EEM_Event::instance()->get_one();
134
+		$this->_req_data['EVT_ID'] = $event->ID();
135
+		$this->export_all_event_data();
136
+	}
137
+
138
+
139
+	/**
140
+	 * @Export data for ALL events
141
+	 * @access public
142
+	 * @return void
143
+	 */
144
+	public function export_all_event_data()
145
+	{
146
+		// are any Event IDs set?
147
+		$event_query_params = array();
148
+		$related_models_query_params = array();
149
+		$related_through_reg_query_params = array();
150
+		$datetime_ticket_query_params = array();
151
+		$price_query_params = array();
152
+		$price_type_query_params = array();
153
+		$term_query_params = array();
154
+		$state_country_query_params = array();
155
+		$question_group_query_params = array();
156
+		$question_query_params = array();
157
+		if (isset($this->_req_data['EVT_ID'])) {
158
+			// do we have an array of IDs ?
159
+
160
+			if (is_array($this->_req_data['EVT_ID'])) {
161
+				$EVT_IDs = array_map('sanitize_text_field', $this->_req_data['EVT_ID']);
162
+				$value_to_equal = array('IN', $EVT_IDs);
163
+				$filename = 'events';
164
+			} else {
165
+				// generate regular where = clause
166
+				$EVT_ID = absint($this->_req_data['EVT_ID']);
167
+				$value_to_equal = $EVT_ID;
168
+				$event = EE_Registry::instance()->load_model('Event')->get_one_by_ID($EVT_ID);
169
+
170
+				$filename = 'event-' . ($event instanceof EE_Event ? $event->slug() : __('unknown', 'event_espresso'));
171
+			}
172
+			$event_query_params[0]['EVT_ID'] = $value_to_equal;
173
+			$related_models_query_params[0]['Event.EVT_ID'] = $value_to_equal;
174
+			$related_through_reg_query_params[0]['Registration.EVT_ID'] = $value_to_equal;
175
+			$datetime_ticket_query_params[0]['Datetime.EVT_ID'] = $value_to_equal;
176
+			$price_query_params[0]['Ticket.Datetime.EVT_ID'] = $value_to_equal;
177
+			$price_type_query_params[0]['Price.Ticket.Datetime.EVT_ID'] = $value_to_equal;
178
+			$term_query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $value_to_equal;
179
+			$state_country_query_params[0]['Venue.Event.EVT_ID'] = $value_to_equal;
180
+			$question_group_query_params[0]['Event.EVT_ID'] = $value_to_equal;
181
+			$question_query_params[0]['Question_Group.Event.EVT_ID'] = $value_to_equal;
182
+		} else {
183
+			$filename = 'all-events';
184
+		}
185
+
186
+
187
+		// array in the format:  table name =>  query where clause
188
+		$models_to_export = array(
189
+			'Event'                   => $event_query_params,
190
+			'Datetime'                => $related_models_query_params,
191
+			'Ticket_Template'         => $price_query_params,
192
+			'Ticket'                  => $datetime_ticket_query_params,
193
+			'Datetime_Ticket'         => $datetime_ticket_query_params,
194
+			'Price_Type'              => $price_type_query_params,
195
+			'Price'                   => $price_query_params,
196
+			'Ticket_Price'            => $price_query_params,
197
+			'Term'                    => $term_query_params,
198
+			'Term_Taxonomy'           => $related_models_query_params,
199
+			'Term_Relationship'       => $related_models_query_params, // model has NO primary key...
200
+			'Country'                 => $state_country_query_params,
201
+			'State'                   => $state_country_query_params,
202
+			'Venue'                   => $related_models_query_params,
203
+			'Event_Venue'             => $related_models_query_params,
204
+			'Question_Group'          => $question_group_query_params,
205
+			'Event_Question_Group'    => $question_group_query_params,
206
+			'Question'                => $question_query_params,
207
+			'Question_Group_Question' => $question_query_params,
208
+			// 'Transaction'=>$related_through_reg_query_params,
209
+			// 'Registration'=>$related_models_query_params,
210
+			// 'Attendee'=>$related_through_reg_query_params,
211
+			// 'Line_Item'=>
212
+
213
+		);
214
+
215
+		$model_data = $this->_get_export_data_for_models($models_to_export);
216
+
217
+		$filename = $this->generate_filename($filename);
218
+
219
+		if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $model_data)) {
220
+			EE_Error::add_error(
221
+				__(
222
+					"'An error occurred and the Event details could not be exported from the database.'",
223
+					"event_espresso"
224
+				),
225
+				__FILE__,
226
+				__FUNCTION__,
227
+				__LINE__
228
+			);
229
+		}
230
+	}
231
+
232
+	public function report_attendees()
233
+	{
234
+		$attendee_rows = EEM_Attendee::instance()->get_all_wpdb_results(
235
+			array(
236
+				'force_join' => array('State', 'Country'),
237
+				'caps'       => EEM_Base::caps_read_admin,
238
+			)
239
+		);
240
+		$csv_data = array();
241
+		foreach ($attendee_rows as $attendee_row) {
242
+			$csv_row = array();
243
+			foreach (EEM_Attendee::instance()->field_settings() as $field_name => $field_obj) {
244
+				if ($field_name == 'STA_ID') {
245
+					$state_name_field = EEM_State::instance()->field_settings_for('STA_name');
246
+					$csv_row[ __('State', 'event_espresso') ] = $attendee_row[ $state_name_field->get_qualified_column(
247
+					) ];
248
+				} elseif ($field_name == 'CNT_ISO') {
249
+					$country_name_field = EEM_Country::instance()->field_settings_for('CNT_name');
250
+					$csv_row[ __(
251
+						'Country',
252
+						'event_espresso'
253
+					) ] = $attendee_row[ $country_name_field->get_qualified_column() ];
254
+				} else {
255
+					$csv_row[ $field_obj->get_nicename() ] = $attendee_row[ $field_obj->get_qualified_column() ];
256
+				}
257
+			}
258
+			$csv_data[] = $csv_row;
259
+		}
260
+
261
+		$filename = $this->generate_filename('contact-list-report');
262
+
263
+		$handle = $this->EE_CSV->begin_sending_csv($filename);
264
+		$this->EE_CSV->write_data_array_to_csv($handle, $csv_data);
265
+		$this->EE_CSV->end_sending_csv($handle);
266
+	}
267
+
268
+
269
+	/**
270
+	 * @Export data for ALL attendees
271
+	 * @access public
272
+	 * @return void
273
+	 */
274
+	public function export_attendees()
275
+	{
276
+
277
+		$states_that_have_an_attendee = EEM_State::instance()->get_all(
278
+			array(0 => array('Attendee.ATT_ID' => array('IS NOT NULL')))
279
+		);
280
+		$countries_that_have_an_attendee = EEM_Country::instance()->get_all(
281
+			array(0 => array('Attendee.ATT_ID' => array('IS NOT NULL')))
282
+		);
283
+		// $states_to_export_query_params
284
+		$models_to_export = array(
285
+			'Country'  => array(array('CNT_ISO' => array('IN', array_keys($countries_that_have_an_attendee)))),
286
+			'State'    => array(array('STA_ID' => array('IN', array_keys($states_that_have_an_attendee)))),
287
+			'Attendee' => array(),
288
+		);
289
+
290
+
291
+		$model_data = $this->_get_export_data_for_models($models_to_export);
292
+		$filename = $this->generate_filename('all-attendees');
293
+
294
+		if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $model_data)) {
295
+			EE_Error::add_error(
296
+				__(
297
+					'An error occurred and the Attendee data could not be exported from the database.',
298
+					'event_espresso'
299
+				),
300
+				__FILE__,
301
+				__FUNCTION__,
302
+				__LINE__
303
+			);
304
+		}
305
+	}
306
+
307
+	/**
308
+	 * Shortcut for preparing a database result for display
309
+	 *
310
+	 * @param EEM_Base       $model
311
+	 * @param string         $field_name
312
+	 * @param string         $raw_db_value
313
+	 * @param boolean|string $pretty_schema true to display pretty, a string to use a specific "Schema", or false to
314
+	 *                                      NOT display pretty
315
+	 * @return string
316
+	 */
317
+	protected function _prepare_value_from_db_for_display($model, $field_name, $raw_db_value, $pretty_schema = true)
318
+	{
319
+		$field_obj = $model->field_settings_for($field_name);
320
+		$value_on_model_obj = $field_obj->prepare_for_set_from_db($raw_db_value);
321
+		if ($field_obj instanceof EE_Datetime_Field) {
322
+			$field_obj->set_date_format(
323
+				EE_CSV::instance()->get_date_format_for_csv($field_obj->get_date_format($pretty_schema)),
324
+				$pretty_schema
325
+			);
326
+			$field_obj->set_time_format(
327
+				EE_CSV::instance()->get_time_format_for_csv($field_obj->get_time_format($pretty_schema)),
328
+				$pretty_schema
329
+			);
330
+		}
331
+		if ($pretty_schema === true) {
332
+			return $field_obj->prepare_for_pretty_echoing($value_on_model_obj);
333
+		} elseif (is_string($pretty_schema)) {
334
+			return $field_obj->prepare_for_pretty_echoing($value_on_model_obj, $pretty_schema);
335
+		} else {
336
+			return $field_obj->prepare_for_get($value_on_model_obj);
337
+		}
338
+	}
339
+
340
+	/**
341
+	 * Export a custom CSV of registration info including: A bunch of the reg fields, the time of the event, the price
342
+	 * name, and the questions associated with the registrations
343
+	 *
344
+	 * @param int $event_id
345
+	 */
346
+	public function report_registrations_for_event($event_id = null)
347
+	{
348
+		$reg_fields_to_include = array(
349
+			'TXN_ID',
350
+			'ATT_ID',
351
+			'REG_ID',
352
+			'REG_date',
353
+			'REG_code',
354
+			'REG_count',
355
+			'REG_final_price',
356
+
357
+		);
358
+		$att_fields_to_include = array(
359
+			'ATT_fname',
360
+			'ATT_lname',
361
+			'ATT_email',
362
+			'ATT_address',
363
+			'ATT_address2',
364
+			'ATT_city',
365
+			'STA_ID',
366
+			'CNT_ISO',
367
+			'ATT_zip',
368
+			'ATT_phone',
369
+		);
370
+
371
+		$registrations_csv_ready_array = array();
372
+		$reg_model = EE_Registry::instance()->load_model('Registration');
373
+		$query_params = apply_filters(
374
+			'FHEE__EE_Export__report_registration_for_event',
375
+			array(
376
+				array(
377
+					'OR'                 => array(
378
+						// don't include registrations from failed or abandoned transactions...
379
+						'Transaction.STS_ID' => array(
380
+							'NOT IN',
381
+							array(EEM_Transaction::failed_status_code, EEM_Transaction::abandoned_status_code),
382
+						),
383
+						// unless the registration is approved, in which case include it regardless of transaction status
384
+						'STS_ID'             => EEM_Registration::status_id_approved,
385
+					),
386
+					'Ticket.TKT_deleted' => array('IN', array(true, false)),
387
+				),
388
+				'order_by'   => array('Transaction.TXN_ID' => 'asc', 'REG_count' => 'asc'),
389
+				'force_join' => array('Transaction', 'Ticket', 'Attendee'),
390
+				'caps'       => EEM_Base::caps_read_admin,
391
+			),
392
+			$event_id
393
+		);
394
+		if ($event_id) {
395
+			$query_params[0]['EVT_ID'] = $event_id;
396
+		} else {
397
+			$query_params['force_join'][] = 'Event';
398
+		}
399
+		$registration_rows = $reg_model->get_all_wpdb_results($query_params);
400
+		// get all questions which relate to someone in this group
401
+		$registration_ids = array();
402
+		foreach ($registration_rows as $reg_row) {
403
+			$registration_ids[] = intval($reg_row['Registration.REG_ID']);
404
+		}
405
+		// EEM_Question::instance()->show_next_x_db_queries();
406
+		$questions_for_these_regs_rows = EEM_Question::instance()->get_all_wpdb_results(
407
+			array(array('Answer.REG_ID' => array('IN', $registration_ids)))
408
+		);
409
+		foreach ($registration_rows as $reg_row) {
410
+			if (is_array($reg_row)) {
411
+				$reg_csv_array = array();
412
+				if (! $event_id) {
413
+					// get the event's name and Id
414
+					$reg_csv_array[ __('Event', 'event_espresso') ] = sprintf(
415
+						__('%1$s (%2$s)', 'event_espresso'),
416
+						$this->_prepare_value_from_db_for_display(
417
+							EEM_Event::instance(),
418
+							'EVT_name',
419
+							$reg_row['Event_CPT.post_title']
420
+						),
421
+						$reg_row['Event_CPT.ID']
422
+					);
423
+				}
424
+				$is_primary_reg = $reg_row['Registration.REG_count'] == '1' ? true : false;
425
+				/*@var $reg_row EE_Registration */
426
+				foreach ($reg_fields_to_include as $field_name) {
427
+					$field = $reg_model->field_settings_for($field_name);
428
+					if ($field_name == 'REG_final_price') {
429
+						$value = $this->_prepare_value_from_db_for_display(
430
+							$reg_model,
431
+							$field_name,
432
+							$reg_row['Registration.REG_final_price'],
433
+							'localized_float'
434
+						);
435
+					} elseif ($field_name == 'REG_count') {
436
+						$value = sprintf(
437
+							__('%s of %s', 'event_espresso'),
438
+							$this->_prepare_value_from_db_for_display(
439
+								$reg_model,
440
+								'REG_count',
441
+								$reg_row['Registration.REG_count']
442
+							),
443
+							$this->_prepare_value_from_db_for_display(
444
+								$reg_model,
445
+								'REG_group_size',
446
+								$reg_row['Registration.REG_group_size']
447
+							)
448
+						);
449
+					} elseif ($field_name == 'REG_date') {
450
+						$value = $this->_prepare_value_from_db_for_display(
451
+							$reg_model,
452
+							$field_name,
453
+							$reg_row['Registration.REG_date'],
454
+							'no_html'
455
+						);
456
+					} else {
457
+						$value = $this->_prepare_value_from_db_for_display(
458
+							$reg_model,
459
+							$field_name,
460
+							$reg_row[ $field->get_qualified_column() ]
461
+						);
462
+					}
463
+					$reg_csv_array[ $this->_get_column_name_for_field($field) ] = $value;
464
+					if ($field_name == 'REG_final_price') {
465
+						// add a column named Currency after the final price
466
+						$reg_csv_array[ __("Currency", "event_espresso") ] = EE_Config::instance()->currency->code;
467
+					}
468
+				}
469
+				// get pretty status
470
+				$stati = EEM_Status::instance()->localized_status(
471
+					array(
472
+						$reg_row['Registration.STS_ID']     => __('unknown', 'event_espresso'),
473
+						$reg_row['TransactionTable.STS_ID'] => __('unknown', 'event_espresso'),
474
+					),
475
+					false,
476
+					'sentence'
477
+				);
478
+				$reg_csv_array[ __(
479
+					"Registration Status",
480
+					'event_espresso'
481
+				) ] = $stati[ $reg_row['Registration.STS_ID'] ];
482
+				// get pretty trnasaction status
483
+				$reg_csv_array[ __(
484
+					"Transaction Status",
485
+					'event_espresso'
486
+				) ] = $stati[ $reg_row['TransactionTable.STS_ID'] ];
487
+				$reg_csv_array[ __('Transaction Amount Due', 'event_espresso') ] = $is_primary_reg
488
+					? $this->_prepare_value_from_db_for_display(
489
+						EEM_Transaction::instance(),
490
+						'TXN_total',
491
+						$reg_row['TransactionTable.TXN_total'],
492
+						'localized_float'
493
+					) : '0.00';
494
+				$reg_csv_array[ __('Amount Paid', 'event_espresso') ] = $is_primary_reg
495
+					? $this->_prepare_value_from_db_for_display(
496
+						EEM_Transaction::instance(),
497
+						'TXN_paid',
498
+						$reg_row['TransactionTable.TXN_paid'],
499
+						'localized_float'
500
+					) : '0.00';
501
+				$payment_methods = array();
502
+				$gateway_txn_ids_etc = array();
503
+				$payment_times = array();
504
+				if ($is_primary_reg && $reg_row['TransactionTable.TXN_ID']) {
505
+					$payments_info = EEM_Payment::instance()->get_all_wpdb_results(
506
+						array(
507
+							array(
508
+								'TXN_ID' => $reg_row['TransactionTable.TXN_ID'],
509
+								'STS_ID' => EEM_Payment::status_id_approved,
510
+							),
511
+							'force_join' => array('Payment_Method'),
512
+						),
513
+						ARRAY_A,
514
+						'Payment_Method.PMD_admin_name as name, Payment.PAY_txn_id_chq_nmbr as gateway_txn_id, Payment.PAY_timestamp as payment_time'
515
+					);
516
+
517
+					foreach ($payments_info as $payment_method_and_gateway_txn_id) {
518
+						$payment_methods[] = isset($payment_method_and_gateway_txn_id['name'])
519
+							? $payment_method_and_gateway_txn_id['name'] : __('Unknown', 'event_espresso');
520
+						$gateway_txn_ids_etc[] = isset($payment_method_and_gateway_txn_id['gateway_txn_id'])
521
+							? $payment_method_and_gateway_txn_id['gateway_txn_id'] : '';
522
+						$payment_times[] = isset($payment_method_and_gateway_txn_id['payment_time'])
523
+							? $payment_method_and_gateway_txn_id['payment_time'] : '';
524
+					}
525
+				}
526
+				$reg_csv_array[ __('Payment Date(s)', 'event_espresso') ] = implode(',', $payment_times);
527
+				$reg_csv_array[ __('Payment Method(s)', 'event_espresso') ] = implode(",", $payment_methods);
528
+				$reg_csv_array[ __('Gateway Transaction ID(s)', 'event_espresso') ] = implode(
529
+					',',
530
+					$gateway_txn_ids_etc
531
+				);
532
+
533
+				// get whether or not the user has checked in
534
+				$reg_csv_array[ __("Check-Ins", "event_espresso") ] = $reg_model->count_related(
535
+					$reg_row['Registration.REG_ID'],
536
+					'Checkin'
537
+				);
538
+				// get ticket of registration and its price
539
+				$ticket_model = EE_Registry::instance()->load_model('Ticket');
540
+				if ($reg_row['Ticket.TKT_ID']) {
541
+					$ticket_name = $this->_prepare_value_from_db_for_display(
542
+						$ticket_model,
543
+						'TKT_name',
544
+						$reg_row['Ticket.TKT_name']
545
+					);
546
+					$datetimes_strings = array();
547
+					foreach (EEM_Datetime::instance()->get_all_wpdb_results(
548
+						array(
549
+							array('Ticket.TKT_ID' => $reg_row['Ticket.TKT_ID']),
550
+							'order_by'                 => array('DTT_EVT_start' => 'ASC'),
551
+							'default_where_conditions' => 'none',
552
+						)
553
+					) as $datetime) {
554
+						$datetimes_strings[] = $this->_prepare_value_from_db_for_display(
555
+							EEM_Datetime::instance(),
556
+							'DTT_EVT_start',
557
+							$datetime['Datetime.DTT_EVT_start']
558
+						);
559
+					}
560
+				} else {
561
+					$ticket_name = __('Unknown', 'event_espresso');
562
+					$datetimes_strings = array(__('Unknown', 'event_espresso'));
563
+				}
564
+				$reg_csv_array[ $ticket_model->field_settings_for('TKT_name')->get_nicename() ] = $ticket_name;
565
+				$reg_csv_array[ __("Datetimes of Ticket", "event_espresso") ] = implode(", ", $datetimes_strings);
566
+				// get datetime(s) of registration
567
+
568
+				// add attendee columns
569
+				foreach ($att_fields_to_include as $att_field_name) {
570
+					$field_obj = EEM_Attendee::instance()->field_settings_for($att_field_name);
571
+					if ($reg_row['Attendee_CPT.ID']) {
572
+						if ($att_field_name == 'STA_ID') {
573
+							$value = EEM_State::instance()->get_var(
574
+								array(array('STA_ID' => $reg_row['Attendee_Meta.STA_ID'])),
575
+								'STA_name'
576
+							);
577
+						} elseif ($att_field_name == 'CNT_ISO') {
578
+							$value = EEM_Country::instance()->get_var(
579
+								array(array('CNT_ISO' => $reg_row['Attendee_Meta.CNT_ISO'])),
580
+								'CNT_name'
581
+							);
582
+						} else {
583
+							$value = $this->_prepare_value_from_db_for_display(
584
+								EEM_Attendee::instance(),
585
+								$att_field_name,
586
+								$reg_row[ $field_obj->get_qualified_column() ]
587
+							);
588
+						}
589
+					} else {
590
+						$value = '';
591
+					}
592
+
593
+					$reg_csv_array[ $this->_get_column_name_for_field($field_obj) ] = $value;
594
+				}
595
+
596
+				// make sure each registration has the same questions in the same order
597
+				foreach ($questions_for_these_regs_rows as $question_row) {
598
+					if (! isset($reg_csv_array[ $question_row['Question.QST_admin_label'] ])) {
599
+						$reg_csv_array[ $question_row['Question.QST_admin_label'] ] = null;
600
+					}
601
+				}
602
+				// now fill out the questions THEY answered
603
+				foreach (EEM_Answer::instance()->get_all_wpdb_results(
604
+					array(array('REG_ID' => $reg_row['Registration.REG_ID']), 'force_join' => array('Question'))
605
+				) as $answer_row) {
606
+					/* @var $answer EE_Answer */
607
+					if ($answer_row['Question.QST_ID']) {
608
+						$question_label = $this->_prepare_value_from_db_for_display(
609
+							EEM_Question::instance(),
610
+							'QST_admin_label',
611
+							$answer_row['Question.QST_admin_label']
612
+						);
613
+					} else {
614
+						$question_label = sprintf(__('Question $s', 'event_espresso'), $answer_row['Answer.QST_ID']);
615
+					}
616
+					if (isset($answer_row['Question.QST_type']) && $answer_row['Question.QST_type'] == EEM_Question::QST_type_state) {
617
+						$reg_csv_array[ $question_label ] = EEM_State::instance()->get_state_name_by_ID(
618
+							$answer_row['Answer.ANS_value']
619
+						);
620
+					} else {
621
+						$reg_csv_array[ $question_label ] = $this->_prepare_value_from_db_for_display(
622
+							EEM_Answer::instance(),
623
+							'ANS_value',
624
+							$answer_row['Answer.ANS_value']
625
+						);
626
+					}
627
+				}
628
+				$registrations_csv_ready_array[] = apply_filters(
629
+					'FHEE__EE_Export__report_registrations__reg_csv_array',
630
+					$reg_csv_array,
631
+					$reg_row
632
+				);
633
+			}
634
+		}
635
+
636
+		// if we couldn't export anything, we want to at least show the column headers
637
+		if (empty($registrations_csv_ready_array)) {
638
+			$reg_csv_array = array();
639
+			$model_and_fields_to_include = array(
640
+				'Registration' => $reg_fields_to_include,
641
+				'Attendee'     => $att_fields_to_include,
642
+			);
643
+			foreach ($model_and_fields_to_include as $model_name => $field_list) {
644
+				$model = EE_Registry::instance()->load_model($model_name);
645
+				foreach ($field_list as $field_name) {
646
+					$field = $model->field_settings_for($field_name);
647
+					$reg_csv_array[ $this->_get_column_name_for_field(
648
+						$field
649
+					) ] = null;// $registration->get($field->get_name());
650
+				}
651
+			}
652
+			$registrations_csv_ready_array [] = $reg_csv_array;
653
+		}
654
+		if ($event_id) {
655
+			$event_slug = EEM_Event::instance()->get_var(array(array('EVT_ID' => $event_id)), 'EVT_slug');
656
+			if (! $event_slug) {
657
+				$event_slug = __('unknown', 'event_espresso');
658
+			}
659
+		} else {
660
+			$event_slug = __('all', 'event_espresso');
661
+		}
662
+		$filename = sprintf("registrations-for-%s", $event_slug);
663
+
664
+		$handle = $this->EE_CSV->begin_sending_csv($filename);
665
+		$this->EE_CSV->write_data_array_to_csv($handle, $registrations_csv_ready_array);
666
+		$this->EE_CSV->end_sending_csv($handle);
667
+	}
668
+
669
+	/**
670
+	 * Gets the 'normal' column named for fields
671
+	 *
672
+	 * @param EE_Model_Field_Base $field
673
+	 * @return string
674
+	 */
675
+	protected function _get_column_name_for_field(EE_Model_Field_Base $field)
676
+	{
677
+		return $field->get_nicename() . "[" . $field->get_name() . "]";
678
+	}
679
+
680
+
681
+	/**
682
+	 * @Export data for ALL events
683
+	 * @access public
684
+	 * @return void
685
+	 */
686
+	public function export_categories()
687
+	{
688
+		// are any Event IDs set?
689
+		$query_params = array();
690
+		if (isset($this->_req_data['EVT_CAT_ID'])) {
691
+			// do we have an array of IDs ?
692
+			if (is_array($this->_req_data['EVT_CAT_ID'])) {
693
+				// generate an "IN (CSV)" where clause
694
+				$EVT_CAT_IDs = array_map('sanitize_text_field', $this->_req_data['EVT_CAT_ID']);
695
+				$filename = 'event-categories';
696
+				$query_params[0]['term_taxonomy_id'] = array('IN', $EVT_CAT_IDs);
697
+			} else {
698
+				// generate regular where = clause
699
+				$EVT_CAT_ID = absint($this->_req_data['EVT_CAT_ID']);
700
+				$filename = 'event-category#' . $EVT_CAT_ID;
701
+				$query_params[0]['term_taxonomy_id'] = $EVT_CAT_ID;
702
+			}
703
+		} else {
704
+			// no IDs means we will d/l the entire table
705
+			$filename = 'all-categories';
706
+		}
707
+
708
+		$tables_to_export = array(
709
+			'Term_Taxonomy' => $query_params,
710
+		);
711
+
712
+		$table_data = $this->_get_export_data_for_models($tables_to_export);
713
+		$filename = $this->generate_filename($filename);
714
+
715
+		if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $table_data)) {
716
+			EE_Error::add_error(
717
+				__(
718
+					'An error occurred and the Category details could not be exported from the database.',
719
+					'event_espresso'
720
+				),
721
+				__FILE__,
722
+				__FUNCTION__,
723
+				__LINE__
724
+			);
725
+		}
726
+	}
727
+
728
+
729
+	/**
730
+	 * @process export name to create a suitable filename
731
+	 * @access  private
732
+	 * @param string - export_name
733
+	 * @return string on success, FALSE on fail
734
+	 */
735
+	private function generate_filename($export_name = '')
736
+	{
737
+		if ($export_name != '') {
738
+			$filename = get_bloginfo('name') . '-' . $export_name;
739
+			$filename = sanitize_key($filename) . '-' . $this->today;
740
+			return $filename;
741
+		} else {
742
+			EE_Error::add_error(__("No filename was provided", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
743
+		}
744
+		return false;
745
+	}
746
+
747
+
748
+	/**
749
+	 * @recursive function for exporting table data and merging the results with the next results
750
+	 * @access    private
751
+	 * @param array $models_to_export keys are model names (eg 'Event', 'Attendee', etc.) and values are arrays of
752
+	 *                                query params like on EEM_Base::get_all
753
+	 * @return array on success, FALSE on fail
754
+	 */
755
+	private function _get_export_data_for_models($models_to_export = array())
756
+	{
757
+		$table_data = false;
758
+		if (is_array($models_to_export)) {
759
+			foreach ($models_to_export as $model_name => $query_params) {
760
+				// check for a numerically-indexed array. in that case, $model_name is the value!!
761
+				if (is_int($model_name)) {
762
+					$model_name = $query_params;
763
+					$query_params = array();
764
+				}
765
+				$model = EE_Registry::instance()->load_model($model_name);
766
+				$model_objects = $model->get_all($query_params);
767
+
768
+				$table_data[ $model_name ] = array();
769
+				foreach ($model_objects as $model_object) {
770
+					$model_data_array = array();
771
+					$fields = $model->field_settings();
772
+					foreach ($fields as $field) {
773
+						$column_name = $field->get_nicename() . "[" . $field->get_name() . "]";
774
+						if ($field instanceof EE_Datetime_Field) {
775
+							// $field->set_date_format('Y-m-d');
776
+							// $field->set_time_format('H:i:s');
777
+							$model_data_array[ $column_name ] = $model_object->get_datetime(
778
+								$field->get_name(),
779
+								'Y-m-d',
780
+								'H:i:s'
781
+							);
782
+						} else {
783
+							$model_data_array[ $column_name ] = $model_object->get($field->get_name());
784
+						}
785
+					}
786
+					$table_data[ $model_name ][] = $model_data_array;
787
+				}
788
+			}
789
+		}
790
+		return $table_data;
791
+	}
792 792
 }
Please login to merge, or discard this patch.
Spacing   +45 added lines, -45 removed lines patch added patch discarded remove patch
@@ -44,7 +44,7 @@  discard block
 block discarded – undo
44 44
     {
45 45
         $this->_req_data = $request_data;
46 46
         $this->today = date("Y-m-d", time());
47
-        require_once(EE_CLASSES . 'EE_CSV.class.php');
47
+        require_once(EE_CLASSES.'EE_CSV.class.php');
48 48
         $this->EE_CSV = EE_CSV::instance();
49 49
     }
50 50
 
@@ -167,7 +167,7 @@  discard block
 block discarded – undo
167 167
                 $value_to_equal = $EVT_ID;
168 168
                 $event = EE_Registry::instance()->load_model('Event')->get_one_by_ID($EVT_ID);
169 169
 
170
-                $filename = 'event-' . ($event instanceof EE_Event ? $event->slug() : __('unknown', 'event_espresso'));
170
+                $filename = 'event-'.($event instanceof EE_Event ? $event->slug() : __('unknown', 'event_espresso'));
171 171
             }
172 172
             $event_query_params[0]['EVT_ID'] = $value_to_equal;
173 173
             $related_models_query_params[0]['Event.EVT_ID'] = $value_to_equal;
@@ -216,7 +216,7 @@  discard block
 block discarded – undo
216 216
 
217 217
         $filename = $this->generate_filename($filename);
218 218
 
219
-        if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $model_data)) {
219
+        if ( ! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $model_data)) {
220 220
             EE_Error::add_error(
221 221
                 __(
222 222
                     "'An error occurred and the Event details could not be exported from the database.'",
@@ -243,16 +243,16 @@  discard block
 block discarded – undo
243 243
             foreach (EEM_Attendee::instance()->field_settings() as $field_name => $field_obj) {
244 244
                 if ($field_name == 'STA_ID') {
245 245
                     $state_name_field = EEM_State::instance()->field_settings_for('STA_name');
246
-                    $csv_row[ __('State', 'event_espresso') ] = $attendee_row[ $state_name_field->get_qualified_column(
247
-                    ) ];
246
+                    $csv_row[__('State', 'event_espresso')] = $attendee_row[$state_name_field->get_qualified_column(
247
+                    )];
248 248
                 } elseif ($field_name == 'CNT_ISO') {
249 249
                     $country_name_field = EEM_Country::instance()->field_settings_for('CNT_name');
250
-                    $csv_row[ __(
250
+                    $csv_row[__(
251 251
                         'Country',
252 252
                         'event_espresso'
253
-                    ) ] = $attendee_row[ $country_name_field->get_qualified_column() ];
253
+                    )] = $attendee_row[$country_name_field->get_qualified_column()];
254 254
                 } else {
255
-                    $csv_row[ $field_obj->get_nicename() ] = $attendee_row[ $field_obj->get_qualified_column() ];
255
+                    $csv_row[$field_obj->get_nicename()] = $attendee_row[$field_obj->get_qualified_column()];
256 256
                 }
257 257
             }
258 258
             $csv_data[] = $csv_row;
@@ -291,7 +291,7 @@  discard block
 block discarded – undo
291 291
         $model_data = $this->_get_export_data_for_models($models_to_export);
292 292
         $filename = $this->generate_filename('all-attendees');
293 293
 
294
-        if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $model_data)) {
294
+        if ( ! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $model_data)) {
295 295
             EE_Error::add_error(
296 296
                 __(
297 297
                     'An error occurred and the Attendee data could not be exported from the database.',
@@ -409,9 +409,9 @@  discard block
 block discarded – undo
409 409
         foreach ($registration_rows as $reg_row) {
410 410
             if (is_array($reg_row)) {
411 411
                 $reg_csv_array = array();
412
-                if (! $event_id) {
412
+                if ( ! $event_id) {
413 413
                     // get the event's name and Id
414
-                    $reg_csv_array[ __('Event', 'event_espresso') ] = sprintf(
414
+                    $reg_csv_array[__('Event', 'event_espresso')] = sprintf(
415 415
                         __('%1$s (%2$s)', 'event_espresso'),
416 416
                         $this->_prepare_value_from_db_for_display(
417 417
                             EEM_Event::instance(),
@@ -457,13 +457,13 @@  discard block
 block discarded – undo
457 457
                         $value = $this->_prepare_value_from_db_for_display(
458 458
                             $reg_model,
459 459
                             $field_name,
460
-                            $reg_row[ $field->get_qualified_column() ]
460
+                            $reg_row[$field->get_qualified_column()]
461 461
                         );
462 462
                     }
463
-                    $reg_csv_array[ $this->_get_column_name_for_field($field) ] = $value;
463
+                    $reg_csv_array[$this->_get_column_name_for_field($field)] = $value;
464 464
                     if ($field_name == 'REG_final_price') {
465 465
                         // add a column named Currency after the final price
466
-                        $reg_csv_array[ __("Currency", "event_espresso") ] = EE_Config::instance()->currency->code;
466
+                        $reg_csv_array[__("Currency", "event_espresso")] = EE_Config::instance()->currency->code;
467 467
                     }
468 468
                 }
469 469
                 // get pretty status
@@ -475,23 +475,23 @@  discard block
 block discarded – undo
475 475
                     false,
476 476
                     'sentence'
477 477
                 );
478
-                $reg_csv_array[ __(
478
+                $reg_csv_array[__(
479 479
                     "Registration Status",
480 480
                     'event_espresso'
481
-                ) ] = $stati[ $reg_row['Registration.STS_ID'] ];
481
+                )] = $stati[$reg_row['Registration.STS_ID']];
482 482
                 // get pretty trnasaction status
483
-                $reg_csv_array[ __(
483
+                $reg_csv_array[__(
484 484
                     "Transaction Status",
485 485
                     'event_espresso'
486
-                ) ] = $stati[ $reg_row['TransactionTable.STS_ID'] ];
487
-                $reg_csv_array[ __('Transaction Amount Due', 'event_espresso') ] = $is_primary_reg
486
+                )] = $stati[$reg_row['TransactionTable.STS_ID']];
487
+                $reg_csv_array[__('Transaction Amount Due', 'event_espresso')] = $is_primary_reg
488 488
                     ? $this->_prepare_value_from_db_for_display(
489 489
                         EEM_Transaction::instance(),
490 490
                         'TXN_total',
491 491
                         $reg_row['TransactionTable.TXN_total'],
492 492
                         'localized_float'
493 493
                     ) : '0.00';
494
-                $reg_csv_array[ __('Amount Paid', 'event_espresso') ] = $is_primary_reg
494
+                $reg_csv_array[__('Amount Paid', 'event_espresso')] = $is_primary_reg
495 495
                     ? $this->_prepare_value_from_db_for_display(
496 496
                         EEM_Transaction::instance(),
497 497
                         'TXN_paid',
@@ -523,15 +523,15 @@  discard block
 block discarded – undo
523 523
                             ? $payment_method_and_gateway_txn_id['payment_time'] : '';
524 524
                     }
525 525
                 }
526
-                $reg_csv_array[ __('Payment Date(s)', 'event_espresso') ] = implode(',', $payment_times);
527
-                $reg_csv_array[ __('Payment Method(s)', 'event_espresso') ] = implode(",", $payment_methods);
528
-                $reg_csv_array[ __('Gateway Transaction ID(s)', 'event_espresso') ] = implode(
526
+                $reg_csv_array[__('Payment Date(s)', 'event_espresso')] = implode(',', $payment_times);
527
+                $reg_csv_array[__('Payment Method(s)', 'event_espresso')] = implode(",", $payment_methods);
528
+                $reg_csv_array[__('Gateway Transaction ID(s)', 'event_espresso')] = implode(
529 529
                     ',',
530 530
                     $gateway_txn_ids_etc
531 531
                 );
532 532
 
533 533
                 // get whether or not the user has checked in
534
-                $reg_csv_array[ __("Check-Ins", "event_espresso") ] = $reg_model->count_related(
534
+                $reg_csv_array[__("Check-Ins", "event_espresso")] = $reg_model->count_related(
535 535
                     $reg_row['Registration.REG_ID'],
536 536
                     'Checkin'
537 537
                 );
@@ -561,8 +561,8 @@  discard block
 block discarded – undo
561 561
                     $ticket_name = __('Unknown', 'event_espresso');
562 562
                     $datetimes_strings = array(__('Unknown', 'event_espresso'));
563 563
                 }
564
-                $reg_csv_array[ $ticket_model->field_settings_for('TKT_name')->get_nicename() ] = $ticket_name;
565
-                $reg_csv_array[ __("Datetimes of Ticket", "event_espresso") ] = implode(", ", $datetimes_strings);
564
+                $reg_csv_array[$ticket_model->field_settings_for('TKT_name')->get_nicename()] = $ticket_name;
565
+                $reg_csv_array[__("Datetimes of Ticket", "event_espresso")] = implode(", ", $datetimes_strings);
566 566
                 // get datetime(s) of registration
567 567
 
568 568
                 // add attendee columns
@@ -583,20 +583,20 @@  discard block
 block discarded – undo
583 583
                             $value = $this->_prepare_value_from_db_for_display(
584 584
                                 EEM_Attendee::instance(),
585 585
                                 $att_field_name,
586
-                                $reg_row[ $field_obj->get_qualified_column() ]
586
+                                $reg_row[$field_obj->get_qualified_column()]
587 587
                             );
588 588
                         }
589 589
                     } else {
590 590
                         $value = '';
591 591
                     }
592 592
 
593
-                    $reg_csv_array[ $this->_get_column_name_for_field($field_obj) ] = $value;
593
+                    $reg_csv_array[$this->_get_column_name_for_field($field_obj)] = $value;
594 594
                 }
595 595
 
596 596
                 // make sure each registration has the same questions in the same order
597 597
                 foreach ($questions_for_these_regs_rows as $question_row) {
598
-                    if (! isset($reg_csv_array[ $question_row['Question.QST_admin_label'] ])) {
599
-                        $reg_csv_array[ $question_row['Question.QST_admin_label'] ] = null;
598
+                    if ( ! isset($reg_csv_array[$question_row['Question.QST_admin_label']])) {
599
+                        $reg_csv_array[$question_row['Question.QST_admin_label']] = null;
600 600
                     }
601 601
                 }
602 602
                 // now fill out the questions THEY answered
@@ -614,11 +614,11 @@  discard block
 block discarded – undo
614 614
                         $question_label = sprintf(__('Question $s', 'event_espresso'), $answer_row['Answer.QST_ID']);
615 615
                     }
616 616
                     if (isset($answer_row['Question.QST_type']) && $answer_row['Question.QST_type'] == EEM_Question::QST_type_state) {
617
-                        $reg_csv_array[ $question_label ] = EEM_State::instance()->get_state_name_by_ID(
617
+                        $reg_csv_array[$question_label] = EEM_State::instance()->get_state_name_by_ID(
618 618
                             $answer_row['Answer.ANS_value']
619 619
                         );
620 620
                     } else {
621
-                        $reg_csv_array[ $question_label ] = $this->_prepare_value_from_db_for_display(
621
+                        $reg_csv_array[$question_label] = $this->_prepare_value_from_db_for_display(
622 622
                             EEM_Answer::instance(),
623 623
                             'ANS_value',
624 624
                             $answer_row['Answer.ANS_value']
@@ -644,16 +644,16 @@  discard block
 block discarded – undo
644 644
                 $model = EE_Registry::instance()->load_model($model_name);
645 645
                 foreach ($field_list as $field_name) {
646 646
                     $field = $model->field_settings_for($field_name);
647
-                    $reg_csv_array[ $this->_get_column_name_for_field(
647
+                    $reg_csv_array[$this->_get_column_name_for_field(
648 648
                         $field
649
-                    ) ] = null;// $registration->get($field->get_name());
649
+                    )] = null; // $registration->get($field->get_name());
650 650
                 }
651 651
             }
652 652
             $registrations_csv_ready_array [] = $reg_csv_array;
653 653
         }
654 654
         if ($event_id) {
655 655
             $event_slug = EEM_Event::instance()->get_var(array(array('EVT_ID' => $event_id)), 'EVT_slug');
656
-            if (! $event_slug) {
656
+            if ( ! $event_slug) {
657 657
                 $event_slug = __('unknown', 'event_espresso');
658 658
             }
659 659
         } else {
@@ -674,7 +674,7 @@  discard block
 block discarded – undo
674 674
      */
675 675
     protected function _get_column_name_for_field(EE_Model_Field_Base $field)
676 676
     {
677
-        return $field->get_nicename() . "[" . $field->get_name() . "]";
677
+        return $field->get_nicename()."[".$field->get_name()."]";
678 678
     }
679 679
 
680 680
 
@@ -697,7 +697,7 @@  discard block
 block discarded – undo
697 697
             } else {
698 698
                 // generate regular where = clause
699 699
                 $EVT_CAT_ID = absint($this->_req_data['EVT_CAT_ID']);
700
-                $filename = 'event-category#' . $EVT_CAT_ID;
700
+                $filename = 'event-category#'.$EVT_CAT_ID;
701 701
                 $query_params[0]['term_taxonomy_id'] = $EVT_CAT_ID;
702 702
             }
703 703
         } else {
@@ -712,7 +712,7 @@  discard block
 block discarded – undo
712 712
         $table_data = $this->_get_export_data_for_models($tables_to_export);
713 713
         $filename = $this->generate_filename($filename);
714 714
 
715
-        if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $table_data)) {
715
+        if ( ! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $table_data)) {
716 716
             EE_Error::add_error(
717 717
                 __(
718 718
                     'An error occurred and the Category details could not be exported from the database.',
@@ -735,8 +735,8 @@  discard block
 block discarded – undo
735 735
     private function generate_filename($export_name = '')
736 736
     {
737 737
         if ($export_name != '') {
738
-            $filename = get_bloginfo('name') . '-' . $export_name;
739
-            $filename = sanitize_key($filename) . '-' . $this->today;
738
+            $filename = get_bloginfo('name').'-'.$export_name;
739
+            $filename = sanitize_key($filename).'-'.$this->today;
740 740
             return $filename;
741 741
         } else {
742 742
             EE_Error::add_error(__("No filename was provided", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
@@ -765,25 +765,25 @@  discard block
 block discarded – undo
765 765
                 $model = EE_Registry::instance()->load_model($model_name);
766 766
                 $model_objects = $model->get_all($query_params);
767 767
 
768
-                $table_data[ $model_name ] = array();
768
+                $table_data[$model_name] = array();
769 769
                 foreach ($model_objects as $model_object) {
770 770
                     $model_data_array = array();
771 771
                     $fields = $model->field_settings();
772 772
                     foreach ($fields as $field) {
773
-                        $column_name = $field->get_nicename() . "[" . $field->get_name() . "]";
773
+                        $column_name = $field->get_nicename()."[".$field->get_name()."]";
774 774
                         if ($field instanceof EE_Datetime_Field) {
775 775
                             // $field->set_date_format('Y-m-d');
776 776
                             // $field->set_time_format('H:i:s');
777
-                            $model_data_array[ $column_name ] = $model_object->get_datetime(
777
+                            $model_data_array[$column_name] = $model_object->get_datetime(
778 778
                                 $field->get_name(),
779 779
                                 'Y-m-d',
780 780
                                 'H:i:s'
781 781
                             );
782 782
                         } else {
783
-                            $model_data_array[ $column_name ] = $model_object->get($field->get_name());
783
+                            $model_data_array[$column_name] = $model_object->get($field->get_name());
784 784
                         }
785 785
                     }
786
-                    $table_data[ $model_name ][] = $model_data_array;
786
+                    $table_data[$model_name][] = $model_data_array;
787 787
                 }
788 788
             }
789 789
         }
Please login to merge, or discard this patch.
core/db_classes/EE_Answer.class.php 1 patch
Indentation   +138 added lines, -138 removed lines patch added patch discarded remove patch
@@ -10,144 +10,144 @@
 block discarded – undo
10 10
 class EE_Answer extends EE_Base_Class
11 11
 {
12 12
 
13
-    /**
14
-     *
15
-     * @param array $props_n_values
16
-     * @return EE_Answer
17
-     */
18
-    public static function new_instance($props_n_values = array())
19
-    {
20
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__);
21
-        return $has_object ? $has_object : new self($props_n_values);
22
-    }
23
-
24
-
25
-    /**
26
-     *
27
-     * @param array $props_n_values
28
-     * @return EE_Answer
29
-     */
30
-    public static function new_instance_from_db($props_n_values = array())
31
-    {
32
-        return new self($props_n_values, true);
33
-    }
34
-
35
-
36
-    /**
37
-     *    Set Question ID
38
-     *
39
-     * @access        public
40
-     * @param int $QST_ID
41
-     */
42
-    public function set_question($QST_ID = 0)
43
-    {
44
-        $this->set('QST_ID', $QST_ID);
45
-    }
46
-
47
-
48
-    /**
49
-     *    Set Registration ID
50
-     *
51
-     * @access        public
52
-     * @param int $REG_ID
53
-     */
54
-    public function set_registration($REG_ID = 0)
55
-    {
56
-        $this->set('REG_ID', $REG_ID);
57
-    }
58
-
59
-
60
-    /**
61
-     *    Set Answer value
62
-     *
63
-     * @access        public
64
-     * @param mixed $ANS_value
65
-     */
66
-    public function set_value($ANS_value = '')
67
-    {
68
-        $this->set('ANS_value', $ANS_value);
69
-    }
70
-
71
-
72
-    /**
73
-     *    get Attendee First Name
74
-     *
75
-     * @access        public
76
-     * @return        int
77
-     */
78
-    public function registration_ID()
79
-    {
80
-        return $this->get('REG_ID');
81
-    }
82
-
83
-
84
-    /**
85
-     *    get Attendee Last Name
86
-     *
87
-     * @access        public
88
-     * @return        int
89
-     */
90
-    public function question_ID()
91
-    {
92
-        return $this->get('QST_ID');
93
-    }
94
-
95
-
96
-    /**
97
-     *    get Attendee Address
98
-     *
99
-     * @access        public
100
-     * @return        string
101
-     */
102
-    public function value()
103
-    {
104
-        return $this->get('ANS_value');
105
-    }
106
-
107
-
108
-    /**
109
-     * Gets a pretty form of the value (mostly applies to answers that have multiple answers)
110
-     *
111
-     * @param null $schema
112
-     * @return string
113
-     */
114
-    public function pretty_value($schema = null)
115
-    {
116
-        return $this->get_pretty('ANS_value', $schema);
117
-    }
118
-
119
-
120
-    /**
121
-     * Echoes out a pretty value (even for multi-choice options)
122
-     *
123
-     * @param string $schema
124
-     */
125
-    public function e_value($schema = null)
126
-    {
127
-        $this->e('ANS_value', $schema);
128
-    }
129
-
130
-
131
-    /**
132
-     * Gets the related EE_Question to this EE_Answer
133
-     *
134
-     * @return EE_Question
135
-     */
136
-    public function question()
137
-    {
138
-        return $this->get_first_related('Question');
139
-    }
140
-
141
-
142
-    /**
143
-     * Gets the related EE_Registration to this EE_Answer
144
-     *
145
-     * @return EE_Registration
146
-     */
147
-    public function registration()
148
-    {
149
-        return $this->get_first_related('Registration');
150
-    }
13
+	/**
14
+	 *
15
+	 * @param array $props_n_values
16
+	 * @return EE_Answer
17
+	 */
18
+	public static function new_instance($props_n_values = array())
19
+	{
20
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__);
21
+		return $has_object ? $has_object : new self($props_n_values);
22
+	}
23
+
24
+
25
+	/**
26
+	 *
27
+	 * @param array $props_n_values
28
+	 * @return EE_Answer
29
+	 */
30
+	public static function new_instance_from_db($props_n_values = array())
31
+	{
32
+		return new self($props_n_values, true);
33
+	}
34
+
35
+
36
+	/**
37
+	 *    Set Question ID
38
+	 *
39
+	 * @access        public
40
+	 * @param int $QST_ID
41
+	 */
42
+	public function set_question($QST_ID = 0)
43
+	{
44
+		$this->set('QST_ID', $QST_ID);
45
+	}
46
+
47
+
48
+	/**
49
+	 *    Set Registration ID
50
+	 *
51
+	 * @access        public
52
+	 * @param int $REG_ID
53
+	 */
54
+	public function set_registration($REG_ID = 0)
55
+	{
56
+		$this->set('REG_ID', $REG_ID);
57
+	}
58
+
59
+
60
+	/**
61
+	 *    Set Answer value
62
+	 *
63
+	 * @access        public
64
+	 * @param mixed $ANS_value
65
+	 */
66
+	public function set_value($ANS_value = '')
67
+	{
68
+		$this->set('ANS_value', $ANS_value);
69
+	}
70
+
71
+
72
+	/**
73
+	 *    get Attendee First Name
74
+	 *
75
+	 * @access        public
76
+	 * @return        int
77
+	 */
78
+	public function registration_ID()
79
+	{
80
+		return $this->get('REG_ID');
81
+	}
82
+
83
+
84
+	/**
85
+	 *    get Attendee Last Name
86
+	 *
87
+	 * @access        public
88
+	 * @return        int
89
+	 */
90
+	public function question_ID()
91
+	{
92
+		return $this->get('QST_ID');
93
+	}
94
+
95
+
96
+	/**
97
+	 *    get Attendee Address
98
+	 *
99
+	 * @access        public
100
+	 * @return        string
101
+	 */
102
+	public function value()
103
+	{
104
+		return $this->get('ANS_value');
105
+	}
106
+
107
+
108
+	/**
109
+	 * Gets a pretty form of the value (mostly applies to answers that have multiple answers)
110
+	 *
111
+	 * @param null $schema
112
+	 * @return string
113
+	 */
114
+	public function pretty_value($schema = null)
115
+	{
116
+		return $this->get_pretty('ANS_value', $schema);
117
+	}
118
+
119
+
120
+	/**
121
+	 * Echoes out a pretty value (even for multi-choice options)
122
+	 *
123
+	 * @param string $schema
124
+	 */
125
+	public function e_value($schema = null)
126
+	{
127
+		$this->e('ANS_value', $schema);
128
+	}
129
+
130
+
131
+	/**
132
+	 * Gets the related EE_Question to this EE_Answer
133
+	 *
134
+	 * @return EE_Question
135
+	 */
136
+	public function question()
137
+	{
138
+		return $this->get_first_related('Question');
139
+	}
140
+
141
+
142
+	/**
143
+	 * Gets the related EE_Registration to this EE_Answer
144
+	 *
145
+	 * @return EE_Registration
146
+	 */
147
+	public function registration()
148
+	{
149
+		return $this->get_first_related('Registration');
150
+	}
151 151
 }
152 152
 
153 153
 /* End of file EE_Answer.class.php */
Please login to merge, or discard this patch.
core/db_classes/EE_Country.class.php 1 patch
Indentation   +119 added lines, -119 removed lines patch added patch discarded remove patch
@@ -10,123 +10,123 @@
 block discarded – undo
10 10
 class EE_Country extends EE_Base_Class
11 11
 {
12 12
 
13
-    /**
14
-     * @param array $props_n_values
15
-     * @return EE_Country|mixed
16
-     */
17
-    public static function new_instance($props_n_values = array())
18
-    {
19
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__);
20
-        return $has_object ? $has_object : new self($props_n_values);
21
-    }
22
-
23
-
24
-    /**
25
-     * @param array $props_n_values
26
-     * @return EE_Country
27
-     */
28
-    public static function new_instance_from_db($props_n_values = array())
29
-    {
30
-        return new self($props_n_values, true);
31
-    }
32
-
33
-
34
-    /**
35
-     * Gets the country name
36
-     *
37
-     * @return string
38
-     */
39
-    public function name()
40
-    {
41
-        return $this->get('CNT_name');
42
-    }
43
-
44
-
45
-    /**
46
-     * gets the country's currency code
47
-     *
48
-     * @return string
49
-     */
50
-    public function currency_code()
51
-    {
52
-        return $this->get('CNT_cur_code');
53
-    }
54
-
55
-
56
-    /**
57
-     * gets the country's currency sign/symbol
58
-     *
59
-     * @return string
60
-     */
61
-    public function currency_sign()
62
-    {
63
-        $CNT_cur_sign = $this->get('CNT_cur_sign');
64
-        return $CNT_cur_sign ? $CNT_cur_sign : '';
65
-    }
66
-
67
-
68
-    /**
69
-     * Currency name singular
70
-     *
71
-     * @return string
72
-     */
73
-    public function currency_name_single()
74
-    {
75
-        return $this->get('CNT_cur_single');
76
-    }
77
-
78
-
79
-    /**
80
-     * Currency name plural
81
-     *
82
-     * @return string
83
-     */
84
-    public function currency_name_plural()
85
-    {
86
-        return $this->get('CNT_cur_plural');
87
-    }
88
-
89
-
90
-    /**
91
-     * currency_sign_before - ie: $TRUE  or  FALSE$
92
-     *
93
-     * @return boolean
94
-     */
95
-    public function currency_sign_before()
96
-    {
97
-        return $this->get('CNT_cur_sign_b4');
98
-    }
99
-
100
-
101
-    /**
102
-     * currency_decimal_places : 2 = 0.00   3 = 0.000
103
-     *
104
-     * @return integer
105
-     */
106
-    public function currency_decimal_places()
107
-    {
108
-        return $this->get('CNT_cur_dec_plc');
109
-    }
110
-
111
-
112
-    /**
113
-     * currency_decimal_mark :   (comma) ',' = 0,01   or   (decimal) '.' = 0.01
114
-     *
115
-     * @return string
116
-     */
117
-    public function currency_decimal_mark()
118
-    {
119
-        return $this->get('CNT_cur_dec_mrk');
120
-    }
121
-
122
-
123
-    /**
124
-     * currency thousands separator:   (comma) ',' = 1,000   or   (decimal) '.' = 1.000
125
-     *
126
-     * @return string
127
-     */
128
-    public function currency_thousands_separator()
129
-    {
130
-        return $this->get('CNT_cur_thsnds');
131
-    }
13
+	/**
14
+	 * @param array $props_n_values
15
+	 * @return EE_Country|mixed
16
+	 */
17
+	public static function new_instance($props_n_values = array())
18
+	{
19
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__);
20
+		return $has_object ? $has_object : new self($props_n_values);
21
+	}
22
+
23
+
24
+	/**
25
+	 * @param array $props_n_values
26
+	 * @return EE_Country
27
+	 */
28
+	public static function new_instance_from_db($props_n_values = array())
29
+	{
30
+		return new self($props_n_values, true);
31
+	}
32
+
33
+
34
+	/**
35
+	 * Gets the country name
36
+	 *
37
+	 * @return string
38
+	 */
39
+	public function name()
40
+	{
41
+		return $this->get('CNT_name');
42
+	}
43
+
44
+
45
+	/**
46
+	 * gets the country's currency code
47
+	 *
48
+	 * @return string
49
+	 */
50
+	public function currency_code()
51
+	{
52
+		return $this->get('CNT_cur_code');
53
+	}
54
+
55
+
56
+	/**
57
+	 * gets the country's currency sign/symbol
58
+	 *
59
+	 * @return string
60
+	 */
61
+	public function currency_sign()
62
+	{
63
+		$CNT_cur_sign = $this->get('CNT_cur_sign');
64
+		return $CNT_cur_sign ? $CNT_cur_sign : '';
65
+	}
66
+
67
+
68
+	/**
69
+	 * Currency name singular
70
+	 *
71
+	 * @return string
72
+	 */
73
+	public function currency_name_single()
74
+	{
75
+		return $this->get('CNT_cur_single');
76
+	}
77
+
78
+
79
+	/**
80
+	 * Currency name plural
81
+	 *
82
+	 * @return string
83
+	 */
84
+	public function currency_name_plural()
85
+	{
86
+		return $this->get('CNT_cur_plural');
87
+	}
88
+
89
+
90
+	/**
91
+	 * currency_sign_before - ie: $TRUE  or  FALSE$
92
+	 *
93
+	 * @return boolean
94
+	 */
95
+	public function currency_sign_before()
96
+	{
97
+		return $this->get('CNT_cur_sign_b4');
98
+	}
99
+
100
+
101
+	/**
102
+	 * currency_decimal_places : 2 = 0.00   3 = 0.000
103
+	 *
104
+	 * @return integer
105
+	 */
106
+	public function currency_decimal_places()
107
+	{
108
+		return $this->get('CNT_cur_dec_plc');
109
+	}
110
+
111
+
112
+	/**
113
+	 * currency_decimal_mark :   (comma) ',' = 0,01   or   (decimal) '.' = 0.01
114
+	 *
115
+	 * @return string
116
+	 */
117
+	public function currency_decimal_mark()
118
+	{
119
+		return $this->get('CNT_cur_dec_mrk');
120
+	}
121
+
122
+
123
+	/**
124
+	 * currency thousands separator:   (comma) ',' = 1,000   or   (decimal) '.' = 1.000
125
+	 *
126
+	 * @return string
127
+	 */
128
+	public function currency_thousands_separator()
129
+	{
130
+		return $this->get('CNT_cur_thsnds');
131
+	}
132 132
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Message.class.php 2 patches
Indentation   +867 added lines, -867 removed lines patch added patch discarded remove patch
@@ -10,875 +10,875 @@
 block discarded – undo
10 10
 class EE_Message extends EE_Base_Class implements EEI_Admin_Links
11 11
 {
12 12
 
13
-    /**
14
-     * @deprecated 4.9.0  Added for backward compat with add-on's
15
-     * @type null
16
-     */
17
-    public $template_pack;
18
-
19
-    /**
20
-     * @deprecated 4.9.0 Added for backward compat with add-on's
21
-     * @type null
22
-     */
23
-    public $template_variation;
24
-
25
-    /**
26
-     * @deprecated 4.9.0 Added for backward compat with add-on's
27
-     * @type string
28
-     */
29
-    public $content = '';
30
-
31
-
32
-    /**
33
-     * @type EE_messenger $_messenger
34
-     */
35
-    protected $_messenger = null;
36
-
37
-    /**
38
-     * @type EE_message_type $_message_type
39
-     */
40
-    protected $_message_type = null;
41
-
42
-
43
-    /**
44
-     * @param array  $props_n_values
45
-     * @param string $timezone
46
-     * @param array  $date_formats incoming date formats in an array.  First value is the date_format, second is time
47
-     *                             format.
48
-     * @return EE_Message
49
-     */
50
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
51
-    {
52
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__);
53
-        // if object doesn't exist, let's generate a unique token on instantiation so that its available even before saving to db.
54
-        if (! $has_object) {
55
-            EE_Registry::instance()->load_helper('URL');
56
-            $props_n_values['MSG_token'] = EEH_URL::generate_unique_token();
57
-        }
58
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
59
-    }
60
-
61
-
62
-    /**
63
-     * @param array  $props_n_values
64
-     * @param string $timezone
65
-     * @return EE_Message
66
-     */
67
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
68
-    {
69
-        return new self($props_n_values, true, $timezone);
70
-    }
71
-
72
-
73
-    /**
74
-     * Gets MSG_token
75
-     *
76
-     * @return int
77
-     */
78
-    public function MSG_token()
79
-    {
80
-        return $this->get('MSG_token');
81
-    }
82
-
83
-
84
-    /**
85
-     * Sets MSG_token
86
-     *
87
-     * @param int $MSG_token
88
-     */
89
-    public function set_MSG_token($MSG_token)
90
-    {
91
-        $this->set('MSG_token', $MSG_token);
92
-    }
93
-
94
-
95
-    /**
96
-     * Gets GRP_ID
97
-     *
98
-     * @return int
99
-     */
100
-    public function GRP_ID()
101
-    {
102
-        return $this->get('GRP_ID');
103
-    }
104
-
105
-
106
-    /**
107
-     * Sets GRP_ID
108
-     *
109
-     * @param int $GRP_ID
110
-     */
111
-    public function set_GRP_ID($GRP_ID)
112
-    {
113
-        $this->set('GRP_ID', $GRP_ID);
114
-    }
115
-
116
-
117
-    /**
118
-     * Gets TXN_ID
119
-     *
120
-     * @return int
121
-     */
122
-    public function TXN_ID()
123
-    {
124
-        return $this->get('TXN_ID');
125
-    }
126
-
127
-
128
-    /**
129
-     * Sets TXN_ID
130
-     *
131
-     * @param int $TXN_ID
132
-     */
133
-    public function set_TXN_ID($TXN_ID)
134
-    {
135
-        $this->set('TXN_ID', $TXN_ID);
136
-    }
137
-
138
-
139
-    /**
140
-     * Gets messenger
141
-     *
142
-     * @return string
143
-     */
144
-    public function messenger()
145
-    {
146
-        return $this->get('MSG_messenger');
147
-    }
148
-
149
-
150
-    /**
151
-     * Sets messenger
152
-     *
153
-     * @param string $messenger
154
-     */
155
-    public function set_messenger($messenger)
156
-    {
157
-        $this->set('MSG_messenger', $messenger);
158
-    }
159
-
160
-
161
-    /**
162
-     * Returns corresponding messenger object for the set messenger on this message
163
-     *
164
-     * @return EE_messenger | null
165
-     */
166
-    public function messenger_object()
167
-    {
168
-        return $this->_messenger;
169
-    }
170
-
171
-
172
-    /**
173
-     * Sets messenger
174
-     *
175
-     * @param EE_messenger $messenger
176
-     */
177
-    public function set_messenger_object(EE_messenger $messenger)
178
-    {
179
-        $this->_messenger = $messenger;
180
-    }
181
-
182
-
183
-    /**
184
-     * validates messenger
185
-     *
186
-     * @param bool $throw_exceptions
187
-     * @return bool
188
-     * @throws \EE_Error
189
-     */
190
-    public function valid_messenger($throw_exceptions = false)
191
-    {
192
-        if ($this->_messenger instanceof EE_messenger) {
193
-            return true;
194
-        }
195
-        if ($throw_exceptions) {
196
-            throw new EE_Error(
197
-                sprintf(
198
-                    __(
199
-                        'The "%1$s" messenger set for this message is missing or invalid. Please double-check the spelling and verify that the correct files exist.',
200
-                        'event_espresso'
201
-                    ),
202
-                    $this->messenger()
203
-                )
204
-            );
205
-        }
206
-        return false;
207
-    }
208
-
209
-
210
-    /**
211
-     * This returns the set localized label for the messenger on this message.
212
-     * Note, if unable to retrieve the EE_messenger object then will just return the messenger slug saved
213
-     * with this message.
214
-     *
215
-     * @param   bool $plural whether to return the plural label or not.
216
-     * @return string
217
-     */
218
-    public function messenger_label($plural = false)
219
-    {
220
-        $label_type = $plural ? 'plural' : 'singular';
221
-        $messenger = $this->messenger_object();
222
-        return $messenger instanceof EE_messenger ? $messenger->label[ $label_type ] : $this->messenger();
223
-    }
224
-
225
-
226
-    /**
227
-     * Gets message_type
228
-     *
229
-     * @return string
230
-     */
231
-    public function message_type()
232
-    {
233
-        return $this->get('MSG_message_type');
234
-    }
235
-
236
-
237
-    /**
238
-     * Sets message_type
239
-     *
240
-     * @param string $message_type
241
-     */
242
-    public function set_message_type($message_type)
243
-    {
244
-        $this->set('MSG_message_type', $message_type);
245
-    }
246
-
247
-
248
-    /**
249
-     * Returns the message type object for the set message type on this message
250
-     *
251
-     * @return EE_message_type | null
252
-     */
253
-    public function message_type_object()
254
-    {
255
-        return $this->_message_type;
256
-    }
257
-
258
-
259
-    /**
260
-     * Sets message_type
261
-     *
262
-     * @param EE_message_type $message_type
263
-     * @param bool            $set_priority   This indicates whether to set the priority to whatever the priority is on
264
-     *                                        the message type or not.
265
-     */
266
-    public function set_message_type_object(EE_message_type $message_type, $set_priority = false)
267
-    {
268
-        $this->_message_type = $message_type;
269
-        if ($set_priority) {
270
-            $this->set_priority($this->_message_type->get_priority());
271
-        }
272
-    }
273
-
274
-
275
-    /**
276
-     * validates message_type
277
-     *
278
-     * @param bool $throw_exceptions
279
-     * @return bool
280
-     * @throws \EE_Error
281
-     */
282
-    public function valid_message_type($throw_exceptions = false)
283
-    {
284
-        if ($this->_message_type instanceof EE_message_type) {
285
-            return true;
286
-        }
287
-        if ($throw_exceptions) {
288
-            throw new EE_Error(
289
-                sprintf(
290
-                    __(
291
-                        'The %1$s message type set for this message is missing or invalid. Please double-check the spelling and verify that the correct files exist.',
292
-                        'event_espresso'
293
-                    ),
294
-                    $this->message_type()
295
-                )
296
-            );
297
-        }
298
-        return false;
299
-    }
300
-
301
-
302
-    /**
303
-     * validates messenger and message_type (that they are valid EE_messenger and EE_message_type objects).
304
-     *
305
-     * @param bool $throw_exceptions
306
-     * @return bool
307
-     * @throws \EE_Error
308
-     */
309
-    public function is_valid($throw_exceptions = false)
310
-    {
311
-        if ($this->valid_messenger($throw_exceptions) && $this->valid_message_type($throw_exceptions)) {
312
-            return true;
313
-        }
314
-        return false;
315
-    }
316
-
317
-
318
-    /**
319
-     * This validates whether the internal messenger and message type objects are valid for sending.
320
-     * Three checks are done:
321
-     * 1. There is a valid messenger object.
322
-     * 2. There is a valid message type object.
323
-     * 3. The message type object is active for the messenger.
324
-     *
325
-     * @throws EE_Error  But only if $throw_exceptions is set to true.
326
-     * @param bool $throw_exceptions
327
-     * @return bool
328
-     */
329
-    public function is_valid_for_sending_or_generation($throw_exceptions = false)
330
-    {
331
-        $valid = false;
332
-        if ($this->is_valid($throw_exceptions)) {
333
-            /** @var EE_Message_Resource_Manager $message_resource_manager */
334
-            $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
335
-            $valid = $message_resource_manager->is_message_type_active_for_messenger(
336
-                $this->messenger(),
337
-                $this->message_type()
338
-            );
339
-            if (! $valid && $throw_exceptions) {
340
-                throw new EE_Error(
341
-                    sprintf(
342
-                        __(
343
-                            'The %1$s message type is not a valid message type for the %2$s messenger so it will not be sent.',
344
-                            'event_espresso'
345
-                        ),
346
-                        $this->message_type(),
347
-                        $this->messenger()
348
-                    )
349
-                );
350
-            }
351
-        }
352
-        return $valid;
353
-    }
354
-
355
-
356
-    /**
357
-     * This returns the set localized label for the message type on this message.
358
-     * Note, if unable to retrieve the EE_message_type object then will just return the message type slug saved
359
-     * with this message.
360
-     *
361
-     * @param   bool $plural whether to return the plural label or not.
362
-     * @return string
363
-     */
364
-    public function message_type_label($plural = false)
365
-    {
366
-        $label_type = $plural ? 'plural' : 'singular';
367
-        $message_type = $this->message_type_object();
368
-        return $message_type instanceof EE_message_type
369
-            ? $message_type->label[ $label_type ]
370
-            : str_replace(
371
-                '_',
372
-                ' ',
373
-                $this->message_type()
374
-            );
375
-    }
376
-
377
-
378
-    /**
379
-     * Gets context
380
-     *
381
-     * @return string
382
-     */
383
-    public function context()
384
-    {
385
-        return $this->get('MSG_context');
386
-    }
387
-
388
-
389
-    /**
390
-     * This returns the corresponding localized label for the given context slug, if possible from installed message
391
-     * types. Otherwise, this will just return the set context slug on this object.
392
-     *
393
-     * @return string
394
-     */
395
-    public function context_label()
396
-    {
397
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
398
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
399
-        $contexts = $message_resource_manager->get_all_contexts();
400
-        return isset($contexts[ $this->context() ]) ? $contexts[ $this->context() ] : $this->context();
401
-    }
402
-
403
-
404
-    /**
405
-     * Sets context
406
-     *
407
-     * @param string $context
408
-     */
409
-    public function set_context($context)
410
-    {
411
-        $this->set('MSG_context', $context);
412
-    }
413
-
414
-
415
-    /**
416
-     * Gets recipient_ID
417
-     *
418
-     * @return int
419
-     */
420
-    public function recipient_ID()
421
-    {
422
-        return $this->get('MSG_recipient_ID');
423
-    }
424
-
425
-
426
-    /**
427
-     * Sets recipient_ID
428
-     *
429
-     * @param string $recipient_ID
430
-     */
431
-    public function set_recipient_ID($recipient_ID)
432
-    {
433
-        $this->set('MSG_recipient_ID', $recipient_ID);
434
-    }
435
-
436
-
437
-    /**
438
-     * Gets recipient_type
439
-     *
440
-     * @return string
441
-     */
442
-    public function recipient_type()
443
-    {
444
-        return $this->get('MSG_recipient_type');
445
-    }
446
-
447
-
448
-    /**
449
-     * Return the related object matching the recipient type and ID.
450
-     *
451
-     * @return EE_Base_Class | null
452
-     */
453
-    public function recipient_object()
454
-    {
455
-        if (! $this->recipient_type() || ! $this->recipient_ID()) {
456
-            return null;
457
-        }
458
-
459
-        return $this->get_first_related($this->recipient_type());
460
-    }
461
-
462
-
463
-    /**
464
-     * Sets recipient_type
465
-     *
466
-     * @param string $recipient_type
467
-     */
468
-    public function set_recipient_type($recipient_type)
469
-    {
470
-        $this->set('MSG_recipient_type', $recipient_type);
471
-    }
472
-
473
-
474
-    /**
475
-     * Gets content
476
-     *
477
-     * @return string
478
-     */
479
-    public function content()
480
-    {
481
-        return $this->get('MSG_content');
482
-    }
483
-
484
-
485
-    /**
486
-     * Sets content
487
-     *
488
-     * @param string $content
489
-     */
490
-    public function set_content($content)
491
-    {
492
-        $this->set('MSG_content', $content);
493
-    }
494
-
495
-
496
-    /**
497
-     * Gets subject
498
-     *
499
-     * @return string
500
-     */
501
-    public function subject()
502
-    {
503
-        return $this->get('MSG_subject');
504
-    }
505
-
506
-
507
-    /**
508
-     * Sets subject
509
-     *
510
-     * @param string $subject
511
-     */
512
-    public function set_subject($subject)
513
-    {
514
-        $this->set('MSG_subject', $subject);
515
-    }
516
-
517
-
518
-    /**
519
-     * Gets to
520
-     *
521
-     * @return string
522
-     */
523
-    public function to()
524
-    {
525
-        $to = $this->get('MSG_to');
526
-        return empty($to) ? __('No recipient', 'event_espresso') : $to;
527
-    }
528
-
529
-
530
-    /**
531
-     * Sets to
532
-     *
533
-     * @param string $to
534
-     */
535
-    public function set_to($to)
536
-    {
537
-        $this->set('MSG_to', $to);
538
-    }
539
-
540
-
541
-    /**
542
-     * Gets from
543
-     *
544
-     * @return string
545
-     */
546
-    public function from()
547
-    {
548
-        return $this->get('MSG_from');
549
-    }
550
-
551
-
552
-    /**
553
-     * Sets from
554
-     *
555
-     * @param string $from
556
-     */
557
-    public function set_from($from)
558
-    {
559
-        $this->set('MSG_from', $from);
560
-    }
561
-
562
-
563
-    /**
564
-     * Gets priority
565
-     *
566
-     * @return int
567
-     */
568
-    public function priority()
569
-    {
570
-        return $this->get('MSG_priority');
571
-    }
572
-
573
-
574
-    /**
575
-     * Sets priority
576
-     * Note.  Send Now Messengers always override any priority that may be set on a Message.  So
577
-     * this method calls the send_now method to verify that.
578
-     *
579
-     * @param int $priority
580
-     */
581
-    public function set_priority($priority)
582
-    {
583
-        $priority = $this->send_now() ? EEM_Message::priority_high : $priority;
584
-        parent::set('MSG_priority', $priority);
585
-    }
586
-
587
-
588
-    /**
589
-     * Overrides parent::set method so we can capture any sets for priority.
590
-     *
591
-     * @see parent::set() for phpdocs
592
-     * @param string $field_name
593
-     * @param mixed  $field_value
594
-     * @param bool   $use_default
595
-     * @throws EE_Error
596
-     */
597
-    public function set($field_name, $field_value, $use_default = false)
598
-    {
599
-        if ($field_name === 'MSG_priority') {
600
-            $this->set_priority($field_value);
601
-        }
602
-        parent::set($field_name, $field_value, $use_default);
603
-    }
604
-
605
-
606
-    /**
607
-     * @return bool
608
-     * @throws \EE_Error
609
-     */
610
-    public function send_now()
611
-    {
612
-        $send_now = $this->valid_messenger() && $this->messenger_object()->send_now() ? EEM_Message::priority_high
613
-            : $this->priority();
614
-        return $send_now === EEM_Message::priority_high ? true : false;
615
-    }
616
-
617
-
618
-    /**
619
-     * Gets STS_ID
620
-     *
621
-     * @return string
622
-     */
623
-    public function STS_ID()
624
-    {
625
-        return $this->get('STS_ID');
626
-    }
627
-
628
-
629
-    /**
630
-     * Sets STS_ID
631
-     *
632
-     * @param string $STS_ID
633
-     */
634
-    public function set_STS_ID($STS_ID)
635
-    {
636
-        $this->set('STS_ID', $STS_ID);
637
-    }
638
-
639
-
640
-    /**
641
-     * Gets created
642
-     *
643
-     * @return string
644
-     */
645
-    public function created()
646
-    {
647
-        return $this->get('MSG_created');
648
-    }
649
-
650
-
651
-    /**
652
-     * Sets created
653
-     *
654
-     * @param string $created
655
-     */
656
-    public function set_created($created)
657
-    {
658
-        $this->set('MSG_created', $created);
659
-    }
660
-
661
-
662
-    /**
663
-     * Gets modified
664
-     *
665
-     * @return string
666
-     */
667
-    public function modified()
668
-    {
669
-        return $this->get('MSG_modified');
670
-    }
671
-
672
-
673
-    /**
674
-     * Sets modified
675
-     *
676
-     * @param string $modified
677
-     */
678
-    public function set_modified($modified)
679
-    {
680
-        $this->set('MSG_modified', $modified);
681
-    }
682
-
683
-
684
-    /**
685
-     * Sets generation data for this message.
686
-     *
687
-     * @param mixed $data
688
-     */
689
-    public function set_generation_data($data)
690
-    {
691
-        $this->set_field_or_extra_meta('MSG_generation_data', $data);
692
-    }
693
-
694
-
695
-    /**
696
-     * Returns any set generation data for this message.
697
-     *
698
-     * @return mixed|null
699
-     */
700
-    public function get_generation_data()
701
-    {
702
-        return $this->get_field_or_extra_meta('MSG_generation_data');
703
-    }
704
-
705
-
706
-    /**
707
-     * Gets any error message.
708
-     *
709
-     * @return mixed|null
710
-     */
711
-    public function error_message()
712
-    {
713
-        return $this->get_field_or_extra_meta('MSG_error');
714
-    }
715
-
716
-
717
-    /**
718
-     * Sets an error message.
719
-     *
720
-     * @param $message
721
-     * @return bool|int
722
-     */
723
-    public function set_error_message($message)
724
-    {
725
-        return $this->set_field_or_extra_meta('MSG_error', $message);
726
-    }
727
-
728
-
729
-    /**
730
-     * This retrieves the associated template pack with this message.
731
-     *
732
-     * @return EE_Messages_Template_Pack | null
733
-     */
734
-    public function get_template_pack()
735
-    {
736
-        /**
737
-         * This is deprecated functionality that will be removed eventually but included here now for backward compat.
738
-         */
739
-        if (! empty($this->template_pack)) {
740
-            return $this->template_pack;
741
-        }
742
-        /** @type EE_Message_Template_Group $grp */
743
-        $grp = $this->get_first_related('Message_Template_Group');
744
-        // if no group then let's try to get the first related group by internal messenger and message type (will use global grp).
745
-        if (! $grp instanceof EE_Message_Template_Group) {
746
-            $grp = EEM_Message_Template_Group::instance()->get_one(
747
-                array(
748
-                    array(
749
-                        'MTP_messenger'    => $this->messenger(),
750
-                        'MTP_message_type' => $this->message_type(),
751
-                        'MTP_is_global'    => true,
752
-                    ),
753
-                )
754
-            );
755
-        }
756
-
757
-        return $grp instanceof EE_Message_Template_Group ? $grp->get_template_pack() : null;
758
-    }
759
-
760
-
761
-    /**
762
-     * Retrieves the variation used for generating this message.
763
-     *
764
-     * @return string
765
-     */
766
-    public function get_template_pack_variation()
767
-    {
768
-        /**
769
-         * This is deprecated functionality that will be removed eventually but included here now for backward compat.
770
-         */
771
-        if (! empty($this->template_variation)) {
772
-            return $this->template_variation;
773
-        }
774
-
775
-        /** @type EE_Message_Template_Group $grp */
776
-        $grp = $this->get_first_related('Message_Template_Group');
777
-
778
-        // if no group then let's try to get the first related group by internal messenger and message type (will use global grp).
779
-        if (! $grp instanceof EE_Message_Template_Group) {
780
-            $grp = EEM_Message_Template_Group::instance()->get_one(
781
-                array(
782
-                    array(
783
-                        'MTP_messenger'    => $this->messenger(),
784
-                        'MTP_message_type' => $this->message_type(),
785
-                        'MTP_is_global'    => true,
786
-                    ),
787
-                )
788
-            );
789
-        }
790
-
791
-        return $grp instanceof EE_Message_Template_Group ? $grp->get_template_pack_variation() : '';
792
-    }
793
-
794
-    /**
795
-     * Return the link to the admin details for the object.
796
-     *
797
-     * @return string
798
-     */
799
-    public function get_admin_details_link()
800
-    {
801
-        EE_Registry::instance()->load_helper('URL');
802
-        EE_Registry::instance()->load_helper('MSG_Template');
803
-        switch ($this->STS_ID()) {
804
-            case EEM_Message::status_failed:
805
-            case EEM_Message::status_debug_only:
806
-                return EEH_MSG_Template::generate_error_display_trigger($this);
807
-                break;
808
-
809
-            case EEM_Message::status_sent:
810
-                return EEH_MSG_Template::generate_browser_trigger($this);
811
-                break;
812
-
813
-            default:
814
-                return '';
815
-        }
816
-    }
817
-
818
-    /**
819
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
820
-     *
821
-     * @return string
822
-     */
823
-    public function get_admin_edit_link()
824
-    {
825
-        return $this->get_admin_details_link();
826
-    }
827
-
828
-    /**
829
-     * Returns the link to a settings page for the object.
830
-     *
831
-     * @return string
832
-     */
833
-    public function get_admin_settings_link()
834
-    {
835
-        EE_Registry::instance()->load_helper('URL');
836
-        return EEH_URL::add_query_args_and_nonce(
837
-            array(
838
-                'page'   => 'espresso_messages',
839
-                'action' => 'settings',
840
-            ),
841
-            admin_url('admin.php')
842
-        );
843
-    }
844
-
845
-    /**
846
-     * Returns the link to the "overview" for the object (typically the "list table" view).
847
-     *
848
-     * @return string
849
-     */
850
-    public function get_admin_overview_link()
851
-    {
852
-        EE_Registry::instance()->load_helper('URL');
853
-        return EEH_URL::add_query_args_and_nonce(
854
-            array(
855
-                'page'   => 'espresso_messages',
856
-                'action' => 'default',
857
-            ),
858
-            admin_url('admin.php')
859
-        );
860
-    }
861
-
862
-
863
-    /**
864
-     * This sets the EEM_Message::status_messenger_executing class on the message and the appropriate error message for
865
-     * it.
866
-     * Note this also SAVES the current message object to the db because it adds an error message to accompany the
867
-     * status.
868
-     *
869
-     */
870
-    public function set_messenger_is_executing()
871
-    {
872
-        $this->set_STS_ID(EEM_Message::status_messenger_executing);
873
-        $this->set_error_message(
874
-            esc_html__(
875
-                'A message with this status indicates that there was a problem that occurred while the message was being
13
+	/**
14
+	 * @deprecated 4.9.0  Added for backward compat with add-on's
15
+	 * @type null
16
+	 */
17
+	public $template_pack;
18
+
19
+	/**
20
+	 * @deprecated 4.9.0 Added for backward compat with add-on's
21
+	 * @type null
22
+	 */
23
+	public $template_variation;
24
+
25
+	/**
26
+	 * @deprecated 4.9.0 Added for backward compat with add-on's
27
+	 * @type string
28
+	 */
29
+	public $content = '';
30
+
31
+
32
+	/**
33
+	 * @type EE_messenger $_messenger
34
+	 */
35
+	protected $_messenger = null;
36
+
37
+	/**
38
+	 * @type EE_message_type $_message_type
39
+	 */
40
+	protected $_message_type = null;
41
+
42
+
43
+	/**
44
+	 * @param array  $props_n_values
45
+	 * @param string $timezone
46
+	 * @param array  $date_formats incoming date formats in an array.  First value is the date_format, second is time
47
+	 *                             format.
48
+	 * @return EE_Message
49
+	 */
50
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
51
+	{
52
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__);
53
+		// if object doesn't exist, let's generate a unique token on instantiation so that its available even before saving to db.
54
+		if (! $has_object) {
55
+			EE_Registry::instance()->load_helper('URL');
56
+			$props_n_values['MSG_token'] = EEH_URL::generate_unique_token();
57
+		}
58
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
59
+	}
60
+
61
+
62
+	/**
63
+	 * @param array  $props_n_values
64
+	 * @param string $timezone
65
+	 * @return EE_Message
66
+	 */
67
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
68
+	{
69
+		return new self($props_n_values, true, $timezone);
70
+	}
71
+
72
+
73
+	/**
74
+	 * Gets MSG_token
75
+	 *
76
+	 * @return int
77
+	 */
78
+	public function MSG_token()
79
+	{
80
+		return $this->get('MSG_token');
81
+	}
82
+
83
+
84
+	/**
85
+	 * Sets MSG_token
86
+	 *
87
+	 * @param int $MSG_token
88
+	 */
89
+	public function set_MSG_token($MSG_token)
90
+	{
91
+		$this->set('MSG_token', $MSG_token);
92
+	}
93
+
94
+
95
+	/**
96
+	 * Gets GRP_ID
97
+	 *
98
+	 * @return int
99
+	 */
100
+	public function GRP_ID()
101
+	{
102
+		return $this->get('GRP_ID');
103
+	}
104
+
105
+
106
+	/**
107
+	 * Sets GRP_ID
108
+	 *
109
+	 * @param int $GRP_ID
110
+	 */
111
+	public function set_GRP_ID($GRP_ID)
112
+	{
113
+		$this->set('GRP_ID', $GRP_ID);
114
+	}
115
+
116
+
117
+	/**
118
+	 * Gets TXN_ID
119
+	 *
120
+	 * @return int
121
+	 */
122
+	public function TXN_ID()
123
+	{
124
+		return $this->get('TXN_ID');
125
+	}
126
+
127
+
128
+	/**
129
+	 * Sets TXN_ID
130
+	 *
131
+	 * @param int $TXN_ID
132
+	 */
133
+	public function set_TXN_ID($TXN_ID)
134
+	{
135
+		$this->set('TXN_ID', $TXN_ID);
136
+	}
137
+
138
+
139
+	/**
140
+	 * Gets messenger
141
+	 *
142
+	 * @return string
143
+	 */
144
+	public function messenger()
145
+	{
146
+		return $this->get('MSG_messenger');
147
+	}
148
+
149
+
150
+	/**
151
+	 * Sets messenger
152
+	 *
153
+	 * @param string $messenger
154
+	 */
155
+	public function set_messenger($messenger)
156
+	{
157
+		$this->set('MSG_messenger', $messenger);
158
+	}
159
+
160
+
161
+	/**
162
+	 * Returns corresponding messenger object for the set messenger on this message
163
+	 *
164
+	 * @return EE_messenger | null
165
+	 */
166
+	public function messenger_object()
167
+	{
168
+		return $this->_messenger;
169
+	}
170
+
171
+
172
+	/**
173
+	 * Sets messenger
174
+	 *
175
+	 * @param EE_messenger $messenger
176
+	 */
177
+	public function set_messenger_object(EE_messenger $messenger)
178
+	{
179
+		$this->_messenger = $messenger;
180
+	}
181
+
182
+
183
+	/**
184
+	 * validates messenger
185
+	 *
186
+	 * @param bool $throw_exceptions
187
+	 * @return bool
188
+	 * @throws \EE_Error
189
+	 */
190
+	public function valid_messenger($throw_exceptions = false)
191
+	{
192
+		if ($this->_messenger instanceof EE_messenger) {
193
+			return true;
194
+		}
195
+		if ($throw_exceptions) {
196
+			throw new EE_Error(
197
+				sprintf(
198
+					__(
199
+						'The "%1$s" messenger set for this message is missing or invalid. Please double-check the spelling and verify that the correct files exist.',
200
+						'event_espresso'
201
+					),
202
+					$this->messenger()
203
+				)
204
+			);
205
+		}
206
+		return false;
207
+	}
208
+
209
+
210
+	/**
211
+	 * This returns the set localized label for the messenger on this message.
212
+	 * Note, if unable to retrieve the EE_messenger object then will just return the messenger slug saved
213
+	 * with this message.
214
+	 *
215
+	 * @param   bool $plural whether to return the plural label or not.
216
+	 * @return string
217
+	 */
218
+	public function messenger_label($plural = false)
219
+	{
220
+		$label_type = $plural ? 'plural' : 'singular';
221
+		$messenger = $this->messenger_object();
222
+		return $messenger instanceof EE_messenger ? $messenger->label[ $label_type ] : $this->messenger();
223
+	}
224
+
225
+
226
+	/**
227
+	 * Gets message_type
228
+	 *
229
+	 * @return string
230
+	 */
231
+	public function message_type()
232
+	{
233
+		return $this->get('MSG_message_type');
234
+	}
235
+
236
+
237
+	/**
238
+	 * Sets message_type
239
+	 *
240
+	 * @param string $message_type
241
+	 */
242
+	public function set_message_type($message_type)
243
+	{
244
+		$this->set('MSG_message_type', $message_type);
245
+	}
246
+
247
+
248
+	/**
249
+	 * Returns the message type object for the set message type on this message
250
+	 *
251
+	 * @return EE_message_type | null
252
+	 */
253
+	public function message_type_object()
254
+	{
255
+		return $this->_message_type;
256
+	}
257
+
258
+
259
+	/**
260
+	 * Sets message_type
261
+	 *
262
+	 * @param EE_message_type $message_type
263
+	 * @param bool            $set_priority   This indicates whether to set the priority to whatever the priority is on
264
+	 *                                        the message type or not.
265
+	 */
266
+	public function set_message_type_object(EE_message_type $message_type, $set_priority = false)
267
+	{
268
+		$this->_message_type = $message_type;
269
+		if ($set_priority) {
270
+			$this->set_priority($this->_message_type->get_priority());
271
+		}
272
+	}
273
+
274
+
275
+	/**
276
+	 * validates message_type
277
+	 *
278
+	 * @param bool $throw_exceptions
279
+	 * @return bool
280
+	 * @throws \EE_Error
281
+	 */
282
+	public function valid_message_type($throw_exceptions = false)
283
+	{
284
+		if ($this->_message_type instanceof EE_message_type) {
285
+			return true;
286
+		}
287
+		if ($throw_exceptions) {
288
+			throw new EE_Error(
289
+				sprintf(
290
+					__(
291
+						'The %1$s message type set for this message is missing or invalid. Please double-check the spelling and verify that the correct files exist.',
292
+						'event_espresso'
293
+					),
294
+					$this->message_type()
295
+				)
296
+			);
297
+		}
298
+		return false;
299
+	}
300
+
301
+
302
+	/**
303
+	 * validates messenger and message_type (that they are valid EE_messenger and EE_message_type objects).
304
+	 *
305
+	 * @param bool $throw_exceptions
306
+	 * @return bool
307
+	 * @throws \EE_Error
308
+	 */
309
+	public function is_valid($throw_exceptions = false)
310
+	{
311
+		if ($this->valid_messenger($throw_exceptions) && $this->valid_message_type($throw_exceptions)) {
312
+			return true;
313
+		}
314
+		return false;
315
+	}
316
+
317
+
318
+	/**
319
+	 * This validates whether the internal messenger and message type objects are valid for sending.
320
+	 * Three checks are done:
321
+	 * 1. There is a valid messenger object.
322
+	 * 2. There is a valid message type object.
323
+	 * 3. The message type object is active for the messenger.
324
+	 *
325
+	 * @throws EE_Error  But only if $throw_exceptions is set to true.
326
+	 * @param bool $throw_exceptions
327
+	 * @return bool
328
+	 */
329
+	public function is_valid_for_sending_or_generation($throw_exceptions = false)
330
+	{
331
+		$valid = false;
332
+		if ($this->is_valid($throw_exceptions)) {
333
+			/** @var EE_Message_Resource_Manager $message_resource_manager */
334
+			$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
335
+			$valid = $message_resource_manager->is_message_type_active_for_messenger(
336
+				$this->messenger(),
337
+				$this->message_type()
338
+			);
339
+			if (! $valid && $throw_exceptions) {
340
+				throw new EE_Error(
341
+					sprintf(
342
+						__(
343
+							'The %1$s message type is not a valid message type for the %2$s messenger so it will not be sent.',
344
+							'event_espresso'
345
+						),
346
+						$this->message_type(),
347
+						$this->messenger()
348
+					)
349
+				);
350
+			}
351
+		}
352
+		return $valid;
353
+	}
354
+
355
+
356
+	/**
357
+	 * This returns the set localized label for the message type on this message.
358
+	 * Note, if unable to retrieve the EE_message_type object then will just return the message type slug saved
359
+	 * with this message.
360
+	 *
361
+	 * @param   bool $plural whether to return the plural label or not.
362
+	 * @return string
363
+	 */
364
+	public function message_type_label($plural = false)
365
+	{
366
+		$label_type = $plural ? 'plural' : 'singular';
367
+		$message_type = $this->message_type_object();
368
+		return $message_type instanceof EE_message_type
369
+			? $message_type->label[ $label_type ]
370
+			: str_replace(
371
+				'_',
372
+				' ',
373
+				$this->message_type()
374
+			);
375
+	}
376
+
377
+
378
+	/**
379
+	 * Gets context
380
+	 *
381
+	 * @return string
382
+	 */
383
+	public function context()
384
+	{
385
+		return $this->get('MSG_context');
386
+	}
387
+
388
+
389
+	/**
390
+	 * This returns the corresponding localized label for the given context slug, if possible from installed message
391
+	 * types. Otherwise, this will just return the set context slug on this object.
392
+	 *
393
+	 * @return string
394
+	 */
395
+	public function context_label()
396
+	{
397
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
398
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
399
+		$contexts = $message_resource_manager->get_all_contexts();
400
+		return isset($contexts[ $this->context() ]) ? $contexts[ $this->context() ] : $this->context();
401
+	}
402
+
403
+
404
+	/**
405
+	 * Sets context
406
+	 *
407
+	 * @param string $context
408
+	 */
409
+	public function set_context($context)
410
+	{
411
+		$this->set('MSG_context', $context);
412
+	}
413
+
414
+
415
+	/**
416
+	 * Gets recipient_ID
417
+	 *
418
+	 * @return int
419
+	 */
420
+	public function recipient_ID()
421
+	{
422
+		return $this->get('MSG_recipient_ID');
423
+	}
424
+
425
+
426
+	/**
427
+	 * Sets recipient_ID
428
+	 *
429
+	 * @param string $recipient_ID
430
+	 */
431
+	public function set_recipient_ID($recipient_ID)
432
+	{
433
+		$this->set('MSG_recipient_ID', $recipient_ID);
434
+	}
435
+
436
+
437
+	/**
438
+	 * Gets recipient_type
439
+	 *
440
+	 * @return string
441
+	 */
442
+	public function recipient_type()
443
+	{
444
+		return $this->get('MSG_recipient_type');
445
+	}
446
+
447
+
448
+	/**
449
+	 * Return the related object matching the recipient type and ID.
450
+	 *
451
+	 * @return EE_Base_Class | null
452
+	 */
453
+	public function recipient_object()
454
+	{
455
+		if (! $this->recipient_type() || ! $this->recipient_ID()) {
456
+			return null;
457
+		}
458
+
459
+		return $this->get_first_related($this->recipient_type());
460
+	}
461
+
462
+
463
+	/**
464
+	 * Sets recipient_type
465
+	 *
466
+	 * @param string $recipient_type
467
+	 */
468
+	public function set_recipient_type($recipient_type)
469
+	{
470
+		$this->set('MSG_recipient_type', $recipient_type);
471
+	}
472
+
473
+
474
+	/**
475
+	 * Gets content
476
+	 *
477
+	 * @return string
478
+	 */
479
+	public function content()
480
+	{
481
+		return $this->get('MSG_content');
482
+	}
483
+
484
+
485
+	/**
486
+	 * Sets content
487
+	 *
488
+	 * @param string $content
489
+	 */
490
+	public function set_content($content)
491
+	{
492
+		$this->set('MSG_content', $content);
493
+	}
494
+
495
+
496
+	/**
497
+	 * Gets subject
498
+	 *
499
+	 * @return string
500
+	 */
501
+	public function subject()
502
+	{
503
+		return $this->get('MSG_subject');
504
+	}
505
+
506
+
507
+	/**
508
+	 * Sets subject
509
+	 *
510
+	 * @param string $subject
511
+	 */
512
+	public function set_subject($subject)
513
+	{
514
+		$this->set('MSG_subject', $subject);
515
+	}
516
+
517
+
518
+	/**
519
+	 * Gets to
520
+	 *
521
+	 * @return string
522
+	 */
523
+	public function to()
524
+	{
525
+		$to = $this->get('MSG_to');
526
+		return empty($to) ? __('No recipient', 'event_espresso') : $to;
527
+	}
528
+
529
+
530
+	/**
531
+	 * Sets to
532
+	 *
533
+	 * @param string $to
534
+	 */
535
+	public function set_to($to)
536
+	{
537
+		$this->set('MSG_to', $to);
538
+	}
539
+
540
+
541
+	/**
542
+	 * Gets from
543
+	 *
544
+	 * @return string
545
+	 */
546
+	public function from()
547
+	{
548
+		return $this->get('MSG_from');
549
+	}
550
+
551
+
552
+	/**
553
+	 * Sets from
554
+	 *
555
+	 * @param string $from
556
+	 */
557
+	public function set_from($from)
558
+	{
559
+		$this->set('MSG_from', $from);
560
+	}
561
+
562
+
563
+	/**
564
+	 * Gets priority
565
+	 *
566
+	 * @return int
567
+	 */
568
+	public function priority()
569
+	{
570
+		return $this->get('MSG_priority');
571
+	}
572
+
573
+
574
+	/**
575
+	 * Sets priority
576
+	 * Note.  Send Now Messengers always override any priority that may be set on a Message.  So
577
+	 * this method calls the send_now method to verify that.
578
+	 *
579
+	 * @param int $priority
580
+	 */
581
+	public function set_priority($priority)
582
+	{
583
+		$priority = $this->send_now() ? EEM_Message::priority_high : $priority;
584
+		parent::set('MSG_priority', $priority);
585
+	}
586
+
587
+
588
+	/**
589
+	 * Overrides parent::set method so we can capture any sets for priority.
590
+	 *
591
+	 * @see parent::set() for phpdocs
592
+	 * @param string $field_name
593
+	 * @param mixed  $field_value
594
+	 * @param bool   $use_default
595
+	 * @throws EE_Error
596
+	 */
597
+	public function set($field_name, $field_value, $use_default = false)
598
+	{
599
+		if ($field_name === 'MSG_priority') {
600
+			$this->set_priority($field_value);
601
+		}
602
+		parent::set($field_name, $field_value, $use_default);
603
+	}
604
+
605
+
606
+	/**
607
+	 * @return bool
608
+	 * @throws \EE_Error
609
+	 */
610
+	public function send_now()
611
+	{
612
+		$send_now = $this->valid_messenger() && $this->messenger_object()->send_now() ? EEM_Message::priority_high
613
+			: $this->priority();
614
+		return $send_now === EEM_Message::priority_high ? true : false;
615
+	}
616
+
617
+
618
+	/**
619
+	 * Gets STS_ID
620
+	 *
621
+	 * @return string
622
+	 */
623
+	public function STS_ID()
624
+	{
625
+		return $this->get('STS_ID');
626
+	}
627
+
628
+
629
+	/**
630
+	 * Sets STS_ID
631
+	 *
632
+	 * @param string $STS_ID
633
+	 */
634
+	public function set_STS_ID($STS_ID)
635
+	{
636
+		$this->set('STS_ID', $STS_ID);
637
+	}
638
+
639
+
640
+	/**
641
+	 * Gets created
642
+	 *
643
+	 * @return string
644
+	 */
645
+	public function created()
646
+	{
647
+		return $this->get('MSG_created');
648
+	}
649
+
650
+
651
+	/**
652
+	 * Sets created
653
+	 *
654
+	 * @param string $created
655
+	 */
656
+	public function set_created($created)
657
+	{
658
+		$this->set('MSG_created', $created);
659
+	}
660
+
661
+
662
+	/**
663
+	 * Gets modified
664
+	 *
665
+	 * @return string
666
+	 */
667
+	public function modified()
668
+	{
669
+		return $this->get('MSG_modified');
670
+	}
671
+
672
+
673
+	/**
674
+	 * Sets modified
675
+	 *
676
+	 * @param string $modified
677
+	 */
678
+	public function set_modified($modified)
679
+	{
680
+		$this->set('MSG_modified', $modified);
681
+	}
682
+
683
+
684
+	/**
685
+	 * Sets generation data for this message.
686
+	 *
687
+	 * @param mixed $data
688
+	 */
689
+	public function set_generation_data($data)
690
+	{
691
+		$this->set_field_or_extra_meta('MSG_generation_data', $data);
692
+	}
693
+
694
+
695
+	/**
696
+	 * Returns any set generation data for this message.
697
+	 *
698
+	 * @return mixed|null
699
+	 */
700
+	public function get_generation_data()
701
+	{
702
+		return $this->get_field_or_extra_meta('MSG_generation_data');
703
+	}
704
+
705
+
706
+	/**
707
+	 * Gets any error message.
708
+	 *
709
+	 * @return mixed|null
710
+	 */
711
+	public function error_message()
712
+	{
713
+		return $this->get_field_or_extra_meta('MSG_error');
714
+	}
715
+
716
+
717
+	/**
718
+	 * Sets an error message.
719
+	 *
720
+	 * @param $message
721
+	 * @return bool|int
722
+	 */
723
+	public function set_error_message($message)
724
+	{
725
+		return $this->set_field_or_extra_meta('MSG_error', $message);
726
+	}
727
+
728
+
729
+	/**
730
+	 * This retrieves the associated template pack with this message.
731
+	 *
732
+	 * @return EE_Messages_Template_Pack | null
733
+	 */
734
+	public function get_template_pack()
735
+	{
736
+		/**
737
+		 * This is deprecated functionality that will be removed eventually but included here now for backward compat.
738
+		 */
739
+		if (! empty($this->template_pack)) {
740
+			return $this->template_pack;
741
+		}
742
+		/** @type EE_Message_Template_Group $grp */
743
+		$grp = $this->get_first_related('Message_Template_Group');
744
+		// if no group then let's try to get the first related group by internal messenger and message type (will use global grp).
745
+		if (! $grp instanceof EE_Message_Template_Group) {
746
+			$grp = EEM_Message_Template_Group::instance()->get_one(
747
+				array(
748
+					array(
749
+						'MTP_messenger'    => $this->messenger(),
750
+						'MTP_message_type' => $this->message_type(),
751
+						'MTP_is_global'    => true,
752
+					),
753
+				)
754
+			);
755
+		}
756
+
757
+		return $grp instanceof EE_Message_Template_Group ? $grp->get_template_pack() : null;
758
+	}
759
+
760
+
761
+	/**
762
+	 * Retrieves the variation used for generating this message.
763
+	 *
764
+	 * @return string
765
+	 */
766
+	public function get_template_pack_variation()
767
+	{
768
+		/**
769
+		 * This is deprecated functionality that will be removed eventually but included here now for backward compat.
770
+		 */
771
+		if (! empty($this->template_variation)) {
772
+			return $this->template_variation;
773
+		}
774
+
775
+		/** @type EE_Message_Template_Group $grp */
776
+		$grp = $this->get_first_related('Message_Template_Group');
777
+
778
+		// if no group then let's try to get the first related group by internal messenger and message type (will use global grp).
779
+		if (! $grp instanceof EE_Message_Template_Group) {
780
+			$grp = EEM_Message_Template_Group::instance()->get_one(
781
+				array(
782
+					array(
783
+						'MTP_messenger'    => $this->messenger(),
784
+						'MTP_message_type' => $this->message_type(),
785
+						'MTP_is_global'    => true,
786
+					),
787
+				)
788
+			);
789
+		}
790
+
791
+		return $grp instanceof EE_Message_Template_Group ? $grp->get_template_pack_variation() : '';
792
+	}
793
+
794
+	/**
795
+	 * Return the link to the admin details for the object.
796
+	 *
797
+	 * @return string
798
+	 */
799
+	public function get_admin_details_link()
800
+	{
801
+		EE_Registry::instance()->load_helper('URL');
802
+		EE_Registry::instance()->load_helper('MSG_Template');
803
+		switch ($this->STS_ID()) {
804
+			case EEM_Message::status_failed:
805
+			case EEM_Message::status_debug_only:
806
+				return EEH_MSG_Template::generate_error_display_trigger($this);
807
+				break;
808
+
809
+			case EEM_Message::status_sent:
810
+				return EEH_MSG_Template::generate_browser_trigger($this);
811
+				break;
812
+
813
+			default:
814
+				return '';
815
+		}
816
+	}
817
+
818
+	/**
819
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
820
+	 *
821
+	 * @return string
822
+	 */
823
+	public function get_admin_edit_link()
824
+	{
825
+		return $this->get_admin_details_link();
826
+	}
827
+
828
+	/**
829
+	 * Returns the link to a settings page for the object.
830
+	 *
831
+	 * @return string
832
+	 */
833
+	public function get_admin_settings_link()
834
+	{
835
+		EE_Registry::instance()->load_helper('URL');
836
+		return EEH_URL::add_query_args_and_nonce(
837
+			array(
838
+				'page'   => 'espresso_messages',
839
+				'action' => 'settings',
840
+			),
841
+			admin_url('admin.php')
842
+		);
843
+	}
844
+
845
+	/**
846
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
847
+	 *
848
+	 * @return string
849
+	 */
850
+	public function get_admin_overview_link()
851
+	{
852
+		EE_Registry::instance()->load_helper('URL');
853
+		return EEH_URL::add_query_args_and_nonce(
854
+			array(
855
+				'page'   => 'espresso_messages',
856
+				'action' => 'default',
857
+			),
858
+			admin_url('admin.php')
859
+		);
860
+	}
861
+
862
+
863
+	/**
864
+	 * This sets the EEM_Message::status_messenger_executing class on the message and the appropriate error message for
865
+	 * it.
866
+	 * Note this also SAVES the current message object to the db because it adds an error message to accompany the
867
+	 * status.
868
+	 *
869
+	 */
870
+	public function set_messenger_is_executing()
871
+	{
872
+		$this->set_STS_ID(EEM_Message::status_messenger_executing);
873
+		$this->set_error_message(
874
+			esc_html__(
875
+				'A message with this status indicates that there was a problem that occurred while the message was being
876 876
                 processed by the messenger.  It is still possible that the message was sent successfully, but at some
877 877
                 point during the processing there was a failure.  This usually is indicative of a timeout issue with PHP 
878 878
                 or memory limits being reached.  If you see this repeatedly you may want to consider upgrading the memory 
879 879
                 available to PHP on your server.',
880
-                'event_espresso'
881
-            )
882
-        );
883
-    }
880
+				'event_espresso'
881
+			)
882
+		);
883
+	}
884 884
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -51,7 +51,7 @@  discard block
 block discarded – undo
51 51
     {
52 52
         $has_object = parent::_check_for_object($props_n_values, __CLASS__);
53 53
         // if object doesn't exist, let's generate a unique token on instantiation so that its available even before saving to db.
54
-        if (! $has_object) {
54
+        if ( ! $has_object) {
55 55
             EE_Registry::instance()->load_helper('URL');
56 56
             $props_n_values['MSG_token'] = EEH_URL::generate_unique_token();
57 57
         }
@@ -219,7 +219,7 @@  discard block
 block discarded – undo
219 219
     {
220 220
         $label_type = $plural ? 'plural' : 'singular';
221 221
         $messenger = $this->messenger_object();
222
-        return $messenger instanceof EE_messenger ? $messenger->label[ $label_type ] : $this->messenger();
222
+        return $messenger instanceof EE_messenger ? $messenger->label[$label_type] : $this->messenger();
223 223
     }
224 224
 
225 225
 
@@ -336,7 +336,7 @@  discard block
 block discarded – undo
336 336
                 $this->messenger(),
337 337
                 $this->message_type()
338 338
             );
339
-            if (! $valid && $throw_exceptions) {
339
+            if ( ! $valid && $throw_exceptions) {
340 340
                 throw new EE_Error(
341 341
                     sprintf(
342 342
                         __(
@@ -366,7 +366,7 @@  discard block
 block discarded – undo
366 366
         $label_type = $plural ? 'plural' : 'singular';
367 367
         $message_type = $this->message_type_object();
368 368
         return $message_type instanceof EE_message_type
369
-            ? $message_type->label[ $label_type ]
369
+            ? $message_type->label[$label_type]
370 370
             : str_replace(
371 371
                 '_',
372 372
                 ' ',
@@ -397,7 +397,7 @@  discard block
 block discarded – undo
397 397
         /** @type EE_Message_Resource_Manager $message_resource_manager */
398 398
         $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
399 399
         $contexts = $message_resource_manager->get_all_contexts();
400
-        return isset($contexts[ $this->context() ]) ? $contexts[ $this->context() ] : $this->context();
400
+        return isset($contexts[$this->context()]) ? $contexts[$this->context()] : $this->context();
401 401
     }
402 402
 
403 403
 
@@ -452,7 +452,7 @@  discard block
 block discarded – undo
452 452
      */
453 453
     public function recipient_object()
454 454
     {
455
-        if (! $this->recipient_type() || ! $this->recipient_ID()) {
455
+        if ( ! $this->recipient_type() || ! $this->recipient_ID()) {
456 456
             return null;
457 457
         }
458 458
 
@@ -736,13 +736,13 @@  discard block
 block discarded – undo
736 736
         /**
737 737
          * This is deprecated functionality that will be removed eventually but included here now for backward compat.
738 738
          */
739
-        if (! empty($this->template_pack)) {
739
+        if ( ! empty($this->template_pack)) {
740 740
             return $this->template_pack;
741 741
         }
742 742
         /** @type EE_Message_Template_Group $grp */
743 743
         $grp = $this->get_first_related('Message_Template_Group');
744 744
         // if no group then let's try to get the first related group by internal messenger and message type (will use global grp).
745
-        if (! $grp instanceof EE_Message_Template_Group) {
745
+        if ( ! $grp instanceof EE_Message_Template_Group) {
746 746
             $grp = EEM_Message_Template_Group::instance()->get_one(
747 747
                 array(
748 748
                     array(
@@ -768,7 +768,7 @@  discard block
 block discarded – undo
768 768
         /**
769 769
          * This is deprecated functionality that will be removed eventually but included here now for backward compat.
770 770
          */
771
-        if (! empty($this->template_variation)) {
771
+        if ( ! empty($this->template_variation)) {
772 772
             return $this->template_variation;
773 773
         }
774 774
 
@@ -776,7 +776,7 @@  discard block
 block discarded – undo
776 776
         $grp = $this->get_first_related('Message_Template_Group');
777 777
 
778 778
         // if no group then let's try to get the first related group by internal messenger and message type (will use global grp).
779
-        if (! $grp instanceof EE_Message_Template_Group) {
779
+        if ( ! $grp instanceof EE_Message_Template_Group) {
780 780
             $grp = EEM_Message_Template_Group::instance()->get_one(
781 781
                 array(
782 782
                     array(
Please login to merge, or discard this patch.
core/db_classes/EE_CSV.class.php 2 patches
Indentation   +669 added lines, -669 removed lines patch added patch discarded remove patch
@@ -16,673 +16,673 @@
 block discarded – undo
16 16
 class EE_CSV
17 17
 {
18 18
 
19
-    // instance of the EE_CSV object
20
-    private static $_instance = null;
21
-
22
-
23
-    // multidimensional array to store update & error messages
24
-    // var $_notices = array( 'updates' => array(), 'errors' => array() );
25
-
26
-
27
-    private $_primary_keys;
28
-
29
-    /**
30
-     *
31
-     * @var EE_Registry
32
-     */
33
-    private $EE;
34
-    /**
35
-     * string used for 1st cell in exports, which indicates that the following 2 rows will be metadata keys and values
36
-     */
37
-    const metadata_header = 'Event Espresso Export Meta Data';
38
-
39
-    /**
40
-     *        private constructor to prevent direct creation
41
-     *
42
-     * @Constructor
43
-     * @access private
44
-     * @return void
45
-     */
46
-    private function __construct()
47
-    {
48
-        global $wpdb;
49
-
50
-        $this->_primary_keys = array(
51
-            $wpdb->prefix . 'esp_answer'                  => array('ANS_ID'),
52
-            $wpdb->prefix . 'esp_attendee'                => array('ATT_ID'),
53
-            $wpdb->prefix . 'esp_datetime'                => array('DTT_ID'),
54
-            $wpdb->prefix . 'esp_event_question_group'    => array('EQG_ID'),
55
-            $wpdb->prefix . 'esp_message_template'        => array('MTP_ID'),
56
-            $wpdb->prefix . 'esp_payment'                 => array('PAY_ID'),
57
-            $wpdb->prefix . 'esp_price'                   => array('PRC_ID'),
58
-            $wpdb->prefix . 'esp_price_type'              => array('PRT_ID'),
59
-            $wpdb->prefix . 'esp_question'                => array('QST_ID'),
60
-            $wpdb->prefix . 'esp_question_group'          => array('QSG_ID'),
61
-            $wpdb->prefix . 'esp_question_group_question' => array('QGQ_ID'),
62
-            $wpdb->prefix . 'esp_question_option'         => array('QSO_ID'),
63
-            $wpdb->prefix . 'esp_registration'            => array('REG_ID'),
64
-            $wpdb->prefix . 'esp_status'                  => array('STS_ID'),
65
-            $wpdb->prefix . 'esp_transaction'             => array('TXN_ID'),
66
-            $wpdb->prefix . 'esp_transaction'             => array('TXN_ID'),
67
-            $wpdb->prefix . 'events_detail'               => array('id'),
68
-            $wpdb->prefix . 'events_category_detail'      => array('id'),
69
-            $wpdb->prefix . 'events_category_rel'         => array('id'),
70
-            $wpdb->prefix . 'events_venue'                => array('id'),
71
-            $wpdb->prefix . 'events_venue_rel'            => array('emeta_id'),
72
-            $wpdb->prefix . 'events_locale'               => array('id'),
73
-            $wpdb->prefix . 'events_locale_rel'           => array('id'),
74
-            $wpdb->prefix . 'events_personnel'            => array('id'),
75
-            $wpdb->prefix . 'events_personnel_rel'        => array('id'),
76
-        );
77
-    }
78
-
79
-
80
-    /**
81
-     *        @ singleton method used to instantiate class object
82
-     *        @ access public
83
-     *
84
-     * @return EE_CSV
85
-     */
86
-    public static function instance()
87
-    {
88
-        // check if class object is instantiated
89
-        if (self::$_instance === null or ! is_object(self::$_instance) or ! (self::$_instance instanceof EE_CSV)) {
90
-            self::$_instance = new self();
91
-        }
92
-        return self::$_instance;
93
-    }
94
-
95
-    /**
96
-     * Opens a unicode or utf file (normal file_get_contents has difficulty readin ga unicode file. @see
97
-     * http://stackoverflow.com/questions/15092764/how-to-read-unicode-text-file-in-php
98
-     *
99
-     * @param string $file_path
100
-     * @return string
101
-     * @throws EE_Error
102
-     */
103
-    private function read_unicode_file($file_path)
104
-    {
105
-        $fc = "";
106
-        $fh = fopen($file_path, "rb");
107
-        if (! $fh) {
108
-            throw new EE_Error(sprintf(__("Cannot open file for read: %s<br>\n", 'event_espresso'), $file_path));
109
-        }
110
-        $flen = filesize($file_path);
111
-        $bc = fread($fh, $flen);
112
-        for ($i = 0; $i < $flen; $i++) {
113
-            $c = substr($bc, $i, 1);
114
-            if ((ord($c) != 0) && (ord($c) != 13)) {
115
-                $fc = $fc . $c;
116
-            }
117
-        }
118
-        if ((ord(substr($fc, 0, 1)) == 255) && (ord(substr($fc, 1, 1)) == 254)) {
119
-            $fc = substr($fc, 2);
120
-        }
121
-        return ($fc);
122
-    }
123
-
124
-
125
-    /**
126
-     * Generic CSV-functionality to turn an entire CSV file into a single array that's
127
-     * NOT in a specific format to EE. It's just a 2-level array, with top-level arrays
128
-     * representing each row in the CSV file, and the second-level arrays being each column in that row
129
-     *
130
-     * @param string $path_to_file
131
-     * @return array of arrays. Top-level array has rows, second-level array has each item
132
-     */
133
-    public function import_csv_to_multi_dimensional_array($path_to_file)
134
-    {
135
-        // needed to deal with Mac line endings
136
-        ini_set('auto_detect_line_endings', true);
137
-
138
-        // because fgetcsv does not correctly deal with backslashed quotes such as \"
139
-        // we'll read the file into a string
140
-        $file_contents = $this->read_unicode_file($path_to_file);
141
-        // replace backslashed quotes with CSV enclosures
142
-        $file_contents = str_replace('\\"', '"""', $file_contents);
143
-        // HEY YOU! PUT THAT FILE BACK!!!
144
-        file_put_contents($path_to_file, $file_contents);
145
-
146
-        if (($file_handle = fopen($path_to_file, "r")) !== false) {
147
-            # Set the parent multidimensional array key to 0.
148
-            $nn = 0;
149
-            $csvarray = array();
150
-
151
-            // in PHP 5.3 fgetcsv accepts a 5th parameter, but the pre 5.3 versions of fgetcsv choke if passed more than 4 - is that crazy or what?
152
-            if (version_compare(PHP_VERSION, '5.3.0') < 0) {
153
-                //  PHP 5.2- version
154
-                // loop through each row of the file
155
-                while (($data = fgetcsv($file_handle, 0, ',', '"')) !== false) {
156
-                    $csvarray[] = $data;
157
-                }
158
-            } else {
159
-                // loop through each row of the file
160
-                while (($data = fgetcsv($file_handle, 0, ',', '"', '\\')) !== false) {
161
-                    $csvarray[] = $data;
162
-                }
163
-            }
164
-            # Close the File.
165
-            fclose($file_handle);
166
-            return $csvarray;
167
-        } else {
168
-            EE_Error::add_error(
169
-                sprintf(__("An error occurred - the file: %s could not opened.", "event_espresso"), $path_to_file),
170
-                __FILE__,
171
-                __FUNCTION__,
172
-                __LINE__
173
-            );
174
-            return false;
175
-        }
176
-    }
177
-
178
-
179
-    /**
180
-     * @Import contents of csv file and store values in an array to be manipulated by other functions
181
-     * @access public
182
-     * @param string  $path_to_file         - the csv file to be imported including the path to it's location.
183
-     *                                      If $model_name is provided, assumes that each row in the CSV represents a
184
-     *                                      model object for that model If $model_name ISN'T provided, assumes that
185
-     *                                      before model object data, there is a row where the first entry is simply
186
-     *                                      'MODEL', and next entry is the model's name, (untranslated) like Event, and
187
-     *                                      then maybe a row of headers, and then the model data. Eg.
188
-     *                                      '<br>MODEL,Event,<br>EVT_ID,EVT_name,...<br>1,Monkey
189
-     *                                      Party,...<br>2,Llamarama,...<br>MODEL,Venue,<br>VNU_ID,VNU_name<br>1,The
190
-     *                                      Forest
191
-     * @param string  $model_name           model name if we know what model we're importing
192
-     * @param boolean $first_row_is_headers - whether the first row of data is headers or not - TRUE = headers, FALSE =
193
-     *                                      data
194
-     * @return mixed - array on success - multi dimensional with headers as keys (if headers exist) OR string on fail -
195
-     *               error message like the following array('Event'=>array( array('EVT_ID'=>1,'EVT_name'=>'bob
196
-     *               party',...), array('EVT_ID'=>2,'EVT_name'=>'llamarama',...),
197
-     *                                      ...
198
-     *                                      )
199
-     *                                      'Venue'=>array(
200
-     *                                      array('VNU_ID'=>1,'VNU_name'=>'the shack',...),
201
-     *                                      array('VNU_ID'=>2,'VNU_name'=>'tree house',...),
202
-     *                                      ...
203
-     *                                      )
204
-     *                                      ...
205
-     *                                      )
206
-     */
207
-    public function import_csv_to_model_data_array($path_to_file, $model_name = false, $first_row_is_headers = true)
208
-    {
209
-        $multi_dimensional_array = $this->import_csv_to_multi_dimensional_array($path_to_file);
210
-        if (! $multi_dimensional_array) {
211
-            return false;
212
-        }
213
-        // gotta start somewhere
214
-        $row = 1;
215
-        // array to store csv data in
216
-        $ee_formatted_data = array();
217
-        // array to store headers (column names)
218
-        $headers = array();
219
-        foreach ($multi_dimensional_array as $data) {
220
-            // if first cell is MODEL, then second cell is the MODEL name
221
-            if ($data[0] == 'MODEL') {
222
-                $model_name = $data[1];
223
-                // don't bother looking for model data in this row. The rest of this
224
-                // row should be blank
225
-                // AND pretend this is the first row again
226
-                $row = 1;
227
-                // reset headers
228
-                $headers = array();
229
-                continue;
230
-            }
231
-            if (strpos($data[0], EE_CSV::metadata_header) !== false) {
232
-                $model_name = EE_CSV::metadata_header;
233
-                // store like model data, we just won't try importing it etc.
234
-                $row = 1;
235
-                continue;
236
-            }
237
-
238
-
239
-            // how many columns are there?
240
-            $columns = count($data);
241
-
242
-            $model_entry = array();
243
-            // loop through each column
244
-            for ($i = 0; $i < $columns; $i++) {
245
-                // replace csv_enclosures with backslashed quotes
246
-                $data[ $i ] = str_replace('"""', '\\"', $data[ $i ]);
247
-                // do we need to grab the column names?
248
-                if ($row === 1) {
249
-                    if ($first_row_is_headers) {
250
-                        // store the column names to use for keys
251
-                        $column_name = $data[ $i ];
252
-                        // check it's not blank... sometimes CSV editign programs adda bunch of empty columns onto the end...
253
-                        if (! $column_name) {
254
-                            continue;
255
-                        }
256
-                        $matches = array();
257
-                        if ($model_name == EE_CSV::metadata_header) {
258
-                            $headers[ $i ] = $column_name;
259
-                        } else {
260
-                            // now get the db table name from it (the part between square brackets)
261
-                            $success = preg_match('~(.*)\[(.*)\]~', $column_name, $matches);
262
-                            if (! $success) {
263
-                                EE_Error::add_error(
264
-                                    sprintf(
265
-                                        __(
266
-                                            "The column titled %s is invalid for importing. It must be be in the format of 'Nice Name[model_field_name]' in row %s",
267
-                                            "event_espresso"
268
-                                        ),
269
-                                        $column_name,
270
-                                        implode(",", $data)
271
-                                    ),
272
-                                    __FILE__,
273
-                                    __FUNCTION__,
274
-                                    __LINE__
275
-                                );
276
-                                return false;
277
-                            }
278
-                            $headers[ $i ] = $matches[2];
279
-                        }
280
-                    } else {
281
-                        // no column names means our final array will just use counters for keys
282
-                        $model_entry[ $headers[ $i ] ] = $data[ $i ];
283
-                        $headers[ $i ] = $i;
284
-                    }
285
-                    // and we need to store csv data
286
-                } else {
287
-                    // this column isn' ta header, store it if there is a header for it
288
-                    if (isset($headers[ $i ])) {
289
-                        $model_entry[ $headers[ $i ] ] = $data[ $i ];
290
-                    }
291
-                }
292
-            }
293
-            // save the row's data IF it's a non-header-row
294
-            if (! $first_row_is_headers || ($first_row_is_headers && $row > 1)) {
295
-                $ee_formatted_data[ $model_name ][] = $model_entry;
296
-            }
297
-            // advance to next row
298
-            $row++;
299
-        }
300
-
301
-        // delete the uploaded file
302
-        unlink($path_to_file);
303
-        // echo '<pre style="height:auto;border:2px solid lightblue;">' . print_r( $ee_formatted_data, TRUE ) . '</pre><br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>';
304
-        // die();
305
-
306
-        // it's good to give back
307
-        return $ee_formatted_data;
308
-    }
309
-
310
-
311
-    public function save_csv_to_db($csv_data_array, $model_name = false)
312
-    {
313
-        EE_Error::doing_it_wrong(
314
-            'save_csv_to_db',
315
-            __(
316
-                'Function moved to EE_Import and renamed to save_csv_data_array_to_db',
317
-                'event_espresso'
318
-            ),
319
-            '4.6.7'
320
-        );
321
-        return EE_Import::instance()->save_csv_data_array_to_db($csv_data_array, $model_name);
322
-    }
323
-
324
-    /**
325
-     * Sends HTTP headers to indicate that the browser should download a file,
326
-     * and starts writing the file to PHP's output. Returns the file handle so other functions can
327
-     * also write to it
328
-     *
329
-     * @param string $new_filename the name of the file that the user will download
330
-     * @return resource, like the results of fopen(), which can be used for fwrite, fputcsv2, etc.
331
-     */
332
-    public function begin_sending_csv($filename)
333
-    {
334
-        // grab file extension
335
-        $ext = substr(strrchr($filename, '.'), 1);
336
-        if ($ext == '.csv' or $ext == '.xls') {
337
-            str_replace($ext, '', $filename);
338
-        }
339
-        $filename .= '.csv';
340
-
341
-        // if somebody's been naughty and already started outputting stuff, trash it
342
-        // and start writing our stuff.
343
-        if (ob_get_length()) {
344
-            @ob_flush();
345
-            @flush();
346
-            @ob_end_flush();
347
-        }
348
-        @ob_start();
349
-        header("Pragma: public");
350
-        header("Expires: 0");
351
-        header("Pragma: no-cache");
352
-        header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
353
-        // header("Content-Type: application/force-download");
354
-        // header("Content-Type: application/octet-stream");
355
-        // header("Content-Type: application/download");
356
-        header('Content-disposition: attachment; filename=' . $filename);
357
-        header("Content-Type: text/csv; charset=utf-8");
358
-        do_action('AHEE__EE_CSV__begin_sending_csv__headers');
359
-        echo apply_filters(
360
-            'FHEE__EE_CSV__begin_sending_csv__start_writing',
361
-            "\xEF\xBB\xBF"
362
-        ); // makes excel open it as UTF-8. UTF-8 BOM, see http://stackoverflow.com/a/4440143/2773835
363
-        $fh = fopen('php://output', 'w');
364
-        return $fh;
365
-    }
366
-
367
-    /**
368
-     * Writes some meta data to the CSV as a bunch of columns. Initially we're only
369
-     * mentioning the version and timezone
370
-     *
371
-     * @param resource $filehandle
372
-     */
373
-    public function write_metadata_to_csv($filehandle)
374
-    {
375
-        $data_row = array(EE_CSV::metadata_header);// do NOT translate because this exact string is used when importing
376
-        $this->fputcsv2($filehandle, $data_row);
377
-        $meta_data = array(
378
-            0 => array(
379
-                'version'        => espresso_version(),
380
-                'timezone'       => EEH_DTT_Helper::get_timezone(),
381
-                'time_of_export' => current_time('mysql'),
382
-                'site_url'       => site_url(),
383
-            ),
384
-        );
385
-        $this->write_data_array_to_csv($filehandle, $meta_data);
386
-    }
387
-
388
-
389
-    /**
390
-     * Writes $data to the csv file open in $filehandle. uses the array indices of $data for column headers
391
-     *
392
-     * @param array   $data                 2D array, first numerically-indexed, and next-level-down preferably indexed
393
-     *                                      by string
394
-     * @param boolean $add_csv_column_names whether or not we should add the keys in the bottom-most array as a row for
395
-     *                                      headers in the CSV. Eg, if $data looked like
396
-     *                                      array(0=>array('EVT_ID'=>1,'EVT_name'=>'monkey'...), 1=>array(...),...))
397
-     *                                      then the first row we'd write to the CSV would be "EVT_ID,EVT_name,..."
398
-     * @return boolean if we successfully wrote to the CSV or not. If there's no $data, we consider that a success
399
-     *                 (because we wrote everything there was...nothing)
400
-     */
401
-    public function write_data_array_to_csv($filehandle, $data)
402
-    {
403
-
404
-
405
-        // determine if $data is actually a 2d array
406
-        if ($data && is_array($data) && is_array(EEH_Array::get_one_item_from_array($data))) {
407
-            // make sure top level is numerically indexed,
408
-
409
-            if (EEH_Array::is_associative_array($data)) {
410
-                throw new EE_Error(
411
-                    sprintf(
412
-                        __(
413
-                            "top-level array must be numerically indexed. Does these look like numbers to you? %s",
414
-                            "event_espresso"
415
-                        ),
416
-                        implode(",", array_keys($data))
417
-                    )
418
-                );
419
-            }
420
-            $item_in_top_level_array = EEH_Array::get_one_item_from_array($data);
421
-            // now, is the last item in the top-level array of $data an associative or numeric array?
422
-            if (EEH_Array::is_associative_array($item_in_top_level_array)) {
423
-                // its associative, so we want to output its keys as column headers
424
-                $keys = array_keys($item_in_top_level_array);
425
-                echo $this->fputcsv2($filehandle, $keys);
426
-            }
427
-            // start writing data
428
-            foreach ($data as $data_row) {
429
-                echo $this->fputcsv2($filehandle, $data_row);
430
-            }
431
-            return true;
432
-        } else {
433
-            // no data TO write... so we can assume that's a success
434
-            return true;
435
-        }
436
-        // //if 2nd level is indexed by strings, use those as csv column headers (ie, the first row)
437
-        //
438
-        //
439
-        // $no_table = TRUE;
440
-        //
441
-        // // loop through data and add each row to the file/stream as csv
442
-        // foreach ( $data as $model_name => $model_data ) {
443
-        // // test first row to see if it is data or a model name
444
-        // $model = EE_Registry::instance();->load_model($model_name);
445
-        // //if the model really exists,
446
-        // if ( $model ) {
447
-        //
448
-        // // we have a table name
449
-        // $no_table = FALSE;
450
-        //
451
-        // // put the tablename into an array cuz that's how fputcsv rolls
452
-        // $model_name_row = array( 'MODEL', $model_name );
453
-        //
454
-        // // add table name to csv output
455
-        // echo self::fputcsv2($filehandle, $model_name_row);
456
-        //
457
-        // // now get the rest of the data
458
-        // foreach ( $model_data as $row ) {
459
-        // // output the row
460
-        // echo self::fputcsv2($filehandle, $row);
461
-        // }
462
-        //
463
-        // }
464
-        //
465
-        // if ( $no_table ) {
466
-        // // no table so just put the data
467
-        // echo self::fputcsv2($filehandle, $model_data);
468
-        // }
469
-        //
470
-        // } // END OF foreach ( $data )
471
-    }
472
-
473
-    /**
474
-     * Should be called after begin_sending_csv(), and one or more write_data_array_to_csv()s.
475
-     * Calls exit to prevent polluting the CSV file with other junk
476
-     *
477
-     * @param resource $fh filehandle where we're writing the CSV to
478
-     */
479
-    public function end_sending_csv($fh)
480
-    {
481
-        fclose($fh);
482
-        exit(0);
483
-    }
484
-
485
-    /**
486
-     * Given an open file, writes all the model data to it in the format the importer expects.
487
-     * Usually preceded by begin_sending_csv($filename), and followed by end_sending_csv($filehandle).
488
-     *
489
-     * @param resource $filehandle
490
-     * @param array    $model_data_array is assumed to be a 3d array: 1st layer has keys of model names (eg 'Event'),
491
-     *                                   next layer is numerically indexed to represent each model object (eg, each
492
-     *                                   individual event), and the last layer has all the attributes o fthat model
493
-     *                                   object (eg, the event's id, name, etc)
494
-     * @return boolean success
495
-     */
496
-    public function write_model_data_to_csv($filehandle, $model_data_array)
497
-    {
498
-        $this->write_metadata_to_csv($filehandle);
499
-        foreach ($model_data_array as $model_name => $model_instance_arrays) {
500
-            // first: output a special row stating the model
501
-            echo $this->fputcsv2($filehandle, array('MODEL', $model_name));
502
-            // if we have items to put in the CSV, do it normally
503
-
504
-            if (! empty($model_instance_arrays)) {
505
-                $this->write_data_array_to_csv($filehandle, $model_instance_arrays);
506
-            } else {
507
-                // echo "no data to write... so just write the headers";
508
-                // so there's actually NO model objects for that model.
509
-                // probably still want to show the columns
510
-                $model = EE_Registry::instance()->load_model($model_name);
511
-                $column_names = array();
512
-                foreach ($model->field_settings() as $field) {
513
-                    $column_names[ $field->get_nicename() . "[" . $field->get_name() . "]" ] = null;
514
-                }
515
-                $this->write_data_array_to_csv($filehandle, array($column_names));
516
-            }
517
-        }
518
-    }
519
-
520
-    /**
521
-     * Writes the CSV file to the output buffer, with rows corresponding to $model_data_array,
522
-     * and dies (in order to avoid other plugins from messing up the csv output)
523
-     *
524
-     * @param string $filename         the filename you want to give the file
525
-     * @param array  $model_data_array 3d array, as described in EE_CSV::write_model_data_to_csv()
526
-     * @return bool | void writes CSV file to output and dies
527
-     */
528
-    public function export_multiple_model_data_to_csv($filename, $model_data_array)
529
-    {
530
-        $filehandle = $this->begin_sending_csv($filename);
531
-        $this->write_model_data_to_csv($filehandle, $model_data_array);
532
-        $this->end_sending_csv($filehandle);
533
-    }
534
-
535
-    /**
536
-     * @Export contents of an array to csv file
537
-     * @access public
538
-     * @param array  $data     - the array of data to be converted to csv and exported
539
-     * @param string $filename - name for newly created csv file
540
-     * @return TRUE on success, FALSE on fail
541
-     */
542
-    public function export_array_to_csv($data = false, $filename = false)
543
-    {
544
-
545
-        // no data file?? get outta here
546
-        if (! $data or ! is_array($data) or empty($data)) {
547
-            return false;
548
-        }
549
-
550
-        // no filename?? get outta here
551
-        if (! $filename) {
552
-            return false;
553
-        }
554
-
555
-
556
-        // somebody told me i might need this ???
557
-        global $wpdb;
558
-        $prefix = $wpdb->prefix;
559
-
560
-
561
-        $fh = $this->begin_sending_csv($filename);
562
-
563
-
564
-        $this->end_sending_csv($fh);
565
-    }
566
-
567
-
568
-    /**
569
-     * @Determine the maximum upload file size based on php.ini settings
570
-     * @access    public
571
-     * @param int $percent_of_max - desired percentage of the max upload_mb
572
-     * @return int KB
573
-     */
574
-    public function get_max_upload_size($percent_of_max = false)
575
-    {
576
-
577
-        $max_upload = (int) (ini_get('upload_max_filesize'));
578
-        $max_post = (int) (ini_get('post_max_size'));
579
-        $memory_limit = (int) (ini_get('memory_limit'));
580
-
581
-        // determine the smallest of the three values from above
582
-        $upload_mb = min($max_upload, $max_post, $memory_limit);
583
-
584
-        // convert MB to KB
585
-        $upload_mb = $upload_mb * 1024;
586
-
587
-        // don't want the full monty? then reduce the max uplaod size
588
-        if ($percent_of_max) {
589
-            // is percent_of_max like this -> 50 or like this -> 0.50 ?
590
-            if ($percent_of_max > 1) {
591
-                // chnages 50 to 0.50
592
-                $percent_of_max = $percent_of_max / 100;
593
-            }
594
-            // make upload_mb a percentage of the max upload_mb
595
-            $upload_mb = $upload_mb * $percent_of_max;
596
-        }
597
-
598
-        return $upload_mb;
599
-    }
600
-
601
-
602
-    /**
603
-     * @Drop   in replacement for PHP's fputcsv function - but this one works!!!
604
-     * @access private
605
-     * @param resource $fh         - file handle - what we are writing to
606
-     * @param array    $row        - individual row of csv data
607
-     * @param string   $delimiter  - csv delimiter
608
-     * @param string   $enclosure  - csv enclosure
609
-     * @param string   $mysql_null - allows php NULL to be overridden with MySQl's insertable NULL value
610
-     * @return void
611
-     */
612
-    private function fputcsv2($fh, array $row, $delimiter = ',', $enclosure = '"', $mysql_null = false)
613
-    {
614
-        // Allow user to filter the csv delimiter and enclosure for other countries csv standards
615
-        $delimiter = apply_filters('FHEE__EE_CSV__fputcsv2__delimiter', $delimiter);
616
-        $enclosure = apply_filters('FHEE__EE_CSV__fputcsv2__enclosure', $enclosure);
617
-
618
-        $delimiter_esc = preg_quote($delimiter, '/');
619
-        $enclosure_esc = preg_quote($enclosure, '/');
620
-
621
-        $output = array();
622
-        foreach ($row as $field_value) {
623
-            if (is_object($field_value) || is_array($field_value)) {
624
-                $field_value = serialize($field_value);
625
-            }
626
-            if ($field_value === null && $mysql_null) {
627
-                $output[] = 'NULL';
628
-                continue;
629
-            }
630
-
631
-            $output[] = preg_match("/(?:${delimiter_esc}|${enclosure_esc}|\s)/", $field_value) ?
632
-                ($enclosure . str_replace($enclosure, $enclosure . $enclosure, $field_value) . $enclosure)
633
-                : $field_value;
634
-        }
635
-
636
-        fwrite($fh, join($delimiter, $output) . PHP_EOL);
637
-    }
638
-
639
-
640
-    // /**
641
-    //  * @CSV    Import / Export messages
642
-    //  * @access public
643
-    //  * @return void
644
-    //  */
645
-    // public function csv_admin_notices()
646
-    // {
647
-    //
648
-    //     // We play both kinds of music here! Country AND Western! - err... I mean, cycle through both types of notices
649
-    //     foreach (array('updates', 'errors') as $type) {
650
-    //
651
-    //         // if particular notice type is not empty, then "You've got Mail"
652
-    //         if (! empty($this->_notices[ $type ])) {
653
-    //
654
-    //             // is it an update or an error ?
655
-    //             $msg_class = $type == 'updates' ? 'updated' : 'error';
656
-    //             echo '<div id="message" class="' . $msg_class . '">';
657
-    //             // display each notice, however many that may be
658
-    //             foreach ($this->_notices[ $type ] as $message) {
659
-    //                 echo '<p>' . $message . '</p>';
660
-    //             }
661
-    //             // wrap it up
662
-    //             echo '</div>';
663
-    //         }
664
-    //     }
665
-    // }
666
-
667
-    /**
668
-     * Gets the date format to use in teh csv. filterable
669
-     *
670
-     * @param string $current_format
671
-     * @return string
672
-     */
673
-    public function get_date_format_for_csv($current_format = null)
674
-    {
675
-        return apply_filters('FHEE__EE_CSV__get_date_format_for_csv__format', 'Y-m-d', $current_format);
676
-    }
677
-
678
-    /**
679
-     * Gets the time format we want to use in CSV reports. Filterable
680
-     *
681
-     * @param string $current_format
682
-     * @return string
683
-     */
684
-    public function get_time_format_for_csv($current_format = null)
685
-    {
686
-        return apply_filters('FHEE__EE_CSV__get_time_format_for_csv__format', 'H:i:s', $current_format);
687
-    }
19
+	// instance of the EE_CSV object
20
+	private static $_instance = null;
21
+
22
+
23
+	// multidimensional array to store update & error messages
24
+	// var $_notices = array( 'updates' => array(), 'errors' => array() );
25
+
26
+
27
+	private $_primary_keys;
28
+
29
+	/**
30
+	 *
31
+	 * @var EE_Registry
32
+	 */
33
+	private $EE;
34
+	/**
35
+	 * string used for 1st cell in exports, which indicates that the following 2 rows will be metadata keys and values
36
+	 */
37
+	const metadata_header = 'Event Espresso Export Meta Data';
38
+
39
+	/**
40
+	 *        private constructor to prevent direct creation
41
+	 *
42
+	 * @Constructor
43
+	 * @access private
44
+	 * @return void
45
+	 */
46
+	private function __construct()
47
+	{
48
+		global $wpdb;
49
+
50
+		$this->_primary_keys = array(
51
+			$wpdb->prefix . 'esp_answer'                  => array('ANS_ID'),
52
+			$wpdb->prefix . 'esp_attendee'                => array('ATT_ID'),
53
+			$wpdb->prefix . 'esp_datetime'                => array('DTT_ID'),
54
+			$wpdb->prefix . 'esp_event_question_group'    => array('EQG_ID'),
55
+			$wpdb->prefix . 'esp_message_template'        => array('MTP_ID'),
56
+			$wpdb->prefix . 'esp_payment'                 => array('PAY_ID'),
57
+			$wpdb->prefix . 'esp_price'                   => array('PRC_ID'),
58
+			$wpdb->prefix . 'esp_price_type'              => array('PRT_ID'),
59
+			$wpdb->prefix . 'esp_question'                => array('QST_ID'),
60
+			$wpdb->prefix . 'esp_question_group'          => array('QSG_ID'),
61
+			$wpdb->prefix . 'esp_question_group_question' => array('QGQ_ID'),
62
+			$wpdb->prefix . 'esp_question_option'         => array('QSO_ID'),
63
+			$wpdb->prefix . 'esp_registration'            => array('REG_ID'),
64
+			$wpdb->prefix . 'esp_status'                  => array('STS_ID'),
65
+			$wpdb->prefix . 'esp_transaction'             => array('TXN_ID'),
66
+			$wpdb->prefix . 'esp_transaction'             => array('TXN_ID'),
67
+			$wpdb->prefix . 'events_detail'               => array('id'),
68
+			$wpdb->prefix . 'events_category_detail'      => array('id'),
69
+			$wpdb->prefix . 'events_category_rel'         => array('id'),
70
+			$wpdb->prefix . 'events_venue'                => array('id'),
71
+			$wpdb->prefix . 'events_venue_rel'            => array('emeta_id'),
72
+			$wpdb->prefix . 'events_locale'               => array('id'),
73
+			$wpdb->prefix . 'events_locale_rel'           => array('id'),
74
+			$wpdb->prefix . 'events_personnel'            => array('id'),
75
+			$wpdb->prefix . 'events_personnel_rel'        => array('id'),
76
+		);
77
+	}
78
+
79
+
80
+	/**
81
+	 *        @ singleton method used to instantiate class object
82
+	 *        @ access public
83
+	 *
84
+	 * @return EE_CSV
85
+	 */
86
+	public static function instance()
87
+	{
88
+		// check if class object is instantiated
89
+		if (self::$_instance === null or ! is_object(self::$_instance) or ! (self::$_instance instanceof EE_CSV)) {
90
+			self::$_instance = new self();
91
+		}
92
+		return self::$_instance;
93
+	}
94
+
95
+	/**
96
+	 * Opens a unicode or utf file (normal file_get_contents has difficulty readin ga unicode file. @see
97
+	 * http://stackoverflow.com/questions/15092764/how-to-read-unicode-text-file-in-php
98
+	 *
99
+	 * @param string $file_path
100
+	 * @return string
101
+	 * @throws EE_Error
102
+	 */
103
+	private function read_unicode_file($file_path)
104
+	{
105
+		$fc = "";
106
+		$fh = fopen($file_path, "rb");
107
+		if (! $fh) {
108
+			throw new EE_Error(sprintf(__("Cannot open file for read: %s<br>\n", 'event_espresso'), $file_path));
109
+		}
110
+		$flen = filesize($file_path);
111
+		$bc = fread($fh, $flen);
112
+		for ($i = 0; $i < $flen; $i++) {
113
+			$c = substr($bc, $i, 1);
114
+			if ((ord($c) != 0) && (ord($c) != 13)) {
115
+				$fc = $fc . $c;
116
+			}
117
+		}
118
+		if ((ord(substr($fc, 0, 1)) == 255) && (ord(substr($fc, 1, 1)) == 254)) {
119
+			$fc = substr($fc, 2);
120
+		}
121
+		return ($fc);
122
+	}
123
+
124
+
125
+	/**
126
+	 * Generic CSV-functionality to turn an entire CSV file into a single array that's
127
+	 * NOT in a specific format to EE. It's just a 2-level array, with top-level arrays
128
+	 * representing each row in the CSV file, and the second-level arrays being each column in that row
129
+	 *
130
+	 * @param string $path_to_file
131
+	 * @return array of arrays. Top-level array has rows, second-level array has each item
132
+	 */
133
+	public function import_csv_to_multi_dimensional_array($path_to_file)
134
+	{
135
+		// needed to deal with Mac line endings
136
+		ini_set('auto_detect_line_endings', true);
137
+
138
+		// because fgetcsv does not correctly deal with backslashed quotes such as \"
139
+		// we'll read the file into a string
140
+		$file_contents = $this->read_unicode_file($path_to_file);
141
+		// replace backslashed quotes with CSV enclosures
142
+		$file_contents = str_replace('\\"', '"""', $file_contents);
143
+		// HEY YOU! PUT THAT FILE BACK!!!
144
+		file_put_contents($path_to_file, $file_contents);
145
+
146
+		if (($file_handle = fopen($path_to_file, "r")) !== false) {
147
+			# Set the parent multidimensional array key to 0.
148
+			$nn = 0;
149
+			$csvarray = array();
150
+
151
+			// in PHP 5.3 fgetcsv accepts a 5th parameter, but the pre 5.3 versions of fgetcsv choke if passed more than 4 - is that crazy or what?
152
+			if (version_compare(PHP_VERSION, '5.3.0') < 0) {
153
+				//  PHP 5.2- version
154
+				// loop through each row of the file
155
+				while (($data = fgetcsv($file_handle, 0, ',', '"')) !== false) {
156
+					$csvarray[] = $data;
157
+				}
158
+			} else {
159
+				// loop through each row of the file
160
+				while (($data = fgetcsv($file_handle, 0, ',', '"', '\\')) !== false) {
161
+					$csvarray[] = $data;
162
+				}
163
+			}
164
+			# Close the File.
165
+			fclose($file_handle);
166
+			return $csvarray;
167
+		} else {
168
+			EE_Error::add_error(
169
+				sprintf(__("An error occurred - the file: %s could not opened.", "event_espresso"), $path_to_file),
170
+				__FILE__,
171
+				__FUNCTION__,
172
+				__LINE__
173
+			);
174
+			return false;
175
+		}
176
+	}
177
+
178
+
179
+	/**
180
+	 * @Import contents of csv file and store values in an array to be manipulated by other functions
181
+	 * @access public
182
+	 * @param string  $path_to_file         - the csv file to be imported including the path to it's location.
183
+	 *                                      If $model_name is provided, assumes that each row in the CSV represents a
184
+	 *                                      model object for that model If $model_name ISN'T provided, assumes that
185
+	 *                                      before model object data, there is a row where the first entry is simply
186
+	 *                                      'MODEL', and next entry is the model's name, (untranslated) like Event, and
187
+	 *                                      then maybe a row of headers, and then the model data. Eg.
188
+	 *                                      '<br>MODEL,Event,<br>EVT_ID,EVT_name,...<br>1,Monkey
189
+	 *                                      Party,...<br>2,Llamarama,...<br>MODEL,Venue,<br>VNU_ID,VNU_name<br>1,The
190
+	 *                                      Forest
191
+	 * @param string  $model_name           model name if we know what model we're importing
192
+	 * @param boolean $first_row_is_headers - whether the first row of data is headers or not - TRUE = headers, FALSE =
193
+	 *                                      data
194
+	 * @return mixed - array on success - multi dimensional with headers as keys (if headers exist) OR string on fail -
195
+	 *               error message like the following array('Event'=>array( array('EVT_ID'=>1,'EVT_name'=>'bob
196
+	 *               party',...), array('EVT_ID'=>2,'EVT_name'=>'llamarama',...),
197
+	 *                                      ...
198
+	 *                                      )
199
+	 *                                      'Venue'=>array(
200
+	 *                                      array('VNU_ID'=>1,'VNU_name'=>'the shack',...),
201
+	 *                                      array('VNU_ID'=>2,'VNU_name'=>'tree house',...),
202
+	 *                                      ...
203
+	 *                                      )
204
+	 *                                      ...
205
+	 *                                      )
206
+	 */
207
+	public function import_csv_to_model_data_array($path_to_file, $model_name = false, $first_row_is_headers = true)
208
+	{
209
+		$multi_dimensional_array = $this->import_csv_to_multi_dimensional_array($path_to_file);
210
+		if (! $multi_dimensional_array) {
211
+			return false;
212
+		}
213
+		// gotta start somewhere
214
+		$row = 1;
215
+		// array to store csv data in
216
+		$ee_formatted_data = array();
217
+		// array to store headers (column names)
218
+		$headers = array();
219
+		foreach ($multi_dimensional_array as $data) {
220
+			// if first cell is MODEL, then second cell is the MODEL name
221
+			if ($data[0] == 'MODEL') {
222
+				$model_name = $data[1];
223
+				// don't bother looking for model data in this row. The rest of this
224
+				// row should be blank
225
+				// AND pretend this is the first row again
226
+				$row = 1;
227
+				// reset headers
228
+				$headers = array();
229
+				continue;
230
+			}
231
+			if (strpos($data[0], EE_CSV::metadata_header) !== false) {
232
+				$model_name = EE_CSV::metadata_header;
233
+				// store like model data, we just won't try importing it etc.
234
+				$row = 1;
235
+				continue;
236
+			}
237
+
238
+
239
+			// how many columns are there?
240
+			$columns = count($data);
241
+
242
+			$model_entry = array();
243
+			// loop through each column
244
+			for ($i = 0; $i < $columns; $i++) {
245
+				// replace csv_enclosures with backslashed quotes
246
+				$data[ $i ] = str_replace('"""', '\\"', $data[ $i ]);
247
+				// do we need to grab the column names?
248
+				if ($row === 1) {
249
+					if ($first_row_is_headers) {
250
+						// store the column names to use for keys
251
+						$column_name = $data[ $i ];
252
+						// check it's not blank... sometimes CSV editign programs adda bunch of empty columns onto the end...
253
+						if (! $column_name) {
254
+							continue;
255
+						}
256
+						$matches = array();
257
+						if ($model_name == EE_CSV::metadata_header) {
258
+							$headers[ $i ] = $column_name;
259
+						} else {
260
+							// now get the db table name from it (the part between square brackets)
261
+							$success = preg_match('~(.*)\[(.*)\]~', $column_name, $matches);
262
+							if (! $success) {
263
+								EE_Error::add_error(
264
+									sprintf(
265
+										__(
266
+											"The column titled %s is invalid for importing. It must be be in the format of 'Nice Name[model_field_name]' in row %s",
267
+											"event_espresso"
268
+										),
269
+										$column_name,
270
+										implode(",", $data)
271
+									),
272
+									__FILE__,
273
+									__FUNCTION__,
274
+									__LINE__
275
+								);
276
+								return false;
277
+							}
278
+							$headers[ $i ] = $matches[2];
279
+						}
280
+					} else {
281
+						// no column names means our final array will just use counters for keys
282
+						$model_entry[ $headers[ $i ] ] = $data[ $i ];
283
+						$headers[ $i ] = $i;
284
+					}
285
+					// and we need to store csv data
286
+				} else {
287
+					// this column isn' ta header, store it if there is a header for it
288
+					if (isset($headers[ $i ])) {
289
+						$model_entry[ $headers[ $i ] ] = $data[ $i ];
290
+					}
291
+				}
292
+			}
293
+			// save the row's data IF it's a non-header-row
294
+			if (! $first_row_is_headers || ($first_row_is_headers && $row > 1)) {
295
+				$ee_formatted_data[ $model_name ][] = $model_entry;
296
+			}
297
+			// advance to next row
298
+			$row++;
299
+		}
300
+
301
+		// delete the uploaded file
302
+		unlink($path_to_file);
303
+		// echo '<pre style="height:auto;border:2px solid lightblue;">' . print_r( $ee_formatted_data, TRUE ) . '</pre><br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>';
304
+		// die();
305
+
306
+		// it's good to give back
307
+		return $ee_formatted_data;
308
+	}
309
+
310
+
311
+	public function save_csv_to_db($csv_data_array, $model_name = false)
312
+	{
313
+		EE_Error::doing_it_wrong(
314
+			'save_csv_to_db',
315
+			__(
316
+				'Function moved to EE_Import and renamed to save_csv_data_array_to_db',
317
+				'event_espresso'
318
+			),
319
+			'4.6.7'
320
+		);
321
+		return EE_Import::instance()->save_csv_data_array_to_db($csv_data_array, $model_name);
322
+	}
323
+
324
+	/**
325
+	 * Sends HTTP headers to indicate that the browser should download a file,
326
+	 * and starts writing the file to PHP's output. Returns the file handle so other functions can
327
+	 * also write to it
328
+	 *
329
+	 * @param string $new_filename the name of the file that the user will download
330
+	 * @return resource, like the results of fopen(), which can be used for fwrite, fputcsv2, etc.
331
+	 */
332
+	public function begin_sending_csv($filename)
333
+	{
334
+		// grab file extension
335
+		$ext = substr(strrchr($filename, '.'), 1);
336
+		if ($ext == '.csv' or $ext == '.xls') {
337
+			str_replace($ext, '', $filename);
338
+		}
339
+		$filename .= '.csv';
340
+
341
+		// if somebody's been naughty and already started outputting stuff, trash it
342
+		// and start writing our stuff.
343
+		if (ob_get_length()) {
344
+			@ob_flush();
345
+			@flush();
346
+			@ob_end_flush();
347
+		}
348
+		@ob_start();
349
+		header("Pragma: public");
350
+		header("Expires: 0");
351
+		header("Pragma: no-cache");
352
+		header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
353
+		// header("Content-Type: application/force-download");
354
+		// header("Content-Type: application/octet-stream");
355
+		// header("Content-Type: application/download");
356
+		header('Content-disposition: attachment; filename=' . $filename);
357
+		header("Content-Type: text/csv; charset=utf-8");
358
+		do_action('AHEE__EE_CSV__begin_sending_csv__headers');
359
+		echo apply_filters(
360
+			'FHEE__EE_CSV__begin_sending_csv__start_writing',
361
+			"\xEF\xBB\xBF"
362
+		); // makes excel open it as UTF-8. UTF-8 BOM, see http://stackoverflow.com/a/4440143/2773835
363
+		$fh = fopen('php://output', 'w');
364
+		return $fh;
365
+	}
366
+
367
+	/**
368
+	 * Writes some meta data to the CSV as a bunch of columns. Initially we're only
369
+	 * mentioning the version and timezone
370
+	 *
371
+	 * @param resource $filehandle
372
+	 */
373
+	public function write_metadata_to_csv($filehandle)
374
+	{
375
+		$data_row = array(EE_CSV::metadata_header);// do NOT translate because this exact string is used when importing
376
+		$this->fputcsv2($filehandle, $data_row);
377
+		$meta_data = array(
378
+			0 => array(
379
+				'version'        => espresso_version(),
380
+				'timezone'       => EEH_DTT_Helper::get_timezone(),
381
+				'time_of_export' => current_time('mysql'),
382
+				'site_url'       => site_url(),
383
+			),
384
+		);
385
+		$this->write_data_array_to_csv($filehandle, $meta_data);
386
+	}
387
+
388
+
389
+	/**
390
+	 * Writes $data to the csv file open in $filehandle. uses the array indices of $data for column headers
391
+	 *
392
+	 * @param array   $data                 2D array, first numerically-indexed, and next-level-down preferably indexed
393
+	 *                                      by string
394
+	 * @param boolean $add_csv_column_names whether or not we should add the keys in the bottom-most array as a row for
395
+	 *                                      headers in the CSV. Eg, if $data looked like
396
+	 *                                      array(0=>array('EVT_ID'=>1,'EVT_name'=>'monkey'...), 1=>array(...),...))
397
+	 *                                      then the first row we'd write to the CSV would be "EVT_ID,EVT_name,..."
398
+	 * @return boolean if we successfully wrote to the CSV or not. If there's no $data, we consider that a success
399
+	 *                 (because we wrote everything there was...nothing)
400
+	 */
401
+	public function write_data_array_to_csv($filehandle, $data)
402
+	{
403
+
404
+
405
+		// determine if $data is actually a 2d array
406
+		if ($data && is_array($data) && is_array(EEH_Array::get_one_item_from_array($data))) {
407
+			// make sure top level is numerically indexed,
408
+
409
+			if (EEH_Array::is_associative_array($data)) {
410
+				throw new EE_Error(
411
+					sprintf(
412
+						__(
413
+							"top-level array must be numerically indexed. Does these look like numbers to you? %s",
414
+							"event_espresso"
415
+						),
416
+						implode(",", array_keys($data))
417
+					)
418
+				);
419
+			}
420
+			$item_in_top_level_array = EEH_Array::get_one_item_from_array($data);
421
+			// now, is the last item in the top-level array of $data an associative or numeric array?
422
+			if (EEH_Array::is_associative_array($item_in_top_level_array)) {
423
+				// its associative, so we want to output its keys as column headers
424
+				$keys = array_keys($item_in_top_level_array);
425
+				echo $this->fputcsv2($filehandle, $keys);
426
+			}
427
+			// start writing data
428
+			foreach ($data as $data_row) {
429
+				echo $this->fputcsv2($filehandle, $data_row);
430
+			}
431
+			return true;
432
+		} else {
433
+			// no data TO write... so we can assume that's a success
434
+			return true;
435
+		}
436
+		// //if 2nd level is indexed by strings, use those as csv column headers (ie, the first row)
437
+		//
438
+		//
439
+		// $no_table = TRUE;
440
+		//
441
+		// // loop through data and add each row to the file/stream as csv
442
+		// foreach ( $data as $model_name => $model_data ) {
443
+		// // test first row to see if it is data or a model name
444
+		// $model = EE_Registry::instance();->load_model($model_name);
445
+		// //if the model really exists,
446
+		// if ( $model ) {
447
+		//
448
+		// // we have a table name
449
+		// $no_table = FALSE;
450
+		//
451
+		// // put the tablename into an array cuz that's how fputcsv rolls
452
+		// $model_name_row = array( 'MODEL', $model_name );
453
+		//
454
+		// // add table name to csv output
455
+		// echo self::fputcsv2($filehandle, $model_name_row);
456
+		//
457
+		// // now get the rest of the data
458
+		// foreach ( $model_data as $row ) {
459
+		// // output the row
460
+		// echo self::fputcsv2($filehandle, $row);
461
+		// }
462
+		//
463
+		// }
464
+		//
465
+		// if ( $no_table ) {
466
+		// // no table so just put the data
467
+		// echo self::fputcsv2($filehandle, $model_data);
468
+		// }
469
+		//
470
+		// } // END OF foreach ( $data )
471
+	}
472
+
473
+	/**
474
+	 * Should be called after begin_sending_csv(), and one or more write_data_array_to_csv()s.
475
+	 * Calls exit to prevent polluting the CSV file with other junk
476
+	 *
477
+	 * @param resource $fh filehandle where we're writing the CSV to
478
+	 */
479
+	public function end_sending_csv($fh)
480
+	{
481
+		fclose($fh);
482
+		exit(0);
483
+	}
484
+
485
+	/**
486
+	 * Given an open file, writes all the model data to it in the format the importer expects.
487
+	 * Usually preceded by begin_sending_csv($filename), and followed by end_sending_csv($filehandle).
488
+	 *
489
+	 * @param resource $filehandle
490
+	 * @param array    $model_data_array is assumed to be a 3d array: 1st layer has keys of model names (eg 'Event'),
491
+	 *                                   next layer is numerically indexed to represent each model object (eg, each
492
+	 *                                   individual event), and the last layer has all the attributes o fthat model
493
+	 *                                   object (eg, the event's id, name, etc)
494
+	 * @return boolean success
495
+	 */
496
+	public function write_model_data_to_csv($filehandle, $model_data_array)
497
+	{
498
+		$this->write_metadata_to_csv($filehandle);
499
+		foreach ($model_data_array as $model_name => $model_instance_arrays) {
500
+			// first: output a special row stating the model
501
+			echo $this->fputcsv2($filehandle, array('MODEL', $model_name));
502
+			// if we have items to put in the CSV, do it normally
503
+
504
+			if (! empty($model_instance_arrays)) {
505
+				$this->write_data_array_to_csv($filehandle, $model_instance_arrays);
506
+			} else {
507
+				// echo "no data to write... so just write the headers";
508
+				// so there's actually NO model objects for that model.
509
+				// probably still want to show the columns
510
+				$model = EE_Registry::instance()->load_model($model_name);
511
+				$column_names = array();
512
+				foreach ($model->field_settings() as $field) {
513
+					$column_names[ $field->get_nicename() . "[" . $field->get_name() . "]" ] = null;
514
+				}
515
+				$this->write_data_array_to_csv($filehandle, array($column_names));
516
+			}
517
+		}
518
+	}
519
+
520
+	/**
521
+	 * Writes the CSV file to the output buffer, with rows corresponding to $model_data_array,
522
+	 * and dies (in order to avoid other plugins from messing up the csv output)
523
+	 *
524
+	 * @param string $filename         the filename you want to give the file
525
+	 * @param array  $model_data_array 3d array, as described in EE_CSV::write_model_data_to_csv()
526
+	 * @return bool | void writes CSV file to output and dies
527
+	 */
528
+	public function export_multiple_model_data_to_csv($filename, $model_data_array)
529
+	{
530
+		$filehandle = $this->begin_sending_csv($filename);
531
+		$this->write_model_data_to_csv($filehandle, $model_data_array);
532
+		$this->end_sending_csv($filehandle);
533
+	}
534
+
535
+	/**
536
+	 * @Export contents of an array to csv file
537
+	 * @access public
538
+	 * @param array  $data     - the array of data to be converted to csv and exported
539
+	 * @param string $filename - name for newly created csv file
540
+	 * @return TRUE on success, FALSE on fail
541
+	 */
542
+	public function export_array_to_csv($data = false, $filename = false)
543
+	{
544
+
545
+		// no data file?? get outta here
546
+		if (! $data or ! is_array($data) or empty($data)) {
547
+			return false;
548
+		}
549
+
550
+		// no filename?? get outta here
551
+		if (! $filename) {
552
+			return false;
553
+		}
554
+
555
+
556
+		// somebody told me i might need this ???
557
+		global $wpdb;
558
+		$prefix = $wpdb->prefix;
559
+
560
+
561
+		$fh = $this->begin_sending_csv($filename);
562
+
563
+
564
+		$this->end_sending_csv($fh);
565
+	}
566
+
567
+
568
+	/**
569
+	 * @Determine the maximum upload file size based on php.ini settings
570
+	 * @access    public
571
+	 * @param int $percent_of_max - desired percentage of the max upload_mb
572
+	 * @return int KB
573
+	 */
574
+	public function get_max_upload_size($percent_of_max = false)
575
+	{
576
+
577
+		$max_upload = (int) (ini_get('upload_max_filesize'));
578
+		$max_post = (int) (ini_get('post_max_size'));
579
+		$memory_limit = (int) (ini_get('memory_limit'));
580
+
581
+		// determine the smallest of the three values from above
582
+		$upload_mb = min($max_upload, $max_post, $memory_limit);
583
+
584
+		// convert MB to KB
585
+		$upload_mb = $upload_mb * 1024;
586
+
587
+		// don't want the full monty? then reduce the max uplaod size
588
+		if ($percent_of_max) {
589
+			// is percent_of_max like this -> 50 or like this -> 0.50 ?
590
+			if ($percent_of_max > 1) {
591
+				// chnages 50 to 0.50
592
+				$percent_of_max = $percent_of_max / 100;
593
+			}
594
+			// make upload_mb a percentage of the max upload_mb
595
+			$upload_mb = $upload_mb * $percent_of_max;
596
+		}
597
+
598
+		return $upload_mb;
599
+	}
600
+
601
+
602
+	/**
603
+	 * @Drop   in replacement for PHP's fputcsv function - but this one works!!!
604
+	 * @access private
605
+	 * @param resource $fh         - file handle - what we are writing to
606
+	 * @param array    $row        - individual row of csv data
607
+	 * @param string   $delimiter  - csv delimiter
608
+	 * @param string   $enclosure  - csv enclosure
609
+	 * @param string   $mysql_null - allows php NULL to be overridden with MySQl's insertable NULL value
610
+	 * @return void
611
+	 */
612
+	private function fputcsv2($fh, array $row, $delimiter = ',', $enclosure = '"', $mysql_null = false)
613
+	{
614
+		// Allow user to filter the csv delimiter and enclosure for other countries csv standards
615
+		$delimiter = apply_filters('FHEE__EE_CSV__fputcsv2__delimiter', $delimiter);
616
+		$enclosure = apply_filters('FHEE__EE_CSV__fputcsv2__enclosure', $enclosure);
617
+
618
+		$delimiter_esc = preg_quote($delimiter, '/');
619
+		$enclosure_esc = preg_quote($enclosure, '/');
620
+
621
+		$output = array();
622
+		foreach ($row as $field_value) {
623
+			if (is_object($field_value) || is_array($field_value)) {
624
+				$field_value = serialize($field_value);
625
+			}
626
+			if ($field_value === null && $mysql_null) {
627
+				$output[] = 'NULL';
628
+				continue;
629
+			}
630
+
631
+			$output[] = preg_match("/(?:${delimiter_esc}|${enclosure_esc}|\s)/", $field_value) ?
632
+				($enclosure . str_replace($enclosure, $enclosure . $enclosure, $field_value) . $enclosure)
633
+				: $field_value;
634
+		}
635
+
636
+		fwrite($fh, join($delimiter, $output) . PHP_EOL);
637
+	}
638
+
639
+
640
+	// /**
641
+	//  * @CSV    Import / Export messages
642
+	//  * @access public
643
+	//  * @return void
644
+	//  */
645
+	// public function csv_admin_notices()
646
+	// {
647
+	//
648
+	//     // We play both kinds of music here! Country AND Western! - err... I mean, cycle through both types of notices
649
+	//     foreach (array('updates', 'errors') as $type) {
650
+	//
651
+	//         // if particular notice type is not empty, then "You've got Mail"
652
+	//         if (! empty($this->_notices[ $type ])) {
653
+	//
654
+	//             // is it an update or an error ?
655
+	//             $msg_class = $type == 'updates' ? 'updated' : 'error';
656
+	//             echo '<div id="message" class="' . $msg_class . '">';
657
+	//             // display each notice, however many that may be
658
+	//             foreach ($this->_notices[ $type ] as $message) {
659
+	//                 echo '<p>' . $message . '</p>';
660
+	//             }
661
+	//             // wrap it up
662
+	//             echo '</div>';
663
+	//         }
664
+	//     }
665
+	// }
666
+
667
+	/**
668
+	 * Gets the date format to use in teh csv. filterable
669
+	 *
670
+	 * @param string $current_format
671
+	 * @return string
672
+	 */
673
+	public function get_date_format_for_csv($current_format = null)
674
+	{
675
+		return apply_filters('FHEE__EE_CSV__get_date_format_for_csv__format', 'Y-m-d', $current_format);
676
+	}
677
+
678
+	/**
679
+	 * Gets the time format we want to use in CSV reports. Filterable
680
+	 *
681
+	 * @param string $current_format
682
+	 * @return string
683
+	 */
684
+	public function get_time_format_for_csv($current_format = null)
685
+	{
686
+		return apply_filters('FHEE__EE_CSV__get_time_format_for_csv__format', 'H:i:s', $current_format);
687
+	}
688 688
 }
Please login to merge, or discard this patch.
Spacing   +48 added lines, -48 removed lines patch added patch discarded remove patch
@@ -48,31 +48,31 @@  discard block
 block discarded – undo
48 48
         global $wpdb;
49 49
 
50 50
         $this->_primary_keys = array(
51
-            $wpdb->prefix . 'esp_answer'                  => array('ANS_ID'),
52
-            $wpdb->prefix . 'esp_attendee'                => array('ATT_ID'),
53
-            $wpdb->prefix . 'esp_datetime'                => array('DTT_ID'),
54
-            $wpdb->prefix . 'esp_event_question_group'    => array('EQG_ID'),
55
-            $wpdb->prefix . 'esp_message_template'        => array('MTP_ID'),
56
-            $wpdb->prefix . 'esp_payment'                 => array('PAY_ID'),
57
-            $wpdb->prefix . 'esp_price'                   => array('PRC_ID'),
58
-            $wpdb->prefix . 'esp_price_type'              => array('PRT_ID'),
59
-            $wpdb->prefix . 'esp_question'                => array('QST_ID'),
60
-            $wpdb->prefix . 'esp_question_group'          => array('QSG_ID'),
61
-            $wpdb->prefix . 'esp_question_group_question' => array('QGQ_ID'),
62
-            $wpdb->prefix . 'esp_question_option'         => array('QSO_ID'),
63
-            $wpdb->prefix . 'esp_registration'            => array('REG_ID'),
64
-            $wpdb->prefix . 'esp_status'                  => array('STS_ID'),
65
-            $wpdb->prefix . 'esp_transaction'             => array('TXN_ID'),
66
-            $wpdb->prefix . 'esp_transaction'             => array('TXN_ID'),
67
-            $wpdb->prefix . 'events_detail'               => array('id'),
68
-            $wpdb->prefix . 'events_category_detail'      => array('id'),
69
-            $wpdb->prefix . 'events_category_rel'         => array('id'),
70
-            $wpdb->prefix . 'events_venue'                => array('id'),
71
-            $wpdb->prefix . 'events_venue_rel'            => array('emeta_id'),
72
-            $wpdb->prefix . 'events_locale'               => array('id'),
73
-            $wpdb->prefix . 'events_locale_rel'           => array('id'),
74
-            $wpdb->prefix . 'events_personnel'            => array('id'),
75
-            $wpdb->prefix . 'events_personnel_rel'        => array('id'),
51
+            $wpdb->prefix.'esp_answer'                  => array('ANS_ID'),
52
+            $wpdb->prefix.'esp_attendee'                => array('ATT_ID'),
53
+            $wpdb->prefix.'esp_datetime'                => array('DTT_ID'),
54
+            $wpdb->prefix.'esp_event_question_group'    => array('EQG_ID'),
55
+            $wpdb->prefix.'esp_message_template'        => array('MTP_ID'),
56
+            $wpdb->prefix.'esp_payment'                 => array('PAY_ID'),
57
+            $wpdb->prefix.'esp_price'                   => array('PRC_ID'),
58
+            $wpdb->prefix.'esp_price_type'              => array('PRT_ID'),
59
+            $wpdb->prefix.'esp_question'                => array('QST_ID'),
60
+            $wpdb->prefix.'esp_question_group'          => array('QSG_ID'),
61
+            $wpdb->prefix.'esp_question_group_question' => array('QGQ_ID'),
62
+            $wpdb->prefix.'esp_question_option'         => array('QSO_ID'),
63
+            $wpdb->prefix.'esp_registration'            => array('REG_ID'),
64
+            $wpdb->prefix.'esp_status'                  => array('STS_ID'),
65
+            $wpdb->prefix.'esp_transaction'             => array('TXN_ID'),
66
+            $wpdb->prefix.'esp_transaction'             => array('TXN_ID'),
67
+            $wpdb->prefix.'events_detail'               => array('id'),
68
+            $wpdb->prefix.'events_category_detail'      => array('id'),
69
+            $wpdb->prefix.'events_category_rel'         => array('id'),
70
+            $wpdb->prefix.'events_venue'                => array('id'),
71
+            $wpdb->prefix.'events_venue_rel'            => array('emeta_id'),
72
+            $wpdb->prefix.'events_locale'               => array('id'),
73
+            $wpdb->prefix.'events_locale_rel'           => array('id'),
74
+            $wpdb->prefix.'events_personnel'            => array('id'),
75
+            $wpdb->prefix.'events_personnel_rel'        => array('id'),
76 76
         );
77 77
     }
78 78
 
@@ -104,7 +104,7 @@  discard block
 block discarded – undo
104 104
     {
105 105
         $fc = "";
106 106
         $fh = fopen($file_path, "rb");
107
-        if (! $fh) {
107
+        if ( ! $fh) {
108 108
             throw new EE_Error(sprintf(__("Cannot open file for read: %s<br>\n", 'event_espresso'), $file_path));
109 109
         }
110 110
         $flen = filesize($file_path);
@@ -112,7 +112,7 @@  discard block
 block discarded – undo
112 112
         for ($i = 0; $i < $flen; $i++) {
113 113
             $c = substr($bc, $i, 1);
114 114
             if ((ord($c) != 0) && (ord($c) != 13)) {
115
-                $fc = $fc . $c;
115
+                $fc = $fc.$c;
116 116
             }
117 117
         }
118 118
         if ((ord(substr($fc, 0, 1)) == 255) && (ord(substr($fc, 1, 1)) == 254)) {
@@ -207,7 +207,7 @@  discard block
 block discarded – undo
207 207
     public function import_csv_to_model_data_array($path_to_file, $model_name = false, $first_row_is_headers = true)
208 208
     {
209 209
         $multi_dimensional_array = $this->import_csv_to_multi_dimensional_array($path_to_file);
210
-        if (! $multi_dimensional_array) {
210
+        if ( ! $multi_dimensional_array) {
211 211
             return false;
212 212
         }
213 213
         // gotta start somewhere
@@ -243,23 +243,23 @@  discard block
 block discarded – undo
243 243
             // loop through each column
244 244
             for ($i = 0; $i < $columns; $i++) {
245 245
                 // replace csv_enclosures with backslashed quotes
246
-                $data[ $i ] = str_replace('"""', '\\"', $data[ $i ]);
246
+                $data[$i] = str_replace('"""', '\\"', $data[$i]);
247 247
                 // do we need to grab the column names?
248 248
                 if ($row === 1) {
249 249
                     if ($first_row_is_headers) {
250 250
                         // store the column names to use for keys
251
-                        $column_name = $data[ $i ];
251
+                        $column_name = $data[$i];
252 252
                         // check it's not blank... sometimes CSV editign programs adda bunch of empty columns onto the end...
253
-                        if (! $column_name) {
253
+                        if ( ! $column_name) {
254 254
                             continue;
255 255
                         }
256 256
                         $matches = array();
257 257
                         if ($model_name == EE_CSV::metadata_header) {
258
-                            $headers[ $i ] = $column_name;
258
+                            $headers[$i] = $column_name;
259 259
                         } else {
260 260
                             // now get the db table name from it (the part between square brackets)
261 261
                             $success = preg_match('~(.*)\[(.*)\]~', $column_name, $matches);
262
-                            if (! $success) {
262
+                            if ( ! $success) {
263 263
                                 EE_Error::add_error(
264 264
                                     sprintf(
265 265
                                         __(
@@ -275,24 +275,24 @@  discard block
 block discarded – undo
275 275
                                 );
276 276
                                 return false;
277 277
                             }
278
-                            $headers[ $i ] = $matches[2];
278
+                            $headers[$i] = $matches[2];
279 279
                         }
280 280
                     } else {
281 281
                         // no column names means our final array will just use counters for keys
282
-                        $model_entry[ $headers[ $i ] ] = $data[ $i ];
283
-                        $headers[ $i ] = $i;
282
+                        $model_entry[$headers[$i]] = $data[$i];
283
+                        $headers[$i] = $i;
284 284
                     }
285 285
                     // and we need to store csv data
286 286
                 } else {
287 287
                     // this column isn' ta header, store it if there is a header for it
288
-                    if (isset($headers[ $i ])) {
289
-                        $model_entry[ $headers[ $i ] ] = $data[ $i ];
288
+                    if (isset($headers[$i])) {
289
+                        $model_entry[$headers[$i]] = $data[$i];
290 290
                     }
291 291
                 }
292 292
             }
293 293
             // save the row's data IF it's a non-header-row
294
-            if (! $first_row_is_headers || ($first_row_is_headers && $row > 1)) {
295
-                $ee_formatted_data[ $model_name ][] = $model_entry;
294
+            if ( ! $first_row_is_headers || ($first_row_is_headers && $row > 1)) {
295
+                $ee_formatted_data[$model_name][] = $model_entry;
296 296
             }
297 297
             // advance to next row
298 298
             $row++;
@@ -353,7 +353,7 @@  discard block
 block discarded – undo
353 353
         // header("Content-Type: application/force-download");
354 354
         // header("Content-Type: application/octet-stream");
355 355
         // header("Content-Type: application/download");
356
-        header('Content-disposition: attachment; filename=' . $filename);
356
+        header('Content-disposition: attachment; filename='.$filename);
357 357
         header("Content-Type: text/csv; charset=utf-8");
358 358
         do_action('AHEE__EE_CSV__begin_sending_csv__headers');
359 359
         echo apply_filters(
@@ -372,7 +372,7 @@  discard block
 block discarded – undo
372 372
      */
373 373
     public function write_metadata_to_csv($filehandle)
374 374
     {
375
-        $data_row = array(EE_CSV::metadata_header);// do NOT translate because this exact string is used when importing
375
+        $data_row = array(EE_CSV::metadata_header); // do NOT translate because this exact string is used when importing
376 376
         $this->fputcsv2($filehandle, $data_row);
377 377
         $meta_data = array(
378 378
             0 => array(
@@ -501,7 +501,7 @@  discard block
 block discarded – undo
501 501
             echo $this->fputcsv2($filehandle, array('MODEL', $model_name));
502 502
             // if we have items to put in the CSV, do it normally
503 503
 
504
-            if (! empty($model_instance_arrays)) {
504
+            if ( ! empty($model_instance_arrays)) {
505 505
                 $this->write_data_array_to_csv($filehandle, $model_instance_arrays);
506 506
             } else {
507 507
                 // echo "no data to write... so just write the headers";
@@ -510,7 +510,7 @@  discard block
 block discarded – undo
510 510
                 $model = EE_Registry::instance()->load_model($model_name);
511 511
                 $column_names = array();
512 512
                 foreach ($model->field_settings() as $field) {
513
-                    $column_names[ $field->get_nicename() . "[" . $field->get_name() . "]" ] = null;
513
+                    $column_names[$field->get_nicename()."[".$field->get_name()."]"] = null;
514 514
                 }
515 515
                 $this->write_data_array_to_csv($filehandle, array($column_names));
516 516
             }
@@ -543,12 +543,12 @@  discard block
 block discarded – undo
543 543
     {
544 544
 
545 545
         // no data file?? get outta here
546
-        if (! $data or ! is_array($data) or empty($data)) {
546
+        if ( ! $data or ! is_array($data) or empty($data)) {
547 547
             return false;
548 548
         }
549 549
 
550 550
         // no filename?? get outta here
551
-        if (! $filename) {
551
+        if ( ! $filename) {
552 552
             return false;
553 553
         }
554 554
 
@@ -629,11 +629,11 @@  discard block
 block discarded – undo
629 629
             }
630 630
 
631 631
             $output[] = preg_match("/(?:${delimiter_esc}|${enclosure_esc}|\s)/", $field_value) ?
632
-                ($enclosure . str_replace($enclosure, $enclosure . $enclosure, $field_value) . $enclosure)
632
+                ($enclosure.str_replace($enclosure, $enclosure.$enclosure, $field_value).$enclosure)
633 633
                 : $field_value;
634 634
         }
635 635
 
636
-        fwrite($fh, join($delimiter, $output) . PHP_EOL);
636
+        fwrite($fh, join($delimiter, $output).PHP_EOL);
637 637
     }
638 638
 
639 639
 
Please login to merge, or discard this patch.