Completed
Branch add-wp-version-to-pue-stats (0dc30c)
by
unknown
35:52 queued 27:20
created
core/libraries/batch/JobHandlerBaseClasses/JobHandlerFile.php 2 patches
Indentation   +124 added lines, -124 removed lines patch added patch discarded remove patch
@@ -17,135 +17,135 @@
 block discarded – undo
17 17
  */
18 18
 abstract class JobHandlerFile extends JobHandler
19 19
 {
20
-    // phpcs:disable Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase
21
-    const temp_folder_name = 'batch_temp_folder';
20
+	// phpcs:disable Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase
21
+	const temp_folder_name = 'batch_temp_folder';
22 22
 
23
-    // phpcs:disable PSR2.Classes.PropertyDeclaration.Underscore
24
-    /**
25
-     * @var \EEHI_File
26
-     */
27
-    protected $_file_helper = null;
23
+	// phpcs:disable PSR2.Classes.PropertyDeclaration.Underscore
24
+	/**
25
+	 * @var \EEHI_File
26
+	 */
27
+	protected $_file_helper = null;
28 28
 
29 29
 
30
-    /**
31
-     * JobHandlerFile constructor.
32
-     *
33
-     * @param \EEHI_File|null $file_helper
34
-     */
35
-    public function __construct(\EEHI_File $file_helper = null)
36
-    {
37
-        if (! $file_helper) {
38
-            $this->_file_helper = new EEH_File();
39
-        }
40
-    }
30
+	/**
31
+	 * JobHandlerFile constructor.
32
+	 *
33
+	 * @param \EEHI_File|null $file_helper
34
+	 */
35
+	public function __construct(\EEHI_File $file_helper = null)
36
+	{
37
+		if (! $file_helper) {
38
+			$this->_file_helper = new EEH_File();
39
+		}
40
+	}
41 41
 
42
-    // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
43
-    /**
44
-     * Creates a file
45
-     *
46
-     * @param string $job_id
47
-     * @param string $filename
48
-     * @param string $filetype
49
-     * @param string $bom initial content to place in the file.
50
-     * @return string
51
-     * @throws \EventEspressoBatchRequest\Helpers\BatchRequestException
52
-     */
53
-    public function create_file_from_job_with_name(
54
-        $job_id,
55
-        $filename,
56
-        $filetype = 'application/ms-excel',
57
-        $bom = "\xEF\xBB\xBF"
58
-    ) {
59
-        $filepath = '';
60
-        try {
61
-            $base_folder = $this->get_base_folder();
62
-            $success = $this->_file_helper->ensure_folder_exists_and_is_writable(
63
-                $base_folder . JobHandlerFile::temp_folder_name
64
-            );
65
-            if ($success) {
66
-                $success = $this->_file_helper->ensure_folder_exists_and_is_writable(
67
-                    $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id
68
-                );
69
-            }
70
-            if ($success) {
71
-                $filepath = $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id . '/' . $filename;
72
-                $success = $this->_file_helper->ensure_file_exists_and_is_writable($filepath);
73
-            }
74
-            // let's add the .htaccess file so safari will open the file properly
75
-            if ($success) {
76
-                $extension = EEH_File::get_file_extension($filepath);
77
-                EEH_File::write_to_file(
78
-                    $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id . '/.htaccess',
79
-                    'AddType ' . $filetype . ' ' . $extension,
80
-                    '.htaccess'
81
-                );
82
-            }
83
-            /**
84
-             * Filters what initial content will be added to the file.
85
-             * @param string $return_value. By default it's whatever was pased into
86
-             *                              JobHandlerFile::create_file_from_job_with_name()
87
-             * @param string $filename
88
-             * @param string $filetype default 'application/ms-excel'
89
-             * @param string $filepath
90
-             */
91
-            EEH_File::write_to_file(
92
-                $filepath,
93
-                apply_filters(
94
-                    'FHEE__EE_CSV__begin_sending_csv__start_writing',
95
-                    $bom,
96
-                    $filename,
97
-                    $filetype,
98
-                    $filepath
99
-                )
100
-            );
101
-            // those methods normally fail with an exception, but if not, let's do it
102
-            if (! $success) {
103
-                throw new \EE_Error(__('Could not create temporary file, an unknown error occurred', 'event_espresso'));
104
-            }
105
-        } catch (\EE_Error $e) {
106
-            throw new BatchRequestException(
107
-                sprintf(
108
-                    // phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment
109
-                    __('Could not create temporary file for job %1$s, because: %2$s ', 'event_espresso'),
110
-                    $job_id,
111
-                    $e->getMessage()
112
-                ),
113
-                500,
114
-                $e
115
-            );
116
-        }
117
-        return $filepath;
118
-    }
42
+	// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
43
+	/**
44
+	 * Creates a file
45
+	 *
46
+	 * @param string $job_id
47
+	 * @param string $filename
48
+	 * @param string $filetype
49
+	 * @param string $bom initial content to place in the file.
50
+	 * @return string
51
+	 * @throws \EventEspressoBatchRequest\Helpers\BatchRequestException
52
+	 */
53
+	public function create_file_from_job_with_name(
54
+		$job_id,
55
+		$filename,
56
+		$filetype = 'application/ms-excel',
57
+		$bom = "\xEF\xBB\xBF"
58
+	) {
59
+		$filepath = '';
60
+		try {
61
+			$base_folder = $this->get_base_folder();
62
+			$success = $this->_file_helper->ensure_folder_exists_and_is_writable(
63
+				$base_folder . JobHandlerFile::temp_folder_name
64
+			);
65
+			if ($success) {
66
+				$success = $this->_file_helper->ensure_folder_exists_and_is_writable(
67
+					$base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id
68
+				);
69
+			}
70
+			if ($success) {
71
+				$filepath = $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id . '/' . $filename;
72
+				$success = $this->_file_helper->ensure_file_exists_and_is_writable($filepath);
73
+			}
74
+			// let's add the .htaccess file so safari will open the file properly
75
+			if ($success) {
76
+				$extension = EEH_File::get_file_extension($filepath);
77
+				EEH_File::write_to_file(
78
+					$base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id . '/.htaccess',
79
+					'AddType ' . $filetype . ' ' . $extension,
80
+					'.htaccess'
81
+				);
82
+			}
83
+			/**
84
+			 * Filters what initial content will be added to the file.
85
+			 * @param string $return_value. By default it's whatever was pased into
86
+			 *                              JobHandlerFile::create_file_from_job_with_name()
87
+			 * @param string $filename
88
+			 * @param string $filetype default 'application/ms-excel'
89
+			 * @param string $filepath
90
+			 */
91
+			EEH_File::write_to_file(
92
+				$filepath,
93
+				apply_filters(
94
+					'FHEE__EE_CSV__begin_sending_csv__start_writing',
95
+					$bom,
96
+					$filename,
97
+					$filetype,
98
+					$filepath
99
+				)
100
+			);
101
+			// those methods normally fail with an exception, but if not, let's do it
102
+			if (! $success) {
103
+				throw new \EE_Error(__('Could not create temporary file, an unknown error occurred', 'event_espresso'));
104
+			}
105
+		} catch (\EE_Error $e) {
106
+			throw new BatchRequestException(
107
+				sprintf(
108
+					// phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment
109
+					__('Could not create temporary file for job %1$s, because: %2$s ', 'event_espresso'),
110
+					$job_id,
111
+					$e->getMessage()
112
+				),
113
+				500,
114
+				$e
115
+			);
116
+		}
117
+		return $filepath;
118
+	}
119 119
 
120
-    /**
121
-     * Gets the URL to download the file
122
-     *
123
-     * @param string $filepath
124
-     * @return string url to file
125
-     */
126
-    public function get_url_to_file($filepath)
127
-    {
128
-        return str_replace($this->get_base_folder(), $this->get_base_url(), $filepath);
129
-    }
120
+	/**
121
+	 * Gets the URL to download the file
122
+	 *
123
+	 * @param string $filepath
124
+	 * @return string url to file
125
+	 */
126
+	public function get_url_to_file($filepath)
127
+	{
128
+		return str_replace($this->get_base_folder(), $this->get_base_url(), $filepath);
129
+	}
130 130
 
131
-    /**
132
-     * Gets the folder which will contain the "batch_temp_folder"
133
-     *
134
-     * @return string
135
-     */
136
-    public function get_base_folder()
137
-    {
138
-        return apply_filters(
139
-            'FHEE__EventEspressoBatchRequest\JobHandlerBaseClasses\JobHandlerFile__get_base_folder',
140
-            EVENT_ESPRESSO_UPLOAD_DIR
141
-        );
142
-    }
131
+	/**
132
+	 * Gets the folder which will contain the "batch_temp_folder"
133
+	 *
134
+	 * @return string
135
+	 */
136
+	public function get_base_folder()
137
+	{
138
+		return apply_filters(
139
+			'FHEE__EventEspressoBatchRequest\JobHandlerBaseClasses\JobHandlerFile__get_base_folder',
140
+			EVENT_ESPRESSO_UPLOAD_DIR
141
+		);
142
+	}
143 143
 
144
-    public function get_base_url()
145
-    {
146
-        return apply_filters(
147
-            'FHEE__EventEspressoBatchRequest\JobHandlerBaseClasses\JobHandlerFile__get_base_url',
148
-            EVENT_ESPRESSO_UPLOAD_URL
149
-        );
150
-    }
144
+	public function get_base_url()
145
+	{
146
+		return apply_filters(
147
+			'FHEE__EventEspressoBatchRequest\JobHandlerBaseClasses\JobHandlerFile__get_base_url',
148
+			EVENT_ESPRESSO_UPLOAD_URL
149
+		);
150
+	}
151 151
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -34,7 +34,7 @@  discard block
 block discarded – undo
34 34
      */
35 35
     public function __construct(\EEHI_File $file_helper = null)
36 36
     {
37
-        if (! $file_helper) {
37
+        if ( ! $file_helper) {
38 38
             $this->_file_helper = new EEH_File();
39 39
         }
40 40
     }
@@ -60,23 +60,23 @@  discard block
 block discarded – undo
60 60
         try {
61 61
             $base_folder = $this->get_base_folder();
62 62
             $success = $this->_file_helper->ensure_folder_exists_and_is_writable(
63
-                $base_folder . JobHandlerFile::temp_folder_name
63
+                $base_folder.JobHandlerFile::temp_folder_name
64 64
             );
65 65
             if ($success) {
66 66
                 $success = $this->_file_helper->ensure_folder_exists_and_is_writable(
67
-                    $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id
67
+                    $base_folder.JobHandlerFile::temp_folder_name.'/'.$job_id
68 68
                 );
69 69
             }
70 70
             if ($success) {
71
-                $filepath = $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id . '/' . $filename;
71
+                $filepath = $base_folder.JobHandlerFile::temp_folder_name.'/'.$job_id.'/'.$filename;
72 72
                 $success = $this->_file_helper->ensure_file_exists_and_is_writable($filepath);
73 73
             }
74 74
             // let's add the .htaccess file so safari will open the file properly
75 75
             if ($success) {
76 76
                 $extension = EEH_File::get_file_extension($filepath);
77 77
                 EEH_File::write_to_file(
78
-                    $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id . '/.htaccess',
79
-                    'AddType ' . $filetype . ' ' . $extension,
78
+                    $base_folder.JobHandlerFile::temp_folder_name.'/'.$job_id.'/.htaccess',
79
+                    'AddType '.$filetype.' '.$extension,
80 80
                     '.htaccess'
81 81
                 );
82 82
             }
@@ -99,7 +99,7 @@  discard block
 block discarded – undo
99 99
                 )
100 100
             );
101 101
             // those methods normally fail with an exception, but if not, let's do it
102
-            if (! $success) {
102
+            if ( ! $success) {
103 103
                 throw new \EE_Error(__('Could not create temporary file, an unknown error occurred', 'event_espresso'));
104 104
             }
105 105
         } catch (\EE_Error $e) {
Please login to merge, or discard this patch.
core/EE_Registry.core.php 2 patches
Indentation   +1675 added lines, -1675 removed lines patch added patch discarded remove patch
@@ -23,1679 +23,1679 @@
 block discarded – undo
23 23
 class EE_Registry implements ResettableInterface
24 24
 {
25 25
 
26
-    /**
27
-     * @var EE_Registry $_instance
28
-     */
29
-    private static $_instance;
30
-
31
-    /**
32
-     * @var EE_Dependency_Map $_dependency_map
33
-     */
34
-    protected $_dependency_map;
35
-
36
-    /**
37
-     * @var Mirror
38
-     */
39
-    private $mirror;
40
-
41
-    /**
42
-     * @var ClassInterfaceCache $class_cache
43
-     */
44
-    private $class_cache;
45
-
46
-    /**
47
-     * @var array $_class_abbreviations
48
-     */
49
-    protected $_class_abbreviations = array();
50
-
51
-    /**
52
-     * @var CommandBusInterface $BUS
53
-     */
54
-    public $BUS;
55
-
56
-    /**
57
-     * @var EE_Cart $CART
58
-     */
59
-    public $CART;
60
-
61
-    /**
62
-     * @var EE_Config $CFG
63
-     */
64
-    public $CFG;
65
-
66
-    /**
67
-     * @var EE_Network_Config $NET_CFG
68
-     */
69
-    public $NET_CFG;
70
-
71
-    /**
72
-     * StdClass object for storing library classes in
73
-     *
74
-     * @var RegistryContainer $LIB
75
-     */
76
-    public $LIB;
77
-
78
-    /**
79
-     * @var EE_Request_Handler $REQ
80
-     */
81
-    public $REQ;
82
-
83
-    /**
84
-     * @var EE_Session $SSN
85
-     */
86
-    public $SSN;
87
-
88
-    /**
89
-     * @since 4.5.0
90
-     * @var EE_Capabilities $CAP
91
-     */
92
-    public $CAP;
93
-
94
-    /**
95
-     * @since 4.9.0
96
-     * @var EE_Message_Resource_Manager $MRM
97
-     */
98
-    public $MRM;
99
-
100
-    /**
101
-     * @var Registry $AssetsRegistry
102
-     */
103
-    public $AssetsRegistry;
104
-
105
-    /**
106
-     * StdClass object for holding addons which have registered themselves to work with EE core
107
-     *
108
-     * @var EE_Addon[] $addons
109
-     */
110
-    public $addons;
111
-
112
-    /**
113
-     * keys are 'short names' (eg Event), values are class names (eg 'EEM_Event')
114
-     *
115
-     * @var EEM_Base[] $models
116
-     */
117
-    public $models = array();
118
-
119
-    /**
120
-     * @var EED_Module[] $modules
121
-     */
122
-    public $modules;
123
-
124
-    /**
125
-     * @var EES_Shortcode[] $shortcodes
126
-     */
127
-    public $shortcodes;
128
-
129
-    /**
130
-     * @var WP_Widget[] $widgets
131
-     */
132
-    public $widgets;
133
-
134
-    /**
135
-     * this is an array of all implemented model names (i.e. not the parent abstract models, or models
136
-     * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)).
137
-     * Keys are model "short names" (eg "Event") as used in model relations, and values are
138
-     * classnames (eg "EEM_Event")
139
-     *
140
-     * @var array $non_abstract_db_models
141
-     */
142
-    public $non_abstract_db_models = array();
143
-
144
-    /**
145
-     * internationalization for JS strings
146
-     *    usage:   EE_Registry::i18n_js_strings['string_key'] = esc_html__( 'string to translate.', 'event_espresso' );
147
-     *    in js file:  var translatedString = eei18n.string_key;
148
-     *
149
-     * @var array $i18n_js_strings
150
-     */
151
-    public static $i18n_js_strings = array();
152
-
153
-    /**
154
-     * $main_file - path to espresso.php
155
-     *
156
-     * @var array $main_file
157
-     */
158
-    public $main_file;
159
-
160
-    /**
161
-     * array of ReflectionClass objects where the key is the class name
162
-     *
163
-     * @deprecated 4.9.62.p
164
-     * @var ReflectionClass[] $_reflectors
165
-     */
166
-    public $_reflectors;
167
-
168
-    /**
169
-     * boolean flag to indicate whether or not to load/save dependencies from/to the cache
170
-     *
171
-     * @var boolean $_cache_on
172
-     */
173
-    protected $_cache_on = true;
174
-
175
-    /**
176
-     * @var ObjectIdentifier
177
-     */
178
-    private $object_identifier;
179
-
180
-
181
-    /**
182
-     * @singleton method used to instantiate class object
183
-     * @param EE_Dependency_Map|null   $dependency_map
184
-     * @param Mirror|null              $mirror
185
-     * @param ClassInterfaceCache|null $class_cache
186
-     * @param ObjectIdentifier|null    $object_identifier
187
-     * @return EE_Registry instance
188
-     */
189
-    public static function instance(
190
-        EE_Dependency_Map $dependency_map = null,
191
-        Mirror $mirror = null,
192
-        ClassInterfaceCache $class_cache = null,
193
-        ObjectIdentifier $object_identifier = null
194
-    ) {
195
-        // check if class object is instantiated
196
-        if (! self::$_instance instanceof EE_Registry
197
-            && $dependency_map instanceof EE_Dependency_Map
198
-            && $mirror instanceof Mirror
199
-            && $class_cache instanceof ClassInterfaceCache
200
-            && $object_identifier instanceof ObjectIdentifier
201
-        ) {
202
-            self::$_instance = new self(
203
-                $dependency_map,
204
-                $mirror,
205
-                $class_cache,
206
-                $object_identifier
207
-            );
208
-        }
209
-        return self::$_instance;
210
-    }
211
-
212
-
213
-    /**
214
-     * protected constructor to prevent direct creation
215
-     *
216
-     * @Constructor
217
-     * @param  EE_Dependency_Map  $dependency_map
218
-     * @param Mirror              $mirror
219
-     * @param ClassInterfaceCache $class_cache
220
-     * @param ObjectIdentifier    $object_identifier
221
-     */
222
-    protected function __construct(
223
-        EE_Dependency_Map $dependency_map,
224
-        Mirror $mirror,
225
-        ClassInterfaceCache $class_cache,
226
-        ObjectIdentifier $object_identifier
227
-    ) {
228
-        $this->_dependency_map = $dependency_map;
229
-        $this->mirror = $mirror;
230
-        $this->class_cache = $class_cache;
231
-        $this->object_identifier = $object_identifier;
232
-        // $registry_container = new RegistryContainer();
233
-        $this->LIB = new RegistryContainer();
234
-        $this->addons = new RegistryContainer();
235
-        $this->modules = new RegistryContainer();
236
-        $this->shortcodes = new RegistryContainer();
237
-        $this->widgets = new RegistryContainer();
238
-        add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
239
-    }
240
-
241
-
242
-    /**
243
-     * initialize
244
-     *
245
-     * @throws OutOfBoundsException
246
-     * @throws InvalidArgumentException
247
-     * @throws InvalidInterfaceException
248
-     * @throws InvalidDataTypeException
249
-     * @throws EE_Error
250
-     * @throws ReflectionException
251
-     */
252
-    public function initialize()
253
-    {
254
-        $this->_class_abbreviations = apply_filters(
255
-            'FHEE__EE_Registry____construct___class_abbreviations',
256
-            array(
257
-                'EE_Config'                                       => 'CFG',
258
-                'EE_Session'                                      => 'SSN',
259
-                'EE_Capabilities'                                 => 'CAP',
260
-                'EE_Cart'                                         => 'CART',
261
-                'EE_Network_Config'                               => 'NET_CFG',
262
-                'EE_Request_Handler'                              => 'REQ',
263
-                'EE_Message_Resource_Manager'                     => 'MRM',
264
-                'EventEspresso\core\services\commands\CommandBus' => 'BUS',
265
-                'EventEspresso\core\services\assets\Registry'     => 'AssetsRegistry',
266
-            )
267
-        );
268
-        $this->load_core('Base', array(), true);
269
-        // add our request and response objects to the cache
270
-        $request_loader = $this->_dependency_map->class_loader(
271
-            'EventEspresso\core\services\request\Request'
272
-        );
273
-        $this->_set_cached_class(
274
-            $request_loader(),
275
-            'EventEspresso\core\services\request\Request'
276
-        );
277
-        $response_loader = $this->_dependency_map->class_loader(
278
-            'EventEspresso\core\services\request\Response'
279
-        );
280
-        $this->_set_cached_class(
281
-            $response_loader(),
282
-            'EventEspresso\core\services\request\Response'
283
-        );
284
-        add_action('AHEE__EE_System__set_hooks_for_core', array($this, 'init'));
285
-    }
286
-
287
-
288
-    /**
289
-     * @return void
290
-     */
291
-    public function init()
292
-    {
293
-        // Get current page protocol
294
-        $protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
295
-        // Output admin-ajax.php URL with same protocol as current page
296
-        self::$i18n_js_strings['ajax_url'] = admin_url('admin-ajax.php', $protocol);
297
-        self::$i18n_js_strings['wp_debug'] = defined('WP_DEBUG') ? WP_DEBUG : false;
298
-    }
299
-
300
-
301
-    /**
302
-     * localize_i18n_js_strings
303
-     *
304
-     * @return string
305
-     */
306
-    public static function localize_i18n_js_strings()
307
-    {
308
-        $i18n_js_strings = (array) self::$i18n_js_strings;
309
-        foreach ($i18n_js_strings as $key => $value) {
310
-            if (is_scalar($value)) {
311
-                $i18n_js_strings[ $key ] = html_entity_decode((string) $value, ENT_QUOTES, 'UTF-8');
312
-            }
313
-        }
314
-        return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
315
-    }
316
-
317
-
318
-    /**
319
-     * @param mixed string | EED_Module $module
320
-     * @throws OutOfBoundsException
321
-     * @throws InvalidArgumentException
322
-     * @throws InvalidInterfaceException
323
-     * @throws InvalidDataTypeException
324
-     * @throws EE_Error
325
-     * @throws ReflectionException
326
-     */
327
-    public function add_module($module)
328
-    {
329
-        if ($module instanceof EED_Module) {
330
-            $module_class = get_class($module);
331
-            $this->modules->{$module_class} = $module;
332
-        } else {
333
-            if (! class_exists('EE_Module_Request_Router', false)) {
334
-                $this->load_core('Module_Request_Router');
335
-            }
336
-            EE_Module_Request_Router::module_factory($module);
337
-        }
338
-    }
339
-
340
-
341
-    /**
342
-     * @param string $module_name
343
-     * @return mixed EED_Module | NULL
344
-     */
345
-    public function get_module($module_name = '')
346
-    {
347
-        return isset($this->modules->{$module_name})
348
-            ? $this->modules->{$module_name}
349
-            : null;
350
-    }
351
-
352
-
353
-    /**
354
-     * loads core classes - must be singletons
355
-     *
356
-     * @param string $class_name - simple class name ie: session
357
-     * @param mixed  $arguments
358
-     * @param bool   $load_only
359
-     * @return mixed
360
-     * @throws InvalidInterfaceException
361
-     * @throws InvalidDataTypeException
362
-     * @throws EE_Error
363
-     * @throws ReflectionException
364
-     * @throws InvalidArgumentException
365
-     */
366
-    public function load_core($class_name, $arguments = array(), $load_only = false)
367
-    {
368
-        $core_paths = apply_filters(
369
-            'FHEE__EE_Registry__load_core__core_paths',
370
-            array(
371
-                EE_CORE,
372
-                EE_ADMIN,
373
-                EE_CPTS,
374
-                EE_CORE . 'data_migration_scripts/',
375
-                EE_CORE . 'capabilities/',
376
-                EE_CORE . 'request_stack/',
377
-                EE_CORE . 'middleware/',
378
-            )
379
-        );
380
-        // retrieve instantiated class
381
-        return $this->_load(
382
-            $core_paths,
383
-            'EE_',
384
-            $class_name,
385
-            'core',
386
-            $arguments,
387
-            false,
388
-            true,
389
-            $load_only
390
-        );
391
-    }
392
-
393
-
394
-    /**
395
-     * loads service classes
396
-     *
397
-     * @param string $class_name - simple class name ie: session
398
-     * @param mixed  $arguments
399
-     * @param bool   $load_only
400
-     * @return mixed
401
-     * @throws InvalidInterfaceException
402
-     * @throws InvalidDataTypeException
403
-     * @throws EE_Error
404
-     * @throws ReflectionException
405
-     * @throws InvalidArgumentException
406
-     */
407
-    public function load_service($class_name, $arguments = array(), $load_only = false)
408
-    {
409
-        $service_paths = apply_filters(
410
-            'FHEE__EE_Registry__load_service__service_paths',
411
-            array(
412
-                EE_CORE . 'services/',
413
-            )
414
-        );
415
-        // retrieve instantiated class
416
-        return $this->_load(
417
-            $service_paths,
418
-            'EE_',
419
-            $class_name,
420
-            'class',
421
-            $arguments,
422
-            false,
423
-            true,
424
-            $load_only
425
-        );
426
-    }
427
-
428
-
429
-    /**
430
-     * loads data_migration_scripts
431
-     *
432
-     * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
433
-     * @param mixed  $arguments
434
-     * @return EE_Data_Migration_Script_Base|mixed
435
-     * @throws InvalidInterfaceException
436
-     * @throws InvalidDataTypeException
437
-     * @throws EE_Error
438
-     * @throws ReflectionException
439
-     * @throws InvalidArgumentException
440
-     */
441
-    public function load_dms($class_name, $arguments = array())
442
-    {
443
-        // retrieve instantiated class
444
-        return $this->_load(
445
-            EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(),
446
-            'EE_DMS_',
447
-            $class_name,
448
-            'dms',
449
-            $arguments,
450
-            false,
451
-            false
452
-        );
453
-    }
454
-
455
-
456
-    /**
457
-     * loads object creating classes - must be singletons
458
-     *
459
-     * @param string $class_name - simple class name ie: attendee
460
-     * @param mixed  $arguments  - an array of arguments to pass to the class
461
-     * @param bool   $from_db    - some classes are instantiated from the db and thus call a different method to
462
-     *                           instantiate
463
-     * @param bool   $cache      if you don't want the class to be stored in the internal cache (non-persistent) then
464
-     *                           set this to FALSE (ie. when instantiating model objects from client in a loop)
465
-     * @param bool   $load_only  whether or not to just load the file and NOT instantiate, or load AND instantiate
466
-     *                           (default)
467
-     * @return EE_Base_Class | bool
468
-     * @throws InvalidInterfaceException
469
-     * @throws InvalidDataTypeException
470
-     * @throws EE_Error
471
-     * @throws ReflectionException
472
-     * @throws InvalidArgumentException
473
-     */
474
-    public function load_class($class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false)
475
-    {
476
-        $paths = apply_filters(
477
-            'FHEE__EE_Registry__load_class__paths',
478
-            array(
479
-                EE_CORE,
480
-                EE_CLASSES,
481
-                EE_BUSINESS,
482
-            )
483
-        );
484
-        // retrieve instantiated class
485
-        return $this->_load(
486
-            $paths,
487
-            'EE_',
488
-            $class_name,
489
-            'class',
490
-            $arguments,
491
-            $from_db,
492
-            $cache,
493
-            $load_only
494
-        );
495
-    }
496
-
497
-
498
-    /**
499
-     * loads helper classes - must be singletons
500
-     *
501
-     * @param string $class_name - simple class name ie: price
502
-     * @param mixed  $arguments
503
-     * @param bool   $load_only
504
-     * @return EEH_Base | bool
505
-     * @throws InvalidInterfaceException
506
-     * @throws InvalidDataTypeException
507
-     * @throws EE_Error
508
-     * @throws ReflectionException
509
-     * @throws InvalidArgumentException
510
-     */
511
-    public function load_helper($class_name, $arguments = array(), $load_only = true)
512
-    {
513
-        // todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed
514
-        $helper_paths = apply_filters('FHEE__EE_Registry__load_helper__helper_paths', array(EE_HELPERS));
515
-        // retrieve instantiated class
516
-        return $this->_load(
517
-            $helper_paths,
518
-            'EEH_',
519
-            $class_name,
520
-            'helper',
521
-            $arguments,
522
-            false,
523
-            true,
524
-            $load_only
525
-        );
526
-    }
527
-
528
-
529
-    /**
530
-     * loads core classes - must be singletons
531
-     *
532
-     * @param string $class_name - simple class name ie: session
533
-     * @param mixed  $arguments
534
-     * @param bool   $load_only
535
-     * @param bool   $cache      whether to cache the object or not.
536
-     * @return mixed
537
-     * @throws InvalidInterfaceException
538
-     * @throws InvalidDataTypeException
539
-     * @throws EE_Error
540
-     * @throws ReflectionException
541
-     * @throws InvalidArgumentException
542
-     */
543
-    public function load_lib($class_name, $arguments = array(), $load_only = false, $cache = true)
544
-    {
545
-        $paths = array(
546
-            EE_LIBRARIES,
547
-            EE_LIBRARIES . 'messages/',
548
-            EE_LIBRARIES . 'shortcodes/',
549
-            EE_LIBRARIES . 'qtips/',
550
-            EE_LIBRARIES . 'payment_methods/',
551
-        );
552
-        // retrieve instantiated class
553
-        return $this->_load(
554
-            $paths,
555
-            'EE_',
556
-            $class_name,
557
-            'lib',
558
-            $arguments,
559
-            false,
560
-            $cache,
561
-            $load_only
562
-        );
563
-    }
564
-
565
-
566
-    /**
567
-     * loads model classes - must be singletons
568
-     *
569
-     * @param string $class_name - simple class name ie: price
570
-     * @param mixed  $arguments
571
-     * @param bool   $load_only
572
-     * @return EEM_Base | bool
573
-     * @throws InvalidInterfaceException
574
-     * @throws InvalidDataTypeException
575
-     * @throws EE_Error
576
-     * @throws ReflectionException
577
-     * @throws InvalidArgumentException
578
-     */
579
-    public function load_model($class_name, $arguments = array(), $load_only = false)
580
-    {
581
-        $paths = apply_filters(
582
-            'FHEE__EE_Registry__load_model__paths',
583
-            array(
584
-                EE_MODELS,
585
-                EE_CORE,
586
-            )
587
-        );
588
-        // retrieve instantiated class
589
-        return $this->_load(
590
-            $paths,
591
-            'EEM_',
592
-            $class_name,
593
-            'model',
594
-            $arguments,
595
-            false,
596
-            true,
597
-            $load_only
598
-        );
599
-    }
600
-
601
-
602
-    /**
603
-     * loads model classes - must be singletons
604
-     *
605
-     * @param string $class_name - simple class name ie: price
606
-     * @param mixed  $arguments
607
-     * @param bool   $load_only
608
-     * @return mixed | bool
609
-     * @throws InvalidInterfaceException
610
-     * @throws InvalidDataTypeException
611
-     * @throws EE_Error
612
-     * @throws ReflectionException
613
-     * @throws InvalidArgumentException
614
-     */
615
-    public function load_model_class($class_name, $arguments = array(), $load_only = true)
616
-    {
617
-        $paths = array(
618
-            EE_MODELS . 'fields/',
619
-            EE_MODELS . 'helpers/',
620
-            EE_MODELS . 'relations/',
621
-            EE_MODELS . 'strategies/',
622
-        );
623
-        // retrieve instantiated class
624
-        return $this->_load(
625
-            $paths,
626
-            'EE_',
627
-            $class_name,
628
-            '',
629
-            $arguments,
630
-            false,
631
-            true,
632
-            $load_only
633
-        );
634
-    }
635
-
636
-
637
-    /**
638
-     * Determines if $model_name is the name of an actual EE model.
639
-     *
640
-     * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
641
-     * @return boolean
642
-     */
643
-    public function is_model_name($model_name)
644
-    {
645
-        return isset($this->models[ $model_name ]);
646
-    }
647
-
648
-
649
-    /**
650
-     * generic class loader
651
-     *
652
-     * @param string $path_to_file - directory path to file location, not including filename
653
-     * @param string $file_name    - file name  ie:  my_file.php, including extension
654
-     * @param string $type         - file type - core? class? helper? model?
655
-     * @param mixed  $arguments
656
-     * @param bool   $load_only
657
-     * @return mixed
658
-     * @throws InvalidInterfaceException
659
-     * @throws InvalidDataTypeException
660
-     * @throws EE_Error
661
-     * @throws ReflectionException
662
-     * @throws InvalidArgumentException
663
-     */
664
-    public function load_file($path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true)
665
-    {
666
-        // retrieve instantiated class
667
-        return $this->_load(
668
-            $path_to_file,
669
-            '',
670
-            $file_name,
671
-            $type,
672
-            $arguments,
673
-            false,
674
-            true,
675
-            $load_only
676
-        );
677
-    }
678
-
679
-
680
-    /**
681
-     * @param string $path_to_file - directory path to file location, not including filename
682
-     * @param string $class_name   - full class name  ie:  My_Class
683
-     * @param string $type         - file type - core? class? helper? model?
684
-     * @param mixed  $arguments
685
-     * @param bool   $load_only
686
-     * @return bool|EE_Addon|object
687
-     * @throws InvalidInterfaceException
688
-     * @throws InvalidDataTypeException
689
-     * @throws EE_Error
690
-     * @throws ReflectionException
691
-     * @throws InvalidArgumentException
692
-     */
693
-    public function load_addon($path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false)
694
-    {
695
-        // retrieve instantiated class
696
-        return $this->_load(
697
-            $path_to_file,
698
-            'addon',
699
-            $class_name,
700
-            $type,
701
-            $arguments,
702
-            false,
703
-            true,
704
-            $load_only
705
-        );
706
-    }
707
-
708
-
709
-    /**
710
-     * instantiates, caches, and automatically resolves dependencies
711
-     * for classes that use a Fully Qualified Class Name.
712
-     * if the class is not capable of being loaded using PSR-4 autoloading,
713
-     * then you need to use one of the existing load_*() methods
714
-     * which can resolve the classname and filepath from the passed arguments
715
-     *
716
-     * @param bool|string $class_name   Fully Qualified Class Name
717
-     * @param array       $arguments    an argument, or array of arguments to pass to the class upon instantiation
718
-     * @param bool        $cache        whether to cache the instantiated object for reuse
719
-     * @param bool        $from_db      some classes are instantiated from the db
720
-     *                                  and thus call a different method to instantiate
721
-     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
722
-     * @param bool|string $addon        if true, will cache the object in the EE_Registry->$addons array
723
-     * @return bool|null|mixed          null = failure to load or instantiate class object.
724
-     *                                  object = class loaded and instantiated successfully.
725
-     *                                  bool = fail or success when $load_only is true
726
-     * @throws InvalidInterfaceException
727
-     * @throws InvalidDataTypeException
728
-     * @throws EE_Error
729
-     * @throws ReflectionException
730
-     * @throws InvalidArgumentException
731
-     */
732
-    public function create(
733
-        $class_name = false,
734
-        $arguments = array(),
735
-        $cache = false,
736
-        $from_db = false,
737
-        $load_only = false,
738
-        $addon = false
739
-    ) {
740
-        $class_name = ltrim($class_name, '\\');
741
-        $class_name = $this->class_cache->getFqnForAlias($class_name);
742
-        $class_exists = $this->loadOrVerifyClassExists($class_name, $arguments);
743
-        // if a non-FQCN was passed, then
744
-        // verifyClassExists() might return an object
745
-        // or it could return null if the class just could not be found anywhere
746
-        if ($class_exists instanceof $class_name || $class_exists === null) {
747
-            // either way, return the results
748
-            return $class_exists;
749
-        }
750
-        $class_name = $class_exists;
751
-        // if we're only loading the class and it already exists, then let's just return true immediately
752
-        if ($load_only) {
753
-            return true;
754
-        }
755
-        $addon = $addon ? 'addon' : '';
756
-        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
757
-        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
758
-        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
759
-        if ($this->_cache_on && $cache && ! $load_only) {
760
-            // return object if it's already cached
761
-            $cached_class = $this->_get_cached_class($class_name, $addon, $arguments);
762
-            if ($cached_class !== null) {
763
-                return $cached_class;
764
-            }
765
-        }// obtain the loader method from the dependency map
766
-        $loader = $this->_dependency_map->class_loader($class_name);// instantiate the requested object
767
-        if ($loader instanceof Closure) {
768
-            $class_obj = $loader($arguments);
769
-        } else {
770
-            if ($loader && method_exists($this, $loader)) {
771
-                $class_obj = $this->{$loader}($class_name, $arguments);
772
-            } else {
773
-                $class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db);
774
-            }
775
-        }
776
-        if (($this->_cache_on && $cache) || $this->get_class_abbreviation($class_name, '')) {
777
-            // save it for later... kinda like gum  { : $
778
-            $this->_set_cached_class(
779
-                $class_obj,
780
-                $class_name,
781
-                $addon,
782
-                $from_db,
783
-                $arguments
784
-            );
785
-        }
786
-        $this->_cache_on = true;
787
-        return $class_obj;
788
-    }
789
-
790
-
791
-    /**
792
-     * Recursively checks that a class exists and potentially attempts to load classes with non-FQCNs
793
-     *
794
-     * @param string|object $class_name
795
-     * @param array         $arguments
796
-     * @param int           $attempt
797
-     * @return mixed
798
-     */
799
-    private function loadOrVerifyClassExists($class_name, array $arguments, $attempt = 1)
800
-    {
801
-        if (is_object($class_name) || class_exists($class_name)) {
802
-            return $class_name;
803
-        }
804
-        switch ($attempt) {
805
-            case 1:
806
-                // if it's a FQCN then maybe the class is registered with a preceding \
807
-                $class_name = strpos($class_name, '\\') !== false
808
-                    ? '\\' . ltrim($class_name, '\\')
809
-                    : $class_name;
810
-                break;
811
-            case 2:
812
-                //
813
-                $loader = $this->_dependency_map->class_loader($class_name);
814
-                if ($loader && method_exists($this, $loader)) {
815
-                    return $this->{$loader}($class_name, $arguments);
816
-                }
817
-                break;
818
-            case 3:
819
-            default:
820
-                return null;
821
-        }
822
-        $attempt++;
823
-        return $this->loadOrVerifyClassExists($class_name, $arguments, $attempt);
824
-    }
825
-
826
-
827
-    /**
828
-     * instantiates, caches, and injects dependencies for classes
829
-     *
830
-     * @param array       $file_paths   an array of paths to folders to look in
831
-     * @param string      $class_prefix EE  or EEM or... ???
832
-     * @param bool|string $class_name   $class name
833
-     * @param string      $type         file type - core? class? helper? model?
834
-     * @param mixed       $arguments    an argument or array of arguments to pass to the class upon instantiation
835
-     * @param bool        $from_db      some classes are instantiated from the db
836
-     *                                  and thus call a different method to instantiate
837
-     * @param bool        $cache        whether to cache the instantiated object for reuse
838
-     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
839
-     * @return bool|null|object null = failure to load or instantiate class object.
840
-     *                                  object = class loaded and instantiated successfully.
841
-     *                                  bool = fail or success when $load_only is true
842
-     * @throws EE_Error
843
-     * @throws ReflectionException
844
-     * @throws InvalidInterfaceException
845
-     * @throws InvalidDataTypeException
846
-     * @throws InvalidArgumentException
847
-     */
848
-    protected function _load(
849
-        $file_paths = array(),
850
-        $class_prefix = 'EE_',
851
-        $class_name = false,
852
-        $type = 'class',
853
-        $arguments = array(),
854
-        $from_db = false,
855
-        $cache = true,
856
-        $load_only = false
857
-    ) {
858
-        $class_name = ltrim($class_name, '\\');
859
-        // strip php file extension
860
-        $class_name = str_replace('.php', '', trim($class_name));
861
-        // does the class have a prefix ?
862
-        if (! empty($class_prefix) && $class_prefix !== 'addon') {
863
-            // make sure $class_prefix is uppercase
864
-            $class_prefix = strtoupper(trim($class_prefix));
865
-            // add class prefix ONCE!!!
866
-            $class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
867
-        }
868
-        $class_name = $this->class_cache->getFqnForAlias($class_name);
869
-        $class_exists = class_exists($class_name, false);
870
-        // if we're only loading the class and it already exists, then let's just return true immediately
871
-        if ($load_only && $class_exists) {
872
-            return true;
873
-        }
874
-        $arguments = is_array($arguments) ? $arguments : array($arguments);
875
-        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
876
-        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
877
-        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
878
-        if ($this->_cache_on && $cache && ! $load_only) {
879
-            // return object if it's already cached
880
-            $cached_class = $this->_get_cached_class($class_name, $class_prefix, $arguments);
881
-            if ($cached_class !== null) {
882
-                return $cached_class;
883
-            }
884
-        }
885
-        // if the class doesn't already exist.. then we need to try and find the file and load it
886
-        if (! $class_exists) {
887
-            // get full path to file
888
-            $path = $this->_resolve_path($class_name, $type, $file_paths);
889
-            // load the file
890
-            $loaded = $this->_require_file($path, $class_name, $type, $file_paths);
891
-            // if we are only loading a file but NOT instantiating an object
892
-            // then return boolean for whether class was loaded or not
893
-            if ($load_only) {
894
-                return $loaded;
895
-            }
896
-            // if an object was expected but loading failed, then return nothing
897
-            if (! $loaded) {
898
-                return null;
899
-            }
900
-        }
901
-        // instantiate the requested object
902
-        $class_obj = $this->_create_object($class_name, $arguments, $type, $from_db);
903
-        if ($this->_cache_on && $cache) {
904
-            // save it for later... kinda like gum  { : $
905
-            $this->_set_cached_class(
906
-                $class_obj,
907
-                $class_name,
908
-                $class_prefix,
909
-                $from_db,
910
-                $arguments
911
-            );
912
-        }
913
-        $this->_cache_on = true;
914
-        return $class_obj;
915
-    }
916
-
917
-
918
-    /**
919
-     * @param string $class_name
920
-     * @param string $default have to specify something, but not anything that will conflict
921
-     * @return mixed|string
922
-     */
923
-    protected function get_class_abbreviation($class_name, $default = 'FANCY_BATMAN_PANTS')
924
-    {
925
-        return isset($this->_class_abbreviations[ $class_name ])
926
-            ? $this->_class_abbreviations[ $class_name ]
927
-            : $default;
928
-    }
929
-
930
-
931
-    /**
932
-     * attempts to find a cached version of the requested class
933
-     * by looking in the following places:
934
-     *        $this->{$class_abbreviation}            ie:    $this->CART
935
-     *        $this->{$class_name}                        ie:    $this->Some_Class
936
-     *        $this->LIB->{$class_name}                ie:    $this->LIB->Some_Class
937
-     *        $this->addon->{$class_name}    ie:    $this->addon->Some_Addon_Class
938
-     *
939
-     * @param string $class_name
940
-     * @param string $class_prefix
941
-     * @param array  $arguments
942
-     * @return mixed
943
-     */
944
-    protected function _get_cached_class(
945
-        $class_name,
946
-        $class_prefix = '',
947
-        $arguments = array()
948
-    ) {
949
-        if ($class_name === 'EE_Registry') {
950
-            return $this;
951
-        }
952
-        $class_abbreviation = $this->get_class_abbreviation($class_name);
953
-        // check if class has already been loaded, and return it if it has been
954
-        if (isset($this->{$class_abbreviation})) {
955
-            return $this->{$class_abbreviation};
956
-        }
957
-        $class_name = str_replace('\\', '_', $class_name);
958
-        if (isset($this->{$class_name})) {
959
-            return $this->{$class_name};
960
-        }
961
-        if ($class_prefix === 'addon' && isset($this->addons->{$class_name})) {
962
-            return $this->addons->{$class_name};
963
-        }
964
-        $object_identifier = $this->object_identifier->getIdentifier($class_name, $arguments);
965
-        if (isset($this->LIB->{$object_identifier})) {
966
-            return $this->LIB->{$object_identifier};
967
-        }
968
-        foreach ($this->LIB as $key => $object) {
969
-            if (// request does not contain new arguments and therefore no args identifier
970
-                ! $this->object_identifier->hasArguments($object_identifier)
971
-                // but previously cached class with args was found
972
-                && $this->object_identifier->fqcnMatchesObjectIdentifier($class_name, $key)
973
-            ) {
974
-                return $object;
975
-            }
976
-        }
977
-        return null;
978
-    }
979
-
980
-
981
-    /**
982
-     * removes a cached version of the requested class
983
-     *
984
-     * @param string  $class_name
985
-     * @param boolean $addon
986
-     * @param array   $arguments
987
-     * @return boolean
988
-     */
989
-    public function clear_cached_class(
990
-        $class_name,
991
-        $addon = false,
992
-        $arguments = array()
993
-    ) {
994
-        $class_abbreviation = $this->get_class_abbreviation($class_name);
995
-        // check if class has already been loaded, and return it if it has been
996
-        if (isset($this->{$class_abbreviation})) {
997
-            $this->{$class_abbreviation} = null;
998
-            return true;
999
-        }
1000
-        $class_name = str_replace('\\', '_', $class_name);
1001
-        if (isset($this->{$class_name})) {
1002
-            $this->{$class_name} = null;
1003
-            return true;
1004
-        }
1005
-        if ($addon && isset($this->addons->{$class_name})) {
1006
-            unset($this->addons->{$class_name});
1007
-            return true;
1008
-        }
1009
-        $class_name = $this->object_identifier->getIdentifier($class_name, $arguments);
1010
-        if (isset($this->LIB->{$class_name})) {
1011
-            unset($this->LIB->{$class_name});
1012
-            return true;
1013
-        }
1014
-        return false;
1015
-    }
1016
-
1017
-
1018
-    /**
1019
-     * _set_cached_class
1020
-     * attempts to cache the instantiated class locally
1021
-     * in one of the following places, in the following order:
1022
-     *        $this->{class_abbreviation}   ie:    $this->CART
1023
-     *        $this->{$class_name}          ie:    $this->Some_Class
1024
-     *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1025
-     *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1026
-     *
1027
-     * @param object $class_obj
1028
-     * @param string $class_name
1029
-     * @param string $class_prefix
1030
-     * @param bool   $from_db
1031
-     * @param array  $arguments
1032
-     * @return void
1033
-     */
1034
-    protected function _set_cached_class(
1035
-        $class_obj,
1036
-        $class_name,
1037
-        $class_prefix = '',
1038
-        $from_db = false,
1039
-        $arguments = array()
1040
-    ) {
1041
-        if ($class_name === 'EE_Registry' || empty($class_obj)) {
1042
-            return;
1043
-        }
1044
-        // return newly instantiated class
1045
-        $class_abbreviation = $this->get_class_abbreviation($class_name, '');
1046
-        if ($class_abbreviation) {
1047
-            $this->{$class_abbreviation} = $class_obj;
1048
-            return;
1049
-        }
1050
-        $class_name = str_replace('\\', '_', $class_name);
1051
-        if (property_exists($this, $class_name)) {
1052
-            $this->{$class_name} = $class_obj;
1053
-            return;
1054
-        }
1055
-        if ($class_prefix === 'addon') {
1056
-            $this->addons->{$class_name} = $class_obj;
1057
-            return;
1058
-        }
1059
-        if (! $from_db) {
1060
-            $class_name = $this->object_identifier->getIdentifier($class_name, $arguments);
1061
-            $this->LIB->{$class_name} = $class_obj;
1062
-        }
1063
-    }
1064
-
1065
-
1066
-    /**
1067
-     * attempts to find a full valid filepath for the requested class.
1068
-     * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
1069
-     * then returns that path if the target file has been found and is readable
1070
-     *
1071
-     * @param string $class_name
1072
-     * @param string $type
1073
-     * @param array  $file_paths
1074
-     * @return string | bool
1075
-     */
1076
-    protected function _resolve_path($class_name, $type = '', $file_paths = array())
1077
-    {
1078
-        // make sure $file_paths is an array
1079
-        $file_paths = is_array($file_paths)
1080
-            ? $file_paths
1081
-            : array($file_paths);
1082
-        // cycle thru paths
1083
-        foreach ($file_paths as $key => $file_path) {
1084
-            // convert all separators to proper /, if no filepath, then use EE_CLASSES
1085
-            $file_path = $file_path
1086
-                ? str_replace(array('/', '\\'), '/', $file_path)
1087
-                : EE_CLASSES;
1088
-            // prep file type
1089
-            $type = ! empty($type)
1090
-                ? trim($type, '.') . '.'
1091
-                : '';
1092
-            // build full file path
1093
-            $file_paths[ $key ] = rtrim($file_path, '/') . '/' . $class_name . '.' . $type . 'php';
1094
-            // does the file exist and can be read ?
1095
-            if (is_readable($file_paths[ $key ])) {
1096
-                return $file_paths[ $key ];
1097
-            }
1098
-        }
1099
-        return false;
1100
-    }
1101
-
1102
-
1103
-    /**
1104
-     * basically just performs a require_once()
1105
-     * but with some error handling
1106
-     *
1107
-     * @param  string $path
1108
-     * @param  string $class_name
1109
-     * @param  string $type
1110
-     * @param  array  $file_paths
1111
-     * @return bool
1112
-     * @throws EE_Error
1113
-     * @throws ReflectionException
1114
-     */
1115
-    protected function _require_file($path, $class_name, $type = '', $file_paths = array())
1116
-    {
1117
-        $this->resolve_legacy_class_parent($class_name);
1118
-        // don't give up! you gotta...
1119
-        try {
1120
-            // does the file exist and can it be read ?
1121
-            if (! $path) {
1122
-                // just in case the file has already been autoloaded,
1123
-                // but discrepancies in the naming schema are preventing it from
1124
-                // being loaded via one of the EE_Registry::load_*() methods,
1125
-                // then let's try one last hail mary before throwing an exception
1126
-                // and call class_exists() again, but with autoloading turned ON
1127
-                if (class_exists($class_name)) {
1128
-                    return true;
1129
-                }
1130
-                // so sorry, can't find the file
1131
-                throw new EE_Error(
1132
-                    sprintf(
1133
-                        esc_html__(
1134
-                            'The %1$s file %2$s could not be located or is not readable due to file permissions. Please ensure that the following filepath(s) are correct: %3$s',
1135
-                            'event_espresso'
1136
-                        ),
1137
-                        trim($type, '.'),
1138
-                        $class_name,
1139
-                        '<br />' . implode(',<br />', $file_paths)
1140
-                    )
1141
-                );
1142
-            }
1143
-            // get the file
1144
-            require_once($path);
1145
-            // if the class isn't already declared somewhere
1146
-            if (class_exists($class_name, false) === false) {
1147
-                // so sorry, not a class
1148
-                throw new EE_Error(
1149
-                    sprintf(
1150
-                        esc_html__(
1151
-                            'The %s file %s does not appear to contain the %s Class.',
1152
-                            'event_espresso'
1153
-                        ),
1154
-                        $type,
1155
-                        $path,
1156
-                        $class_name
1157
-                    )
1158
-                );
1159
-            }
1160
-        } catch (EE_Error $e) {
1161
-            $e->get_error();
1162
-            return false;
1163
-        }
1164
-        return true;
1165
-    }
1166
-
1167
-
1168
-    /**
1169
-     * Some of our legacy classes that extended a parent class would simply use a require() statement
1170
-     * before their class declaration in order to ensure that the parent class was loaded.
1171
-     * This is not ideal, but it's nearly impossible to determine the parent class of a non-namespaced class,
1172
-     * without triggering a fatal error because the parent class has yet to be loaded and therefore doesn't exist.
1173
-     *
1174
-     * @param string $class_name
1175
-     */
1176
-    protected function resolve_legacy_class_parent($class_name = '')
1177
-    {
1178
-        try {
1179
-            $legacy_parent_class_map = array(
1180
-                'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php',
1181
-            );
1182
-            if (isset($legacy_parent_class_map[ $class_name ])) {
1183
-                require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[ $class_name ];
1184
-            }
1185
-        } catch (Exception $exception) {
1186
-        }
1187
-    }
1188
-
1189
-
1190
-    /**
1191
-     * _create_object
1192
-     * Attempts to instantiate the requested class via any of the
1193
-     * commonly used instantiation methods employed throughout EE.
1194
-     * The priority for instantiation is as follows:
1195
-     *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
1196
-     *        - model objects via their 'new_instance_from_db' method
1197
-     *        - model objects via their 'new_instance' method
1198
-     *        - "singleton" classes" via their 'instance' method
1199
-     *    - standard instantiable classes via their __constructor
1200
-     * Prior to instantiation, if the classname exists in the dependency_map,
1201
-     * then the constructor for the requested class will be examined to determine
1202
-     * if any dependencies exist, and if they can be injected.
1203
-     * If so, then those classes will be added to the array of arguments passed to the constructor
1204
-     *
1205
-     * @param string $class_name
1206
-     * @param array  $arguments
1207
-     * @param string $type
1208
-     * @param bool   $from_db
1209
-     * @return null|object|bool
1210
-     * @throws InvalidArgumentException
1211
-     * @throws InvalidInterfaceException
1212
-     * @throws EE_Error
1213
-     * @throws ReflectionException
1214
-     * @throws InvalidDataTypeException
1215
-     */
1216
-    protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false)
1217
-    {
1218
-        // create reflection
1219
-        $reflector = $this->mirror->getReflectionClass($class_name);
1220
-        // make sure arguments are an array
1221
-        $arguments = is_array($arguments)
1222
-            ? $arguments
1223
-            : array($arguments);
1224
-        // and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
1225
-        // else wrap it in an additional array so that it doesn't get split into multiple parameters
1226
-        $arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
1227
-            ? $arguments
1228
-            : array($arguments);
1229
-        // attempt to inject dependencies ?
1230
-        if ($this->_dependency_map->has($class_name)) {
1231
-            $arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
1232
-        }
1233
-        // instantiate the class if possible
1234
-        if ($reflector->isAbstract()) {
1235
-            // nothing to instantiate, loading file was enough
1236
-            // does not throw an exception so $instantiation_mode is unused
1237
-            // $instantiation_mode = "1) no constructor abstract class";
1238
-            return true;
1239
-        }
1240
-        if (empty($arguments)
1241
-            && $this->mirror->getConstructorFromReflection($reflector) === null
1242
-            && $reflector->isInstantiable()
1243
-        ) {
1244
-            // no constructor = static methods only... nothing to instantiate, loading file was enough
1245
-            // $instantiation_mode = "2) no constructor but instantiable";
1246
-            return $reflector->newInstance();
1247
-        }
1248
-        if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
1249
-            // $instantiation_mode = "3) new_instance_from_db()";
1250
-            return call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments);
1251
-        }
1252
-        if (method_exists($class_name, 'new_instance')) {
1253
-            // $instantiation_mode = "4) new_instance()";
1254
-            return call_user_func_array(array($class_name, 'new_instance'), $arguments);
1255
-        }
1256
-        if (method_exists($class_name, 'instance')) {
1257
-            // $instantiation_mode = "5) instance()";
1258
-            return call_user_func_array(array($class_name, 'instance'), $arguments);
1259
-        }
1260
-        if ($reflector->isInstantiable()) {
1261
-            // $instantiation_mode = "6) constructor";
1262
-            return $reflector->newInstanceArgs($arguments);
1263
-        }
1264
-        // heh ? something's not right !
1265
-        throw new EE_Error(
1266
-            sprintf(
1267
-                __('The %s file %s could not be instantiated.', 'event_espresso'),
1268
-                $type,
1269
-                $class_name
1270
-            )
1271
-        );
1272
-    }
1273
-
1274
-
1275
-    /**
1276
-     * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1277
-     * @param array $array
1278
-     * @return bool
1279
-     */
1280
-    protected function _array_is_numerically_and_sequentially_indexed(array $array)
1281
-    {
1282
-        return ! empty($array)
1283
-            ? array_keys($array) === range(0, count($array) - 1)
1284
-            : true;
1285
-    }
1286
-
1287
-
1288
-    /**
1289
-     * _resolve_dependencies
1290
-     * examines the constructor for the requested class to determine
1291
-     * if any dependencies exist, and if they can be injected.
1292
-     * If so, then those classes will be added to the array of arguments passed to the constructor
1293
-     * PLZ NOTE: this is achieved by type hinting the constructor params
1294
-     * For example:
1295
-     *        if attempting to load a class "Foo" with the following constructor:
1296
-     *        __construct( Bar $bar_class, Fighter $grohl_class )
1297
-     *        then $bar_class and $grohl_class will be added to the $arguments array,
1298
-     *        but only IF they are NOT already present in the incoming arguments array,
1299
-     *        and the correct classes can be loaded
1300
-     *
1301
-     * @param ReflectionClass $reflector
1302
-     * @param string          $class_name
1303
-     * @param array           $arguments
1304
-     * @return array
1305
-     * @throws InvalidArgumentException
1306
-     * @throws InvalidDataTypeException
1307
-     * @throws InvalidInterfaceException
1308
-     * @throws ReflectionException
1309
-     */
1310
-    protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, array $arguments = array())
1311
-    {
1312
-        // let's examine the constructor
1313
-        $constructor = $this->mirror->getConstructorFromReflection($reflector);
1314
-        // whu? huh? nothing?
1315
-        if (! $constructor) {
1316
-            return $arguments;
1317
-        }
1318
-        // get constructor parameters
1319
-        $params = $this->mirror->getParametersFromReflection($reflector);
1320
-        // and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1321
-        $argument_keys = array_keys($arguments);
1322
-        // now loop thru all of the constructors expected parameters
1323
-        foreach ($params as $index => $param) {
1324
-            try {
1325
-                // is this a dependency for a specific class ?
1326
-                $param_class = $this->mirror->getParameterClassName($param, $class_name, $index);
1327
-            } catch (ReflectionException $exception) {
1328
-                // uh-oh... most likely a legacy class that has not been autoloaded
1329
-                // let's try to derive the classname from what we have now
1330
-                // and hope that the property var name is close to the class name
1331
-                $param_class = $param->getName();
1332
-                $param_class = str_replace('_', ' ', $param_class);
1333
-                $param_class = ucwords($param_class);
1334
-                $param_class = str_replace(' ', '_', $param_class);
1335
-            }
1336
-            // BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1337
-            $param_class = $this->class_cache->isAlias($param_class, $class_name)
1338
-                ? $this->class_cache->getFqnForAlias($param_class, $class_name)
1339
-                : $param_class;
1340
-            if (// param is not even a class
1341
-                $param_class === null
1342
-                // and something already exists in the incoming arguments for this param
1343
-                && array_key_exists($index, $argument_keys)
1344
-                && array_key_exists($argument_keys[ $index ], $arguments)
1345
-            ) {
1346
-                // so let's skip this argument and move on to the next
1347
-                continue;
1348
-            }
1349
-            if (// parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
1350
-                $param_class !== null
1351
-                && isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ])
1352
-                && $arguments[ $argument_keys[ $index ] ] instanceof $param_class
1353
-            ) {
1354
-                // skip this argument and move on to the next
1355
-                continue;
1356
-            }
1357
-            if (// parameter is type hinted as a class, and should be injected
1358
-                $param_class !== null
1359
-                && $this->_dependency_map->has_dependency_for_class($class_name, $param_class)
1360
-            ) {
1361
-                $arguments = $this->_resolve_dependency(
1362
-                    $class_name,
1363
-                    $param_class,
1364
-                    $arguments,
1365
-                    $index
1366
-                );
1367
-            }
1368
-            if (empty($arguments[ $index ])) {
1369
-                $arguments[ $index ] = $this->mirror->getParameterDefaultValue(
1370
-                    $param,
1371
-                    $class_name,
1372
-                    $index
1373
-                );
1374
-            }
1375
-        }
1376
-        return $arguments;
1377
-    }
1378
-
1379
-
1380
-    /**
1381
-     * @param string $class_name
1382
-     * @param string $param_class
1383
-     * @param array  $arguments
1384
-     * @param mixed  $index
1385
-     * @return array
1386
-     * @throws InvalidArgumentException
1387
-     * @throws InvalidInterfaceException
1388
-     * @throws InvalidDataTypeException
1389
-     */
1390
-    protected function _resolve_dependency($class_name, $param_class, $arguments, $index)
1391
-    {
1392
-        $dependency = null;
1393
-        // should dependency be loaded from cache ?
1394
-        $cache_on = $this->_dependency_map->loading_strategy_for_class_dependency(
1395
-            $class_name,
1396
-            $param_class
1397
-        );
1398
-        $cache_on = $cache_on !== EE_Dependency_Map::load_new_object;
1399
-        // we might have a dependency...
1400
-        // let's MAYBE try and find it in our cache if that's what's been requested
1401
-        $cached_class = $cache_on
1402
-            ? $this->_get_cached_class($param_class)
1403
-            : null;
1404
-        // and grab it if it exists
1405
-        if ($cached_class instanceof $param_class) {
1406
-            $dependency = $cached_class;
1407
-        } elseif ($param_class !== $class_name) {
1408
-            // obtain the loader method from the dependency map
1409
-            $loader = $this->_dependency_map->class_loader($param_class);
1410
-            // is loader a custom closure ?
1411
-            if ($loader instanceof Closure) {
1412
-                $dependency = $loader($arguments);
1413
-            } else {
1414
-                // set the cache on property for the recursive loading call
1415
-                $this->_cache_on = $cache_on;
1416
-                // if not, then let's try and load it via the registry
1417
-                if ($loader && method_exists($this, $loader)) {
1418
-                    $dependency = $this->{$loader}($param_class);
1419
-                } else {
1420
-                    $dependency = LoaderFactory::getLoader()->load(
1421
-                        $param_class,
1422
-                        array(),
1423
-                        $cache_on
1424
-                    );
1425
-                }
1426
-            }
1427
-        }
1428
-        // did we successfully find the correct dependency ?
1429
-        if ($dependency instanceof $param_class) {
1430
-            // then let's inject it into the incoming array of arguments at the correct location
1431
-            $arguments[ $index ] = $dependency;
1432
-        }
1433
-        return $arguments;
1434
-    }
1435
-
1436
-
1437
-    /**
1438
-     * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1439
-     *
1440
-     * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1441
-     *                          in the EE_Dependency_Map::$_class_loaders array,
1442
-     *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1443
-     * @param array  $arguments
1444
-     * @return object
1445
-     */
1446
-    public static function factory($classname, $arguments = array())
1447
-    {
1448
-        $loader = self::instance()->_dependency_map->class_loader($classname);
1449
-        if ($loader instanceof Closure) {
1450
-            return $loader($arguments);
1451
-        }
1452
-        if (method_exists(self::instance(), $loader)) {
1453
-            return self::instance()->{$loader}($classname, $arguments);
1454
-        }
1455
-        return null;
1456
-    }
1457
-
1458
-
1459
-    /**
1460
-     * Gets the addon by its class name
1461
-     *
1462
-     * @param string $class_name
1463
-     * @return EE_Addon
1464
-     */
1465
-    public function getAddon($class_name)
1466
-    {
1467
-        $class_name = str_replace('\\', '_', $class_name);
1468
-        if (isset($this->addons->{$class_name})) {
1469
-            return $this->addons->{$class_name};
1470
-        } else {
1471
-            return null;
1472
-        }
1473
-    }
1474
-
1475
-
1476
-    /**
1477
-     * removes the addon from the internal cache
1478
-     *
1479
-     * @param string $class_name
1480
-     * @return void
1481
-     */
1482
-    public function removeAddon($class_name)
1483
-    {
1484
-        $class_name = str_replace('\\', '_', $class_name);
1485
-        unset($this->addons->{$class_name});
1486
-    }
1487
-
1488
-
1489
-    /**
1490
-     * Gets the addon by its name/slug (not classname. For that, just
1491
-     * use the get_addon() method above
1492
-     *
1493
-     * @param string $name
1494
-     * @return EE_Addon
1495
-     */
1496
-    public function get_addon_by_name($name)
1497
-    {
1498
-        foreach ($this->addons as $addon) {
1499
-            if ($addon->name() === $name) {
1500
-                return $addon;
1501
-            }
1502
-        }
1503
-        return null;
1504
-    }
1505
-
1506
-
1507
-    /**
1508
-     * Gets an array of all the registered addons, where the keys are their names.
1509
-     * (ie, what each returns for their name() function)
1510
-     * They're already available on EE_Registry::instance()->addons as properties,
1511
-     * where each property's name is the addon's classname,
1512
-     * So if you just want to get the addon by classname,
1513
-     * OR use the get_addon() method above.
1514
-     * PLEASE  NOTE:
1515
-     * addons with Fully Qualified Class Names
1516
-     * have had the namespace separators converted to underscores,
1517
-     * so a classname like Fully\Qualified\ClassName
1518
-     * would have been converted to Fully_Qualified_ClassName
1519
-     *
1520
-     * @return EE_Addon[] where the KEYS are the addon's name()
1521
-     */
1522
-    public function get_addons_by_name()
1523
-    {
1524
-        $addons = array();
1525
-        foreach ($this->addons as $addon) {
1526
-            $addons[ $addon->name() ] = $addon;
1527
-        }
1528
-        return $addons;
1529
-    }
1530
-
1531
-
1532
-    /**
1533
-     * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1534
-     * a stale copy of it around
1535
-     *
1536
-     * @param string $model_name
1537
-     * @return \EEM_Base
1538
-     * @throws \EE_Error
1539
-     */
1540
-    public function reset_model($model_name)
1541
-    {
1542
-        $model_class_name = strpos($model_name, 'EEM_') !== 0
1543
-            ? "EEM_{$model_name}"
1544
-            : $model_name;
1545
-        if (! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1546
-            return null;
1547
-        }
1548
-        // get that model reset it and make sure we nuke the old reference to it
1549
-        if ($this->LIB->{$model_class_name} instanceof $model_class_name
1550
-            && is_callable(
1551
-                array($model_class_name, 'reset')
1552
-            )) {
1553
-            $this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset();
1554
-        } else {
1555
-            throw new EE_Error(
1556
-                sprintf(
1557
-                    esc_html__('Model %s does not have a method "reset"', 'event_espresso'),
1558
-                    $model_name
1559
-                )
1560
-            );
1561
-        }
1562
-        return $this->LIB->{$model_class_name};
1563
-    }
1564
-
1565
-
1566
-    /**
1567
-     * Resets the registry.
1568
-     * The criteria for what gets reset is based on what can be shared between sites on the same request when
1569
-     * switch_to_blog is used in a multisite install.  Here is a list of things that are NOT reset.
1570
-     * - $_dependency_map
1571
-     * - $_class_abbreviations
1572
-     * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1573
-     * - $REQ:  Still on the same request so no need to change.
1574
-     * - $CAP: There is no site specific state in the EE_Capability class.
1575
-     * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only
1576
-     * one Session can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1577
-     * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1578
-     *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1579
-     *             switch or on the restore.
1580
-     * - $modules
1581
-     * - $shortcodes
1582
-     * - $widgets
1583
-     *
1584
-     * @param boolean $hard             [deprecated]
1585
-     * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1586
-     *                                  or just reset without re-instantiating (handy to set to FALSE if you're not
1587
-     *                                  sure if you CAN currently reinstantiate the singletons at the moment)
1588
-     * @param   bool  $reset_models     Defaults to true.  When false, then the models are not reset.  This is so
1589
-     *                                  client
1590
-     *                                  code instead can just change the model context to a different blog id if
1591
-     *                                  necessary
1592
-     * @return EE_Registry
1593
-     * @throws InvalidInterfaceException
1594
-     * @throws InvalidDataTypeException
1595
-     * @throws EE_Error
1596
-     * @throws ReflectionException
1597
-     * @throws InvalidArgumentException
1598
-     */
1599
-    public static function reset($hard = false, $reinstantiate = true, $reset_models = true)
1600
-    {
1601
-        $instance = self::instance();
1602
-        $instance->_cache_on = true;
1603
-        // reset some "special" classes
1604
-        EEH_Activation::reset();
1605
-        $hard = apply_filters('FHEE__EE_Registry__reset__hard', $hard);
1606
-        $instance->CFG = EE_Config::reset($hard, $reinstantiate);
1607
-        $instance->CART = null;
1608
-        $instance->MRM = null;
1609
-        $instance->AssetsRegistry = LoaderFactory::getLoader()->getShared(
1610
-            'EventEspresso\core\services\assets\Registry'
1611
-        );
1612
-        // messages reset
1613
-        EED_Messages::reset();
1614
-        // handle of objects cached on LIB
1615
-        foreach (array('LIB', 'modules') as $cache) {
1616
-            foreach ($instance->{$cache} as $class_name => $class) {
1617
-                if (self::_reset_and_unset_object($class, $reset_models)) {
1618
-                    unset($instance->{$cache}->{$class_name});
1619
-                }
1620
-            }
1621
-        }
1622
-        return $instance;
1623
-    }
1624
-
1625
-
1626
-    /**
1627
-     * if passed object implements ResettableInterface, then call it's reset() method
1628
-     * if passed object implements InterminableInterface, then return false,
1629
-     * to indicate that it should NOT be cleared from the Registry cache
1630
-     *
1631
-     * @param      $object
1632
-     * @param bool $reset_models
1633
-     * @return bool returns true if cached object should be unset
1634
-     */
1635
-    private static function _reset_and_unset_object($object, $reset_models)
1636
-    {
1637
-        if (! is_object($object)) {
1638
-            // don't unset anything that's not an object
1639
-            return false;
1640
-        }
1641
-        if ($object instanceof EED_Module) {
1642
-            $object::reset();
1643
-            // don't unset modules
1644
-            return false;
1645
-        }
1646
-        if ($object instanceof ResettableInterface) {
1647
-            if ($object instanceof EEM_Base) {
1648
-                if ($reset_models) {
1649
-                    $object->reset();
1650
-                    return true;
1651
-                }
1652
-                return false;
1653
-            }
1654
-            $object->reset();
1655
-            return true;
1656
-        }
1657
-        if (! $object instanceof InterminableInterface) {
1658
-            return true;
1659
-        }
1660
-        return false;
1661
-    }
1662
-
1663
-
1664
-    /**
1665
-     * Gets all the custom post type models defined
1666
-     *
1667
-     * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1668
-     */
1669
-    public function cpt_models()
1670
-    {
1671
-        $cpt_models = array();
1672
-        foreach ($this->non_abstract_db_models as $short_name => $classname) {
1673
-            if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1674
-                $cpt_models[ $short_name ] = $classname;
1675
-            }
1676
-        }
1677
-        return $cpt_models;
1678
-    }
1679
-
1680
-
1681
-    /**
1682
-     * @return \EE_Config
1683
-     */
1684
-    public static function CFG()
1685
-    {
1686
-        return self::instance()->CFG;
1687
-    }
1688
-
1689
-
1690
-    /**
1691
-     * @deprecated 4.9.62.p
1692
-     * @param string $class_name
1693
-     * @return ReflectionClass
1694
-     * @throws ReflectionException
1695
-     * @throws InvalidDataTypeException
1696
-     */
1697
-    public function get_ReflectionClass($class_name)
1698
-    {
1699
-        return $this->mirror->getReflectionClass($class_name);
1700
-    }
26
+	/**
27
+	 * @var EE_Registry $_instance
28
+	 */
29
+	private static $_instance;
30
+
31
+	/**
32
+	 * @var EE_Dependency_Map $_dependency_map
33
+	 */
34
+	protected $_dependency_map;
35
+
36
+	/**
37
+	 * @var Mirror
38
+	 */
39
+	private $mirror;
40
+
41
+	/**
42
+	 * @var ClassInterfaceCache $class_cache
43
+	 */
44
+	private $class_cache;
45
+
46
+	/**
47
+	 * @var array $_class_abbreviations
48
+	 */
49
+	protected $_class_abbreviations = array();
50
+
51
+	/**
52
+	 * @var CommandBusInterface $BUS
53
+	 */
54
+	public $BUS;
55
+
56
+	/**
57
+	 * @var EE_Cart $CART
58
+	 */
59
+	public $CART;
60
+
61
+	/**
62
+	 * @var EE_Config $CFG
63
+	 */
64
+	public $CFG;
65
+
66
+	/**
67
+	 * @var EE_Network_Config $NET_CFG
68
+	 */
69
+	public $NET_CFG;
70
+
71
+	/**
72
+	 * StdClass object for storing library classes in
73
+	 *
74
+	 * @var RegistryContainer $LIB
75
+	 */
76
+	public $LIB;
77
+
78
+	/**
79
+	 * @var EE_Request_Handler $REQ
80
+	 */
81
+	public $REQ;
82
+
83
+	/**
84
+	 * @var EE_Session $SSN
85
+	 */
86
+	public $SSN;
87
+
88
+	/**
89
+	 * @since 4.5.0
90
+	 * @var EE_Capabilities $CAP
91
+	 */
92
+	public $CAP;
93
+
94
+	/**
95
+	 * @since 4.9.0
96
+	 * @var EE_Message_Resource_Manager $MRM
97
+	 */
98
+	public $MRM;
99
+
100
+	/**
101
+	 * @var Registry $AssetsRegistry
102
+	 */
103
+	public $AssetsRegistry;
104
+
105
+	/**
106
+	 * StdClass object for holding addons which have registered themselves to work with EE core
107
+	 *
108
+	 * @var EE_Addon[] $addons
109
+	 */
110
+	public $addons;
111
+
112
+	/**
113
+	 * keys are 'short names' (eg Event), values are class names (eg 'EEM_Event')
114
+	 *
115
+	 * @var EEM_Base[] $models
116
+	 */
117
+	public $models = array();
118
+
119
+	/**
120
+	 * @var EED_Module[] $modules
121
+	 */
122
+	public $modules;
123
+
124
+	/**
125
+	 * @var EES_Shortcode[] $shortcodes
126
+	 */
127
+	public $shortcodes;
128
+
129
+	/**
130
+	 * @var WP_Widget[] $widgets
131
+	 */
132
+	public $widgets;
133
+
134
+	/**
135
+	 * this is an array of all implemented model names (i.e. not the parent abstract models, or models
136
+	 * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)).
137
+	 * Keys are model "short names" (eg "Event") as used in model relations, and values are
138
+	 * classnames (eg "EEM_Event")
139
+	 *
140
+	 * @var array $non_abstract_db_models
141
+	 */
142
+	public $non_abstract_db_models = array();
143
+
144
+	/**
145
+	 * internationalization for JS strings
146
+	 *    usage:   EE_Registry::i18n_js_strings['string_key'] = esc_html__( 'string to translate.', 'event_espresso' );
147
+	 *    in js file:  var translatedString = eei18n.string_key;
148
+	 *
149
+	 * @var array $i18n_js_strings
150
+	 */
151
+	public static $i18n_js_strings = array();
152
+
153
+	/**
154
+	 * $main_file - path to espresso.php
155
+	 *
156
+	 * @var array $main_file
157
+	 */
158
+	public $main_file;
159
+
160
+	/**
161
+	 * array of ReflectionClass objects where the key is the class name
162
+	 *
163
+	 * @deprecated 4.9.62.p
164
+	 * @var ReflectionClass[] $_reflectors
165
+	 */
166
+	public $_reflectors;
167
+
168
+	/**
169
+	 * boolean flag to indicate whether or not to load/save dependencies from/to the cache
170
+	 *
171
+	 * @var boolean $_cache_on
172
+	 */
173
+	protected $_cache_on = true;
174
+
175
+	/**
176
+	 * @var ObjectIdentifier
177
+	 */
178
+	private $object_identifier;
179
+
180
+
181
+	/**
182
+	 * @singleton method used to instantiate class object
183
+	 * @param EE_Dependency_Map|null   $dependency_map
184
+	 * @param Mirror|null              $mirror
185
+	 * @param ClassInterfaceCache|null $class_cache
186
+	 * @param ObjectIdentifier|null    $object_identifier
187
+	 * @return EE_Registry instance
188
+	 */
189
+	public static function instance(
190
+		EE_Dependency_Map $dependency_map = null,
191
+		Mirror $mirror = null,
192
+		ClassInterfaceCache $class_cache = null,
193
+		ObjectIdentifier $object_identifier = null
194
+	) {
195
+		// check if class object is instantiated
196
+		if (! self::$_instance instanceof EE_Registry
197
+			&& $dependency_map instanceof EE_Dependency_Map
198
+			&& $mirror instanceof Mirror
199
+			&& $class_cache instanceof ClassInterfaceCache
200
+			&& $object_identifier instanceof ObjectIdentifier
201
+		) {
202
+			self::$_instance = new self(
203
+				$dependency_map,
204
+				$mirror,
205
+				$class_cache,
206
+				$object_identifier
207
+			);
208
+		}
209
+		return self::$_instance;
210
+	}
211
+
212
+
213
+	/**
214
+	 * protected constructor to prevent direct creation
215
+	 *
216
+	 * @Constructor
217
+	 * @param  EE_Dependency_Map  $dependency_map
218
+	 * @param Mirror              $mirror
219
+	 * @param ClassInterfaceCache $class_cache
220
+	 * @param ObjectIdentifier    $object_identifier
221
+	 */
222
+	protected function __construct(
223
+		EE_Dependency_Map $dependency_map,
224
+		Mirror $mirror,
225
+		ClassInterfaceCache $class_cache,
226
+		ObjectIdentifier $object_identifier
227
+	) {
228
+		$this->_dependency_map = $dependency_map;
229
+		$this->mirror = $mirror;
230
+		$this->class_cache = $class_cache;
231
+		$this->object_identifier = $object_identifier;
232
+		// $registry_container = new RegistryContainer();
233
+		$this->LIB = new RegistryContainer();
234
+		$this->addons = new RegistryContainer();
235
+		$this->modules = new RegistryContainer();
236
+		$this->shortcodes = new RegistryContainer();
237
+		$this->widgets = new RegistryContainer();
238
+		add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
239
+	}
240
+
241
+
242
+	/**
243
+	 * initialize
244
+	 *
245
+	 * @throws OutOfBoundsException
246
+	 * @throws InvalidArgumentException
247
+	 * @throws InvalidInterfaceException
248
+	 * @throws InvalidDataTypeException
249
+	 * @throws EE_Error
250
+	 * @throws ReflectionException
251
+	 */
252
+	public function initialize()
253
+	{
254
+		$this->_class_abbreviations = apply_filters(
255
+			'FHEE__EE_Registry____construct___class_abbreviations',
256
+			array(
257
+				'EE_Config'                                       => 'CFG',
258
+				'EE_Session'                                      => 'SSN',
259
+				'EE_Capabilities'                                 => 'CAP',
260
+				'EE_Cart'                                         => 'CART',
261
+				'EE_Network_Config'                               => 'NET_CFG',
262
+				'EE_Request_Handler'                              => 'REQ',
263
+				'EE_Message_Resource_Manager'                     => 'MRM',
264
+				'EventEspresso\core\services\commands\CommandBus' => 'BUS',
265
+				'EventEspresso\core\services\assets\Registry'     => 'AssetsRegistry',
266
+			)
267
+		);
268
+		$this->load_core('Base', array(), true);
269
+		// add our request and response objects to the cache
270
+		$request_loader = $this->_dependency_map->class_loader(
271
+			'EventEspresso\core\services\request\Request'
272
+		);
273
+		$this->_set_cached_class(
274
+			$request_loader(),
275
+			'EventEspresso\core\services\request\Request'
276
+		);
277
+		$response_loader = $this->_dependency_map->class_loader(
278
+			'EventEspresso\core\services\request\Response'
279
+		);
280
+		$this->_set_cached_class(
281
+			$response_loader(),
282
+			'EventEspresso\core\services\request\Response'
283
+		);
284
+		add_action('AHEE__EE_System__set_hooks_for_core', array($this, 'init'));
285
+	}
286
+
287
+
288
+	/**
289
+	 * @return void
290
+	 */
291
+	public function init()
292
+	{
293
+		// Get current page protocol
294
+		$protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
295
+		// Output admin-ajax.php URL with same protocol as current page
296
+		self::$i18n_js_strings['ajax_url'] = admin_url('admin-ajax.php', $protocol);
297
+		self::$i18n_js_strings['wp_debug'] = defined('WP_DEBUG') ? WP_DEBUG : false;
298
+	}
299
+
300
+
301
+	/**
302
+	 * localize_i18n_js_strings
303
+	 *
304
+	 * @return string
305
+	 */
306
+	public static function localize_i18n_js_strings()
307
+	{
308
+		$i18n_js_strings = (array) self::$i18n_js_strings;
309
+		foreach ($i18n_js_strings as $key => $value) {
310
+			if (is_scalar($value)) {
311
+				$i18n_js_strings[ $key ] = html_entity_decode((string) $value, ENT_QUOTES, 'UTF-8');
312
+			}
313
+		}
314
+		return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
315
+	}
316
+
317
+
318
+	/**
319
+	 * @param mixed string | EED_Module $module
320
+	 * @throws OutOfBoundsException
321
+	 * @throws InvalidArgumentException
322
+	 * @throws InvalidInterfaceException
323
+	 * @throws InvalidDataTypeException
324
+	 * @throws EE_Error
325
+	 * @throws ReflectionException
326
+	 */
327
+	public function add_module($module)
328
+	{
329
+		if ($module instanceof EED_Module) {
330
+			$module_class = get_class($module);
331
+			$this->modules->{$module_class} = $module;
332
+		} else {
333
+			if (! class_exists('EE_Module_Request_Router', false)) {
334
+				$this->load_core('Module_Request_Router');
335
+			}
336
+			EE_Module_Request_Router::module_factory($module);
337
+		}
338
+	}
339
+
340
+
341
+	/**
342
+	 * @param string $module_name
343
+	 * @return mixed EED_Module | NULL
344
+	 */
345
+	public function get_module($module_name = '')
346
+	{
347
+		return isset($this->modules->{$module_name})
348
+			? $this->modules->{$module_name}
349
+			: null;
350
+	}
351
+
352
+
353
+	/**
354
+	 * loads core classes - must be singletons
355
+	 *
356
+	 * @param string $class_name - simple class name ie: session
357
+	 * @param mixed  $arguments
358
+	 * @param bool   $load_only
359
+	 * @return mixed
360
+	 * @throws InvalidInterfaceException
361
+	 * @throws InvalidDataTypeException
362
+	 * @throws EE_Error
363
+	 * @throws ReflectionException
364
+	 * @throws InvalidArgumentException
365
+	 */
366
+	public function load_core($class_name, $arguments = array(), $load_only = false)
367
+	{
368
+		$core_paths = apply_filters(
369
+			'FHEE__EE_Registry__load_core__core_paths',
370
+			array(
371
+				EE_CORE,
372
+				EE_ADMIN,
373
+				EE_CPTS,
374
+				EE_CORE . 'data_migration_scripts/',
375
+				EE_CORE . 'capabilities/',
376
+				EE_CORE . 'request_stack/',
377
+				EE_CORE . 'middleware/',
378
+			)
379
+		);
380
+		// retrieve instantiated class
381
+		return $this->_load(
382
+			$core_paths,
383
+			'EE_',
384
+			$class_name,
385
+			'core',
386
+			$arguments,
387
+			false,
388
+			true,
389
+			$load_only
390
+		);
391
+	}
392
+
393
+
394
+	/**
395
+	 * loads service classes
396
+	 *
397
+	 * @param string $class_name - simple class name ie: session
398
+	 * @param mixed  $arguments
399
+	 * @param bool   $load_only
400
+	 * @return mixed
401
+	 * @throws InvalidInterfaceException
402
+	 * @throws InvalidDataTypeException
403
+	 * @throws EE_Error
404
+	 * @throws ReflectionException
405
+	 * @throws InvalidArgumentException
406
+	 */
407
+	public function load_service($class_name, $arguments = array(), $load_only = false)
408
+	{
409
+		$service_paths = apply_filters(
410
+			'FHEE__EE_Registry__load_service__service_paths',
411
+			array(
412
+				EE_CORE . 'services/',
413
+			)
414
+		);
415
+		// retrieve instantiated class
416
+		return $this->_load(
417
+			$service_paths,
418
+			'EE_',
419
+			$class_name,
420
+			'class',
421
+			$arguments,
422
+			false,
423
+			true,
424
+			$load_only
425
+		);
426
+	}
427
+
428
+
429
+	/**
430
+	 * loads data_migration_scripts
431
+	 *
432
+	 * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
433
+	 * @param mixed  $arguments
434
+	 * @return EE_Data_Migration_Script_Base|mixed
435
+	 * @throws InvalidInterfaceException
436
+	 * @throws InvalidDataTypeException
437
+	 * @throws EE_Error
438
+	 * @throws ReflectionException
439
+	 * @throws InvalidArgumentException
440
+	 */
441
+	public function load_dms($class_name, $arguments = array())
442
+	{
443
+		// retrieve instantiated class
444
+		return $this->_load(
445
+			EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(),
446
+			'EE_DMS_',
447
+			$class_name,
448
+			'dms',
449
+			$arguments,
450
+			false,
451
+			false
452
+		);
453
+	}
454
+
455
+
456
+	/**
457
+	 * loads object creating classes - must be singletons
458
+	 *
459
+	 * @param string $class_name - simple class name ie: attendee
460
+	 * @param mixed  $arguments  - an array of arguments to pass to the class
461
+	 * @param bool   $from_db    - some classes are instantiated from the db and thus call a different method to
462
+	 *                           instantiate
463
+	 * @param bool   $cache      if you don't want the class to be stored in the internal cache (non-persistent) then
464
+	 *                           set this to FALSE (ie. when instantiating model objects from client in a loop)
465
+	 * @param bool   $load_only  whether or not to just load the file and NOT instantiate, or load AND instantiate
466
+	 *                           (default)
467
+	 * @return EE_Base_Class | bool
468
+	 * @throws InvalidInterfaceException
469
+	 * @throws InvalidDataTypeException
470
+	 * @throws EE_Error
471
+	 * @throws ReflectionException
472
+	 * @throws InvalidArgumentException
473
+	 */
474
+	public function load_class($class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false)
475
+	{
476
+		$paths = apply_filters(
477
+			'FHEE__EE_Registry__load_class__paths',
478
+			array(
479
+				EE_CORE,
480
+				EE_CLASSES,
481
+				EE_BUSINESS,
482
+			)
483
+		);
484
+		// retrieve instantiated class
485
+		return $this->_load(
486
+			$paths,
487
+			'EE_',
488
+			$class_name,
489
+			'class',
490
+			$arguments,
491
+			$from_db,
492
+			$cache,
493
+			$load_only
494
+		);
495
+	}
496
+
497
+
498
+	/**
499
+	 * loads helper classes - must be singletons
500
+	 *
501
+	 * @param string $class_name - simple class name ie: price
502
+	 * @param mixed  $arguments
503
+	 * @param bool   $load_only
504
+	 * @return EEH_Base | bool
505
+	 * @throws InvalidInterfaceException
506
+	 * @throws InvalidDataTypeException
507
+	 * @throws EE_Error
508
+	 * @throws ReflectionException
509
+	 * @throws InvalidArgumentException
510
+	 */
511
+	public function load_helper($class_name, $arguments = array(), $load_only = true)
512
+	{
513
+		// todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed
514
+		$helper_paths = apply_filters('FHEE__EE_Registry__load_helper__helper_paths', array(EE_HELPERS));
515
+		// retrieve instantiated class
516
+		return $this->_load(
517
+			$helper_paths,
518
+			'EEH_',
519
+			$class_name,
520
+			'helper',
521
+			$arguments,
522
+			false,
523
+			true,
524
+			$load_only
525
+		);
526
+	}
527
+
528
+
529
+	/**
530
+	 * loads core classes - must be singletons
531
+	 *
532
+	 * @param string $class_name - simple class name ie: session
533
+	 * @param mixed  $arguments
534
+	 * @param bool   $load_only
535
+	 * @param bool   $cache      whether to cache the object or not.
536
+	 * @return mixed
537
+	 * @throws InvalidInterfaceException
538
+	 * @throws InvalidDataTypeException
539
+	 * @throws EE_Error
540
+	 * @throws ReflectionException
541
+	 * @throws InvalidArgumentException
542
+	 */
543
+	public function load_lib($class_name, $arguments = array(), $load_only = false, $cache = true)
544
+	{
545
+		$paths = array(
546
+			EE_LIBRARIES,
547
+			EE_LIBRARIES . 'messages/',
548
+			EE_LIBRARIES . 'shortcodes/',
549
+			EE_LIBRARIES . 'qtips/',
550
+			EE_LIBRARIES . 'payment_methods/',
551
+		);
552
+		// retrieve instantiated class
553
+		return $this->_load(
554
+			$paths,
555
+			'EE_',
556
+			$class_name,
557
+			'lib',
558
+			$arguments,
559
+			false,
560
+			$cache,
561
+			$load_only
562
+		);
563
+	}
564
+
565
+
566
+	/**
567
+	 * loads model classes - must be singletons
568
+	 *
569
+	 * @param string $class_name - simple class name ie: price
570
+	 * @param mixed  $arguments
571
+	 * @param bool   $load_only
572
+	 * @return EEM_Base | bool
573
+	 * @throws InvalidInterfaceException
574
+	 * @throws InvalidDataTypeException
575
+	 * @throws EE_Error
576
+	 * @throws ReflectionException
577
+	 * @throws InvalidArgumentException
578
+	 */
579
+	public function load_model($class_name, $arguments = array(), $load_only = false)
580
+	{
581
+		$paths = apply_filters(
582
+			'FHEE__EE_Registry__load_model__paths',
583
+			array(
584
+				EE_MODELS,
585
+				EE_CORE,
586
+			)
587
+		);
588
+		// retrieve instantiated class
589
+		return $this->_load(
590
+			$paths,
591
+			'EEM_',
592
+			$class_name,
593
+			'model',
594
+			$arguments,
595
+			false,
596
+			true,
597
+			$load_only
598
+		);
599
+	}
600
+
601
+
602
+	/**
603
+	 * loads model classes - must be singletons
604
+	 *
605
+	 * @param string $class_name - simple class name ie: price
606
+	 * @param mixed  $arguments
607
+	 * @param bool   $load_only
608
+	 * @return mixed | bool
609
+	 * @throws InvalidInterfaceException
610
+	 * @throws InvalidDataTypeException
611
+	 * @throws EE_Error
612
+	 * @throws ReflectionException
613
+	 * @throws InvalidArgumentException
614
+	 */
615
+	public function load_model_class($class_name, $arguments = array(), $load_only = true)
616
+	{
617
+		$paths = array(
618
+			EE_MODELS . 'fields/',
619
+			EE_MODELS . 'helpers/',
620
+			EE_MODELS . 'relations/',
621
+			EE_MODELS . 'strategies/',
622
+		);
623
+		// retrieve instantiated class
624
+		return $this->_load(
625
+			$paths,
626
+			'EE_',
627
+			$class_name,
628
+			'',
629
+			$arguments,
630
+			false,
631
+			true,
632
+			$load_only
633
+		);
634
+	}
635
+
636
+
637
+	/**
638
+	 * Determines if $model_name is the name of an actual EE model.
639
+	 *
640
+	 * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
641
+	 * @return boolean
642
+	 */
643
+	public function is_model_name($model_name)
644
+	{
645
+		return isset($this->models[ $model_name ]);
646
+	}
647
+
648
+
649
+	/**
650
+	 * generic class loader
651
+	 *
652
+	 * @param string $path_to_file - directory path to file location, not including filename
653
+	 * @param string $file_name    - file name  ie:  my_file.php, including extension
654
+	 * @param string $type         - file type - core? class? helper? model?
655
+	 * @param mixed  $arguments
656
+	 * @param bool   $load_only
657
+	 * @return mixed
658
+	 * @throws InvalidInterfaceException
659
+	 * @throws InvalidDataTypeException
660
+	 * @throws EE_Error
661
+	 * @throws ReflectionException
662
+	 * @throws InvalidArgumentException
663
+	 */
664
+	public function load_file($path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true)
665
+	{
666
+		// retrieve instantiated class
667
+		return $this->_load(
668
+			$path_to_file,
669
+			'',
670
+			$file_name,
671
+			$type,
672
+			$arguments,
673
+			false,
674
+			true,
675
+			$load_only
676
+		);
677
+	}
678
+
679
+
680
+	/**
681
+	 * @param string $path_to_file - directory path to file location, not including filename
682
+	 * @param string $class_name   - full class name  ie:  My_Class
683
+	 * @param string $type         - file type - core? class? helper? model?
684
+	 * @param mixed  $arguments
685
+	 * @param bool   $load_only
686
+	 * @return bool|EE_Addon|object
687
+	 * @throws InvalidInterfaceException
688
+	 * @throws InvalidDataTypeException
689
+	 * @throws EE_Error
690
+	 * @throws ReflectionException
691
+	 * @throws InvalidArgumentException
692
+	 */
693
+	public function load_addon($path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false)
694
+	{
695
+		// retrieve instantiated class
696
+		return $this->_load(
697
+			$path_to_file,
698
+			'addon',
699
+			$class_name,
700
+			$type,
701
+			$arguments,
702
+			false,
703
+			true,
704
+			$load_only
705
+		);
706
+	}
707
+
708
+
709
+	/**
710
+	 * instantiates, caches, and automatically resolves dependencies
711
+	 * for classes that use a Fully Qualified Class Name.
712
+	 * if the class is not capable of being loaded using PSR-4 autoloading,
713
+	 * then you need to use one of the existing load_*() methods
714
+	 * which can resolve the classname and filepath from the passed arguments
715
+	 *
716
+	 * @param bool|string $class_name   Fully Qualified Class Name
717
+	 * @param array       $arguments    an argument, or array of arguments to pass to the class upon instantiation
718
+	 * @param bool        $cache        whether to cache the instantiated object for reuse
719
+	 * @param bool        $from_db      some classes are instantiated from the db
720
+	 *                                  and thus call a different method to instantiate
721
+	 * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
722
+	 * @param bool|string $addon        if true, will cache the object in the EE_Registry->$addons array
723
+	 * @return bool|null|mixed          null = failure to load or instantiate class object.
724
+	 *                                  object = class loaded and instantiated successfully.
725
+	 *                                  bool = fail or success when $load_only is true
726
+	 * @throws InvalidInterfaceException
727
+	 * @throws InvalidDataTypeException
728
+	 * @throws EE_Error
729
+	 * @throws ReflectionException
730
+	 * @throws InvalidArgumentException
731
+	 */
732
+	public function create(
733
+		$class_name = false,
734
+		$arguments = array(),
735
+		$cache = false,
736
+		$from_db = false,
737
+		$load_only = false,
738
+		$addon = false
739
+	) {
740
+		$class_name = ltrim($class_name, '\\');
741
+		$class_name = $this->class_cache->getFqnForAlias($class_name);
742
+		$class_exists = $this->loadOrVerifyClassExists($class_name, $arguments);
743
+		// if a non-FQCN was passed, then
744
+		// verifyClassExists() might return an object
745
+		// or it could return null if the class just could not be found anywhere
746
+		if ($class_exists instanceof $class_name || $class_exists === null) {
747
+			// either way, return the results
748
+			return $class_exists;
749
+		}
750
+		$class_name = $class_exists;
751
+		// if we're only loading the class and it already exists, then let's just return true immediately
752
+		if ($load_only) {
753
+			return true;
754
+		}
755
+		$addon = $addon ? 'addon' : '';
756
+		// $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
757
+		// $cache is controlled by individual calls to separate Registry loader methods like load_class()
758
+		// $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
759
+		if ($this->_cache_on && $cache && ! $load_only) {
760
+			// return object if it's already cached
761
+			$cached_class = $this->_get_cached_class($class_name, $addon, $arguments);
762
+			if ($cached_class !== null) {
763
+				return $cached_class;
764
+			}
765
+		}// obtain the loader method from the dependency map
766
+		$loader = $this->_dependency_map->class_loader($class_name);// instantiate the requested object
767
+		if ($loader instanceof Closure) {
768
+			$class_obj = $loader($arguments);
769
+		} else {
770
+			if ($loader && method_exists($this, $loader)) {
771
+				$class_obj = $this->{$loader}($class_name, $arguments);
772
+			} else {
773
+				$class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db);
774
+			}
775
+		}
776
+		if (($this->_cache_on && $cache) || $this->get_class_abbreviation($class_name, '')) {
777
+			// save it for later... kinda like gum  { : $
778
+			$this->_set_cached_class(
779
+				$class_obj,
780
+				$class_name,
781
+				$addon,
782
+				$from_db,
783
+				$arguments
784
+			);
785
+		}
786
+		$this->_cache_on = true;
787
+		return $class_obj;
788
+	}
789
+
790
+
791
+	/**
792
+	 * Recursively checks that a class exists and potentially attempts to load classes with non-FQCNs
793
+	 *
794
+	 * @param string|object $class_name
795
+	 * @param array         $arguments
796
+	 * @param int           $attempt
797
+	 * @return mixed
798
+	 */
799
+	private function loadOrVerifyClassExists($class_name, array $arguments, $attempt = 1)
800
+	{
801
+		if (is_object($class_name) || class_exists($class_name)) {
802
+			return $class_name;
803
+		}
804
+		switch ($attempt) {
805
+			case 1:
806
+				// if it's a FQCN then maybe the class is registered with a preceding \
807
+				$class_name = strpos($class_name, '\\') !== false
808
+					? '\\' . ltrim($class_name, '\\')
809
+					: $class_name;
810
+				break;
811
+			case 2:
812
+				//
813
+				$loader = $this->_dependency_map->class_loader($class_name);
814
+				if ($loader && method_exists($this, $loader)) {
815
+					return $this->{$loader}($class_name, $arguments);
816
+				}
817
+				break;
818
+			case 3:
819
+			default:
820
+				return null;
821
+		}
822
+		$attempt++;
823
+		return $this->loadOrVerifyClassExists($class_name, $arguments, $attempt);
824
+	}
825
+
826
+
827
+	/**
828
+	 * instantiates, caches, and injects dependencies for classes
829
+	 *
830
+	 * @param array       $file_paths   an array of paths to folders to look in
831
+	 * @param string      $class_prefix EE  or EEM or... ???
832
+	 * @param bool|string $class_name   $class name
833
+	 * @param string      $type         file type - core? class? helper? model?
834
+	 * @param mixed       $arguments    an argument or array of arguments to pass to the class upon instantiation
835
+	 * @param bool        $from_db      some classes are instantiated from the db
836
+	 *                                  and thus call a different method to instantiate
837
+	 * @param bool        $cache        whether to cache the instantiated object for reuse
838
+	 * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
839
+	 * @return bool|null|object null = failure to load or instantiate class object.
840
+	 *                                  object = class loaded and instantiated successfully.
841
+	 *                                  bool = fail or success when $load_only is true
842
+	 * @throws EE_Error
843
+	 * @throws ReflectionException
844
+	 * @throws InvalidInterfaceException
845
+	 * @throws InvalidDataTypeException
846
+	 * @throws InvalidArgumentException
847
+	 */
848
+	protected function _load(
849
+		$file_paths = array(),
850
+		$class_prefix = 'EE_',
851
+		$class_name = false,
852
+		$type = 'class',
853
+		$arguments = array(),
854
+		$from_db = false,
855
+		$cache = true,
856
+		$load_only = false
857
+	) {
858
+		$class_name = ltrim($class_name, '\\');
859
+		// strip php file extension
860
+		$class_name = str_replace('.php', '', trim($class_name));
861
+		// does the class have a prefix ?
862
+		if (! empty($class_prefix) && $class_prefix !== 'addon') {
863
+			// make sure $class_prefix is uppercase
864
+			$class_prefix = strtoupper(trim($class_prefix));
865
+			// add class prefix ONCE!!!
866
+			$class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
867
+		}
868
+		$class_name = $this->class_cache->getFqnForAlias($class_name);
869
+		$class_exists = class_exists($class_name, false);
870
+		// if we're only loading the class and it already exists, then let's just return true immediately
871
+		if ($load_only && $class_exists) {
872
+			return true;
873
+		}
874
+		$arguments = is_array($arguments) ? $arguments : array($arguments);
875
+		// $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
876
+		// $cache is controlled by individual calls to separate Registry loader methods like load_class()
877
+		// $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
878
+		if ($this->_cache_on && $cache && ! $load_only) {
879
+			// return object if it's already cached
880
+			$cached_class = $this->_get_cached_class($class_name, $class_prefix, $arguments);
881
+			if ($cached_class !== null) {
882
+				return $cached_class;
883
+			}
884
+		}
885
+		// if the class doesn't already exist.. then we need to try and find the file and load it
886
+		if (! $class_exists) {
887
+			// get full path to file
888
+			$path = $this->_resolve_path($class_name, $type, $file_paths);
889
+			// load the file
890
+			$loaded = $this->_require_file($path, $class_name, $type, $file_paths);
891
+			// if we are only loading a file but NOT instantiating an object
892
+			// then return boolean for whether class was loaded or not
893
+			if ($load_only) {
894
+				return $loaded;
895
+			}
896
+			// if an object was expected but loading failed, then return nothing
897
+			if (! $loaded) {
898
+				return null;
899
+			}
900
+		}
901
+		// instantiate the requested object
902
+		$class_obj = $this->_create_object($class_name, $arguments, $type, $from_db);
903
+		if ($this->_cache_on && $cache) {
904
+			// save it for later... kinda like gum  { : $
905
+			$this->_set_cached_class(
906
+				$class_obj,
907
+				$class_name,
908
+				$class_prefix,
909
+				$from_db,
910
+				$arguments
911
+			);
912
+		}
913
+		$this->_cache_on = true;
914
+		return $class_obj;
915
+	}
916
+
917
+
918
+	/**
919
+	 * @param string $class_name
920
+	 * @param string $default have to specify something, but not anything that will conflict
921
+	 * @return mixed|string
922
+	 */
923
+	protected function get_class_abbreviation($class_name, $default = 'FANCY_BATMAN_PANTS')
924
+	{
925
+		return isset($this->_class_abbreviations[ $class_name ])
926
+			? $this->_class_abbreviations[ $class_name ]
927
+			: $default;
928
+	}
929
+
930
+
931
+	/**
932
+	 * attempts to find a cached version of the requested class
933
+	 * by looking in the following places:
934
+	 *        $this->{$class_abbreviation}            ie:    $this->CART
935
+	 *        $this->{$class_name}                        ie:    $this->Some_Class
936
+	 *        $this->LIB->{$class_name}                ie:    $this->LIB->Some_Class
937
+	 *        $this->addon->{$class_name}    ie:    $this->addon->Some_Addon_Class
938
+	 *
939
+	 * @param string $class_name
940
+	 * @param string $class_prefix
941
+	 * @param array  $arguments
942
+	 * @return mixed
943
+	 */
944
+	protected function _get_cached_class(
945
+		$class_name,
946
+		$class_prefix = '',
947
+		$arguments = array()
948
+	) {
949
+		if ($class_name === 'EE_Registry') {
950
+			return $this;
951
+		}
952
+		$class_abbreviation = $this->get_class_abbreviation($class_name);
953
+		// check if class has already been loaded, and return it if it has been
954
+		if (isset($this->{$class_abbreviation})) {
955
+			return $this->{$class_abbreviation};
956
+		}
957
+		$class_name = str_replace('\\', '_', $class_name);
958
+		if (isset($this->{$class_name})) {
959
+			return $this->{$class_name};
960
+		}
961
+		if ($class_prefix === 'addon' && isset($this->addons->{$class_name})) {
962
+			return $this->addons->{$class_name};
963
+		}
964
+		$object_identifier = $this->object_identifier->getIdentifier($class_name, $arguments);
965
+		if (isset($this->LIB->{$object_identifier})) {
966
+			return $this->LIB->{$object_identifier};
967
+		}
968
+		foreach ($this->LIB as $key => $object) {
969
+			if (// request does not contain new arguments and therefore no args identifier
970
+				! $this->object_identifier->hasArguments($object_identifier)
971
+				// but previously cached class with args was found
972
+				&& $this->object_identifier->fqcnMatchesObjectIdentifier($class_name, $key)
973
+			) {
974
+				return $object;
975
+			}
976
+		}
977
+		return null;
978
+	}
979
+
980
+
981
+	/**
982
+	 * removes a cached version of the requested class
983
+	 *
984
+	 * @param string  $class_name
985
+	 * @param boolean $addon
986
+	 * @param array   $arguments
987
+	 * @return boolean
988
+	 */
989
+	public function clear_cached_class(
990
+		$class_name,
991
+		$addon = false,
992
+		$arguments = array()
993
+	) {
994
+		$class_abbreviation = $this->get_class_abbreviation($class_name);
995
+		// check if class has already been loaded, and return it if it has been
996
+		if (isset($this->{$class_abbreviation})) {
997
+			$this->{$class_abbreviation} = null;
998
+			return true;
999
+		}
1000
+		$class_name = str_replace('\\', '_', $class_name);
1001
+		if (isset($this->{$class_name})) {
1002
+			$this->{$class_name} = null;
1003
+			return true;
1004
+		}
1005
+		if ($addon && isset($this->addons->{$class_name})) {
1006
+			unset($this->addons->{$class_name});
1007
+			return true;
1008
+		}
1009
+		$class_name = $this->object_identifier->getIdentifier($class_name, $arguments);
1010
+		if (isset($this->LIB->{$class_name})) {
1011
+			unset($this->LIB->{$class_name});
1012
+			return true;
1013
+		}
1014
+		return false;
1015
+	}
1016
+
1017
+
1018
+	/**
1019
+	 * _set_cached_class
1020
+	 * attempts to cache the instantiated class locally
1021
+	 * in one of the following places, in the following order:
1022
+	 *        $this->{class_abbreviation}   ie:    $this->CART
1023
+	 *        $this->{$class_name}          ie:    $this->Some_Class
1024
+	 *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1025
+	 *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1026
+	 *
1027
+	 * @param object $class_obj
1028
+	 * @param string $class_name
1029
+	 * @param string $class_prefix
1030
+	 * @param bool   $from_db
1031
+	 * @param array  $arguments
1032
+	 * @return void
1033
+	 */
1034
+	protected function _set_cached_class(
1035
+		$class_obj,
1036
+		$class_name,
1037
+		$class_prefix = '',
1038
+		$from_db = false,
1039
+		$arguments = array()
1040
+	) {
1041
+		if ($class_name === 'EE_Registry' || empty($class_obj)) {
1042
+			return;
1043
+		}
1044
+		// return newly instantiated class
1045
+		$class_abbreviation = $this->get_class_abbreviation($class_name, '');
1046
+		if ($class_abbreviation) {
1047
+			$this->{$class_abbreviation} = $class_obj;
1048
+			return;
1049
+		}
1050
+		$class_name = str_replace('\\', '_', $class_name);
1051
+		if (property_exists($this, $class_name)) {
1052
+			$this->{$class_name} = $class_obj;
1053
+			return;
1054
+		}
1055
+		if ($class_prefix === 'addon') {
1056
+			$this->addons->{$class_name} = $class_obj;
1057
+			return;
1058
+		}
1059
+		if (! $from_db) {
1060
+			$class_name = $this->object_identifier->getIdentifier($class_name, $arguments);
1061
+			$this->LIB->{$class_name} = $class_obj;
1062
+		}
1063
+	}
1064
+
1065
+
1066
+	/**
1067
+	 * attempts to find a full valid filepath for the requested class.
1068
+	 * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
1069
+	 * then returns that path if the target file has been found and is readable
1070
+	 *
1071
+	 * @param string $class_name
1072
+	 * @param string $type
1073
+	 * @param array  $file_paths
1074
+	 * @return string | bool
1075
+	 */
1076
+	protected function _resolve_path($class_name, $type = '', $file_paths = array())
1077
+	{
1078
+		// make sure $file_paths is an array
1079
+		$file_paths = is_array($file_paths)
1080
+			? $file_paths
1081
+			: array($file_paths);
1082
+		// cycle thru paths
1083
+		foreach ($file_paths as $key => $file_path) {
1084
+			// convert all separators to proper /, if no filepath, then use EE_CLASSES
1085
+			$file_path = $file_path
1086
+				? str_replace(array('/', '\\'), '/', $file_path)
1087
+				: EE_CLASSES;
1088
+			// prep file type
1089
+			$type = ! empty($type)
1090
+				? trim($type, '.') . '.'
1091
+				: '';
1092
+			// build full file path
1093
+			$file_paths[ $key ] = rtrim($file_path, '/') . '/' . $class_name . '.' . $type . 'php';
1094
+			// does the file exist and can be read ?
1095
+			if (is_readable($file_paths[ $key ])) {
1096
+				return $file_paths[ $key ];
1097
+			}
1098
+		}
1099
+		return false;
1100
+	}
1101
+
1102
+
1103
+	/**
1104
+	 * basically just performs a require_once()
1105
+	 * but with some error handling
1106
+	 *
1107
+	 * @param  string $path
1108
+	 * @param  string $class_name
1109
+	 * @param  string $type
1110
+	 * @param  array  $file_paths
1111
+	 * @return bool
1112
+	 * @throws EE_Error
1113
+	 * @throws ReflectionException
1114
+	 */
1115
+	protected function _require_file($path, $class_name, $type = '', $file_paths = array())
1116
+	{
1117
+		$this->resolve_legacy_class_parent($class_name);
1118
+		// don't give up! you gotta...
1119
+		try {
1120
+			// does the file exist and can it be read ?
1121
+			if (! $path) {
1122
+				// just in case the file has already been autoloaded,
1123
+				// but discrepancies in the naming schema are preventing it from
1124
+				// being loaded via one of the EE_Registry::load_*() methods,
1125
+				// then let's try one last hail mary before throwing an exception
1126
+				// and call class_exists() again, but with autoloading turned ON
1127
+				if (class_exists($class_name)) {
1128
+					return true;
1129
+				}
1130
+				// so sorry, can't find the file
1131
+				throw new EE_Error(
1132
+					sprintf(
1133
+						esc_html__(
1134
+							'The %1$s file %2$s could not be located or is not readable due to file permissions. Please ensure that the following filepath(s) are correct: %3$s',
1135
+							'event_espresso'
1136
+						),
1137
+						trim($type, '.'),
1138
+						$class_name,
1139
+						'<br />' . implode(',<br />', $file_paths)
1140
+					)
1141
+				);
1142
+			}
1143
+			// get the file
1144
+			require_once($path);
1145
+			// if the class isn't already declared somewhere
1146
+			if (class_exists($class_name, false) === false) {
1147
+				// so sorry, not a class
1148
+				throw new EE_Error(
1149
+					sprintf(
1150
+						esc_html__(
1151
+							'The %s file %s does not appear to contain the %s Class.',
1152
+							'event_espresso'
1153
+						),
1154
+						$type,
1155
+						$path,
1156
+						$class_name
1157
+					)
1158
+				);
1159
+			}
1160
+		} catch (EE_Error $e) {
1161
+			$e->get_error();
1162
+			return false;
1163
+		}
1164
+		return true;
1165
+	}
1166
+
1167
+
1168
+	/**
1169
+	 * Some of our legacy classes that extended a parent class would simply use a require() statement
1170
+	 * before their class declaration in order to ensure that the parent class was loaded.
1171
+	 * This is not ideal, but it's nearly impossible to determine the parent class of a non-namespaced class,
1172
+	 * without triggering a fatal error because the parent class has yet to be loaded and therefore doesn't exist.
1173
+	 *
1174
+	 * @param string $class_name
1175
+	 */
1176
+	protected function resolve_legacy_class_parent($class_name = '')
1177
+	{
1178
+		try {
1179
+			$legacy_parent_class_map = array(
1180
+				'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php',
1181
+			);
1182
+			if (isset($legacy_parent_class_map[ $class_name ])) {
1183
+				require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[ $class_name ];
1184
+			}
1185
+		} catch (Exception $exception) {
1186
+		}
1187
+	}
1188
+
1189
+
1190
+	/**
1191
+	 * _create_object
1192
+	 * Attempts to instantiate the requested class via any of the
1193
+	 * commonly used instantiation methods employed throughout EE.
1194
+	 * The priority for instantiation is as follows:
1195
+	 *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
1196
+	 *        - model objects via their 'new_instance_from_db' method
1197
+	 *        - model objects via their 'new_instance' method
1198
+	 *        - "singleton" classes" via their 'instance' method
1199
+	 *    - standard instantiable classes via their __constructor
1200
+	 * Prior to instantiation, if the classname exists in the dependency_map,
1201
+	 * then the constructor for the requested class will be examined to determine
1202
+	 * if any dependencies exist, and if they can be injected.
1203
+	 * If so, then those classes will be added to the array of arguments passed to the constructor
1204
+	 *
1205
+	 * @param string $class_name
1206
+	 * @param array  $arguments
1207
+	 * @param string $type
1208
+	 * @param bool   $from_db
1209
+	 * @return null|object|bool
1210
+	 * @throws InvalidArgumentException
1211
+	 * @throws InvalidInterfaceException
1212
+	 * @throws EE_Error
1213
+	 * @throws ReflectionException
1214
+	 * @throws InvalidDataTypeException
1215
+	 */
1216
+	protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false)
1217
+	{
1218
+		// create reflection
1219
+		$reflector = $this->mirror->getReflectionClass($class_name);
1220
+		// make sure arguments are an array
1221
+		$arguments = is_array($arguments)
1222
+			? $arguments
1223
+			: array($arguments);
1224
+		// and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
1225
+		// else wrap it in an additional array so that it doesn't get split into multiple parameters
1226
+		$arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
1227
+			? $arguments
1228
+			: array($arguments);
1229
+		// attempt to inject dependencies ?
1230
+		if ($this->_dependency_map->has($class_name)) {
1231
+			$arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
1232
+		}
1233
+		// instantiate the class if possible
1234
+		if ($reflector->isAbstract()) {
1235
+			// nothing to instantiate, loading file was enough
1236
+			// does not throw an exception so $instantiation_mode is unused
1237
+			// $instantiation_mode = "1) no constructor abstract class";
1238
+			return true;
1239
+		}
1240
+		if (empty($arguments)
1241
+			&& $this->mirror->getConstructorFromReflection($reflector) === null
1242
+			&& $reflector->isInstantiable()
1243
+		) {
1244
+			// no constructor = static methods only... nothing to instantiate, loading file was enough
1245
+			// $instantiation_mode = "2) no constructor but instantiable";
1246
+			return $reflector->newInstance();
1247
+		}
1248
+		if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
1249
+			// $instantiation_mode = "3) new_instance_from_db()";
1250
+			return call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments);
1251
+		}
1252
+		if (method_exists($class_name, 'new_instance')) {
1253
+			// $instantiation_mode = "4) new_instance()";
1254
+			return call_user_func_array(array($class_name, 'new_instance'), $arguments);
1255
+		}
1256
+		if (method_exists($class_name, 'instance')) {
1257
+			// $instantiation_mode = "5) instance()";
1258
+			return call_user_func_array(array($class_name, 'instance'), $arguments);
1259
+		}
1260
+		if ($reflector->isInstantiable()) {
1261
+			// $instantiation_mode = "6) constructor";
1262
+			return $reflector->newInstanceArgs($arguments);
1263
+		}
1264
+		// heh ? something's not right !
1265
+		throw new EE_Error(
1266
+			sprintf(
1267
+				__('The %s file %s could not be instantiated.', 'event_espresso'),
1268
+				$type,
1269
+				$class_name
1270
+			)
1271
+		);
1272
+	}
1273
+
1274
+
1275
+	/**
1276
+	 * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1277
+	 * @param array $array
1278
+	 * @return bool
1279
+	 */
1280
+	protected function _array_is_numerically_and_sequentially_indexed(array $array)
1281
+	{
1282
+		return ! empty($array)
1283
+			? array_keys($array) === range(0, count($array) - 1)
1284
+			: true;
1285
+	}
1286
+
1287
+
1288
+	/**
1289
+	 * _resolve_dependencies
1290
+	 * examines the constructor for the requested class to determine
1291
+	 * if any dependencies exist, and if they can be injected.
1292
+	 * If so, then those classes will be added to the array of arguments passed to the constructor
1293
+	 * PLZ NOTE: this is achieved by type hinting the constructor params
1294
+	 * For example:
1295
+	 *        if attempting to load a class "Foo" with the following constructor:
1296
+	 *        __construct( Bar $bar_class, Fighter $grohl_class )
1297
+	 *        then $bar_class and $grohl_class will be added to the $arguments array,
1298
+	 *        but only IF they are NOT already present in the incoming arguments array,
1299
+	 *        and the correct classes can be loaded
1300
+	 *
1301
+	 * @param ReflectionClass $reflector
1302
+	 * @param string          $class_name
1303
+	 * @param array           $arguments
1304
+	 * @return array
1305
+	 * @throws InvalidArgumentException
1306
+	 * @throws InvalidDataTypeException
1307
+	 * @throws InvalidInterfaceException
1308
+	 * @throws ReflectionException
1309
+	 */
1310
+	protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, array $arguments = array())
1311
+	{
1312
+		// let's examine the constructor
1313
+		$constructor = $this->mirror->getConstructorFromReflection($reflector);
1314
+		// whu? huh? nothing?
1315
+		if (! $constructor) {
1316
+			return $arguments;
1317
+		}
1318
+		// get constructor parameters
1319
+		$params = $this->mirror->getParametersFromReflection($reflector);
1320
+		// and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1321
+		$argument_keys = array_keys($arguments);
1322
+		// now loop thru all of the constructors expected parameters
1323
+		foreach ($params as $index => $param) {
1324
+			try {
1325
+				// is this a dependency for a specific class ?
1326
+				$param_class = $this->mirror->getParameterClassName($param, $class_name, $index);
1327
+			} catch (ReflectionException $exception) {
1328
+				// uh-oh... most likely a legacy class that has not been autoloaded
1329
+				// let's try to derive the classname from what we have now
1330
+				// and hope that the property var name is close to the class name
1331
+				$param_class = $param->getName();
1332
+				$param_class = str_replace('_', ' ', $param_class);
1333
+				$param_class = ucwords($param_class);
1334
+				$param_class = str_replace(' ', '_', $param_class);
1335
+			}
1336
+			// BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1337
+			$param_class = $this->class_cache->isAlias($param_class, $class_name)
1338
+				? $this->class_cache->getFqnForAlias($param_class, $class_name)
1339
+				: $param_class;
1340
+			if (// param is not even a class
1341
+				$param_class === null
1342
+				// and something already exists in the incoming arguments for this param
1343
+				&& array_key_exists($index, $argument_keys)
1344
+				&& array_key_exists($argument_keys[ $index ], $arguments)
1345
+			) {
1346
+				// so let's skip this argument and move on to the next
1347
+				continue;
1348
+			}
1349
+			if (// parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
1350
+				$param_class !== null
1351
+				&& isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ])
1352
+				&& $arguments[ $argument_keys[ $index ] ] instanceof $param_class
1353
+			) {
1354
+				// skip this argument and move on to the next
1355
+				continue;
1356
+			}
1357
+			if (// parameter is type hinted as a class, and should be injected
1358
+				$param_class !== null
1359
+				&& $this->_dependency_map->has_dependency_for_class($class_name, $param_class)
1360
+			) {
1361
+				$arguments = $this->_resolve_dependency(
1362
+					$class_name,
1363
+					$param_class,
1364
+					$arguments,
1365
+					$index
1366
+				);
1367
+			}
1368
+			if (empty($arguments[ $index ])) {
1369
+				$arguments[ $index ] = $this->mirror->getParameterDefaultValue(
1370
+					$param,
1371
+					$class_name,
1372
+					$index
1373
+				);
1374
+			}
1375
+		}
1376
+		return $arguments;
1377
+	}
1378
+
1379
+
1380
+	/**
1381
+	 * @param string $class_name
1382
+	 * @param string $param_class
1383
+	 * @param array  $arguments
1384
+	 * @param mixed  $index
1385
+	 * @return array
1386
+	 * @throws InvalidArgumentException
1387
+	 * @throws InvalidInterfaceException
1388
+	 * @throws InvalidDataTypeException
1389
+	 */
1390
+	protected function _resolve_dependency($class_name, $param_class, $arguments, $index)
1391
+	{
1392
+		$dependency = null;
1393
+		// should dependency be loaded from cache ?
1394
+		$cache_on = $this->_dependency_map->loading_strategy_for_class_dependency(
1395
+			$class_name,
1396
+			$param_class
1397
+		);
1398
+		$cache_on = $cache_on !== EE_Dependency_Map::load_new_object;
1399
+		// we might have a dependency...
1400
+		// let's MAYBE try and find it in our cache if that's what's been requested
1401
+		$cached_class = $cache_on
1402
+			? $this->_get_cached_class($param_class)
1403
+			: null;
1404
+		// and grab it if it exists
1405
+		if ($cached_class instanceof $param_class) {
1406
+			$dependency = $cached_class;
1407
+		} elseif ($param_class !== $class_name) {
1408
+			// obtain the loader method from the dependency map
1409
+			$loader = $this->_dependency_map->class_loader($param_class);
1410
+			// is loader a custom closure ?
1411
+			if ($loader instanceof Closure) {
1412
+				$dependency = $loader($arguments);
1413
+			} else {
1414
+				// set the cache on property for the recursive loading call
1415
+				$this->_cache_on = $cache_on;
1416
+				// if not, then let's try and load it via the registry
1417
+				if ($loader && method_exists($this, $loader)) {
1418
+					$dependency = $this->{$loader}($param_class);
1419
+				} else {
1420
+					$dependency = LoaderFactory::getLoader()->load(
1421
+						$param_class,
1422
+						array(),
1423
+						$cache_on
1424
+					);
1425
+				}
1426
+			}
1427
+		}
1428
+		// did we successfully find the correct dependency ?
1429
+		if ($dependency instanceof $param_class) {
1430
+			// then let's inject it into the incoming array of arguments at the correct location
1431
+			$arguments[ $index ] = $dependency;
1432
+		}
1433
+		return $arguments;
1434
+	}
1435
+
1436
+
1437
+	/**
1438
+	 * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1439
+	 *
1440
+	 * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1441
+	 *                          in the EE_Dependency_Map::$_class_loaders array,
1442
+	 *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1443
+	 * @param array  $arguments
1444
+	 * @return object
1445
+	 */
1446
+	public static function factory($classname, $arguments = array())
1447
+	{
1448
+		$loader = self::instance()->_dependency_map->class_loader($classname);
1449
+		if ($loader instanceof Closure) {
1450
+			return $loader($arguments);
1451
+		}
1452
+		if (method_exists(self::instance(), $loader)) {
1453
+			return self::instance()->{$loader}($classname, $arguments);
1454
+		}
1455
+		return null;
1456
+	}
1457
+
1458
+
1459
+	/**
1460
+	 * Gets the addon by its class name
1461
+	 *
1462
+	 * @param string $class_name
1463
+	 * @return EE_Addon
1464
+	 */
1465
+	public function getAddon($class_name)
1466
+	{
1467
+		$class_name = str_replace('\\', '_', $class_name);
1468
+		if (isset($this->addons->{$class_name})) {
1469
+			return $this->addons->{$class_name};
1470
+		} else {
1471
+			return null;
1472
+		}
1473
+	}
1474
+
1475
+
1476
+	/**
1477
+	 * removes the addon from the internal cache
1478
+	 *
1479
+	 * @param string $class_name
1480
+	 * @return void
1481
+	 */
1482
+	public function removeAddon($class_name)
1483
+	{
1484
+		$class_name = str_replace('\\', '_', $class_name);
1485
+		unset($this->addons->{$class_name});
1486
+	}
1487
+
1488
+
1489
+	/**
1490
+	 * Gets the addon by its name/slug (not classname. For that, just
1491
+	 * use the get_addon() method above
1492
+	 *
1493
+	 * @param string $name
1494
+	 * @return EE_Addon
1495
+	 */
1496
+	public function get_addon_by_name($name)
1497
+	{
1498
+		foreach ($this->addons as $addon) {
1499
+			if ($addon->name() === $name) {
1500
+				return $addon;
1501
+			}
1502
+		}
1503
+		return null;
1504
+	}
1505
+
1506
+
1507
+	/**
1508
+	 * Gets an array of all the registered addons, where the keys are their names.
1509
+	 * (ie, what each returns for their name() function)
1510
+	 * They're already available on EE_Registry::instance()->addons as properties,
1511
+	 * where each property's name is the addon's classname,
1512
+	 * So if you just want to get the addon by classname,
1513
+	 * OR use the get_addon() method above.
1514
+	 * PLEASE  NOTE:
1515
+	 * addons with Fully Qualified Class Names
1516
+	 * have had the namespace separators converted to underscores,
1517
+	 * so a classname like Fully\Qualified\ClassName
1518
+	 * would have been converted to Fully_Qualified_ClassName
1519
+	 *
1520
+	 * @return EE_Addon[] where the KEYS are the addon's name()
1521
+	 */
1522
+	public function get_addons_by_name()
1523
+	{
1524
+		$addons = array();
1525
+		foreach ($this->addons as $addon) {
1526
+			$addons[ $addon->name() ] = $addon;
1527
+		}
1528
+		return $addons;
1529
+	}
1530
+
1531
+
1532
+	/**
1533
+	 * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1534
+	 * a stale copy of it around
1535
+	 *
1536
+	 * @param string $model_name
1537
+	 * @return \EEM_Base
1538
+	 * @throws \EE_Error
1539
+	 */
1540
+	public function reset_model($model_name)
1541
+	{
1542
+		$model_class_name = strpos($model_name, 'EEM_') !== 0
1543
+			? "EEM_{$model_name}"
1544
+			: $model_name;
1545
+		if (! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1546
+			return null;
1547
+		}
1548
+		// get that model reset it and make sure we nuke the old reference to it
1549
+		if ($this->LIB->{$model_class_name} instanceof $model_class_name
1550
+			&& is_callable(
1551
+				array($model_class_name, 'reset')
1552
+			)) {
1553
+			$this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset();
1554
+		} else {
1555
+			throw new EE_Error(
1556
+				sprintf(
1557
+					esc_html__('Model %s does not have a method "reset"', 'event_espresso'),
1558
+					$model_name
1559
+				)
1560
+			);
1561
+		}
1562
+		return $this->LIB->{$model_class_name};
1563
+	}
1564
+
1565
+
1566
+	/**
1567
+	 * Resets the registry.
1568
+	 * The criteria for what gets reset is based on what can be shared between sites on the same request when
1569
+	 * switch_to_blog is used in a multisite install.  Here is a list of things that are NOT reset.
1570
+	 * - $_dependency_map
1571
+	 * - $_class_abbreviations
1572
+	 * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1573
+	 * - $REQ:  Still on the same request so no need to change.
1574
+	 * - $CAP: There is no site specific state in the EE_Capability class.
1575
+	 * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only
1576
+	 * one Session can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1577
+	 * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1578
+	 *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1579
+	 *             switch or on the restore.
1580
+	 * - $modules
1581
+	 * - $shortcodes
1582
+	 * - $widgets
1583
+	 *
1584
+	 * @param boolean $hard             [deprecated]
1585
+	 * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1586
+	 *                                  or just reset without re-instantiating (handy to set to FALSE if you're not
1587
+	 *                                  sure if you CAN currently reinstantiate the singletons at the moment)
1588
+	 * @param   bool  $reset_models     Defaults to true.  When false, then the models are not reset.  This is so
1589
+	 *                                  client
1590
+	 *                                  code instead can just change the model context to a different blog id if
1591
+	 *                                  necessary
1592
+	 * @return EE_Registry
1593
+	 * @throws InvalidInterfaceException
1594
+	 * @throws InvalidDataTypeException
1595
+	 * @throws EE_Error
1596
+	 * @throws ReflectionException
1597
+	 * @throws InvalidArgumentException
1598
+	 */
1599
+	public static function reset($hard = false, $reinstantiate = true, $reset_models = true)
1600
+	{
1601
+		$instance = self::instance();
1602
+		$instance->_cache_on = true;
1603
+		// reset some "special" classes
1604
+		EEH_Activation::reset();
1605
+		$hard = apply_filters('FHEE__EE_Registry__reset__hard', $hard);
1606
+		$instance->CFG = EE_Config::reset($hard, $reinstantiate);
1607
+		$instance->CART = null;
1608
+		$instance->MRM = null;
1609
+		$instance->AssetsRegistry = LoaderFactory::getLoader()->getShared(
1610
+			'EventEspresso\core\services\assets\Registry'
1611
+		);
1612
+		// messages reset
1613
+		EED_Messages::reset();
1614
+		// handle of objects cached on LIB
1615
+		foreach (array('LIB', 'modules') as $cache) {
1616
+			foreach ($instance->{$cache} as $class_name => $class) {
1617
+				if (self::_reset_and_unset_object($class, $reset_models)) {
1618
+					unset($instance->{$cache}->{$class_name});
1619
+				}
1620
+			}
1621
+		}
1622
+		return $instance;
1623
+	}
1624
+
1625
+
1626
+	/**
1627
+	 * if passed object implements ResettableInterface, then call it's reset() method
1628
+	 * if passed object implements InterminableInterface, then return false,
1629
+	 * to indicate that it should NOT be cleared from the Registry cache
1630
+	 *
1631
+	 * @param      $object
1632
+	 * @param bool $reset_models
1633
+	 * @return bool returns true if cached object should be unset
1634
+	 */
1635
+	private static function _reset_and_unset_object($object, $reset_models)
1636
+	{
1637
+		if (! is_object($object)) {
1638
+			// don't unset anything that's not an object
1639
+			return false;
1640
+		}
1641
+		if ($object instanceof EED_Module) {
1642
+			$object::reset();
1643
+			// don't unset modules
1644
+			return false;
1645
+		}
1646
+		if ($object instanceof ResettableInterface) {
1647
+			if ($object instanceof EEM_Base) {
1648
+				if ($reset_models) {
1649
+					$object->reset();
1650
+					return true;
1651
+				}
1652
+				return false;
1653
+			}
1654
+			$object->reset();
1655
+			return true;
1656
+		}
1657
+		if (! $object instanceof InterminableInterface) {
1658
+			return true;
1659
+		}
1660
+		return false;
1661
+	}
1662
+
1663
+
1664
+	/**
1665
+	 * Gets all the custom post type models defined
1666
+	 *
1667
+	 * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1668
+	 */
1669
+	public function cpt_models()
1670
+	{
1671
+		$cpt_models = array();
1672
+		foreach ($this->non_abstract_db_models as $short_name => $classname) {
1673
+			if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1674
+				$cpt_models[ $short_name ] = $classname;
1675
+			}
1676
+		}
1677
+		return $cpt_models;
1678
+	}
1679
+
1680
+
1681
+	/**
1682
+	 * @return \EE_Config
1683
+	 */
1684
+	public static function CFG()
1685
+	{
1686
+		return self::instance()->CFG;
1687
+	}
1688
+
1689
+
1690
+	/**
1691
+	 * @deprecated 4.9.62.p
1692
+	 * @param string $class_name
1693
+	 * @return ReflectionClass
1694
+	 * @throws ReflectionException
1695
+	 * @throws InvalidDataTypeException
1696
+	 */
1697
+	public function get_ReflectionClass($class_name)
1698
+	{
1699
+		return $this->mirror->getReflectionClass($class_name);
1700
+	}
1701 1701
 }
Please login to merge, or discard this patch.
Spacing   +47 added lines, -47 removed lines patch added patch discarded remove patch
@@ -193,7 +193,7 @@  discard block
 block discarded – undo
193 193
         ObjectIdentifier $object_identifier = null
194 194
     ) {
195 195
         // check if class object is instantiated
196
-        if (! self::$_instance instanceof EE_Registry
196
+        if ( ! self::$_instance instanceof EE_Registry
197 197
             && $dependency_map instanceof EE_Dependency_Map
198 198
             && $mirror instanceof Mirror
199 199
             && $class_cache instanceof ClassInterfaceCache
@@ -308,10 +308,10 @@  discard block
 block discarded – undo
308 308
         $i18n_js_strings = (array) self::$i18n_js_strings;
309 309
         foreach ($i18n_js_strings as $key => $value) {
310 310
             if (is_scalar($value)) {
311
-                $i18n_js_strings[ $key ] = html_entity_decode((string) $value, ENT_QUOTES, 'UTF-8');
311
+                $i18n_js_strings[$key] = html_entity_decode((string) $value, ENT_QUOTES, 'UTF-8');
312 312
             }
313 313
         }
314
-        return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
314
+        return '/* <![CDATA[ */ var eei18n = '.wp_json_encode($i18n_js_strings).'; /* ]]> */';
315 315
     }
316 316
 
317 317
 
@@ -330,7 +330,7 @@  discard block
 block discarded – undo
330 330
             $module_class = get_class($module);
331 331
             $this->modules->{$module_class} = $module;
332 332
         } else {
333
-            if (! class_exists('EE_Module_Request_Router', false)) {
333
+            if ( ! class_exists('EE_Module_Request_Router', false)) {
334 334
                 $this->load_core('Module_Request_Router');
335 335
             }
336 336
             EE_Module_Request_Router::module_factory($module);
@@ -371,10 +371,10 @@  discard block
 block discarded – undo
371 371
                 EE_CORE,
372 372
                 EE_ADMIN,
373 373
                 EE_CPTS,
374
-                EE_CORE . 'data_migration_scripts/',
375
-                EE_CORE . 'capabilities/',
376
-                EE_CORE . 'request_stack/',
377
-                EE_CORE . 'middleware/',
374
+                EE_CORE.'data_migration_scripts/',
375
+                EE_CORE.'capabilities/',
376
+                EE_CORE.'request_stack/',
377
+                EE_CORE.'middleware/',
378 378
             )
379 379
         );
380 380
         // retrieve instantiated class
@@ -409,7 +409,7 @@  discard block
 block discarded – undo
409 409
         $service_paths = apply_filters(
410 410
             'FHEE__EE_Registry__load_service__service_paths',
411 411
             array(
412
-                EE_CORE . 'services/',
412
+                EE_CORE.'services/',
413 413
             )
414 414
         );
415 415
         // retrieve instantiated class
@@ -544,10 +544,10 @@  discard block
 block discarded – undo
544 544
     {
545 545
         $paths = array(
546 546
             EE_LIBRARIES,
547
-            EE_LIBRARIES . 'messages/',
548
-            EE_LIBRARIES . 'shortcodes/',
549
-            EE_LIBRARIES . 'qtips/',
550
-            EE_LIBRARIES . 'payment_methods/',
547
+            EE_LIBRARIES.'messages/',
548
+            EE_LIBRARIES.'shortcodes/',
549
+            EE_LIBRARIES.'qtips/',
550
+            EE_LIBRARIES.'payment_methods/',
551 551
         );
552 552
         // retrieve instantiated class
553 553
         return $this->_load(
@@ -615,10 +615,10 @@  discard block
 block discarded – undo
615 615
     public function load_model_class($class_name, $arguments = array(), $load_only = true)
616 616
     {
617 617
         $paths = array(
618
-            EE_MODELS . 'fields/',
619
-            EE_MODELS . 'helpers/',
620
-            EE_MODELS . 'relations/',
621
-            EE_MODELS . 'strategies/',
618
+            EE_MODELS.'fields/',
619
+            EE_MODELS.'helpers/',
620
+            EE_MODELS.'relations/',
621
+            EE_MODELS.'strategies/',
622 622
         );
623 623
         // retrieve instantiated class
624 624
         return $this->_load(
@@ -642,7 +642,7 @@  discard block
 block discarded – undo
642 642
      */
643 643
     public function is_model_name($model_name)
644 644
     {
645
-        return isset($this->models[ $model_name ]);
645
+        return isset($this->models[$model_name]);
646 646
     }
647 647
 
648 648
 
@@ -763,7 +763,7 @@  discard block
 block discarded – undo
763 763
                 return $cached_class;
764 764
             }
765 765
         }// obtain the loader method from the dependency map
766
-        $loader = $this->_dependency_map->class_loader($class_name);// instantiate the requested object
766
+        $loader = $this->_dependency_map->class_loader($class_name); // instantiate the requested object
767 767
         if ($loader instanceof Closure) {
768 768
             $class_obj = $loader($arguments);
769 769
         } else {
@@ -805,7 +805,7 @@  discard block
 block discarded – undo
805 805
             case 1:
806 806
                 // if it's a FQCN then maybe the class is registered with a preceding \
807 807
                 $class_name = strpos($class_name, '\\') !== false
808
-                    ? '\\' . ltrim($class_name, '\\')
808
+                    ? '\\'.ltrim($class_name, '\\')
809 809
                     : $class_name;
810 810
                 break;
811 811
             case 2:
@@ -859,11 +859,11 @@  discard block
 block discarded – undo
859 859
         // strip php file extension
860 860
         $class_name = str_replace('.php', '', trim($class_name));
861 861
         // does the class have a prefix ?
862
-        if (! empty($class_prefix) && $class_prefix !== 'addon') {
862
+        if ( ! empty($class_prefix) && $class_prefix !== 'addon') {
863 863
             // make sure $class_prefix is uppercase
864 864
             $class_prefix = strtoupper(trim($class_prefix));
865 865
             // add class prefix ONCE!!!
866
-            $class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
866
+            $class_name = $class_prefix.str_replace($class_prefix, '', $class_name);
867 867
         }
868 868
         $class_name = $this->class_cache->getFqnForAlias($class_name);
869 869
         $class_exists = class_exists($class_name, false);
@@ -883,7 +883,7 @@  discard block
 block discarded – undo
883 883
             }
884 884
         }
885 885
         // if the class doesn't already exist.. then we need to try and find the file and load it
886
-        if (! $class_exists) {
886
+        if ( ! $class_exists) {
887 887
             // get full path to file
888 888
             $path = $this->_resolve_path($class_name, $type, $file_paths);
889 889
             // load the file
@@ -894,7 +894,7 @@  discard block
 block discarded – undo
894 894
                 return $loaded;
895 895
             }
896 896
             // if an object was expected but loading failed, then return nothing
897
-            if (! $loaded) {
897
+            if ( ! $loaded) {
898 898
                 return null;
899 899
             }
900 900
         }
@@ -922,8 +922,8 @@  discard block
 block discarded – undo
922 922
      */
923 923
     protected function get_class_abbreviation($class_name, $default = 'FANCY_BATMAN_PANTS')
924 924
     {
925
-        return isset($this->_class_abbreviations[ $class_name ])
926
-            ? $this->_class_abbreviations[ $class_name ]
925
+        return isset($this->_class_abbreviations[$class_name])
926
+            ? $this->_class_abbreviations[$class_name]
927 927
             : $default;
928 928
     }
929 929
 
@@ -1056,7 +1056,7 @@  discard block
 block discarded – undo
1056 1056
             $this->addons->{$class_name} = $class_obj;
1057 1057
             return;
1058 1058
         }
1059
-        if (! $from_db) {
1059
+        if ( ! $from_db) {
1060 1060
             $class_name = $this->object_identifier->getIdentifier($class_name, $arguments);
1061 1061
             $this->LIB->{$class_name} = $class_obj;
1062 1062
         }
@@ -1087,13 +1087,13 @@  discard block
 block discarded – undo
1087 1087
                 : EE_CLASSES;
1088 1088
             // prep file type
1089 1089
             $type = ! empty($type)
1090
-                ? trim($type, '.') . '.'
1090
+                ? trim($type, '.').'.'
1091 1091
                 : '';
1092 1092
             // build full file path
1093
-            $file_paths[ $key ] = rtrim($file_path, '/') . '/' . $class_name . '.' . $type . 'php';
1093
+            $file_paths[$key] = rtrim($file_path, '/').'/'.$class_name.'.'.$type.'php';
1094 1094
             // does the file exist and can be read ?
1095
-            if (is_readable($file_paths[ $key ])) {
1096
-                return $file_paths[ $key ];
1095
+            if (is_readable($file_paths[$key])) {
1096
+                return $file_paths[$key];
1097 1097
             }
1098 1098
         }
1099 1099
         return false;
@@ -1118,7 +1118,7 @@  discard block
 block discarded – undo
1118 1118
         // don't give up! you gotta...
1119 1119
         try {
1120 1120
             // does the file exist and can it be read ?
1121
-            if (! $path) {
1121
+            if ( ! $path) {
1122 1122
                 // just in case the file has already been autoloaded,
1123 1123
                 // but discrepancies in the naming schema are preventing it from
1124 1124
                 // being loaded via one of the EE_Registry::load_*() methods,
@@ -1136,7 +1136,7 @@  discard block
 block discarded – undo
1136 1136
                         ),
1137 1137
                         trim($type, '.'),
1138 1138
                         $class_name,
1139
-                        '<br />' . implode(',<br />', $file_paths)
1139
+                        '<br />'.implode(',<br />', $file_paths)
1140 1140
                     )
1141 1141
                 );
1142 1142
             }
@@ -1179,8 +1179,8 @@  discard block
 block discarded – undo
1179 1179
             $legacy_parent_class_map = array(
1180 1180
                 'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php',
1181 1181
             );
1182
-            if (isset($legacy_parent_class_map[ $class_name ])) {
1183
-                require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[ $class_name ];
1182
+            if (isset($legacy_parent_class_map[$class_name])) {
1183
+                require_once EE_PLUGIN_DIR_PATH.$legacy_parent_class_map[$class_name];
1184 1184
             }
1185 1185
         } catch (Exception $exception) {
1186 1186
         }
@@ -1312,7 +1312,7 @@  discard block
 block discarded – undo
1312 1312
         // let's examine the constructor
1313 1313
         $constructor = $this->mirror->getConstructorFromReflection($reflector);
1314 1314
         // whu? huh? nothing?
1315
-        if (! $constructor) {
1315
+        if ( ! $constructor) {
1316 1316
             return $arguments;
1317 1317
         }
1318 1318
         // get constructor parameters
@@ -1341,15 +1341,15 @@  discard block
 block discarded – undo
1341 1341
                 $param_class === null
1342 1342
                 // and something already exists in the incoming arguments for this param
1343 1343
                 && array_key_exists($index, $argument_keys)
1344
-                && array_key_exists($argument_keys[ $index ], $arguments)
1344
+                && array_key_exists($argument_keys[$index], $arguments)
1345 1345
             ) {
1346 1346
                 // so let's skip this argument and move on to the next
1347 1347
                 continue;
1348 1348
             }
1349 1349
             if (// parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
1350 1350
                 $param_class !== null
1351
-                && isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ])
1352
-                && $arguments[ $argument_keys[ $index ] ] instanceof $param_class
1351
+                && isset($argument_keys[$index], $arguments[$argument_keys[$index]])
1352
+                && $arguments[$argument_keys[$index]] instanceof $param_class
1353 1353
             ) {
1354 1354
                 // skip this argument and move on to the next
1355 1355
                 continue;
@@ -1365,8 +1365,8 @@  discard block
 block discarded – undo
1365 1365
                     $index
1366 1366
                 );
1367 1367
             }
1368
-            if (empty($arguments[ $index ])) {
1369
-                $arguments[ $index ] = $this->mirror->getParameterDefaultValue(
1368
+            if (empty($arguments[$index])) {
1369
+                $arguments[$index] = $this->mirror->getParameterDefaultValue(
1370 1370
                     $param,
1371 1371
                     $class_name,
1372 1372
                     $index
@@ -1428,7 +1428,7 @@  discard block
 block discarded – undo
1428 1428
         // did we successfully find the correct dependency ?
1429 1429
         if ($dependency instanceof $param_class) {
1430 1430
             // then let's inject it into the incoming array of arguments at the correct location
1431
-            $arguments[ $index ] = $dependency;
1431
+            $arguments[$index] = $dependency;
1432 1432
         }
1433 1433
         return $arguments;
1434 1434
     }
@@ -1523,7 +1523,7 @@  discard block
 block discarded – undo
1523 1523
     {
1524 1524
         $addons = array();
1525 1525
         foreach ($this->addons as $addon) {
1526
-            $addons[ $addon->name() ] = $addon;
1526
+            $addons[$addon->name()] = $addon;
1527 1527
         }
1528 1528
         return $addons;
1529 1529
     }
@@ -1542,7 +1542,7 @@  discard block
 block discarded – undo
1542 1542
         $model_class_name = strpos($model_name, 'EEM_') !== 0
1543 1543
             ? "EEM_{$model_name}"
1544 1544
             : $model_name;
1545
-        if (! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1545
+        if ( ! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1546 1546
             return null;
1547 1547
         }
1548 1548
         // get that model reset it and make sure we nuke the old reference to it
@@ -1634,7 +1634,7 @@  discard block
 block discarded – undo
1634 1634
      */
1635 1635
     private static function _reset_and_unset_object($object, $reset_models)
1636 1636
     {
1637
-        if (! is_object($object)) {
1637
+        if ( ! is_object($object)) {
1638 1638
             // don't unset anything that's not an object
1639 1639
             return false;
1640 1640
         }
@@ -1654,7 +1654,7 @@  discard block
 block discarded – undo
1654 1654
             $object->reset();
1655 1655
             return true;
1656 1656
         }
1657
-        if (! $object instanceof InterminableInterface) {
1657
+        if ( ! $object instanceof InterminableInterface) {
1658 1658
             return true;
1659 1659
         }
1660 1660
         return false;
@@ -1671,7 +1671,7 @@  discard block
 block discarded – undo
1671 1671
         $cpt_models = array();
1672 1672
         foreach ($this->non_abstract_db_models as $short_name => $classname) {
1673 1673
             if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1674
-                $cpt_models[ $short_name ] = $classname;
1674
+                $cpt_models[$short_name] = $classname;
1675 1675
             }
1676 1676
         }
1677 1677
         return $cpt_models;
Please login to merge, or discard this patch.
core/EE_Data_Migration_Manager.core.php 1 patch
Indentation   +1234 added lines, -1234 removed lines patch added patch discarded remove patch
@@ -33,1238 +33,1238 @@
 block discarded – undo
33 33
 class EE_Data_Migration_Manager implements ResettableInterface
34 34
 {
35 35
 
36
-    /**
37
-     *
38
-     * @var EE_Registry
39
-     */
40
-    // protected $EE;
41
-    /**
42
-     * name of the wordpress option which stores an array of data about
43
-     */
44
-    const data_migrations_option_name = 'ee_data_migration';
45
-
46
-
47
-    const data_migration_script_option_prefix = 'ee_data_migration_script_';
48
-
49
-    const data_migration_script_mapping_option_prefix = 'ee_dms_map_';
50
-
51
-    /**
52
-     * name of the wordpress option which stores the database' current version. IE, the code may be at version 4.2.0,
53
-     * but as migrations are performed the database will progress from 3.1.35 to 4.1.0 etc.
54
-     */
55
-    const current_database_state = 'ee_data_migration_current_db_state';
56
-
57
-    /**
58
-     * Special status string returned when we're positive there are no more data migration
59
-     * scripts that can be run.
60
-     */
61
-    const status_no_more_migration_scripts = 'no_more_migration_scripts';
62
-    /**
63
-     * string indicating the migration should continue
64
-     */
65
-    const status_continue = 'status_continue';
66
-    /**
67
-     * string indicating the migration has completed and should be ended
68
-     */
69
-    const status_completed = 'status_completed';
70
-    /**
71
-     * string indicating a fatal error occurred and the data migration should be completely aborted
72
-     */
73
-    const status_fatal_error = 'status_fatal_error';
74
-
75
-    /**
76
-     * the number of 'items' (usually DB rows) to migrate on each 'step' (ajax request sent
77
-     * during migration)
78
-     */
79
-    const step_size = 50;
80
-
81
-    /**
82
-     * option name that stores the queue of ee plugins needing to have
83
-     * their data initialized (or re-initialized) once we are done migrations
84
-     */
85
-    const db_init_queue_option_name = 'ee_db_init_queue';
86
-    /**
87
-     * Array of information concerning data migrations that have ran in the history
88
-     * of this EE installation. Keys should be the name of the version the script upgraded to
89
-     *
90
-     * @var EE_Data_Migration_Script_Base[]
91
-     */
92
-    private $_data_migrations_ran = null;
93
-    /**
94
-     * The last ran script. It's nice to store this somewhere accessible, as its easiest
95
-     * to know which was the last run by which is the newest wp option; but in most of the code
96
-     * we just use the local $_data_migration_ran array, which organized the scripts differently
97
-     *
98
-     * @var EE_Data_Migration_Script_Base
99
-     */
100
-    private $_last_ran_script = null;
101
-
102
-    /**
103
-     * Similarly to _last_ran_script, but this is the last INCOMPLETE migration script.
104
-     *
105
-     * @var EE_Data_Migration_Script_Base
106
-     */
107
-    private $_last_ran_incomplete_script = null;
108
-    /**
109
-     * array where keys are classnames, and values are filepaths of all the known migration scripts
110
-     *
111
-     * @var array
112
-     */
113
-    private $_data_migration_class_to_filepath_map;
114
-
115
-    /**
116
-     * the following 4 properties are fully set on construction.
117
-     * Note: the first two apply to whether to continue running ALL migration scripts (ie, even though we're finished
118
-     * one, we may want to start the next one); whereas the last two indicate whether to continue running a single
119
-     * data migration script
120
-     *
121
-     * @var array
122
-     */
123
-    public $stati_that_indicate_to_continue_migrations = array();
124
-
125
-    public $stati_that_indicate_to_stop_migrations = array();
126
-
127
-    public $stati_that_indicate_to_continue_single_migration_script = array();
128
-
129
-    public $stati_that_indicate_to_stop_single_migration_script = array();
130
-
131
-    /**
132
-     * @var \EventEspresso\core\services\database\TableManager $table_manager
133
-     */
134
-    protected $_table_manager;
135
-
136
-    /**
137
-     * @var \EventEspresso\core\services\database\TableAnalysis $table_analysis
138
-     */
139
-    protected $_table_analysis;
140
-
141
-    /**
142
-     * @var array $script_migration_versions
143
-     */
144
-    protected $script_migration_versions;
145
-
146
-    /**
147
-     * @var EE_Data_Migration_Manager $_instance
148
-     * @access    private
149
-     */
150
-    private static $_instance = null;
151
-
152
-
153
-    /**
154
-     * @singleton method used to instantiate class object
155
-     * @access    public
156
-     * @return EE_Data_Migration_Manager instance
157
-     */
158
-    public static function instance()
159
-    {
160
-        // check if class object is instantiated
161
-        if (! self::$_instance instanceof EE_Data_Migration_Manager) {
162
-            self::$_instance = new self();
163
-        }
164
-        return self::$_instance;
165
-    }
166
-
167
-    /**
168
-     * resets the singleton to its brand-new state (but does NOT delete old references to the old singleton. Meaning,
169
-     * all new usages of the singleton should be made with Classname::instance()) and returns it
170
-     *
171
-     * @return EE_Data_Migration_Manager
172
-     */
173
-    public static function reset()
174
-    {
175
-        self::$_instance = null;
176
-        return self::instance();
177
-    }
178
-
179
-
180
-    /**
181
-     * constructor
182
-     */
183
-    private function __construct()
184
-    {
185
-        $this->stati_that_indicate_to_continue_migrations = array(
186
-            self::status_continue,
187
-            self::status_completed,
188
-        );
189
-        $this->stati_that_indicate_to_stop_migrations = array(
190
-            self::status_fatal_error,
191
-            self::status_no_more_migration_scripts,
192
-        );
193
-        $this->stati_that_indicate_to_continue_single_migration_script = array(
194
-            self::status_continue,
195
-        );
196
-        $this->stati_that_indicate_to_stop_single_migration_script = array(
197
-            self::status_completed,
198
-            self::status_fatal_error
199
-            // note: status_no_more_migration_scripts doesn't apply
200
-        );
201
-        // make sure we've included the base migration script, because we may need the EE_DMS_Unknown_1_0_0 class
202
-        // to be defined, because right now it doesn't get autoloaded on its own
203
-        EE_Registry::instance()->load_core('Data_Migration_Class_Base', array(), true);
204
-        EE_Registry::instance()->load_core('Data_Migration_Script_Base', array(), true);
205
-        EE_Registry::instance()->load_core('DMS_Unknown_1_0_0', array(), true);
206
-        EE_Registry::instance()->load_core('Data_Migration_Script_Stage', array(), true);
207
-        EE_Registry::instance()->load_core('Data_Migration_Script_Stage_Table', array(), true);
208
-        $this->_table_manager = EE_Registry::instance()->create('TableManager', array(), true);
209
-        $this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
210
-    }
211
-
212
-
213
-    /**
214
-     * Deciphers, from an option's name, what plugin and version it relates to (see _save_migrations_ran to see what
215
-     * the option names are like, but generally they're like
216
-     * 'ee_data_migration_script_Core.4.1.0' in 4.2 or 'ee_data_migration_script_4.1.0' before that).
217
-     * The option name shouldn't ever be like 'ee_data_migration_script_Core.4.1.0.reg' because it's derived,
218
-     * indirectly, from the data migration's classname, which should always be like EE_DMS_%s_%d_%d_%d.dms.php (eg
219
-     * EE_DMS_Core_4_1_0.dms.php)
220
-     *
221
-     * @param string $option_name (see EE_Data_Migration_Manage::_save_migrations_ran() where the option name is set)
222
-     * @return array where the first item is the plugin slug (eg 'Core','Calendar',etc) and the 2nd is the version of
223
-     *               that plugin (eg '4.1.0')
224
-     */
225
-    private function _get_plugin_slug_and_version_string_from_dms_option_name($option_name)
226
-    {
227
-        $plugin_slug_and_version_string = str_replace(
228
-            EE_Data_Migration_Manager::data_migration_script_option_prefix,
229
-            "",
230
-            $option_name
231
-        );
232
-        // check if $plugin_slug_and_version_string is like '4.1.0' (4.1-style) or 'Core.4.1.0' (4.2-style)
233
-        $parts = explode(".", $plugin_slug_and_version_string);
234
-
235
-        if (count($parts) == 4) {
236
-            // it's 4.2-style.eg Core.4.1.0
237
-            $plugin_slug = $parts[0];// eg Core
238
-            $version_string = $parts[1] . "." . $parts[2] . "." . $parts[3]; // eg 4.1.0
239
-        } else {
240
-            // it's 4.1-style: eg 4.1.0
241
-            $plugin_slug = 'Core';
242
-            $version_string = $plugin_slug_and_version_string;// eg 4.1.0
243
-        }
244
-        return array($plugin_slug, $version_string);
245
-    }
246
-
247
-    /**
248
-     * Gets the DMS class from the wordpress option, otherwise throws an EE_Error if it's not
249
-     * for a known DMS class.
250
-     *
251
-     * @param string $dms_option_name
252
-     * @param string $dms_option_value (serialized)
253
-     * @return EE_Data_Migration_Script_Base
254
-     * @throws EE_Error
255
-     */
256
-    private function _get_dms_class_from_wp_option($dms_option_name, $dms_option_value)
257
-    {
258
-        $data_migration_data = maybe_unserialize($dms_option_value);
259
-        if (isset($data_migration_data['class']) && class_exists($data_migration_data['class'])) {
260
-            $class = LoaderFactory::getLoader()->getShared($data_migration_data['class']);
261
-            if ($class instanceof EE_Data_Migration_Script_Base) {
262
-                $class->instantiate_from_array_of_properties($data_migration_data);
263
-                return $class;
264
-            } else {
265
-                // huh, so its an object but not a data migration script?? that shouldn't happen
266
-                // just leave it as an array (which will probably just get ignored)
267
-                throw new EE_Error(
268
-                    sprintf(
269
-                        __(
270
-                            "Trying to retrieve DMS class from wp option. No DMS by the name '%s' exists",
271
-                            'event_espresso'
272
-                        ),
273
-                        $data_migration_data['class']
274
-                    )
275
-                );
276
-            }
277
-        } else {
278
-            // so the data doesn't specify a class. So it must either be a legacy array of info or some array (which we'll probably just ignore), or a class that no longer exists
279
-            throw new EE_Error(
280
-                sprintf(__("The wp option  with key '%s' does not represent a DMS", 'event_espresso'), $dms_option_name)
281
-            );
282
-        }
283
-    }
284
-
285
-    /**
286
-     * Gets the array describing what data migrations have run. Also has a side-effect of recording which was the last
287
-     * ran, and which was the last ran which hasn't finished yet
288
-     *
289
-     * @return array where each element should be an array of EE_Data_Migration_Script_Base (but also has a few legacy
290
-     *               arrays in there - which should probably be ignored)
291
-     */
292
-    public function get_data_migrations_ran()
293
-    {
294
-        if (! $this->_data_migrations_ran) {
295
-            // setup autoloaders for each of the scripts in there
296
-            $this->get_all_data_migration_scripts_available();
297
-            $data_migrations_options = $this->get_all_migration_script_options(
298
-            );// get_option(EE_Data_Migration_Manager::data_migrations_option_name,get_option('espresso_data_migrations',array()));
299
-
300
-            $data_migrations_ran = array();
301
-            // convert into data migration script classes where possible
302
-            foreach ($data_migrations_options as $data_migration_option) {
303
-                list($plugin_slug, $version_string) = $this->_get_plugin_slug_and_version_string_from_dms_option_name(
304
-                    $data_migration_option['option_name']
305
-                );
306
-
307
-                try {
308
-                    $class = $this->_get_dms_class_from_wp_option(
309
-                        $data_migration_option['option_name'],
310
-                        $data_migration_option['option_value']
311
-                    );
312
-                    $data_migrations_ran[ $plugin_slug ][ $version_string ] = $class;
313
-                    // ok so far THIS is the 'last-ran-script'... unless we find another on next iteration
314
-                    $this->_last_ran_script = $class;
315
-                    if (! $class->is_completed()) {
316
-                        // sometimes we also like to know which was the last incomplete script (or if there are any at all)
317
-                        $this->_last_ran_incomplete_script = $class;
318
-                    }
319
-                } catch (EE_Error $e) {
320
-                    // ok so its not a DMS. We'll just keep it, although other code will need to expect non-DMSs
321
-                    $data_migrations_ran[ $plugin_slug ][ $version_string ] = maybe_unserialize(
322
-                        $data_migration_option['option_value']
323
-                    );
324
-                }
325
-            }
326
-            // so here the array of $data_migrations_ran is actually a mix of classes and a few legacy arrays
327
-            $this->_data_migrations_ran = $data_migrations_ran;
328
-            if (! $this->_data_migrations_ran || ! is_array($this->_data_migrations_ran)) {
329
-                $this->_data_migrations_ran = array();
330
-            }
331
-        }
332
-        return $this->_data_migrations_ran;
333
-    }
334
-
335
-
336
-    /**
337
-     *
338
-     * @param string $script_name eg 'DMS_Core_4_1_0'
339
-     * @param string $old_table   eg 'wp_events_detail'
340
-     * @param string $old_pk      eg 'wp_esp_posts'
341
-     * @param        $new_table
342
-     * @return mixed string or int
343
-     */
344
-    public function get_mapping_new_pk($script_name, $old_table, $old_pk, $new_table)
345
-    {
346
-        $script = EE_Registry::instance()->load_dms($script_name);
347
-        $mapping = $script->get_mapping_new_pk($old_table, $old_pk, $new_table);
348
-        return $mapping;
349
-    }
350
-
351
-    /**
352
-     * Gets all the options containing migration scripts that have been run. Ordering is important: it's assumed that
353
-     * the last option returned in this array is the most-recently ran DMS option
354
-     *
355
-     * @return array
356
-     */
357
-    public function get_all_migration_script_options()
358
-    {
359
-        global $wpdb;
360
-        return $wpdb->get_results(
361
-            "SELECT * FROM {$wpdb->options} WHERE option_name like '" . EE_Data_Migration_Manager::data_migration_script_option_prefix . "%' ORDER BY option_id ASC",
362
-            ARRAY_A
363
-        );
364
-    }
365
-
366
-    /**
367
-     * Gets the array of folders which contain data migration scripts. Also adds them to be auto-loaded
368
-     *
369
-     * @return array where each value is the full folder path of a folder containing data migration scripts, WITH
370
-     *               slashes at the end of the folder name.
371
-     */
372
-    public function get_data_migration_script_folders()
373
-    {
374
-        return apply_filters(
375
-            'FHEE__EE_Data_Migration_Manager__get_data_migration_script_folders',
376
-            array('Core' => EE_CORE . 'data_migration_scripts')
377
-        );
378
-    }
379
-
380
-    /**
381
-     * Gets the version the migration script upgrades to
382
-     *
383
-     * @param string $migration_script_name eg 'EE_DMS_Core_4_1_0'
384
-     * @return array {
385
-     * @type string  $slug                  like 'Core','Calendar',etc
386
-     * @type string  $version               like 4.3.0
387
-     *                                      }
388
-     * @throws EE_Error
389
-     */
390
-    public function script_migrates_to_version($migration_script_name, $eeAddonClass = '')
391
-    {
392
-        if (isset($this->script_migration_versions[ $migration_script_name ])) {
393
-            return $this->script_migration_versions[ $migration_script_name ];
394
-        }
395
-        $dms_info = $this->parse_dms_classname($migration_script_name);
396
-        $this->script_migration_versions[ $migration_script_name ] = array(
397
-            'slug'    => $eeAddonClass !== '' ? $eeAddonClass : $dms_info['slug'],
398
-            'version' => $dms_info['major_version'] . "." . $dms_info['minor_version'] . "." . $dms_info['micro_version'],
399
-        );
400
-        return $this->script_migration_versions[ $migration_script_name ];
401
-    }
402
-
403
-    /**
404
-     * Gets the juicy details out of a dms filename like 'EE_DMS_Core_4_1_0'
405
-     *
406
-     * @param string $classname
407
-     * @return array with keys 'slug','major_version','minor_version', and 'micro_version' (the last 3 are ints)
408
-     * @throws EE_Error
409
-     */
410
-    public function parse_dms_classname($classname)
411
-    {
412
-        $matches = array();
413
-        preg_match('~EE_DMS_(.*)_([0-9]*)_([0-9]*)_([0-9]*)~', $classname, $matches);
414
-        if (! $matches || ! (isset($matches[1]) && isset($matches[2]) && isset($matches[3]))) {
415
-            throw new EE_Error(
416
-                sprintf(
417
-                    __(
418
-                        "%s is not a valid Data Migration Script. The classname should be like EE_DMS_w_x_y_z, where w is either 'Core' or the slug of an addon and x, y and z are numbers, ",
419
-                        "event_espresso"
420
-                    ),
421
-                    $classname
422
-                )
423
-            );
424
-        }
425
-        return array(
426
-            'slug'          => $matches[1],
427
-            'major_version' => intval($matches[2]),
428
-            'minor_version' => intval($matches[3]),
429
-            'micro_version' => intval($matches[4]),
430
-        );
431
-    }
432
-
433
-    /**
434
-     * Ensures that the option indicating the current DB version is set. This should only be
435
-     * a concern when activating EE for the first time, THEORETICALLY.
436
-     * If we detect that we're activating EE4 over top of EE3.1, then we set the current db state to 3.1.x, otherwise
437
-     * to 4.1.x.
438
-     *
439
-     * @return string of current db state
440
-     */
441
-    public function ensure_current_database_state_is_set()
442
-    {
443
-        $espresso_db_core_updates = get_option('espresso_db_update', array());
444
-        $db_state = get_option(EE_Data_Migration_Manager::current_database_state);
445
-        if (! $db_state) {
446
-            // mark the DB as being in the state as the last version in there.
447
-            // this is done to trigger maintenance mode and do data migration scripts
448
-            // if the admin installed this version of EE over 3.1.x or 4.0.x
449
-            // otherwise, the normal maintenance mode code is fine
450
-            $previous_versions_installed = array_keys($espresso_db_core_updates);
451
-            $previous_version_installed = end($previous_versions_installed);
452
-            if (version_compare('4.1.0', $previous_version_installed)) {
453
-                // last installed version was less than 4.1
454
-                // so we want the data migrations to happen. SO, we're going to say the DB is at that state
455
-                $db_state = array('Core' => $previous_version_installed);
456
-            } else {
457
-                $db_state = array('Core' => EVENT_ESPRESSO_VERSION);
458
-            }
459
-            update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
460
-        }
461
-        // in 4.1, $db_state would have only been a simple string like '4.1.0',
462
-        // but in 4.2+ it should be an array with at least key 'Core' and the value of that plugin's
463
-        // db, and possibly other keys for other addons like 'Calendar','Permissions',etc
464
-        if (! is_array($db_state)) {
465
-            $db_state = array('Core' => $db_state);
466
-            update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
467
-        }
468
-        return $db_state;
469
-    }
470
-
471
-    /**
472
-     * Checks if there are any data migration scripts that ought to be run. If found,
473
-     * returns the instantiated classes. If none are found (ie, they've all already been run
474
-     * or they don't apply), returns an empty array
475
-     *
476
-     * @return EE_Data_Migration_Script_Base[]
477
-     */
478
-    public function check_for_applicable_data_migration_scripts()
479
-    {
480
-        // get the option describing what options have already run
481
-        $scripts_ran = $this->get_data_migrations_ran();
482
-        // $scripts_ran = array('4.1.0.core'=>array('monkey'=>null));
483
-        $script_class_and_filepaths_available = $this->get_all_data_migration_scripts_available();
484
-
485
-
486
-        $current_database_state = $this->ensure_current_database_state_is_set();
487
-        // determine which have already been run
488
-        $script_classes_that_should_run_per_iteration = array();
489
-        $iteration = 0;
490
-        $next_database_state_to_consider = $current_database_state;
491
-        $theoretical_database_state = null;
492
-        do {
493
-            // the next state after the currently-considered one will start off looking the same as the current, but we may make additions...
494
-            $theoretical_database_state = $next_database_state_to_consider;
495
-            // the next db state to consider is "what would the DB be like had we run all the scripts we found that applied last time?)
496
-            foreach ($script_class_and_filepaths_available as $classname => $filepath) {
497
-                $migrates_to_version = $this->script_migrates_to_version($classname);
498
-                $script_converts_plugin_slug = $migrates_to_version['slug'];
499
-                $script_converts_to_version = $migrates_to_version['version'];
500
-                // check if this version script is DONE or not; or if it's never been ran
501
-                if (! $scripts_ran ||
502
-                    ! isset($scripts_ran[ $script_converts_plugin_slug ]) ||
503
-                    ! isset($scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ])) {
504
-                    // we haven't ran this conversion script before
505
-                    // now check if it applies... note that we've added an autoloader for it on get_all_data_migration_scripts_available
506
-                    $script = LoaderFactory::getLoader()->load($classname);
507
-                    /* @var $script EE_Data_Migration_Script_Base */
508
-                    $can_migrate = $script->can_migrate_from_version($theoretical_database_state);
509
-                    if ($can_migrate) {
510
-                        $script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
511
-                        $migrates_to_version = $script->migrates_to_version();
512
-                        $next_database_state_to_consider[ $migrates_to_version['slug'] ] = $migrates_to_version['version'];
513
-                        unset($script_class_and_filepaths_available[ $classname ]);
514
-                    }
515
-                } elseif ($scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ] instanceof EE_Data_Migration_Script_Base) {
516
-                    // this script has been ran, or at least started
517
-                    $script = $scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ];
518
-                    if ($script->get_status() != self::status_completed) {
519
-                        // this script is already underway... keep going with it
520
-                        $script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
521
-                        $migrates_to_version = $script->migrates_to_version();
522
-                        $next_database_state_to_consider[ $migrates_to_version['slug'] ] = $migrates_to_version['version'];
523
-                        unset($script_class_and_filepaths_available[ $classname ]);
524
-                    } else {
525
-                        // it must have a status that indicates it has finished, so we don't want to try and run it again
526
-                    }
527
-                } else {
528
-                    // it exists but it's not  a proper data migration script
529
-                    // maybe the script got renamed? or was simply removed from EE?
530
-                    // either way, its certainly not runnable!
531
-                }
532
-            }
533
-            $iteration++;
534
-        } while ($next_database_state_to_consider != $theoretical_database_state && $iteration < 6);
535
-        // ok we have all the scripts that should run, now let's make them into flat array
536
-        $scripts_that_should_run = array();
537
-        foreach ($script_classes_that_should_run_per_iteration as $scripts_at_priority) {
538
-            ksort($scripts_at_priority);
539
-            foreach ($scripts_at_priority as $scripts) {
540
-                foreach ($scripts as $script) {
541
-                    $scripts_that_should_run[ get_class($script) ] = $script;
542
-                }
543
-            }
544
-        }
545
-
546
-        do_action(
547
-            'AHEE__EE_Data_Migration_Manager__check_for_applicable_data_migration_scripts__scripts_that_should_run',
548
-            $scripts_that_should_run
549
-        );
550
-        return $scripts_that_should_run;
551
-    }
552
-
553
-
554
-    /**
555
-     * Gets the script which is currently being ran, if there is one. If $include_completed_scripts is set to TRUE
556
-     * it will return the last ran script even if its complete.
557
-     * This means: if you want to find the currently-executing script, leave it as FALSE.
558
-     * If you really just want to find the script which ran most recently, regardless of status, leave it as TRUE.
559
-     *
560
-     * @param bool $include_completed_scripts
561
-     * @return EE_Data_Migration_Script_Base
562
-     */
563
-    public function get_last_ran_script($include_completed_scripts = false)
564
-    {
565
-        // make sure we've setup the class properties _last_ran_script and _last_ran_incomplete_script
566
-        if (! $this->_data_migrations_ran) {
567
-            $this->get_data_migrations_ran();
568
-        }
569
-        if ($include_completed_scripts) {
570
-            return $this->_last_ran_script;
571
-        } else {
572
-            return $this->_last_ran_incomplete_script;
573
-        }
574
-    }
575
-
576
-
577
-    /**
578
-     * Runs the data migration scripts (well, each request to this method calls one of the
579
-     * data migration scripts' migration_step() functions).
580
-     *
581
-     * @param int   $step_size
582
-     * @throws EE_Error
583
-     * @return array {
584
-     *                                  // where the first item is one EE_Data_Migration_Script_Base's stati,
585
-     *                                  //and the second item is a string describing what was done
586
-     * @type int    $records_to_migrate from the current migration script
587
-     * @type int    $records_migrated
588
-     * @type string $status             one of EE_Data_Migration_Manager::status_*
589
-     * @type string $script             verbose name of the current DMS
590
-     * @type string $message            string describing what was done during this step
591
-     *                                  }
592
-     */
593
-    public function migration_step($step_size = 0)
594
-    {
595
-
596
-        // bandaid fix for issue https://events.codebasehq.com/projects/event-espresso/tickets/7535
597
-        if (class_exists('EE_CPT_Strategy')) {
598
-            remove_action('pre_get_posts', array(EE_CPT_Strategy::instance(), 'pre_get_posts'), 5);
599
-        }
600
-
601
-        try {
602
-            $currently_executing_script = $this->get_last_ran_script();
603
-            if (! $currently_executing_script) {
604
-                // Find the next script that needs to execute
605
-                $scripts = $this->check_for_applicable_data_migration_scripts();
606
-                if (! $scripts) {
607
-                    // huh, no more scripts to run... apparently we're done!
608
-                    // but dont forget to make sure initial data is there
609
-                    // we should be good to allow them to exit maintenance mode now
610
-                    EE_Maintenance_Mode::instance()->set_maintenance_level(
611
-                        intval(EE_Maintenance_Mode::level_0_not_in_maintenance)
612
-                    );
613
-                    // saving migrations ran should actually be unnecessary, but leaving in place just in case
614
-                    // remember this migration was finished (even if we timeout initing db for core and plugins)
615
-                    $this->_save_migrations_ran();
616
-                    // make sure DB was updated AFTER we've recorded the migration was done
617
-                    $this->initialize_db_for_enqueued_ee_plugins();
618
-                    return array(
619
-                        'records_to_migrate' => 1,
620
-                        'records_migrated'   => 1,
621
-                        'status'             => self::status_no_more_migration_scripts,
622
-                        'script'             => __("Data Migration Completed Successfully", "event_espresso"),
623
-                        'message'            => __("All done!", "event_espresso"),
624
-                    );
625
-                }
626
-                $currently_executing_script = array_shift($scripts);
627
-                // and add to the array/wp option showing the scripts ran
628
-
629
-                $migrates_to = $this->script_migrates_to_version(get_class($currently_executing_script));
630
-                $plugin_slug = $migrates_to['slug'];
631
-                $version = $migrates_to['version'];
632
-                $this->_data_migrations_ran[ $plugin_slug ][ $version ] = $currently_executing_script;
633
-            }
634
-            $current_script_name = get_class($currently_executing_script);
635
-        } catch (Exception $e) {
636
-            // an exception occurred while trying to get migration scripts
637
-
638
-            $message = sprintf(
639
-                __("Error Message: %sStack Trace:%s", "event_espresso"),
640
-                $e->getMessage() . '<br>',
641
-                $e->getTraceAsString()
642
-            );
643
-            // record it on the array of data migration scripts ran. This will be overwritten next time we try and try to run data migrations
644
-            // but that's ok-- it's just an FYI to support that we couldn't even run any data migrations
645
-            $this->add_error_to_migrations_ran(
646
-                sprintf(__("Could not run data migrations because: %s", "event_espresso"), $message)
647
-            );
648
-            return array(
649
-                'records_to_migrate' => 1,
650
-                'records_migrated'   => 0,
651
-                'status'             => self::status_fatal_error,
652
-                'script'             => __("Error loading data migration scripts", "event_espresso"),
653
-                'message'            => $message,
654
-            );
655
-        }
656
-        // ok so we definitely have a data migration script
657
-        try {
658
-            // how big of a bite do we want to take? Allow users to easily override via their wp-config
659
-            if (absint($step_size) < 1) {
660
-                $step_size = defined('EE_MIGRATION_STEP_SIZE') && absint(EE_MIGRATION_STEP_SIZE)
661
-                    ? EE_MIGRATION_STEP_SIZE : EE_Data_Migration_Manager::step_size;
662
-            }
663
-            // do what we came to do!
664
-            $currently_executing_script->migration_step($step_size);
665
-            // can we wrap it up and verify default data?
666
-            $init_dbs = false;
667
-            switch ($currently_executing_script->get_status()) {
668
-                case EE_Data_Migration_Manager::status_continue:
669
-                    $response_array = array(
670
-                        'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
671
-                        'records_migrated'   => $currently_executing_script->count_records_migrated(),
672
-                        'status'             => EE_Data_Migration_Manager::status_continue,
673
-                        'message'            => $currently_executing_script->get_feedback_message(),
674
-                        'script'             => $currently_executing_script->pretty_name(),
675
-                    );
676
-                    break;
677
-                case EE_Data_Migration_Manager::status_completed:
678
-                    // ok so THAT script has completed
679
-                    $this->update_current_database_state_to($this->script_migrates_to_version($current_script_name));
680
-                    $response_array = array(
681
-                        'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
682
-                        'records_migrated'   => $currently_executing_script->count_records_migrated(),
683
-                        'status'             => EE_Data_Migration_Manager::status_completed,
684
-                        'message'            => $currently_executing_script->get_feedback_message(),
685
-                        'script'             => sprintf(
686
-                            __("%s Completed", 'event_espresso'),
687
-                            $currently_executing_script->pretty_name()
688
-                        ),
689
-                    );
690
-                    // check if there are any more after this one.
691
-                    $scripts_remaining = $this->check_for_applicable_data_migration_scripts();
692
-                    if (! $scripts_remaining) {
693
-                        // we should be good to allow them to exit maintenance mode now
694
-                        EE_Maintenance_Mode::instance()->set_maintenance_level(
695
-                            intval(EE_Maintenance_Mode::level_0_not_in_maintenance)
696
-                        );
697
-                        // huh, no more scripts to run... apparently we're done!
698
-                        // but dont forget to make sure initial data is there
699
-                        $init_dbs = true;
700
-                        $response_array['status'] = self::status_no_more_migration_scripts;
701
-                    }
702
-                    break;
703
-                default:
704
-                    $response_array = array(
705
-                        'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
706
-                        'records_migrated'   => $currently_executing_script->count_records_migrated(),
707
-                        'status'             => $currently_executing_script->get_status(),
708
-                        'message'            => sprintf(
709
-                            __("Minor errors occurred during %s: %s", "event_espresso"),
710
-                            $currently_executing_script->pretty_name(),
711
-                            implode(", ", $currently_executing_script->get_errors())
712
-                        ),
713
-                        'script'             => $currently_executing_script->pretty_name(),
714
-                    );
715
-                    break;
716
-            }
717
-        } catch (Exception $e) {
718
-            // ok so some exception was thrown which killed the data migration script
719
-            // double-check we have a real script
720
-            if ($currently_executing_script instanceof EE_Data_Migration_Script_Base) {
721
-                $script_name = $currently_executing_script->pretty_name();
722
-                $currently_executing_script->set_broken();
723
-                $currently_executing_script->add_error($e->getMessage());
724
-            } else {
725
-                $script_name = __("Error getting Migration Script", "event_espresso");
726
-            }
727
-            $response_array = array(
728
-                'records_to_migrate' => 1,
729
-                'records_migrated'   => 0,
730
-                'status'             => self::status_fatal_error,
731
-                'message'            => sprintf(
732
-                    __("A fatal error occurred during the migration: %s", "event_espresso"),
733
-                    $e->getMessage()
734
-                ),
735
-                'script'             => $script_name,
736
-            );
737
-        }
738
-        $successful_save = $this->_save_migrations_ran();
739
-        if ($successful_save !== true) {
740
-            // ok so the current wp option didn't save. that's tricky, because we'd like to update it
741
-            // and mark it as having a fatal error, but remember- WE CAN'T SAVE THIS WP OPTION!
742
-            // however, if we throw an exception, and return that, then the next request
743
-            // won't have as much info in it, and it may be able to save
744
-            throw new EE_Error(
745
-                sprintf(
746
-                    __(
747
-                        "The error '%s' occurred updating the status of the migration. This is a FATAL ERROR, but the error is preventing the system from remembering that. Please contact event espresso support.",
748
-                        "event_espresso"
749
-                    ),
750
-                    $successful_save
751
-                )
752
-            );
753
-        }
754
-        // if we're all done, initialize EE plugins' default data etc.
755
-        if ($init_dbs) {
756
-            $this->initialize_db_for_enqueued_ee_plugins();
757
-        }
758
-        return $response_array;
759
-    }
760
-
761
-
762
-    /**
763
-     * Echo out JSON response to migration script AJAX requests. Takes precautions
764
-     * to buffer output so that we don't throw junk into our json.
765
-     *
766
-     * @return array with keys:
767
-     * 'records_to_migrate' which counts ALL the records for the current migration, and should remain constant. (ie,
768
-     * it's NOT the count of hwo many remain)
769
-     * 'records_migrated' which also counts ALL the records which have been migrated (ie, percent_complete =
770
-     * records_migrated/records_to_migrate)
771
-     * 'status'=>a string, one of EE_Data_migration_Manager::status_*
772
-     * 'message'=>a string, containing any message you want to show to the user. We may decide to split this up into
773
-     * errors, notifications, and successes
774
-     * 'script'=>a pretty name of the script currently running
775
-     */
776
-    public function response_to_migration_ajax_request()
777
-    {
778
-        ob_start();
779
-        try {
780
-            $response = $this->migration_step();
781
-        } catch (Exception $e) {
782
-            $response = array(
783
-                'records_to_migrate' => 0,
784
-                'records_migrated'   => 0,
785
-                'status'             => EE_Data_Migration_Manager::status_fatal_error,
786
-                'message'            => sprintf(
787
-                    __("Unknown fatal error occurred: %s", "event_espresso"),
788
-                    $e->getMessage()
789
-                ),
790
-                'script'             => 'Unknown',
791
-            );
792
-            $this->add_error_to_migrations_ran($e->getMessage() . "; Stack trace:" . $e->getTraceAsString());
793
-        }
794
-        $warnings_etc = @ob_get_contents();
795
-        ob_end_clean();
796
-        $response['message'] .= $warnings_etc;
797
-        return $response;
798
-    }
799
-
800
-    /**
801
-     * Updates the wordpress option that keeps track of which which EE version the database
802
-     * is at (ie, the code may be at 4.1.0, but the database is still at 3.1.35)
803
-     *
804
-     * @param array $slug_and_version {
805
-     * @type string $slug             like 'Core' or 'Calendar',
806
-     * @type string $version          like '4.1.0'
807
-     *                                }
808
-     * @return void
809
-     */
810
-    public function update_current_database_state_to($slug_and_version = null)
811
-    {
812
-        if (! $slug_and_version) {
813
-            // no version was provided, assume it should be at the current code version
814
-            $slug_and_version = array('slug' => 'Core', 'version' => espresso_version());
815
-        }
816
-        $current_database_state = get_option(self::current_database_state);
817
-        $current_database_state[ $slug_and_version['slug'] ] = $slug_and_version['version'];
818
-        update_option(self::current_database_state, $current_database_state);
819
-    }
820
-
821
-    /**
822
-     * Determines if the database is currently at a state matching what's indicated in $slug and $version.
823
-     *
824
-     * @param array $slug_and_version {
825
-     * @type string $slug             like 'Core' or 'Calendar',
826
-     * @type string $version          like '4.1.0'
827
-     *                                }
828
-     * @return boolean
829
-     */
830
-    public function database_needs_updating_to($slug_and_version)
831
-    {
832
-
833
-        $slug = $slug_and_version['slug'];
834
-        $version = $slug_and_version['version'];
835
-        $current_database_state = get_option(self::current_database_state);
836
-        if (! isset($current_database_state[ $slug ])) {
837
-            return true;
838
-        } else {
839
-            // just compare the first 3 parts of version string, eg "4.7.1", not "4.7.1.dev.032" because DBs shouldn't change on nano version changes
840
-            $version_parts_current_db_state = array_slice(explode('.', $current_database_state[ $slug ]), 0, 3);
841
-            $version_parts_of_provided_db_state = array_slice(explode('.', $version), 0, 3);
842
-            $needs_updating = false;
843
-            foreach ($version_parts_current_db_state as $offset => $version_part_in_current_db_state) {
844
-                if ($version_part_in_current_db_state < $version_parts_of_provided_db_state[ $offset ]) {
845
-                    $needs_updating = true;
846
-                    break;
847
-                }
848
-            }
849
-            return $needs_updating;
850
-        }
851
-    }
852
-
853
-
854
-    /**
855
-     * Gets all the data migration scripts available in the core folder and folders
856
-     * in addons. Has the side effect of adding them for autoloading
857
-     *
858
-     * @return array keys are expected classnames, values are their filepaths
859
-     * @throws InvalidInterfaceException
860
-     * @throws InvalidDataTypeException
861
-     * @throws EE_Error
862
-     * @throws InvalidArgumentException
863
-     */
864
-    public function get_all_data_migration_scripts_available()
865
-    {
866
-        if (! $this->_data_migration_class_to_filepath_map) {
867
-            $this->_data_migration_class_to_filepath_map = array();
868
-            foreach ($this->get_data_migration_script_folders() as $eeAddonClass => $folder_path) {
869
-                // strip any placeholders added to classname to make it a unique array key
870
-                $eeAddonClass = trim($eeAddonClass, '*');
871
-                $eeAddonClass = $eeAddonClass === 'Core' || class_exists($eeAddonClass)
872
-                    ? $eeAddonClass
873
-                    : '';
874
-                $folder_path = EEH_File::end_with_directory_separator($folder_path);
875
-                $files = glob($folder_path . '*.dms.php');
876
-                if (empty($files)) {
877
-                    continue;
878
-                }
879
-                foreach ($files as $file) {
880
-                    $pos_of_last_slash = strrpos($file, '/');
881
-                    $classname = str_replace('.dms.php', '', substr($file, $pos_of_last_slash + 1));
882
-                    $migrates_to = $this->script_migrates_to_version($classname, $eeAddonClass);
883
-                    $slug = $migrates_to['slug'];
884
-                    // check that the slug as contained in the DMS is associated with
885
-                    // the slug of an addon or core
886
-                    if ($slug !== 'Core' && EE_Registry::instance()->get_addon_by_name($slug) === null) {
887
-                        EE_Error::doing_it_wrong(
888
-                            __FUNCTION__,
889
-                            sprintf(
890
-                                esc_html__(
891
-                                    'The data migration script "%s" migrates the "%s" data, but there is no EE addon with that name. There is only: %s. ',
892
-                                    'event_espresso'
893
-                                ),
894
-                                $classname,
895
-                                $slug,
896
-                                implode(', ', array_keys(EE_Registry::instance()->get_addons_by_name()))
897
-                            ),
898
-                            '4.3.0.alpha.019'
899
-                        );
900
-                    }
901
-                    $this->_data_migration_class_to_filepath_map[ $classname ] = $file;
902
-                }
903
-            }
904
-            EEH_Autoloader::register_autoloader($this->_data_migration_class_to_filepath_map);
905
-        }
906
-        return $this->_data_migration_class_to_filepath_map;
907
-    }
908
-
909
-
910
-    /**
911
-     * Once we have an addon that works with EE4.1, we will actually want to fetch the PUE slugs
912
-     * from each addon, and check if they need updating,
913
-     *
914
-     * @return boolean
915
-     */
916
-    public function addons_need_updating()
917
-    {
918
-        return false;
919
-    }
920
-
921
-    /**
922
-     * Adds this error string to the data_migrations_ran array, but we dont necessarily know
923
-     * where to put it, so we just throw it in there... better than nothing...
924
-     *
925
-     * @param string $error_message
926
-     * @throws EE_Error
927
-     */
928
-    public function add_error_to_migrations_ran($error_message)
929
-    {
930
-        // get last-ran migration script
931
-        global $wpdb;
932
-        $last_migration_script_option = $wpdb->get_row(
933
-            "SELECT * FROM $wpdb->options WHERE option_name like '" . EE_Data_Migration_Manager::data_migration_script_option_prefix . "%' ORDER BY option_id DESC LIMIT 1",
934
-            ARRAY_A
935
-        );
936
-
937
-        $last_ran_migration_script_properties = isset($last_migration_script_option['option_value'])
938
-            ? maybe_unserialize($last_migration_script_option['option_value']) : null;
939
-        // now, tread lightly because we're here because a FATAL non-catchable error
940
-        // was thrown last time when we were trying to run a data migration script
941
-        // so the fatal error could have happened while getting the migration script
942
-        // or doing running it...
943
-        $versions_migrated_to = isset($last_migration_script_option['option_name']) ? str_replace(
944
-            EE_Data_Migration_Manager::data_migration_script_option_prefix,
945
-            "",
946
-            $last_migration_script_option['option_name']
947
-        ) : null;
948
-
949
-        // check if it THINKS its a data migration script and especially if it's one that HASN'T finished yet
950
-        // because if it has finished, then it obviously couldn't be the cause of this error, right? (because its all done)
951
-        if (isset($last_ran_migration_script_properties['class']) && isset($last_ran_migration_script_properties['_status']) && $last_ran_migration_script_properties['_status'] != self::status_completed) {
952
-            // ok then just add this error to its list of errors
953
-            $last_ran_migration_script_properties['_errors'][] = $error_message;
954
-            $last_ran_migration_script_properties['_status'] = self::status_fatal_error;
955
-        } else {
956
-            // so we don't even know which script was last running
957
-            // use the data migration error stub, which is designed specifically for this type of thing
958
-            $general_migration_error = new EE_DMS_Unknown_1_0_0();
959
-            $general_migration_error->add_error($error_message);
960
-            $general_migration_error->set_broken();
961
-            $last_ran_migration_script_properties = $general_migration_error->properties_as_array();
962
-            $versions_migrated_to = 'Unknown.1.0.0';
963
-            // now just to make sure appears as last (in case the were previously a fatal error like this)
964
-            // delete the old one
965
-            delete_option(self::data_migration_script_option_prefix . $versions_migrated_to);
966
-        }
967
-        update_option(
968
-            self::data_migration_script_option_prefix . $versions_migrated_to,
969
-            $last_ran_migration_script_properties
970
-        );
971
-    }
972
-
973
-    /**
974
-     * saves what data migrations have ran to the database
975
-     *
976
-     * @return mixed TRUE if successfully saved migrations ran, string if an error occurred
977
-     */
978
-    protected function _save_migrations_ran()
979
-    {
980
-        if ($this->_data_migrations_ran == null) {
981
-            $this->get_data_migrations_ran();
982
-        }
983
-        // now, we don't want to save actual classes to the DB because that's messy
984
-        $successful_updates = true;
985
-        foreach ($this->_data_migrations_ran as $plugin_slug => $migrations_ran_for_plugin) {
986
-            foreach ($migrations_ran_for_plugin as $version_string => $array_or_migration_obj) {
987
-                $plugin_slug_for_use_in_option_name = $plugin_slug . ".";
988
-                $option_name = self::data_migration_script_option_prefix . $plugin_slug_for_use_in_option_name . $version_string;
989
-                $old_option_value = get_option($option_name);
990
-                if ($array_or_migration_obj instanceof EE_Data_Migration_Script_Base) {
991
-                    $script_array_for_saving = $array_or_migration_obj->properties_as_array();
992
-                    if ($old_option_value != $script_array_for_saving) {
993
-                        $successful_updates = update_option($option_name, $script_array_for_saving);
994
-                    }
995
-                } else {// we don't know what this array-thing is. So just save it as-is
996
-                    if ($old_option_value != $array_or_migration_obj) {
997
-                        $successful_updates = update_option($option_name, $array_or_migration_obj);
998
-                    }
999
-                }
1000
-                if (! $successful_updates) {
1001
-                    global $wpdb;
1002
-                    return $wpdb->last_error;
1003
-                }
1004
-            }
1005
-        }
1006
-        return true;
1007
-        // $updated = update_option(self::data_migrations_option_name, $array_of_migrations);
1008
-        // if ($updated !== true) {
1009
-        //     global $wpdb;
1010
-        //     return $wpdb->last_error;
1011
-        // } else {
1012
-        //     return true;
1013
-        // }
1014
-        // wp_mail(
1015
-        //     "[email protected]",
1016
-        //     time() . " price debug info",
1017
-        //     "updated: $updated, last error: $last_error, byte length of option: " . strlen(
1018
-        //         serialize($array_of_migrations)
1019
-        //     )
1020
-        // );
1021
-    }
1022
-
1023
-    /**
1024
-     * Takes an array of data migration script properties and re-creates the class from
1025
-     * them. The argument $properties_array is assumed to have been made by
1026
-     * EE_Data_Migration_Script_Base::properties_as_array()
1027
-     *
1028
-     * @param array $properties_array
1029
-     * @return EE_Data_Migration_Script_Base
1030
-     * @throws EE_Error
1031
-     */
1032
-    public function _instantiate_script_from_properties_array($properties_array)
1033
-    {
1034
-        if (! isset($properties_array['class'])) {
1035
-            throw new EE_Error(
1036
-                sprintf(
1037
-                    __("Properties array  has no 'class' properties. Here's what it has: %s", "event_espresso"),
1038
-                    implode(",", $properties_array)
1039
-                )
1040
-            );
1041
-        }
1042
-        $class_name = $properties_array['class'];
1043
-        if (! class_exists($class_name)) {
1044
-            throw new EE_Error(sprintf(__("There is no migration script named %s", "event_espresso"), $class_name));
1045
-        }
1046
-        $class = new $class_name;
1047
-        if (! $class instanceof EE_Data_Migration_Script_Base) {
1048
-            throw new EE_Error(
1049
-                sprintf(
1050
-                    __("Class '%s' is supposed to be a migration script. Its not, its a '%s'", "event_espresso"),
1051
-                    $class_name,
1052
-                    get_class($class)
1053
-                )
1054
-            );
1055
-        }
1056
-        $class->instantiate_from_array_of_properties($properties_array);
1057
-        return $class;
1058
-    }
1059
-
1060
-    /**
1061
-     * Gets the classname for the most up-to-date DMS (ie, the one that will finally
1062
-     * leave the DB in a state usable by the current plugin code).
1063
-     *
1064
-     * @param string $plugin_slug the slug for the ee plugin we are searching for. Default is 'Core'
1065
-     * @return string
1066
-     */
1067
-    public function get_most_up_to_date_dms($plugin_slug = 'Core')
1068
-    {
1069
-        $class_to_filepath_map = $this->get_all_data_migration_scripts_available();
1070
-        $most_up_to_date_dms_classname = null;
1071
-        foreach ($class_to_filepath_map as $classname => $filepath) {
1072
-            if ($most_up_to_date_dms_classname === null) {
1073
-                $migrates_to = $this->script_migrates_to_version($classname);
1074
-                $this_plugin_slug = $migrates_to['slug'];
1075
-                if ($this_plugin_slug == $plugin_slug) {
1076
-                    // if it's for core, it wins
1077
-                    $most_up_to_date_dms_classname = $classname;
1078
-                }
1079
-                // if it wasn't for core, we must keep searching for one that is!
1080
-                continue;
1081
-            } else {
1082
-                $champion_migrates_to = $this->script_migrates_to_version($most_up_to_date_dms_classname);
1083
-                $contender_migrates_to = $this->script_migrates_to_version($classname);
1084
-                if ($contender_migrates_to['slug'] == $plugin_slug
1085
-                    && version_compare(
1086
-                        $champion_migrates_to['version'],
1087
-                        $contender_migrates_to['version'],
1088
-                        '<'
1089
-                    )) {
1090
-                    // so the contenders version is higher and its for Core
1091
-                    $most_up_to_date_dms_classname = $classname;
1092
-                }
1093
-            }
1094
-        }
1095
-        return $most_up_to_date_dms_classname;
1096
-    }
1097
-
1098
-    /**
1099
-     * Gets the migration script specified but ONLY if it has already ran.
1100
-     *
1101
-     * Eg, if you wanted to see if 'EE_DMS_Core_4_1_0' has ran, you would run the following code:
1102
-     * <code> $core_4_1_0_dms_ran = EE_Data_Migration_Manager::instance()->get_migration_ran( '4.1.0', 'Core' ) !==
1103
-     * NULL;</code> This is especially useful in addons' data migration scripts, this way they can tell if a core (or
1104
-     * other addon) DMS has ran, in case the current DMS depends on it.
1105
-     *
1106
-     * @param string $version     the version the DMS searched for migrates to. Usually just the content before the 3rd
1107
-     *                            period. Eg '4.1.0'
1108
-     * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
1109
-     * @return EE_Data_Migration_Script_Base
1110
-     */
1111
-    public function get_migration_ran($version, $plugin_slug = 'Core')
1112
-    {
1113
-        $migrations_ran = $this->get_data_migrations_ran();
1114
-        if (isset($migrations_ran[ $plugin_slug ]) && isset($migrations_ran[ $plugin_slug ][ $version ])) {
1115
-            return $migrations_ran[ $plugin_slug ][ $version ];
1116
-        } else {
1117
-            return null;
1118
-        }
1119
-    }
1120
-
1121
-    /**
1122
-     * Resets the borked data migration scripts so they're no longer borked
1123
-     * so we can again attempt to migrate
1124
-     *
1125
-     * @return bool
1126
-     * @throws EE_Error
1127
-     */
1128
-    public function reattempt()
1129
-    {
1130
-        // find if the last-ran script was borked
1131
-        // set it as being non-borked (we shouldn't ever get DMSs that we don't recognize)
1132
-        // add an 'error' saying that we attempted to reset
1133
-        // does it have a stage that was borked too? if so make it no longer borked
1134
-        // add an 'error' saying we attempted to reset
1135
-        $last_ran_script = $this->get_last_ran_script();
1136
-        if ($last_ran_script instanceof EE_DMS_Unknown_1_0_0) {
1137
-            // if it was an error DMS, just mark it as complete (if another error occurs it will overwrite it)
1138
-            $last_ran_script->set_completed();
1139
-        } elseif ($last_ran_script instanceof EE_Data_Migration_Script_Base) {
1140
-            $last_ran_script->reattempt();
1141
-        } else {
1142
-            throw new EE_Error(
1143
-                sprintf(
1144
-                    __(
1145
-                        'Unable to reattempt the last ran migration script because it was not a valid migration script. || It was %s',
1146
-                        'event_espresso'
1147
-                    ),
1148
-                    print_r($last_ran_script, true)
1149
-                )
1150
-            );
1151
-        }
1152
-        return $this->_save_migrations_ran();
1153
-    }
1154
-
1155
-    /**
1156
-     * Gets whether or not this particular migration has run or not
1157
-     *
1158
-     * @param string $version     the version the DMS searched for migrates to. Usually just the content before the 3rd
1159
-     *                            period. Eg '4.1.0'
1160
-     * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
1161
-     * @return boolean
1162
-     */
1163
-    public function migration_has_ran($version, $plugin_slug = 'Core')
1164
-    {
1165
-        return $this->get_migration_ran($version, $plugin_slug) !== null;
1166
-    }
1167
-
1168
-    /**
1169
-     * Enqueues this ee plugin to have its data initialized
1170
-     *
1171
-     * @param string $plugin_slug either 'Core' or EE_Addon::name()'s return value
1172
-     */
1173
-    public function enqueue_db_initialization_for($plugin_slug)
1174
-    {
1175
-        $queue = $this->get_db_initialization_queue();
1176
-        if (! in_array($plugin_slug, $queue)) {
1177
-            $queue[] = $plugin_slug;
1178
-        }
1179
-        update_option(self::db_init_queue_option_name, $queue);
1180
-    }
1181
-
1182
-    /**
1183
-     * Calls EE_Addon::initialize_db_if_no_migrations_required() on each addon
1184
-     * specified in EE_Data_Migration_Manager::get_db_init_queue(), and if 'Core' is
1185
-     * in the queue, calls EE_System::initialize_db_if_no_migrations_required().
1186
-     */
1187
-    public function initialize_db_for_enqueued_ee_plugins()
1188
-    {
1189
-        $queue = $this->get_db_initialization_queue();
1190
-        foreach ($queue as $plugin_slug) {
1191
-            $most_up_to_date_dms = $this->get_most_up_to_date_dms($plugin_slug);
1192
-            if (! $most_up_to_date_dms) {
1193
-                // if there is NO DMS for this plugin, obviously there's no schema to verify anyways
1194
-                $verify_db = false;
1195
-            } else {
1196
-                $most_up_to_date_dms_migrates_to = $this->script_migrates_to_version($most_up_to_date_dms);
1197
-                $verify_db = $this->database_needs_updating_to($most_up_to_date_dms_migrates_to);
1198
-            }
1199
-            if ($plugin_slug == 'Core') {
1200
-                EE_System::instance()->initialize_db_if_no_migrations_required(
1201
-                    false,
1202
-                    $verify_db
1203
-                );
1204
-            } else {
1205
-                // just loop through the addons to make sure their database is setup
1206
-                foreach (EE_Registry::instance()->addons as $addon) {
1207
-                    if ($addon->name() == $plugin_slug) {
1208
-                        $addon->initialize_db_if_no_migrations_required($verify_db);
1209
-                        break;
1210
-                    }
1211
-                }
1212
-            }
1213
-        }
1214
-        // because we just initialized the DBs for the enqueued ee plugins
1215
-        // we don't need to keep remembering which ones needed to be initialized
1216
-        delete_option(self::db_init_queue_option_name);
1217
-    }
1218
-
1219
-    /**
1220
-     * Gets a numerically-indexed array of plugin slugs that need to have their databases
1221
-     * (re-)initialized after migrations are complete. ie, each element should be either
1222
-     * 'Core', or the return value of EE_Addon::name() for an addon
1223
-     *
1224
-     * @return array
1225
-     */
1226
-    public function get_db_initialization_queue()
1227
-    {
1228
-        return get_option(self::db_init_queue_option_name, array());
1229
-    }
1230
-
1231
-    /**
1232
-     * Gets the injected table analyzer, or throws an exception
1233
-     *
1234
-     * @return TableAnalysis
1235
-     * @throws EE_Error
1236
-     */
1237
-    protected function _get_table_analysis()
1238
-    {
1239
-        if ($this->_table_analysis instanceof TableAnalysis) {
1240
-            return $this->_table_analysis;
1241
-        } else {
1242
-            throw new EE_Error(
1243
-                sprintf(
1244
-                    __('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
1245
-                    get_class($this)
1246
-                )
1247
-            );
1248
-        }
1249
-    }
1250
-
1251
-    /**
1252
-     * Gets the injected table manager, or throws an exception
1253
-     *
1254
-     * @return TableManager
1255
-     * @throws EE_Error
1256
-     */
1257
-    protected function _get_table_manager()
1258
-    {
1259
-        if ($this->_table_manager instanceof TableManager) {
1260
-            return $this->_table_manager;
1261
-        } else {
1262
-            throw new EE_Error(
1263
-                sprintf(
1264
-                    __('Table manager class on class %1$s is not set properly.', 'event_espresso'),
1265
-                    get_class($this)
1266
-                )
1267
-            );
1268
-        }
1269
-    }
36
+	/**
37
+	 *
38
+	 * @var EE_Registry
39
+	 */
40
+	// protected $EE;
41
+	/**
42
+	 * name of the wordpress option which stores an array of data about
43
+	 */
44
+	const data_migrations_option_name = 'ee_data_migration';
45
+
46
+
47
+	const data_migration_script_option_prefix = 'ee_data_migration_script_';
48
+
49
+	const data_migration_script_mapping_option_prefix = 'ee_dms_map_';
50
+
51
+	/**
52
+	 * name of the wordpress option which stores the database' current version. IE, the code may be at version 4.2.0,
53
+	 * but as migrations are performed the database will progress from 3.1.35 to 4.1.0 etc.
54
+	 */
55
+	const current_database_state = 'ee_data_migration_current_db_state';
56
+
57
+	/**
58
+	 * Special status string returned when we're positive there are no more data migration
59
+	 * scripts that can be run.
60
+	 */
61
+	const status_no_more_migration_scripts = 'no_more_migration_scripts';
62
+	/**
63
+	 * string indicating the migration should continue
64
+	 */
65
+	const status_continue = 'status_continue';
66
+	/**
67
+	 * string indicating the migration has completed and should be ended
68
+	 */
69
+	const status_completed = 'status_completed';
70
+	/**
71
+	 * string indicating a fatal error occurred and the data migration should be completely aborted
72
+	 */
73
+	const status_fatal_error = 'status_fatal_error';
74
+
75
+	/**
76
+	 * the number of 'items' (usually DB rows) to migrate on each 'step' (ajax request sent
77
+	 * during migration)
78
+	 */
79
+	const step_size = 50;
80
+
81
+	/**
82
+	 * option name that stores the queue of ee plugins needing to have
83
+	 * their data initialized (or re-initialized) once we are done migrations
84
+	 */
85
+	const db_init_queue_option_name = 'ee_db_init_queue';
86
+	/**
87
+	 * Array of information concerning data migrations that have ran in the history
88
+	 * of this EE installation. Keys should be the name of the version the script upgraded to
89
+	 *
90
+	 * @var EE_Data_Migration_Script_Base[]
91
+	 */
92
+	private $_data_migrations_ran = null;
93
+	/**
94
+	 * The last ran script. It's nice to store this somewhere accessible, as its easiest
95
+	 * to know which was the last run by which is the newest wp option; but in most of the code
96
+	 * we just use the local $_data_migration_ran array, which organized the scripts differently
97
+	 *
98
+	 * @var EE_Data_Migration_Script_Base
99
+	 */
100
+	private $_last_ran_script = null;
101
+
102
+	/**
103
+	 * Similarly to _last_ran_script, but this is the last INCOMPLETE migration script.
104
+	 *
105
+	 * @var EE_Data_Migration_Script_Base
106
+	 */
107
+	private $_last_ran_incomplete_script = null;
108
+	/**
109
+	 * array where keys are classnames, and values are filepaths of all the known migration scripts
110
+	 *
111
+	 * @var array
112
+	 */
113
+	private $_data_migration_class_to_filepath_map;
114
+
115
+	/**
116
+	 * the following 4 properties are fully set on construction.
117
+	 * Note: the first two apply to whether to continue running ALL migration scripts (ie, even though we're finished
118
+	 * one, we may want to start the next one); whereas the last two indicate whether to continue running a single
119
+	 * data migration script
120
+	 *
121
+	 * @var array
122
+	 */
123
+	public $stati_that_indicate_to_continue_migrations = array();
124
+
125
+	public $stati_that_indicate_to_stop_migrations = array();
126
+
127
+	public $stati_that_indicate_to_continue_single_migration_script = array();
128
+
129
+	public $stati_that_indicate_to_stop_single_migration_script = array();
130
+
131
+	/**
132
+	 * @var \EventEspresso\core\services\database\TableManager $table_manager
133
+	 */
134
+	protected $_table_manager;
135
+
136
+	/**
137
+	 * @var \EventEspresso\core\services\database\TableAnalysis $table_analysis
138
+	 */
139
+	protected $_table_analysis;
140
+
141
+	/**
142
+	 * @var array $script_migration_versions
143
+	 */
144
+	protected $script_migration_versions;
145
+
146
+	/**
147
+	 * @var EE_Data_Migration_Manager $_instance
148
+	 * @access    private
149
+	 */
150
+	private static $_instance = null;
151
+
152
+
153
+	/**
154
+	 * @singleton method used to instantiate class object
155
+	 * @access    public
156
+	 * @return EE_Data_Migration_Manager instance
157
+	 */
158
+	public static function instance()
159
+	{
160
+		// check if class object is instantiated
161
+		if (! self::$_instance instanceof EE_Data_Migration_Manager) {
162
+			self::$_instance = new self();
163
+		}
164
+		return self::$_instance;
165
+	}
166
+
167
+	/**
168
+	 * resets the singleton to its brand-new state (but does NOT delete old references to the old singleton. Meaning,
169
+	 * all new usages of the singleton should be made with Classname::instance()) and returns it
170
+	 *
171
+	 * @return EE_Data_Migration_Manager
172
+	 */
173
+	public static function reset()
174
+	{
175
+		self::$_instance = null;
176
+		return self::instance();
177
+	}
178
+
179
+
180
+	/**
181
+	 * constructor
182
+	 */
183
+	private function __construct()
184
+	{
185
+		$this->stati_that_indicate_to_continue_migrations = array(
186
+			self::status_continue,
187
+			self::status_completed,
188
+		);
189
+		$this->stati_that_indicate_to_stop_migrations = array(
190
+			self::status_fatal_error,
191
+			self::status_no_more_migration_scripts,
192
+		);
193
+		$this->stati_that_indicate_to_continue_single_migration_script = array(
194
+			self::status_continue,
195
+		);
196
+		$this->stati_that_indicate_to_stop_single_migration_script = array(
197
+			self::status_completed,
198
+			self::status_fatal_error
199
+			// note: status_no_more_migration_scripts doesn't apply
200
+		);
201
+		// make sure we've included the base migration script, because we may need the EE_DMS_Unknown_1_0_0 class
202
+		// to be defined, because right now it doesn't get autoloaded on its own
203
+		EE_Registry::instance()->load_core('Data_Migration_Class_Base', array(), true);
204
+		EE_Registry::instance()->load_core('Data_Migration_Script_Base', array(), true);
205
+		EE_Registry::instance()->load_core('DMS_Unknown_1_0_0', array(), true);
206
+		EE_Registry::instance()->load_core('Data_Migration_Script_Stage', array(), true);
207
+		EE_Registry::instance()->load_core('Data_Migration_Script_Stage_Table', array(), true);
208
+		$this->_table_manager = EE_Registry::instance()->create('TableManager', array(), true);
209
+		$this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
210
+	}
211
+
212
+
213
+	/**
214
+	 * Deciphers, from an option's name, what plugin and version it relates to (see _save_migrations_ran to see what
215
+	 * the option names are like, but generally they're like
216
+	 * 'ee_data_migration_script_Core.4.1.0' in 4.2 or 'ee_data_migration_script_4.1.0' before that).
217
+	 * The option name shouldn't ever be like 'ee_data_migration_script_Core.4.1.0.reg' because it's derived,
218
+	 * indirectly, from the data migration's classname, which should always be like EE_DMS_%s_%d_%d_%d.dms.php (eg
219
+	 * EE_DMS_Core_4_1_0.dms.php)
220
+	 *
221
+	 * @param string $option_name (see EE_Data_Migration_Manage::_save_migrations_ran() where the option name is set)
222
+	 * @return array where the first item is the plugin slug (eg 'Core','Calendar',etc) and the 2nd is the version of
223
+	 *               that plugin (eg '4.1.0')
224
+	 */
225
+	private function _get_plugin_slug_and_version_string_from_dms_option_name($option_name)
226
+	{
227
+		$plugin_slug_and_version_string = str_replace(
228
+			EE_Data_Migration_Manager::data_migration_script_option_prefix,
229
+			"",
230
+			$option_name
231
+		);
232
+		// check if $plugin_slug_and_version_string is like '4.1.0' (4.1-style) or 'Core.4.1.0' (4.2-style)
233
+		$parts = explode(".", $plugin_slug_and_version_string);
234
+
235
+		if (count($parts) == 4) {
236
+			// it's 4.2-style.eg Core.4.1.0
237
+			$plugin_slug = $parts[0];// eg Core
238
+			$version_string = $parts[1] . "." . $parts[2] . "." . $parts[3]; // eg 4.1.0
239
+		} else {
240
+			// it's 4.1-style: eg 4.1.0
241
+			$plugin_slug = 'Core';
242
+			$version_string = $plugin_slug_and_version_string;// eg 4.1.0
243
+		}
244
+		return array($plugin_slug, $version_string);
245
+	}
246
+
247
+	/**
248
+	 * Gets the DMS class from the wordpress option, otherwise throws an EE_Error if it's not
249
+	 * for a known DMS class.
250
+	 *
251
+	 * @param string $dms_option_name
252
+	 * @param string $dms_option_value (serialized)
253
+	 * @return EE_Data_Migration_Script_Base
254
+	 * @throws EE_Error
255
+	 */
256
+	private function _get_dms_class_from_wp_option($dms_option_name, $dms_option_value)
257
+	{
258
+		$data_migration_data = maybe_unserialize($dms_option_value);
259
+		if (isset($data_migration_data['class']) && class_exists($data_migration_data['class'])) {
260
+			$class = LoaderFactory::getLoader()->getShared($data_migration_data['class']);
261
+			if ($class instanceof EE_Data_Migration_Script_Base) {
262
+				$class->instantiate_from_array_of_properties($data_migration_data);
263
+				return $class;
264
+			} else {
265
+				// huh, so its an object but not a data migration script?? that shouldn't happen
266
+				// just leave it as an array (which will probably just get ignored)
267
+				throw new EE_Error(
268
+					sprintf(
269
+						__(
270
+							"Trying to retrieve DMS class from wp option. No DMS by the name '%s' exists",
271
+							'event_espresso'
272
+						),
273
+						$data_migration_data['class']
274
+					)
275
+				);
276
+			}
277
+		} else {
278
+			// so the data doesn't specify a class. So it must either be a legacy array of info or some array (which we'll probably just ignore), or a class that no longer exists
279
+			throw new EE_Error(
280
+				sprintf(__("The wp option  with key '%s' does not represent a DMS", 'event_espresso'), $dms_option_name)
281
+			);
282
+		}
283
+	}
284
+
285
+	/**
286
+	 * Gets the array describing what data migrations have run. Also has a side-effect of recording which was the last
287
+	 * ran, and which was the last ran which hasn't finished yet
288
+	 *
289
+	 * @return array where each element should be an array of EE_Data_Migration_Script_Base (but also has a few legacy
290
+	 *               arrays in there - which should probably be ignored)
291
+	 */
292
+	public function get_data_migrations_ran()
293
+	{
294
+		if (! $this->_data_migrations_ran) {
295
+			// setup autoloaders for each of the scripts in there
296
+			$this->get_all_data_migration_scripts_available();
297
+			$data_migrations_options = $this->get_all_migration_script_options(
298
+			);// get_option(EE_Data_Migration_Manager::data_migrations_option_name,get_option('espresso_data_migrations',array()));
299
+
300
+			$data_migrations_ran = array();
301
+			// convert into data migration script classes where possible
302
+			foreach ($data_migrations_options as $data_migration_option) {
303
+				list($plugin_slug, $version_string) = $this->_get_plugin_slug_and_version_string_from_dms_option_name(
304
+					$data_migration_option['option_name']
305
+				);
306
+
307
+				try {
308
+					$class = $this->_get_dms_class_from_wp_option(
309
+						$data_migration_option['option_name'],
310
+						$data_migration_option['option_value']
311
+					);
312
+					$data_migrations_ran[ $plugin_slug ][ $version_string ] = $class;
313
+					// ok so far THIS is the 'last-ran-script'... unless we find another on next iteration
314
+					$this->_last_ran_script = $class;
315
+					if (! $class->is_completed()) {
316
+						// sometimes we also like to know which was the last incomplete script (or if there are any at all)
317
+						$this->_last_ran_incomplete_script = $class;
318
+					}
319
+				} catch (EE_Error $e) {
320
+					// ok so its not a DMS. We'll just keep it, although other code will need to expect non-DMSs
321
+					$data_migrations_ran[ $plugin_slug ][ $version_string ] = maybe_unserialize(
322
+						$data_migration_option['option_value']
323
+					);
324
+				}
325
+			}
326
+			// so here the array of $data_migrations_ran is actually a mix of classes and a few legacy arrays
327
+			$this->_data_migrations_ran = $data_migrations_ran;
328
+			if (! $this->_data_migrations_ran || ! is_array($this->_data_migrations_ran)) {
329
+				$this->_data_migrations_ran = array();
330
+			}
331
+		}
332
+		return $this->_data_migrations_ran;
333
+	}
334
+
335
+
336
+	/**
337
+	 *
338
+	 * @param string $script_name eg 'DMS_Core_4_1_0'
339
+	 * @param string $old_table   eg 'wp_events_detail'
340
+	 * @param string $old_pk      eg 'wp_esp_posts'
341
+	 * @param        $new_table
342
+	 * @return mixed string or int
343
+	 */
344
+	public function get_mapping_new_pk($script_name, $old_table, $old_pk, $new_table)
345
+	{
346
+		$script = EE_Registry::instance()->load_dms($script_name);
347
+		$mapping = $script->get_mapping_new_pk($old_table, $old_pk, $new_table);
348
+		return $mapping;
349
+	}
350
+
351
+	/**
352
+	 * Gets all the options containing migration scripts that have been run. Ordering is important: it's assumed that
353
+	 * the last option returned in this array is the most-recently ran DMS option
354
+	 *
355
+	 * @return array
356
+	 */
357
+	public function get_all_migration_script_options()
358
+	{
359
+		global $wpdb;
360
+		return $wpdb->get_results(
361
+			"SELECT * FROM {$wpdb->options} WHERE option_name like '" . EE_Data_Migration_Manager::data_migration_script_option_prefix . "%' ORDER BY option_id ASC",
362
+			ARRAY_A
363
+		);
364
+	}
365
+
366
+	/**
367
+	 * Gets the array of folders which contain data migration scripts. Also adds them to be auto-loaded
368
+	 *
369
+	 * @return array where each value is the full folder path of a folder containing data migration scripts, WITH
370
+	 *               slashes at the end of the folder name.
371
+	 */
372
+	public function get_data_migration_script_folders()
373
+	{
374
+		return apply_filters(
375
+			'FHEE__EE_Data_Migration_Manager__get_data_migration_script_folders',
376
+			array('Core' => EE_CORE . 'data_migration_scripts')
377
+		);
378
+	}
379
+
380
+	/**
381
+	 * Gets the version the migration script upgrades to
382
+	 *
383
+	 * @param string $migration_script_name eg 'EE_DMS_Core_4_1_0'
384
+	 * @return array {
385
+	 * @type string  $slug                  like 'Core','Calendar',etc
386
+	 * @type string  $version               like 4.3.0
387
+	 *                                      }
388
+	 * @throws EE_Error
389
+	 */
390
+	public function script_migrates_to_version($migration_script_name, $eeAddonClass = '')
391
+	{
392
+		if (isset($this->script_migration_versions[ $migration_script_name ])) {
393
+			return $this->script_migration_versions[ $migration_script_name ];
394
+		}
395
+		$dms_info = $this->parse_dms_classname($migration_script_name);
396
+		$this->script_migration_versions[ $migration_script_name ] = array(
397
+			'slug'    => $eeAddonClass !== '' ? $eeAddonClass : $dms_info['slug'],
398
+			'version' => $dms_info['major_version'] . "." . $dms_info['minor_version'] . "." . $dms_info['micro_version'],
399
+		);
400
+		return $this->script_migration_versions[ $migration_script_name ];
401
+	}
402
+
403
+	/**
404
+	 * Gets the juicy details out of a dms filename like 'EE_DMS_Core_4_1_0'
405
+	 *
406
+	 * @param string $classname
407
+	 * @return array with keys 'slug','major_version','minor_version', and 'micro_version' (the last 3 are ints)
408
+	 * @throws EE_Error
409
+	 */
410
+	public function parse_dms_classname($classname)
411
+	{
412
+		$matches = array();
413
+		preg_match('~EE_DMS_(.*)_([0-9]*)_([0-9]*)_([0-9]*)~', $classname, $matches);
414
+		if (! $matches || ! (isset($matches[1]) && isset($matches[2]) && isset($matches[3]))) {
415
+			throw new EE_Error(
416
+				sprintf(
417
+					__(
418
+						"%s is not a valid Data Migration Script. The classname should be like EE_DMS_w_x_y_z, where w is either 'Core' or the slug of an addon and x, y and z are numbers, ",
419
+						"event_espresso"
420
+					),
421
+					$classname
422
+				)
423
+			);
424
+		}
425
+		return array(
426
+			'slug'          => $matches[1],
427
+			'major_version' => intval($matches[2]),
428
+			'minor_version' => intval($matches[3]),
429
+			'micro_version' => intval($matches[4]),
430
+		);
431
+	}
432
+
433
+	/**
434
+	 * Ensures that the option indicating the current DB version is set. This should only be
435
+	 * a concern when activating EE for the first time, THEORETICALLY.
436
+	 * If we detect that we're activating EE4 over top of EE3.1, then we set the current db state to 3.1.x, otherwise
437
+	 * to 4.1.x.
438
+	 *
439
+	 * @return string of current db state
440
+	 */
441
+	public function ensure_current_database_state_is_set()
442
+	{
443
+		$espresso_db_core_updates = get_option('espresso_db_update', array());
444
+		$db_state = get_option(EE_Data_Migration_Manager::current_database_state);
445
+		if (! $db_state) {
446
+			// mark the DB as being in the state as the last version in there.
447
+			// this is done to trigger maintenance mode and do data migration scripts
448
+			// if the admin installed this version of EE over 3.1.x or 4.0.x
449
+			// otherwise, the normal maintenance mode code is fine
450
+			$previous_versions_installed = array_keys($espresso_db_core_updates);
451
+			$previous_version_installed = end($previous_versions_installed);
452
+			if (version_compare('4.1.0', $previous_version_installed)) {
453
+				// last installed version was less than 4.1
454
+				// so we want the data migrations to happen. SO, we're going to say the DB is at that state
455
+				$db_state = array('Core' => $previous_version_installed);
456
+			} else {
457
+				$db_state = array('Core' => EVENT_ESPRESSO_VERSION);
458
+			}
459
+			update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
460
+		}
461
+		// in 4.1, $db_state would have only been a simple string like '4.1.0',
462
+		// but in 4.2+ it should be an array with at least key 'Core' and the value of that plugin's
463
+		// db, and possibly other keys for other addons like 'Calendar','Permissions',etc
464
+		if (! is_array($db_state)) {
465
+			$db_state = array('Core' => $db_state);
466
+			update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
467
+		}
468
+		return $db_state;
469
+	}
470
+
471
+	/**
472
+	 * Checks if there are any data migration scripts that ought to be run. If found,
473
+	 * returns the instantiated classes. If none are found (ie, they've all already been run
474
+	 * or they don't apply), returns an empty array
475
+	 *
476
+	 * @return EE_Data_Migration_Script_Base[]
477
+	 */
478
+	public function check_for_applicable_data_migration_scripts()
479
+	{
480
+		// get the option describing what options have already run
481
+		$scripts_ran = $this->get_data_migrations_ran();
482
+		// $scripts_ran = array('4.1.0.core'=>array('monkey'=>null));
483
+		$script_class_and_filepaths_available = $this->get_all_data_migration_scripts_available();
484
+
485
+
486
+		$current_database_state = $this->ensure_current_database_state_is_set();
487
+		// determine which have already been run
488
+		$script_classes_that_should_run_per_iteration = array();
489
+		$iteration = 0;
490
+		$next_database_state_to_consider = $current_database_state;
491
+		$theoretical_database_state = null;
492
+		do {
493
+			// the next state after the currently-considered one will start off looking the same as the current, but we may make additions...
494
+			$theoretical_database_state = $next_database_state_to_consider;
495
+			// the next db state to consider is "what would the DB be like had we run all the scripts we found that applied last time?)
496
+			foreach ($script_class_and_filepaths_available as $classname => $filepath) {
497
+				$migrates_to_version = $this->script_migrates_to_version($classname);
498
+				$script_converts_plugin_slug = $migrates_to_version['slug'];
499
+				$script_converts_to_version = $migrates_to_version['version'];
500
+				// check if this version script is DONE or not; or if it's never been ran
501
+				if (! $scripts_ran ||
502
+					! isset($scripts_ran[ $script_converts_plugin_slug ]) ||
503
+					! isset($scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ])) {
504
+					// we haven't ran this conversion script before
505
+					// now check if it applies... note that we've added an autoloader for it on get_all_data_migration_scripts_available
506
+					$script = LoaderFactory::getLoader()->load($classname);
507
+					/* @var $script EE_Data_Migration_Script_Base */
508
+					$can_migrate = $script->can_migrate_from_version($theoretical_database_state);
509
+					if ($can_migrate) {
510
+						$script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
511
+						$migrates_to_version = $script->migrates_to_version();
512
+						$next_database_state_to_consider[ $migrates_to_version['slug'] ] = $migrates_to_version['version'];
513
+						unset($script_class_and_filepaths_available[ $classname ]);
514
+					}
515
+				} elseif ($scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ] instanceof EE_Data_Migration_Script_Base) {
516
+					// this script has been ran, or at least started
517
+					$script = $scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ];
518
+					if ($script->get_status() != self::status_completed) {
519
+						// this script is already underway... keep going with it
520
+						$script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
521
+						$migrates_to_version = $script->migrates_to_version();
522
+						$next_database_state_to_consider[ $migrates_to_version['slug'] ] = $migrates_to_version['version'];
523
+						unset($script_class_and_filepaths_available[ $classname ]);
524
+					} else {
525
+						// it must have a status that indicates it has finished, so we don't want to try and run it again
526
+					}
527
+				} else {
528
+					// it exists but it's not  a proper data migration script
529
+					// maybe the script got renamed? or was simply removed from EE?
530
+					// either way, its certainly not runnable!
531
+				}
532
+			}
533
+			$iteration++;
534
+		} while ($next_database_state_to_consider != $theoretical_database_state && $iteration < 6);
535
+		// ok we have all the scripts that should run, now let's make them into flat array
536
+		$scripts_that_should_run = array();
537
+		foreach ($script_classes_that_should_run_per_iteration as $scripts_at_priority) {
538
+			ksort($scripts_at_priority);
539
+			foreach ($scripts_at_priority as $scripts) {
540
+				foreach ($scripts as $script) {
541
+					$scripts_that_should_run[ get_class($script) ] = $script;
542
+				}
543
+			}
544
+		}
545
+
546
+		do_action(
547
+			'AHEE__EE_Data_Migration_Manager__check_for_applicable_data_migration_scripts__scripts_that_should_run',
548
+			$scripts_that_should_run
549
+		);
550
+		return $scripts_that_should_run;
551
+	}
552
+
553
+
554
+	/**
555
+	 * Gets the script which is currently being ran, if there is one. If $include_completed_scripts is set to TRUE
556
+	 * it will return the last ran script even if its complete.
557
+	 * This means: if you want to find the currently-executing script, leave it as FALSE.
558
+	 * If you really just want to find the script which ran most recently, regardless of status, leave it as TRUE.
559
+	 *
560
+	 * @param bool $include_completed_scripts
561
+	 * @return EE_Data_Migration_Script_Base
562
+	 */
563
+	public function get_last_ran_script($include_completed_scripts = false)
564
+	{
565
+		// make sure we've setup the class properties _last_ran_script and _last_ran_incomplete_script
566
+		if (! $this->_data_migrations_ran) {
567
+			$this->get_data_migrations_ran();
568
+		}
569
+		if ($include_completed_scripts) {
570
+			return $this->_last_ran_script;
571
+		} else {
572
+			return $this->_last_ran_incomplete_script;
573
+		}
574
+	}
575
+
576
+
577
+	/**
578
+	 * Runs the data migration scripts (well, each request to this method calls one of the
579
+	 * data migration scripts' migration_step() functions).
580
+	 *
581
+	 * @param int   $step_size
582
+	 * @throws EE_Error
583
+	 * @return array {
584
+	 *                                  // where the first item is one EE_Data_Migration_Script_Base's stati,
585
+	 *                                  //and the second item is a string describing what was done
586
+	 * @type int    $records_to_migrate from the current migration script
587
+	 * @type int    $records_migrated
588
+	 * @type string $status             one of EE_Data_Migration_Manager::status_*
589
+	 * @type string $script             verbose name of the current DMS
590
+	 * @type string $message            string describing what was done during this step
591
+	 *                                  }
592
+	 */
593
+	public function migration_step($step_size = 0)
594
+	{
595
+
596
+		// bandaid fix for issue https://events.codebasehq.com/projects/event-espresso/tickets/7535
597
+		if (class_exists('EE_CPT_Strategy')) {
598
+			remove_action('pre_get_posts', array(EE_CPT_Strategy::instance(), 'pre_get_posts'), 5);
599
+		}
600
+
601
+		try {
602
+			$currently_executing_script = $this->get_last_ran_script();
603
+			if (! $currently_executing_script) {
604
+				// Find the next script that needs to execute
605
+				$scripts = $this->check_for_applicable_data_migration_scripts();
606
+				if (! $scripts) {
607
+					// huh, no more scripts to run... apparently we're done!
608
+					// but dont forget to make sure initial data is there
609
+					// we should be good to allow them to exit maintenance mode now
610
+					EE_Maintenance_Mode::instance()->set_maintenance_level(
611
+						intval(EE_Maintenance_Mode::level_0_not_in_maintenance)
612
+					);
613
+					// saving migrations ran should actually be unnecessary, but leaving in place just in case
614
+					// remember this migration was finished (even if we timeout initing db for core and plugins)
615
+					$this->_save_migrations_ran();
616
+					// make sure DB was updated AFTER we've recorded the migration was done
617
+					$this->initialize_db_for_enqueued_ee_plugins();
618
+					return array(
619
+						'records_to_migrate' => 1,
620
+						'records_migrated'   => 1,
621
+						'status'             => self::status_no_more_migration_scripts,
622
+						'script'             => __("Data Migration Completed Successfully", "event_espresso"),
623
+						'message'            => __("All done!", "event_espresso"),
624
+					);
625
+				}
626
+				$currently_executing_script = array_shift($scripts);
627
+				// and add to the array/wp option showing the scripts ran
628
+
629
+				$migrates_to = $this->script_migrates_to_version(get_class($currently_executing_script));
630
+				$plugin_slug = $migrates_to['slug'];
631
+				$version = $migrates_to['version'];
632
+				$this->_data_migrations_ran[ $plugin_slug ][ $version ] = $currently_executing_script;
633
+			}
634
+			$current_script_name = get_class($currently_executing_script);
635
+		} catch (Exception $e) {
636
+			// an exception occurred while trying to get migration scripts
637
+
638
+			$message = sprintf(
639
+				__("Error Message: %sStack Trace:%s", "event_espresso"),
640
+				$e->getMessage() . '<br>',
641
+				$e->getTraceAsString()
642
+			);
643
+			// record it on the array of data migration scripts ran. This will be overwritten next time we try and try to run data migrations
644
+			// but that's ok-- it's just an FYI to support that we couldn't even run any data migrations
645
+			$this->add_error_to_migrations_ran(
646
+				sprintf(__("Could not run data migrations because: %s", "event_espresso"), $message)
647
+			);
648
+			return array(
649
+				'records_to_migrate' => 1,
650
+				'records_migrated'   => 0,
651
+				'status'             => self::status_fatal_error,
652
+				'script'             => __("Error loading data migration scripts", "event_espresso"),
653
+				'message'            => $message,
654
+			);
655
+		}
656
+		// ok so we definitely have a data migration script
657
+		try {
658
+			// how big of a bite do we want to take? Allow users to easily override via their wp-config
659
+			if (absint($step_size) < 1) {
660
+				$step_size = defined('EE_MIGRATION_STEP_SIZE') && absint(EE_MIGRATION_STEP_SIZE)
661
+					? EE_MIGRATION_STEP_SIZE : EE_Data_Migration_Manager::step_size;
662
+			}
663
+			// do what we came to do!
664
+			$currently_executing_script->migration_step($step_size);
665
+			// can we wrap it up and verify default data?
666
+			$init_dbs = false;
667
+			switch ($currently_executing_script->get_status()) {
668
+				case EE_Data_Migration_Manager::status_continue:
669
+					$response_array = array(
670
+						'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
671
+						'records_migrated'   => $currently_executing_script->count_records_migrated(),
672
+						'status'             => EE_Data_Migration_Manager::status_continue,
673
+						'message'            => $currently_executing_script->get_feedback_message(),
674
+						'script'             => $currently_executing_script->pretty_name(),
675
+					);
676
+					break;
677
+				case EE_Data_Migration_Manager::status_completed:
678
+					// ok so THAT script has completed
679
+					$this->update_current_database_state_to($this->script_migrates_to_version($current_script_name));
680
+					$response_array = array(
681
+						'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
682
+						'records_migrated'   => $currently_executing_script->count_records_migrated(),
683
+						'status'             => EE_Data_Migration_Manager::status_completed,
684
+						'message'            => $currently_executing_script->get_feedback_message(),
685
+						'script'             => sprintf(
686
+							__("%s Completed", 'event_espresso'),
687
+							$currently_executing_script->pretty_name()
688
+						),
689
+					);
690
+					// check if there are any more after this one.
691
+					$scripts_remaining = $this->check_for_applicable_data_migration_scripts();
692
+					if (! $scripts_remaining) {
693
+						// we should be good to allow them to exit maintenance mode now
694
+						EE_Maintenance_Mode::instance()->set_maintenance_level(
695
+							intval(EE_Maintenance_Mode::level_0_not_in_maintenance)
696
+						);
697
+						// huh, no more scripts to run... apparently we're done!
698
+						// but dont forget to make sure initial data is there
699
+						$init_dbs = true;
700
+						$response_array['status'] = self::status_no_more_migration_scripts;
701
+					}
702
+					break;
703
+				default:
704
+					$response_array = array(
705
+						'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
706
+						'records_migrated'   => $currently_executing_script->count_records_migrated(),
707
+						'status'             => $currently_executing_script->get_status(),
708
+						'message'            => sprintf(
709
+							__("Minor errors occurred during %s: %s", "event_espresso"),
710
+							$currently_executing_script->pretty_name(),
711
+							implode(", ", $currently_executing_script->get_errors())
712
+						),
713
+						'script'             => $currently_executing_script->pretty_name(),
714
+					);
715
+					break;
716
+			}
717
+		} catch (Exception $e) {
718
+			// ok so some exception was thrown which killed the data migration script
719
+			// double-check we have a real script
720
+			if ($currently_executing_script instanceof EE_Data_Migration_Script_Base) {
721
+				$script_name = $currently_executing_script->pretty_name();
722
+				$currently_executing_script->set_broken();
723
+				$currently_executing_script->add_error($e->getMessage());
724
+			} else {
725
+				$script_name = __("Error getting Migration Script", "event_espresso");
726
+			}
727
+			$response_array = array(
728
+				'records_to_migrate' => 1,
729
+				'records_migrated'   => 0,
730
+				'status'             => self::status_fatal_error,
731
+				'message'            => sprintf(
732
+					__("A fatal error occurred during the migration: %s", "event_espresso"),
733
+					$e->getMessage()
734
+				),
735
+				'script'             => $script_name,
736
+			);
737
+		}
738
+		$successful_save = $this->_save_migrations_ran();
739
+		if ($successful_save !== true) {
740
+			// ok so the current wp option didn't save. that's tricky, because we'd like to update it
741
+			// and mark it as having a fatal error, but remember- WE CAN'T SAVE THIS WP OPTION!
742
+			// however, if we throw an exception, and return that, then the next request
743
+			// won't have as much info in it, and it may be able to save
744
+			throw new EE_Error(
745
+				sprintf(
746
+					__(
747
+						"The error '%s' occurred updating the status of the migration. This is a FATAL ERROR, but the error is preventing the system from remembering that. Please contact event espresso support.",
748
+						"event_espresso"
749
+					),
750
+					$successful_save
751
+				)
752
+			);
753
+		}
754
+		// if we're all done, initialize EE plugins' default data etc.
755
+		if ($init_dbs) {
756
+			$this->initialize_db_for_enqueued_ee_plugins();
757
+		}
758
+		return $response_array;
759
+	}
760
+
761
+
762
+	/**
763
+	 * Echo out JSON response to migration script AJAX requests. Takes precautions
764
+	 * to buffer output so that we don't throw junk into our json.
765
+	 *
766
+	 * @return array with keys:
767
+	 * 'records_to_migrate' which counts ALL the records for the current migration, and should remain constant. (ie,
768
+	 * it's NOT the count of hwo many remain)
769
+	 * 'records_migrated' which also counts ALL the records which have been migrated (ie, percent_complete =
770
+	 * records_migrated/records_to_migrate)
771
+	 * 'status'=>a string, one of EE_Data_migration_Manager::status_*
772
+	 * 'message'=>a string, containing any message you want to show to the user. We may decide to split this up into
773
+	 * errors, notifications, and successes
774
+	 * 'script'=>a pretty name of the script currently running
775
+	 */
776
+	public function response_to_migration_ajax_request()
777
+	{
778
+		ob_start();
779
+		try {
780
+			$response = $this->migration_step();
781
+		} catch (Exception $e) {
782
+			$response = array(
783
+				'records_to_migrate' => 0,
784
+				'records_migrated'   => 0,
785
+				'status'             => EE_Data_Migration_Manager::status_fatal_error,
786
+				'message'            => sprintf(
787
+					__("Unknown fatal error occurred: %s", "event_espresso"),
788
+					$e->getMessage()
789
+				),
790
+				'script'             => 'Unknown',
791
+			);
792
+			$this->add_error_to_migrations_ran($e->getMessage() . "; Stack trace:" . $e->getTraceAsString());
793
+		}
794
+		$warnings_etc = @ob_get_contents();
795
+		ob_end_clean();
796
+		$response['message'] .= $warnings_etc;
797
+		return $response;
798
+	}
799
+
800
+	/**
801
+	 * Updates the wordpress option that keeps track of which which EE version the database
802
+	 * is at (ie, the code may be at 4.1.0, but the database is still at 3.1.35)
803
+	 *
804
+	 * @param array $slug_and_version {
805
+	 * @type string $slug             like 'Core' or 'Calendar',
806
+	 * @type string $version          like '4.1.0'
807
+	 *                                }
808
+	 * @return void
809
+	 */
810
+	public function update_current_database_state_to($slug_and_version = null)
811
+	{
812
+		if (! $slug_and_version) {
813
+			// no version was provided, assume it should be at the current code version
814
+			$slug_and_version = array('slug' => 'Core', 'version' => espresso_version());
815
+		}
816
+		$current_database_state = get_option(self::current_database_state);
817
+		$current_database_state[ $slug_and_version['slug'] ] = $slug_and_version['version'];
818
+		update_option(self::current_database_state, $current_database_state);
819
+	}
820
+
821
+	/**
822
+	 * Determines if the database is currently at a state matching what's indicated in $slug and $version.
823
+	 *
824
+	 * @param array $slug_and_version {
825
+	 * @type string $slug             like 'Core' or 'Calendar',
826
+	 * @type string $version          like '4.1.0'
827
+	 *                                }
828
+	 * @return boolean
829
+	 */
830
+	public function database_needs_updating_to($slug_and_version)
831
+	{
832
+
833
+		$slug = $slug_and_version['slug'];
834
+		$version = $slug_and_version['version'];
835
+		$current_database_state = get_option(self::current_database_state);
836
+		if (! isset($current_database_state[ $slug ])) {
837
+			return true;
838
+		} else {
839
+			// just compare the first 3 parts of version string, eg "4.7.1", not "4.7.1.dev.032" because DBs shouldn't change on nano version changes
840
+			$version_parts_current_db_state = array_slice(explode('.', $current_database_state[ $slug ]), 0, 3);
841
+			$version_parts_of_provided_db_state = array_slice(explode('.', $version), 0, 3);
842
+			$needs_updating = false;
843
+			foreach ($version_parts_current_db_state as $offset => $version_part_in_current_db_state) {
844
+				if ($version_part_in_current_db_state < $version_parts_of_provided_db_state[ $offset ]) {
845
+					$needs_updating = true;
846
+					break;
847
+				}
848
+			}
849
+			return $needs_updating;
850
+		}
851
+	}
852
+
853
+
854
+	/**
855
+	 * Gets all the data migration scripts available in the core folder and folders
856
+	 * in addons. Has the side effect of adding them for autoloading
857
+	 *
858
+	 * @return array keys are expected classnames, values are their filepaths
859
+	 * @throws InvalidInterfaceException
860
+	 * @throws InvalidDataTypeException
861
+	 * @throws EE_Error
862
+	 * @throws InvalidArgumentException
863
+	 */
864
+	public function get_all_data_migration_scripts_available()
865
+	{
866
+		if (! $this->_data_migration_class_to_filepath_map) {
867
+			$this->_data_migration_class_to_filepath_map = array();
868
+			foreach ($this->get_data_migration_script_folders() as $eeAddonClass => $folder_path) {
869
+				// strip any placeholders added to classname to make it a unique array key
870
+				$eeAddonClass = trim($eeAddonClass, '*');
871
+				$eeAddonClass = $eeAddonClass === 'Core' || class_exists($eeAddonClass)
872
+					? $eeAddonClass
873
+					: '';
874
+				$folder_path = EEH_File::end_with_directory_separator($folder_path);
875
+				$files = glob($folder_path . '*.dms.php');
876
+				if (empty($files)) {
877
+					continue;
878
+				}
879
+				foreach ($files as $file) {
880
+					$pos_of_last_slash = strrpos($file, '/');
881
+					$classname = str_replace('.dms.php', '', substr($file, $pos_of_last_slash + 1));
882
+					$migrates_to = $this->script_migrates_to_version($classname, $eeAddonClass);
883
+					$slug = $migrates_to['slug'];
884
+					// check that the slug as contained in the DMS is associated with
885
+					// the slug of an addon or core
886
+					if ($slug !== 'Core' && EE_Registry::instance()->get_addon_by_name($slug) === null) {
887
+						EE_Error::doing_it_wrong(
888
+							__FUNCTION__,
889
+							sprintf(
890
+								esc_html__(
891
+									'The data migration script "%s" migrates the "%s" data, but there is no EE addon with that name. There is only: %s. ',
892
+									'event_espresso'
893
+								),
894
+								$classname,
895
+								$slug,
896
+								implode(', ', array_keys(EE_Registry::instance()->get_addons_by_name()))
897
+							),
898
+							'4.3.0.alpha.019'
899
+						);
900
+					}
901
+					$this->_data_migration_class_to_filepath_map[ $classname ] = $file;
902
+				}
903
+			}
904
+			EEH_Autoloader::register_autoloader($this->_data_migration_class_to_filepath_map);
905
+		}
906
+		return $this->_data_migration_class_to_filepath_map;
907
+	}
908
+
909
+
910
+	/**
911
+	 * Once we have an addon that works with EE4.1, we will actually want to fetch the PUE slugs
912
+	 * from each addon, and check if they need updating,
913
+	 *
914
+	 * @return boolean
915
+	 */
916
+	public function addons_need_updating()
917
+	{
918
+		return false;
919
+	}
920
+
921
+	/**
922
+	 * Adds this error string to the data_migrations_ran array, but we dont necessarily know
923
+	 * where to put it, so we just throw it in there... better than nothing...
924
+	 *
925
+	 * @param string $error_message
926
+	 * @throws EE_Error
927
+	 */
928
+	public function add_error_to_migrations_ran($error_message)
929
+	{
930
+		// get last-ran migration script
931
+		global $wpdb;
932
+		$last_migration_script_option = $wpdb->get_row(
933
+			"SELECT * FROM $wpdb->options WHERE option_name like '" . EE_Data_Migration_Manager::data_migration_script_option_prefix . "%' ORDER BY option_id DESC LIMIT 1",
934
+			ARRAY_A
935
+		);
936
+
937
+		$last_ran_migration_script_properties = isset($last_migration_script_option['option_value'])
938
+			? maybe_unserialize($last_migration_script_option['option_value']) : null;
939
+		// now, tread lightly because we're here because a FATAL non-catchable error
940
+		// was thrown last time when we were trying to run a data migration script
941
+		// so the fatal error could have happened while getting the migration script
942
+		// or doing running it...
943
+		$versions_migrated_to = isset($last_migration_script_option['option_name']) ? str_replace(
944
+			EE_Data_Migration_Manager::data_migration_script_option_prefix,
945
+			"",
946
+			$last_migration_script_option['option_name']
947
+		) : null;
948
+
949
+		// check if it THINKS its a data migration script and especially if it's one that HASN'T finished yet
950
+		// because if it has finished, then it obviously couldn't be the cause of this error, right? (because its all done)
951
+		if (isset($last_ran_migration_script_properties['class']) && isset($last_ran_migration_script_properties['_status']) && $last_ran_migration_script_properties['_status'] != self::status_completed) {
952
+			// ok then just add this error to its list of errors
953
+			$last_ran_migration_script_properties['_errors'][] = $error_message;
954
+			$last_ran_migration_script_properties['_status'] = self::status_fatal_error;
955
+		} else {
956
+			// so we don't even know which script was last running
957
+			// use the data migration error stub, which is designed specifically for this type of thing
958
+			$general_migration_error = new EE_DMS_Unknown_1_0_0();
959
+			$general_migration_error->add_error($error_message);
960
+			$general_migration_error->set_broken();
961
+			$last_ran_migration_script_properties = $general_migration_error->properties_as_array();
962
+			$versions_migrated_to = 'Unknown.1.0.0';
963
+			// now just to make sure appears as last (in case the were previously a fatal error like this)
964
+			// delete the old one
965
+			delete_option(self::data_migration_script_option_prefix . $versions_migrated_to);
966
+		}
967
+		update_option(
968
+			self::data_migration_script_option_prefix . $versions_migrated_to,
969
+			$last_ran_migration_script_properties
970
+		);
971
+	}
972
+
973
+	/**
974
+	 * saves what data migrations have ran to the database
975
+	 *
976
+	 * @return mixed TRUE if successfully saved migrations ran, string if an error occurred
977
+	 */
978
+	protected function _save_migrations_ran()
979
+	{
980
+		if ($this->_data_migrations_ran == null) {
981
+			$this->get_data_migrations_ran();
982
+		}
983
+		// now, we don't want to save actual classes to the DB because that's messy
984
+		$successful_updates = true;
985
+		foreach ($this->_data_migrations_ran as $plugin_slug => $migrations_ran_for_plugin) {
986
+			foreach ($migrations_ran_for_plugin as $version_string => $array_or_migration_obj) {
987
+				$plugin_slug_for_use_in_option_name = $plugin_slug . ".";
988
+				$option_name = self::data_migration_script_option_prefix . $plugin_slug_for_use_in_option_name . $version_string;
989
+				$old_option_value = get_option($option_name);
990
+				if ($array_or_migration_obj instanceof EE_Data_Migration_Script_Base) {
991
+					$script_array_for_saving = $array_or_migration_obj->properties_as_array();
992
+					if ($old_option_value != $script_array_for_saving) {
993
+						$successful_updates = update_option($option_name, $script_array_for_saving);
994
+					}
995
+				} else {// we don't know what this array-thing is. So just save it as-is
996
+					if ($old_option_value != $array_or_migration_obj) {
997
+						$successful_updates = update_option($option_name, $array_or_migration_obj);
998
+					}
999
+				}
1000
+				if (! $successful_updates) {
1001
+					global $wpdb;
1002
+					return $wpdb->last_error;
1003
+				}
1004
+			}
1005
+		}
1006
+		return true;
1007
+		// $updated = update_option(self::data_migrations_option_name, $array_of_migrations);
1008
+		// if ($updated !== true) {
1009
+		//     global $wpdb;
1010
+		//     return $wpdb->last_error;
1011
+		// } else {
1012
+		//     return true;
1013
+		// }
1014
+		// wp_mail(
1015
+		//     "[email protected]",
1016
+		//     time() . " price debug info",
1017
+		//     "updated: $updated, last error: $last_error, byte length of option: " . strlen(
1018
+		//         serialize($array_of_migrations)
1019
+		//     )
1020
+		// );
1021
+	}
1022
+
1023
+	/**
1024
+	 * Takes an array of data migration script properties and re-creates the class from
1025
+	 * them. The argument $properties_array is assumed to have been made by
1026
+	 * EE_Data_Migration_Script_Base::properties_as_array()
1027
+	 *
1028
+	 * @param array $properties_array
1029
+	 * @return EE_Data_Migration_Script_Base
1030
+	 * @throws EE_Error
1031
+	 */
1032
+	public function _instantiate_script_from_properties_array($properties_array)
1033
+	{
1034
+		if (! isset($properties_array['class'])) {
1035
+			throw new EE_Error(
1036
+				sprintf(
1037
+					__("Properties array  has no 'class' properties. Here's what it has: %s", "event_espresso"),
1038
+					implode(",", $properties_array)
1039
+				)
1040
+			);
1041
+		}
1042
+		$class_name = $properties_array['class'];
1043
+		if (! class_exists($class_name)) {
1044
+			throw new EE_Error(sprintf(__("There is no migration script named %s", "event_espresso"), $class_name));
1045
+		}
1046
+		$class = new $class_name;
1047
+		if (! $class instanceof EE_Data_Migration_Script_Base) {
1048
+			throw new EE_Error(
1049
+				sprintf(
1050
+					__("Class '%s' is supposed to be a migration script. Its not, its a '%s'", "event_espresso"),
1051
+					$class_name,
1052
+					get_class($class)
1053
+				)
1054
+			);
1055
+		}
1056
+		$class->instantiate_from_array_of_properties($properties_array);
1057
+		return $class;
1058
+	}
1059
+
1060
+	/**
1061
+	 * Gets the classname for the most up-to-date DMS (ie, the one that will finally
1062
+	 * leave the DB in a state usable by the current plugin code).
1063
+	 *
1064
+	 * @param string $plugin_slug the slug for the ee plugin we are searching for. Default is 'Core'
1065
+	 * @return string
1066
+	 */
1067
+	public function get_most_up_to_date_dms($plugin_slug = 'Core')
1068
+	{
1069
+		$class_to_filepath_map = $this->get_all_data_migration_scripts_available();
1070
+		$most_up_to_date_dms_classname = null;
1071
+		foreach ($class_to_filepath_map as $classname => $filepath) {
1072
+			if ($most_up_to_date_dms_classname === null) {
1073
+				$migrates_to = $this->script_migrates_to_version($classname);
1074
+				$this_plugin_slug = $migrates_to['slug'];
1075
+				if ($this_plugin_slug == $plugin_slug) {
1076
+					// if it's for core, it wins
1077
+					$most_up_to_date_dms_classname = $classname;
1078
+				}
1079
+				// if it wasn't for core, we must keep searching for one that is!
1080
+				continue;
1081
+			} else {
1082
+				$champion_migrates_to = $this->script_migrates_to_version($most_up_to_date_dms_classname);
1083
+				$contender_migrates_to = $this->script_migrates_to_version($classname);
1084
+				if ($contender_migrates_to['slug'] == $plugin_slug
1085
+					&& version_compare(
1086
+						$champion_migrates_to['version'],
1087
+						$contender_migrates_to['version'],
1088
+						'<'
1089
+					)) {
1090
+					// so the contenders version is higher and its for Core
1091
+					$most_up_to_date_dms_classname = $classname;
1092
+				}
1093
+			}
1094
+		}
1095
+		return $most_up_to_date_dms_classname;
1096
+	}
1097
+
1098
+	/**
1099
+	 * Gets the migration script specified but ONLY if it has already ran.
1100
+	 *
1101
+	 * Eg, if you wanted to see if 'EE_DMS_Core_4_1_0' has ran, you would run the following code:
1102
+	 * <code> $core_4_1_0_dms_ran = EE_Data_Migration_Manager::instance()->get_migration_ran( '4.1.0', 'Core' ) !==
1103
+	 * NULL;</code> This is especially useful in addons' data migration scripts, this way they can tell if a core (or
1104
+	 * other addon) DMS has ran, in case the current DMS depends on it.
1105
+	 *
1106
+	 * @param string $version     the version the DMS searched for migrates to. Usually just the content before the 3rd
1107
+	 *                            period. Eg '4.1.0'
1108
+	 * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
1109
+	 * @return EE_Data_Migration_Script_Base
1110
+	 */
1111
+	public function get_migration_ran($version, $plugin_slug = 'Core')
1112
+	{
1113
+		$migrations_ran = $this->get_data_migrations_ran();
1114
+		if (isset($migrations_ran[ $plugin_slug ]) && isset($migrations_ran[ $plugin_slug ][ $version ])) {
1115
+			return $migrations_ran[ $plugin_slug ][ $version ];
1116
+		} else {
1117
+			return null;
1118
+		}
1119
+	}
1120
+
1121
+	/**
1122
+	 * Resets the borked data migration scripts so they're no longer borked
1123
+	 * so we can again attempt to migrate
1124
+	 *
1125
+	 * @return bool
1126
+	 * @throws EE_Error
1127
+	 */
1128
+	public function reattempt()
1129
+	{
1130
+		// find if the last-ran script was borked
1131
+		// set it as being non-borked (we shouldn't ever get DMSs that we don't recognize)
1132
+		// add an 'error' saying that we attempted to reset
1133
+		// does it have a stage that was borked too? if so make it no longer borked
1134
+		// add an 'error' saying we attempted to reset
1135
+		$last_ran_script = $this->get_last_ran_script();
1136
+		if ($last_ran_script instanceof EE_DMS_Unknown_1_0_0) {
1137
+			// if it was an error DMS, just mark it as complete (if another error occurs it will overwrite it)
1138
+			$last_ran_script->set_completed();
1139
+		} elseif ($last_ran_script instanceof EE_Data_Migration_Script_Base) {
1140
+			$last_ran_script->reattempt();
1141
+		} else {
1142
+			throw new EE_Error(
1143
+				sprintf(
1144
+					__(
1145
+						'Unable to reattempt the last ran migration script because it was not a valid migration script. || It was %s',
1146
+						'event_espresso'
1147
+					),
1148
+					print_r($last_ran_script, true)
1149
+				)
1150
+			);
1151
+		}
1152
+		return $this->_save_migrations_ran();
1153
+	}
1154
+
1155
+	/**
1156
+	 * Gets whether or not this particular migration has run or not
1157
+	 *
1158
+	 * @param string $version     the version the DMS searched for migrates to. Usually just the content before the 3rd
1159
+	 *                            period. Eg '4.1.0'
1160
+	 * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
1161
+	 * @return boolean
1162
+	 */
1163
+	public function migration_has_ran($version, $plugin_slug = 'Core')
1164
+	{
1165
+		return $this->get_migration_ran($version, $plugin_slug) !== null;
1166
+	}
1167
+
1168
+	/**
1169
+	 * Enqueues this ee plugin to have its data initialized
1170
+	 *
1171
+	 * @param string $plugin_slug either 'Core' or EE_Addon::name()'s return value
1172
+	 */
1173
+	public function enqueue_db_initialization_for($plugin_slug)
1174
+	{
1175
+		$queue = $this->get_db_initialization_queue();
1176
+		if (! in_array($plugin_slug, $queue)) {
1177
+			$queue[] = $plugin_slug;
1178
+		}
1179
+		update_option(self::db_init_queue_option_name, $queue);
1180
+	}
1181
+
1182
+	/**
1183
+	 * Calls EE_Addon::initialize_db_if_no_migrations_required() on each addon
1184
+	 * specified in EE_Data_Migration_Manager::get_db_init_queue(), and if 'Core' is
1185
+	 * in the queue, calls EE_System::initialize_db_if_no_migrations_required().
1186
+	 */
1187
+	public function initialize_db_for_enqueued_ee_plugins()
1188
+	{
1189
+		$queue = $this->get_db_initialization_queue();
1190
+		foreach ($queue as $plugin_slug) {
1191
+			$most_up_to_date_dms = $this->get_most_up_to_date_dms($plugin_slug);
1192
+			if (! $most_up_to_date_dms) {
1193
+				// if there is NO DMS for this plugin, obviously there's no schema to verify anyways
1194
+				$verify_db = false;
1195
+			} else {
1196
+				$most_up_to_date_dms_migrates_to = $this->script_migrates_to_version($most_up_to_date_dms);
1197
+				$verify_db = $this->database_needs_updating_to($most_up_to_date_dms_migrates_to);
1198
+			}
1199
+			if ($plugin_slug == 'Core') {
1200
+				EE_System::instance()->initialize_db_if_no_migrations_required(
1201
+					false,
1202
+					$verify_db
1203
+				);
1204
+			} else {
1205
+				// just loop through the addons to make sure their database is setup
1206
+				foreach (EE_Registry::instance()->addons as $addon) {
1207
+					if ($addon->name() == $plugin_slug) {
1208
+						$addon->initialize_db_if_no_migrations_required($verify_db);
1209
+						break;
1210
+					}
1211
+				}
1212
+			}
1213
+		}
1214
+		// because we just initialized the DBs for the enqueued ee plugins
1215
+		// we don't need to keep remembering which ones needed to be initialized
1216
+		delete_option(self::db_init_queue_option_name);
1217
+	}
1218
+
1219
+	/**
1220
+	 * Gets a numerically-indexed array of plugin slugs that need to have their databases
1221
+	 * (re-)initialized after migrations are complete. ie, each element should be either
1222
+	 * 'Core', or the return value of EE_Addon::name() for an addon
1223
+	 *
1224
+	 * @return array
1225
+	 */
1226
+	public function get_db_initialization_queue()
1227
+	{
1228
+		return get_option(self::db_init_queue_option_name, array());
1229
+	}
1230
+
1231
+	/**
1232
+	 * Gets the injected table analyzer, or throws an exception
1233
+	 *
1234
+	 * @return TableAnalysis
1235
+	 * @throws EE_Error
1236
+	 */
1237
+	protected function _get_table_analysis()
1238
+	{
1239
+		if ($this->_table_analysis instanceof TableAnalysis) {
1240
+			return $this->_table_analysis;
1241
+		} else {
1242
+			throw new EE_Error(
1243
+				sprintf(
1244
+					__('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
1245
+					get_class($this)
1246
+				)
1247
+			);
1248
+		}
1249
+	}
1250
+
1251
+	/**
1252
+	 * Gets the injected table manager, or throws an exception
1253
+	 *
1254
+	 * @return TableManager
1255
+	 * @throws EE_Error
1256
+	 */
1257
+	protected function _get_table_manager()
1258
+	{
1259
+		if ($this->_table_manager instanceof TableManager) {
1260
+			return $this->_table_manager;
1261
+		} else {
1262
+			throw new EE_Error(
1263
+				sprintf(
1264
+					__('Table manager class on class %1$s is not set properly.', 'event_espresso'),
1265
+					get_class($this)
1266
+				)
1267
+			);
1268
+		}
1269
+	}
1270 1270
 }
Please login to merge, or discard this patch.
core/Psr4Autoloader.php 1 patch
Indentation   +146 added lines, -146 removed lines patch added patch discarded remove patch
@@ -45,150 +45,150 @@
 block discarded – undo
45 45
 class Psr4Autoloader
46 46
 {
47 47
 
48
-    /**
49
-     * namespace separator
50
-     */
51
-    const NS = '\\';
52
-
53
-    /**
54
-     * An associative array where the key is a namespace prefix and the value
55
-     * is an array of base directories for classes in that namespace.
56
-     *
57
-     * @var array
58
-     */
59
-    protected $prefixes = array();
60
-
61
-
62
-    /**
63
-     * returns an array of registered namespace prefixes
64
-     *
65
-     * @param string $prefix
66
-     * @return array
67
-     */
68
-    public function prefixes($prefix = '')
69
-    {
70
-        if (! empty($prefix)) {
71
-            // are there any base directories for this namespace prefix?
72
-            return isset($this->prefixes[ $prefix ]) ? $this->prefixes[ $prefix ] : array();
73
-        }
74
-        return $this->prefixes;
75
-    }
76
-
77
-
78
-    /**
79
-     * Register loader with SPL autoloader stack.
80
-     *
81
-     * @return void
82
-     */
83
-    public function register()
84
-    {
85
-        spl_autoload_register(array($this, 'loadClass'));
86
-    }
87
-
88
-
89
-    /**
90
-     * Adds a base directory for a namespace prefix.
91
-     *
92
-     * @param string $prefix   The namespace prefix.
93
-     * @param string $base_dir A base directory for class files in the
94
-     *                         namespace.
95
-     * @param bool   $prepend  If true, prepend the base directory to the stack
96
-     *                         instead of appending it; this causes it to be searched first rather
97
-     *                         than last.
98
-     * @return void
99
-     */
100
-    public function addNamespace($prefix, $base_dir, $prepend = false)
101
-    {
102
-        // normalize namespace prefix
103
-        $prefix = trim($prefix, Psr4Autoloader::NS) . Psr4Autoloader::NS;
104
-        // normalize the base directory with a trailing separator
105
-        $base_dir = \EEH_File::standardise_and_end_with_directory_separator($base_dir);
106
-        // initialize the namespace prefix array
107
-        if (isset($this->prefixes[ $prefix ]) === false) {
108
-            $this->prefixes[ $prefix ] = array();
109
-        }
110
-        // retain the base directory for the namespace prefix
111
-        if ($prepend) {
112
-            array_unshift($this->prefixes[ $prefix ], $base_dir);
113
-        } else {
114
-            $this->prefixes[ $prefix ][] = $base_dir;
115
-        }
116
-    }
117
-
118
-
119
-    /**
120
-     * Loads the class file for a given class name.
121
-     *
122
-     * @param string $class The fully-qualified class name.
123
-     * @return mixed The mapped file name on success, or boolean false on
124
-     *                      failure.
125
-     */
126
-    public function loadClass($class)
127
-    {
128
-        // the current namespace prefix
129
-        $prefix = $class;
130
-        // work backwards through the namespace names of the fully-qualified
131
-        // class name to find a mapped file name
132
-        while (false !== $pos = strrpos($prefix, Psr4Autoloader::NS)) {
133
-            // retain the trailing namespace separator in the prefix
134
-            $prefix = substr($class, 0, $pos + 1);
135
-            // the rest is the relative class name
136
-            $relative_class = substr($class, $pos + 1);
137
-            // try to load a mapped file for the prefix and relative class
138
-            $mapped_file = $this->loadMappedFile($prefix, $relative_class);
139
-            if ($mapped_file) {
140
-                return $mapped_file;
141
-            }
142
-            // remove the trailing namespace separator for the next iteration
143
-            // of strrpos()
144
-            $prefix = rtrim($prefix, Psr4Autoloader::NS);
145
-        }
146
-        // never found a mapped file
147
-        return false;
148
-    }
149
-
150
-
151
-    /**
152
-     * Load the mapped file for a namespace prefix and relative class.
153
-     *
154
-     * @param string $prefix         The namespace prefix.
155
-     * @param string $relative_class The relative class name.
156
-     * @return mixed Boolean false if no mapped file can be loaded, or the
157
-     *                               name of the mapped file that was loaded.
158
-     */
159
-    protected function loadMappedFile($prefix, $relative_class)
160
-    {
161
-        // look through base directories for this namespace prefix
162
-        foreach ($this->prefixes($prefix) as $base_dir) {
163
-            // replace the namespace prefix with the base directory,
164
-            // replace namespace separators with directory separators
165
-            // in the relative class name, append with .php
166
-            $file = $base_dir
167
-                    . str_replace(Psr4Autoloader::NS, '/', $relative_class)
168
-                    . '.php';
169
-            // if the mapped file exists, require it
170
-            if ($this->requireFile($file)) {
171
-                // yes, we're done
172
-                return $file;
173
-            }
174
-        }
175
-        // never found it
176
-        return false;
177
-    }
178
-
179
-
180
-    /**
181
-     * If a file exists, require it from the file system.
182
-     *
183
-     * @param string $file The file to require.
184
-     * @return bool True if the file exists, false if not.
185
-     */
186
-    protected function requireFile($file)
187
-    {
188
-        if (file_exists($file)) {
189
-            require $file;
190
-            return true;
191
-        }
192
-        return false;
193
-    }
48
+	/**
49
+	 * namespace separator
50
+	 */
51
+	const NS = '\\';
52
+
53
+	/**
54
+	 * An associative array where the key is a namespace prefix and the value
55
+	 * is an array of base directories for classes in that namespace.
56
+	 *
57
+	 * @var array
58
+	 */
59
+	protected $prefixes = array();
60
+
61
+
62
+	/**
63
+	 * returns an array of registered namespace prefixes
64
+	 *
65
+	 * @param string $prefix
66
+	 * @return array
67
+	 */
68
+	public function prefixes($prefix = '')
69
+	{
70
+		if (! empty($prefix)) {
71
+			// are there any base directories for this namespace prefix?
72
+			return isset($this->prefixes[ $prefix ]) ? $this->prefixes[ $prefix ] : array();
73
+		}
74
+		return $this->prefixes;
75
+	}
76
+
77
+
78
+	/**
79
+	 * Register loader with SPL autoloader stack.
80
+	 *
81
+	 * @return void
82
+	 */
83
+	public function register()
84
+	{
85
+		spl_autoload_register(array($this, 'loadClass'));
86
+	}
87
+
88
+
89
+	/**
90
+	 * Adds a base directory for a namespace prefix.
91
+	 *
92
+	 * @param string $prefix   The namespace prefix.
93
+	 * @param string $base_dir A base directory for class files in the
94
+	 *                         namespace.
95
+	 * @param bool   $prepend  If true, prepend the base directory to the stack
96
+	 *                         instead of appending it; this causes it to be searched first rather
97
+	 *                         than last.
98
+	 * @return void
99
+	 */
100
+	public function addNamespace($prefix, $base_dir, $prepend = false)
101
+	{
102
+		// normalize namespace prefix
103
+		$prefix = trim($prefix, Psr4Autoloader::NS) . Psr4Autoloader::NS;
104
+		// normalize the base directory with a trailing separator
105
+		$base_dir = \EEH_File::standardise_and_end_with_directory_separator($base_dir);
106
+		// initialize the namespace prefix array
107
+		if (isset($this->prefixes[ $prefix ]) === false) {
108
+			$this->prefixes[ $prefix ] = array();
109
+		}
110
+		// retain the base directory for the namespace prefix
111
+		if ($prepend) {
112
+			array_unshift($this->prefixes[ $prefix ], $base_dir);
113
+		} else {
114
+			$this->prefixes[ $prefix ][] = $base_dir;
115
+		}
116
+	}
117
+
118
+
119
+	/**
120
+	 * Loads the class file for a given class name.
121
+	 *
122
+	 * @param string $class The fully-qualified class name.
123
+	 * @return mixed The mapped file name on success, or boolean false on
124
+	 *                      failure.
125
+	 */
126
+	public function loadClass($class)
127
+	{
128
+		// the current namespace prefix
129
+		$prefix = $class;
130
+		// work backwards through the namespace names of the fully-qualified
131
+		// class name to find a mapped file name
132
+		while (false !== $pos = strrpos($prefix, Psr4Autoloader::NS)) {
133
+			// retain the trailing namespace separator in the prefix
134
+			$prefix = substr($class, 0, $pos + 1);
135
+			// the rest is the relative class name
136
+			$relative_class = substr($class, $pos + 1);
137
+			// try to load a mapped file for the prefix and relative class
138
+			$mapped_file = $this->loadMappedFile($prefix, $relative_class);
139
+			if ($mapped_file) {
140
+				return $mapped_file;
141
+			}
142
+			// remove the trailing namespace separator for the next iteration
143
+			// of strrpos()
144
+			$prefix = rtrim($prefix, Psr4Autoloader::NS);
145
+		}
146
+		// never found a mapped file
147
+		return false;
148
+	}
149
+
150
+
151
+	/**
152
+	 * Load the mapped file for a namespace prefix and relative class.
153
+	 *
154
+	 * @param string $prefix         The namespace prefix.
155
+	 * @param string $relative_class The relative class name.
156
+	 * @return mixed Boolean false if no mapped file can be loaded, or the
157
+	 *                               name of the mapped file that was loaded.
158
+	 */
159
+	protected function loadMappedFile($prefix, $relative_class)
160
+	{
161
+		// look through base directories for this namespace prefix
162
+		foreach ($this->prefixes($prefix) as $base_dir) {
163
+			// replace the namespace prefix with the base directory,
164
+			// replace namespace separators with directory separators
165
+			// in the relative class name, append with .php
166
+			$file = $base_dir
167
+					. str_replace(Psr4Autoloader::NS, '/', $relative_class)
168
+					. '.php';
169
+			// if the mapped file exists, require it
170
+			if ($this->requireFile($file)) {
171
+				// yes, we're done
172
+				return $file;
173
+			}
174
+		}
175
+		// never found it
176
+		return false;
177
+	}
178
+
179
+
180
+	/**
181
+	 * If a file exists, require it from the file system.
182
+	 *
183
+	 * @param string $file The file to require.
184
+	 * @return bool True if the file exists, false if not.
185
+	 */
186
+	protected function requireFile($file)
187
+	{
188
+		if (file_exists($file)) {
189
+			require $file;
190
+			return true;
191
+		}
192
+		return false;
193
+	}
194 194
 }
Please login to merge, or discard this patch.
core/EE_System.core.php 2 patches
Indentation   +1309 added lines, -1309 removed lines patch added patch discarded remove patch
@@ -27,1313 +27,1313 @@
 block discarded – undo
27 27
 final class EE_System implements ResettableInterface
28 28
 {
29 29
 
30
-    /**
31
-     * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
32
-     * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
33
-     */
34
-    const req_type_normal = 0;
35
-
36
-    /**
37
-     * Indicates this is a brand new installation of EE so we should install
38
-     * tables and default data etc
39
-     */
40
-    const req_type_new_activation = 1;
41
-
42
-    /**
43
-     * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
44
-     * and we just exited maintenance mode). We MUST check the database is setup properly
45
-     * and that default data is setup too
46
-     */
47
-    const req_type_reactivation = 2;
48
-
49
-    /**
50
-     * indicates that EE has been upgraded since its previous request.
51
-     * We may have data migration scripts to call and will want to trigger maintenance mode
52
-     */
53
-    const req_type_upgrade = 3;
54
-
55
-    /**
56
-     * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
57
-     */
58
-    const req_type_downgrade = 4;
59
-
60
-    /**
61
-     * @deprecated since version 4.6.0.dev.006
62
-     * Now whenever a new_activation is detected the request type is still just
63
-     * new_activation (same for reactivation, upgrade, downgrade etc), but if we'r ein maintenance mode
64
-     * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
65
-     * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
66
-     * (Specifically, when the migration manager indicates migrations are finished
67
-     * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
68
-     */
69
-    const req_type_activation_but_not_installed = 5;
70
-
71
-    /**
72
-     * option prefix for recording the activation history (like core's "espresso_db_update") of addons
73
-     */
74
-    const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
75
-
76
-    /**
77
-     * @var EE_System $_instance
78
-     */
79
-    private static $_instance;
80
-
81
-    /**
82
-     * @var EE_Registry $registry
83
-     */
84
-    private $registry;
85
-
86
-    /**
87
-     * @var LoaderInterface $loader
88
-     */
89
-    private $loader;
90
-
91
-    /**
92
-     * @var EE_Capabilities $capabilities
93
-     */
94
-    private $capabilities;
95
-
96
-    /**
97
-     * @var RequestInterface $request
98
-     */
99
-    private $request;
100
-
101
-    /**
102
-     * @var EE_Maintenance_Mode $maintenance_mode
103
-     */
104
-    private $maintenance_mode;
105
-
106
-    /**
107
-     * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
108
-     * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
109
-     *
110
-     * @var int $_req_type
111
-     */
112
-    private $_req_type;
113
-
114
-    /**
115
-     * Whether or not there was a non-micro version change in EE core version during this request
116
-     *
117
-     * @var boolean $_major_version_change
118
-     */
119
-    private $_major_version_change = false;
120
-
121
-    /**
122
-     * A Context DTO dedicated solely to identifying the current request type.
123
-     *
124
-     * @var RequestTypeContextCheckerInterface $request_type
125
-     */
126
-    private $request_type;
127
-
128
-
129
-    /**
130
-     * @singleton method used to instantiate class object
131
-     * @param EE_Registry|null         $registry
132
-     * @param LoaderInterface|null     $loader
133
-     * @param RequestInterface|null    $request
134
-     * @param EE_Maintenance_Mode|null $maintenance_mode
135
-     * @return EE_System
136
-     */
137
-    public static function instance(
138
-        EE_Registry $registry = null,
139
-        LoaderInterface $loader = null,
140
-        RequestInterface $request = null,
141
-        EE_Maintenance_Mode $maintenance_mode = null
142
-    ) {
143
-        // check if class object is instantiated
144
-        if (! self::$_instance instanceof EE_System) {
145
-            self::$_instance = new self($registry, $loader, $request, $maintenance_mode);
146
-        }
147
-        return self::$_instance;
148
-    }
149
-
150
-
151
-    /**
152
-     * resets the instance and returns it
153
-     *
154
-     * @return EE_System
155
-     */
156
-    public static function reset()
157
-    {
158
-        self::$_instance->_req_type = null;
159
-        // make sure none of the old hooks are left hanging around
160
-        remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
161
-        // we need to reset the migration manager in order for it to detect DMSs properly
162
-        EE_Data_Migration_Manager::reset();
163
-        self::instance()->detect_activations_or_upgrades();
164
-        self::instance()->perform_activations_upgrades_and_migrations();
165
-        return self::instance();
166
-    }
167
-
168
-
169
-    /**
170
-     * sets hooks for running rest of system
171
-     * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
172
-     * starting EE Addons from any other point may lead to problems
173
-     *
174
-     * @param EE_Registry         $registry
175
-     * @param LoaderInterface     $loader
176
-     * @param RequestInterface    $request
177
-     * @param EE_Maintenance_Mode $maintenance_mode
178
-     */
179
-    private function __construct(
180
-        EE_Registry $registry,
181
-        LoaderInterface $loader,
182
-        RequestInterface $request,
183
-        EE_Maintenance_Mode $maintenance_mode
184
-    ) {
185
-        $this->registry = $registry;
186
-        $this->loader = $loader;
187
-        $this->request = $request;
188
-        $this->maintenance_mode = $maintenance_mode;
189
-        do_action('AHEE__EE_System__construct__begin', $this);
190
-        add_action(
191
-            'AHEE__EE_Bootstrap__load_espresso_addons',
192
-            array($this, 'loadCapabilities'),
193
-            5
194
-        );
195
-        add_action(
196
-            'AHEE__EE_Bootstrap__load_espresso_addons',
197
-            array($this, 'loadCommandBus'),
198
-            7
199
-        );
200
-        add_action(
201
-            'AHEE__EE_Bootstrap__load_espresso_addons',
202
-            array($this, 'loadPluginApi'),
203
-            9
204
-        );
205
-        // allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
206
-        add_action(
207
-            'AHEE__EE_Bootstrap__load_espresso_addons',
208
-            array($this, 'load_espresso_addons')
209
-        );
210
-        // when an ee addon is activated, we want to call the core hook(s) again
211
-        // because the newly-activated addon didn't get a chance to run at all
212
-        add_action('activate_plugin', array($this, 'load_espresso_addons'), 1);
213
-        // detect whether install or upgrade
214
-        add_action(
215
-            'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
216
-            array($this, 'detect_activations_or_upgrades'),
217
-            3
218
-        );
219
-        // load EE_Config, EE_Textdomain, etc
220
-        add_action(
221
-            'AHEE__EE_Bootstrap__load_core_configuration',
222
-            array($this, 'load_core_configuration'),
223
-            5
224
-        );
225
-        // load specifications for matching routes to current request
226
-        add_action(
227
-            'AHEE__EE_Bootstrap__load_core_configuration',
228
-            array($this, 'loadRouteMatchSpecifications')
229
-        );
230
-        // load EE_Config, EE_Textdomain, etc
231
-        add_action(
232
-            'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
233
-            array($this, 'register_shortcodes_modules_and_widgets'),
234
-            7
235
-        );
236
-        // you wanna get going? I wanna get going... let's get going!
237
-        add_action(
238
-            'AHEE__EE_Bootstrap__brew_espresso',
239
-            array($this, 'brew_espresso'),
240
-            9
241
-        );
242
-        // other housekeeping
243
-        // exclude EE critical pages from wp_list_pages
244
-        add_filter(
245
-            'wp_list_pages_excludes',
246
-            array($this, 'remove_pages_from_wp_list_pages'),
247
-            10
248
-        );
249
-        // ALL EE Addons should use the following hook point to attach their initial setup too
250
-        // it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
251
-        do_action('AHEE__EE_System__construct__complete', $this);
252
-    }
253
-
254
-
255
-    /**
256
-     * load and setup EE_Capabilities
257
-     *
258
-     * @return void
259
-     * @throws EE_Error
260
-     */
261
-    public function loadCapabilities()
262
-    {
263
-        $this->capabilities = $this->loader->getShared('EE_Capabilities');
264
-        add_action(
265
-            'AHEE__EE_Capabilities__init_caps__before_initialization',
266
-            function () {
267
-                LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
268
-            }
269
-        );
270
-    }
271
-
272
-
273
-    /**
274
-     * create and cache the CommandBus, and also add middleware
275
-     * The CapChecker middleware requires the use of EE_Capabilities
276
-     * which is why we need to load the CommandBus after Caps are set up
277
-     *
278
-     * @return void
279
-     * @throws EE_Error
280
-     */
281
-    public function loadCommandBus()
282
-    {
283
-        $this->loader->getShared(
284
-            'CommandBusInterface',
285
-            array(
286
-                null,
287
-                apply_filters(
288
-                    'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
289
-                    array(
290
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
291
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
292
-                    )
293
-                ),
294
-            )
295
-        );
296
-    }
297
-
298
-
299
-    /**
300
-     * @return void
301
-     * @throws EE_Error
302
-     */
303
-    public function loadPluginApi()
304
-    {
305
-        // set autoloaders for all of the classes implementing EEI_Plugin_API
306
-        // which provide helpers for EE plugin authors to more easily register certain components with EE.
307
-        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
308
-        $this->loader->getShared('EE_Request_Handler');
309
-    }
310
-
311
-
312
-    /**
313
-     * @param string $addon_name
314
-     * @param string $version_constant
315
-     * @param string $min_version_required
316
-     * @param string $load_callback
317
-     * @param string $plugin_file_constant
318
-     * @return void
319
-     */
320
-    private function deactivateIncompatibleAddon(
321
-        $addon_name,
322
-        $version_constant,
323
-        $min_version_required,
324
-        $load_callback,
325
-        $plugin_file_constant
326
-    ) {
327
-        if (! defined($version_constant)) {
328
-            return;
329
-        }
330
-        $addon_version = constant($version_constant);
331
-        if ($addon_version && version_compare($addon_version, $min_version_required, '<')) {
332
-            remove_action('AHEE__EE_System__load_espresso_addons', $load_callback);
333
-            if (! function_exists('deactivate_plugins')) {
334
-                require_once ABSPATH . 'wp-admin/includes/plugin.php';
335
-            }
336
-            deactivate_plugins(plugin_basename(constant($plugin_file_constant)));
337
-            unset($_GET['activate'], $_REQUEST['activate'], $_GET['activate-multi'], $_REQUEST['activate-multi']);
338
-            EE_Error::add_error(
339
-                sprintf(
340
-                    esc_html__(
341
-                        'We\'re sorry, but the Event Espresso %1$s addon was deactivated because version %2$s or higher is required with this version of Event Espresso core.',
342
-                        'event_espresso'
343
-                    ),
344
-                    $addon_name,
345
-                    $min_version_required
346
-                ),
347
-                __FILE__,
348
-                __FUNCTION__ . "({$addon_name})",
349
-                __LINE__
350
-            );
351
-            EE_Error::get_notices(false, true);
352
-        }
353
-    }
354
-
355
-
356
-    /**
357
-     * load_espresso_addons
358
-     * allow addons to load first so that they can set hooks for running DMS's, etc
359
-     * this is hooked into both:
360
-     *    'AHEE__EE_Bootstrap__load_core_configuration'
361
-     *        which runs during the WP 'plugins_loaded' action at priority 5
362
-     *    and the WP 'activate_plugin' hook point
363
-     *
364
-     * @access public
365
-     * @return void
366
-     */
367
-    public function load_espresso_addons()
368
-    {
369
-        $this->deactivateIncompatibleAddon(
370
-            'Wait Lists',
371
-            'EE_WAIT_LISTS_VERSION',
372
-            '1.0.0.beta.074',
373
-            'load_espresso_wait_lists',
374
-            'EE_WAIT_LISTS_PLUGIN_FILE'
375
-        );
376
-        $this->deactivateIncompatibleAddon(
377
-            'Automated Upcoming Event Notifications',
378
-            'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_VERSION',
379
-            '1.0.0.beta.091',
380
-            'load_espresso_automated_upcoming_event_notification',
381
-            'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_PLUGIN_FILE'
382
-        );
383
-        do_action('AHEE__EE_System__load_espresso_addons');
384
-        // if the WP API basic auth plugin isn't already loaded, load it now.
385
-        // We want it for mobile apps. Just include the entire plugin
386
-        // also, don't load the basic auth when a plugin is getting activated, because
387
-        // it could be the basic auth plugin, and it doesn't check if its methods are already defined
388
-        // and causes a fatal error
389
-        if (($this->request->isWordPressApi() || $this->request->isApi())
390
-            && $this->request->getRequestParam('activate') !== 'true'
391
-            && ! function_exists('json_basic_auth_handler')
392
-            && ! function_exists('json_basic_auth_error')
393
-            && ! in_array(
394
-                $this->request->getRequestParam('action'),
395
-                array('activate', 'activate-selected'),
396
-                true
397
-            )
398
-        ) {
399
-            include_once EE_THIRD_PARTY . 'wp-api-basic-auth/basic-auth.php';
400
-        }
401
-        do_action('AHEE__EE_System__load_espresso_addons__complete');
402
-    }
403
-
404
-
405
-    /**
406
-     * detect_activations_or_upgrades
407
-     * Checks for activation or upgrade of core first;
408
-     * then also checks if any registered addons have been activated or upgraded
409
-     * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
410
-     * which runs during the WP 'plugins_loaded' action at priority 3
411
-     *
412
-     * @access public
413
-     * @return void
414
-     */
415
-    public function detect_activations_or_upgrades()
416
-    {
417
-        // first off: let's make sure to handle core
418
-        $this->detect_if_activation_or_upgrade();
419
-        foreach ($this->registry->addons as $addon) {
420
-            if ($addon instanceof EE_Addon) {
421
-                // detect teh request type for that addon
422
-                $addon->detect_activation_or_upgrade();
423
-            }
424
-        }
425
-    }
426
-
427
-
428
-    /**
429
-     * detect_if_activation_or_upgrade
430
-     * Takes care of detecting whether this is a brand new install or code upgrade,
431
-     * and either setting up the DB or setting up maintenance mode etc.
432
-     *
433
-     * @access public
434
-     * @return void
435
-     */
436
-    public function detect_if_activation_or_upgrade()
437
-    {
438
-        do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
439
-        // check if db has been updated, or if its a brand-new installation
440
-        $espresso_db_update = $this->fix_espresso_db_upgrade_option();
441
-        $request_type = $this->detect_req_type($espresso_db_update);
442
-        // EEH_Debug_Tools::printr( $request_type, '$request_type', __FILE__, __LINE__ );
443
-        switch ($request_type) {
444
-            case EE_System::req_type_new_activation:
445
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
446
-                $this->_handle_core_version_change($espresso_db_update);
447
-                break;
448
-            case EE_System::req_type_reactivation:
449
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
450
-                $this->_handle_core_version_change($espresso_db_update);
451
-                break;
452
-            case EE_System::req_type_upgrade:
453
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
454
-                // migrations may be required now that we've upgraded
455
-                $this->maintenance_mode->set_maintenance_mode_if_db_old();
456
-                $this->_handle_core_version_change($espresso_db_update);
457
-                break;
458
-            case EE_System::req_type_downgrade:
459
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
460
-                // its possible migrations are no longer required
461
-                $this->maintenance_mode->set_maintenance_mode_if_db_old();
462
-                $this->_handle_core_version_change($espresso_db_update);
463
-                break;
464
-            case EE_System::req_type_normal:
465
-            default:
466
-                break;
467
-        }
468
-        do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
469
-    }
470
-
471
-
472
-    /**
473
-     * Updates the list of installed versions and sets hooks for
474
-     * initializing the database later during the request
475
-     *
476
-     * @param array $espresso_db_update
477
-     */
478
-    private function _handle_core_version_change($espresso_db_update)
479
-    {
480
-        $this->update_list_of_installed_versions($espresso_db_update);
481
-        // get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
482
-        add_action(
483
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
484
-            array($this, 'initialize_db_if_no_migrations_required')
485
-        );
486
-    }
487
-
488
-
489
-    /**
490
-     * standardizes the wp option 'espresso_db_upgrade' which actually stores
491
-     * information about what versions of EE have been installed and activated,
492
-     * NOT necessarily the state of the database
493
-     *
494
-     * @param mixed $espresso_db_update           the value of the WordPress option.
495
-     *                                            If not supplied, fetches it from the options table
496
-     * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
497
-     */
498
-    private function fix_espresso_db_upgrade_option($espresso_db_update = null)
499
-    {
500
-        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
501
-        if (! $espresso_db_update) {
502
-            $espresso_db_update = get_option('espresso_db_update');
503
-        }
504
-        // check that option is an array
505
-        if (! is_array($espresso_db_update)) {
506
-            // if option is FALSE, then it never existed
507
-            if ($espresso_db_update === false) {
508
-                // make $espresso_db_update an array and save option with autoload OFF
509
-                $espresso_db_update = array();
510
-                add_option('espresso_db_update', $espresso_db_update, '', 'no');
511
-            } else {
512
-                // option is NOT FALSE but also is NOT an array, so make it an array and save it
513
-                $espresso_db_update = array($espresso_db_update => array());
514
-                update_option('espresso_db_update', $espresso_db_update);
515
-            }
516
-        } else {
517
-            $corrected_db_update = array();
518
-            // if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
519
-            foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
520
-                if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
521
-                    // the key is an int, and the value IS NOT an array
522
-                    // so it must be numerically-indexed, where values are versions installed...
523
-                    // fix it!
524
-                    $version_string = $should_be_array;
525
-                    $corrected_db_update[ $version_string ] = array('unknown-date');
526
-                } else {
527
-                    // ok it checks out
528
-                    $corrected_db_update[ $should_be_version_string ] = $should_be_array;
529
-                }
530
-            }
531
-            $espresso_db_update = $corrected_db_update;
532
-            update_option('espresso_db_update', $espresso_db_update);
533
-        }
534
-        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
535
-        return $espresso_db_update;
536
-    }
537
-
538
-
539
-    /**
540
-     * Does the traditional work of setting up the plugin's database and adding default data.
541
-     * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
542
-     * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
543
-     * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
544
-     * so that it will be done when migrations are finished
545
-     *
546
-     * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
547
-     * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
548
-     *                                       This is a resource-intensive job
549
-     *                                       so we prefer to only do it when necessary
550
-     * @return void
551
-     * @throws EE_Error
552
-     */
553
-    public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
554
-    {
555
-        $request_type = $this->detect_req_type();
556
-        // only initialize system if we're not in maintenance mode.
557
-        if ($this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
558
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
559
-            $rewrite_rules = $this->loader->getShared(
560
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
561
-            );
562
-            $rewrite_rules->flush();
563
-            if ($verify_schema) {
564
-                EEH_Activation::initialize_db_and_folders();
565
-            }
566
-            EEH_Activation::initialize_db_content();
567
-            EEH_Activation::system_initialization();
568
-            if ($initialize_addons_too) {
569
-                $this->initialize_addons();
570
-            }
571
-        } else {
572
-            EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
573
-        }
574
-        if ($request_type === EE_System::req_type_new_activation
575
-            || $request_type === EE_System::req_type_reactivation
576
-            || (
577
-                $request_type === EE_System::req_type_upgrade
578
-                && $this->is_major_version_change()
579
-            )
580
-        ) {
581
-            add_action('AHEE__EE_System__initialize_last', array($this, 'redirect_to_about_ee'), 9);
582
-        }
583
-    }
584
-
585
-
586
-    /**
587
-     * Initializes the db for all registered addons
588
-     *
589
-     * @throws EE_Error
590
-     */
591
-    public function initialize_addons()
592
-    {
593
-        // foreach registered addon, make sure its db is up-to-date too
594
-        foreach ($this->registry->addons as $addon) {
595
-            if ($addon instanceof EE_Addon) {
596
-                $addon->initialize_db_if_no_migrations_required();
597
-            }
598
-        }
599
-    }
600
-
601
-
602
-    /**
603
-     * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
604
-     *
605
-     * @param    array  $version_history
606
-     * @param    string $current_version_to_add version to be added to the version history
607
-     * @return    boolean success as to whether or not this option was changed
608
-     */
609
-    public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
610
-    {
611
-        if (! $version_history) {
612
-            $version_history = $this->fix_espresso_db_upgrade_option($version_history);
613
-        }
614
-        if ($current_version_to_add === null) {
615
-            $current_version_to_add = espresso_version();
616
-        }
617
-        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
618
-        // re-save
619
-        return update_option('espresso_db_update', $version_history);
620
-    }
621
-
622
-
623
-    /**
624
-     * Detects if the current version indicated in the has existed in the list of
625
-     * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
626
-     *
627
-     * @param array $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
628
-     *                                  If not supplied, fetches it from the options table.
629
-     *                                  Also, caches its result so later parts of the code can also know whether
630
-     *                                  there's been an update or not. This way we can add the current version to
631
-     *                                  espresso_db_update, but still know if this is a new install or not
632
-     * @return int one of the constants on EE_System::req_type_
633
-     */
634
-    public function detect_req_type($espresso_db_update = null)
635
-    {
636
-        if ($this->_req_type === null) {
637
-            $espresso_db_update = ! empty($espresso_db_update)
638
-                ? $espresso_db_update
639
-                : $this->fix_espresso_db_upgrade_option();
640
-            $this->_req_type = EE_System::detect_req_type_given_activation_history(
641
-                $espresso_db_update,
642
-                'ee_espresso_activation',
643
-                espresso_version()
644
-            );
645
-            $this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
646
-            $this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
647
-        }
648
-        return $this->_req_type;
649
-    }
650
-
651
-
652
-    /**
653
-     * Returns whether or not there was a non-micro version change (ie, change in either
654
-     * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
655
-     * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
656
-     *
657
-     * @param $activation_history
658
-     * @return bool
659
-     */
660
-    private function _detect_major_version_change($activation_history)
661
-    {
662
-        $previous_version = EE_System::_get_most_recently_active_version_from_activation_history($activation_history);
663
-        $previous_version_parts = explode('.', $previous_version);
664
-        $current_version_parts = explode('.', espresso_version());
665
-        return isset($previous_version_parts[0], $previous_version_parts[1], $current_version_parts[0], $current_version_parts[1])
666
-               && ($previous_version_parts[0] !== $current_version_parts[0]
667
-                   || $previous_version_parts[1] !== $current_version_parts[1]
668
-               );
669
-    }
670
-
671
-
672
-    /**
673
-     * Returns true if either the major or minor version of EE changed during this request.
674
-     * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
675
-     *
676
-     * @return bool
677
-     */
678
-    public function is_major_version_change()
679
-    {
680
-        return $this->_major_version_change;
681
-    }
682
-
683
-
684
-    /**
685
-     * Determines the request type for any ee addon, given three piece of info: the current array of activation
686
-     * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
687
-     * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
688
-     * just activated to (for core that will always be espresso_version())
689
-     *
690
-     * @param array  $activation_history_for_addon     the option's value which stores the activation history for this
691
-     *                                                 ee plugin. for core that's 'espresso_db_update'
692
-     * @param string $activation_indicator_option_name the name of the WordPress option that is temporarily set to
693
-     *                                                 indicate that this plugin was just activated
694
-     * @param string $version_to_upgrade_to            the version that was just upgraded to (for core that will be
695
-     *                                                 espresso_version())
696
-     * @return int one of the constants on EE_System::req_type_*
697
-     */
698
-    public static function detect_req_type_given_activation_history(
699
-        $activation_history_for_addon,
700
-        $activation_indicator_option_name,
701
-        $version_to_upgrade_to
702
-    ) {
703
-        $version_is_higher = self::_new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to);
704
-        if ($activation_history_for_addon) {
705
-            // it exists, so this isn't a completely new install
706
-            // check if this version already in that list of previously installed versions
707
-            if (! isset($activation_history_for_addon[ $version_to_upgrade_to ])) {
708
-                // it a version we haven't seen before
709
-                if ($version_is_higher === 1) {
710
-                    $req_type = EE_System::req_type_upgrade;
711
-                } else {
712
-                    $req_type = EE_System::req_type_downgrade;
713
-                }
714
-                delete_option($activation_indicator_option_name);
715
-            } else {
716
-                // its not an update. maybe a reactivation?
717
-                if (get_option($activation_indicator_option_name, false)) {
718
-                    if ($version_is_higher === -1) {
719
-                        $req_type = EE_System::req_type_downgrade;
720
-                    } elseif ($version_is_higher === 0) {
721
-                        // we've seen this version before, but it's an activation. must be a reactivation
722
-                        $req_type = EE_System::req_type_reactivation;
723
-                    } else {// $version_is_higher === 1
724
-                        $req_type = EE_System::req_type_upgrade;
725
-                    }
726
-                    delete_option($activation_indicator_option_name);
727
-                } else {
728
-                    // we've seen this version before and the activation indicate doesn't show it was just activated
729
-                    if ($version_is_higher === -1) {
730
-                        $req_type = EE_System::req_type_downgrade;
731
-                    } elseif ($version_is_higher === 0) {
732
-                        // we've seen this version before and it's not an activation. its normal request
733
-                        $req_type = EE_System::req_type_normal;
734
-                    } else {// $version_is_higher === 1
735
-                        $req_type = EE_System::req_type_upgrade;
736
-                    }
737
-                }
738
-            }
739
-        } else {
740
-            // brand new install
741
-            $req_type = EE_System::req_type_new_activation;
742
-            delete_option($activation_indicator_option_name);
743
-        }
744
-        return $req_type;
745
-    }
746
-
747
-
748
-    /**
749
-     * Detects if the $version_to_upgrade_to is higher than the most recent version in
750
-     * the $activation_history_for_addon
751
-     *
752
-     * @param array  $activation_history_for_addon (keys are versions, values are arrays of times activated,
753
-     *                                             sometimes containing 'unknown-date'
754
-     * @param string $version_to_upgrade_to        (current version)
755
-     * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
756
-     *                                             ie, -1 if $version_to_upgrade_to is LOWER (downgrade);
757
-     *                                             0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
758
-     *                                             1 if $version_to_upgrade_to is HIGHER (upgrade) ;
759
-     */
760
-    private static function _new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to)
761
-    {
762
-        // find the most recently-activated version
763
-        $most_recently_active_version =
764
-            EE_System::_get_most_recently_active_version_from_activation_history($activation_history_for_addon);
765
-        return version_compare($version_to_upgrade_to, $most_recently_active_version);
766
-    }
767
-
768
-
769
-    /**
770
-     * Gets the most recently active version listed in the activation history,
771
-     * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
772
-     *
773
-     * @param array $activation_history  (keys are versions, values are arrays of times activated,
774
-     *                                   sometimes containing 'unknown-date'
775
-     * @return string
776
-     */
777
-    private static function _get_most_recently_active_version_from_activation_history($activation_history)
778
-    {
779
-        $most_recently_active_version_activation = '1970-01-01 00:00:00';
780
-        $most_recently_active_version = '0.0.0.dev.000';
781
-        if (is_array($activation_history)) {
782
-            foreach ($activation_history as $version => $times_activated) {
783
-                // check there is a record of when this version was activated. Otherwise,
784
-                // mark it as unknown
785
-                if (! $times_activated) {
786
-                    $times_activated = array('unknown-date');
787
-                }
788
-                if (is_string($times_activated)) {
789
-                    $times_activated = array($times_activated);
790
-                }
791
-                foreach ($times_activated as $an_activation) {
792
-                    if ($an_activation !== 'unknown-date'
793
-                        && $an_activation
794
-                           > $most_recently_active_version_activation) {
795
-                        $most_recently_active_version = $version;
796
-                        $most_recently_active_version_activation = $an_activation === 'unknown-date'
797
-                            ? '1970-01-01 00:00:00'
798
-                            : $an_activation;
799
-                    }
800
-                }
801
-            }
802
-        }
803
-        return $most_recently_active_version;
804
-    }
805
-
806
-
807
-    /**
808
-     * This redirects to the about EE page after activation
809
-     *
810
-     * @return void
811
-     */
812
-    public function redirect_to_about_ee()
813
-    {
814
-        $notices = EE_Error::get_notices(false);
815
-        // if current user is an admin and it's not an ajax or rest request
816
-        if (! isset($notices['errors'])
817
-            && $this->request->isAdmin()
818
-            && apply_filters(
819
-                'FHEE__EE_System__redirect_to_about_ee__do_redirect',
820
-                $this->capabilities->current_user_can('manage_options', 'espresso_about_default')
821
-            )
822
-        ) {
823
-            $query_params = array('page' => 'espresso_about');
824
-            if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
825
-                $query_params['new_activation'] = true;
826
-            }
827
-            if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
828
-                $query_params['reactivation'] = true;
829
-            }
830
-            $url = add_query_arg($query_params, admin_url('admin.php'));
831
-            wp_safe_redirect($url);
832
-            exit();
833
-        }
834
-    }
835
-
836
-
837
-    /**
838
-     * load_core_configuration
839
-     * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
840
-     * which runs during the WP 'plugins_loaded' action at priority 5
841
-     *
842
-     * @return void
843
-     * @throws ReflectionException
844
-     * @throws Exception
845
-     */
846
-    public function load_core_configuration()
847
-    {
848
-        do_action('AHEE__EE_System__load_core_configuration__begin', $this);
849
-        $this->loader->getShared('EE_Load_Textdomain');
850
-        // load textdomain
851
-        EE_Load_Textdomain::load_textdomain();
852
-        // load caf stuff a chance to play during the activation process too.
853
-        $this->_maybe_brew_regular();
854
-        // load and setup EE_Config and EE_Network_Config
855
-        $config = $this->loader->getShared('EE_Config');
856
-        $this->loader->getShared('EE_Network_Config');
857
-        // setup autoloaders
858
-        // enable logging?
859
-        if ($config->admin->use_full_logging) {
860
-            $this->loader->getShared('EE_Log');
861
-        }
862
-        // check for activation errors
863
-        $activation_errors = get_option('ee_plugin_activation_errors', false);
864
-        if ($activation_errors) {
865
-            EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
866
-            update_option('ee_plugin_activation_errors', false);
867
-        }
868
-        // get model names
869
-        $this->_parse_model_names();
870
-        // configure custom post type definitions
871
-        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions');
872
-        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions');
873
-        do_action('AHEE__EE_System__load_core_configuration__complete', $this);
874
-    }
875
-
876
-
877
-    /**
878
-     * cycles through all of the models/*.model.php files, and assembles an array of model names
879
-     *
880
-     * @return void
881
-     * @throws ReflectionException
882
-     */
883
-    private function _parse_model_names()
884
-    {
885
-        // get all the files in the EE_MODELS folder that end in .model.php
886
-        $models = glob(EE_MODELS . '*.model.php');
887
-        $model_names = array();
888
-        $non_abstract_db_models = array();
889
-        foreach ($models as $model) {
890
-            // get model classname
891
-            $classname = EEH_File::get_classname_from_filepath_with_standard_filename($model);
892
-            $short_name = str_replace('EEM_', '', $classname);
893
-            $reflectionClass = new ReflectionClass($classname);
894
-            if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
895
-                $non_abstract_db_models[ $short_name ] = $classname;
896
-            }
897
-            $model_names[ $short_name ] = $classname;
898
-        }
899
-        $this->registry->models = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
900
-        $this->registry->non_abstract_db_models = apply_filters(
901
-            'FHEE__EE_System__parse_implemented_model_names',
902
-            $non_abstract_db_models
903
-        );
904
-    }
905
-
906
-
907
-    /**
908
-     * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
909
-     * that need to be setup before our EE_System launches.
910
-     *
911
-     * @return void
912
-     * @throws DomainException
913
-     * @throws InvalidArgumentException
914
-     * @throws InvalidDataTypeException
915
-     * @throws InvalidInterfaceException
916
-     * @throws InvalidClassException
917
-     * @throws InvalidFilePathException
918
-     */
919
-    private function _maybe_brew_regular()
920
-    {
921
-        /** @var Domain $domain */
922
-        $domain = DomainFactory::getShared(
923
-            new FullyQualifiedName(
924
-                'EventEspresso\core\domain\Domain'
925
-            ),
926
-            array(
927
-                new FilePath(EVENT_ESPRESSO_MAIN_FILE),
928
-                Version::fromString(espresso_version()),
929
-            )
930
-        );
931
-        if ($domain->isCaffeinated()) {
932
-            require_once EE_CAFF_PATH . 'brewing_regular.php';
933
-        }
934
-    }
935
-
936
-
937
-    /**
938
-     * @since 4.9.71.p
939
-     * @throws Exception
940
-     */
941
-    public function loadRouteMatchSpecifications()
942
-    {
943
-        try {
944
-            $this->loader->getShared(
945
-                'EventEspresso\core\services\route_match\RouteMatchSpecificationManager'
946
-            );
947
-        } catch (Exception $exception) {
948
-            new ExceptionStackTraceDisplay($exception);
949
-        }
950
-        do_action('AHEE__EE_System__loadRouteMatchSpecifications');
951
-    }
952
-
953
-
954
-    /**
955
-     * register_shortcodes_modules_and_widgets
956
-     * generate lists of shortcodes and modules, then verify paths and classes
957
-     * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
958
-     * which runs during the WP 'plugins_loaded' action at priority 7
959
-     *
960
-     * @access public
961
-     * @return void
962
-     * @throws Exception
963
-     */
964
-    public function register_shortcodes_modules_and_widgets()
965
-    {
966
-        if ($this->request->isFrontend() || $this->request->isIframe() || $this->request->isAjax()) {
967
-            try {
968
-                // load, register, and add shortcodes the new way
969
-                $this->loader->getShared(
970
-                    'EventEspresso\core\services\shortcodes\ShortcodesManager',
971
-                    array(
972
-                        // and the old way, but we'll put it under control of the new system
973
-                        EE_Config::getLegacyShortcodesManager(),
974
-                    )
975
-                );
976
-            } catch (Exception $exception) {
977
-                new ExceptionStackTraceDisplay($exception);
978
-            }
979
-        }
980
-        do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
981
-        // check for addons using old hook point
982
-        if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
983
-            $this->_incompatible_addon_error();
984
-        }
985
-    }
986
-
987
-
988
-    /**
989
-     * _incompatible_addon_error
990
-     *
991
-     * @access public
992
-     * @return void
993
-     */
994
-    private function _incompatible_addon_error()
995
-    {
996
-        // get array of classes hooking into here
997
-        $class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
998
-            'AHEE__EE_System__register_shortcodes_modules_and_addons'
999
-        );
1000
-        if (! empty($class_names)) {
1001
-            $msg = __(
1002
-                'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
1003
-                'event_espresso'
1004
-            );
1005
-            $msg .= '<ul>';
1006
-            foreach ($class_names as $class_name) {
1007
-                $msg .= '<li><b>Event Espresso - '
1008
-                        . str_replace(
1009
-                            array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'),
1010
-                            '',
1011
-                            $class_name
1012
-                        ) . '</b></li>';
1013
-            }
1014
-            $msg .= '</ul>';
1015
-            $msg .= __(
1016
-                'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
1017
-                'event_espresso'
1018
-            );
1019
-            // save list of incompatible addons to wp-options for later use
1020
-            add_option('ee_incompatible_addons', $class_names, '', 'no');
1021
-            if (is_admin()) {
1022
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1023
-            }
1024
-        }
1025
-    }
1026
-
1027
-
1028
-    /**
1029
-     * brew_espresso
1030
-     * begins the process of setting hooks for initializing EE in the correct order
1031
-     * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1032
-     * which runs during the WP 'plugins_loaded' action at priority 9
1033
-     *
1034
-     * @return void
1035
-     */
1036
-    public function brew_espresso()
1037
-    {
1038
-        do_action('AHEE__EE_System__brew_espresso__begin', $this);
1039
-        // load some final core systems
1040
-        add_action('init', array($this, 'set_hooks_for_core'), 1);
1041
-        add_action('init', array($this, 'perform_activations_upgrades_and_migrations'), 3);
1042
-        add_action('init', array($this, 'load_CPTs_and_session'), 5);
1043
-        add_action('init', array($this, 'load_controllers'), 7);
1044
-        add_action('init', array($this, 'core_loaded_and_ready'), 9);
1045
-        add_action('init', array($this, 'initialize'), 10);
1046
-        add_action('init', array($this, 'initialize_last'), 100);
1047
-        if (is_admin() && apply_filters('FHEE__EE_System__brew_espresso__load_pue', true)) {
1048
-            // pew pew pew
1049
-            $this->loader->getShared('EventEspresso\core\services\licensing\LicenseService');
1050
-            do_action('AHEE__EE_System__brew_espresso__after_pue_init');
1051
-        }
1052
-        do_action('AHEE__EE_System__brew_espresso__complete', $this);
1053
-    }
1054
-
1055
-
1056
-    /**
1057
-     *    set_hooks_for_core
1058
-     *
1059
-     * @access public
1060
-     * @return    void
1061
-     * @throws EE_Error
1062
-     */
1063
-    public function set_hooks_for_core()
1064
-    {
1065
-        $this->_deactivate_incompatible_addons();
1066
-        do_action('AHEE__EE_System__set_hooks_for_core');
1067
-        $this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1068
-        // caps need to be initialized on every request so that capability maps are set.
1069
-        // @see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1070
-        $this->registry->CAP->init_caps();
1071
-    }
1072
-
1073
-
1074
-    /**
1075
-     * Using the information gathered in EE_System::_incompatible_addon_error,
1076
-     * deactivates any addons considered incompatible with the current version of EE
1077
-     */
1078
-    private function _deactivate_incompatible_addons()
1079
-    {
1080
-        $incompatible_addons = get_option('ee_incompatible_addons', array());
1081
-        if (! empty($incompatible_addons)) {
1082
-            $active_plugins = get_option('active_plugins', array());
1083
-            foreach ($active_plugins as $active_plugin) {
1084
-                foreach ($incompatible_addons as $incompatible_addon) {
1085
-                    if (strpos($active_plugin, $incompatible_addon) !== false) {
1086
-                        unset($_GET['activate']);
1087
-                        espresso_deactivate_plugin($active_plugin);
1088
-                    }
1089
-                }
1090
-            }
1091
-        }
1092
-    }
1093
-
1094
-
1095
-    /**
1096
-     *    perform_activations_upgrades_and_migrations
1097
-     *
1098
-     * @access public
1099
-     * @return    void
1100
-     */
1101
-    public function perform_activations_upgrades_and_migrations()
1102
-    {
1103
-        do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1104
-    }
1105
-
1106
-
1107
-    /**
1108
-     * @return void
1109
-     * @throws DomainException
1110
-     */
1111
-    public function load_CPTs_and_session()
1112
-    {
1113
-        do_action('AHEE__EE_System__load_CPTs_and_session__start');
1114
-        /** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies $register_custom_taxonomies */
1115
-        $register_custom_taxonomies = $this->loader->getShared(
1116
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'
1117
-        );
1118
-        $register_custom_taxonomies->registerCustomTaxonomies();
1119
-        /** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes $register_custom_post_types */
1120
-        $register_custom_post_types = $this->loader->getShared(
1121
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'
1122
-        );
1123
-        $register_custom_post_types->registerCustomPostTypes();
1124
-        /** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms $register_custom_taxonomy_terms */
1125
-        $register_custom_taxonomy_terms = $this->loader->getShared(
1126
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms'
1127
-        );
1128
-        $register_custom_taxonomy_terms->registerCustomTaxonomyTerms();
1129
-        // load legacy Custom Post Types and Taxonomies
1130
-        $this->loader->getShared('EE_Register_CPTs');
1131
-        do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1132
-    }
1133
-
1134
-
1135
-    /**
1136
-     * load_controllers
1137
-     * this is the best place to load any additional controllers that needs access to EE core.
1138
-     * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1139
-     * time
1140
-     *
1141
-     * @access public
1142
-     * @return void
1143
-     */
1144
-    public function load_controllers()
1145
-    {
1146
-        do_action('AHEE__EE_System__load_controllers__start');
1147
-        // let's get it started
1148
-        if (! $this->maintenance_mode->level()
1149
-            && ($this->request->isFrontend() || $this->request->isFrontAjax())
1150
-        ) {
1151
-            do_action('AHEE__EE_System__load_controllers__load_front_controllers');
1152
-            $this->loader->getShared('EE_Front_Controller');
1153
-        } elseif ($this->request->isAdmin() || $this->request->isAdminAjax()) {
1154
-            do_action('AHEE__EE_System__load_controllers__load_admin_controllers');
1155
-            $this->loader->getShared('EE_Admin');
1156
-        } elseif ($this->request->isWordPressHeartbeat()) {
1157
-            $this->loader->getShared('EventEspresso\core\domain\services\admin\ajax\WordpressHeartbeat');
1158
-        }
1159
-        do_action('AHEE__EE_System__load_controllers__complete');
1160
-    }
1161
-
1162
-
1163
-    /**
1164
-     * core_loaded_and_ready
1165
-     * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1166
-     *
1167
-     * @access public
1168
-     * @return void
1169
-     * @throws Exception
1170
-     */
1171
-    public function core_loaded_and_ready()
1172
-    {
1173
-        if ($this->request->isAdmin()
1174
-            || $this->request->isFrontend()
1175
-            || $this->request->isIframe()
1176
-            || $this->request->isWordPressApi()
1177
-        ) {
1178
-            try {
1179
-                $this->loader->getShared('EventEspresso\core\services\assets\Registry');
1180
-                $this->loader->getShared('EventEspresso\core\domain\services\assets\CoreAssetManager');
1181
-                if ($this->canLoadBlocks()) {
1182
-                    $this->loader->getShared(
1183
-                        'EventEspresso\core\services\editor\BlockRegistrationManager'
1184
-                    );
1185
-                }
1186
-            } catch (Exception $exception) {
1187
-                new ExceptionStackTraceDisplay($exception);
1188
-            }
1189
-        }
1190
-        if ($this->request->isAdmin()
1191
-            || $this->request->isEeAjax()
1192
-            || $this->request->isFrontend()
1193
-        ) {
1194
-            $this->loader->getShared('EE_Session');
1195
-        }
1196
-        // integrate WP_Query with the EE models
1197
-        $this->loader->getShared('EE_CPT_Strategy');
1198
-        do_action('AHEE__EE_System__core_loaded_and_ready');
1199
-        // always load template tags, because it's faster than checking if it's a front-end request, and many page
1200
-        // builders require these even on the front-end
1201
-        require_once EE_PUBLIC . 'template_tags.php';
1202
-        do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1203
-    }
1204
-
1205
-
1206
-    /**
1207
-     * initialize
1208
-     * this is the best place to begin initializing client code
1209
-     *
1210
-     * @access public
1211
-     * @return void
1212
-     */
1213
-    public function initialize()
1214
-    {
1215
-        do_action('AHEE__EE_System__initialize');
1216
-    }
1217
-
1218
-
1219
-    /**
1220
-     * initialize_last
1221
-     * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1222
-     * initialize has done so
1223
-     *
1224
-     * @access public
1225
-     * @return void
1226
-     */
1227
-    public function initialize_last()
1228
-    {
1229
-        do_action('AHEE__EE_System__initialize_last');
1230
-        /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
1231
-        $rewrite_rules = $this->loader->getShared(
1232
-            'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
1233
-        );
1234
-        $rewrite_rules->flushRewriteRules();
1235
-        add_action('admin_bar_init', array($this, 'addEspressoToolbar'));
1236
-        if (($this->request->isAjax() || $this->request->isAdmin())
1237
-            && $this->maintenance_mode->models_can_query()) {
1238
-            $this->loader->getShared('EventEspresso\core\services\privacy\export\PersonalDataExporterManager');
1239
-            $this->loader->getShared('EventEspresso\core\services\privacy\erasure\PersonalDataEraserManager');
1240
-        }
1241
-    }
1242
-
1243
-
1244
-    /**
1245
-     * @return void
1246
-     * @throws EE_Error
1247
-     */
1248
-    public function addEspressoToolbar()
1249
-    {
1250
-        $this->loader->getShared(
1251
-            'EventEspresso\core\domain\services\admin\AdminToolBar',
1252
-            array($this->registry->CAP)
1253
-        );
1254
-    }
1255
-
1256
-
1257
-    /**
1258
-     * do_not_cache
1259
-     * sets no cache headers and defines no cache constants for WP plugins
1260
-     *
1261
-     * @access public
1262
-     * @return void
1263
-     */
1264
-    public static function do_not_cache()
1265
-    {
1266
-        // set no cache constants
1267
-        if (! defined('DONOTCACHEPAGE')) {
1268
-            define('DONOTCACHEPAGE', true);
1269
-        }
1270
-        if (! defined('DONOTCACHCEOBJECT')) {
1271
-            define('DONOTCACHCEOBJECT', true);
1272
-        }
1273
-        if (! defined('DONOTCACHEDB')) {
1274
-            define('DONOTCACHEDB', true);
1275
-        }
1276
-        // add no cache headers
1277
-        add_action('send_headers', array('EE_System', 'nocache_headers'), 10);
1278
-        // plus a little extra for nginx and Google Chrome
1279
-        add_filter('nocache_headers', array('EE_System', 'extra_nocache_headers'), 10, 1);
1280
-        // prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1281
-        remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1282
-    }
1283
-
1284
-
1285
-    /**
1286
-     *    extra_nocache_headers
1287
-     *
1288
-     * @access    public
1289
-     * @param $headers
1290
-     * @return    array
1291
-     */
1292
-    public static function extra_nocache_headers($headers)
1293
-    {
1294
-        // for NGINX
1295
-        $headers['X-Accel-Expires'] = 0;
1296
-        // plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1297
-        $headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1298
-        return $headers;
1299
-    }
1300
-
1301
-
1302
-    /**
1303
-     *    nocache_headers
1304
-     *
1305
-     * @access    public
1306
-     * @return    void
1307
-     */
1308
-    public static function nocache_headers()
1309
-    {
1310
-        nocache_headers();
1311
-    }
1312
-
1313
-
1314
-    /**
1315
-     * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1316
-     * never returned with the function.
1317
-     *
1318
-     * @param  array $exclude_array any existing pages being excluded are in this array.
1319
-     * @return array
1320
-     */
1321
-    public function remove_pages_from_wp_list_pages($exclude_array)
1322
-    {
1323
-        return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1324
-    }
1325
-
1326
-
1327
-    /**
1328
-     * Return whether blocks can be registered/loaded or not.
1329
-     * @return bool
1330
-     */
1331
-    private function canLoadBlocks()
1332
-    {
1333
-        return apply_filters('FHEE__EE_System__canLoadBlocks', true)
1334
-               && function_exists('register_block_type')
1335
-               // don't load blocks if in the Divi page builder editor context
1336
-               // @see https://github.com/eventespresso/event-espresso-core/issues/814
1337
-               && ! $this->request->getRequestParam('et_fb', false);
1338
-    }
30
+	/**
31
+	 * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
32
+	 * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
33
+	 */
34
+	const req_type_normal = 0;
35
+
36
+	/**
37
+	 * Indicates this is a brand new installation of EE so we should install
38
+	 * tables and default data etc
39
+	 */
40
+	const req_type_new_activation = 1;
41
+
42
+	/**
43
+	 * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
44
+	 * and we just exited maintenance mode). We MUST check the database is setup properly
45
+	 * and that default data is setup too
46
+	 */
47
+	const req_type_reactivation = 2;
48
+
49
+	/**
50
+	 * indicates that EE has been upgraded since its previous request.
51
+	 * We may have data migration scripts to call and will want to trigger maintenance mode
52
+	 */
53
+	const req_type_upgrade = 3;
54
+
55
+	/**
56
+	 * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
57
+	 */
58
+	const req_type_downgrade = 4;
59
+
60
+	/**
61
+	 * @deprecated since version 4.6.0.dev.006
62
+	 * Now whenever a new_activation is detected the request type is still just
63
+	 * new_activation (same for reactivation, upgrade, downgrade etc), but if we'r ein maintenance mode
64
+	 * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
65
+	 * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
66
+	 * (Specifically, when the migration manager indicates migrations are finished
67
+	 * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
68
+	 */
69
+	const req_type_activation_but_not_installed = 5;
70
+
71
+	/**
72
+	 * option prefix for recording the activation history (like core's "espresso_db_update") of addons
73
+	 */
74
+	const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
75
+
76
+	/**
77
+	 * @var EE_System $_instance
78
+	 */
79
+	private static $_instance;
80
+
81
+	/**
82
+	 * @var EE_Registry $registry
83
+	 */
84
+	private $registry;
85
+
86
+	/**
87
+	 * @var LoaderInterface $loader
88
+	 */
89
+	private $loader;
90
+
91
+	/**
92
+	 * @var EE_Capabilities $capabilities
93
+	 */
94
+	private $capabilities;
95
+
96
+	/**
97
+	 * @var RequestInterface $request
98
+	 */
99
+	private $request;
100
+
101
+	/**
102
+	 * @var EE_Maintenance_Mode $maintenance_mode
103
+	 */
104
+	private $maintenance_mode;
105
+
106
+	/**
107
+	 * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
108
+	 * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
109
+	 *
110
+	 * @var int $_req_type
111
+	 */
112
+	private $_req_type;
113
+
114
+	/**
115
+	 * Whether or not there was a non-micro version change in EE core version during this request
116
+	 *
117
+	 * @var boolean $_major_version_change
118
+	 */
119
+	private $_major_version_change = false;
120
+
121
+	/**
122
+	 * A Context DTO dedicated solely to identifying the current request type.
123
+	 *
124
+	 * @var RequestTypeContextCheckerInterface $request_type
125
+	 */
126
+	private $request_type;
127
+
128
+
129
+	/**
130
+	 * @singleton method used to instantiate class object
131
+	 * @param EE_Registry|null         $registry
132
+	 * @param LoaderInterface|null     $loader
133
+	 * @param RequestInterface|null    $request
134
+	 * @param EE_Maintenance_Mode|null $maintenance_mode
135
+	 * @return EE_System
136
+	 */
137
+	public static function instance(
138
+		EE_Registry $registry = null,
139
+		LoaderInterface $loader = null,
140
+		RequestInterface $request = null,
141
+		EE_Maintenance_Mode $maintenance_mode = null
142
+	) {
143
+		// check if class object is instantiated
144
+		if (! self::$_instance instanceof EE_System) {
145
+			self::$_instance = new self($registry, $loader, $request, $maintenance_mode);
146
+		}
147
+		return self::$_instance;
148
+	}
149
+
150
+
151
+	/**
152
+	 * resets the instance and returns it
153
+	 *
154
+	 * @return EE_System
155
+	 */
156
+	public static function reset()
157
+	{
158
+		self::$_instance->_req_type = null;
159
+		// make sure none of the old hooks are left hanging around
160
+		remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
161
+		// we need to reset the migration manager in order for it to detect DMSs properly
162
+		EE_Data_Migration_Manager::reset();
163
+		self::instance()->detect_activations_or_upgrades();
164
+		self::instance()->perform_activations_upgrades_and_migrations();
165
+		return self::instance();
166
+	}
167
+
168
+
169
+	/**
170
+	 * sets hooks for running rest of system
171
+	 * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
172
+	 * starting EE Addons from any other point may lead to problems
173
+	 *
174
+	 * @param EE_Registry         $registry
175
+	 * @param LoaderInterface     $loader
176
+	 * @param RequestInterface    $request
177
+	 * @param EE_Maintenance_Mode $maintenance_mode
178
+	 */
179
+	private function __construct(
180
+		EE_Registry $registry,
181
+		LoaderInterface $loader,
182
+		RequestInterface $request,
183
+		EE_Maintenance_Mode $maintenance_mode
184
+	) {
185
+		$this->registry = $registry;
186
+		$this->loader = $loader;
187
+		$this->request = $request;
188
+		$this->maintenance_mode = $maintenance_mode;
189
+		do_action('AHEE__EE_System__construct__begin', $this);
190
+		add_action(
191
+			'AHEE__EE_Bootstrap__load_espresso_addons',
192
+			array($this, 'loadCapabilities'),
193
+			5
194
+		);
195
+		add_action(
196
+			'AHEE__EE_Bootstrap__load_espresso_addons',
197
+			array($this, 'loadCommandBus'),
198
+			7
199
+		);
200
+		add_action(
201
+			'AHEE__EE_Bootstrap__load_espresso_addons',
202
+			array($this, 'loadPluginApi'),
203
+			9
204
+		);
205
+		// allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
206
+		add_action(
207
+			'AHEE__EE_Bootstrap__load_espresso_addons',
208
+			array($this, 'load_espresso_addons')
209
+		);
210
+		// when an ee addon is activated, we want to call the core hook(s) again
211
+		// because the newly-activated addon didn't get a chance to run at all
212
+		add_action('activate_plugin', array($this, 'load_espresso_addons'), 1);
213
+		// detect whether install or upgrade
214
+		add_action(
215
+			'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
216
+			array($this, 'detect_activations_or_upgrades'),
217
+			3
218
+		);
219
+		// load EE_Config, EE_Textdomain, etc
220
+		add_action(
221
+			'AHEE__EE_Bootstrap__load_core_configuration',
222
+			array($this, 'load_core_configuration'),
223
+			5
224
+		);
225
+		// load specifications for matching routes to current request
226
+		add_action(
227
+			'AHEE__EE_Bootstrap__load_core_configuration',
228
+			array($this, 'loadRouteMatchSpecifications')
229
+		);
230
+		// load EE_Config, EE_Textdomain, etc
231
+		add_action(
232
+			'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
233
+			array($this, 'register_shortcodes_modules_and_widgets'),
234
+			7
235
+		);
236
+		// you wanna get going? I wanna get going... let's get going!
237
+		add_action(
238
+			'AHEE__EE_Bootstrap__brew_espresso',
239
+			array($this, 'brew_espresso'),
240
+			9
241
+		);
242
+		// other housekeeping
243
+		// exclude EE critical pages from wp_list_pages
244
+		add_filter(
245
+			'wp_list_pages_excludes',
246
+			array($this, 'remove_pages_from_wp_list_pages'),
247
+			10
248
+		);
249
+		// ALL EE Addons should use the following hook point to attach their initial setup too
250
+		// it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
251
+		do_action('AHEE__EE_System__construct__complete', $this);
252
+	}
253
+
254
+
255
+	/**
256
+	 * load and setup EE_Capabilities
257
+	 *
258
+	 * @return void
259
+	 * @throws EE_Error
260
+	 */
261
+	public function loadCapabilities()
262
+	{
263
+		$this->capabilities = $this->loader->getShared('EE_Capabilities');
264
+		add_action(
265
+			'AHEE__EE_Capabilities__init_caps__before_initialization',
266
+			function () {
267
+				LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
268
+			}
269
+		);
270
+	}
271
+
272
+
273
+	/**
274
+	 * create and cache the CommandBus, and also add middleware
275
+	 * The CapChecker middleware requires the use of EE_Capabilities
276
+	 * which is why we need to load the CommandBus after Caps are set up
277
+	 *
278
+	 * @return void
279
+	 * @throws EE_Error
280
+	 */
281
+	public function loadCommandBus()
282
+	{
283
+		$this->loader->getShared(
284
+			'CommandBusInterface',
285
+			array(
286
+				null,
287
+				apply_filters(
288
+					'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
289
+					array(
290
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
291
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
292
+					)
293
+				),
294
+			)
295
+		);
296
+	}
297
+
298
+
299
+	/**
300
+	 * @return void
301
+	 * @throws EE_Error
302
+	 */
303
+	public function loadPluginApi()
304
+	{
305
+		// set autoloaders for all of the classes implementing EEI_Plugin_API
306
+		// which provide helpers for EE plugin authors to more easily register certain components with EE.
307
+		EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
308
+		$this->loader->getShared('EE_Request_Handler');
309
+	}
310
+
311
+
312
+	/**
313
+	 * @param string $addon_name
314
+	 * @param string $version_constant
315
+	 * @param string $min_version_required
316
+	 * @param string $load_callback
317
+	 * @param string $plugin_file_constant
318
+	 * @return void
319
+	 */
320
+	private function deactivateIncompatibleAddon(
321
+		$addon_name,
322
+		$version_constant,
323
+		$min_version_required,
324
+		$load_callback,
325
+		$plugin_file_constant
326
+	) {
327
+		if (! defined($version_constant)) {
328
+			return;
329
+		}
330
+		$addon_version = constant($version_constant);
331
+		if ($addon_version && version_compare($addon_version, $min_version_required, '<')) {
332
+			remove_action('AHEE__EE_System__load_espresso_addons', $load_callback);
333
+			if (! function_exists('deactivate_plugins')) {
334
+				require_once ABSPATH . 'wp-admin/includes/plugin.php';
335
+			}
336
+			deactivate_plugins(plugin_basename(constant($plugin_file_constant)));
337
+			unset($_GET['activate'], $_REQUEST['activate'], $_GET['activate-multi'], $_REQUEST['activate-multi']);
338
+			EE_Error::add_error(
339
+				sprintf(
340
+					esc_html__(
341
+						'We\'re sorry, but the Event Espresso %1$s addon was deactivated because version %2$s or higher is required with this version of Event Espresso core.',
342
+						'event_espresso'
343
+					),
344
+					$addon_name,
345
+					$min_version_required
346
+				),
347
+				__FILE__,
348
+				__FUNCTION__ . "({$addon_name})",
349
+				__LINE__
350
+			);
351
+			EE_Error::get_notices(false, true);
352
+		}
353
+	}
354
+
355
+
356
+	/**
357
+	 * load_espresso_addons
358
+	 * allow addons to load first so that they can set hooks for running DMS's, etc
359
+	 * this is hooked into both:
360
+	 *    'AHEE__EE_Bootstrap__load_core_configuration'
361
+	 *        which runs during the WP 'plugins_loaded' action at priority 5
362
+	 *    and the WP 'activate_plugin' hook point
363
+	 *
364
+	 * @access public
365
+	 * @return void
366
+	 */
367
+	public function load_espresso_addons()
368
+	{
369
+		$this->deactivateIncompatibleAddon(
370
+			'Wait Lists',
371
+			'EE_WAIT_LISTS_VERSION',
372
+			'1.0.0.beta.074',
373
+			'load_espresso_wait_lists',
374
+			'EE_WAIT_LISTS_PLUGIN_FILE'
375
+		);
376
+		$this->deactivateIncompatibleAddon(
377
+			'Automated Upcoming Event Notifications',
378
+			'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_VERSION',
379
+			'1.0.0.beta.091',
380
+			'load_espresso_automated_upcoming_event_notification',
381
+			'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_PLUGIN_FILE'
382
+		);
383
+		do_action('AHEE__EE_System__load_espresso_addons');
384
+		// if the WP API basic auth plugin isn't already loaded, load it now.
385
+		// We want it for mobile apps. Just include the entire plugin
386
+		// also, don't load the basic auth when a plugin is getting activated, because
387
+		// it could be the basic auth plugin, and it doesn't check if its methods are already defined
388
+		// and causes a fatal error
389
+		if (($this->request->isWordPressApi() || $this->request->isApi())
390
+			&& $this->request->getRequestParam('activate') !== 'true'
391
+			&& ! function_exists('json_basic_auth_handler')
392
+			&& ! function_exists('json_basic_auth_error')
393
+			&& ! in_array(
394
+				$this->request->getRequestParam('action'),
395
+				array('activate', 'activate-selected'),
396
+				true
397
+			)
398
+		) {
399
+			include_once EE_THIRD_PARTY . 'wp-api-basic-auth/basic-auth.php';
400
+		}
401
+		do_action('AHEE__EE_System__load_espresso_addons__complete');
402
+	}
403
+
404
+
405
+	/**
406
+	 * detect_activations_or_upgrades
407
+	 * Checks for activation or upgrade of core first;
408
+	 * then also checks if any registered addons have been activated or upgraded
409
+	 * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
410
+	 * which runs during the WP 'plugins_loaded' action at priority 3
411
+	 *
412
+	 * @access public
413
+	 * @return void
414
+	 */
415
+	public function detect_activations_or_upgrades()
416
+	{
417
+		// first off: let's make sure to handle core
418
+		$this->detect_if_activation_or_upgrade();
419
+		foreach ($this->registry->addons as $addon) {
420
+			if ($addon instanceof EE_Addon) {
421
+				// detect teh request type for that addon
422
+				$addon->detect_activation_or_upgrade();
423
+			}
424
+		}
425
+	}
426
+
427
+
428
+	/**
429
+	 * detect_if_activation_or_upgrade
430
+	 * Takes care of detecting whether this is a brand new install or code upgrade,
431
+	 * and either setting up the DB or setting up maintenance mode etc.
432
+	 *
433
+	 * @access public
434
+	 * @return void
435
+	 */
436
+	public function detect_if_activation_or_upgrade()
437
+	{
438
+		do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
439
+		// check if db has been updated, or if its a brand-new installation
440
+		$espresso_db_update = $this->fix_espresso_db_upgrade_option();
441
+		$request_type = $this->detect_req_type($espresso_db_update);
442
+		// EEH_Debug_Tools::printr( $request_type, '$request_type', __FILE__, __LINE__ );
443
+		switch ($request_type) {
444
+			case EE_System::req_type_new_activation:
445
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
446
+				$this->_handle_core_version_change($espresso_db_update);
447
+				break;
448
+			case EE_System::req_type_reactivation:
449
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
450
+				$this->_handle_core_version_change($espresso_db_update);
451
+				break;
452
+			case EE_System::req_type_upgrade:
453
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
454
+				// migrations may be required now that we've upgraded
455
+				$this->maintenance_mode->set_maintenance_mode_if_db_old();
456
+				$this->_handle_core_version_change($espresso_db_update);
457
+				break;
458
+			case EE_System::req_type_downgrade:
459
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
460
+				// its possible migrations are no longer required
461
+				$this->maintenance_mode->set_maintenance_mode_if_db_old();
462
+				$this->_handle_core_version_change($espresso_db_update);
463
+				break;
464
+			case EE_System::req_type_normal:
465
+			default:
466
+				break;
467
+		}
468
+		do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
469
+	}
470
+
471
+
472
+	/**
473
+	 * Updates the list of installed versions and sets hooks for
474
+	 * initializing the database later during the request
475
+	 *
476
+	 * @param array $espresso_db_update
477
+	 */
478
+	private function _handle_core_version_change($espresso_db_update)
479
+	{
480
+		$this->update_list_of_installed_versions($espresso_db_update);
481
+		// get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
482
+		add_action(
483
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
484
+			array($this, 'initialize_db_if_no_migrations_required')
485
+		);
486
+	}
487
+
488
+
489
+	/**
490
+	 * standardizes the wp option 'espresso_db_upgrade' which actually stores
491
+	 * information about what versions of EE have been installed and activated,
492
+	 * NOT necessarily the state of the database
493
+	 *
494
+	 * @param mixed $espresso_db_update           the value of the WordPress option.
495
+	 *                                            If not supplied, fetches it from the options table
496
+	 * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
497
+	 */
498
+	private function fix_espresso_db_upgrade_option($espresso_db_update = null)
499
+	{
500
+		do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
501
+		if (! $espresso_db_update) {
502
+			$espresso_db_update = get_option('espresso_db_update');
503
+		}
504
+		// check that option is an array
505
+		if (! is_array($espresso_db_update)) {
506
+			// if option is FALSE, then it never existed
507
+			if ($espresso_db_update === false) {
508
+				// make $espresso_db_update an array and save option with autoload OFF
509
+				$espresso_db_update = array();
510
+				add_option('espresso_db_update', $espresso_db_update, '', 'no');
511
+			} else {
512
+				// option is NOT FALSE but also is NOT an array, so make it an array and save it
513
+				$espresso_db_update = array($espresso_db_update => array());
514
+				update_option('espresso_db_update', $espresso_db_update);
515
+			}
516
+		} else {
517
+			$corrected_db_update = array();
518
+			// if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
519
+			foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
520
+				if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
521
+					// the key is an int, and the value IS NOT an array
522
+					// so it must be numerically-indexed, where values are versions installed...
523
+					// fix it!
524
+					$version_string = $should_be_array;
525
+					$corrected_db_update[ $version_string ] = array('unknown-date');
526
+				} else {
527
+					// ok it checks out
528
+					$corrected_db_update[ $should_be_version_string ] = $should_be_array;
529
+				}
530
+			}
531
+			$espresso_db_update = $corrected_db_update;
532
+			update_option('espresso_db_update', $espresso_db_update);
533
+		}
534
+		do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
535
+		return $espresso_db_update;
536
+	}
537
+
538
+
539
+	/**
540
+	 * Does the traditional work of setting up the plugin's database and adding default data.
541
+	 * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
542
+	 * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
543
+	 * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
544
+	 * so that it will be done when migrations are finished
545
+	 *
546
+	 * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
547
+	 * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
548
+	 *                                       This is a resource-intensive job
549
+	 *                                       so we prefer to only do it when necessary
550
+	 * @return void
551
+	 * @throws EE_Error
552
+	 */
553
+	public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
554
+	{
555
+		$request_type = $this->detect_req_type();
556
+		// only initialize system if we're not in maintenance mode.
557
+		if ($this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
558
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
559
+			$rewrite_rules = $this->loader->getShared(
560
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
561
+			);
562
+			$rewrite_rules->flush();
563
+			if ($verify_schema) {
564
+				EEH_Activation::initialize_db_and_folders();
565
+			}
566
+			EEH_Activation::initialize_db_content();
567
+			EEH_Activation::system_initialization();
568
+			if ($initialize_addons_too) {
569
+				$this->initialize_addons();
570
+			}
571
+		} else {
572
+			EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
573
+		}
574
+		if ($request_type === EE_System::req_type_new_activation
575
+			|| $request_type === EE_System::req_type_reactivation
576
+			|| (
577
+				$request_type === EE_System::req_type_upgrade
578
+				&& $this->is_major_version_change()
579
+			)
580
+		) {
581
+			add_action('AHEE__EE_System__initialize_last', array($this, 'redirect_to_about_ee'), 9);
582
+		}
583
+	}
584
+
585
+
586
+	/**
587
+	 * Initializes the db for all registered addons
588
+	 *
589
+	 * @throws EE_Error
590
+	 */
591
+	public function initialize_addons()
592
+	{
593
+		// foreach registered addon, make sure its db is up-to-date too
594
+		foreach ($this->registry->addons as $addon) {
595
+			if ($addon instanceof EE_Addon) {
596
+				$addon->initialize_db_if_no_migrations_required();
597
+			}
598
+		}
599
+	}
600
+
601
+
602
+	/**
603
+	 * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
604
+	 *
605
+	 * @param    array  $version_history
606
+	 * @param    string $current_version_to_add version to be added to the version history
607
+	 * @return    boolean success as to whether or not this option was changed
608
+	 */
609
+	public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
610
+	{
611
+		if (! $version_history) {
612
+			$version_history = $this->fix_espresso_db_upgrade_option($version_history);
613
+		}
614
+		if ($current_version_to_add === null) {
615
+			$current_version_to_add = espresso_version();
616
+		}
617
+		$version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
618
+		// re-save
619
+		return update_option('espresso_db_update', $version_history);
620
+	}
621
+
622
+
623
+	/**
624
+	 * Detects if the current version indicated in the has existed in the list of
625
+	 * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
626
+	 *
627
+	 * @param array $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
628
+	 *                                  If not supplied, fetches it from the options table.
629
+	 *                                  Also, caches its result so later parts of the code can also know whether
630
+	 *                                  there's been an update or not. This way we can add the current version to
631
+	 *                                  espresso_db_update, but still know if this is a new install or not
632
+	 * @return int one of the constants on EE_System::req_type_
633
+	 */
634
+	public function detect_req_type($espresso_db_update = null)
635
+	{
636
+		if ($this->_req_type === null) {
637
+			$espresso_db_update = ! empty($espresso_db_update)
638
+				? $espresso_db_update
639
+				: $this->fix_espresso_db_upgrade_option();
640
+			$this->_req_type = EE_System::detect_req_type_given_activation_history(
641
+				$espresso_db_update,
642
+				'ee_espresso_activation',
643
+				espresso_version()
644
+			);
645
+			$this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
646
+			$this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
647
+		}
648
+		return $this->_req_type;
649
+	}
650
+
651
+
652
+	/**
653
+	 * Returns whether or not there was a non-micro version change (ie, change in either
654
+	 * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
655
+	 * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
656
+	 *
657
+	 * @param $activation_history
658
+	 * @return bool
659
+	 */
660
+	private function _detect_major_version_change($activation_history)
661
+	{
662
+		$previous_version = EE_System::_get_most_recently_active_version_from_activation_history($activation_history);
663
+		$previous_version_parts = explode('.', $previous_version);
664
+		$current_version_parts = explode('.', espresso_version());
665
+		return isset($previous_version_parts[0], $previous_version_parts[1], $current_version_parts[0], $current_version_parts[1])
666
+			   && ($previous_version_parts[0] !== $current_version_parts[0]
667
+				   || $previous_version_parts[1] !== $current_version_parts[1]
668
+			   );
669
+	}
670
+
671
+
672
+	/**
673
+	 * Returns true if either the major or minor version of EE changed during this request.
674
+	 * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
675
+	 *
676
+	 * @return bool
677
+	 */
678
+	public function is_major_version_change()
679
+	{
680
+		return $this->_major_version_change;
681
+	}
682
+
683
+
684
+	/**
685
+	 * Determines the request type for any ee addon, given three piece of info: the current array of activation
686
+	 * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
687
+	 * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
688
+	 * just activated to (for core that will always be espresso_version())
689
+	 *
690
+	 * @param array  $activation_history_for_addon     the option's value which stores the activation history for this
691
+	 *                                                 ee plugin. for core that's 'espresso_db_update'
692
+	 * @param string $activation_indicator_option_name the name of the WordPress option that is temporarily set to
693
+	 *                                                 indicate that this plugin was just activated
694
+	 * @param string $version_to_upgrade_to            the version that was just upgraded to (for core that will be
695
+	 *                                                 espresso_version())
696
+	 * @return int one of the constants on EE_System::req_type_*
697
+	 */
698
+	public static function detect_req_type_given_activation_history(
699
+		$activation_history_for_addon,
700
+		$activation_indicator_option_name,
701
+		$version_to_upgrade_to
702
+	) {
703
+		$version_is_higher = self::_new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to);
704
+		if ($activation_history_for_addon) {
705
+			// it exists, so this isn't a completely new install
706
+			// check if this version already in that list of previously installed versions
707
+			if (! isset($activation_history_for_addon[ $version_to_upgrade_to ])) {
708
+				// it a version we haven't seen before
709
+				if ($version_is_higher === 1) {
710
+					$req_type = EE_System::req_type_upgrade;
711
+				} else {
712
+					$req_type = EE_System::req_type_downgrade;
713
+				}
714
+				delete_option($activation_indicator_option_name);
715
+			} else {
716
+				// its not an update. maybe a reactivation?
717
+				if (get_option($activation_indicator_option_name, false)) {
718
+					if ($version_is_higher === -1) {
719
+						$req_type = EE_System::req_type_downgrade;
720
+					} elseif ($version_is_higher === 0) {
721
+						// we've seen this version before, but it's an activation. must be a reactivation
722
+						$req_type = EE_System::req_type_reactivation;
723
+					} else {// $version_is_higher === 1
724
+						$req_type = EE_System::req_type_upgrade;
725
+					}
726
+					delete_option($activation_indicator_option_name);
727
+				} else {
728
+					// we've seen this version before and the activation indicate doesn't show it was just activated
729
+					if ($version_is_higher === -1) {
730
+						$req_type = EE_System::req_type_downgrade;
731
+					} elseif ($version_is_higher === 0) {
732
+						// we've seen this version before and it's not an activation. its normal request
733
+						$req_type = EE_System::req_type_normal;
734
+					} else {// $version_is_higher === 1
735
+						$req_type = EE_System::req_type_upgrade;
736
+					}
737
+				}
738
+			}
739
+		} else {
740
+			// brand new install
741
+			$req_type = EE_System::req_type_new_activation;
742
+			delete_option($activation_indicator_option_name);
743
+		}
744
+		return $req_type;
745
+	}
746
+
747
+
748
+	/**
749
+	 * Detects if the $version_to_upgrade_to is higher than the most recent version in
750
+	 * the $activation_history_for_addon
751
+	 *
752
+	 * @param array  $activation_history_for_addon (keys are versions, values are arrays of times activated,
753
+	 *                                             sometimes containing 'unknown-date'
754
+	 * @param string $version_to_upgrade_to        (current version)
755
+	 * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
756
+	 *                                             ie, -1 if $version_to_upgrade_to is LOWER (downgrade);
757
+	 *                                             0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
758
+	 *                                             1 if $version_to_upgrade_to is HIGHER (upgrade) ;
759
+	 */
760
+	private static function _new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to)
761
+	{
762
+		// find the most recently-activated version
763
+		$most_recently_active_version =
764
+			EE_System::_get_most_recently_active_version_from_activation_history($activation_history_for_addon);
765
+		return version_compare($version_to_upgrade_to, $most_recently_active_version);
766
+	}
767
+
768
+
769
+	/**
770
+	 * Gets the most recently active version listed in the activation history,
771
+	 * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
772
+	 *
773
+	 * @param array $activation_history  (keys are versions, values are arrays of times activated,
774
+	 *                                   sometimes containing 'unknown-date'
775
+	 * @return string
776
+	 */
777
+	private static function _get_most_recently_active_version_from_activation_history($activation_history)
778
+	{
779
+		$most_recently_active_version_activation = '1970-01-01 00:00:00';
780
+		$most_recently_active_version = '0.0.0.dev.000';
781
+		if (is_array($activation_history)) {
782
+			foreach ($activation_history as $version => $times_activated) {
783
+				// check there is a record of when this version was activated. Otherwise,
784
+				// mark it as unknown
785
+				if (! $times_activated) {
786
+					$times_activated = array('unknown-date');
787
+				}
788
+				if (is_string($times_activated)) {
789
+					$times_activated = array($times_activated);
790
+				}
791
+				foreach ($times_activated as $an_activation) {
792
+					if ($an_activation !== 'unknown-date'
793
+						&& $an_activation
794
+						   > $most_recently_active_version_activation) {
795
+						$most_recently_active_version = $version;
796
+						$most_recently_active_version_activation = $an_activation === 'unknown-date'
797
+							? '1970-01-01 00:00:00'
798
+							: $an_activation;
799
+					}
800
+				}
801
+			}
802
+		}
803
+		return $most_recently_active_version;
804
+	}
805
+
806
+
807
+	/**
808
+	 * This redirects to the about EE page after activation
809
+	 *
810
+	 * @return void
811
+	 */
812
+	public function redirect_to_about_ee()
813
+	{
814
+		$notices = EE_Error::get_notices(false);
815
+		// if current user is an admin and it's not an ajax or rest request
816
+		if (! isset($notices['errors'])
817
+			&& $this->request->isAdmin()
818
+			&& apply_filters(
819
+				'FHEE__EE_System__redirect_to_about_ee__do_redirect',
820
+				$this->capabilities->current_user_can('manage_options', 'espresso_about_default')
821
+			)
822
+		) {
823
+			$query_params = array('page' => 'espresso_about');
824
+			if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
825
+				$query_params['new_activation'] = true;
826
+			}
827
+			if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
828
+				$query_params['reactivation'] = true;
829
+			}
830
+			$url = add_query_arg($query_params, admin_url('admin.php'));
831
+			wp_safe_redirect($url);
832
+			exit();
833
+		}
834
+	}
835
+
836
+
837
+	/**
838
+	 * load_core_configuration
839
+	 * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
840
+	 * which runs during the WP 'plugins_loaded' action at priority 5
841
+	 *
842
+	 * @return void
843
+	 * @throws ReflectionException
844
+	 * @throws Exception
845
+	 */
846
+	public function load_core_configuration()
847
+	{
848
+		do_action('AHEE__EE_System__load_core_configuration__begin', $this);
849
+		$this->loader->getShared('EE_Load_Textdomain');
850
+		// load textdomain
851
+		EE_Load_Textdomain::load_textdomain();
852
+		// load caf stuff a chance to play during the activation process too.
853
+		$this->_maybe_brew_regular();
854
+		// load and setup EE_Config and EE_Network_Config
855
+		$config = $this->loader->getShared('EE_Config');
856
+		$this->loader->getShared('EE_Network_Config');
857
+		// setup autoloaders
858
+		// enable logging?
859
+		if ($config->admin->use_full_logging) {
860
+			$this->loader->getShared('EE_Log');
861
+		}
862
+		// check for activation errors
863
+		$activation_errors = get_option('ee_plugin_activation_errors', false);
864
+		if ($activation_errors) {
865
+			EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
866
+			update_option('ee_plugin_activation_errors', false);
867
+		}
868
+		// get model names
869
+		$this->_parse_model_names();
870
+		// configure custom post type definitions
871
+		$this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions');
872
+		$this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions');
873
+		do_action('AHEE__EE_System__load_core_configuration__complete', $this);
874
+	}
875
+
876
+
877
+	/**
878
+	 * cycles through all of the models/*.model.php files, and assembles an array of model names
879
+	 *
880
+	 * @return void
881
+	 * @throws ReflectionException
882
+	 */
883
+	private function _parse_model_names()
884
+	{
885
+		// get all the files in the EE_MODELS folder that end in .model.php
886
+		$models = glob(EE_MODELS . '*.model.php');
887
+		$model_names = array();
888
+		$non_abstract_db_models = array();
889
+		foreach ($models as $model) {
890
+			// get model classname
891
+			$classname = EEH_File::get_classname_from_filepath_with_standard_filename($model);
892
+			$short_name = str_replace('EEM_', '', $classname);
893
+			$reflectionClass = new ReflectionClass($classname);
894
+			if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
895
+				$non_abstract_db_models[ $short_name ] = $classname;
896
+			}
897
+			$model_names[ $short_name ] = $classname;
898
+		}
899
+		$this->registry->models = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
900
+		$this->registry->non_abstract_db_models = apply_filters(
901
+			'FHEE__EE_System__parse_implemented_model_names',
902
+			$non_abstract_db_models
903
+		);
904
+	}
905
+
906
+
907
+	/**
908
+	 * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
909
+	 * that need to be setup before our EE_System launches.
910
+	 *
911
+	 * @return void
912
+	 * @throws DomainException
913
+	 * @throws InvalidArgumentException
914
+	 * @throws InvalidDataTypeException
915
+	 * @throws InvalidInterfaceException
916
+	 * @throws InvalidClassException
917
+	 * @throws InvalidFilePathException
918
+	 */
919
+	private function _maybe_brew_regular()
920
+	{
921
+		/** @var Domain $domain */
922
+		$domain = DomainFactory::getShared(
923
+			new FullyQualifiedName(
924
+				'EventEspresso\core\domain\Domain'
925
+			),
926
+			array(
927
+				new FilePath(EVENT_ESPRESSO_MAIN_FILE),
928
+				Version::fromString(espresso_version()),
929
+			)
930
+		);
931
+		if ($domain->isCaffeinated()) {
932
+			require_once EE_CAFF_PATH . 'brewing_regular.php';
933
+		}
934
+	}
935
+
936
+
937
+	/**
938
+	 * @since 4.9.71.p
939
+	 * @throws Exception
940
+	 */
941
+	public function loadRouteMatchSpecifications()
942
+	{
943
+		try {
944
+			$this->loader->getShared(
945
+				'EventEspresso\core\services\route_match\RouteMatchSpecificationManager'
946
+			);
947
+		} catch (Exception $exception) {
948
+			new ExceptionStackTraceDisplay($exception);
949
+		}
950
+		do_action('AHEE__EE_System__loadRouteMatchSpecifications');
951
+	}
952
+
953
+
954
+	/**
955
+	 * register_shortcodes_modules_and_widgets
956
+	 * generate lists of shortcodes and modules, then verify paths and classes
957
+	 * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
958
+	 * which runs during the WP 'plugins_loaded' action at priority 7
959
+	 *
960
+	 * @access public
961
+	 * @return void
962
+	 * @throws Exception
963
+	 */
964
+	public function register_shortcodes_modules_and_widgets()
965
+	{
966
+		if ($this->request->isFrontend() || $this->request->isIframe() || $this->request->isAjax()) {
967
+			try {
968
+				// load, register, and add shortcodes the new way
969
+				$this->loader->getShared(
970
+					'EventEspresso\core\services\shortcodes\ShortcodesManager',
971
+					array(
972
+						// and the old way, but we'll put it under control of the new system
973
+						EE_Config::getLegacyShortcodesManager(),
974
+					)
975
+				);
976
+			} catch (Exception $exception) {
977
+				new ExceptionStackTraceDisplay($exception);
978
+			}
979
+		}
980
+		do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
981
+		// check for addons using old hook point
982
+		if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
983
+			$this->_incompatible_addon_error();
984
+		}
985
+	}
986
+
987
+
988
+	/**
989
+	 * _incompatible_addon_error
990
+	 *
991
+	 * @access public
992
+	 * @return void
993
+	 */
994
+	private function _incompatible_addon_error()
995
+	{
996
+		// get array of classes hooking into here
997
+		$class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
998
+			'AHEE__EE_System__register_shortcodes_modules_and_addons'
999
+		);
1000
+		if (! empty($class_names)) {
1001
+			$msg = __(
1002
+				'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
1003
+				'event_espresso'
1004
+			);
1005
+			$msg .= '<ul>';
1006
+			foreach ($class_names as $class_name) {
1007
+				$msg .= '<li><b>Event Espresso - '
1008
+						. str_replace(
1009
+							array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'),
1010
+							'',
1011
+							$class_name
1012
+						) . '</b></li>';
1013
+			}
1014
+			$msg .= '</ul>';
1015
+			$msg .= __(
1016
+				'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
1017
+				'event_espresso'
1018
+			);
1019
+			// save list of incompatible addons to wp-options for later use
1020
+			add_option('ee_incompatible_addons', $class_names, '', 'no');
1021
+			if (is_admin()) {
1022
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1023
+			}
1024
+		}
1025
+	}
1026
+
1027
+
1028
+	/**
1029
+	 * brew_espresso
1030
+	 * begins the process of setting hooks for initializing EE in the correct order
1031
+	 * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1032
+	 * which runs during the WP 'plugins_loaded' action at priority 9
1033
+	 *
1034
+	 * @return void
1035
+	 */
1036
+	public function brew_espresso()
1037
+	{
1038
+		do_action('AHEE__EE_System__brew_espresso__begin', $this);
1039
+		// load some final core systems
1040
+		add_action('init', array($this, 'set_hooks_for_core'), 1);
1041
+		add_action('init', array($this, 'perform_activations_upgrades_and_migrations'), 3);
1042
+		add_action('init', array($this, 'load_CPTs_and_session'), 5);
1043
+		add_action('init', array($this, 'load_controllers'), 7);
1044
+		add_action('init', array($this, 'core_loaded_and_ready'), 9);
1045
+		add_action('init', array($this, 'initialize'), 10);
1046
+		add_action('init', array($this, 'initialize_last'), 100);
1047
+		if (is_admin() && apply_filters('FHEE__EE_System__brew_espresso__load_pue', true)) {
1048
+			// pew pew pew
1049
+			$this->loader->getShared('EventEspresso\core\services\licensing\LicenseService');
1050
+			do_action('AHEE__EE_System__brew_espresso__after_pue_init');
1051
+		}
1052
+		do_action('AHEE__EE_System__brew_espresso__complete', $this);
1053
+	}
1054
+
1055
+
1056
+	/**
1057
+	 *    set_hooks_for_core
1058
+	 *
1059
+	 * @access public
1060
+	 * @return    void
1061
+	 * @throws EE_Error
1062
+	 */
1063
+	public function set_hooks_for_core()
1064
+	{
1065
+		$this->_deactivate_incompatible_addons();
1066
+		do_action('AHEE__EE_System__set_hooks_for_core');
1067
+		$this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1068
+		// caps need to be initialized on every request so that capability maps are set.
1069
+		// @see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1070
+		$this->registry->CAP->init_caps();
1071
+	}
1072
+
1073
+
1074
+	/**
1075
+	 * Using the information gathered in EE_System::_incompatible_addon_error,
1076
+	 * deactivates any addons considered incompatible with the current version of EE
1077
+	 */
1078
+	private function _deactivate_incompatible_addons()
1079
+	{
1080
+		$incompatible_addons = get_option('ee_incompatible_addons', array());
1081
+		if (! empty($incompatible_addons)) {
1082
+			$active_plugins = get_option('active_plugins', array());
1083
+			foreach ($active_plugins as $active_plugin) {
1084
+				foreach ($incompatible_addons as $incompatible_addon) {
1085
+					if (strpos($active_plugin, $incompatible_addon) !== false) {
1086
+						unset($_GET['activate']);
1087
+						espresso_deactivate_plugin($active_plugin);
1088
+					}
1089
+				}
1090
+			}
1091
+		}
1092
+	}
1093
+
1094
+
1095
+	/**
1096
+	 *    perform_activations_upgrades_and_migrations
1097
+	 *
1098
+	 * @access public
1099
+	 * @return    void
1100
+	 */
1101
+	public function perform_activations_upgrades_and_migrations()
1102
+	{
1103
+		do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1104
+	}
1105
+
1106
+
1107
+	/**
1108
+	 * @return void
1109
+	 * @throws DomainException
1110
+	 */
1111
+	public function load_CPTs_and_session()
1112
+	{
1113
+		do_action('AHEE__EE_System__load_CPTs_and_session__start');
1114
+		/** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies $register_custom_taxonomies */
1115
+		$register_custom_taxonomies = $this->loader->getShared(
1116
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'
1117
+		);
1118
+		$register_custom_taxonomies->registerCustomTaxonomies();
1119
+		/** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes $register_custom_post_types */
1120
+		$register_custom_post_types = $this->loader->getShared(
1121
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'
1122
+		);
1123
+		$register_custom_post_types->registerCustomPostTypes();
1124
+		/** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms $register_custom_taxonomy_terms */
1125
+		$register_custom_taxonomy_terms = $this->loader->getShared(
1126
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms'
1127
+		);
1128
+		$register_custom_taxonomy_terms->registerCustomTaxonomyTerms();
1129
+		// load legacy Custom Post Types and Taxonomies
1130
+		$this->loader->getShared('EE_Register_CPTs');
1131
+		do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1132
+	}
1133
+
1134
+
1135
+	/**
1136
+	 * load_controllers
1137
+	 * this is the best place to load any additional controllers that needs access to EE core.
1138
+	 * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1139
+	 * time
1140
+	 *
1141
+	 * @access public
1142
+	 * @return void
1143
+	 */
1144
+	public function load_controllers()
1145
+	{
1146
+		do_action('AHEE__EE_System__load_controllers__start');
1147
+		// let's get it started
1148
+		if (! $this->maintenance_mode->level()
1149
+			&& ($this->request->isFrontend() || $this->request->isFrontAjax())
1150
+		) {
1151
+			do_action('AHEE__EE_System__load_controllers__load_front_controllers');
1152
+			$this->loader->getShared('EE_Front_Controller');
1153
+		} elseif ($this->request->isAdmin() || $this->request->isAdminAjax()) {
1154
+			do_action('AHEE__EE_System__load_controllers__load_admin_controllers');
1155
+			$this->loader->getShared('EE_Admin');
1156
+		} elseif ($this->request->isWordPressHeartbeat()) {
1157
+			$this->loader->getShared('EventEspresso\core\domain\services\admin\ajax\WordpressHeartbeat');
1158
+		}
1159
+		do_action('AHEE__EE_System__load_controllers__complete');
1160
+	}
1161
+
1162
+
1163
+	/**
1164
+	 * core_loaded_and_ready
1165
+	 * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1166
+	 *
1167
+	 * @access public
1168
+	 * @return void
1169
+	 * @throws Exception
1170
+	 */
1171
+	public function core_loaded_and_ready()
1172
+	{
1173
+		if ($this->request->isAdmin()
1174
+			|| $this->request->isFrontend()
1175
+			|| $this->request->isIframe()
1176
+			|| $this->request->isWordPressApi()
1177
+		) {
1178
+			try {
1179
+				$this->loader->getShared('EventEspresso\core\services\assets\Registry');
1180
+				$this->loader->getShared('EventEspresso\core\domain\services\assets\CoreAssetManager');
1181
+				if ($this->canLoadBlocks()) {
1182
+					$this->loader->getShared(
1183
+						'EventEspresso\core\services\editor\BlockRegistrationManager'
1184
+					);
1185
+				}
1186
+			} catch (Exception $exception) {
1187
+				new ExceptionStackTraceDisplay($exception);
1188
+			}
1189
+		}
1190
+		if ($this->request->isAdmin()
1191
+			|| $this->request->isEeAjax()
1192
+			|| $this->request->isFrontend()
1193
+		) {
1194
+			$this->loader->getShared('EE_Session');
1195
+		}
1196
+		// integrate WP_Query with the EE models
1197
+		$this->loader->getShared('EE_CPT_Strategy');
1198
+		do_action('AHEE__EE_System__core_loaded_and_ready');
1199
+		// always load template tags, because it's faster than checking if it's a front-end request, and many page
1200
+		// builders require these even on the front-end
1201
+		require_once EE_PUBLIC . 'template_tags.php';
1202
+		do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1203
+	}
1204
+
1205
+
1206
+	/**
1207
+	 * initialize
1208
+	 * this is the best place to begin initializing client code
1209
+	 *
1210
+	 * @access public
1211
+	 * @return void
1212
+	 */
1213
+	public function initialize()
1214
+	{
1215
+		do_action('AHEE__EE_System__initialize');
1216
+	}
1217
+
1218
+
1219
+	/**
1220
+	 * initialize_last
1221
+	 * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1222
+	 * initialize has done so
1223
+	 *
1224
+	 * @access public
1225
+	 * @return void
1226
+	 */
1227
+	public function initialize_last()
1228
+	{
1229
+		do_action('AHEE__EE_System__initialize_last');
1230
+		/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
1231
+		$rewrite_rules = $this->loader->getShared(
1232
+			'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
1233
+		);
1234
+		$rewrite_rules->flushRewriteRules();
1235
+		add_action('admin_bar_init', array($this, 'addEspressoToolbar'));
1236
+		if (($this->request->isAjax() || $this->request->isAdmin())
1237
+			&& $this->maintenance_mode->models_can_query()) {
1238
+			$this->loader->getShared('EventEspresso\core\services\privacy\export\PersonalDataExporterManager');
1239
+			$this->loader->getShared('EventEspresso\core\services\privacy\erasure\PersonalDataEraserManager');
1240
+		}
1241
+	}
1242
+
1243
+
1244
+	/**
1245
+	 * @return void
1246
+	 * @throws EE_Error
1247
+	 */
1248
+	public function addEspressoToolbar()
1249
+	{
1250
+		$this->loader->getShared(
1251
+			'EventEspresso\core\domain\services\admin\AdminToolBar',
1252
+			array($this->registry->CAP)
1253
+		);
1254
+	}
1255
+
1256
+
1257
+	/**
1258
+	 * do_not_cache
1259
+	 * sets no cache headers and defines no cache constants for WP plugins
1260
+	 *
1261
+	 * @access public
1262
+	 * @return void
1263
+	 */
1264
+	public static function do_not_cache()
1265
+	{
1266
+		// set no cache constants
1267
+		if (! defined('DONOTCACHEPAGE')) {
1268
+			define('DONOTCACHEPAGE', true);
1269
+		}
1270
+		if (! defined('DONOTCACHCEOBJECT')) {
1271
+			define('DONOTCACHCEOBJECT', true);
1272
+		}
1273
+		if (! defined('DONOTCACHEDB')) {
1274
+			define('DONOTCACHEDB', true);
1275
+		}
1276
+		// add no cache headers
1277
+		add_action('send_headers', array('EE_System', 'nocache_headers'), 10);
1278
+		// plus a little extra for nginx and Google Chrome
1279
+		add_filter('nocache_headers', array('EE_System', 'extra_nocache_headers'), 10, 1);
1280
+		// prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1281
+		remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1282
+	}
1283
+
1284
+
1285
+	/**
1286
+	 *    extra_nocache_headers
1287
+	 *
1288
+	 * @access    public
1289
+	 * @param $headers
1290
+	 * @return    array
1291
+	 */
1292
+	public static function extra_nocache_headers($headers)
1293
+	{
1294
+		// for NGINX
1295
+		$headers['X-Accel-Expires'] = 0;
1296
+		// plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1297
+		$headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1298
+		return $headers;
1299
+	}
1300
+
1301
+
1302
+	/**
1303
+	 *    nocache_headers
1304
+	 *
1305
+	 * @access    public
1306
+	 * @return    void
1307
+	 */
1308
+	public static function nocache_headers()
1309
+	{
1310
+		nocache_headers();
1311
+	}
1312
+
1313
+
1314
+	/**
1315
+	 * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1316
+	 * never returned with the function.
1317
+	 *
1318
+	 * @param  array $exclude_array any existing pages being excluded are in this array.
1319
+	 * @return array
1320
+	 */
1321
+	public function remove_pages_from_wp_list_pages($exclude_array)
1322
+	{
1323
+		return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1324
+	}
1325
+
1326
+
1327
+	/**
1328
+	 * Return whether blocks can be registered/loaded or not.
1329
+	 * @return bool
1330
+	 */
1331
+	private function canLoadBlocks()
1332
+	{
1333
+		return apply_filters('FHEE__EE_System__canLoadBlocks', true)
1334
+			   && function_exists('register_block_type')
1335
+			   // don't load blocks if in the Divi page builder editor context
1336
+			   // @see https://github.com/eventespresso/event-espresso-core/issues/814
1337
+			   && ! $this->request->getRequestParam('et_fb', false);
1338
+	}
1339 1339
 }
Please login to merge, or discard this patch.
Spacing   +29 added lines, -29 removed lines patch added patch discarded remove patch
@@ -141,7 +141,7 @@  discard block
 block discarded – undo
141 141
         EE_Maintenance_Mode $maintenance_mode = null
142 142
     ) {
143 143
         // check if class object is instantiated
144
-        if (! self::$_instance instanceof EE_System) {
144
+        if ( ! self::$_instance instanceof EE_System) {
145 145
             self::$_instance = new self($registry, $loader, $request, $maintenance_mode);
146 146
         }
147 147
         return self::$_instance;
@@ -263,7 +263,7 @@  discard block
 block discarded – undo
263 263
         $this->capabilities = $this->loader->getShared('EE_Capabilities');
264 264
         add_action(
265 265
             'AHEE__EE_Capabilities__init_caps__before_initialization',
266
-            function () {
266
+            function() {
267 267
                 LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
268 268
             }
269 269
         );
@@ -304,7 +304,7 @@  discard block
 block discarded – undo
304 304
     {
305 305
         // set autoloaders for all of the classes implementing EEI_Plugin_API
306 306
         // which provide helpers for EE plugin authors to more easily register certain components with EE.
307
-        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
307
+        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES.'plugin_api');
308 308
         $this->loader->getShared('EE_Request_Handler');
309 309
     }
310 310
 
@@ -324,14 +324,14 @@  discard block
 block discarded – undo
324 324
         $load_callback,
325 325
         $plugin_file_constant
326 326
     ) {
327
-        if (! defined($version_constant)) {
327
+        if ( ! defined($version_constant)) {
328 328
             return;
329 329
         }
330 330
         $addon_version = constant($version_constant);
331 331
         if ($addon_version && version_compare($addon_version, $min_version_required, '<')) {
332 332
             remove_action('AHEE__EE_System__load_espresso_addons', $load_callback);
333
-            if (! function_exists('deactivate_plugins')) {
334
-                require_once ABSPATH . 'wp-admin/includes/plugin.php';
333
+            if ( ! function_exists('deactivate_plugins')) {
334
+                require_once ABSPATH.'wp-admin/includes/plugin.php';
335 335
             }
336 336
             deactivate_plugins(plugin_basename(constant($plugin_file_constant)));
337 337
             unset($_GET['activate'], $_REQUEST['activate'], $_GET['activate-multi'], $_REQUEST['activate-multi']);
@@ -345,7 +345,7 @@  discard block
 block discarded – undo
345 345
                     $min_version_required
346 346
                 ),
347 347
                 __FILE__,
348
-                __FUNCTION__ . "({$addon_name})",
348
+                __FUNCTION__."({$addon_name})",
349 349
                 __LINE__
350 350
             );
351 351
             EE_Error::get_notices(false, true);
@@ -396,7 +396,7 @@  discard block
 block discarded – undo
396 396
                 true
397 397
             )
398 398
         ) {
399
-            include_once EE_THIRD_PARTY . 'wp-api-basic-auth/basic-auth.php';
399
+            include_once EE_THIRD_PARTY.'wp-api-basic-auth/basic-auth.php';
400 400
         }
401 401
         do_action('AHEE__EE_System__load_espresso_addons__complete');
402 402
     }
@@ -498,11 +498,11 @@  discard block
 block discarded – undo
498 498
     private function fix_espresso_db_upgrade_option($espresso_db_update = null)
499 499
     {
500 500
         do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
501
-        if (! $espresso_db_update) {
501
+        if ( ! $espresso_db_update) {
502 502
             $espresso_db_update = get_option('espresso_db_update');
503 503
         }
504 504
         // check that option is an array
505
-        if (! is_array($espresso_db_update)) {
505
+        if ( ! is_array($espresso_db_update)) {
506 506
             // if option is FALSE, then it never existed
507 507
             if ($espresso_db_update === false) {
508 508
                 // make $espresso_db_update an array and save option with autoload OFF
@@ -522,10 +522,10 @@  discard block
 block discarded – undo
522 522
                     // so it must be numerically-indexed, where values are versions installed...
523 523
                     // fix it!
524 524
                     $version_string = $should_be_array;
525
-                    $corrected_db_update[ $version_string ] = array('unknown-date');
525
+                    $corrected_db_update[$version_string] = array('unknown-date');
526 526
                 } else {
527 527
                     // ok it checks out
528
-                    $corrected_db_update[ $should_be_version_string ] = $should_be_array;
528
+                    $corrected_db_update[$should_be_version_string] = $should_be_array;
529 529
                 }
530 530
             }
531 531
             $espresso_db_update = $corrected_db_update;
@@ -608,13 +608,13 @@  discard block
 block discarded – undo
608 608
      */
609 609
     public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
610 610
     {
611
-        if (! $version_history) {
611
+        if ( ! $version_history) {
612 612
             $version_history = $this->fix_espresso_db_upgrade_option($version_history);
613 613
         }
614 614
         if ($current_version_to_add === null) {
615 615
             $current_version_to_add = espresso_version();
616 616
         }
617
-        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
617
+        $version_history[$current_version_to_add][] = date('Y-m-d H:i:s', time());
618 618
         // re-save
619 619
         return update_option('espresso_db_update', $version_history);
620 620
     }
@@ -704,7 +704,7 @@  discard block
 block discarded – undo
704 704
         if ($activation_history_for_addon) {
705 705
             // it exists, so this isn't a completely new install
706 706
             // check if this version already in that list of previously installed versions
707
-            if (! isset($activation_history_for_addon[ $version_to_upgrade_to ])) {
707
+            if ( ! isset($activation_history_for_addon[$version_to_upgrade_to])) {
708 708
                 // it a version we haven't seen before
709 709
                 if ($version_is_higher === 1) {
710 710
                     $req_type = EE_System::req_type_upgrade;
@@ -782,7 +782,7 @@  discard block
 block discarded – undo
782 782
             foreach ($activation_history as $version => $times_activated) {
783 783
                 // check there is a record of when this version was activated. Otherwise,
784 784
                 // mark it as unknown
785
-                if (! $times_activated) {
785
+                if ( ! $times_activated) {
786 786
                     $times_activated = array('unknown-date');
787 787
                 }
788 788
                 if (is_string($times_activated)) {
@@ -813,7 +813,7 @@  discard block
 block discarded – undo
813 813
     {
814 814
         $notices = EE_Error::get_notices(false);
815 815
         // if current user is an admin and it's not an ajax or rest request
816
-        if (! isset($notices['errors'])
816
+        if ( ! isset($notices['errors'])
817 817
             && $this->request->isAdmin()
818 818
             && apply_filters(
819 819
                 'FHEE__EE_System__redirect_to_about_ee__do_redirect',
@@ -883,7 +883,7 @@  discard block
 block discarded – undo
883 883
     private function _parse_model_names()
884 884
     {
885 885
         // get all the files in the EE_MODELS folder that end in .model.php
886
-        $models = glob(EE_MODELS . '*.model.php');
886
+        $models = glob(EE_MODELS.'*.model.php');
887 887
         $model_names = array();
888 888
         $non_abstract_db_models = array();
889 889
         foreach ($models as $model) {
@@ -892,9 +892,9 @@  discard block
 block discarded – undo
892 892
             $short_name = str_replace('EEM_', '', $classname);
893 893
             $reflectionClass = new ReflectionClass($classname);
894 894
             if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
895
-                $non_abstract_db_models[ $short_name ] = $classname;
895
+                $non_abstract_db_models[$short_name] = $classname;
896 896
             }
897
-            $model_names[ $short_name ] = $classname;
897
+            $model_names[$short_name] = $classname;
898 898
         }
899 899
         $this->registry->models = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
900 900
         $this->registry->non_abstract_db_models = apply_filters(
@@ -929,7 +929,7 @@  discard block
 block discarded – undo
929 929
             )
930 930
         );
931 931
         if ($domain->isCaffeinated()) {
932
-            require_once EE_CAFF_PATH . 'brewing_regular.php';
932
+            require_once EE_CAFF_PATH.'brewing_regular.php';
933 933
         }
934 934
     }
935 935
 
@@ -997,7 +997,7 @@  discard block
 block discarded – undo
997 997
         $class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
998 998
             'AHEE__EE_System__register_shortcodes_modules_and_addons'
999 999
         );
1000
-        if (! empty($class_names)) {
1000
+        if ( ! empty($class_names)) {
1001 1001
             $msg = __(
1002 1002
                 'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
1003 1003
                 'event_espresso'
@@ -1009,7 +1009,7 @@  discard block
 block discarded – undo
1009 1009
                             array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'),
1010 1010
                             '',
1011 1011
                             $class_name
1012
-                        ) . '</b></li>';
1012
+                        ).'</b></li>';
1013 1013
             }
1014 1014
             $msg .= '</ul>';
1015 1015
             $msg .= __(
@@ -1078,7 +1078,7 @@  discard block
 block discarded – undo
1078 1078
     private function _deactivate_incompatible_addons()
1079 1079
     {
1080 1080
         $incompatible_addons = get_option('ee_incompatible_addons', array());
1081
-        if (! empty($incompatible_addons)) {
1081
+        if ( ! empty($incompatible_addons)) {
1082 1082
             $active_plugins = get_option('active_plugins', array());
1083 1083
             foreach ($active_plugins as $active_plugin) {
1084 1084
                 foreach ($incompatible_addons as $incompatible_addon) {
@@ -1145,7 +1145,7 @@  discard block
 block discarded – undo
1145 1145
     {
1146 1146
         do_action('AHEE__EE_System__load_controllers__start');
1147 1147
         // let's get it started
1148
-        if (! $this->maintenance_mode->level()
1148
+        if ( ! $this->maintenance_mode->level()
1149 1149
             && ($this->request->isFrontend() || $this->request->isFrontAjax())
1150 1150
         ) {
1151 1151
             do_action('AHEE__EE_System__load_controllers__load_front_controllers');
@@ -1198,7 +1198,7 @@  discard block
 block discarded – undo
1198 1198
         do_action('AHEE__EE_System__core_loaded_and_ready');
1199 1199
         // always load template tags, because it's faster than checking if it's a front-end request, and many page
1200 1200
         // builders require these even on the front-end
1201
-        require_once EE_PUBLIC . 'template_tags.php';
1201
+        require_once EE_PUBLIC.'template_tags.php';
1202 1202
         do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1203 1203
     }
1204 1204
 
@@ -1264,13 +1264,13 @@  discard block
 block discarded – undo
1264 1264
     public static function do_not_cache()
1265 1265
     {
1266 1266
         // set no cache constants
1267
-        if (! defined('DONOTCACHEPAGE')) {
1267
+        if ( ! defined('DONOTCACHEPAGE')) {
1268 1268
             define('DONOTCACHEPAGE', true);
1269 1269
         }
1270
-        if (! defined('DONOTCACHCEOBJECT')) {
1270
+        if ( ! defined('DONOTCACHCEOBJECT')) {
1271 1271
             define('DONOTCACHCEOBJECT', true);
1272 1272
         }
1273
-        if (! defined('DONOTCACHEDB')) {
1273
+        if ( ! defined('DONOTCACHEDB')) {
1274 1274
             define('DONOTCACHEDB', true);
1275 1275
         }
1276 1276
         // add no cache headers
Please login to merge, or discard this patch.
modules/thank_you_page/EED_Thank_You_Page.module.php 2 patches
Indentation   +785 added lines, -785 removed lines patch added patch discarded remove patch
@@ -10,609 +10,609 @@  discard block
 block discarded – undo
10 10
 class EED_Thank_You_Page extends EED_Module
11 11
 {
12 12
 
13
-    /**
14
-     * time in seconds to wait for the IPN to arrive before telling the registrant to bugger off ( 1200s = 20 minutes )
15
-     */
16
-    const IPN_wait_time = 1200;
17
-
18
-    /**
19
-     * The transaction specified by the reg_url_link passed from the Request, or from the Session
20
-     *
21
-     * @var EE_Transaction $_current_txn
22
-     */
23
-    private $_current_txn;
24
-
25
-    /**
26
-     * @var EE_Registration $_primary_registrant
27
-     */
28
-    private $_primary_registrant;
29
-
30
-    /**
31
-     * The reg_url_link passed from the Request, or from the Session
32
-     *
33
-     * @var string $_reg_url_link
34
-     */
35
-    private $_reg_url_link;
36
-
37
-    /**
38
-     * whether the incoming reg_url_link is for the primary registrant or not
39
-     *
40
-     * @var boolean $_is_primary
41
-     */
42
-    private $_is_primary;
43
-
44
-    /**
45
-     * The URL for revisiting the SPCO attendee information step
46
-     *
47
-     * @var string $_SPCO_attendee_information_url
48
-     */
49
-    private $_SPCO_attendee_information_url;
50
-
51
-    /**
52
-     * The URL for revisiting the SPCO payment options step
53
-     *
54
-     * @var string $_SPCO_payment_options_url
55
-     */
56
-    private $_SPCO_payment_options_url;
57
-
58
-    /**
59
-     * whether to display the Payment Options link
60
-     *
61
-     * @var boolean $_show_try_pay_again_link
62
-     */
63
-    private $_show_try_pay_again_link = false;
64
-
65
-    /**
66
-     * whether payments are allowed at this time
67
-     *
68
-     * @var boolean $_payments_closed
69
-     */
70
-    private $_payments_closed = false;
71
-
72
-    /**
73
-     * whether the selected payment method is Bank, Check , Invoice, etc
74
-     *
75
-     * @var boolean $_is_offline_payment_method
76
-     */
77
-    private $_is_offline_payment_method = true;
78
-
79
-
80
-    /**
81
-     * @return EED_Module|EED_Thank_You_Page
82
-     */
83
-    public static function instance()
84
-    {
85
-        return parent::get_instance(__CLASS__);
86
-    }
87
-
88
-
89
-    /**
90
-     * set_hooks - for hooking into EE Core, modules, etc
91
-     *
92
-     * @return void
93
-     */
94
-    public static function set_hooks()
95
-    {
96
-        add_action('wp_loaded', array('EED_Thank_You_Page', 'set_definitions'), 2);
97
-    }
98
-
99
-
100
-    /**
101
-     * set_hooks_admin - for hooking into EE Admin Core, modules, etc
102
-     *
103
-     * @return void
104
-     */
105
-    public static function set_hooks_admin()
106
-    {
107
-        add_action(
108
-            'wp_ajax_espresso_resend_reg_confirmation_email',
109
-            array('EED_Thank_You_Page', 'resend_reg_confirmation_email'),
110
-            10,
111
-            2
112
-        );
113
-        add_action(
114
-            'wp_ajax_nopriv_espresso_resend_reg_confirmation_email',
115
-            array('EED_Thank_You_Page', 'resend_reg_confirmation_email'),
116
-            10,
117
-            2
118
-        );
119
-    }
120
-
121
-
122
-    /**
123
-     * set_definitions
124
-     *
125
-     * @return void
126
-     */
127
-    public static function set_definitions()
128
-    {
129
-        define('THANK_YOU_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets/');
130
-        define('THANK_YOU_TEMPLATES_PATH', str_replace('\\', '/', plugin_dir_path(__FILE__)) . 'templates/');
131
-    }
132
-
133
-
134
-    /**
135
-     * get_txn
136
-     *
137
-     * @return EE_Transaction
138
-     */
139
-    public function get_txn()
140
-    {
141
-        if ($this->_current_txn instanceof EE_Transaction) {
142
-            return $this->_current_txn;
143
-        }
144
-        $TXN_model = EE_Registry::instance()->load_model('Transaction');
145
-        if (! $TXN_model instanceof EEM_Transaction) {
146
-            EE_Error::add_error(
147
-                __('The transaction model could not be established.', 'event_espresso'),
148
-                __FILE__,
149
-                __FUNCTION__,
150
-                __LINE__
151
-            );
152
-            return null;
153
-        }
154
-        // get the transaction. yes, we may have just loaded it, but it may have been updated, or this may be via an ajax request
155
-        $this->_current_txn = $TXN_model->get_transaction_from_reg_url_link($this->_reg_url_link);
156
-        // verify TXN
157
-        if (WP_DEBUG && ! $this->_current_txn instanceof EE_Transaction) {
158
-            EE_Error::add_error(
159
-                __(
160
-                    'No transaction information could be retrieved or the transaction data is not of the correct type.',
161
-                    'event_espresso'
162
-                ),
163
-                __FILE__,
164
-                __FUNCTION__,
165
-                __LINE__
166
-            );
167
-            return null;
168
-        }
169
-        return $this->_current_txn;
170
-    }
171
-
172
-
173
-    /**
174
-     * get_txn_payments
175
-     *
176
-     * @param int $since
177
-     * @return mixed array of EE_Payment || FALSE
178
-     * @throws \EE_Error
179
-     */
180
-    public function get_txn_payments($since = 0)
181
-    {
182
-        if (! $this->get_txn()) {
183
-            return false;
184
-        }
185
-        $args = array('order_by' => array('PAY_timestamp' => 'ASC'));
186
-        if ($since > 0) {
187
-            $args[0] = array('PAY_timestamp' => array('>', $since));
188
-        }
189
-        // get array of payments with most recent first
190
-        return $this->_current_txn->payments($args);
191
-    }
192
-
193
-
194
-    /**
195
-     * @return bool
196
-     */
197
-    public function isOfflinePaymentMethod()
198
-    {
199
-        return $this->_is_offline_payment_method;
200
-    }
201
-
202
-
203
-
204
-
205
-    /**
206
-     * get_reg_url_link
207
-     *
208
-     * @return void
209
-     */
210
-    private function _get_reg_url_link()
211
-    {
212
-        if (! empty($this->_reg_url_link)) {
213
-            return;
214
-        }
215
-        // only do thank you page stuff if we have a REG_url_link in the url
216
-        if (WP_DEBUG && ! EE_Registry::instance()->REQ->is_set('e_reg_url_link')) {
217
-            EE_Error::add_error(
218
-                __(
219
-                    'No transaction information could be retrieved because the registration URL link is missing or invalid.',
220
-                    'event_espresso'
221
-                ),
222
-                __FILE__,
223
-                __FUNCTION__,
224
-                __LINE__
225
-            );
226
-            return;
227
-        }
228
-        // check for reg_url_link
229
-        $this->_reg_url_link = EE_Registry::instance()->REQ->get('e_reg_url_link');
230
-    }
231
-
232
-
233
-    /**
234
-     * set_reg_url_link
235
-     *
236
-     * @param string $reg_url_link
237
-     */
238
-    public function set_reg_url_link($reg_url_link = null)
239
-    {
240
-        $this->_reg_url_link = ! empty($reg_url_link) ? $reg_url_link : $this->_reg_url_link;
241
-    }
242
-
243
-
244
-    /**
245
-     * run - initial module setup
246
-     * this method is primarily used for activating resources in the EE_Front_Controller thru the use of filters
247
-     *
248
-     * @param WP $WP
249
-     * @return void
250
-     * @throws \EE_Error
251
-     */
252
-    public function run($WP)
253
-    {
254
-    }
255
-
256
-
257
-    /**
258
-     * load_resources
259
-     *
260
-     * @return void
261
-     * @throws \EE_Error
262
-     */
263
-    public function load_resources()
264
-    {
265
-        $this->_get_reg_url_link();
266
-        // resend_reg_confirmation_email ?
267
-        if (EE_Registry::instance()->REQ->is_set('resend')) {
268
-            EED_Thank_You_Page::resend_reg_confirmation_email();
269
-        }
270
-        EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
271
-        $this->_translate_strings();
272
-        // load assets
273
-        add_action('wp_enqueue_scripts', array($this, 'load_js'), 10);
274
-    }
275
-
276
-
277
-    /**
278
-     * load_js
279
-     *
280
-     * @return void
281
-     */
282
-    protected function _translate_strings()
283
-    {
284
-        EE_Registry::$i18n_js_strings['e_reg_url_link'] = $this->_reg_url_link;
285
-        EE_Registry::$i18n_js_strings['initial_access'] = time();
286
-        EE_Registry::$i18n_js_strings['IPN_wait_time'] = EED_Thank_You_Page::IPN_wait_time;
287
-        EE_Registry::$i18n_js_strings['TXN_complete'] = EEM_Transaction::complete_status_code;
288
-        EE_Registry::$i18n_js_strings['TXN_incomplete'] = EEM_Transaction::incomplete_status_code;
289
-        EE_Registry::$i18n_js_strings['checking_for_new_payments'] = __(
290
-            'checking for new payments...',
291
-            'event_espresso'
292
-        );
293
-        EE_Registry::$i18n_js_strings['loading_payment_info'] = __(
294
-            'loading payment information...',
295
-            'event_espresso'
296
-        );
297
-        EE_Registry::$i18n_js_strings['server_error'] = __(
298
-            'An unknown error occurred on the server while attempting to process your request. Please refresh the page and try again.',
299
-            'event_espresso'
300
-        );
301
-        EE_Registry::$i18n_js_strings['slow_IPN'] = apply_filters(
302
-            'EED_Thank_You_Page__load_js__slow_IPN',
303
-            sprintf(
304
-                __(
305
-                    '%sThe Payment Notification appears to be taking longer than usual to arrive. Maybe check back later or just wait for your payment and registration confirmation results to be sent to you via email. We apologize for any inconvenience this may have caused.%s',
306
-                    'event_espresso'
307
-                ),
308
-                '<div id="espresso-thank-you-page-slow-IPN-dv" class="ee-attention jst-left">',
309
-                '</div>'
310
-            )
311
-        );
312
-    }
313
-
314
-
315
-    /**
316
-     * load_js
317
-     *
318
-     * @return void
319
-     */
320
-    public function load_js()
321
-    {
322
-        wp_register_script(
323
-            'thank_you_page',
324
-            THANK_YOU_ASSETS_URL . 'thank_you_page.js',
325
-            array('espresso_core', 'heartbeat'),
326
-            EVENT_ESPRESSO_VERSION,
327
-            true
328
-        );
329
-        wp_enqueue_script('thank_you_page');
330
-        wp_enqueue_style('espresso_default');
331
-    }
332
-
333
-
334
-    /**
335
-     * init
336
-     *
337
-     * @return void
338
-     * @throws \EE_Error
339
-     */
340
-    public function init()
341
-    {
342
-        $this->_get_reg_url_link();
343
-        if (! $this->get_txn()) {
344
-            echo EEH_HTML::div(
345
-                EEH_HTML::h4(__('We\'re sorry...', 'event_espresso'), '', '') .
346
-                sprintf(
347
-                    __(
348
-                        'This is a system page for displaying transaction information after a purchase.%1$sYou are most likely seeing this notice because you have navigated to this page%1$sthrough some means other than completing a transaction.%1$sSorry for the disappointment, but you will most likely find nothing of interest here.%1$s%1$s',
349
-                        'event_espresso'
350
-                    ),
351
-                    '<br/>'
352
-                ),
353
-                '',
354
-                'ee-attention'
355
-            );
356
-            return null;
357
-        }
358
-        // if we've made it to the Thank You page, then let's toggle any "Failed" transactions to "Incomplete"
359
-        if ($this->_current_txn->status_ID() === EEM_Transaction::failed_status_code) {
360
-            $this->_current_txn->set_status(EEM_Transaction::incomplete_status_code);
361
-            $this->_current_txn->save();
362
-        }
363
-        $this->_primary_registrant = $this->_current_txn->primary_registration() instanceof EE_Registration
364
-            ? $this->_current_txn->primary_registration()
365
-            : null;
366
-        $this->_is_primary = $this->_primary_registrant->reg_url_link() === $this->_reg_url_link ? true : false;
367
-        $show_try_pay_again_link_default = apply_filters(
368
-            'AFEE__EED_Thank_You_Page__init__show_try_pay_again_link_default',
369
-            true
370
-        );
371
-        $this->_show_try_pay_again_link = $show_try_pay_again_link_default;
372
-        // txn status ?
373
-        if ($this->_current_txn->is_completed()) {
374
-            $this->_show_try_pay_again_link = $show_try_pay_again_link_default;
375
-        } elseif ($this->_current_txn->is_incomplete()
376
-            && ($this->_primary_registrant->is_approved()
377
-                || $this->_primary_registrant->is_pending_payment())
378
-        ) {
379
-            $this->_show_try_pay_again_link = true;
380
-        } elseif ($this->_primary_registrant->is_approved() || $this->_primary_registrant->is_pending_payment()) {
381
-            // its pending
382
-            $this->_show_try_pay_again_link = isset(
383
-                EE_Registry::instance()->CFG->registration->show_pending_payment_options
384
-            )
385
-                                              && EE_Registry::instance()->CFG
386
-                                                  ->registration->show_pending_payment_options
387
-                ? true
388
-                : $show_try_pay_again_link_default;
389
-        }
390
-        $this->_payments_closed = ! $this->_current_txn->payment_method() instanceof EE_Payment_Method
391
-            ? true
392
-            : false;
393
-        $this->_is_offline_payment_method = false;
394
-        if (// if payment method is unknown
395
-            ! $this->_current_txn->payment_method() instanceof EE_Payment_Method
396
-            || (
397
-                // or is an offline payment method
398
-                $this->_current_txn->payment_method() instanceof EE_Payment_Method
399
-                && $this->_current_txn->payment_method()->is_off_line()
400
-            )
401
-        ) {
402
-            $this->_is_offline_payment_method = true;
403
-        }
404
-        // link to SPCO
405
-        $revisit_spco_url = add_query_arg(
406
-            array('ee' => '_register', 'revisit' => true, 'e_reg_url_link' => $this->_reg_url_link),
407
-            EE_Registry::instance()->CFG->core->reg_page_url()
408
-        );
409
-        // link to SPCO payment_options
410
-        $this->_SPCO_payment_options_url = $this->_primary_registrant instanceof EE_Registration
411
-            ? $this->_primary_registrant->payment_overview_url()
412
-            : add_query_arg(
413
-                array('step' => 'payment_options'),
414
-                $revisit_spco_url
415
-            );
416
-        // link to SPCO attendee_information
417
-        $this->_SPCO_attendee_information_url = $this->_primary_registrant instanceof EE_Registration
418
-            ? $this->_primary_registrant->edit_attendee_information_url()
419
-            : false;
420
-        do_action('AHEE__EED_Thank_You_Page__init_end', $this->_current_txn);
421
-        // set no cache headers and constants
422
-        EE_System::do_not_cache();
423
-    }
424
-
425
-
426
-    /**
427
-     * display_thank_you_page_results
428
-     *
429
-     * @return string
430
-     * @throws \EE_Error
431
-     */
432
-    public function thank_you_page_results()
433
-    {
434
-        $this->init();
435
-        if (! $this->_current_txn instanceof EE_Transaction) {
436
-            return EE_Error::get_notices();
437
-        }
438
-        // link to receipt
439
-        $template_args['TXN_receipt_url'] = $this->_current_txn->receipt_url('html');
440
-        if (! empty($template_args['TXN_receipt_url'])) {
441
-            $template_args['order_conf_desc'] = __(
442
-                '%1$sCongratulations%2$sYour registration has been successfully processed.%3$sCheck your email for your registration confirmation or click the button below to view / download / print a full description of your purchases and registration information.',
443
-                'event_espresso'
444
-            );
445
-        } else {
446
-            $template_args['order_conf_desc'] = __(
447
-                '%1$sCongratulations%2$sYour registration has been successfully processed.%3$sCheck your email for your registration confirmation.',
448
-                'event_espresso'
449
-            );
450
-        }
451
-        $template_args['transaction'] = $this->_current_txn;
452
-        $template_args['revisit'] = EE_Registry::instance()->REQ->get('revisit', false);
453
-        add_action('AHEE__thank_you_page_overview_template__content', array($this, 'get_registration_details'));
454
-        if ($this->_is_primary && ! $this->_current_txn->is_free()) {
455
-            add_action('AHEE__thank_you_page_overview_template__content', array($this, 'get_ajax_content'));
456
-        }
457
-        return EEH_Template::locate_template(
458
-            THANK_YOU_TEMPLATES_PATH . 'thank-you-page-overview.template.php',
459
-            $template_args,
460
-            true,
461
-            true
462
-        );
463
-    }
464
-
465
-
466
-
467
-    /**
468
-     * _update_server_wait_time
469
-     *
470
-     * @param array $thank_you_page_data thank you page portion of the incoming JSON array from the WP heartbeat data
471
-     * @return array
472
-     * @throws \EE_Error
473
-     */
474
-    private function _update_server_wait_time($thank_you_page_data = array())
475
-    {
476
-        $response['espresso_thank_you_page'] = array(
477
-            'still_waiting' => isset($thank_you_page_data['initial_access'])
478
-                ? time() - $thank_you_page_data['initial_access']
479
-                : 0,
480
-            'txn_status'    => $this->_current_txn->status_ID(),
481
-        );
482
-        return $response;
483
-    }
484
-
485
-
486
-    /**
487
-     * get_registration_details
488
-     *
489
-     * @throws \EE_Error
490
-     */
491
-    public function get_registration_details()
492
-    {
493
-        // prepare variables for displaying
494
-        $template_args = array();
495
-        $template_args['transaction'] = $this->_current_txn;
496
-        $template_args['reg_url_link'] = $this->_reg_url_link;
497
-        $template_args['is_primary'] = $this->_is_primary;
498
-        $template_args['SPCO_attendee_information_url'] = $this->_SPCO_attendee_information_url;
499
-        $template_args['resend_reg_confirmation_url'] = add_query_arg(
500
-            array('token' => $this->_reg_url_link, 'resend_reg_confirmation' => 'true'),
501
-            EE_Registry::instance()->CFG->core->thank_you_page_url()
502
-        );
503
-        // verify template arguments
504
-        EEH_Template_Validator::verify_instanceof($template_args['transaction'], '$transaction', 'EE_Transaction');
505
-        EEH_Template_Validator::verify_isnt_null(
506
-            $template_args['SPCO_attendee_information_url'],
507
-            '$SPCO_attendee_information_url'
508
-        );
509
-        echo EEH_Template::locate_template(
510
-            THANK_YOU_TEMPLATES_PATH . 'thank-you-page-registration-details.template.php',
511
-            $template_args,
512
-            true,
513
-            true
514
-        );
515
-    }
516
-
517
-
518
-    /**
519
-     * resend_reg_confirmation_email
520
-     *
521
-     * @throws \EE_Error
522
-     */
523
-    public static function resend_reg_confirmation_email()
524
-    {
525
-        EE_Registry::instance()->load_core('Request_Handler');
526
-        $reg_url_link = EE_Registry::instance()->REQ->get('token');
527
-        // was a REG_ID passed ?
528
-        if ($reg_url_link) {
529
-            $registration = EE_Registry::instance()->load_model('Registration')->get_one(
530
-                array(array('REG_url_link' => $reg_url_link))
531
-            );
532
-            if ($registration instanceof EE_Registration) {
533
-                // resend email
534
-                EED_Messages::process_resend(array('_REG_ID' => $registration->ID()));
535
-            } else {
536
-                EE_Error::add_error(
537
-                    __(
538
-                        'The Registration Confirmation email could not be sent because a valid Registration could not be retrieved from the database.',
539
-                        'event_espresso'
540
-                    ),
541
-                    __FILE__,
542
-                    __FUNCTION__,
543
-                    __LINE__
544
-                );
545
-            }
546
-        } else {
547
-            EE_Error::add_error(
548
-                __(
549
-                    'The Registration Confirmation email could not be sent because a registration token is missing or invalid.',
550
-                    'event_espresso'
551
-                ),
552
-                __FILE__,
553
-                __FUNCTION__,
554
-                __LINE__
555
-            );
556
-        }
557
-        // request sent via AJAX ?
558
-        if (EE_FRONT_AJAX) {
559
-            echo wp_json_encode(EE_Error::get_notices(false));
560
-            die();
561
-            // or was JS disabled ?
562
-        } else {
563
-            // save errors so that they get picked up on the next request
564
-            EE_Error::get_notices(true, true);
565
-            wp_safe_redirect(
566
-                add_query_arg(
567
-                    array('e_reg_url_link' => $reg_url_link),
568
-                    EE_Registry::instance()->CFG->core->thank_you_page_url()
569
-                )
570
-            );
571
-        }
572
-    }
573
-
574
-
575
-    /**
576
-     * get_ajax_content
577
-     *
578
-     * @return void
579
-     * @throws \EE_Error
580
-     */
581
-    public function get_ajax_content()
582
-    {
583
-        if (! $this->get_txn()) {
584
-            return;
585
-        }
586
-        // first determine which event(s) require pre-approval or not
587
-        $events = array();
588
-        $events_requiring_pre_approval = array();
589
-        foreach ($this->_current_txn->registrations() as $registration) {
590
-            if ($registration instanceof EE_Registration) {
591
-                $event = $registration->event();
592
-                if ($event instanceof EE_Event) {
593
-                    if ($registration->is_not_approved() && $registration->event() instanceof EE_Event) {
594
-                        $events_requiring_pre_approval[ $event->ID() ] = $event;
595
-                    } else {
596
-                        $events[ $event->ID() ] = $event;
597
-                    }
598
-                }
599
-            }
600
-        }
601
-        $this->display_details_for_events_requiring_pre_approval($events_requiring_pre_approval);
602
-        $this->display_details_for_events($events);
603
-    }
604
-
605
-
606
-    /**
607
-     * display_details_for_events
608
-     *
609
-     * @param EE_Event[] $events
610
-     * @return void
611
-     */
612
-    public function display_details_for_events($events = array())
613
-    {
614
-        if (! empty($events)) {
615
-            ?>
13
+	/**
14
+	 * time in seconds to wait for the IPN to arrive before telling the registrant to bugger off ( 1200s = 20 minutes )
15
+	 */
16
+	const IPN_wait_time = 1200;
17
+
18
+	/**
19
+	 * The transaction specified by the reg_url_link passed from the Request, or from the Session
20
+	 *
21
+	 * @var EE_Transaction $_current_txn
22
+	 */
23
+	private $_current_txn;
24
+
25
+	/**
26
+	 * @var EE_Registration $_primary_registrant
27
+	 */
28
+	private $_primary_registrant;
29
+
30
+	/**
31
+	 * The reg_url_link passed from the Request, or from the Session
32
+	 *
33
+	 * @var string $_reg_url_link
34
+	 */
35
+	private $_reg_url_link;
36
+
37
+	/**
38
+	 * whether the incoming reg_url_link is for the primary registrant or not
39
+	 *
40
+	 * @var boolean $_is_primary
41
+	 */
42
+	private $_is_primary;
43
+
44
+	/**
45
+	 * The URL for revisiting the SPCO attendee information step
46
+	 *
47
+	 * @var string $_SPCO_attendee_information_url
48
+	 */
49
+	private $_SPCO_attendee_information_url;
50
+
51
+	/**
52
+	 * The URL for revisiting the SPCO payment options step
53
+	 *
54
+	 * @var string $_SPCO_payment_options_url
55
+	 */
56
+	private $_SPCO_payment_options_url;
57
+
58
+	/**
59
+	 * whether to display the Payment Options link
60
+	 *
61
+	 * @var boolean $_show_try_pay_again_link
62
+	 */
63
+	private $_show_try_pay_again_link = false;
64
+
65
+	/**
66
+	 * whether payments are allowed at this time
67
+	 *
68
+	 * @var boolean $_payments_closed
69
+	 */
70
+	private $_payments_closed = false;
71
+
72
+	/**
73
+	 * whether the selected payment method is Bank, Check , Invoice, etc
74
+	 *
75
+	 * @var boolean $_is_offline_payment_method
76
+	 */
77
+	private $_is_offline_payment_method = true;
78
+
79
+
80
+	/**
81
+	 * @return EED_Module|EED_Thank_You_Page
82
+	 */
83
+	public static function instance()
84
+	{
85
+		return parent::get_instance(__CLASS__);
86
+	}
87
+
88
+
89
+	/**
90
+	 * set_hooks - for hooking into EE Core, modules, etc
91
+	 *
92
+	 * @return void
93
+	 */
94
+	public static function set_hooks()
95
+	{
96
+		add_action('wp_loaded', array('EED_Thank_You_Page', 'set_definitions'), 2);
97
+	}
98
+
99
+
100
+	/**
101
+	 * set_hooks_admin - for hooking into EE Admin Core, modules, etc
102
+	 *
103
+	 * @return void
104
+	 */
105
+	public static function set_hooks_admin()
106
+	{
107
+		add_action(
108
+			'wp_ajax_espresso_resend_reg_confirmation_email',
109
+			array('EED_Thank_You_Page', 'resend_reg_confirmation_email'),
110
+			10,
111
+			2
112
+		);
113
+		add_action(
114
+			'wp_ajax_nopriv_espresso_resend_reg_confirmation_email',
115
+			array('EED_Thank_You_Page', 'resend_reg_confirmation_email'),
116
+			10,
117
+			2
118
+		);
119
+	}
120
+
121
+
122
+	/**
123
+	 * set_definitions
124
+	 *
125
+	 * @return void
126
+	 */
127
+	public static function set_definitions()
128
+	{
129
+		define('THANK_YOU_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets/');
130
+		define('THANK_YOU_TEMPLATES_PATH', str_replace('\\', '/', plugin_dir_path(__FILE__)) . 'templates/');
131
+	}
132
+
133
+
134
+	/**
135
+	 * get_txn
136
+	 *
137
+	 * @return EE_Transaction
138
+	 */
139
+	public function get_txn()
140
+	{
141
+		if ($this->_current_txn instanceof EE_Transaction) {
142
+			return $this->_current_txn;
143
+		}
144
+		$TXN_model = EE_Registry::instance()->load_model('Transaction');
145
+		if (! $TXN_model instanceof EEM_Transaction) {
146
+			EE_Error::add_error(
147
+				__('The transaction model could not be established.', 'event_espresso'),
148
+				__FILE__,
149
+				__FUNCTION__,
150
+				__LINE__
151
+			);
152
+			return null;
153
+		}
154
+		// get the transaction. yes, we may have just loaded it, but it may have been updated, or this may be via an ajax request
155
+		$this->_current_txn = $TXN_model->get_transaction_from_reg_url_link($this->_reg_url_link);
156
+		// verify TXN
157
+		if (WP_DEBUG && ! $this->_current_txn instanceof EE_Transaction) {
158
+			EE_Error::add_error(
159
+				__(
160
+					'No transaction information could be retrieved or the transaction data is not of the correct type.',
161
+					'event_espresso'
162
+				),
163
+				__FILE__,
164
+				__FUNCTION__,
165
+				__LINE__
166
+			);
167
+			return null;
168
+		}
169
+		return $this->_current_txn;
170
+	}
171
+
172
+
173
+	/**
174
+	 * get_txn_payments
175
+	 *
176
+	 * @param int $since
177
+	 * @return mixed array of EE_Payment || FALSE
178
+	 * @throws \EE_Error
179
+	 */
180
+	public function get_txn_payments($since = 0)
181
+	{
182
+		if (! $this->get_txn()) {
183
+			return false;
184
+		}
185
+		$args = array('order_by' => array('PAY_timestamp' => 'ASC'));
186
+		if ($since > 0) {
187
+			$args[0] = array('PAY_timestamp' => array('>', $since));
188
+		}
189
+		// get array of payments with most recent first
190
+		return $this->_current_txn->payments($args);
191
+	}
192
+
193
+
194
+	/**
195
+	 * @return bool
196
+	 */
197
+	public function isOfflinePaymentMethod()
198
+	{
199
+		return $this->_is_offline_payment_method;
200
+	}
201
+
202
+
203
+
204
+
205
+	/**
206
+	 * get_reg_url_link
207
+	 *
208
+	 * @return void
209
+	 */
210
+	private function _get_reg_url_link()
211
+	{
212
+		if (! empty($this->_reg_url_link)) {
213
+			return;
214
+		}
215
+		// only do thank you page stuff if we have a REG_url_link in the url
216
+		if (WP_DEBUG && ! EE_Registry::instance()->REQ->is_set('e_reg_url_link')) {
217
+			EE_Error::add_error(
218
+				__(
219
+					'No transaction information could be retrieved because the registration URL link is missing or invalid.',
220
+					'event_espresso'
221
+				),
222
+				__FILE__,
223
+				__FUNCTION__,
224
+				__LINE__
225
+			);
226
+			return;
227
+		}
228
+		// check for reg_url_link
229
+		$this->_reg_url_link = EE_Registry::instance()->REQ->get('e_reg_url_link');
230
+	}
231
+
232
+
233
+	/**
234
+	 * set_reg_url_link
235
+	 *
236
+	 * @param string $reg_url_link
237
+	 */
238
+	public function set_reg_url_link($reg_url_link = null)
239
+	{
240
+		$this->_reg_url_link = ! empty($reg_url_link) ? $reg_url_link : $this->_reg_url_link;
241
+	}
242
+
243
+
244
+	/**
245
+	 * run - initial module setup
246
+	 * this method is primarily used for activating resources in the EE_Front_Controller thru the use of filters
247
+	 *
248
+	 * @param WP $WP
249
+	 * @return void
250
+	 * @throws \EE_Error
251
+	 */
252
+	public function run($WP)
253
+	{
254
+	}
255
+
256
+
257
+	/**
258
+	 * load_resources
259
+	 *
260
+	 * @return void
261
+	 * @throws \EE_Error
262
+	 */
263
+	public function load_resources()
264
+	{
265
+		$this->_get_reg_url_link();
266
+		// resend_reg_confirmation_email ?
267
+		if (EE_Registry::instance()->REQ->is_set('resend')) {
268
+			EED_Thank_You_Page::resend_reg_confirmation_email();
269
+		}
270
+		EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
271
+		$this->_translate_strings();
272
+		// load assets
273
+		add_action('wp_enqueue_scripts', array($this, 'load_js'), 10);
274
+	}
275
+
276
+
277
+	/**
278
+	 * load_js
279
+	 *
280
+	 * @return void
281
+	 */
282
+	protected function _translate_strings()
283
+	{
284
+		EE_Registry::$i18n_js_strings['e_reg_url_link'] = $this->_reg_url_link;
285
+		EE_Registry::$i18n_js_strings['initial_access'] = time();
286
+		EE_Registry::$i18n_js_strings['IPN_wait_time'] = EED_Thank_You_Page::IPN_wait_time;
287
+		EE_Registry::$i18n_js_strings['TXN_complete'] = EEM_Transaction::complete_status_code;
288
+		EE_Registry::$i18n_js_strings['TXN_incomplete'] = EEM_Transaction::incomplete_status_code;
289
+		EE_Registry::$i18n_js_strings['checking_for_new_payments'] = __(
290
+			'checking for new payments...',
291
+			'event_espresso'
292
+		);
293
+		EE_Registry::$i18n_js_strings['loading_payment_info'] = __(
294
+			'loading payment information...',
295
+			'event_espresso'
296
+		);
297
+		EE_Registry::$i18n_js_strings['server_error'] = __(
298
+			'An unknown error occurred on the server while attempting to process your request. Please refresh the page and try again.',
299
+			'event_espresso'
300
+		);
301
+		EE_Registry::$i18n_js_strings['slow_IPN'] = apply_filters(
302
+			'EED_Thank_You_Page__load_js__slow_IPN',
303
+			sprintf(
304
+				__(
305
+					'%sThe Payment Notification appears to be taking longer than usual to arrive. Maybe check back later or just wait for your payment and registration confirmation results to be sent to you via email. We apologize for any inconvenience this may have caused.%s',
306
+					'event_espresso'
307
+				),
308
+				'<div id="espresso-thank-you-page-slow-IPN-dv" class="ee-attention jst-left">',
309
+				'</div>'
310
+			)
311
+		);
312
+	}
313
+
314
+
315
+	/**
316
+	 * load_js
317
+	 *
318
+	 * @return void
319
+	 */
320
+	public function load_js()
321
+	{
322
+		wp_register_script(
323
+			'thank_you_page',
324
+			THANK_YOU_ASSETS_URL . 'thank_you_page.js',
325
+			array('espresso_core', 'heartbeat'),
326
+			EVENT_ESPRESSO_VERSION,
327
+			true
328
+		);
329
+		wp_enqueue_script('thank_you_page');
330
+		wp_enqueue_style('espresso_default');
331
+	}
332
+
333
+
334
+	/**
335
+	 * init
336
+	 *
337
+	 * @return void
338
+	 * @throws \EE_Error
339
+	 */
340
+	public function init()
341
+	{
342
+		$this->_get_reg_url_link();
343
+		if (! $this->get_txn()) {
344
+			echo EEH_HTML::div(
345
+				EEH_HTML::h4(__('We\'re sorry...', 'event_espresso'), '', '') .
346
+				sprintf(
347
+					__(
348
+						'This is a system page for displaying transaction information after a purchase.%1$sYou are most likely seeing this notice because you have navigated to this page%1$sthrough some means other than completing a transaction.%1$sSorry for the disappointment, but you will most likely find nothing of interest here.%1$s%1$s',
349
+						'event_espresso'
350
+					),
351
+					'<br/>'
352
+				),
353
+				'',
354
+				'ee-attention'
355
+			);
356
+			return null;
357
+		}
358
+		// if we've made it to the Thank You page, then let's toggle any "Failed" transactions to "Incomplete"
359
+		if ($this->_current_txn->status_ID() === EEM_Transaction::failed_status_code) {
360
+			$this->_current_txn->set_status(EEM_Transaction::incomplete_status_code);
361
+			$this->_current_txn->save();
362
+		}
363
+		$this->_primary_registrant = $this->_current_txn->primary_registration() instanceof EE_Registration
364
+			? $this->_current_txn->primary_registration()
365
+			: null;
366
+		$this->_is_primary = $this->_primary_registrant->reg_url_link() === $this->_reg_url_link ? true : false;
367
+		$show_try_pay_again_link_default = apply_filters(
368
+			'AFEE__EED_Thank_You_Page__init__show_try_pay_again_link_default',
369
+			true
370
+		);
371
+		$this->_show_try_pay_again_link = $show_try_pay_again_link_default;
372
+		// txn status ?
373
+		if ($this->_current_txn->is_completed()) {
374
+			$this->_show_try_pay_again_link = $show_try_pay_again_link_default;
375
+		} elseif ($this->_current_txn->is_incomplete()
376
+			&& ($this->_primary_registrant->is_approved()
377
+				|| $this->_primary_registrant->is_pending_payment())
378
+		) {
379
+			$this->_show_try_pay_again_link = true;
380
+		} elseif ($this->_primary_registrant->is_approved() || $this->_primary_registrant->is_pending_payment()) {
381
+			// its pending
382
+			$this->_show_try_pay_again_link = isset(
383
+				EE_Registry::instance()->CFG->registration->show_pending_payment_options
384
+			)
385
+											  && EE_Registry::instance()->CFG
386
+												  ->registration->show_pending_payment_options
387
+				? true
388
+				: $show_try_pay_again_link_default;
389
+		}
390
+		$this->_payments_closed = ! $this->_current_txn->payment_method() instanceof EE_Payment_Method
391
+			? true
392
+			: false;
393
+		$this->_is_offline_payment_method = false;
394
+		if (// if payment method is unknown
395
+			! $this->_current_txn->payment_method() instanceof EE_Payment_Method
396
+			|| (
397
+				// or is an offline payment method
398
+				$this->_current_txn->payment_method() instanceof EE_Payment_Method
399
+				&& $this->_current_txn->payment_method()->is_off_line()
400
+			)
401
+		) {
402
+			$this->_is_offline_payment_method = true;
403
+		}
404
+		// link to SPCO
405
+		$revisit_spco_url = add_query_arg(
406
+			array('ee' => '_register', 'revisit' => true, 'e_reg_url_link' => $this->_reg_url_link),
407
+			EE_Registry::instance()->CFG->core->reg_page_url()
408
+		);
409
+		// link to SPCO payment_options
410
+		$this->_SPCO_payment_options_url = $this->_primary_registrant instanceof EE_Registration
411
+			? $this->_primary_registrant->payment_overview_url()
412
+			: add_query_arg(
413
+				array('step' => 'payment_options'),
414
+				$revisit_spco_url
415
+			);
416
+		// link to SPCO attendee_information
417
+		$this->_SPCO_attendee_information_url = $this->_primary_registrant instanceof EE_Registration
418
+			? $this->_primary_registrant->edit_attendee_information_url()
419
+			: false;
420
+		do_action('AHEE__EED_Thank_You_Page__init_end', $this->_current_txn);
421
+		// set no cache headers and constants
422
+		EE_System::do_not_cache();
423
+	}
424
+
425
+
426
+	/**
427
+	 * display_thank_you_page_results
428
+	 *
429
+	 * @return string
430
+	 * @throws \EE_Error
431
+	 */
432
+	public function thank_you_page_results()
433
+	{
434
+		$this->init();
435
+		if (! $this->_current_txn instanceof EE_Transaction) {
436
+			return EE_Error::get_notices();
437
+		}
438
+		// link to receipt
439
+		$template_args['TXN_receipt_url'] = $this->_current_txn->receipt_url('html');
440
+		if (! empty($template_args['TXN_receipt_url'])) {
441
+			$template_args['order_conf_desc'] = __(
442
+				'%1$sCongratulations%2$sYour registration has been successfully processed.%3$sCheck your email for your registration confirmation or click the button below to view / download / print a full description of your purchases and registration information.',
443
+				'event_espresso'
444
+			);
445
+		} else {
446
+			$template_args['order_conf_desc'] = __(
447
+				'%1$sCongratulations%2$sYour registration has been successfully processed.%3$sCheck your email for your registration confirmation.',
448
+				'event_espresso'
449
+			);
450
+		}
451
+		$template_args['transaction'] = $this->_current_txn;
452
+		$template_args['revisit'] = EE_Registry::instance()->REQ->get('revisit', false);
453
+		add_action('AHEE__thank_you_page_overview_template__content', array($this, 'get_registration_details'));
454
+		if ($this->_is_primary && ! $this->_current_txn->is_free()) {
455
+			add_action('AHEE__thank_you_page_overview_template__content', array($this, 'get_ajax_content'));
456
+		}
457
+		return EEH_Template::locate_template(
458
+			THANK_YOU_TEMPLATES_PATH . 'thank-you-page-overview.template.php',
459
+			$template_args,
460
+			true,
461
+			true
462
+		);
463
+	}
464
+
465
+
466
+
467
+	/**
468
+	 * _update_server_wait_time
469
+	 *
470
+	 * @param array $thank_you_page_data thank you page portion of the incoming JSON array from the WP heartbeat data
471
+	 * @return array
472
+	 * @throws \EE_Error
473
+	 */
474
+	private function _update_server_wait_time($thank_you_page_data = array())
475
+	{
476
+		$response['espresso_thank_you_page'] = array(
477
+			'still_waiting' => isset($thank_you_page_data['initial_access'])
478
+				? time() - $thank_you_page_data['initial_access']
479
+				: 0,
480
+			'txn_status'    => $this->_current_txn->status_ID(),
481
+		);
482
+		return $response;
483
+	}
484
+
485
+
486
+	/**
487
+	 * get_registration_details
488
+	 *
489
+	 * @throws \EE_Error
490
+	 */
491
+	public function get_registration_details()
492
+	{
493
+		// prepare variables for displaying
494
+		$template_args = array();
495
+		$template_args['transaction'] = $this->_current_txn;
496
+		$template_args['reg_url_link'] = $this->_reg_url_link;
497
+		$template_args['is_primary'] = $this->_is_primary;
498
+		$template_args['SPCO_attendee_information_url'] = $this->_SPCO_attendee_information_url;
499
+		$template_args['resend_reg_confirmation_url'] = add_query_arg(
500
+			array('token' => $this->_reg_url_link, 'resend_reg_confirmation' => 'true'),
501
+			EE_Registry::instance()->CFG->core->thank_you_page_url()
502
+		);
503
+		// verify template arguments
504
+		EEH_Template_Validator::verify_instanceof($template_args['transaction'], '$transaction', 'EE_Transaction');
505
+		EEH_Template_Validator::verify_isnt_null(
506
+			$template_args['SPCO_attendee_information_url'],
507
+			'$SPCO_attendee_information_url'
508
+		);
509
+		echo EEH_Template::locate_template(
510
+			THANK_YOU_TEMPLATES_PATH . 'thank-you-page-registration-details.template.php',
511
+			$template_args,
512
+			true,
513
+			true
514
+		);
515
+	}
516
+
517
+
518
+	/**
519
+	 * resend_reg_confirmation_email
520
+	 *
521
+	 * @throws \EE_Error
522
+	 */
523
+	public static function resend_reg_confirmation_email()
524
+	{
525
+		EE_Registry::instance()->load_core('Request_Handler');
526
+		$reg_url_link = EE_Registry::instance()->REQ->get('token');
527
+		// was a REG_ID passed ?
528
+		if ($reg_url_link) {
529
+			$registration = EE_Registry::instance()->load_model('Registration')->get_one(
530
+				array(array('REG_url_link' => $reg_url_link))
531
+			);
532
+			if ($registration instanceof EE_Registration) {
533
+				// resend email
534
+				EED_Messages::process_resend(array('_REG_ID' => $registration->ID()));
535
+			} else {
536
+				EE_Error::add_error(
537
+					__(
538
+						'The Registration Confirmation email could not be sent because a valid Registration could not be retrieved from the database.',
539
+						'event_espresso'
540
+					),
541
+					__FILE__,
542
+					__FUNCTION__,
543
+					__LINE__
544
+				);
545
+			}
546
+		} else {
547
+			EE_Error::add_error(
548
+				__(
549
+					'The Registration Confirmation email could not be sent because a registration token is missing or invalid.',
550
+					'event_espresso'
551
+				),
552
+				__FILE__,
553
+				__FUNCTION__,
554
+				__LINE__
555
+			);
556
+		}
557
+		// request sent via AJAX ?
558
+		if (EE_FRONT_AJAX) {
559
+			echo wp_json_encode(EE_Error::get_notices(false));
560
+			die();
561
+			// or was JS disabled ?
562
+		} else {
563
+			// save errors so that they get picked up on the next request
564
+			EE_Error::get_notices(true, true);
565
+			wp_safe_redirect(
566
+				add_query_arg(
567
+					array('e_reg_url_link' => $reg_url_link),
568
+					EE_Registry::instance()->CFG->core->thank_you_page_url()
569
+				)
570
+			);
571
+		}
572
+	}
573
+
574
+
575
+	/**
576
+	 * get_ajax_content
577
+	 *
578
+	 * @return void
579
+	 * @throws \EE_Error
580
+	 */
581
+	public function get_ajax_content()
582
+	{
583
+		if (! $this->get_txn()) {
584
+			return;
585
+		}
586
+		// first determine which event(s) require pre-approval or not
587
+		$events = array();
588
+		$events_requiring_pre_approval = array();
589
+		foreach ($this->_current_txn->registrations() as $registration) {
590
+			if ($registration instanceof EE_Registration) {
591
+				$event = $registration->event();
592
+				if ($event instanceof EE_Event) {
593
+					if ($registration->is_not_approved() && $registration->event() instanceof EE_Event) {
594
+						$events_requiring_pre_approval[ $event->ID() ] = $event;
595
+					} else {
596
+						$events[ $event->ID() ] = $event;
597
+					}
598
+				}
599
+			}
600
+		}
601
+		$this->display_details_for_events_requiring_pre_approval($events_requiring_pre_approval);
602
+		$this->display_details_for_events($events);
603
+	}
604
+
605
+
606
+	/**
607
+	 * display_details_for_events
608
+	 *
609
+	 * @param EE_Event[] $events
610
+	 * @return void
611
+	 */
612
+	public function display_details_for_events($events = array())
613
+	{
614
+		if (! empty($events)) {
615
+			?>
616 616
             <div id="espresso-thank-you-page-ajax-content-dv">
617 617
                 <div id="espresso-thank-you-page-ajax-transaction-dv"></div>
618 618
                 <div id="espresso-thank-you-page-ajax-payment-dv"></div>
@@ -620,19 +620,19 @@  discard block
 block discarded – undo
620 620
                     <div id="ee-ajax-loading-dv" class="float-left lt-blue-text">
621 621
                         <span class="dashicons dashicons-upload"></span><span id="ee-ajax-loading-msg-spn">
622 622
                             <?php _e(
623
-                                'loading transaction and payment information...',
624
-                                'event_espresso'
625
-                            ); ?></span>
623
+								'loading transaction and payment information...',
624
+								'event_espresso'
625
+							); ?></span>
626 626
                     </div>
627 627
                     <?php if (! $this->_is_offline_payment_method && ! $this->_payments_closed) : ?>
628 628
                         <p id="ee-ajax-loading-pg" class="highlight-bg small-text clear">
629 629
                             <?php echo apply_filters(
630
-                                'EED_Thank_You_Page__get_ajax_content__waiting_for_IPN_msg',
631
-                                __(
632
-                                    'Some payment gateways can take 15 minutes or more to return their payment notification, so please be patient if you require payment confirmation as soon as possible. Please note that as soon as everything is finalized, we will send your full payment and registration confirmation results to you via email.',
633
-                                    'event_espresso'
634
-                                )
635
-                            ); ?>
630
+								'EED_Thank_You_Page__get_ajax_content__waiting_for_IPN_msg',
631
+								__(
632
+									'Some payment gateways can take 15 minutes or more to return their payment notification, so please be patient if you require payment confirmation as soon as possible. Please note that as soon as everything is finalized, we will send your full payment and registration confirmation results to you via email.',
633
+									'event_espresso'
634
+								)
635
+							); ?>
636 636
                             <br/>
637 637
                             <span class="jst-rght ee-block small-text lt-grey-text">
638 638
                                 <?php _e('current wait time ', 'event_espresso'); ?>
@@ -643,117 +643,117 @@  discard block
 block discarded – undo
643 643
                 <div class="clear"></div>
644 644
             </div>
645 645
             <?php
646
-        }
647
-    }
648
-
649
-
650
-    /**
651
-     * display_details_for_events_requiring_pre_approval
652
-     *
653
-     * @param EE_Event[] $events
654
-     * @return void
655
-     */
656
-    public function display_details_for_events_requiring_pre_approval($events = array())
657
-    {
658
-        if (! empty($events)) {
659
-            ?>
646
+		}
647
+	}
648
+
649
+
650
+	/**
651
+	 * display_details_for_events_requiring_pre_approval
652
+	 *
653
+	 * @param EE_Event[] $events
654
+	 * @return void
655
+	 */
656
+	public function display_details_for_events_requiring_pre_approval($events = array())
657
+	{
658
+		if (! empty($events)) {
659
+			?>
660 660
             <div id="espresso-thank-you-page-not-approved-message-dv">
661 661
                 <h4 class="orange-text"><?php _e('Important Notice:', 'event_espresso'); ?></h4>
662 662
                 <p id="events-requiring-pre-approval-pg" class="small-text">
663 663
                     <?php echo apply_filters(
664
-                        'AHEE__EED_Thank_You_Page__get_ajax_content__not_approved_message',
665
-                        __(
666
-                            'The following Event(s) you have registered for do not require payment at this time and will not be billed for during this transaction. Billing will only occur after all attendees have been approved by the event organizer. You will be notified when your registration has been processed. If this is a free event, then no billing will occur.',
667
-                            'event_espresso'
668
-                        )
669
-                    ); ?>
664
+						'AHEE__EED_Thank_You_Page__get_ajax_content__not_approved_message',
665
+						__(
666
+							'The following Event(s) you have registered for do not require payment at this time and will not be billed for during this transaction. Billing will only occur after all attendees have been approved by the event organizer. You will be notified when your registration has been processed. If this is a free event, then no billing will occur.',
667
+							'event_espresso'
668
+						)
669
+					); ?>
670 670
                 </p>
671 671
                 <ul class="events-requiring-pre-approval-ul">
672 672
                     <?php
673
-                    foreach ($events as $event) {
674
-                        if ($event instanceof EE_Event) {
675
-                            echo '<li><span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>',
676
-                            $event->name(),
677
-                            '</li>';
678
-                        }
679
-                    } ?>
673
+					foreach ($events as $event) {
674
+						if ($event instanceof EE_Event) {
675
+							echo '<li><span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>',
676
+							$event->name(),
677
+							'</li>';
678
+						}
679
+					} ?>
680 680
                 </ul>
681 681
                 <div class="clear"></div>
682 682
             </div>
683 683
             <?php
684
-        }
685
-    }
686
-
687
-
688
-    /**
689
-     * get_transaction_details
690
-     *
691
-     * @return string
692
-     * @throws \EE_Error
693
-     */
694
-    public function get_transaction_details()
695
-    {
696
-        // prepare variables for displaying
697
-        $template_args = array();
698
-        $template_args['transaction'] = $this->_current_txn;
699
-        $template_args['reg_url_link'] = $this->_reg_url_link;
700
-        $template_args['primary_registrant_name'] = $this->_primary_registrant->attendee()->full_name(true);
701
-        // link to SPCO payment_options
702
-        $template_args['show_try_pay_again_link'] = $this->_show_try_pay_again_link;
703
-        $template_args['SPCO_payment_options_url'] = $this->_SPCO_payment_options_url;
704
-        // verify template arguments
705
-        EEH_Template_Validator::verify_instanceof($template_args['transaction'], '$transaction', 'EE_Transaction');
706
-        EEH_Template_Validator::verify_isnt_null(
707
-            $template_args['show_try_pay_again_link'],
708
-            '$show_try_pay_again_link'
709
-        );
710
-        EEH_Template_Validator::verify_isnt_null(
711
-            $template_args['SPCO_payment_options_url'],
712
-            '$SPCO_payment_options_url'
713
-        );
714
-        return EEH_Template::locate_template(
715
-            THANK_YOU_TEMPLATES_PATH . 'thank-you-page-transaction-details.template.php',
716
-            $template_args,
717
-            true,
718
-            true
719
-        );
720
-    }
721
-
722
-
723
-    /**
724
-     * get_payment_row_html
725
-     *
726
-     * @param EE_Payment $payment
727
-     * @return string
728
-     * @throws \EE_Error
729
-     */
730
-    public function get_payment_row_html($payment = null)
731
-    {
732
-        $html = '';
733
-        if ($payment instanceof EE_Payment) {
734
-            if ($payment->payment_method() instanceof EE_Payment_Method
735
-                && $payment->status() === EEM_Payment::status_id_failed
736
-                && $payment->payment_method()->is_off_site()
737
-            ) {
738
-                // considering the registrant has made it to the Thank You page,
739
-                // any failed payments may actually be pending and the IPN is just slow
740
-                // so let's
741
-                $payment->set_status(EEM_Payment::status_id_pending);
742
-            }
743
-            $payment_declined_msg = $payment->STS_ID() === EEM_Payment::status_id_declined
744
-                ? '<br /><span class="small-text">' . $payment->gateway_response() . '</span>'
745
-                : '';
746
-            $html .= '
684
+		}
685
+	}
686
+
687
+
688
+	/**
689
+	 * get_transaction_details
690
+	 *
691
+	 * @return string
692
+	 * @throws \EE_Error
693
+	 */
694
+	public function get_transaction_details()
695
+	{
696
+		// prepare variables for displaying
697
+		$template_args = array();
698
+		$template_args['transaction'] = $this->_current_txn;
699
+		$template_args['reg_url_link'] = $this->_reg_url_link;
700
+		$template_args['primary_registrant_name'] = $this->_primary_registrant->attendee()->full_name(true);
701
+		// link to SPCO payment_options
702
+		$template_args['show_try_pay_again_link'] = $this->_show_try_pay_again_link;
703
+		$template_args['SPCO_payment_options_url'] = $this->_SPCO_payment_options_url;
704
+		// verify template arguments
705
+		EEH_Template_Validator::verify_instanceof($template_args['transaction'], '$transaction', 'EE_Transaction');
706
+		EEH_Template_Validator::verify_isnt_null(
707
+			$template_args['show_try_pay_again_link'],
708
+			'$show_try_pay_again_link'
709
+		);
710
+		EEH_Template_Validator::verify_isnt_null(
711
+			$template_args['SPCO_payment_options_url'],
712
+			'$SPCO_payment_options_url'
713
+		);
714
+		return EEH_Template::locate_template(
715
+			THANK_YOU_TEMPLATES_PATH . 'thank-you-page-transaction-details.template.php',
716
+			$template_args,
717
+			true,
718
+			true
719
+		);
720
+	}
721
+
722
+
723
+	/**
724
+	 * get_payment_row_html
725
+	 *
726
+	 * @param EE_Payment $payment
727
+	 * @return string
728
+	 * @throws \EE_Error
729
+	 */
730
+	public function get_payment_row_html($payment = null)
731
+	{
732
+		$html = '';
733
+		if ($payment instanceof EE_Payment) {
734
+			if ($payment->payment_method() instanceof EE_Payment_Method
735
+				&& $payment->status() === EEM_Payment::status_id_failed
736
+				&& $payment->payment_method()->is_off_site()
737
+			) {
738
+				// considering the registrant has made it to the Thank You page,
739
+				// any failed payments may actually be pending and the IPN is just slow
740
+				// so let's
741
+				$payment->set_status(EEM_Payment::status_id_pending);
742
+			}
743
+			$payment_declined_msg = $payment->STS_ID() === EEM_Payment::status_id_declined
744
+				? '<br /><span class="small-text">' . $payment->gateway_response() . '</span>'
745
+				: '';
746
+			$html .= '
747 747
 				<tr>
748 748
 					<td>
749 749
 						' . $payment->timestamp() . '
750 750
 					</td>
751 751
 					<td>
752 752
 						' . (
753
-                $payment->payment_method() instanceof EE_Payment_Method
754
-                    ? $payment->payment_method()->name()
755
-                    : __('Unknown', 'event_espresso')
756
-                ) . '
753
+				$payment->payment_method() instanceof EE_Payment_Method
754
+					? $payment->payment_method()->name()
755
+					: __('Unknown', 'event_espresso')
756
+				) . '
757 757
 					</td>
758 758
 					<td class="jst-rght">
759 759
 						' . EEH_Template::format_currency($payment->amount()) . '
@@ -762,83 +762,83 @@  discard block
 block discarded – undo
762 762
 						' . $payment->pretty_status(true) . $payment_declined_msg . '
763 763
 					</td>
764 764
 				</tr>';
765
-            do_action('AHEE__thank_you_page_payment_details_template__after_each_payment', $payment);
766
-        }
767
-        return $html;
768
-    }
769
-
770
-
771
-    /**
772
-     * get_payment_details
773
-     *
774
-     * @param array $payments
775
-     * @return string
776
-     * @throws \EE_Error
777
-     */
778
-    public function get_payment_details($payments = array())
779
-    {
780
-        // prepare variables for displaying
781
-        $template_args = array();
782
-        $template_args['transaction'] = $this->_current_txn;
783
-        $template_args['reg_url_link'] = $this->_reg_url_link;
784
-        $template_args['payments'] = array();
785
-        foreach ($payments as $payment) {
786
-            $template_args['payments'][] = $this->get_payment_row_html($payment);
787
-        }
788
-        // create a hacky payment object, but dont save it
789
-        $payment = EE_Payment::new_instance(
790
-            array(
791
-                'TXN_ID'        => $this->_current_txn->ID(),
792
-                'STS_ID'        => EEM_Payment::status_id_pending,
793
-                'PAY_timestamp' => time(),
794
-                'PAY_amount'    => $this->_current_txn->total(),
795
-                'PMD_ID'        => $this->_current_txn->payment_method_ID(),
796
-            )
797
-        );
798
-        $payment_method = $this->_current_txn->payment_method();
799
-        if ($payment_method instanceof EE_Payment_Method && $payment_method->type_obj() instanceof EE_PMT_Base) {
800
-            $template_args['gateway_content'] = $payment_method->type_obj()->payment_overview_content($payment);
801
-        } else {
802
-            $template_args['gateway_content'] = '';
803
-        }
804
-        // link to SPCO payment_options
805
-        $template_args['show_try_pay_again_link'] = $this->_show_try_pay_again_link;
806
-        $template_args['SPCO_payment_options_url'] = $this->_SPCO_payment_options_url;
807
-        // verify template arguments
808
-        EEH_Template_Validator::verify_instanceof($template_args['transaction'], '$transaction', 'EE_Transaction');
809
-        EEH_Template_Validator::verify_isnt_null($template_args['payments'], '$payments');
810
-        EEH_Template_Validator::verify_isnt_null(
811
-            $template_args['show_try_pay_again_link'],
812
-            '$show_try_pay_again_link'
813
-        );
814
-        EEH_Template_Validator::verify_isnt_null($template_args['gateway_content'], '$gateway_content');
815
-        EEH_Template_Validator::verify_isnt_null(
816
-            $template_args['SPCO_payment_options_url'],
817
-            '$SPCO_payment_options_url'
818
-        );
819
-        return EEH_Template::locate_template(
820
-            THANK_YOU_TEMPLATES_PATH . 'thank-you-page-payment-details.template.php',
821
-            $template_args,
822
-            true,
823
-            true
824
-        );
825
-    }
826
-
827
-
828
-    /**
829
-     * get_payment_details
830
-     *
831
-     * @param array $payments
832
-     * @return string
833
-     * @throws \EE_Error
834
-     */
835
-    public function get_new_payments($payments = array())
836
-    {
837
-        $payments_html = '';
838
-        // prepare variables for displaying
839
-        foreach ($payments as $payment) {
840
-            $payments_html .= $this->get_payment_row_html($payment);
841
-        }
842
-        return $payments_html;
843
-    }
765
+			do_action('AHEE__thank_you_page_payment_details_template__after_each_payment', $payment);
766
+		}
767
+		return $html;
768
+	}
769
+
770
+
771
+	/**
772
+	 * get_payment_details
773
+	 *
774
+	 * @param array $payments
775
+	 * @return string
776
+	 * @throws \EE_Error
777
+	 */
778
+	public function get_payment_details($payments = array())
779
+	{
780
+		// prepare variables for displaying
781
+		$template_args = array();
782
+		$template_args['transaction'] = $this->_current_txn;
783
+		$template_args['reg_url_link'] = $this->_reg_url_link;
784
+		$template_args['payments'] = array();
785
+		foreach ($payments as $payment) {
786
+			$template_args['payments'][] = $this->get_payment_row_html($payment);
787
+		}
788
+		// create a hacky payment object, but dont save it
789
+		$payment = EE_Payment::new_instance(
790
+			array(
791
+				'TXN_ID'        => $this->_current_txn->ID(),
792
+				'STS_ID'        => EEM_Payment::status_id_pending,
793
+				'PAY_timestamp' => time(),
794
+				'PAY_amount'    => $this->_current_txn->total(),
795
+				'PMD_ID'        => $this->_current_txn->payment_method_ID(),
796
+			)
797
+		);
798
+		$payment_method = $this->_current_txn->payment_method();
799
+		if ($payment_method instanceof EE_Payment_Method && $payment_method->type_obj() instanceof EE_PMT_Base) {
800
+			$template_args['gateway_content'] = $payment_method->type_obj()->payment_overview_content($payment);
801
+		} else {
802
+			$template_args['gateway_content'] = '';
803
+		}
804
+		// link to SPCO payment_options
805
+		$template_args['show_try_pay_again_link'] = $this->_show_try_pay_again_link;
806
+		$template_args['SPCO_payment_options_url'] = $this->_SPCO_payment_options_url;
807
+		// verify template arguments
808
+		EEH_Template_Validator::verify_instanceof($template_args['transaction'], '$transaction', 'EE_Transaction');
809
+		EEH_Template_Validator::verify_isnt_null($template_args['payments'], '$payments');
810
+		EEH_Template_Validator::verify_isnt_null(
811
+			$template_args['show_try_pay_again_link'],
812
+			'$show_try_pay_again_link'
813
+		);
814
+		EEH_Template_Validator::verify_isnt_null($template_args['gateway_content'], '$gateway_content');
815
+		EEH_Template_Validator::verify_isnt_null(
816
+			$template_args['SPCO_payment_options_url'],
817
+			'$SPCO_payment_options_url'
818
+		);
819
+		return EEH_Template::locate_template(
820
+			THANK_YOU_TEMPLATES_PATH . 'thank-you-page-payment-details.template.php',
821
+			$template_args,
822
+			true,
823
+			true
824
+		);
825
+	}
826
+
827
+
828
+	/**
829
+	 * get_payment_details
830
+	 *
831
+	 * @param array $payments
832
+	 * @return string
833
+	 * @throws \EE_Error
834
+	 */
835
+	public function get_new_payments($payments = array())
836
+	{
837
+		$payments_html = '';
838
+		// prepare variables for displaying
839
+		foreach ($payments as $payment) {
840
+			$payments_html .= $this->get_payment_row_html($payment);
841
+		}
842
+		return $payments_html;
843
+	}
844 844
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -126,8 +126,8 @@  discard block
 block discarded – undo
126 126
      */
127 127
     public static function set_definitions()
128 128
     {
129
-        define('THANK_YOU_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets/');
130
-        define('THANK_YOU_TEMPLATES_PATH', str_replace('\\', '/', plugin_dir_path(__FILE__)) . 'templates/');
129
+        define('THANK_YOU_ASSETS_URL', plugin_dir_url(__FILE__).'assets/');
130
+        define('THANK_YOU_TEMPLATES_PATH', str_replace('\\', '/', plugin_dir_path(__FILE__)).'templates/');
131 131
     }
132 132
 
133 133
 
@@ -142,7 +142,7 @@  discard block
 block discarded – undo
142 142
             return $this->_current_txn;
143 143
         }
144 144
         $TXN_model = EE_Registry::instance()->load_model('Transaction');
145
-        if (! $TXN_model instanceof EEM_Transaction) {
145
+        if ( ! $TXN_model instanceof EEM_Transaction) {
146 146
             EE_Error::add_error(
147 147
                 __('The transaction model could not be established.', 'event_espresso'),
148 148
                 __FILE__,
@@ -179,7 +179,7 @@  discard block
 block discarded – undo
179 179
      */
180 180
     public function get_txn_payments($since = 0)
181 181
     {
182
-        if (! $this->get_txn()) {
182
+        if ( ! $this->get_txn()) {
183 183
             return false;
184 184
         }
185 185
         $args = array('order_by' => array('PAY_timestamp' => 'ASC'));
@@ -209,7 +209,7 @@  discard block
 block discarded – undo
209 209
      */
210 210
     private function _get_reg_url_link()
211 211
     {
212
-        if (! empty($this->_reg_url_link)) {
212
+        if ( ! empty($this->_reg_url_link)) {
213 213
             return;
214 214
         }
215 215
         // only do thank you page stuff if we have a REG_url_link in the url
@@ -321,7 +321,7 @@  discard block
 block discarded – undo
321 321
     {
322 322
         wp_register_script(
323 323
             'thank_you_page',
324
-            THANK_YOU_ASSETS_URL . 'thank_you_page.js',
324
+            THANK_YOU_ASSETS_URL.'thank_you_page.js',
325 325
             array('espresso_core', 'heartbeat'),
326 326
             EVENT_ESPRESSO_VERSION,
327 327
             true
@@ -340,9 +340,9 @@  discard block
 block discarded – undo
340 340
     public function init()
341 341
     {
342 342
         $this->_get_reg_url_link();
343
-        if (! $this->get_txn()) {
343
+        if ( ! $this->get_txn()) {
344 344
             echo EEH_HTML::div(
345
-                EEH_HTML::h4(__('We\'re sorry...', 'event_espresso'), '', '') .
345
+                EEH_HTML::h4(__('We\'re sorry...', 'event_espresso'), '', '').
346 346
                 sprintf(
347 347
                     __(
348 348
                         'This is a system page for displaying transaction information after a purchase.%1$sYou are most likely seeing this notice because you have navigated to this page%1$sthrough some means other than completing a transaction.%1$sSorry for the disappointment, but you will most likely find nothing of interest here.%1$s%1$s',
@@ -432,12 +432,12 @@  discard block
 block discarded – undo
432 432
     public function thank_you_page_results()
433 433
     {
434 434
         $this->init();
435
-        if (! $this->_current_txn instanceof EE_Transaction) {
435
+        if ( ! $this->_current_txn instanceof EE_Transaction) {
436 436
             return EE_Error::get_notices();
437 437
         }
438 438
         // link to receipt
439 439
         $template_args['TXN_receipt_url'] = $this->_current_txn->receipt_url('html');
440
-        if (! empty($template_args['TXN_receipt_url'])) {
440
+        if ( ! empty($template_args['TXN_receipt_url'])) {
441 441
             $template_args['order_conf_desc'] = __(
442 442
                 '%1$sCongratulations%2$sYour registration has been successfully processed.%3$sCheck your email for your registration confirmation or click the button below to view / download / print a full description of your purchases and registration information.',
443 443
                 'event_espresso'
@@ -455,7 +455,7 @@  discard block
 block discarded – undo
455 455
             add_action('AHEE__thank_you_page_overview_template__content', array($this, 'get_ajax_content'));
456 456
         }
457 457
         return EEH_Template::locate_template(
458
-            THANK_YOU_TEMPLATES_PATH . 'thank-you-page-overview.template.php',
458
+            THANK_YOU_TEMPLATES_PATH.'thank-you-page-overview.template.php',
459 459
             $template_args,
460 460
             true,
461 461
             true
@@ -507,7 +507,7 @@  discard block
 block discarded – undo
507 507
             '$SPCO_attendee_information_url'
508 508
         );
509 509
         echo EEH_Template::locate_template(
510
-            THANK_YOU_TEMPLATES_PATH . 'thank-you-page-registration-details.template.php',
510
+            THANK_YOU_TEMPLATES_PATH.'thank-you-page-registration-details.template.php',
511 511
             $template_args,
512 512
             true,
513 513
             true
@@ -580,7 +580,7 @@  discard block
 block discarded – undo
580 580
      */
581 581
     public function get_ajax_content()
582 582
     {
583
-        if (! $this->get_txn()) {
583
+        if ( ! $this->get_txn()) {
584 584
             return;
585 585
         }
586 586
         // first determine which event(s) require pre-approval or not
@@ -591,9 +591,9 @@  discard block
 block discarded – undo
591 591
                 $event = $registration->event();
592 592
                 if ($event instanceof EE_Event) {
593 593
                     if ($registration->is_not_approved() && $registration->event() instanceof EE_Event) {
594
-                        $events_requiring_pre_approval[ $event->ID() ] = $event;
594
+                        $events_requiring_pre_approval[$event->ID()] = $event;
595 595
                     } else {
596
-                        $events[ $event->ID() ] = $event;
596
+                        $events[$event->ID()] = $event;
597 597
                     }
598 598
                 }
599 599
             }
@@ -611,7 +611,7 @@  discard block
 block discarded – undo
611 611
      */
612 612
     public function display_details_for_events($events = array())
613 613
     {
614
-        if (! empty($events)) {
614
+        if ( ! empty($events)) {
615 615
             ?>
616 616
             <div id="espresso-thank-you-page-ajax-content-dv">
617 617
                 <div id="espresso-thank-you-page-ajax-transaction-dv"></div>
@@ -624,7 +624,7 @@  discard block
 block discarded – undo
624 624
                                 'event_espresso'
625 625
                             ); ?></span>
626 626
                     </div>
627
-                    <?php if (! $this->_is_offline_payment_method && ! $this->_payments_closed) : ?>
627
+                    <?php if ( ! $this->_is_offline_payment_method && ! $this->_payments_closed) : ?>
628 628
                         <p id="ee-ajax-loading-pg" class="highlight-bg small-text clear">
629 629
                             <?php echo apply_filters(
630 630
                                 'EED_Thank_You_Page__get_ajax_content__waiting_for_IPN_msg',
@@ -655,7 +655,7 @@  discard block
 block discarded – undo
655 655
      */
656 656
     public function display_details_for_events_requiring_pre_approval($events = array())
657 657
     {
658
-        if (! empty($events)) {
658
+        if ( ! empty($events)) {
659 659
             ?>
660 660
             <div id="espresso-thank-you-page-not-approved-message-dv">
661 661
                 <h4 class="orange-text"><?php _e('Important Notice:', 'event_espresso'); ?></h4>
@@ -712,7 +712,7 @@  discard block
 block discarded – undo
712 712
             '$SPCO_payment_options_url'
713 713
         );
714 714
         return EEH_Template::locate_template(
715
-            THANK_YOU_TEMPLATES_PATH . 'thank-you-page-transaction-details.template.php',
715
+            THANK_YOU_TEMPLATES_PATH.'thank-you-page-transaction-details.template.php',
716 716
             $template_args,
717 717
             true,
718 718
             true
@@ -741,25 +741,25 @@  discard block
 block discarded – undo
741 741
                 $payment->set_status(EEM_Payment::status_id_pending);
742 742
             }
743 743
             $payment_declined_msg = $payment->STS_ID() === EEM_Payment::status_id_declined
744
-                ? '<br /><span class="small-text">' . $payment->gateway_response() . '</span>'
744
+                ? '<br /><span class="small-text">'.$payment->gateway_response().'</span>'
745 745
                 : '';
746 746
             $html .= '
747 747
 				<tr>
748 748
 					<td>
749
-						' . $payment->timestamp() . '
749
+						' . $payment->timestamp().'
750 750
 					</td>
751 751
 					<td>
752 752
 						' . (
753 753
                 $payment->payment_method() instanceof EE_Payment_Method
754 754
                     ? $payment->payment_method()->name()
755 755
                     : __('Unknown', 'event_espresso')
756
-                ) . '
756
+                ).'
757 757
 					</td>
758 758
 					<td class="jst-rght">
759
-						' . EEH_Template::format_currency($payment->amount()) . '
759
+						' . EEH_Template::format_currency($payment->amount()).'
760 760
 					</td>
761 761
 					<td class="jst-rght" style="line-height:1;">
762
-						' . $payment->pretty_status(true) . $payment_declined_msg . '
762
+						' . $payment->pretty_status(true).$payment_declined_msg.'
763 763
 					</td>
764 764
 				</tr>';
765 765
             do_action('AHEE__thank_you_page_payment_details_template__after_each_payment', $payment);
@@ -817,7 +817,7 @@  discard block
 block discarded – undo
817 817
             '$SPCO_payment_options_url'
818 818
         );
819 819
         return EEH_Template::locate_template(
820
-            THANK_YOU_TEMPLATES_PATH . 'thank-you-page-payment-details.template.php',
820
+            THANK_YOU_TEMPLATES_PATH.'thank-you-page-payment-details.template.php',
821 821
             $template_args,
822 822
             true,
823 823
             true
Please login to merge, or discard this patch.
modules/core_rest_api/EED_Core_Rest_Api.module.php 2 patches
Indentation   +1329 added lines, -1329 removed lines patch added patch discarded remove patch
@@ -23,1333 +23,1333 @@
 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/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 || EED_Core_Rest_Api::debugMode()) {
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, true),
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
-                $model_routes[ $related_route ] = 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
-
547
-                $related_write_route = $related_route . '/' . '(?P<related_id>[^\/]+)';
548
-                $model_routes[ $related_write_route ] = array(
549
-                    array(
550
-                        'callback'        => array(
551
-                            'EventEspresso\core\libraries\rest_api\controllers\model\Write',
552
-                            'handleRequestAddRelation',
553
-                        ),
554
-                        'callback_args'   => array($version, $model_name, $relation_name),
555
-                        'methods'         => WP_REST_Server::EDITABLE,
556
-                        'hidden_endpoint' => $hidden_endpoint,
557
-                        'args'            => $this->_get_add_relation_query_params($model, $relation_obj->get_other_model(), $version)
558
-                    ),
559
-                    array(
560
-                        'callback'        => array(
561
-                            'EventEspresso\core\libraries\rest_api\controllers\model\Write',
562
-                            'handleRequestRemoveRelation',
563
-                        ),
564
-                        'callback_args'   => array($version, $model_name, $relation_name),
565
-                        'methods'         => WP_REST_Server::DELETABLE,
566
-                        'hidden_endpoint' => $hidden_endpoint,
567
-                        'args'            => array()
568
-                    ),
569
-                );
570
-            }
571
-        }
572
-        return $model_routes;
573
-    }
574
-
575
-
576
-    /**
577
-     * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace,
578
-     * excluding the preceding slash.
579
-     * Eg you pass get_plural_route_to('Event') = 'events'
580
-     *
581
-     * @param EEM_Base $model
582
-     * @return string
583
-     */
584
-    public static function get_collection_route(EEM_Base $model)
585
-    {
586
-        return EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
587
-    }
588
-
589
-
590
-    /**
591
-     * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
592
-     * excluding the preceding slash.
593
-     * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
594
-     *
595
-     * @param EEM_Base $model eg Event or Venue
596
-     * @param string   $id
597
-     * @return string
598
-     */
599
-    public static function get_entity_route($model, $id)
600
-    {
601
-        return EED_Core_Rest_Api::get_collection_route($model) . '/' . $id;
602
-    }
603
-
604
-
605
-    /**
606
-     * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
607
-     * excluding the preceding slash.
608
-     * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
609
-     *
610
-     * @param EEM_Base               $model eg Event or Venue
611
-     * @param string                 $id
612
-     * @param EE_Model_Relation_Base $relation_obj
613
-     * @return string
614
-     */
615
-    public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj)
616
-    {
617
-        $related_model_name_endpoint_part = ModelRead::getRelatedEntityName(
618
-            $relation_obj->get_other_model()->get_this_model_name(),
619
-            $relation_obj
620
-        );
621
-        return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
622
-    }
623
-
624
-
625
-    /**
626
-     * Adds onto the $relative_route the EE4 REST API versioned namespace.
627
-     * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events'
628
-     *
629
-     * @param string $relative_route
630
-     * @param string $version
631
-     * @return string
632
-     */
633
-    public static function get_versioned_route_to($relative_route, $version = '4.8.36')
634
-    {
635
-        return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
636
-    }
637
-
638
-
639
-    /**
640
-     * Adds all the RPC-style routes (remote procedure call-like routes, ie
641
-     * routes that don't conform to the traditional REST CRUD-style).
642
-     *
643
-     * @deprecated since 4.9.1
644
-     */
645
-    protected function _register_rpc_routes()
646
-    {
647
-        $routes = array();
648
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
649
-            $routes[ self::ee_api_namespace . $version ] = $this->_get_rpc_route_data_for_version(
650
-                $version,
651
-                $hidden_endpoint
652
-            );
653
-        }
654
-        return $routes;
655
-    }
656
-
657
-
658
-    /**
659
-     * @param string  $version
660
-     * @param boolean $hidden_endpoint
661
-     * @return array
662
-     */
663
-    protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false)
664
-    {
665
-        $this_versions_routes = array();
666
-        // checkin endpoint
667
-        $this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = array(
668
-            array(
669
-                'callback'        => array(
670
-                    'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin',
671
-                    'handleRequestToggleCheckin',
672
-                ),
673
-                'methods'         => WP_REST_Server::CREATABLE,
674
-                'hidden_endpoint' => $hidden_endpoint,
675
-                'args'            => array(
676
-                    'force' => array(
677
-                        'required'    => false,
678
-                        'default'     => false,
679
-                        'description' => __(
680
-                        // @codingStandardsIgnoreStart
681
-                            'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses',
682
-                            // @codingStandardsIgnoreEnd
683
-                            'event_espresso'
684
-                        ),
685
-                    ),
686
-                ),
687
-                'callback_args'   => array($version),
688
-            ),
689
-        );
690
-        return apply_filters(
691
-            'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes',
692
-            $this_versions_routes,
693
-            $version,
694
-            $hidden_endpoint
695
-        );
696
-    }
697
-
698
-
699
-    /**
700
-     * Gets the query params that can be used when request one or many
701
-     *
702
-     * @param EEM_Base $model
703
-     * @param string   $version
704
-     * @return array
705
-     */
706
-    protected function _get_response_selection_query_params(\EEM_Base $model, $version, $single_only = false)
707
-    {
708
-        $query_params = array(
709
-            'include'   => array(
710
-                'required' => false,
711
-                'default'  => '*',
712
-                'type'     => 'string',
713
-            ),
714
-            'calculate' => array(
715
-                'required'          => false,
716
-                'default'           => '',
717
-                'enum'              => self::$_field_calculator->retrieveCalculatedFieldsForModel($model),
718
-                'type'              => 'string',
719
-                // because we accept a CSV'd list of the enumerated strings, WP core validation and sanitization
720
-                // freaks out. We'll just validate this argument while handling the request
721
-                'validate_callback' => null,
722
-                'sanitize_callback' => null,
723
-            ),
724
-            'password' => array(
725
-                'required' => false,
726
-                'default' => '',
727
-                'type' => 'string'
728
-            )
729
-        );
730
-        return apply_filters(
731
-            'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
732
-            $query_params,
733
-            $model,
734
-            $version
735
-        );
736
-    }
737
-
738
-
739
-    /**
740
-     * Gets the parameters acceptable for delete requests
741
-     *
742
-     * @param \EEM_Base $model
743
-     * @param string    $version
744
-     * @return array
745
-     */
746
-    protected function _get_delete_query_params(\EEM_Base $model, $version)
747
-    {
748
-        $params_for_delete = array(
749
-            'allow_blocking' => array(
750
-                'required' => false,
751
-                'default'  => true,
752
-                'type'     => 'boolean',
753
-            ),
754
-        );
755
-        $params_for_delete['force'] = array(
756
-            'required' => false,
757
-            'default'  => false,
758
-            'type'     => 'boolean',
759
-        );
760
-        return apply_filters(
761
-            'FHEE__EED_Core_Rest_Api___get_delete_query_params',
762
-            $params_for_delete,
763
-            $model,
764
-            $version
765
-        );
766
-    }
767
-
768
-    protected function _get_add_relation_query_params(\EEM_Base $source_model, \EEM_Base $related_model, $version)
769
-    {
770
-        // if they're related through a HABTM relation, check for any non-FKs
771
-        $all_relation_settings = $source_model->relation_settings();
772
-        $relation_settings = $all_relation_settings[ $related_model->get_this_model_name() ];
773
-        $params = array();
774
-        if ($relation_settings instanceof EE_HABTM_Relation && $relation_settings->hasNonKeyFields()) {
775
-            foreach ($relation_settings->getNonKeyFields() as $field) {
776
-                /* @var $field EE_Model_Field_Base */
777
-                $params[ $field->get_name() ] = array(
778
-                    'required' => ! $field->is_nullable(),
779
-                    'default' => ModelDataTranslator::prepareFieldValueForJson($field, $field->get_default_value(), $version),
780
-                    'type' => $field->getSchemaType(),
781
-                    'validate_callbaack' => null,
782
-                    'sanitize_callback' => null
783
-                );
784
-            }
785
-        }
786
-        return $params;
787
-    }
788
-
789
-
790
-    /**
791
-     * Gets info about reading query params that are acceptable
792
-     *
793
-     * @param \EEM_Base $model eg 'Event' or 'Venue'
794
-     * @param  string   $version
795
-     * @return array    describing the args acceptable when querying this model
796
-     * @throws EE_Error
797
-     */
798
-    protected function _get_read_query_params(\EEM_Base $model, $version)
799
-    {
800
-        $default_orderby = array();
801
-        foreach ($model->get_combined_primary_key_fields() as $key_field) {
802
-            $default_orderby[ $key_field->get_name() ] = 'ASC';
803
-        }
804
-        return array_merge(
805
-            $this->_get_response_selection_query_params($model, $version),
806
-            array(
807
-                'where'    => array(
808
-                    'required'          => false,
809
-                    'default'           => array(),
810
-                    'type'              => 'object',
811
-                    // because we accept an almost infinite list of possible where conditions, WP
812
-                    // core validation and sanitization freaks out. We'll just validate this argument
813
-                    // while handling the request
814
-                    'validate_callback' => null,
815
-                    'sanitize_callback' => null,
816
-                ),
817
-                'limit'    => array(
818
-                    'required'          => false,
819
-                    'default'           => EED_Core_Rest_Api::get_default_query_limit(),
820
-                    'type'              => array(
821
-                        'array',
822
-                        'string',
823
-                        'integer',
824
-                    ),
825
-                    // because we accept a variety of types, WP core validation and sanitization
826
-                    // freaks out. We'll just validate this argument while handling the request
827
-                    'validate_callback' => null,
828
-                    'sanitize_callback' => null,
829
-                ),
830
-                'order_by' => array(
831
-                    'required'          => false,
832
-                    'default'           => $default_orderby,
833
-                    'type'              => array(
834
-                        'object',
835
-                        'string',
836
-                    ),// because we accept a variety of types, WP core validation and sanitization
837
-                    // freaks out. We'll just validate this argument while handling the request
838
-                    'validate_callback' => null,
839
-                    'sanitize_callback' => null,
840
-                ),
841
-                'group_by' => array(
842
-                    'required'          => false,
843
-                    'default'           => null,
844
-                    'type'              => array(
845
-                        'object',
846
-                        'string',
847
-                    ),
848
-                    // because we accept  an almost infinite list of possible groupings,
849
-                    // WP core validation and sanitization
850
-                    // freaks out. We'll just validate this argument while handling the request
851
-                    'validate_callback' => null,
852
-                    'sanitize_callback' => null,
853
-                ),
854
-                'having'   => array(
855
-                    'required'          => false,
856
-                    'default'           => null,
857
-                    'type'              => 'object',
858
-                    // because we accept an almost infinite list of possible where conditions, WP
859
-                    // core validation and sanitization freaks out. We'll just validate this argument
860
-                    // while handling the request
861
-                    'validate_callback' => null,
862
-                    'sanitize_callback' => null,
863
-                ),
864
-                'caps'     => array(
865
-                    'required' => false,
866
-                    'default'  => EEM_Base::caps_read,
867
-                    'type'     => 'string',
868
-                    'enum'     => array(
869
-                        EEM_Base::caps_read,
870
-                        EEM_Base::caps_read_admin,
871
-                        EEM_Base::caps_edit,
872
-                        EEM_Base::caps_delete,
873
-                    ),
874
-                ),
875
-            )
876
-        );
877
-    }
878
-
879
-
880
-    /**
881
-     * Gets parameter information for a model regarding writing data
882
-     *
883
-     * @param string           $model_name
884
-     * @param ModelVersionInfo $model_version_info
885
-     * @param boolean          $create                                       whether this is for request to create (in
886
-     *                                                                       which case we need all required params) or
887
-     *                                                                       just to update (in which case we don't
888
-     *                                                                       need those on every request)
889
-     * @return array
890
-     */
891
-    protected function _get_write_params(
892
-        $model_name,
893
-        ModelVersionInfo $model_version_info,
894
-        $create = false
895
-    ) {
896
-        $model = EE_Registry::instance()->load_model($model_name);
897
-        $fields = $model_version_info->fieldsOnModelInThisVersion($model);
898
-        $args_info = array();
899
-        foreach ($fields as $field_name => $field_obj) {
900
-            if ($field_obj->is_auto_increment()) {
901
-                // totally ignore auto increment IDs
902
-                continue;
903
-            }
904
-            $arg_info = $field_obj->getSchema();
905
-            $required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null;
906
-            $arg_info['required'] = $required;
907
-            // remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right?
908
-            unset($arg_info['readonly']);
909
-            $schema_properties = $field_obj->getSchemaProperties();
910
-            if (isset($schema_properties['raw'])
911
-                && $field_obj->getSchemaType() === 'object'
912
-            ) {
913
-                // if there's a "raw" form of this argument, use those properties instead
914
-                $arg_info = array_replace(
915
-                    $arg_info,
916
-                    $schema_properties['raw']
917
-                );
918
-            }
919
-            $arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson(
920
-                $field_obj,
921
-                $field_obj->get_default_value(),
922
-                $model_version_info->requestedVersion()
923
-            );
924
-            // we do our own validation and sanitization within the controller
925
-            if (function_exists('rest_validate_value_from_schema')) {
926
-                $sanitize_callback = array(
927
-                    'EED_Core_Rest_Api',
928
-                    'default_sanitize_callback',
929
-                );
930
-            } else {
931
-                $sanitize_callback = null;
932
-            }
933
-            $arg_info['sanitize_callback'] = $sanitize_callback;
934
-            $args_info[ $field_name ] = $arg_info;
935
-            if ($field_obj instanceof EE_Datetime_Field) {
936
-                $gmt_arg_info = $arg_info;
937
-                $gmt_arg_info['description'] = sprintf(
938
-                    esc_html__(
939
-                        '%1$s - the value for this field in UTC. Ignored if %2$s is provided.',
940
-                        'event_espresso'
941
-                    ),
942
-                    $field_obj->get_nicename(),
943
-                    $field_name
944
-                );
945
-                $args_info[ $field_name . '_gmt' ] = $gmt_arg_info;
946
-            }
947
-        }
948
-        return $args_info;
949
-    }
950
-
951
-
952
-    /**
953
-     * Replacement for WP API's 'rest_parse_request_arg'.
954
-     * If the value is blank but not required, don't bother validating it.
955
-     * Also, it uses our email validation instead of WP API's default.
956
-     *
957
-     * @param                 $value
958
-     * @param WP_REST_Request $request
959
-     * @param                 $param
960
-     * @return bool|true|WP_Error
961
-     * @throws InvalidArgumentException
962
-     * @throws InvalidInterfaceException
963
-     * @throws InvalidDataTypeException
964
-     */
965
-    public static function default_sanitize_callback($value, WP_REST_Request $request, $param)
966
-    {
967
-        $attributes = $request->get_attributes();
968
-        if (! isset($attributes['args'][ $param ])
969
-            || ! is_array($attributes['args'][ $param ])) {
970
-            $validation_result = true;
971
-        } else {
972
-            $args = $attributes['args'][ $param ];
973
-            if ((
974
-                    $value === ''
975
-                    || $value === null
976
-                )
977
-                && (! isset($args['required'])
978
-                    || $args['required'] === false
979
-                )
980
-            ) {
981
-                // not required and not provided? that's cool
982
-                $validation_result = true;
983
-            } elseif (isset($args['format'])
984
-                      && $args['format'] === 'email'
985
-            ) {
986
-                $validation_result = true;
987
-                if (! self::_validate_email($value)) {
988
-                    $validation_result = new WP_Error(
989
-                        'rest_invalid_param',
990
-                        esc_html__(
991
-                            'The email address is not valid or does not exist.',
992
-                            'event_espresso'
993
-                        )
994
-                    );
995
-                }
996
-            } else {
997
-                $validation_result = rest_validate_value_from_schema($value, $args, $param);
998
-            }
999
-        }
1000
-        if (is_wp_error($validation_result)) {
1001
-            return $validation_result;
1002
-        }
1003
-        return rest_sanitize_request_arg($value, $request, $param);
1004
-    }
1005
-
1006
-
1007
-    /**
1008
-     * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email()
1009
-     *
1010
-     * @param $email
1011
-     * @return bool
1012
-     * @throws InvalidArgumentException
1013
-     * @throws InvalidInterfaceException
1014
-     * @throws InvalidDataTypeException
1015
-     */
1016
-    protected static function _validate_email($email)
1017
-    {
1018
-        try {
1019
-            EmailAddressFactory::create($email);
1020
-            return true;
1021
-        } catch (EmailValidationException $e) {
1022
-            return false;
1023
-        }
1024
-    }
1025
-
1026
-
1027
-    /**
1028
-     * Gets routes for the config
1029
-     *
1030
-     * @return array @see _register_model_routes
1031
-     * @deprecated since version 4.9.1
1032
-     */
1033
-    protected function _register_config_routes()
1034
-    {
1035
-        $config_routes = array();
1036
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
1037
-            $config_routes[ self::ee_api_namespace . $version ] = $this->_get_config_route_data_for_version(
1038
-                $version,
1039
-                $hidden_endpoint
1040
-            );
1041
-        }
1042
-        return $config_routes;
1043
-    }
1044
-
1045
-
1046
-    /**
1047
-     * Gets routes for the config for the specified version
1048
-     *
1049
-     * @param string  $version
1050
-     * @param boolean $hidden_endpoint
1051
-     * @return array
1052
-     */
1053
-    protected function _get_config_route_data_for_version($version, $hidden_endpoint)
1054
-    {
1055
-        return array(
1056
-            'config'    => array(
1057
-                array(
1058
-                    'callback'        => array(
1059
-                        'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1060
-                        'handleRequest',
1061
-                    ),
1062
-                    'methods'         => WP_REST_Server::READABLE,
1063
-                    'hidden_endpoint' => $hidden_endpoint,
1064
-                    'callback_args'   => array($version),
1065
-                ),
1066
-            ),
1067
-            'site_info' => array(
1068
-                array(
1069
-                    'callback'        => array(
1070
-                        'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1071
-                        'handleRequestSiteInfo',
1072
-                    ),
1073
-                    'methods'         => WP_REST_Server::READABLE,
1074
-                    'hidden_endpoint' => $hidden_endpoint,
1075
-                    'callback_args'   => array($version),
1076
-                ),
1077
-            ),
1078
-        );
1079
-    }
1080
-
1081
-
1082
-    /**
1083
-     * Gets the meta info routes
1084
-     *
1085
-     * @return array @see _register_model_routes
1086
-     * @deprecated since version 4.9.1
1087
-     */
1088
-    protected function _register_meta_routes()
1089
-    {
1090
-        $meta_routes = array();
1091
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
1092
-            $meta_routes[ self::ee_api_namespace . $version ] = $this->_get_meta_route_data_for_version(
1093
-                $version,
1094
-                $hidden_endpoint
1095
-            );
1096
-        }
1097
-        return $meta_routes;
1098
-    }
1099
-
1100
-
1101
-    /**
1102
-     * @param string  $version
1103
-     * @param boolean $hidden_endpoint
1104
-     * @return array
1105
-     */
1106
-    protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false)
1107
-    {
1108
-        return array(
1109
-            'resources' => array(
1110
-                array(
1111
-                    'callback'        => array(
1112
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Meta',
1113
-                        'handleRequestModelsMeta',
1114
-                    ),
1115
-                    'methods'         => WP_REST_Server::READABLE,
1116
-                    'hidden_endpoint' => $hidden_endpoint,
1117
-                    'callback_args'   => array($version),
1118
-                ),
1119
-            ),
1120
-        );
1121
-    }
1122
-
1123
-
1124
-    /**
1125
-     * Tries to hide old 4.6 endpoints from the
1126
-     *
1127
-     * @param array $route_data
1128
-     * @return array
1129
-     * @throws \EE_Error
1130
-     */
1131
-    public static function hide_old_endpoints($route_data)
1132
-    {
1133
-        // allow API clients to override which endpoints get hidden, in case
1134
-        // they want to discover particular endpoints
1135
-        // also, we don't have access to the request so we have to just grab it from the superglobal
1136
-        $force_show_ee_namespace = ltrim(
1137
-            EEH_Array::is_set($_REQUEST, 'force_show_ee_namespace', ''),
1138
-            '/'
1139
-        );
1140
-        foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) {
1141
-            foreach ($relative_urls as $resource_name => $endpoints) {
1142
-                foreach ($endpoints as $key => $endpoint) {
1143
-                    // skip schema and other route options
1144
-                    if (! is_numeric($key)) {
1145
-                        continue;
1146
-                    }
1147
-                    // by default, hide "hidden_endpoint"s, unless the request indicates
1148
-                    // to $force_show_ee_namespace, in which case only show that one
1149
-                    // namespace's endpoints (and hide all others)
1150
-                    if (($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1151
-                        || ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1152
-                    ) {
1153
-                        $full_route = '/' . ltrim($namespace, '/');
1154
-                        $full_route .= '/' . ltrim($resource_name, '/');
1155
-                        unset($route_data[ $full_route ]);
1156
-                    }
1157
-                }
1158
-            }
1159
-        }
1160
-        return $route_data;
1161
-    }
1162
-
1163
-
1164
-    /**
1165
-     * Returns an array describing which versions of core support serving requests for.
1166
-     * Keys are core versions' major and minor version, and values are the
1167
-     * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like
1168
-     * data by just removing a few models and fields from the responses. However, 4.15 might remove
1169
-     * the answers table entirely, in which case it would be very difficult for
1170
-     * it to serve 4.6-style responses.
1171
-     * Versions of core that are missing from this array are unknowns.
1172
-     * previous ver
1173
-     *
1174
-     * @return array
1175
-     */
1176
-    public static function version_compatibilities()
1177
-    {
1178
-        return apply_filters(
1179
-            'FHEE__EED_Core_REST_API__version_compatibilities',
1180
-            array(
1181
-                '4.8.29' => '4.8.29',
1182
-                '4.8.33' => '4.8.29',
1183
-                '4.8.34' => '4.8.29',
1184
-                '4.8.36' => '4.8.29',
1185
-            )
1186
-        );
1187
-    }
1188
-
1189
-
1190
-    /**
1191
-     * Gets the latest API version served. Eg if there
1192
-     * are two versions served of the API, 4.8.29 and 4.8.32, and
1193
-     * we are on core version 4.8.34, it will return the string "4.8.32"
1194
-     *
1195
-     * @return string
1196
-     */
1197
-    public static function latest_rest_api_version()
1198
-    {
1199
-        $versions_served = \EED_Core_Rest_Api::versions_served();
1200
-        $versions_served_keys = array_keys($versions_served);
1201
-        return end($versions_served_keys);
1202
-    }
1203
-
1204
-
1205
-    /**
1206
-     * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of
1207
-     * EE the API can serve requests for. Eg, if we are on 4.15 of core, and
1208
-     * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ).
1209
-     * We also indicate whether or not this version should be put in the index or not
1210
-     *
1211
-     * @return array keys are API version numbers (just major and minor numbers), and values
1212
-     * are whether or not they should be hidden
1213
-     */
1214
-    public static function versions_served()
1215
-    {
1216
-        $versions_served = array();
1217
-        $possibly_served_versions = EED_Core_Rest_Api::version_compatibilities();
1218
-        $lowest_compatible_version = end($possibly_served_versions);
1219
-        reset($possibly_served_versions);
1220
-        $versions_served_historically = array_keys($possibly_served_versions);
1221
-        $latest_version = end($versions_served_historically);
1222
-        reset($versions_served_historically);
1223
-        // for each version of core we have ever served:
1224
-        foreach ($versions_served_historically as $key_versioned_endpoint) {
1225
-            // if it's not above the current core version, and it's compatible with the current version of core
1226
-
1227
-            if ($key_versioned_endpoint === $latest_version) {
1228
-                // don't hide the latest version in the index
1229
-                $versions_served[ $key_versioned_endpoint ] = false;
1230
-            } elseif (version_compare($key_versioned_endpoint, $lowest_compatible_version, '>=')
1231
-                && version_compare($key_versioned_endpoint, EED_Core_Rest_Api::core_version(), '<')
1232
-            ) {
1233
-                // include, but hide, previous versions which are still supported
1234
-                $versions_served[ $key_versioned_endpoint ] = true;
1235
-            } elseif (apply_filters(
1236
-                'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions',
1237
-                false,
1238
-                $possibly_served_versions
1239
-            )) {
1240
-                // if a version is no longer supported, don't include it in index or list of versions served
1241
-                $versions_served[ $key_versioned_endpoint ] = true;
1242
-            }
1243
-        }
1244
-        return $versions_served;
1245
-    }
1246
-
1247
-
1248
-    /**
1249
-     * Gets the major and minor version of EE core's version string
1250
-     *
1251
-     * @return string
1252
-     */
1253
-    public static function core_version()
1254
-    {
1255
-        return apply_filters(
1256
-            'FHEE__EED_Core_REST_API__core_version',
1257
-            implode(
1258
-                '.',
1259
-                array_slice(
1260
-                    explode(
1261
-                        '.',
1262
-                        espresso_version()
1263
-                    ),
1264
-                    0,
1265
-                    3
1266
-                )
1267
-            )
1268
-        );
1269
-    }
1270
-
1271
-
1272
-    /**
1273
-     * Gets the default limit that should be used when querying for resources
1274
-     *
1275
-     * @return int
1276
-     */
1277
-    public static function get_default_query_limit()
1278
-    {
1279
-        // we actually don't use a const because we want folks to always use
1280
-        // this method, not the const directly
1281
-        return apply_filters(
1282
-            'FHEE__EED_Core_Rest_Api__get_default_query_limit',
1283
-            50
1284
-        );
1285
-    }
1286
-
1287
-
1288
-    /**
1289
-     *
1290
-     * @param string $version api version string (i.e. '4.8.36')
1291
-     * @return array
1292
-     */
1293
-    public static function getCollectionRoutesIndexedByModelName($version = '')
1294
-    {
1295
-        $version = empty($version) ? self::latest_rest_api_version() : $version;
1296
-        $model_names = self::model_names_with_plural_routes($version);
1297
-        $collection_routes = array();
1298
-        foreach ($model_names as $model_name => $model_class_name) {
1299
-            $collection_routes[ strtolower($model_name) ] = '/' . self::ee_api_namespace . $version . '/'
1300
-                                                            . EEH_Inflector::pluralize_and_lower($model_name);
1301
-        }
1302
-        return $collection_routes;
1303
-    }
1304
-
1305
-
1306
-    /**
1307
-     * Returns an array of primary key names indexed by model names.
1308
-     * @param string $version
1309
-     * @return array
1310
-     */
1311
-    public static function getPrimaryKeyNamesIndexedByModelName($version = '')
1312
-    {
1313
-        $version = empty($version) ? self::latest_rest_api_version() : $version;
1314
-        $model_names = self::model_names_with_plural_routes($version);
1315
-        $primary_key_items = array();
1316
-        foreach ($model_names as $model_name => $model_class_name) {
1317
-            $primary_keys = $model_class_name::instance()->get_combined_primary_key_fields();
1318
-            foreach ($primary_keys as $primary_key_name => $primary_key_field) {
1319
-                if (count($primary_keys) > 1) {
1320
-                    $primary_key_items[ strtolower($model_name) ][] = $primary_key_name;
1321
-                } else {
1322
-                    $primary_key_items[ strtolower($model_name) ] = $primary_key_name;
1323
-                }
1324
-            }
1325
-        }
1326
-        return $primary_key_items;
1327
-    }
1328
-
1329
-    /**
1330
-     * Determines the EE REST API debug mode is activated, or not.
1331
-     * @since 4.9.76.p
1332
-     * @return bool
1333
-     */
1334
-    public static function debugMode()
1335
-    {
1336
-        static $debug_mode = null; // could be class prop
1337
-        if ($debug_mode === null) {
1338
-            $debug_mode = defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE;
1339
-        }
1340
-        return $debug_mode;
1341
-    }
1342
-
1343
-
1344
-
1345
-    /**
1346
-     *    run - initial module setup
1347
-     *
1348
-     * @access    public
1349
-     * @param  WP $WP
1350
-     * @return    void
1351
-     */
1352
-    public function run($WP)
1353
-    {
1354
-    }
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/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 || EED_Core_Rest_Api::debugMode()) {
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, true),
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
+				$model_routes[ $related_route ] = 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
+
547
+				$related_write_route = $related_route . '/' . '(?P<related_id>[^\/]+)';
548
+				$model_routes[ $related_write_route ] = array(
549
+					array(
550
+						'callback'        => array(
551
+							'EventEspresso\core\libraries\rest_api\controllers\model\Write',
552
+							'handleRequestAddRelation',
553
+						),
554
+						'callback_args'   => array($version, $model_name, $relation_name),
555
+						'methods'         => WP_REST_Server::EDITABLE,
556
+						'hidden_endpoint' => $hidden_endpoint,
557
+						'args'            => $this->_get_add_relation_query_params($model, $relation_obj->get_other_model(), $version)
558
+					),
559
+					array(
560
+						'callback'        => array(
561
+							'EventEspresso\core\libraries\rest_api\controllers\model\Write',
562
+							'handleRequestRemoveRelation',
563
+						),
564
+						'callback_args'   => array($version, $model_name, $relation_name),
565
+						'methods'         => WP_REST_Server::DELETABLE,
566
+						'hidden_endpoint' => $hidden_endpoint,
567
+						'args'            => array()
568
+					),
569
+				);
570
+			}
571
+		}
572
+		return $model_routes;
573
+	}
574
+
575
+
576
+	/**
577
+	 * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace,
578
+	 * excluding the preceding slash.
579
+	 * Eg you pass get_plural_route_to('Event') = 'events'
580
+	 *
581
+	 * @param EEM_Base $model
582
+	 * @return string
583
+	 */
584
+	public static function get_collection_route(EEM_Base $model)
585
+	{
586
+		return EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
587
+	}
588
+
589
+
590
+	/**
591
+	 * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
592
+	 * excluding the preceding slash.
593
+	 * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
594
+	 *
595
+	 * @param EEM_Base $model eg Event or Venue
596
+	 * @param string   $id
597
+	 * @return string
598
+	 */
599
+	public static function get_entity_route($model, $id)
600
+	{
601
+		return EED_Core_Rest_Api::get_collection_route($model) . '/' . $id;
602
+	}
603
+
604
+
605
+	/**
606
+	 * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
607
+	 * excluding the preceding slash.
608
+	 * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
609
+	 *
610
+	 * @param EEM_Base               $model eg Event or Venue
611
+	 * @param string                 $id
612
+	 * @param EE_Model_Relation_Base $relation_obj
613
+	 * @return string
614
+	 */
615
+	public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj)
616
+	{
617
+		$related_model_name_endpoint_part = ModelRead::getRelatedEntityName(
618
+			$relation_obj->get_other_model()->get_this_model_name(),
619
+			$relation_obj
620
+		);
621
+		return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
622
+	}
623
+
624
+
625
+	/**
626
+	 * Adds onto the $relative_route the EE4 REST API versioned namespace.
627
+	 * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events'
628
+	 *
629
+	 * @param string $relative_route
630
+	 * @param string $version
631
+	 * @return string
632
+	 */
633
+	public static function get_versioned_route_to($relative_route, $version = '4.8.36')
634
+	{
635
+		return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
636
+	}
637
+
638
+
639
+	/**
640
+	 * Adds all the RPC-style routes (remote procedure call-like routes, ie
641
+	 * routes that don't conform to the traditional REST CRUD-style).
642
+	 *
643
+	 * @deprecated since 4.9.1
644
+	 */
645
+	protected function _register_rpc_routes()
646
+	{
647
+		$routes = array();
648
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
649
+			$routes[ self::ee_api_namespace . $version ] = $this->_get_rpc_route_data_for_version(
650
+				$version,
651
+				$hidden_endpoint
652
+			);
653
+		}
654
+		return $routes;
655
+	}
656
+
657
+
658
+	/**
659
+	 * @param string  $version
660
+	 * @param boolean $hidden_endpoint
661
+	 * @return array
662
+	 */
663
+	protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false)
664
+	{
665
+		$this_versions_routes = array();
666
+		// checkin endpoint
667
+		$this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = array(
668
+			array(
669
+				'callback'        => array(
670
+					'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin',
671
+					'handleRequestToggleCheckin',
672
+				),
673
+				'methods'         => WP_REST_Server::CREATABLE,
674
+				'hidden_endpoint' => $hidden_endpoint,
675
+				'args'            => array(
676
+					'force' => array(
677
+						'required'    => false,
678
+						'default'     => false,
679
+						'description' => __(
680
+						// @codingStandardsIgnoreStart
681
+							'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses',
682
+							// @codingStandardsIgnoreEnd
683
+							'event_espresso'
684
+						),
685
+					),
686
+				),
687
+				'callback_args'   => array($version),
688
+			),
689
+		);
690
+		return apply_filters(
691
+			'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes',
692
+			$this_versions_routes,
693
+			$version,
694
+			$hidden_endpoint
695
+		);
696
+	}
697
+
698
+
699
+	/**
700
+	 * Gets the query params that can be used when request one or many
701
+	 *
702
+	 * @param EEM_Base $model
703
+	 * @param string   $version
704
+	 * @return array
705
+	 */
706
+	protected function _get_response_selection_query_params(\EEM_Base $model, $version, $single_only = false)
707
+	{
708
+		$query_params = array(
709
+			'include'   => array(
710
+				'required' => false,
711
+				'default'  => '*',
712
+				'type'     => 'string',
713
+			),
714
+			'calculate' => array(
715
+				'required'          => false,
716
+				'default'           => '',
717
+				'enum'              => self::$_field_calculator->retrieveCalculatedFieldsForModel($model),
718
+				'type'              => 'string',
719
+				// because we accept a CSV'd list of the enumerated strings, WP core validation and sanitization
720
+				// freaks out. We'll just validate this argument while handling the request
721
+				'validate_callback' => null,
722
+				'sanitize_callback' => null,
723
+			),
724
+			'password' => array(
725
+				'required' => false,
726
+				'default' => '',
727
+				'type' => 'string'
728
+			)
729
+		);
730
+		return apply_filters(
731
+			'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
732
+			$query_params,
733
+			$model,
734
+			$version
735
+		);
736
+	}
737
+
738
+
739
+	/**
740
+	 * Gets the parameters acceptable for delete requests
741
+	 *
742
+	 * @param \EEM_Base $model
743
+	 * @param string    $version
744
+	 * @return array
745
+	 */
746
+	protected function _get_delete_query_params(\EEM_Base $model, $version)
747
+	{
748
+		$params_for_delete = array(
749
+			'allow_blocking' => array(
750
+				'required' => false,
751
+				'default'  => true,
752
+				'type'     => 'boolean',
753
+			),
754
+		);
755
+		$params_for_delete['force'] = array(
756
+			'required' => false,
757
+			'default'  => false,
758
+			'type'     => 'boolean',
759
+		);
760
+		return apply_filters(
761
+			'FHEE__EED_Core_Rest_Api___get_delete_query_params',
762
+			$params_for_delete,
763
+			$model,
764
+			$version
765
+		);
766
+	}
767
+
768
+	protected function _get_add_relation_query_params(\EEM_Base $source_model, \EEM_Base $related_model, $version)
769
+	{
770
+		// if they're related through a HABTM relation, check for any non-FKs
771
+		$all_relation_settings = $source_model->relation_settings();
772
+		$relation_settings = $all_relation_settings[ $related_model->get_this_model_name() ];
773
+		$params = array();
774
+		if ($relation_settings instanceof EE_HABTM_Relation && $relation_settings->hasNonKeyFields()) {
775
+			foreach ($relation_settings->getNonKeyFields() as $field) {
776
+				/* @var $field EE_Model_Field_Base */
777
+				$params[ $field->get_name() ] = array(
778
+					'required' => ! $field->is_nullable(),
779
+					'default' => ModelDataTranslator::prepareFieldValueForJson($field, $field->get_default_value(), $version),
780
+					'type' => $field->getSchemaType(),
781
+					'validate_callbaack' => null,
782
+					'sanitize_callback' => null
783
+				);
784
+			}
785
+		}
786
+		return $params;
787
+	}
788
+
789
+
790
+	/**
791
+	 * Gets info about reading query params that are acceptable
792
+	 *
793
+	 * @param \EEM_Base $model eg 'Event' or 'Venue'
794
+	 * @param  string   $version
795
+	 * @return array    describing the args acceptable when querying this model
796
+	 * @throws EE_Error
797
+	 */
798
+	protected function _get_read_query_params(\EEM_Base $model, $version)
799
+	{
800
+		$default_orderby = array();
801
+		foreach ($model->get_combined_primary_key_fields() as $key_field) {
802
+			$default_orderby[ $key_field->get_name() ] = 'ASC';
803
+		}
804
+		return array_merge(
805
+			$this->_get_response_selection_query_params($model, $version),
806
+			array(
807
+				'where'    => array(
808
+					'required'          => false,
809
+					'default'           => array(),
810
+					'type'              => 'object',
811
+					// because we accept an almost infinite list of possible where conditions, WP
812
+					// core validation and sanitization freaks out. We'll just validate this argument
813
+					// while handling the request
814
+					'validate_callback' => null,
815
+					'sanitize_callback' => null,
816
+				),
817
+				'limit'    => array(
818
+					'required'          => false,
819
+					'default'           => EED_Core_Rest_Api::get_default_query_limit(),
820
+					'type'              => array(
821
+						'array',
822
+						'string',
823
+						'integer',
824
+					),
825
+					// because we accept a variety of types, WP core validation and sanitization
826
+					// freaks out. We'll just validate this argument while handling the request
827
+					'validate_callback' => null,
828
+					'sanitize_callback' => null,
829
+				),
830
+				'order_by' => array(
831
+					'required'          => false,
832
+					'default'           => $default_orderby,
833
+					'type'              => array(
834
+						'object',
835
+						'string',
836
+					),// because we accept a variety of types, WP core validation and sanitization
837
+					// freaks out. We'll just validate this argument while handling the request
838
+					'validate_callback' => null,
839
+					'sanitize_callback' => null,
840
+				),
841
+				'group_by' => array(
842
+					'required'          => false,
843
+					'default'           => null,
844
+					'type'              => array(
845
+						'object',
846
+						'string',
847
+					),
848
+					// because we accept  an almost infinite list of possible groupings,
849
+					// WP core validation and sanitization
850
+					// freaks out. We'll just validate this argument while handling the request
851
+					'validate_callback' => null,
852
+					'sanitize_callback' => null,
853
+				),
854
+				'having'   => array(
855
+					'required'          => false,
856
+					'default'           => null,
857
+					'type'              => 'object',
858
+					// because we accept an almost infinite list of possible where conditions, WP
859
+					// core validation and sanitization freaks out. We'll just validate this argument
860
+					// while handling the request
861
+					'validate_callback' => null,
862
+					'sanitize_callback' => null,
863
+				),
864
+				'caps'     => array(
865
+					'required' => false,
866
+					'default'  => EEM_Base::caps_read,
867
+					'type'     => 'string',
868
+					'enum'     => array(
869
+						EEM_Base::caps_read,
870
+						EEM_Base::caps_read_admin,
871
+						EEM_Base::caps_edit,
872
+						EEM_Base::caps_delete,
873
+					),
874
+				),
875
+			)
876
+		);
877
+	}
878
+
879
+
880
+	/**
881
+	 * Gets parameter information for a model regarding writing data
882
+	 *
883
+	 * @param string           $model_name
884
+	 * @param ModelVersionInfo $model_version_info
885
+	 * @param boolean          $create                                       whether this is for request to create (in
886
+	 *                                                                       which case we need all required params) or
887
+	 *                                                                       just to update (in which case we don't
888
+	 *                                                                       need those on every request)
889
+	 * @return array
890
+	 */
891
+	protected function _get_write_params(
892
+		$model_name,
893
+		ModelVersionInfo $model_version_info,
894
+		$create = false
895
+	) {
896
+		$model = EE_Registry::instance()->load_model($model_name);
897
+		$fields = $model_version_info->fieldsOnModelInThisVersion($model);
898
+		$args_info = array();
899
+		foreach ($fields as $field_name => $field_obj) {
900
+			if ($field_obj->is_auto_increment()) {
901
+				// totally ignore auto increment IDs
902
+				continue;
903
+			}
904
+			$arg_info = $field_obj->getSchema();
905
+			$required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null;
906
+			$arg_info['required'] = $required;
907
+			// remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right?
908
+			unset($arg_info['readonly']);
909
+			$schema_properties = $field_obj->getSchemaProperties();
910
+			if (isset($schema_properties['raw'])
911
+				&& $field_obj->getSchemaType() === 'object'
912
+			) {
913
+				// if there's a "raw" form of this argument, use those properties instead
914
+				$arg_info = array_replace(
915
+					$arg_info,
916
+					$schema_properties['raw']
917
+				);
918
+			}
919
+			$arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson(
920
+				$field_obj,
921
+				$field_obj->get_default_value(),
922
+				$model_version_info->requestedVersion()
923
+			);
924
+			// we do our own validation and sanitization within the controller
925
+			if (function_exists('rest_validate_value_from_schema')) {
926
+				$sanitize_callback = array(
927
+					'EED_Core_Rest_Api',
928
+					'default_sanitize_callback',
929
+				);
930
+			} else {
931
+				$sanitize_callback = null;
932
+			}
933
+			$arg_info['sanitize_callback'] = $sanitize_callback;
934
+			$args_info[ $field_name ] = $arg_info;
935
+			if ($field_obj instanceof EE_Datetime_Field) {
936
+				$gmt_arg_info = $arg_info;
937
+				$gmt_arg_info['description'] = sprintf(
938
+					esc_html__(
939
+						'%1$s - the value for this field in UTC. Ignored if %2$s is provided.',
940
+						'event_espresso'
941
+					),
942
+					$field_obj->get_nicename(),
943
+					$field_name
944
+				);
945
+				$args_info[ $field_name . '_gmt' ] = $gmt_arg_info;
946
+			}
947
+		}
948
+		return $args_info;
949
+	}
950
+
951
+
952
+	/**
953
+	 * Replacement for WP API's 'rest_parse_request_arg'.
954
+	 * If the value is blank but not required, don't bother validating it.
955
+	 * Also, it uses our email validation instead of WP API's default.
956
+	 *
957
+	 * @param                 $value
958
+	 * @param WP_REST_Request $request
959
+	 * @param                 $param
960
+	 * @return bool|true|WP_Error
961
+	 * @throws InvalidArgumentException
962
+	 * @throws InvalidInterfaceException
963
+	 * @throws InvalidDataTypeException
964
+	 */
965
+	public static function default_sanitize_callback($value, WP_REST_Request $request, $param)
966
+	{
967
+		$attributes = $request->get_attributes();
968
+		if (! isset($attributes['args'][ $param ])
969
+			|| ! is_array($attributes['args'][ $param ])) {
970
+			$validation_result = true;
971
+		} else {
972
+			$args = $attributes['args'][ $param ];
973
+			if ((
974
+					$value === ''
975
+					|| $value === null
976
+				)
977
+				&& (! isset($args['required'])
978
+					|| $args['required'] === false
979
+				)
980
+			) {
981
+				// not required and not provided? that's cool
982
+				$validation_result = true;
983
+			} elseif (isset($args['format'])
984
+					  && $args['format'] === 'email'
985
+			) {
986
+				$validation_result = true;
987
+				if (! self::_validate_email($value)) {
988
+					$validation_result = new WP_Error(
989
+						'rest_invalid_param',
990
+						esc_html__(
991
+							'The email address is not valid or does not exist.',
992
+							'event_espresso'
993
+						)
994
+					);
995
+				}
996
+			} else {
997
+				$validation_result = rest_validate_value_from_schema($value, $args, $param);
998
+			}
999
+		}
1000
+		if (is_wp_error($validation_result)) {
1001
+			return $validation_result;
1002
+		}
1003
+		return rest_sanitize_request_arg($value, $request, $param);
1004
+	}
1005
+
1006
+
1007
+	/**
1008
+	 * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email()
1009
+	 *
1010
+	 * @param $email
1011
+	 * @return bool
1012
+	 * @throws InvalidArgumentException
1013
+	 * @throws InvalidInterfaceException
1014
+	 * @throws InvalidDataTypeException
1015
+	 */
1016
+	protected static function _validate_email($email)
1017
+	{
1018
+		try {
1019
+			EmailAddressFactory::create($email);
1020
+			return true;
1021
+		} catch (EmailValidationException $e) {
1022
+			return false;
1023
+		}
1024
+	}
1025
+
1026
+
1027
+	/**
1028
+	 * Gets routes for the config
1029
+	 *
1030
+	 * @return array @see _register_model_routes
1031
+	 * @deprecated since version 4.9.1
1032
+	 */
1033
+	protected function _register_config_routes()
1034
+	{
1035
+		$config_routes = array();
1036
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
1037
+			$config_routes[ self::ee_api_namespace . $version ] = $this->_get_config_route_data_for_version(
1038
+				$version,
1039
+				$hidden_endpoint
1040
+			);
1041
+		}
1042
+		return $config_routes;
1043
+	}
1044
+
1045
+
1046
+	/**
1047
+	 * Gets routes for the config for the specified version
1048
+	 *
1049
+	 * @param string  $version
1050
+	 * @param boolean $hidden_endpoint
1051
+	 * @return array
1052
+	 */
1053
+	protected function _get_config_route_data_for_version($version, $hidden_endpoint)
1054
+	{
1055
+		return array(
1056
+			'config'    => array(
1057
+				array(
1058
+					'callback'        => array(
1059
+						'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1060
+						'handleRequest',
1061
+					),
1062
+					'methods'         => WP_REST_Server::READABLE,
1063
+					'hidden_endpoint' => $hidden_endpoint,
1064
+					'callback_args'   => array($version),
1065
+				),
1066
+			),
1067
+			'site_info' => array(
1068
+				array(
1069
+					'callback'        => array(
1070
+						'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1071
+						'handleRequestSiteInfo',
1072
+					),
1073
+					'methods'         => WP_REST_Server::READABLE,
1074
+					'hidden_endpoint' => $hidden_endpoint,
1075
+					'callback_args'   => array($version),
1076
+				),
1077
+			),
1078
+		);
1079
+	}
1080
+
1081
+
1082
+	/**
1083
+	 * Gets the meta info routes
1084
+	 *
1085
+	 * @return array @see _register_model_routes
1086
+	 * @deprecated since version 4.9.1
1087
+	 */
1088
+	protected function _register_meta_routes()
1089
+	{
1090
+		$meta_routes = array();
1091
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
1092
+			$meta_routes[ self::ee_api_namespace . $version ] = $this->_get_meta_route_data_for_version(
1093
+				$version,
1094
+				$hidden_endpoint
1095
+			);
1096
+		}
1097
+		return $meta_routes;
1098
+	}
1099
+
1100
+
1101
+	/**
1102
+	 * @param string  $version
1103
+	 * @param boolean $hidden_endpoint
1104
+	 * @return array
1105
+	 */
1106
+	protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false)
1107
+	{
1108
+		return array(
1109
+			'resources' => array(
1110
+				array(
1111
+					'callback'        => array(
1112
+						'EventEspresso\core\libraries\rest_api\controllers\model\Meta',
1113
+						'handleRequestModelsMeta',
1114
+					),
1115
+					'methods'         => WP_REST_Server::READABLE,
1116
+					'hidden_endpoint' => $hidden_endpoint,
1117
+					'callback_args'   => array($version),
1118
+				),
1119
+			),
1120
+		);
1121
+	}
1122
+
1123
+
1124
+	/**
1125
+	 * Tries to hide old 4.6 endpoints from the
1126
+	 *
1127
+	 * @param array $route_data
1128
+	 * @return array
1129
+	 * @throws \EE_Error
1130
+	 */
1131
+	public static function hide_old_endpoints($route_data)
1132
+	{
1133
+		// allow API clients to override which endpoints get hidden, in case
1134
+		// they want to discover particular endpoints
1135
+		// also, we don't have access to the request so we have to just grab it from the superglobal
1136
+		$force_show_ee_namespace = ltrim(
1137
+			EEH_Array::is_set($_REQUEST, 'force_show_ee_namespace', ''),
1138
+			'/'
1139
+		);
1140
+		foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) {
1141
+			foreach ($relative_urls as $resource_name => $endpoints) {
1142
+				foreach ($endpoints as $key => $endpoint) {
1143
+					// skip schema and other route options
1144
+					if (! is_numeric($key)) {
1145
+						continue;
1146
+					}
1147
+					// by default, hide "hidden_endpoint"s, unless the request indicates
1148
+					// to $force_show_ee_namespace, in which case only show that one
1149
+					// namespace's endpoints (and hide all others)
1150
+					if (($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1151
+						|| ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1152
+					) {
1153
+						$full_route = '/' . ltrim($namespace, '/');
1154
+						$full_route .= '/' . ltrim($resource_name, '/');
1155
+						unset($route_data[ $full_route ]);
1156
+					}
1157
+				}
1158
+			}
1159
+		}
1160
+		return $route_data;
1161
+	}
1162
+
1163
+
1164
+	/**
1165
+	 * Returns an array describing which versions of core support serving requests for.
1166
+	 * Keys are core versions' major and minor version, and values are the
1167
+	 * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like
1168
+	 * data by just removing a few models and fields from the responses. However, 4.15 might remove
1169
+	 * the answers table entirely, in which case it would be very difficult for
1170
+	 * it to serve 4.6-style responses.
1171
+	 * Versions of core that are missing from this array are unknowns.
1172
+	 * previous ver
1173
+	 *
1174
+	 * @return array
1175
+	 */
1176
+	public static function version_compatibilities()
1177
+	{
1178
+		return apply_filters(
1179
+			'FHEE__EED_Core_REST_API__version_compatibilities',
1180
+			array(
1181
+				'4.8.29' => '4.8.29',
1182
+				'4.8.33' => '4.8.29',
1183
+				'4.8.34' => '4.8.29',
1184
+				'4.8.36' => '4.8.29',
1185
+			)
1186
+		);
1187
+	}
1188
+
1189
+
1190
+	/**
1191
+	 * Gets the latest API version served. Eg if there
1192
+	 * are two versions served of the API, 4.8.29 and 4.8.32, and
1193
+	 * we are on core version 4.8.34, it will return the string "4.8.32"
1194
+	 *
1195
+	 * @return string
1196
+	 */
1197
+	public static function latest_rest_api_version()
1198
+	{
1199
+		$versions_served = \EED_Core_Rest_Api::versions_served();
1200
+		$versions_served_keys = array_keys($versions_served);
1201
+		return end($versions_served_keys);
1202
+	}
1203
+
1204
+
1205
+	/**
1206
+	 * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of
1207
+	 * EE the API can serve requests for. Eg, if we are on 4.15 of core, and
1208
+	 * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ).
1209
+	 * We also indicate whether or not this version should be put in the index or not
1210
+	 *
1211
+	 * @return array keys are API version numbers (just major and minor numbers), and values
1212
+	 * are whether or not they should be hidden
1213
+	 */
1214
+	public static function versions_served()
1215
+	{
1216
+		$versions_served = array();
1217
+		$possibly_served_versions = EED_Core_Rest_Api::version_compatibilities();
1218
+		$lowest_compatible_version = end($possibly_served_versions);
1219
+		reset($possibly_served_versions);
1220
+		$versions_served_historically = array_keys($possibly_served_versions);
1221
+		$latest_version = end($versions_served_historically);
1222
+		reset($versions_served_historically);
1223
+		// for each version of core we have ever served:
1224
+		foreach ($versions_served_historically as $key_versioned_endpoint) {
1225
+			// if it's not above the current core version, and it's compatible with the current version of core
1226
+
1227
+			if ($key_versioned_endpoint === $latest_version) {
1228
+				// don't hide the latest version in the index
1229
+				$versions_served[ $key_versioned_endpoint ] = false;
1230
+			} elseif (version_compare($key_versioned_endpoint, $lowest_compatible_version, '>=')
1231
+				&& version_compare($key_versioned_endpoint, EED_Core_Rest_Api::core_version(), '<')
1232
+			) {
1233
+				// include, but hide, previous versions which are still supported
1234
+				$versions_served[ $key_versioned_endpoint ] = true;
1235
+			} elseif (apply_filters(
1236
+				'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions',
1237
+				false,
1238
+				$possibly_served_versions
1239
+			)) {
1240
+				// if a version is no longer supported, don't include it in index or list of versions served
1241
+				$versions_served[ $key_versioned_endpoint ] = true;
1242
+			}
1243
+		}
1244
+		return $versions_served;
1245
+	}
1246
+
1247
+
1248
+	/**
1249
+	 * Gets the major and minor version of EE core's version string
1250
+	 *
1251
+	 * @return string
1252
+	 */
1253
+	public static function core_version()
1254
+	{
1255
+		return apply_filters(
1256
+			'FHEE__EED_Core_REST_API__core_version',
1257
+			implode(
1258
+				'.',
1259
+				array_slice(
1260
+					explode(
1261
+						'.',
1262
+						espresso_version()
1263
+					),
1264
+					0,
1265
+					3
1266
+				)
1267
+			)
1268
+		);
1269
+	}
1270
+
1271
+
1272
+	/**
1273
+	 * Gets the default limit that should be used when querying for resources
1274
+	 *
1275
+	 * @return int
1276
+	 */
1277
+	public static function get_default_query_limit()
1278
+	{
1279
+		// we actually don't use a const because we want folks to always use
1280
+		// this method, not the const directly
1281
+		return apply_filters(
1282
+			'FHEE__EED_Core_Rest_Api__get_default_query_limit',
1283
+			50
1284
+		);
1285
+	}
1286
+
1287
+
1288
+	/**
1289
+	 *
1290
+	 * @param string $version api version string (i.e. '4.8.36')
1291
+	 * @return array
1292
+	 */
1293
+	public static function getCollectionRoutesIndexedByModelName($version = '')
1294
+	{
1295
+		$version = empty($version) ? self::latest_rest_api_version() : $version;
1296
+		$model_names = self::model_names_with_plural_routes($version);
1297
+		$collection_routes = array();
1298
+		foreach ($model_names as $model_name => $model_class_name) {
1299
+			$collection_routes[ strtolower($model_name) ] = '/' . self::ee_api_namespace . $version . '/'
1300
+															. EEH_Inflector::pluralize_and_lower($model_name);
1301
+		}
1302
+		return $collection_routes;
1303
+	}
1304
+
1305
+
1306
+	/**
1307
+	 * Returns an array of primary key names indexed by model names.
1308
+	 * @param string $version
1309
+	 * @return array
1310
+	 */
1311
+	public static function getPrimaryKeyNamesIndexedByModelName($version = '')
1312
+	{
1313
+		$version = empty($version) ? self::latest_rest_api_version() : $version;
1314
+		$model_names = self::model_names_with_plural_routes($version);
1315
+		$primary_key_items = array();
1316
+		foreach ($model_names as $model_name => $model_class_name) {
1317
+			$primary_keys = $model_class_name::instance()->get_combined_primary_key_fields();
1318
+			foreach ($primary_keys as $primary_key_name => $primary_key_field) {
1319
+				if (count($primary_keys) > 1) {
1320
+					$primary_key_items[ strtolower($model_name) ][] = $primary_key_name;
1321
+				} else {
1322
+					$primary_key_items[ strtolower($model_name) ] = $primary_key_name;
1323
+				}
1324
+			}
1325
+		}
1326
+		return $primary_key_items;
1327
+	}
1328
+
1329
+	/**
1330
+	 * Determines the EE REST API debug mode is activated, or not.
1331
+	 * @since 4.9.76.p
1332
+	 * @return bool
1333
+	 */
1334
+	public static function debugMode()
1335
+	{
1336
+		static $debug_mode = null; // could be class prop
1337
+		if ($debug_mode === null) {
1338
+			$debug_mode = defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE;
1339
+		}
1340
+		return $debug_mode;
1341
+	}
1342
+
1343
+
1344
+
1345
+	/**
1346
+	 *    run - initial module setup
1347
+	 *
1348
+	 * @access    public
1349
+	 * @param  WP $WP
1350
+	 * @return    void
1351
+	 */
1352
+	public function run($WP)
1353
+	{
1354
+	}
1355 1355
 }
Please login to merge, or discard this patch.
Spacing   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -123,7 +123,7 @@  discard block
 block discarded – undo
123 123
      */
124 124
     protected static function _set_hooks_for_changes()
125 125
     {
126
-        $folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES . 'rest_api/changes'), false);
126
+        $folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES.'rest_api/changes'), false);
127 127
         foreach ($folder_contents as $classname_in_namespace => $filepath) {
128 128
             // ignore the base parent class
129 129
             // and legacy named classes
@@ -132,7 +132,7 @@  discard block
 block discarded – undo
132 132
             ) {
133 133
                 continue;
134 134
             }
135
-            $full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace;
135
+            $full_classname = 'EventEspresso\core\libraries\rest_api\changes\\'.$classname_in_namespace;
136 136
             if (class_exists($full_classname)) {
137 137
                 $instance_of_class = new $full_classname;
138 138
                 if ($instance_of_class instanceof ChangesInBase) {
@@ -177,10 +177,10 @@  discard block
 block discarded – undo
177 177
                      * }
178 178
                      */
179 179
                     // skip route options
180
-                    if (! is_numeric($endpoint_key)) {
180
+                    if ( ! is_numeric($endpoint_key)) {
181 181
                         continue;
182 182
                     }
183
-                    if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
183
+                    if ( ! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
184 184
                         throw new EE_Error(
185 185
                             esc_html__(
186 186
                             // @codingStandardsIgnoreStart
@@ -201,7 +201,7 @@  discard block
 block discarded – undo
201 201
                     }
202 202
                     if (isset($data_for_single_endpoint['callback_args'])) {
203 203
                         $callback_args = $data_for_single_endpoint['callback_args'];
204
-                        $single_endpoint_args['callback'] = function (\WP_REST_Request $request) use (
204
+                        $single_endpoint_args['callback'] = function(\WP_REST_Request $request) use (
205 205
                             $callback,
206 206
                             $callback_args
207 207
                         ) {
@@ -220,7 +220,7 @@  discard block
 block discarded – undo
220 220
                     $schema_route_data = $data_for_multiple_endpoints['schema'];
221 221
                     $schema_callback = $schema_route_data['schema_callback'];
222 222
                     $callback_args = $schema_route_data['callback_args'];
223
-                    $multiple_endpoint_args['schema'] = function () use ($schema_callback, $callback_args) {
223
+                    $multiple_endpoint_args['schema'] = function() use ($schema_callback, $callback_args) {
224 224
                         return call_user_func_array(
225 225
                             $schema_callback,
226 226
                             $callback_args
@@ -262,7 +262,7 @@  discard block
 block discarded – undo
262 262
     {
263 263
         // delete the saved EE REST API routes
264 264
         foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) {
265
-            delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version);
265
+            delete_option(EED_Core_Rest_Api::saved_routes_option_names.$version);
266 266
         }
267 267
     }
268 268
 
@@ -281,7 +281,7 @@  discard block
 block discarded – undo
281 281
     {
282 282
         $ee_routes = array();
283 283
         foreach (self::versions_served() as $version => $hidden_endpoints) {
284
-            $ee_routes[ self::ee_api_namespace . $version ] = self::_get_ee_route_data_for_version(
284
+            $ee_routes[self::ee_api_namespace.$version] = self::_get_ee_route_data_for_version(
285 285
                 $version,
286 286
                 $hidden_endpoints
287 287
             );
@@ -301,8 +301,8 @@  discard block
 block discarded – undo
301 301
      */
302 302
     protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false)
303 303
     {
304
-        $ee_routes = get_option(self::saved_routes_option_names . $version, null);
305
-        if (! $ee_routes || EED_Core_Rest_Api::debugMode()) {
304
+        $ee_routes = get_option(self::saved_routes_option_names.$version, null);
305
+        if ( ! $ee_routes || EED_Core_Rest_Api::debugMode()) {
306 306
             $ee_routes = self::_save_ee_route_data_for_version($version, $hidden_endpoints);
307 307
         }
308 308
         return $ee_routes;
@@ -329,7 +329,7 @@  discard block
 block discarded – undo
329 329
                 $instance->_get_rpc_route_data_for_version($version, $hidden_endpoints)
330 330
             )
331 331
         );
332
-        $option_name = self::saved_routes_option_names . $version;
332
+        $option_name = self::saved_routes_option_names.$version;
333 333
         if (get_option($option_name)) {
334 334
             update_option($option_name, $routes, true);
335 335
         } else {
@@ -374,8 +374,8 @@  discard block
 block discarded – undo
374 374
     {
375 375
         $model_routes = array();
376 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);
377
+            $model_routes[EED_Core_Rest_Api::ee_api_namespace
378
+                           . $version] = $this->_get_config_route_data_for_version($version, $hidden_endpoint);
379 379
         }
380 380
         return $model_routes;
381 381
     }
@@ -444,13 +444,13 @@  discard block
 block discarded – undo
444 444
         foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) {
445 445
             $model = \EE_Registry::instance()->load_model($model_name);
446 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) {
447
+            if ( ! $model instanceof EEM_Base) {
448 448
                 continue;
449 449
             }
450 450
             // yes we could just register one route for ALL models, but then they wouldn't show up in the index
451 451
             $plural_model_route = EED_Core_Rest_Api::get_collection_route($model);
452 452
             $singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)');
453
-            $model_routes[ $plural_model_route ] = array(
453
+            $model_routes[$plural_model_route] = array(
454 454
                 array(
455 455
                     'callback'        => array(
456 456
                         'EventEspresso\core\libraries\rest_api\controllers\model\Read',
@@ -461,7 +461,7 @@  discard block
 block discarded – undo
461 461
                     'hidden_endpoint' => $hidden_endpoint,
462 462
                     'args'            => $this->_get_read_query_params($model, $version),
463 463
                     '_links'          => array(
464
-                        'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route),
464
+                        'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace.$version.$singular_model_route),
465 465
                     ),
466 466
                 ),
467 467
                 'schema' => array(
@@ -472,7 +472,7 @@  discard block
 block discarded – undo
472 472
                     'callback_args'   => array($version, $model_name),
473 473
                 ),
474 474
             );
475
-            $model_routes[ $singular_model_route ] = array(
475
+            $model_routes[$singular_model_route] = array(
476 476
                 array(
477 477
                     'callback'        => array(
478 478
                         'EventEspresso\core\libraries\rest_api\controllers\model\Read',
@@ -489,7 +489,7 @@  discard block
 block discarded – undo
489 489
                 EED_Core_Rest_Api::should_have_write_endpoints($model),
490 490
                 $model
491 491
             )) {
492
-                $model_routes[ $plural_model_route ][] = array(
492
+                $model_routes[$plural_model_route][] = array(
493 493
                     'callback'        => array(
494 494
                         'EventEspresso\core\libraries\rest_api\controllers\model\Write',
495 495
                         'handleRequestInsert',
@@ -499,8 +499,8 @@  discard block
 block discarded – undo
499 499
                     'hidden_endpoint' => $hidden_endpoint,
500 500
                     'args'            => $this->_get_write_params($model_name, $model_version_info, true),
501 501
                 );
502
-                $model_routes[ $singular_model_route ] = array_merge(
503
-                    $model_routes[ $singular_model_route ],
502
+                $model_routes[$singular_model_route] = array_merge(
503
+                    $model_routes[$singular_model_route],
504 504
                     array(
505 505
                         array(
506 506
                             'callback'        => array(
@@ -531,7 +531,7 @@  discard block
 block discarded – undo
531 531
                     '(?P<id>[^\/]+)',
532 532
                     $relation_obj
533 533
                 );
534
-                $model_routes[ $related_route ] = array(
534
+                $model_routes[$related_route] = array(
535 535
                     array(
536 536
                         'callback'        => array(
537 537
                             'EventEspresso\core\libraries\rest_api\controllers\model\Read',
@@ -544,8 +544,8 @@  discard block
 block discarded – undo
544 544
                     ),
545 545
                 );
546 546
 
547
-                $related_write_route = $related_route . '/' . '(?P<related_id>[^\/]+)';
548
-                $model_routes[ $related_write_route ] = array(
547
+                $related_write_route = $related_route.'/'.'(?P<related_id>[^\/]+)';
548
+                $model_routes[$related_write_route] = array(
549 549
                     array(
550 550
                         'callback'        => array(
551 551
                             'EventEspresso\core\libraries\rest_api\controllers\model\Write',
@@ -598,7 +598,7 @@  discard block
 block discarded – undo
598 598
      */
599 599
     public static function get_entity_route($model, $id)
600 600
     {
601
-        return EED_Core_Rest_Api::get_collection_route($model) . '/' . $id;
601
+        return EED_Core_Rest_Api::get_collection_route($model).'/'.$id;
602 602
     }
603 603
 
604 604
 
@@ -618,7 +618,7 @@  discard block
 block discarded – undo
618 618
             $relation_obj->get_other_model()->get_this_model_name(),
619 619
             $relation_obj
620 620
         );
621
-        return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
621
+        return EED_Core_Rest_Api::get_entity_route($model, $id).'/'.$related_model_name_endpoint_part;
622 622
     }
623 623
 
624 624
 
@@ -632,7 +632,7 @@  discard block
 block discarded – undo
632 632
      */
633 633
     public static function get_versioned_route_to($relative_route, $version = '4.8.36')
634 634
     {
635
-        return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
635
+        return '/'.EED_Core_Rest_Api::ee_api_namespace.$version.'/'.$relative_route;
636 636
     }
637 637
 
638 638
 
@@ -646,7 +646,7 @@  discard block
 block discarded – undo
646 646
     {
647 647
         $routes = array();
648 648
         foreach (self::versions_served() as $version => $hidden_endpoint) {
649
-            $routes[ self::ee_api_namespace . $version ] = $this->_get_rpc_route_data_for_version(
649
+            $routes[self::ee_api_namespace.$version] = $this->_get_rpc_route_data_for_version(
650 650
                 $version,
651 651
                 $hidden_endpoint
652 652
             );
@@ -769,12 +769,12 @@  discard block
 block discarded – undo
769 769
     {
770 770
         // if they're related through a HABTM relation, check for any non-FKs
771 771
         $all_relation_settings = $source_model->relation_settings();
772
-        $relation_settings = $all_relation_settings[ $related_model->get_this_model_name() ];
772
+        $relation_settings = $all_relation_settings[$related_model->get_this_model_name()];
773 773
         $params = array();
774 774
         if ($relation_settings instanceof EE_HABTM_Relation && $relation_settings->hasNonKeyFields()) {
775 775
             foreach ($relation_settings->getNonKeyFields() as $field) {
776 776
                 /* @var $field EE_Model_Field_Base */
777
-                $params[ $field->get_name() ] = array(
777
+                $params[$field->get_name()] = array(
778 778
                     'required' => ! $field->is_nullable(),
779 779
                     'default' => ModelDataTranslator::prepareFieldValueForJson($field, $field->get_default_value(), $version),
780 780
                     'type' => $field->getSchemaType(),
@@ -799,7 +799,7 @@  discard block
 block discarded – undo
799 799
     {
800 800
         $default_orderby = array();
801 801
         foreach ($model->get_combined_primary_key_fields() as $key_field) {
802
-            $default_orderby[ $key_field->get_name() ] = 'ASC';
802
+            $default_orderby[$key_field->get_name()] = 'ASC';
803 803
         }
804 804
         return array_merge(
805 805
             $this->_get_response_selection_query_params($model, $version),
@@ -833,7 +833,7 @@  discard block
 block discarded – undo
833 833
                     'type'              => array(
834 834
                         'object',
835 835
                         'string',
836
-                    ),// because we accept a variety of types, WP core validation and sanitization
836
+                    ), // because we accept a variety of types, WP core validation and sanitization
837 837
                     // freaks out. We'll just validate this argument while handling the request
838 838
                     'validate_callback' => null,
839 839
                     'sanitize_callback' => null,
@@ -931,7 +931,7 @@  discard block
 block discarded – undo
931 931
                 $sanitize_callback = null;
932 932
             }
933 933
             $arg_info['sanitize_callback'] = $sanitize_callback;
934
-            $args_info[ $field_name ] = $arg_info;
934
+            $args_info[$field_name] = $arg_info;
935 935
             if ($field_obj instanceof EE_Datetime_Field) {
936 936
                 $gmt_arg_info = $arg_info;
937 937
                 $gmt_arg_info['description'] = sprintf(
@@ -942,7 +942,7 @@  discard block
 block discarded – undo
942 942
                     $field_obj->get_nicename(),
943 943
                     $field_name
944 944
                 );
945
-                $args_info[ $field_name . '_gmt' ] = $gmt_arg_info;
945
+                $args_info[$field_name.'_gmt'] = $gmt_arg_info;
946 946
             }
947 947
         }
948 948
         return $args_info;
@@ -965,16 +965,16 @@  discard block
 block discarded – undo
965 965
     public static function default_sanitize_callback($value, WP_REST_Request $request, $param)
966 966
     {
967 967
         $attributes = $request->get_attributes();
968
-        if (! isset($attributes['args'][ $param ])
969
-            || ! is_array($attributes['args'][ $param ])) {
968
+        if ( ! isset($attributes['args'][$param])
969
+            || ! is_array($attributes['args'][$param])) {
970 970
             $validation_result = true;
971 971
         } else {
972
-            $args = $attributes['args'][ $param ];
972
+            $args = $attributes['args'][$param];
973 973
             if ((
974 974
                     $value === ''
975 975
                     || $value === null
976 976
                 )
977
-                && (! isset($args['required'])
977
+                && ( ! isset($args['required'])
978 978
                     || $args['required'] === false
979 979
                 )
980 980
             ) {
@@ -984,7 +984,7 @@  discard block
 block discarded – undo
984 984
                       && $args['format'] === 'email'
985 985
             ) {
986 986
                 $validation_result = true;
987
-                if (! self::_validate_email($value)) {
987
+                if ( ! self::_validate_email($value)) {
988 988
                     $validation_result = new WP_Error(
989 989
                         'rest_invalid_param',
990 990
                         esc_html__(
@@ -1034,7 +1034,7 @@  discard block
 block discarded – undo
1034 1034
     {
1035 1035
         $config_routes = array();
1036 1036
         foreach (self::versions_served() as $version => $hidden_endpoint) {
1037
-            $config_routes[ self::ee_api_namespace . $version ] = $this->_get_config_route_data_for_version(
1037
+            $config_routes[self::ee_api_namespace.$version] = $this->_get_config_route_data_for_version(
1038 1038
                 $version,
1039 1039
                 $hidden_endpoint
1040 1040
             );
@@ -1089,7 +1089,7 @@  discard block
 block discarded – undo
1089 1089
     {
1090 1090
         $meta_routes = array();
1091 1091
         foreach (self::versions_served() as $version => $hidden_endpoint) {
1092
-            $meta_routes[ self::ee_api_namespace . $version ] = $this->_get_meta_route_data_for_version(
1092
+            $meta_routes[self::ee_api_namespace.$version] = $this->_get_meta_route_data_for_version(
1093 1093
                 $version,
1094 1094
                 $hidden_endpoint
1095 1095
             );
@@ -1141,7 +1141,7 @@  discard block
 block discarded – undo
1141 1141
             foreach ($relative_urls as $resource_name => $endpoints) {
1142 1142
                 foreach ($endpoints as $key => $endpoint) {
1143 1143
                     // skip schema and other route options
1144
-                    if (! is_numeric($key)) {
1144
+                    if ( ! is_numeric($key)) {
1145 1145
                         continue;
1146 1146
                     }
1147 1147
                     // by default, hide "hidden_endpoint"s, unless the request indicates
@@ -1150,9 +1150,9 @@  discard block
 block discarded – undo
1150 1150
                     if (($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1151 1151
                         || ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1152 1152
                     ) {
1153
-                        $full_route = '/' . ltrim($namespace, '/');
1154
-                        $full_route .= '/' . ltrim($resource_name, '/');
1155
-                        unset($route_data[ $full_route ]);
1153
+                        $full_route = '/'.ltrim($namespace, '/');
1154
+                        $full_route .= '/'.ltrim($resource_name, '/');
1155
+                        unset($route_data[$full_route]);
1156 1156
                     }
1157 1157
                 }
1158 1158
             }
@@ -1226,19 +1226,19 @@  discard block
 block discarded – undo
1226 1226
 
1227 1227
             if ($key_versioned_endpoint === $latest_version) {
1228 1228
                 // don't hide the latest version in the index
1229
-                $versions_served[ $key_versioned_endpoint ] = false;
1229
+                $versions_served[$key_versioned_endpoint] = false;
1230 1230
             } elseif (version_compare($key_versioned_endpoint, $lowest_compatible_version, '>=')
1231 1231
                 && version_compare($key_versioned_endpoint, EED_Core_Rest_Api::core_version(), '<')
1232 1232
             ) {
1233 1233
                 // include, but hide, previous versions which are still supported
1234
-                $versions_served[ $key_versioned_endpoint ] = true;
1234
+                $versions_served[$key_versioned_endpoint] = true;
1235 1235
             } elseif (apply_filters(
1236 1236
                 'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions',
1237 1237
                 false,
1238 1238
                 $possibly_served_versions
1239 1239
             )) {
1240 1240
                 // if a version is no longer supported, don't include it in index or list of versions served
1241
-                $versions_served[ $key_versioned_endpoint ] = true;
1241
+                $versions_served[$key_versioned_endpoint] = true;
1242 1242
             }
1243 1243
         }
1244 1244
         return $versions_served;
@@ -1296,7 +1296,7 @@  discard block
 block discarded – undo
1296 1296
         $model_names = self::model_names_with_plural_routes($version);
1297 1297
         $collection_routes = array();
1298 1298
         foreach ($model_names as $model_name => $model_class_name) {
1299
-            $collection_routes[ strtolower($model_name) ] = '/' . self::ee_api_namespace . $version . '/'
1299
+            $collection_routes[strtolower($model_name)] = '/'.self::ee_api_namespace.$version.'/'
1300 1300
                                                             . EEH_Inflector::pluralize_and_lower($model_name);
1301 1301
         }
1302 1302
         return $collection_routes;
@@ -1317,9 +1317,9 @@  discard block
 block discarded – undo
1317 1317
             $primary_keys = $model_class_name::instance()->get_combined_primary_key_fields();
1318 1318
             foreach ($primary_keys as $primary_key_name => $primary_key_field) {
1319 1319
                 if (count($primary_keys) > 1) {
1320
-                    $primary_key_items[ strtolower($model_name) ][] = $primary_key_name;
1320
+                    $primary_key_items[strtolower($model_name)][] = $primary_key_name;
1321 1321
                 } else {
1322
-                    $primary_key_items[ strtolower($model_name) ] = $primary_key_name;
1322
+                    $primary_key_items[strtolower($model_name)] = $primary_key_name;
1323 1323
                 }
1324 1324
             }
1325 1325
         }
Please login to merge, or discard this patch.
modules/add_new_state/EED_Add_New_State.module.php 2 patches
Indentation   +814 added lines, -814 removed lines patch added patch discarded remove patch
@@ -17,818 +17,818 @@
 block discarded – undo
17 17
 {
18 18
 
19 19
 
20
-    /**
21
-     * @return EED_Module|EED_Add_New_State
22
-     */
23
-    public static function instance()
24
-    {
25
-        return parent::get_instance(__CLASS__);
26
-    }
27
-
28
-
29
-    /**
30
-     * set_hooks - for hooking into EE Core, other modules, etc
31
-     *
32
-     * @return void
33
-     */
34
-    public static function set_hooks()
35
-    {
36
-        add_action('wp_loaded', array('EED_Add_New_State', 'set_definitions'), 2);
37
-        add_action('wp_enqueue_scripts', array('EED_Add_New_State', 'translate_js_strings'), 0);
38
-        add_action('wp_enqueue_scripts', array('EED_Add_New_State', 'wp_enqueue_scripts'), 10);
39
-        add_filter(
40
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
41
-            array('EED_Add_New_State', 'display_add_new_state_micro_form'),
42
-            1,
43
-            1
44
-        );
45
-        add_filter(
46
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
47
-            array('EED_Add_New_State', 'display_add_new_state_micro_form'),
48
-            1,
49
-            1
50
-        );
51
-        add_filter(
52
-            'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
53
-            array('EED_Add_New_State', 'unset_new_state_request_params'),
54
-            10,
55
-            1
56
-        );
57
-        add_filter(
58
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
59
-            array('EED_Add_New_State', 'inject_new_reg_state_into_options'),
60
-            10,
61
-            5
62
-        );
63
-        add_filter(
64
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
65
-            array('EED_Add_New_State', 'inject_new_reg_country_into_options'),
66
-            10,
67
-            5
68
-        );
69
-        add_filter(
70
-            'FHEE__EE_State_Select_Input____construct__state_options',
71
-            array('EED_Add_New_State', 'state_options'),
72
-            10,
73
-            1
74
-        );
75
-        add_filter(
76
-            'FHEE__EE_Country_Select_Input____construct__country_options',
77
-            array('EED_Add_New_State', 'country_options'),
78
-            10,
79
-            1
80
-        );
81
-    }
82
-
83
-
84
-    /**
85
-     * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
86
-     *
87
-     * @return void
88
-     */
89
-    public static function set_hooks_admin()
90
-    {
91
-        add_action('wp_loaded', array('EED_Add_New_State', 'set_definitions'), 2);
92
-        add_filter(
93
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
94
-            array('EED_Add_New_State', 'display_add_new_state_micro_form'),
95
-            1,
96
-            1
97
-        );
98
-        add_filter(
99
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
100
-            array('EED_Add_New_State', 'display_add_new_state_micro_form'),
101
-            1,
102
-            1
103
-        );
104
-        add_action('wp_ajax_espresso_add_new_state', array('EED_Add_New_State', 'add_new_state'));
105
-        add_action('wp_ajax_nopriv_espresso_add_new_state', array('EED_Add_New_State', 'add_new_state'));
106
-        add_filter(
107
-            'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
108
-            array('EED_Add_New_State', 'unset_new_state_request_params'),
109
-            10,
110
-            1
111
-        );
112
-        add_action(
113
-            'AHEE__General_Settings_Admin_Page__update_country_settings__state_saved',
114
-            array('EED_Add_New_State', 'update_country_settings'),
115
-            10,
116
-            3
117
-        );
118
-        add_action(
119
-            'AHEE__General_Settings_Admin_Page__delete_state__state_deleted',
120
-            array('EED_Add_New_State', 'update_country_settings'),
121
-            10,
122
-            3
123
-        );
124
-        add_filter(
125
-            'FHEE__EE_State_Select_Input____construct__state_options',
126
-            array('EED_Add_New_State', 'state_options'),
127
-            10,
128
-            1
129
-        );
130
-        add_filter(
131
-            'FHEE__EE_Country_Select_Input____construct__country_options',
132
-            array('EED_Add_New_State', 'country_options'),
133
-            10,
134
-            1
135
-        );
136
-        add_filter(
137
-            'FHEE__EE_Form_Section_Proper__receive_form_submission__request_data',
138
-            array('EED_Add_New_State', 'filter_checkout_request_params'),
139
-            10,
140
-            1
141
-        );
142
-        add_filter(
143
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
144
-            array('EED_Add_New_State', 'inject_new_reg_state_into_options'),
145
-            10,
146
-            5
147
-        );
148
-        add_filter(
149
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
150
-            array('EED_Add_New_State', 'inject_new_reg_country_into_options'),
151
-            10,
152
-            5
153
-        );
154
-    }
155
-
156
-
157
-    /**
158
-     * @return void
159
-     */
160
-    public static function set_definitions()
161
-    {
162
-        define('ANS_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets/');
163
-        define(
164
-            'ANS_TEMPLATES_PATH',
165
-            str_replace(
166
-                '\\',
167
-                '/',
168
-                plugin_dir_path(__FILE__)
169
-            ) . 'templates/'
170
-        );
171
-    }
172
-
173
-
174
-    /**
175
-     * @param WP $WP
176
-     * @return void
177
-     */
178
-    public function run($WP)
179
-    {
180
-    }
181
-
182
-
183
-    /**
184
-     * @return void
185
-     */
186
-    public static function translate_js_strings()
187
-    {
188
-        EE_Registry::$i18n_js_strings['ans_no_country'] = esc_html__(
189
-            'In order to proceed, you need to select the Country that your State/Province belongs to.',
190
-            'event_espresso'
191
-        );
192
-        EE_Registry::$i18n_js_strings['ans_no_name'] = esc_html__(
193
-            'In order to proceed, you need to enter the name of your State/Province.',
194
-            'event_espresso'
195
-        );
196
-        EE_Registry::$i18n_js_strings['ans_no_abbreviation'] = esc_html__(
197
-            'In order to proceed, you need to enter an abbreviation for the name of your State/Province.',
198
-            'event_espresso'
199
-        );
200
-        EE_Registry::$i18n_js_strings['ans_save_success'] = esc_html__(
201
-            'The new state was successfully saved to the database.',
202
-            'event_espresso'
203
-        );
204
-        EE_Registry::$i18n_js_strings['ans_server_save_error'] = esc_html__(
205
-            'An unknown error has occurred on the server while saving the new state to the database.',
206
-            'event_espresso'
207
-        );
208
-    }
209
-
210
-
211
-    /**
212
-     * @return void
213
-     */
214
-    public static function wp_enqueue_scripts()
215
-    {
216
-        if (apply_filters('EED_Single_Page_Checkout__SPCO_active', false)) {
217
-            wp_register_script(
218
-                'add_new_state',
219
-                ANS_ASSETS_URL . 'add_new_state.js',
220
-                array('espresso_core', 'single_page_checkout'),
221
-                EVENT_ESPRESSO_VERSION,
222
-                true
223
-            );
224
-            wp_enqueue_script('add_new_state');
225
-        }
226
-    }
227
-
228
-
229
-
230
-    /**
231
-     * display_add_new_state_micro_form
232
-     *
233
-     * @param EE_Form_Section_Proper $question_group_reg_form
234
-     * @return string
235
-     * @throws EE_Error
236
-     * @throws InvalidArgumentException
237
-     * @throws InvalidDataTypeException
238
-     * @throws InvalidInterfaceException
239
-     */
240
-    public static function display_add_new_state_micro_form(EE_Form_Section_Proper $question_group_reg_form)
241
-    {
242
-        // only add the 'new_state_micro_form' when displaying reg forms,
243
-        // not during processing since we process the 'new_state_micro_form' in it's own AJAX request
244
-        $action = EE_Registry::instance()->REQ->get('action', '');
245
-        // is the "state" question in this form section?
246
-        $input = $question_group_reg_form->get_subsection('state');
247
-        if ($action === 'process_reg_step' || $action === 'update_reg_step') {
248
-            // ok then all we need to do is make sure the input's HTML name is consistent
249
-            // by forcing it to set it now, like it did while getting the form for display
250
-            if ($input instanceof EE_State_Select_Input) {
251
-                $input->html_name();
252
-            }
253
-            return $question_group_reg_form;
254
-        }
255
-        // we're only doing this for state select inputs
256
-        if ($input instanceof EE_State_Select_Input
257
-            && ! $input->get_display_strategy() instanceof EE_Hidden_Display_Strategy
258
-        ) {
259
-            // grab any set values from the request
260
-            $country_name = str_replace('state', 'nsmf_new_state_country', $input->html_name());
261
-            $state_name = str_replace('state', 'nsmf_new_state_name', $input->html_name());
262
-            $abbrv_name = str_replace('state', 'nsmf_new_state_abbrv', $input->html_name());
263
-            $new_state_submit_id = str_replace('state', 'new_state', $input->html_id());
264
-            $country_options = array();
265
-            $countries = EEM_Country::instance()->get_all_countries();
266
-            if (! empty($countries)) {
267
-                foreach ($countries as $country) {
268
-                    if ($country instanceof EE_Country) {
269
-                        $country_options[ $country->ID() ] = $country->name();
270
-                    }
271
-                }
272
-            }
273
-            $new_state_micro_form = new EE_Form_Section_Proper(
274
-                array(
275
-                    'name'            => 'new_state_micro_form',
276
-                    'html_id'         => 'new_state_micro_form',
277
-                    'layout_strategy' => new EE_Div_Per_Section_Layout(),
278
-                    'subsections'     => array(
279
-                        // add hidden input to indicate that a new state is being added
280
-                        'add_new_state'               => new EE_Hidden_Input(
281
-                            array(
282
-                                'html_name' => str_replace(
283
-                                    'state',
284
-                                    'nsmf_add_new_state',
285
-                                    $input->html_name()
286
-                                ),
287
-                                'html_id'   => str_replace(
288
-                                    'state',
289
-                                    'nsmf_add_new_state',
290
-                                    $input->html_id()
291
-                                ),
292
-                                'default'   => 0,
293
-                            )
294
-                        ),
295
-                        // add link for displaying hidden container
296
-                        'click_here_link'             => new EE_Form_Section_HTML(
297
-                            apply_filters(
298
-                                'FHEE__EED_Add_New_State__display_add_new_state_micro_form__click_here_link',
299
-                                EEH_HTML::link(
300
-                                    '',
301
-                                    esc_html__('click here to add a new state/province', 'event_espresso'),
302
-                                    '',
303
-                                    'display-' . $input->html_id(),
304
-                                    'ee-form-add-new-state-lnk display-the-hidden smaller-text hide-if-no-js',
305
-                                    '',
306
-                                    'data-target="' . $input->html_id() . '"'
307
-                                )
308
-                            )
309
-                        ),
310
-                        // add initial html for hidden container
311
-                        'add_new_state_micro_form'    => new EE_Form_Section_HTML(
312
-                            apply_filters(
313
-                                'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_micro_form',
314
-                                EEH_HTML::div(
315
-                                    '',
316
-                                    $input->html_id() . '-dv',
317
-                                    'ee-form-add-new-state-dv',
318
-                                    'display: none;'
319
-                                ) .
320
-                                EEH_HTML::h6(
321
-                                    esc_html__(
322
-                                        'Is your state/province missing from the dropdown menu above? You can add it by completing the following steps:',
323
-                                        'event_espresso'
324
-                                    )
325
-                                ) .
326
-                                EEH_HTML::ul() .
327
-                                EEH_HTML::li(
328
-                                    esc_html__(
329
-                                        'first select the Country that your State/Province belongs to',
330
-                                        'event_espresso'
331
-                                    )
332
-                                ) .
333
-                                EEH_HTML::li(
334
-                                    esc_html__('enter the name of your State/Province', 'event_espresso')
335
-                                ) .
336
-                                EEH_HTML::li(
337
-                                    esc_html__(
338
-                                        'enter a two to six letter abbreviation for the name of your State/Province',
339
-                                        'event_espresso'
340
-                                    )
341
-                                ) .
342
-                                EEH_HTML::li(esc_html__('click the ADD button', 'event_espresso')) .
343
-                                EEH_HTML::ulx()
344
-                            )
345
-                        ),
346
-                        // NEW STATE COUNTRY
347
-                        'new_state_country'           => new EE_Country_Select_Input(
348
-                            $country_options,
349
-                            array(
350
-                                'html_name'       => $country_name,
351
-                                'html_id'         => str_replace(
352
-                                    'state',
353
-                                    'nsmf_new_state_country',
354
-                                    $input->html_id()
355
-                                ),
356
-                                'html_class'      => $input->html_class() . ' new-state-country',
357
-                                'html_label_text' => esc_html__('New State/Province Country', 'event_espresso'),
358
-                                'default'         => EE_Registry::instance()->REQ->get($country_name, ''),
359
-                                'required'        => false,
360
-                            )
361
-                        ),
362
-                        // NEW STATE NAME
363
-                        'new_state_name'              => new EE_Text_Input(
364
-                            array(
365
-                                'html_name'       => $state_name,
366
-                                'html_id'         => str_replace(
367
-                                    'state',
368
-                                    'nsmf_new_state_name',
369
-                                    $input->html_id()
370
-                                ),
371
-                                'html_class'      => $input->html_class() . ' new-state-state',
372
-                                'html_label_text' => esc_html__(
373
-                                    'New State/Province Name',
374
-                                    'event_espresso'
375
-                                ),
376
-                                'default'         => EE_Registry::instance()->REQ->get($state_name, ''),
377
-                                'required'        => false,
378
-                            )
379
-                        ),
380
-                        'spacer'                      => new EE_Form_Section_HTML(EEH_HTML::br()),
381
-                        // NEW STATE NAME
382
-                        'new_state_abbrv'             => new EE_Text_Input(
383
-                            array(
384
-                                'html_name'             => $abbrv_name,
385
-                                'html_id'               => str_replace(
386
-                                    'state',
387
-                                    'nsmf_new_state_abbrv',
388
-                                    $input->html_id()
389
-                                ),
390
-                                'html_class'            => $input->html_class() . ' new-state-abbrv',
391
-                                'html_label_text'       => esc_html__(
392
-                                    'New State/Province Abbreviation',
393
-                                    'event_espresso'
394
-                                ) . ' *',
395
-                                'html_other_attributes' => 'size="24"',
396
-                                'default'               => EE_Registry::instance()->REQ->get($abbrv_name, ''),
397
-                                'required'              => false,
398
-                            )
399
-                        ),
400
-                        // "submit" button
401
-                        'add_new_state_submit_button' => new EE_Form_Section_HTML(
402
-                            apply_filters(
403
-                                'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_submit_button',
404
-                                EEH_HTML::nbsp(3) .
405
-                                EEH_HTML::link(
406
-                                    '',
407
-                                    esc_html__('ADD', 'event_espresso'),
408
-                                    '',
409
-                                    'submit-' . $new_state_submit_id,
410
-                                    'ee-form-add-new-state-submit button button-secondary',
411
-                                    '',
412
-                                    'data-target="' . $new_state_submit_id . '" data-value-field-name="' . $input->valueFieldName(). '"'
413
-                                )
414
-                            )
415
-                        ),
416
-                        // extra info
417
-                        'add_new_state_extra'         => new EE_Form_Section_HTML(
418
-                            apply_filters(
419
-                                'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_extra',
420
-                                EEH_HTML::br(2)
421
-                                .
422
-                                EEH_HTML::div('', '', 'small-text')
423
-                                .
424
-                                EEH_HTML::strong(
425
-                                    '* ' .
426
-                                    esc_html__(
427
-                                        'Don\'t know your State/Province Abbreviation?',
428
-                                        'event_espresso'
429
-                                    )
430
-                                )
431
-                                .
432
-                                EEH_HTML::br()
433
-                                .
434
-                                sprintf(
435
-                                    esc_html__(
436
-                                        'You can look here: %s, for a list of Countries and links to their State/Province Abbreviations ("Subdivisions assigned codes" column).',
437
-                                        'event_espresso'
438
-                                    ),
439
-                                    EEH_HTML::link(
440
-                                        'http://en.wikipedia.org/wiki/ISO_3166-2',
441
-                                        'http://en.wikipedia.org/wiki/ISO_3166-2',
442
-                                        '',
443
-                                        '',
444
-                                        'ee-form-add-new-state-wiki-lnk',
445
-                                        '',
446
-                                        'target="_blank"'
447
-                                    )
448
-                                )
449
-                                .
450
-                                EEH_HTML::divx()
451
-                                .
452
-                                EEH_HTML::br()
453
-                                .
454
-                                EEH_HTML::link(
455
-                                    '',
456
-                                    esc_html__('cancel new State/Province', 'event_espresso'),
457
-                                    '',
458
-                                    'hide-' . $input->html_id(),
459
-                                    'ee-form-cancel-new-state-lnk smaller-text',
460
-                                    '',
461
-                                    'data-target="' . $input->html_id() . '"'
462
-                                )
463
-                                .
464
-                                EEH_HTML::divx()
465
-                                .
466
-                                EEH_HTML::br()
467
-                            )
468
-                        ),
469
-                    ),
470
-                )
471
-            );
472
-            $question_group_reg_form->add_subsections(
473
-                array('new_state_micro_form' => $new_state_micro_form),
474
-                'state',
475
-                false
476
-            );
477
-        }
478
-        return $question_group_reg_form;
479
-    }
480
-
481
-
482
-    /**
483
-     * set_new_state_input_width
484
-     *
485
-     * @return int|string
486
-     * @throws EE_Error
487
-     * @throws InvalidArgumentException
488
-     * @throws InvalidDataTypeException
489
-     * @throws InvalidInterfaceException
490
-     * @throws ReflectionException
491
-     */
492
-    public static function add_new_state()
493
-    {
494
-        $REQ = EE_Registry::instance()->load_core('Request_Handler');
495
-        if (absint($REQ->get('nsmf_add_new_state')) === 1) {
496
-            EE_Registry::instance()->load_model('State');
497
-            // grab country ISO code, new state name, and new state abbreviation
498
-            $state_country = $REQ->is_set('nsmf_new_state_country')
499
-                ? sanitize_text_field($REQ->get('nsmf_new_state_country'))
500
-                : false;
501
-            $state_name = $REQ->is_set('nsmf_new_state_name')
502
-                ? sanitize_text_field($REQ->get('nsmf_new_state_name'))
503
-                : false;
504
-            $state_abbr = $REQ->is_set('nsmf_new_state_abbrv')
505
-                ? sanitize_text_field($REQ->get('nsmf_new_state_abbrv'))
506
-                : false;
507
-            if ($state_country && $state_name && $state_abbr) {
508
-                $new_state = EED_Add_New_State::save_new_state_to_db(
509
-                    array(
510
-                        'CNT_ISO'    => strtoupper($state_country),
511
-                        'STA_abbrev' => strtoupper($state_abbr),
512
-                        'STA_name'   => ucwords($state_name),
513
-                        'STA_active' => false,
514
-                    )
515
-                );
516
-                if ($new_state instanceof EE_State) {
517
-                    // clean house
518
-                    EE_Registry::instance()->REQ->un_set('nsmf_add_new_state');
519
-                    EE_Registry::instance()->REQ->un_set('nsmf_new_state_country');
520
-                    EE_Registry::instance()->REQ->un_set('nsmf_new_state_name');
521
-                    EE_Registry::instance()->REQ->un_set('nsmf_new_state_abbrv');
522
-                    // get any existing new states
523
-                    $new_states = EE_Registry::instance()->SSN->get_session_data(
524
-                        'nsmf_new_states'
525
-                    );
526
-                    $new_states[ $new_state->ID() ] = $new_state;
527
-                    EE_Registry::instance()->SSN->set_session_data(
528
-                        array('nsmf_new_states' => $new_states)
529
-                    );
530
-                    if (EE_Registry::instance()->REQ->ajax) {
531
-                        echo wp_json_encode(
532
-                            array(
533
-                                'success'      => true,
534
-                                'id'           => $new_state->ID(),
535
-                                'name'         => $new_state->name(),
536
-                                'abbrev'       => $new_state->abbrev(),
537
-                                'country_iso'  => $new_state->country_iso(),
538
-                                'country_name' => $new_state->country()->name(),
539
-                            )
540
-                        );
541
-                        exit();
542
-                    }
543
-                    return $new_state->ID();
544
-                }
545
-            } else {
546
-                $error = esc_html__(
547
-                    'A new State/Province could not be added because invalid or missing data was received.',
548
-                    'event_espresso'
549
-                );
550
-                if (EE_Registry::instance()->REQ->ajax) {
551
-                    echo wp_json_encode(array('error' => $error));
552
-                    exit();
553
-                }
554
-                EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
555
-            }
556
-        }
557
-        return false;
558
-    }
559
-
560
-
561
-    /**
562
-     * recursively drills down through request params to remove any that were added by this module
563
-     *
564
-     * @param array $request_params
565
-     * @return array
566
-     */
567
-    public static function filter_checkout_request_params($request_params)
568
-    {
569
-        foreach ($request_params as $form_section) {
570
-            if (is_array($form_section)) {
571
-                EED_Add_New_State::unset_new_state_request_params($form_section);
572
-                EED_Add_New_State::filter_checkout_request_params($form_section);
573
-            }
574
-        }
575
-        return $request_params;
576
-    }
577
-
578
-
579
-    /**
580
-     * @param array $request_params
581
-     * @return array
582
-     */
583
-    public static function unset_new_state_request_params($request_params)
584
-    {
585
-        unset(
586
-            $request_params['new_state_micro_form'],
587
-            $request_params['new_state_micro_add_new_state'],
588
-            $request_params['new_state_micro_new_state_country'],
589
-            $request_params['new_state_micro_new_state_name'],
590
-            $request_params['new_state_micro_new_state_abbrv']
591
-        );
592
-        return $request_params;
593
-    }
594
-
595
-
596
-    /**
597
-     * @param array $props_n_values
598
-     * @return bool
599
-     * @throws EE_Error
600
-     * @throws InvalidArgumentException
601
-     * @throws InvalidDataTypeException
602
-     * @throws InvalidInterfaceException
603
-     */
604
-    public static function save_new_state_to_db($props_n_values = array())
605
-    {
606
-        $existing_state = EEM_State::instance()->get_all(array($props_n_values, 'limit' => 1));
607
-        if (! empty($existing_state)) {
608
-            return array_pop($existing_state);
609
-        }
610
-        $new_state = EE_State::new_instance($props_n_values);
611
-        if ($new_state instanceof EE_State) {
612
-            $country_settings_url = add_query_arg(
613
-                array(
614
-                    'page'    => 'espresso_general_settings',
615
-                    'action'  => 'country_settings',
616
-                    'country' => $new_state->country_iso(),
617
-                ),
618
-                admin_url('admin.php')
619
-            );
620
-            // if not non-ajax admin
621
-            new PersistentAdminNotice(
622
-                'new-state-added-' . $new_state->country_iso() . '-' . $new_state->abbrev(),
623
-                sprintf(
624
-                    esc_html__(
625
-                        'A new State named "%1$s (%2$s)" was dynamically added from an Event Espresso form for the Country of "%3$s".%5$sTo verify, edit, and/or delete this new State, please go to the %4$s and update the States / Provinces section.%5$sCheck "Yes" to have this new State added to dropdown select lists in forms.',
626
-                        'event_espresso'
627
-                    ),
628
-                    '<b>' . $new_state->name() . '</b>',
629
-                    '<b>' . $new_state->abbrev() . '</b>',
630
-                    '<b>' . $new_state->country()->name() . '</b>',
631
-                    '<a href="'
632
-                    . $country_settings_url
633
-                    . '">'
634
-                    . esc_html__(
635
-                        'Event Espresso - General Settings > Countries Tab',
636
-                        'event_espresso'
637
-                    )
638
-                    . '</a>',
639
-                    '<br />'
640
-                )
641
-            );
642
-            $new_state->save();
643
-            EEM_State::instance()->reset_cached_states();
644
-            return $new_state;
645
-        }
646
-        return false;
647
-    }
648
-
649
-
650
-    /**
651
-     * @param string $CNT_ISO
652
-     * @param string $STA_ID
653
-     * @param array  $cols_n_values
654
-     * @return void
655
-     * @throws DomainException
656
-     * @throws EE_Error
657
-     * @throws InvalidArgumentException
658
-     * @throws InvalidDataTypeException
659
-     * @throws InvalidInterfaceException
660
-     */
661
-    public static function update_country_settings($CNT_ISO = '', $STA_ID = '', $cols_n_values = array())
662
-    {
663
-        if (! $CNT_ISO) {
664
-            EE_Error::add_error(
665
-                esc_html__('An invalid or missing Country ISO Code was received.', 'event_espresso'),
666
-                __FILE__,
667
-                __FUNCTION__,
668
-                __LINE__
669
-            );
670
-        }
671
-        $STA_abbrev = is_array($cols_n_values) && isset($cols_n_values['STA_abbrev']) ? $cols_n_values['STA_abbrev']
672
-            : false;
673
-        if (! $STA_abbrev && ! empty($STA_ID)) {
674
-            $state = EEM_State::instance()->get_one_by_ID($STA_ID);
675
-            if ($state instanceof EE_State) {
676
-                $STA_abbrev = $state->abbrev();
677
-            }
678
-        }
679
-        if (! $STA_abbrev) {
680
-            EE_Error::add_error(
681
-                esc_html__('An invalid or missing State Abbreviation was received.', 'event_espresso'),
682
-                __FILE__,
683
-                __FUNCTION__,
684
-                __LINE__
685
-            );
686
-        }
687
-        /** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
688
-        $persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
689
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
690
-        );
691
-        $persistent_admin_notice_manager->dismissNotice($CNT_ISO . '-' . $STA_abbrev, true, true);
692
-    }
693
-
694
-
695
-    /**
696
-     * @param EE_State[]                            $state_options
697
-     * @param EE_SPCO_Reg_Step_Attendee_Information $reg_step
698
-     * @param EE_Registration                       $registration
699
-     * @param EE_Question                           $question
700
-     * @param                                       $answer
701
-     * @return array
702
-     * @throws EE_Error
703
-     * @throws InvalidArgumentException
704
-     * @throws InvalidDataTypeException
705
-     * @throws InvalidInterfaceException
706
-     */
707
-    public static function inject_new_reg_state_into_options(
708
-        $state_options = array(),
709
-        EE_SPCO_Reg_Step_Attendee_Information $reg_step,
710
-        EE_Registration $registration,
711
-        EE_Question $question,
712
-        $answer
713
-    ) {
714
-        if ($answer instanceof EE_Answer && $question instanceof EE_Question
715
-            && $question->type() === EEM_Question::QST_type_state
716
-        ) {
717
-            $STA_ID = $answer->value();
718
-            if (! empty($STA_ID)) {
719
-                $state = EEM_State::instance()->get_one_by_ID($STA_ID);
720
-                if ($state instanceof EE_State) {
721
-                    $country = $state->country();
722
-                    if ($country instanceof EE_Country) {
723
-                        if (! isset($state_options[ $country->name() ])) {
724
-                            $state_options[ $country->name() ] = array();
725
-                        }
726
-                        if (! isset($state_options[ $country->name() ][ $STA_ID ])) {
727
-                            $state_options[ $country->name() ][ $STA_ID ] = $state->name();
728
-                        }
729
-                    }
730
-                }
731
-            }
732
-        }
733
-        return $state_options;
734
-    }
735
-
736
-
737
-    /**
738
-     * @param EE_Country[]                          $country_options
739
-     * @param EE_SPCO_Reg_Step_Attendee_Information $reg_step
740
-     * @param EE_Registration                       $registration
741
-     * @param EE_Question                           $question
742
-     * @param                                       $answer
743
-     * @return array
744
-     * @throws EE_Error
745
-     * @throws InvalidArgumentException
746
-     * @throws InvalidDataTypeException
747
-     * @throws InvalidInterfaceException
748
-     */
749
-    public static function inject_new_reg_country_into_options(
750
-        $country_options = array(),
751
-        EE_SPCO_Reg_Step_Attendee_Information $reg_step,
752
-        EE_Registration $registration,
753
-        EE_Question $question,
754
-        $answer
755
-    ) {
756
-        if ($answer instanceof EE_Answer && $question instanceof EE_Question
757
-            && $question->type()
758
-               === EEM_Question::QST_type_country
759
-        ) {
760
-            $CNT_ISO = $answer->value();
761
-            if (! empty($CNT_ISO)) {
762
-                $country = EEM_Country::instance()->get_one_by_ID($CNT_ISO);
763
-                if ($country instanceof EE_Country) {
764
-                    if (! isset($country_options[ $CNT_ISO ])) {
765
-                        $country_options[ $CNT_ISO ] = $country->name();
766
-                    }
767
-                }
768
-            }
769
-        }
770
-        return $country_options;
771
-    }
772
-
773
-
774
-    /**
775
-     * @param EE_State[] $state_options
776
-     * @return array
777
-     * @throws EE_Error
778
-     * @throws InvalidArgumentException
779
-     * @throws InvalidDataTypeException
780
-     * @throws InvalidInterfaceException
781
-     */
782
-    public static function state_options($state_options = array())
783
-    {
784
-        $new_states = EED_Add_New_State::_get_new_states();
785
-        foreach ($new_states as $new_state) {
786
-            if ($new_state instanceof EE_State
787
-                && $new_state->country() instanceof EE_Country
788
-            ) {
789
-                $state_options[ $new_state->country()->name() ][ $new_state->ID() ] = $new_state->name();
790
-            }
791
-        }
792
-        return $state_options;
793
-    }
794
-
795
-
796
-    /**
797
-     * @return array
798
-     * @throws InvalidArgumentException
799
-     * @throws InvalidDataTypeException
800
-     * @throws InvalidInterfaceException
801
-     */
802
-    protected static function _get_new_states()
803
-    {
804
-        $new_states = array();
805
-        if (EE_Registry::instance()->SSN instanceof EE_Session) {
806
-            $new_states = EE_Registry::instance()->SSN->get_session_data(
807
-                'nsmf_new_states'
808
-            );
809
-        }
810
-        return is_array($new_states) ? $new_states : array();
811
-    }
812
-
813
-
814
-    /**
815
-     * @param EE_Country[] $country_options
816
-     * @return array
817
-     * @throws EE_Error
818
-     * @throws InvalidArgumentException
819
-     * @throws InvalidDataTypeException
820
-     * @throws InvalidInterfaceException
821
-     */
822
-    public static function country_options($country_options = array())
823
-    {
824
-        $new_states = EED_Add_New_State::_get_new_states();
825
-        foreach ($new_states as $new_state) {
826
-            if ($new_state instanceof EE_State
827
-                && $new_state->country() instanceof EE_Country
828
-            ) {
829
-                $country_options[ $new_state->country()->ID() ] = $new_state->country()->name();
830
-            }
831
-        }
832
-        return $country_options;
833
-    }
20
+	/**
21
+	 * @return EED_Module|EED_Add_New_State
22
+	 */
23
+	public static function instance()
24
+	{
25
+		return parent::get_instance(__CLASS__);
26
+	}
27
+
28
+
29
+	/**
30
+	 * set_hooks - for hooking into EE Core, other modules, etc
31
+	 *
32
+	 * @return void
33
+	 */
34
+	public static function set_hooks()
35
+	{
36
+		add_action('wp_loaded', array('EED_Add_New_State', 'set_definitions'), 2);
37
+		add_action('wp_enqueue_scripts', array('EED_Add_New_State', 'translate_js_strings'), 0);
38
+		add_action('wp_enqueue_scripts', array('EED_Add_New_State', 'wp_enqueue_scripts'), 10);
39
+		add_filter(
40
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
41
+			array('EED_Add_New_State', 'display_add_new_state_micro_form'),
42
+			1,
43
+			1
44
+		);
45
+		add_filter(
46
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
47
+			array('EED_Add_New_State', 'display_add_new_state_micro_form'),
48
+			1,
49
+			1
50
+		);
51
+		add_filter(
52
+			'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
53
+			array('EED_Add_New_State', 'unset_new_state_request_params'),
54
+			10,
55
+			1
56
+		);
57
+		add_filter(
58
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
59
+			array('EED_Add_New_State', 'inject_new_reg_state_into_options'),
60
+			10,
61
+			5
62
+		);
63
+		add_filter(
64
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
65
+			array('EED_Add_New_State', 'inject_new_reg_country_into_options'),
66
+			10,
67
+			5
68
+		);
69
+		add_filter(
70
+			'FHEE__EE_State_Select_Input____construct__state_options',
71
+			array('EED_Add_New_State', 'state_options'),
72
+			10,
73
+			1
74
+		);
75
+		add_filter(
76
+			'FHEE__EE_Country_Select_Input____construct__country_options',
77
+			array('EED_Add_New_State', 'country_options'),
78
+			10,
79
+			1
80
+		);
81
+	}
82
+
83
+
84
+	/**
85
+	 * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
86
+	 *
87
+	 * @return void
88
+	 */
89
+	public static function set_hooks_admin()
90
+	{
91
+		add_action('wp_loaded', array('EED_Add_New_State', 'set_definitions'), 2);
92
+		add_filter(
93
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
94
+			array('EED_Add_New_State', 'display_add_new_state_micro_form'),
95
+			1,
96
+			1
97
+		);
98
+		add_filter(
99
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
100
+			array('EED_Add_New_State', 'display_add_new_state_micro_form'),
101
+			1,
102
+			1
103
+		);
104
+		add_action('wp_ajax_espresso_add_new_state', array('EED_Add_New_State', 'add_new_state'));
105
+		add_action('wp_ajax_nopriv_espresso_add_new_state', array('EED_Add_New_State', 'add_new_state'));
106
+		add_filter(
107
+			'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
108
+			array('EED_Add_New_State', 'unset_new_state_request_params'),
109
+			10,
110
+			1
111
+		);
112
+		add_action(
113
+			'AHEE__General_Settings_Admin_Page__update_country_settings__state_saved',
114
+			array('EED_Add_New_State', 'update_country_settings'),
115
+			10,
116
+			3
117
+		);
118
+		add_action(
119
+			'AHEE__General_Settings_Admin_Page__delete_state__state_deleted',
120
+			array('EED_Add_New_State', 'update_country_settings'),
121
+			10,
122
+			3
123
+		);
124
+		add_filter(
125
+			'FHEE__EE_State_Select_Input____construct__state_options',
126
+			array('EED_Add_New_State', 'state_options'),
127
+			10,
128
+			1
129
+		);
130
+		add_filter(
131
+			'FHEE__EE_Country_Select_Input____construct__country_options',
132
+			array('EED_Add_New_State', 'country_options'),
133
+			10,
134
+			1
135
+		);
136
+		add_filter(
137
+			'FHEE__EE_Form_Section_Proper__receive_form_submission__request_data',
138
+			array('EED_Add_New_State', 'filter_checkout_request_params'),
139
+			10,
140
+			1
141
+		);
142
+		add_filter(
143
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
144
+			array('EED_Add_New_State', 'inject_new_reg_state_into_options'),
145
+			10,
146
+			5
147
+		);
148
+		add_filter(
149
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
150
+			array('EED_Add_New_State', 'inject_new_reg_country_into_options'),
151
+			10,
152
+			5
153
+		);
154
+	}
155
+
156
+
157
+	/**
158
+	 * @return void
159
+	 */
160
+	public static function set_definitions()
161
+	{
162
+		define('ANS_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets/');
163
+		define(
164
+			'ANS_TEMPLATES_PATH',
165
+			str_replace(
166
+				'\\',
167
+				'/',
168
+				plugin_dir_path(__FILE__)
169
+			) . 'templates/'
170
+		);
171
+	}
172
+
173
+
174
+	/**
175
+	 * @param WP $WP
176
+	 * @return void
177
+	 */
178
+	public function run($WP)
179
+	{
180
+	}
181
+
182
+
183
+	/**
184
+	 * @return void
185
+	 */
186
+	public static function translate_js_strings()
187
+	{
188
+		EE_Registry::$i18n_js_strings['ans_no_country'] = esc_html__(
189
+			'In order to proceed, you need to select the Country that your State/Province belongs to.',
190
+			'event_espresso'
191
+		);
192
+		EE_Registry::$i18n_js_strings['ans_no_name'] = esc_html__(
193
+			'In order to proceed, you need to enter the name of your State/Province.',
194
+			'event_espresso'
195
+		);
196
+		EE_Registry::$i18n_js_strings['ans_no_abbreviation'] = esc_html__(
197
+			'In order to proceed, you need to enter an abbreviation for the name of your State/Province.',
198
+			'event_espresso'
199
+		);
200
+		EE_Registry::$i18n_js_strings['ans_save_success'] = esc_html__(
201
+			'The new state was successfully saved to the database.',
202
+			'event_espresso'
203
+		);
204
+		EE_Registry::$i18n_js_strings['ans_server_save_error'] = esc_html__(
205
+			'An unknown error has occurred on the server while saving the new state to the database.',
206
+			'event_espresso'
207
+		);
208
+	}
209
+
210
+
211
+	/**
212
+	 * @return void
213
+	 */
214
+	public static function wp_enqueue_scripts()
215
+	{
216
+		if (apply_filters('EED_Single_Page_Checkout__SPCO_active', false)) {
217
+			wp_register_script(
218
+				'add_new_state',
219
+				ANS_ASSETS_URL . 'add_new_state.js',
220
+				array('espresso_core', 'single_page_checkout'),
221
+				EVENT_ESPRESSO_VERSION,
222
+				true
223
+			);
224
+			wp_enqueue_script('add_new_state');
225
+		}
226
+	}
227
+
228
+
229
+
230
+	/**
231
+	 * display_add_new_state_micro_form
232
+	 *
233
+	 * @param EE_Form_Section_Proper $question_group_reg_form
234
+	 * @return string
235
+	 * @throws EE_Error
236
+	 * @throws InvalidArgumentException
237
+	 * @throws InvalidDataTypeException
238
+	 * @throws InvalidInterfaceException
239
+	 */
240
+	public static function display_add_new_state_micro_form(EE_Form_Section_Proper $question_group_reg_form)
241
+	{
242
+		// only add the 'new_state_micro_form' when displaying reg forms,
243
+		// not during processing since we process the 'new_state_micro_form' in it's own AJAX request
244
+		$action = EE_Registry::instance()->REQ->get('action', '');
245
+		// is the "state" question in this form section?
246
+		$input = $question_group_reg_form->get_subsection('state');
247
+		if ($action === 'process_reg_step' || $action === 'update_reg_step') {
248
+			// ok then all we need to do is make sure the input's HTML name is consistent
249
+			// by forcing it to set it now, like it did while getting the form for display
250
+			if ($input instanceof EE_State_Select_Input) {
251
+				$input->html_name();
252
+			}
253
+			return $question_group_reg_form;
254
+		}
255
+		// we're only doing this for state select inputs
256
+		if ($input instanceof EE_State_Select_Input
257
+			&& ! $input->get_display_strategy() instanceof EE_Hidden_Display_Strategy
258
+		) {
259
+			// grab any set values from the request
260
+			$country_name = str_replace('state', 'nsmf_new_state_country', $input->html_name());
261
+			$state_name = str_replace('state', 'nsmf_new_state_name', $input->html_name());
262
+			$abbrv_name = str_replace('state', 'nsmf_new_state_abbrv', $input->html_name());
263
+			$new_state_submit_id = str_replace('state', 'new_state', $input->html_id());
264
+			$country_options = array();
265
+			$countries = EEM_Country::instance()->get_all_countries();
266
+			if (! empty($countries)) {
267
+				foreach ($countries as $country) {
268
+					if ($country instanceof EE_Country) {
269
+						$country_options[ $country->ID() ] = $country->name();
270
+					}
271
+				}
272
+			}
273
+			$new_state_micro_form = new EE_Form_Section_Proper(
274
+				array(
275
+					'name'            => 'new_state_micro_form',
276
+					'html_id'         => 'new_state_micro_form',
277
+					'layout_strategy' => new EE_Div_Per_Section_Layout(),
278
+					'subsections'     => array(
279
+						// add hidden input to indicate that a new state is being added
280
+						'add_new_state'               => new EE_Hidden_Input(
281
+							array(
282
+								'html_name' => str_replace(
283
+									'state',
284
+									'nsmf_add_new_state',
285
+									$input->html_name()
286
+								),
287
+								'html_id'   => str_replace(
288
+									'state',
289
+									'nsmf_add_new_state',
290
+									$input->html_id()
291
+								),
292
+								'default'   => 0,
293
+							)
294
+						),
295
+						// add link for displaying hidden container
296
+						'click_here_link'             => new EE_Form_Section_HTML(
297
+							apply_filters(
298
+								'FHEE__EED_Add_New_State__display_add_new_state_micro_form__click_here_link',
299
+								EEH_HTML::link(
300
+									'',
301
+									esc_html__('click here to add a new state/province', 'event_espresso'),
302
+									'',
303
+									'display-' . $input->html_id(),
304
+									'ee-form-add-new-state-lnk display-the-hidden smaller-text hide-if-no-js',
305
+									'',
306
+									'data-target="' . $input->html_id() . '"'
307
+								)
308
+							)
309
+						),
310
+						// add initial html for hidden container
311
+						'add_new_state_micro_form'    => new EE_Form_Section_HTML(
312
+							apply_filters(
313
+								'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_micro_form',
314
+								EEH_HTML::div(
315
+									'',
316
+									$input->html_id() . '-dv',
317
+									'ee-form-add-new-state-dv',
318
+									'display: none;'
319
+								) .
320
+								EEH_HTML::h6(
321
+									esc_html__(
322
+										'Is your state/province missing from the dropdown menu above? You can add it by completing the following steps:',
323
+										'event_espresso'
324
+									)
325
+								) .
326
+								EEH_HTML::ul() .
327
+								EEH_HTML::li(
328
+									esc_html__(
329
+										'first select the Country that your State/Province belongs to',
330
+										'event_espresso'
331
+									)
332
+								) .
333
+								EEH_HTML::li(
334
+									esc_html__('enter the name of your State/Province', 'event_espresso')
335
+								) .
336
+								EEH_HTML::li(
337
+									esc_html__(
338
+										'enter a two to six letter abbreviation for the name of your State/Province',
339
+										'event_espresso'
340
+									)
341
+								) .
342
+								EEH_HTML::li(esc_html__('click the ADD button', 'event_espresso')) .
343
+								EEH_HTML::ulx()
344
+							)
345
+						),
346
+						// NEW STATE COUNTRY
347
+						'new_state_country'           => new EE_Country_Select_Input(
348
+							$country_options,
349
+							array(
350
+								'html_name'       => $country_name,
351
+								'html_id'         => str_replace(
352
+									'state',
353
+									'nsmf_new_state_country',
354
+									$input->html_id()
355
+								),
356
+								'html_class'      => $input->html_class() . ' new-state-country',
357
+								'html_label_text' => esc_html__('New State/Province Country', 'event_espresso'),
358
+								'default'         => EE_Registry::instance()->REQ->get($country_name, ''),
359
+								'required'        => false,
360
+							)
361
+						),
362
+						// NEW STATE NAME
363
+						'new_state_name'              => new EE_Text_Input(
364
+							array(
365
+								'html_name'       => $state_name,
366
+								'html_id'         => str_replace(
367
+									'state',
368
+									'nsmf_new_state_name',
369
+									$input->html_id()
370
+								),
371
+								'html_class'      => $input->html_class() . ' new-state-state',
372
+								'html_label_text' => esc_html__(
373
+									'New State/Province Name',
374
+									'event_espresso'
375
+								),
376
+								'default'         => EE_Registry::instance()->REQ->get($state_name, ''),
377
+								'required'        => false,
378
+							)
379
+						),
380
+						'spacer'                      => new EE_Form_Section_HTML(EEH_HTML::br()),
381
+						// NEW STATE NAME
382
+						'new_state_abbrv'             => new EE_Text_Input(
383
+							array(
384
+								'html_name'             => $abbrv_name,
385
+								'html_id'               => str_replace(
386
+									'state',
387
+									'nsmf_new_state_abbrv',
388
+									$input->html_id()
389
+								),
390
+								'html_class'            => $input->html_class() . ' new-state-abbrv',
391
+								'html_label_text'       => esc_html__(
392
+									'New State/Province Abbreviation',
393
+									'event_espresso'
394
+								) . ' *',
395
+								'html_other_attributes' => 'size="24"',
396
+								'default'               => EE_Registry::instance()->REQ->get($abbrv_name, ''),
397
+								'required'              => false,
398
+							)
399
+						),
400
+						// "submit" button
401
+						'add_new_state_submit_button' => new EE_Form_Section_HTML(
402
+							apply_filters(
403
+								'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_submit_button',
404
+								EEH_HTML::nbsp(3) .
405
+								EEH_HTML::link(
406
+									'',
407
+									esc_html__('ADD', 'event_espresso'),
408
+									'',
409
+									'submit-' . $new_state_submit_id,
410
+									'ee-form-add-new-state-submit button button-secondary',
411
+									'',
412
+									'data-target="' . $new_state_submit_id . '" data-value-field-name="' . $input->valueFieldName(). '"'
413
+								)
414
+							)
415
+						),
416
+						// extra info
417
+						'add_new_state_extra'         => new EE_Form_Section_HTML(
418
+							apply_filters(
419
+								'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_extra',
420
+								EEH_HTML::br(2)
421
+								.
422
+								EEH_HTML::div('', '', 'small-text')
423
+								.
424
+								EEH_HTML::strong(
425
+									'* ' .
426
+									esc_html__(
427
+										'Don\'t know your State/Province Abbreviation?',
428
+										'event_espresso'
429
+									)
430
+								)
431
+								.
432
+								EEH_HTML::br()
433
+								.
434
+								sprintf(
435
+									esc_html__(
436
+										'You can look here: %s, for a list of Countries and links to their State/Province Abbreviations ("Subdivisions assigned codes" column).',
437
+										'event_espresso'
438
+									),
439
+									EEH_HTML::link(
440
+										'http://en.wikipedia.org/wiki/ISO_3166-2',
441
+										'http://en.wikipedia.org/wiki/ISO_3166-2',
442
+										'',
443
+										'',
444
+										'ee-form-add-new-state-wiki-lnk',
445
+										'',
446
+										'target="_blank"'
447
+									)
448
+								)
449
+								.
450
+								EEH_HTML::divx()
451
+								.
452
+								EEH_HTML::br()
453
+								.
454
+								EEH_HTML::link(
455
+									'',
456
+									esc_html__('cancel new State/Province', 'event_espresso'),
457
+									'',
458
+									'hide-' . $input->html_id(),
459
+									'ee-form-cancel-new-state-lnk smaller-text',
460
+									'',
461
+									'data-target="' . $input->html_id() . '"'
462
+								)
463
+								.
464
+								EEH_HTML::divx()
465
+								.
466
+								EEH_HTML::br()
467
+							)
468
+						),
469
+					),
470
+				)
471
+			);
472
+			$question_group_reg_form->add_subsections(
473
+				array('new_state_micro_form' => $new_state_micro_form),
474
+				'state',
475
+				false
476
+			);
477
+		}
478
+		return $question_group_reg_form;
479
+	}
480
+
481
+
482
+	/**
483
+	 * set_new_state_input_width
484
+	 *
485
+	 * @return int|string
486
+	 * @throws EE_Error
487
+	 * @throws InvalidArgumentException
488
+	 * @throws InvalidDataTypeException
489
+	 * @throws InvalidInterfaceException
490
+	 * @throws ReflectionException
491
+	 */
492
+	public static function add_new_state()
493
+	{
494
+		$REQ = EE_Registry::instance()->load_core('Request_Handler');
495
+		if (absint($REQ->get('nsmf_add_new_state')) === 1) {
496
+			EE_Registry::instance()->load_model('State');
497
+			// grab country ISO code, new state name, and new state abbreviation
498
+			$state_country = $REQ->is_set('nsmf_new_state_country')
499
+				? sanitize_text_field($REQ->get('nsmf_new_state_country'))
500
+				: false;
501
+			$state_name = $REQ->is_set('nsmf_new_state_name')
502
+				? sanitize_text_field($REQ->get('nsmf_new_state_name'))
503
+				: false;
504
+			$state_abbr = $REQ->is_set('nsmf_new_state_abbrv')
505
+				? sanitize_text_field($REQ->get('nsmf_new_state_abbrv'))
506
+				: false;
507
+			if ($state_country && $state_name && $state_abbr) {
508
+				$new_state = EED_Add_New_State::save_new_state_to_db(
509
+					array(
510
+						'CNT_ISO'    => strtoupper($state_country),
511
+						'STA_abbrev' => strtoupper($state_abbr),
512
+						'STA_name'   => ucwords($state_name),
513
+						'STA_active' => false,
514
+					)
515
+				);
516
+				if ($new_state instanceof EE_State) {
517
+					// clean house
518
+					EE_Registry::instance()->REQ->un_set('nsmf_add_new_state');
519
+					EE_Registry::instance()->REQ->un_set('nsmf_new_state_country');
520
+					EE_Registry::instance()->REQ->un_set('nsmf_new_state_name');
521
+					EE_Registry::instance()->REQ->un_set('nsmf_new_state_abbrv');
522
+					// get any existing new states
523
+					$new_states = EE_Registry::instance()->SSN->get_session_data(
524
+						'nsmf_new_states'
525
+					);
526
+					$new_states[ $new_state->ID() ] = $new_state;
527
+					EE_Registry::instance()->SSN->set_session_data(
528
+						array('nsmf_new_states' => $new_states)
529
+					);
530
+					if (EE_Registry::instance()->REQ->ajax) {
531
+						echo wp_json_encode(
532
+							array(
533
+								'success'      => true,
534
+								'id'           => $new_state->ID(),
535
+								'name'         => $new_state->name(),
536
+								'abbrev'       => $new_state->abbrev(),
537
+								'country_iso'  => $new_state->country_iso(),
538
+								'country_name' => $new_state->country()->name(),
539
+							)
540
+						);
541
+						exit();
542
+					}
543
+					return $new_state->ID();
544
+				}
545
+			} else {
546
+				$error = esc_html__(
547
+					'A new State/Province could not be added because invalid or missing data was received.',
548
+					'event_espresso'
549
+				);
550
+				if (EE_Registry::instance()->REQ->ajax) {
551
+					echo wp_json_encode(array('error' => $error));
552
+					exit();
553
+				}
554
+				EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
555
+			}
556
+		}
557
+		return false;
558
+	}
559
+
560
+
561
+	/**
562
+	 * recursively drills down through request params to remove any that were added by this module
563
+	 *
564
+	 * @param array $request_params
565
+	 * @return array
566
+	 */
567
+	public static function filter_checkout_request_params($request_params)
568
+	{
569
+		foreach ($request_params as $form_section) {
570
+			if (is_array($form_section)) {
571
+				EED_Add_New_State::unset_new_state_request_params($form_section);
572
+				EED_Add_New_State::filter_checkout_request_params($form_section);
573
+			}
574
+		}
575
+		return $request_params;
576
+	}
577
+
578
+
579
+	/**
580
+	 * @param array $request_params
581
+	 * @return array
582
+	 */
583
+	public static function unset_new_state_request_params($request_params)
584
+	{
585
+		unset(
586
+			$request_params['new_state_micro_form'],
587
+			$request_params['new_state_micro_add_new_state'],
588
+			$request_params['new_state_micro_new_state_country'],
589
+			$request_params['new_state_micro_new_state_name'],
590
+			$request_params['new_state_micro_new_state_abbrv']
591
+		);
592
+		return $request_params;
593
+	}
594
+
595
+
596
+	/**
597
+	 * @param array $props_n_values
598
+	 * @return bool
599
+	 * @throws EE_Error
600
+	 * @throws InvalidArgumentException
601
+	 * @throws InvalidDataTypeException
602
+	 * @throws InvalidInterfaceException
603
+	 */
604
+	public static function save_new_state_to_db($props_n_values = array())
605
+	{
606
+		$existing_state = EEM_State::instance()->get_all(array($props_n_values, 'limit' => 1));
607
+		if (! empty($existing_state)) {
608
+			return array_pop($existing_state);
609
+		}
610
+		$new_state = EE_State::new_instance($props_n_values);
611
+		if ($new_state instanceof EE_State) {
612
+			$country_settings_url = add_query_arg(
613
+				array(
614
+					'page'    => 'espresso_general_settings',
615
+					'action'  => 'country_settings',
616
+					'country' => $new_state->country_iso(),
617
+				),
618
+				admin_url('admin.php')
619
+			);
620
+			// if not non-ajax admin
621
+			new PersistentAdminNotice(
622
+				'new-state-added-' . $new_state->country_iso() . '-' . $new_state->abbrev(),
623
+				sprintf(
624
+					esc_html__(
625
+						'A new State named "%1$s (%2$s)" was dynamically added from an Event Espresso form for the Country of "%3$s".%5$sTo verify, edit, and/or delete this new State, please go to the %4$s and update the States / Provinces section.%5$sCheck "Yes" to have this new State added to dropdown select lists in forms.',
626
+						'event_espresso'
627
+					),
628
+					'<b>' . $new_state->name() . '</b>',
629
+					'<b>' . $new_state->abbrev() . '</b>',
630
+					'<b>' . $new_state->country()->name() . '</b>',
631
+					'<a href="'
632
+					. $country_settings_url
633
+					. '">'
634
+					. esc_html__(
635
+						'Event Espresso - General Settings > Countries Tab',
636
+						'event_espresso'
637
+					)
638
+					. '</a>',
639
+					'<br />'
640
+				)
641
+			);
642
+			$new_state->save();
643
+			EEM_State::instance()->reset_cached_states();
644
+			return $new_state;
645
+		}
646
+		return false;
647
+	}
648
+
649
+
650
+	/**
651
+	 * @param string $CNT_ISO
652
+	 * @param string $STA_ID
653
+	 * @param array  $cols_n_values
654
+	 * @return void
655
+	 * @throws DomainException
656
+	 * @throws EE_Error
657
+	 * @throws InvalidArgumentException
658
+	 * @throws InvalidDataTypeException
659
+	 * @throws InvalidInterfaceException
660
+	 */
661
+	public static function update_country_settings($CNT_ISO = '', $STA_ID = '', $cols_n_values = array())
662
+	{
663
+		if (! $CNT_ISO) {
664
+			EE_Error::add_error(
665
+				esc_html__('An invalid or missing Country ISO Code was received.', 'event_espresso'),
666
+				__FILE__,
667
+				__FUNCTION__,
668
+				__LINE__
669
+			);
670
+		}
671
+		$STA_abbrev = is_array($cols_n_values) && isset($cols_n_values['STA_abbrev']) ? $cols_n_values['STA_abbrev']
672
+			: false;
673
+		if (! $STA_abbrev && ! empty($STA_ID)) {
674
+			$state = EEM_State::instance()->get_one_by_ID($STA_ID);
675
+			if ($state instanceof EE_State) {
676
+				$STA_abbrev = $state->abbrev();
677
+			}
678
+		}
679
+		if (! $STA_abbrev) {
680
+			EE_Error::add_error(
681
+				esc_html__('An invalid or missing State Abbreviation was received.', 'event_espresso'),
682
+				__FILE__,
683
+				__FUNCTION__,
684
+				__LINE__
685
+			);
686
+		}
687
+		/** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
688
+		$persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
689
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
690
+		);
691
+		$persistent_admin_notice_manager->dismissNotice($CNT_ISO . '-' . $STA_abbrev, true, true);
692
+	}
693
+
694
+
695
+	/**
696
+	 * @param EE_State[]                            $state_options
697
+	 * @param EE_SPCO_Reg_Step_Attendee_Information $reg_step
698
+	 * @param EE_Registration                       $registration
699
+	 * @param EE_Question                           $question
700
+	 * @param                                       $answer
701
+	 * @return array
702
+	 * @throws EE_Error
703
+	 * @throws InvalidArgumentException
704
+	 * @throws InvalidDataTypeException
705
+	 * @throws InvalidInterfaceException
706
+	 */
707
+	public static function inject_new_reg_state_into_options(
708
+		$state_options = array(),
709
+		EE_SPCO_Reg_Step_Attendee_Information $reg_step,
710
+		EE_Registration $registration,
711
+		EE_Question $question,
712
+		$answer
713
+	) {
714
+		if ($answer instanceof EE_Answer && $question instanceof EE_Question
715
+			&& $question->type() === EEM_Question::QST_type_state
716
+		) {
717
+			$STA_ID = $answer->value();
718
+			if (! empty($STA_ID)) {
719
+				$state = EEM_State::instance()->get_one_by_ID($STA_ID);
720
+				if ($state instanceof EE_State) {
721
+					$country = $state->country();
722
+					if ($country instanceof EE_Country) {
723
+						if (! isset($state_options[ $country->name() ])) {
724
+							$state_options[ $country->name() ] = array();
725
+						}
726
+						if (! isset($state_options[ $country->name() ][ $STA_ID ])) {
727
+							$state_options[ $country->name() ][ $STA_ID ] = $state->name();
728
+						}
729
+					}
730
+				}
731
+			}
732
+		}
733
+		return $state_options;
734
+	}
735
+
736
+
737
+	/**
738
+	 * @param EE_Country[]                          $country_options
739
+	 * @param EE_SPCO_Reg_Step_Attendee_Information $reg_step
740
+	 * @param EE_Registration                       $registration
741
+	 * @param EE_Question                           $question
742
+	 * @param                                       $answer
743
+	 * @return array
744
+	 * @throws EE_Error
745
+	 * @throws InvalidArgumentException
746
+	 * @throws InvalidDataTypeException
747
+	 * @throws InvalidInterfaceException
748
+	 */
749
+	public static function inject_new_reg_country_into_options(
750
+		$country_options = array(),
751
+		EE_SPCO_Reg_Step_Attendee_Information $reg_step,
752
+		EE_Registration $registration,
753
+		EE_Question $question,
754
+		$answer
755
+	) {
756
+		if ($answer instanceof EE_Answer && $question instanceof EE_Question
757
+			&& $question->type()
758
+			   === EEM_Question::QST_type_country
759
+		) {
760
+			$CNT_ISO = $answer->value();
761
+			if (! empty($CNT_ISO)) {
762
+				$country = EEM_Country::instance()->get_one_by_ID($CNT_ISO);
763
+				if ($country instanceof EE_Country) {
764
+					if (! isset($country_options[ $CNT_ISO ])) {
765
+						$country_options[ $CNT_ISO ] = $country->name();
766
+					}
767
+				}
768
+			}
769
+		}
770
+		return $country_options;
771
+	}
772
+
773
+
774
+	/**
775
+	 * @param EE_State[] $state_options
776
+	 * @return array
777
+	 * @throws EE_Error
778
+	 * @throws InvalidArgumentException
779
+	 * @throws InvalidDataTypeException
780
+	 * @throws InvalidInterfaceException
781
+	 */
782
+	public static function state_options($state_options = array())
783
+	{
784
+		$new_states = EED_Add_New_State::_get_new_states();
785
+		foreach ($new_states as $new_state) {
786
+			if ($new_state instanceof EE_State
787
+				&& $new_state->country() instanceof EE_Country
788
+			) {
789
+				$state_options[ $new_state->country()->name() ][ $new_state->ID() ] = $new_state->name();
790
+			}
791
+		}
792
+		return $state_options;
793
+	}
794
+
795
+
796
+	/**
797
+	 * @return array
798
+	 * @throws InvalidArgumentException
799
+	 * @throws InvalidDataTypeException
800
+	 * @throws InvalidInterfaceException
801
+	 */
802
+	protected static function _get_new_states()
803
+	{
804
+		$new_states = array();
805
+		if (EE_Registry::instance()->SSN instanceof EE_Session) {
806
+			$new_states = EE_Registry::instance()->SSN->get_session_data(
807
+				'nsmf_new_states'
808
+			);
809
+		}
810
+		return is_array($new_states) ? $new_states : array();
811
+	}
812
+
813
+
814
+	/**
815
+	 * @param EE_Country[] $country_options
816
+	 * @return array
817
+	 * @throws EE_Error
818
+	 * @throws InvalidArgumentException
819
+	 * @throws InvalidDataTypeException
820
+	 * @throws InvalidInterfaceException
821
+	 */
822
+	public static function country_options($country_options = array())
823
+	{
824
+		$new_states = EED_Add_New_State::_get_new_states();
825
+		foreach ($new_states as $new_state) {
826
+			if ($new_state instanceof EE_State
827
+				&& $new_state->country() instanceof EE_Country
828
+			) {
829
+				$country_options[ $new_state->country()->ID() ] = $new_state->country()->name();
830
+			}
831
+		}
832
+		return $country_options;
833
+	}
834 834
 }
Please login to merge, or discard this patch.
Spacing   +45 added lines, -45 removed lines patch added patch discarded remove patch
@@ -159,14 +159,14 @@  discard block
 block discarded – undo
159 159
      */
160 160
     public static function set_definitions()
161 161
     {
162
-        define('ANS_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets/');
162
+        define('ANS_ASSETS_URL', plugin_dir_url(__FILE__).'assets/');
163 163
         define(
164 164
             'ANS_TEMPLATES_PATH',
165 165
             str_replace(
166 166
                 '\\',
167 167
                 '/',
168 168
                 plugin_dir_path(__FILE__)
169
-            ) . 'templates/'
169
+            ).'templates/'
170 170
         );
171 171
     }
172 172
 
@@ -216,7 +216,7 @@  discard block
 block discarded – undo
216 216
         if (apply_filters('EED_Single_Page_Checkout__SPCO_active', false)) {
217 217
             wp_register_script(
218 218
                 'add_new_state',
219
-                ANS_ASSETS_URL . 'add_new_state.js',
219
+                ANS_ASSETS_URL.'add_new_state.js',
220 220
                 array('espresso_core', 'single_page_checkout'),
221 221
                 EVENT_ESPRESSO_VERSION,
222 222
                 true
@@ -263,10 +263,10 @@  discard block
 block discarded – undo
263 263
             $new_state_submit_id = str_replace('state', 'new_state', $input->html_id());
264 264
             $country_options = array();
265 265
             $countries = EEM_Country::instance()->get_all_countries();
266
-            if (! empty($countries)) {
266
+            if ( ! empty($countries)) {
267 267
                 foreach ($countries as $country) {
268 268
                     if ($country instanceof EE_Country) {
269
-                        $country_options[ $country->ID() ] = $country->name();
269
+                        $country_options[$country->ID()] = $country->name();
270 270
                     }
271 271
                 }
272 272
             }
@@ -300,10 +300,10 @@  discard block
 block discarded – undo
300 300
                                     '',
301 301
                                     esc_html__('click here to add a new state/province', 'event_espresso'),
302 302
                                     '',
303
-                                    'display-' . $input->html_id(),
303
+                                    'display-'.$input->html_id(),
304 304
                                     'ee-form-add-new-state-lnk display-the-hidden smaller-text hide-if-no-js',
305 305
                                     '',
306
-                                    'data-target="' . $input->html_id() . '"'
306
+                                    'data-target="'.$input->html_id().'"'
307 307
                                 )
308 308
                             )
309 309
                         ),
@@ -313,33 +313,33 @@  discard block
 block discarded – undo
313 313
                                 'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_micro_form',
314 314
                                 EEH_HTML::div(
315 315
                                     '',
316
-                                    $input->html_id() . '-dv',
316
+                                    $input->html_id().'-dv',
317 317
                                     'ee-form-add-new-state-dv',
318 318
                                     'display: none;'
319
-                                ) .
319
+                                ).
320 320
                                 EEH_HTML::h6(
321 321
                                     esc_html__(
322 322
                                         'Is your state/province missing from the dropdown menu above? You can add it by completing the following steps:',
323 323
                                         'event_espresso'
324 324
                                     )
325
-                                ) .
326
-                                EEH_HTML::ul() .
325
+                                ).
326
+                                EEH_HTML::ul().
327 327
                                 EEH_HTML::li(
328 328
                                     esc_html__(
329 329
                                         'first select the Country that your State/Province belongs to',
330 330
                                         'event_espresso'
331 331
                                     )
332
-                                ) .
332
+                                ).
333 333
                                 EEH_HTML::li(
334 334
                                     esc_html__('enter the name of your State/Province', 'event_espresso')
335
-                                ) .
335
+                                ).
336 336
                                 EEH_HTML::li(
337 337
                                     esc_html__(
338 338
                                         'enter a two to six letter abbreviation for the name of your State/Province',
339 339
                                         'event_espresso'
340 340
                                     )
341
-                                ) .
342
-                                EEH_HTML::li(esc_html__('click the ADD button', 'event_espresso')) .
341
+                                ).
342
+                                EEH_HTML::li(esc_html__('click the ADD button', 'event_espresso')).
343 343
                                 EEH_HTML::ulx()
344 344
                             )
345 345
                         ),
@@ -353,7 +353,7 @@  discard block
 block discarded – undo
353 353
                                     'nsmf_new_state_country',
354 354
                                     $input->html_id()
355 355
                                 ),
356
-                                'html_class'      => $input->html_class() . ' new-state-country',
356
+                                'html_class'      => $input->html_class().' new-state-country',
357 357
                                 'html_label_text' => esc_html__('New State/Province Country', 'event_espresso'),
358 358
                                 'default'         => EE_Registry::instance()->REQ->get($country_name, ''),
359 359
                                 'required'        => false,
@@ -368,7 +368,7 @@  discard block
 block discarded – undo
368 368
                                     'nsmf_new_state_name',
369 369
                                     $input->html_id()
370 370
                                 ),
371
-                                'html_class'      => $input->html_class() . ' new-state-state',
371
+                                'html_class'      => $input->html_class().' new-state-state',
372 372
                                 'html_label_text' => esc_html__(
373 373
                                     'New State/Province Name',
374 374
                                     'event_espresso'
@@ -387,11 +387,11 @@  discard block
 block discarded – undo
387 387
                                     'nsmf_new_state_abbrv',
388 388
                                     $input->html_id()
389 389
                                 ),
390
-                                'html_class'            => $input->html_class() . ' new-state-abbrv',
390
+                                'html_class'            => $input->html_class().' new-state-abbrv',
391 391
                                 'html_label_text'       => esc_html__(
392 392
                                     'New State/Province Abbreviation',
393 393
                                     'event_espresso'
394
-                                ) . ' *',
394
+                                ).' *',
395 395
                                 'html_other_attributes' => 'size="24"',
396 396
                                 'default'               => EE_Registry::instance()->REQ->get($abbrv_name, ''),
397 397
                                 'required'              => false,
@@ -401,15 +401,15 @@  discard block
 block discarded – undo
401 401
                         'add_new_state_submit_button' => new EE_Form_Section_HTML(
402 402
                             apply_filters(
403 403
                                 'FHEE__EED_Add_New_State__display_add_new_state_micro_form__add_new_state_submit_button',
404
-                                EEH_HTML::nbsp(3) .
404
+                                EEH_HTML::nbsp(3).
405 405
                                 EEH_HTML::link(
406 406
                                     '',
407 407
                                     esc_html__('ADD', 'event_espresso'),
408 408
                                     '',
409
-                                    'submit-' . $new_state_submit_id,
409
+                                    'submit-'.$new_state_submit_id,
410 410
                                     'ee-form-add-new-state-submit button button-secondary',
411 411
                                     '',
412
-                                    'data-target="' . $new_state_submit_id . '" data-value-field-name="' . $input->valueFieldName(). '"'
412
+                                    'data-target="'.$new_state_submit_id.'" data-value-field-name="'.$input->valueFieldName().'"'
413 413
                                 )
414 414
                             )
415 415
                         ),
@@ -422,7 +422,7 @@  discard block
 block discarded – undo
422 422
                                 EEH_HTML::div('', '', 'small-text')
423 423
                                 .
424 424
                                 EEH_HTML::strong(
425
-                                    '* ' .
425
+                                    '* '.
426 426
                                     esc_html__(
427 427
                                         'Don\'t know your State/Province Abbreviation?',
428 428
                                         'event_espresso'
@@ -455,10 +455,10 @@  discard block
 block discarded – undo
455 455
                                     '',
456 456
                                     esc_html__('cancel new State/Province', 'event_espresso'),
457 457
                                     '',
458
-                                    'hide-' . $input->html_id(),
458
+                                    'hide-'.$input->html_id(),
459 459
                                     'ee-form-cancel-new-state-lnk smaller-text',
460 460
                                     '',
461
-                                    'data-target="' . $input->html_id() . '"'
461
+                                    'data-target="'.$input->html_id().'"'
462 462
                                 )
463 463
                                 .
464 464
                                 EEH_HTML::divx()
@@ -523,7 +523,7 @@  discard block
 block discarded – undo
523 523
                     $new_states = EE_Registry::instance()->SSN->get_session_data(
524 524
                         'nsmf_new_states'
525 525
                     );
526
-                    $new_states[ $new_state->ID() ] = $new_state;
526
+                    $new_states[$new_state->ID()] = $new_state;
527 527
                     EE_Registry::instance()->SSN->set_session_data(
528 528
                         array('nsmf_new_states' => $new_states)
529 529
                     );
@@ -604,7 +604,7 @@  discard block
 block discarded – undo
604 604
     public static function save_new_state_to_db($props_n_values = array())
605 605
     {
606 606
         $existing_state = EEM_State::instance()->get_all(array($props_n_values, 'limit' => 1));
607
-        if (! empty($existing_state)) {
607
+        if ( ! empty($existing_state)) {
608 608
             return array_pop($existing_state);
609 609
         }
610 610
         $new_state = EE_State::new_instance($props_n_values);
@@ -619,15 +619,15 @@  discard block
 block discarded – undo
619 619
             );
620 620
             // if not non-ajax admin
621 621
             new PersistentAdminNotice(
622
-                'new-state-added-' . $new_state->country_iso() . '-' . $new_state->abbrev(),
622
+                'new-state-added-'.$new_state->country_iso().'-'.$new_state->abbrev(),
623 623
                 sprintf(
624 624
                     esc_html__(
625 625
                         'A new State named "%1$s (%2$s)" was dynamically added from an Event Espresso form for the Country of "%3$s".%5$sTo verify, edit, and/or delete this new State, please go to the %4$s and update the States / Provinces section.%5$sCheck "Yes" to have this new State added to dropdown select lists in forms.',
626 626
                         'event_espresso'
627 627
                     ),
628
-                    '<b>' . $new_state->name() . '</b>',
629
-                    '<b>' . $new_state->abbrev() . '</b>',
630
-                    '<b>' . $new_state->country()->name() . '</b>',
628
+                    '<b>'.$new_state->name().'</b>',
629
+                    '<b>'.$new_state->abbrev().'</b>',
630
+                    '<b>'.$new_state->country()->name().'</b>',
631 631
                     '<a href="'
632 632
                     . $country_settings_url
633 633
                     . '">'
@@ -660,7 +660,7 @@  discard block
 block discarded – undo
660 660
      */
661 661
     public static function update_country_settings($CNT_ISO = '', $STA_ID = '', $cols_n_values = array())
662 662
     {
663
-        if (! $CNT_ISO) {
663
+        if ( ! $CNT_ISO) {
664 664
             EE_Error::add_error(
665 665
                 esc_html__('An invalid or missing Country ISO Code was received.', 'event_espresso'),
666 666
                 __FILE__,
@@ -670,13 +670,13 @@  discard block
 block discarded – undo
670 670
         }
671 671
         $STA_abbrev = is_array($cols_n_values) && isset($cols_n_values['STA_abbrev']) ? $cols_n_values['STA_abbrev']
672 672
             : false;
673
-        if (! $STA_abbrev && ! empty($STA_ID)) {
673
+        if ( ! $STA_abbrev && ! empty($STA_ID)) {
674 674
             $state = EEM_State::instance()->get_one_by_ID($STA_ID);
675 675
             if ($state instanceof EE_State) {
676 676
                 $STA_abbrev = $state->abbrev();
677 677
             }
678 678
         }
679
-        if (! $STA_abbrev) {
679
+        if ( ! $STA_abbrev) {
680 680
             EE_Error::add_error(
681 681
                 esc_html__('An invalid or missing State Abbreviation was received.', 'event_espresso'),
682 682
                 __FILE__,
@@ -688,7 +688,7 @@  discard block
 block discarded – undo
688 688
         $persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
689 689
             'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
690 690
         );
691
-        $persistent_admin_notice_manager->dismissNotice($CNT_ISO . '-' . $STA_abbrev, true, true);
691
+        $persistent_admin_notice_manager->dismissNotice($CNT_ISO.'-'.$STA_abbrev, true, true);
692 692
     }
693 693
 
694 694
 
@@ -715,16 +715,16 @@  discard block
 block discarded – undo
715 715
             && $question->type() === EEM_Question::QST_type_state
716 716
         ) {
717 717
             $STA_ID = $answer->value();
718
-            if (! empty($STA_ID)) {
718
+            if ( ! empty($STA_ID)) {
719 719
                 $state = EEM_State::instance()->get_one_by_ID($STA_ID);
720 720
                 if ($state instanceof EE_State) {
721 721
                     $country = $state->country();
722 722
                     if ($country instanceof EE_Country) {
723
-                        if (! isset($state_options[ $country->name() ])) {
724
-                            $state_options[ $country->name() ] = array();
723
+                        if ( ! isset($state_options[$country->name()])) {
724
+                            $state_options[$country->name()] = array();
725 725
                         }
726
-                        if (! isset($state_options[ $country->name() ][ $STA_ID ])) {
727
-                            $state_options[ $country->name() ][ $STA_ID ] = $state->name();
726
+                        if ( ! isset($state_options[$country->name()][$STA_ID])) {
727
+                            $state_options[$country->name()][$STA_ID] = $state->name();
728 728
                         }
729 729
                     }
730 730
                 }
@@ -758,11 +758,11 @@  discard block
 block discarded – undo
758 758
                === EEM_Question::QST_type_country
759 759
         ) {
760 760
             $CNT_ISO = $answer->value();
761
-            if (! empty($CNT_ISO)) {
761
+            if ( ! empty($CNT_ISO)) {
762 762
                 $country = EEM_Country::instance()->get_one_by_ID($CNT_ISO);
763 763
                 if ($country instanceof EE_Country) {
764
-                    if (! isset($country_options[ $CNT_ISO ])) {
765
-                        $country_options[ $CNT_ISO ] = $country->name();
764
+                    if ( ! isset($country_options[$CNT_ISO])) {
765
+                        $country_options[$CNT_ISO] = $country->name();
766 766
                     }
767 767
                 }
768 768
             }
@@ -786,7 +786,7 @@  discard block
 block discarded – undo
786 786
             if ($new_state instanceof EE_State
787 787
                 && $new_state->country() instanceof EE_Country
788 788
             ) {
789
-                $state_options[ $new_state->country()->name() ][ $new_state->ID() ] = $new_state->name();
789
+                $state_options[$new_state->country()->name()][$new_state->ID()] = $new_state->name();
790 790
             }
791 791
         }
792 792
         return $state_options;
@@ -826,7 +826,7 @@  discard block
 block discarded – undo
826 826
             if ($new_state instanceof EE_State
827 827
                 && $new_state->country() instanceof EE_Country
828 828
             ) {
829
-                $country_options[ $new_state->country()->ID() ] = $new_state->country()->name();
829
+                $country_options[$new_state->country()->ID()] = $new_state->country()->name();
830 830
             }
831 831
         }
832 832
         return $country_options;
Please login to merge, or discard this patch.
modules/venue_single/EED_Venue_Single.module.php 2 patches
Indentation   +167 added lines, -167 removed lines patch added patch discarded remove patch
@@ -29,171 +29,171 @@
 block discarded – undo
29 29
 class EED_Venue_Single extends EED_Module
30 30
 {
31 31
 
32
-    /**
33
-     * @return EED_Venue_Single
34
-     */
35
-    public static function instance()
36
-    {
37
-        return parent::get_instance(__CLASS__);
38
-    }
39
-
40
-
41
-    /**
42
-     * set_hooks - for hooking into EE Core, other modules, etc
43
-     *
44
-     * @return void
45
-     * @throws InvalidArgumentException
46
-     * @throws InvalidDataTypeException
47
-     * @throws InvalidInterfaceException
48
-     */
49
-    public static function set_hooks()
50
-    {
51
-        /** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_type_definitions */
52
-        $custom_post_type_definitions = LoaderFactory::getLoader()->getShared(
53
-            'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
54
-        );
55
-        $custom_post_types = $custom_post_type_definitions->getDefinitions();
56
-        EE_Config::register_route(
57
-            $custom_post_types['espresso_venues']['singular_slug'],
58
-            'Venue_Single',
59
-            'run'
60
-        );
61
-    }
62
-
63
-    /**
64
-     *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
65
-     *
66
-     * @access    public
67
-     * @return    void
68
-     */
69
-    public static function set_hooks_admin()
70
-    {
71
-    }
72
-
73
-
74
-    /**
75
-     * run - initial module setup
76
-     *
77
-     * @access    public
78
-     * @param \WP $WP
79
-     */
80
-    public function run($WP)
81
-    {
82
-        // check what template is loaded
83
-        add_filter('template_include', array($this, 'template_include'), 999, 1);
84
-        add_action('wp_enqueue_scripts', array($this, 'wp_enqueue_scripts'), 10);
85
-    }
86
-
87
-
88
-    /**
89
-     * template_include
90
-     *
91
-     * @access public
92
-     * @param  string $template
93
-     * @return string
94
-     */
95
-    public function template_include($template)
96
-    {
97
-        // not a custom template?
98
-        if (EE_Registry::instance()
99
-                       ->load_core('Front_Controller', array(), false, true)
100
-                       ->get_selected_template() != 'single-espresso_venues.php'
101
-        ) {
102
-            EEH_Template::load_espresso_theme_functions();
103
-            // then add extra event data via hooks
104
-            add_filter('the_title', array($this, 'the_title'), 100, 1);
105
-            add_filter('the_content', array($this, 'venue_details'), 100);
106
-            // don't display entry meta because the existing theme will take car of that
107
-            add_filter('FHEE__content_espresso_venues_details_template__display_entry_meta', '__return_false');
108
-        }
109
-        return $template;
110
-    }
111
-
112
-
113
-    /**
114
-     * the_title
115
-     *
116
-     * @access public
117
-     * @param  string $title
118
-     * @return string
119
-     */
120
-    public function the_title($title = '')
121
-    {
122
-        return $title;
123
-    }
124
-
125
-
126
-    /**
127
-     *    venue_details
128
-     *
129
-     * @access public
130
-     * @param  string $content
131
-     * @return string
132
-     */
133
-    public function venue_details($content)
134
-    {
135
-        global $post;
136
-        if ($post->post_type == 'espresso_venues'
137
-            && ! post_password_required()
138
-        ) {
139
-            // since the 'content-espresso_venues-details.php' template might be used directly from within a theme,
140
-            // it uses the_content() for displaying the $post->post_content
141
-            // so in order to load a template that uses the_content() from within a callback being used to filter the_content(),
142
-            // we need to first remove this callback from being applied to the_content() (otherwise it will recurse and blow up the interweb)
143
-            remove_filter('the_content', array($this, 'venue_details'), 100);
144
-            // add filters we want
145
-            add_filter('the_content', array($this, 'venue_location'), 110);
146
-            // now load our template
147
-            $template = EEH_Template::locate_template('content-espresso_venues-details.php');
148
-            // remove other filters we added so they won't get applied to the next post
149
-            remove_filter('the_content', array($this, 'venue_location'), 110);
150
-        }
151
-        // we're not returning the $content directly because the template we are loading uses the_content (or the_excerpt)
152
-        return ! empty($template) ? $template : $content;
153
-    }
154
-
155
-
156
-    /**
157
-     * venue_location
158
-     *
159
-     * @access public
160
-     * @param  string $content
161
-     * @return string
162
-     */
163
-    public function venue_location($content)
164
-    {
165
-        return $content . EEH_Template::locate_template('content-espresso_venues-location.php');
166
-    }
167
-
168
-
169
-    /**
170
-     *    wp_enqueue_scripts
171
-     *
172
-     * @access public
173
-     * @return void
174
-     */
175
-    public function wp_enqueue_scripts()
176
-    {
177
-        // get some style
178
-        if (apply_filters('FHEE_enable_default_espresso_css', true) && is_single()) {
179
-            // first check theme folder
180
-            if (is_readable(get_stylesheet_directory() . $this->theme . '/style.css')) {
181
-                wp_register_style(
182
-                    $this->theme,
183
-                    get_stylesheet_directory_uri() . $this->theme . '/style.css',
184
-                    array('dashicons', 'espresso_default')
185
-                );
186
-            } elseif (is_readable(EE_TEMPLATES . $this->theme . '/style.css')) {
187
-                wp_register_style(
188
-                    $this->theme,
189
-                    EE_TEMPLATES_URL . $this->theme . '/style.css',
190
-                    array('dashicons', 'espresso_default')
191
-                );
192
-            }
193
-            wp_enqueue_style($this->theme);
194
-            if (EE_Registry::instance()->CFG->map_settings->use_google_maps) {
195
-                add_action('wp_enqueue_scripts', array('EEH_Maps', 'espresso_google_map_js'), 11);
196
-            }
197
-        }
198
-    }
32
+	/**
33
+	 * @return EED_Venue_Single
34
+	 */
35
+	public static function instance()
36
+	{
37
+		return parent::get_instance(__CLASS__);
38
+	}
39
+
40
+
41
+	/**
42
+	 * set_hooks - for hooking into EE Core, other modules, etc
43
+	 *
44
+	 * @return void
45
+	 * @throws InvalidArgumentException
46
+	 * @throws InvalidDataTypeException
47
+	 * @throws InvalidInterfaceException
48
+	 */
49
+	public static function set_hooks()
50
+	{
51
+		/** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_type_definitions */
52
+		$custom_post_type_definitions = LoaderFactory::getLoader()->getShared(
53
+			'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
54
+		);
55
+		$custom_post_types = $custom_post_type_definitions->getDefinitions();
56
+		EE_Config::register_route(
57
+			$custom_post_types['espresso_venues']['singular_slug'],
58
+			'Venue_Single',
59
+			'run'
60
+		);
61
+	}
62
+
63
+	/**
64
+	 *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
65
+	 *
66
+	 * @access    public
67
+	 * @return    void
68
+	 */
69
+	public static function set_hooks_admin()
70
+	{
71
+	}
72
+
73
+
74
+	/**
75
+	 * run - initial module setup
76
+	 *
77
+	 * @access    public
78
+	 * @param \WP $WP
79
+	 */
80
+	public function run($WP)
81
+	{
82
+		// check what template is loaded
83
+		add_filter('template_include', array($this, 'template_include'), 999, 1);
84
+		add_action('wp_enqueue_scripts', array($this, 'wp_enqueue_scripts'), 10);
85
+	}
86
+
87
+
88
+	/**
89
+	 * template_include
90
+	 *
91
+	 * @access public
92
+	 * @param  string $template
93
+	 * @return string
94
+	 */
95
+	public function template_include($template)
96
+	{
97
+		// not a custom template?
98
+		if (EE_Registry::instance()
99
+					   ->load_core('Front_Controller', array(), false, true)
100
+					   ->get_selected_template() != 'single-espresso_venues.php'
101
+		) {
102
+			EEH_Template::load_espresso_theme_functions();
103
+			// then add extra event data via hooks
104
+			add_filter('the_title', array($this, 'the_title'), 100, 1);
105
+			add_filter('the_content', array($this, 'venue_details'), 100);
106
+			// don't display entry meta because the existing theme will take car of that
107
+			add_filter('FHEE__content_espresso_venues_details_template__display_entry_meta', '__return_false');
108
+		}
109
+		return $template;
110
+	}
111
+
112
+
113
+	/**
114
+	 * the_title
115
+	 *
116
+	 * @access public
117
+	 * @param  string $title
118
+	 * @return string
119
+	 */
120
+	public function the_title($title = '')
121
+	{
122
+		return $title;
123
+	}
124
+
125
+
126
+	/**
127
+	 *    venue_details
128
+	 *
129
+	 * @access public
130
+	 * @param  string $content
131
+	 * @return string
132
+	 */
133
+	public function venue_details($content)
134
+	{
135
+		global $post;
136
+		if ($post->post_type == 'espresso_venues'
137
+			&& ! post_password_required()
138
+		) {
139
+			// since the 'content-espresso_venues-details.php' template might be used directly from within a theme,
140
+			// it uses the_content() for displaying the $post->post_content
141
+			// so in order to load a template that uses the_content() from within a callback being used to filter the_content(),
142
+			// we need to first remove this callback from being applied to the_content() (otherwise it will recurse and blow up the interweb)
143
+			remove_filter('the_content', array($this, 'venue_details'), 100);
144
+			// add filters we want
145
+			add_filter('the_content', array($this, 'venue_location'), 110);
146
+			// now load our template
147
+			$template = EEH_Template::locate_template('content-espresso_venues-details.php');
148
+			// remove other filters we added so they won't get applied to the next post
149
+			remove_filter('the_content', array($this, 'venue_location'), 110);
150
+		}
151
+		// we're not returning the $content directly because the template we are loading uses the_content (or the_excerpt)
152
+		return ! empty($template) ? $template : $content;
153
+	}
154
+
155
+
156
+	/**
157
+	 * venue_location
158
+	 *
159
+	 * @access public
160
+	 * @param  string $content
161
+	 * @return string
162
+	 */
163
+	public function venue_location($content)
164
+	{
165
+		return $content . EEH_Template::locate_template('content-espresso_venues-location.php');
166
+	}
167
+
168
+
169
+	/**
170
+	 *    wp_enqueue_scripts
171
+	 *
172
+	 * @access public
173
+	 * @return void
174
+	 */
175
+	public function wp_enqueue_scripts()
176
+	{
177
+		// get some style
178
+		if (apply_filters('FHEE_enable_default_espresso_css', true) && is_single()) {
179
+			// first check theme folder
180
+			if (is_readable(get_stylesheet_directory() . $this->theme . '/style.css')) {
181
+				wp_register_style(
182
+					$this->theme,
183
+					get_stylesheet_directory_uri() . $this->theme . '/style.css',
184
+					array('dashicons', 'espresso_default')
185
+				);
186
+			} elseif (is_readable(EE_TEMPLATES . $this->theme . '/style.css')) {
187
+				wp_register_style(
188
+					$this->theme,
189
+					EE_TEMPLATES_URL . $this->theme . '/style.css',
190
+					array('dashicons', 'espresso_default')
191
+				);
192
+			}
193
+			wp_enqueue_style($this->theme);
194
+			if (EE_Registry::instance()->CFG->map_settings->use_google_maps) {
195
+				add_action('wp_enqueue_scripts', array('EEH_Maps', 'espresso_google_map_js'), 11);
196
+			}
197
+		}
198
+	}
199 199
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -162,7 +162,7 @@  discard block
 block discarded – undo
162 162
      */
163 163
     public function venue_location($content)
164 164
     {
165
-        return $content . EEH_Template::locate_template('content-espresso_venues-location.php');
165
+        return $content.EEH_Template::locate_template('content-espresso_venues-location.php');
166 166
     }
167 167
 
168 168
 
@@ -177,16 +177,16 @@  discard block
 block discarded – undo
177 177
         // get some style
178 178
         if (apply_filters('FHEE_enable_default_espresso_css', true) && is_single()) {
179 179
             // first check theme folder
180
-            if (is_readable(get_stylesheet_directory() . $this->theme . '/style.css')) {
180
+            if (is_readable(get_stylesheet_directory().$this->theme.'/style.css')) {
181 181
                 wp_register_style(
182 182
                     $this->theme,
183
-                    get_stylesheet_directory_uri() . $this->theme . '/style.css',
183
+                    get_stylesheet_directory_uri().$this->theme.'/style.css',
184 184
                     array('dashicons', 'espresso_default')
185 185
                 );
186
-            } elseif (is_readable(EE_TEMPLATES . $this->theme . '/style.css')) {
186
+            } elseif (is_readable(EE_TEMPLATES.$this->theme.'/style.css')) {
187 187
                 wp_register_style(
188 188
                     $this->theme,
189
-                    EE_TEMPLATES_URL . $this->theme . '/style.css',
189
+                    EE_TEMPLATES_URL.$this->theme.'/style.css',
190 190
                     array('dashicons', 'espresso_default')
191 191
                 );
192 192
             }
Please login to merge, or discard this patch.