Completed
Branch BUG/better-url-validation (3a3c7e)
by
unknown
62:16 queued 39:30
created
core/db_models/EEM_System_Status.model.php 1 patch
Indentation   +273 added lines, -273 removed lines patch added patch discarded remove patch
@@ -6,79 +6,79 @@  discard block
 block discarded – undo
6 6
 class EEM_System_Status
7 7
 {
8 8
 
9
-    // private instance of the EEM_System_Status object
10
-    protected static $_instance = null;
9
+	// private instance of the EEM_System_Status object
10
+	protected static $_instance = null;
11 11
 
12 12
 
13 13
 
14
-    /**
15
-     *      This function is a singleton method used to instantiate the EEM_Attendee object
16
-     *
17
-     *      @access public
18
-     *      @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any incoming timezone data that gets saved).  Note this just sends the timezone info to the date time model field objects.  Default is NULL (and will be assumed using the set timezone in the 'timezone_string' wp option)
19
-     *      @return EEM_System_Status
20
-     */
21
-    public static function instance()
22
-    {
14
+	/**
15
+	 *      This function is a singleton method used to instantiate the EEM_Attendee object
16
+	 *
17
+	 *      @access public
18
+	 *      @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any incoming timezone data that gets saved).  Note this just sends the timezone info to the date time model field objects.  Default is NULL (and will be assumed using the set timezone in the 'timezone_string' wp option)
19
+	 *      @return EEM_System_Status
20
+	 */
21
+	public static function instance()
22
+	{
23 23
 
24
-        // check if instance of EEM_System_Status already exists
25
-        if (self::$_instance === null) {
26
-            // instantiate EEM_System_Status
27
-            self::$_instance = new self();
28
-        }
29
-        return self::$_instance;
30
-    }
31
-    private function __construct()
32
-    {
33
-    }
34
-    /**
35
-     *
36
-     * @return array where each key is a function name on this class, and each value is SOMETHING--
37
-     * it might be a value, an array, or an object
38
-     */
39
-    public function get_system_stati()
40
-    {
41
-        return apply_filters(
42
-            'FHEE__EEM_System_Status__get_system_stati',
43
-            array(
44
-                'ee_version'=>$this->get_ee_version(),
45
-                'ee_activation_history'=>$this->get_ee_activation_history(),
46
-                'ee_config'=>$this->get_ee_config(),
47
-                'ee_migration_history'=>$this->get_ee_migration_history(),
48
-                'active_plugins'=>$this->get_active_plugins(),
49
-                'wp_settings'=>$this->get_wp_settings(),
50
-                'wp_maintenance_mode' => $this->get_wp_maintenance_mode(),
51
-                'https_enabled'=>$this->get_https_enabled(),
52
-                'logging_enabled' => $this->get_logging_enabled(),
53
-                'remote_posting' => $this->get_remote_posting(),
54
-                'php_version'=>$this->php_version(),
55
-                'php.ini_settings'=>$this->get_php_ini_all(),
56
-                'php_info'=>$this->get_php_info(),
57
-            ),
58
-            $this
59
-        );
60
-    }
61
-    /**
62
-     *
63
-     * @return string
64
-     */
65
-    public function get_ee_version()
66
-    {
67
-        return espresso_version();
68
-    }
69
-    /**
70
-     *
71
-     * @return string
72
-     */
73
-    public function php_version()
74
-    {
75
-        return phpversion();
76
-    }
77
-    /**
78
-     *
79
-     * @return array, where each key is a plugin name (lower-cased), values are sub-arrays.
80
-     * Sub-arrays like described in wp function get_plugin_data. Ie,     *
81
-     *  'Name' => 'Plugin Name',
24
+		// check if instance of EEM_System_Status already exists
25
+		if (self::$_instance === null) {
26
+			// instantiate EEM_System_Status
27
+			self::$_instance = new self();
28
+		}
29
+		return self::$_instance;
30
+	}
31
+	private function __construct()
32
+	{
33
+	}
34
+	/**
35
+	 *
36
+	 * @return array where each key is a function name on this class, and each value is SOMETHING--
37
+	 * it might be a value, an array, or an object
38
+	 */
39
+	public function get_system_stati()
40
+	{
41
+		return apply_filters(
42
+			'FHEE__EEM_System_Status__get_system_stati',
43
+			array(
44
+				'ee_version'=>$this->get_ee_version(),
45
+				'ee_activation_history'=>$this->get_ee_activation_history(),
46
+				'ee_config'=>$this->get_ee_config(),
47
+				'ee_migration_history'=>$this->get_ee_migration_history(),
48
+				'active_plugins'=>$this->get_active_plugins(),
49
+				'wp_settings'=>$this->get_wp_settings(),
50
+				'wp_maintenance_mode' => $this->get_wp_maintenance_mode(),
51
+				'https_enabled'=>$this->get_https_enabled(),
52
+				'logging_enabled' => $this->get_logging_enabled(),
53
+				'remote_posting' => $this->get_remote_posting(),
54
+				'php_version'=>$this->php_version(),
55
+				'php.ini_settings'=>$this->get_php_ini_all(),
56
+				'php_info'=>$this->get_php_info(),
57
+			),
58
+			$this
59
+		);
60
+	}
61
+	/**
62
+	 *
63
+	 * @return string
64
+	 */
65
+	public function get_ee_version()
66
+	{
67
+		return espresso_version();
68
+	}
69
+	/**
70
+	 *
71
+	 * @return string
72
+	 */
73
+	public function php_version()
74
+	{
75
+		return phpversion();
76
+	}
77
+	/**
78
+	 *
79
+	 * @return array, where each key is a plugin name (lower-cased), values are sub-arrays.
80
+	 * Sub-arrays like described in wp function get_plugin_data. Ie,     *
81
+	 *  'Name' => 'Plugin Name',
82 82
         'PluginURI' => 'Plugin URI',
83 83
         'Version' => 'Version',
84 84
         'Description' => 'Description',
@@ -87,221 +87,221 @@  discard block
 block discarded – undo
87 87
         'TextDomain' => 'Text Domain',
88 88
         'DomainPath' => 'Domain Path',
89 89
         'Network' => 'Network',
90
-     */
91
-    public function get_active_plugins()
92
-    {
93
-        $active_plugins = (array) get_option('active_plugins', array());
94
-        if (is_multisite()) {
95
-            $active_plugins = array_merge($active_plugins, get_site_option('active_sitewide_plugins', array()));
96
-        }
97
-        $active_plugins = array_map('strtolower', $active_plugins);
98
-        $plugin_info = array();
99
-        foreach ($active_plugins as $plugin) {
100
-                $plugin_data = @get_plugin_data(WP_PLUGIN_DIR . '/' . $plugin);
90
+	 */
91
+	public function get_active_plugins()
92
+	{
93
+		$active_plugins = (array) get_option('active_plugins', array());
94
+		if (is_multisite()) {
95
+			$active_plugins = array_merge($active_plugins, get_site_option('active_sitewide_plugins', array()));
96
+		}
97
+		$active_plugins = array_map('strtolower', $active_plugins);
98
+		$plugin_info = array();
99
+		foreach ($active_plugins as $plugin) {
100
+				$plugin_data = @get_plugin_data(WP_PLUGIN_DIR . '/' . $plugin);
101 101
 
102
-                $plugin_info[ $plugin ] = $plugin_data;
103
-        }
104
-        return $plugin_info;
105
-    }
102
+				$plugin_info[ $plugin ] = $plugin_data;
103
+		}
104
+		return $plugin_info;
105
+	}
106 106
 
107
-    /**
108
-     *
109
-     * @return array with keys 'home_url' and 'site_url'
110
-     */
111
-    public function get_wp_settings()
112
-    {
113
-        $wp_memory_int = $this->let_to_num(WP_MEMORY_LIMIT);
114
-        if ($wp_memory_int < 67108864) {
115
-            $wp_memory_to_display = '<mark class="error">' . sprintf(__('%s - We recommend setting memory to at least 64MB. See: %s Increasing memory allocated to PHP %s', 'event_espresso'), WP_MEMORY_LIMIT, '<a href="http://codex.wordpress.org/Editing_wp-config.php#Increasing_memory_allocated_to_PHP">', '</a>"') . '</mark>';
116
-        } else {
117
-            $wp_memory_to_display = '<mark class="yes">' . size_format($wp_memory_int) . '</mark>';
118
-        }
119
-        return array(
120
-            'name'=>get_bloginfo('name', 'display'),
121
-            'is_multisite'=>is_multisite(),
122
-            'version'=>  get_bloginfo('version', 'display'),
123
-            'home_url'=>home_url(),
124
-            'site_url'=>site_url(),
125
-            'WP_DEBUG'=>WP_DEBUG,
126
-            'permalink_structure'=>get_option('permalink_structure'),
127
-            'theme'=>wp_get_theme(),
128
-            'gmt_offset'=>get_option('gmt_offset'),
129
-            'timezone_string'=>get_option('timezone_string'),
130
-            'admin_email'=>  get_bloginfo('admin_email', 'display'),
131
-            'language'=>get_bloginfo('language', 'display'),
132
-            'wp_max_upload_size' => size_format(wp_max_upload_size()),
133
-            'wp_memory' => $wp_memory_to_display
134
-            );
135
-    }
107
+	/**
108
+	 *
109
+	 * @return array with keys 'home_url' and 'site_url'
110
+	 */
111
+	public function get_wp_settings()
112
+	{
113
+		$wp_memory_int = $this->let_to_num(WP_MEMORY_LIMIT);
114
+		if ($wp_memory_int < 67108864) {
115
+			$wp_memory_to_display = '<mark class="error">' . sprintf(__('%s - We recommend setting memory to at least 64MB. See: %s Increasing memory allocated to PHP %s', 'event_espresso'), WP_MEMORY_LIMIT, '<a href="http://codex.wordpress.org/Editing_wp-config.php#Increasing_memory_allocated_to_PHP">', '</a>"') . '</mark>';
116
+		} else {
117
+			$wp_memory_to_display = '<mark class="yes">' . size_format($wp_memory_int) . '</mark>';
118
+		}
119
+		return array(
120
+			'name'=>get_bloginfo('name', 'display'),
121
+			'is_multisite'=>is_multisite(),
122
+			'version'=>  get_bloginfo('version', 'display'),
123
+			'home_url'=>home_url(),
124
+			'site_url'=>site_url(),
125
+			'WP_DEBUG'=>WP_DEBUG,
126
+			'permalink_structure'=>get_option('permalink_structure'),
127
+			'theme'=>wp_get_theme(),
128
+			'gmt_offset'=>get_option('gmt_offset'),
129
+			'timezone_string'=>get_option('timezone_string'),
130
+			'admin_email'=>  get_bloginfo('admin_email', 'display'),
131
+			'language'=>get_bloginfo('language', 'display'),
132
+			'wp_max_upload_size' => size_format(wp_max_upload_size()),
133
+			'wp_memory' => $wp_memory_to_display
134
+			);
135
+	}
136 136
 
137
-    /**
138
-     * Gets an array of information about the history of ee versions installed
139
-     * @return array
140
-     */
141
-    public function get_ee_activation_history()
142
-    {
143
-        return get_option('espresso_db_update');
144
-    }
137
+	/**
138
+	 * Gets an array of information about the history of ee versions installed
139
+	 * @return array
140
+	 */
141
+	public function get_ee_activation_history()
142
+	{
143
+		return get_option('espresso_db_update');
144
+	}
145 145
 
146 146
 
147
-    /**
148
-     * Gets an array where keys are ee versions, and their values are arrays indicating all the different times that version was installed
149
-     * @return EE_Data_Migration_Script_Base[]
150
-     */
151
-    public function get_ee_migration_history()
152
-    {
153
-        $options = EE_Data_Migration_Manager::instance()->get_all_migration_script_options();
154
-        $presentable_migration_scripts = array();
155
-        foreach ($options as $option_array) {
156
-            $presentable_migration_scripts[ str_replace(EE_Data_Migration_Manager::data_migration_script_option_prefix, "", $option_array['option_name']) ] = maybe_unserialize($option_array['option_value']);
157
-        }
158
-        return $presentable_migration_scripts;
147
+	/**
148
+	 * Gets an array where keys are ee versions, and their values are arrays indicating all the different times that version was installed
149
+	 * @return EE_Data_Migration_Script_Base[]
150
+	 */
151
+	public function get_ee_migration_history()
152
+	{
153
+		$options = EE_Data_Migration_Manager::instance()->get_all_migration_script_options();
154
+		$presentable_migration_scripts = array();
155
+		foreach ($options as $option_array) {
156
+			$presentable_migration_scripts[ str_replace(EE_Data_Migration_Manager::data_migration_script_option_prefix, "", $option_array['option_name']) ] = maybe_unserialize($option_array['option_value']);
157
+		}
158
+		return $presentable_migration_scripts;
159 159
 //      return get_option(EE_Data_Migration_Manager::data_migrations_option_name);//EE_Data_Migration_Manager::instance()->get_data_migrations_ran();
160
-    }
160
+	}
161 161
 
162
-    /**
163
-     *
164
-     * @return array like EE_Config class
165
-     */
166
-    public function get_ee_config()
167
-    {
168
-        return EE_Config::instance();
169
-    }
162
+	/**
163
+	 *
164
+	 * @return array like EE_Config class
165
+	 */
166
+	public function get_ee_config()
167
+	{
168
+		return EE_Config::instance();
169
+	}
170 170
 
171
-    /**
172
-     * Gets an array of php setup info, pilfered from http://www.php.net/manual/en/function.phpinfo.php#87463
173
-     * @return array like the output of phpinfo(), but in an array
174
-     */
175
-    public function get_php_info()
176
-    {
177
-        ob_start();
178
-        phpinfo(-1);
171
+	/**
172
+	 * Gets an array of php setup info, pilfered from http://www.php.net/manual/en/function.phpinfo.php#87463
173
+	 * @return array like the output of phpinfo(), but in an array
174
+	 */
175
+	public function get_php_info()
176
+	{
177
+		ob_start();
178
+		phpinfo(-1);
179 179
 
180
-        $pi = preg_replace(
181
-            array('#^.*<body>(.*)</body>.*$#ms', '#<h2>PHP License</h2>.*$#ms',
182
-            '#<h1>Configuration</h1>#',  "#\r?\n#", "#</(h1|h2|h3|tr)>#", '# +<#',
183
-            "#[ \t]+#", '#&nbsp;#', '#  +#', '# class=".*?"#', '%&#039;%',
184
-            '#<tr>(?:.*?)" src="(?:.*?)=(.*?)" alt="PHP Logo" /></a>'
185
-            .'<h1>PHP Version (.*?)</h1>(?:\n+?)</td></tr>#',
186
-            '#<h1><a href="(?:.*?)\?=(.*?)">PHP Credits</a></h1>#',
187
-            '#<tr>(?:.*?)" src="(?:.*?)=(.*?)"(?:.*?)Zend Engine (.*?),(?:.*?)</tr>#',
188
-            "# +#", '#<tr>#', '#</tr>#'),
189
-            array('$1', '', '', '', '</$1>' . "\n", '<', ' ', ' ', ' ', '', ' ',
190
-            '<h2>PHP Configuration</h2>'."\n".'<tr><td>PHP Version</td><td>$2</td></tr>'.
191
-            "\n".'<tr><td>PHP Egg</td><td>$1</td></tr>',
192
-            '<tr><td>PHP Credits Egg</td><td>$1</td></tr>',
193
-            '<tr><td>Zend Engine</td><td>$2</td></tr>' . "\n" .
194
-            '<tr><td>Zend Egg</td><td>$1</td></tr>', ' ', '%S%', '%E%'),
195
-            ob_get_clean()
196
-        );
180
+		$pi = preg_replace(
181
+			array('#^.*<body>(.*)</body>.*$#ms', '#<h2>PHP License</h2>.*$#ms',
182
+			'#<h1>Configuration</h1>#',  "#\r?\n#", "#</(h1|h2|h3|tr)>#", '# +<#',
183
+			"#[ \t]+#", '#&nbsp;#', '#  +#', '# class=".*?"#', '%&#039;%',
184
+			'#<tr>(?:.*?)" src="(?:.*?)=(.*?)" alt="PHP Logo" /></a>'
185
+			.'<h1>PHP Version (.*?)</h1>(?:\n+?)</td></tr>#',
186
+			'#<h1><a href="(?:.*?)\?=(.*?)">PHP Credits</a></h1>#',
187
+			'#<tr>(?:.*?)" src="(?:.*?)=(.*?)"(?:.*?)Zend Engine (.*?),(?:.*?)</tr>#',
188
+			"# +#", '#<tr>#', '#</tr>#'),
189
+			array('$1', '', '', '', '</$1>' . "\n", '<', ' ', ' ', ' ', '', ' ',
190
+			'<h2>PHP Configuration</h2>'."\n".'<tr><td>PHP Version</td><td>$2</td></tr>'.
191
+			"\n".'<tr><td>PHP Egg</td><td>$1</td></tr>',
192
+			'<tr><td>PHP Credits Egg</td><td>$1</td></tr>',
193
+			'<tr><td>Zend Engine</td><td>$2</td></tr>' . "\n" .
194
+			'<tr><td>Zend Egg</td><td>$1</td></tr>', ' ', '%S%', '%E%'),
195
+			ob_get_clean()
196
+		);
197 197
 
198
-        $sections = explode('<h2>', strip_tags($pi, '<h2><th><td>'));
199
-        unset($sections[0]);
198
+		$sections = explode('<h2>', strip_tags($pi, '<h2><th><td>'));
199
+		unset($sections[0]);
200 200
 
201
-        $pi = array();
202
-        foreach ($sections as $section) {
203
-            $n = substr($section, 0, strpos($section, '</h2>'));
204
-            preg_match_all(
205
-                '#%S%(?:<td>(.*?)</td>)?(?:<td>(.*?)</td>)?(?:<td>(.*?)</td>)?%E%#',
206
-                $section,
207
-                $askapache,
208
-                PREG_SET_ORDER
209
-            );
210
-            foreach ($askapache as $m) {
211
-                $m2 = isset($m[2]) ? $m[2] : null;
212
-            }
213
-              $pi[ $n ][ $m[1] ]=(!isset($m[3])||$m2==$m[3]) ? $m2 : array_slice($m, 2);
214
-        }
201
+		$pi = array();
202
+		foreach ($sections as $section) {
203
+			$n = substr($section, 0, strpos($section, '</h2>'));
204
+			preg_match_all(
205
+				'#%S%(?:<td>(.*?)</td>)?(?:<td>(.*?)</td>)?(?:<td>(.*?)</td>)?%E%#',
206
+				$section,
207
+				$askapache,
208
+				PREG_SET_ORDER
209
+			);
210
+			foreach ($askapache as $m) {
211
+				$m2 = isset($m[2]) ? $m[2] : null;
212
+			}
213
+			  $pi[ $n ][ $m[1] ]=(!isset($m[3])||$m2==$m[3]) ? $m2 : array_slice($m, 2);
214
+		}
215 215
 
216
-        return $pi;
217
-    }
216
+		return $pi;
217
+	}
218 218
 
219
-    /**
220
-     * Checks if site responds ot HTTPS
221
-     * @return boolean
222
-     */
223
-    public function get_https_enabled()
224
-    {
225
-        $home = str_replace("http://", "https://", home_url());
226
-        $response = wp_remote_get($home);
227
-        if ($response instanceof WP_Error) {
228
-            $error_string = '';
229
-            foreach ($response->errors as $short_name => $description_array) {
230
-                $error_string .= "<b>$short_name</b>: ".implode(", ", $description_array);
231
-            }
232
-            return $error_string;
233
-        }
234
-        return "ok!";
235
-    }
236
-    /**
237
-     * Whether or not a .maintenance file is detected
238
-     * @return string descripting wp_maintenance_mode status
239
-     */
240
-    public function get_wp_maintenance_mode()
241
-    {
242
-        $opened = file_exists(ABSPATH . '.maintenance');
243
-        return $opened ? sprintf(__('%s.maintenance file detected.%s Wordpress may have a failed auto-update which could prevent Event Espresso from updating the database correctly.', 'event_espresso'), '<strong>', '</strong>') : __('.maintenance file not detected. WordPress is not in maintenance mode.', 'event_espresso')  ;
244
-    }
245
-    /**
246
-     * Whether or not logging is enabled
247
-     * @return string descripting logging's status
248
-     */
249
-    public function get_logging_enabled()
250
-    {
251
-            $opened = @fopen(EVENT_ESPRESSO_UPLOAD_DIR . '/logs/espresso_log.txt', 'a');
252
-            return $opened ? __('Log Directory is writable', 'event_espresso') : sprintf(__('%sLog directory is NOT writable%s', 'event_espresso'), '<mark class="error"', '</mark>') ;
253
-    }
254
-    /**
255
-     *  Whether curl ro fsock works
256
-     * @return string describing posting's status
257
-     */
258
-    public function get_remote_posting()
259
-    {
260
-        $fsock_works = function_exists('fsockopen');
261
-        $curl_works = function_exists('curl_init');
262
-        if ($fsock_works && $curl_works) {
263
-            $status = __('Your server has fsockopen and cURL enabled.', 'event_espresso');
264
-        } elseif ($fsock_works) {
265
-            $status = __('Your server has fsockopen enabled, cURL is disabled.', 'event_espresso');
266
-        } elseif ($curl_works) {
267
-            $status = __('Your server has cURL enabled, fsockopen is disabled.', 'event_espresso');
268
-        } else {
269
-            $status = __('Your server does not have fsockopen or cURL enabled - PayPal IPN and other scripts which communicate with other servers will not work. Contact your hosting provider.', 'event_espresso'). '</mark>';
270
-        }
271
-        return $status;
272
-    }
273
-    /**
274
-     * Gets all the php.ini settings
275
-     * @return array
276
-     */
277
-    public function get_php_ini_all()
278
-    {
279
-        return ini_get_all();
280
-    }
281
-    /**
282
-     * Transforms the php.ini notation for numbers (like '2M') to an integer.
283
-     *
284
-     * @param type $size
285
-     * @return int
286
-     */
287
-    public function let_to_num($size)
288
-    {
289
-        $l      = substr($size, -1);
290
-        $ret    = substr($size, 0, -1);
291
-        // phpcs:disable PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
292
-        switch (strtoupper($l)) {
293
-            case 'P':
294
-                $ret *= 1024;
295
-            case 'T':
296
-                $ret *= 1024;
297
-            case 'G':
298
-                $ret *= 1024;
299
-            case 'M':
300
-                $ret *= 1024;
301
-            case 'K':
302
-                $ret *= 1024;
303
-        }
304
-        // phpcs:enable
305
-        return $ret;
306
-    }
219
+	/**
220
+	 * Checks if site responds ot HTTPS
221
+	 * @return boolean
222
+	 */
223
+	public function get_https_enabled()
224
+	{
225
+		$home = str_replace("http://", "https://", home_url());
226
+		$response = wp_remote_get($home);
227
+		if ($response instanceof WP_Error) {
228
+			$error_string = '';
229
+			foreach ($response->errors as $short_name => $description_array) {
230
+				$error_string .= "<b>$short_name</b>: ".implode(", ", $description_array);
231
+			}
232
+			return $error_string;
233
+		}
234
+		return "ok!";
235
+	}
236
+	/**
237
+	 * Whether or not a .maintenance file is detected
238
+	 * @return string descripting wp_maintenance_mode status
239
+	 */
240
+	public function get_wp_maintenance_mode()
241
+	{
242
+		$opened = file_exists(ABSPATH . '.maintenance');
243
+		return $opened ? sprintf(__('%s.maintenance file detected.%s Wordpress may have a failed auto-update which could prevent Event Espresso from updating the database correctly.', 'event_espresso'), '<strong>', '</strong>') : __('.maintenance file not detected. WordPress is not in maintenance mode.', 'event_espresso')  ;
244
+	}
245
+	/**
246
+	 * Whether or not logging is enabled
247
+	 * @return string descripting logging's status
248
+	 */
249
+	public function get_logging_enabled()
250
+	{
251
+			$opened = @fopen(EVENT_ESPRESSO_UPLOAD_DIR . '/logs/espresso_log.txt', 'a');
252
+			return $opened ? __('Log Directory is writable', 'event_espresso') : sprintf(__('%sLog directory is NOT writable%s', 'event_espresso'), '<mark class="error"', '</mark>') ;
253
+	}
254
+	/**
255
+	 *  Whether curl ro fsock works
256
+	 * @return string describing posting's status
257
+	 */
258
+	public function get_remote_posting()
259
+	{
260
+		$fsock_works = function_exists('fsockopen');
261
+		$curl_works = function_exists('curl_init');
262
+		if ($fsock_works && $curl_works) {
263
+			$status = __('Your server has fsockopen and cURL enabled.', 'event_espresso');
264
+		} elseif ($fsock_works) {
265
+			$status = __('Your server has fsockopen enabled, cURL is disabled.', 'event_espresso');
266
+		} elseif ($curl_works) {
267
+			$status = __('Your server has cURL enabled, fsockopen is disabled.', 'event_espresso');
268
+		} else {
269
+			$status = __('Your server does not have fsockopen or cURL enabled - PayPal IPN and other scripts which communicate with other servers will not work. Contact your hosting provider.', 'event_espresso'). '</mark>';
270
+		}
271
+		return $status;
272
+	}
273
+	/**
274
+	 * Gets all the php.ini settings
275
+	 * @return array
276
+	 */
277
+	public function get_php_ini_all()
278
+	{
279
+		return ini_get_all();
280
+	}
281
+	/**
282
+	 * Transforms the php.ini notation for numbers (like '2M') to an integer.
283
+	 *
284
+	 * @param type $size
285
+	 * @return int
286
+	 */
287
+	public function let_to_num($size)
288
+	{
289
+		$l      = substr($size, -1);
290
+		$ret    = substr($size, 0, -1);
291
+		// phpcs:disable PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
292
+		switch (strtoupper($l)) {
293
+			case 'P':
294
+				$ret *= 1024;
295
+			case 'T':
296
+				$ret *= 1024;
297
+			case 'G':
298
+				$ret *= 1024;
299
+			case 'M':
300
+				$ret *= 1024;
301
+			case 'K':
302
+				$ret *= 1024;
303
+		}
304
+		// phpcs:enable
305
+		return $ret;
306
+	}
307 307
 }
Please login to merge, or discard this patch.
admin_pages/transactions/Transactions_Admin_Page.core.php 2 patches
Indentation   +2464 added lines, -2464 removed lines patch added patch discarded remove patch
@@ -14,2468 +14,2468 @@
 block discarded – undo
14 14
 class Transactions_Admin_Page extends EE_Admin_Page
15 15
 {
16 16
 
17
-    /**
18
-     * @var EE_Transaction
19
-     */
20
-    private $_transaction;
21
-
22
-    /**
23
-     * @var EE_Session
24
-     */
25
-    private $_session;
26
-
27
-    /**
28
-     * @var array $_txn_status
29
-     */
30
-    private static $_txn_status;
31
-
32
-    /**
33
-     * @var array $_pay_status
34
-     */
35
-    private static $_pay_status;
36
-
37
-    /**
38
-     * @var array $_existing_reg_payment_REG_IDs
39
-     */
40
-    protected $_existing_reg_payment_REG_IDs = null;
41
-
42
-
43
-    /**
44
-     * @Constructor
45
-     * @access public
46
-     * @param bool $routing
47
-     * @throws EE_Error
48
-     * @throws InvalidArgumentException
49
-     * @throws ReflectionException
50
-     * @throws InvalidDataTypeException
51
-     * @throws InvalidInterfaceException
52
-     */
53
-    public function __construct($routing = true)
54
-    {
55
-        parent::__construct($routing);
56
-    }
57
-
58
-
59
-    /**
60
-     *    _init_page_props
61
-     *
62
-     * @return void
63
-     */
64
-    protected function _init_page_props()
65
-    {
66
-        $this->page_slug = TXN_PG_SLUG;
67
-        $this->page_label = esc_html__('Transactions', 'event_espresso');
68
-        $this->_admin_base_url = TXN_ADMIN_URL;
69
-        $this->_admin_base_path = TXN_ADMIN;
70
-    }
71
-
72
-
73
-    /**
74
-     *    _ajax_hooks
75
-     *
76
-     * @return void
77
-     */
78
-    protected function _ajax_hooks()
79
-    {
80
-        add_action('wp_ajax_espresso_apply_payment', array($this, 'apply_payments_or_refunds'));
81
-        add_action('wp_ajax_espresso_apply_refund', array($this, 'apply_payments_or_refunds'));
82
-        add_action('wp_ajax_espresso_delete_payment', array($this, 'delete_payment'));
83
-    }
84
-
85
-
86
-    /**
87
-     *    _define_page_props
88
-     *
89
-     * @return void
90
-     */
91
-    protected function _define_page_props()
92
-    {
93
-        $this->_admin_page_title = $this->page_label;
94
-        $this->_labels = array(
95
-            'buttons' => array(
96
-                'add'    => esc_html__('Add New Transaction', 'event_espresso'),
97
-                'edit'   => esc_html__('Edit Transaction', 'event_espresso'),
98
-                'delete' => esc_html__('Delete Transaction', 'event_espresso'),
99
-            ),
100
-        );
101
-    }
102
-
103
-
104
-    /**
105
-     *        grab url requests and route them
106
-     *
107
-     * @access private
108
-     * @return void
109
-     * @throws EE_Error
110
-     * @throws InvalidArgumentException
111
-     * @throws InvalidDataTypeException
112
-     * @throws InvalidInterfaceException
113
-     */
114
-    public function _set_page_routes()
115
-    {
116
-
117
-        $this->_set_transaction_status_array();
118
-
119
-        $txn_id = ! empty($this->_req_data['TXN_ID'])
120
-                  && ! is_array($this->_req_data['TXN_ID'])
121
-            ? $this->_req_data['TXN_ID']
122
-            : 0;
123
-
124
-        $this->_page_routes = array(
125
-
126
-            'default' => array(
127
-                'func'       => '_transactions_overview_list_table',
128
-                'capability' => 'ee_read_transactions',
129
-            ),
130
-
131
-            'view_transaction' => array(
132
-                'func'       => '_transaction_details',
133
-                'capability' => 'ee_read_transaction',
134
-                'obj_id'     => $txn_id,
135
-            ),
136
-
137
-            'send_payment_reminder' => array(
138
-                'func'       => '_send_payment_reminder',
139
-                'noheader'   => true,
140
-                'capability' => 'ee_send_message',
141
-            ),
142
-
143
-            'espresso_apply_payment' => array(
144
-                'func'       => 'apply_payments_or_refunds',
145
-                'noheader'   => true,
146
-                'capability' => 'ee_edit_payments',
147
-            ),
148
-
149
-            'espresso_apply_refund' => array(
150
-                'func'       => 'apply_payments_or_refunds',
151
-                'noheader'   => true,
152
-                'capability' => 'ee_edit_payments',
153
-            ),
154
-
155
-            'espresso_delete_payment' => array(
156
-                'func'       => 'delete_payment',
157
-                'noheader'   => true,
158
-                'capability' => 'ee_delete_payments',
159
-            ),
160
-
161
-        );
162
-    }
163
-
164
-
165
-    protected function _set_page_config()
166
-    {
167
-        $this->_page_config = array(
168
-            'default'          => array(
169
-                'nav'           => array(
170
-                    'label' => esc_html__('Overview', 'event_espresso'),
171
-                    'order' => 10,
172
-                ),
173
-                'list_table'    => 'EE_Admin_Transactions_List_Table',
174
-                'help_tabs'     => array(
175
-                    'transactions_overview_help_tab'                       => array(
176
-                        'title'    => esc_html__('Transactions Overview', 'event_espresso'),
177
-                        'filename' => 'transactions_overview',
178
-                    ),
179
-                    'transactions_overview_table_column_headings_help_tab' => array(
180
-                        'title'    => esc_html__('Transactions Table Column Headings', 'event_espresso'),
181
-                        'filename' => 'transactions_overview_table_column_headings',
182
-                    ),
183
-                    'transactions_overview_views_filters_help_tab'         => array(
184
-                        'title'    => esc_html__('Transaction Views & Filters & Search', 'event_espresso'),
185
-                        'filename' => 'transactions_overview_views_filters_search',
186
-                    ),
187
-                ),
188
-                'help_tour'     => array('Transactions_Overview_Help_Tour'),
189
-                /**
190
-                 * commented out because currently we are not displaying tips for transaction list table status but this
191
-                 * may change in a later iteration so want to keep the code for then.
192
-                 */
193
-                // 'qtips' => array( 'Transactions_List_Table_Tips' ),
194
-                'require_nonce' => false,
195
-            ),
196
-            'view_transaction' => array(
197
-                'nav'       => array(
198
-                    'label'      => esc_html__('View Transaction', 'event_espresso'),
199
-                    'order'      => 5,
200
-                    'url'        => isset($this->_req_data['TXN_ID'])
201
-                        ? add_query_arg(array('TXN_ID' => $this->_req_data['TXN_ID']), $this->_current_page_view_url)
202
-                        : $this->_admin_base_url,
203
-                    'persistent' => false,
204
-                ),
205
-                'help_tabs' => array(
206
-                    'transactions_view_transaction_help_tab'                                              => array(
207
-                        'title'    => esc_html__('View Transaction', 'event_espresso'),
208
-                        'filename' => 'transactions_view_transaction',
209
-                    ),
210
-                    'transactions_view_transaction_transaction_details_table_help_tab'                    => array(
211
-                        'title'    => esc_html__('Transaction Details Table', 'event_espresso'),
212
-                        'filename' => 'transactions_view_transaction_transaction_details_table',
213
-                    ),
214
-                    'transactions_view_transaction_attendees_registered_help_tab'                         => array(
215
-                        'title'    => esc_html__('Attendees Registered', 'event_espresso'),
216
-                        'filename' => 'transactions_view_transaction_attendees_registered',
217
-                    ),
218
-                    'transactions_view_transaction_views_primary_registrant_billing_information_help_tab' => array(
219
-                        'title'    => esc_html__('Primary Registrant & Billing Information', 'event_espresso'),
220
-                        'filename' => 'transactions_view_transaction_primary_registrant_billing_information',
221
-                    ),
222
-                ),
223
-                'qtips'     => array('Transaction_Details_Tips'),
224
-                'help_tour' => array('Transaction_Details_Help_Tour'),
225
-                'metaboxes' => array('_transaction_details_metaboxes'),
226
-
227
-                'require_nonce' => false,
228
-            ),
229
-        );
230
-    }
231
-
232
-
233
-    /**
234
-     * The below methods aren't used by this class currently
235
-     */
236
-    protected function _add_screen_options()
237
-    {
238
-        // noop
239
-    }
240
-
241
-    protected function _add_feature_pointers()
242
-    {
243
-        // noop
244
-    }
245
-
246
-    public function admin_init()
247
-    {
248
-        // IF a registration was JUST added via the admin...
249
-        if (isset(
250
-            $this->_req_data['redirect_from'],
251
-            $this->_req_data['EVT_ID'],
252
-            $this->_req_data['event_name']
253
-        )) {
254
-            // then set a cookie so that we can block any attempts to use
255
-            // the back button as a way to enter another registration.
256
-            setcookie(
257
-                'ee_registration_added',
258
-                $this->_req_data['EVT_ID'],
259
-                time() + WEEK_IN_SECONDS,
260
-                '/'
261
-            );
262
-            // and update the global
263
-            $_COOKIE['ee_registration_added'] = $this->_req_data['EVT_ID'];
264
-        }
265
-        EE_Registry::$i18n_js_strings['invalid_server_response'] = esc_html__(
266
-            'An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
267
-            'event_espresso'
268
-        );
269
-        EE_Registry::$i18n_js_strings['error_occurred'] = esc_html__(
270
-            'An error occurred! Please refresh the page and try again.',
271
-            'event_espresso'
272
-        );
273
-        EE_Registry::$i18n_js_strings['txn_status_array'] = self::$_txn_status;
274
-        EE_Registry::$i18n_js_strings['pay_status_array'] = self::$_pay_status;
275
-        EE_Registry::$i18n_js_strings['payments_total'] = esc_html__('Payments Total', 'event_espresso');
276
-        EE_Registry::$i18n_js_strings['transaction_overpaid'] = esc_html__(
277
-            'This transaction has been overpaid ! Payments Total',
278
-            'event_espresso'
279
-        );
280
-    }
281
-
282
-    public function admin_notices()
283
-    {
284
-        // noop
285
-    }
286
-
287
-    public function admin_footer_scripts()
288
-    {
289
-        // noop
290
-    }
291
-
292
-
293
-    /**
294
-     * _set_transaction_status_array
295
-     * sets list of transaction statuses
296
-     *
297
-     * @access private
298
-     * @return void
299
-     * @throws EE_Error
300
-     * @throws InvalidArgumentException
301
-     * @throws InvalidDataTypeException
302
-     * @throws InvalidInterfaceException
303
-     */
304
-    private function _set_transaction_status_array()
305
-    {
306
-        self::$_txn_status = EEM_Transaction::instance()->status_array(true);
307
-    }
308
-
309
-
310
-    /**
311
-     * get_transaction_status_array
312
-     * return the transaction status array for wp_list_table
313
-     *
314
-     * @access public
315
-     * @return array
316
-     */
317
-    public function get_transaction_status_array()
318
-    {
319
-        return self::$_txn_status;
320
-    }
321
-
322
-
323
-    /**
324
-     *    get list of payment statuses
325
-     *
326
-     * @access private
327
-     * @return void
328
-     * @throws EE_Error
329
-     * @throws InvalidArgumentException
330
-     * @throws InvalidDataTypeException
331
-     * @throws InvalidInterfaceException
332
-     */
333
-    private function _get_payment_status_array()
334
-    {
335
-        self::$_pay_status = EEM_Payment::instance()->status_array(true);
336
-        $this->_template_args['payment_status'] = self::$_pay_status;
337
-    }
338
-
339
-
340
-    /**
341
-     *    _add_screen_options_default
342
-     *
343
-     * @access protected
344
-     * @return void
345
-     * @throws InvalidArgumentException
346
-     * @throws InvalidDataTypeException
347
-     * @throws InvalidInterfaceException
348
-     */
349
-    protected function _add_screen_options_default()
350
-    {
351
-        $this->_per_page_screen_option();
352
-    }
353
-
354
-
355
-    /**
356
-     * load_scripts_styles
357
-     *
358
-     * @access public
359
-     * @return void
360
-     */
361
-    public function load_scripts_styles()
362
-    {
363
-        // enqueue style
364
-        wp_register_style(
365
-            'espresso_txn',
366
-            TXN_ASSETS_URL . 'espresso_transactions_admin.css',
367
-            array(),
368
-            EVENT_ESPRESSO_VERSION
369
-        );
370
-        wp_enqueue_style('espresso_txn');
371
-        // scripts
372
-        wp_register_script(
373
-            'espresso_txn',
374
-            TXN_ASSETS_URL . 'espresso_transactions_admin.js',
375
-            array(
376
-                'ee_admin_js',
377
-                'ee-datepicker',
378
-                'jquery-ui-datepicker',
379
-                'jquery-ui-draggable',
380
-                'ee-dialog',
381
-                'ee-accounting',
382
-                'ee-serialize-full-array',
383
-            ),
384
-            EVENT_ESPRESSO_VERSION,
385
-            true
386
-        );
387
-        wp_enqueue_script('espresso_txn');
388
-    }
389
-
390
-
391
-    /**
392
-     *    load_scripts_styles_view_transaction
393
-     *
394
-     * @access public
395
-     * @return void
396
-     */
397
-    public function load_scripts_styles_view_transaction()
398
-    {
399
-        // styles
400
-        wp_enqueue_style('espresso-ui-theme');
401
-    }
402
-
403
-
404
-    /**
405
-     *    load_scripts_styles_default
406
-     *
407
-     * @access public
408
-     * @return void
409
-     */
410
-    public function load_scripts_styles_default()
411
-    {
412
-        // styles
413
-        wp_enqueue_style('espresso-ui-theme');
414
-    }
415
-
416
-
417
-    /**
418
-     *    _set_list_table_views_default
419
-     *
420
-     * @access protected
421
-     * @return void
422
-     */
423
-    protected function _set_list_table_views_default()
424
-    {
425
-        $this->_views = array(
426
-            'all'       => array(
427
-                'slug'  => 'all',
428
-                'label' => esc_html__('View All Transactions', 'event_espresso'),
429
-                'count' => 0,
430
-            ),
431
-            'abandoned' => array(
432
-                'slug'  => 'abandoned',
433
-                'label' => esc_html__('Abandoned Transactions', 'event_espresso'),
434
-                'count' => 0,
435
-            ),
436
-            'failed'    => array(
437
-                'slug'  => 'failed',
438
-                'label' => esc_html__('Failed Transactions', 'event_espresso'),
439
-                'count' => 0,
440
-            ),
441
-        );
442
-    }
443
-
444
-
445
-    /**
446
-     * _set_transaction_object
447
-     * This sets the _transaction property for the transaction details screen
448
-     *
449
-     * @access private
450
-     * @return void
451
-     * @throws EE_Error
452
-     * @throws InvalidArgumentException
453
-     * @throws RuntimeException
454
-     * @throws InvalidDataTypeException
455
-     * @throws InvalidInterfaceException
456
-     * @throws ReflectionException
457
-     */
458
-    private function _set_transaction_object()
459
-    {
460
-        if ($this->_transaction instanceof EE_Transaction) {
461
-            return;
462
-        } //get out we've already set the object
463
-
464
-        $TXN_ID = ! empty($this->_req_data['TXN_ID'])
465
-            ? absint($this->_req_data['TXN_ID'])
466
-            : false;
467
-
468
-        // get transaction object
469
-        $this->_transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
470
-        $this->_session = $this->_transaction instanceof EE_Transaction
471
-            ? $this->_transaction->get('TXN_session_data')
472
-            : null;
473
-        if ($this->_transaction instanceof EE_Transaction) {
474
-            $this->_transaction->verify_abandoned_transaction_status();
475
-        }
476
-
477
-        if (! $this->_transaction instanceof EE_Transaction) {
478
-            $error_msg = sprintf(
479
-                esc_html__(
480
-                    'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
481
-                    'event_espresso'
482
-                ),
483
-                $TXN_ID
484
-            );
485
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
486
-        }
487
-    }
488
-
489
-
490
-    /**
491
-     *    _transaction_legend_items
492
-     *
493
-     * @access protected
494
-     * @return array
495
-     * @throws EE_Error
496
-     * @throws InvalidArgumentException
497
-     * @throws ReflectionException
498
-     * @throws InvalidDataTypeException
499
-     * @throws InvalidInterfaceException
500
-     */
501
-    protected function _transaction_legend_items()
502
-    {
503
-        EE_Registry::instance()->load_helper('MSG_Template');
504
-        $items = array();
505
-
506
-        if (EE_Registry::instance()->CAP->current_user_can(
507
-            'ee_read_global_messages',
508
-            'view_filtered_messages'
509
-        )) {
510
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
511
-            if (is_array($related_for_icon)
512
-                && isset($related_for_icon['css_class'], $related_for_icon['label'])
513
-            ) {
514
-                $items['view_related_messages'] = array(
515
-                    'class' => $related_for_icon['css_class'],
516
-                    'desc'  => $related_for_icon['label'],
517
-                );
518
-            }
519
-        }
520
-
521
-        $items = apply_filters(
522
-            'FHEE__Transactions_Admin_Page___transaction_legend_items__items',
523
-            array_merge(
524
-                $items,
525
-                array(
526
-                    'view_details'          => array(
527
-                        'class' => 'dashicons dashicons-cart',
528
-                        'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
529
-                    ),
530
-                    'view_invoice'          => array(
531
-                        'class' => 'dashicons dashicons-media-spreadsheet',
532
-                        'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
533
-                    ),
534
-                    'view_receipt'          => array(
535
-                        'class' => 'dashicons dashicons-media-default',
536
-                        'desc'  => esc_html__('View Transaction Receipt', 'event_espresso'),
537
-                    ),
538
-                    'view_registration'     => array(
539
-                        'class' => 'dashicons dashicons-clipboard',
540
-                        'desc'  => esc_html__('View Registration Details', 'event_espresso'),
541
-                    ),
542
-                    'payment_overview_link' => array(
543
-                        'class' => 'dashicons dashicons-money',
544
-                        'desc'  => esc_html__('Make Payment on Frontend', 'event_espresso'),
545
-                    ),
546
-                )
547
-            )
548
-        );
549
-
550
-        if (EE_Registry::instance()->CAP->current_user_can(
551
-            'ee_send_message',
552
-            'espresso_transactions_send_payment_reminder'
553
-        )) {
554
-            if (EEH_MSG_Template::is_mt_active('payment_reminder')) {
555
-                $items['send_payment_reminder'] = array(
556
-                    'class' => 'dashicons dashicons-email-alt',
557
-                    'desc'  => esc_html__('Send Payment Reminder', 'event_espresso'),
558
-                );
559
-            } else {
560
-                $items['blank*'] = array(
561
-                    'class' => '',
562
-                    'desc'  => '',
563
-                );
564
-            }
565
-        } else {
566
-            $items['blank*'] = array(
567
-                'class' => '',
568
-                'desc'  => '',
569
-            );
570
-        }
571
-        $more_items = apply_filters(
572
-            'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
573
-            array(
574
-                'overpaid'   => array(
575
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::overpaid_status_code,
576
-                    'desc'  => EEH_Template::pretty_status(
577
-                        EEM_Transaction::overpaid_status_code,
578
-                        false,
579
-                        'sentence'
580
-                    ),
581
-                ),
582
-                'complete'   => array(
583
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::complete_status_code,
584
-                    'desc'  => EEH_Template::pretty_status(
585
-                        EEM_Transaction::complete_status_code,
586
-                        false,
587
-                        'sentence'
588
-                    ),
589
-                ),
590
-                'incomplete' => array(
591
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::incomplete_status_code,
592
-                    'desc'  => EEH_Template::pretty_status(
593
-                        EEM_Transaction::incomplete_status_code,
594
-                        false,
595
-                        'sentence'
596
-                    ),
597
-                ),
598
-                'abandoned'  => array(
599
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::abandoned_status_code,
600
-                    'desc'  => EEH_Template::pretty_status(
601
-                        EEM_Transaction::abandoned_status_code,
602
-                        false,
603
-                        'sentence'
604
-                    ),
605
-                ),
606
-                'failed'     => array(
607
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::failed_status_code,
608
-                    'desc'  => EEH_Template::pretty_status(
609
-                        EEM_Transaction::failed_status_code,
610
-                        false,
611
-                        'sentence'
612
-                    ),
613
-                ),
614
-            )
615
-        );
616
-
617
-        return array_merge($items, $more_items);
618
-    }
619
-
620
-
621
-    /**
622
-     *    _transactions_overview_list_table
623
-     *
624
-     * @access protected
625
-     * @return void
626
-     * @throws DomainException
627
-     * @throws EE_Error
628
-     * @throws InvalidArgumentException
629
-     * @throws InvalidDataTypeException
630
-     * @throws InvalidInterfaceException
631
-     * @throws ReflectionException
632
-     */
633
-    protected function _transactions_overview_list_table()
634
-    {
635
-        $this->_admin_page_title = esc_html__('Transactions', 'event_espresso');
636
-        $event = isset($this->_req_data['EVT_ID'])
637
-            ? EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID'])
638
-            : null;
639
-        $this->_template_args['admin_page_header'] = $event instanceof EE_Event
640
-            ? sprintf(
641
-                esc_html__(
642
-                    '%sViewing Transactions for the Event: %s%s',
643
-                    'event_espresso'
644
-                ),
645
-                '<h3>',
646
-                '<a href="'
647
-                . EE_Admin_Page::add_query_args_and_nonce(
648
-                    array('action' => 'edit', 'post' => $event->ID()),
649
-                    EVENTS_ADMIN_URL
650
-                )
651
-                . '" title="'
652
-                . esc_attr__(
653
-                    'Click to Edit event',
654
-                    'event_espresso'
655
-                )
656
-                . '">' . $event->get('EVT_name') . '</a>',
657
-                '</h3>'
658
-            )
659
-            : '';
660
-        $this->_template_args['after_list_table'] = $this->_display_legend($this->_transaction_legend_items());
661
-        $this->display_admin_list_table_page_with_no_sidebar();
662
-    }
663
-
664
-
665
-    /**
666
-     *    _transaction_details
667
-     * generates HTML for the View Transaction Details Admin page
668
-     *
669
-     * @access protected
670
-     * @return void
671
-     * @throws DomainException
672
-     * @throws EE_Error
673
-     * @throws InvalidArgumentException
674
-     * @throws InvalidDataTypeException
675
-     * @throws InvalidInterfaceException
676
-     * @throws RuntimeException
677
-     * @throws ReflectionException
678
-     */
679
-    protected function _transaction_details()
680
-    {
681
-        do_action('AHEE__Transactions_Admin_Page__transaction_details__start', $this->_transaction);
682
-
683
-        $this->_set_transaction_status_array();
684
-
685
-        $this->_template_args = array();
686
-        $this->_template_args['transactions_page'] = $this->_wp_page_slug;
687
-
688
-        $this->_set_transaction_object();
689
-
690
-        if (! $this->_transaction instanceof EE_Transaction) {
691
-            return;
692
-        }
693
-        $primary_registration = $this->_transaction->primary_registration();
694
-        $attendee = $primary_registration instanceof EE_Registration
695
-            ? $primary_registration->attendee()
696
-            : null;
697
-
698
-        $this->_template_args['txn_nmbr']['value'] = $this->_transaction->ID();
699
-        $this->_template_args['txn_nmbr']['label'] = esc_html__('Transaction Number', 'event_espresso');
700
-
701
-        $this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
702
-        $this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
703
-
704
-        $this->_template_args['txn_status']['value'] = self::$_txn_status[ $this->_transaction->get('STS_ID') ];
705
-        $this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
706
-        $this->_template_args['txn_status']['class'] = 'status-' . $this->_transaction->get('STS_ID');
707
-
708
-        $this->_template_args['grand_total'] = $this->_transaction->get('TXN_total');
709
-        $this->_template_args['total_paid'] = $this->_transaction->get('TXN_paid');
710
-
711
-        $amount_due = $this->_transaction->get('TXN_total') - $this->_transaction->get('TXN_paid');
712
-        $this->_template_args['amount_due'] = EEH_Template::format_currency(
713
-            $amount_due,
714
-            true
715
-        );
716
-        if (EE_Registry::instance()->CFG->currency->sign_b4) {
717
-            $this->_template_args['amount_due'] = EE_Registry::instance()->CFG->currency->sign
718
-                                                  . $this->_template_args['amount_due'];
719
-        } else {
720
-            $this->_template_args['amount_due'] .= EE_Registry::instance()->CFG->currency->sign;
721
-        }
722
-        $this->_template_args['amount_due_class'] = '';
723
-
724
-        if ($this->_transaction->get('TXN_paid') == $this->_transaction->get('TXN_total')) {
725
-            // paid in full
726
-            $this->_template_args['amount_due'] = false;
727
-        } elseif ($this->_transaction->get('TXN_paid') > $this->_transaction->get('TXN_total')) {
728
-            // overpaid
729
-            $this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
730
-        } elseif ($this->_transaction->get('TXN_total') > 0
731
-                  && $this->_transaction->get('TXN_paid') > 0
732
-        ) {
733
-            // monies owing
734
-            $this->_template_args['amount_due_class'] = 'txn-overview-part-payment-spn';
735
-        } elseif ($this->_transaction->get('TXN_total') > 0
736
-                  && $this->_transaction->get('TXN_paid') == 0
737
-        ) {
738
-            // no payments made yet
739
-            $this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
740
-        } elseif ($this->_transaction->get('TXN_total') == 0) {
741
-            // free event
742
-            $this->_template_args['amount_due'] = false;
743
-        }
744
-
745
-        $payment_method = $this->_transaction->payment_method();
746
-
747
-        $this->_template_args['method_of_payment_name'] = $payment_method instanceof EE_Payment_Method
748
-            ? $payment_method->admin_name()
749
-            : esc_html__('Unknown', 'event_espresso');
750
-
751
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
752
-        // link back to overview
753
-        $this->_template_args['txn_overview_url'] = ! empty($_SERVER['HTTP_REFERER'])
754
-            ? $_SERVER['HTTP_REFERER']
755
-            : TXN_ADMIN_URL;
756
-
757
-
758
-        // next link
759
-        $next_txn = $this->_transaction->next(
760
-            null,
761
-            array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
762
-            'TXN_ID'
763
-        );
764
-        $this->_template_args['next_transaction'] = $next_txn
765
-            ? $this->_next_link(
766
-                EE_Admin_Page::add_query_args_and_nonce(
767
-                    array('action' => 'view_transaction', 'TXN_ID' => $next_txn['TXN_ID']),
768
-                    TXN_ADMIN_URL
769
-                ),
770
-                'dashicons dashicons-arrow-right ee-icon-size-22'
771
-            )
772
-            : '';
773
-        // previous link
774
-        $previous_txn = $this->_transaction->previous(
775
-            null,
776
-            array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
777
-            'TXN_ID'
778
-        );
779
-        $this->_template_args['previous_transaction'] = $previous_txn
780
-            ? $this->_previous_link(
781
-                EE_Admin_Page::add_query_args_and_nonce(
782
-                    array('action' => 'view_transaction', 'TXN_ID' => $previous_txn['TXN_ID']),
783
-                    TXN_ADMIN_URL
784
-                ),
785
-                'dashicons dashicons-arrow-left ee-icon-size-22'
786
-            )
787
-            : '';
788
-
789
-        // were we just redirected here after adding a new registration ???
790
-        if (isset(
791
-            $this->_req_data['redirect_from'],
792
-            $this->_req_data['EVT_ID'],
793
-            $this->_req_data['event_name']
794
-        )) {
795
-            if (EE_Registry::instance()->CAP->current_user_can(
796
-                'ee_edit_registrations',
797
-                'espresso_registrations_new_registration',
798
-                $this->_req_data['EVT_ID']
799
-            )) {
800
-                $this->_admin_page_title .= '<a id="add-new-registration" class="add-new-h2 button-primary" href="';
801
-                $this->_admin_page_title .= EE_Admin_Page::add_query_args_and_nonce(
802
-                    array(
803
-                        'page'     => 'espresso_registrations',
804
-                        'action'   => 'new_registration',
805
-                        'return'   => 'default',
806
-                        'TXN_ID'   => $this->_transaction->ID(),
807
-                        'event_id' => $this->_req_data['EVT_ID'],
808
-                    ),
809
-                    REG_ADMIN_URL
810
-                );
811
-                $this->_admin_page_title .= '">';
812
-
813
-                $this->_admin_page_title .= sprintf(
814
-                    esc_html__('Add Another New Registration to Event: "%1$s" ?', 'event_espresso'),
815
-                    htmlentities(urldecode($this->_req_data['event_name']), ENT_QUOTES, 'UTF-8')
816
-                );
817
-                $this->_admin_page_title .= '</a>';
818
-            }
819
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
820
-        }
821
-        // grab messages at the last second
822
-        $this->_template_args['notices'] = EE_Error::get_notices();
823
-        // path to template
824
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
825
-        $this->_template_args['admin_page_header'] = EEH_Template::display_template(
826
-            $template_path,
827
-            $this->_template_args,
828
-            true
829
-        );
830
-
831
-        // the details template wrapper
832
-        $this->display_admin_page_with_sidebar();
833
-    }
834
-
835
-
836
-    /**
837
-     *        _transaction_details_metaboxes
838
-     *
839
-     * @access protected
840
-     * @return void
841
-     * @throws EE_Error
842
-     * @throws InvalidArgumentException
843
-     * @throws InvalidDataTypeException
844
-     * @throws InvalidInterfaceException
845
-     * @throws RuntimeException
846
-     * @throws ReflectionException
847
-     */
848
-    protected function _transaction_details_metaboxes()
849
-    {
850
-
851
-        $this->_set_transaction_object();
852
-
853
-        if (! $this->_transaction instanceof EE_Transaction) {
854
-            return;
855
-        }
856
-        add_meta_box(
857
-            'edit-txn-details-mbox',
858
-            esc_html__('Transaction Details', 'event_espresso'),
859
-            array($this, 'txn_details_meta_box'),
860
-            $this->_wp_page_slug,
861
-            'normal',
862
-            'high'
863
-        );
864
-        add_meta_box(
865
-            'edit-txn-attendees-mbox',
866
-            esc_html__('Attendees Registered in this Transaction', 'event_espresso'),
867
-            array($this, 'txn_attendees_meta_box'),
868
-            $this->_wp_page_slug,
869
-            'normal',
870
-            'high',
871
-            array('TXN_ID' => $this->_transaction->ID())
872
-        );
873
-        add_meta_box(
874
-            'edit-txn-registrant-mbox',
875
-            esc_html__('Primary Contact', 'event_espresso'),
876
-            array($this, 'txn_registrant_side_meta_box'),
877
-            $this->_wp_page_slug,
878
-            'side',
879
-            'high'
880
-        );
881
-        add_meta_box(
882
-            'edit-txn-billing-info-mbox',
883
-            esc_html__('Billing Information', 'event_espresso'),
884
-            array($this, 'txn_billing_info_side_meta_box'),
885
-            $this->_wp_page_slug,
886
-            'side',
887
-            'high'
888
-        );
889
-    }
890
-
891
-
892
-    /**
893
-     * Callback for transaction actions metabox.
894
-     *
895
-     * @param EE_Transaction|null $transaction
896
-     * @throws DomainException
897
-     * @throws EE_Error
898
-     * @throws InvalidArgumentException
899
-     * @throws InvalidDataTypeException
900
-     * @throws InvalidInterfaceException
901
-     * @throws ReflectionException
902
-     * @throws RuntimeException
903
-     */
904
-    public function getActionButtons(EE_Transaction $transaction = null)
905
-    {
906
-        $content = '';
907
-        $actions = array();
908
-        if (! $transaction instanceof EE_Transaction) {
909
-            return $content;
910
-        }
911
-        /** @var EE_Registration $primary_registration */
912
-        $primary_registration = $transaction->primary_registration();
913
-        $attendee = $primary_registration instanceof EE_Registration
914
-            ? $primary_registration->attendee()
915
-            : null;
916
-
917
-        if ($attendee instanceof EE_Attendee
918
-            && EE_Registry::instance()->CAP->current_user_can(
919
-                'ee_send_message',
920
-                'espresso_transactions_send_payment_reminder'
921
-            )
922
-        ) {
923
-            $actions['payment_reminder'] =
924
-                EEH_MSG_Template::is_mt_active('payment_reminder')
925
-                && $this->_transaction->get('STS_ID') !== EEM_Transaction::complete_status_code
926
-                && $this->_transaction->get('STS_ID') !== EEM_Transaction::overpaid_status_code
927
-                    ? EEH_Template::get_button_or_link(
928
-                        EE_Admin_Page::add_query_args_and_nonce(
929
-                            array(
930
-                                'action'      => 'send_payment_reminder',
931
-                                'TXN_ID'      => $this->_transaction->ID(),
932
-                                'redirect_to' => 'view_transaction',
933
-                            ),
934
-                            TXN_ADMIN_URL
935
-                        ),
936
-                        esc_html__(' Send Payment Reminder', 'event_espresso'),
937
-                        'button secondary-button',
938
-                        'dashicons dashicons-email-alt'
939
-                    )
940
-                    : '';
941
-        }
942
-
943
-        if ($primary_registration instanceof EE_Registration
944
-            && EEH_MSG_Template::is_mt_active('receipt')
945
-        ) {
946
-            $actions['receipt'] = EEH_Template::get_button_or_link(
947
-                $primary_registration->receipt_url(),
948
-                esc_html__('View Receipt', 'event_espresso'),
949
-                'button secondary-button',
950
-                'dashicons dashicons-media-default'
951
-            );
952
-        }
953
-
954
-        if ($primary_registration instanceof EE_Registration
955
-            && EEH_MSG_Template::is_mt_active('invoice')
956
-        ) {
957
-            $actions['invoice'] = EEH_Template::get_button_or_link(
958
-                $primary_registration->invoice_url(),
959
-                esc_html__('View Invoice', 'event_espresso'),
960
-                'button secondary-button',
961
-                'dashicons dashicons-media-spreadsheet'
962
-            );
963
-        }
964
-        $actions = array_filter(
965
-            apply_filters('FHEE__Transactions_Admin_Page__getActionButtons__actions', $actions, $transaction)
966
-        );
967
-        if ($actions) {
968
-            $content = '<ul>';
969
-            $content .= '<li>' . implode('</li><li>', $actions) . '</li>';
970
-            $content .= '</uL>';
971
-        }
972
-        return $content;
973
-    }
974
-
975
-
976
-    /**
977
-     * txn_details_meta_box
978
-     * generates HTML for the Transaction main meta box
979
-     *
980
-     * @return void
981
-     * @throws DomainException
982
-     * @throws EE_Error
983
-     * @throws InvalidArgumentException
984
-     * @throws InvalidDataTypeException
985
-     * @throws InvalidInterfaceException
986
-     * @throws RuntimeException
987
-     * @throws ReflectionException
988
-     */
989
-    public function txn_details_meta_box()
990
-    {
991
-        $this->_set_transaction_object();
992
-        $this->_template_args['TXN_ID'] = $this->_transaction->ID();
993
-        $this->_template_args['attendee'] = $this->_transaction->primary_registration() instanceof EE_Registration
994
-            ? $this->_transaction->primary_registration()->attendee()
995
-            : null;
996
-        $this->_template_args['can_edit_payments'] = EE_Registry::instance()->CAP->current_user_can(
997
-            'ee_edit_payments',
998
-            'apply_payment_or_refund_from_registration_details'
999
-        );
1000
-        $this->_template_args['can_delete_payments'] = EE_Registry::instance()->CAP->current_user_can(
1001
-            'ee_delete_payments',
1002
-            'delete_payment_from_registration_details'
1003
-        );
1004
-
1005
-        // get line table
1006
-        EEH_Autoloader::register_line_item_display_autoloaders();
1007
-        $Line_Item_Display = new EE_Line_Item_Display(
1008
-            'admin_table',
1009
-            'EE_Admin_Table_Line_Item_Display_Strategy'
1010
-        );
1011
-        $this->_template_args['line_item_table'] = $Line_Item_Display->display_line_item(
1012
-            $this->_transaction->total_line_item()
1013
-        );
1014
-        $this->_template_args['REG_code'] = $this->_transaction->get_first_related('Registration')
1015
-                                                               ->get('REG_code');
1016
-
1017
-        // process taxes
1018
-        $taxes = $this->_transaction->get_many_related(
1019
-            'Line_Item',
1020
-            array(array('LIN_type' => EEM_Line_Item::type_tax))
1021
-        );
1022
-        $this->_template_args['taxes'] = ! empty($taxes) ? $taxes : false;
1023
-
1024
-        $this->_template_args['grand_total'] = EEH_Template::format_currency(
1025
-            $this->_transaction->get('TXN_total'),
1026
-            false,
1027
-            false
1028
-        );
1029
-        $this->_template_args['grand_raw_total'] = $this->_transaction->get('TXN_total');
1030
-        $this->_template_args['TXN_status'] = $this->_transaction->get('STS_ID');
1031
-
1032
-        // process payment details
1033
-        $payments = $this->_transaction->get_many_related('Payment');
1034
-        if (! empty($payments)) {
1035
-            $this->_template_args['payments'] = $payments;
1036
-            $this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1037
-        } else {
1038
-            $this->_template_args['payments'] = false;
1039
-            $this->_template_args['existing_reg_payments'] = array();
1040
-        }
1041
-
1042
-        $this->_template_args['edit_payment_url'] = add_query_arg(array('action' => 'edit_payment'), TXN_ADMIN_URL);
1043
-        $this->_template_args['delete_payment_url'] = add_query_arg(
1044
-            array('action' => 'espresso_delete_payment'),
1045
-            TXN_ADMIN_URL
1046
-        );
1047
-
1048
-        if (isset($txn_details['invoice_number'])) {
1049
-            $this->_template_args['txn_details']['invoice_number']['value'] = $this->_template_args['REG_code'];
1050
-            $this->_template_args['txn_details']['invoice_number']['label'] = esc_html__(
1051
-                'Invoice Number',
1052
-                'event_espresso'
1053
-            );
1054
-        }
1055
-
1056
-        $this->_template_args['txn_details']['registration_session']['value'] = $this->_transaction
1057
-            ->get_first_related('Registration')
1058
-            ->get('REG_session');
1059
-        $this->_template_args['txn_details']['registration_session']['label'] = esc_html__(
1060
-            'Registration Session',
1061
-            'event_espresso'
1062
-        );
1063
-
1064
-        $this->_template_args['txn_details']['ip_address']['value'] = isset($this->_session['ip_address'])
1065
-            ? $this->_session['ip_address']
1066
-            : '';
1067
-        $this->_template_args['txn_details']['ip_address']['label'] = esc_html__(
1068
-            'Transaction placed from IP',
1069
-            'event_espresso'
1070
-        );
1071
-
1072
-        $this->_template_args['txn_details']['user_agent']['value'] = isset($this->_session['user_agent'])
1073
-            ? $this->_session['user_agent']
1074
-            : '';
1075
-        $this->_template_args['txn_details']['user_agent']['label'] = esc_html__(
1076
-            'Registrant User Agent',
1077
-            'event_espresso'
1078
-        );
1079
-
1080
-        $reg_steps = '<ul>';
1081
-        foreach ($this->_transaction->reg_steps() as $reg_step => $reg_step_status) {
1082
-            if ($reg_step_status === true) {
1083
-                $reg_steps .= '<li style="color:#70cc50">'
1084
-                              . sprintf(
1085
-                                  esc_html__('%1$s : Completed', 'event_espresso'),
1086
-                                  ucwords(str_replace('_', ' ', $reg_step))
1087
-                              )
1088
-                              . '</li>';
1089
-            } elseif (is_numeric($reg_step_status) && $reg_step_status !== false) {
1090
-                $reg_steps .= '<li style="color:#2EA2CC">'
1091
-                              . sprintf(
1092
-                                  esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1093
-                                  ucwords(str_replace('_', ' ', $reg_step)),
1094
-                                  date(
1095
-                                      get_option('date_format') . ' ' . get_option('time_format'),
1096
-                                      ($reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS))
1097
-                                  )
1098
-                              )
1099
-                              . '</li>';
1100
-            } else {
1101
-                $reg_steps .= '<li style="color:#E76700">'
1102
-                              . sprintf(
1103
-                                  esc_html__('%1$s : Never Initiated', 'event_espresso'),
1104
-                                  ucwords(str_replace('_', ' ', $reg_step))
1105
-                              )
1106
-                              . '</li>';
1107
-            }
1108
-        }
1109
-        $reg_steps .= '</ul>';
1110
-        $this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
1111
-        $this->_template_args['txn_details']['reg_steps']['label'] = esc_html__(
1112
-            'Registration Step Progress',
1113
-            'event_espresso'
1114
-        );
1115
-
1116
-
1117
-        $this->_get_registrations_to_apply_payment_to();
1118
-        $this->_get_payment_methods($payments);
1119
-        $this->_get_payment_status_array();
1120
-        $this->_get_reg_status_selection(); // sets up the template args for the reg status array for the transaction.
1121
-
1122
-        $this->_template_args['transaction_form_url'] = add_query_arg(
1123
-            array(
1124
-                'action'  => 'edit_transaction',
1125
-                'process' => 'transaction',
1126
-            ),
1127
-            TXN_ADMIN_URL
1128
-        );
1129
-        $this->_template_args['apply_payment_form_url'] = add_query_arg(
1130
-            array(
1131
-                'page'   => 'espresso_transactions',
1132
-                'action' => 'espresso_apply_payment',
1133
-            ),
1134
-            WP_AJAX_URL
1135
-        );
1136
-        $this->_template_args['delete_payment_form_url'] = add_query_arg(
1137
-            array(
1138
-                'page'   => 'espresso_transactions',
1139
-                'action' => 'espresso_delete_payment',
1140
-            ),
1141
-            WP_AJAX_URL
1142
-        );
1143
-
1144
-        $this->_template_args['action_buttons'] = $this->getActionButtons($this->_transaction);
1145
-
1146
-        // 'espresso_delete_payment_nonce'
1147
-
1148
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1149
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
1150
-    }
1151
-
1152
-
1153
-    /**
1154
-     * _get_registration_payment_IDs
1155
-     *    generates an array of Payment IDs and their corresponding Registration IDs
1156
-     *
1157
-     * @access protected
1158
-     * @param EE_Payment[] $payments
1159
-     * @return array
1160
-     * @throws EE_Error
1161
-     * @throws InvalidArgumentException
1162
-     * @throws InvalidDataTypeException
1163
-     * @throws InvalidInterfaceException
1164
-     * @throws ReflectionException
1165
-     */
1166
-    protected function _get_registration_payment_IDs($payments = array())
1167
-    {
1168
-        $existing_reg_payments = array();
1169
-        // get all reg payments for these payments
1170
-        $reg_payments = EEM_Registration_Payment::instance()->get_all(
1171
-            array(
1172
-                array(
1173
-                    'PAY_ID' => array(
1174
-                        'IN',
1175
-                        array_keys($payments),
1176
-                    ),
1177
-                ),
1178
-            )
1179
-        );
1180
-        if (! empty($reg_payments)) {
1181
-            foreach ($payments as $payment) {
1182
-                if (! $payment instanceof EE_Payment) {
1183
-                    continue;
1184
-                } elseif (! isset($existing_reg_payments[ $payment->ID() ])) {
1185
-                    $existing_reg_payments[ $payment->ID() ] = array();
1186
-                }
1187
-                foreach ($reg_payments as $reg_payment) {
1188
-                    if ($reg_payment instanceof EE_Registration_Payment
1189
-                        && $reg_payment->payment_ID() === $payment->ID()
1190
-                    ) {
1191
-                        $existing_reg_payments[ $payment->ID() ][] = $reg_payment->registration_ID();
1192
-                    }
1193
-                }
1194
-            }
1195
-        }
1196
-
1197
-        return $existing_reg_payments;
1198
-    }
1199
-
1200
-
1201
-    /**
1202
-     * _get_registrations_to_apply_payment_to
1203
-     *    generates HTML for displaying a series of checkboxes in the admin payment modal window
1204
-     * which allows the admin to only apply the payment to the specific registrations
1205
-     *
1206
-     * @access protected
1207
-     * @return void
1208
-     * @throws \EE_Error
1209
-     */
1210
-    protected function _get_registrations_to_apply_payment_to()
1211
-    {
1212
-        // we want any registration with an active status (ie: not deleted or cancelled)
1213
-        $query_params = array(
1214
-            array(
1215
-                'STS_ID' => array(
1216
-                    'IN',
1217
-                    array(
1218
-                        EEM_Registration::status_id_approved,
1219
-                        EEM_Registration::status_id_pending_payment,
1220
-                        EEM_Registration::status_id_not_approved,
1221
-                    ),
1222
-                ),
1223
-            ),
1224
-        );
1225
-        $registrations_to_apply_payment_to = EEH_HTML::br()
1226
-                                             . EEH_HTML::div(
1227
-                                                 '',
1228
-                                                 'txn-admin-apply-payment-to-registrations-dv',
1229
-                                                 '',
1230
-                                                 'clear: both; margin: 1.5em 0 0; display: none;'
1231
-                                             );
1232
-        $registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1233
-        $registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl');
1234
-        $registrations_to_apply_payment_to .= EEH_HTML::thead(
1235
-            EEH_HTML::tr(
1236
-                EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1237
-                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1238
-                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1239
-                EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1240
-                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1241
-                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1242
-                EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1243
-            )
1244
-        );
1245
-        $registrations_to_apply_payment_to .= EEH_HTML::tbody();
1246
-        // get registrations for TXN
1247
-        $registrations = $this->_transaction->registrations($query_params);
1248
-        $existing_reg_payments = $this->_template_args['existing_reg_payments'];
1249
-        foreach ($registrations as $registration) {
1250
-            if ($registration instanceof EE_Registration) {
1251
-                $attendee_name = $registration->attendee() instanceof EE_Attendee
1252
-                    ? $registration->attendee()->full_name()
1253
-                    : esc_html__('Unknown Attendee', 'event_espresso');
1254
-                $owing = $registration->final_price() - $registration->paid();
1255
-                $taxable = $registration->ticket()->taxable()
1256
-                    ? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1257
-                    : '';
1258
-                $checked = empty($existing_reg_payments) || in_array($registration->ID(), $existing_reg_payments)
1259
-                    ? ' checked="checked"'
1260
-                    : '';
1261
-                $disabled = $registration->final_price() > 0 ? '' : ' disabled';
1262
-                $registrations_to_apply_payment_to .= EEH_HTML::tr(
1263
-                    EEH_HTML::td($registration->ID()) .
1264
-                    EEH_HTML::td($attendee_name) .
1265
-                    EEH_HTML::td(
1266
-                        $registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1267
-                    ) .
1268
-                    EEH_HTML::td($registration->event_name()) .
1269
-                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1270
-                    EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr') .
1271
-                    EEH_HTML::td(
1272
-                        '<input type="checkbox" value="' . $registration->ID()
1273
-                        . '" name="txn_admin_payment[registrations]"'
1274
-                        . $checked . $disabled . '>',
1275
-                        '',
1276
-                        'jst-cntr'
1277
-                    ),
1278
-                    'apply-payment-registration-row-' . $registration->ID()
1279
-                );
1280
-            }
1281
-        }
1282
-        $registrations_to_apply_payment_to .= EEH_HTML::tbodyx();
1283
-        $registrations_to_apply_payment_to .= EEH_HTML::tablex();
1284
-        $registrations_to_apply_payment_to .= EEH_HTML::divx();
1285
-        $registrations_to_apply_payment_to .= EEH_HTML::p(
1286
-            esc_html__(
1287
-                'The payment will only be applied to the registrations that have a check mark in their corresponding check box. Checkboxes for free registrations have been disabled.',
1288
-                'event_espresso'
1289
-            ),
1290
-            '',
1291
-            'clear description'
1292
-        );
1293
-        $registrations_to_apply_payment_to .= EEH_HTML::divx();
1294
-        $this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1295
-    }
1296
-
1297
-
1298
-    /**
1299
-     * _get_reg_status_selection
1300
-     *
1301
-     * @todo   this will need to be adjusted either once MER comes along OR we move default reg status to tickets
1302
-     *         instead of events.
1303
-     * @access protected
1304
-     * @return void
1305
-     * @throws EE_Error
1306
-     */
1307
-    protected function _get_reg_status_selection()
1308
-    {
1309
-        // first get all possible statuses
1310
-        $statuses = EEM_Registration::reg_status_array(array(), true);
1311
-        // let's add a "don't change" option.
1312
-        $status_array['NAN'] = esc_html__('Leave the Same', 'event_espresso');
1313
-        $status_array = array_merge($status_array, $statuses);
1314
-        $this->_template_args['status_change_select'] = EEH_Form_Fields::select_input(
1315
-            'txn_reg_status_change[reg_status]',
1316
-            $status_array,
1317
-            'NAN',
1318
-            'id="txn-admin-payment-reg-status-inp"',
1319
-            'txn-reg-status-change-reg-status'
1320
-        );
1321
-        $this->_template_args['delete_status_change_select'] = EEH_Form_Fields::select_input(
1322
-            'delete_txn_reg_status_change[reg_status]',
1323
-            $status_array,
1324
-            'NAN',
1325
-            'delete-txn-admin-payment-reg-status-inp',
1326
-            'delete-txn-reg-status-change-reg-status'
1327
-        );
1328
-    }
1329
-
1330
-
1331
-    /**
1332
-     *    _get_payment_methods
1333
-     * Gets all the payment methods available generally, or the ones that are already
1334
-     * selected on these payments (in case their payment methods are no longer active).
1335
-     * Has the side-effect of updating the template args' payment_methods item
1336
-     *
1337
-     * @access private
1338
-     * @param EE_Payment[] to show on this page
1339
-     * @return void
1340
-     * @throws EE_Error
1341
-     * @throws InvalidArgumentException
1342
-     * @throws InvalidDataTypeException
1343
-     * @throws InvalidInterfaceException
1344
-     * @throws ReflectionException
1345
-     */
1346
-    private function _get_payment_methods($payments = array())
1347
-    {
1348
-        $payment_methods_of_payments = array();
1349
-        foreach ($payments as $payment) {
1350
-            if ($payment instanceof EE_Payment) {
1351
-                $payment_methods_of_payments[] = $payment->get('PMD_ID');
1352
-            }
1353
-        }
1354
-        if ($payment_methods_of_payments) {
1355
-            $query_args = array(
1356
-                array(
1357
-                    'OR*payment_method_for_payment' => array(
1358
-                        'PMD_ID'    => array('IN', $payment_methods_of_payments),
1359
-                        'PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%'),
1360
-                    ),
1361
-                ),
1362
-            );
1363
-        } else {
1364
-            $query_args = array(array('PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%')));
1365
-        }
1366
-        $this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1367
-    }
1368
-
1369
-
1370
-    /**
1371
-     * txn_attendees_meta_box
1372
-     *    generates HTML for the Attendees Transaction main meta box
1373
-     *
1374
-     * @access public
1375
-     * @param WP_Post $post
1376
-     * @param array   $metabox
1377
-     * @return void
1378
-     * @throws DomainException
1379
-     * @throws EE_Error
1380
-     */
1381
-    public function txn_attendees_meta_box($post, $metabox = array('args' => array()))
1382
-    {
1383
-
1384
-        /** @noinspection NonSecureExtractUsageInspection */
1385
-        extract($metabox['args']);
1386
-        $this->_template_args['post'] = $post;
1387
-        $this->_template_args['event_attendees'] = array();
1388
-        // process items in cart
1389
-        $line_items = $this->_transaction->get_many_related(
1390
-            'Line_Item',
1391
-            array(array('LIN_type' => 'line-item'))
1392
-        );
1393
-        if (! empty($line_items)) {
1394
-            foreach ($line_items as $item) {
1395
-                if ($item instanceof EE_Line_Item) {
1396
-                    switch ($item->OBJ_type()) {
1397
-                        case 'Event':
1398
-                            break;
1399
-                        case 'Ticket':
1400
-                            $ticket = $item->ticket();
1401
-                            // right now we're only handling tickets here.
1402
-                            // Cause its expected that only tickets will have attendees right?
1403
-                            if (! $ticket instanceof EE_Ticket) {
1404
-                                continue;
1405
-                            }
1406
-                            try {
1407
-                                $event_name = $ticket->get_event_name();
1408
-                            } catch (Exception $e) {
1409
-                                EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1410
-                                $event_name = esc_html__('Unknown Event', 'event_espresso');
1411
-                            }
1412
-                            $event_name .= ' - ' . $item->get('LIN_name');
1413
-                            $ticket_price = EEH_Template::format_currency($item->get('LIN_unit_price'));
1414
-                            // now get all of the registrations for this transaction that use this ticket
1415
-                            $registrations = $ticket->get_many_related(
1416
-                                'Registration',
1417
-                                array(array('TXN_ID' => $this->_transaction->ID()))
1418
-                            );
1419
-                            foreach ($registrations as $registration) {
1420
-                                if (! $registration instanceof EE_Registration) {
1421
-                                    continue;
1422
-                                }
1423
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['STS_ID']
1424
-                                    = $registration->status_ID();
1425
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['att_num']
1426
-                                    = $registration->count();
1427
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['event_ticket_name']
1428
-                                    = $event_name;
1429
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['ticket_price']
1430
-                                    = $ticket_price;
1431
-                                // attendee info
1432
-                                $attendee = $registration->get_first_related('Attendee');
1433
-                                if ($attendee instanceof EE_Attendee) {
1434
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['att_id']
1435
-                                        = $attendee->ID();
1436
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['attendee']
1437
-                                        = $attendee->full_name();
1438
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['email']
1439
-                                        = '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1440
-                                          . esc_html__(
1441
-                                              ' Event',
1442
-                                              'event_espresso'
1443
-                                          )
1444
-                                          . '">' . $attendee->email() . '</a>';
1445
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['address']
1446
-                                        = EEH_Address::format($attendee, 'inline', false, false);
1447
-                                } else {
1448
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['att_id'] = '';
1449
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['attendee'] = '';
1450
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['email'] = '';
1451
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['address'] = '';
1452
-                                }
1453
-                            }
1454
-                            break;
1455
-                    }
1456
-                }
1457
-            }
1458
-
1459
-            $this->_template_args['transaction_form_url'] = add_query_arg(
1460
-                array(
1461
-                    'action'  => 'edit_transaction',
1462
-                    'process' => 'attendees',
1463
-                ),
1464
-                TXN_ADMIN_URL
1465
-            );
1466
-            echo EEH_Template::display_template(
1467
-                TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1468
-                $this->_template_args,
1469
-                true
1470
-            );
1471
-        } else {
1472
-            echo sprintf(
1473
-                esc_html__(
1474
-                    '%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s',
1475
-                    'event_espresso'
1476
-                ),
1477
-                '<p class="important-notice">',
1478
-                '</p>'
1479
-            );
1480
-        }
1481
-    }
1482
-
1483
-
1484
-    /**
1485
-     * txn_registrant_side_meta_box
1486
-     * generates HTML for the Edit Transaction side meta box
1487
-     *
1488
-     * @access public
1489
-     * @return void
1490
-     * @throws DomainException
1491
-     * @throws EE_Error
1492
-     * @throws InvalidArgumentException
1493
-     * @throws InvalidDataTypeException
1494
-     * @throws InvalidInterfaceException
1495
-     * @throws ReflectionException
1496
-     */
1497
-    public function txn_registrant_side_meta_box()
1498
-    {
1499
-        $primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1500
-            ? $this->_transaction->primary_registration()->get_first_related('Attendee')
1501
-            : null;
1502
-        if (! $primary_att instanceof EE_Attendee) {
1503
-            $this->_template_args['no_attendee_message'] = esc_html__(
1504
-                'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1505
-                'event_espresso'
1506
-            );
1507
-            $primary_att = EEM_Attendee::instance()->create_default_object();
1508
-        }
1509
-        $this->_template_args['ATT_ID'] = $primary_att->ID();
1510
-        $this->_template_args['prime_reg_fname'] = $primary_att->fname();
1511
-        $this->_template_args['prime_reg_lname'] = $primary_att->lname();
1512
-        $this->_template_args['prime_reg_email'] = $primary_att->email();
1513
-        $this->_template_args['prime_reg_phone'] = $primary_att->phone();
1514
-        $this->_template_args['edit_attendee_url'] = EE_Admin_Page::add_query_args_and_nonce(
1515
-            array(
1516
-                'action' => 'edit_attendee',
1517
-                'post'   => $primary_att->ID(),
1518
-            ),
1519
-            REG_ADMIN_URL
1520
-        );
1521
-        // get formatted address for registrant
1522
-        $this->_template_args['formatted_address'] = EEH_Address::format($primary_att);
1523
-        echo EEH_Template::display_template(
1524
-            TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1525
-            $this->_template_args,
1526
-            true
1527
-        );
1528
-    }
1529
-
1530
-
1531
-    /**
1532
-     * txn_billing_info_side_meta_box
1533
-     *    generates HTML for the Edit Transaction side meta box
1534
-     *
1535
-     * @access public
1536
-     * @return void
1537
-     * @throws DomainException
1538
-     * @throws EE_Error
1539
-     */
1540
-    public function txn_billing_info_side_meta_box()
1541
-    {
1542
-
1543
-        $this->_template_args['billing_form'] = $this->_transaction->billing_info();
1544
-        $this->_template_args['billing_form_url'] = add_query_arg(
1545
-            array('action' => 'edit_transaction', 'process' => 'billing'),
1546
-            TXN_ADMIN_URL
1547
-        );
1548
-
1549
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1550
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);/**/
1551
-    }
1552
-
1553
-
1554
-    /**
1555
-     * apply_payments_or_refunds
1556
-     *    registers a payment or refund made towards a transaction
1557
-     *
1558
-     * @access public
1559
-     * @return void
1560
-     * @throws EE_Error
1561
-     * @throws InvalidArgumentException
1562
-     * @throws ReflectionException
1563
-     * @throws RuntimeException
1564
-     * @throws InvalidDataTypeException
1565
-     * @throws InvalidInterfaceException
1566
-     */
1567
-    public function apply_payments_or_refunds()
1568
-    {
1569
-        $json_response_data = array('return_data' => false);
1570
-        $valid_data = $this->_validate_payment_request_data();
1571
-        $has_access = EE_Registry::instance()->CAP->current_user_can(
1572
-            'ee_edit_payments',
1573
-            'apply_payment_or_refund_from_registration_details'
1574
-        );
1575
-        if (! empty($valid_data) && $has_access) {
1576
-            $PAY_ID = $valid_data['PAY_ID'];
1577
-            // save  the new payment
1578
-            $payment = $this->_create_payment_from_request_data($valid_data);
1579
-            // get the TXN for this payment
1580
-            $transaction = $payment->transaction();
1581
-            // verify transaction
1582
-            if ($transaction instanceof EE_Transaction) {
1583
-                // calculate_total_payments_and_update_status
1584
-                $this->_process_transaction_payments($transaction);
1585
-                $REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1586
-                $this->_remove_existing_registration_payments($payment, $PAY_ID);
1587
-                // apply payment to registrations (if applicable)
1588
-                if (! empty($REG_IDs)) {
1589
-                    $this->_update_registration_payments($transaction, $payment, $REG_IDs);
1590
-                    $this->_maybe_send_notifications();
1591
-                    // now process status changes for the same registrations
1592
-                    $this->_process_registration_status_change($transaction, $REG_IDs);
1593
-                }
1594
-                $this->_maybe_send_notifications($payment);
1595
-                // prepare to render page
1596
-                $json_response_data['return_data'] = $this->_build_payment_json_response($payment, $REG_IDs);
1597
-                do_action(
1598
-                    'AHEE__Transactions_Admin_Page__apply_payments_or_refund__after_recording',
1599
-                    $transaction,
1600
-                    $payment
1601
-                );
1602
-            } else {
1603
-                EE_Error::add_error(
1604
-                    esc_html__(
1605
-                        'A valid Transaction for this payment could not be retrieved.',
1606
-                        'event_espresso'
1607
-                    ),
1608
-                    __FILE__,
1609
-                    __FUNCTION__,
1610
-                    __LINE__
1611
-                );
1612
-            }
1613
-        } else {
1614
-            if ($has_access) {
1615
-                EE_Error::add_error(
1616
-                    esc_html__(
1617
-                        'The payment form data could not be processed. Please try again.',
1618
-                        'event_espresso'
1619
-                    ),
1620
-                    __FILE__,
1621
-                    __FUNCTION__,
1622
-                    __LINE__
1623
-                );
1624
-            } else {
1625
-                EE_Error::add_error(
1626
-                    esc_html__(
1627
-                        'You do not have access to apply payments or refunds to a registration.',
1628
-                        'event_espresso'
1629
-                    ),
1630
-                    __FILE__,
1631
-                    __FUNCTION__,
1632
-                    __LINE__
1633
-                );
1634
-            }
1635
-        }
1636
-        $notices = EE_Error::get_notices(
1637
-            false,
1638
-            false,
1639
-            false
1640
-        );
1641
-        $this->_template_args = array(
1642
-            'data'    => $json_response_data,
1643
-            'error'   => $notices['errors'],
1644
-            'success' => $notices['success'],
1645
-        );
1646
-        $this->_return_json();
1647
-    }
1648
-
1649
-
1650
-    /**
1651
-     * _validate_payment_request_data
1652
-     *
1653
-     * @return array
1654
-     * @throws EE_Error
1655
-     */
1656
-    protected function _validate_payment_request_data()
1657
-    {
1658
-        if (! isset($this->_req_data['txn_admin_payment'])) {
1659
-            return false;
1660
-        }
1661
-        $payment_form = $this->_generate_payment_form_section();
1662
-        try {
1663
-            if ($payment_form->was_submitted()) {
1664
-                $payment_form->receive_form_submission();
1665
-                if (! $payment_form->is_valid()) {
1666
-                    $submission_error_messages = array();
1667
-                    foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1668
-                        if ($validation_error instanceof EE_Validation_Error) {
1669
-                            $submission_error_messages[] = sprintf(
1670
-                                _x('%s : %s', 'Form Section Name : Form Validation Error', 'event_espresso'),
1671
-                                $validation_error->get_form_section()->html_label_text(),
1672
-                                $validation_error->getMessage()
1673
-                            );
1674
-                        }
1675
-                    }
1676
-                    EE_Error::add_error(
1677
-                        implode('<br />', $submission_error_messages),
1678
-                        __FILE__,
1679
-                        __FUNCTION__,
1680
-                        __LINE__
1681
-                    );
1682
-
1683
-                    return array();
1684
-                }
1685
-            }
1686
-        } catch (EE_Error $e) {
1687
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1688
-
1689
-            return array();
1690
-        }
1691
-
1692
-        return $payment_form->valid_data();
1693
-    }
1694
-
1695
-
1696
-    /**
1697
-     * _generate_payment_form_section
1698
-     *
1699
-     * @return EE_Form_Section_Proper
1700
-     * @throws EE_Error
1701
-     */
1702
-    protected function _generate_payment_form_section()
1703
-    {
1704
-        return new EE_Form_Section_Proper(
1705
-            array(
1706
-                'name'        => 'txn_admin_payment',
1707
-                'subsections' => array(
1708
-                    'PAY_ID'          => new EE_Text_Input(
1709
-                        array(
1710
-                            'default'               => 0,
1711
-                            'required'              => false,
1712
-                            'html_label_text'       => esc_html__('Payment ID', 'event_espresso'),
1713
-                            'validation_strategies' => array(new EE_Int_Normalization()),
1714
-                        )
1715
-                    ),
1716
-                    'TXN_ID'          => new EE_Text_Input(
1717
-                        array(
1718
-                            'default'               => 0,
1719
-                            'required'              => true,
1720
-                            'html_label_text'       => esc_html__('Transaction ID', 'event_espresso'),
1721
-                            'validation_strategies' => array(new EE_Int_Normalization()),
1722
-                        )
1723
-                    ),
1724
-                    'type'            => new EE_Text_Input(
1725
-                        array(
1726
-                            'default'               => 1,
1727
-                            'required'              => true,
1728
-                            'html_label_text'       => esc_html__('Payment or Refund', 'event_espresso'),
1729
-                            'validation_strategies' => array(new EE_Int_Normalization()),
1730
-                        )
1731
-                    ),
1732
-                    'amount'          => new EE_Text_Input(
1733
-                        array(
1734
-                            'default'               => 0,
1735
-                            'required'              => true,
1736
-                            'html_label_text'       => esc_html__('Payment amount', 'event_espresso'),
1737
-                            'validation_strategies' => array(new EE_Float_Normalization()),
1738
-                        )
1739
-                    ),
1740
-                    'status'          => new EE_Text_Input(
1741
-                        array(
1742
-                            'default'         => EEM_Payment::status_id_approved,
1743
-                            'required'        => true,
1744
-                            'html_label_text' => esc_html__('Payment status', 'event_espresso'),
1745
-                        )
1746
-                    ),
1747
-                    'PMD_ID'          => new EE_Text_Input(
1748
-                        array(
1749
-                            'default'               => 2,
1750
-                            'required'              => true,
1751
-                            'html_label_text'       => esc_html__('Payment Method', 'event_espresso'),
1752
-                            'validation_strategies' => array(new EE_Int_Normalization()),
1753
-                        )
1754
-                    ),
1755
-                    'date'            => new EE_Text_Input(
1756
-                        array(
1757
-                            'default'         => time(),
1758
-                            'required'        => true,
1759
-                            'html_label_text' => esc_html__('Payment date', 'event_espresso'),
1760
-                        )
1761
-                    ),
1762
-                    'txn_id_chq_nmbr' => new EE_Text_Input(
1763
-                        array(
1764
-                            'default'               => '',
1765
-                            'required'              => false,
1766
-                            'html_label_text'       => esc_html__('Transaction or Cheque Number', 'event_espresso'),
1767
-                            'validation_strategies' => array(
1768
-                                new EE_Max_Length_Validation_Strategy(
1769
-                                    esc_html__('Input too long', 'event_espresso'),
1770
-                                    100
1771
-                                ),
1772
-                            ),
1773
-                        )
1774
-                    ),
1775
-                    'po_number'       => new EE_Text_Input(
1776
-                        array(
1777
-                            'default'               => '',
1778
-                            'required'              => false,
1779
-                            'html_label_text'       => esc_html__('Purchase Order Number', 'event_espresso'),
1780
-                            'validation_strategies' => array(
1781
-                                new EE_Max_Length_Validation_Strategy(
1782
-                                    esc_html__('Input too long', 'event_espresso'),
1783
-                                    100
1784
-                                ),
1785
-                            ),
1786
-                        )
1787
-                    ),
1788
-                    'accounting'      => new EE_Text_Input(
1789
-                        array(
1790
-                            'default'               => '',
1791
-                            'required'              => false,
1792
-                            'html_label_text'       => esc_html__('Extra Field for Accounting', 'event_espresso'),
1793
-                            'validation_strategies' => array(
1794
-                                new EE_Max_Length_Validation_Strategy(
1795
-                                    esc_html__('Input too long', 'event_espresso'),
1796
-                                    100
1797
-                                ),
1798
-                            ),
1799
-                        )
1800
-                    ),
1801
-                ),
1802
-            )
1803
-        );
1804
-    }
1805
-
1806
-
1807
-    /**
1808
-     * _create_payment_from_request_data
1809
-     *
1810
-     * @param array $valid_data
1811
-     * @return EE_Payment
1812
-     * @throws EE_Error
1813
-     */
1814
-    protected function _create_payment_from_request_data($valid_data)
1815
-    {
1816
-        $PAY_ID = $valid_data['PAY_ID'];
1817
-        // get payment amount
1818
-        $amount = $valid_data['amount'] ? abs($valid_data['amount']) : 0;
1819
-        // payments have a type value of 1 and refunds have a type value of -1
1820
-        // so multiplying amount by type will give a positive value for payments, and negative values for refunds
1821
-        $amount = $valid_data['type'] < 0 ? $amount * -1 : $amount;
1822
-        // for some reason the date string coming in has extra spaces between the date and time.  This fixes that.
1823
-        $date = $valid_data['date']
1824
-            ? preg_replace('/\s+/', ' ', $valid_data['date'])
1825
-            : date('Y-m-d g:i a', current_time('timestamp'));
1826
-        $payment = EE_Payment::new_instance(
1827
-            array(
1828
-                'TXN_ID'              => $valid_data['TXN_ID'],
1829
-                'STS_ID'              => $valid_data['status'],
1830
-                'PAY_timestamp'       => $date,
1831
-                'PAY_source'          => EEM_Payment_Method::scope_admin,
1832
-                'PMD_ID'              => $valid_data['PMD_ID'],
1833
-                'PAY_amount'          => $amount,
1834
-                'PAY_txn_id_chq_nmbr' => $valid_data['txn_id_chq_nmbr'],
1835
-                'PAY_po_number'       => $valid_data['po_number'],
1836
-                'PAY_extra_accntng'   => $valid_data['accounting'],
1837
-                'PAY_details'         => $valid_data,
1838
-                'PAY_ID'              => $PAY_ID,
1839
-            ),
1840
-            '',
1841
-            array('Y-m-d', 'g:i a')
1842
-        );
1843
-
1844
-        if (! $payment->save()) {
1845
-            EE_Error::add_error(
1846
-                sprintf(
1847
-                    esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
1848
-                    $payment->ID()
1849
-                ),
1850
-                __FILE__,
1851
-                __FUNCTION__,
1852
-                __LINE__
1853
-            );
1854
-        }
1855
-
1856
-        return $payment;
1857
-    }
1858
-
1859
-
1860
-    /**
1861
-     * _process_transaction_payments
1862
-     *
1863
-     * @param \EE_Transaction $transaction
1864
-     * @return void
1865
-     * @throws EE_Error
1866
-     * @throws InvalidArgumentException
1867
-     * @throws ReflectionException
1868
-     * @throws InvalidDataTypeException
1869
-     * @throws InvalidInterfaceException
1870
-     */
1871
-    protected function _process_transaction_payments(EE_Transaction $transaction)
1872
-    {
1873
-        /** @type EE_Transaction_Payments $transaction_payments */
1874
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1875
-        // update the transaction with this payment
1876
-        if ($transaction_payments->calculate_total_payments_and_update_status($transaction)) {
1877
-            EE_Error::add_success(
1878
-                esc_html__(
1879
-                    'The payment has been processed successfully.',
1880
-                    'event_espresso'
1881
-                ),
1882
-                __FILE__,
1883
-                __FUNCTION__,
1884
-                __LINE__
1885
-            );
1886
-        } else {
1887
-            EE_Error::add_error(
1888
-                esc_html__(
1889
-                    'The payment was processed successfully but the amount paid for the transaction was not updated.',
1890
-                    'event_espresso'
1891
-                ),
1892
-                __FILE__,
1893
-                __FUNCTION__,
1894
-                __LINE__
1895
-            );
1896
-        }
1897
-    }
1898
-
1899
-
1900
-    /**
1901
-     * _get_REG_IDs_to_apply_payment_to
1902
-     * returns a list of registration IDs that the payment will apply to
1903
-     *
1904
-     * @param \EE_Payment $payment
1905
-     * @return array
1906
-     * @throws EE_Error
1907
-     */
1908
-    protected function _get_REG_IDs_to_apply_payment_to(EE_Payment $payment)
1909
-    {
1910
-        $REG_IDs = array();
1911
-        // grab array of IDs for specific registrations to apply changes to
1912
-        if (isset($this->_req_data['txn_admin_payment']['registrations'])) {
1913
-            $REG_IDs = (array) $this->_req_data['txn_admin_payment']['registrations'];
1914
-        }
1915
-        // nothing specified ? then get all reg IDs
1916
-        if (empty($REG_IDs)) {
1917
-            $registrations = $payment->transaction()->registrations();
1918
-            $REG_IDs = ! empty($registrations)
1919
-                ? array_keys($registrations)
1920
-                : $this->_get_existing_reg_payment_REG_IDs($payment);
1921
-        }
1922
-
1923
-        // ensure that REG_IDs are integers and NOT strings
1924
-        return array_map('intval', $REG_IDs);
1925
-    }
1926
-
1927
-
1928
-    /**
1929
-     * @return array
1930
-     */
1931
-    public function existing_reg_payment_REG_IDs()
1932
-    {
1933
-        return $this->_existing_reg_payment_REG_IDs;
1934
-    }
1935
-
1936
-
1937
-    /**
1938
-     * @param array $existing_reg_payment_REG_IDs
1939
-     */
1940
-    public function set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs = null)
1941
-    {
1942
-        $this->_existing_reg_payment_REG_IDs = $existing_reg_payment_REG_IDs;
1943
-    }
1944
-
1945
-
1946
-    /**
1947
-     * _get_existing_reg_payment_REG_IDs
1948
-     * returns a list of registration IDs that the payment is currently related to
1949
-     * as recorded in the database
1950
-     *
1951
-     * @param \EE_Payment $payment
1952
-     * @return array
1953
-     * @throws EE_Error
1954
-     */
1955
-    protected function _get_existing_reg_payment_REG_IDs(EE_Payment $payment)
1956
-    {
1957
-        if ($this->existing_reg_payment_REG_IDs() === null) {
1958
-            // let's get any existing reg payment records for this payment
1959
-            $existing_reg_payment_REG_IDs = $payment->get_many_related('Registration');
1960
-            // but we only want the REG IDs, so grab the array keys
1961
-            $existing_reg_payment_REG_IDs = ! empty($existing_reg_payment_REG_IDs)
1962
-                ? array_keys($existing_reg_payment_REG_IDs)
1963
-                : array();
1964
-            $this->set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs);
1965
-        }
1966
-
1967
-        return $this->existing_reg_payment_REG_IDs();
1968
-    }
1969
-
1970
-
1971
-    /**
1972
-     * _remove_existing_registration_payments
1973
-     * this calculates the difference between existing relations
1974
-     * to the supplied payment and the new list registration IDs,
1975
-     * removes any related registrations that no longer apply,
1976
-     * and then updates the registration paid fields
1977
-     *
1978
-     * @param \EE_Payment $payment
1979
-     * @param int         $PAY_ID
1980
-     * @return bool;
1981
-     * @throws EE_Error
1982
-     * @throws InvalidArgumentException
1983
-     * @throws ReflectionException
1984
-     * @throws InvalidDataTypeException
1985
-     * @throws InvalidInterfaceException
1986
-     */
1987
-    protected function _remove_existing_registration_payments(EE_Payment $payment, $PAY_ID = 0)
1988
-    {
1989
-        // newly created payments will have nothing recorded for $PAY_ID
1990
-        if ($PAY_ID == 0) {
1991
-            return false;
1992
-        }
1993
-        $existing_reg_payment_REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
1994
-        if (empty($existing_reg_payment_REG_IDs)) {
1995
-            return false;
1996
-        }
1997
-        /** @type EE_Transaction_Payments $transaction_payments */
1998
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1999
-
2000
-        return $transaction_payments->delete_registration_payments_and_update_registrations(
2001
-            $payment,
2002
-            array(
2003
-                array(
2004
-                    'PAY_ID' => $payment->ID(),
2005
-                    'REG_ID' => array('IN', $existing_reg_payment_REG_IDs),
2006
-                ),
2007
-            )
2008
-        );
2009
-    }
2010
-
2011
-
2012
-    /**
2013
-     * _update_registration_payments
2014
-     * this applies the payments to the selected registrations
2015
-     * but only if they have not already been paid for
2016
-     *
2017
-     * @param  EE_Transaction $transaction
2018
-     * @param \EE_Payment     $payment
2019
-     * @param array           $REG_IDs
2020
-     * @return void
2021
-     * @throws EE_Error
2022
-     * @throws InvalidArgumentException
2023
-     * @throws ReflectionException
2024
-     * @throws RuntimeException
2025
-     * @throws InvalidDataTypeException
2026
-     * @throws InvalidInterfaceException
2027
-     */
2028
-    protected function _update_registration_payments(
2029
-        EE_Transaction $transaction,
2030
-        EE_Payment $payment,
2031
-        $REG_IDs = array()
2032
-    ) {
2033
-        // we can pass our own custom set of registrations to EE_Payment_Processor::process_registration_payments()
2034
-        // so let's do that using our set of REG_IDs from the form
2035
-        $registration_query_where_params = array(
2036
-            'REG_ID' => array('IN', $REG_IDs),
2037
-        );
2038
-        // but add in some conditions regarding payment,
2039
-        // so that we don't apply payments to registrations that are free or have already been paid for
2040
-        // but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2041
-        if (! $payment->is_a_refund()) {
2042
-            $registration_query_where_params['REG_final_price'] = array('!=', 0);
2043
-            $registration_query_where_params['REG_final_price*'] = array('!=', 'REG_paid', true);
2044
-        }
2045
-        $registrations = $transaction->registrations(array($registration_query_where_params));
2046
-        if (! empty($registrations)) {
2047
-            /** @type EE_Payment_Processor $payment_processor */
2048
-            $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2049
-            $payment_processor->process_registration_payments($transaction, $payment, $registrations);
2050
-        }
2051
-    }
2052
-
2053
-
2054
-    /**
2055
-     * _process_registration_status_change
2056
-     * This processes requested registration status changes for all the registrations
2057
-     * on a given transaction and (optionally) sends out notifications for the changes.
2058
-     *
2059
-     * @param  EE_Transaction $transaction
2060
-     * @param array           $REG_IDs
2061
-     * @return bool
2062
-     * @throws EE_Error
2063
-     * @throws InvalidArgumentException
2064
-     * @throws ReflectionException
2065
-     * @throws InvalidDataTypeException
2066
-     * @throws InvalidInterfaceException
2067
-     */
2068
-    protected function _process_registration_status_change(EE_Transaction $transaction, $REG_IDs = array())
2069
-    {
2070
-        // first if there is no change in status then we get out.
2071
-        if (! isset($this->_req_data['txn_reg_status_change']['reg_status'])
2072
-            || $this->_req_data['txn_reg_status_change']['reg_status'] === 'NAN'
2073
-        ) {
2074
-            // no error message, no change requested, just nothing to do man.
2075
-            return false;
2076
-        }
2077
-        /** @type EE_Transaction_Processor $transaction_processor */
2078
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
2079
-
2080
-        // made it here dude?  Oh WOW.  K, let's take care of changing the statuses
2081
-        return $transaction_processor->manually_update_registration_statuses(
2082
-            $transaction,
2083
-            sanitize_text_field($this->_req_data['txn_reg_status_change']['reg_status']),
2084
-            array(array('REG_ID' => array('IN', $REG_IDs)))
2085
-        );
2086
-    }
2087
-
2088
-
2089
-    /**
2090
-     * _build_payment_json_response
2091
-     *
2092
-     * @access public
2093
-     * @param \EE_Payment $payment
2094
-     * @param array       $REG_IDs
2095
-     * @param bool | null $delete_txn_reg_status_change
2096
-     * @return array
2097
-     * @throws EE_Error
2098
-     * @throws InvalidArgumentException
2099
-     * @throws InvalidDataTypeException
2100
-     * @throws InvalidInterfaceException
2101
-     * @throws ReflectionException
2102
-     */
2103
-    protected function _build_payment_json_response(
2104
-        EE_Payment $payment,
2105
-        $REG_IDs = array(),
2106
-        $delete_txn_reg_status_change = null
2107
-    ) {
2108
-        // was the payment deleted ?
2109
-        if (is_bool($delete_txn_reg_status_change)) {
2110
-            return array(
2111
-                'PAY_ID'                       => $payment->ID(),
2112
-                'amount'                       => $payment->amount(),
2113
-                'total_paid'                   => $payment->transaction()->paid(),
2114
-                'txn_status'                   => $payment->transaction()->status_ID(),
2115
-                'pay_status'                   => $payment->STS_ID(),
2116
-                'registrations'                => $this->_registration_payment_data_array($REG_IDs),
2117
-                'delete_txn_reg_status_change' => $delete_txn_reg_status_change,
2118
-            );
2119
-        } else {
2120
-            $this->_get_payment_status_array();
2121
-
2122
-            return array(
2123
-                'amount'           => $payment->amount(),
2124
-                'total_paid'       => $payment->transaction()->paid(),
2125
-                'txn_status'       => $payment->transaction()->status_ID(),
2126
-                'pay_status'       => $payment->STS_ID(),
2127
-                'PAY_ID'           => $payment->ID(),
2128
-                'STS_ID'           => $payment->STS_ID(),
2129
-                'status'           => self::$_pay_status[ $payment->STS_ID() ],
2130
-                'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
2131
-                'method'           => strtoupper($payment->source()),
2132
-                'PM_ID'            => $payment->payment_method() ? $payment->payment_method()->ID() : 1,
2133
-                'gateway'          => $payment->payment_method()
2134
-                    ? $payment->payment_method()->admin_name()
2135
-                    : esc_html__("Unknown", 'event_espresso'),
2136
-                'gateway_response' => $payment->gateway_response(),
2137
-                'txn_id_chq_nmbr'  => $payment->txn_id_chq_nmbr(),
2138
-                'po_number'        => $payment->po_number(),
2139
-                'extra_accntng'    => $payment->extra_accntng(),
2140
-                'registrations'    => $this->_registration_payment_data_array($REG_IDs),
2141
-            );
2142
-        }
2143
-    }
2144
-
2145
-
2146
-    /**
2147
-     * delete_payment
2148
-     *    delete a payment or refund made towards a transaction
2149
-     *
2150
-     * @access public
2151
-     * @return void
2152
-     * @throws EE_Error
2153
-     * @throws InvalidArgumentException
2154
-     * @throws ReflectionException
2155
-     * @throws InvalidDataTypeException
2156
-     * @throws InvalidInterfaceException
2157
-     */
2158
-    public function delete_payment()
2159
-    {
2160
-        $json_response_data = array('return_data' => false);
2161
-        $PAY_ID = isset($this->_req_data['delete_txn_admin_payment']['PAY_ID'])
2162
-            ? absint($this->_req_data['delete_txn_admin_payment']['PAY_ID'])
2163
-            : 0;
2164
-        $can_delete = EE_Registry::instance()->CAP->current_user_can(
2165
-            'ee_delete_payments',
2166
-            'delete_payment_from_registration_details'
2167
-        );
2168
-        if ($PAY_ID && $can_delete) {
2169
-            $delete_txn_reg_status_change = isset($this->_req_data['delete_txn_reg_status_change'])
2170
-                ? $this->_req_data['delete_txn_reg_status_change']
2171
-                : false;
2172
-            $payment = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
2173
-            if ($payment instanceof EE_Payment) {
2174
-                $REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2175
-                /** @type EE_Transaction_Payments $transaction_payments */
2176
-                $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2177
-                if ($transaction_payments->delete_payment_and_update_transaction($payment)) {
2178
-                    $json_response_data['return_data'] = $this->_build_payment_json_response(
2179
-                        $payment,
2180
-                        $REG_IDs,
2181
-                        $delete_txn_reg_status_change
2182
-                    );
2183
-                    if ($delete_txn_reg_status_change) {
2184
-                        $this->_req_data['txn_reg_status_change'] = $delete_txn_reg_status_change;
2185
-                        // MAKE sure we also add the delete_txn_req_status_change to the
2186
-                        // $_REQUEST global because that's how messages will be looking for it.
2187
-                        $_REQUEST['txn_reg_status_change'] = $delete_txn_reg_status_change;
2188
-                        $this->_maybe_send_notifications();
2189
-                        $this->_process_registration_status_change($payment->transaction(), $REG_IDs);
2190
-                    }
2191
-                }
2192
-            } else {
2193
-                EE_Error::add_error(
2194
-                    esc_html__('Valid Payment data could not be retrieved from the database.', 'event_espresso'),
2195
-                    __FILE__,
2196
-                    __FUNCTION__,
2197
-                    __LINE__
2198
-                );
2199
-            }
2200
-        } else {
2201
-            if ($can_delete) {
2202
-                EE_Error::add_error(
2203
-                    esc_html__(
2204
-                        'A valid Payment ID was not received, therefore payment form data could not be loaded.',
2205
-                        'event_espresso'
2206
-                    ),
2207
-                    __FILE__,
2208
-                    __FUNCTION__,
2209
-                    __LINE__
2210
-                );
2211
-            } else {
2212
-                EE_Error::add_error(
2213
-                    esc_html__(
2214
-                        'You do not have access to delete a payment.',
2215
-                        'event_espresso'
2216
-                    ),
2217
-                    __FILE__,
2218
-                    __FUNCTION__,
2219
-                    __LINE__
2220
-                );
2221
-            }
2222
-        }
2223
-        $notices = EE_Error::get_notices(false, false, false);
2224
-        $this->_template_args = array(
2225
-            'data'      => $json_response_data,
2226
-            'success'   => $notices['success'],
2227
-            'error'     => $notices['errors'],
2228
-            'attention' => $notices['attention'],
2229
-        );
2230
-        $this->_return_json();
2231
-    }
2232
-
2233
-
2234
-    /**
2235
-     * _registration_payment_data_array
2236
-     * adds info for 'owing' and 'paid' for each registration to the json response
2237
-     *
2238
-     * @access protected
2239
-     * @param array $REG_IDs
2240
-     * @return array
2241
-     * @throws EE_Error
2242
-     * @throws InvalidArgumentException
2243
-     * @throws InvalidDataTypeException
2244
-     * @throws InvalidInterfaceException
2245
-     * @throws ReflectionException
2246
-     */
2247
-    protected function _registration_payment_data_array($REG_IDs)
2248
-    {
2249
-        $registration_payment_data = array();
2250
-        // if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2251
-        if (! empty($REG_IDs)) {
2252
-            $registrations = EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $REG_IDs))));
2253
-            foreach ($registrations as $registration) {
2254
-                if ($registration instanceof EE_Registration) {
2255
-                    $registration_payment_data[ $registration->ID() ] = array(
2256
-                        'paid'  => $registration->pretty_paid(),
2257
-                        'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
2258
-                    );
2259
-                }
2260
-            }
2261
-        }
2262
-
2263
-        return $registration_payment_data;
2264
-    }
2265
-
2266
-
2267
-    /**
2268
-     * _maybe_send_notifications
2269
-     * determines whether or not the admin has indicated that notifications should be sent.
2270
-     * If so, will toggle a filter switch for delivering registration notices.
2271
-     * If passed an EE_Payment object, then it will trigger payment notifications instead.
2272
-     *
2273
-     * @access protected
2274
-     * @param \EE_Payment | null $payment
2275
-     */
2276
-    protected function _maybe_send_notifications($payment = null)
2277
-    {
2278
-        switch ($payment instanceof EE_Payment) {
2279
-            // payment notifications
2280
-            case true:
2281
-                if (isset(
2282
-                    $this->_req_data['txn_payments'],
2283
-                    $this->_req_data['txn_payments']['send_notifications']
2284
-                )
2285
-                    && filter_var($this->_req_data['txn_payments']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
2286
-                ) {
2287
-                    $this->_process_payment_notification($payment);
2288
-                }
2289
-                break;
2290
-            // registration notifications
2291
-            case false:
2292
-                if (isset(
2293
-                    $this->_req_data['txn_reg_status_change'],
2294
-                    $this->_req_data['txn_reg_status_change']['send_notifications']
2295
-                )
2296
-                    && filter_var($this->_req_data['txn_reg_status_change']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
2297
-                ) {
2298
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
2299
-                }
2300
-                break;
2301
-        }
2302
-    }
2303
-
2304
-
2305
-    /**
2306
-     * _send_payment_reminder
2307
-     *    generates HTML for the View Transaction Details Admin page
2308
-     *
2309
-     * @access protected
2310
-     * @return void
2311
-     * @throws EE_Error
2312
-     * @throws InvalidArgumentException
2313
-     * @throws InvalidDataTypeException
2314
-     * @throws InvalidInterfaceException
2315
-     */
2316
-    protected function _send_payment_reminder()
2317
-    {
2318
-        $TXN_ID = ! empty($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : false;
2319
-        $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2320
-        $query_args = isset($this->_req_data['redirect_to']) ? array(
2321
-            'action' => $this->_req_data['redirect_to'],
2322
-            'TXN_ID' => $this->_req_data['TXN_ID'],
2323
-        ) : array();
2324
-        do_action(
2325
-            'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
2326
-            $transaction
2327
-        );
2328
-        $this->_redirect_after_action(
2329
-            false,
2330
-            esc_html__('payment reminder', 'event_espresso'),
2331
-            esc_html__('sent', 'event_espresso'),
2332
-            $query_args,
2333
-            true
2334
-        );
2335
-    }
2336
-
2337
-
2338
-    /**
2339
-     *  get_transactions
2340
-     *    get transactions for given parameters (used by list table)
2341
-     *
2342
-     * @param  int     $perpage how many transactions displayed per page
2343
-     * @param  boolean $count   return the count or objects
2344
-     * @param string   $view
2345
-     * @return mixed int = count || array of transaction objects
2346
-     * @throws EE_Error
2347
-     * @throws InvalidArgumentException
2348
-     * @throws InvalidDataTypeException
2349
-     * @throws InvalidInterfaceException
2350
-     */
2351
-    public function get_transactions($perpage, $count = false, $view = '')
2352
-    {
2353
-
2354
-        $TXN = EEM_Transaction::instance();
2355
-
2356
-        $start_date = isset($this->_req_data['txn-filter-start-date'])
2357
-            ? wp_strip_all_tags($this->_req_data['txn-filter-start-date'])
2358
-            : date(
2359
-                'm/d/Y',
2360
-                strtotime('-10 year')
2361
-            );
2362
-        $end_date = isset($this->_req_data['txn-filter-end-date'])
2363
-            ? wp_strip_all_tags($this->_req_data['txn-filter-end-date'])
2364
-            : date('m/d/Y');
2365
-
2366
-        // make sure our timestamps start and end right at the boundaries for each day
2367
-        $start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2368
-        $end_date = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2369
-
2370
-
2371
-        // convert to timestamps
2372
-        $start_date = strtotime($start_date);
2373
-        $end_date = strtotime($end_date);
2374
-
2375
-        // makes sure start date is the lowest value and vice versa
2376
-        $start_date = min($start_date, $end_date);
2377
-        $end_date = max($start_date, $end_date);
2378
-
2379
-        // convert to correct format for query
2380
-        $start_date = EEM_Transaction::instance()->convert_datetime_for_query(
2381
-            'TXN_timestamp',
2382
-            date('Y-m-d H:i:s', $start_date),
2383
-            'Y-m-d H:i:s'
2384
-        );
2385
-        $end_date = EEM_Transaction::instance()->convert_datetime_for_query(
2386
-            'TXN_timestamp',
2387
-            date('Y-m-d H:i:s', $end_date),
2388
-            'Y-m-d H:i:s'
2389
-        );
2390
-
2391
-
2392
-        // set orderby
2393
-        $this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
2394
-
2395
-        switch ($this->_req_data['orderby']) {
2396
-            case 'TXN_ID':
2397
-                $orderby = 'TXN_ID';
2398
-                break;
2399
-            case 'ATT_fname':
2400
-                $orderby = 'Registration.Attendee.ATT_fname';
2401
-                break;
2402
-            case 'event_name':
2403
-                $orderby = 'Registration.Event.EVT_name';
2404
-                break;
2405
-            default: // 'TXN_timestamp'
2406
-                $orderby = 'TXN_timestamp';
2407
-        }
2408
-
2409
-        $sort = ! empty($this->_req_data['order']) ? $this->_req_data['order'] : 'DESC';
2410
-        $current_page = ! empty($this->_req_data['paged']) ? $this->_req_data['paged'] : 1;
2411
-        $per_page = ! empty($perpage) ? $perpage : 10;
2412
-        $per_page = ! empty($this->_req_data['perpage']) ? $this->_req_data['perpage'] : $per_page;
2413
-
2414
-        $offset = ($current_page - 1) * $per_page;
2415
-        $limit = array($offset, $per_page);
2416
-
2417
-        $_where = array(
2418
-            'TXN_timestamp'          => array('BETWEEN', array($start_date, $end_date)),
2419
-            'Registration.REG_count' => 1,
2420
-        );
2421
-
2422
-        if (isset($this->_req_data['EVT_ID'])) {
2423
-            $_where['Registration.EVT_ID'] = $this->_req_data['EVT_ID'];
2424
-        }
2425
-
2426
-        if (isset($this->_req_data['s'])) {
2427
-            $search_string = '%' . $this->_req_data['s'] . '%';
2428
-            $_where['OR'] = array(
2429
-                'Registration.Event.EVT_name'         => array('LIKE', $search_string),
2430
-                'Registration.Event.EVT_desc'         => array('LIKE', $search_string),
2431
-                'Registration.Event.EVT_short_desc'   => array('LIKE', $search_string),
2432
-                'Registration.Attendee.ATT_full_name' => array('LIKE', $search_string),
2433
-                'Registration.Attendee.ATT_fname'     => array('LIKE', $search_string),
2434
-                'Registration.Attendee.ATT_lname'     => array('LIKE', $search_string),
2435
-                'Registration.Attendee.ATT_short_bio' => array('LIKE', $search_string),
2436
-                'Registration.Attendee.ATT_email'     => array('LIKE', $search_string),
2437
-                'Registration.Attendee.ATT_address'   => array('LIKE', $search_string),
2438
-                'Registration.Attendee.ATT_address2'  => array('LIKE', $search_string),
2439
-                'Registration.Attendee.ATT_city'      => array('LIKE', $search_string),
2440
-                'Registration.REG_final_price'        => array('LIKE', $search_string),
2441
-                'Registration.REG_code'               => array('LIKE', $search_string),
2442
-                'Registration.REG_count'              => array('LIKE', $search_string),
2443
-                'Registration.REG_group_size'         => array('LIKE', $search_string),
2444
-                'Registration.Ticket.TKT_name'        => array('LIKE', $search_string),
2445
-                'Registration.Ticket.TKT_description' => array('LIKE', $search_string),
2446
-                'Payment.PAY_source'                  => array('LIKE', $search_string),
2447
-                'Payment.Payment_Method.PMD_name'     => array('LIKE', $search_string),
2448
-                'TXN_session_data'                    => array('LIKE', $search_string),
2449
-                'Payment.PAY_txn_id_chq_nmbr'         => array('LIKE', $search_string),
2450
-            );
2451
-        }
2452
-
2453
-        // failed transactions
2454
-        $failed = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'failed' && ! $count)
2455
-                  || ($count && $view === 'failed');
2456
-        $abandoned = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'abandoned' && ! $count)
2457
-                     || ($count && $view === 'abandoned');
2458
-
2459
-        if ($failed) {
2460
-            $_where['STS_ID'] = EEM_Transaction::failed_status_code;
2461
-        } elseif ($abandoned) {
2462
-            $_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
2463
-        } else {
2464
-            $_where['STS_ID'] = array('!=', EEM_Transaction::failed_status_code);
2465
-            $_where['STS_ID*'] = array('!=', EEM_Transaction::abandoned_status_code);
2466
-        }
2467
-
2468
-        $query_params = array(
2469
-            $_where,
2470
-            'order_by'                 => array($orderby => $sort),
2471
-            'limit'                    => $limit,
2472
-            'default_where_conditions' => EEM_Base::default_where_conditions_this_only,
2473
-        );
2474
-
2475
-        $transactions = $count
2476
-            ? $TXN->count(array($_where), 'TXN_ID', true)
2477
-            : $TXN->get_all($query_params);
2478
-
2479
-        return $transactions;
2480
-    }
17
+	/**
18
+	 * @var EE_Transaction
19
+	 */
20
+	private $_transaction;
21
+
22
+	/**
23
+	 * @var EE_Session
24
+	 */
25
+	private $_session;
26
+
27
+	/**
28
+	 * @var array $_txn_status
29
+	 */
30
+	private static $_txn_status;
31
+
32
+	/**
33
+	 * @var array $_pay_status
34
+	 */
35
+	private static $_pay_status;
36
+
37
+	/**
38
+	 * @var array $_existing_reg_payment_REG_IDs
39
+	 */
40
+	protected $_existing_reg_payment_REG_IDs = null;
41
+
42
+
43
+	/**
44
+	 * @Constructor
45
+	 * @access public
46
+	 * @param bool $routing
47
+	 * @throws EE_Error
48
+	 * @throws InvalidArgumentException
49
+	 * @throws ReflectionException
50
+	 * @throws InvalidDataTypeException
51
+	 * @throws InvalidInterfaceException
52
+	 */
53
+	public function __construct($routing = true)
54
+	{
55
+		parent::__construct($routing);
56
+	}
57
+
58
+
59
+	/**
60
+	 *    _init_page_props
61
+	 *
62
+	 * @return void
63
+	 */
64
+	protected function _init_page_props()
65
+	{
66
+		$this->page_slug = TXN_PG_SLUG;
67
+		$this->page_label = esc_html__('Transactions', 'event_espresso');
68
+		$this->_admin_base_url = TXN_ADMIN_URL;
69
+		$this->_admin_base_path = TXN_ADMIN;
70
+	}
71
+
72
+
73
+	/**
74
+	 *    _ajax_hooks
75
+	 *
76
+	 * @return void
77
+	 */
78
+	protected function _ajax_hooks()
79
+	{
80
+		add_action('wp_ajax_espresso_apply_payment', array($this, 'apply_payments_or_refunds'));
81
+		add_action('wp_ajax_espresso_apply_refund', array($this, 'apply_payments_or_refunds'));
82
+		add_action('wp_ajax_espresso_delete_payment', array($this, 'delete_payment'));
83
+	}
84
+
85
+
86
+	/**
87
+	 *    _define_page_props
88
+	 *
89
+	 * @return void
90
+	 */
91
+	protected function _define_page_props()
92
+	{
93
+		$this->_admin_page_title = $this->page_label;
94
+		$this->_labels = array(
95
+			'buttons' => array(
96
+				'add'    => esc_html__('Add New Transaction', 'event_espresso'),
97
+				'edit'   => esc_html__('Edit Transaction', 'event_espresso'),
98
+				'delete' => esc_html__('Delete Transaction', 'event_espresso'),
99
+			),
100
+		);
101
+	}
102
+
103
+
104
+	/**
105
+	 *        grab url requests and route them
106
+	 *
107
+	 * @access private
108
+	 * @return void
109
+	 * @throws EE_Error
110
+	 * @throws InvalidArgumentException
111
+	 * @throws InvalidDataTypeException
112
+	 * @throws InvalidInterfaceException
113
+	 */
114
+	public function _set_page_routes()
115
+	{
116
+
117
+		$this->_set_transaction_status_array();
118
+
119
+		$txn_id = ! empty($this->_req_data['TXN_ID'])
120
+				  && ! is_array($this->_req_data['TXN_ID'])
121
+			? $this->_req_data['TXN_ID']
122
+			: 0;
123
+
124
+		$this->_page_routes = array(
125
+
126
+			'default' => array(
127
+				'func'       => '_transactions_overview_list_table',
128
+				'capability' => 'ee_read_transactions',
129
+			),
130
+
131
+			'view_transaction' => array(
132
+				'func'       => '_transaction_details',
133
+				'capability' => 'ee_read_transaction',
134
+				'obj_id'     => $txn_id,
135
+			),
136
+
137
+			'send_payment_reminder' => array(
138
+				'func'       => '_send_payment_reminder',
139
+				'noheader'   => true,
140
+				'capability' => 'ee_send_message',
141
+			),
142
+
143
+			'espresso_apply_payment' => array(
144
+				'func'       => 'apply_payments_or_refunds',
145
+				'noheader'   => true,
146
+				'capability' => 'ee_edit_payments',
147
+			),
148
+
149
+			'espresso_apply_refund' => array(
150
+				'func'       => 'apply_payments_or_refunds',
151
+				'noheader'   => true,
152
+				'capability' => 'ee_edit_payments',
153
+			),
154
+
155
+			'espresso_delete_payment' => array(
156
+				'func'       => 'delete_payment',
157
+				'noheader'   => true,
158
+				'capability' => 'ee_delete_payments',
159
+			),
160
+
161
+		);
162
+	}
163
+
164
+
165
+	protected function _set_page_config()
166
+	{
167
+		$this->_page_config = array(
168
+			'default'          => array(
169
+				'nav'           => array(
170
+					'label' => esc_html__('Overview', 'event_espresso'),
171
+					'order' => 10,
172
+				),
173
+				'list_table'    => 'EE_Admin_Transactions_List_Table',
174
+				'help_tabs'     => array(
175
+					'transactions_overview_help_tab'                       => array(
176
+						'title'    => esc_html__('Transactions Overview', 'event_espresso'),
177
+						'filename' => 'transactions_overview',
178
+					),
179
+					'transactions_overview_table_column_headings_help_tab' => array(
180
+						'title'    => esc_html__('Transactions Table Column Headings', 'event_espresso'),
181
+						'filename' => 'transactions_overview_table_column_headings',
182
+					),
183
+					'transactions_overview_views_filters_help_tab'         => array(
184
+						'title'    => esc_html__('Transaction Views & Filters & Search', 'event_espresso'),
185
+						'filename' => 'transactions_overview_views_filters_search',
186
+					),
187
+				),
188
+				'help_tour'     => array('Transactions_Overview_Help_Tour'),
189
+				/**
190
+				 * commented out because currently we are not displaying tips for transaction list table status but this
191
+				 * may change in a later iteration so want to keep the code for then.
192
+				 */
193
+				// 'qtips' => array( 'Transactions_List_Table_Tips' ),
194
+				'require_nonce' => false,
195
+			),
196
+			'view_transaction' => array(
197
+				'nav'       => array(
198
+					'label'      => esc_html__('View Transaction', 'event_espresso'),
199
+					'order'      => 5,
200
+					'url'        => isset($this->_req_data['TXN_ID'])
201
+						? add_query_arg(array('TXN_ID' => $this->_req_data['TXN_ID']), $this->_current_page_view_url)
202
+						: $this->_admin_base_url,
203
+					'persistent' => false,
204
+				),
205
+				'help_tabs' => array(
206
+					'transactions_view_transaction_help_tab'                                              => array(
207
+						'title'    => esc_html__('View Transaction', 'event_espresso'),
208
+						'filename' => 'transactions_view_transaction',
209
+					),
210
+					'transactions_view_transaction_transaction_details_table_help_tab'                    => array(
211
+						'title'    => esc_html__('Transaction Details Table', 'event_espresso'),
212
+						'filename' => 'transactions_view_transaction_transaction_details_table',
213
+					),
214
+					'transactions_view_transaction_attendees_registered_help_tab'                         => array(
215
+						'title'    => esc_html__('Attendees Registered', 'event_espresso'),
216
+						'filename' => 'transactions_view_transaction_attendees_registered',
217
+					),
218
+					'transactions_view_transaction_views_primary_registrant_billing_information_help_tab' => array(
219
+						'title'    => esc_html__('Primary Registrant & Billing Information', 'event_espresso'),
220
+						'filename' => 'transactions_view_transaction_primary_registrant_billing_information',
221
+					),
222
+				),
223
+				'qtips'     => array('Transaction_Details_Tips'),
224
+				'help_tour' => array('Transaction_Details_Help_Tour'),
225
+				'metaboxes' => array('_transaction_details_metaboxes'),
226
+
227
+				'require_nonce' => false,
228
+			),
229
+		);
230
+	}
231
+
232
+
233
+	/**
234
+	 * The below methods aren't used by this class currently
235
+	 */
236
+	protected function _add_screen_options()
237
+	{
238
+		// noop
239
+	}
240
+
241
+	protected function _add_feature_pointers()
242
+	{
243
+		// noop
244
+	}
245
+
246
+	public function admin_init()
247
+	{
248
+		// IF a registration was JUST added via the admin...
249
+		if (isset(
250
+			$this->_req_data['redirect_from'],
251
+			$this->_req_data['EVT_ID'],
252
+			$this->_req_data['event_name']
253
+		)) {
254
+			// then set a cookie so that we can block any attempts to use
255
+			// the back button as a way to enter another registration.
256
+			setcookie(
257
+				'ee_registration_added',
258
+				$this->_req_data['EVT_ID'],
259
+				time() + WEEK_IN_SECONDS,
260
+				'/'
261
+			);
262
+			// and update the global
263
+			$_COOKIE['ee_registration_added'] = $this->_req_data['EVT_ID'];
264
+		}
265
+		EE_Registry::$i18n_js_strings['invalid_server_response'] = esc_html__(
266
+			'An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
267
+			'event_espresso'
268
+		);
269
+		EE_Registry::$i18n_js_strings['error_occurred'] = esc_html__(
270
+			'An error occurred! Please refresh the page and try again.',
271
+			'event_espresso'
272
+		);
273
+		EE_Registry::$i18n_js_strings['txn_status_array'] = self::$_txn_status;
274
+		EE_Registry::$i18n_js_strings['pay_status_array'] = self::$_pay_status;
275
+		EE_Registry::$i18n_js_strings['payments_total'] = esc_html__('Payments Total', 'event_espresso');
276
+		EE_Registry::$i18n_js_strings['transaction_overpaid'] = esc_html__(
277
+			'This transaction has been overpaid ! Payments Total',
278
+			'event_espresso'
279
+		);
280
+	}
281
+
282
+	public function admin_notices()
283
+	{
284
+		// noop
285
+	}
286
+
287
+	public function admin_footer_scripts()
288
+	{
289
+		// noop
290
+	}
291
+
292
+
293
+	/**
294
+	 * _set_transaction_status_array
295
+	 * sets list of transaction statuses
296
+	 *
297
+	 * @access private
298
+	 * @return void
299
+	 * @throws EE_Error
300
+	 * @throws InvalidArgumentException
301
+	 * @throws InvalidDataTypeException
302
+	 * @throws InvalidInterfaceException
303
+	 */
304
+	private function _set_transaction_status_array()
305
+	{
306
+		self::$_txn_status = EEM_Transaction::instance()->status_array(true);
307
+	}
308
+
309
+
310
+	/**
311
+	 * get_transaction_status_array
312
+	 * return the transaction status array for wp_list_table
313
+	 *
314
+	 * @access public
315
+	 * @return array
316
+	 */
317
+	public function get_transaction_status_array()
318
+	{
319
+		return self::$_txn_status;
320
+	}
321
+
322
+
323
+	/**
324
+	 *    get list of payment statuses
325
+	 *
326
+	 * @access private
327
+	 * @return void
328
+	 * @throws EE_Error
329
+	 * @throws InvalidArgumentException
330
+	 * @throws InvalidDataTypeException
331
+	 * @throws InvalidInterfaceException
332
+	 */
333
+	private function _get_payment_status_array()
334
+	{
335
+		self::$_pay_status = EEM_Payment::instance()->status_array(true);
336
+		$this->_template_args['payment_status'] = self::$_pay_status;
337
+	}
338
+
339
+
340
+	/**
341
+	 *    _add_screen_options_default
342
+	 *
343
+	 * @access protected
344
+	 * @return void
345
+	 * @throws InvalidArgumentException
346
+	 * @throws InvalidDataTypeException
347
+	 * @throws InvalidInterfaceException
348
+	 */
349
+	protected function _add_screen_options_default()
350
+	{
351
+		$this->_per_page_screen_option();
352
+	}
353
+
354
+
355
+	/**
356
+	 * load_scripts_styles
357
+	 *
358
+	 * @access public
359
+	 * @return void
360
+	 */
361
+	public function load_scripts_styles()
362
+	{
363
+		// enqueue style
364
+		wp_register_style(
365
+			'espresso_txn',
366
+			TXN_ASSETS_URL . 'espresso_transactions_admin.css',
367
+			array(),
368
+			EVENT_ESPRESSO_VERSION
369
+		);
370
+		wp_enqueue_style('espresso_txn');
371
+		// scripts
372
+		wp_register_script(
373
+			'espresso_txn',
374
+			TXN_ASSETS_URL . 'espresso_transactions_admin.js',
375
+			array(
376
+				'ee_admin_js',
377
+				'ee-datepicker',
378
+				'jquery-ui-datepicker',
379
+				'jquery-ui-draggable',
380
+				'ee-dialog',
381
+				'ee-accounting',
382
+				'ee-serialize-full-array',
383
+			),
384
+			EVENT_ESPRESSO_VERSION,
385
+			true
386
+		);
387
+		wp_enqueue_script('espresso_txn');
388
+	}
389
+
390
+
391
+	/**
392
+	 *    load_scripts_styles_view_transaction
393
+	 *
394
+	 * @access public
395
+	 * @return void
396
+	 */
397
+	public function load_scripts_styles_view_transaction()
398
+	{
399
+		// styles
400
+		wp_enqueue_style('espresso-ui-theme');
401
+	}
402
+
403
+
404
+	/**
405
+	 *    load_scripts_styles_default
406
+	 *
407
+	 * @access public
408
+	 * @return void
409
+	 */
410
+	public function load_scripts_styles_default()
411
+	{
412
+		// styles
413
+		wp_enqueue_style('espresso-ui-theme');
414
+	}
415
+
416
+
417
+	/**
418
+	 *    _set_list_table_views_default
419
+	 *
420
+	 * @access protected
421
+	 * @return void
422
+	 */
423
+	protected function _set_list_table_views_default()
424
+	{
425
+		$this->_views = array(
426
+			'all'       => array(
427
+				'slug'  => 'all',
428
+				'label' => esc_html__('View All Transactions', 'event_espresso'),
429
+				'count' => 0,
430
+			),
431
+			'abandoned' => array(
432
+				'slug'  => 'abandoned',
433
+				'label' => esc_html__('Abandoned Transactions', 'event_espresso'),
434
+				'count' => 0,
435
+			),
436
+			'failed'    => array(
437
+				'slug'  => 'failed',
438
+				'label' => esc_html__('Failed Transactions', 'event_espresso'),
439
+				'count' => 0,
440
+			),
441
+		);
442
+	}
443
+
444
+
445
+	/**
446
+	 * _set_transaction_object
447
+	 * This sets the _transaction property for the transaction details screen
448
+	 *
449
+	 * @access private
450
+	 * @return void
451
+	 * @throws EE_Error
452
+	 * @throws InvalidArgumentException
453
+	 * @throws RuntimeException
454
+	 * @throws InvalidDataTypeException
455
+	 * @throws InvalidInterfaceException
456
+	 * @throws ReflectionException
457
+	 */
458
+	private function _set_transaction_object()
459
+	{
460
+		if ($this->_transaction instanceof EE_Transaction) {
461
+			return;
462
+		} //get out we've already set the object
463
+
464
+		$TXN_ID = ! empty($this->_req_data['TXN_ID'])
465
+			? absint($this->_req_data['TXN_ID'])
466
+			: false;
467
+
468
+		// get transaction object
469
+		$this->_transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
470
+		$this->_session = $this->_transaction instanceof EE_Transaction
471
+			? $this->_transaction->get('TXN_session_data')
472
+			: null;
473
+		if ($this->_transaction instanceof EE_Transaction) {
474
+			$this->_transaction->verify_abandoned_transaction_status();
475
+		}
476
+
477
+		if (! $this->_transaction instanceof EE_Transaction) {
478
+			$error_msg = sprintf(
479
+				esc_html__(
480
+					'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
481
+					'event_espresso'
482
+				),
483
+				$TXN_ID
484
+			);
485
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
486
+		}
487
+	}
488
+
489
+
490
+	/**
491
+	 *    _transaction_legend_items
492
+	 *
493
+	 * @access protected
494
+	 * @return array
495
+	 * @throws EE_Error
496
+	 * @throws InvalidArgumentException
497
+	 * @throws ReflectionException
498
+	 * @throws InvalidDataTypeException
499
+	 * @throws InvalidInterfaceException
500
+	 */
501
+	protected function _transaction_legend_items()
502
+	{
503
+		EE_Registry::instance()->load_helper('MSG_Template');
504
+		$items = array();
505
+
506
+		if (EE_Registry::instance()->CAP->current_user_can(
507
+			'ee_read_global_messages',
508
+			'view_filtered_messages'
509
+		)) {
510
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
511
+			if (is_array($related_for_icon)
512
+				&& isset($related_for_icon['css_class'], $related_for_icon['label'])
513
+			) {
514
+				$items['view_related_messages'] = array(
515
+					'class' => $related_for_icon['css_class'],
516
+					'desc'  => $related_for_icon['label'],
517
+				);
518
+			}
519
+		}
520
+
521
+		$items = apply_filters(
522
+			'FHEE__Transactions_Admin_Page___transaction_legend_items__items',
523
+			array_merge(
524
+				$items,
525
+				array(
526
+					'view_details'          => array(
527
+						'class' => 'dashicons dashicons-cart',
528
+						'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
529
+					),
530
+					'view_invoice'          => array(
531
+						'class' => 'dashicons dashicons-media-spreadsheet',
532
+						'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
533
+					),
534
+					'view_receipt'          => array(
535
+						'class' => 'dashicons dashicons-media-default',
536
+						'desc'  => esc_html__('View Transaction Receipt', 'event_espresso'),
537
+					),
538
+					'view_registration'     => array(
539
+						'class' => 'dashicons dashicons-clipboard',
540
+						'desc'  => esc_html__('View Registration Details', 'event_espresso'),
541
+					),
542
+					'payment_overview_link' => array(
543
+						'class' => 'dashicons dashicons-money',
544
+						'desc'  => esc_html__('Make Payment on Frontend', 'event_espresso'),
545
+					),
546
+				)
547
+			)
548
+		);
549
+
550
+		if (EE_Registry::instance()->CAP->current_user_can(
551
+			'ee_send_message',
552
+			'espresso_transactions_send_payment_reminder'
553
+		)) {
554
+			if (EEH_MSG_Template::is_mt_active('payment_reminder')) {
555
+				$items['send_payment_reminder'] = array(
556
+					'class' => 'dashicons dashicons-email-alt',
557
+					'desc'  => esc_html__('Send Payment Reminder', 'event_espresso'),
558
+				);
559
+			} else {
560
+				$items['blank*'] = array(
561
+					'class' => '',
562
+					'desc'  => '',
563
+				);
564
+			}
565
+		} else {
566
+			$items['blank*'] = array(
567
+				'class' => '',
568
+				'desc'  => '',
569
+			);
570
+		}
571
+		$more_items = apply_filters(
572
+			'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
573
+			array(
574
+				'overpaid'   => array(
575
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::overpaid_status_code,
576
+					'desc'  => EEH_Template::pretty_status(
577
+						EEM_Transaction::overpaid_status_code,
578
+						false,
579
+						'sentence'
580
+					),
581
+				),
582
+				'complete'   => array(
583
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::complete_status_code,
584
+					'desc'  => EEH_Template::pretty_status(
585
+						EEM_Transaction::complete_status_code,
586
+						false,
587
+						'sentence'
588
+					),
589
+				),
590
+				'incomplete' => array(
591
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::incomplete_status_code,
592
+					'desc'  => EEH_Template::pretty_status(
593
+						EEM_Transaction::incomplete_status_code,
594
+						false,
595
+						'sentence'
596
+					),
597
+				),
598
+				'abandoned'  => array(
599
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::abandoned_status_code,
600
+					'desc'  => EEH_Template::pretty_status(
601
+						EEM_Transaction::abandoned_status_code,
602
+						false,
603
+						'sentence'
604
+					),
605
+				),
606
+				'failed'     => array(
607
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::failed_status_code,
608
+					'desc'  => EEH_Template::pretty_status(
609
+						EEM_Transaction::failed_status_code,
610
+						false,
611
+						'sentence'
612
+					),
613
+				),
614
+			)
615
+		);
616
+
617
+		return array_merge($items, $more_items);
618
+	}
619
+
620
+
621
+	/**
622
+	 *    _transactions_overview_list_table
623
+	 *
624
+	 * @access protected
625
+	 * @return void
626
+	 * @throws DomainException
627
+	 * @throws EE_Error
628
+	 * @throws InvalidArgumentException
629
+	 * @throws InvalidDataTypeException
630
+	 * @throws InvalidInterfaceException
631
+	 * @throws ReflectionException
632
+	 */
633
+	protected function _transactions_overview_list_table()
634
+	{
635
+		$this->_admin_page_title = esc_html__('Transactions', 'event_espresso');
636
+		$event = isset($this->_req_data['EVT_ID'])
637
+			? EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID'])
638
+			: null;
639
+		$this->_template_args['admin_page_header'] = $event instanceof EE_Event
640
+			? sprintf(
641
+				esc_html__(
642
+					'%sViewing Transactions for the Event: %s%s',
643
+					'event_espresso'
644
+				),
645
+				'<h3>',
646
+				'<a href="'
647
+				. EE_Admin_Page::add_query_args_and_nonce(
648
+					array('action' => 'edit', 'post' => $event->ID()),
649
+					EVENTS_ADMIN_URL
650
+				)
651
+				. '" title="'
652
+				. esc_attr__(
653
+					'Click to Edit event',
654
+					'event_espresso'
655
+				)
656
+				. '">' . $event->get('EVT_name') . '</a>',
657
+				'</h3>'
658
+			)
659
+			: '';
660
+		$this->_template_args['after_list_table'] = $this->_display_legend($this->_transaction_legend_items());
661
+		$this->display_admin_list_table_page_with_no_sidebar();
662
+	}
663
+
664
+
665
+	/**
666
+	 *    _transaction_details
667
+	 * generates HTML for the View Transaction Details Admin page
668
+	 *
669
+	 * @access protected
670
+	 * @return void
671
+	 * @throws DomainException
672
+	 * @throws EE_Error
673
+	 * @throws InvalidArgumentException
674
+	 * @throws InvalidDataTypeException
675
+	 * @throws InvalidInterfaceException
676
+	 * @throws RuntimeException
677
+	 * @throws ReflectionException
678
+	 */
679
+	protected function _transaction_details()
680
+	{
681
+		do_action('AHEE__Transactions_Admin_Page__transaction_details__start', $this->_transaction);
682
+
683
+		$this->_set_transaction_status_array();
684
+
685
+		$this->_template_args = array();
686
+		$this->_template_args['transactions_page'] = $this->_wp_page_slug;
687
+
688
+		$this->_set_transaction_object();
689
+
690
+		if (! $this->_transaction instanceof EE_Transaction) {
691
+			return;
692
+		}
693
+		$primary_registration = $this->_transaction->primary_registration();
694
+		$attendee = $primary_registration instanceof EE_Registration
695
+			? $primary_registration->attendee()
696
+			: null;
697
+
698
+		$this->_template_args['txn_nmbr']['value'] = $this->_transaction->ID();
699
+		$this->_template_args['txn_nmbr']['label'] = esc_html__('Transaction Number', 'event_espresso');
700
+
701
+		$this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
702
+		$this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
703
+
704
+		$this->_template_args['txn_status']['value'] = self::$_txn_status[ $this->_transaction->get('STS_ID') ];
705
+		$this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
706
+		$this->_template_args['txn_status']['class'] = 'status-' . $this->_transaction->get('STS_ID');
707
+
708
+		$this->_template_args['grand_total'] = $this->_transaction->get('TXN_total');
709
+		$this->_template_args['total_paid'] = $this->_transaction->get('TXN_paid');
710
+
711
+		$amount_due = $this->_transaction->get('TXN_total') - $this->_transaction->get('TXN_paid');
712
+		$this->_template_args['amount_due'] = EEH_Template::format_currency(
713
+			$amount_due,
714
+			true
715
+		);
716
+		if (EE_Registry::instance()->CFG->currency->sign_b4) {
717
+			$this->_template_args['amount_due'] = EE_Registry::instance()->CFG->currency->sign
718
+												  . $this->_template_args['amount_due'];
719
+		} else {
720
+			$this->_template_args['amount_due'] .= EE_Registry::instance()->CFG->currency->sign;
721
+		}
722
+		$this->_template_args['amount_due_class'] = '';
723
+
724
+		if ($this->_transaction->get('TXN_paid') == $this->_transaction->get('TXN_total')) {
725
+			// paid in full
726
+			$this->_template_args['amount_due'] = false;
727
+		} elseif ($this->_transaction->get('TXN_paid') > $this->_transaction->get('TXN_total')) {
728
+			// overpaid
729
+			$this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
730
+		} elseif ($this->_transaction->get('TXN_total') > 0
731
+				  && $this->_transaction->get('TXN_paid') > 0
732
+		) {
733
+			// monies owing
734
+			$this->_template_args['amount_due_class'] = 'txn-overview-part-payment-spn';
735
+		} elseif ($this->_transaction->get('TXN_total') > 0
736
+				  && $this->_transaction->get('TXN_paid') == 0
737
+		) {
738
+			// no payments made yet
739
+			$this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
740
+		} elseif ($this->_transaction->get('TXN_total') == 0) {
741
+			// free event
742
+			$this->_template_args['amount_due'] = false;
743
+		}
744
+
745
+		$payment_method = $this->_transaction->payment_method();
746
+
747
+		$this->_template_args['method_of_payment_name'] = $payment_method instanceof EE_Payment_Method
748
+			? $payment_method->admin_name()
749
+			: esc_html__('Unknown', 'event_espresso');
750
+
751
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
752
+		// link back to overview
753
+		$this->_template_args['txn_overview_url'] = ! empty($_SERVER['HTTP_REFERER'])
754
+			? $_SERVER['HTTP_REFERER']
755
+			: TXN_ADMIN_URL;
756
+
757
+
758
+		// next link
759
+		$next_txn = $this->_transaction->next(
760
+			null,
761
+			array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
762
+			'TXN_ID'
763
+		);
764
+		$this->_template_args['next_transaction'] = $next_txn
765
+			? $this->_next_link(
766
+				EE_Admin_Page::add_query_args_and_nonce(
767
+					array('action' => 'view_transaction', 'TXN_ID' => $next_txn['TXN_ID']),
768
+					TXN_ADMIN_URL
769
+				),
770
+				'dashicons dashicons-arrow-right ee-icon-size-22'
771
+			)
772
+			: '';
773
+		// previous link
774
+		$previous_txn = $this->_transaction->previous(
775
+			null,
776
+			array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
777
+			'TXN_ID'
778
+		);
779
+		$this->_template_args['previous_transaction'] = $previous_txn
780
+			? $this->_previous_link(
781
+				EE_Admin_Page::add_query_args_and_nonce(
782
+					array('action' => 'view_transaction', 'TXN_ID' => $previous_txn['TXN_ID']),
783
+					TXN_ADMIN_URL
784
+				),
785
+				'dashicons dashicons-arrow-left ee-icon-size-22'
786
+			)
787
+			: '';
788
+
789
+		// were we just redirected here after adding a new registration ???
790
+		if (isset(
791
+			$this->_req_data['redirect_from'],
792
+			$this->_req_data['EVT_ID'],
793
+			$this->_req_data['event_name']
794
+		)) {
795
+			if (EE_Registry::instance()->CAP->current_user_can(
796
+				'ee_edit_registrations',
797
+				'espresso_registrations_new_registration',
798
+				$this->_req_data['EVT_ID']
799
+			)) {
800
+				$this->_admin_page_title .= '<a id="add-new-registration" class="add-new-h2 button-primary" href="';
801
+				$this->_admin_page_title .= EE_Admin_Page::add_query_args_and_nonce(
802
+					array(
803
+						'page'     => 'espresso_registrations',
804
+						'action'   => 'new_registration',
805
+						'return'   => 'default',
806
+						'TXN_ID'   => $this->_transaction->ID(),
807
+						'event_id' => $this->_req_data['EVT_ID'],
808
+					),
809
+					REG_ADMIN_URL
810
+				);
811
+				$this->_admin_page_title .= '">';
812
+
813
+				$this->_admin_page_title .= sprintf(
814
+					esc_html__('Add Another New Registration to Event: "%1$s" ?', 'event_espresso'),
815
+					htmlentities(urldecode($this->_req_data['event_name']), ENT_QUOTES, 'UTF-8')
816
+				);
817
+				$this->_admin_page_title .= '</a>';
818
+			}
819
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
820
+		}
821
+		// grab messages at the last second
822
+		$this->_template_args['notices'] = EE_Error::get_notices();
823
+		// path to template
824
+		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
825
+		$this->_template_args['admin_page_header'] = EEH_Template::display_template(
826
+			$template_path,
827
+			$this->_template_args,
828
+			true
829
+		);
830
+
831
+		// the details template wrapper
832
+		$this->display_admin_page_with_sidebar();
833
+	}
834
+
835
+
836
+	/**
837
+	 *        _transaction_details_metaboxes
838
+	 *
839
+	 * @access protected
840
+	 * @return void
841
+	 * @throws EE_Error
842
+	 * @throws InvalidArgumentException
843
+	 * @throws InvalidDataTypeException
844
+	 * @throws InvalidInterfaceException
845
+	 * @throws RuntimeException
846
+	 * @throws ReflectionException
847
+	 */
848
+	protected function _transaction_details_metaboxes()
849
+	{
850
+
851
+		$this->_set_transaction_object();
852
+
853
+		if (! $this->_transaction instanceof EE_Transaction) {
854
+			return;
855
+		}
856
+		add_meta_box(
857
+			'edit-txn-details-mbox',
858
+			esc_html__('Transaction Details', 'event_espresso'),
859
+			array($this, 'txn_details_meta_box'),
860
+			$this->_wp_page_slug,
861
+			'normal',
862
+			'high'
863
+		);
864
+		add_meta_box(
865
+			'edit-txn-attendees-mbox',
866
+			esc_html__('Attendees Registered in this Transaction', 'event_espresso'),
867
+			array($this, 'txn_attendees_meta_box'),
868
+			$this->_wp_page_slug,
869
+			'normal',
870
+			'high',
871
+			array('TXN_ID' => $this->_transaction->ID())
872
+		);
873
+		add_meta_box(
874
+			'edit-txn-registrant-mbox',
875
+			esc_html__('Primary Contact', 'event_espresso'),
876
+			array($this, 'txn_registrant_side_meta_box'),
877
+			$this->_wp_page_slug,
878
+			'side',
879
+			'high'
880
+		);
881
+		add_meta_box(
882
+			'edit-txn-billing-info-mbox',
883
+			esc_html__('Billing Information', 'event_espresso'),
884
+			array($this, 'txn_billing_info_side_meta_box'),
885
+			$this->_wp_page_slug,
886
+			'side',
887
+			'high'
888
+		);
889
+	}
890
+
891
+
892
+	/**
893
+	 * Callback for transaction actions metabox.
894
+	 *
895
+	 * @param EE_Transaction|null $transaction
896
+	 * @throws DomainException
897
+	 * @throws EE_Error
898
+	 * @throws InvalidArgumentException
899
+	 * @throws InvalidDataTypeException
900
+	 * @throws InvalidInterfaceException
901
+	 * @throws ReflectionException
902
+	 * @throws RuntimeException
903
+	 */
904
+	public function getActionButtons(EE_Transaction $transaction = null)
905
+	{
906
+		$content = '';
907
+		$actions = array();
908
+		if (! $transaction instanceof EE_Transaction) {
909
+			return $content;
910
+		}
911
+		/** @var EE_Registration $primary_registration */
912
+		$primary_registration = $transaction->primary_registration();
913
+		$attendee = $primary_registration instanceof EE_Registration
914
+			? $primary_registration->attendee()
915
+			: null;
916
+
917
+		if ($attendee instanceof EE_Attendee
918
+			&& EE_Registry::instance()->CAP->current_user_can(
919
+				'ee_send_message',
920
+				'espresso_transactions_send_payment_reminder'
921
+			)
922
+		) {
923
+			$actions['payment_reminder'] =
924
+				EEH_MSG_Template::is_mt_active('payment_reminder')
925
+				&& $this->_transaction->get('STS_ID') !== EEM_Transaction::complete_status_code
926
+				&& $this->_transaction->get('STS_ID') !== EEM_Transaction::overpaid_status_code
927
+					? EEH_Template::get_button_or_link(
928
+						EE_Admin_Page::add_query_args_and_nonce(
929
+							array(
930
+								'action'      => 'send_payment_reminder',
931
+								'TXN_ID'      => $this->_transaction->ID(),
932
+								'redirect_to' => 'view_transaction',
933
+							),
934
+							TXN_ADMIN_URL
935
+						),
936
+						esc_html__(' Send Payment Reminder', 'event_espresso'),
937
+						'button secondary-button',
938
+						'dashicons dashicons-email-alt'
939
+					)
940
+					: '';
941
+		}
942
+
943
+		if ($primary_registration instanceof EE_Registration
944
+			&& EEH_MSG_Template::is_mt_active('receipt')
945
+		) {
946
+			$actions['receipt'] = EEH_Template::get_button_or_link(
947
+				$primary_registration->receipt_url(),
948
+				esc_html__('View Receipt', 'event_espresso'),
949
+				'button secondary-button',
950
+				'dashicons dashicons-media-default'
951
+			);
952
+		}
953
+
954
+		if ($primary_registration instanceof EE_Registration
955
+			&& EEH_MSG_Template::is_mt_active('invoice')
956
+		) {
957
+			$actions['invoice'] = EEH_Template::get_button_or_link(
958
+				$primary_registration->invoice_url(),
959
+				esc_html__('View Invoice', 'event_espresso'),
960
+				'button secondary-button',
961
+				'dashicons dashicons-media-spreadsheet'
962
+			);
963
+		}
964
+		$actions = array_filter(
965
+			apply_filters('FHEE__Transactions_Admin_Page__getActionButtons__actions', $actions, $transaction)
966
+		);
967
+		if ($actions) {
968
+			$content = '<ul>';
969
+			$content .= '<li>' . implode('</li><li>', $actions) . '</li>';
970
+			$content .= '</uL>';
971
+		}
972
+		return $content;
973
+	}
974
+
975
+
976
+	/**
977
+	 * txn_details_meta_box
978
+	 * generates HTML for the Transaction main meta box
979
+	 *
980
+	 * @return void
981
+	 * @throws DomainException
982
+	 * @throws EE_Error
983
+	 * @throws InvalidArgumentException
984
+	 * @throws InvalidDataTypeException
985
+	 * @throws InvalidInterfaceException
986
+	 * @throws RuntimeException
987
+	 * @throws ReflectionException
988
+	 */
989
+	public function txn_details_meta_box()
990
+	{
991
+		$this->_set_transaction_object();
992
+		$this->_template_args['TXN_ID'] = $this->_transaction->ID();
993
+		$this->_template_args['attendee'] = $this->_transaction->primary_registration() instanceof EE_Registration
994
+			? $this->_transaction->primary_registration()->attendee()
995
+			: null;
996
+		$this->_template_args['can_edit_payments'] = EE_Registry::instance()->CAP->current_user_can(
997
+			'ee_edit_payments',
998
+			'apply_payment_or_refund_from_registration_details'
999
+		);
1000
+		$this->_template_args['can_delete_payments'] = EE_Registry::instance()->CAP->current_user_can(
1001
+			'ee_delete_payments',
1002
+			'delete_payment_from_registration_details'
1003
+		);
1004
+
1005
+		// get line table
1006
+		EEH_Autoloader::register_line_item_display_autoloaders();
1007
+		$Line_Item_Display = new EE_Line_Item_Display(
1008
+			'admin_table',
1009
+			'EE_Admin_Table_Line_Item_Display_Strategy'
1010
+		);
1011
+		$this->_template_args['line_item_table'] = $Line_Item_Display->display_line_item(
1012
+			$this->_transaction->total_line_item()
1013
+		);
1014
+		$this->_template_args['REG_code'] = $this->_transaction->get_first_related('Registration')
1015
+															   ->get('REG_code');
1016
+
1017
+		// process taxes
1018
+		$taxes = $this->_transaction->get_many_related(
1019
+			'Line_Item',
1020
+			array(array('LIN_type' => EEM_Line_Item::type_tax))
1021
+		);
1022
+		$this->_template_args['taxes'] = ! empty($taxes) ? $taxes : false;
1023
+
1024
+		$this->_template_args['grand_total'] = EEH_Template::format_currency(
1025
+			$this->_transaction->get('TXN_total'),
1026
+			false,
1027
+			false
1028
+		);
1029
+		$this->_template_args['grand_raw_total'] = $this->_transaction->get('TXN_total');
1030
+		$this->_template_args['TXN_status'] = $this->_transaction->get('STS_ID');
1031
+
1032
+		// process payment details
1033
+		$payments = $this->_transaction->get_many_related('Payment');
1034
+		if (! empty($payments)) {
1035
+			$this->_template_args['payments'] = $payments;
1036
+			$this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1037
+		} else {
1038
+			$this->_template_args['payments'] = false;
1039
+			$this->_template_args['existing_reg_payments'] = array();
1040
+		}
1041
+
1042
+		$this->_template_args['edit_payment_url'] = add_query_arg(array('action' => 'edit_payment'), TXN_ADMIN_URL);
1043
+		$this->_template_args['delete_payment_url'] = add_query_arg(
1044
+			array('action' => 'espresso_delete_payment'),
1045
+			TXN_ADMIN_URL
1046
+		);
1047
+
1048
+		if (isset($txn_details['invoice_number'])) {
1049
+			$this->_template_args['txn_details']['invoice_number']['value'] = $this->_template_args['REG_code'];
1050
+			$this->_template_args['txn_details']['invoice_number']['label'] = esc_html__(
1051
+				'Invoice Number',
1052
+				'event_espresso'
1053
+			);
1054
+		}
1055
+
1056
+		$this->_template_args['txn_details']['registration_session']['value'] = $this->_transaction
1057
+			->get_first_related('Registration')
1058
+			->get('REG_session');
1059
+		$this->_template_args['txn_details']['registration_session']['label'] = esc_html__(
1060
+			'Registration Session',
1061
+			'event_espresso'
1062
+		);
1063
+
1064
+		$this->_template_args['txn_details']['ip_address']['value'] = isset($this->_session['ip_address'])
1065
+			? $this->_session['ip_address']
1066
+			: '';
1067
+		$this->_template_args['txn_details']['ip_address']['label'] = esc_html__(
1068
+			'Transaction placed from IP',
1069
+			'event_espresso'
1070
+		);
1071
+
1072
+		$this->_template_args['txn_details']['user_agent']['value'] = isset($this->_session['user_agent'])
1073
+			? $this->_session['user_agent']
1074
+			: '';
1075
+		$this->_template_args['txn_details']['user_agent']['label'] = esc_html__(
1076
+			'Registrant User Agent',
1077
+			'event_espresso'
1078
+		);
1079
+
1080
+		$reg_steps = '<ul>';
1081
+		foreach ($this->_transaction->reg_steps() as $reg_step => $reg_step_status) {
1082
+			if ($reg_step_status === true) {
1083
+				$reg_steps .= '<li style="color:#70cc50">'
1084
+							  . sprintf(
1085
+								  esc_html__('%1$s : Completed', 'event_espresso'),
1086
+								  ucwords(str_replace('_', ' ', $reg_step))
1087
+							  )
1088
+							  . '</li>';
1089
+			} elseif (is_numeric($reg_step_status) && $reg_step_status !== false) {
1090
+				$reg_steps .= '<li style="color:#2EA2CC">'
1091
+							  . sprintf(
1092
+								  esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1093
+								  ucwords(str_replace('_', ' ', $reg_step)),
1094
+								  date(
1095
+									  get_option('date_format') . ' ' . get_option('time_format'),
1096
+									  ($reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS))
1097
+								  )
1098
+							  )
1099
+							  . '</li>';
1100
+			} else {
1101
+				$reg_steps .= '<li style="color:#E76700">'
1102
+							  . sprintf(
1103
+								  esc_html__('%1$s : Never Initiated', 'event_espresso'),
1104
+								  ucwords(str_replace('_', ' ', $reg_step))
1105
+							  )
1106
+							  . '</li>';
1107
+			}
1108
+		}
1109
+		$reg_steps .= '</ul>';
1110
+		$this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
1111
+		$this->_template_args['txn_details']['reg_steps']['label'] = esc_html__(
1112
+			'Registration Step Progress',
1113
+			'event_espresso'
1114
+		);
1115
+
1116
+
1117
+		$this->_get_registrations_to_apply_payment_to();
1118
+		$this->_get_payment_methods($payments);
1119
+		$this->_get_payment_status_array();
1120
+		$this->_get_reg_status_selection(); // sets up the template args for the reg status array for the transaction.
1121
+
1122
+		$this->_template_args['transaction_form_url'] = add_query_arg(
1123
+			array(
1124
+				'action'  => 'edit_transaction',
1125
+				'process' => 'transaction',
1126
+			),
1127
+			TXN_ADMIN_URL
1128
+		);
1129
+		$this->_template_args['apply_payment_form_url'] = add_query_arg(
1130
+			array(
1131
+				'page'   => 'espresso_transactions',
1132
+				'action' => 'espresso_apply_payment',
1133
+			),
1134
+			WP_AJAX_URL
1135
+		);
1136
+		$this->_template_args['delete_payment_form_url'] = add_query_arg(
1137
+			array(
1138
+				'page'   => 'espresso_transactions',
1139
+				'action' => 'espresso_delete_payment',
1140
+			),
1141
+			WP_AJAX_URL
1142
+		);
1143
+
1144
+		$this->_template_args['action_buttons'] = $this->getActionButtons($this->_transaction);
1145
+
1146
+		// 'espresso_delete_payment_nonce'
1147
+
1148
+		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1149
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
1150
+	}
1151
+
1152
+
1153
+	/**
1154
+	 * _get_registration_payment_IDs
1155
+	 *    generates an array of Payment IDs and their corresponding Registration IDs
1156
+	 *
1157
+	 * @access protected
1158
+	 * @param EE_Payment[] $payments
1159
+	 * @return array
1160
+	 * @throws EE_Error
1161
+	 * @throws InvalidArgumentException
1162
+	 * @throws InvalidDataTypeException
1163
+	 * @throws InvalidInterfaceException
1164
+	 * @throws ReflectionException
1165
+	 */
1166
+	protected function _get_registration_payment_IDs($payments = array())
1167
+	{
1168
+		$existing_reg_payments = array();
1169
+		// get all reg payments for these payments
1170
+		$reg_payments = EEM_Registration_Payment::instance()->get_all(
1171
+			array(
1172
+				array(
1173
+					'PAY_ID' => array(
1174
+						'IN',
1175
+						array_keys($payments),
1176
+					),
1177
+				),
1178
+			)
1179
+		);
1180
+		if (! empty($reg_payments)) {
1181
+			foreach ($payments as $payment) {
1182
+				if (! $payment instanceof EE_Payment) {
1183
+					continue;
1184
+				} elseif (! isset($existing_reg_payments[ $payment->ID() ])) {
1185
+					$existing_reg_payments[ $payment->ID() ] = array();
1186
+				}
1187
+				foreach ($reg_payments as $reg_payment) {
1188
+					if ($reg_payment instanceof EE_Registration_Payment
1189
+						&& $reg_payment->payment_ID() === $payment->ID()
1190
+					) {
1191
+						$existing_reg_payments[ $payment->ID() ][] = $reg_payment->registration_ID();
1192
+					}
1193
+				}
1194
+			}
1195
+		}
1196
+
1197
+		return $existing_reg_payments;
1198
+	}
1199
+
1200
+
1201
+	/**
1202
+	 * _get_registrations_to_apply_payment_to
1203
+	 *    generates HTML for displaying a series of checkboxes in the admin payment modal window
1204
+	 * which allows the admin to only apply the payment to the specific registrations
1205
+	 *
1206
+	 * @access protected
1207
+	 * @return void
1208
+	 * @throws \EE_Error
1209
+	 */
1210
+	protected function _get_registrations_to_apply_payment_to()
1211
+	{
1212
+		// we want any registration with an active status (ie: not deleted or cancelled)
1213
+		$query_params = array(
1214
+			array(
1215
+				'STS_ID' => array(
1216
+					'IN',
1217
+					array(
1218
+						EEM_Registration::status_id_approved,
1219
+						EEM_Registration::status_id_pending_payment,
1220
+						EEM_Registration::status_id_not_approved,
1221
+					),
1222
+				),
1223
+			),
1224
+		);
1225
+		$registrations_to_apply_payment_to = EEH_HTML::br()
1226
+											 . EEH_HTML::div(
1227
+												 '',
1228
+												 'txn-admin-apply-payment-to-registrations-dv',
1229
+												 '',
1230
+												 'clear: both; margin: 1.5em 0 0; display: none;'
1231
+											 );
1232
+		$registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1233
+		$registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl');
1234
+		$registrations_to_apply_payment_to .= EEH_HTML::thead(
1235
+			EEH_HTML::tr(
1236
+				EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1237
+				EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1238
+				EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1239
+				EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1240
+				EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1241
+				EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1242
+				EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1243
+			)
1244
+		);
1245
+		$registrations_to_apply_payment_to .= EEH_HTML::tbody();
1246
+		// get registrations for TXN
1247
+		$registrations = $this->_transaction->registrations($query_params);
1248
+		$existing_reg_payments = $this->_template_args['existing_reg_payments'];
1249
+		foreach ($registrations as $registration) {
1250
+			if ($registration instanceof EE_Registration) {
1251
+				$attendee_name = $registration->attendee() instanceof EE_Attendee
1252
+					? $registration->attendee()->full_name()
1253
+					: esc_html__('Unknown Attendee', 'event_espresso');
1254
+				$owing = $registration->final_price() - $registration->paid();
1255
+				$taxable = $registration->ticket()->taxable()
1256
+					? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1257
+					: '';
1258
+				$checked = empty($existing_reg_payments) || in_array($registration->ID(), $existing_reg_payments)
1259
+					? ' checked="checked"'
1260
+					: '';
1261
+				$disabled = $registration->final_price() > 0 ? '' : ' disabled';
1262
+				$registrations_to_apply_payment_to .= EEH_HTML::tr(
1263
+					EEH_HTML::td($registration->ID()) .
1264
+					EEH_HTML::td($attendee_name) .
1265
+					EEH_HTML::td(
1266
+						$registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1267
+					) .
1268
+					EEH_HTML::td($registration->event_name()) .
1269
+					EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1270
+					EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr') .
1271
+					EEH_HTML::td(
1272
+						'<input type="checkbox" value="' . $registration->ID()
1273
+						. '" name="txn_admin_payment[registrations]"'
1274
+						. $checked . $disabled . '>',
1275
+						'',
1276
+						'jst-cntr'
1277
+					),
1278
+					'apply-payment-registration-row-' . $registration->ID()
1279
+				);
1280
+			}
1281
+		}
1282
+		$registrations_to_apply_payment_to .= EEH_HTML::tbodyx();
1283
+		$registrations_to_apply_payment_to .= EEH_HTML::tablex();
1284
+		$registrations_to_apply_payment_to .= EEH_HTML::divx();
1285
+		$registrations_to_apply_payment_to .= EEH_HTML::p(
1286
+			esc_html__(
1287
+				'The payment will only be applied to the registrations that have a check mark in their corresponding check box. Checkboxes for free registrations have been disabled.',
1288
+				'event_espresso'
1289
+			),
1290
+			'',
1291
+			'clear description'
1292
+		);
1293
+		$registrations_to_apply_payment_to .= EEH_HTML::divx();
1294
+		$this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1295
+	}
1296
+
1297
+
1298
+	/**
1299
+	 * _get_reg_status_selection
1300
+	 *
1301
+	 * @todo   this will need to be adjusted either once MER comes along OR we move default reg status to tickets
1302
+	 *         instead of events.
1303
+	 * @access protected
1304
+	 * @return void
1305
+	 * @throws EE_Error
1306
+	 */
1307
+	protected function _get_reg_status_selection()
1308
+	{
1309
+		// first get all possible statuses
1310
+		$statuses = EEM_Registration::reg_status_array(array(), true);
1311
+		// let's add a "don't change" option.
1312
+		$status_array['NAN'] = esc_html__('Leave the Same', 'event_espresso');
1313
+		$status_array = array_merge($status_array, $statuses);
1314
+		$this->_template_args['status_change_select'] = EEH_Form_Fields::select_input(
1315
+			'txn_reg_status_change[reg_status]',
1316
+			$status_array,
1317
+			'NAN',
1318
+			'id="txn-admin-payment-reg-status-inp"',
1319
+			'txn-reg-status-change-reg-status'
1320
+		);
1321
+		$this->_template_args['delete_status_change_select'] = EEH_Form_Fields::select_input(
1322
+			'delete_txn_reg_status_change[reg_status]',
1323
+			$status_array,
1324
+			'NAN',
1325
+			'delete-txn-admin-payment-reg-status-inp',
1326
+			'delete-txn-reg-status-change-reg-status'
1327
+		);
1328
+	}
1329
+
1330
+
1331
+	/**
1332
+	 *    _get_payment_methods
1333
+	 * Gets all the payment methods available generally, or the ones that are already
1334
+	 * selected on these payments (in case their payment methods are no longer active).
1335
+	 * Has the side-effect of updating the template args' payment_methods item
1336
+	 *
1337
+	 * @access private
1338
+	 * @param EE_Payment[] to show on this page
1339
+	 * @return void
1340
+	 * @throws EE_Error
1341
+	 * @throws InvalidArgumentException
1342
+	 * @throws InvalidDataTypeException
1343
+	 * @throws InvalidInterfaceException
1344
+	 * @throws ReflectionException
1345
+	 */
1346
+	private function _get_payment_methods($payments = array())
1347
+	{
1348
+		$payment_methods_of_payments = array();
1349
+		foreach ($payments as $payment) {
1350
+			if ($payment instanceof EE_Payment) {
1351
+				$payment_methods_of_payments[] = $payment->get('PMD_ID');
1352
+			}
1353
+		}
1354
+		if ($payment_methods_of_payments) {
1355
+			$query_args = array(
1356
+				array(
1357
+					'OR*payment_method_for_payment' => array(
1358
+						'PMD_ID'    => array('IN', $payment_methods_of_payments),
1359
+						'PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%'),
1360
+					),
1361
+				),
1362
+			);
1363
+		} else {
1364
+			$query_args = array(array('PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%')));
1365
+		}
1366
+		$this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1367
+	}
1368
+
1369
+
1370
+	/**
1371
+	 * txn_attendees_meta_box
1372
+	 *    generates HTML for the Attendees Transaction main meta box
1373
+	 *
1374
+	 * @access public
1375
+	 * @param WP_Post $post
1376
+	 * @param array   $metabox
1377
+	 * @return void
1378
+	 * @throws DomainException
1379
+	 * @throws EE_Error
1380
+	 */
1381
+	public function txn_attendees_meta_box($post, $metabox = array('args' => array()))
1382
+	{
1383
+
1384
+		/** @noinspection NonSecureExtractUsageInspection */
1385
+		extract($metabox['args']);
1386
+		$this->_template_args['post'] = $post;
1387
+		$this->_template_args['event_attendees'] = array();
1388
+		// process items in cart
1389
+		$line_items = $this->_transaction->get_many_related(
1390
+			'Line_Item',
1391
+			array(array('LIN_type' => 'line-item'))
1392
+		);
1393
+		if (! empty($line_items)) {
1394
+			foreach ($line_items as $item) {
1395
+				if ($item instanceof EE_Line_Item) {
1396
+					switch ($item->OBJ_type()) {
1397
+						case 'Event':
1398
+							break;
1399
+						case 'Ticket':
1400
+							$ticket = $item->ticket();
1401
+							// right now we're only handling tickets here.
1402
+							// Cause its expected that only tickets will have attendees right?
1403
+							if (! $ticket instanceof EE_Ticket) {
1404
+								continue;
1405
+							}
1406
+							try {
1407
+								$event_name = $ticket->get_event_name();
1408
+							} catch (Exception $e) {
1409
+								EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1410
+								$event_name = esc_html__('Unknown Event', 'event_espresso');
1411
+							}
1412
+							$event_name .= ' - ' . $item->get('LIN_name');
1413
+							$ticket_price = EEH_Template::format_currency($item->get('LIN_unit_price'));
1414
+							// now get all of the registrations for this transaction that use this ticket
1415
+							$registrations = $ticket->get_many_related(
1416
+								'Registration',
1417
+								array(array('TXN_ID' => $this->_transaction->ID()))
1418
+							);
1419
+							foreach ($registrations as $registration) {
1420
+								if (! $registration instanceof EE_Registration) {
1421
+									continue;
1422
+								}
1423
+								$this->_template_args['event_attendees'][ $registration->ID() ]['STS_ID']
1424
+									= $registration->status_ID();
1425
+								$this->_template_args['event_attendees'][ $registration->ID() ]['att_num']
1426
+									= $registration->count();
1427
+								$this->_template_args['event_attendees'][ $registration->ID() ]['event_ticket_name']
1428
+									= $event_name;
1429
+								$this->_template_args['event_attendees'][ $registration->ID() ]['ticket_price']
1430
+									= $ticket_price;
1431
+								// attendee info
1432
+								$attendee = $registration->get_first_related('Attendee');
1433
+								if ($attendee instanceof EE_Attendee) {
1434
+									$this->_template_args['event_attendees'][ $registration->ID() ]['att_id']
1435
+										= $attendee->ID();
1436
+									$this->_template_args['event_attendees'][ $registration->ID() ]['attendee']
1437
+										= $attendee->full_name();
1438
+									$this->_template_args['event_attendees'][ $registration->ID() ]['email']
1439
+										= '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1440
+										  . esc_html__(
1441
+											  ' Event',
1442
+											  'event_espresso'
1443
+										  )
1444
+										  . '">' . $attendee->email() . '</a>';
1445
+									$this->_template_args['event_attendees'][ $registration->ID() ]['address']
1446
+										= EEH_Address::format($attendee, 'inline', false, false);
1447
+								} else {
1448
+									$this->_template_args['event_attendees'][ $registration->ID() ]['att_id'] = '';
1449
+									$this->_template_args['event_attendees'][ $registration->ID() ]['attendee'] = '';
1450
+									$this->_template_args['event_attendees'][ $registration->ID() ]['email'] = '';
1451
+									$this->_template_args['event_attendees'][ $registration->ID() ]['address'] = '';
1452
+								}
1453
+							}
1454
+							break;
1455
+					}
1456
+				}
1457
+			}
1458
+
1459
+			$this->_template_args['transaction_form_url'] = add_query_arg(
1460
+				array(
1461
+					'action'  => 'edit_transaction',
1462
+					'process' => 'attendees',
1463
+				),
1464
+				TXN_ADMIN_URL
1465
+			);
1466
+			echo EEH_Template::display_template(
1467
+				TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1468
+				$this->_template_args,
1469
+				true
1470
+			);
1471
+		} else {
1472
+			echo sprintf(
1473
+				esc_html__(
1474
+					'%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s',
1475
+					'event_espresso'
1476
+				),
1477
+				'<p class="important-notice">',
1478
+				'</p>'
1479
+			);
1480
+		}
1481
+	}
1482
+
1483
+
1484
+	/**
1485
+	 * txn_registrant_side_meta_box
1486
+	 * generates HTML for the Edit Transaction side meta box
1487
+	 *
1488
+	 * @access public
1489
+	 * @return void
1490
+	 * @throws DomainException
1491
+	 * @throws EE_Error
1492
+	 * @throws InvalidArgumentException
1493
+	 * @throws InvalidDataTypeException
1494
+	 * @throws InvalidInterfaceException
1495
+	 * @throws ReflectionException
1496
+	 */
1497
+	public function txn_registrant_side_meta_box()
1498
+	{
1499
+		$primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1500
+			? $this->_transaction->primary_registration()->get_first_related('Attendee')
1501
+			: null;
1502
+		if (! $primary_att instanceof EE_Attendee) {
1503
+			$this->_template_args['no_attendee_message'] = esc_html__(
1504
+				'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1505
+				'event_espresso'
1506
+			);
1507
+			$primary_att = EEM_Attendee::instance()->create_default_object();
1508
+		}
1509
+		$this->_template_args['ATT_ID'] = $primary_att->ID();
1510
+		$this->_template_args['prime_reg_fname'] = $primary_att->fname();
1511
+		$this->_template_args['prime_reg_lname'] = $primary_att->lname();
1512
+		$this->_template_args['prime_reg_email'] = $primary_att->email();
1513
+		$this->_template_args['prime_reg_phone'] = $primary_att->phone();
1514
+		$this->_template_args['edit_attendee_url'] = EE_Admin_Page::add_query_args_and_nonce(
1515
+			array(
1516
+				'action' => 'edit_attendee',
1517
+				'post'   => $primary_att->ID(),
1518
+			),
1519
+			REG_ADMIN_URL
1520
+		);
1521
+		// get formatted address for registrant
1522
+		$this->_template_args['formatted_address'] = EEH_Address::format($primary_att);
1523
+		echo EEH_Template::display_template(
1524
+			TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1525
+			$this->_template_args,
1526
+			true
1527
+		);
1528
+	}
1529
+
1530
+
1531
+	/**
1532
+	 * txn_billing_info_side_meta_box
1533
+	 *    generates HTML for the Edit Transaction side meta box
1534
+	 *
1535
+	 * @access public
1536
+	 * @return void
1537
+	 * @throws DomainException
1538
+	 * @throws EE_Error
1539
+	 */
1540
+	public function txn_billing_info_side_meta_box()
1541
+	{
1542
+
1543
+		$this->_template_args['billing_form'] = $this->_transaction->billing_info();
1544
+		$this->_template_args['billing_form_url'] = add_query_arg(
1545
+			array('action' => 'edit_transaction', 'process' => 'billing'),
1546
+			TXN_ADMIN_URL
1547
+		);
1548
+
1549
+		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1550
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);/**/
1551
+	}
1552
+
1553
+
1554
+	/**
1555
+	 * apply_payments_or_refunds
1556
+	 *    registers a payment or refund made towards a transaction
1557
+	 *
1558
+	 * @access public
1559
+	 * @return void
1560
+	 * @throws EE_Error
1561
+	 * @throws InvalidArgumentException
1562
+	 * @throws ReflectionException
1563
+	 * @throws RuntimeException
1564
+	 * @throws InvalidDataTypeException
1565
+	 * @throws InvalidInterfaceException
1566
+	 */
1567
+	public function apply_payments_or_refunds()
1568
+	{
1569
+		$json_response_data = array('return_data' => false);
1570
+		$valid_data = $this->_validate_payment_request_data();
1571
+		$has_access = EE_Registry::instance()->CAP->current_user_can(
1572
+			'ee_edit_payments',
1573
+			'apply_payment_or_refund_from_registration_details'
1574
+		);
1575
+		if (! empty($valid_data) && $has_access) {
1576
+			$PAY_ID = $valid_data['PAY_ID'];
1577
+			// save  the new payment
1578
+			$payment = $this->_create_payment_from_request_data($valid_data);
1579
+			// get the TXN for this payment
1580
+			$transaction = $payment->transaction();
1581
+			// verify transaction
1582
+			if ($transaction instanceof EE_Transaction) {
1583
+				// calculate_total_payments_and_update_status
1584
+				$this->_process_transaction_payments($transaction);
1585
+				$REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1586
+				$this->_remove_existing_registration_payments($payment, $PAY_ID);
1587
+				// apply payment to registrations (if applicable)
1588
+				if (! empty($REG_IDs)) {
1589
+					$this->_update_registration_payments($transaction, $payment, $REG_IDs);
1590
+					$this->_maybe_send_notifications();
1591
+					// now process status changes for the same registrations
1592
+					$this->_process_registration_status_change($transaction, $REG_IDs);
1593
+				}
1594
+				$this->_maybe_send_notifications($payment);
1595
+				// prepare to render page
1596
+				$json_response_data['return_data'] = $this->_build_payment_json_response($payment, $REG_IDs);
1597
+				do_action(
1598
+					'AHEE__Transactions_Admin_Page__apply_payments_or_refund__after_recording',
1599
+					$transaction,
1600
+					$payment
1601
+				);
1602
+			} else {
1603
+				EE_Error::add_error(
1604
+					esc_html__(
1605
+						'A valid Transaction for this payment could not be retrieved.',
1606
+						'event_espresso'
1607
+					),
1608
+					__FILE__,
1609
+					__FUNCTION__,
1610
+					__LINE__
1611
+				);
1612
+			}
1613
+		} else {
1614
+			if ($has_access) {
1615
+				EE_Error::add_error(
1616
+					esc_html__(
1617
+						'The payment form data could not be processed. Please try again.',
1618
+						'event_espresso'
1619
+					),
1620
+					__FILE__,
1621
+					__FUNCTION__,
1622
+					__LINE__
1623
+				);
1624
+			} else {
1625
+				EE_Error::add_error(
1626
+					esc_html__(
1627
+						'You do not have access to apply payments or refunds to a registration.',
1628
+						'event_espresso'
1629
+					),
1630
+					__FILE__,
1631
+					__FUNCTION__,
1632
+					__LINE__
1633
+				);
1634
+			}
1635
+		}
1636
+		$notices = EE_Error::get_notices(
1637
+			false,
1638
+			false,
1639
+			false
1640
+		);
1641
+		$this->_template_args = array(
1642
+			'data'    => $json_response_data,
1643
+			'error'   => $notices['errors'],
1644
+			'success' => $notices['success'],
1645
+		);
1646
+		$this->_return_json();
1647
+	}
1648
+
1649
+
1650
+	/**
1651
+	 * _validate_payment_request_data
1652
+	 *
1653
+	 * @return array
1654
+	 * @throws EE_Error
1655
+	 */
1656
+	protected function _validate_payment_request_data()
1657
+	{
1658
+		if (! isset($this->_req_data['txn_admin_payment'])) {
1659
+			return false;
1660
+		}
1661
+		$payment_form = $this->_generate_payment_form_section();
1662
+		try {
1663
+			if ($payment_form->was_submitted()) {
1664
+				$payment_form->receive_form_submission();
1665
+				if (! $payment_form->is_valid()) {
1666
+					$submission_error_messages = array();
1667
+					foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1668
+						if ($validation_error instanceof EE_Validation_Error) {
1669
+							$submission_error_messages[] = sprintf(
1670
+								_x('%s : %s', 'Form Section Name : Form Validation Error', 'event_espresso'),
1671
+								$validation_error->get_form_section()->html_label_text(),
1672
+								$validation_error->getMessage()
1673
+							);
1674
+						}
1675
+					}
1676
+					EE_Error::add_error(
1677
+						implode('<br />', $submission_error_messages),
1678
+						__FILE__,
1679
+						__FUNCTION__,
1680
+						__LINE__
1681
+					);
1682
+
1683
+					return array();
1684
+				}
1685
+			}
1686
+		} catch (EE_Error $e) {
1687
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1688
+
1689
+			return array();
1690
+		}
1691
+
1692
+		return $payment_form->valid_data();
1693
+	}
1694
+
1695
+
1696
+	/**
1697
+	 * _generate_payment_form_section
1698
+	 *
1699
+	 * @return EE_Form_Section_Proper
1700
+	 * @throws EE_Error
1701
+	 */
1702
+	protected function _generate_payment_form_section()
1703
+	{
1704
+		return new EE_Form_Section_Proper(
1705
+			array(
1706
+				'name'        => 'txn_admin_payment',
1707
+				'subsections' => array(
1708
+					'PAY_ID'          => new EE_Text_Input(
1709
+						array(
1710
+							'default'               => 0,
1711
+							'required'              => false,
1712
+							'html_label_text'       => esc_html__('Payment ID', 'event_espresso'),
1713
+							'validation_strategies' => array(new EE_Int_Normalization()),
1714
+						)
1715
+					),
1716
+					'TXN_ID'          => new EE_Text_Input(
1717
+						array(
1718
+							'default'               => 0,
1719
+							'required'              => true,
1720
+							'html_label_text'       => esc_html__('Transaction ID', 'event_espresso'),
1721
+							'validation_strategies' => array(new EE_Int_Normalization()),
1722
+						)
1723
+					),
1724
+					'type'            => new EE_Text_Input(
1725
+						array(
1726
+							'default'               => 1,
1727
+							'required'              => true,
1728
+							'html_label_text'       => esc_html__('Payment or Refund', 'event_espresso'),
1729
+							'validation_strategies' => array(new EE_Int_Normalization()),
1730
+						)
1731
+					),
1732
+					'amount'          => new EE_Text_Input(
1733
+						array(
1734
+							'default'               => 0,
1735
+							'required'              => true,
1736
+							'html_label_text'       => esc_html__('Payment amount', 'event_espresso'),
1737
+							'validation_strategies' => array(new EE_Float_Normalization()),
1738
+						)
1739
+					),
1740
+					'status'          => new EE_Text_Input(
1741
+						array(
1742
+							'default'         => EEM_Payment::status_id_approved,
1743
+							'required'        => true,
1744
+							'html_label_text' => esc_html__('Payment status', 'event_espresso'),
1745
+						)
1746
+					),
1747
+					'PMD_ID'          => new EE_Text_Input(
1748
+						array(
1749
+							'default'               => 2,
1750
+							'required'              => true,
1751
+							'html_label_text'       => esc_html__('Payment Method', 'event_espresso'),
1752
+							'validation_strategies' => array(new EE_Int_Normalization()),
1753
+						)
1754
+					),
1755
+					'date'            => new EE_Text_Input(
1756
+						array(
1757
+							'default'         => time(),
1758
+							'required'        => true,
1759
+							'html_label_text' => esc_html__('Payment date', 'event_espresso'),
1760
+						)
1761
+					),
1762
+					'txn_id_chq_nmbr' => new EE_Text_Input(
1763
+						array(
1764
+							'default'               => '',
1765
+							'required'              => false,
1766
+							'html_label_text'       => esc_html__('Transaction or Cheque Number', 'event_espresso'),
1767
+							'validation_strategies' => array(
1768
+								new EE_Max_Length_Validation_Strategy(
1769
+									esc_html__('Input too long', 'event_espresso'),
1770
+									100
1771
+								),
1772
+							),
1773
+						)
1774
+					),
1775
+					'po_number'       => new EE_Text_Input(
1776
+						array(
1777
+							'default'               => '',
1778
+							'required'              => false,
1779
+							'html_label_text'       => esc_html__('Purchase Order Number', 'event_espresso'),
1780
+							'validation_strategies' => array(
1781
+								new EE_Max_Length_Validation_Strategy(
1782
+									esc_html__('Input too long', 'event_espresso'),
1783
+									100
1784
+								),
1785
+							),
1786
+						)
1787
+					),
1788
+					'accounting'      => new EE_Text_Input(
1789
+						array(
1790
+							'default'               => '',
1791
+							'required'              => false,
1792
+							'html_label_text'       => esc_html__('Extra Field for Accounting', 'event_espresso'),
1793
+							'validation_strategies' => array(
1794
+								new EE_Max_Length_Validation_Strategy(
1795
+									esc_html__('Input too long', 'event_espresso'),
1796
+									100
1797
+								),
1798
+							),
1799
+						)
1800
+					),
1801
+				),
1802
+			)
1803
+		);
1804
+	}
1805
+
1806
+
1807
+	/**
1808
+	 * _create_payment_from_request_data
1809
+	 *
1810
+	 * @param array $valid_data
1811
+	 * @return EE_Payment
1812
+	 * @throws EE_Error
1813
+	 */
1814
+	protected function _create_payment_from_request_data($valid_data)
1815
+	{
1816
+		$PAY_ID = $valid_data['PAY_ID'];
1817
+		// get payment amount
1818
+		$amount = $valid_data['amount'] ? abs($valid_data['amount']) : 0;
1819
+		// payments have a type value of 1 and refunds have a type value of -1
1820
+		// so multiplying amount by type will give a positive value for payments, and negative values for refunds
1821
+		$amount = $valid_data['type'] < 0 ? $amount * -1 : $amount;
1822
+		// for some reason the date string coming in has extra spaces between the date and time.  This fixes that.
1823
+		$date = $valid_data['date']
1824
+			? preg_replace('/\s+/', ' ', $valid_data['date'])
1825
+			: date('Y-m-d g:i a', current_time('timestamp'));
1826
+		$payment = EE_Payment::new_instance(
1827
+			array(
1828
+				'TXN_ID'              => $valid_data['TXN_ID'],
1829
+				'STS_ID'              => $valid_data['status'],
1830
+				'PAY_timestamp'       => $date,
1831
+				'PAY_source'          => EEM_Payment_Method::scope_admin,
1832
+				'PMD_ID'              => $valid_data['PMD_ID'],
1833
+				'PAY_amount'          => $amount,
1834
+				'PAY_txn_id_chq_nmbr' => $valid_data['txn_id_chq_nmbr'],
1835
+				'PAY_po_number'       => $valid_data['po_number'],
1836
+				'PAY_extra_accntng'   => $valid_data['accounting'],
1837
+				'PAY_details'         => $valid_data,
1838
+				'PAY_ID'              => $PAY_ID,
1839
+			),
1840
+			'',
1841
+			array('Y-m-d', 'g:i a')
1842
+		);
1843
+
1844
+		if (! $payment->save()) {
1845
+			EE_Error::add_error(
1846
+				sprintf(
1847
+					esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
1848
+					$payment->ID()
1849
+				),
1850
+				__FILE__,
1851
+				__FUNCTION__,
1852
+				__LINE__
1853
+			);
1854
+		}
1855
+
1856
+		return $payment;
1857
+	}
1858
+
1859
+
1860
+	/**
1861
+	 * _process_transaction_payments
1862
+	 *
1863
+	 * @param \EE_Transaction $transaction
1864
+	 * @return void
1865
+	 * @throws EE_Error
1866
+	 * @throws InvalidArgumentException
1867
+	 * @throws ReflectionException
1868
+	 * @throws InvalidDataTypeException
1869
+	 * @throws InvalidInterfaceException
1870
+	 */
1871
+	protected function _process_transaction_payments(EE_Transaction $transaction)
1872
+	{
1873
+		/** @type EE_Transaction_Payments $transaction_payments */
1874
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1875
+		// update the transaction with this payment
1876
+		if ($transaction_payments->calculate_total_payments_and_update_status($transaction)) {
1877
+			EE_Error::add_success(
1878
+				esc_html__(
1879
+					'The payment has been processed successfully.',
1880
+					'event_espresso'
1881
+				),
1882
+				__FILE__,
1883
+				__FUNCTION__,
1884
+				__LINE__
1885
+			);
1886
+		} else {
1887
+			EE_Error::add_error(
1888
+				esc_html__(
1889
+					'The payment was processed successfully but the amount paid for the transaction was not updated.',
1890
+					'event_espresso'
1891
+				),
1892
+				__FILE__,
1893
+				__FUNCTION__,
1894
+				__LINE__
1895
+			);
1896
+		}
1897
+	}
1898
+
1899
+
1900
+	/**
1901
+	 * _get_REG_IDs_to_apply_payment_to
1902
+	 * returns a list of registration IDs that the payment will apply to
1903
+	 *
1904
+	 * @param \EE_Payment $payment
1905
+	 * @return array
1906
+	 * @throws EE_Error
1907
+	 */
1908
+	protected function _get_REG_IDs_to_apply_payment_to(EE_Payment $payment)
1909
+	{
1910
+		$REG_IDs = array();
1911
+		// grab array of IDs for specific registrations to apply changes to
1912
+		if (isset($this->_req_data['txn_admin_payment']['registrations'])) {
1913
+			$REG_IDs = (array) $this->_req_data['txn_admin_payment']['registrations'];
1914
+		}
1915
+		// nothing specified ? then get all reg IDs
1916
+		if (empty($REG_IDs)) {
1917
+			$registrations = $payment->transaction()->registrations();
1918
+			$REG_IDs = ! empty($registrations)
1919
+				? array_keys($registrations)
1920
+				: $this->_get_existing_reg_payment_REG_IDs($payment);
1921
+		}
1922
+
1923
+		// ensure that REG_IDs are integers and NOT strings
1924
+		return array_map('intval', $REG_IDs);
1925
+	}
1926
+
1927
+
1928
+	/**
1929
+	 * @return array
1930
+	 */
1931
+	public function existing_reg_payment_REG_IDs()
1932
+	{
1933
+		return $this->_existing_reg_payment_REG_IDs;
1934
+	}
1935
+
1936
+
1937
+	/**
1938
+	 * @param array $existing_reg_payment_REG_IDs
1939
+	 */
1940
+	public function set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs = null)
1941
+	{
1942
+		$this->_existing_reg_payment_REG_IDs = $existing_reg_payment_REG_IDs;
1943
+	}
1944
+
1945
+
1946
+	/**
1947
+	 * _get_existing_reg_payment_REG_IDs
1948
+	 * returns a list of registration IDs that the payment is currently related to
1949
+	 * as recorded in the database
1950
+	 *
1951
+	 * @param \EE_Payment $payment
1952
+	 * @return array
1953
+	 * @throws EE_Error
1954
+	 */
1955
+	protected function _get_existing_reg_payment_REG_IDs(EE_Payment $payment)
1956
+	{
1957
+		if ($this->existing_reg_payment_REG_IDs() === null) {
1958
+			// let's get any existing reg payment records for this payment
1959
+			$existing_reg_payment_REG_IDs = $payment->get_many_related('Registration');
1960
+			// but we only want the REG IDs, so grab the array keys
1961
+			$existing_reg_payment_REG_IDs = ! empty($existing_reg_payment_REG_IDs)
1962
+				? array_keys($existing_reg_payment_REG_IDs)
1963
+				: array();
1964
+			$this->set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs);
1965
+		}
1966
+
1967
+		return $this->existing_reg_payment_REG_IDs();
1968
+	}
1969
+
1970
+
1971
+	/**
1972
+	 * _remove_existing_registration_payments
1973
+	 * this calculates the difference between existing relations
1974
+	 * to the supplied payment and the new list registration IDs,
1975
+	 * removes any related registrations that no longer apply,
1976
+	 * and then updates the registration paid fields
1977
+	 *
1978
+	 * @param \EE_Payment $payment
1979
+	 * @param int         $PAY_ID
1980
+	 * @return bool;
1981
+	 * @throws EE_Error
1982
+	 * @throws InvalidArgumentException
1983
+	 * @throws ReflectionException
1984
+	 * @throws InvalidDataTypeException
1985
+	 * @throws InvalidInterfaceException
1986
+	 */
1987
+	protected function _remove_existing_registration_payments(EE_Payment $payment, $PAY_ID = 0)
1988
+	{
1989
+		// newly created payments will have nothing recorded for $PAY_ID
1990
+		if ($PAY_ID == 0) {
1991
+			return false;
1992
+		}
1993
+		$existing_reg_payment_REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
1994
+		if (empty($existing_reg_payment_REG_IDs)) {
1995
+			return false;
1996
+		}
1997
+		/** @type EE_Transaction_Payments $transaction_payments */
1998
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1999
+
2000
+		return $transaction_payments->delete_registration_payments_and_update_registrations(
2001
+			$payment,
2002
+			array(
2003
+				array(
2004
+					'PAY_ID' => $payment->ID(),
2005
+					'REG_ID' => array('IN', $existing_reg_payment_REG_IDs),
2006
+				),
2007
+			)
2008
+		);
2009
+	}
2010
+
2011
+
2012
+	/**
2013
+	 * _update_registration_payments
2014
+	 * this applies the payments to the selected registrations
2015
+	 * but only if they have not already been paid for
2016
+	 *
2017
+	 * @param  EE_Transaction $transaction
2018
+	 * @param \EE_Payment     $payment
2019
+	 * @param array           $REG_IDs
2020
+	 * @return void
2021
+	 * @throws EE_Error
2022
+	 * @throws InvalidArgumentException
2023
+	 * @throws ReflectionException
2024
+	 * @throws RuntimeException
2025
+	 * @throws InvalidDataTypeException
2026
+	 * @throws InvalidInterfaceException
2027
+	 */
2028
+	protected function _update_registration_payments(
2029
+		EE_Transaction $transaction,
2030
+		EE_Payment $payment,
2031
+		$REG_IDs = array()
2032
+	) {
2033
+		// we can pass our own custom set of registrations to EE_Payment_Processor::process_registration_payments()
2034
+		// so let's do that using our set of REG_IDs from the form
2035
+		$registration_query_where_params = array(
2036
+			'REG_ID' => array('IN', $REG_IDs),
2037
+		);
2038
+		// but add in some conditions regarding payment,
2039
+		// so that we don't apply payments to registrations that are free or have already been paid for
2040
+		// but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2041
+		if (! $payment->is_a_refund()) {
2042
+			$registration_query_where_params['REG_final_price'] = array('!=', 0);
2043
+			$registration_query_where_params['REG_final_price*'] = array('!=', 'REG_paid', true);
2044
+		}
2045
+		$registrations = $transaction->registrations(array($registration_query_where_params));
2046
+		if (! empty($registrations)) {
2047
+			/** @type EE_Payment_Processor $payment_processor */
2048
+			$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2049
+			$payment_processor->process_registration_payments($transaction, $payment, $registrations);
2050
+		}
2051
+	}
2052
+
2053
+
2054
+	/**
2055
+	 * _process_registration_status_change
2056
+	 * This processes requested registration status changes for all the registrations
2057
+	 * on a given transaction and (optionally) sends out notifications for the changes.
2058
+	 *
2059
+	 * @param  EE_Transaction $transaction
2060
+	 * @param array           $REG_IDs
2061
+	 * @return bool
2062
+	 * @throws EE_Error
2063
+	 * @throws InvalidArgumentException
2064
+	 * @throws ReflectionException
2065
+	 * @throws InvalidDataTypeException
2066
+	 * @throws InvalidInterfaceException
2067
+	 */
2068
+	protected function _process_registration_status_change(EE_Transaction $transaction, $REG_IDs = array())
2069
+	{
2070
+		// first if there is no change in status then we get out.
2071
+		if (! isset($this->_req_data['txn_reg_status_change']['reg_status'])
2072
+			|| $this->_req_data['txn_reg_status_change']['reg_status'] === 'NAN'
2073
+		) {
2074
+			// no error message, no change requested, just nothing to do man.
2075
+			return false;
2076
+		}
2077
+		/** @type EE_Transaction_Processor $transaction_processor */
2078
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
2079
+
2080
+		// made it here dude?  Oh WOW.  K, let's take care of changing the statuses
2081
+		return $transaction_processor->manually_update_registration_statuses(
2082
+			$transaction,
2083
+			sanitize_text_field($this->_req_data['txn_reg_status_change']['reg_status']),
2084
+			array(array('REG_ID' => array('IN', $REG_IDs)))
2085
+		);
2086
+	}
2087
+
2088
+
2089
+	/**
2090
+	 * _build_payment_json_response
2091
+	 *
2092
+	 * @access public
2093
+	 * @param \EE_Payment $payment
2094
+	 * @param array       $REG_IDs
2095
+	 * @param bool | null $delete_txn_reg_status_change
2096
+	 * @return array
2097
+	 * @throws EE_Error
2098
+	 * @throws InvalidArgumentException
2099
+	 * @throws InvalidDataTypeException
2100
+	 * @throws InvalidInterfaceException
2101
+	 * @throws ReflectionException
2102
+	 */
2103
+	protected function _build_payment_json_response(
2104
+		EE_Payment $payment,
2105
+		$REG_IDs = array(),
2106
+		$delete_txn_reg_status_change = null
2107
+	) {
2108
+		// was the payment deleted ?
2109
+		if (is_bool($delete_txn_reg_status_change)) {
2110
+			return array(
2111
+				'PAY_ID'                       => $payment->ID(),
2112
+				'amount'                       => $payment->amount(),
2113
+				'total_paid'                   => $payment->transaction()->paid(),
2114
+				'txn_status'                   => $payment->transaction()->status_ID(),
2115
+				'pay_status'                   => $payment->STS_ID(),
2116
+				'registrations'                => $this->_registration_payment_data_array($REG_IDs),
2117
+				'delete_txn_reg_status_change' => $delete_txn_reg_status_change,
2118
+			);
2119
+		} else {
2120
+			$this->_get_payment_status_array();
2121
+
2122
+			return array(
2123
+				'amount'           => $payment->amount(),
2124
+				'total_paid'       => $payment->transaction()->paid(),
2125
+				'txn_status'       => $payment->transaction()->status_ID(),
2126
+				'pay_status'       => $payment->STS_ID(),
2127
+				'PAY_ID'           => $payment->ID(),
2128
+				'STS_ID'           => $payment->STS_ID(),
2129
+				'status'           => self::$_pay_status[ $payment->STS_ID() ],
2130
+				'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
2131
+				'method'           => strtoupper($payment->source()),
2132
+				'PM_ID'            => $payment->payment_method() ? $payment->payment_method()->ID() : 1,
2133
+				'gateway'          => $payment->payment_method()
2134
+					? $payment->payment_method()->admin_name()
2135
+					: esc_html__("Unknown", 'event_espresso'),
2136
+				'gateway_response' => $payment->gateway_response(),
2137
+				'txn_id_chq_nmbr'  => $payment->txn_id_chq_nmbr(),
2138
+				'po_number'        => $payment->po_number(),
2139
+				'extra_accntng'    => $payment->extra_accntng(),
2140
+				'registrations'    => $this->_registration_payment_data_array($REG_IDs),
2141
+			);
2142
+		}
2143
+	}
2144
+
2145
+
2146
+	/**
2147
+	 * delete_payment
2148
+	 *    delete a payment or refund made towards a transaction
2149
+	 *
2150
+	 * @access public
2151
+	 * @return void
2152
+	 * @throws EE_Error
2153
+	 * @throws InvalidArgumentException
2154
+	 * @throws ReflectionException
2155
+	 * @throws InvalidDataTypeException
2156
+	 * @throws InvalidInterfaceException
2157
+	 */
2158
+	public function delete_payment()
2159
+	{
2160
+		$json_response_data = array('return_data' => false);
2161
+		$PAY_ID = isset($this->_req_data['delete_txn_admin_payment']['PAY_ID'])
2162
+			? absint($this->_req_data['delete_txn_admin_payment']['PAY_ID'])
2163
+			: 0;
2164
+		$can_delete = EE_Registry::instance()->CAP->current_user_can(
2165
+			'ee_delete_payments',
2166
+			'delete_payment_from_registration_details'
2167
+		);
2168
+		if ($PAY_ID && $can_delete) {
2169
+			$delete_txn_reg_status_change = isset($this->_req_data['delete_txn_reg_status_change'])
2170
+				? $this->_req_data['delete_txn_reg_status_change']
2171
+				: false;
2172
+			$payment = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
2173
+			if ($payment instanceof EE_Payment) {
2174
+				$REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2175
+				/** @type EE_Transaction_Payments $transaction_payments */
2176
+				$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2177
+				if ($transaction_payments->delete_payment_and_update_transaction($payment)) {
2178
+					$json_response_data['return_data'] = $this->_build_payment_json_response(
2179
+						$payment,
2180
+						$REG_IDs,
2181
+						$delete_txn_reg_status_change
2182
+					);
2183
+					if ($delete_txn_reg_status_change) {
2184
+						$this->_req_data['txn_reg_status_change'] = $delete_txn_reg_status_change;
2185
+						// MAKE sure we also add the delete_txn_req_status_change to the
2186
+						// $_REQUEST global because that's how messages will be looking for it.
2187
+						$_REQUEST['txn_reg_status_change'] = $delete_txn_reg_status_change;
2188
+						$this->_maybe_send_notifications();
2189
+						$this->_process_registration_status_change($payment->transaction(), $REG_IDs);
2190
+					}
2191
+				}
2192
+			} else {
2193
+				EE_Error::add_error(
2194
+					esc_html__('Valid Payment data could not be retrieved from the database.', 'event_espresso'),
2195
+					__FILE__,
2196
+					__FUNCTION__,
2197
+					__LINE__
2198
+				);
2199
+			}
2200
+		} else {
2201
+			if ($can_delete) {
2202
+				EE_Error::add_error(
2203
+					esc_html__(
2204
+						'A valid Payment ID was not received, therefore payment form data could not be loaded.',
2205
+						'event_espresso'
2206
+					),
2207
+					__FILE__,
2208
+					__FUNCTION__,
2209
+					__LINE__
2210
+				);
2211
+			} else {
2212
+				EE_Error::add_error(
2213
+					esc_html__(
2214
+						'You do not have access to delete a payment.',
2215
+						'event_espresso'
2216
+					),
2217
+					__FILE__,
2218
+					__FUNCTION__,
2219
+					__LINE__
2220
+				);
2221
+			}
2222
+		}
2223
+		$notices = EE_Error::get_notices(false, false, false);
2224
+		$this->_template_args = array(
2225
+			'data'      => $json_response_data,
2226
+			'success'   => $notices['success'],
2227
+			'error'     => $notices['errors'],
2228
+			'attention' => $notices['attention'],
2229
+		);
2230
+		$this->_return_json();
2231
+	}
2232
+
2233
+
2234
+	/**
2235
+	 * _registration_payment_data_array
2236
+	 * adds info for 'owing' and 'paid' for each registration to the json response
2237
+	 *
2238
+	 * @access protected
2239
+	 * @param array $REG_IDs
2240
+	 * @return array
2241
+	 * @throws EE_Error
2242
+	 * @throws InvalidArgumentException
2243
+	 * @throws InvalidDataTypeException
2244
+	 * @throws InvalidInterfaceException
2245
+	 * @throws ReflectionException
2246
+	 */
2247
+	protected function _registration_payment_data_array($REG_IDs)
2248
+	{
2249
+		$registration_payment_data = array();
2250
+		// if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2251
+		if (! empty($REG_IDs)) {
2252
+			$registrations = EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $REG_IDs))));
2253
+			foreach ($registrations as $registration) {
2254
+				if ($registration instanceof EE_Registration) {
2255
+					$registration_payment_data[ $registration->ID() ] = array(
2256
+						'paid'  => $registration->pretty_paid(),
2257
+						'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
2258
+					);
2259
+				}
2260
+			}
2261
+		}
2262
+
2263
+		return $registration_payment_data;
2264
+	}
2265
+
2266
+
2267
+	/**
2268
+	 * _maybe_send_notifications
2269
+	 * determines whether or not the admin has indicated that notifications should be sent.
2270
+	 * If so, will toggle a filter switch for delivering registration notices.
2271
+	 * If passed an EE_Payment object, then it will trigger payment notifications instead.
2272
+	 *
2273
+	 * @access protected
2274
+	 * @param \EE_Payment | null $payment
2275
+	 */
2276
+	protected function _maybe_send_notifications($payment = null)
2277
+	{
2278
+		switch ($payment instanceof EE_Payment) {
2279
+			// payment notifications
2280
+			case true:
2281
+				if (isset(
2282
+					$this->_req_data['txn_payments'],
2283
+					$this->_req_data['txn_payments']['send_notifications']
2284
+				)
2285
+					&& filter_var($this->_req_data['txn_payments']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
2286
+				) {
2287
+					$this->_process_payment_notification($payment);
2288
+				}
2289
+				break;
2290
+			// registration notifications
2291
+			case false:
2292
+				if (isset(
2293
+					$this->_req_data['txn_reg_status_change'],
2294
+					$this->_req_data['txn_reg_status_change']['send_notifications']
2295
+				)
2296
+					&& filter_var($this->_req_data['txn_reg_status_change']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
2297
+				) {
2298
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
2299
+				}
2300
+				break;
2301
+		}
2302
+	}
2303
+
2304
+
2305
+	/**
2306
+	 * _send_payment_reminder
2307
+	 *    generates HTML for the View Transaction Details Admin page
2308
+	 *
2309
+	 * @access protected
2310
+	 * @return void
2311
+	 * @throws EE_Error
2312
+	 * @throws InvalidArgumentException
2313
+	 * @throws InvalidDataTypeException
2314
+	 * @throws InvalidInterfaceException
2315
+	 */
2316
+	protected function _send_payment_reminder()
2317
+	{
2318
+		$TXN_ID = ! empty($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : false;
2319
+		$transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2320
+		$query_args = isset($this->_req_data['redirect_to']) ? array(
2321
+			'action' => $this->_req_data['redirect_to'],
2322
+			'TXN_ID' => $this->_req_data['TXN_ID'],
2323
+		) : array();
2324
+		do_action(
2325
+			'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
2326
+			$transaction
2327
+		);
2328
+		$this->_redirect_after_action(
2329
+			false,
2330
+			esc_html__('payment reminder', 'event_espresso'),
2331
+			esc_html__('sent', 'event_espresso'),
2332
+			$query_args,
2333
+			true
2334
+		);
2335
+	}
2336
+
2337
+
2338
+	/**
2339
+	 *  get_transactions
2340
+	 *    get transactions for given parameters (used by list table)
2341
+	 *
2342
+	 * @param  int     $perpage how many transactions displayed per page
2343
+	 * @param  boolean $count   return the count or objects
2344
+	 * @param string   $view
2345
+	 * @return mixed int = count || array of transaction objects
2346
+	 * @throws EE_Error
2347
+	 * @throws InvalidArgumentException
2348
+	 * @throws InvalidDataTypeException
2349
+	 * @throws InvalidInterfaceException
2350
+	 */
2351
+	public function get_transactions($perpage, $count = false, $view = '')
2352
+	{
2353
+
2354
+		$TXN = EEM_Transaction::instance();
2355
+
2356
+		$start_date = isset($this->_req_data['txn-filter-start-date'])
2357
+			? wp_strip_all_tags($this->_req_data['txn-filter-start-date'])
2358
+			: date(
2359
+				'm/d/Y',
2360
+				strtotime('-10 year')
2361
+			);
2362
+		$end_date = isset($this->_req_data['txn-filter-end-date'])
2363
+			? wp_strip_all_tags($this->_req_data['txn-filter-end-date'])
2364
+			: date('m/d/Y');
2365
+
2366
+		// make sure our timestamps start and end right at the boundaries for each day
2367
+		$start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2368
+		$end_date = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2369
+
2370
+
2371
+		// convert to timestamps
2372
+		$start_date = strtotime($start_date);
2373
+		$end_date = strtotime($end_date);
2374
+
2375
+		// makes sure start date is the lowest value and vice versa
2376
+		$start_date = min($start_date, $end_date);
2377
+		$end_date = max($start_date, $end_date);
2378
+
2379
+		// convert to correct format for query
2380
+		$start_date = EEM_Transaction::instance()->convert_datetime_for_query(
2381
+			'TXN_timestamp',
2382
+			date('Y-m-d H:i:s', $start_date),
2383
+			'Y-m-d H:i:s'
2384
+		);
2385
+		$end_date = EEM_Transaction::instance()->convert_datetime_for_query(
2386
+			'TXN_timestamp',
2387
+			date('Y-m-d H:i:s', $end_date),
2388
+			'Y-m-d H:i:s'
2389
+		);
2390
+
2391
+
2392
+		// set orderby
2393
+		$this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
2394
+
2395
+		switch ($this->_req_data['orderby']) {
2396
+			case 'TXN_ID':
2397
+				$orderby = 'TXN_ID';
2398
+				break;
2399
+			case 'ATT_fname':
2400
+				$orderby = 'Registration.Attendee.ATT_fname';
2401
+				break;
2402
+			case 'event_name':
2403
+				$orderby = 'Registration.Event.EVT_name';
2404
+				break;
2405
+			default: // 'TXN_timestamp'
2406
+				$orderby = 'TXN_timestamp';
2407
+		}
2408
+
2409
+		$sort = ! empty($this->_req_data['order']) ? $this->_req_data['order'] : 'DESC';
2410
+		$current_page = ! empty($this->_req_data['paged']) ? $this->_req_data['paged'] : 1;
2411
+		$per_page = ! empty($perpage) ? $perpage : 10;
2412
+		$per_page = ! empty($this->_req_data['perpage']) ? $this->_req_data['perpage'] : $per_page;
2413
+
2414
+		$offset = ($current_page - 1) * $per_page;
2415
+		$limit = array($offset, $per_page);
2416
+
2417
+		$_where = array(
2418
+			'TXN_timestamp'          => array('BETWEEN', array($start_date, $end_date)),
2419
+			'Registration.REG_count' => 1,
2420
+		);
2421
+
2422
+		if (isset($this->_req_data['EVT_ID'])) {
2423
+			$_where['Registration.EVT_ID'] = $this->_req_data['EVT_ID'];
2424
+		}
2425
+
2426
+		if (isset($this->_req_data['s'])) {
2427
+			$search_string = '%' . $this->_req_data['s'] . '%';
2428
+			$_where['OR'] = array(
2429
+				'Registration.Event.EVT_name'         => array('LIKE', $search_string),
2430
+				'Registration.Event.EVT_desc'         => array('LIKE', $search_string),
2431
+				'Registration.Event.EVT_short_desc'   => array('LIKE', $search_string),
2432
+				'Registration.Attendee.ATT_full_name' => array('LIKE', $search_string),
2433
+				'Registration.Attendee.ATT_fname'     => array('LIKE', $search_string),
2434
+				'Registration.Attendee.ATT_lname'     => array('LIKE', $search_string),
2435
+				'Registration.Attendee.ATT_short_bio' => array('LIKE', $search_string),
2436
+				'Registration.Attendee.ATT_email'     => array('LIKE', $search_string),
2437
+				'Registration.Attendee.ATT_address'   => array('LIKE', $search_string),
2438
+				'Registration.Attendee.ATT_address2'  => array('LIKE', $search_string),
2439
+				'Registration.Attendee.ATT_city'      => array('LIKE', $search_string),
2440
+				'Registration.REG_final_price'        => array('LIKE', $search_string),
2441
+				'Registration.REG_code'               => array('LIKE', $search_string),
2442
+				'Registration.REG_count'              => array('LIKE', $search_string),
2443
+				'Registration.REG_group_size'         => array('LIKE', $search_string),
2444
+				'Registration.Ticket.TKT_name'        => array('LIKE', $search_string),
2445
+				'Registration.Ticket.TKT_description' => array('LIKE', $search_string),
2446
+				'Payment.PAY_source'                  => array('LIKE', $search_string),
2447
+				'Payment.Payment_Method.PMD_name'     => array('LIKE', $search_string),
2448
+				'TXN_session_data'                    => array('LIKE', $search_string),
2449
+				'Payment.PAY_txn_id_chq_nmbr'         => array('LIKE', $search_string),
2450
+			);
2451
+		}
2452
+
2453
+		// failed transactions
2454
+		$failed = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'failed' && ! $count)
2455
+				  || ($count && $view === 'failed');
2456
+		$abandoned = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'abandoned' && ! $count)
2457
+					 || ($count && $view === 'abandoned');
2458
+
2459
+		if ($failed) {
2460
+			$_where['STS_ID'] = EEM_Transaction::failed_status_code;
2461
+		} elseif ($abandoned) {
2462
+			$_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
2463
+		} else {
2464
+			$_where['STS_ID'] = array('!=', EEM_Transaction::failed_status_code);
2465
+			$_where['STS_ID*'] = array('!=', EEM_Transaction::abandoned_status_code);
2466
+		}
2467
+
2468
+		$query_params = array(
2469
+			$_where,
2470
+			'order_by'                 => array($orderby => $sort),
2471
+			'limit'                    => $limit,
2472
+			'default_where_conditions' => EEM_Base::default_where_conditions_this_only,
2473
+		);
2474
+
2475
+		$transactions = $count
2476
+			? $TXN->count(array($_where), 'TXN_ID', true)
2477
+			: $TXN->get_all($query_params);
2478
+
2479
+		return $transactions;
2480
+	}
2481 2481
 }
Please login to merge, or discard this patch.
Spacing   +83 added lines, -83 removed lines patch added patch discarded remove patch
@@ -363,7 +363,7 @@  discard block
 block discarded – undo
363 363
         // enqueue style
364 364
         wp_register_style(
365 365
             'espresso_txn',
366
-            TXN_ASSETS_URL . 'espresso_transactions_admin.css',
366
+            TXN_ASSETS_URL.'espresso_transactions_admin.css',
367 367
             array(),
368 368
             EVENT_ESPRESSO_VERSION
369 369
         );
@@ -371,7 +371,7 @@  discard block
 block discarded – undo
371 371
         // scripts
372 372
         wp_register_script(
373 373
             'espresso_txn',
374
-            TXN_ASSETS_URL . 'espresso_transactions_admin.js',
374
+            TXN_ASSETS_URL.'espresso_transactions_admin.js',
375 375
             array(
376 376
                 'ee_admin_js',
377 377
                 'ee-datepicker',
@@ -474,7 +474,7 @@  discard block
 block discarded – undo
474 474
             $this->_transaction->verify_abandoned_transaction_status();
475 475
         }
476 476
 
477
-        if (! $this->_transaction instanceof EE_Transaction) {
477
+        if ( ! $this->_transaction instanceof EE_Transaction) {
478 478
             $error_msg = sprintf(
479 479
                 esc_html__(
480 480
                     'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
@@ -572,7 +572,7 @@  discard block
 block discarded – undo
572 572
             'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
573 573
             array(
574 574
                 'overpaid'   => array(
575
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::overpaid_status_code,
575
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::overpaid_status_code,
576 576
                     'desc'  => EEH_Template::pretty_status(
577 577
                         EEM_Transaction::overpaid_status_code,
578 578
                         false,
@@ -580,7 +580,7 @@  discard block
 block discarded – undo
580 580
                     ),
581 581
                 ),
582 582
                 'complete'   => array(
583
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::complete_status_code,
583
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::complete_status_code,
584 584
                     'desc'  => EEH_Template::pretty_status(
585 585
                         EEM_Transaction::complete_status_code,
586 586
                         false,
@@ -588,7 +588,7 @@  discard block
 block discarded – undo
588 588
                     ),
589 589
                 ),
590 590
                 'incomplete' => array(
591
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::incomplete_status_code,
591
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::incomplete_status_code,
592 592
                     'desc'  => EEH_Template::pretty_status(
593 593
                         EEM_Transaction::incomplete_status_code,
594 594
                         false,
@@ -596,7 +596,7 @@  discard block
 block discarded – undo
596 596
                     ),
597 597
                 ),
598 598
                 'abandoned'  => array(
599
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::abandoned_status_code,
599
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::abandoned_status_code,
600 600
                     'desc'  => EEH_Template::pretty_status(
601 601
                         EEM_Transaction::abandoned_status_code,
602 602
                         false,
@@ -604,7 +604,7 @@  discard block
 block discarded – undo
604 604
                     ),
605 605
                 ),
606 606
                 'failed'     => array(
607
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::failed_status_code,
607
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::failed_status_code,
608 608
                     'desc'  => EEH_Template::pretty_status(
609 609
                         EEM_Transaction::failed_status_code,
610 610
                         false,
@@ -653,7 +653,7 @@  discard block
 block discarded – undo
653 653
                     'Click to Edit event',
654 654
                     'event_espresso'
655 655
                 )
656
-                . '">' . $event->get('EVT_name') . '</a>',
656
+                . '">'.$event->get('EVT_name').'</a>',
657 657
                 '</h3>'
658 658
             )
659 659
             : '';
@@ -687,7 +687,7 @@  discard block
 block discarded – undo
687 687
 
688 688
         $this->_set_transaction_object();
689 689
 
690
-        if (! $this->_transaction instanceof EE_Transaction) {
690
+        if ( ! $this->_transaction instanceof EE_Transaction) {
691 691
             return;
692 692
         }
693 693
         $primary_registration = $this->_transaction->primary_registration();
@@ -701,9 +701,9 @@  discard block
 block discarded – undo
701 701
         $this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
702 702
         $this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
703 703
 
704
-        $this->_template_args['txn_status']['value'] = self::$_txn_status[ $this->_transaction->get('STS_ID') ];
704
+        $this->_template_args['txn_status']['value'] = self::$_txn_status[$this->_transaction->get('STS_ID')];
705 705
         $this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
706
-        $this->_template_args['txn_status']['class'] = 'status-' . $this->_transaction->get('STS_ID');
706
+        $this->_template_args['txn_status']['class'] = 'status-'.$this->_transaction->get('STS_ID');
707 707
 
708 708
         $this->_template_args['grand_total'] = $this->_transaction->get('TXN_total');
709 709
         $this->_template_args['total_paid'] = $this->_transaction->get('TXN_paid');
@@ -821,7 +821,7 @@  discard block
 block discarded – undo
821 821
         // grab messages at the last second
822 822
         $this->_template_args['notices'] = EE_Error::get_notices();
823 823
         // path to template
824
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
824
+        $template_path = TXN_TEMPLATE_PATH.'txn_admin_details_header.template.php';
825 825
         $this->_template_args['admin_page_header'] = EEH_Template::display_template(
826 826
             $template_path,
827 827
             $this->_template_args,
@@ -850,7 +850,7 @@  discard block
 block discarded – undo
850 850
 
851 851
         $this->_set_transaction_object();
852 852
 
853
-        if (! $this->_transaction instanceof EE_Transaction) {
853
+        if ( ! $this->_transaction instanceof EE_Transaction) {
854 854
             return;
855 855
         }
856 856
         add_meta_box(
@@ -905,7 +905,7 @@  discard block
 block discarded – undo
905 905
     {
906 906
         $content = '';
907 907
         $actions = array();
908
-        if (! $transaction instanceof EE_Transaction) {
908
+        if ( ! $transaction instanceof EE_Transaction) {
909 909
             return $content;
910 910
         }
911 911
         /** @var EE_Registration $primary_registration */
@@ -966,7 +966,7 @@  discard block
 block discarded – undo
966 966
         );
967 967
         if ($actions) {
968 968
             $content = '<ul>';
969
-            $content .= '<li>' . implode('</li><li>', $actions) . '</li>';
969
+            $content .= '<li>'.implode('</li><li>', $actions).'</li>';
970 970
             $content .= '</uL>';
971 971
         }
972 972
         return $content;
@@ -1031,7 +1031,7 @@  discard block
 block discarded – undo
1031 1031
 
1032 1032
         // process payment details
1033 1033
         $payments = $this->_transaction->get_many_related('Payment');
1034
-        if (! empty($payments)) {
1034
+        if ( ! empty($payments)) {
1035 1035
             $this->_template_args['payments'] = $payments;
1036 1036
             $this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1037 1037
         } else {
@@ -1092,7 +1092,7 @@  discard block
 block discarded – undo
1092 1092
                                   esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1093 1093
                                   ucwords(str_replace('_', ' ', $reg_step)),
1094 1094
                                   date(
1095
-                                      get_option('date_format') . ' ' . get_option('time_format'),
1095
+                                      get_option('date_format').' '.get_option('time_format'),
1096 1096
                                       ($reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS))
1097 1097
                                   )
1098 1098
                               )
@@ -1145,7 +1145,7 @@  discard block
 block discarded – undo
1145 1145
 
1146 1146
         // 'espresso_delete_payment_nonce'
1147 1147
 
1148
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1148
+        $template_path = TXN_TEMPLATE_PATH.'txn_admin_details_main_meta_box_txn_details.template.php';
1149 1149
         echo EEH_Template::display_template($template_path, $this->_template_args, true);
1150 1150
     }
1151 1151
 
@@ -1177,18 +1177,18 @@  discard block
 block discarded – undo
1177 1177
                 ),
1178 1178
             )
1179 1179
         );
1180
-        if (! empty($reg_payments)) {
1180
+        if ( ! empty($reg_payments)) {
1181 1181
             foreach ($payments as $payment) {
1182
-                if (! $payment instanceof EE_Payment) {
1182
+                if ( ! $payment instanceof EE_Payment) {
1183 1183
                     continue;
1184
-                } elseif (! isset($existing_reg_payments[ $payment->ID() ])) {
1185
-                    $existing_reg_payments[ $payment->ID() ] = array();
1184
+                } elseif ( ! isset($existing_reg_payments[$payment->ID()])) {
1185
+                    $existing_reg_payments[$payment->ID()] = array();
1186 1186
                 }
1187 1187
                 foreach ($reg_payments as $reg_payment) {
1188 1188
                     if ($reg_payment instanceof EE_Registration_Payment
1189 1189
                         && $reg_payment->payment_ID() === $payment->ID()
1190 1190
                     ) {
1191
-                        $existing_reg_payments[ $payment->ID() ][] = $reg_payment->registration_ID();
1191
+                        $existing_reg_payments[$payment->ID()][] = $reg_payment->registration_ID();
1192 1192
                     }
1193 1193
                 }
1194 1194
             }
@@ -1229,16 +1229,16 @@  discard block
 block discarded – undo
1229 1229
                                                  '',
1230 1230
                                                  'clear: both; margin: 1.5em 0 0; display: none;'
1231 1231
                                              );
1232
-        $registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1232
+        $registrations_to_apply_payment_to .= EEH_HTML::br().EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1233 1233
         $registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl');
1234 1234
         $registrations_to_apply_payment_to .= EEH_HTML::thead(
1235 1235
             EEH_HTML::tr(
1236
-                EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1237
-                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1238
-                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1239
-                EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1240
-                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1241
-                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1236
+                EEH_HTML::th(esc_html__('ID', 'event_espresso')).
1237
+                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')).
1238
+                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')).
1239
+                EEH_HTML::th(esc_html__('Event', 'event_espresso')).
1240
+                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr').
1241
+                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr').
1242 1242
                 EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1243 1243
             )
1244 1244
         );
@@ -1253,29 +1253,29 @@  discard block
 block discarded – undo
1253 1253
                     : esc_html__('Unknown Attendee', 'event_espresso');
1254 1254
                 $owing = $registration->final_price() - $registration->paid();
1255 1255
                 $taxable = $registration->ticket()->taxable()
1256
-                    ? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1256
+                    ? ' <span class="smaller-text lt-grey-text"> '.esc_html__('+ tax', 'event_espresso').'</span>'
1257 1257
                     : '';
1258 1258
                 $checked = empty($existing_reg_payments) || in_array($registration->ID(), $existing_reg_payments)
1259 1259
                     ? ' checked="checked"'
1260 1260
                     : '';
1261 1261
                 $disabled = $registration->final_price() > 0 ? '' : ' disabled';
1262 1262
                 $registrations_to_apply_payment_to .= EEH_HTML::tr(
1263
-                    EEH_HTML::td($registration->ID()) .
1264
-                    EEH_HTML::td($attendee_name) .
1263
+                    EEH_HTML::td($registration->ID()).
1264
+                    EEH_HTML::td($attendee_name).
1265 1265
                     EEH_HTML::td(
1266
-                        $registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1267
-                    ) .
1268
-                    EEH_HTML::td($registration->event_name()) .
1269
-                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1270
-                    EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr') .
1266
+                        $registration->ticket()->name().' : '.$registration->ticket()->pretty_price().$taxable
1267
+                    ).
1268
+                    EEH_HTML::td($registration->event_name()).
1269
+                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr').
1270
+                    EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr').
1271 1271
                     EEH_HTML::td(
1272
-                        '<input type="checkbox" value="' . $registration->ID()
1272
+                        '<input type="checkbox" value="'.$registration->ID()
1273 1273
                         . '" name="txn_admin_payment[registrations]"'
1274
-                        . $checked . $disabled . '>',
1274
+                        . $checked.$disabled.'>',
1275 1275
                         '',
1276 1276
                         'jst-cntr'
1277 1277
                     ),
1278
-                    'apply-payment-registration-row-' . $registration->ID()
1278
+                    'apply-payment-registration-row-'.$registration->ID()
1279 1279
                 );
1280 1280
             }
1281 1281
         }
@@ -1356,12 +1356,12 @@  discard block
 block discarded – undo
1356 1356
                 array(
1357 1357
                     'OR*payment_method_for_payment' => array(
1358 1358
                         'PMD_ID'    => array('IN', $payment_methods_of_payments),
1359
-                        'PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%'),
1359
+                        'PMD_scope' => array('LIKE', '%'.EEM_Payment_Method::scope_admin.'%'),
1360 1360
                     ),
1361 1361
                 ),
1362 1362
             );
1363 1363
         } else {
1364
-            $query_args = array(array('PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%')));
1364
+            $query_args = array(array('PMD_scope' => array('LIKE', '%'.EEM_Payment_Method::scope_admin.'%')));
1365 1365
         }
1366 1366
         $this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1367 1367
     }
@@ -1390,7 +1390,7 @@  discard block
 block discarded – undo
1390 1390
             'Line_Item',
1391 1391
             array(array('LIN_type' => 'line-item'))
1392 1392
         );
1393
-        if (! empty($line_items)) {
1393
+        if ( ! empty($line_items)) {
1394 1394
             foreach ($line_items as $item) {
1395 1395
                 if ($item instanceof EE_Line_Item) {
1396 1396
                     switch ($item->OBJ_type()) {
@@ -1400,7 +1400,7 @@  discard block
 block discarded – undo
1400 1400
                             $ticket = $item->ticket();
1401 1401
                             // right now we're only handling tickets here.
1402 1402
                             // Cause its expected that only tickets will have attendees right?
1403
-                            if (! $ticket instanceof EE_Ticket) {
1403
+                            if ( ! $ticket instanceof EE_Ticket) {
1404 1404
                                 continue;
1405 1405
                             }
1406 1406
                             try {
@@ -1409,7 +1409,7 @@  discard block
 block discarded – undo
1409 1409
                                 EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1410 1410
                                 $event_name = esc_html__('Unknown Event', 'event_espresso');
1411 1411
                             }
1412
-                            $event_name .= ' - ' . $item->get('LIN_name');
1412
+                            $event_name .= ' - '.$item->get('LIN_name');
1413 1413
                             $ticket_price = EEH_Template::format_currency($item->get('LIN_unit_price'));
1414 1414
                             // now get all of the registrations for this transaction that use this ticket
1415 1415
                             $registrations = $ticket->get_many_related(
@@ -1417,38 +1417,38 @@  discard block
 block discarded – undo
1417 1417
                                 array(array('TXN_ID' => $this->_transaction->ID()))
1418 1418
                             );
1419 1419
                             foreach ($registrations as $registration) {
1420
-                                if (! $registration instanceof EE_Registration) {
1420
+                                if ( ! $registration instanceof EE_Registration) {
1421 1421
                                     continue;
1422 1422
                                 }
1423
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['STS_ID']
1423
+                                $this->_template_args['event_attendees'][$registration->ID()]['STS_ID']
1424 1424
                                     = $registration->status_ID();
1425
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['att_num']
1425
+                                $this->_template_args['event_attendees'][$registration->ID()]['att_num']
1426 1426
                                     = $registration->count();
1427
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['event_ticket_name']
1427
+                                $this->_template_args['event_attendees'][$registration->ID()]['event_ticket_name']
1428 1428
                                     = $event_name;
1429
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['ticket_price']
1429
+                                $this->_template_args['event_attendees'][$registration->ID()]['ticket_price']
1430 1430
                                     = $ticket_price;
1431 1431
                                 // attendee info
1432 1432
                                 $attendee = $registration->get_first_related('Attendee');
1433 1433
                                 if ($attendee instanceof EE_Attendee) {
1434
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['att_id']
1434
+                                    $this->_template_args['event_attendees'][$registration->ID()]['att_id']
1435 1435
                                         = $attendee->ID();
1436
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['attendee']
1436
+                                    $this->_template_args['event_attendees'][$registration->ID()]['attendee']
1437 1437
                                         = $attendee->full_name();
1438
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['email']
1439
-                                        = '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1438
+                                    $this->_template_args['event_attendees'][$registration->ID()]['email']
1439
+                                        = '<a href="mailto:'.$attendee->email().'?subject='.$event_name
1440 1440
                                           . esc_html__(
1441 1441
                                               ' Event',
1442 1442
                                               'event_espresso'
1443 1443
                                           )
1444
-                                          . '">' . $attendee->email() . '</a>';
1445
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['address']
1444
+                                          . '">'.$attendee->email().'</a>';
1445
+                                    $this->_template_args['event_attendees'][$registration->ID()]['address']
1446 1446
                                         = EEH_Address::format($attendee, 'inline', false, false);
1447 1447
                                 } else {
1448
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['att_id'] = '';
1449
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['attendee'] = '';
1450
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['email'] = '';
1451
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['address'] = '';
1448
+                                    $this->_template_args['event_attendees'][$registration->ID()]['att_id'] = '';
1449
+                                    $this->_template_args['event_attendees'][$registration->ID()]['attendee'] = '';
1450
+                                    $this->_template_args['event_attendees'][$registration->ID()]['email'] = '';
1451
+                                    $this->_template_args['event_attendees'][$registration->ID()]['address'] = '';
1452 1452
                                 }
1453 1453
                             }
1454 1454
                             break;
@@ -1464,7 +1464,7 @@  discard block
 block discarded – undo
1464 1464
                 TXN_ADMIN_URL
1465 1465
             );
1466 1466
             echo EEH_Template::display_template(
1467
-                TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1467
+                TXN_TEMPLATE_PATH.'txn_admin_details_main_meta_box_attendees.template.php',
1468 1468
                 $this->_template_args,
1469 1469
                 true
1470 1470
             );
@@ -1499,7 +1499,7 @@  discard block
 block discarded – undo
1499 1499
         $primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1500 1500
             ? $this->_transaction->primary_registration()->get_first_related('Attendee')
1501 1501
             : null;
1502
-        if (! $primary_att instanceof EE_Attendee) {
1502
+        if ( ! $primary_att instanceof EE_Attendee) {
1503 1503
             $this->_template_args['no_attendee_message'] = esc_html__(
1504 1504
                 'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1505 1505
                 'event_espresso'
@@ -1521,7 +1521,7 @@  discard block
 block discarded – undo
1521 1521
         // get formatted address for registrant
1522 1522
         $this->_template_args['formatted_address'] = EEH_Address::format($primary_att);
1523 1523
         echo EEH_Template::display_template(
1524
-            TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1524
+            TXN_TEMPLATE_PATH.'txn_admin_details_side_meta_box_registrant.template.php',
1525 1525
             $this->_template_args,
1526 1526
             true
1527 1527
         );
@@ -1546,8 +1546,8 @@  discard block
 block discarded – undo
1546 1546
             TXN_ADMIN_URL
1547 1547
         );
1548 1548
 
1549
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1550
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);/**/
1549
+        $template_path = TXN_TEMPLATE_PATH.'txn_admin_details_side_meta_box_billing_info.template.php';
1550
+        echo EEH_Template::display_template($template_path, $this->_template_args, true); /**/
1551 1551
     }
1552 1552
 
1553 1553
 
@@ -1572,7 +1572,7 @@  discard block
 block discarded – undo
1572 1572
             'ee_edit_payments',
1573 1573
             'apply_payment_or_refund_from_registration_details'
1574 1574
         );
1575
-        if (! empty($valid_data) && $has_access) {
1575
+        if ( ! empty($valid_data) && $has_access) {
1576 1576
             $PAY_ID = $valid_data['PAY_ID'];
1577 1577
             // save  the new payment
1578 1578
             $payment = $this->_create_payment_from_request_data($valid_data);
@@ -1585,7 +1585,7 @@  discard block
 block discarded – undo
1585 1585
                 $REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1586 1586
                 $this->_remove_existing_registration_payments($payment, $PAY_ID);
1587 1587
                 // apply payment to registrations (if applicable)
1588
-                if (! empty($REG_IDs)) {
1588
+                if ( ! empty($REG_IDs)) {
1589 1589
                     $this->_update_registration_payments($transaction, $payment, $REG_IDs);
1590 1590
                     $this->_maybe_send_notifications();
1591 1591
                     // now process status changes for the same registrations
@@ -1655,14 +1655,14 @@  discard block
 block discarded – undo
1655 1655
      */
1656 1656
     protected function _validate_payment_request_data()
1657 1657
     {
1658
-        if (! isset($this->_req_data['txn_admin_payment'])) {
1658
+        if ( ! isset($this->_req_data['txn_admin_payment'])) {
1659 1659
             return false;
1660 1660
         }
1661 1661
         $payment_form = $this->_generate_payment_form_section();
1662 1662
         try {
1663 1663
             if ($payment_form->was_submitted()) {
1664 1664
                 $payment_form->receive_form_submission();
1665
-                if (! $payment_form->is_valid()) {
1665
+                if ( ! $payment_form->is_valid()) {
1666 1666
                     $submission_error_messages = array();
1667 1667
                     foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1668 1668
                         if ($validation_error instanceof EE_Validation_Error) {
@@ -1841,7 +1841,7 @@  discard block
 block discarded – undo
1841 1841
             array('Y-m-d', 'g:i a')
1842 1842
         );
1843 1843
 
1844
-        if (! $payment->save()) {
1844
+        if ( ! $payment->save()) {
1845 1845
             EE_Error::add_error(
1846 1846
                 sprintf(
1847 1847
                     esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
@@ -2038,12 +2038,12 @@  discard block
 block discarded – undo
2038 2038
         // but add in some conditions regarding payment,
2039 2039
         // so that we don't apply payments to registrations that are free or have already been paid for
2040 2040
         // but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2041
-        if (! $payment->is_a_refund()) {
2041
+        if ( ! $payment->is_a_refund()) {
2042 2042
             $registration_query_where_params['REG_final_price'] = array('!=', 0);
2043 2043
             $registration_query_where_params['REG_final_price*'] = array('!=', 'REG_paid', true);
2044 2044
         }
2045 2045
         $registrations = $transaction->registrations(array($registration_query_where_params));
2046
-        if (! empty($registrations)) {
2046
+        if ( ! empty($registrations)) {
2047 2047
             /** @type EE_Payment_Processor $payment_processor */
2048 2048
             $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2049 2049
             $payment_processor->process_registration_payments($transaction, $payment, $registrations);
@@ -2068,7 +2068,7 @@  discard block
 block discarded – undo
2068 2068
     protected function _process_registration_status_change(EE_Transaction $transaction, $REG_IDs = array())
2069 2069
     {
2070 2070
         // first if there is no change in status then we get out.
2071
-        if (! isset($this->_req_data['txn_reg_status_change']['reg_status'])
2071
+        if ( ! isset($this->_req_data['txn_reg_status_change']['reg_status'])
2072 2072
             || $this->_req_data['txn_reg_status_change']['reg_status'] === 'NAN'
2073 2073
         ) {
2074 2074
             // no error message, no change requested, just nothing to do man.
@@ -2126,7 +2126,7 @@  discard block
 block discarded – undo
2126 2126
                 'pay_status'       => $payment->STS_ID(),
2127 2127
                 'PAY_ID'           => $payment->ID(),
2128 2128
                 'STS_ID'           => $payment->STS_ID(),
2129
-                'status'           => self::$_pay_status[ $payment->STS_ID() ],
2129
+                'status'           => self::$_pay_status[$payment->STS_ID()],
2130 2130
                 'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
2131 2131
                 'method'           => strtoupper($payment->source()),
2132 2132
                 'PM_ID'            => $payment->payment_method() ? $payment->payment_method()->ID() : 1,
@@ -2248,11 +2248,11 @@  discard block
 block discarded – undo
2248 2248
     {
2249 2249
         $registration_payment_data = array();
2250 2250
         // if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2251
-        if (! empty($REG_IDs)) {
2251
+        if ( ! empty($REG_IDs)) {
2252 2252
             $registrations = EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $REG_IDs))));
2253 2253
             foreach ($registrations as $registration) {
2254 2254
                 if ($registration instanceof EE_Registration) {
2255
-                    $registration_payment_data[ $registration->ID() ] = array(
2255
+                    $registration_payment_data[$registration->ID()] = array(
2256 2256
                         'paid'  => $registration->pretty_paid(),
2257 2257
                         'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
2258 2258
                     );
@@ -2364,8 +2364,8 @@  discard block
 block discarded – undo
2364 2364
             : date('m/d/Y');
2365 2365
 
2366 2366
         // make sure our timestamps start and end right at the boundaries for each day
2367
-        $start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2368
-        $end_date = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2367
+        $start_date = date('Y-m-d', strtotime($start_date)).' 00:00:00';
2368
+        $end_date = date('Y-m-d', strtotime($end_date)).' 23:59:59';
2369 2369
 
2370 2370
 
2371 2371
         // convert to timestamps
@@ -2424,7 +2424,7 @@  discard block
 block discarded – undo
2424 2424
         }
2425 2425
 
2426 2426
         if (isset($this->_req_data['s'])) {
2427
-            $search_string = '%' . $this->_req_data['s'] . '%';
2427
+            $search_string = '%'.$this->_req_data['s'].'%';
2428 2428
             $_where['OR'] = array(
2429 2429
                 'Registration.Event.EVT_name'         => array('LIKE', $search_string),
2430 2430
                 'Registration.Event.EVT_desc'         => array('LIKE', $search_string),
@@ -2451,9 +2451,9 @@  discard block
 block discarded – undo
2451 2451
         }
2452 2452
 
2453 2453
         // failed transactions
2454
-        $failed = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'failed' && ! $count)
2454
+        $failed = ( ! empty($this->_req_data['status']) && $this->_req_data['status'] === 'failed' && ! $count)
2455 2455
                   || ($count && $view === 'failed');
2456
-        $abandoned = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'abandoned' && ! $count)
2456
+        $abandoned = ( ! empty($this->_req_data['status']) && $this->_req_data['status'] === 'abandoned' && ! $count)
2457 2457
                      || ($count && $view === 'abandoned');
2458 2458
 
2459 2459
         if ($failed) {
Please login to merge, or discard this patch.
core/entities/models/JsonModelSchema.php 2 patches
Indentation   +226 added lines, -226 removed lines patch added patch discarded remove patch
@@ -25,230 +25,230 @@
 block discarded – undo
25 25
 class JsonModelSchema
26 26
 {
27 27
 
28
-    /**
29
-     * @var EEM_Base
30
-     */
31
-    protected $model;
32
-
33
-    /**
34
-     * @var CalculatedModelFields
35
-     */
36
-    protected $fields_calculator;
37
-
38
-
39
-    /**
40
-     * JsonModelSchema constructor.
41
-     *
42
-     * @param EEM_Base              $model
43
-     * @param CalculatedModelFields $fields_calculator
44
-     */
45
-    public function __construct(EEM_Base $model, CalculatedModelFields $fields_calculator)
46
-    {
47
-        $this->model = $model;
48
-        $this->fields_calculator = $fields_calculator;
49
-    }
50
-
51
-
52
-    /**
53
-     * Return the schema for a given model from a given model.
54
-     *
55
-     * @return array
56
-     */
57
-    public function getModelSchema()
58
-    {
59
-        return $this->getModelSchemaForRelations(
60
-            $this->model->relation_settings(),
61
-            $this->getModelSchemaForFields(
62
-                $this->model->field_settings(),
63
-                $this->getInitialSchemaStructure()
64
-            )
65
-        );
66
-    }
67
-
68
-
69
-    /**
70
-     * Get the schema for a given set of model fields.
71
-     *
72
-     * @param EE_Model_Field_Base[] $model_fields
73
-     * @param array                  $schema
74
-     * @return array
75
-     */
76
-    public function getModelSchemaForFields(array $model_fields, array $schema)
77
-    {
78
-        foreach ($model_fields as $field => $model_field) {
79
-            if (! $model_field instanceof EE_Model_Field_Base) {
80
-                continue;
81
-            }
82
-            $schema['properties'][ $field ] = $model_field->getSchema();
83
-
84
-            // if this is a primary key field add the primary key item
85
-            if ($model_field instanceof EE_Primary_Key_Field_Base) {
86
-                $schema['properties'][ $field ]['primary_key'] = true;
87
-                if ($model_field instanceof EE_Primary_Key_Int_Field) {
88
-                    $schema['properties'][ $field ]['readonly'] = true;
89
-                }
90
-            }
91
-
92
-            // if this is a foreign key field add the foreign key item
93
-            if ($model_field instanceof EE_Foreign_Key_Field_Base) {
94
-                $schema['properties'][ $field ]['foreign_key'] = array(
95
-                    'description' => esc_html__(
96
-                        'This is a foreign key the points to the given models.',
97
-                        'event_espresso'
98
-                    ),
99
-                    'type'        => 'array',
100
-                    'enum'        => $model_field->get_model_class_names_pointed_to(),
101
-                );
102
-            }
103
-        }
104
-        return $schema;
105
-    }
106
-
107
-
108
-    /**
109
-     * Get the schema for a given set of model relations
110
-     *
111
-     * @param EE_Model_Relation_Base[] $relations_on_model
112
-     * @param array                    $schema
113
-     * @return array
114
-     */
115
-    public function getModelSchemaForRelations(array $relations_on_model, array $schema)
116
-    {
117
-        foreach ($relations_on_model as $model_name => $relation) {
118
-            if (! $relation instanceof EE_Model_Relation_Base) {
119
-                continue;
120
-            }
121
-            $model_name_for_schema = $relation instanceof EE_Belongs_To_Relation
122
-                ? strtolower($model_name)
123
-                : EEH_Inflector::pluralize_and_lower($model_name);
124
-            $schema['properties'][ $model_name_for_schema ] = $relation->getSchema();
125
-            $schema['properties'][ $model_name_for_schema ]['relation_model'] = $model_name;
126
-
127
-            // links schema
128
-            $links_key = 'https://api.eventespresso.com/' . strtolower($model_name);
129
-            $schema['properties']['_links']['properties'][ $links_key ] = array(
130
-                'description' => esc_html__(
131
-                    'Array of objects describing the link(s) for this relation resource.',
132
-                    'event_espresso'
133
-                ),
134
-                'type' => 'array',
135
-                'readonly' => true,
136
-                'items' => array(
137
-                    'type' => 'object',
138
-                    'properties' => array(
139
-                        'href' => array(
140
-                            'type' => 'string',
141
-                            'description' => sprintf(
142
-                                // translators: placeholder is the model name for the relation.
143
-                                esc_html__(
144
-                                    'The link to the resource for the %s relation(s) to this entity',
145
-                                    'event_espresso'
146
-                                ),
147
-                                $model_name
148
-                            ),
149
-                        ),
150
-                        'single' => array(
151
-                            'type' => 'boolean',
152
-                            'description' => sprintf(
153
-                                // translators: placeholder is the model name for the relation.
154
-                                esc_html__(
155
-                                    'Whether or not there is only a single %s relation to this entity',
156
-                                    'event_espresso'
157
-                                ),
158
-                                $model_name
159
-                            ),
160
-                        ),
161
-                    ),
162
-                    'additionalProperties' => false
163
-                ),
164
-            );
165
-        }
166
-        return $schema;
167
-    }
168
-
169
-
170
-    /**
171
-     * Outputs the schema header for a model.
172
-     *
173
-     * @return array
174
-     */
175
-    public function getInitialSchemaStructure()
176
-    {
177
-        return array(
178
-            '$schema'    => 'http://json-schema.org/draft-04/schema#',
179
-            'title'      => $this->model->get_this_model_name(),
180
-            'type'       => 'object',
181
-            'properties' => array(
182
-                'link' => array(
183
-                    'description' => esc_html__(
184
-                        'Link to event on WordPress site hosting events.',
185
-                        'event_espresso'
186
-                    ),
187
-                    'type' => 'string',
188
-                    'readonly' => true,
189
-                ),
190
-                '_links' => array(
191
-                    'description' => esc_html__(
192
-                        'Various links for resources related to the entity.',
193
-                        'event_espresso'
194
-                    ),
195
-                    'type' => 'object',
196
-                    'readonly' => true,
197
-                    'properties' => array(
198
-                        'self' => array(
199
-                            'description' => esc_html__(
200
-                                'Link to this entities resource.',
201
-                                'event_espresso'
202
-                            ),
203
-                            'type' => 'array',
204
-                            'items' => array(
205
-                                'type' => 'object',
206
-                                'properties' => array(
207
-                                    'href' => array(
208
-                                        'type' => 'string',
209
-                                    ),
210
-                                ),
211
-                                'additionalProperties' => false
212
-                            ),
213
-                            'readonly' => true
214
-                        ),
215
-                        'collection' => array(
216
-                            'description' => esc_html__(
217
-                                'Link to this entities collection resource.',
218
-                                'event_espresso'
219
-                            ),
220
-                            'type' => 'array',
221
-                            'items' => array(
222
-                                'type' => 'object',
223
-                                'properties' => array(
224
-                                    'href' => array(
225
-                                        'type' => 'string'
226
-                                    ),
227
-                                ),
228
-                                'additionalProperties' => false
229
-                            ),
230
-                            'readonly' => true
231
-                        ),
232
-                    ),
233
-                    'additionalProperties' => false,
234
-                ),
235
-                '_calculated_fields' => $this->fields_calculator->getJsonSchemaForModel($this->model)
236
-            ),
237
-            'additionalProperties' => false,
238
-        );
239
-    }
240
-
241
-
242
-    /**
243
-     * Allows one to just use the object as a string to get the json.
244
-     * eg.
245
-     * $json_schema = new JsonModelSchema(EEM_Event::instance(), new CalculatedModelFields);
246
-     * echo $json_schema; //outputs the schema as a json formatted string.
247
-     *
248
-     * @return bool|false|mixed|string
249
-     */
250
-    public function __toString()
251
-    {
252
-        return wp_json_encode($this->getModelSchema());
253
-    }
28
+	/**
29
+	 * @var EEM_Base
30
+	 */
31
+	protected $model;
32
+
33
+	/**
34
+	 * @var CalculatedModelFields
35
+	 */
36
+	protected $fields_calculator;
37
+
38
+
39
+	/**
40
+	 * JsonModelSchema constructor.
41
+	 *
42
+	 * @param EEM_Base              $model
43
+	 * @param CalculatedModelFields $fields_calculator
44
+	 */
45
+	public function __construct(EEM_Base $model, CalculatedModelFields $fields_calculator)
46
+	{
47
+		$this->model = $model;
48
+		$this->fields_calculator = $fields_calculator;
49
+	}
50
+
51
+
52
+	/**
53
+	 * Return the schema for a given model from a given model.
54
+	 *
55
+	 * @return array
56
+	 */
57
+	public function getModelSchema()
58
+	{
59
+		return $this->getModelSchemaForRelations(
60
+			$this->model->relation_settings(),
61
+			$this->getModelSchemaForFields(
62
+				$this->model->field_settings(),
63
+				$this->getInitialSchemaStructure()
64
+			)
65
+		);
66
+	}
67
+
68
+
69
+	/**
70
+	 * Get the schema for a given set of model fields.
71
+	 *
72
+	 * @param EE_Model_Field_Base[] $model_fields
73
+	 * @param array                  $schema
74
+	 * @return array
75
+	 */
76
+	public function getModelSchemaForFields(array $model_fields, array $schema)
77
+	{
78
+		foreach ($model_fields as $field => $model_field) {
79
+			if (! $model_field instanceof EE_Model_Field_Base) {
80
+				continue;
81
+			}
82
+			$schema['properties'][ $field ] = $model_field->getSchema();
83
+
84
+			// if this is a primary key field add the primary key item
85
+			if ($model_field instanceof EE_Primary_Key_Field_Base) {
86
+				$schema['properties'][ $field ]['primary_key'] = true;
87
+				if ($model_field instanceof EE_Primary_Key_Int_Field) {
88
+					$schema['properties'][ $field ]['readonly'] = true;
89
+				}
90
+			}
91
+
92
+			// if this is a foreign key field add the foreign key item
93
+			if ($model_field instanceof EE_Foreign_Key_Field_Base) {
94
+				$schema['properties'][ $field ]['foreign_key'] = array(
95
+					'description' => esc_html__(
96
+						'This is a foreign key the points to the given models.',
97
+						'event_espresso'
98
+					),
99
+					'type'        => 'array',
100
+					'enum'        => $model_field->get_model_class_names_pointed_to(),
101
+				);
102
+			}
103
+		}
104
+		return $schema;
105
+	}
106
+
107
+
108
+	/**
109
+	 * Get the schema for a given set of model relations
110
+	 *
111
+	 * @param EE_Model_Relation_Base[] $relations_on_model
112
+	 * @param array                    $schema
113
+	 * @return array
114
+	 */
115
+	public function getModelSchemaForRelations(array $relations_on_model, array $schema)
116
+	{
117
+		foreach ($relations_on_model as $model_name => $relation) {
118
+			if (! $relation instanceof EE_Model_Relation_Base) {
119
+				continue;
120
+			}
121
+			$model_name_for_schema = $relation instanceof EE_Belongs_To_Relation
122
+				? strtolower($model_name)
123
+				: EEH_Inflector::pluralize_and_lower($model_name);
124
+			$schema['properties'][ $model_name_for_schema ] = $relation->getSchema();
125
+			$schema['properties'][ $model_name_for_schema ]['relation_model'] = $model_name;
126
+
127
+			// links schema
128
+			$links_key = 'https://api.eventespresso.com/' . strtolower($model_name);
129
+			$schema['properties']['_links']['properties'][ $links_key ] = array(
130
+				'description' => esc_html__(
131
+					'Array of objects describing the link(s) for this relation resource.',
132
+					'event_espresso'
133
+				),
134
+				'type' => 'array',
135
+				'readonly' => true,
136
+				'items' => array(
137
+					'type' => 'object',
138
+					'properties' => array(
139
+						'href' => array(
140
+							'type' => 'string',
141
+							'description' => sprintf(
142
+								// translators: placeholder is the model name for the relation.
143
+								esc_html__(
144
+									'The link to the resource for the %s relation(s) to this entity',
145
+									'event_espresso'
146
+								),
147
+								$model_name
148
+							),
149
+						),
150
+						'single' => array(
151
+							'type' => 'boolean',
152
+							'description' => sprintf(
153
+								// translators: placeholder is the model name for the relation.
154
+								esc_html__(
155
+									'Whether or not there is only a single %s relation to this entity',
156
+									'event_espresso'
157
+								),
158
+								$model_name
159
+							),
160
+						),
161
+					),
162
+					'additionalProperties' => false
163
+				),
164
+			);
165
+		}
166
+		return $schema;
167
+	}
168
+
169
+
170
+	/**
171
+	 * Outputs the schema header for a model.
172
+	 *
173
+	 * @return array
174
+	 */
175
+	public function getInitialSchemaStructure()
176
+	{
177
+		return array(
178
+			'$schema'    => 'http://json-schema.org/draft-04/schema#',
179
+			'title'      => $this->model->get_this_model_name(),
180
+			'type'       => 'object',
181
+			'properties' => array(
182
+				'link' => array(
183
+					'description' => esc_html__(
184
+						'Link to event on WordPress site hosting events.',
185
+						'event_espresso'
186
+					),
187
+					'type' => 'string',
188
+					'readonly' => true,
189
+				),
190
+				'_links' => array(
191
+					'description' => esc_html__(
192
+						'Various links for resources related to the entity.',
193
+						'event_espresso'
194
+					),
195
+					'type' => 'object',
196
+					'readonly' => true,
197
+					'properties' => array(
198
+						'self' => array(
199
+							'description' => esc_html__(
200
+								'Link to this entities resource.',
201
+								'event_espresso'
202
+							),
203
+							'type' => 'array',
204
+							'items' => array(
205
+								'type' => 'object',
206
+								'properties' => array(
207
+									'href' => array(
208
+										'type' => 'string',
209
+									),
210
+								),
211
+								'additionalProperties' => false
212
+							),
213
+							'readonly' => true
214
+						),
215
+						'collection' => array(
216
+							'description' => esc_html__(
217
+								'Link to this entities collection resource.',
218
+								'event_espresso'
219
+							),
220
+							'type' => 'array',
221
+							'items' => array(
222
+								'type' => 'object',
223
+								'properties' => array(
224
+									'href' => array(
225
+										'type' => 'string'
226
+									),
227
+								),
228
+								'additionalProperties' => false
229
+							),
230
+							'readonly' => true
231
+						),
232
+					),
233
+					'additionalProperties' => false,
234
+				),
235
+				'_calculated_fields' => $this->fields_calculator->getJsonSchemaForModel($this->model)
236
+			),
237
+			'additionalProperties' => false,
238
+		);
239
+	}
240
+
241
+
242
+	/**
243
+	 * Allows one to just use the object as a string to get the json.
244
+	 * eg.
245
+	 * $json_schema = new JsonModelSchema(EEM_Event::instance(), new CalculatedModelFields);
246
+	 * echo $json_schema; //outputs the schema as a json formatted string.
247
+	 *
248
+	 * @return bool|false|mixed|string
249
+	 */
250
+	public function __toString()
251
+	{
252
+		return wp_json_encode($this->getModelSchema());
253
+	}
254 254
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -76,22 +76,22 @@  discard block
 block discarded – undo
76 76
     public function getModelSchemaForFields(array $model_fields, array $schema)
77 77
     {
78 78
         foreach ($model_fields as $field => $model_field) {
79
-            if (! $model_field instanceof EE_Model_Field_Base) {
79
+            if ( ! $model_field instanceof EE_Model_Field_Base) {
80 80
                 continue;
81 81
             }
82
-            $schema['properties'][ $field ] = $model_field->getSchema();
82
+            $schema['properties'][$field] = $model_field->getSchema();
83 83
 
84 84
             // if this is a primary key field add the primary key item
85 85
             if ($model_field instanceof EE_Primary_Key_Field_Base) {
86
-                $schema['properties'][ $field ]['primary_key'] = true;
86
+                $schema['properties'][$field]['primary_key'] = true;
87 87
                 if ($model_field instanceof EE_Primary_Key_Int_Field) {
88
-                    $schema['properties'][ $field ]['readonly'] = true;
88
+                    $schema['properties'][$field]['readonly'] = true;
89 89
                 }
90 90
             }
91 91
 
92 92
             // if this is a foreign key field add the foreign key item
93 93
             if ($model_field instanceof EE_Foreign_Key_Field_Base) {
94
-                $schema['properties'][ $field ]['foreign_key'] = array(
94
+                $schema['properties'][$field]['foreign_key'] = array(
95 95
                     'description' => esc_html__(
96 96
                         'This is a foreign key the points to the given models.',
97 97
                         'event_espresso'
@@ -115,18 +115,18 @@  discard block
 block discarded – undo
115 115
     public function getModelSchemaForRelations(array $relations_on_model, array $schema)
116 116
     {
117 117
         foreach ($relations_on_model as $model_name => $relation) {
118
-            if (! $relation instanceof EE_Model_Relation_Base) {
118
+            if ( ! $relation instanceof EE_Model_Relation_Base) {
119 119
                 continue;
120 120
             }
121 121
             $model_name_for_schema = $relation instanceof EE_Belongs_To_Relation
122 122
                 ? strtolower($model_name)
123 123
                 : EEH_Inflector::pluralize_and_lower($model_name);
124
-            $schema['properties'][ $model_name_for_schema ] = $relation->getSchema();
125
-            $schema['properties'][ $model_name_for_schema ]['relation_model'] = $model_name;
124
+            $schema['properties'][$model_name_for_schema] = $relation->getSchema();
125
+            $schema['properties'][$model_name_for_schema]['relation_model'] = $model_name;
126 126
 
127 127
             // links schema
128
-            $links_key = 'https://api.eventespresso.com/' . strtolower($model_name);
129
-            $schema['properties']['_links']['properties'][ $links_key ] = array(
128
+            $links_key = 'https://api.eventespresso.com/'.strtolower($model_name);
129
+            $schema['properties']['_links']['properties'][$links_key] = array(
130 130
                 'description' => esc_html__(
131 131
                     'Array of objects describing the link(s) for this relation resource.',
132 132
                     'event_espresso'
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/Registration.php 2 patches
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -43,7 +43,7 @@  discard block
 block discarded – undo
43 43
         } else {
44 44
             $reg = null;
45 45
         }
46
-        if (! $reg instanceof EE_Registration
46
+        if ( ! $reg instanceof EE_Registration
47 47
         ) {
48 48
             throw new EE_Error(
49 49
                 sprintf(
@@ -81,7 +81,7 @@  discard block
 block discarded – undo
81 81
                     $status_pretty = 'NEVER';
82 82
                     break;
83 83
             }
84
-            $checkin_stati[ $datetime_id ] = $status_pretty;
84
+            $checkin_stati[$datetime_id] = $status_pretty;
85 85
         }
86 86
         return $checkin_stati;
87 87
     }
Please login to merge, or discard this patch.
Indentation   +100 added lines, -100 removed lines patch added patch discarded remove patch
@@ -24,108 +24,108 @@
 block discarded – undo
24 24
  */
25 25
 class Registration extends RegistrationCalculationBase
26 26
 {
27
-    /**
28
-     * @var EEM_Registration
29
-     */
30
-    protected $registration_model;
27
+	/**
28
+	 * @var EEM_Registration
29
+	 */
30
+	protected $registration_model;
31 31
 
32
-    /**
33
-     * Registration constructor.
34
-     * @param EEM_Registration $registration_model
35
-     */
36
-    public function __construct(EEM_Registration $registration_model)
37
-    {
38
-        $this->registration_model = $registration_model;
39
-    }
32
+	/**
33
+	 * Registration constructor.
34
+	 * @param EEM_Registration $registration_model
35
+	 */
36
+	public function __construct(EEM_Registration $registration_model)
37
+	{
38
+		$this->registration_model = $registration_model;
39
+	}
40 40
 
41
-    /**
42
-     * Calculates the checkin status for each datetime this registration has access to
43
-     *
44
-     * @param array            $wpdb_row
45
-     * @param WP_REST_Request $request
46
-     * @param RegistrationControllerBase $controller
47
-     * @return array
48
-     * @throws EE_Error
49
-     * @throws InvalidDataTypeException
50
-     * @throws InvalidInterfaceException
51
-     * @throws InvalidArgumentException
52
-     */
53
-    public function datetimeCheckinStati($wpdb_row, $request, $controller)
54
-    {
55
-        if (is_array($wpdb_row) && isset($wpdb_row['Registration.REG_ID'])) {
56
-            $reg = $this->registration_model->get_one_by_ID($wpdb_row['Registration.REG_ID']);
57
-        } else {
58
-            $reg = null;
59
-        }
60
-        if (! $reg instanceof EE_Registration
61
-        ) {
62
-            throw new EE_Error(
63
-                sprintf(
64
-                    __(
65
-                    // @codingStandardsIgnoreStart
66
-                        'Cannot calculate datetime_checkin_stati because the registration with ID %1$s (from database row %2$s) was not found',
67
-                        // @codingStandardsIgnoreEnd
68
-                        'event_espresso'
69
-                    ),
70
-                    $wpdb_row['Registration.REG_ID'],
71
-                    print_r($wpdb_row, true)
72
-                )
73
-            );
74
-        }
75
-        $datetime_ids = EEM_Datetime::instance()->get_col(
76
-            [
77
-                [
78
-                    'Ticket.TKT_ID' => $reg->ticket_ID(),
79
-                ],
80
-                'default_where_conditions' => EEM_Base::default_where_conditions_minimum_all,
81
-            ]
82
-        );
83
-        $checkin_stati = array();
84
-        foreach ($datetime_ids as $datetime_id) {
85
-            $status = $reg->check_in_status_for_datetime($datetime_id);
86
-            switch ($status) {
87
-                case EE_Checkin::status_checked_out:
88
-                    $status_pretty = 'OUT';
89
-                    break;
90
-                case EE_Checkin::status_checked_in:
91
-                    $status_pretty = 'IN';
92
-                    break;
93
-                case EE_Checkin::status_checked_never:
94
-                default:
95
-                    $status_pretty = 'NEVER';
96
-                    break;
97
-            }
98
-            $checkin_stati[ $datetime_id ] = $status_pretty;
99
-        }
100
-        return $checkin_stati;
101
-    }
41
+	/**
42
+	 * Calculates the checkin status for each datetime this registration has access to
43
+	 *
44
+	 * @param array            $wpdb_row
45
+	 * @param WP_REST_Request $request
46
+	 * @param RegistrationControllerBase $controller
47
+	 * @return array
48
+	 * @throws EE_Error
49
+	 * @throws InvalidDataTypeException
50
+	 * @throws InvalidInterfaceException
51
+	 * @throws InvalidArgumentException
52
+	 */
53
+	public function datetimeCheckinStati($wpdb_row, $request, $controller)
54
+	{
55
+		if (is_array($wpdb_row) && isset($wpdb_row['Registration.REG_ID'])) {
56
+			$reg = $this->registration_model->get_one_by_ID($wpdb_row['Registration.REG_ID']);
57
+		} else {
58
+			$reg = null;
59
+		}
60
+		if (! $reg instanceof EE_Registration
61
+		) {
62
+			throw new EE_Error(
63
+				sprintf(
64
+					__(
65
+					// @codingStandardsIgnoreStart
66
+						'Cannot calculate datetime_checkin_stati because the registration with ID %1$s (from database row %2$s) was not found',
67
+						// @codingStandardsIgnoreEnd
68
+						'event_espresso'
69
+					),
70
+					$wpdb_row['Registration.REG_ID'],
71
+					print_r($wpdb_row, true)
72
+				)
73
+			);
74
+		}
75
+		$datetime_ids = EEM_Datetime::instance()->get_col(
76
+			[
77
+				[
78
+					'Ticket.TKT_ID' => $reg->ticket_ID(),
79
+				],
80
+				'default_where_conditions' => EEM_Base::default_where_conditions_minimum_all,
81
+			]
82
+		);
83
+		$checkin_stati = array();
84
+		foreach ($datetime_ids as $datetime_id) {
85
+			$status = $reg->check_in_status_for_datetime($datetime_id);
86
+			switch ($status) {
87
+				case EE_Checkin::status_checked_out:
88
+					$status_pretty = 'OUT';
89
+					break;
90
+				case EE_Checkin::status_checked_in:
91
+					$status_pretty = 'IN';
92
+					break;
93
+				case EE_Checkin::status_checked_never:
94
+				default:
95
+					$status_pretty = 'NEVER';
96
+					break;
97
+			}
98
+			$checkin_stati[ $datetime_id ] = $status_pretty;
99
+		}
100
+		return $checkin_stati;
101
+	}
102 102
 
103 103
 
104
-    /**
105
-     * Provides an array for all the calculations possible that outlines a json schema for those calculations.
106
-     * Array is indexed by calculation (snake case) and value is the schema for that calculation.
107
-     *
108
-     * @since $VID:$
109
-     * @return array
110
-     */
111
-    public function schemaForCalculations()
112
-    {
113
-        return array(
114
-            'datetime_checkin_stati' => array(
115
-                'description' => esc_html__(
116
-                    'Returns the checkin status for each datetime this registration has access to.',
117
-                    'event_espresso'
118
-                ),
119
-                'type' => 'object',
120
-                'properties' => array(),
121
-                'additionalProperties' => array(
122
-                    'description' => esc_html(
123
-                        'Keys are date-time ids and values are the check-in status',
124
-                        'event_espresso'
125
-                    ),
126
-                    'type' => 'string'
127
-                ),
128
-            ),
129
-        );
130
-    }
104
+	/**
105
+	 * Provides an array for all the calculations possible that outlines a json schema for those calculations.
106
+	 * Array is indexed by calculation (snake case) and value is the schema for that calculation.
107
+	 *
108
+	 * @since $VID:$
109
+	 * @return array
110
+	 */
111
+	public function schemaForCalculations()
112
+	{
113
+		return array(
114
+			'datetime_checkin_stati' => array(
115
+				'description' => esc_html__(
116
+					'Returns the checkin status for each datetime this registration has access to.',
117
+					'event_espresso'
118
+				),
119
+				'type' => 'object',
120
+				'properties' => array(),
121
+				'additionalProperties' => array(
122
+					'description' => esc_html(
123
+						'Keys are date-time ids and values are the check-in status',
124
+						'event_espresso'
125
+					),
126
+					'type' => 'string'
127
+				),
128
+			),
129
+		);
130
+	}
131 131
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/CalculatedModelFields.php 3 patches
Unused Use Statements   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -5,9 +5,8 @@
 block discarded – undo
5 5
 use EEM_Base;
6 6
 use EventEspresso\core\exceptions\UnexpectedEntityException;
7 7
 use EventEspresso\core\libraries\rest_api\calculations\CalculatedModelFieldsFactory;
8
-use EventEspresso\core\libraries\rest_api\controllers\Base;
9
-use EEH_Inflector;
10 8
 use EventEspresso\core\libraries\rest_api\controllers\Base as BaseController;
9
+use EEH_Inflector;
11 10
 
12 11
 /**
13 12
  * Class CalculatedModelFields
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -57,7 +57,7 @@  discard block
 block discarded – undo
57 57
      */
58 58
     public function mapping($refresh = false)
59 59
     {
60
-        if (! $this->mapping || $refresh) {
60
+        if ( ! $this->mapping || $refresh) {
61 61
             $this->mapping = $this->generateNewMapping();
62 62
         }
63 63
         return $this->mapping;
@@ -84,7 +84,7 @@  discard block
 block discarded – undo
84 84
         foreach ($models_with_calculated_fields as $model_name) {
85 85
             $calculator = $this->factory->createFromModel($model_name);
86 86
             foreach (array_keys(call_user_func(array($calculator, 'schemaForCalculations'))) as $field_name) {
87
-                $mapping[ $model_name ][ $field_name ] = get_class($calculator);
87
+                $mapping[$model_name][$field_name] = get_class($calculator);
88 88
             }
89 89
         }
90 90
         return apply_filters(
@@ -113,8 +113,8 @@  discard block
 block discarded – undo
113 113
             foreach ($map_for_model as $calculation_index => $calculations_class) {
114 114
                 $calculator = $this->factory->createFromClassname($calculations_class);
115 115
                 $schema = call_user_func(array($calculator, 'schemaForCalculation'), $calculation_index);
116
-                if (! empty($schema)) {
117
-                    $schema_map[ $map_model ][ $calculation_index ] = $schema;
116
+                if ( ! empty($schema)) {
117
+                    $schema_map[$map_model][$calculation_index] = $schema;
118 118
                 }
119 119
             }
120 120
         }
@@ -131,8 +131,8 @@  discard block
 block discarded – undo
131 131
     public function retrieveCalculatedFieldsForModel(EEM_Base $model)
132 132
     {
133 133
         $mapping = $this->mapping();
134
-        if (isset($mapping[ $model->get_this_model_name() ])) {
135
-            return array_keys($mapping[ $model->get_this_model_name() ]);
134
+        if (isset($mapping[$model->get_this_model_name()])) {
135
+            return array_keys($mapping[$model->get_this_model_name()]);
136 136
         }
137 137
         return array();
138 138
     }
@@ -145,7 +145,7 @@  discard block
 block discarded – undo
145 145
      */
146 146
     public function getJsonSchemaForModel(EEM_Base $model)
147 147
     {
148
-        if (! $this->mapping_schema) {
148
+        if ( ! $this->mapping_schema) {
149 149
             $this->mapping_schema = $this->generateNewMappingSchema();
150 150
         }
151 151
         return array(
@@ -154,8 +154,8 @@  discard block
 block discarded – undo
154 154
                 'event_espresso'
155 155
             ),
156 156
             'type' => 'object',
157
-            'properties' => isset($this->mapping_schema[ $model->get_this_model_name() ])
158
-                ? $this->mapping_schema[ $model->get_this_model_name() ]
157
+            'properties' => isset($this->mapping_schema[$model->get_this_model_name()])
158
+                ? $this->mapping_schema[$model->get_this_model_name()]
159 159
                 : array(),
160 160
             'additionalProperties' => false,
161 161
             'readonly' => true,
@@ -183,10 +183,10 @@  discard block
 block discarded – undo
183 183
         Base $controller
184 184
     ) {
185 185
         $mapping = $this->mapping();
186
-        if (isset($mapping[ $model->get_this_model_name() ])
187
-            && isset($mapping[ $model->get_this_model_name() ][ $field_name ])
186
+        if (isset($mapping[$model->get_this_model_name()])
187
+            && isset($mapping[$model->get_this_model_name()][$field_name])
188 188
         ) {
189
-            $classname = $mapping[ $model->get_this_model_name() ][ $field_name ];
189
+            $classname = $mapping[$model->get_this_model_name()][$field_name];
190 190
             $calculator = $this->factory->createFromClassname($classname);
191 191
             $class_method_name = EEH_Inflector::camelize_all_but_first($field_name);
192 192
             return call_user_func(array($calculator, $class_method_name), $wpdb_row, $rest_request, $controller);
Please login to merge, or discard this patch.
Indentation   +173 added lines, -173 removed lines patch added patch discarded remove patch
@@ -22,177 +22,177 @@
 block discarded – undo
22 22
 class CalculatedModelFields
23 23
 {
24 24
 
25
-    /**
26
-     * @var array
27
-     */
28
-    protected $mapping;
29
-
30
-    /**
31
-     * @var array
32
-     */
33
-    protected $mapping_schema;
34
-
35
-    /**
36
-     * @var CalculatedModelFieldsFactory
37
-     */
38
-    private $factory;
39
-
40
-    /**
41
-     * CalculatedModelFields constructor.
42
-     * @param CalculatedModelFieldsFactory $factory
43
-     */
44
-    public function __construct(CalculatedModelFieldsFactory $factory)
45
-    {
46
-        $this->factory = $factory;
47
-    }
48
-    /**
49
-     * @param bool $refresh
50
-     * @return array top-level-keys are model names (eg "Event")
51
-     * next-level are the calculated field names AND method names on classes
52
-     * which perform calculations, values are the fully qualified classnames which do the calculations
53
-     * These callbacks should accept as arguments:
54
-     * the wpdb row results,
55
-     * the WP_Request object,
56
-     * the controller object
57
-     */
58
-    public function mapping($refresh = false)
59
-    {
60
-        if (! $this->mapping || $refresh) {
61
-            $this->mapping = $this->generateNewMapping();
62
-        }
63
-        return $this->mapping;
64
-    }
65
-
66
-
67
-    /**
68
-     * Generates a new mapping between model calculated fields and their callbacks
69
-     *
70
-     * @return array
71
-     */
72
-    protected function generateNewMapping()
73
-    {
74
-        $mapping = array();
75
-        $models_with_calculated_fields = array(
76
-            'Attendee',
77
-            'Datetime',
78
-            'Event',
79
-            'Registration'
80
-        );
81
-        foreach ($models_with_calculated_fields as $model_name) {
82
-            $calculator = $this->factory->createFromModel($model_name);
83
-            foreach (array_keys(call_user_func(array($calculator, 'schemaForCalculations'))) as $field_name) {
84
-                $mapping[ $model_name ][ $field_name ] = get_class($calculator);
85
-            }
86
-        }
87
-        return apply_filters(
88
-            'FHEE__EventEspresso\core\libraries\rest_api\Calculated_Model_Fields__mapping',
89
-            $mapping
90
-        );
91
-    }
92
-
93
-
94
-    /**
95
-     * Generates the schema for each calculation index in the calculation map.
96
-     *
97
-     * @return array
98
-     * @throws UnexpectedEntityException
99
-     */
100
-    protected function generateNewMappingSchema()
101
-    {
102
-        $schema_map = array();
103
-        foreach ($this->mapping() as $map_model => $map_for_model) {
104
-            /**
105
-             * @var string $calculation_index
106
-             * @var string $calculations_class
107
-             */
108
-            foreach ($map_for_model as $calculation_index => $calculations_class) {
109
-                $calculator = $this->factory->createFromClassname($calculations_class);
110
-                $schema = call_user_func(array($calculator, 'schemaForCalculation'), $calculation_index);
111
-                if (! empty($schema)) {
112
-                    $schema_map[ $map_model ][ $calculation_index ] = $schema;
113
-                }
114
-            }
115
-        }
116
-        return $schema_map;
117
-    }
118
-
119
-
120
-    /**
121
-     * Gets the known calculated fields for model
122
-     *
123
-     * @param EEM_Base $model
124
-     * @return array allowable values for this field
125
-     */
126
-    public function retrieveCalculatedFieldsForModel(EEM_Base $model)
127
-    {
128
-        $mapping = $this->mapping();
129
-        if (isset($mapping[ $model->get_this_model_name() ])) {
130
-            return array_keys($mapping[ $model->get_this_model_name() ]);
131
-        }
132
-        return array();
133
-    }
134
-
135
-
136
-    /**
137
-     * Returns the JsonSchema for the calculated fields on the given model.
138
-     * @param EEM_Base $model
139
-     * @return array
140
-     */
141
-    public function getJsonSchemaForModel(EEM_Base $model)
142
-    {
143
-        if (! $this->mapping_schema) {
144
-            $this->mapping_schema = $this->generateNewMappingSchema();
145
-        }
146
-        return array(
147
-            'description' => esc_html__(
148
-                'Available calculated fields for this model.  Fields are only present in the response if explicitly requested',
149
-                'event_espresso'
150
-            ),
151
-            'type' => 'object',
152
-            'properties' => isset($this->mapping_schema[ $model->get_this_model_name() ])
153
-                ? $this->mapping_schema[ $model->get_this_model_name() ]
154
-                : array(),
155
-            'additionalProperties' => false,
156
-            'readonly' => true,
157
-        );
158
-    }
159
-
160
-
161
-    /**
162
-     * Retrieves the value for this calculation
163
-     *
164
-     * @param EEM_Base $model
165
-     * @param string $field_name
166
-     * @param array $wpdb_row
167
-     * @param $rest_request
168
-     * @param BaseController $controller
169
-     * @return mixed|null
170
-     * @throws RestException
171
-     * @throws UnexpectedEntityException
172
-     */
173
-    public function retrieveCalculatedFieldValue(
174
-        EEM_Base $model,
175
-        $field_name,
176
-        $wpdb_row,
177
-        $rest_request,
178
-        Base $controller
179
-    ) {
180
-        $mapping = $this->mapping();
181
-        if (isset($mapping[ $model->get_this_model_name() ])
182
-            && isset($mapping[ $model->get_this_model_name() ][ $field_name ])
183
-        ) {
184
-            $classname = $mapping[ $model->get_this_model_name() ][ $field_name ];
185
-            $calculator = $this->factory->createFromClassname($classname);
186
-            $class_method_name = EEH_Inflector::camelize_all_but_first($field_name);
187
-            return call_user_func(array($calculator, $class_method_name), $wpdb_row, $rest_request, $controller);
188
-        }
189
-        throw new RestException(
190
-            'calculated_field_does_not_exist',
191
-            sprintf(
192
-                __('There is no calculated field %1$s on resource %2$s', 'event_espresso'),
193
-                $field_name,
194
-                $model->get_this_model_name()
195
-            )
196
-        );
197
-    }
25
+	/**
26
+	 * @var array
27
+	 */
28
+	protected $mapping;
29
+
30
+	/**
31
+	 * @var array
32
+	 */
33
+	protected $mapping_schema;
34
+
35
+	/**
36
+	 * @var CalculatedModelFieldsFactory
37
+	 */
38
+	private $factory;
39
+
40
+	/**
41
+	 * CalculatedModelFields constructor.
42
+	 * @param CalculatedModelFieldsFactory $factory
43
+	 */
44
+	public function __construct(CalculatedModelFieldsFactory $factory)
45
+	{
46
+		$this->factory = $factory;
47
+	}
48
+	/**
49
+	 * @param bool $refresh
50
+	 * @return array top-level-keys are model names (eg "Event")
51
+	 * next-level are the calculated field names AND method names on classes
52
+	 * which perform calculations, values are the fully qualified classnames which do the calculations
53
+	 * These callbacks should accept as arguments:
54
+	 * the wpdb row results,
55
+	 * the WP_Request object,
56
+	 * the controller object
57
+	 */
58
+	public function mapping($refresh = false)
59
+	{
60
+		if (! $this->mapping || $refresh) {
61
+			$this->mapping = $this->generateNewMapping();
62
+		}
63
+		return $this->mapping;
64
+	}
65
+
66
+
67
+	/**
68
+	 * Generates a new mapping between model calculated fields and their callbacks
69
+	 *
70
+	 * @return array
71
+	 */
72
+	protected function generateNewMapping()
73
+	{
74
+		$mapping = array();
75
+		$models_with_calculated_fields = array(
76
+			'Attendee',
77
+			'Datetime',
78
+			'Event',
79
+			'Registration'
80
+		);
81
+		foreach ($models_with_calculated_fields as $model_name) {
82
+			$calculator = $this->factory->createFromModel($model_name);
83
+			foreach (array_keys(call_user_func(array($calculator, 'schemaForCalculations'))) as $field_name) {
84
+				$mapping[ $model_name ][ $field_name ] = get_class($calculator);
85
+			}
86
+		}
87
+		return apply_filters(
88
+			'FHEE__EventEspresso\core\libraries\rest_api\Calculated_Model_Fields__mapping',
89
+			$mapping
90
+		);
91
+	}
92
+
93
+
94
+	/**
95
+	 * Generates the schema for each calculation index in the calculation map.
96
+	 *
97
+	 * @return array
98
+	 * @throws UnexpectedEntityException
99
+	 */
100
+	protected function generateNewMappingSchema()
101
+	{
102
+		$schema_map = array();
103
+		foreach ($this->mapping() as $map_model => $map_for_model) {
104
+			/**
105
+			 * @var string $calculation_index
106
+			 * @var string $calculations_class
107
+			 */
108
+			foreach ($map_for_model as $calculation_index => $calculations_class) {
109
+				$calculator = $this->factory->createFromClassname($calculations_class);
110
+				$schema = call_user_func(array($calculator, 'schemaForCalculation'), $calculation_index);
111
+				if (! empty($schema)) {
112
+					$schema_map[ $map_model ][ $calculation_index ] = $schema;
113
+				}
114
+			}
115
+		}
116
+		return $schema_map;
117
+	}
118
+
119
+
120
+	/**
121
+	 * Gets the known calculated fields for model
122
+	 *
123
+	 * @param EEM_Base $model
124
+	 * @return array allowable values for this field
125
+	 */
126
+	public function retrieveCalculatedFieldsForModel(EEM_Base $model)
127
+	{
128
+		$mapping = $this->mapping();
129
+		if (isset($mapping[ $model->get_this_model_name() ])) {
130
+			return array_keys($mapping[ $model->get_this_model_name() ]);
131
+		}
132
+		return array();
133
+	}
134
+
135
+
136
+	/**
137
+	 * Returns the JsonSchema for the calculated fields on the given model.
138
+	 * @param EEM_Base $model
139
+	 * @return array
140
+	 */
141
+	public function getJsonSchemaForModel(EEM_Base $model)
142
+	{
143
+		if (! $this->mapping_schema) {
144
+			$this->mapping_schema = $this->generateNewMappingSchema();
145
+		}
146
+		return array(
147
+			'description' => esc_html__(
148
+				'Available calculated fields for this model.  Fields are only present in the response if explicitly requested',
149
+				'event_espresso'
150
+			),
151
+			'type' => 'object',
152
+			'properties' => isset($this->mapping_schema[ $model->get_this_model_name() ])
153
+				? $this->mapping_schema[ $model->get_this_model_name() ]
154
+				: array(),
155
+			'additionalProperties' => false,
156
+			'readonly' => true,
157
+		);
158
+	}
159
+
160
+
161
+	/**
162
+	 * Retrieves the value for this calculation
163
+	 *
164
+	 * @param EEM_Base $model
165
+	 * @param string $field_name
166
+	 * @param array $wpdb_row
167
+	 * @param $rest_request
168
+	 * @param BaseController $controller
169
+	 * @return mixed|null
170
+	 * @throws RestException
171
+	 * @throws UnexpectedEntityException
172
+	 */
173
+	public function retrieveCalculatedFieldValue(
174
+		EEM_Base $model,
175
+		$field_name,
176
+		$wpdb_row,
177
+		$rest_request,
178
+		Base $controller
179
+	) {
180
+		$mapping = $this->mapping();
181
+		if (isset($mapping[ $model->get_this_model_name() ])
182
+			&& isset($mapping[ $model->get_this_model_name() ][ $field_name ])
183
+		) {
184
+			$classname = $mapping[ $model->get_this_model_name() ][ $field_name ];
185
+			$calculator = $this->factory->createFromClassname($classname);
186
+			$class_method_name = EEH_Inflector::camelize_all_but_first($field_name);
187
+			return call_user_func(array($calculator, $class_method_name), $wpdb_row, $rest_request, $controller);
188
+		}
189
+		throw new RestException(
190
+			'calculated_field_does_not_exist',
191
+			sprintf(
192
+				__('There is no calculated field %1$s on resource %2$s', 'event_espresso'),
193
+				$field_name,
194
+				$model->get_this_model_name()
195
+			)
196
+		);
197
+	}
198 198
 }
Please login to merge, or discard this patch.
modules/core_rest_api/EED_Core_Rest_Api.module.php 1 patch
Indentation   +1221 added lines, -1221 removed lines patch added patch discarded remove patch
@@ -23,1225 +23,1225 @@
 block discarded – undo
23 23
 class EED_Core_Rest_Api extends \EED_Module
24 24
 {
25 25
 
26
-    const ee_api_namespace = Domain::API_NAMESPACE;
27
-
28
-    const ee_api_namespace_for_regex = 'ee\/v([^/]*)\/';
29
-
30
-    const saved_routes_option_names = 'ee_core_routes';
31
-
32
-    /**
33
-     * string used in _links response bodies to make them globally unique.
34
-     *
35
-     * @see http://v2.wp-api.org/extending/linking/
36
-     */
37
-    const ee_api_link_namespace = 'https://api.eventespresso.com/';
38
-
39
-    /**
40
-     * @var CalculatedModelFields
41
-     */
42
-    protected static $_field_calculator;
43
-
44
-
45
-    /**
46
-     * @return EED_Core_Rest_Api|EED_Module
47
-     */
48
-    public static function instance()
49
-    {
50
-        self::$_field_calculator = LoaderFactory::getLoader()->load('EventEspresso\core\libraries\rest_api\CalculatedModelFields');
51
-        return parent::get_instance(__CLASS__);
52
-    }
53
-
54
-
55
-    /**
56
-     *    set_hooks - for hooking into EE Core, other modules, etc
57
-     *
58
-     * @access    public
59
-     * @return    void
60
-     */
61
-    public static function set_hooks()
62
-    {
63
-        self::set_hooks_both();
64
-    }
65
-
66
-
67
-    /**
68
-     *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
69
-     *
70
-     * @access    public
71
-     * @return    void
72
-     */
73
-    public static function set_hooks_admin()
74
-    {
75
-        self::set_hooks_both();
76
-    }
77
-
78
-
79
-    public static function set_hooks_both()
80
-    {
81
-        add_action('rest_api_init', array('EED_Core_Rest_Api', 'register_routes'), 10);
82
-        add_action('rest_api_init', array('EED_Core_Rest_Api', 'set_hooks_rest_api'), 5);
83
-        add_filter('rest_route_data', array('EED_Core_Rest_Api', 'hide_old_endpoints'), 10, 2);
84
-        add_filter(
85
-            'rest_index',
86
-            array('EventEspresso\core\libraries\rest_api\controllers\model\Meta', 'filterEeMetadataIntoIndex')
87
-        );
88
-        EED_Core_Rest_Api::invalidate_cached_route_data_on_version_change();
89
-    }
90
-
91
-
92
-    /**
93
-     * sets up hooks which only need to be included as part of REST API requests;
94
-     * other requests like to the frontend or admin etc don't need them
95
-     *
96
-     * @throws \EE_Error
97
-     */
98
-    public static function set_hooks_rest_api()
99
-    {
100
-        // set hooks which account for changes made to the API
101
-        EED_Core_Rest_Api::_set_hooks_for_changes();
102
-    }
103
-
104
-
105
-    /**
106
-     * public wrapper of _set_hooks_for_changes.
107
-     * Loads all the hooks which make requests to old versions of the API
108
-     * appear the same as they always did
109
-     *
110
-     * @throws EE_Error
111
-     */
112
-    public static function set_hooks_for_changes()
113
-    {
114
-        self::_set_hooks_for_changes();
115
-    }
116
-
117
-
118
-    /**
119
-     * Loads all the hooks which make requests to old versions of the API
120
-     * appear the same as they always did
121
-     *
122
-     * @throws EE_Error
123
-     */
124
-    protected static function _set_hooks_for_changes()
125
-    {
126
-        $folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES . 'rest_api' . DS . 'changes'), false);
127
-        foreach ($folder_contents as $classname_in_namespace => $filepath) {
128
-            // ignore the base parent class
129
-            // and legacy named classes
130
-            if ($classname_in_namespace === 'ChangesInBase'
131
-                || strpos($classname_in_namespace, 'Changes_In_') === 0
132
-            ) {
133
-                continue;
134
-            }
135
-            $full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace;
136
-            if (class_exists($full_classname)) {
137
-                $instance_of_class = new $full_classname;
138
-                if ($instance_of_class instanceof ChangesInBase) {
139
-                    $instance_of_class->setHooks();
140
-                }
141
-            }
142
-        }
143
-    }
144
-
145
-
146
-    /**
147
-     * Filters the WP routes to add our EE-related ones. This takes a bit of time
148
-     * so we actually prefer to only do it when an EE plugin is activated or upgraded
149
-     *
150
-     * @throws \EE_Error
151
-     */
152
-    public static function register_routes()
153
-    {
154
-        foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_routes) {
155
-            foreach ($relative_routes as $relative_route => $data_for_multiple_endpoints) {
156
-                /**
157
-                 * @var array     $data_for_multiple_endpoints numerically indexed array
158
-                 *                                         but can also contain route options like {
159
-                 * @type array    $schema                      {
160
-                 * @type callable $schema_callback
161
-                 * @type array    $callback_args               arguments that will be passed to the callback, after the
162
-                 * WP_REST_Request of course
163
-                 * }
164
-                 * }
165
-                 */
166
-                // when registering routes, register all the endpoints' data at the same time
167
-                $multiple_endpoint_args = array();
168
-                foreach ($data_for_multiple_endpoints as $endpoint_key => $data_for_single_endpoint) {
169
-                    /**
170
-                     * @var array     $data_for_single_endpoint {
171
-                     * @type callable $callback
172
-                     * @type string methods
173
-                     * @type array args
174
-                     * @type array _links
175
-                     * @type array    $callback_args            arguments that will be passed to the callback, after the
176
-                     * WP_REST_Request of course
177
-                     * }
178
-                     */
179
-                    // skip route options
180
-                    if (! is_numeric($endpoint_key)) {
181
-                        continue;
182
-                    }
183
-                    if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
184
-                        throw new EE_Error(
185
-                            esc_html__(
186
-                            // @codingStandardsIgnoreStart
187
-                                'Endpoint configuration data needs to have entries "callback" (callable) and "methods" (comma-separated list of accepts HTTP methods).',
188
-                                // @codingStandardsIgnoreEnd
189
-                                'event_espresso'
190
-                            )
191
-                        );
192
-                    }
193
-                    $callback = $data_for_single_endpoint['callback'];
194
-                    $single_endpoint_args = array(
195
-                        'methods' => $data_for_single_endpoint['methods'],
196
-                        'args'    => isset($data_for_single_endpoint['args']) ? $data_for_single_endpoint['args']
197
-                            : array(),
198
-                    );
199
-                    if (isset($data_for_single_endpoint['_links'])) {
200
-                        $single_endpoint_args['_links'] = $data_for_single_endpoint['_links'];
201
-                    }
202
-                    if (isset($data_for_single_endpoint['callback_args'])) {
203
-                        $callback_args = $data_for_single_endpoint['callback_args'];
204
-                        $single_endpoint_args['callback'] = function (\WP_REST_Request $request) use (
205
-                            $callback,
206
-                            $callback_args
207
-                        ) {
208
-                            array_unshift($callback_args, $request);
209
-                            return call_user_func_array(
210
-                                $callback,
211
-                                $callback_args
212
-                            );
213
-                        };
214
-                    } else {
215
-                        $single_endpoint_args['callback'] = $data_for_single_endpoint['callback'];
216
-                    }
217
-                    $multiple_endpoint_args[] = $single_endpoint_args;
218
-                }
219
-                if (isset($data_for_multiple_endpoints['schema'])) {
220
-                    $schema_route_data = $data_for_multiple_endpoints['schema'];
221
-                    $schema_callback = $schema_route_data['schema_callback'];
222
-                    $callback_args = $schema_route_data['callback_args'];
223
-                    $multiple_endpoint_args['schema'] = function () use ($schema_callback, $callback_args) {
224
-                        return call_user_func_array(
225
-                            $schema_callback,
226
-                            $callback_args
227
-                        );
228
-                    };
229
-                }
230
-                register_rest_route(
231
-                    $namespace,
232
-                    $relative_route,
233
-                    $multiple_endpoint_args
234
-                );
235
-            }
236
-        }
237
-    }
238
-
239
-
240
-    /**
241
-     * Checks if there was a version change or something that merits invalidating the cached
242
-     * route data. If so, invalidates the cached route data so that it gets refreshed
243
-     * next time the WP API is used
244
-     */
245
-    public static function invalidate_cached_route_data_on_version_change()
246
-    {
247
-        if (EE_System::instance()->detect_req_type() !== EE_System::req_type_normal) {
248
-            EED_Core_Rest_Api::invalidate_cached_route_data();
249
-        }
250
-        foreach (EE_Registry::instance()->addons as $addon) {
251
-            if ($addon instanceof EE_Addon && $addon->detect_req_type() !== EE_System::req_type_normal) {
252
-                EED_Core_Rest_Api::invalidate_cached_route_data();
253
-            }
254
-        }
255
-    }
256
-
257
-
258
-    /**
259
-     * Removes the cached route data so it will get refreshed next time the WP API is used
260
-     */
261
-    public static function invalidate_cached_route_data()
262
-    {
263
-        // delete the saved EE REST API routes
264
-        foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) {
265
-            delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version);
266
-        }
267
-    }
268
-
269
-
270
-    /**
271
-     * Gets the EE route data
272
-     *
273
-     * @return array top-level key is the namespace, next-level key is the route and its value is array{
274
-     * @throws \EE_Error
275
-     * @type string|array $callback
276
-     * @type string       $methods
277
-     * @type boolean      $hidden_endpoint
278
-     * }
279
-     */
280
-    public static function get_ee_route_data()
281
-    {
282
-        $ee_routes = array();
283
-        foreach (self::versions_served() as $version => $hidden_endpoints) {
284
-            $ee_routes[ self::ee_api_namespace . $version ] = self::_get_ee_route_data_for_version(
285
-                $version,
286
-                $hidden_endpoints
287
-            );
288
-        }
289
-        return $ee_routes;
290
-    }
291
-
292
-
293
-    /**
294
-     * Gets the EE route data from the wp options if it exists already,
295
-     * otherwise re-generates it and saves it to the option
296
-     *
297
-     * @param string  $version
298
-     * @param boolean $hidden_endpoints
299
-     * @return array
300
-     * @throws \EE_Error
301
-     */
302
-    protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false)
303
-    {
304
-        $ee_routes = get_option(self::saved_routes_option_names . $version, null);
305
-        if (! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) {
306
-            $ee_routes = self::_save_ee_route_data_for_version($version, $hidden_endpoints);
307
-        }
308
-        return $ee_routes;
309
-    }
310
-
311
-
312
-    /**
313
-     * Saves the EE REST API route data to a wp option and returns it
314
-     *
315
-     * @param string  $version
316
-     * @param boolean $hidden_endpoints
317
-     * @return mixed|null
318
-     * @throws \EE_Error
319
-     */
320
-    protected static function _save_ee_route_data_for_version($version, $hidden_endpoints = false)
321
-    {
322
-        $instance = self::instance();
323
-        $routes = apply_filters(
324
-            'EED_Core_Rest_Api__save_ee_route_data_for_version__routes',
325
-            array_replace_recursive(
326
-                $instance->_get_config_route_data_for_version($version, $hidden_endpoints),
327
-                $instance->_get_meta_route_data_for_version($version, $hidden_endpoints),
328
-                $instance->_get_model_route_data_for_version($version, $hidden_endpoints),
329
-                $instance->_get_rpc_route_data_for_version($version, $hidden_endpoints)
330
-            )
331
-        );
332
-        $option_name = self::saved_routes_option_names . $version;
333
-        if (get_option($option_name)) {
334
-            update_option($option_name, $routes, true);
335
-        } else {
336
-            add_option($option_name, $routes, null, 'no');
337
-        }
338
-        return $routes;
339
-    }
340
-
341
-
342
-    /**
343
-     * Calculates all the EE routes and saves it to a WordPress option so we don't
344
-     * need to calculate it on every request
345
-     *
346
-     * @deprecated since version 4.9.1
347
-     * @return void
348
-     */
349
-    public static function save_ee_routes()
350
-    {
351
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
352
-            $instance = self::instance();
353
-            $routes = apply_filters(
354
-                'EED_Core_Rest_Api__save_ee_routes__routes',
355
-                array_replace_recursive(
356
-                    $instance->_register_config_routes(),
357
-                    $instance->_register_meta_routes(),
358
-                    $instance->_register_model_routes(),
359
-                    $instance->_register_rpc_routes()
360
-                )
361
-            );
362
-            update_option(self::saved_routes_option_names, $routes, true);
363
-        }
364
-    }
365
-
366
-
367
-    /**
368
-     * Gets all the route information relating to EE models
369
-     *
370
-     * @return array @see get_ee_route_data
371
-     * @deprecated since version 4.9.1
372
-     */
373
-    protected function _register_model_routes()
374
-    {
375
-        $model_routes = array();
376
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
377
-            $model_routes[ EED_Core_Rest_Api::ee_api_namespace
378
-                           . $version ] = $this->_get_config_route_data_for_version($version, $hidden_endpoint);
379
-        }
380
-        return $model_routes;
381
-    }
382
-
383
-
384
-    /**
385
-     * Decides whether or not to add write endpoints for this model.
386
-     *
387
-     * Currently, this defaults to exclude all global tables and models
388
-     * which would allow inserting WP core data (we don't want to duplicate
389
-     * what WP API does, as it's unnecessary, extra work, and potentially extra bugs)
390
-     *
391
-     * @param EEM_Base $model
392
-     * @return bool
393
-     */
394
-    public static function should_have_write_endpoints(EEM_Base $model)
395
-    {
396
-        if ($model->is_wp_core_model()) {
397
-            return false;
398
-        }
399
-        foreach ($model->get_tables() as $table) {
400
-            if ($table->is_global()) {
401
-                return false;
402
-            }
403
-        }
404
-        return true;
405
-    }
406
-
407
-
408
-    /**
409
-     * Gets the names of all models which should have plural routes (eg `ee/v4.8.36/events`)
410
-     * in this versioned namespace of EE4
411
-     *
412
-     * @param $version
413
-     * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event')
414
-     */
415
-    public static function model_names_with_plural_routes($version)
416
-    {
417
-        $model_version_info = new ModelVersionInfo($version);
418
-        $models_to_register = $model_version_info->modelsForRequestedVersion();
419
-        // let's not bother having endpoints for extra metas
420
-        unset(
421
-            $models_to_register['Extra_Meta'],
422
-            $models_to_register['Extra_Join'],
423
-            $models_to_register['Post_Meta']
424
-        );
425
-        return apply_filters(
426
-            'FHEE__EED_Core_REST_API___register_model_routes',
427
-            $models_to_register
428
-        );
429
-    }
430
-
431
-
432
-    /**
433
-     * Gets the route data for EE models in the specified version
434
-     *
435
-     * @param string  $version
436
-     * @param boolean $hidden_endpoint
437
-     * @return array
438
-     * @throws EE_Error
439
-     */
440
-    protected function _get_model_route_data_for_version($version, $hidden_endpoint = false)
441
-    {
442
-        $model_routes = array();
443
-        $model_version_info = new ModelVersionInfo($version);
444
-        foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) {
445
-            $model = \EE_Registry::instance()->load_model($model_name);
446
-            // if this isn't a valid model then let's skip iterate to the next item in the loop.
447
-            if (! $model instanceof EEM_Base) {
448
-                continue;
449
-            }
450
-            // yes we could just register one route for ALL models, but then they wouldn't show up in the index
451
-            $plural_model_route = EED_Core_Rest_Api::get_collection_route($model);
452
-            $singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)');
453
-            $model_routes[ $plural_model_route ] = array(
454
-                array(
455
-                    'callback'        => array(
456
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
457
-                        'handleRequestGetAll',
458
-                    ),
459
-                    'callback_args'   => array($version, $model_name),
460
-                    'methods'         => WP_REST_Server::READABLE,
461
-                    'hidden_endpoint' => $hidden_endpoint,
462
-                    'args'            => $this->_get_read_query_params($model, $version),
463
-                    '_links'          => array(
464
-                        'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route),
465
-                    ),
466
-                ),
467
-                'schema' => array(
468
-                    'schema_callback' => array(
469
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
470
-                        'handleSchemaRequest',
471
-                    ),
472
-                    'callback_args'   => array($version, $model_name),
473
-                ),
474
-            );
475
-            $model_routes[ $singular_model_route ] = array(
476
-                array(
477
-                    'callback'        => array(
478
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
479
-                        'handleRequestGetOne',
480
-                    ),
481
-                    'callback_args'   => array($version, $model_name),
482
-                    'methods'         => WP_REST_Server::READABLE,
483
-                    'hidden_endpoint' => $hidden_endpoint,
484
-                    'args'            => $this->_get_response_selection_query_params($model, $version),
485
-                ),
486
-            );
487
-            if (apply_filters(
488
-                'FHEE__EED_Core_Rest_Api___get_model_route_data_for_version__add_write_endpoints',
489
-                EED_Core_Rest_Api::should_have_write_endpoints($model),
490
-                $model
491
-            )) {
492
-                $model_routes[ $plural_model_route ][] = array(
493
-                    'callback'        => array(
494
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Write',
495
-                        'handleRequestInsert',
496
-                    ),
497
-                    'callback_args'   => array($version, $model_name),
498
-                    'methods'         => WP_REST_Server::CREATABLE,
499
-                    'hidden_endpoint' => $hidden_endpoint,
500
-                    'args'            => $this->_get_write_params($model_name, $model_version_info, true),
501
-                );
502
-                $model_routes[ $singular_model_route ] = array_merge(
503
-                    $model_routes[ $singular_model_route ],
504
-                    array(
505
-                        array(
506
-                            'callback'        => array(
507
-                                'EventEspresso\core\libraries\rest_api\controllers\model\Write',
508
-                                'handleRequestUpdate',
509
-                            ),
510
-                            'callback_args'   => array($version, $model_name),
511
-                            'methods'         => WP_REST_Server::EDITABLE,
512
-                            'hidden_endpoint' => $hidden_endpoint,
513
-                            'args'            => $this->_get_write_params($model_name, $model_version_info),
514
-                        ),
515
-                        array(
516
-                            'callback'        => array(
517
-                                'EventEspresso\core\libraries\rest_api\controllers\model\Write',
518
-                                'handleRequestDelete',
519
-                            ),
520
-                            'callback_args'   => array($version, $model_name),
521
-                            'methods'         => WP_REST_Server::DELETABLE,
522
-                            'hidden_endpoint' => $hidden_endpoint,
523
-                            'args'            => $this->_get_delete_query_params($model, $version),
524
-                        ),
525
-                    )
526
-                );
527
-            }
528
-            foreach ($model->relation_settings() as $relation_name => $relation_obj) {
529
-                $related_route = EED_Core_Rest_Api::get_relation_route_via(
530
-                    $model,
531
-                    '(?P<id>[^\/]+)',
532
-                    $relation_obj
533
-                );
534
-                $endpoints = array(
535
-                    array(
536
-                        'callback'        => array(
537
-                            'EventEspresso\core\libraries\rest_api\controllers\model\Read',
538
-                            'handleRequestGetRelated',
539
-                        ),
540
-                        'callback_args'   => array($version, $model_name, $relation_name),
541
-                        'methods'         => WP_REST_Server::READABLE,
542
-                        'hidden_endpoint' => $hidden_endpoint,
543
-                        'args'            => $this->_get_read_query_params($relation_obj->get_other_model(), $version),
544
-                    ),
545
-                );
546
-                $model_routes[ $related_route ] = $endpoints;
547
-            }
548
-        }
549
-        return $model_routes;
550
-    }
551
-
552
-
553
-    /**
554
-     * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace,
555
-     * excluding the preceding slash.
556
-     * Eg you pass get_plural_route_to('Event') = 'events'
557
-     *
558
-     * @param EEM_Base $model
559
-     * @return string
560
-     */
561
-    public static function get_collection_route(EEM_Base $model)
562
-    {
563
-        return EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
564
-    }
565
-
566
-
567
-    /**
568
-     * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
569
-     * excluding the preceding slash.
570
-     * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
571
-     *
572
-     * @param EEM_Base $model eg Event or Venue
573
-     * @param string   $id
574
-     * @return string
575
-     */
576
-    public static function get_entity_route($model, $id)
577
-    {
578
-        return EED_Core_Rest_Api::get_collection_route($model) . '/' . $id;
579
-    }
580
-
581
-
582
-    /**
583
-     * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
584
-     * excluding the preceding slash.
585
-     * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
586
-     *
587
-     * @param EEM_Base               $model eg Event or Venue
588
-     * @param string                 $id
589
-     * @param EE_Model_Relation_Base $relation_obj
590
-     * @return string
591
-     */
592
-    public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj)
593
-    {
594
-        $related_model_name_endpoint_part = ModelRead::getRelatedEntityName(
595
-            $relation_obj->get_other_model()->get_this_model_name(),
596
-            $relation_obj
597
-        );
598
-        return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
599
-    }
600
-
601
-
602
-    /**
603
-     * Adds onto the $relative_route the EE4 REST API versioned namespace.
604
-     * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events'
605
-     *
606
-     * @param string $relative_route
607
-     * @param string $version
608
-     * @return string
609
-     */
610
-    public static function get_versioned_route_to($relative_route, $version = '4.8.36')
611
-    {
612
-        return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
613
-    }
614
-
615
-
616
-    /**
617
-     * Adds all the RPC-style routes (remote procedure call-like routes, ie
618
-     * routes that don't conform to the traditional REST CRUD-style).
619
-     *
620
-     * @deprecated since 4.9.1
621
-     */
622
-    protected function _register_rpc_routes()
623
-    {
624
-        $routes = array();
625
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
626
-            $routes[ self::ee_api_namespace . $version ] = $this->_get_rpc_route_data_for_version(
627
-                $version,
628
-                $hidden_endpoint
629
-            );
630
-        }
631
-        return $routes;
632
-    }
633
-
634
-
635
-    /**
636
-     * @param string  $version
637
-     * @param boolean $hidden_endpoint
638
-     * @return array
639
-     */
640
-    protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false)
641
-    {
642
-        $this_versions_routes = array();
643
-        // checkin endpoint
644
-        $this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = array(
645
-            array(
646
-                'callback'        => array(
647
-                    'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin',
648
-                    'handleRequestToggleCheckin',
649
-                ),
650
-                'methods'         => WP_REST_Server::CREATABLE,
651
-                'hidden_endpoint' => $hidden_endpoint,
652
-                'args'            => array(
653
-                    'force' => array(
654
-                        'required'    => false,
655
-                        'default'     => false,
656
-                        'description' => __(
657
-                        // @codingStandardsIgnoreStart
658
-                            'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses',
659
-                            // @codingStandardsIgnoreEnd
660
-                            'event_espresso'
661
-                        ),
662
-                    ),
663
-                ),
664
-                'callback_args'   => array($version),
665
-            ),
666
-        );
667
-        return apply_filters(
668
-            'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes',
669
-            $this_versions_routes,
670
-            $version,
671
-            $hidden_endpoint
672
-        );
673
-    }
674
-
675
-
676
-    /**
677
-     * Gets the query params that can be used when request one or many
678
-     *
679
-     * @param EEM_Base $model
680
-     * @param string   $version
681
-     * @return array
682
-     */
683
-    protected function _get_response_selection_query_params(\EEM_Base $model, $version)
684
-    {
685
-        return apply_filters(
686
-            'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
687
-            array(
688
-                'include'   => array(
689
-                    'required' => false,
690
-                    'default'  => '*',
691
-                    'type'     => 'string',
692
-                ),
693
-                'calculate' => array(
694
-                    'required'          => false,
695
-                    'default'           => '',
696
-                    'enum'              => self::$_field_calculator->retrieveCalculatedFieldsForModel($model),
697
-                    'type'              => 'string',
698
-                    // because we accept a CSV'd list of the enumerated strings, WP core validation and sanitization
699
-                    // freaks out. We'll just validate this argument while handling the request
700
-                    'validate_callback' => null,
701
-                    'sanitize_callback' => null,
702
-                ),
703
-            ),
704
-            $model,
705
-            $version
706
-        );
707
-    }
708
-
709
-
710
-    /**
711
-     * Gets the parameters acceptable for delete requests
712
-     *
713
-     * @param \EEM_Base $model
714
-     * @param string    $version
715
-     * @return array
716
-     */
717
-    protected function _get_delete_query_params(\EEM_Base $model, $version)
718
-    {
719
-        $params_for_delete = array(
720
-            'allow_blocking' => array(
721
-                'required' => false,
722
-                'default'  => true,
723
-                'type'     => 'boolean',
724
-            ),
725
-        );
726
-        $params_for_delete['force'] = array(
727
-            'required' => false,
728
-            'default'  => false,
729
-            'type'     => 'boolean',
730
-        );
731
-        return apply_filters(
732
-            'FHEE__EED_Core_Rest_Api___get_delete_query_params',
733
-            $params_for_delete,
734
-            $model,
735
-            $version
736
-        );
737
-    }
738
-
739
-
740
-    /**
741
-     * Gets info about reading query params that are acceptable
742
-     *
743
-     * @param \EEM_Base $model eg 'Event' or 'Venue'
744
-     * @param  string   $version
745
-     * @return array    describing the args acceptable when querying this model
746
-     * @throws EE_Error
747
-     */
748
-    protected function _get_read_query_params(\EEM_Base $model, $version)
749
-    {
750
-        $default_orderby = array();
751
-        foreach ($model->get_combined_primary_key_fields() as $key_field) {
752
-            $default_orderby[ $key_field->get_name() ] = 'ASC';
753
-        }
754
-        return array_merge(
755
-            $this->_get_response_selection_query_params($model, $version),
756
-            array(
757
-                'where'    => array(
758
-                    'required'          => false,
759
-                    'default'           => array(),
760
-                    'type'              => 'object',
761
-                    // because we accept an almost infinite list of possible where conditions, WP
762
-                    // core validation and sanitization freaks out. We'll just validate this argument
763
-                    // while handling the request
764
-                    'validate_callback' => null,
765
-                    'sanitize_callback' => null,
766
-                ),
767
-                'limit'    => array(
768
-                    'required'          => false,
769
-                    'default'           => EED_Core_Rest_Api::get_default_query_limit(),
770
-                    'type'              => array(
771
-                        'array',
772
-                        'string',
773
-                        'integer',
774
-                    ),
775
-                    // because we accept a variety of types, WP core validation and sanitization
776
-                    // freaks out. We'll just validate this argument while handling the request
777
-                    'validate_callback' => null,
778
-                    'sanitize_callback' => null,
779
-                ),
780
-                'order_by' => array(
781
-                    'required'          => false,
782
-                    'default'           => $default_orderby,
783
-                    'type'              => array(
784
-                        'object',
785
-                        'string',
786
-                    ),// because we accept a variety of types, WP core validation and sanitization
787
-                    // freaks out. We'll just validate this argument while handling the request
788
-                    'validate_callback' => null,
789
-                    'sanitize_callback' => null,
790
-                ),
791
-                'group_by' => array(
792
-                    'required'          => false,
793
-                    'default'           => null,
794
-                    'type'              => array(
795
-                        'object',
796
-                        'string',
797
-                    ),
798
-                    // because we accept  an almost infinite list of possible groupings,
799
-                    // WP core validation and sanitization
800
-                    // freaks out. We'll just validate this argument while handling the request
801
-                    'validate_callback' => null,
802
-                    'sanitize_callback' => null,
803
-                ),
804
-                'having'   => array(
805
-                    'required'          => false,
806
-                    'default'           => null,
807
-                    'type'              => 'object',
808
-                    // because we accept an almost infinite list of possible where conditions, WP
809
-                    // core validation and sanitization freaks out. We'll just validate this argument
810
-                    // while handling the request
811
-                    'validate_callback' => null,
812
-                    'sanitize_callback' => null,
813
-                ),
814
-                'caps'     => array(
815
-                    'required' => false,
816
-                    'default'  => EEM_Base::caps_read,
817
-                    'type'     => 'string',
818
-                    'enum'     => array(
819
-                        EEM_Base::caps_read,
820
-                        EEM_Base::caps_read_admin,
821
-                        EEM_Base::caps_edit,
822
-                        EEM_Base::caps_delete,
823
-                    ),
824
-                ),
825
-            )
826
-        );
827
-    }
828
-
829
-
830
-    /**
831
-     * Gets parameter information for a model regarding writing data
832
-     *
833
-     * @param string           $model_name
834
-     * @param ModelVersionInfo $model_version_info
835
-     * @param boolean          $create                                       whether this is for request to create (in
836
-     *                                                                       which case we need all required params) or
837
-     *                                                                       just to update (in which case we don't
838
-     *                                                                       need those on every request)
839
-     * @return array
840
-     */
841
-    protected function _get_write_params(
842
-        $model_name,
843
-        ModelVersionInfo $model_version_info,
844
-        $create = false
845
-    ) {
846
-        $model = EE_Registry::instance()->load_model($model_name);
847
-        $fields = $model_version_info->fieldsOnModelInThisVersion($model);
848
-        $args_info = array();
849
-        foreach ($fields as $field_name => $field_obj) {
850
-            if ($field_obj->is_auto_increment()) {
851
-                // totally ignore auto increment IDs
852
-                continue;
853
-            }
854
-            $arg_info = $field_obj->getSchema();
855
-            $required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null;
856
-            $arg_info['required'] = $required;
857
-            // remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right?
858
-            unset($arg_info['readonly']);
859
-            $schema_properties = $field_obj->getSchemaProperties();
860
-            if (isset($schema_properties['raw'])
861
-                && $field_obj->getSchemaType() === 'object'
862
-            ) {
863
-                // if there's a "raw" form of this argument, use those properties instead
864
-                $arg_info = array_replace(
865
-                    $arg_info,
866
-                    $schema_properties['raw']
867
-                );
868
-            }
869
-            $arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson(
870
-                $field_obj,
871
-                $field_obj->get_default_value(),
872
-                $model_version_info->requestedVersion()
873
-            );
874
-            // we do our own validation and sanitization within the controller
875
-            if (function_exists('rest_validate_value_from_schema')) {
876
-                $sanitize_callback = array(
877
-                    'EED_Core_Rest_Api',
878
-                    'default_sanitize_callback',
879
-                );
880
-            } else {
881
-                $sanitize_callback = null;
882
-            }
883
-            $arg_info['sanitize_callback'] = $sanitize_callback;
884
-            $args_info[ $field_name ] = $arg_info;
885
-            if ($field_obj instanceof EE_Datetime_Field) {
886
-                $gmt_arg_info = $arg_info;
887
-                $gmt_arg_info['description'] = sprintf(
888
-                    esc_html__(
889
-                        '%1$s - the value for this field in UTC. Ignored if %2$s is provided.',
890
-                        'event_espresso'
891
-                    ),
892
-                    $field_obj->get_nicename(),
893
-                    $field_name
894
-                );
895
-                $args_info[ $field_name . '_gmt' ] = $gmt_arg_info;
896
-            }
897
-        }
898
-        return $args_info;
899
-    }
900
-
901
-
902
-    /**
903
-     * Replacement for WP API's 'rest_parse_request_arg'.
904
-     * If the value is blank but not required, don't bother validating it.
905
-     * Also, it uses our email validation instead of WP API's default.
906
-     *
907
-     * @param                 $value
908
-     * @param WP_REST_Request $request
909
-     * @param                 $param
910
-     * @return bool|true|WP_Error
911
-     * @throws InvalidArgumentException
912
-     * @throws InvalidInterfaceException
913
-     * @throws InvalidDataTypeException
914
-     */
915
-    public static function default_sanitize_callback($value, WP_REST_Request $request, $param)
916
-    {
917
-        $attributes = $request->get_attributes();
918
-        if (! isset($attributes['args'][ $param ])
919
-            || ! is_array($attributes['args'][ $param ])) {
920
-            $validation_result = true;
921
-        } else {
922
-            $args = $attributes['args'][ $param ];
923
-            if ((
924
-                    $value === ''
925
-                    || $value === null
926
-                )
927
-                && (! isset($args['required'])
928
-                    || $args['required'] === false
929
-                )
930
-            ) {
931
-                // not required and not provided? that's cool
932
-                $validation_result = true;
933
-            } elseif (isset($args['format'])
934
-                      && $args['format'] === 'email'
935
-            ) {
936
-                $validation_result = true;
937
-                if (! self::_validate_email($value)) {
938
-                    $validation_result = new WP_Error(
939
-                        'rest_invalid_param',
940
-                        esc_html__(
941
-                            'The email address is not valid or does not exist.',
942
-                            'event_espresso'
943
-                        )
944
-                    );
945
-                }
946
-            } else {
947
-                $validation_result = rest_validate_value_from_schema($value, $args, $param);
948
-            }
949
-        }
950
-        if (is_wp_error($validation_result)) {
951
-            return $validation_result;
952
-        }
953
-        return rest_sanitize_request_arg($value, $request, $param);
954
-    }
955
-
956
-
957
-    /**
958
-     * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email()
959
-     *
960
-     * @param $email
961
-     * @return bool
962
-     * @throws InvalidArgumentException
963
-     * @throws InvalidInterfaceException
964
-     * @throws InvalidDataTypeException
965
-     */
966
-    protected static function _validate_email($email)
967
-    {
968
-        try {
969
-            EmailAddressFactory::create($email);
970
-            return true;
971
-        } catch (EmailValidationException $e) {
972
-            return false;
973
-        }
974
-    }
975
-
976
-
977
-    /**
978
-     * Gets routes for the config
979
-     *
980
-     * @return array @see _register_model_routes
981
-     * @deprecated since version 4.9.1
982
-     */
983
-    protected function _register_config_routes()
984
-    {
985
-        $config_routes = array();
986
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
987
-            $config_routes[ self::ee_api_namespace . $version ] = $this->_get_config_route_data_for_version(
988
-                $version,
989
-                $hidden_endpoint
990
-            );
991
-        }
992
-        return $config_routes;
993
-    }
994
-
995
-
996
-    /**
997
-     * Gets routes for the config for the specified version
998
-     *
999
-     * @param string  $version
1000
-     * @param boolean $hidden_endpoint
1001
-     * @return array
1002
-     */
1003
-    protected function _get_config_route_data_for_version($version, $hidden_endpoint)
1004
-    {
1005
-        return array(
1006
-            'config'    => array(
1007
-                array(
1008
-                    'callback'        => array(
1009
-                        'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1010
-                        'handleRequest',
1011
-                    ),
1012
-                    'methods'         => WP_REST_Server::READABLE,
1013
-                    'hidden_endpoint' => $hidden_endpoint,
1014
-                    'callback_args'   => array($version),
1015
-                ),
1016
-            ),
1017
-            'site_info' => array(
1018
-                array(
1019
-                    'callback'        => array(
1020
-                        'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1021
-                        'handleRequestSiteInfo',
1022
-                    ),
1023
-                    'methods'         => WP_REST_Server::READABLE,
1024
-                    'hidden_endpoint' => $hidden_endpoint,
1025
-                    'callback_args'   => array($version),
1026
-                ),
1027
-            ),
1028
-        );
1029
-    }
1030
-
1031
-
1032
-    /**
1033
-     * Gets the meta info routes
1034
-     *
1035
-     * @return array @see _register_model_routes
1036
-     * @deprecated since version 4.9.1
1037
-     */
1038
-    protected function _register_meta_routes()
1039
-    {
1040
-        $meta_routes = array();
1041
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
1042
-            $meta_routes[ self::ee_api_namespace . $version ] = $this->_get_meta_route_data_for_version(
1043
-                $version,
1044
-                $hidden_endpoint
1045
-            );
1046
-        }
1047
-        return $meta_routes;
1048
-    }
1049
-
1050
-
1051
-    /**
1052
-     * @param string  $version
1053
-     * @param boolean $hidden_endpoint
1054
-     * @return array
1055
-     */
1056
-    protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false)
1057
-    {
1058
-        return array(
1059
-            'resources' => array(
1060
-                array(
1061
-                    'callback'        => array(
1062
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Meta',
1063
-                        'handleRequestModelsMeta',
1064
-                    ),
1065
-                    'methods'         => WP_REST_Server::READABLE,
1066
-                    'hidden_endpoint' => $hidden_endpoint,
1067
-                    'callback_args'   => array($version),
1068
-                ),
1069
-            ),
1070
-        );
1071
-    }
1072
-
1073
-
1074
-    /**
1075
-     * Tries to hide old 4.6 endpoints from the
1076
-     *
1077
-     * @param array $route_data
1078
-     * @return array
1079
-     * @throws \EE_Error
1080
-     */
1081
-    public static function hide_old_endpoints($route_data)
1082
-    {
1083
-        // allow API clients to override which endpoints get hidden, in case
1084
-        // they want to discover particular endpoints
1085
-        // also, we don't have access to the request so we have to just grab it from the superglobal
1086
-        $force_show_ee_namespace = ltrim(
1087
-            EEH_Array::is_set($_REQUEST, 'force_show_ee_namespace', ''),
1088
-            '/'
1089
-        );
1090
-        foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) {
1091
-            foreach ($relative_urls as $resource_name => $endpoints) {
1092
-                foreach ($endpoints as $key => $endpoint) {
1093
-                    // skip schema and other route options
1094
-                    if (! is_numeric($key)) {
1095
-                        continue;
1096
-                    }
1097
-                    // by default, hide "hidden_endpoint"s, unless the request indicates
1098
-                    // to $force_show_ee_namespace, in which case only show that one
1099
-                    // namespace's endpoints (and hide all others)
1100
-                    if (($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1101
-                        || ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1102
-                    ) {
1103
-                        $full_route = '/' . ltrim($namespace, '/');
1104
-                        $full_route .= '/' . ltrim($resource_name, '/');
1105
-                        unset($route_data[ $full_route ]);
1106
-                    }
1107
-                }
1108
-            }
1109
-        }
1110
-        return $route_data;
1111
-    }
1112
-
1113
-
1114
-    /**
1115
-     * Returns an array describing which versions of core support serving requests for.
1116
-     * Keys are core versions' major and minor version, and values are the
1117
-     * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like
1118
-     * data by just removing a few models and fields from the responses. However, 4.15 might remove
1119
-     * the answers table entirely, in which case it would be very difficult for
1120
-     * it to serve 4.6-style responses.
1121
-     * Versions of core that are missing from this array are unknowns.
1122
-     * previous ver
1123
-     *
1124
-     * @return array
1125
-     */
1126
-    public static function version_compatibilities()
1127
-    {
1128
-        return apply_filters(
1129
-            'FHEE__EED_Core_REST_API__version_compatibilities',
1130
-            array(
1131
-                '4.8.29' => '4.8.29',
1132
-                '4.8.33' => '4.8.29',
1133
-                '4.8.34' => '4.8.29',
1134
-                '4.8.36' => '4.8.29',
1135
-            )
1136
-        );
1137
-    }
1138
-
1139
-
1140
-    /**
1141
-     * Gets the latest API version served. Eg if there
1142
-     * are two versions served of the API, 4.8.29 and 4.8.32, and
1143
-     * we are on core version 4.8.34, it will return the string "4.8.32"
1144
-     *
1145
-     * @return string
1146
-     */
1147
-    public static function latest_rest_api_version()
1148
-    {
1149
-        $versions_served = \EED_Core_Rest_Api::versions_served();
1150
-        $versions_served_keys = array_keys($versions_served);
1151
-        return end($versions_served_keys);
1152
-    }
1153
-
1154
-
1155
-    /**
1156
-     * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of
1157
-     * EE the API can serve requests for. Eg, if we are on 4.15 of core, and
1158
-     * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ).
1159
-     * We also indicate whether or not this version should be put in the index or not
1160
-     *
1161
-     * @return array keys are API version numbers (just major and minor numbers), and values
1162
-     * are whether or not they should be hidden
1163
-     */
1164
-    public static function versions_served()
1165
-    {
1166
-        $versions_served = array();
1167
-        $possibly_served_versions = EED_Core_Rest_Api::version_compatibilities();
1168
-        $lowest_compatible_version = end($possibly_served_versions);
1169
-        reset($possibly_served_versions);
1170
-        $versions_served_historically = array_keys($possibly_served_versions);
1171
-        $latest_version = end($versions_served_historically);
1172
-        reset($versions_served_historically);
1173
-        // for each version of core we have ever served:
1174
-        foreach ($versions_served_historically as $key_versioned_endpoint) {
1175
-            // if it's not above the current core version, and it's compatible with the current version of core
1176
-            if ($key_versioned_endpoint === $latest_version) {
1177
-                // don't hide the latest version in the index
1178
-                $versions_served[ $key_versioned_endpoint ] = false;
1179
-            } elseif ($key_versioned_endpoint >= $lowest_compatible_version
1180
-                && $key_versioned_endpoint < EED_Core_Rest_Api::core_version()
1181
-            ) {
1182
-                // include, but hide, previous versions which are still supported
1183
-                $versions_served[ $key_versioned_endpoint ] = true;
1184
-            } elseif (apply_filters(
1185
-                'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions',
1186
-                false,
1187
-                $possibly_served_versions
1188
-            )) {
1189
-                // if a version is no longer supported, don't include it in index or list of versions served
1190
-                $versions_served[ $key_versioned_endpoint ] = true;
1191
-            }
1192
-        }
1193
-        return $versions_served;
1194
-    }
1195
-
1196
-
1197
-    /**
1198
-     * Gets the major and minor version of EE core's version string
1199
-     *
1200
-     * @return string
1201
-     */
1202
-    public static function core_version()
1203
-    {
1204
-        return apply_filters(
1205
-            'FHEE__EED_Core_REST_API__core_version',
1206
-            implode(
1207
-                '.',
1208
-                array_slice(
1209
-                    explode(
1210
-                        '.',
1211
-                        espresso_version()
1212
-                    ),
1213
-                    0,
1214
-                    3
1215
-                )
1216
-            )
1217
-        );
1218
-    }
1219
-
1220
-
1221
-    /**
1222
-     * Gets the default limit that should be used when querying for resources
1223
-     *
1224
-     * @return int
1225
-     */
1226
-    public static function get_default_query_limit()
1227
-    {
1228
-        // we actually don't use a const because we want folks to always use
1229
-        // this method, not the const directly
1230
-        return apply_filters(
1231
-            'FHEE__EED_Core_Rest_Api__get_default_query_limit',
1232
-            50
1233
-        );
1234
-    }
1235
-
1236
-
1237
-    /**
1238
-     *    run - initial module setup
1239
-     *
1240
-     * @access    public
1241
-     * @param  WP $WP
1242
-     * @return    void
1243
-     */
1244
-    public function run($WP)
1245
-    {
1246
-    }
26
+	const ee_api_namespace = Domain::API_NAMESPACE;
27
+
28
+	const ee_api_namespace_for_regex = 'ee\/v([^/]*)\/';
29
+
30
+	const saved_routes_option_names = 'ee_core_routes';
31
+
32
+	/**
33
+	 * string used in _links response bodies to make them globally unique.
34
+	 *
35
+	 * @see http://v2.wp-api.org/extending/linking/
36
+	 */
37
+	const ee_api_link_namespace = 'https://api.eventespresso.com/';
38
+
39
+	/**
40
+	 * @var CalculatedModelFields
41
+	 */
42
+	protected static $_field_calculator;
43
+
44
+
45
+	/**
46
+	 * @return EED_Core_Rest_Api|EED_Module
47
+	 */
48
+	public static function instance()
49
+	{
50
+		self::$_field_calculator = LoaderFactory::getLoader()->load('EventEspresso\core\libraries\rest_api\CalculatedModelFields');
51
+		return parent::get_instance(__CLASS__);
52
+	}
53
+
54
+
55
+	/**
56
+	 *    set_hooks - for hooking into EE Core, other modules, etc
57
+	 *
58
+	 * @access    public
59
+	 * @return    void
60
+	 */
61
+	public static function set_hooks()
62
+	{
63
+		self::set_hooks_both();
64
+	}
65
+
66
+
67
+	/**
68
+	 *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
69
+	 *
70
+	 * @access    public
71
+	 * @return    void
72
+	 */
73
+	public static function set_hooks_admin()
74
+	{
75
+		self::set_hooks_both();
76
+	}
77
+
78
+
79
+	public static function set_hooks_both()
80
+	{
81
+		add_action('rest_api_init', array('EED_Core_Rest_Api', 'register_routes'), 10);
82
+		add_action('rest_api_init', array('EED_Core_Rest_Api', 'set_hooks_rest_api'), 5);
83
+		add_filter('rest_route_data', array('EED_Core_Rest_Api', 'hide_old_endpoints'), 10, 2);
84
+		add_filter(
85
+			'rest_index',
86
+			array('EventEspresso\core\libraries\rest_api\controllers\model\Meta', 'filterEeMetadataIntoIndex')
87
+		);
88
+		EED_Core_Rest_Api::invalidate_cached_route_data_on_version_change();
89
+	}
90
+
91
+
92
+	/**
93
+	 * sets up hooks which only need to be included as part of REST API requests;
94
+	 * other requests like to the frontend or admin etc don't need them
95
+	 *
96
+	 * @throws \EE_Error
97
+	 */
98
+	public static function set_hooks_rest_api()
99
+	{
100
+		// set hooks which account for changes made to the API
101
+		EED_Core_Rest_Api::_set_hooks_for_changes();
102
+	}
103
+
104
+
105
+	/**
106
+	 * public wrapper of _set_hooks_for_changes.
107
+	 * Loads all the hooks which make requests to old versions of the API
108
+	 * appear the same as they always did
109
+	 *
110
+	 * @throws EE_Error
111
+	 */
112
+	public static function set_hooks_for_changes()
113
+	{
114
+		self::_set_hooks_for_changes();
115
+	}
116
+
117
+
118
+	/**
119
+	 * Loads all the hooks which make requests to old versions of the API
120
+	 * appear the same as they always did
121
+	 *
122
+	 * @throws EE_Error
123
+	 */
124
+	protected static function _set_hooks_for_changes()
125
+	{
126
+		$folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES . 'rest_api' . DS . 'changes'), false);
127
+		foreach ($folder_contents as $classname_in_namespace => $filepath) {
128
+			// ignore the base parent class
129
+			// and legacy named classes
130
+			if ($classname_in_namespace === 'ChangesInBase'
131
+				|| strpos($classname_in_namespace, 'Changes_In_') === 0
132
+			) {
133
+				continue;
134
+			}
135
+			$full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace;
136
+			if (class_exists($full_classname)) {
137
+				$instance_of_class = new $full_classname;
138
+				if ($instance_of_class instanceof ChangesInBase) {
139
+					$instance_of_class->setHooks();
140
+				}
141
+			}
142
+		}
143
+	}
144
+
145
+
146
+	/**
147
+	 * Filters the WP routes to add our EE-related ones. This takes a bit of time
148
+	 * so we actually prefer to only do it when an EE plugin is activated or upgraded
149
+	 *
150
+	 * @throws \EE_Error
151
+	 */
152
+	public static function register_routes()
153
+	{
154
+		foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_routes) {
155
+			foreach ($relative_routes as $relative_route => $data_for_multiple_endpoints) {
156
+				/**
157
+				 * @var array     $data_for_multiple_endpoints numerically indexed array
158
+				 *                                         but can also contain route options like {
159
+				 * @type array    $schema                      {
160
+				 * @type callable $schema_callback
161
+				 * @type array    $callback_args               arguments that will be passed to the callback, after the
162
+				 * WP_REST_Request of course
163
+				 * }
164
+				 * }
165
+				 */
166
+				// when registering routes, register all the endpoints' data at the same time
167
+				$multiple_endpoint_args = array();
168
+				foreach ($data_for_multiple_endpoints as $endpoint_key => $data_for_single_endpoint) {
169
+					/**
170
+					 * @var array     $data_for_single_endpoint {
171
+					 * @type callable $callback
172
+					 * @type string methods
173
+					 * @type array args
174
+					 * @type array _links
175
+					 * @type array    $callback_args            arguments that will be passed to the callback, after the
176
+					 * WP_REST_Request of course
177
+					 * }
178
+					 */
179
+					// skip route options
180
+					if (! is_numeric($endpoint_key)) {
181
+						continue;
182
+					}
183
+					if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
184
+						throw new EE_Error(
185
+							esc_html__(
186
+							// @codingStandardsIgnoreStart
187
+								'Endpoint configuration data needs to have entries "callback" (callable) and "methods" (comma-separated list of accepts HTTP methods).',
188
+								// @codingStandardsIgnoreEnd
189
+								'event_espresso'
190
+							)
191
+						);
192
+					}
193
+					$callback = $data_for_single_endpoint['callback'];
194
+					$single_endpoint_args = array(
195
+						'methods' => $data_for_single_endpoint['methods'],
196
+						'args'    => isset($data_for_single_endpoint['args']) ? $data_for_single_endpoint['args']
197
+							: array(),
198
+					);
199
+					if (isset($data_for_single_endpoint['_links'])) {
200
+						$single_endpoint_args['_links'] = $data_for_single_endpoint['_links'];
201
+					}
202
+					if (isset($data_for_single_endpoint['callback_args'])) {
203
+						$callback_args = $data_for_single_endpoint['callback_args'];
204
+						$single_endpoint_args['callback'] = function (\WP_REST_Request $request) use (
205
+							$callback,
206
+							$callback_args
207
+						) {
208
+							array_unshift($callback_args, $request);
209
+							return call_user_func_array(
210
+								$callback,
211
+								$callback_args
212
+							);
213
+						};
214
+					} else {
215
+						$single_endpoint_args['callback'] = $data_for_single_endpoint['callback'];
216
+					}
217
+					$multiple_endpoint_args[] = $single_endpoint_args;
218
+				}
219
+				if (isset($data_for_multiple_endpoints['schema'])) {
220
+					$schema_route_data = $data_for_multiple_endpoints['schema'];
221
+					$schema_callback = $schema_route_data['schema_callback'];
222
+					$callback_args = $schema_route_data['callback_args'];
223
+					$multiple_endpoint_args['schema'] = function () use ($schema_callback, $callback_args) {
224
+						return call_user_func_array(
225
+							$schema_callback,
226
+							$callback_args
227
+						);
228
+					};
229
+				}
230
+				register_rest_route(
231
+					$namespace,
232
+					$relative_route,
233
+					$multiple_endpoint_args
234
+				);
235
+			}
236
+		}
237
+	}
238
+
239
+
240
+	/**
241
+	 * Checks if there was a version change or something that merits invalidating the cached
242
+	 * route data. If so, invalidates the cached route data so that it gets refreshed
243
+	 * next time the WP API is used
244
+	 */
245
+	public static function invalidate_cached_route_data_on_version_change()
246
+	{
247
+		if (EE_System::instance()->detect_req_type() !== EE_System::req_type_normal) {
248
+			EED_Core_Rest_Api::invalidate_cached_route_data();
249
+		}
250
+		foreach (EE_Registry::instance()->addons as $addon) {
251
+			if ($addon instanceof EE_Addon && $addon->detect_req_type() !== EE_System::req_type_normal) {
252
+				EED_Core_Rest_Api::invalidate_cached_route_data();
253
+			}
254
+		}
255
+	}
256
+
257
+
258
+	/**
259
+	 * Removes the cached route data so it will get refreshed next time the WP API is used
260
+	 */
261
+	public static function invalidate_cached_route_data()
262
+	{
263
+		// delete the saved EE REST API routes
264
+		foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) {
265
+			delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version);
266
+		}
267
+	}
268
+
269
+
270
+	/**
271
+	 * Gets the EE route data
272
+	 *
273
+	 * @return array top-level key is the namespace, next-level key is the route and its value is array{
274
+	 * @throws \EE_Error
275
+	 * @type string|array $callback
276
+	 * @type string       $methods
277
+	 * @type boolean      $hidden_endpoint
278
+	 * }
279
+	 */
280
+	public static function get_ee_route_data()
281
+	{
282
+		$ee_routes = array();
283
+		foreach (self::versions_served() as $version => $hidden_endpoints) {
284
+			$ee_routes[ self::ee_api_namespace . $version ] = self::_get_ee_route_data_for_version(
285
+				$version,
286
+				$hidden_endpoints
287
+			);
288
+		}
289
+		return $ee_routes;
290
+	}
291
+
292
+
293
+	/**
294
+	 * Gets the EE route data from the wp options if it exists already,
295
+	 * otherwise re-generates it and saves it to the option
296
+	 *
297
+	 * @param string  $version
298
+	 * @param boolean $hidden_endpoints
299
+	 * @return array
300
+	 * @throws \EE_Error
301
+	 */
302
+	protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false)
303
+	{
304
+		$ee_routes = get_option(self::saved_routes_option_names . $version, null);
305
+		if (! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) {
306
+			$ee_routes = self::_save_ee_route_data_for_version($version, $hidden_endpoints);
307
+		}
308
+		return $ee_routes;
309
+	}
310
+
311
+
312
+	/**
313
+	 * Saves the EE REST API route data to a wp option and returns it
314
+	 *
315
+	 * @param string  $version
316
+	 * @param boolean $hidden_endpoints
317
+	 * @return mixed|null
318
+	 * @throws \EE_Error
319
+	 */
320
+	protected static function _save_ee_route_data_for_version($version, $hidden_endpoints = false)
321
+	{
322
+		$instance = self::instance();
323
+		$routes = apply_filters(
324
+			'EED_Core_Rest_Api__save_ee_route_data_for_version__routes',
325
+			array_replace_recursive(
326
+				$instance->_get_config_route_data_for_version($version, $hidden_endpoints),
327
+				$instance->_get_meta_route_data_for_version($version, $hidden_endpoints),
328
+				$instance->_get_model_route_data_for_version($version, $hidden_endpoints),
329
+				$instance->_get_rpc_route_data_for_version($version, $hidden_endpoints)
330
+			)
331
+		);
332
+		$option_name = self::saved_routes_option_names . $version;
333
+		if (get_option($option_name)) {
334
+			update_option($option_name, $routes, true);
335
+		} else {
336
+			add_option($option_name, $routes, null, 'no');
337
+		}
338
+		return $routes;
339
+	}
340
+
341
+
342
+	/**
343
+	 * Calculates all the EE routes and saves it to a WordPress option so we don't
344
+	 * need to calculate it on every request
345
+	 *
346
+	 * @deprecated since version 4.9.1
347
+	 * @return void
348
+	 */
349
+	public static function save_ee_routes()
350
+	{
351
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
352
+			$instance = self::instance();
353
+			$routes = apply_filters(
354
+				'EED_Core_Rest_Api__save_ee_routes__routes',
355
+				array_replace_recursive(
356
+					$instance->_register_config_routes(),
357
+					$instance->_register_meta_routes(),
358
+					$instance->_register_model_routes(),
359
+					$instance->_register_rpc_routes()
360
+				)
361
+			);
362
+			update_option(self::saved_routes_option_names, $routes, true);
363
+		}
364
+	}
365
+
366
+
367
+	/**
368
+	 * Gets all the route information relating to EE models
369
+	 *
370
+	 * @return array @see get_ee_route_data
371
+	 * @deprecated since version 4.9.1
372
+	 */
373
+	protected function _register_model_routes()
374
+	{
375
+		$model_routes = array();
376
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
377
+			$model_routes[ EED_Core_Rest_Api::ee_api_namespace
378
+						   . $version ] = $this->_get_config_route_data_for_version($version, $hidden_endpoint);
379
+		}
380
+		return $model_routes;
381
+	}
382
+
383
+
384
+	/**
385
+	 * Decides whether or not to add write endpoints for this model.
386
+	 *
387
+	 * Currently, this defaults to exclude all global tables and models
388
+	 * which would allow inserting WP core data (we don't want to duplicate
389
+	 * what WP API does, as it's unnecessary, extra work, and potentially extra bugs)
390
+	 *
391
+	 * @param EEM_Base $model
392
+	 * @return bool
393
+	 */
394
+	public static function should_have_write_endpoints(EEM_Base $model)
395
+	{
396
+		if ($model->is_wp_core_model()) {
397
+			return false;
398
+		}
399
+		foreach ($model->get_tables() as $table) {
400
+			if ($table->is_global()) {
401
+				return false;
402
+			}
403
+		}
404
+		return true;
405
+	}
406
+
407
+
408
+	/**
409
+	 * Gets the names of all models which should have plural routes (eg `ee/v4.8.36/events`)
410
+	 * in this versioned namespace of EE4
411
+	 *
412
+	 * @param $version
413
+	 * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event')
414
+	 */
415
+	public static function model_names_with_plural_routes($version)
416
+	{
417
+		$model_version_info = new ModelVersionInfo($version);
418
+		$models_to_register = $model_version_info->modelsForRequestedVersion();
419
+		// let's not bother having endpoints for extra metas
420
+		unset(
421
+			$models_to_register['Extra_Meta'],
422
+			$models_to_register['Extra_Join'],
423
+			$models_to_register['Post_Meta']
424
+		);
425
+		return apply_filters(
426
+			'FHEE__EED_Core_REST_API___register_model_routes',
427
+			$models_to_register
428
+		);
429
+	}
430
+
431
+
432
+	/**
433
+	 * Gets the route data for EE models in the specified version
434
+	 *
435
+	 * @param string  $version
436
+	 * @param boolean $hidden_endpoint
437
+	 * @return array
438
+	 * @throws EE_Error
439
+	 */
440
+	protected function _get_model_route_data_for_version($version, $hidden_endpoint = false)
441
+	{
442
+		$model_routes = array();
443
+		$model_version_info = new ModelVersionInfo($version);
444
+		foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) {
445
+			$model = \EE_Registry::instance()->load_model($model_name);
446
+			// if this isn't a valid model then let's skip iterate to the next item in the loop.
447
+			if (! $model instanceof EEM_Base) {
448
+				continue;
449
+			}
450
+			// yes we could just register one route for ALL models, but then they wouldn't show up in the index
451
+			$plural_model_route = EED_Core_Rest_Api::get_collection_route($model);
452
+			$singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)');
453
+			$model_routes[ $plural_model_route ] = array(
454
+				array(
455
+					'callback'        => array(
456
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
457
+						'handleRequestGetAll',
458
+					),
459
+					'callback_args'   => array($version, $model_name),
460
+					'methods'         => WP_REST_Server::READABLE,
461
+					'hidden_endpoint' => $hidden_endpoint,
462
+					'args'            => $this->_get_read_query_params($model, $version),
463
+					'_links'          => array(
464
+						'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route),
465
+					),
466
+				),
467
+				'schema' => array(
468
+					'schema_callback' => array(
469
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
470
+						'handleSchemaRequest',
471
+					),
472
+					'callback_args'   => array($version, $model_name),
473
+				),
474
+			);
475
+			$model_routes[ $singular_model_route ] = array(
476
+				array(
477
+					'callback'        => array(
478
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
479
+						'handleRequestGetOne',
480
+					),
481
+					'callback_args'   => array($version, $model_name),
482
+					'methods'         => WP_REST_Server::READABLE,
483
+					'hidden_endpoint' => $hidden_endpoint,
484
+					'args'            => $this->_get_response_selection_query_params($model, $version),
485
+				),
486
+			);
487
+			if (apply_filters(
488
+				'FHEE__EED_Core_Rest_Api___get_model_route_data_for_version__add_write_endpoints',
489
+				EED_Core_Rest_Api::should_have_write_endpoints($model),
490
+				$model
491
+			)) {
492
+				$model_routes[ $plural_model_route ][] = array(
493
+					'callback'        => array(
494
+						'EventEspresso\core\libraries\rest_api\controllers\model\Write',
495
+						'handleRequestInsert',
496
+					),
497
+					'callback_args'   => array($version, $model_name),
498
+					'methods'         => WP_REST_Server::CREATABLE,
499
+					'hidden_endpoint' => $hidden_endpoint,
500
+					'args'            => $this->_get_write_params($model_name, $model_version_info, true),
501
+				);
502
+				$model_routes[ $singular_model_route ] = array_merge(
503
+					$model_routes[ $singular_model_route ],
504
+					array(
505
+						array(
506
+							'callback'        => array(
507
+								'EventEspresso\core\libraries\rest_api\controllers\model\Write',
508
+								'handleRequestUpdate',
509
+							),
510
+							'callback_args'   => array($version, $model_name),
511
+							'methods'         => WP_REST_Server::EDITABLE,
512
+							'hidden_endpoint' => $hidden_endpoint,
513
+							'args'            => $this->_get_write_params($model_name, $model_version_info),
514
+						),
515
+						array(
516
+							'callback'        => array(
517
+								'EventEspresso\core\libraries\rest_api\controllers\model\Write',
518
+								'handleRequestDelete',
519
+							),
520
+							'callback_args'   => array($version, $model_name),
521
+							'methods'         => WP_REST_Server::DELETABLE,
522
+							'hidden_endpoint' => $hidden_endpoint,
523
+							'args'            => $this->_get_delete_query_params($model, $version),
524
+						),
525
+					)
526
+				);
527
+			}
528
+			foreach ($model->relation_settings() as $relation_name => $relation_obj) {
529
+				$related_route = EED_Core_Rest_Api::get_relation_route_via(
530
+					$model,
531
+					'(?P<id>[^\/]+)',
532
+					$relation_obj
533
+				);
534
+				$endpoints = array(
535
+					array(
536
+						'callback'        => array(
537
+							'EventEspresso\core\libraries\rest_api\controllers\model\Read',
538
+							'handleRequestGetRelated',
539
+						),
540
+						'callback_args'   => array($version, $model_name, $relation_name),
541
+						'methods'         => WP_REST_Server::READABLE,
542
+						'hidden_endpoint' => $hidden_endpoint,
543
+						'args'            => $this->_get_read_query_params($relation_obj->get_other_model(), $version),
544
+					),
545
+				);
546
+				$model_routes[ $related_route ] = $endpoints;
547
+			}
548
+		}
549
+		return $model_routes;
550
+	}
551
+
552
+
553
+	/**
554
+	 * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace,
555
+	 * excluding the preceding slash.
556
+	 * Eg you pass get_plural_route_to('Event') = 'events'
557
+	 *
558
+	 * @param EEM_Base $model
559
+	 * @return string
560
+	 */
561
+	public static function get_collection_route(EEM_Base $model)
562
+	{
563
+		return EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
564
+	}
565
+
566
+
567
+	/**
568
+	 * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
569
+	 * excluding the preceding slash.
570
+	 * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
571
+	 *
572
+	 * @param EEM_Base $model eg Event or Venue
573
+	 * @param string   $id
574
+	 * @return string
575
+	 */
576
+	public static function get_entity_route($model, $id)
577
+	{
578
+		return EED_Core_Rest_Api::get_collection_route($model) . '/' . $id;
579
+	}
580
+
581
+
582
+	/**
583
+	 * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
584
+	 * excluding the preceding slash.
585
+	 * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
586
+	 *
587
+	 * @param EEM_Base               $model eg Event or Venue
588
+	 * @param string                 $id
589
+	 * @param EE_Model_Relation_Base $relation_obj
590
+	 * @return string
591
+	 */
592
+	public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj)
593
+	{
594
+		$related_model_name_endpoint_part = ModelRead::getRelatedEntityName(
595
+			$relation_obj->get_other_model()->get_this_model_name(),
596
+			$relation_obj
597
+		);
598
+		return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
599
+	}
600
+
601
+
602
+	/**
603
+	 * Adds onto the $relative_route the EE4 REST API versioned namespace.
604
+	 * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events'
605
+	 *
606
+	 * @param string $relative_route
607
+	 * @param string $version
608
+	 * @return string
609
+	 */
610
+	public static function get_versioned_route_to($relative_route, $version = '4.8.36')
611
+	{
612
+		return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
613
+	}
614
+
615
+
616
+	/**
617
+	 * Adds all the RPC-style routes (remote procedure call-like routes, ie
618
+	 * routes that don't conform to the traditional REST CRUD-style).
619
+	 *
620
+	 * @deprecated since 4.9.1
621
+	 */
622
+	protected function _register_rpc_routes()
623
+	{
624
+		$routes = array();
625
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
626
+			$routes[ self::ee_api_namespace . $version ] = $this->_get_rpc_route_data_for_version(
627
+				$version,
628
+				$hidden_endpoint
629
+			);
630
+		}
631
+		return $routes;
632
+	}
633
+
634
+
635
+	/**
636
+	 * @param string  $version
637
+	 * @param boolean $hidden_endpoint
638
+	 * @return array
639
+	 */
640
+	protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false)
641
+	{
642
+		$this_versions_routes = array();
643
+		// checkin endpoint
644
+		$this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = array(
645
+			array(
646
+				'callback'        => array(
647
+					'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin',
648
+					'handleRequestToggleCheckin',
649
+				),
650
+				'methods'         => WP_REST_Server::CREATABLE,
651
+				'hidden_endpoint' => $hidden_endpoint,
652
+				'args'            => array(
653
+					'force' => array(
654
+						'required'    => false,
655
+						'default'     => false,
656
+						'description' => __(
657
+						// @codingStandardsIgnoreStart
658
+							'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses',
659
+							// @codingStandardsIgnoreEnd
660
+							'event_espresso'
661
+						),
662
+					),
663
+				),
664
+				'callback_args'   => array($version),
665
+			),
666
+		);
667
+		return apply_filters(
668
+			'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes',
669
+			$this_versions_routes,
670
+			$version,
671
+			$hidden_endpoint
672
+		);
673
+	}
674
+
675
+
676
+	/**
677
+	 * Gets the query params that can be used when request one or many
678
+	 *
679
+	 * @param EEM_Base $model
680
+	 * @param string   $version
681
+	 * @return array
682
+	 */
683
+	protected function _get_response_selection_query_params(\EEM_Base $model, $version)
684
+	{
685
+		return apply_filters(
686
+			'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
687
+			array(
688
+				'include'   => array(
689
+					'required' => false,
690
+					'default'  => '*',
691
+					'type'     => 'string',
692
+				),
693
+				'calculate' => array(
694
+					'required'          => false,
695
+					'default'           => '',
696
+					'enum'              => self::$_field_calculator->retrieveCalculatedFieldsForModel($model),
697
+					'type'              => 'string',
698
+					// because we accept a CSV'd list of the enumerated strings, WP core validation and sanitization
699
+					// freaks out. We'll just validate this argument while handling the request
700
+					'validate_callback' => null,
701
+					'sanitize_callback' => null,
702
+				),
703
+			),
704
+			$model,
705
+			$version
706
+		);
707
+	}
708
+
709
+
710
+	/**
711
+	 * Gets the parameters acceptable for delete requests
712
+	 *
713
+	 * @param \EEM_Base $model
714
+	 * @param string    $version
715
+	 * @return array
716
+	 */
717
+	protected function _get_delete_query_params(\EEM_Base $model, $version)
718
+	{
719
+		$params_for_delete = array(
720
+			'allow_blocking' => array(
721
+				'required' => false,
722
+				'default'  => true,
723
+				'type'     => 'boolean',
724
+			),
725
+		);
726
+		$params_for_delete['force'] = array(
727
+			'required' => false,
728
+			'default'  => false,
729
+			'type'     => 'boolean',
730
+		);
731
+		return apply_filters(
732
+			'FHEE__EED_Core_Rest_Api___get_delete_query_params',
733
+			$params_for_delete,
734
+			$model,
735
+			$version
736
+		);
737
+	}
738
+
739
+
740
+	/**
741
+	 * Gets info about reading query params that are acceptable
742
+	 *
743
+	 * @param \EEM_Base $model eg 'Event' or 'Venue'
744
+	 * @param  string   $version
745
+	 * @return array    describing the args acceptable when querying this model
746
+	 * @throws EE_Error
747
+	 */
748
+	protected function _get_read_query_params(\EEM_Base $model, $version)
749
+	{
750
+		$default_orderby = array();
751
+		foreach ($model->get_combined_primary_key_fields() as $key_field) {
752
+			$default_orderby[ $key_field->get_name() ] = 'ASC';
753
+		}
754
+		return array_merge(
755
+			$this->_get_response_selection_query_params($model, $version),
756
+			array(
757
+				'where'    => array(
758
+					'required'          => false,
759
+					'default'           => array(),
760
+					'type'              => 'object',
761
+					// because we accept an almost infinite list of possible where conditions, WP
762
+					// core validation and sanitization freaks out. We'll just validate this argument
763
+					// while handling the request
764
+					'validate_callback' => null,
765
+					'sanitize_callback' => null,
766
+				),
767
+				'limit'    => array(
768
+					'required'          => false,
769
+					'default'           => EED_Core_Rest_Api::get_default_query_limit(),
770
+					'type'              => array(
771
+						'array',
772
+						'string',
773
+						'integer',
774
+					),
775
+					// because we accept a variety of types, WP core validation and sanitization
776
+					// freaks out. We'll just validate this argument while handling the request
777
+					'validate_callback' => null,
778
+					'sanitize_callback' => null,
779
+				),
780
+				'order_by' => array(
781
+					'required'          => false,
782
+					'default'           => $default_orderby,
783
+					'type'              => array(
784
+						'object',
785
+						'string',
786
+					),// because we accept a variety of types, WP core validation and sanitization
787
+					// freaks out. We'll just validate this argument while handling the request
788
+					'validate_callback' => null,
789
+					'sanitize_callback' => null,
790
+				),
791
+				'group_by' => array(
792
+					'required'          => false,
793
+					'default'           => null,
794
+					'type'              => array(
795
+						'object',
796
+						'string',
797
+					),
798
+					// because we accept  an almost infinite list of possible groupings,
799
+					// WP core validation and sanitization
800
+					// freaks out. We'll just validate this argument while handling the request
801
+					'validate_callback' => null,
802
+					'sanitize_callback' => null,
803
+				),
804
+				'having'   => array(
805
+					'required'          => false,
806
+					'default'           => null,
807
+					'type'              => 'object',
808
+					// because we accept an almost infinite list of possible where conditions, WP
809
+					// core validation and sanitization freaks out. We'll just validate this argument
810
+					// while handling the request
811
+					'validate_callback' => null,
812
+					'sanitize_callback' => null,
813
+				),
814
+				'caps'     => array(
815
+					'required' => false,
816
+					'default'  => EEM_Base::caps_read,
817
+					'type'     => 'string',
818
+					'enum'     => array(
819
+						EEM_Base::caps_read,
820
+						EEM_Base::caps_read_admin,
821
+						EEM_Base::caps_edit,
822
+						EEM_Base::caps_delete,
823
+					),
824
+				),
825
+			)
826
+		);
827
+	}
828
+
829
+
830
+	/**
831
+	 * Gets parameter information for a model regarding writing data
832
+	 *
833
+	 * @param string           $model_name
834
+	 * @param ModelVersionInfo $model_version_info
835
+	 * @param boolean          $create                                       whether this is for request to create (in
836
+	 *                                                                       which case we need all required params) or
837
+	 *                                                                       just to update (in which case we don't
838
+	 *                                                                       need those on every request)
839
+	 * @return array
840
+	 */
841
+	protected function _get_write_params(
842
+		$model_name,
843
+		ModelVersionInfo $model_version_info,
844
+		$create = false
845
+	) {
846
+		$model = EE_Registry::instance()->load_model($model_name);
847
+		$fields = $model_version_info->fieldsOnModelInThisVersion($model);
848
+		$args_info = array();
849
+		foreach ($fields as $field_name => $field_obj) {
850
+			if ($field_obj->is_auto_increment()) {
851
+				// totally ignore auto increment IDs
852
+				continue;
853
+			}
854
+			$arg_info = $field_obj->getSchema();
855
+			$required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null;
856
+			$arg_info['required'] = $required;
857
+			// remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right?
858
+			unset($arg_info['readonly']);
859
+			$schema_properties = $field_obj->getSchemaProperties();
860
+			if (isset($schema_properties['raw'])
861
+				&& $field_obj->getSchemaType() === 'object'
862
+			) {
863
+				// if there's a "raw" form of this argument, use those properties instead
864
+				$arg_info = array_replace(
865
+					$arg_info,
866
+					$schema_properties['raw']
867
+				);
868
+			}
869
+			$arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson(
870
+				$field_obj,
871
+				$field_obj->get_default_value(),
872
+				$model_version_info->requestedVersion()
873
+			);
874
+			// we do our own validation and sanitization within the controller
875
+			if (function_exists('rest_validate_value_from_schema')) {
876
+				$sanitize_callback = array(
877
+					'EED_Core_Rest_Api',
878
+					'default_sanitize_callback',
879
+				);
880
+			} else {
881
+				$sanitize_callback = null;
882
+			}
883
+			$arg_info['sanitize_callback'] = $sanitize_callback;
884
+			$args_info[ $field_name ] = $arg_info;
885
+			if ($field_obj instanceof EE_Datetime_Field) {
886
+				$gmt_arg_info = $arg_info;
887
+				$gmt_arg_info['description'] = sprintf(
888
+					esc_html__(
889
+						'%1$s - the value for this field in UTC. Ignored if %2$s is provided.',
890
+						'event_espresso'
891
+					),
892
+					$field_obj->get_nicename(),
893
+					$field_name
894
+				);
895
+				$args_info[ $field_name . '_gmt' ] = $gmt_arg_info;
896
+			}
897
+		}
898
+		return $args_info;
899
+	}
900
+
901
+
902
+	/**
903
+	 * Replacement for WP API's 'rest_parse_request_arg'.
904
+	 * If the value is blank but not required, don't bother validating it.
905
+	 * Also, it uses our email validation instead of WP API's default.
906
+	 *
907
+	 * @param                 $value
908
+	 * @param WP_REST_Request $request
909
+	 * @param                 $param
910
+	 * @return bool|true|WP_Error
911
+	 * @throws InvalidArgumentException
912
+	 * @throws InvalidInterfaceException
913
+	 * @throws InvalidDataTypeException
914
+	 */
915
+	public static function default_sanitize_callback($value, WP_REST_Request $request, $param)
916
+	{
917
+		$attributes = $request->get_attributes();
918
+		if (! isset($attributes['args'][ $param ])
919
+			|| ! is_array($attributes['args'][ $param ])) {
920
+			$validation_result = true;
921
+		} else {
922
+			$args = $attributes['args'][ $param ];
923
+			if ((
924
+					$value === ''
925
+					|| $value === null
926
+				)
927
+				&& (! isset($args['required'])
928
+					|| $args['required'] === false
929
+				)
930
+			) {
931
+				// not required and not provided? that's cool
932
+				$validation_result = true;
933
+			} elseif (isset($args['format'])
934
+					  && $args['format'] === 'email'
935
+			) {
936
+				$validation_result = true;
937
+				if (! self::_validate_email($value)) {
938
+					$validation_result = new WP_Error(
939
+						'rest_invalid_param',
940
+						esc_html__(
941
+							'The email address is not valid or does not exist.',
942
+							'event_espresso'
943
+						)
944
+					);
945
+				}
946
+			} else {
947
+				$validation_result = rest_validate_value_from_schema($value, $args, $param);
948
+			}
949
+		}
950
+		if (is_wp_error($validation_result)) {
951
+			return $validation_result;
952
+		}
953
+		return rest_sanitize_request_arg($value, $request, $param);
954
+	}
955
+
956
+
957
+	/**
958
+	 * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email()
959
+	 *
960
+	 * @param $email
961
+	 * @return bool
962
+	 * @throws InvalidArgumentException
963
+	 * @throws InvalidInterfaceException
964
+	 * @throws InvalidDataTypeException
965
+	 */
966
+	protected static function _validate_email($email)
967
+	{
968
+		try {
969
+			EmailAddressFactory::create($email);
970
+			return true;
971
+		} catch (EmailValidationException $e) {
972
+			return false;
973
+		}
974
+	}
975
+
976
+
977
+	/**
978
+	 * Gets routes for the config
979
+	 *
980
+	 * @return array @see _register_model_routes
981
+	 * @deprecated since version 4.9.1
982
+	 */
983
+	protected function _register_config_routes()
984
+	{
985
+		$config_routes = array();
986
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
987
+			$config_routes[ self::ee_api_namespace . $version ] = $this->_get_config_route_data_for_version(
988
+				$version,
989
+				$hidden_endpoint
990
+			);
991
+		}
992
+		return $config_routes;
993
+	}
994
+
995
+
996
+	/**
997
+	 * Gets routes for the config for the specified version
998
+	 *
999
+	 * @param string  $version
1000
+	 * @param boolean $hidden_endpoint
1001
+	 * @return array
1002
+	 */
1003
+	protected function _get_config_route_data_for_version($version, $hidden_endpoint)
1004
+	{
1005
+		return array(
1006
+			'config'    => array(
1007
+				array(
1008
+					'callback'        => array(
1009
+						'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1010
+						'handleRequest',
1011
+					),
1012
+					'methods'         => WP_REST_Server::READABLE,
1013
+					'hidden_endpoint' => $hidden_endpoint,
1014
+					'callback_args'   => array($version),
1015
+				),
1016
+			),
1017
+			'site_info' => array(
1018
+				array(
1019
+					'callback'        => array(
1020
+						'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1021
+						'handleRequestSiteInfo',
1022
+					),
1023
+					'methods'         => WP_REST_Server::READABLE,
1024
+					'hidden_endpoint' => $hidden_endpoint,
1025
+					'callback_args'   => array($version),
1026
+				),
1027
+			),
1028
+		);
1029
+	}
1030
+
1031
+
1032
+	/**
1033
+	 * Gets the meta info routes
1034
+	 *
1035
+	 * @return array @see _register_model_routes
1036
+	 * @deprecated since version 4.9.1
1037
+	 */
1038
+	protected function _register_meta_routes()
1039
+	{
1040
+		$meta_routes = array();
1041
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
1042
+			$meta_routes[ self::ee_api_namespace . $version ] = $this->_get_meta_route_data_for_version(
1043
+				$version,
1044
+				$hidden_endpoint
1045
+			);
1046
+		}
1047
+		return $meta_routes;
1048
+	}
1049
+
1050
+
1051
+	/**
1052
+	 * @param string  $version
1053
+	 * @param boolean $hidden_endpoint
1054
+	 * @return array
1055
+	 */
1056
+	protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false)
1057
+	{
1058
+		return array(
1059
+			'resources' => array(
1060
+				array(
1061
+					'callback'        => array(
1062
+						'EventEspresso\core\libraries\rest_api\controllers\model\Meta',
1063
+						'handleRequestModelsMeta',
1064
+					),
1065
+					'methods'         => WP_REST_Server::READABLE,
1066
+					'hidden_endpoint' => $hidden_endpoint,
1067
+					'callback_args'   => array($version),
1068
+				),
1069
+			),
1070
+		);
1071
+	}
1072
+
1073
+
1074
+	/**
1075
+	 * Tries to hide old 4.6 endpoints from the
1076
+	 *
1077
+	 * @param array $route_data
1078
+	 * @return array
1079
+	 * @throws \EE_Error
1080
+	 */
1081
+	public static function hide_old_endpoints($route_data)
1082
+	{
1083
+		// allow API clients to override which endpoints get hidden, in case
1084
+		// they want to discover particular endpoints
1085
+		// also, we don't have access to the request so we have to just grab it from the superglobal
1086
+		$force_show_ee_namespace = ltrim(
1087
+			EEH_Array::is_set($_REQUEST, 'force_show_ee_namespace', ''),
1088
+			'/'
1089
+		);
1090
+		foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) {
1091
+			foreach ($relative_urls as $resource_name => $endpoints) {
1092
+				foreach ($endpoints as $key => $endpoint) {
1093
+					// skip schema and other route options
1094
+					if (! is_numeric($key)) {
1095
+						continue;
1096
+					}
1097
+					// by default, hide "hidden_endpoint"s, unless the request indicates
1098
+					// to $force_show_ee_namespace, in which case only show that one
1099
+					// namespace's endpoints (and hide all others)
1100
+					if (($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1101
+						|| ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1102
+					) {
1103
+						$full_route = '/' . ltrim($namespace, '/');
1104
+						$full_route .= '/' . ltrim($resource_name, '/');
1105
+						unset($route_data[ $full_route ]);
1106
+					}
1107
+				}
1108
+			}
1109
+		}
1110
+		return $route_data;
1111
+	}
1112
+
1113
+
1114
+	/**
1115
+	 * Returns an array describing which versions of core support serving requests for.
1116
+	 * Keys are core versions' major and minor version, and values are the
1117
+	 * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like
1118
+	 * data by just removing a few models and fields from the responses. However, 4.15 might remove
1119
+	 * the answers table entirely, in which case it would be very difficult for
1120
+	 * it to serve 4.6-style responses.
1121
+	 * Versions of core that are missing from this array are unknowns.
1122
+	 * previous ver
1123
+	 *
1124
+	 * @return array
1125
+	 */
1126
+	public static function version_compatibilities()
1127
+	{
1128
+		return apply_filters(
1129
+			'FHEE__EED_Core_REST_API__version_compatibilities',
1130
+			array(
1131
+				'4.8.29' => '4.8.29',
1132
+				'4.8.33' => '4.8.29',
1133
+				'4.8.34' => '4.8.29',
1134
+				'4.8.36' => '4.8.29',
1135
+			)
1136
+		);
1137
+	}
1138
+
1139
+
1140
+	/**
1141
+	 * Gets the latest API version served. Eg if there
1142
+	 * are two versions served of the API, 4.8.29 and 4.8.32, and
1143
+	 * we are on core version 4.8.34, it will return the string "4.8.32"
1144
+	 *
1145
+	 * @return string
1146
+	 */
1147
+	public static function latest_rest_api_version()
1148
+	{
1149
+		$versions_served = \EED_Core_Rest_Api::versions_served();
1150
+		$versions_served_keys = array_keys($versions_served);
1151
+		return end($versions_served_keys);
1152
+	}
1153
+
1154
+
1155
+	/**
1156
+	 * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of
1157
+	 * EE the API can serve requests for. Eg, if we are on 4.15 of core, and
1158
+	 * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ).
1159
+	 * We also indicate whether or not this version should be put in the index or not
1160
+	 *
1161
+	 * @return array keys are API version numbers (just major and minor numbers), and values
1162
+	 * are whether or not they should be hidden
1163
+	 */
1164
+	public static function versions_served()
1165
+	{
1166
+		$versions_served = array();
1167
+		$possibly_served_versions = EED_Core_Rest_Api::version_compatibilities();
1168
+		$lowest_compatible_version = end($possibly_served_versions);
1169
+		reset($possibly_served_versions);
1170
+		$versions_served_historically = array_keys($possibly_served_versions);
1171
+		$latest_version = end($versions_served_historically);
1172
+		reset($versions_served_historically);
1173
+		// for each version of core we have ever served:
1174
+		foreach ($versions_served_historically as $key_versioned_endpoint) {
1175
+			// if it's not above the current core version, and it's compatible with the current version of core
1176
+			if ($key_versioned_endpoint === $latest_version) {
1177
+				// don't hide the latest version in the index
1178
+				$versions_served[ $key_versioned_endpoint ] = false;
1179
+			} elseif ($key_versioned_endpoint >= $lowest_compatible_version
1180
+				&& $key_versioned_endpoint < EED_Core_Rest_Api::core_version()
1181
+			) {
1182
+				// include, but hide, previous versions which are still supported
1183
+				$versions_served[ $key_versioned_endpoint ] = true;
1184
+			} elseif (apply_filters(
1185
+				'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions',
1186
+				false,
1187
+				$possibly_served_versions
1188
+			)) {
1189
+				// if a version is no longer supported, don't include it in index or list of versions served
1190
+				$versions_served[ $key_versioned_endpoint ] = true;
1191
+			}
1192
+		}
1193
+		return $versions_served;
1194
+	}
1195
+
1196
+
1197
+	/**
1198
+	 * Gets the major and minor version of EE core's version string
1199
+	 *
1200
+	 * @return string
1201
+	 */
1202
+	public static function core_version()
1203
+	{
1204
+		return apply_filters(
1205
+			'FHEE__EED_Core_REST_API__core_version',
1206
+			implode(
1207
+				'.',
1208
+				array_slice(
1209
+					explode(
1210
+						'.',
1211
+						espresso_version()
1212
+					),
1213
+					0,
1214
+					3
1215
+				)
1216
+			)
1217
+		);
1218
+	}
1219
+
1220
+
1221
+	/**
1222
+	 * Gets the default limit that should be used when querying for resources
1223
+	 *
1224
+	 * @return int
1225
+	 */
1226
+	public static function get_default_query_limit()
1227
+	{
1228
+		// we actually don't use a const because we want folks to always use
1229
+		// this method, not the const directly
1230
+		return apply_filters(
1231
+			'FHEE__EED_Core_Rest_Api__get_default_query_limit',
1232
+			50
1233
+		);
1234
+	}
1235
+
1236
+
1237
+	/**
1238
+	 *    run - initial module setup
1239
+	 *
1240
+	 * @access    public
1241
+	 * @param  WP $WP
1242
+	 * @return    void
1243
+	 */
1244
+	public function run($WP)
1245
+	{
1246
+	}
1247 1247
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/CalculatedModelFieldsFactory.php 2 patches
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -40,7 +40,7 @@  discard block
 block discarded – undo
40 40
      */
41 41
     public function createFromModel($model_name)
42 42
     {
43
-        return $this->createFromClassname('EventEspresso\core\libraries\rest_api\calculations\\' . $model_name);
43
+        return $this->createFromClassname('EventEspresso\core\libraries\rest_api\calculations\\'.$model_name);
44 44
     }
45 45
 
46 46
     /**
@@ -51,7 +51,7 @@  discard block
 block discarded – undo
51 51
     public function createFromClassname($calculator_classname)
52 52
     {
53 53
         $calculator = $this->loader->getShared($calculator_classname);
54
-        if (!$calculator instanceof Base) {
54
+        if ( ! $calculator instanceof Base) {
55 55
             throw new UnexpectedEntityException(
56 56
                 $calculator_classname,
57 57
                 'EventEspresso\core\libraries\rest_api\calculations\Base'
Please login to merge, or discard this patch.
Indentation   +37 added lines, -37 removed lines patch added patch discarded remove patch
@@ -18,46 +18,46 @@
 block discarded – undo
18 18
  */
19 19
 class CalculatedModelFieldsFactory
20 20
 {
21
-    private $loader;
21
+	private $loader;
22 22
 
23
-    /**
24
-     * CalculatedModelFieldsFactory constructor.
25
-     * @param LoaderInterface $loader
26
-     */
27
-    public function __construct(LoaderInterface $loader)
28
-    {
29
-        $this->loader = $loader;
30
-    }
23
+	/**
24
+	 * CalculatedModelFieldsFactory constructor.
25
+	 * @param LoaderInterface $loader
26
+	 */
27
+	public function __construct(LoaderInterface $loader)
28
+	{
29
+		$this->loader = $loader;
30
+	}
31 31
 
32
-    /**
33
-     * Creates the calculator class that corresponds to that particular model
34
-     * @since $VID:$
35
-     * @param string $model_name
36
-     * @return Base
37
-     * @throws UnexpectedEntityException
38
-     */
39
-    public function createFromModel($model_name)
40
-    {
41
-        return $this->createFromClassname('EventEspresso\core\libraries\rest_api\calculations\\' . $model_name);
42
-    }
32
+	/**
33
+	 * Creates the calculator class that corresponds to that particular model
34
+	 * @since $VID:$
35
+	 * @param string $model_name
36
+	 * @return Base
37
+	 * @throws UnexpectedEntityException
38
+	 */
39
+	public function createFromModel($model_name)
40
+	{
41
+		return $this->createFromClassname('EventEspresso\core\libraries\rest_api\calculations\\' . $model_name);
42
+	}
43 43
 
44
-    /**
45
-     * Creates the calculator class that corresponds to that classname and verifies it's of the correct type
46
-     * @param string $calculator_classname
47
-     * @return Base
48
-     * @throws UnexpectedEntityException
49
-     */
50
-    public function createFromClassname($calculator_classname)
51
-    {
52
-        $calculator = $this->loader->getShared($calculator_classname);
53
-        if (!$calculator instanceof Base) {
54
-            throw new UnexpectedEntityException(
55
-                $calculator_classname,
56
-                'EventEspresso\core\libraries\rest_api\calculations\Base'
57
-            );
58
-        }
59
-        return $calculator;
60
-    }
44
+	/**
45
+	 * Creates the calculator class that corresponds to that classname and verifies it's of the correct type
46
+	 * @param string $calculator_classname
47
+	 * @return Base
48
+	 * @throws UnexpectedEntityException
49
+	 */
50
+	public function createFromClassname($calculator_classname)
51
+	{
52
+		$calculator = $this->loader->getShared($calculator_classname);
53
+		if (!$calculator instanceof Base) {
54
+			throw new UnexpectedEntityException(
55
+				$calculator_classname,
56
+				'EventEspresso\core\libraries\rest_api\calculations\Base'
57
+			);
58
+		}
59
+		return $calculator;
60
+	}
61 61
 }
62 62
 // End of file CalculationsFactory.php
63 63
 // Location: EventEspresso\core\libraries\rest_api\calculations/CalculationsFactory.php
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/Datetime.php 2 patches
Indentation   +196 added lines, -196 removed lines patch added patch discarded remove patch
@@ -17,210 +17,210 @@
 block discarded – undo
17 17
 
18 18
 class Datetime extends DatetimeCalculationBase
19 19
 {
20
-    /**
21
-     * @var EEM_Datetime
22
-     */
23
-    protected $datetime_model;
20
+	/**
21
+	 * @var EEM_Datetime
22
+	 */
23
+	protected $datetime_model;
24 24
 
25
-    /**
26
-     * @var EEM_Registration
27
-     */
28
-    protected $registration_model;
29
-    public function __construct(EEM_Datetime $datetime_model, EEM_Registration $registration_model)
30
-    {
31
-        $this->datetime_model = $datetime_model;
32
-        $this->registration_model = $registration_model;
33
-    }
25
+	/**
26
+	 * @var EEM_Registration
27
+	 */
28
+	protected $registration_model;
29
+	public function __construct(EEM_Datetime $datetime_model, EEM_Registration $registration_model)
30
+	{
31
+		$this->datetime_model = $datetime_model;
32
+		$this->registration_model = $registration_model;
33
+	}
34 34
 
35
-    /**
36
-     * Calculates the total spaces available on the datetime, taking into account
37
-     * ticket limits too.
38
-     *
39
-     * @see EE_Datetime::spaces_remaining( true )
40
-     * @param array            $wpdb_row
41
-     * @param WP_REST_Request $request
42
-     * @param DatetimeControllerBase  $controller
43
-     * @return int
44
-     * @throws EE_Error
45
-     * @throws InvalidDataTypeException
46
-     * @throws InvalidInterfaceException
47
-     * @throws InvalidArgumentException
48
-     * @throws ReflectionException
49
-     */
50
-    public function spacesRemainingConsideringTickets($wpdb_row, $request, $controller)
51
-    {
52
-        if (is_array($wpdb_row) && isset($wpdb_row['Datetime.DTT_ID'])) {
53
-            $dtt_obj = $this->datetime_model->get_one_by_ID($wpdb_row['Datetime.DTT_ID']);
54
-        } else {
55
-            $dtt_obj = null;
56
-        }
57
-        if ($dtt_obj instanceof EE_Datetime) {
58
-            return $dtt_obj->spaces_remaining(true);
59
-        }
60
-        throw new EE_Error(
61
-            sprintf(
62
-                __(
63
-                // @codingStandardsIgnoreStart
64
-                    'Cannot calculate spaces_remaining_considering_tickets because the datetime with ID %1$s (from database row %2$s) was not found',
65
-                    // @codingStandardsIgnoreEnd
66
-                    'event_espresso'
67
-                ),
68
-                $wpdb_row['Datetime.DTT_ID'],
69
-                print_r($wpdb_row, true)
70
-            )
71
-        );
72
-    }
35
+	/**
36
+	 * Calculates the total spaces available on the datetime, taking into account
37
+	 * ticket limits too.
38
+	 *
39
+	 * @see EE_Datetime::spaces_remaining( true )
40
+	 * @param array            $wpdb_row
41
+	 * @param WP_REST_Request $request
42
+	 * @param DatetimeControllerBase  $controller
43
+	 * @return int
44
+	 * @throws EE_Error
45
+	 * @throws InvalidDataTypeException
46
+	 * @throws InvalidInterfaceException
47
+	 * @throws InvalidArgumentException
48
+	 * @throws ReflectionException
49
+	 */
50
+	public function spacesRemainingConsideringTickets($wpdb_row, $request, $controller)
51
+	{
52
+		if (is_array($wpdb_row) && isset($wpdb_row['Datetime.DTT_ID'])) {
53
+			$dtt_obj = $this->datetime_model->get_one_by_ID($wpdb_row['Datetime.DTT_ID']);
54
+		} else {
55
+			$dtt_obj = null;
56
+		}
57
+		if ($dtt_obj instanceof EE_Datetime) {
58
+			return $dtt_obj->spaces_remaining(true);
59
+		}
60
+		throw new EE_Error(
61
+			sprintf(
62
+				__(
63
+				// @codingStandardsIgnoreStart
64
+					'Cannot calculate spaces_remaining_considering_tickets because the datetime with ID %1$s (from database row %2$s) was not found',
65
+					// @codingStandardsIgnoreEnd
66
+					'event_espresso'
67
+				),
68
+				$wpdb_row['Datetime.DTT_ID'],
69
+				print_r($wpdb_row, true)
70
+			)
71
+		);
72
+	}
73 73
 
74 74
 
75
-    /**
76
-     * Counts registrations who have checked into this datetime
77
-     *
78
-     * @param array           $wpdb_row
79
-     * @param WP_REST_Request $request
80
-     * @param DatetimeControllerBase $controller
81
-     * @return int
82
-     * @throws EE_Error
83
-     * @throws InvalidArgumentException
84
-     * @throws InvalidDataTypeException
85
-     * @throws InvalidInterfaceException
86
-     * @throws RestException
87
-     */
88
-    public function registrationsCheckedInCount($wpdb_row, $request, $controller)
89
-    {
90
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
91
-            throw new EE_Error(
92
-                sprintf(
93
-                    __(
94
-                    // @codingStandardsIgnoreStart
95
-                        'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
96
-                        // @codingStandardsIgnoreEnd
97
-                        'event_espresso'
98
-                    ),
99
-                    print_r($wpdb_row, true)
100
-                )
101
-            );
102
-        }
103
-        $this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
104
-        return $this->registration_model
105
-                               ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], true);
106
-    }
75
+	/**
76
+	 * Counts registrations who have checked into this datetime
77
+	 *
78
+	 * @param array           $wpdb_row
79
+	 * @param WP_REST_Request $request
80
+	 * @param DatetimeControllerBase $controller
81
+	 * @return int
82
+	 * @throws EE_Error
83
+	 * @throws InvalidArgumentException
84
+	 * @throws InvalidDataTypeException
85
+	 * @throws InvalidInterfaceException
86
+	 * @throws RestException
87
+	 */
88
+	public function registrationsCheckedInCount($wpdb_row, $request, $controller)
89
+	{
90
+		if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
91
+			throw new EE_Error(
92
+				sprintf(
93
+					__(
94
+					// @codingStandardsIgnoreStart
95
+						'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
96
+						// @codingStandardsIgnoreEnd
97
+						'event_espresso'
98
+					),
99
+					print_r($wpdb_row, true)
100
+				)
101
+			);
102
+		}
103
+		$this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
104
+		return $this->registration_model
105
+							   ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], true);
106
+	}
107 107
 
108 108
 
109
-    /**
110
-     * Counts registrations who have checked out of this datetime
111
-     *
112
-     * @param array           $wpdb_row
113
-     * @param WP_REST_Request $request
114
-     * @param DatetimeControllerBase $controller
115
-     * @return int
116
-     * @throws EE_Error
117
-     * @throws InvalidArgumentException
118
-     * @throws InvalidDataTypeException
119
-     * @throws InvalidInterfaceException
120
-     * @throws RestException
121
-     */
122
-    public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
123
-    {
124
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
125
-            throw new EE_Error(
126
-                sprintf(
127
-                    __(
128
-                    // @codingStandardsIgnoreStart
129
-                        'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
130
-                        // @codingStandardsIgnoreEnd
131
-                        'event_espresso'
132
-                    ),
133
-                    print_r($wpdb_row, true)
134
-                )
135
-            );
136
-        }
137
-        $this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
138
-        return $this->registration_model
139
-                               ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], false);
140
-    }
109
+	/**
110
+	 * Counts registrations who have checked out of this datetime
111
+	 *
112
+	 * @param array           $wpdb_row
113
+	 * @param WP_REST_Request $request
114
+	 * @param DatetimeControllerBase $controller
115
+	 * @return int
116
+	 * @throws EE_Error
117
+	 * @throws InvalidArgumentException
118
+	 * @throws InvalidDataTypeException
119
+	 * @throws InvalidInterfaceException
120
+	 * @throws RestException
121
+	 */
122
+	public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
123
+	{
124
+		if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
125
+			throw new EE_Error(
126
+				sprintf(
127
+					__(
128
+					// @codingStandardsIgnoreStart
129
+						'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
130
+						// @codingStandardsIgnoreEnd
131
+						'event_espresso'
132
+					),
133
+					print_r($wpdb_row, true)
134
+				)
135
+			);
136
+		}
137
+		$this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
138
+		return $this->registration_model
139
+							   ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], false);
140
+	}
141 141
 
142 142
 
143
-    /**
144
-     * Counts the number of pending-payment registrations for this event (regardless
145
-     * of how many datetimes each registrations' ticket purchase is for)
146
-     *
147
-     * @param array           $wpdb_row
148
-     * @param WP_REST_Request $request
149
-     * @param DatetimeControllerBase $controller
150
-     * @return int
151
-     * @throws EE_Error
152
-     * @throws InvalidArgumentException
153
-     * @throws InvalidDataTypeException
154
-     * @throws InvalidInterfaceException
155
-     * @throws RestException
156
-     */
157
-    public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
158
-    {
159
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
160
-            throw new EE_Error(
161
-                sprintf(
162
-                    __(
163
-                    // @codingStandardsIgnoreStart
164
-                        'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
165
-                        // @codingStandardsIgnoreEnd
166
-                        'event_espresso'
167
-                    ),
168
-                    print_r($wpdb_row, true)
169
-                )
170
-            );
171
-        }
172
-        $this->verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
173
-        return $this->registration_model->count(
174
-            array(
175
-                array(
176
-                    'Ticket.Datetime.DTT_ID' => $wpdb_row['Datetime.DTT_ID'],
177
-                    'STS_ID'                 => EEM_Registration::status_id_pending_payment,
178
-                ),
179
-            ),
180
-            'REG_ID',
181
-            true
182
-        );
183
-    }
143
+	/**
144
+	 * Counts the number of pending-payment registrations for this event (regardless
145
+	 * of how many datetimes each registrations' ticket purchase is for)
146
+	 *
147
+	 * @param array           $wpdb_row
148
+	 * @param WP_REST_Request $request
149
+	 * @param DatetimeControllerBase $controller
150
+	 * @return int
151
+	 * @throws EE_Error
152
+	 * @throws InvalidArgumentException
153
+	 * @throws InvalidDataTypeException
154
+	 * @throws InvalidInterfaceException
155
+	 * @throws RestException
156
+	 */
157
+	public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
158
+	{
159
+		if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
160
+			throw new EE_Error(
161
+				sprintf(
162
+					__(
163
+					// @codingStandardsIgnoreStart
164
+						'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
165
+						// @codingStandardsIgnoreEnd
166
+						'event_espresso'
167
+					),
168
+					print_r($wpdb_row, true)
169
+				)
170
+			);
171
+		}
172
+		$this->verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
173
+		return $this->registration_model->count(
174
+			array(
175
+				array(
176
+					'Ticket.Datetime.DTT_ID' => $wpdb_row['Datetime.DTT_ID'],
177
+					'STS_ID'                 => EEM_Registration::status_id_pending_payment,
178
+				),
179
+			),
180
+			'REG_ID',
181
+			true
182
+		);
183
+	}
184 184
 
185 185
 
186
-    /**
187
-     * Provides an array for all the calculations possible that outlines a json schema for those calculations.
188
-     * Array is indexed by calculation (snake case) and value is the schema for that calculation.
189
-     *
190
-     * @since $VID:$
191
-     * @return array
192
-     */
193
-    public function schemaForCalculations()
194
-    {
195
-        return array(
196
-            'spaces_remaining_considering_tickets' => array(
197
-                'description' => esc_html__(
198
-                    'Calculates the total spaces available on the datetime, taking into account ticket limits too.',
199
-                    'event_espresso'
200
-                ),
201
-                'type' => 'number'
202
-            ),
203
-            'registrations_checked_in_count' => array(
204
-                'description' => esc_html__(
205
-                    'Counts registrations who have checked into this datetime.',
206
-                    'event_espresso'
207
-                ),
208
-                'type' => 'number'
209
-            ),
210
-            'registrations_checked_out_count' => array(
211
-                'description' => esc_html__(
212
-                    'Counts registrations who have checked out of this datetime.',
213
-                    'event_espresso'
214
-                ),
215
-                'type' => 'number'
216
-            ),
217
-            'spots_taken_pending_payment' => array(
218
-                'description' => esc_html__(
219
-                    'The count of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for',
220
-                    'event_espresso'
221
-                ),
222
-                'type' => 'number'
223
-            ),
224
-        );
225
-    }
186
+	/**
187
+	 * Provides an array for all the calculations possible that outlines a json schema for those calculations.
188
+	 * Array is indexed by calculation (snake case) and value is the schema for that calculation.
189
+	 *
190
+	 * @since $VID:$
191
+	 * @return array
192
+	 */
193
+	public function schemaForCalculations()
194
+	{
195
+		return array(
196
+			'spaces_remaining_considering_tickets' => array(
197
+				'description' => esc_html__(
198
+					'Calculates the total spaces available on the datetime, taking into account ticket limits too.',
199
+					'event_espresso'
200
+				),
201
+				'type' => 'number'
202
+			),
203
+			'registrations_checked_in_count' => array(
204
+				'description' => esc_html__(
205
+					'Counts registrations who have checked into this datetime.',
206
+					'event_espresso'
207
+				),
208
+				'type' => 'number'
209
+			),
210
+			'registrations_checked_out_count' => array(
211
+				'description' => esc_html__(
212
+					'Counts registrations who have checked out of this datetime.',
213
+					'event_espresso'
214
+				),
215
+				'type' => 'number'
216
+			),
217
+			'spots_taken_pending_payment' => array(
218
+				'description' => esc_html__(
219
+					'The count of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for',
220
+					'event_espresso'
221
+				),
222
+				'type' => 'number'
223
+			),
224
+		);
225
+	}
226 226
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -87,7 +87,7 @@  discard block
 block discarded – undo
87 87
      */
88 88
     public function registrationsCheckedInCount($wpdb_row, $request, $controller)
89 89
     {
90
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
90
+        if ( ! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
91 91
             throw new EE_Error(
92 92
                 sprintf(
93 93
                     __(
@@ -121,7 +121,7 @@  discard block
 block discarded – undo
121 121
      */
122 122
     public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
123 123
     {
124
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
124
+        if ( ! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
125 125
             throw new EE_Error(
126 126
                 sprintf(
127 127
                     __(
@@ -156,7 +156,7 @@  discard block
 block discarded – undo
156 156
      */
157 157
     public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
158 158
     {
159
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
159
+        if ( ! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
160 160
             throw new EE_Error(
161 161
                 sprintf(
162 162
                     __(
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/Attendee.php 1 patch
Indentation   +37 added lines, -37 removed lines patch added patch discarded remove patch
@@ -17,43 +17,43 @@
 block discarded – undo
17 17
 class Attendee extends AttendeeCalculationsBase
18 18
 {
19 19
 
20
-    /**
21
-     * @param array                  $wpdb_row
22
-     * @param WP_REST_Request        $request
23
-     * @param AttendeeControllerBase $controller
24
-     * @since 4.9.66.p
25
-     * @return string
26
-     */
27
-    public function userAvatar(array $wpdb_row, WP_REST_Request $request, AttendeeControllerBase $controller)
28
-    {
29
-        if (is_array($wpdb_row) && isset($wpdb_row['Attendee_Meta.ATT_email'])) {
30
-            $email_address = $wpdb_row['Attendee_Meta.ATT_email'];
31
-        }
32
-        if (empty($email_address)) {
33
-            return '';
34
-        }
35
-        $avatar = get_avatar_url($email_address);
36
-        return $avatar ? $avatar : '';
37
-    }
20
+	/**
21
+	 * @param array                  $wpdb_row
22
+	 * @param WP_REST_Request        $request
23
+	 * @param AttendeeControllerBase $controller
24
+	 * @since 4.9.66.p
25
+	 * @return string
26
+	 */
27
+	public function userAvatar(array $wpdb_row, WP_REST_Request $request, AttendeeControllerBase $controller)
28
+	{
29
+		if (is_array($wpdb_row) && isset($wpdb_row['Attendee_Meta.ATT_email'])) {
30
+			$email_address = $wpdb_row['Attendee_Meta.ATT_email'];
31
+		}
32
+		if (empty($email_address)) {
33
+			return '';
34
+		}
35
+		$avatar = get_avatar_url($email_address);
36
+		return $avatar ? $avatar : '';
37
+	}
38 38
 
39 39
 
40
-    /**
41
-     * Provides an array for all the calculations possible that outlines a json schema for those calculations.
42
-     * Array is indexed by calculation (snake case) and value is the schema for that calculation.
43
-     *
44
-     * @since $VID:$
45
-     * @return array
46
-     */
47
-    public function schemaForCalculations()
48
-    {
49
-        return array(
50
-            'user_avatar' => array(
51
-                'description' => esc_html__(
52
-                    'The avatar url for the attendee (if available).',
53
-                    'event_espresso'
54
-                ),
55
-                'type'        => 'string',
56
-            ),
57
-        );
58
-    }
40
+	/**
41
+	 * Provides an array for all the calculations possible that outlines a json schema for those calculations.
42
+	 * Array is indexed by calculation (snake case) and value is the schema for that calculation.
43
+	 *
44
+	 * @since $VID:$
45
+	 * @return array
46
+	 */
47
+	public function schemaForCalculations()
48
+	{
49
+		return array(
50
+			'user_avatar' => array(
51
+				'description' => esc_html__(
52
+					'The avatar url for the attendee (if available).',
53
+					'event_espresso'
54
+				),
55
+				'type'        => 'string',
56
+			),
57
+		);
58
+	}
59 59
 }
Please login to merge, or discard this patch.