@@ -7,16 +7,16 @@ discard block |
||
7 | 7 | define('EE_SUPPORT_EMAIL', '[email protected]'); |
8 | 8 | // used to be DIRECTORY_SEPARATOR, but that caused issues on windows |
9 | 9 | if (! defined('DS')) { |
10 | - define('DS', '/'); |
|
10 | + define('DS', '/'); |
|
11 | 11 | } |
12 | 12 | if (! defined('PS')) { |
13 | - define('PS', PATH_SEPARATOR); |
|
13 | + define('PS', PATH_SEPARATOR); |
|
14 | 14 | } |
15 | 15 | if (! defined('SP')) { |
16 | - define('SP', ' '); |
|
16 | + define('SP', ' '); |
|
17 | 17 | } |
18 | 18 | if (! defined('EENL')) { |
19 | - define('EENL', "\n"); |
|
19 | + define('EENL', "\n"); |
|
20 | 20 | } |
21 | 21 | // define the plugin directory and URL |
22 | 22 | define('EE_PLUGIN_BASENAME', plugin_basename(EVENT_ESPRESSO_MAIN_FILE)); |
@@ -70,7 +70,7 @@ discard block |
||
70 | 70 | define('EE_LANGUAGES_SAFE_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'languages/'); |
71 | 71 | // check for DOMPDF fonts in uploads |
72 | 72 | if (file_exists(EVENT_ESPRESSO_UPLOAD_DIR . 'fonts/')) { |
73 | - define('DOMPDF_FONT_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'fonts/'); |
|
73 | + define('DOMPDF_FONT_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'fonts/'); |
|
74 | 74 | } |
75 | 75 | // just a handy constant occasionally needed for finding values representing infinity in the DB |
76 | 76 | // you're better to use this than its straight value (currently -1) in case you ever |
@@ -78,9 +78,9 @@ discard block |
||
78 | 78 | define('EE_INF_IN_DB', -1); |
79 | 79 | define('EE_INF', INF > (float) PHP_INT_MAX ? INF : PHP_INT_MAX); |
80 | 80 | if (! defined('EE_DEBUG')) { |
81 | - define('EE_DEBUG', false); |
|
81 | + define('EE_DEBUG', false); |
|
82 | 82 | } |
83 | 83 | // for older WP versions |
84 | 84 | if (! defined('MONTH_IN_SECONDS')) { |
85 | - define('MONTH_IN_SECONDS', DAY_IN_SECONDS * 30); |
|
85 | + define('MONTH_IN_SECONDS', DAY_IN_SECONDS * 30); |
|
86 | 86 | } |
@@ -6,81 +6,81 @@ |
||
6 | 6 | define('EE_MIN_PHP_VER_RECOMMENDED', '5.6.32'); |
7 | 7 | define('EE_SUPPORT_EMAIL', '[email protected]'); |
8 | 8 | // used to be DIRECTORY_SEPARATOR, but that caused issues on windows |
9 | -if (! defined('DS')) { |
|
9 | +if ( ! defined('DS')) { |
|
10 | 10 | define('DS', '/'); |
11 | 11 | } |
12 | -if (! defined('PS')) { |
|
12 | +if ( ! defined('PS')) { |
|
13 | 13 | define('PS', PATH_SEPARATOR); |
14 | 14 | } |
15 | -if (! defined('SP')) { |
|
15 | +if ( ! defined('SP')) { |
|
16 | 16 | define('SP', ' '); |
17 | 17 | } |
18 | -if (! defined('EENL')) { |
|
18 | +if ( ! defined('EENL')) { |
|
19 | 19 | define('EENL', "\n"); |
20 | 20 | } |
21 | 21 | // define the plugin directory and URL |
22 | 22 | define('EE_PLUGIN_BASENAME', plugin_basename(EVENT_ESPRESSO_MAIN_FILE)); |
23 | -define('EE_PLUGIN_DIR_PATH', dirname(EVENT_ESPRESSO_MAIN_FILE) . '/'); |
|
23 | +define('EE_PLUGIN_DIR_PATH', dirname(EVENT_ESPRESSO_MAIN_FILE).'/'); |
|
24 | 24 | define('EE_PLUGIN_DIR_URL', plugin_dir_url(EVENT_ESPRESSO_MAIN_FILE)); |
25 | 25 | // main root folder paths |
26 | -define('EE_ADMIN_PAGES', EE_PLUGIN_DIR_PATH . 'admin_pages/'); |
|
27 | -define('EE_CORE', EE_PLUGIN_DIR_PATH . 'core/'); |
|
28 | -define('EE_MODULES', EE_PLUGIN_DIR_PATH . 'modules/'); |
|
29 | -define('EE_PUBLIC', EE_PLUGIN_DIR_PATH . 'public/'); |
|
30 | -define('EE_SHORTCODES', EE_PLUGIN_DIR_PATH . 'shortcodes/'); |
|
31 | -define('EE_WIDGETS', EE_PLUGIN_DIR_PATH . 'widgets/'); |
|
32 | -define('EE_PAYMENT_METHODS', EE_PLUGIN_DIR_PATH . 'payment_methods/'); |
|
33 | -define('EE_CAFF_PATH', EE_PLUGIN_DIR_PATH . 'caffeinated/'); |
|
26 | +define('EE_ADMIN_PAGES', EE_PLUGIN_DIR_PATH.'admin_pages/'); |
|
27 | +define('EE_CORE', EE_PLUGIN_DIR_PATH.'core/'); |
|
28 | +define('EE_MODULES', EE_PLUGIN_DIR_PATH.'modules/'); |
|
29 | +define('EE_PUBLIC', EE_PLUGIN_DIR_PATH.'public/'); |
|
30 | +define('EE_SHORTCODES', EE_PLUGIN_DIR_PATH.'shortcodes/'); |
|
31 | +define('EE_WIDGETS', EE_PLUGIN_DIR_PATH.'widgets/'); |
|
32 | +define('EE_PAYMENT_METHODS', EE_PLUGIN_DIR_PATH.'payment_methods/'); |
|
33 | +define('EE_CAFF_PATH', EE_PLUGIN_DIR_PATH.'caffeinated/'); |
|
34 | 34 | // core system paths |
35 | -define('EE_ADMIN', EE_CORE . 'admin/'); |
|
36 | -define('EE_CPTS', EE_CORE . 'CPTs/'); |
|
37 | -define('EE_CLASSES', EE_CORE . 'db_classes/'); |
|
38 | -define('EE_INTERFACES', EE_CORE . 'interfaces/'); |
|
39 | -define('EE_BUSINESS', EE_CORE . 'business/'); |
|
40 | -define('EE_MODELS', EE_CORE . 'db_models/'); |
|
41 | -define('EE_HELPERS', EE_CORE . 'helpers/'); |
|
42 | -define('EE_LIBRARIES', EE_CORE . 'libraries/'); |
|
43 | -define('EE_TEMPLATES', EE_CORE . 'templates/'); |
|
44 | -define('EE_THIRD_PARTY', EE_CORE . 'third_party_libs/'); |
|
45 | -define('EE_GLOBAL_ASSETS', EE_TEMPLATES . 'global_assets/'); |
|
46 | -define('EE_FORM_SECTIONS', EE_LIBRARIES . 'form_sections/'); |
|
35 | +define('EE_ADMIN', EE_CORE.'admin/'); |
|
36 | +define('EE_CPTS', EE_CORE.'CPTs/'); |
|
37 | +define('EE_CLASSES', EE_CORE.'db_classes/'); |
|
38 | +define('EE_INTERFACES', EE_CORE.'interfaces/'); |
|
39 | +define('EE_BUSINESS', EE_CORE.'business/'); |
|
40 | +define('EE_MODELS', EE_CORE.'db_models/'); |
|
41 | +define('EE_HELPERS', EE_CORE.'helpers/'); |
|
42 | +define('EE_LIBRARIES', EE_CORE.'libraries/'); |
|
43 | +define('EE_TEMPLATES', EE_CORE.'templates/'); |
|
44 | +define('EE_THIRD_PARTY', EE_CORE.'third_party_libs/'); |
|
45 | +define('EE_GLOBAL_ASSETS', EE_TEMPLATES.'global_assets/'); |
|
46 | +define('EE_FORM_SECTIONS', EE_LIBRARIES.'form_sections/'); |
|
47 | 47 | // gateways |
48 | -define('EE_GATEWAYS', EE_MODULES . 'gateways/'); |
|
49 | -define('EE_GATEWAYS_URL', EE_PLUGIN_DIR_URL . 'modules/gateways/'); |
|
48 | +define('EE_GATEWAYS', EE_MODULES.'gateways/'); |
|
49 | +define('EE_GATEWAYS_URL', EE_PLUGIN_DIR_URL.'modules/gateways/'); |
|
50 | 50 | // asset URL paths |
51 | -define('EE_TEMPLATES_URL', EE_PLUGIN_DIR_URL . 'core/templates/'); |
|
52 | -define('EE_GLOBAL_ASSETS_URL', EE_TEMPLATES_URL . 'global_assets/'); |
|
53 | -define('EE_IMAGES_URL', EE_GLOBAL_ASSETS_URL . 'images/'); |
|
54 | -define('EE_THIRD_PARTY_URL', EE_PLUGIN_DIR_URL . 'core/third_party_libs/'); |
|
55 | -define('EE_HELPERS_ASSETS', EE_PLUGIN_DIR_URL . 'core/helpers/assets/'); |
|
56 | -define('EE_LIBRARIES_URL', EE_PLUGIN_DIR_URL . 'core/libraries/'); |
|
51 | +define('EE_TEMPLATES_URL', EE_PLUGIN_DIR_URL.'core/templates/'); |
|
52 | +define('EE_GLOBAL_ASSETS_URL', EE_TEMPLATES_URL.'global_assets/'); |
|
53 | +define('EE_IMAGES_URL', EE_GLOBAL_ASSETS_URL.'images/'); |
|
54 | +define('EE_THIRD_PARTY_URL', EE_PLUGIN_DIR_URL.'core/third_party_libs/'); |
|
55 | +define('EE_HELPERS_ASSETS', EE_PLUGIN_DIR_URL.'core/helpers/assets/'); |
|
56 | +define('EE_LIBRARIES_URL', EE_PLUGIN_DIR_URL.'core/libraries/'); |
|
57 | 57 | // define upload paths |
58 | 58 | $uploads = wp_upload_dir(); |
59 | 59 | // define the uploads directory and URL |
60 | -define('EVENT_ESPRESSO_UPLOAD_DIR', $uploads['basedir'] . '/espresso/'); |
|
61 | -define('EVENT_ESPRESSO_UPLOAD_URL', $uploads['baseurl'] . '/espresso/'); |
|
60 | +define('EVENT_ESPRESSO_UPLOAD_DIR', $uploads['basedir'].'/espresso/'); |
|
61 | +define('EVENT_ESPRESSO_UPLOAD_URL', $uploads['baseurl'].'/espresso/'); |
|
62 | 62 | // define the templates directory and URL |
63 | -define('EVENT_ESPRESSO_TEMPLATE_DIR', $uploads['basedir'] . '/espresso/templates/'); |
|
64 | -define('EVENT_ESPRESSO_TEMPLATE_URL', $uploads['baseurl'] . '/espresso/templates/'); |
|
63 | +define('EVENT_ESPRESSO_TEMPLATE_DIR', $uploads['basedir'].'/espresso/templates/'); |
|
64 | +define('EVENT_ESPRESSO_TEMPLATE_URL', $uploads['baseurl'].'/espresso/templates/'); |
|
65 | 65 | // define the gateway directory and URL |
66 | -define('EVENT_ESPRESSO_GATEWAY_DIR', $uploads['basedir'] . '/espresso/gateways/'); |
|
67 | -define('EVENT_ESPRESSO_GATEWAY_URL', $uploads['baseurl'] . '/espresso/gateways/'); |
|
66 | +define('EVENT_ESPRESSO_GATEWAY_DIR', $uploads['basedir'].'/espresso/gateways/'); |
|
67 | +define('EVENT_ESPRESSO_GATEWAY_URL', $uploads['baseurl'].'/espresso/gateways/'); |
|
68 | 68 | // languages folder/path |
69 | -define('EE_LANGUAGES_SAFE_LOC', '../' . 'uploads/' . 'espresso/languages/'); |
|
70 | -define('EE_LANGUAGES_SAFE_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'languages/'); |
|
69 | +define('EE_LANGUAGES_SAFE_LOC', '../'.'uploads/'.'espresso/languages/'); |
|
70 | +define('EE_LANGUAGES_SAFE_DIR', EVENT_ESPRESSO_UPLOAD_DIR.'languages/'); |
|
71 | 71 | // check for DOMPDF fonts in uploads |
72 | -if (file_exists(EVENT_ESPRESSO_UPLOAD_DIR . 'fonts/')) { |
|
73 | - define('DOMPDF_FONT_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'fonts/'); |
|
72 | +if (file_exists(EVENT_ESPRESSO_UPLOAD_DIR.'fonts/')) { |
|
73 | + define('DOMPDF_FONT_DIR', EVENT_ESPRESSO_UPLOAD_DIR.'fonts/'); |
|
74 | 74 | } |
75 | 75 | // just a handy constant occasionally needed for finding values representing infinity in the DB |
76 | 76 | // you're better to use this than its straight value (currently -1) in case you ever |
77 | 77 | // want to change its default value! or find when -1 means infinity |
78 | 78 | define('EE_INF_IN_DB', -1); |
79 | 79 | define('EE_INF', INF > (float) PHP_INT_MAX ? INF : PHP_INT_MAX); |
80 | -if (! defined('EE_DEBUG')) { |
|
80 | +if ( ! defined('EE_DEBUG')) { |
|
81 | 81 | define('EE_DEBUG', false); |
82 | 82 | } |
83 | 83 | // for older WP versions |
84 | -if (! defined('MONTH_IN_SECONDS')) { |
|
84 | +if ( ! defined('MONTH_IN_SECONDS')) { |
|
85 | 85 | define('MONTH_IN_SECONDS', DAY_IN_SECONDS * 30); |
86 | 86 | } |
@@ -74,9 +74,9 @@ discard block |
||
74 | 74 | public function statsCallback() |
75 | 75 | { |
76 | 76 | // returns a callback that can is used to retrieve the stats to send along to the pue server. |
77 | - return function () { |
|
77 | + return function() { |
|
78 | 78 | // we only send stats one a week, so let's see if our stat timestamp has expired. |
79 | - if (! $this->sendStats()) { |
|
79 | + if ( ! $this->sendStats()) { |
|
80 | 80 | return array(); |
81 | 81 | } |
82 | 82 | return $this->stats_gatherer->stats(); |
@@ -124,9 +124,9 @@ discard block |
||
124 | 124 | */ |
125 | 125 | public static function optinText($extra = true) |
126 | 126 | { |
127 | - if (! $extra) { |
|
127 | + if ( ! $extra) { |
|
128 | 128 | echo '<h2 class="ee-admin-settings-hdr" ' |
129 | - . (! $extra ? 'id="UXIP_settings"' : '') |
|
129 | + . ( ! $extra ? 'id="UXIP_settings"' : '') |
|
130 | 130 | . '>' |
131 | 131 | . esc_html__('User eXperience Improvement Program (UXIP)', 'event_espresso') |
132 | 132 | . EEH_Template::get_help_tab_link('organization_logo_info') |
@@ -157,7 +157,7 @@ discard block |
||
157 | 157 | ), |
158 | 158 | '<a href="https://eventespresso.com/about/user-experience-improvement-program-uxip/" target="_blank">', |
159 | 159 | '</a>', |
160 | - '<a href="' . $settings_url . '" target="_blank">', |
|
160 | + '<a href="'.$settings_url.'" target="_blank">', |
|
161 | 161 | '</a>' |
162 | 162 | ); |
163 | 163 | } |
@@ -171,14 +171,14 @@ discard block |
||
171 | 171 | { |
172 | 172 | wp_register_script( |
173 | 173 | 'ee-data-optin-js', |
174 | - EE_GLOBAL_ASSETS_URL . 'scripts/ee-data-optin.js', |
|
174 | + EE_GLOBAL_ASSETS_URL.'scripts/ee-data-optin.js', |
|
175 | 175 | array('jquery'), |
176 | 176 | EVENT_ESPRESSO_VERSION, |
177 | 177 | true |
178 | 178 | ); |
179 | 179 | wp_register_style( |
180 | 180 | 'ee-data-optin-css', |
181 | - EE_GLOBAL_ASSETS_URL . 'css/ee-data-optin.css', |
|
181 | + EE_GLOBAL_ASSETS_URL.'css/ee-data-optin.css', |
|
182 | 182 | array(), |
183 | 183 | EVENT_ESPRESSO_VERSION |
184 | 184 | ); |
@@ -197,7 +197,7 @@ discard block |
||
197 | 197 | $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
198 | 198 | $nonce = $request->getRequestParam('nonce'); |
199 | 199 | // verify nonce |
200 | - if (! $nonce || ! wp_verify_nonce($nonce, 'ee-data-optin')) { |
|
200 | + if ( ! $nonce || ! wp_verify_nonce($nonce, 'ee-data-optin')) { |
|
201 | 201 | exit(); |
202 | 202 | } |
203 | 203 |
@@ -21,86 +21,86 @@ discard block |
||
21 | 21 | */ |
22 | 22 | class Stats |
23 | 23 | { |
24 | - const OPTIONS_KEY_EXPIRY_TIMESTAMP_FOR_SENDING_STATS = 'ee_uxip_stats_expiry'; |
|
25 | - |
|
26 | - /** |
|
27 | - * @var Config |
|
28 | - */ |
|
29 | - private $config; |
|
30 | - |
|
31 | - |
|
32 | - /** |
|
33 | - * @var StatsGatherer |
|
34 | - */ |
|
35 | - private $stats_gatherer; |
|
36 | - |
|
37 | - |
|
38 | - /** |
|
39 | - * @var EE_Maintenance_Mode |
|
40 | - */ |
|
41 | - private $maintenance_mode; |
|
42 | - |
|
43 | - public function __construct( |
|
44 | - Config $config, |
|
45 | - EE_Maintenance_Mode $maintenance_mode, |
|
46 | - StatsGatherer $stats_gatherer |
|
47 | - ) { |
|
48 | - $this->config = $config; |
|
49 | - $this->maintenance_mode = $maintenance_mode; |
|
50 | - $this->stats_gatherer = $stats_gatherer; |
|
51 | - $this->setUxipNotices(); |
|
52 | - } |
|
53 | - |
|
54 | - |
|
55 | - /** |
|
56 | - * Displays uxip opt-in notice if necessary. |
|
57 | - */ |
|
58 | - private function setUxipNotices() |
|
59 | - { |
|
60 | - if ($this->canDisplayNotices()) { |
|
61 | - add_action('admin_notices', array($this, 'optinNotice')); |
|
62 | - add_action('admin_enqueue_scripts', array($this, 'enqueueScripts')); |
|
63 | - add_action('wp_ajax_espresso_data_optin', array($this, 'ajaxHandler')); |
|
64 | - } |
|
65 | - } |
|
66 | - |
|
67 | - |
|
68 | - /** |
|
69 | - * This returns the callback that PluginUpdateEngineChecker will use for getting any extra stats to send. |
|
70 | - * |
|
71 | - * @return Closure |
|
72 | - */ |
|
73 | - public function statsCallback() |
|
74 | - { |
|
75 | - // returns a callback that can is used to retrieve the stats to send along to the pue server. |
|
76 | - return function () { |
|
77 | - // we only send stats one a week, so let's see if our stat timestamp has expired. |
|
78 | - if (! $this->sendStats()) { |
|
79 | - return array(); |
|
80 | - } |
|
81 | - return $this->stats_gatherer->stats(); |
|
82 | - }; |
|
83 | - } |
|
84 | - |
|
85 | - |
|
86 | - /** |
|
87 | - * Return whether notices can be displayed or not |
|
88 | - * |
|
89 | - * @return bool |
|
90 | - */ |
|
91 | - private function canDisplayNotices() |
|
92 | - { |
|
93 | - return ! $this->config->hasNotifiedForUxip() |
|
94 | - && $this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance; |
|
95 | - } |
|
96 | - |
|
97 | - |
|
98 | - /** |
|
99 | - * Callback for the admin_notices hook that outputs the UXIP optin-in notice. |
|
100 | - */ |
|
101 | - public function optinNotice() |
|
102 | - { |
|
103 | - ?> |
|
24 | + const OPTIONS_KEY_EXPIRY_TIMESTAMP_FOR_SENDING_STATS = 'ee_uxip_stats_expiry'; |
|
25 | + |
|
26 | + /** |
|
27 | + * @var Config |
|
28 | + */ |
|
29 | + private $config; |
|
30 | + |
|
31 | + |
|
32 | + /** |
|
33 | + * @var StatsGatherer |
|
34 | + */ |
|
35 | + private $stats_gatherer; |
|
36 | + |
|
37 | + |
|
38 | + /** |
|
39 | + * @var EE_Maintenance_Mode |
|
40 | + */ |
|
41 | + private $maintenance_mode; |
|
42 | + |
|
43 | + public function __construct( |
|
44 | + Config $config, |
|
45 | + EE_Maintenance_Mode $maintenance_mode, |
|
46 | + StatsGatherer $stats_gatherer |
|
47 | + ) { |
|
48 | + $this->config = $config; |
|
49 | + $this->maintenance_mode = $maintenance_mode; |
|
50 | + $this->stats_gatherer = $stats_gatherer; |
|
51 | + $this->setUxipNotices(); |
|
52 | + } |
|
53 | + |
|
54 | + |
|
55 | + /** |
|
56 | + * Displays uxip opt-in notice if necessary. |
|
57 | + */ |
|
58 | + private function setUxipNotices() |
|
59 | + { |
|
60 | + if ($this->canDisplayNotices()) { |
|
61 | + add_action('admin_notices', array($this, 'optinNotice')); |
|
62 | + add_action('admin_enqueue_scripts', array($this, 'enqueueScripts')); |
|
63 | + add_action('wp_ajax_espresso_data_optin', array($this, 'ajaxHandler')); |
|
64 | + } |
|
65 | + } |
|
66 | + |
|
67 | + |
|
68 | + /** |
|
69 | + * This returns the callback that PluginUpdateEngineChecker will use for getting any extra stats to send. |
|
70 | + * |
|
71 | + * @return Closure |
|
72 | + */ |
|
73 | + public function statsCallback() |
|
74 | + { |
|
75 | + // returns a callback that can is used to retrieve the stats to send along to the pue server. |
|
76 | + return function () { |
|
77 | + // we only send stats one a week, so let's see if our stat timestamp has expired. |
|
78 | + if (! $this->sendStats()) { |
|
79 | + return array(); |
|
80 | + } |
|
81 | + return $this->stats_gatherer->stats(); |
|
82 | + }; |
|
83 | + } |
|
84 | + |
|
85 | + |
|
86 | + /** |
|
87 | + * Return whether notices can be displayed or not |
|
88 | + * |
|
89 | + * @return bool |
|
90 | + */ |
|
91 | + private function canDisplayNotices() |
|
92 | + { |
|
93 | + return ! $this->config->hasNotifiedForUxip() |
|
94 | + && $this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance; |
|
95 | + } |
|
96 | + |
|
97 | + |
|
98 | + /** |
|
99 | + * Callback for the admin_notices hook that outputs the UXIP optin-in notice. |
|
100 | + */ |
|
101 | + public function optinNotice() |
|
102 | + { |
|
103 | + ?> |
|
104 | 104 | <div class="updated data-collect-optin" id="espresso-data-collect-optin-container"> |
105 | 105 | <div id="data-collect-optin-options-container"> |
106 | 106 | <span class="dashicons dashicons-admin-site"></span> |
@@ -113,128 +113,128 @@ discard block |
||
113 | 113 | </div> |
114 | 114 | </div> |
115 | 115 | <?php |
116 | - } |
|
117 | - |
|
118 | - |
|
119 | - /** |
|
120 | - * Retrieves the optin text (static so it can be used in multiple places as necessary). |
|
121 | - * |
|
122 | - * @param bool $extra |
|
123 | - */ |
|
124 | - public static function optinText($extra = true) |
|
125 | - { |
|
126 | - if (! $extra) { |
|
127 | - echo '<h2 class="ee-admin-settings-hdr" ' |
|
128 | - . (! $extra ? 'id="UXIP_settings"' : '') |
|
129 | - . '>' |
|
130 | - . esc_html__('User eXperience Improvement Program (UXIP)', 'event_espresso') |
|
131 | - . EEH_Template::get_help_tab_link('organization_logo_info') |
|
132 | - . '</h2>'; |
|
133 | - printf( |
|
134 | - esc_html__( |
|
135 | - '%1$sPlease help us make Event Espresso better and vote for your favorite features.%2$s The %3$sUser eXperience Improvement Program (UXIP)%4$s, has been created so when you use Event Espresso you are voting for the features and settings that are important to you. The UXIP helps us understand how you use our products and services, track problems and in what context. If you opt-out of the UXIP you essentially elect for us to disregard how you use Event Espresso as we build new features and make changes. Participation in the program is completely voluntary and it is disabled by default. The end results of the UXIP are software improvements to better meet your needs. The data we collect will never be sold, traded, or misused in any way. %5$sPlease see our %6$sPrivacy Policy%7$s for more information.', |
|
136 | - 'event_espresso' |
|
137 | - ), |
|
138 | - '<p><em>', |
|
139 | - '</em></p>', |
|
140 | - '<a href="https://eventespresso.com/about/user-experience-improvement-program-uxip/" target="_blank">', |
|
141 | - '</a>', |
|
142 | - '<br><br>', |
|
143 | - '<a href="https://eventespresso.com/about/privacy-policy/" target="_blank">', |
|
144 | - '</a>' |
|
145 | - ); |
|
146 | - } else { |
|
147 | - $settings_url = EEH_URL::add_query_args_and_nonce( |
|
148 | - array('action' => 'default'), |
|
149 | - admin_url('admin.php?page=espresso_general_settings') |
|
150 | - ); |
|
151 | - $settings_url .= '#UXIP_settings'; |
|
152 | - printf( |
|
153 | - esc_html__( |
|
154 | - 'The Event Espresso UXIP feature is not yet active on your site. For %1$smore info%2$s and to opt-in %3$sclick here%4$s.', |
|
155 | - 'event_espresso' |
|
156 | - ), |
|
157 | - '<a href="https://eventespresso.com/about/user-experience-improvement-program-uxip/" target="_blank">', |
|
158 | - '</a>', |
|
159 | - '<a href="' . $settings_url . '" target="_blank">', |
|
160 | - '</a>' |
|
161 | - ); |
|
162 | - } |
|
163 | - } |
|
164 | - |
|
165 | - |
|
166 | - /** |
|
167 | - * Callback for admin_enqueue_scripts that sets up the scripts and styles for the uxip notice |
|
168 | - */ |
|
169 | - public function enqueueScripts() |
|
170 | - { |
|
171 | - wp_register_script( |
|
172 | - 'ee-data-optin-js', |
|
173 | - EE_GLOBAL_ASSETS_URL . 'scripts/ee-data-optin.js', |
|
174 | - array('jquery'), |
|
175 | - EVENT_ESPRESSO_VERSION, |
|
176 | - true |
|
177 | - ); |
|
178 | - wp_register_style( |
|
179 | - 'ee-data-optin-css', |
|
180 | - EE_GLOBAL_ASSETS_URL . 'css/ee-data-optin.css', |
|
181 | - array(), |
|
182 | - EVENT_ESPRESSO_VERSION |
|
183 | - ); |
|
184 | - |
|
185 | - wp_enqueue_script('ee-data-optin-js'); |
|
186 | - wp_enqueue_style('ee-data-optin-css'); |
|
187 | - } |
|
188 | - |
|
189 | - |
|
190 | - /** |
|
191 | - * Callback for wp_ajax_espresso_data_optin that handles the ajax request |
|
192 | - */ |
|
193 | - public function ajaxHandler() |
|
194 | - { |
|
195 | - /** @var RequestInterface $request */ |
|
196 | - $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
197 | - $nonce = $request->getRequestParam('nonce'); |
|
198 | - // verify nonce |
|
199 | - if (! $nonce || ! wp_verify_nonce($nonce, 'ee-data-optin')) { |
|
200 | - exit(); |
|
201 | - } |
|
202 | - |
|
203 | - // update has notified option |
|
204 | - $this->config->setHasNotifiedAboutUxip(); |
|
205 | - exit(); |
|
206 | - } |
|
207 | - |
|
208 | - |
|
209 | - /** |
|
210 | - * Used to determine whether additional stats are sent. |
|
211 | - */ |
|
212 | - private function sendStats() |
|
213 | - { |
|
214 | - return $this->config->isOptedInForUxip() |
|
215 | - && $this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance |
|
216 | - && $this->statSendTimestampExpired(); |
|
217 | - } |
|
218 | - |
|
219 | - |
|
220 | - /** |
|
221 | - * Returns true when the timestamp used to track whether stats get sent (currently a weekly interval) is expired. |
|
222 | - * Returns false otherwise. |
|
223 | - * |
|
224 | - * @return bool |
|
225 | - */ |
|
226 | - private function statSendTimestampExpired() |
|
227 | - { |
|
228 | - $current_expiry = get_option(self::OPTIONS_KEY_EXPIRY_TIMESTAMP_FOR_SENDING_STATS, null); |
|
229 | - if ($current_expiry === null) { |
|
230 | - add_option(self::OPTIONS_KEY_EXPIRY_TIMESTAMP_FOR_SENDING_STATS, time() + WEEK_IN_SECONDS, '', 'no'); |
|
231 | - return true; |
|
232 | - } |
|
233 | - |
|
234 | - if (time() > (int) $current_expiry) { |
|
235 | - update_option(self::OPTIONS_KEY_EXPIRY_TIMESTAMP_FOR_SENDING_STATS, time() + WEEK_IN_SECONDS); |
|
236 | - return true; |
|
237 | - } |
|
238 | - return false; |
|
239 | - } |
|
116 | + } |
|
117 | + |
|
118 | + |
|
119 | + /** |
|
120 | + * Retrieves the optin text (static so it can be used in multiple places as necessary). |
|
121 | + * |
|
122 | + * @param bool $extra |
|
123 | + */ |
|
124 | + public static function optinText($extra = true) |
|
125 | + { |
|
126 | + if (! $extra) { |
|
127 | + echo '<h2 class="ee-admin-settings-hdr" ' |
|
128 | + . (! $extra ? 'id="UXIP_settings"' : '') |
|
129 | + . '>' |
|
130 | + . esc_html__('User eXperience Improvement Program (UXIP)', 'event_espresso') |
|
131 | + . EEH_Template::get_help_tab_link('organization_logo_info') |
|
132 | + . '</h2>'; |
|
133 | + printf( |
|
134 | + esc_html__( |
|
135 | + '%1$sPlease help us make Event Espresso better and vote for your favorite features.%2$s The %3$sUser eXperience Improvement Program (UXIP)%4$s, has been created so when you use Event Espresso you are voting for the features and settings that are important to you. The UXIP helps us understand how you use our products and services, track problems and in what context. If you opt-out of the UXIP you essentially elect for us to disregard how you use Event Espresso as we build new features and make changes. Participation in the program is completely voluntary and it is disabled by default. The end results of the UXIP are software improvements to better meet your needs. The data we collect will never be sold, traded, or misused in any way. %5$sPlease see our %6$sPrivacy Policy%7$s for more information.', |
|
136 | + 'event_espresso' |
|
137 | + ), |
|
138 | + '<p><em>', |
|
139 | + '</em></p>', |
|
140 | + '<a href="https://eventespresso.com/about/user-experience-improvement-program-uxip/" target="_blank">', |
|
141 | + '</a>', |
|
142 | + '<br><br>', |
|
143 | + '<a href="https://eventespresso.com/about/privacy-policy/" target="_blank">', |
|
144 | + '</a>' |
|
145 | + ); |
|
146 | + } else { |
|
147 | + $settings_url = EEH_URL::add_query_args_and_nonce( |
|
148 | + array('action' => 'default'), |
|
149 | + admin_url('admin.php?page=espresso_general_settings') |
|
150 | + ); |
|
151 | + $settings_url .= '#UXIP_settings'; |
|
152 | + printf( |
|
153 | + esc_html__( |
|
154 | + 'The Event Espresso UXIP feature is not yet active on your site. For %1$smore info%2$s and to opt-in %3$sclick here%4$s.', |
|
155 | + 'event_espresso' |
|
156 | + ), |
|
157 | + '<a href="https://eventespresso.com/about/user-experience-improvement-program-uxip/" target="_blank">', |
|
158 | + '</a>', |
|
159 | + '<a href="' . $settings_url . '" target="_blank">', |
|
160 | + '</a>' |
|
161 | + ); |
|
162 | + } |
|
163 | + } |
|
164 | + |
|
165 | + |
|
166 | + /** |
|
167 | + * Callback for admin_enqueue_scripts that sets up the scripts and styles for the uxip notice |
|
168 | + */ |
|
169 | + public function enqueueScripts() |
|
170 | + { |
|
171 | + wp_register_script( |
|
172 | + 'ee-data-optin-js', |
|
173 | + EE_GLOBAL_ASSETS_URL . 'scripts/ee-data-optin.js', |
|
174 | + array('jquery'), |
|
175 | + EVENT_ESPRESSO_VERSION, |
|
176 | + true |
|
177 | + ); |
|
178 | + wp_register_style( |
|
179 | + 'ee-data-optin-css', |
|
180 | + EE_GLOBAL_ASSETS_URL . 'css/ee-data-optin.css', |
|
181 | + array(), |
|
182 | + EVENT_ESPRESSO_VERSION |
|
183 | + ); |
|
184 | + |
|
185 | + wp_enqueue_script('ee-data-optin-js'); |
|
186 | + wp_enqueue_style('ee-data-optin-css'); |
|
187 | + } |
|
188 | + |
|
189 | + |
|
190 | + /** |
|
191 | + * Callback for wp_ajax_espresso_data_optin that handles the ajax request |
|
192 | + */ |
|
193 | + public function ajaxHandler() |
|
194 | + { |
|
195 | + /** @var RequestInterface $request */ |
|
196 | + $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
197 | + $nonce = $request->getRequestParam('nonce'); |
|
198 | + // verify nonce |
|
199 | + if (! $nonce || ! wp_verify_nonce($nonce, 'ee-data-optin')) { |
|
200 | + exit(); |
|
201 | + } |
|
202 | + |
|
203 | + // update has notified option |
|
204 | + $this->config->setHasNotifiedAboutUxip(); |
|
205 | + exit(); |
|
206 | + } |
|
207 | + |
|
208 | + |
|
209 | + /** |
|
210 | + * Used to determine whether additional stats are sent. |
|
211 | + */ |
|
212 | + private function sendStats() |
|
213 | + { |
|
214 | + return $this->config->isOptedInForUxip() |
|
215 | + && $this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance |
|
216 | + && $this->statSendTimestampExpired(); |
|
217 | + } |
|
218 | + |
|
219 | + |
|
220 | + /** |
|
221 | + * Returns true when the timestamp used to track whether stats get sent (currently a weekly interval) is expired. |
|
222 | + * Returns false otherwise. |
|
223 | + * |
|
224 | + * @return bool |
|
225 | + */ |
|
226 | + private function statSendTimestampExpired() |
|
227 | + { |
|
228 | + $current_expiry = get_option(self::OPTIONS_KEY_EXPIRY_TIMESTAMP_FOR_SENDING_STATS, null); |
|
229 | + if ($current_expiry === null) { |
|
230 | + add_option(self::OPTIONS_KEY_EXPIRY_TIMESTAMP_FOR_SENDING_STATS, time() + WEEK_IN_SECONDS, '', 'no'); |
|
231 | + return true; |
|
232 | + } |
|
233 | + |
|
234 | + if (time() > (int) $current_expiry) { |
|
235 | + update_option(self::OPTIONS_KEY_EXPIRY_TIMESTAMP_FOR_SENDING_STATS, time() + WEEK_IN_SECONDS); |
|
236 | + return true; |
|
237 | + } |
|
238 | + return false; |
|
239 | + } |
|
240 | 240 | } |
@@ -48,7 +48,7 @@ discard block |
||
48 | 48 | */ |
49 | 49 | public static function instance() |
50 | 50 | { |
51 | - if (! self::$_instance instanceof EE_Log) { |
|
51 | + if ( ! self::$_instance instanceof EE_Log) { |
|
52 | 52 | self::$_instance = new self(); |
53 | 53 | } |
54 | 54 | return self::$_instance; |
@@ -61,7 +61,7 @@ discard block |
||
61 | 61 | private function __construct() |
62 | 62 | { |
63 | 63 | |
64 | - if (! EE_Registry::instance()->CFG->admin->use_remote_logging) { |
|
64 | + if ( ! EE_Registry::instance()->CFG->admin->use_remote_logging) { |
|
65 | 65 | return; |
66 | 66 | } |
67 | 67 | |
@@ -105,14 +105,14 @@ discard block |
||
105 | 105 | */ |
106 | 106 | private function _format_message($file = '', $function = '', $message = '', $type = '') |
107 | 107 | { |
108 | - $msg = '----------------------------------------------------------------------------------------' . PHP_EOL; |
|
109 | - $msg .= '[' . current_time('mysql') . '] '; |
|
108 | + $msg = '----------------------------------------------------------------------------------------'.PHP_EOL; |
|
109 | + $msg .= '['.current_time('mysql').'] '; |
|
110 | 110 | $msg .= ! empty($file) ? basename($file) : ''; |
111 | 111 | $msg .= ! empty($file) && ! empty($function) ? ' -> ' : ''; |
112 | - $msg .= ! empty($function) ? $function . '()' : ''; |
|
112 | + $msg .= ! empty($function) ? $function.'()' : ''; |
|
113 | 113 | $msg .= PHP_EOL; |
114 | 114 | $type = ! empty($type) ? $type : 'log message'; |
115 | - $msg .= ! empty($message) ? "\t" . '[' . $type . '] ' . $message . PHP_EOL : ''; |
|
115 | + $msg .= ! empty($message) ? "\t".'['.$type.'] '.$message.PHP_EOL : ''; |
|
116 | 116 | return $msg; |
117 | 117 | } |
118 | 118 | |
@@ -164,18 +164,18 @@ discard block |
||
164 | 164 | |
165 | 165 | /** @var RequestInterface $request */ |
166 | 166 | $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
167 | - $data = 'domain=' . $request->getServerParam('HTTP_HOST'); |
|
168 | - $data .= '&ip=' . $request->getServerParam('SERVER_ADDR'); |
|
169 | - $data .= '&server_type=' . $request->getServerParam('SERVER_SOFTWARE'); |
|
170 | - $data .= '&time=' . time(); |
|
171 | - $data .= '&remote_log=' . $this->_log; |
|
167 | + $data = 'domain='.$request->getServerParam('HTTP_HOST'); |
|
168 | + $data .= '&ip='.$request->getServerParam('SERVER_ADDR'); |
|
169 | + $data .= '&server_type='.$request->getServerParam('SERVER_SOFTWARE'); |
|
170 | + $data .= '&time='.time(); |
|
171 | + $data .= '&remote_log='.$this->_log; |
|
172 | 172 | $data .= '&action=save'; |
173 | 173 | |
174 | 174 | if (defined('EELOGGING_PASS')) { |
175 | - $data .= '&pass=' . EELOGGING_PASS; |
|
175 | + $data .= '&pass='.EELOGGING_PASS; |
|
176 | 176 | } |
177 | 177 | if (defined('EELOGGING_KEY')) { |
178 | - $data .= '&key=' . EELOGGING_KEY; |
|
178 | + $data .= '&key='.EELOGGING_KEY; |
|
179 | 179 | } |
180 | 180 | |
181 | 181 | $c = curl_init($this->_remote_logging_url); |
@@ -19,197 +19,197 @@ |
||
19 | 19 | */ |
20 | 20 | class EE_Log |
21 | 21 | { |
22 | - /** |
|
23 | - * @var string |
|
24 | - */ |
|
25 | - private $_log = ''; |
|
26 | - |
|
27 | - /** |
|
28 | - * Used for remote logging |
|
29 | - * |
|
30 | - * @var string |
|
31 | - */ |
|
32 | - private $_remote_logging_url = ''; |
|
33 | - |
|
34 | - /** |
|
35 | - * @var string |
|
36 | - */ |
|
37 | - private $_remote_log = ''; |
|
38 | - |
|
39 | - /** |
|
40 | - * @var EE_Log |
|
41 | - */ |
|
42 | - private static $_instance; |
|
43 | - |
|
44 | - |
|
45 | - /** |
|
46 | - * @return EE_Log |
|
47 | - */ |
|
48 | - public static function instance() |
|
49 | - { |
|
50 | - if (! self::$_instance instanceof EE_Log) { |
|
51 | - self::$_instance = new self(); |
|
52 | - } |
|
53 | - return self::$_instance; |
|
54 | - } |
|
55 | - |
|
56 | - /** |
|
57 | - * @access private |
|
58 | - * @return EE_Log |
|
59 | - */ |
|
60 | - private function __construct() |
|
61 | - { |
|
62 | - |
|
63 | - if (! EE_Registry::instance()->CFG->admin->use_remote_logging) { |
|
64 | - return; |
|
65 | - } |
|
66 | - |
|
67 | - $this->_remote_logging_url = EE_Registry::instance()->CFG->admin->remote_logging_url; |
|
68 | - $this->_remote_log = ''; |
|
69 | - |
|
70 | - if (EE_Registry::instance()->CFG->admin->use_remote_logging) { |
|
71 | - add_action('shutdown', array($this, 'send_log'), 9999); |
|
72 | - } |
|
73 | - } |
|
74 | - |
|
75 | - |
|
76 | - /** |
|
77 | - * verify_filesystem |
|
78 | - * tests that the required files and folders exist and are writable |
|
79 | - * |
|
80 | - */ |
|
81 | - public function verify_filesystem() |
|
82 | - { |
|
83 | - $msg = esc_html__( |
|
84 | - 'The Local File Logging functionality was removed permanently. Remote Logging is recommended instead.', |
|
85 | - 'event_espresso' |
|
86 | - ); |
|
87 | - EE_Error::doing_it_wrong( |
|
88 | - __METHOD__, |
|
89 | - $msg, |
|
90 | - '4.10.1.p' |
|
91 | - ); |
|
92 | - } |
|
93 | - |
|
94 | - |
|
95 | - /** |
|
96 | - * _format_message |
|
97 | - * makes yer log entries look all purdy |
|
98 | - * |
|
99 | - * @param string $file |
|
100 | - * @param string $function |
|
101 | - * @param string $message |
|
102 | - * @param string $type |
|
103 | - * @return string |
|
104 | - */ |
|
105 | - private function _format_message($file = '', $function = '', $message = '', $type = '') |
|
106 | - { |
|
107 | - $msg = '----------------------------------------------------------------------------------------' . PHP_EOL; |
|
108 | - $msg .= '[' . current_time('mysql') . '] '; |
|
109 | - $msg .= ! empty($file) ? basename($file) : ''; |
|
110 | - $msg .= ! empty($file) && ! empty($function) ? ' -> ' : ''; |
|
111 | - $msg .= ! empty($function) ? $function . '()' : ''; |
|
112 | - $msg .= PHP_EOL; |
|
113 | - $type = ! empty($type) ? $type : 'log message'; |
|
114 | - $msg .= ! empty($message) ? "\t" . '[' . $type . '] ' . $message . PHP_EOL : ''; |
|
115 | - return $msg; |
|
116 | - } |
|
117 | - |
|
118 | - |
|
119 | - /** |
|
120 | - * log |
|
121 | - * adds content to the EE_Log->_log property which gets written to file during the WP 'shutdown' hookpoint via the |
|
122 | - * EE_Log::write_log() callback |
|
123 | - * |
|
124 | - * @param string $file |
|
125 | - * @param string $function |
|
126 | - * @param string $message |
|
127 | - * @param string $type |
|
128 | - */ |
|
129 | - public function log($file = '', $function = '', $message = '', $type = '') |
|
130 | - { |
|
131 | - $this->_log .= $this->_format_message($file, $function, $message, $type); |
|
132 | - } |
|
133 | - |
|
134 | - |
|
135 | - /** |
|
136 | - * write_log |
|
137 | - * appends the results of the 'AHEE_log' filter to the espresso log file |
|
138 | - */ |
|
139 | - public function write_log() |
|
140 | - { |
|
141 | - $msg = esc_html__( |
|
142 | - 'The Local File Logging functionality was removed permanently. Remote Logging is recommended instead.', |
|
143 | - 'event_espresso' |
|
144 | - ); |
|
145 | - EE_Error::doing_it_wrong( |
|
146 | - __METHOD__, |
|
147 | - $msg, |
|
148 | - '4.10.1.p' |
|
149 | - ); |
|
150 | - } |
|
151 | - |
|
152 | - |
|
153 | - /** |
|
154 | - * send_log |
|
155 | - * sends the espresso log to a remote URL via a PHP cURL request |
|
156 | - */ |
|
157 | - public function send_log() |
|
158 | - { |
|
159 | - |
|
160 | - if (empty($this->_remote_logging_url)) { |
|
161 | - return; |
|
162 | - } |
|
163 | - |
|
164 | - /** @var RequestInterface $request */ |
|
165 | - $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
166 | - $data = 'domain=' . $request->getServerParam('HTTP_HOST'); |
|
167 | - $data .= '&ip=' . $request->getServerParam('SERVER_ADDR'); |
|
168 | - $data .= '&server_type=' . $request->getServerParam('SERVER_SOFTWARE'); |
|
169 | - $data .= '&time=' . time(); |
|
170 | - $data .= '&remote_log=' . $this->_log; |
|
171 | - $data .= '&action=save'; |
|
172 | - |
|
173 | - if (defined('EELOGGING_PASS')) { |
|
174 | - $data .= '&pass=' . EELOGGING_PASS; |
|
175 | - } |
|
176 | - if (defined('EELOGGING_KEY')) { |
|
177 | - $data .= '&key=' . EELOGGING_KEY; |
|
178 | - } |
|
179 | - |
|
180 | - $c = curl_init($this->_remote_logging_url); |
|
181 | - curl_setopt($c, CURLOPT_POST, true); |
|
182 | - curl_setopt($c, CURLOPT_POSTFIELDS, $data); |
|
183 | - curl_setopt($c, CURLOPT_RETURNTRANSFER, true); |
|
184 | - curl_exec($c); |
|
185 | - curl_close($c); |
|
186 | - } |
|
187 | - |
|
188 | - |
|
189 | - /** |
|
190 | - * write_debug |
|
191 | - * writes the contents of the current request's data to a log file. |
|
192 | - * previous entries are overwritten |
|
193 | - */ |
|
194 | - public function write_debug() |
|
195 | - { |
|
196 | - $msg = esc_html__( |
|
197 | - 'The Local File Logging functionality was removed permanently. Remote Logging is recommended instead.', |
|
198 | - 'event_espresso' |
|
199 | - ); |
|
200 | - EE_Error::doing_it_wrong( |
|
201 | - __METHOD__, |
|
202 | - $msg, |
|
203 | - '4.10.1.p' |
|
204 | - ); |
|
205 | - } |
|
206 | - |
|
207 | - |
|
208 | - /** |
|
209 | - * __clone |
|
210 | - */ |
|
211 | - public function __clone() |
|
212 | - { |
|
213 | - trigger_error(esc_html__('Clone is not allowed.', 'event_espresso'), E_USER_ERROR); |
|
214 | - } |
|
22 | + /** |
|
23 | + * @var string |
|
24 | + */ |
|
25 | + private $_log = ''; |
|
26 | + |
|
27 | + /** |
|
28 | + * Used for remote logging |
|
29 | + * |
|
30 | + * @var string |
|
31 | + */ |
|
32 | + private $_remote_logging_url = ''; |
|
33 | + |
|
34 | + /** |
|
35 | + * @var string |
|
36 | + */ |
|
37 | + private $_remote_log = ''; |
|
38 | + |
|
39 | + /** |
|
40 | + * @var EE_Log |
|
41 | + */ |
|
42 | + private static $_instance; |
|
43 | + |
|
44 | + |
|
45 | + /** |
|
46 | + * @return EE_Log |
|
47 | + */ |
|
48 | + public static function instance() |
|
49 | + { |
|
50 | + if (! self::$_instance instanceof EE_Log) { |
|
51 | + self::$_instance = new self(); |
|
52 | + } |
|
53 | + return self::$_instance; |
|
54 | + } |
|
55 | + |
|
56 | + /** |
|
57 | + * @access private |
|
58 | + * @return EE_Log |
|
59 | + */ |
|
60 | + private function __construct() |
|
61 | + { |
|
62 | + |
|
63 | + if (! EE_Registry::instance()->CFG->admin->use_remote_logging) { |
|
64 | + return; |
|
65 | + } |
|
66 | + |
|
67 | + $this->_remote_logging_url = EE_Registry::instance()->CFG->admin->remote_logging_url; |
|
68 | + $this->_remote_log = ''; |
|
69 | + |
|
70 | + if (EE_Registry::instance()->CFG->admin->use_remote_logging) { |
|
71 | + add_action('shutdown', array($this, 'send_log'), 9999); |
|
72 | + } |
|
73 | + } |
|
74 | + |
|
75 | + |
|
76 | + /** |
|
77 | + * verify_filesystem |
|
78 | + * tests that the required files and folders exist and are writable |
|
79 | + * |
|
80 | + */ |
|
81 | + public function verify_filesystem() |
|
82 | + { |
|
83 | + $msg = esc_html__( |
|
84 | + 'The Local File Logging functionality was removed permanently. Remote Logging is recommended instead.', |
|
85 | + 'event_espresso' |
|
86 | + ); |
|
87 | + EE_Error::doing_it_wrong( |
|
88 | + __METHOD__, |
|
89 | + $msg, |
|
90 | + '4.10.1.p' |
|
91 | + ); |
|
92 | + } |
|
93 | + |
|
94 | + |
|
95 | + /** |
|
96 | + * _format_message |
|
97 | + * makes yer log entries look all purdy |
|
98 | + * |
|
99 | + * @param string $file |
|
100 | + * @param string $function |
|
101 | + * @param string $message |
|
102 | + * @param string $type |
|
103 | + * @return string |
|
104 | + */ |
|
105 | + private function _format_message($file = '', $function = '', $message = '', $type = '') |
|
106 | + { |
|
107 | + $msg = '----------------------------------------------------------------------------------------' . PHP_EOL; |
|
108 | + $msg .= '[' . current_time('mysql') . '] '; |
|
109 | + $msg .= ! empty($file) ? basename($file) : ''; |
|
110 | + $msg .= ! empty($file) && ! empty($function) ? ' -> ' : ''; |
|
111 | + $msg .= ! empty($function) ? $function . '()' : ''; |
|
112 | + $msg .= PHP_EOL; |
|
113 | + $type = ! empty($type) ? $type : 'log message'; |
|
114 | + $msg .= ! empty($message) ? "\t" . '[' . $type . '] ' . $message . PHP_EOL : ''; |
|
115 | + return $msg; |
|
116 | + } |
|
117 | + |
|
118 | + |
|
119 | + /** |
|
120 | + * log |
|
121 | + * adds content to the EE_Log->_log property which gets written to file during the WP 'shutdown' hookpoint via the |
|
122 | + * EE_Log::write_log() callback |
|
123 | + * |
|
124 | + * @param string $file |
|
125 | + * @param string $function |
|
126 | + * @param string $message |
|
127 | + * @param string $type |
|
128 | + */ |
|
129 | + public function log($file = '', $function = '', $message = '', $type = '') |
|
130 | + { |
|
131 | + $this->_log .= $this->_format_message($file, $function, $message, $type); |
|
132 | + } |
|
133 | + |
|
134 | + |
|
135 | + /** |
|
136 | + * write_log |
|
137 | + * appends the results of the 'AHEE_log' filter to the espresso log file |
|
138 | + */ |
|
139 | + public function write_log() |
|
140 | + { |
|
141 | + $msg = esc_html__( |
|
142 | + 'The Local File Logging functionality was removed permanently. Remote Logging is recommended instead.', |
|
143 | + 'event_espresso' |
|
144 | + ); |
|
145 | + EE_Error::doing_it_wrong( |
|
146 | + __METHOD__, |
|
147 | + $msg, |
|
148 | + '4.10.1.p' |
|
149 | + ); |
|
150 | + } |
|
151 | + |
|
152 | + |
|
153 | + /** |
|
154 | + * send_log |
|
155 | + * sends the espresso log to a remote URL via a PHP cURL request |
|
156 | + */ |
|
157 | + public function send_log() |
|
158 | + { |
|
159 | + |
|
160 | + if (empty($this->_remote_logging_url)) { |
|
161 | + return; |
|
162 | + } |
|
163 | + |
|
164 | + /** @var RequestInterface $request */ |
|
165 | + $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
166 | + $data = 'domain=' . $request->getServerParam('HTTP_HOST'); |
|
167 | + $data .= '&ip=' . $request->getServerParam('SERVER_ADDR'); |
|
168 | + $data .= '&server_type=' . $request->getServerParam('SERVER_SOFTWARE'); |
|
169 | + $data .= '&time=' . time(); |
|
170 | + $data .= '&remote_log=' . $this->_log; |
|
171 | + $data .= '&action=save'; |
|
172 | + |
|
173 | + if (defined('EELOGGING_PASS')) { |
|
174 | + $data .= '&pass=' . EELOGGING_PASS; |
|
175 | + } |
|
176 | + if (defined('EELOGGING_KEY')) { |
|
177 | + $data .= '&key=' . EELOGGING_KEY; |
|
178 | + } |
|
179 | + |
|
180 | + $c = curl_init($this->_remote_logging_url); |
|
181 | + curl_setopt($c, CURLOPT_POST, true); |
|
182 | + curl_setopt($c, CURLOPT_POSTFIELDS, $data); |
|
183 | + curl_setopt($c, CURLOPT_RETURNTRANSFER, true); |
|
184 | + curl_exec($c); |
|
185 | + curl_close($c); |
|
186 | + } |
|
187 | + |
|
188 | + |
|
189 | + /** |
|
190 | + * write_debug |
|
191 | + * writes the contents of the current request's data to a log file. |
|
192 | + * previous entries are overwritten |
|
193 | + */ |
|
194 | + public function write_debug() |
|
195 | + { |
|
196 | + $msg = esc_html__( |
|
197 | + 'The Local File Logging functionality was removed permanently. Remote Logging is recommended instead.', |
|
198 | + 'event_espresso' |
|
199 | + ); |
|
200 | + EE_Error::doing_it_wrong( |
|
201 | + __METHOD__, |
|
202 | + $msg, |
|
203 | + '4.10.1.p' |
|
204 | + ); |
|
205 | + } |
|
206 | + |
|
207 | + |
|
208 | + /** |
|
209 | + * __clone |
|
210 | + */ |
|
211 | + public function __clone() |
|
212 | + { |
|
213 | + trigger_error(esc_html__('Clone is not allowed.', 'event_espresso'), E_USER_ERROR); |
|
214 | + } |
|
215 | 215 | } |
@@ -141,7 +141,7 @@ discard block |
||
141 | 141 | public function import() |
142 | 142 | { |
143 | 143 | |
144 | - require_once(EE_CLASSES . 'EE_CSV.class.php'); |
|
144 | + require_once(EE_CLASSES.'EE_CSV.class.php'); |
|
145 | 145 | $this->EE_CSV = EE_CSV::instance(); |
146 | 146 | |
147 | 147 | /** @var RequestInterface $request */ |
@@ -188,18 +188,18 @@ discard block |
||
188 | 188 | break; |
189 | 189 | } |
190 | 190 | |
191 | - if (! $error_msg) { |
|
191 | + if ( ! $error_msg) { |
|
192 | 192 | $filename = $files['file']['name'][0]; |
193 | 193 | $file_ext = substr(strrchr($filename, '.'), 1); |
194 | 194 | $file_type = $files['file']['type'][0]; |
195 | 195 | $temp_file = $files['file']['tmp_name'][0]; |
196 | - $filesize = $files['file']['size'][0] / 1024;// convert from bytes to KB |
|
196 | + $filesize = $files['file']['size'][0] / 1024; // convert from bytes to KB |
|
197 | 197 | |
198 | 198 | if ($file_ext == 'csv') { |
199 | - $max_upload = $this->EE_CSV->get_max_upload_size();// max upload size in KB |
|
199 | + $max_upload = $this->EE_CSV->get_max_upload_size(); // max upload size in KB |
|
200 | 200 | if ($filesize < $max_upload || true) { |
201 | 201 | $wp_upload_dir = str_replace(array('\\', '/'), '/', wp_upload_dir()); |
202 | - $path_to_file = $wp_upload_dir['basedir'] . '/espresso/' . $filename; |
|
202 | + $path_to_file = $wp_upload_dir['basedir'].'/espresso/'.$filename; |
|
203 | 203 | |
204 | 204 | if (move_uploaded_file($temp_file, $path_to_file)) { |
205 | 205 | // convert csv to array |
@@ -334,8 +334,8 @@ discard block |
||
334 | 334 | // begin looking through the $csv_data_array, expecting the toplevel key to be the model's name... |
335 | 335 | $old_site_url = 'none-specified'; |
336 | 336 | // hanlde metadata |
337 | - if (isset($csv_data_array[ EE_CSV::metadata_header ])) { |
|
338 | - $csv_metadata = array_shift($csv_data_array[ EE_CSV::metadata_header ]); |
|
337 | + if (isset($csv_data_array[EE_CSV::metadata_header])) { |
|
338 | + $csv_metadata = array_shift($csv_data_array[EE_CSV::metadata_header]); |
|
339 | 339 | // ok so its metadata, dont try to save it to ehte db obviously... |
340 | 340 | if (isset($csv_metadata['site_url']) && $csv_metadata['site_url'] == site_url()) { |
341 | 341 | EE_Error::add_attention( |
@@ -360,14 +360,14 @@ discard block |
||
360 | 360 | ) |
361 | 361 | ); |
362 | 362 | }; |
363 | - unset($csv_data_array[ EE_CSV::metadata_header ]); |
|
363 | + unset($csv_data_array[EE_CSV::metadata_header]); |
|
364 | 364 | } |
365 | 365 | /** |
366 | 366 | * @var $old_db_to_new_db_mapping 2d array: toplevel keys being model names, bottom-level keys being the original key, and |
367 | 367 | * the value will be the newly-inserted ID. |
368 | 368 | * If we have already imported data from the same website via CSV, it shoudl be kept in this wp option |
369 | 369 | */ |
370 | - $old_db_to_new_db_mapping = get_option('ee_id_mapping_from' . sanitize_title($old_site_url), array()); |
|
370 | + $old_db_to_new_db_mapping = get_option('ee_id_mapping_from'.sanitize_title($old_site_url), array()); |
|
371 | 371 | if ($old_db_to_new_db_mapping) { |
372 | 372 | EE_Error::add_attention( |
373 | 373 | sprintf( |
@@ -387,7 +387,7 @@ discard block |
||
387 | 387 | ); |
388 | 388 | |
389 | 389 | // save the mapping from old db to new db in case they try re-importing the same data from the same website again |
390 | - update_option('ee_id_mapping_from' . sanitize_title($old_site_url), $old_db_to_new_db_mapping); |
|
390 | + update_option('ee_id_mapping_from'.sanitize_title($old_site_url), $old_db_to_new_db_mapping); |
|
391 | 391 | |
392 | 392 | if ($this->_total_updates > 0) { |
393 | 393 | EE_Error::add_success( |
@@ -510,7 +510,7 @@ discard block |
||
510 | 510 | // find the PK in the row of data (or a combined key if |
511 | 511 | // there is no primary key) |
512 | 512 | if ($model->has_primary_key_field()) { |
513 | - $id_in_csv = $model_object_data[ $model->primary_key_name() ]; |
|
513 | + $id_in_csv = $model_object_data[$model->primary_key_name()]; |
|
514 | 514 | } else { |
515 | 515 | $id_in_csv = $model->get_index_primary_key_string($model_object_data); |
516 | 516 | } |
@@ -554,14 +554,14 @@ discard block |
||
554 | 554 | $what_to_do = self::do_update; |
555 | 555 | // and if this model has a primary key, remember its mapping |
556 | 556 | if ($model->has_primary_key_field()) { |
557 | - $old_db_to_new_db_mapping[ $model_name ][ $id_in_csv ] = $conflicting->ID(); |
|
558 | - $model_object_data[ $model->primary_key_name() ] = $conflicting->ID(); |
|
557 | + $old_db_to_new_db_mapping[$model_name][$id_in_csv] = $conflicting->ID(); |
|
558 | + $model_object_data[$model->primary_key_name()] = $conflicting->ID(); |
|
559 | 559 | } else { |
560 | 560 | // we want to update this conflicting item, instead of inserting a conflicting item |
561 | 561 | // so we need to make sure they match entirely (its possible that they only conflicted on one field, but we need them to match on other fields |
562 | 562 | // for the WHERE conditions in the update). At the time of this comment, there were no models like this |
563 | 563 | foreach ($model->get_combined_primary_key_fields() as $key_field) { |
564 | - $model_object_data[ $key_field->get_name() ] = $conflicting->get( |
|
564 | + $model_object_data[$key_field->get_name()] = $conflicting->get( |
|
565 | 565 | $key_field->get_name() |
566 | 566 | ); |
567 | 567 | } |
@@ -621,7 +621,7 @@ discard block |
||
621 | 621 | $model_name = $model->get_this_model_name(); |
622 | 622 | // if it's a site-to-site export-and-import, see if this modelobject's id |
623 | 623 | // in the old data that we know of |
624 | - if (isset($old_db_to_new_db_mapping[ $model_name ][ $id_in_csv ])) { |
|
624 | + if (isset($old_db_to_new_db_mapping[$model_name][$id_in_csv])) { |
|
625 | 625 | return self::do_update; |
626 | 626 | } else { |
627 | 627 | return self::do_insert; |
@@ -677,13 +677,13 @@ discard block |
||
677 | 677 | if ( |
678 | 678 | $model->has_primary_key_field() && |
679 | 679 | $model->get_primary_key_field()->is_auto_increment() && |
680 | - isset($old_db_to_new_db_mapping[ $model->get_this_model_name() ]) && |
|
680 | + isset($old_db_to_new_db_mapping[$model->get_this_model_name()]) && |
|
681 | 681 | isset( |
682 | - $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $model_object_data[ $model->primary_key_name() ] ] |
|
682 | + $old_db_to_new_db_mapping[$model->get_this_model_name()][$model_object_data[$model->primary_key_name()]] |
|
683 | 683 | ) |
684 | 684 | ) { |
685 | - $model_object_data[ $model->primary_key_name() ] = $old_db_to_new_db_mapping[ $model->get_this_model_name( |
|
686 | - ) ][ $model_object_data[ $model->primary_key_name() ] ]; |
|
685 | + $model_object_data[$model->primary_key_name()] = $old_db_to_new_db_mapping[$model->get_this_model_name( |
|
686 | + )][$model_object_data[$model->primary_key_name()]]; |
|
687 | 687 | } |
688 | 688 | |
689 | 689 | try { |
@@ -699,10 +699,10 @@ discard block |
||
699 | 699 | $found_a_mapping = false; |
700 | 700 | foreach ($models_pointed_to as $model_pointed_to_by_fk) { |
701 | 701 | if ($model_name_field) { |
702 | - $value_of_model_name_field = $model_object_data[ $model_name_field->get_name() ]; |
|
702 | + $value_of_model_name_field = $model_object_data[$model_name_field->get_name()]; |
|
703 | 703 | if ($value_of_model_name_field == $model_pointed_to_by_fk) { |
704 | - $model_object_data[ $field_obj->get_name() ] = $this->_find_mapping_in( |
|
705 | - $model_object_data[ $field_obj->get_name() ], |
|
704 | + $model_object_data[$field_obj->get_name()] = $this->_find_mapping_in( |
|
705 | + $model_object_data[$field_obj->get_name()], |
|
706 | 706 | $model_pointed_to_by_fk, |
707 | 707 | $old_db_to_new_db_mapping, |
708 | 708 | $export_from_site_a_to_b |
@@ -711,8 +711,8 @@ discard block |
||
711 | 711 | break; |
712 | 712 | } |
713 | 713 | } else { |
714 | - $model_object_data[ $field_obj->get_name() ] = $this->_find_mapping_in( |
|
715 | - $model_object_data[ $field_obj->get_name() ], |
|
714 | + $model_object_data[$field_obj->get_name()] = $this->_find_mapping_in( |
|
715 | + $model_object_data[$field_obj->get_name()], |
|
716 | 716 | $model_pointed_to_by_fk, |
717 | 717 | $old_db_to_new_db_mapping, |
718 | 718 | $export_from_site_a_to_b |
@@ -777,8 +777,8 @@ discard block |
||
777 | 777 | */ |
778 | 778 | protected function _find_mapping_in($object_id, $model_name, $old_db_to_new_db_mapping, $export_from_site_a_to_b) |
779 | 779 | { |
780 | - if (isset($old_db_to_new_db_mapping[ $model_name ][ $object_id ])) { |
|
781 | - return $old_db_to_new_db_mapping[ $model_name ][ $object_id ]; |
|
780 | + if (isset($old_db_to_new_db_mapping[$model_name][$object_id])) { |
|
781 | + return $old_db_to_new_db_mapping[$model_name][$object_id]; |
|
782 | 782 | } elseif ($object_id == '0' || $object_id == '') { |
783 | 783 | // leave as-is |
784 | 784 | return $object_id; |
@@ -786,7 +786,7 @@ discard block |
||
786 | 786 | // we couldn't find a mapping for this, and it's from a different site, |
787 | 787 | // so blank it out |
788 | 788 | return null; |
789 | - } elseif (! $export_from_site_a_to_b) { |
|
789 | + } elseif ( ! $export_from_site_a_to_b) { |
|
790 | 790 | // we coudln't find a mapping for this, but it's from thsi DB anyway |
791 | 791 | // so let's just leave it as-is |
792 | 792 | return $object_id; |
@@ -806,8 +806,8 @@ discard block |
||
806 | 806 | // remove the primary key, if there is one (we don't want it for inserts OR updates) |
807 | 807 | // we'll put it back in if we need it |
808 | 808 | if ($model->has_primary_key_field() && $model->get_primary_key_field()->is_auto_increment()) { |
809 | - $effective_id = $model_object_data[ $model->primary_key_name() ]; |
|
810 | - unset($model_object_data[ $model->primary_key_name() ]); |
|
809 | + $effective_id = $model_object_data[$model->primary_key_name()]; |
|
810 | + unset($model_object_data[$model->primary_key_name()]); |
|
811 | 811 | } else { |
812 | 812 | $effective_id = $model->get_index_primary_key_string($model_object_data); |
813 | 813 | } |
@@ -815,7 +815,7 @@ discard block |
||
815 | 815 | try { |
816 | 816 | $new_id = $model->insert($model_object_data); |
817 | 817 | if ($new_id) { |
818 | - $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $id_in_csv ] = $new_id; |
|
818 | + $old_db_to_new_db_mapping[$model->get_this_model_name()][$id_in_csv] = $new_id; |
|
819 | 819 | $this->_total_inserts++; |
820 | 820 | EE_Error::add_success( |
821 | 821 | sprintf( |
@@ -829,7 +829,7 @@ discard block |
||
829 | 829 | $this->_total_insert_errors++; |
830 | 830 | // put the ID used back in there for the error message |
831 | 831 | if ($model->has_primary_key_field()) { |
832 | - $model_object_data[ $model->primary_key_name() ] = $effective_id; |
|
832 | + $model_object_data[$model->primary_key_name()] = $effective_id; |
|
833 | 833 | } |
834 | 834 | EE_Error::add_error( |
835 | 835 | sprintf( |
@@ -845,7 +845,7 @@ discard block |
||
845 | 845 | } catch (EE_Error $e) { |
846 | 846 | $this->_total_insert_errors++; |
847 | 847 | if ($model->has_primary_key_field()) { |
848 | - $model_object_data[ $model->primary_key_name() ] = $effective_id; |
|
848 | + $model_object_data[$model->primary_key_name()] = $effective_id; |
|
849 | 849 | } |
850 | 850 | EE_Error::add_error( |
851 | 851 | sprintf( |
@@ -878,17 +878,17 @@ discard block |
||
878 | 878 | // one for performing an update, one for everthing else |
879 | 879 | $model_object_data_for_update = $model_object_data; |
880 | 880 | if ($model->has_primary_key_field()) { |
881 | - $conditions = array($model->primary_key_name() => $model_object_data[ $model->primary_key_name() ]); |
|
881 | + $conditions = array($model->primary_key_name() => $model_object_data[$model->primary_key_name()]); |
|
882 | 882 | // remove the primary key because we shouldn't use it for updating |
883 | - unset($model_object_data_for_update[ $model->primary_key_name() ]); |
|
883 | + unset($model_object_data_for_update[$model->primary_key_name()]); |
|
884 | 884 | } elseif ($model->get_combined_primary_key_fields() > 1) { |
885 | 885 | $conditions = array(); |
886 | 886 | foreach ($model->get_combined_primary_key_fields() as $key_field) { |
887 | - $conditions[ $key_field->get_name() ] = $model_object_data[ $key_field->get_name() ]; |
|
887 | + $conditions[$key_field->get_name()] = $model_object_data[$key_field->get_name()]; |
|
888 | 888 | } |
889 | 889 | } else { |
890 | 890 | $model->primary_key_name( |
891 | - );// this shoudl just throw an exception, explaining that we dont have a primary key (or a combine dkey) |
|
891 | + ); // this shoudl just throw an exception, explaining that we dont have a primary key (or a combine dkey) |
|
892 | 892 | } |
893 | 893 | |
894 | 894 | $success = $model->update($model_object_data_for_update, array($conditions)); |
@@ -906,15 +906,15 @@ discard block |
||
906 | 906 | // we would have last-minute decided to update. So we'd like to know what we updated |
907 | 907 | // and so we record what record ended up being updated using the mapping |
908 | 908 | if ($model->has_primary_key_field()) { |
909 | - $new_key_for_mapping = $model_object_data[ $model->primary_key_name() ]; |
|
909 | + $new_key_for_mapping = $model_object_data[$model->primary_key_name()]; |
|
910 | 910 | } else { |
911 | 911 | // no primary key just a combined key |
912 | 912 | $new_key_for_mapping = $model->get_index_primary_key_string($model_object_data); |
913 | 913 | } |
914 | - $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $id_in_csv ] = $new_key_for_mapping; |
|
914 | + $old_db_to_new_db_mapping[$model->get_this_model_name()][$id_in_csv] = $new_key_for_mapping; |
|
915 | 915 | } else { |
916 | 916 | $matched_items = $model->get_all(array($conditions)); |
917 | - if (! $matched_items) { |
|
917 | + if ( ! $matched_items) { |
|
918 | 918 | // no items were matched (so we shouldn't have updated)... but then we should have inserted? what the heck? |
919 | 919 | $this->_total_update_errors++; |
920 | 920 | EE_Error::add_error( |
@@ -953,7 +953,7 @@ discard block |
||
953 | 953 | implode(",", $model_object_data), |
954 | 954 | $e->getMessage() |
955 | 955 | ); |
956 | - $debug_message = $basic_message . ' Stack trace: ' . $e->getTraceAsString(); |
|
956 | + $debug_message = $basic_message.' Stack trace: '.$e->getTraceAsString(); |
|
957 | 957 | EE_Error::add_error("$basic_message | $debug_message", __FILE__, __FUNCTION__, __LINE__); |
958 | 958 | } |
959 | 959 | return $old_db_to_new_db_mapping; |
@@ -13,97 +13,97 @@ discard block |
||
13 | 13 | */ |
14 | 14 | class EE_Import implements ResettableInterface |
15 | 15 | { |
16 | - const do_insert = 'insert'; |
|
17 | - const do_update = 'update'; |
|
18 | - const do_nothing = 'nothing'; |
|
19 | - |
|
20 | - |
|
21 | - // instance of the EE_Import object |
|
22 | - private static $_instance; |
|
23 | - |
|
24 | - private static $_csv_array = array(); |
|
25 | - |
|
26 | - /** |
|
27 | - * |
|
28 | - * @var array of model names |
|
29 | - */ |
|
30 | - private static $_model_list = array(); |
|
31 | - |
|
32 | - private static $_columns_to_save = array(); |
|
33 | - |
|
34 | - protected $_total_inserts = 0; |
|
35 | - protected $_total_updates = 0; |
|
36 | - protected $_total_insert_errors = 0; |
|
37 | - protected $_total_update_errors = 0; |
|
38 | - |
|
39 | - /** |
|
40 | - * @var EE_CSV |
|
41 | - * @since 4.10.14.p |
|
42 | - */ |
|
43 | - private $EE_CSV; |
|
44 | - |
|
45 | - |
|
46 | - /** |
|
47 | - * private constructor to prevent direct creation |
|
48 | - * |
|
49 | - * @Constructor |
|
50 | - * @access private |
|
51 | - * @return void |
|
52 | - */ |
|
53 | - private function __construct() |
|
54 | - { |
|
55 | - $this->_total_inserts = 0; |
|
56 | - $this->_total_updates = 0; |
|
57 | - $this->_total_insert_errors = 0; |
|
58 | - $this->_total_update_errors = 0; |
|
59 | - } |
|
60 | - |
|
61 | - |
|
62 | - /** |
|
63 | - * @ singleton method used to instantiate class object |
|
64 | - * @ access public |
|
65 | - * |
|
66 | - * @return EE_Import |
|
67 | - */ |
|
68 | - public static function instance() |
|
69 | - { |
|
70 | - // check if class object is instantiated |
|
71 | - if (self::$_instance === null or ! is_object(self::$_instance) or ! (self::$_instance instanceof EE_Import)) { |
|
72 | - self::$_instance = new self(); |
|
73 | - } |
|
74 | - return self::$_instance; |
|
75 | - } |
|
76 | - |
|
77 | - /** |
|
78 | - * Resets the importer |
|
79 | - * |
|
80 | - * @return EE_Import |
|
81 | - */ |
|
82 | - public static function reset() |
|
83 | - { |
|
84 | - self::$_instance = null; |
|
85 | - return self::instance(); |
|
86 | - } |
|
87 | - |
|
88 | - |
|
89 | - /** |
|
90 | - * @ generates HTML for a file upload input and form |
|
91 | - * @ access public |
|
92 | - * |
|
93 | - * @param string $title - heading for the form |
|
94 | - * @param string $intro - additional text explaing what to do |
|
95 | - * @param string $page - EE Admin page to direct form to - in the form "espresso_{pageslug}" |
|
96 | - * @param string $action - EE Admin page route array "action" that form will direct to |
|
97 | - * @param string $type - type of file to import |
|
98 | - * @ return string |
|
99 | - */ |
|
100 | - public function upload_form($title, $intro, $form_url, $action, $type) |
|
101 | - { |
|
102 | - |
|
103 | - $form_url = EE_Admin_Page::add_query_args_and_nonce(array('action' => $action), $form_url); |
|
104 | - |
|
105 | - ob_start(); |
|
106 | - ?> |
|
16 | + const do_insert = 'insert'; |
|
17 | + const do_update = 'update'; |
|
18 | + const do_nothing = 'nothing'; |
|
19 | + |
|
20 | + |
|
21 | + // instance of the EE_Import object |
|
22 | + private static $_instance; |
|
23 | + |
|
24 | + private static $_csv_array = array(); |
|
25 | + |
|
26 | + /** |
|
27 | + * |
|
28 | + * @var array of model names |
|
29 | + */ |
|
30 | + private static $_model_list = array(); |
|
31 | + |
|
32 | + private static $_columns_to_save = array(); |
|
33 | + |
|
34 | + protected $_total_inserts = 0; |
|
35 | + protected $_total_updates = 0; |
|
36 | + protected $_total_insert_errors = 0; |
|
37 | + protected $_total_update_errors = 0; |
|
38 | + |
|
39 | + /** |
|
40 | + * @var EE_CSV |
|
41 | + * @since 4.10.14.p |
|
42 | + */ |
|
43 | + private $EE_CSV; |
|
44 | + |
|
45 | + |
|
46 | + /** |
|
47 | + * private constructor to prevent direct creation |
|
48 | + * |
|
49 | + * @Constructor |
|
50 | + * @access private |
|
51 | + * @return void |
|
52 | + */ |
|
53 | + private function __construct() |
|
54 | + { |
|
55 | + $this->_total_inserts = 0; |
|
56 | + $this->_total_updates = 0; |
|
57 | + $this->_total_insert_errors = 0; |
|
58 | + $this->_total_update_errors = 0; |
|
59 | + } |
|
60 | + |
|
61 | + |
|
62 | + /** |
|
63 | + * @ singleton method used to instantiate class object |
|
64 | + * @ access public |
|
65 | + * |
|
66 | + * @return EE_Import |
|
67 | + */ |
|
68 | + public static function instance() |
|
69 | + { |
|
70 | + // check if class object is instantiated |
|
71 | + if (self::$_instance === null or ! is_object(self::$_instance) or ! (self::$_instance instanceof EE_Import)) { |
|
72 | + self::$_instance = new self(); |
|
73 | + } |
|
74 | + return self::$_instance; |
|
75 | + } |
|
76 | + |
|
77 | + /** |
|
78 | + * Resets the importer |
|
79 | + * |
|
80 | + * @return EE_Import |
|
81 | + */ |
|
82 | + public static function reset() |
|
83 | + { |
|
84 | + self::$_instance = null; |
|
85 | + return self::instance(); |
|
86 | + } |
|
87 | + |
|
88 | + |
|
89 | + /** |
|
90 | + * @ generates HTML for a file upload input and form |
|
91 | + * @ access public |
|
92 | + * |
|
93 | + * @param string $title - heading for the form |
|
94 | + * @param string $intro - additional text explaing what to do |
|
95 | + * @param string $page - EE Admin page to direct form to - in the form "espresso_{pageslug}" |
|
96 | + * @param string $action - EE Admin page route array "action" that form will direct to |
|
97 | + * @param string $type - type of file to import |
|
98 | + * @ return string |
|
99 | + */ |
|
100 | + public function upload_form($title, $intro, $form_url, $action, $type) |
|
101 | + { |
|
102 | + |
|
103 | + $form_url = EE_Admin_Page::add_query_args_and_nonce(array('action' => $action), $form_url); |
|
104 | + |
|
105 | + ob_start(); |
|
106 | + ?> |
|
107 | 107 | <div class="ee-upload-form-dv"> |
108 | 108 | <h3><?php echo esc_html($title); ?></h3> |
109 | 109 | <p><?php echo esc_html($intro); ?></p> |
@@ -119,882 +119,882 @@ discard block |
||
119 | 119 | <b><?php esc_html_e('Attention', 'event_espresso'); ?></b><br/> |
120 | 120 | <?php echo sprintf(esc_html__('Accepts .%s file types only.', 'event_espresso'), $type); ?> |
121 | 121 | <?php echo esc_html__( |
122 | - 'Please only import CSV files exported from Event Espresso, or compatible 3rd-party software.', |
|
123 | - 'event_espresso' |
|
124 | - ); ?> |
|
122 | + 'Please only import CSV files exported from Event Espresso, or compatible 3rd-party software.', |
|
123 | + 'event_espresso' |
|
124 | + ); ?> |
|
125 | 125 | </p> |
126 | 126 | |
127 | 127 | </div> |
128 | 128 | |
129 | 129 | <?php |
130 | - $uploader = ob_get_clean(); |
|
131 | - return $uploader; |
|
132 | - } |
|
133 | - |
|
134 | - |
|
135 | - /** |
|
136 | - * @Import Event Espresso data - some code "borrowed" from event espresso csv_import.php |
|
137 | - * @access public |
|
138 | - * @return boolean success |
|
139 | - */ |
|
140 | - public function import() |
|
141 | - { |
|
142 | - |
|
143 | - require_once(EE_CLASSES . 'EE_CSV.class.php'); |
|
144 | - $this->EE_CSV = EE_CSV::instance(); |
|
145 | - |
|
146 | - /** @var RequestInterface $request */ |
|
147 | - $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
148 | - |
|
149 | - if ($request->requestParamIsSet('import') && $request->requestParamIsSet('csv_submitted')) { |
|
150 | - $files = $request->filesParams(); |
|
151 | - switch ($files['file']['error'][0]) { |
|
152 | - case UPLOAD_ERR_OK: |
|
153 | - $error_msg = false; |
|
154 | - break; |
|
155 | - case UPLOAD_ERR_INI_SIZE: |
|
156 | - $error_msg = esc_html__( |
|
157 | - "'The uploaded file exceeds the upload_max_filesize directive in php.ini.'", |
|
158 | - "event_espresso" |
|
159 | - ); |
|
160 | - break; |
|
161 | - case UPLOAD_ERR_FORM_SIZE: |
|
162 | - $error_msg = esc_html__( |
|
163 | - 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.', |
|
164 | - "event_espresso" |
|
165 | - ); |
|
166 | - break; |
|
167 | - case UPLOAD_ERR_PARTIAL: |
|
168 | - $error_msg = esc_html__('The uploaded file was only partially uploaded.', "event_espresso"); |
|
169 | - break; |
|
170 | - case UPLOAD_ERR_NO_FILE: |
|
171 | - $error_msg = esc_html__('No file was uploaded.', "event_espresso"); |
|
172 | - break; |
|
173 | - case UPLOAD_ERR_NO_TMP_DIR: |
|
174 | - $error_msg = esc_html__('Missing a temporary folder.', "event_espresso"); |
|
175 | - break; |
|
176 | - case UPLOAD_ERR_CANT_WRITE: |
|
177 | - $error_msg = esc_html__('Failed to write file to disk.', "event_espresso"); |
|
178 | - break; |
|
179 | - case UPLOAD_ERR_EXTENSION: |
|
180 | - $error_msg = esc_html__('File upload stopped by extension.', "event_espresso"); |
|
181 | - break; |
|
182 | - default: |
|
183 | - $error_msg = esc_html__( |
|
184 | - 'An unknown error occurred and the file could not be uploaded', |
|
185 | - "event_espresso" |
|
186 | - ); |
|
187 | - break; |
|
188 | - } |
|
189 | - |
|
190 | - if (! $error_msg) { |
|
191 | - $filename = $files['file']['name'][0]; |
|
192 | - $file_ext = substr(strrchr($filename, '.'), 1); |
|
193 | - $file_type = $files['file']['type'][0]; |
|
194 | - $temp_file = $files['file']['tmp_name'][0]; |
|
195 | - $filesize = $files['file']['size'][0] / 1024;// convert from bytes to KB |
|
196 | - |
|
197 | - if ($file_ext == 'csv') { |
|
198 | - $max_upload = $this->EE_CSV->get_max_upload_size();// max upload size in KB |
|
199 | - if ($filesize < $max_upload || true) { |
|
200 | - $wp_upload_dir = str_replace(array('\\', '/'), '/', wp_upload_dir()); |
|
201 | - $path_to_file = $wp_upload_dir['basedir'] . '/espresso/' . $filename; |
|
202 | - |
|
203 | - if (move_uploaded_file($temp_file, $path_to_file)) { |
|
204 | - // convert csv to array |
|
205 | - $this->csv_array = $this->EE_CSV->import_csv_to_model_data_array($path_to_file); |
|
206 | - |
|
207 | - $action = $request->getRequestParam('action'); |
|
208 | - |
|
209 | - // was data successfully stored in an array? |
|
210 | - if (is_array($this->csv_array)) { |
|
211 | - $import_what = str_replace('csv_import_', '', $action); |
|
212 | - $import_what = str_replace('_', ' ', ucwords($import_what)); |
|
213 | - $processed_data = $this->csv_array; |
|
214 | - $this->columns_to_save = false; |
|
215 | - |
|
216 | - // if any imports require funky processing, we'll catch them in the switch |
|
217 | - switch ($action) { |
|
218 | - case "import_events": |
|
219 | - case "event_list": |
|
220 | - $import_what = 'Event Details'; |
|
221 | - break; |
|
222 | - |
|
223 | - case 'groupon_import_csv': |
|
224 | - $import_what = 'Groupon Codes'; |
|
225 | - $processed_data = $this->process_groupon_codes(); |
|
226 | - break; |
|
227 | - } |
|
228 | - // save processed codes to db |
|
229 | - if ($this->save_csv_data_array_to_db($processed_data, $this->columns_to_save)) { |
|
230 | - return true; |
|
231 | - } |
|
232 | - } else { |
|
233 | - // no array? must be an error |
|
234 | - EE_Error::add_error( |
|
235 | - sprintf(esc_html__("No file seems to have been uploaded", "event_espresso")), |
|
236 | - __FILE__, |
|
237 | - __FUNCTION__, |
|
238 | - __LINE__ |
|
239 | - ); |
|
240 | - return false; |
|
241 | - } |
|
242 | - } else { |
|
243 | - EE_Error::add_error( |
|
244 | - sprintf(esc_html__("%s was not successfully uploaded", "event_espresso"), $filename), |
|
245 | - __FILE__, |
|
246 | - __FUNCTION__, |
|
247 | - __LINE__ |
|
248 | - ); |
|
249 | - return false; |
|
250 | - } |
|
251 | - } else { |
|
252 | - EE_Error::add_error( |
|
253 | - sprintf( |
|
254 | - esc_html__( |
|
255 | - "%s was too large of a file and could not be uploaded. The max filesize is %s' KB.", |
|
256 | - "event_espresso" |
|
257 | - ), |
|
258 | - $filename, |
|
259 | - $max_upload |
|
260 | - ), |
|
261 | - __FILE__, |
|
262 | - __FUNCTION__, |
|
263 | - __LINE__ |
|
264 | - ); |
|
265 | - return false; |
|
266 | - } |
|
267 | - } else { |
|
268 | - EE_Error::add_error( |
|
269 | - sprintf(esc_html__("%s had an invalid file extension, not uploaded", "event_espresso"), $filename), |
|
270 | - __FILE__, |
|
271 | - __FUNCTION__, |
|
272 | - __LINE__ |
|
273 | - ); |
|
274 | - return false; |
|
275 | - } |
|
276 | - } else { |
|
277 | - EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__); |
|
278 | - return false; |
|
279 | - } |
|
280 | - } |
|
281 | - return false; |
|
282 | - } |
|
283 | - |
|
284 | - |
|
285 | - /** |
|
286 | - * Given an array of data (usually from a CSV import) attempts to save that data to the db. |
|
287 | - * If $model_name ISN'T provided, assumes that this is a 3d array, with toplevel keys being model names, |
|
288 | - * next level being numeric indexes adn each value representing a model object, and the last layer down |
|
289 | - * being keys of model fields and their proposed values. |
|
290 | - * If $model_name IS provided, assumes a 2d array of the bottom two layers previously mentioned. |
|
291 | - * If the CSV data says (in the metadata row) that it's from the SAME database, |
|
292 | - * we treat the IDs in the CSV as the normal IDs, and try to update those records. However, if those |
|
293 | - * IDs DON'T exist in the database, they're treated as temporary IDs, |
|
294 | - * which can used elsewhere to refer to the same object. Once an item |
|
295 | - * with a temporary ID gets inserted, we record its mapping from temporary |
|
296 | - * ID to real ID, and use the real ID in place of the temporary ID |
|
297 | - * when that temporary ID was used as a foreign key. |
|
298 | - * If the CSV data says (in the metadata again) that it's from a DIFFERENT database, |
|
299 | - * we treat all the IDs in the CSV as temporary ID- eg, if the CSV specifies an event with |
|
300 | - * ID 1, and the database already has an event with ID 1, we assume that's just a coincidence, |
|
301 | - * and insert a new event, and map it's temporary ID of 1 over to its new real ID. |
|
302 | - * An important exception are non-auto-increment primary keys. If one entry in the |
|
303 | - * CSV file has the same ID as one in the DB, we assume they are meant to be |
|
304 | - * the same item, and instead update the item in the DB with that same ID. |
|
305 | - * Also note, we remember the mappings permanently. So the 2nd, 3rd, and 10000th |
|
306 | - * time you import a CSV from a different site, we remember their mappings, and |
|
307 | - * will try to update the item in the DB instead of inserting another item (eg |
|
308 | - * if we previously imported an event with temporary ID 1, and then it got a |
|
309 | - * real ID of 123, we remember that. So the next time we import an event with |
|
310 | - * temporary ID, from the same site, we know that it's real ID is 123, and will |
|
311 | - * update that event, instead of adding a new event). |
|
312 | - * |
|
313 | - * @access public |
|
314 | - * @param array $csv_data_array - the array containing the csv data produced from |
|
315 | - * EE_CSV::import_csv_to_model_data_array() |
|
316 | - * @param array $fields_to_save - an array containing the csv column names as keys with the corresponding db table |
|
317 | - * fields they will be saved to |
|
318 | - * @return TRUE on success, FALSE on fail |
|
319 | - * @throws \EE_Error |
|
320 | - */ |
|
321 | - public function save_csv_data_array_to_db($csv_data_array, $model_name = false) |
|
322 | - { |
|
323 | - $success = false; |
|
324 | - $error = false; |
|
325 | - // whther to treat this import as if it's data froma different database or not |
|
326 | - // ie, if it IS from a different database, ignore foreign keys whihf |
|
327 | - $export_from_site_a_to_b = true; |
|
328 | - // first level of array is not table information but a table name was passed to the function |
|
329 | - // array is only two levels deep, so let's fix that by adding a level, else the next steps will fail |
|
330 | - if ($model_name) { |
|
331 | - $csv_data_array = array($csv_data_array); |
|
332 | - } |
|
333 | - // begin looking through the $csv_data_array, expecting the toplevel key to be the model's name... |
|
334 | - $old_site_url = 'none-specified'; |
|
335 | - // hanlde metadata |
|
336 | - if (isset($csv_data_array[ EE_CSV::metadata_header ])) { |
|
337 | - $csv_metadata = array_shift($csv_data_array[ EE_CSV::metadata_header ]); |
|
338 | - // ok so its metadata, dont try to save it to ehte db obviously... |
|
339 | - if (isset($csv_metadata['site_url']) && $csv_metadata['site_url'] == site_url()) { |
|
340 | - EE_Error::add_attention( |
|
341 | - sprintf( |
|
342 | - esc_html__( |
|
343 | - "CSV Data appears to be from the same database, so attempting to update data", |
|
344 | - "event_espresso" |
|
345 | - ) |
|
346 | - ) |
|
347 | - ); |
|
348 | - $export_from_site_a_to_b = false; |
|
349 | - } else { |
|
350 | - $old_site_url = isset($csv_metadata['site_url']) ? $csv_metadata['site_url'] : $old_site_url; |
|
351 | - EE_Error::add_attention( |
|
352 | - sprintf( |
|
353 | - esc_html__( |
|
354 | - "CSV Data appears to be from a different database (%s instead of %s), so we assume IDs in the CSV data DO NOT correspond to IDs in this database", |
|
355 | - "event_espresso" |
|
356 | - ), |
|
357 | - $old_site_url, |
|
358 | - site_url() |
|
359 | - ) |
|
360 | - ); |
|
361 | - }; |
|
362 | - unset($csv_data_array[ EE_CSV::metadata_header ]); |
|
363 | - } |
|
364 | - /** |
|
365 | - * @var $old_db_to_new_db_mapping 2d array: toplevel keys being model names, bottom-level keys being the original key, and |
|
366 | - * the value will be the newly-inserted ID. |
|
367 | - * If we have already imported data from the same website via CSV, it shoudl be kept in this wp option |
|
368 | - */ |
|
369 | - $old_db_to_new_db_mapping = get_option('ee_id_mapping_from' . sanitize_title($old_site_url), array()); |
|
370 | - if ($old_db_to_new_db_mapping) { |
|
371 | - EE_Error::add_attention( |
|
372 | - sprintf( |
|
373 | - esc_html__( |
|
374 | - "We noticed you have imported data via CSV from %s before. Because of this, IDs in your CSV have been mapped to their new IDs in %s", |
|
375 | - "event_espresso" |
|
376 | - ), |
|
377 | - $old_site_url, |
|
378 | - site_url() |
|
379 | - ) |
|
380 | - ); |
|
381 | - } |
|
382 | - $old_db_to_new_db_mapping = $this->save_data_rows_to_db( |
|
383 | - $csv_data_array, |
|
384 | - $export_from_site_a_to_b, |
|
385 | - $old_db_to_new_db_mapping |
|
386 | - ); |
|
387 | - |
|
388 | - // save the mapping from old db to new db in case they try re-importing the same data from the same website again |
|
389 | - update_option('ee_id_mapping_from' . sanitize_title($old_site_url), $old_db_to_new_db_mapping); |
|
390 | - |
|
391 | - if ($this->_total_updates > 0) { |
|
392 | - EE_Error::add_success( |
|
393 | - sprintf( |
|
394 | - esc_html__("%s existing records in the database were updated.", "event_espresso"), |
|
395 | - $this->_total_updates |
|
396 | - ) |
|
397 | - ); |
|
398 | - $success = true; |
|
399 | - } |
|
400 | - if ($this->_total_inserts > 0) { |
|
401 | - EE_Error::add_success( |
|
402 | - sprintf(esc_html__("%s new records were added to the database.", "event_espresso"), $this->_total_inserts) |
|
403 | - ); |
|
404 | - $success = true; |
|
405 | - } |
|
406 | - |
|
407 | - if ($this->_total_update_errors > 0) { |
|
408 | - EE_Error::add_error( |
|
409 | - sprintf( |
|
410 | - esc_html__( |
|
411 | - "'One or more errors occurred, and a total of %s existing records in the database were <strong>not</strong> updated.'", |
|
412 | - "event_espresso" |
|
413 | - ), |
|
414 | - $this->_total_update_errors |
|
415 | - ), |
|
416 | - __FILE__, |
|
417 | - __FUNCTION__, |
|
418 | - __LINE__ |
|
419 | - ); |
|
420 | - $error = true; |
|
421 | - } |
|
422 | - if ($this->_total_insert_errors > 0) { |
|
423 | - EE_Error::add_error( |
|
424 | - sprintf( |
|
425 | - esc_html__( |
|
426 | - "One or more errors occurred, and a total of %s new records were <strong>not</strong> added to the database.'", |
|
427 | - "event_espresso" |
|
428 | - ), |
|
429 | - $this->_total_insert_errors |
|
430 | - ), |
|
431 | - __FILE__, |
|
432 | - __FUNCTION__, |
|
433 | - __LINE__ |
|
434 | - ); |
|
435 | - $error = true; |
|
436 | - } |
|
437 | - |
|
438 | - // lastly, we need to update the datetime and ticket sold amounts |
|
439 | - // as those may have been affected by this |
|
440 | - EEM_Ticket::instance()->update_tickets_sold(EEM_Ticket::instance()->get_all()); |
|
441 | - |
|
442 | - // if there was at least one success and absolutely no errors |
|
443 | - if ($success && ! $error) { |
|
444 | - return true; |
|
445 | - } else { |
|
446 | - return false; |
|
447 | - } |
|
448 | - } |
|
449 | - |
|
450 | - |
|
451 | - /** |
|
452 | - * Processes the array of data, given the knowledge that it's from the same database or a different one, |
|
453 | - * and the mapping from temporary IDs to real IDs. |
|
454 | - * If the data is from a different database, we treat the primary keys and their corresponding |
|
455 | - * foreign keys as "temp Ids", basically identifiers that get mapped to real primary keys |
|
456 | - * in the real target database. As items are inserted, their temporary primary keys |
|
457 | - * are mapped to the real IDs in the target database. Also, before doing any update or |
|
458 | - * insert, we replace all the temp ID which are foreign keys with their mapped real IDs. |
|
459 | - * An exception: string primary keys are treated as real IDs, or else we'd need to |
|
460 | - * dynamically generate new string primary keys which would be very awkard for the country table etc. |
|
461 | - * Also, models with no primary key are strange too. We combine use their primar key INDEX (a |
|
462 | - * combination of fields) to create a unique string identifying the row and store |
|
463 | - * those in the mapping. |
|
464 | - * |
|
465 | - * If the data is from the same database, we usually treat primary keys as real IDs. |
|
466 | - * An exception is if there is nothing in the database for that ID. If that's the case, |
|
467 | - * we need to insert a new row for that ID, and then map from the non-existent ID |
|
468 | - * to the newly-inserted real ID. |
|
469 | - * |
|
470 | - * @param type $csv_data_array |
|
471 | - * @param type $export_from_site_a_to_b |
|
472 | - * @param type $old_db_to_new_db_mapping |
|
473 | - * @return array updated $old_db_to_new_db_mapping |
|
474 | - */ |
|
475 | - public function save_data_rows_to_db($csv_data_array, $export_from_site_a_to_b, $old_db_to_new_db_mapping) |
|
476 | - { |
|
477 | - foreach ($csv_data_array as $model_name_in_csv_data => $model_data_from_import) { |
|
478 | - // now check that assumption was correct. If |
|
479 | - if (EE_Registry::instance()->is_model_name($model_name_in_csv_data)) { |
|
480 | - $model_name = $model_name_in_csv_data; |
|
481 | - } else { |
|
482 | - // no table info in the array and no table name passed to the function?? FAIL |
|
483 | - EE_Error::add_error( |
|
484 | - esc_html__( |
|
485 | - 'No table information was specified and/or found, therefore the import could not be completed', |
|
486 | - 'event_espresso' |
|
487 | - ), |
|
488 | - __FILE__, |
|
489 | - __FUNCTION__, |
|
490 | - __LINE__ |
|
491 | - ); |
|
492 | - return false; |
|
493 | - } |
|
494 | - /* @var $model EEM_Base */ |
|
495 | - $model = EE_Registry::instance()->load_model($model_name); |
|
496 | - |
|
497 | - // so without further ado, scanning all the data provided for primary keys and their inital values |
|
498 | - foreach ($model_data_from_import as $model_object_data) { |
|
499 | - // before we do ANYTHING, make sure the csv row wasn't just completely blank |
|
500 | - $row_is_completely_empty = true; |
|
501 | - foreach ($model_object_data as $field) { |
|
502 | - if ($field) { |
|
503 | - $row_is_completely_empty = false; |
|
504 | - } |
|
505 | - } |
|
506 | - if ($row_is_completely_empty) { |
|
507 | - continue; |
|
508 | - } |
|
509 | - // find the PK in the row of data (or a combined key if |
|
510 | - // there is no primary key) |
|
511 | - if ($model->has_primary_key_field()) { |
|
512 | - $id_in_csv = $model_object_data[ $model->primary_key_name() ]; |
|
513 | - } else { |
|
514 | - $id_in_csv = $model->get_index_primary_key_string($model_object_data); |
|
515 | - } |
|
516 | - |
|
517 | - |
|
518 | - $model_object_data = $this->_replace_temp_ids_with_mappings( |
|
519 | - $model_object_data, |
|
520 | - $model, |
|
521 | - $old_db_to_new_db_mapping, |
|
522 | - $export_from_site_a_to_b |
|
523 | - ); |
|
524 | - // now we need to decide if we're going to add a new model object given the $model_object_data, |
|
525 | - // or just update. |
|
526 | - if ($export_from_site_a_to_b) { |
|
527 | - $what_to_do = $this->_decide_whether_to_insert_or_update_given_data_from_other_db( |
|
528 | - $id_in_csv, |
|
529 | - $model_object_data, |
|
530 | - $model, |
|
531 | - $old_db_to_new_db_mapping |
|
532 | - ); |
|
533 | - } else {// this is just a re-import |
|
534 | - $what_to_do = $this->_decide_whether_to_insert_or_update_given_data_from_same_db( |
|
535 | - $id_in_csv, |
|
536 | - $model_object_data, |
|
537 | - $model, |
|
538 | - $old_db_to_new_db_mapping |
|
539 | - ); |
|
540 | - } |
|
541 | - if ($what_to_do == self::do_nothing) { |
|
542 | - continue; |
|
543 | - } |
|
544 | - |
|
545 | - // double-check we actually want to insert, if that's what we're planning |
|
546 | - // based on whether this item would be unique in the DB or not |
|
547 | - if ($what_to_do == self::do_insert) { |
|
548 | - // we're supposed to be inserting. But wait, will this thing |
|
549 | - // be acceptable if inserted? |
|
550 | - $conflicting = $model->get_one_conflicting($model_object_data, false); |
|
551 | - if ($conflicting) { |
|
552 | - // ok, this item would conflict if inserted. Just update the item that it conflicts with. |
|
553 | - $what_to_do = self::do_update; |
|
554 | - // and if this model has a primary key, remember its mapping |
|
555 | - if ($model->has_primary_key_field()) { |
|
556 | - $old_db_to_new_db_mapping[ $model_name ][ $id_in_csv ] = $conflicting->ID(); |
|
557 | - $model_object_data[ $model->primary_key_name() ] = $conflicting->ID(); |
|
558 | - } else { |
|
559 | - // we want to update this conflicting item, instead of inserting a conflicting item |
|
560 | - // so we need to make sure they match entirely (its possible that they only conflicted on one field, but we need them to match on other fields |
|
561 | - // for the WHERE conditions in the update). At the time of this comment, there were no models like this |
|
562 | - foreach ($model->get_combined_primary_key_fields() as $key_field) { |
|
563 | - $model_object_data[ $key_field->get_name() ] = $conflicting->get( |
|
564 | - $key_field->get_name() |
|
565 | - ); |
|
566 | - } |
|
567 | - } |
|
568 | - } |
|
569 | - } |
|
570 | - if ($what_to_do == self::do_insert) { |
|
571 | - $old_db_to_new_db_mapping = $this->_insert_from_data_array( |
|
572 | - $id_in_csv, |
|
573 | - $model_object_data, |
|
574 | - $model, |
|
575 | - $old_db_to_new_db_mapping |
|
576 | - ); |
|
577 | - } elseif ($what_to_do == self::do_update) { |
|
578 | - $old_db_to_new_db_mapping = $this->_update_from_data_array( |
|
579 | - $id_in_csv, |
|
580 | - $model_object_data, |
|
581 | - $model, |
|
582 | - $old_db_to_new_db_mapping |
|
583 | - ); |
|
584 | - } else { |
|
585 | - throw new EE_Error( |
|
586 | - sprintf( |
|
587 | - esc_html__( |
|
588 | - 'Programming error. We shoudl be inserting or updating, but instead we are being told to "%s", whifh is invalid', |
|
589 | - 'event_espresso' |
|
590 | - ), |
|
591 | - $what_to_do |
|
592 | - ) |
|
593 | - ); |
|
594 | - } |
|
595 | - } |
|
596 | - } |
|
597 | - return $old_db_to_new_db_mapping; |
|
598 | - } |
|
599 | - |
|
600 | - |
|
601 | - /** |
|
602 | - * Decides whether or not to insert, given that this data is from another database. |
|
603 | - * So, if the primary key of this $model_object_data already exists in the database, |
|
604 | - * it's just a coincidence and we should still insert. The only time we should |
|
605 | - * update is when we know what it maps to, or there's something that would |
|
606 | - * conflict (and we should instead just update that conflicting thing) |
|
607 | - * |
|
608 | - * @param string $id_in_csv |
|
609 | - * @param array $model_object_data by reference so it can be modified |
|
610 | - * @param EEM_Base $model |
|
611 | - * @param array $old_db_to_new_db_mapping by reference so it can be modified |
|
612 | - * @return string one of the consts on this class that starts with do_* |
|
613 | - */ |
|
614 | - protected function _decide_whether_to_insert_or_update_given_data_from_other_db( |
|
615 | - $id_in_csv, |
|
616 | - $model_object_data, |
|
617 | - $model, |
|
618 | - $old_db_to_new_db_mapping |
|
619 | - ) { |
|
620 | - $model_name = $model->get_this_model_name(); |
|
621 | - // if it's a site-to-site export-and-import, see if this modelobject's id |
|
622 | - // in the old data that we know of |
|
623 | - if (isset($old_db_to_new_db_mapping[ $model_name ][ $id_in_csv ])) { |
|
624 | - return self::do_update; |
|
625 | - } else { |
|
626 | - return self::do_insert; |
|
627 | - } |
|
628 | - } |
|
629 | - |
|
630 | - /** |
|
631 | - * If this thing basically already exists in the database, we want to update it; |
|
632 | - * otherwise insert it (ie, someone tweaked the CSV file, or the item was |
|
633 | - * deleted in the database so it should be re-inserted) |
|
634 | - * |
|
635 | - * @param type $id_in_csv |
|
636 | - * @param type $model_object_data |
|
637 | - * @param EEM_Base $model |
|
638 | - * @param type $old_db_to_new_db_mapping |
|
639 | - * @return |
|
640 | - */ |
|
641 | - protected function _decide_whether_to_insert_or_update_given_data_from_same_db( |
|
642 | - $id_in_csv, |
|
643 | - $model_object_data, |
|
644 | - $model |
|
645 | - ) { |
|
646 | - // in this case, check if this thing ACTUALLY exists in the database |
|
647 | - if ($model->get_one_conflicting($model_object_data)) { |
|
648 | - return self::do_update; |
|
649 | - } else { |
|
650 | - return self::do_insert; |
|
651 | - } |
|
652 | - } |
|
653 | - |
|
654 | - /** |
|
655 | - * Using the $old_db_to_new_db_mapping array, replaces all the temporary IDs |
|
656 | - * with their mapped real IDs. Eg, if importing from site A to B, the mapping |
|
657 | - * file may indicate that the ID "my_event_id" maps to an actual event ID of 123. |
|
658 | - * So this function searches for any event temp Ids called "my_event_id" and |
|
659 | - * replaces them with 123. |
|
660 | - * Also, if there is no temp ID for the INT foreign keys from another database, |
|
661 | - * replaces them with 0 or the field's default. |
|
662 | - * |
|
663 | - * @param type $model_object_data |
|
664 | - * @param EEM_Base $model |
|
665 | - * @param type $old_db_to_new_db_mapping |
|
666 | - * @param boolean $export_from_site_a_to_b |
|
667 | - * @return array updated model object data with temp IDs removed |
|
668 | - */ |
|
669 | - protected function _replace_temp_ids_with_mappings( |
|
670 | - $model_object_data, |
|
671 | - $model, |
|
672 | - $old_db_to_new_db_mapping, |
|
673 | - $export_from_site_a_to_b |
|
674 | - ) { |
|
675 | - // if this model object's primary key is in the mapping, replace it |
|
676 | - if ( |
|
677 | - $model->has_primary_key_field() && |
|
678 | - $model->get_primary_key_field()->is_auto_increment() && |
|
679 | - isset($old_db_to_new_db_mapping[ $model->get_this_model_name() ]) && |
|
680 | - isset( |
|
681 | - $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $model_object_data[ $model->primary_key_name() ] ] |
|
682 | - ) |
|
683 | - ) { |
|
684 | - $model_object_data[ $model->primary_key_name() ] = $old_db_to_new_db_mapping[ $model->get_this_model_name( |
|
685 | - ) ][ $model_object_data[ $model->primary_key_name() ] ]; |
|
686 | - } |
|
687 | - |
|
688 | - try { |
|
689 | - $model_name_field = $model->get_field_containing_related_model_name(); |
|
690 | - $models_pointed_to_by_model_name_field = $model_name_field->get_model_names_pointed_to(); |
|
691 | - } catch (EE_Error $e) { |
|
692 | - $model_name_field = null; |
|
693 | - $models_pointed_to_by_model_name_field = array(); |
|
694 | - } |
|
695 | - foreach ($model->field_settings(true) as $field_obj) { |
|
696 | - if ($field_obj instanceof EE_Foreign_Key_Int_Field) { |
|
697 | - $models_pointed_to = $field_obj->get_model_names_pointed_to(); |
|
698 | - $found_a_mapping = false; |
|
699 | - foreach ($models_pointed_to as $model_pointed_to_by_fk) { |
|
700 | - if ($model_name_field) { |
|
701 | - $value_of_model_name_field = $model_object_data[ $model_name_field->get_name() ]; |
|
702 | - if ($value_of_model_name_field == $model_pointed_to_by_fk) { |
|
703 | - $model_object_data[ $field_obj->get_name() ] = $this->_find_mapping_in( |
|
704 | - $model_object_data[ $field_obj->get_name() ], |
|
705 | - $model_pointed_to_by_fk, |
|
706 | - $old_db_to_new_db_mapping, |
|
707 | - $export_from_site_a_to_b |
|
708 | - ); |
|
709 | - $found_a_mapping = true; |
|
710 | - break; |
|
711 | - } |
|
712 | - } else { |
|
713 | - $model_object_data[ $field_obj->get_name() ] = $this->_find_mapping_in( |
|
714 | - $model_object_data[ $field_obj->get_name() ], |
|
715 | - $model_pointed_to_by_fk, |
|
716 | - $old_db_to_new_db_mapping, |
|
717 | - $export_from_site_a_to_b |
|
718 | - ); |
|
719 | - $found_a_mapping = true; |
|
720 | - } |
|
721 | - // once we've found a mapping for this field no need to continue |
|
722 | - if ($found_a_mapping) { |
|
723 | - break; |
|
724 | - } |
|
725 | - } |
|
726 | - } else { |
|
727 | - // it's a string foreign key (which we leave alone, because those are things |
|
728 | - // like country names, which we'd really rather not make 2 USAs etc (we'd actually |
|
729 | - // prefer to just update one) |
|
730 | - // or it's just a regular value that ought to be replaced |
|
731 | - } |
|
732 | - } |
|
733 | - // |
|
734 | - if ($model instanceof EEM_Term_Taxonomy) { |
|
735 | - $model_object_data = $this->_handle_split_term_ids($model_object_data); |
|
736 | - } |
|
737 | - return $model_object_data; |
|
738 | - } |
|
739 | - |
|
740 | - /** |
|
741 | - * If the data was exported PRE-4.2, but then imported POST-4.2, then the term_id |
|
742 | - * this term-taxonomy refers to may be out-of-date so we need to update it. |
|
743 | - * see https://make.wordpress.org/core/2015/02/16/taxonomy-term-splitting-in-4-2-a-developer-guide/ |
|
744 | - * |
|
745 | - * @param type $model_object_data |
|
746 | - * @return array new model object data |
|
747 | - */ |
|
748 | - protected function _handle_split_term_ids($model_object_data) |
|
749 | - { |
|
750 | - if ( |
|
751 | - isset($model_object_data['term_id']) |
|
752 | - && isset($model_object_data['taxonomy']) |
|
753 | - && apply_filters( |
|
754 | - 'FHEE__EE_Import__handle_split_term_ids__function_exists', |
|
755 | - function_exists('wp_get_split_term'), |
|
756 | - $model_object_data |
|
757 | - ) |
|
758 | - ) { |
|
759 | - $new_term_id = wp_get_split_term($model_object_data['term_id'], $model_object_data['taxonomy']); |
|
760 | - if ($new_term_id) { |
|
761 | - $model_object_data['term_id'] = $new_term_id; |
|
762 | - } |
|
763 | - } |
|
764 | - return $model_object_data; |
|
765 | - } |
|
766 | - |
|
767 | - /** |
|
768 | - * Given the object's ID and its model's name, find it int he mapping data, |
|
769 | - * bearing in mind where it came from |
|
770 | - * |
|
771 | - * @param type $object_id |
|
772 | - * @param string $model_name |
|
773 | - * @param array $old_db_to_new_db_mapping |
|
774 | - * @param type $export_from_site_a_to_b |
|
775 | - * @return int |
|
776 | - */ |
|
777 | - protected function _find_mapping_in($object_id, $model_name, $old_db_to_new_db_mapping, $export_from_site_a_to_b) |
|
778 | - { |
|
779 | - if (isset($old_db_to_new_db_mapping[ $model_name ][ $object_id ])) { |
|
780 | - return $old_db_to_new_db_mapping[ $model_name ][ $object_id ]; |
|
781 | - } elseif ($object_id == '0' || $object_id == '') { |
|
782 | - // leave as-is |
|
783 | - return $object_id; |
|
784 | - } elseif ($export_from_site_a_to_b) { |
|
785 | - // we couldn't find a mapping for this, and it's from a different site, |
|
786 | - // so blank it out |
|
787 | - return null; |
|
788 | - } elseif (! $export_from_site_a_to_b) { |
|
789 | - // we coudln't find a mapping for this, but it's from thsi DB anyway |
|
790 | - // so let's just leave it as-is |
|
791 | - return $object_id; |
|
792 | - } |
|
793 | - } |
|
794 | - |
|
795 | - /** |
|
796 | - * |
|
797 | - * @param type $id_in_csv |
|
798 | - * @param type $model_object_data |
|
799 | - * @param EEM_Base $model |
|
800 | - * @param type $old_db_to_new_db_mapping |
|
801 | - * @return array updated $old_db_to_new_db_mapping |
|
802 | - */ |
|
803 | - protected function _insert_from_data_array($id_in_csv, $model_object_data, $model, $old_db_to_new_db_mapping) |
|
804 | - { |
|
805 | - // remove the primary key, if there is one (we don't want it for inserts OR updates) |
|
806 | - // we'll put it back in if we need it |
|
807 | - if ($model->has_primary_key_field() && $model->get_primary_key_field()->is_auto_increment()) { |
|
808 | - $effective_id = $model_object_data[ $model->primary_key_name() ]; |
|
809 | - unset($model_object_data[ $model->primary_key_name() ]); |
|
810 | - } else { |
|
811 | - $effective_id = $model->get_index_primary_key_string($model_object_data); |
|
812 | - } |
|
813 | - // the model takes care of validating the CSV's input |
|
814 | - try { |
|
815 | - $new_id = $model->insert($model_object_data); |
|
816 | - if ($new_id) { |
|
817 | - $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $id_in_csv ] = $new_id; |
|
818 | - $this->_total_inserts++; |
|
819 | - EE_Error::add_success( |
|
820 | - sprintf( |
|
821 | - esc_html__("Successfully added new %s (with id %s) with csv data %s", "event_espresso"), |
|
822 | - $model->get_this_model_name(), |
|
823 | - $new_id, |
|
824 | - implode(",", $model_object_data) |
|
825 | - ) |
|
826 | - ); |
|
827 | - } else { |
|
828 | - $this->_total_insert_errors++; |
|
829 | - // put the ID used back in there for the error message |
|
830 | - if ($model->has_primary_key_field()) { |
|
831 | - $model_object_data[ $model->primary_key_name() ] = $effective_id; |
|
832 | - } |
|
833 | - EE_Error::add_error( |
|
834 | - sprintf( |
|
835 | - esc_html__("Could not insert new %s with the csv data: %s", "event_espresso"), |
|
836 | - $model->get_this_model_name(), |
|
837 | - http_build_query($model_object_data) |
|
838 | - ), |
|
839 | - __FILE__, |
|
840 | - __FUNCTION__, |
|
841 | - __LINE__ |
|
842 | - ); |
|
843 | - } |
|
844 | - } catch (EE_Error $e) { |
|
845 | - $this->_total_insert_errors++; |
|
846 | - if ($model->has_primary_key_field()) { |
|
847 | - $model_object_data[ $model->primary_key_name() ] = $effective_id; |
|
848 | - } |
|
849 | - EE_Error::add_error( |
|
850 | - sprintf( |
|
851 | - esc_html__("Could not insert new %s with the csv data: %s because %s", "event_espresso"), |
|
852 | - $model->get_this_model_name(), |
|
853 | - implode(",", $model_object_data), |
|
854 | - $e->getMessage() |
|
855 | - ), |
|
856 | - __FILE__, |
|
857 | - __FUNCTION__, |
|
858 | - __LINE__ |
|
859 | - ); |
|
860 | - } |
|
861 | - return $old_db_to_new_db_mapping; |
|
862 | - } |
|
863 | - |
|
864 | - /** |
|
865 | - * Given the model object data, finds the row to update and updates it |
|
866 | - * |
|
867 | - * @param string|int $id_in_csv |
|
868 | - * @param array $model_object_data |
|
869 | - * @param EEM_Base $model |
|
870 | - * @param array $old_db_to_new_db_mapping |
|
871 | - * @return array updated $old_db_to_new_db_mapping |
|
872 | - */ |
|
873 | - protected function _update_from_data_array($id_in_csv, $model_object_data, $model, $old_db_to_new_db_mapping) |
|
874 | - { |
|
875 | - try { |
|
876 | - // let's keep two copies of the model object data: |
|
877 | - // one for performing an update, one for everthing else |
|
878 | - $model_object_data_for_update = $model_object_data; |
|
879 | - if ($model->has_primary_key_field()) { |
|
880 | - $conditions = array($model->primary_key_name() => $model_object_data[ $model->primary_key_name() ]); |
|
881 | - // remove the primary key because we shouldn't use it for updating |
|
882 | - unset($model_object_data_for_update[ $model->primary_key_name() ]); |
|
883 | - } elseif ($model->get_combined_primary_key_fields() > 1) { |
|
884 | - $conditions = array(); |
|
885 | - foreach ($model->get_combined_primary_key_fields() as $key_field) { |
|
886 | - $conditions[ $key_field->get_name() ] = $model_object_data[ $key_field->get_name() ]; |
|
887 | - } |
|
888 | - } else { |
|
889 | - $model->primary_key_name( |
|
890 | - );// this shoudl just throw an exception, explaining that we dont have a primary key (or a combine dkey) |
|
891 | - } |
|
892 | - |
|
893 | - $success = $model->update($model_object_data_for_update, array($conditions)); |
|
894 | - if ($success) { |
|
895 | - $this->_total_updates++; |
|
896 | - EE_Error::add_success( |
|
897 | - sprintf( |
|
898 | - esc_html__("Successfully updated %s with csv data %s", "event_espresso"), |
|
899 | - $model->get_this_model_name(), |
|
900 | - implode(",", $model_object_data_for_update) |
|
901 | - ) |
|
902 | - ); |
|
903 | - // we should still record the mapping even though it was an update |
|
904 | - // because if we were going to insert somethign but it was going to conflict |
|
905 | - // we would have last-minute decided to update. So we'd like to know what we updated |
|
906 | - // and so we record what record ended up being updated using the mapping |
|
907 | - if ($model->has_primary_key_field()) { |
|
908 | - $new_key_for_mapping = $model_object_data[ $model->primary_key_name() ]; |
|
909 | - } else { |
|
910 | - // no primary key just a combined key |
|
911 | - $new_key_for_mapping = $model->get_index_primary_key_string($model_object_data); |
|
912 | - } |
|
913 | - $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $id_in_csv ] = $new_key_for_mapping; |
|
914 | - } else { |
|
915 | - $matched_items = $model->get_all(array($conditions)); |
|
916 | - if (! $matched_items) { |
|
917 | - // no items were matched (so we shouldn't have updated)... but then we should have inserted? what the heck? |
|
918 | - $this->_total_update_errors++; |
|
919 | - EE_Error::add_error( |
|
920 | - sprintf( |
|
921 | - esc_html__( |
|
922 | - "Could not update %s with the csv data: '%s' for an unknown reason (using WHERE conditions %s)", |
|
923 | - "event_espresso" |
|
924 | - ), |
|
925 | - $model->get_this_model_name(), |
|
926 | - http_build_query($model_object_data), |
|
927 | - http_build_query($conditions) |
|
928 | - ), |
|
929 | - __FILE__, |
|
930 | - __FUNCTION__, |
|
931 | - __LINE__ |
|
932 | - ); |
|
933 | - } else { |
|
934 | - $this->_total_updates++; |
|
935 | - EE_Error::add_success( |
|
936 | - sprintf( |
|
937 | - esc_html__( |
|
938 | - "%s with csv data '%s' was found in the database and didn't need updating because all the data is identical.", |
|
939 | - "event_espresso" |
|
940 | - ), |
|
941 | - $model->get_this_model_name(), |
|
942 | - implode(",", $model_object_data) |
|
943 | - ) |
|
944 | - ); |
|
945 | - } |
|
946 | - } |
|
947 | - } catch (EE_Error $e) { |
|
948 | - $this->_total_update_errors++; |
|
949 | - $basic_message = sprintf( |
|
950 | - esc_html__("Could not update %s with the csv data: %s because %s", "event_espresso"), |
|
951 | - $model->get_this_model_name(), |
|
952 | - implode(",", $model_object_data), |
|
953 | - $e->getMessage() |
|
954 | - ); |
|
955 | - $debug_message = $basic_message . ' Stack trace: ' . $e->getTraceAsString(); |
|
956 | - EE_Error::add_error("$basic_message | $debug_message", __FILE__, __FUNCTION__, __LINE__); |
|
957 | - } |
|
958 | - return $old_db_to_new_db_mapping; |
|
959 | - } |
|
960 | - |
|
961 | - /** |
|
962 | - * Gets the number of inserts performed since importer was instantiated or reset |
|
963 | - * |
|
964 | - * @return int |
|
965 | - */ |
|
966 | - public function get_total_inserts() |
|
967 | - { |
|
968 | - return $this->_total_inserts; |
|
969 | - } |
|
970 | - |
|
971 | - /** |
|
972 | - * Gets the number of insert errors since importer was instantiated or reset |
|
973 | - * |
|
974 | - * @return int |
|
975 | - */ |
|
976 | - public function get_total_insert_errors() |
|
977 | - { |
|
978 | - return $this->_total_insert_errors; |
|
979 | - } |
|
980 | - |
|
981 | - /** |
|
982 | - * Gets the number of updates performed since importer was instantiated or reset |
|
983 | - * |
|
984 | - * @return int |
|
985 | - */ |
|
986 | - public function get_total_updates() |
|
987 | - { |
|
988 | - return $this->_total_updates; |
|
989 | - } |
|
990 | - |
|
991 | - /** |
|
992 | - * Gets the number of update errors since importer was instantiated or reset |
|
993 | - * |
|
994 | - * @return int |
|
995 | - */ |
|
996 | - public function get_total_update_errors() |
|
997 | - { |
|
998 | - return $this->_total_update_errors; |
|
999 | - } |
|
130 | + $uploader = ob_get_clean(); |
|
131 | + return $uploader; |
|
132 | + } |
|
133 | + |
|
134 | + |
|
135 | + /** |
|
136 | + * @Import Event Espresso data - some code "borrowed" from event espresso csv_import.php |
|
137 | + * @access public |
|
138 | + * @return boolean success |
|
139 | + */ |
|
140 | + public function import() |
|
141 | + { |
|
142 | + |
|
143 | + require_once(EE_CLASSES . 'EE_CSV.class.php'); |
|
144 | + $this->EE_CSV = EE_CSV::instance(); |
|
145 | + |
|
146 | + /** @var RequestInterface $request */ |
|
147 | + $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
148 | + |
|
149 | + if ($request->requestParamIsSet('import') && $request->requestParamIsSet('csv_submitted')) { |
|
150 | + $files = $request->filesParams(); |
|
151 | + switch ($files['file']['error'][0]) { |
|
152 | + case UPLOAD_ERR_OK: |
|
153 | + $error_msg = false; |
|
154 | + break; |
|
155 | + case UPLOAD_ERR_INI_SIZE: |
|
156 | + $error_msg = esc_html__( |
|
157 | + "'The uploaded file exceeds the upload_max_filesize directive in php.ini.'", |
|
158 | + "event_espresso" |
|
159 | + ); |
|
160 | + break; |
|
161 | + case UPLOAD_ERR_FORM_SIZE: |
|
162 | + $error_msg = esc_html__( |
|
163 | + 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.', |
|
164 | + "event_espresso" |
|
165 | + ); |
|
166 | + break; |
|
167 | + case UPLOAD_ERR_PARTIAL: |
|
168 | + $error_msg = esc_html__('The uploaded file was only partially uploaded.', "event_espresso"); |
|
169 | + break; |
|
170 | + case UPLOAD_ERR_NO_FILE: |
|
171 | + $error_msg = esc_html__('No file was uploaded.', "event_espresso"); |
|
172 | + break; |
|
173 | + case UPLOAD_ERR_NO_TMP_DIR: |
|
174 | + $error_msg = esc_html__('Missing a temporary folder.', "event_espresso"); |
|
175 | + break; |
|
176 | + case UPLOAD_ERR_CANT_WRITE: |
|
177 | + $error_msg = esc_html__('Failed to write file to disk.', "event_espresso"); |
|
178 | + break; |
|
179 | + case UPLOAD_ERR_EXTENSION: |
|
180 | + $error_msg = esc_html__('File upload stopped by extension.', "event_espresso"); |
|
181 | + break; |
|
182 | + default: |
|
183 | + $error_msg = esc_html__( |
|
184 | + 'An unknown error occurred and the file could not be uploaded', |
|
185 | + "event_espresso" |
|
186 | + ); |
|
187 | + break; |
|
188 | + } |
|
189 | + |
|
190 | + if (! $error_msg) { |
|
191 | + $filename = $files['file']['name'][0]; |
|
192 | + $file_ext = substr(strrchr($filename, '.'), 1); |
|
193 | + $file_type = $files['file']['type'][0]; |
|
194 | + $temp_file = $files['file']['tmp_name'][0]; |
|
195 | + $filesize = $files['file']['size'][0] / 1024;// convert from bytes to KB |
|
196 | + |
|
197 | + if ($file_ext == 'csv') { |
|
198 | + $max_upload = $this->EE_CSV->get_max_upload_size();// max upload size in KB |
|
199 | + if ($filesize < $max_upload || true) { |
|
200 | + $wp_upload_dir = str_replace(array('\\', '/'), '/', wp_upload_dir()); |
|
201 | + $path_to_file = $wp_upload_dir['basedir'] . '/espresso/' . $filename; |
|
202 | + |
|
203 | + if (move_uploaded_file($temp_file, $path_to_file)) { |
|
204 | + // convert csv to array |
|
205 | + $this->csv_array = $this->EE_CSV->import_csv_to_model_data_array($path_to_file); |
|
206 | + |
|
207 | + $action = $request->getRequestParam('action'); |
|
208 | + |
|
209 | + // was data successfully stored in an array? |
|
210 | + if (is_array($this->csv_array)) { |
|
211 | + $import_what = str_replace('csv_import_', '', $action); |
|
212 | + $import_what = str_replace('_', ' ', ucwords($import_what)); |
|
213 | + $processed_data = $this->csv_array; |
|
214 | + $this->columns_to_save = false; |
|
215 | + |
|
216 | + // if any imports require funky processing, we'll catch them in the switch |
|
217 | + switch ($action) { |
|
218 | + case "import_events": |
|
219 | + case "event_list": |
|
220 | + $import_what = 'Event Details'; |
|
221 | + break; |
|
222 | + |
|
223 | + case 'groupon_import_csv': |
|
224 | + $import_what = 'Groupon Codes'; |
|
225 | + $processed_data = $this->process_groupon_codes(); |
|
226 | + break; |
|
227 | + } |
|
228 | + // save processed codes to db |
|
229 | + if ($this->save_csv_data_array_to_db($processed_data, $this->columns_to_save)) { |
|
230 | + return true; |
|
231 | + } |
|
232 | + } else { |
|
233 | + // no array? must be an error |
|
234 | + EE_Error::add_error( |
|
235 | + sprintf(esc_html__("No file seems to have been uploaded", "event_espresso")), |
|
236 | + __FILE__, |
|
237 | + __FUNCTION__, |
|
238 | + __LINE__ |
|
239 | + ); |
|
240 | + return false; |
|
241 | + } |
|
242 | + } else { |
|
243 | + EE_Error::add_error( |
|
244 | + sprintf(esc_html__("%s was not successfully uploaded", "event_espresso"), $filename), |
|
245 | + __FILE__, |
|
246 | + __FUNCTION__, |
|
247 | + __LINE__ |
|
248 | + ); |
|
249 | + return false; |
|
250 | + } |
|
251 | + } else { |
|
252 | + EE_Error::add_error( |
|
253 | + sprintf( |
|
254 | + esc_html__( |
|
255 | + "%s was too large of a file and could not be uploaded. The max filesize is %s' KB.", |
|
256 | + "event_espresso" |
|
257 | + ), |
|
258 | + $filename, |
|
259 | + $max_upload |
|
260 | + ), |
|
261 | + __FILE__, |
|
262 | + __FUNCTION__, |
|
263 | + __LINE__ |
|
264 | + ); |
|
265 | + return false; |
|
266 | + } |
|
267 | + } else { |
|
268 | + EE_Error::add_error( |
|
269 | + sprintf(esc_html__("%s had an invalid file extension, not uploaded", "event_espresso"), $filename), |
|
270 | + __FILE__, |
|
271 | + __FUNCTION__, |
|
272 | + __LINE__ |
|
273 | + ); |
|
274 | + return false; |
|
275 | + } |
|
276 | + } else { |
|
277 | + EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__); |
|
278 | + return false; |
|
279 | + } |
|
280 | + } |
|
281 | + return false; |
|
282 | + } |
|
283 | + |
|
284 | + |
|
285 | + /** |
|
286 | + * Given an array of data (usually from a CSV import) attempts to save that data to the db. |
|
287 | + * If $model_name ISN'T provided, assumes that this is a 3d array, with toplevel keys being model names, |
|
288 | + * next level being numeric indexes adn each value representing a model object, and the last layer down |
|
289 | + * being keys of model fields and their proposed values. |
|
290 | + * If $model_name IS provided, assumes a 2d array of the bottom two layers previously mentioned. |
|
291 | + * If the CSV data says (in the metadata row) that it's from the SAME database, |
|
292 | + * we treat the IDs in the CSV as the normal IDs, and try to update those records. However, if those |
|
293 | + * IDs DON'T exist in the database, they're treated as temporary IDs, |
|
294 | + * which can used elsewhere to refer to the same object. Once an item |
|
295 | + * with a temporary ID gets inserted, we record its mapping from temporary |
|
296 | + * ID to real ID, and use the real ID in place of the temporary ID |
|
297 | + * when that temporary ID was used as a foreign key. |
|
298 | + * If the CSV data says (in the metadata again) that it's from a DIFFERENT database, |
|
299 | + * we treat all the IDs in the CSV as temporary ID- eg, if the CSV specifies an event with |
|
300 | + * ID 1, and the database already has an event with ID 1, we assume that's just a coincidence, |
|
301 | + * and insert a new event, and map it's temporary ID of 1 over to its new real ID. |
|
302 | + * An important exception are non-auto-increment primary keys. If one entry in the |
|
303 | + * CSV file has the same ID as one in the DB, we assume they are meant to be |
|
304 | + * the same item, and instead update the item in the DB with that same ID. |
|
305 | + * Also note, we remember the mappings permanently. So the 2nd, 3rd, and 10000th |
|
306 | + * time you import a CSV from a different site, we remember their mappings, and |
|
307 | + * will try to update the item in the DB instead of inserting another item (eg |
|
308 | + * if we previously imported an event with temporary ID 1, and then it got a |
|
309 | + * real ID of 123, we remember that. So the next time we import an event with |
|
310 | + * temporary ID, from the same site, we know that it's real ID is 123, and will |
|
311 | + * update that event, instead of adding a new event). |
|
312 | + * |
|
313 | + * @access public |
|
314 | + * @param array $csv_data_array - the array containing the csv data produced from |
|
315 | + * EE_CSV::import_csv_to_model_data_array() |
|
316 | + * @param array $fields_to_save - an array containing the csv column names as keys with the corresponding db table |
|
317 | + * fields they will be saved to |
|
318 | + * @return TRUE on success, FALSE on fail |
|
319 | + * @throws \EE_Error |
|
320 | + */ |
|
321 | + public function save_csv_data_array_to_db($csv_data_array, $model_name = false) |
|
322 | + { |
|
323 | + $success = false; |
|
324 | + $error = false; |
|
325 | + // whther to treat this import as if it's data froma different database or not |
|
326 | + // ie, if it IS from a different database, ignore foreign keys whihf |
|
327 | + $export_from_site_a_to_b = true; |
|
328 | + // first level of array is not table information but a table name was passed to the function |
|
329 | + // array is only two levels deep, so let's fix that by adding a level, else the next steps will fail |
|
330 | + if ($model_name) { |
|
331 | + $csv_data_array = array($csv_data_array); |
|
332 | + } |
|
333 | + // begin looking through the $csv_data_array, expecting the toplevel key to be the model's name... |
|
334 | + $old_site_url = 'none-specified'; |
|
335 | + // hanlde metadata |
|
336 | + if (isset($csv_data_array[ EE_CSV::metadata_header ])) { |
|
337 | + $csv_metadata = array_shift($csv_data_array[ EE_CSV::metadata_header ]); |
|
338 | + // ok so its metadata, dont try to save it to ehte db obviously... |
|
339 | + if (isset($csv_metadata['site_url']) && $csv_metadata['site_url'] == site_url()) { |
|
340 | + EE_Error::add_attention( |
|
341 | + sprintf( |
|
342 | + esc_html__( |
|
343 | + "CSV Data appears to be from the same database, so attempting to update data", |
|
344 | + "event_espresso" |
|
345 | + ) |
|
346 | + ) |
|
347 | + ); |
|
348 | + $export_from_site_a_to_b = false; |
|
349 | + } else { |
|
350 | + $old_site_url = isset($csv_metadata['site_url']) ? $csv_metadata['site_url'] : $old_site_url; |
|
351 | + EE_Error::add_attention( |
|
352 | + sprintf( |
|
353 | + esc_html__( |
|
354 | + "CSV Data appears to be from a different database (%s instead of %s), so we assume IDs in the CSV data DO NOT correspond to IDs in this database", |
|
355 | + "event_espresso" |
|
356 | + ), |
|
357 | + $old_site_url, |
|
358 | + site_url() |
|
359 | + ) |
|
360 | + ); |
|
361 | + }; |
|
362 | + unset($csv_data_array[ EE_CSV::metadata_header ]); |
|
363 | + } |
|
364 | + /** |
|
365 | + * @var $old_db_to_new_db_mapping 2d array: toplevel keys being model names, bottom-level keys being the original key, and |
|
366 | + * the value will be the newly-inserted ID. |
|
367 | + * If we have already imported data from the same website via CSV, it shoudl be kept in this wp option |
|
368 | + */ |
|
369 | + $old_db_to_new_db_mapping = get_option('ee_id_mapping_from' . sanitize_title($old_site_url), array()); |
|
370 | + if ($old_db_to_new_db_mapping) { |
|
371 | + EE_Error::add_attention( |
|
372 | + sprintf( |
|
373 | + esc_html__( |
|
374 | + "We noticed you have imported data via CSV from %s before. Because of this, IDs in your CSV have been mapped to their new IDs in %s", |
|
375 | + "event_espresso" |
|
376 | + ), |
|
377 | + $old_site_url, |
|
378 | + site_url() |
|
379 | + ) |
|
380 | + ); |
|
381 | + } |
|
382 | + $old_db_to_new_db_mapping = $this->save_data_rows_to_db( |
|
383 | + $csv_data_array, |
|
384 | + $export_from_site_a_to_b, |
|
385 | + $old_db_to_new_db_mapping |
|
386 | + ); |
|
387 | + |
|
388 | + // save the mapping from old db to new db in case they try re-importing the same data from the same website again |
|
389 | + update_option('ee_id_mapping_from' . sanitize_title($old_site_url), $old_db_to_new_db_mapping); |
|
390 | + |
|
391 | + if ($this->_total_updates > 0) { |
|
392 | + EE_Error::add_success( |
|
393 | + sprintf( |
|
394 | + esc_html__("%s existing records in the database were updated.", "event_espresso"), |
|
395 | + $this->_total_updates |
|
396 | + ) |
|
397 | + ); |
|
398 | + $success = true; |
|
399 | + } |
|
400 | + if ($this->_total_inserts > 0) { |
|
401 | + EE_Error::add_success( |
|
402 | + sprintf(esc_html__("%s new records were added to the database.", "event_espresso"), $this->_total_inserts) |
|
403 | + ); |
|
404 | + $success = true; |
|
405 | + } |
|
406 | + |
|
407 | + if ($this->_total_update_errors > 0) { |
|
408 | + EE_Error::add_error( |
|
409 | + sprintf( |
|
410 | + esc_html__( |
|
411 | + "'One or more errors occurred, and a total of %s existing records in the database were <strong>not</strong> updated.'", |
|
412 | + "event_espresso" |
|
413 | + ), |
|
414 | + $this->_total_update_errors |
|
415 | + ), |
|
416 | + __FILE__, |
|
417 | + __FUNCTION__, |
|
418 | + __LINE__ |
|
419 | + ); |
|
420 | + $error = true; |
|
421 | + } |
|
422 | + if ($this->_total_insert_errors > 0) { |
|
423 | + EE_Error::add_error( |
|
424 | + sprintf( |
|
425 | + esc_html__( |
|
426 | + "One or more errors occurred, and a total of %s new records were <strong>not</strong> added to the database.'", |
|
427 | + "event_espresso" |
|
428 | + ), |
|
429 | + $this->_total_insert_errors |
|
430 | + ), |
|
431 | + __FILE__, |
|
432 | + __FUNCTION__, |
|
433 | + __LINE__ |
|
434 | + ); |
|
435 | + $error = true; |
|
436 | + } |
|
437 | + |
|
438 | + // lastly, we need to update the datetime and ticket sold amounts |
|
439 | + // as those may have been affected by this |
|
440 | + EEM_Ticket::instance()->update_tickets_sold(EEM_Ticket::instance()->get_all()); |
|
441 | + |
|
442 | + // if there was at least one success and absolutely no errors |
|
443 | + if ($success && ! $error) { |
|
444 | + return true; |
|
445 | + } else { |
|
446 | + return false; |
|
447 | + } |
|
448 | + } |
|
449 | + |
|
450 | + |
|
451 | + /** |
|
452 | + * Processes the array of data, given the knowledge that it's from the same database or a different one, |
|
453 | + * and the mapping from temporary IDs to real IDs. |
|
454 | + * If the data is from a different database, we treat the primary keys and their corresponding |
|
455 | + * foreign keys as "temp Ids", basically identifiers that get mapped to real primary keys |
|
456 | + * in the real target database. As items are inserted, their temporary primary keys |
|
457 | + * are mapped to the real IDs in the target database. Also, before doing any update or |
|
458 | + * insert, we replace all the temp ID which are foreign keys with their mapped real IDs. |
|
459 | + * An exception: string primary keys are treated as real IDs, or else we'd need to |
|
460 | + * dynamically generate new string primary keys which would be very awkard for the country table etc. |
|
461 | + * Also, models with no primary key are strange too. We combine use their primar key INDEX (a |
|
462 | + * combination of fields) to create a unique string identifying the row and store |
|
463 | + * those in the mapping. |
|
464 | + * |
|
465 | + * If the data is from the same database, we usually treat primary keys as real IDs. |
|
466 | + * An exception is if there is nothing in the database for that ID. If that's the case, |
|
467 | + * we need to insert a new row for that ID, and then map from the non-existent ID |
|
468 | + * to the newly-inserted real ID. |
|
469 | + * |
|
470 | + * @param type $csv_data_array |
|
471 | + * @param type $export_from_site_a_to_b |
|
472 | + * @param type $old_db_to_new_db_mapping |
|
473 | + * @return array updated $old_db_to_new_db_mapping |
|
474 | + */ |
|
475 | + public function save_data_rows_to_db($csv_data_array, $export_from_site_a_to_b, $old_db_to_new_db_mapping) |
|
476 | + { |
|
477 | + foreach ($csv_data_array as $model_name_in_csv_data => $model_data_from_import) { |
|
478 | + // now check that assumption was correct. If |
|
479 | + if (EE_Registry::instance()->is_model_name($model_name_in_csv_data)) { |
|
480 | + $model_name = $model_name_in_csv_data; |
|
481 | + } else { |
|
482 | + // no table info in the array and no table name passed to the function?? FAIL |
|
483 | + EE_Error::add_error( |
|
484 | + esc_html__( |
|
485 | + 'No table information was specified and/or found, therefore the import could not be completed', |
|
486 | + 'event_espresso' |
|
487 | + ), |
|
488 | + __FILE__, |
|
489 | + __FUNCTION__, |
|
490 | + __LINE__ |
|
491 | + ); |
|
492 | + return false; |
|
493 | + } |
|
494 | + /* @var $model EEM_Base */ |
|
495 | + $model = EE_Registry::instance()->load_model($model_name); |
|
496 | + |
|
497 | + // so without further ado, scanning all the data provided for primary keys and their inital values |
|
498 | + foreach ($model_data_from_import as $model_object_data) { |
|
499 | + // before we do ANYTHING, make sure the csv row wasn't just completely blank |
|
500 | + $row_is_completely_empty = true; |
|
501 | + foreach ($model_object_data as $field) { |
|
502 | + if ($field) { |
|
503 | + $row_is_completely_empty = false; |
|
504 | + } |
|
505 | + } |
|
506 | + if ($row_is_completely_empty) { |
|
507 | + continue; |
|
508 | + } |
|
509 | + // find the PK in the row of data (or a combined key if |
|
510 | + // there is no primary key) |
|
511 | + if ($model->has_primary_key_field()) { |
|
512 | + $id_in_csv = $model_object_data[ $model->primary_key_name() ]; |
|
513 | + } else { |
|
514 | + $id_in_csv = $model->get_index_primary_key_string($model_object_data); |
|
515 | + } |
|
516 | + |
|
517 | + |
|
518 | + $model_object_data = $this->_replace_temp_ids_with_mappings( |
|
519 | + $model_object_data, |
|
520 | + $model, |
|
521 | + $old_db_to_new_db_mapping, |
|
522 | + $export_from_site_a_to_b |
|
523 | + ); |
|
524 | + // now we need to decide if we're going to add a new model object given the $model_object_data, |
|
525 | + // or just update. |
|
526 | + if ($export_from_site_a_to_b) { |
|
527 | + $what_to_do = $this->_decide_whether_to_insert_or_update_given_data_from_other_db( |
|
528 | + $id_in_csv, |
|
529 | + $model_object_data, |
|
530 | + $model, |
|
531 | + $old_db_to_new_db_mapping |
|
532 | + ); |
|
533 | + } else {// this is just a re-import |
|
534 | + $what_to_do = $this->_decide_whether_to_insert_or_update_given_data_from_same_db( |
|
535 | + $id_in_csv, |
|
536 | + $model_object_data, |
|
537 | + $model, |
|
538 | + $old_db_to_new_db_mapping |
|
539 | + ); |
|
540 | + } |
|
541 | + if ($what_to_do == self::do_nothing) { |
|
542 | + continue; |
|
543 | + } |
|
544 | + |
|
545 | + // double-check we actually want to insert, if that's what we're planning |
|
546 | + // based on whether this item would be unique in the DB or not |
|
547 | + if ($what_to_do == self::do_insert) { |
|
548 | + // we're supposed to be inserting. But wait, will this thing |
|
549 | + // be acceptable if inserted? |
|
550 | + $conflicting = $model->get_one_conflicting($model_object_data, false); |
|
551 | + if ($conflicting) { |
|
552 | + // ok, this item would conflict if inserted. Just update the item that it conflicts with. |
|
553 | + $what_to_do = self::do_update; |
|
554 | + // and if this model has a primary key, remember its mapping |
|
555 | + if ($model->has_primary_key_field()) { |
|
556 | + $old_db_to_new_db_mapping[ $model_name ][ $id_in_csv ] = $conflicting->ID(); |
|
557 | + $model_object_data[ $model->primary_key_name() ] = $conflicting->ID(); |
|
558 | + } else { |
|
559 | + // we want to update this conflicting item, instead of inserting a conflicting item |
|
560 | + // so we need to make sure they match entirely (its possible that they only conflicted on one field, but we need them to match on other fields |
|
561 | + // for the WHERE conditions in the update). At the time of this comment, there were no models like this |
|
562 | + foreach ($model->get_combined_primary_key_fields() as $key_field) { |
|
563 | + $model_object_data[ $key_field->get_name() ] = $conflicting->get( |
|
564 | + $key_field->get_name() |
|
565 | + ); |
|
566 | + } |
|
567 | + } |
|
568 | + } |
|
569 | + } |
|
570 | + if ($what_to_do == self::do_insert) { |
|
571 | + $old_db_to_new_db_mapping = $this->_insert_from_data_array( |
|
572 | + $id_in_csv, |
|
573 | + $model_object_data, |
|
574 | + $model, |
|
575 | + $old_db_to_new_db_mapping |
|
576 | + ); |
|
577 | + } elseif ($what_to_do == self::do_update) { |
|
578 | + $old_db_to_new_db_mapping = $this->_update_from_data_array( |
|
579 | + $id_in_csv, |
|
580 | + $model_object_data, |
|
581 | + $model, |
|
582 | + $old_db_to_new_db_mapping |
|
583 | + ); |
|
584 | + } else { |
|
585 | + throw new EE_Error( |
|
586 | + sprintf( |
|
587 | + esc_html__( |
|
588 | + 'Programming error. We shoudl be inserting or updating, but instead we are being told to "%s", whifh is invalid', |
|
589 | + 'event_espresso' |
|
590 | + ), |
|
591 | + $what_to_do |
|
592 | + ) |
|
593 | + ); |
|
594 | + } |
|
595 | + } |
|
596 | + } |
|
597 | + return $old_db_to_new_db_mapping; |
|
598 | + } |
|
599 | + |
|
600 | + |
|
601 | + /** |
|
602 | + * Decides whether or not to insert, given that this data is from another database. |
|
603 | + * So, if the primary key of this $model_object_data already exists in the database, |
|
604 | + * it's just a coincidence and we should still insert. The only time we should |
|
605 | + * update is when we know what it maps to, or there's something that would |
|
606 | + * conflict (and we should instead just update that conflicting thing) |
|
607 | + * |
|
608 | + * @param string $id_in_csv |
|
609 | + * @param array $model_object_data by reference so it can be modified |
|
610 | + * @param EEM_Base $model |
|
611 | + * @param array $old_db_to_new_db_mapping by reference so it can be modified |
|
612 | + * @return string one of the consts on this class that starts with do_* |
|
613 | + */ |
|
614 | + protected function _decide_whether_to_insert_or_update_given_data_from_other_db( |
|
615 | + $id_in_csv, |
|
616 | + $model_object_data, |
|
617 | + $model, |
|
618 | + $old_db_to_new_db_mapping |
|
619 | + ) { |
|
620 | + $model_name = $model->get_this_model_name(); |
|
621 | + // if it's a site-to-site export-and-import, see if this modelobject's id |
|
622 | + // in the old data that we know of |
|
623 | + if (isset($old_db_to_new_db_mapping[ $model_name ][ $id_in_csv ])) { |
|
624 | + return self::do_update; |
|
625 | + } else { |
|
626 | + return self::do_insert; |
|
627 | + } |
|
628 | + } |
|
629 | + |
|
630 | + /** |
|
631 | + * If this thing basically already exists in the database, we want to update it; |
|
632 | + * otherwise insert it (ie, someone tweaked the CSV file, or the item was |
|
633 | + * deleted in the database so it should be re-inserted) |
|
634 | + * |
|
635 | + * @param type $id_in_csv |
|
636 | + * @param type $model_object_data |
|
637 | + * @param EEM_Base $model |
|
638 | + * @param type $old_db_to_new_db_mapping |
|
639 | + * @return |
|
640 | + */ |
|
641 | + protected function _decide_whether_to_insert_or_update_given_data_from_same_db( |
|
642 | + $id_in_csv, |
|
643 | + $model_object_data, |
|
644 | + $model |
|
645 | + ) { |
|
646 | + // in this case, check if this thing ACTUALLY exists in the database |
|
647 | + if ($model->get_one_conflicting($model_object_data)) { |
|
648 | + return self::do_update; |
|
649 | + } else { |
|
650 | + return self::do_insert; |
|
651 | + } |
|
652 | + } |
|
653 | + |
|
654 | + /** |
|
655 | + * Using the $old_db_to_new_db_mapping array, replaces all the temporary IDs |
|
656 | + * with their mapped real IDs. Eg, if importing from site A to B, the mapping |
|
657 | + * file may indicate that the ID "my_event_id" maps to an actual event ID of 123. |
|
658 | + * So this function searches for any event temp Ids called "my_event_id" and |
|
659 | + * replaces them with 123. |
|
660 | + * Also, if there is no temp ID for the INT foreign keys from another database, |
|
661 | + * replaces them with 0 or the field's default. |
|
662 | + * |
|
663 | + * @param type $model_object_data |
|
664 | + * @param EEM_Base $model |
|
665 | + * @param type $old_db_to_new_db_mapping |
|
666 | + * @param boolean $export_from_site_a_to_b |
|
667 | + * @return array updated model object data with temp IDs removed |
|
668 | + */ |
|
669 | + protected function _replace_temp_ids_with_mappings( |
|
670 | + $model_object_data, |
|
671 | + $model, |
|
672 | + $old_db_to_new_db_mapping, |
|
673 | + $export_from_site_a_to_b |
|
674 | + ) { |
|
675 | + // if this model object's primary key is in the mapping, replace it |
|
676 | + if ( |
|
677 | + $model->has_primary_key_field() && |
|
678 | + $model->get_primary_key_field()->is_auto_increment() && |
|
679 | + isset($old_db_to_new_db_mapping[ $model->get_this_model_name() ]) && |
|
680 | + isset( |
|
681 | + $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $model_object_data[ $model->primary_key_name() ] ] |
|
682 | + ) |
|
683 | + ) { |
|
684 | + $model_object_data[ $model->primary_key_name() ] = $old_db_to_new_db_mapping[ $model->get_this_model_name( |
|
685 | + ) ][ $model_object_data[ $model->primary_key_name() ] ]; |
|
686 | + } |
|
687 | + |
|
688 | + try { |
|
689 | + $model_name_field = $model->get_field_containing_related_model_name(); |
|
690 | + $models_pointed_to_by_model_name_field = $model_name_field->get_model_names_pointed_to(); |
|
691 | + } catch (EE_Error $e) { |
|
692 | + $model_name_field = null; |
|
693 | + $models_pointed_to_by_model_name_field = array(); |
|
694 | + } |
|
695 | + foreach ($model->field_settings(true) as $field_obj) { |
|
696 | + if ($field_obj instanceof EE_Foreign_Key_Int_Field) { |
|
697 | + $models_pointed_to = $field_obj->get_model_names_pointed_to(); |
|
698 | + $found_a_mapping = false; |
|
699 | + foreach ($models_pointed_to as $model_pointed_to_by_fk) { |
|
700 | + if ($model_name_field) { |
|
701 | + $value_of_model_name_field = $model_object_data[ $model_name_field->get_name() ]; |
|
702 | + if ($value_of_model_name_field == $model_pointed_to_by_fk) { |
|
703 | + $model_object_data[ $field_obj->get_name() ] = $this->_find_mapping_in( |
|
704 | + $model_object_data[ $field_obj->get_name() ], |
|
705 | + $model_pointed_to_by_fk, |
|
706 | + $old_db_to_new_db_mapping, |
|
707 | + $export_from_site_a_to_b |
|
708 | + ); |
|
709 | + $found_a_mapping = true; |
|
710 | + break; |
|
711 | + } |
|
712 | + } else { |
|
713 | + $model_object_data[ $field_obj->get_name() ] = $this->_find_mapping_in( |
|
714 | + $model_object_data[ $field_obj->get_name() ], |
|
715 | + $model_pointed_to_by_fk, |
|
716 | + $old_db_to_new_db_mapping, |
|
717 | + $export_from_site_a_to_b |
|
718 | + ); |
|
719 | + $found_a_mapping = true; |
|
720 | + } |
|
721 | + // once we've found a mapping for this field no need to continue |
|
722 | + if ($found_a_mapping) { |
|
723 | + break; |
|
724 | + } |
|
725 | + } |
|
726 | + } else { |
|
727 | + // it's a string foreign key (which we leave alone, because those are things |
|
728 | + // like country names, which we'd really rather not make 2 USAs etc (we'd actually |
|
729 | + // prefer to just update one) |
|
730 | + // or it's just a regular value that ought to be replaced |
|
731 | + } |
|
732 | + } |
|
733 | + // |
|
734 | + if ($model instanceof EEM_Term_Taxonomy) { |
|
735 | + $model_object_data = $this->_handle_split_term_ids($model_object_data); |
|
736 | + } |
|
737 | + return $model_object_data; |
|
738 | + } |
|
739 | + |
|
740 | + /** |
|
741 | + * If the data was exported PRE-4.2, but then imported POST-4.2, then the term_id |
|
742 | + * this term-taxonomy refers to may be out-of-date so we need to update it. |
|
743 | + * see https://make.wordpress.org/core/2015/02/16/taxonomy-term-splitting-in-4-2-a-developer-guide/ |
|
744 | + * |
|
745 | + * @param type $model_object_data |
|
746 | + * @return array new model object data |
|
747 | + */ |
|
748 | + protected function _handle_split_term_ids($model_object_data) |
|
749 | + { |
|
750 | + if ( |
|
751 | + isset($model_object_data['term_id']) |
|
752 | + && isset($model_object_data['taxonomy']) |
|
753 | + && apply_filters( |
|
754 | + 'FHEE__EE_Import__handle_split_term_ids__function_exists', |
|
755 | + function_exists('wp_get_split_term'), |
|
756 | + $model_object_data |
|
757 | + ) |
|
758 | + ) { |
|
759 | + $new_term_id = wp_get_split_term($model_object_data['term_id'], $model_object_data['taxonomy']); |
|
760 | + if ($new_term_id) { |
|
761 | + $model_object_data['term_id'] = $new_term_id; |
|
762 | + } |
|
763 | + } |
|
764 | + return $model_object_data; |
|
765 | + } |
|
766 | + |
|
767 | + /** |
|
768 | + * Given the object's ID and its model's name, find it int he mapping data, |
|
769 | + * bearing in mind where it came from |
|
770 | + * |
|
771 | + * @param type $object_id |
|
772 | + * @param string $model_name |
|
773 | + * @param array $old_db_to_new_db_mapping |
|
774 | + * @param type $export_from_site_a_to_b |
|
775 | + * @return int |
|
776 | + */ |
|
777 | + protected function _find_mapping_in($object_id, $model_name, $old_db_to_new_db_mapping, $export_from_site_a_to_b) |
|
778 | + { |
|
779 | + if (isset($old_db_to_new_db_mapping[ $model_name ][ $object_id ])) { |
|
780 | + return $old_db_to_new_db_mapping[ $model_name ][ $object_id ]; |
|
781 | + } elseif ($object_id == '0' || $object_id == '') { |
|
782 | + // leave as-is |
|
783 | + return $object_id; |
|
784 | + } elseif ($export_from_site_a_to_b) { |
|
785 | + // we couldn't find a mapping for this, and it's from a different site, |
|
786 | + // so blank it out |
|
787 | + return null; |
|
788 | + } elseif (! $export_from_site_a_to_b) { |
|
789 | + // we coudln't find a mapping for this, but it's from thsi DB anyway |
|
790 | + // so let's just leave it as-is |
|
791 | + return $object_id; |
|
792 | + } |
|
793 | + } |
|
794 | + |
|
795 | + /** |
|
796 | + * |
|
797 | + * @param type $id_in_csv |
|
798 | + * @param type $model_object_data |
|
799 | + * @param EEM_Base $model |
|
800 | + * @param type $old_db_to_new_db_mapping |
|
801 | + * @return array updated $old_db_to_new_db_mapping |
|
802 | + */ |
|
803 | + protected function _insert_from_data_array($id_in_csv, $model_object_data, $model, $old_db_to_new_db_mapping) |
|
804 | + { |
|
805 | + // remove the primary key, if there is one (we don't want it for inserts OR updates) |
|
806 | + // we'll put it back in if we need it |
|
807 | + if ($model->has_primary_key_field() && $model->get_primary_key_field()->is_auto_increment()) { |
|
808 | + $effective_id = $model_object_data[ $model->primary_key_name() ]; |
|
809 | + unset($model_object_data[ $model->primary_key_name() ]); |
|
810 | + } else { |
|
811 | + $effective_id = $model->get_index_primary_key_string($model_object_data); |
|
812 | + } |
|
813 | + // the model takes care of validating the CSV's input |
|
814 | + try { |
|
815 | + $new_id = $model->insert($model_object_data); |
|
816 | + if ($new_id) { |
|
817 | + $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $id_in_csv ] = $new_id; |
|
818 | + $this->_total_inserts++; |
|
819 | + EE_Error::add_success( |
|
820 | + sprintf( |
|
821 | + esc_html__("Successfully added new %s (with id %s) with csv data %s", "event_espresso"), |
|
822 | + $model->get_this_model_name(), |
|
823 | + $new_id, |
|
824 | + implode(",", $model_object_data) |
|
825 | + ) |
|
826 | + ); |
|
827 | + } else { |
|
828 | + $this->_total_insert_errors++; |
|
829 | + // put the ID used back in there for the error message |
|
830 | + if ($model->has_primary_key_field()) { |
|
831 | + $model_object_data[ $model->primary_key_name() ] = $effective_id; |
|
832 | + } |
|
833 | + EE_Error::add_error( |
|
834 | + sprintf( |
|
835 | + esc_html__("Could not insert new %s with the csv data: %s", "event_espresso"), |
|
836 | + $model->get_this_model_name(), |
|
837 | + http_build_query($model_object_data) |
|
838 | + ), |
|
839 | + __FILE__, |
|
840 | + __FUNCTION__, |
|
841 | + __LINE__ |
|
842 | + ); |
|
843 | + } |
|
844 | + } catch (EE_Error $e) { |
|
845 | + $this->_total_insert_errors++; |
|
846 | + if ($model->has_primary_key_field()) { |
|
847 | + $model_object_data[ $model->primary_key_name() ] = $effective_id; |
|
848 | + } |
|
849 | + EE_Error::add_error( |
|
850 | + sprintf( |
|
851 | + esc_html__("Could not insert new %s with the csv data: %s because %s", "event_espresso"), |
|
852 | + $model->get_this_model_name(), |
|
853 | + implode(",", $model_object_data), |
|
854 | + $e->getMessage() |
|
855 | + ), |
|
856 | + __FILE__, |
|
857 | + __FUNCTION__, |
|
858 | + __LINE__ |
|
859 | + ); |
|
860 | + } |
|
861 | + return $old_db_to_new_db_mapping; |
|
862 | + } |
|
863 | + |
|
864 | + /** |
|
865 | + * Given the model object data, finds the row to update and updates it |
|
866 | + * |
|
867 | + * @param string|int $id_in_csv |
|
868 | + * @param array $model_object_data |
|
869 | + * @param EEM_Base $model |
|
870 | + * @param array $old_db_to_new_db_mapping |
|
871 | + * @return array updated $old_db_to_new_db_mapping |
|
872 | + */ |
|
873 | + protected function _update_from_data_array($id_in_csv, $model_object_data, $model, $old_db_to_new_db_mapping) |
|
874 | + { |
|
875 | + try { |
|
876 | + // let's keep two copies of the model object data: |
|
877 | + // one for performing an update, one for everthing else |
|
878 | + $model_object_data_for_update = $model_object_data; |
|
879 | + if ($model->has_primary_key_field()) { |
|
880 | + $conditions = array($model->primary_key_name() => $model_object_data[ $model->primary_key_name() ]); |
|
881 | + // remove the primary key because we shouldn't use it for updating |
|
882 | + unset($model_object_data_for_update[ $model->primary_key_name() ]); |
|
883 | + } elseif ($model->get_combined_primary_key_fields() > 1) { |
|
884 | + $conditions = array(); |
|
885 | + foreach ($model->get_combined_primary_key_fields() as $key_field) { |
|
886 | + $conditions[ $key_field->get_name() ] = $model_object_data[ $key_field->get_name() ]; |
|
887 | + } |
|
888 | + } else { |
|
889 | + $model->primary_key_name( |
|
890 | + );// this shoudl just throw an exception, explaining that we dont have a primary key (or a combine dkey) |
|
891 | + } |
|
892 | + |
|
893 | + $success = $model->update($model_object_data_for_update, array($conditions)); |
|
894 | + if ($success) { |
|
895 | + $this->_total_updates++; |
|
896 | + EE_Error::add_success( |
|
897 | + sprintf( |
|
898 | + esc_html__("Successfully updated %s with csv data %s", "event_espresso"), |
|
899 | + $model->get_this_model_name(), |
|
900 | + implode(",", $model_object_data_for_update) |
|
901 | + ) |
|
902 | + ); |
|
903 | + // we should still record the mapping even though it was an update |
|
904 | + // because if we were going to insert somethign but it was going to conflict |
|
905 | + // we would have last-minute decided to update. So we'd like to know what we updated |
|
906 | + // and so we record what record ended up being updated using the mapping |
|
907 | + if ($model->has_primary_key_field()) { |
|
908 | + $new_key_for_mapping = $model_object_data[ $model->primary_key_name() ]; |
|
909 | + } else { |
|
910 | + // no primary key just a combined key |
|
911 | + $new_key_for_mapping = $model->get_index_primary_key_string($model_object_data); |
|
912 | + } |
|
913 | + $old_db_to_new_db_mapping[ $model->get_this_model_name() ][ $id_in_csv ] = $new_key_for_mapping; |
|
914 | + } else { |
|
915 | + $matched_items = $model->get_all(array($conditions)); |
|
916 | + if (! $matched_items) { |
|
917 | + // no items were matched (so we shouldn't have updated)... but then we should have inserted? what the heck? |
|
918 | + $this->_total_update_errors++; |
|
919 | + EE_Error::add_error( |
|
920 | + sprintf( |
|
921 | + esc_html__( |
|
922 | + "Could not update %s with the csv data: '%s' for an unknown reason (using WHERE conditions %s)", |
|
923 | + "event_espresso" |
|
924 | + ), |
|
925 | + $model->get_this_model_name(), |
|
926 | + http_build_query($model_object_data), |
|
927 | + http_build_query($conditions) |
|
928 | + ), |
|
929 | + __FILE__, |
|
930 | + __FUNCTION__, |
|
931 | + __LINE__ |
|
932 | + ); |
|
933 | + } else { |
|
934 | + $this->_total_updates++; |
|
935 | + EE_Error::add_success( |
|
936 | + sprintf( |
|
937 | + esc_html__( |
|
938 | + "%s with csv data '%s' was found in the database and didn't need updating because all the data is identical.", |
|
939 | + "event_espresso" |
|
940 | + ), |
|
941 | + $model->get_this_model_name(), |
|
942 | + implode(",", $model_object_data) |
|
943 | + ) |
|
944 | + ); |
|
945 | + } |
|
946 | + } |
|
947 | + } catch (EE_Error $e) { |
|
948 | + $this->_total_update_errors++; |
|
949 | + $basic_message = sprintf( |
|
950 | + esc_html__("Could not update %s with the csv data: %s because %s", "event_espresso"), |
|
951 | + $model->get_this_model_name(), |
|
952 | + implode(",", $model_object_data), |
|
953 | + $e->getMessage() |
|
954 | + ); |
|
955 | + $debug_message = $basic_message . ' Stack trace: ' . $e->getTraceAsString(); |
|
956 | + EE_Error::add_error("$basic_message | $debug_message", __FILE__, __FUNCTION__, __LINE__); |
|
957 | + } |
|
958 | + return $old_db_to_new_db_mapping; |
|
959 | + } |
|
960 | + |
|
961 | + /** |
|
962 | + * Gets the number of inserts performed since importer was instantiated or reset |
|
963 | + * |
|
964 | + * @return int |
|
965 | + */ |
|
966 | + public function get_total_inserts() |
|
967 | + { |
|
968 | + return $this->_total_inserts; |
|
969 | + } |
|
970 | + |
|
971 | + /** |
|
972 | + * Gets the number of insert errors since importer was instantiated or reset |
|
973 | + * |
|
974 | + * @return int |
|
975 | + */ |
|
976 | + public function get_total_insert_errors() |
|
977 | + { |
|
978 | + return $this->_total_insert_errors; |
|
979 | + } |
|
980 | + |
|
981 | + /** |
|
982 | + * Gets the number of updates performed since importer was instantiated or reset |
|
983 | + * |
|
984 | + * @return int |
|
985 | + */ |
|
986 | + public function get_total_updates() |
|
987 | + { |
|
988 | + return $this->_total_updates; |
|
989 | + } |
|
990 | + |
|
991 | + /** |
|
992 | + * Gets the number of update errors since importer was instantiated or reset |
|
993 | + * |
|
994 | + * @return int |
|
995 | + */ |
|
996 | + public function get_total_update_errors() |
|
997 | + { |
|
998 | + return $this->_total_update_errors; |
|
999 | + } |
|
1000 | 1000 | } |
@@ -114,7 +114,7 @@ discard block |
||
114 | 114 | */ |
115 | 115 | public function set_question_form_input_meta($q_meta = []) |
116 | 116 | { |
117 | - $default_q_meta = [ |
|
117 | + $default_q_meta = [ |
|
118 | 118 | 'att_nmbr' => 1, |
119 | 119 | 'ticket_id' => '', |
120 | 120 | 'date' => '', |
@@ -160,13 +160,13 @@ discard block |
||
160 | 160 | */ |
161 | 161 | private function _set_input_name($qstn_id) |
162 | 162 | { |
163 | - if (! empty($qstn_id)) { |
|
163 | + if ( ! empty($qstn_id)) { |
|
164 | 164 | $ANS_ID = $this->get('ANS_ID'); |
165 | - $qstn_id = ! empty($ANS_ID) ? '[' . $qstn_id . '][' . $ANS_ID . ']' : '[' . $qstn_id . ']'; |
|
165 | + $qstn_id = ! empty($ANS_ID) ? '['.$qstn_id.']['.$ANS_ID.']' : '['.$qstn_id.']'; |
|
166 | 166 | } |
167 | 167 | $this->QST_input_name = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id) |
168 | - ? $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'] . $qstn_id |
|
169 | - : $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name']; |
|
168 | + ? $this->_QST_meta['input_prefix'].$this->_QST_meta['input_name'].$qstn_id |
|
169 | + : $this->_QST_meta['input_prefix'].$this->_QST_meta['input_name']; |
|
170 | 170 | } |
171 | 171 | |
172 | 172 | |
@@ -181,7 +181,7 @@ discard block |
||
181 | 181 | */ |
182 | 182 | public function get($property = null) |
183 | 183 | { |
184 | - if (! empty($property)) { |
|
184 | + if ( ! empty($property)) { |
|
185 | 185 | if (EEM_Question::instance()->has_field($property)) { |
186 | 186 | return $this->_QST->get($property); |
187 | 187 | } elseif (EEM_Answer::instance()->has_field($property)) { |
@@ -207,7 +207,7 @@ discard block |
||
207 | 207 | { |
208 | 208 | // first try regular property exists method which works as expected in PHP 5.3+ |
209 | 209 | $prop = EEH_Class_Tools::has_property($classname, $property); |
210 | - if (! $prop) { |
|
210 | + if ( ! $prop) { |
|
211 | 211 | // use reflection for < PHP 5.3 as a double check when property is not found, possible due to access restriction |
212 | 212 | $reflector = new ReflectionClass($classname); |
213 | 213 | $prop = $reflector->hasProperty($property); |
@@ -231,7 +231,7 @@ discard block |
||
231 | 231 | ? $this->_QST_meta['input_id'] |
232 | 232 | : sanitize_key(strip_tags($this->_QST->get('QST_display_text'))); |
233 | 233 | $this->QST_input_id = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id) |
234 | - ? $input_id . '-' . $qstn_id |
|
234 | + ? $input_id.'-'.$qstn_id |
|
235 | 235 | : $input_id; |
236 | 236 | } |
237 | 237 | |
@@ -272,8 +272,8 @@ discard block |
||
272 | 272 | $date = $this->_QST_meta['date']; |
273 | 273 | $time = $this->_QST_meta['time']; |
274 | 274 | $price_id = $this->_QST_meta['price_id']; |
275 | - if (isset($this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ])) { |
|
276 | - $answer = $this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ]; |
|
275 | + if (isset($this->form_data['qstn'][$EVT_ID][$att_nmbr][$date][$time][$price_id][$qstn_id])) { |
|
276 | + $answer = $this->form_data['qstn'][$EVT_ID][$att_nmbr][$date][$time][$price_id][$qstn_id]; |
|
277 | 277 | $this->_ANS->set('ANS_value', $answer); |
278 | 278 | } |
279 | 279 | } |
@@ -292,42 +292,42 @@ discard block |
||
292 | 292 | */ |
293 | 293 | public static function generate_question_form_inputs_for_object($object = false, $input_types = []) |
294 | 294 | { |
295 | - if (! is_object($object)) { |
|
295 | + if ( ! is_object($object)) { |
|
296 | 296 | return []; |
297 | 297 | } |
298 | 298 | $inputs = []; |
299 | 299 | $fields = $object->get_model()->field_settings(false); |
300 | 300 | foreach ($fields as $field_ID => $field) { |
301 | 301 | if ($field instanceof EE_Model_Field_Base) { |
302 | - if (isset($input_types[ $field_ID ])) { |
|
302 | + if (isset($input_types[$field_ID])) { |
|
303 | 303 | // get saved value for field |
304 | 304 | $value = $object->get($field_ID); |
305 | 305 | // if no saved value, then use default |
306 | 306 | $value = $value !== null ? $value : $field->get_default_value(); |
307 | 307 | // determine question type |
308 | - $type = isset($input_types[ $field_ID ]) ? $input_types[ $field_ID ]['type'] : 'TEXT'; |
|
308 | + $type = isset($input_types[$field_ID]) ? $input_types[$field_ID]['type'] : 'TEXT'; |
|
309 | 309 | // input name |
310 | - $input_name = isset($input_types[ $field_ID ]) && isset($input_types[ $field_ID ]['input_name']) |
|
311 | - ? $input_types[ $field_ID ]['input_name'] . '[' . $field_ID . ']' |
|
310 | + $input_name = isset($input_types[$field_ID]) && isset($input_types[$field_ID]['input_name']) |
|
311 | + ? $input_types[$field_ID]['input_name'].'['.$field_ID.']' |
|
312 | 312 | : $field_ID; |
313 | 313 | // css class for input |
314 | - $class = isset($input_types[ $field_ID ]['class']) && ! empty($input_types[ $field_ID ]['class']) |
|
315 | - ? ' ' . $input_types[ $field_ID ]['class'] |
|
314 | + $class = isset($input_types[$field_ID]['class']) && ! empty($input_types[$field_ID]['class']) |
|
315 | + ? ' '.$input_types[$field_ID]['class'] |
|
316 | 316 | : ''; |
317 | 317 | // whether to apply htmlentities to answer |
318 | - $htmlentities = isset($input_types[ $field_ID ]['htmlentities']) |
|
319 | - ? $input_types[ $field_ID ]['htmlentities'] |
|
318 | + $htmlentities = isset($input_types[$field_ID]['htmlentities']) |
|
319 | + ? $input_types[$field_ID]['htmlentities'] |
|
320 | 320 | : true; |
321 | 321 | // whether to apply htmlentities to answer |
322 | - $label_b4 = isset($input_types[ $field_ID ]['label_b4']) |
|
323 | - ? $input_types[ $field_ID ]['label_b4'] |
|
322 | + $label_b4 = isset($input_types[$field_ID]['label_b4']) |
|
323 | + ? $input_types[$field_ID]['label_b4'] |
|
324 | 324 | : false; |
325 | 325 | // whether to apply htmlentities to answer |
326 | - $use_desc_4_label = isset($input_types[ $field_ID ]['use_desc_4_label']) |
|
327 | - ? $input_types[ $field_ID ]['use_desc_4_label'] |
|
326 | + $use_desc_4_label = isset($input_types[$field_ID]['use_desc_4_label']) |
|
327 | + ? $input_types[$field_ID]['use_desc_4_label'] |
|
328 | 328 | : false; |
329 | 329 | // whether input is disabled |
330 | - $disabled = isset($input_types[ $field_ID ]['disabled']) && $input_types[ $field_ID ]['disabled']; |
|
330 | + $disabled = isset($input_types[$field_ID]['disabled']) && $input_types[$field_ID]['disabled']; |
|
331 | 331 | |
332 | 332 | // create EE_Question_Form_Input object |
333 | 333 | $QFI = new EE_Question_Form_Input( |
@@ -347,9 +347,9 @@ discard block |
||
347 | 347 | ] |
348 | 348 | ), |
349 | 349 | [ |
350 | - 'input_id' => $field_ID . '-' . $object->ID(), |
|
350 | + 'input_id' => $field_ID.'-'.$object->ID(), |
|
351 | 351 | 'input_name' => $input_name, |
352 | - 'input_class' => $field_ID . $class, |
|
352 | + 'input_class' => $field_ID.$class, |
|
353 | 353 | 'input_prefix' => '', |
354 | 354 | 'append_qstn_id' => false, |
355 | 355 | 'htmlentities' => $htmlentities, |
@@ -360,10 +360,10 @@ discard block |
||
360 | 360 | // does question type have options ? |
361 | 361 | if ( |
362 | 362 | in_array($type, ['DROPDOWN', 'RADIO_BTN', 'CHECKBOX']) |
363 | - && isset($input_types[ $field_ID ]) |
|
364 | - && isset($input_types[ $field_ID ]['options']) |
|
363 | + && isset($input_types[$field_ID]) |
|
364 | + && isset($input_types[$field_ID]['options']) |
|
365 | 365 | ) { |
366 | - foreach ($input_types[ $field_ID ]['options'] as $option) { |
|
366 | + foreach ($input_types[$field_ID]['options'] as $option) { |
|
367 | 367 | $option = stripslashes_deep($option); |
368 | 368 | $option_id = ! empty($option['id']) ? $option['id'] : 0; |
369 | 369 | $QSO = EE_Question_Option::new_instance( |
@@ -381,7 +381,7 @@ discard block |
||
381 | 381 | if ($disabled || $field_ID == $object->get_model()->primary_key_name()) { |
382 | 382 | $QFI->set('QST_disabled', true); |
383 | 383 | } |
384 | - $inputs[ $field_ID ] = $QFI; |
|
384 | + $inputs[$field_ID] = $QFI; |
|
385 | 385 | } |
386 | 386 | } |
387 | 387 | } |
@@ -414,7 +414,7 @@ discard block |
||
414 | 414 | */ |
415 | 415 | public function set($property = null, $value = null) |
416 | 416 | { |
417 | - if (! empty($property)) { |
|
417 | + if ( ! empty($property)) { |
|
418 | 418 | if (EEM_Question::instance()->has_field($property)) { |
419 | 419 | $this->_QST->set($property, $value); |
420 | 420 | } elseif (EEM_Answer::instance()->has_field($property)) { |
@@ -460,6 +460,6 @@ discard block |
||
460 | 460 | */ |
461 | 461 | public function get_meta($key = false) |
462 | 462 | { |
463 | - return $key && isset($this->_QST_meta[ $key ]) ? $this->_QST_meta[ $key ] : false; |
|
463 | + return $key && isset($this->_QST_meta[$key]) ? $this->_QST_meta[$key] : false; |
|
464 | 464 | } |
465 | 465 | } |
@@ -15,450 +15,450 @@ |
||
15 | 15 | */ |
16 | 16 | class EE_Question_Form_Input |
17 | 17 | { |
18 | - /** |
|
19 | - * EE_Question object |
|
20 | - * |
|
21 | - * @access private |
|
22 | - * @var object |
|
23 | - */ |
|
24 | - private $_QST = null; |
|
25 | - |
|
26 | - /** |
|
27 | - * EE_Answer object |
|
28 | - * |
|
29 | - * @access private |
|
30 | - * @var object |
|
31 | - */ |
|
32 | - private $_ANS = null; |
|
33 | - |
|
34 | - /** |
|
35 | - * $_QST_meta |
|
36 | - * @access private |
|
37 | - * @var array |
|
38 | - */ |
|
39 | - private $_QST_meta = []; |
|
40 | - |
|
41 | - /** |
|
42 | - * $QST_input_name |
|
43 | - * @access private |
|
44 | - * @var string |
|
45 | - */ |
|
46 | - private $QST_input_name = ''; |
|
47 | - |
|
48 | - /** |
|
49 | - * $QST_input_id |
|
50 | - * @access private |
|
51 | - * @var string |
|
52 | - */ |
|
53 | - private $QST_input_id = ''; |
|
54 | - |
|
55 | - /** |
|
56 | - * $QST_input_class |
|
57 | - * @access private |
|
58 | - * @var string |
|
59 | - */ |
|
60 | - private $QST_input_class = ''; |
|
61 | - |
|
62 | - /** |
|
63 | - * @var bool $QST_disabled |
|
64 | - */ |
|
65 | - private $QST_disabled = false; |
|
66 | - |
|
67 | - /** |
|
68 | - * @var RequestInterface |
|
69 | - */ |
|
70 | - protected $request; |
|
71 | - |
|
72 | - /** |
|
73 | - * @var array |
|
74 | - */ |
|
75 | - protected $form_data; |
|
76 | - |
|
77 | - |
|
78 | - /** |
|
79 | - * constructor for questions |
|
80 | - * |
|
81 | - * @param EE_Question $QST EE_Question object |
|
82 | - * @param EE_Answer $ANS EE_Answer object |
|
83 | - * @param array $q_meta |
|
84 | - * @throws EE_Error |
|
85 | - * @throws ReflectionException |
|
86 | - */ |
|
87 | - public function __construct(EE_Question $QST = null, EE_Answer $ANS = null, $q_meta = []) |
|
88 | - { |
|
89 | - $this->request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
90 | - $this->form_data = $this->request->requestParams(); |
|
91 | - if (empty($QST) || empty($ANS)) { |
|
92 | - EE_Error::add_error( |
|
93 | - esc_html__('An error occurred. A valid EE_Question or EE_Answer object was not received.', 'event_espresso'), |
|
94 | - __FILE__, |
|
95 | - __FUNCTION__, |
|
96 | - __LINE__ |
|
97 | - ); |
|
98 | - return null; |
|
99 | - } |
|
100 | - $this->_QST = $QST; |
|
101 | - $this->_ANS = $ANS; |
|
102 | - $this->set_question_form_input_meta($q_meta); |
|
103 | - $this->set_question_form_input_init(); |
|
104 | - } |
|
105 | - |
|
106 | - |
|
107 | - /** |
|
108 | - * sets meta data for the question form input |
|
109 | - * |
|
110 | - * @access public |
|
111 | - * @param array $q_meta |
|
112 | - * @return void |
|
113 | - */ |
|
114 | - public function set_question_form_input_meta($q_meta = []) |
|
115 | - { |
|
116 | - $default_q_meta = [ |
|
117 | - 'att_nmbr' => 1, |
|
118 | - 'ticket_id' => '', |
|
119 | - 'date' => '', |
|
120 | - 'time' => '', |
|
121 | - 'input_name' => '', |
|
122 | - 'input_id' => '', |
|
123 | - 'input_class' => '', |
|
124 | - 'input_prefix' => 'qstn', |
|
125 | - 'append_qstn_id' => true, |
|
126 | - 'htmlentities' => true, |
|
127 | - 'allow_null' => false, |
|
128 | - ]; |
|
129 | - $this->_QST_meta = array_merge($default_q_meta, $q_meta); |
|
130 | - } |
|
131 | - |
|
132 | - |
|
133 | - /** |
|
134 | - * set_question_form_input_init |
|
135 | - * |
|
136 | - * @access public |
|
137 | - * @return void |
|
138 | - * @throws EE_Error |
|
139 | - * @throws ReflectionException |
|
140 | - */ |
|
141 | - public function set_question_form_input_init() |
|
142 | - { |
|
143 | - $qstn_id = $this->_QST->system_ID() ? $this->_QST->system_ID() : $this->_QST->ID(); |
|
144 | - $this->_set_input_name($qstn_id); |
|
145 | - $this->_set_input_id($qstn_id); |
|
146 | - $this->_set_input_class(); |
|
147 | - $this->set_question_form_input_answer($qstn_id); |
|
148 | - } |
|
149 | - |
|
150 | - |
|
151 | - /** |
|
152 | - * set_input_name |
|
153 | - * |
|
154 | - * @access private |
|
155 | - * @param $qstn_id |
|
156 | - * @return void |
|
157 | - * @throws EE_Error |
|
158 | - * @throws ReflectionException |
|
159 | - */ |
|
160 | - private function _set_input_name($qstn_id) |
|
161 | - { |
|
162 | - if (! empty($qstn_id)) { |
|
163 | - $ANS_ID = $this->get('ANS_ID'); |
|
164 | - $qstn_id = ! empty($ANS_ID) ? '[' . $qstn_id . '][' . $ANS_ID . ']' : '[' . $qstn_id . ']'; |
|
165 | - } |
|
166 | - $this->QST_input_name = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id) |
|
167 | - ? $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'] . $qstn_id |
|
168 | - : $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name']; |
|
169 | - } |
|
170 | - |
|
171 | - |
|
172 | - /** |
|
173 | - * get property values for question form input |
|
174 | - * |
|
175 | - * @access public |
|
176 | - * @param string $property |
|
177 | - * @return mixed |
|
178 | - * @throws EE_Error |
|
179 | - * @throws ReflectionException |
|
180 | - */ |
|
181 | - public function get($property = null) |
|
182 | - { |
|
183 | - if (! empty($property)) { |
|
184 | - if (EEM_Question::instance()->has_field($property)) { |
|
185 | - return $this->_QST->get($property); |
|
186 | - } elseif (EEM_Answer::instance()->has_field($property)) { |
|
187 | - return $this->_ANS->get($property); |
|
188 | - } elseif ($this->_question_form_input_property_exists(__CLASS__, $property)) { |
|
189 | - return $this->{$property}; |
|
190 | - } |
|
191 | - } |
|
192 | - return null; |
|
193 | - } |
|
194 | - |
|
195 | - |
|
196 | - /** |
|
197 | - * _question_form_input_property_exists |
|
198 | - * |
|
199 | - * @access private |
|
200 | - * @param string $classname |
|
201 | - * @param string $property |
|
202 | - * @return boolean |
|
203 | - * @throws ReflectionException |
|
204 | - */ |
|
205 | - private function _question_form_input_property_exists($classname, $property) |
|
206 | - { |
|
207 | - // first try regular property exists method which works as expected in PHP 5.3+ |
|
208 | - $prop = EEH_Class_Tools::has_property($classname, $property); |
|
209 | - if (! $prop) { |
|
210 | - // use reflection for < PHP 5.3 as a double check when property is not found, possible due to access restriction |
|
211 | - $reflector = new ReflectionClass($classname); |
|
212 | - $prop = $reflector->hasProperty($property); |
|
213 | - } |
|
214 | - return $prop; |
|
215 | - } |
|
216 | - |
|
217 | - |
|
218 | - /** |
|
219 | - * set_input_id |
|
220 | - * |
|
221 | - * @access private |
|
222 | - * @param $qstn_id |
|
223 | - * @return void |
|
224 | - * @throws EE_Error |
|
225 | - * @throws ReflectionException |
|
226 | - */ |
|
227 | - private function _set_input_id($qstn_id) |
|
228 | - { |
|
229 | - $input_id = isset($this->_QST_meta['input_id']) && ! empty($this->_QST_meta['input_id']) |
|
230 | - ? $this->_QST_meta['input_id'] |
|
231 | - : sanitize_key(strip_tags($this->_QST->get('QST_display_text'))); |
|
232 | - $this->QST_input_id = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id) |
|
233 | - ? $input_id . '-' . $qstn_id |
|
234 | - : $input_id; |
|
235 | - } |
|
236 | - |
|
237 | - |
|
238 | - /** |
|
239 | - * set_input_class |
|
240 | - * |
|
241 | - * @access private |
|
242 | - * @return void |
|
243 | - */ |
|
244 | - private function _set_input_class() |
|
245 | - { |
|
246 | - $this->QST_input_class = isset($this->_QST_meta['input_class']) ? $this->_QST_meta['input_class'] : ''; |
|
247 | - } |
|
248 | - |
|
249 | - |
|
250 | - /** |
|
251 | - * set_question_form_input_answer |
|
252 | - * |
|
253 | - * @access public |
|
254 | - * @param mixed int | string $qstn_id |
|
255 | - * @return void |
|
256 | - * @throws EE_Error |
|
257 | - * @throws ReflectionException |
|
258 | - */ |
|
259 | - public function set_question_form_input_answer($qstn_id) |
|
260 | - { |
|
261 | - // check for answer in $this->form_data in case we are reprocessing a form after an error |
|
262 | - if ( |
|
263 | - isset($this->_QST_meta['EVT_ID']) |
|
264 | - && isset($this->_QST_meta['att_nmbr']) |
|
265 | - && isset($this->_QST_meta['date']) |
|
266 | - && isset($this->_QST_meta['time']) |
|
267 | - && isset($this->_QST_meta['price_id']) |
|
268 | - ) { |
|
269 | - $EVT_ID = $this->_QST_meta['EVT_ID']; |
|
270 | - $att_nmbr = $this->_QST_meta['att_nmbr']; |
|
271 | - $date = $this->_QST_meta['date']; |
|
272 | - $time = $this->_QST_meta['time']; |
|
273 | - $price_id = $this->_QST_meta['price_id']; |
|
274 | - if (isset($this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ])) { |
|
275 | - $answer = $this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ]; |
|
276 | - $this->_ANS->set('ANS_value', $answer); |
|
277 | - } |
|
278 | - } |
|
279 | - } |
|
280 | - |
|
281 | - |
|
282 | - /** |
|
283 | - * generate_question_form_inputs_for_object |
|
284 | - * |
|
285 | - * @access protected |
|
286 | - * @param bool|object $object $object |
|
287 | - * @param array $input_types |
|
288 | - * @return array |
|
289 | - * @throws EE_Error |
|
290 | - * @throws ReflectionException |
|
291 | - */ |
|
292 | - public static function generate_question_form_inputs_for_object($object = false, $input_types = []) |
|
293 | - { |
|
294 | - if (! is_object($object)) { |
|
295 | - return []; |
|
296 | - } |
|
297 | - $inputs = []; |
|
298 | - $fields = $object->get_model()->field_settings(false); |
|
299 | - foreach ($fields as $field_ID => $field) { |
|
300 | - if ($field instanceof EE_Model_Field_Base) { |
|
301 | - if (isset($input_types[ $field_ID ])) { |
|
302 | - // get saved value for field |
|
303 | - $value = $object->get($field_ID); |
|
304 | - // if no saved value, then use default |
|
305 | - $value = $value !== null ? $value : $field->get_default_value(); |
|
306 | - // determine question type |
|
307 | - $type = isset($input_types[ $field_ID ]) ? $input_types[ $field_ID ]['type'] : 'TEXT'; |
|
308 | - // input name |
|
309 | - $input_name = isset($input_types[ $field_ID ]) && isset($input_types[ $field_ID ]['input_name']) |
|
310 | - ? $input_types[ $field_ID ]['input_name'] . '[' . $field_ID . ']' |
|
311 | - : $field_ID; |
|
312 | - // css class for input |
|
313 | - $class = isset($input_types[ $field_ID ]['class']) && ! empty($input_types[ $field_ID ]['class']) |
|
314 | - ? ' ' . $input_types[ $field_ID ]['class'] |
|
315 | - : ''; |
|
316 | - // whether to apply htmlentities to answer |
|
317 | - $htmlentities = isset($input_types[ $field_ID ]['htmlentities']) |
|
318 | - ? $input_types[ $field_ID ]['htmlentities'] |
|
319 | - : true; |
|
320 | - // whether to apply htmlentities to answer |
|
321 | - $label_b4 = isset($input_types[ $field_ID ]['label_b4']) |
|
322 | - ? $input_types[ $field_ID ]['label_b4'] |
|
323 | - : false; |
|
324 | - // whether to apply htmlentities to answer |
|
325 | - $use_desc_4_label = isset($input_types[ $field_ID ]['use_desc_4_label']) |
|
326 | - ? $input_types[ $field_ID ]['use_desc_4_label'] |
|
327 | - : false; |
|
328 | - // whether input is disabled |
|
329 | - $disabled = isset($input_types[ $field_ID ]['disabled']) && $input_types[ $field_ID ]['disabled']; |
|
330 | - |
|
331 | - // create EE_Question_Form_Input object |
|
332 | - $QFI = new EE_Question_Form_Input( |
|
333 | - EE_Question::new_instance( |
|
334 | - [ |
|
335 | - 'QST_ID' => 0, |
|
336 | - 'QST_display_text' => $field->get_nicename(), |
|
337 | - 'QST_type' => $type, |
|
338 | - ] |
|
339 | - ), |
|
340 | - EE_Answer::new_instance( |
|
341 | - [ |
|
342 | - 'ANS_ID' => 0, |
|
343 | - 'QST_ID' => 0, |
|
344 | - 'REG_ID' => 0, |
|
345 | - 'ANS_value' => $value, |
|
346 | - ] |
|
347 | - ), |
|
348 | - [ |
|
349 | - 'input_id' => $field_ID . '-' . $object->ID(), |
|
350 | - 'input_name' => $input_name, |
|
351 | - 'input_class' => $field_ID . $class, |
|
352 | - 'input_prefix' => '', |
|
353 | - 'append_qstn_id' => false, |
|
354 | - 'htmlentities' => $htmlentities, |
|
355 | - 'label_b4' => $label_b4, |
|
356 | - 'use_desc_4_label' => $use_desc_4_label, |
|
357 | - ] |
|
358 | - ); |
|
359 | - // does question type have options ? |
|
360 | - if ( |
|
361 | - in_array($type, ['DROPDOWN', 'RADIO_BTN', 'CHECKBOX']) |
|
362 | - && isset($input_types[ $field_ID ]) |
|
363 | - && isset($input_types[ $field_ID ]['options']) |
|
364 | - ) { |
|
365 | - foreach ($input_types[ $field_ID ]['options'] as $option) { |
|
366 | - $option = stripslashes_deep($option); |
|
367 | - $option_id = ! empty($option['id']) ? $option['id'] : 0; |
|
368 | - $QSO = EE_Question_Option::new_instance( |
|
369 | - [ |
|
370 | - 'QSO_value' => (string) $option_id, |
|
371 | - 'QSO_desc' => $option['text'], |
|
372 | - 'QSO_deleted' => false, |
|
373 | - ] |
|
374 | - ); |
|
375 | - // all QST (and ANS) properties can be accessed indirectly thru QFI |
|
376 | - $QFI->add_temp_option($QSO); |
|
377 | - } |
|
378 | - } |
|
379 | - // we don't want ppl manually changing primary keys cuz that would just lead to total craziness man |
|
380 | - if ($disabled || $field_ID == $object->get_model()->primary_key_name()) { |
|
381 | - $QFI->set('QST_disabled', true); |
|
382 | - } |
|
383 | - $inputs[ $field_ID ] = $QFI; |
|
384 | - } |
|
385 | - } |
|
386 | - } |
|
387 | - return $inputs; |
|
388 | - } |
|
389 | - |
|
390 | - |
|
391 | - /** |
|
392 | - * add_temp_option |
|
393 | - * |
|
394 | - * @access public |
|
395 | - * @param EE_Question_Option $QSO EE_Question_Option |
|
396 | - * @return void |
|
397 | - */ |
|
398 | - public function add_temp_option(EE_Question_Option $QSO) |
|
399 | - { |
|
400 | - $this->_QST->add_temp_option($QSO); |
|
401 | - } |
|
402 | - |
|
403 | - |
|
404 | - /** |
|
405 | - * set property values for question form input |
|
406 | - * |
|
407 | - * @access public |
|
408 | - * @param string $property |
|
409 | - * @param mixed $value |
|
410 | - * @return void |
|
411 | - * @throws EE_Error |
|
412 | - * @throws ReflectionException |
|
413 | - */ |
|
414 | - public function set($property = null, $value = null) |
|
415 | - { |
|
416 | - if (! empty($property)) { |
|
417 | - if (EEM_Question::instance()->has_field($property)) { |
|
418 | - $this->_QST->set($property, $value); |
|
419 | - } elseif (EEM_Answer::instance()->has_field($property)) { |
|
420 | - $this->_ANS->set($property, $value); |
|
421 | - } elseif ($this->_question_form_input_property_exists(__CLASS__, $property)) { |
|
422 | - $this->{$property} = $value; |
|
423 | - } |
|
424 | - } |
|
425 | - } |
|
426 | - |
|
427 | - |
|
428 | - /** |
|
429 | - * _question_form_input_property_exists |
|
430 | - * |
|
431 | - * @access public |
|
432 | - * @param boolean $notDeletedOptionsOnly 1 |
|
433 | - * whether to return ALL options, or only the ones which have |
|
434 | - * not yet been deleted |
|
435 | - * @param string|array $selected_value_to_always_include , when retrieving options to an ANSWERED question, |
|
436 | - * we want to usually only show non-deleted options AND the |
|
437 | - * value that was selected for the answer, whether it was |
|
438 | - * trashed or not. |
|
439 | - * @return EE_Question_Option |
|
440 | - */ |
|
441 | - public function options($notDeletedOptionsOnly = true, $selected_value_to_always_include = null) |
|
442 | - { |
|
443 | - $temp_options = $this->_QST->temp_options(); |
|
444 | - return ! empty($temp_options) |
|
445 | - ? $temp_options |
|
446 | - : $this->_QST->options( |
|
447 | - $notDeletedOptionsOnly, |
|
448 | - $selected_value_to_always_include |
|
449 | - ); |
|
450 | - } |
|
451 | - |
|
452 | - |
|
453 | - /** |
|
454 | - * get_meta |
|
455 | - * |
|
456 | - * @access public |
|
457 | - * @param mixed $key |
|
458 | - * @return mixed |
|
459 | - */ |
|
460 | - public function get_meta($key = false) |
|
461 | - { |
|
462 | - return $key && isset($this->_QST_meta[ $key ]) ? $this->_QST_meta[ $key ] : false; |
|
463 | - } |
|
18 | + /** |
|
19 | + * EE_Question object |
|
20 | + * |
|
21 | + * @access private |
|
22 | + * @var object |
|
23 | + */ |
|
24 | + private $_QST = null; |
|
25 | + |
|
26 | + /** |
|
27 | + * EE_Answer object |
|
28 | + * |
|
29 | + * @access private |
|
30 | + * @var object |
|
31 | + */ |
|
32 | + private $_ANS = null; |
|
33 | + |
|
34 | + /** |
|
35 | + * $_QST_meta |
|
36 | + * @access private |
|
37 | + * @var array |
|
38 | + */ |
|
39 | + private $_QST_meta = []; |
|
40 | + |
|
41 | + /** |
|
42 | + * $QST_input_name |
|
43 | + * @access private |
|
44 | + * @var string |
|
45 | + */ |
|
46 | + private $QST_input_name = ''; |
|
47 | + |
|
48 | + /** |
|
49 | + * $QST_input_id |
|
50 | + * @access private |
|
51 | + * @var string |
|
52 | + */ |
|
53 | + private $QST_input_id = ''; |
|
54 | + |
|
55 | + /** |
|
56 | + * $QST_input_class |
|
57 | + * @access private |
|
58 | + * @var string |
|
59 | + */ |
|
60 | + private $QST_input_class = ''; |
|
61 | + |
|
62 | + /** |
|
63 | + * @var bool $QST_disabled |
|
64 | + */ |
|
65 | + private $QST_disabled = false; |
|
66 | + |
|
67 | + /** |
|
68 | + * @var RequestInterface |
|
69 | + */ |
|
70 | + protected $request; |
|
71 | + |
|
72 | + /** |
|
73 | + * @var array |
|
74 | + */ |
|
75 | + protected $form_data; |
|
76 | + |
|
77 | + |
|
78 | + /** |
|
79 | + * constructor for questions |
|
80 | + * |
|
81 | + * @param EE_Question $QST EE_Question object |
|
82 | + * @param EE_Answer $ANS EE_Answer object |
|
83 | + * @param array $q_meta |
|
84 | + * @throws EE_Error |
|
85 | + * @throws ReflectionException |
|
86 | + */ |
|
87 | + public function __construct(EE_Question $QST = null, EE_Answer $ANS = null, $q_meta = []) |
|
88 | + { |
|
89 | + $this->request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
90 | + $this->form_data = $this->request->requestParams(); |
|
91 | + if (empty($QST) || empty($ANS)) { |
|
92 | + EE_Error::add_error( |
|
93 | + esc_html__('An error occurred. A valid EE_Question or EE_Answer object was not received.', 'event_espresso'), |
|
94 | + __FILE__, |
|
95 | + __FUNCTION__, |
|
96 | + __LINE__ |
|
97 | + ); |
|
98 | + return null; |
|
99 | + } |
|
100 | + $this->_QST = $QST; |
|
101 | + $this->_ANS = $ANS; |
|
102 | + $this->set_question_form_input_meta($q_meta); |
|
103 | + $this->set_question_form_input_init(); |
|
104 | + } |
|
105 | + |
|
106 | + |
|
107 | + /** |
|
108 | + * sets meta data for the question form input |
|
109 | + * |
|
110 | + * @access public |
|
111 | + * @param array $q_meta |
|
112 | + * @return void |
|
113 | + */ |
|
114 | + public function set_question_form_input_meta($q_meta = []) |
|
115 | + { |
|
116 | + $default_q_meta = [ |
|
117 | + 'att_nmbr' => 1, |
|
118 | + 'ticket_id' => '', |
|
119 | + 'date' => '', |
|
120 | + 'time' => '', |
|
121 | + 'input_name' => '', |
|
122 | + 'input_id' => '', |
|
123 | + 'input_class' => '', |
|
124 | + 'input_prefix' => 'qstn', |
|
125 | + 'append_qstn_id' => true, |
|
126 | + 'htmlentities' => true, |
|
127 | + 'allow_null' => false, |
|
128 | + ]; |
|
129 | + $this->_QST_meta = array_merge($default_q_meta, $q_meta); |
|
130 | + } |
|
131 | + |
|
132 | + |
|
133 | + /** |
|
134 | + * set_question_form_input_init |
|
135 | + * |
|
136 | + * @access public |
|
137 | + * @return void |
|
138 | + * @throws EE_Error |
|
139 | + * @throws ReflectionException |
|
140 | + */ |
|
141 | + public function set_question_form_input_init() |
|
142 | + { |
|
143 | + $qstn_id = $this->_QST->system_ID() ? $this->_QST->system_ID() : $this->_QST->ID(); |
|
144 | + $this->_set_input_name($qstn_id); |
|
145 | + $this->_set_input_id($qstn_id); |
|
146 | + $this->_set_input_class(); |
|
147 | + $this->set_question_form_input_answer($qstn_id); |
|
148 | + } |
|
149 | + |
|
150 | + |
|
151 | + /** |
|
152 | + * set_input_name |
|
153 | + * |
|
154 | + * @access private |
|
155 | + * @param $qstn_id |
|
156 | + * @return void |
|
157 | + * @throws EE_Error |
|
158 | + * @throws ReflectionException |
|
159 | + */ |
|
160 | + private function _set_input_name($qstn_id) |
|
161 | + { |
|
162 | + if (! empty($qstn_id)) { |
|
163 | + $ANS_ID = $this->get('ANS_ID'); |
|
164 | + $qstn_id = ! empty($ANS_ID) ? '[' . $qstn_id . '][' . $ANS_ID . ']' : '[' . $qstn_id . ']'; |
|
165 | + } |
|
166 | + $this->QST_input_name = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id) |
|
167 | + ? $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'] . $qstn_id |
|
168 | + : $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name']; |
|
169 | + } |
|
170 | + |
|
171 | + |
|
172 | + /** |
|
173 | + * get property values for question form input |
|
174 | + * |
|
175 | + * @access public |
|
176 | + * @param string $property |
|
177 | + * @return mixed |
|
178 | + * @throws EE_Error |
|
179 | + * @throws ReflectionException |
|
180 | + */ |
|
181 | + public function get($property = null) |
|
182 | + { |
|
183 | + if (! empty($property)) { |
|
184 | + if (EEM_Question::instance()->has_field($property)) { |
|
185 | + return $this->_QST->get($property); |
|
186 | + } elseif (EEM_Answer::instance()->has_field($property)) { |
|
187 | + return $this->_ANS->get($property); |
|
188 | + } elseif ($this->_question_form_input_property_exists(__CLASS__, $property)) { |
|
189 | + return $this->{$property}; |
|
190 | + } |
|
191 | + } |
|
192 | + return null; |
|
193 | + } |
|
194 | + |
|
195 | + |
|
196 | + /** |
|
197 | + * _question_form_input_property_exists |
|
198 | + * |
|
199 | + * @access private |
|
200 | + * @param string $classname |
|
201 | + * @param string $property |
|
202 | + * @return boolean |
|
203 | + * @throws ReflectionException |
|
204 | + */ |
|
205 | + private function _question_form_input_property_exists($classname, $property) |
|
206 | + { |
|
207 | + // first try regular property exists method which works as expected in PHP 5.3+ |
|
208 | + $prop = EEH_Class_Tools::has_property($classname, $property); |
|
209 | + if (! $prop) { |
|
210 | + // use reflection for < PHP 5.3 as a double check when property is not found, possible due to access restriction |
|
211 | + $reflector = new ReflectionClass($classname); |
|
212 | + $prop = $reflector->hasProperty($property); |
|
213 | + } |
|
214 | + return $prop; |
|
215 | + } |
|
216 | + |
|
217 | + |
|
218 | + /** |
|
219 | + * set_input_id |
|
220 | + * |
|
221 | + * @access private |
|
222 | + * @param $qstn_id |
|
223 | + * @return void |
|
224 | + * @throws EE_Error |
|
225 | + * @throws ReflectionException |
|
226 | + */ |
|
227 | + private function _set_input_id($qstn_id) |
|
228 | + { |
|
229 | + $input_id = isset($this->_QST_meta['input_id']) && ! empty($this->_QST_meta['input_id']) |
|
230 | + ? $this->_QST_meta['input_id'] |
|
231 | + : sanitize_key(strip_tags($this->_QST->get('QST_display_text'))); |
|
232 | + $this->QST_input_id = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id) |
|
233 | + ? $input_id . '-' . $qstn_id |
|
234 | + : $input_id; |
|
235 | + } |
|
236 | + |
|
237 | + |
|
238 | + /** |
|
239 | + * set_input_class |
|
240 | + * |
|
241 | + * @access private |
|
242 | + * @return void |
|
243 | + */ |
|
244 | + private function _set_input_class() |
|
245 | + { |
|
246 | + $this->QST_input_class = isset($this->_QST_meta['input_class']) ? $this->_QST_meta['input_class'] : ''; |
|
247 | + } |
|
248 | + |
|
249 | + |
|
250 | + /** |
|
251 | + * set_question_form_input_answer |
|
252 | + * |
|
253 | + * @access public |
|
254 | + * @param mixed int | string $qstn_id |
|
255 | + * @return void |
|
256 | + * @throws EE_Error |
|
257 | + * @throws ReflectionException |
|
258 | + */ |
|
259 | + public function set_question_form_input_answer($qstn_id) |
|
260 | + { |
|
261 | + // check for answer in $this->form_data in case we are reprocessing a form after an error |
|
262 | + if ( |
|
263 | + isset($this->_QST_meta['EVT_ID']) |
|
264 | + && isset($this->_QST_meta['att_nmbr']) |
|
265 | + && isset($this->_QST_meta['date']) |
|
266 | + && isset($this->_QST_meta['time']) |
|
267 | + && isset($this->_QST_meta['price_id']) |
|
268 | + ) { |
|
269 | + $EVT_ID = $this->_QST_meta['EVT_ID']; |
|
270 | + $att_nmbr = $this->_QST_meta['att_nmbr']; |
|
271 | + $date = $this->_QST_meta['date']; |
|
272 | + $time = $this->_QST_meta['time']; |
|
273 | + $price_id = $this->_QST_meta['price_id']; |
|
274 | + if (isset($this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ])) { |
|
275 | + $answer = $this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ]; |
|
276 | + $this->_ANS->set('ANS_value', $answer); |
|
277 | + } |
|
278 | + } |
|
279 | + } |
|
280 | + |
|
281 | + |
|
282 | + /** |
|
283 | + * generate_question_form_inputs_for_object |
|
284 | + * |
|
285 | + * @access protected |
|
286 | + * @param bool|object $object $object |
|
287 | + * @param array $input_types |
|
288 | + * @return array |
|
289 | + * @throws EE_Error |
|
290 | + * @throws ReflectionException |
|
291 | + */ |
|
292 | + public static function generate_question_form_inputs_for_object($object = false, $input_types = []) |
|
293 | + { |
|
294 | + if (! is_object($object)) { |
|
295 | + return []; |
|
296 | + } |
|
297 | + $inputs = []; |
|
298 | + $fields = $object->get_model()->field_settings(false); |
|
299 | + foreach ($fields as $field_ID => $field) { |
|
300 | + if ($field instanceof EE_Model_Field_Base) { |
|
301 | + if (isset($input_types[ $field_ID ])) { |
|
302 | + // get saved value for field |
|
303 | + $value = $object->get($field_ID); |
|
304 | + // if no saved value, then use default |
|
305 | + $value = $value !== null ? $value : $field->get_default_value(); |
|
306 | + // determine question type |
|
307 | + $type = isset($input_types[ $field_ID ]) ? $input_types[ $field_ID ]['type'] : 'TEXT'; |
|
308 | + // input name |
|
309 | + $input_name = isset($input_types[ $field_ID ]) && isset($input_types[ $field_ID ]['input_name']) |
|
310 | + ? $input_types[ $field_ID ]['input_name'] . '[' . $field_ID . ']' |
|
311 | + : $field_ID; |
|
312 | + // css class for input |
|
313 | + $class = isset($input_types[ $field_ID ]['class']) && ! empty($input_types[ $field_ID ]['class']) |
|
314 | + ? ' ' . $input_types[ $field_ID ]['class'] |
|
315 | + : ''; |
|
316 | + // whether to apply htmlentities to answer |
|
317 | + $htmlentities = isset($input_types[ $field_ID ]['htmlentities']) |
|
318 | + ? $input_types[ $field_ID ]['htmlentities'] |
|
319 | + : true; |
|
320 | + // whether to apply htmlentities to answer |
|
321 | + $label_b4 = isset($input_types[ $field_ID ]['label_b4']) |
|
322 | + ? $input_types[ $field_ID ]['label_b4'] |
|
323 | + : false; |
|
324 | + // whether to apply htmlentities to answer |
|
325 | + $use_desc_4_label = isset($input_types[ $field_ID ]['use_desc_4_label']) |
|
326 | + ? $input_types[ $field_ID ]['use_desc_4_label'] |
|
327 | + : false; |
|
328 | + // whether input is disabled |
|
329 | + $disabled = isset($input_types[ $field_ID ]['disabled']) && $input_types[ $field_ID ]['disabled']; |
|
330 | + |
|
331 | + // create EE_Question_Form_Input object |
|
332 | + $QFI = new EE_Question_Form_Input( |
|
333 | + EE_Question::new_instance( |
|
334 | + [ |
|
335 | + 'QST_ID' => 0, |
|
336 | + 'QST_display_text' => $field->get_nicename(), |
|
337 | + 'QST_type' => $type, |
|
338 | + ] |
|
339 | + ), |
|
340 | + EE_Answer::new_instance( |
|
341 | + [ |
|
342 | + 'ANS_ID' => 0, |
|
343 | + 'QST_ID' => 0, |
|
344 | + 'REG_ID' => 0, |
|
345 | + 'ANS_value' => $value, |
|
346 | + ] |
|
347 | + ), |
|
348 | + [ |
|
349 | + 'input_id' => $field_ID . '-' . $object->ID(), |
|
350 | + 'input_name' => $input_name, |
|
351 | + 'input_class' => $field_ID . $class, |
|
352 | + 'input_prefix' => '', |
|
353 | + 'append_qstn_id' => false, |
|
354 | + 'htmlentities' => $htmlentities, |
|
355 | + 'label_b4' => $label_b4, |
|
356 | + 'use_desc_4_label' => $use_desc_4_label, |
|
357 | + ] |
|
358 | + ); |
|
359 | + // does question type have options ? |
|
360 | + if ( |
|
361 | + in_array($type, ['DROPDOWN', 'RADIO_BTN', 'CHECKBOX']) |
|
362 | + && isset($input_types[ $field_ID ]) |
|
363 | + && isset($input_types[ $field_ID ]['options']) |
|
364 | + ) { |
|
365 | + foreach ($input_types[ $field_ID ]['options'] as $option) { |
|
366 | + $option = stripslashes_deep($option); |
|
367 | + $option_id = ! empty($option['id']) ? $option['id'] : 0; |
|
368 | + $QSO = EE_Question_Option::new_instance( |
|
369 | + [ |
|
370 | + 'QSO_value' => (string) $option_id, |
|
371 | + 'QSO_desc' => $option['text'], |
|
372 | + 'QSO_deleted' => false, |
|
373 | + ] |
|
374 | + ); |
|
375 | + // all QST (and ANS) properties can be accessed indirectly thru QFI |
|
376 | + $QFI->add_temp_option($QSO); |
|
377 | + } |
|
378 | + } |
|
379 | + // we don't want ppl manually changing primary keys cuz that would just lead to total craziness man |
|
380 | + if ($disabled || $field_ID == $object->get_model()->primary_key_name()) { |
|
381 | + $QFI->set('QST_disabled', true); |
|
382 | + } |
|
383 | + $inputs[ $field_ID ] = $QFI; |
|
384 | + } |
|
385 | + } |
|
386 | + } |
|
387 | + return $inputs; |
|
388 | + } |
|
389 | + |
|
390 | + |
|
391 | + /** |
|
392 | + * add_temp_option |
|
393 | + * |
|
394 | + * @access public |
|
395 | + * @param EE_Question_Option $QSO EE_Question_Option |
|
396 | + * @return void |
|
397 | + */ |
|
398 | + public function add_temp_option(EE_Question_Option $QSO) |
|
399 | + { |
|
400 | + $this->_QST->add_temp_option($QSO); |
|
401 | + } |
|
402 | + |
|
403 | + |
|
404 | + /** |
|
405 | + * set property values for question form input |
|
406 | + * |
|
407 | + * @access public |
|
408 | + * @param string $property |
|
409 | + * @param mixed $value |
|
410 | + * @return void |
|
411 | + * @throws EE_Error |
|
412 | + * @throws ReflectionException |
|
413 | + */ |
|
414 | + public function set($property = null, $value = null) |
|
415 | + { |
|
416 | + if (! empty($property)) { |
|
417 | + if (EEM_Question::instance()->has_field($property)) { |
|
418 | + $this->_QST->set($property, $value); |
|
419 | + } elseif (EEM_Answer::instance()->has_field($property)) { |
|
420 | + $this->_ANS->set($property, $value); |
|
421 | + } elseif ($this->_question_form_input_property_exists(__CLASS__, $property)) { |
|
422 | + $this->{$property} = $value; |
|
423 | + } |
|
424 | + } |
|
425 | + } |
|
426 | + |
|
427 | + |
|
428 | + /** |
|
429 | + * _question_form_input_property_exists |
|
430 | + * |
|
431 | + * @access public |
|
432 | + * @param boolean $notDeletedOptionsOnly 1 |
|
433 | + * whether to return ALL options, or only the ones which have |
|
434 | + * not yet been deleted |
|
435 | + * @param string|array $selected_value_to_always_include , when retrieving options to an ANSWERED question, |
|
436 | + * we want to usually only show non-deleted options AND the |
|
437 | + * value that was selected for the answer, whether it was |
|
438 | + * trashed or not. |
|
439 | + * @return EE_Question_Option |
|
440 | + */ |
|
441 | + public function options($notDeletedOptionsOnly = true, $selected_value_to_always_include = null) |
|
442 | + { |
|
443 | + $temp_options = $this->_QST->temp_options(); |
|
444 | + return ! empty($temp_options) |
|
445 | + ? $temp_options |
|
446 | + : $this->_QST->options( |
|
447 | + $notDeletedOptionsOnly, |
|
448 | + $selected_value_to_always_include |
|
449 | + ); |
|
450 | + } |
|
451 | + |
|
452 | + |
|
453 | + /** |
|
454 | + * get_meta |
|
455 | + * |
|
456 | + * @access public |
|
457 | + * @param mixed $key |
|
458 | + * @return mixed |
|
459 | + */ |
|
460 | + public function get_meta($key = false) |
|
461 | + { |
|
462 | + return $key && isset($this->_QST_meta[ $key ]) ? $this->_QST_meta[ $key ] : false; |
|
463 | + } |
|
464 | 464 | } |
@@ -88,7 +88,7 @@ discard block |
||
88 | 88 | protected function __construct($fieldValues = array(), $bydb = false, $timezone = '') |
89 | 89 | { |
90 | 90 | parent::__construct($fieldValues, $bydb, $timezone); |
91 | - if (! $this->get('LIN_code')) { |
|
91 | + if ( ! $this->get('LIN_code')) { |
|
92 | 92 | $this->set_code($this->generate_code()); |
93 | 93 | } |
94 | 94 | } |
@@ -155,7 +155,7 @@ discard block |
||
155 | 155 | public function name() |
156 | 156 | { |
157 | 157 | $name = $this->get('LIN_name'); |
158 | - if (! $name) { |
|
158 | + if ( ! $name) { |
|
159 | 159 | $name = ucwords(str_replace('-', ' ', $this->type())); |
160 | 160 | } |
161 | 161 | return $name; |
@@ -615,7 +615,7 @@ discard block |
||
615 | 615 | ) |
616 | 616 | ); |
617 | 617 | } |
618 | - if (! is_array($this->_children)) { |
|
618 | + if ( ! is_array($this->_children)) { |
|
619 | 619 | $this->_children = array(); |
620 | 620 | } |
621 | 621 | return $this->_children; |
@@ -856,7 +856,7 @@ discard block |
||
856 | 856 | } |
857 | 857 | return $line_item->save(); |
858 | 858 | } |
859 | - $this->_children[ $line_item->code() ] = $line_item; |
|
859 | + $this->_children[$line_item->code()] = $line_item; |
|
860 | 860 | if ($line_item->parent() !== $this) { |
861 | 861 | $line_item->set_parent($this); |
862 | 862 | } |
@@ -880,7 +880,7 @@ discard block |
||
880 | 880 | public function set_parent($line_item) |
881 | 881 | { |
882 | 882 | if ($this->ID()) { |
883 | - if (! $line_item->ID()) { |
|
883 | + if ( ! $line_item->ID()) { |
|
884 | 884 | $line_item->save(); |
885 | 885 | } |
886 | 886 | $this->set_parent_ID($line_item->ID()); |
@@ -912,8 +912,8 @@ discard block |
||
912 | 912 | array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code)) |
913 | 913 | ); |
914 | 914 | } |
915 | - return isset($this->_children[ $code ]) |
|
916 | - ? $this->_children[ $code ] |
|
915 | + return isset($this->_children[$code]) |
|
916 | + ? $this->_children[$code] |
|
917 | 917 | : null; |
918 | 918 | } |
919 | 919 | |
@@ -973,8 +973,8 @@ discard block |
||
973 | 973 | } |
974 | 974 | return $items_deleted; |
975 | 975 | } |
976 | - if (isset($this->_children[ $code ])) { |
|
977 | - unset($this->_children[ $code ]); |
|
976 | + if (isset($this->_children[$code])) { |
|
977 | + unset($this->_children[$code]); |
|
978 | 978 | return 1; |
979 | 979 | } |
980 | 980 | return 0; |
@@ -1015,7 +1015,7 @@ discard block |
||
1015 | 1015 | public function generate_code() |
1016 | 1016 | { |
1017 | 1017 | // each line item in the cart requires a unique identifier |
1018 | - return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime()); |
|
1018 | + return md5($this->get('OBJ_type').$this->get('OBJ_ID').microtime()); |
|
1019 | 1019 | } |
1020 | 1020 | |
1021 | 1021 | |
@@ -1228,7 +1228,7 @@ discard block |
||
1228 | 1228 | $has_children = ! empty($my_children); |
1229 | 1229 | if ($has_children && $this->is_line_item()) { |
1230 | 1230 | $total = $this->_recalculate_pretax_total_for_line_item($total, $my_children); |
1231 | - } elseif (! $has_children && ($this->is_sub_line_item() || $this->is_line_item())) { |
|
1231 | + } elseif ( ! $has_children && ($this->is_sub_line_item() || $this->is_line_item())) { |
|
1232 | 1232 | $total = $this->unit_price() * $this->quantity(); |
1233 | 1233 | } elseif ($this->is_sub_total() || $this->is_total()) { |
1234 | 1234 | $total = $this->_recalculate_pretax_total_for_subtotal($total, $my_children); |
@@ -1243,13 +1243,13 @@ discard block |
||
1243 | 1243 | if ($this->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_EVENT) { |
1244 | 1244 | $this->set_quantity(1); |
1245 | 1245 | } |
1246 | - if (! $this->is_percent()) { |
|
1246 | + if ( ! $this->is_percent()) { |
|
1247 | 1247 | $this->set_unit_price($total); |
1248 | 1248 | } |
1249 | 1249 | } |
1250 | 1250 | // we don't want to bother saving grand totals, because that needs to factor in taxes anyways |
1251 | 1251 | // so it ought to be |
1252 | - if (! $this->is_total()) { |
|
1252 | + if ( ! $this->is_total()) { |
|
1253 | 1253 | $this->set_total($total); |
1254 | 1254 | // if not a percent line item, make sure we keep the unit price in sync |
1255 | 1255 | if ( |
@@ -1597,7 +1597,7 @@ discard block |
||
1597 | 1597 | public function save_this_and_descendants_to_txn($txn_id = null) |
1598 | 1598 | { |
1599 | 1599 | $count = 0; |
1600 | - if (! $txn_id) { |
|
1600 | + if ( ! $txn_id) { |
|
1601 | 1601 | $txn_id = $this->TXN_ID(); |
1602 | 1602 | } |
1603 | 1603 | $this->set_TXN_ID($txn_id); |
@@ -13,1742 +13,1742 @@ |
||
13 | 13 | */ |
14 | 14 | class EE_Line_Item extends EE_Base_Class implements EEI_Line_Item |
15 | 15 | { |
16 | - /** |
|
17 | - * for children line items (currently not a normal relation) |
|
18 | - * |
|
19 | - * @type EE_Line_Item[] |
|
20 | - */ |
|
21 | - protected $_children = array(); |
|
22 | - |
|
23 | - /** |
|
24 | - * for the parent line item |
|
25 | - * |
|
26 | - * @var EE_Line_Item |
|
27 | - */ |
|
28 | - protected $_parent; |
|
29 | - |
|
30 | - |
|
31 | - /** |
|
32 | - * @param array $props_n_values incoming values |
|
33 | - * @param string $timezone incoming timezone (if not set the timezone set for the website will be |
|
34 | - * used.) |
|
35 | - * @param array $date_formats incoming date_formats in an array where the first value is the |
|
36 | - * date_format and the second value is the time format |
|
37 | - * @return EE_Line_Item |
|
38 | - * @throws EE_Error |
|
39 | - * @throws InvalidArgumentException |
|
40 | - * @throws InvalidDataTypeException |
|
41 | - * @throws InvalidInterfaceException |
|
42 | - * @throws ReflectionException |
|
43 | - */ |
|
44 | - public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) |
|
45 | - { |
|
46 | - $has_object = parent::_check_for_object( |
|
47 | - $props_n_values, |
|
48 | - __CLASS__, |
|
49 | - $timezone, |
|
50 | - $date_formats |
|
51 | - ); |
|
52 | - return $has_object |
|
53 | - ? $has_object |
|
54 | - : new self($props_n_values, false, $timezone); |
|
55 | - } |
|
56 | - |
|
57 | - |
|
58 | - /** |
|
59 | - * @param array $props_n_values incoming values from the database |
|
60 | - * @param string $timezone incoming timezone as set by the model. If not set the timezone for |
|
61 | - * the website will be used. |
|
62 | - * @return EE_Line_Item |
|
63 | - * @throws EE_Error |
|
64 | - * @throws InvalidArgumentException |
|
65 | - * @throws InvalidDataTypeException |
|
66 | - * @throws InvalidInterfaceException |
|
67 | - * @throws ReflectionException |
|
68 | - */ |
|
69 | - public static function new_instance_from_db($props_n_values = array(), $timezone = null) |
|
70 | - { |
|
71 | - return new self($props_n_values, true, $timezone); |
|
72 | - } |
|
73 | - |
|
74 | - |
|
75 | - /** |
|
76 | - * Adds some defaults if they're not specified |
|
77 | - * |
|
78 | - * @param array $fieldValues |
|
79 | - * @param bool $bydb |
|
80 | - * @param string $timezone |
|
81 | - * @throws EE_Error |
|
82 | - * @throws InvalidArgumentException |
|
83 | - * @throws InvalidDataTypeException |
|
84 | - * @throws InvalidInterfaceException |
|
85 | - * @throws ReflectionException |
|
86 | - */ |
|
87 | - protected function __construct($fieldValues = array(), $bydb = false, $timezone = '') |
|
88 | - { |
|
89 | - parent::__construct($fieldValues, $bydb, $timezone); |
|
90 | - if (! $this->get('LIN_code')) { |
|
91 | - $this->set_code($this->generate_code()); |
|
92 | - } |
|
93 | - } |
|
94 | - |
|
95 | - |
|
96 | - /** |
|
97 | - * Gets ID |
|
98 | - * |
|
99 | - * @return int |
|
100 | - * @throws EE_Error |
|
101 | - * @throws InvalidArgumentException |
|
102 | - * @throws InvalidDataTypeException |
|
103 | - * @throws InvalidInterfaceException |
|
104 | - * @throws ReflectionException |
|
105 | - */ |
|
106 | - public function ID() |
|
107 | - { |
|
108 | - return $this->get('LIN_ID'); |
|
109 | - } |
|
110 | - |
|
111 | - |
|
112 | - /** |
|
113 | - * Gets TXN_ID |
|
114 | - * |
|
115 | - * @return int |
|
116 | - * @throws EE_Error |
|
117 | - * @throws InvalidArgumentException |
|
118 | - * @throws InvalidDataTypeException |
|
119 | - * @throws InvalidInterfaceException |
|
120 | - * @throws ReflectionException |
|
121 | - */ |
|
122 | - public function TXN_ID() |
|
123 | - { |
|
124 | - return $this->get('TXN_ID'); |
|
125 | - } |
|
126 | - |
|
127 | - |
|
128 | - /** |
|
129 | - * Sets TXN_ID |
|
130 | - * |
|
131 | - * @param int $TXN_ID |
|
132 | - * @throws EE_Error |
|
133 | - * @throws InvalidArgumentException |
|
134 | - * @throws InvalidDataTypeException |
|
135 | - * @throws InvalidInterfaceException |
|
136 | - * @throws ReflectionException |
|
137 | - */ |
|
138 | - public function set_TXN_ID($TXN_ID) |
|
139 | - { |
|
140 | - $this->set('TXN_ID', $TXN_ID); |
|
141 | - } |
|
142 | - |
|
143 | - |
|
144 | - /** |
|
145 | - * Gets name |
|
146 | - * |
|
147 | - * @return string |
|
148 | - * @throws EE_Error |
|
149 | - * @throws InvalidArgumentException |
|
150 | - * @throws InvalidDataTypeException |
|
151 | - * @throws InvalidInterfaceException |
|
152 | - * @throws ReflectionException |
|
153 | - */ |
|
154 | - public function name() |
|
155 | - { |
|
156 | - $name = $this->get('LIN_name'); |
|
157 | - if (! $name) { |
|
158 | - $name = ucwords(str_replace('-', ' ', $this->type())); |
|
159 | - } |
|
160 | - return $name; |
|
161 | - } |
|
162 | - |
|
163 | - |
|
164 | - /** |
|
165 | - * Sets name |
|
166 | - * |
|
167 | - * @param string $name |
|
168 | - * @throws EE_Error |
|
169 | - * @throws InvalidArgumentException |
|
170 | - * @throws InvalidDataTypeException |
|
171 | - * @throws InvalidInterfaceException |
|
172 | - * @throws ReflectionException |
|
173 | - */ |
|
174 | - public function set_name($name) |
|
175 | - { |
|
176 | - $this->set('LIN_name', $name); |
|
177 | - } |
|
178 | - |
|
179 | - |
|
180 | - /** |
|
181 | - * Gets desc |
|
182 | - * |
|
183 | - * @return string |
|
184 | - * @throws EE_Error |
|
185 | - * @throws InvalidArgumentException |
|
186 | - * @throws InvalidDataTypeException |
|
187 | - * @throws InvalidInterfaceException |
|
188 | - * @throws ReflectionException |
|
189 | - */ |
|
190 | - public function desc() |
|
191 | - { |
|
192 | - return $this->get('LIN_desc'); |
|
193 | - } |
|
194 | - |
|
195 | - |
|
196 | - /** |
|
197 | - * Sets desc |
|
198 | - * |
|
199 | - * @param string $desc |
|
200 | - * @throws EE_Error |
|
201 | - * @throws InvalidArgumentException |
|
202 | - * @throws InvalidDataTypeException |
|
203 | - * @throws InvalidInterfaceException |
|
204 | - * @throws ReflectionException |
|
205 | - */ |
|
206 | - public function set_desc($desc) |
|
207 | - { |
|
208 | - $this->set('LIN_desc', $desc); |
|
209 | - } |
|
210 | - |
|
211 | - |
|
212 | - /** |
|
213 | - * Gets quantity |
|
214 | - * |
|
215 | - * @return int |
|
216 | - * @throws EE_Error |
|
217 | - * @throws InvalidArgumentException |
|
218 | - * @throws InvalidDataTypeException |
|
219 | - * @throws InvalidInterfaceException |
|
220 | - * @throws ReflectionException |
|
221 | - */ |
|
222 | - public function quantity() |
|
223 | - { |
|
224 | - return $this->get('LIN_quantity'); |
|
225 | - } |
|
226 | - |
|
227 | - |
|
228 | - /** |
|
229 | - * Sets quantity |
|
230 | - * |
|
231 | - * @param int $quantity |
|
232 | - * @throws EE_Error |
|
233 | - * @throws InvalidArgumentException |
|
234 | - * @throws InvalidDataTypeException |
|
235 | - * @throws InvalidInterfaceException |
|
236 | - * @throws ReflectionException |
|
237 | - */ |
|
238 | - public function set_quantity($quantity) |
|
239 | - { |
|
240 | - $this->set('LIN_quantity', max($quantity, 0)); |
|
241 | - } |
|
242 | - |
|
243 | - |
|
244 | - /** |
|
245 | - * Gets item_id |
|
246 | - * |
|
247 | - * @return string |
|
248 | - * @throws EE_Error |
|
249 | - * @throws InvalidArgumentException |
|
250 | - * @throws InvalidDataTypeException |
|
251 | - * @throws InvalidInterfaceException |
|
252 | - * @throws ReflectionException |
|
253 | - */ |
|
254 | - public function OBJ_ID() |
|
255 | - { |
|
256 | - return $this->get('OBJ_ID'); |
|
257 | - } |
|
258 | - |
|
259 | - |
|
260 | - /** |
|
261 | - * Sets item_id |
|
262 | - * |
|
263 | - * @param string $item_id |
|
264 | - * @throws EE_Error |
|
265 | - * @throws InvalidArgumentException |
|
266 | - * @throws InvalidDataTypeException |
|
267 | - * @throws InvalidInterfaceException |
|
268 | - * @throws ReflectionException |
|
269 | - */ |
|
270 | - public function set_OBJ_ID($item_id) |
|
271 | - { |
|
272 | - $this->set('OBJ_ID', $item_id); |
|
273 | - } |
|
274 | - |
|
275 | - |
|
276 | - /** |
|
277 | - * Gets item_type |
|
278 | - * |
|
279 | - * @return string |
|
280 | - * @throws EE_Error |
|
281 | - * @throws InvalidArgumentException |
|
282 | - * @throws InvalidDataTypeException |
|
283 | - * @throws InvalidInterfaceException |
|
284 | - * @throws ReflectionException |
|
285 | - */ |
|
286 | - public function OBJ_type() |
|
287 | - { |
|
288 | - return $this->get('OBJ_type'); |
|
289 | - } |
|
290 | - |
|
291 | - |
|
292 | - /** |
|
293 | - * Gets item_type |
|
294 | - * |
|
295 | - * @return string |
|
296 | - * @throws EE_Error |
|
297 | - * @throws InvalidArgumentException |
|
298 | - * @throws InvalidDataTypeException |
|
299 | - * @throws InvalidInterfaceException |
|
300 | - * @throws ReflectionException |
|
301 | - */ |
|
302 | - public function OBJ_type_i18n() |
|
303 | - { |
|
304 | - $obj_type = $this->OBJ_type(); |
|
305 | - switch ($obj_type) { |
|
306 | - case EEM_Line_Item::OBJ_TYPE_EVENT: |
|
307 | - $obj_type = esc_html__('Event', 'event_espresso'); |
|
308 | - break; |
|
309 | - case EEM_Line_Item::OBJ_TYPE_PRICE: |
|
310 | - $obj_type = esc_html__('Price', 'event_espresso'); |
|
311 | - break; |
|
312 | - case EEM_Line_Item::OBJ_TYPE_PROMOTION: |
|
313 | - $obj_type = esc_html__('Promotion', 'event_espresso'); |
|
314 | - break; |
|
315 | - case EEM_Line_Item::OBJ_TYPE_TICKET: |
|
316 | - $obj_type = esc_html__('Ticket', 'event_espresso'); |
|
317 | - break; |
|
318 | - case EEM_Line_Item::OBJ_TYPE_TRANSACTION: |
|
319 | - $obj_type = esc_html__('Transaction', 'event_espresso'); |
|
320 | - break; |
|
321 | - } |
|
322 | - return apply_filters('FHEE__EE_Line_Item__OBJ_type_i18n', $obj_type, $this); |
|
323 | - } |
|
324 | - |
|
325 | - |
|
326 | - /** |
|
327 | - * Sets item_type |
|
328 | - * |
|
329 | - * @param string $OBJ_type |
|
330 | - * @throws EE_Error |
|
331 | - * @throws InvalidArgumentException |
|
332 | - * @throws InvalidDataTypeException |
|
333 | - * @throws InvalidInterfaceException |
|
334 | - * @throws ReflectionException |
|
335 | - */ |
|
336 | - public function set_OBJ_type($OBJ_type) |
|
337 | - { |
|
338 | - $this->set('OBJ_type', $OBJ_type); |
|
339 | - } |
|
340 | - |
|
341 | - |
|
342 | - /** |
|
343 | - * Gets unit_price |
|
344 | - * |
|
345 | - * @return float |
|
346 | - * @throws EE_Error |
|
347 | - * @throws InvalidArgumentException |
|
348 | - * @throws InvalidDataTypeException |
|
349 | - * @throws InvalidInterfaceException |
|
350 | - * @throws ReflectionException |
|
351 | - */ |
|
352 | - public function unit_price() |
|
353 | - { |
|
354 | - return $this->get('LIN_unit_price'); |
|
355 | - } |
|
356 | - |
|
357 | - |
|
358 | - /** |
|
359 | - * Sets unit_price |
|
360 | - * |
|
361 | - * @param float $unit_price |
|
362 | - * @throws EE_Error |
|
363 | - * @throws InvalidArgumentException |
|
364 | - * @throws InvalidDataTypeException |
|
365 | - * @throws InvalidInterfaceException |
|
366 | - * @throws ReflectionException |
|
367 | - */ |
|
368 | - public function set_unit_price($unit_price) |
|
369 | - { |
|
370 | - $this->set('LIN_unit_price', $unit_price); |
|
371 | - } |
|
372 | - |
|
373 | - |
|
374 | - /** |
|
375 | - * Checks if this item is a percentage modifier or not |
|
376 | - * |
|
377 | - * @return boolean |
|
378 | - * @throws EE_Error |
|
379 | - * @throws InvalidArgumentException |
|
380 | - * @throws InvalidDataTypeException |
|
381 | - * @throws InvalidInterfaceException |
|
382 | - * @throws ReflectionException |
|
383 | - */ |
|
384 | - public function is_percent() |
|
385 | - { |
|
386 | - if ($this->is_tax_sub_total()) { |
|
387 | - // tax subtotals HAVE a percent on them, that percentage only applies |
|
388 | - // to taxable items, so its' an exception. Treat it like a flat line item |
|
389 | - return false; |
|
390 | - } |
|
391 | - $unit_price = abs($this->get('LIN_unit_price')); |
|
392 | - $percent = abs($this->get('LIN_percent')); |
|
393 | - if ($unit_price < .001 && $percent) { |
|
394 | - return true; |
|
395 | - } |
|
396 | - if ($unit_price >= .001 && ! $percent) { |
|
397 | - return false; |
|
398 | - } |
|
399 | - if ($unit_price >= .001 && $percent) { |
|
400 | - throw new EE_Error( |
|
401 | - sprintf( |
|
402 | - esc_html__( |
|
403 | - 'A Line Item can not have a unit price of (%s) AND a percent (%s)!', |
|
404 | - 'event_espresso' |
|
405 | - ), |
|
406 | - $unit_price, |
|
407 | - $percent |
|
408 | - ) |
|
409 | - ); |
|
410 | - } |
|
411 | - // if they're both 0, assume its not a percent item |
|
412 | - return false; |
|
413 | - } |
|
414 | - |
|
415 | - |
|
416 | - /** |
|
417 | - * Gets percent (between 100-.001) |
|
418 | - * |
|
419 | - * @return float |
|
420 | - * @throws EE_Error |
|
421 | - * @throws InvalidArgumentException |
|
422 | - * @throws InvalidDataTypeException |
|
423 | - * @throws InvalidInterfaceException |
|
424 | - * @throws ReflectionException |
|
425 | - */ |
|
426 | - public function percent() |
|
427 | - { |
|
428 | - return $this->get('LIN_percent'); |
|
429 | - } |
|
430 | - |
|
431 | - |
|
432 | - /** |
|
433 | - * Sets percent (between 100-0.01) |
|
434 | - * |
|
435 | - * @param float $percent |
|
436 | - * @throws EE_Error |
|
437 | - * @throws InvalidArgumentException |
|
438 | - * @throws InvalidDataTypeException |
|
439 | - * @throws InvalidInterfaceException |
|
440 | - * @throws ReflectionException |
|
441 | - */ |
|
442 | - public function set_percent($percent) |
|
443 | - { |
|
444 | - $this->set('LIN_percent', $percent); |
|
445 | - } |
|
446 | - |
|
447 | - |
|
448 | - /** |
|
449 | - * Gets total |
|
450 | - * |
|
451 | - * @return float |
|
452 | - * @throws EE_Error |
|
453 | - * @throws InvalidArgumentException |
|
454 | - * @throws InvalidDataTypeException |
|
455 | - * @throws InvalidInterfaceException |
|
456 | - * @throws ReflectionException |
|
457 | - */ |
|
458 | - public function total() |
|
459 | - { |
|
460 | - return $this->get('LIN_total'); |
|
461 | - } |
|
462 | - |
|
463 | - |
|
464 | - /** |
|
465 | - * Sets total |
|
466 | - * |
|
467 | - * @param float $total |
|
468 | - * @throws EE_Error |
|
469 | - * @throws InvalidArgumentException |
|
470 | - * @throws InvalidDataTypeException |
|
471 | - * @throws InvalidInterfaceException |
|
472 | - * @throws ReflectionException |
|
473 | - */ |
|
474 | - public function set_total($total) |
|
475 | - { |
|
476 | - $this->set('LIN_total', $total); |
|
477 | - } |
|
478 | - |
|
479 | - |
|
480 | - /** |
|
481 | - * Gets order |
|
482 | - * |
|
483 | - * @return int |
|
484 | - * @throws EE_Error |
|
485 | - * @throws InvalidArgumentException |
|
486 | - * @throws InvalidDataTypeException |
|
487 | - * @throws InvalidInterfaceException |
|
488 | - * @throws ReflectionException |
|
489 | - */ |
|
490 | - public function order() |
|
491 | - { |
|
492 | - return $this->get('LIN_order'); |
|
493 | - } |
|
494 | - |
|
495 | - |
|
496 | - /** |
|
497 | - * Sets order |
|
498 | - * |
|
499 | - * @param int $order |
|
500 | - * @throws EE_Error |
|
501 | - * @throws InvalidArgumentException |
|
502 | - * @throws InvalidDataTypeException |
|
503 | - * @throws InvalidInterfaceException |
|
504 | - * @throws ReflectionException |
|
505 | - */ |
|
506 | - public function set_order($order) |
|
507 | - { |
|
508 | - $this->set('LIN_order', $order); |
|
509 | - } |
|
510 | - |
|
511 | - |
|
512 | - /** |
|
513 | - * Gets parent |
|
514 | - * |
|
515 | - * @return int |
|
516 | - * @throws EE_Error |
|
517 | - * @throws InvalidArgumentException |
|
518 | - * @throws InvalidDataTypeException |
|
519 | - * @throws InvalidInterfaceException |
|
520 | - * @throws ReflectionException |
|
521 | - */ |
|
522 | - public function parent_ID() |
|
523 | - { |
|
524 | - return $this->get('LIN_parent'); |
|
525 | - } |
|
526 | - |
|
527 | - |
|
528 | - /** |
|
529 | - * Sets parent |
|
530 | - * |
|
531 | - * @param int $parent |
|
532 | - * @throws EE_Error |
|
533 | - * @throws InvalidArgumentException |
|
534 | - * @throws InvalidDataTypeException |
|
535 | - * @throws InvalidInterfaceException |
|
536 | - * @throws ReflectionException |
|
537 | - */ |
|
538 | - public function set_parent_ID($parent) |
|
539 | - { |
|
540 | - $this->set('LIN_parent', $parent); |
|
541 | - } |
|
542 | - |
|
543 | - |
|
544 | - /** |
|
545 | - * Gets type |
|
546 | - * |
|
547 | - * @return string |
|
548 | - * @throws EE_Error |
|
549 | - * @throws InvalidArgumentException |
|
550 | - * @throws InvalidDataTypeException |
|
551 | - * @throws InvalidInterfaceException |
|
552 | - * @throws ReflectionException |
|
553 | - */ |
|
554 | - public function type() |
|
555 | - { |
|
556 | - return $this->get('LIN_type'); |
|
557 | - } |
|
558 | - |
|
559 | - |
|
560 | - /** |
|
561 | - * Sets type |
|
562 | - * |
|
563 | - * @param string $type |
|
564 | - * @throws EE_Error |
|
565 | - * @throws InvalidArgumentException |
|
566 | - * @throws InvalidDataTypeException |
|
567 | - * @throws InvalidInterfaceException |
|
568 | - * @throws ReflectionException |
|
569 | - */ |
|
570 | - public function set_type($type) |
|
571 | - { |
|
572 | - $this->set('LIN_type', $type); |
|
573 | - } |
|
574 | - |
|
575 | - |
|
576 | - /** |
|
577 | - * Gets the line item of which this item is a composite. Eg, if this is a subtotal, the parent might be a total\ |
|
578 | - * If this line item is saved to the DB, fetches the parent from the DB. However, if this line item isn't in the DB |
|
579 | - * it uses its cached reference to its parent line item (which would have been set by `EE_Line_Item::set_parent()` |
|
580 | - * or indirectly by `EE_Line_item::add_child_line_item()`) |
|
581 | - * |
|
582 | - * @return EE_Base_Class|EE_Line_Item |
|
583 | - * @throws EE_Error |
|
584 | - * @throws InvalidArgumentException |
|
585 | - * @throws InvalidDataTypeException |
|
586 | - * @throws InvalidInterfaceException |
|
587 | - * @throws ReflectionException |
|
588 | - */ |
|
589 | - public function parent() |
|
590 | - { |
|
591 | - return $this->ID() |
|
592 | - ? $this->get_model()->get_one_by_ID($this->parent_ID()) |
|
593 | - : $this->_parent; |
|
594 | - } |
|
595 | - |
|
596 | - |
|
597 | - /** |
|
598 | - * Gets ALL the children of this line item (ie, all the parts that contribute towards this total). |
|
599 | - * |
|
600 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
601 | - * @throws EE_Error |
|
602 | - * @throws InvalidArgumentException |
|
603 | - * @throws InvalidDataTypeException |
|
604 | - * @throws InvalidInterfaceException |
|
605 | - * @throws ReflectionException |
|
606 | - */ |
|
607 | - public function children() |
|
608 | - { |
|
609 | - if ($this->ID()) { |
|
610 | - return $this->get_model()->get_all( |
|
611 | - array( |
|
612 | - array('LIN_parent' => $this->ID()), |
|
613 | - 'order_by' => array('LIN_order' => 'ASC'), |
|
614 | - ) |
|
615 | - ); |
|
616 | - } |
|
617 | - if (! is_array($this->_children)) { |
|
618 | - $this->_children = array(); |
|
619 | - } |
|
620 | - return $this->_children; |
|
621 | - } |
|
622 | - |
|
623 | - |
|
624 | - /** |
|
625 | - * Gets code |
|
626 | - * |
|
627 | - * @return string |
|
628 | - * @throws EE_Error |
|
629 | - * @throws InvalidArgumentException |
|
630 | - * @throws InvalidDataTypeException |
|
631 | - * @throws InvalidInterfaceException |
|
632 | - * @throws ReflectionException |
|
633 | - */ |
|
634 | - public function code() |
|
635 | - { |
|
636 | - return $this->get('LIN_code'); |
|
637 | - } |
|
638 | - |
|
639 | - |
|
640 | - /** |
|
641 | - * Sets code |
|
642 | - * |
|
643 | - * @param string $code |
|
644 | - * @throws EE_Error |
|
645 | - * @throws InvalidArgumentException |
|
646 | - * @throws InvalidDataTypeException |
|
647 | - * @throws InvalidInterfaceException |
|
648 | - * @throws ReflectionException |
|
649 | - */ |
|
650 | - public function set_code($code) |
|
651 | - { |
|
652 | - $this->set('LIN_code', $code); |
|
653 | - } |
|
654 | - |
|
655 | - |
|
656 | - /** |
|
657 | - * Gets is_taxable |
|
658 | - * |
|
659 | - * @return boolean |
|
660 | - * @throws EE_Error |
|
661 | - * @throws InvalidArgumentException |
|
662 | - * @throws InvalidDataTypeException |
|
663 | - * @throws InvalidInterfaceException |
|
664 | - * @throws ReflectionException |
|
665 | - */ |
|
666 | - public function is_taxable() |
|
667 | - { |
|
668 | - return $this->get('LIN_is_taxable'); |
|
669 | - } |
|
670 | - |
|
671 | - |
|
672 | - /** |
|
673 | - * Sets is_taxable |
|
674 | - * |
|
675 | - * @param boolean $is_taxable |
|
676 | - * @throws EE_Error |
|
677 | - * @throws InvalidArgumentException |
|
678 | - * @throws InvalidDataTypeException |
|
679 | - * @throws InvalidInterfaceException |
|
680 | - * @throws ReflectionException |
|
681 | - */ |
|
682 | - public function set_is_taxable($is_taxable) |
|
683 | - { |
|
684 | - $this->set('LIN_is_taxable', $is_taxable); |
|
685 | - } |
|
686 | - |
|
687 | - |
|
688 | - /** |
|
689 | - * Gets the object that this model-joins-to. |
|
690 | - * returns one of the model objects that the field OBJ_ID can point to... see the 'OBJ_ID' field on |
|
691 | - * EEM_Promotion_Object |
|
692 | - * Eg, if this line item join model object is for a ticket, this will return the EE_Ticket object |
|
693 | - * |
|
694 | - * @return EE_Base_Class | NULL |
|
695 | - * @throws EE_Error |
|
696 | - * @throws InvalidArgumentException |
|
697 | - * @throws InvalidDataTypeException |
|
698 | - * @throws InvalidInterfaceException |
|
699 | - * @throws ReflectionException |
|
700 | - */ |
|
701 | - public function get_object() |
|
702 | - { |
|
703 | - $model_name_of_related_obj = $this->OBJ_type(); |
|
704 | - return $this->get_model()->has_relation($model_name_of_related_obj) |
|
705 | - ? $this->get_first_related($model_name_of_related_obj) |
|
706 | - : null; |
|
707 | - } |
|
708 | - |
|
709 | - |
|
710 | - /** |
|
711 | - * Like EE_Line_Item::get_object(), but can only ever actually return an EE_Ticket. |
|
712 | - * (IE, if this line item is for a price or something else, will return NULL) |
|
713 | - * |
|
714 | - * @param array $query_params |
|
715 | - * @return EE_Base_Class|EE_Ticket |
|
716 | - * @throws EE_Error |
|
717 | - * @throws InvalidArgumentException |
|
718 | - * @throws InvalidDataTypeException |
|
719 | - * @throws InvalidInterfaceException |
|
720 | - * @throws ReflectionException |
|
721 | - */ |
|
722 | - public function ticket($query_params = array()) |
|
723 | - { |
|
724 | - // we're going to assume that when this method is called |
|
725 | - // we always want to receive the attached ticket EVEN if that ticket is archived. |
|
726 | - // This can be overridden via the incoming $query_params argument |
|
727 | - $remove_defaults = array('default_where_conditions' => 'none'); |
|
728 | - $query_params = array_merge($remove_defaults, $query_params); |
|
729 | - return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TICKET, $query_params); |
|
730 | - } |
|
731 | - |
|
732 | - |
|
733 | - /** |
|
734 | - * Gets the EE_Datetime that's related to the ticket, IF this is for a ticket |
|
735 | - * |
|
736 | - * @return EE_Datetime | NULL |
|
737 | - * @throws EE_Error |
|
738 | - * @throws InvalidArgumentException |
|
739 | - * @throws InvalidDataTypeException |
|
740 | - * @throws InvalidInterfaceException |
|
741 | - * @throws ReflectionException |
|
742 | - */ |
|
743 | - public function get_ticket_datetime() |
|
744 | - { |
|
745 | - if ($this->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
746 | - $ticket = $this->ticket(); |
|
747 | - if ($ticket instanceof EE_Ticket) { |
|
748 | - $datetime = $ticket->first_datetime(); |
|
749 | - if ($datetime instanceof EE_Datetime) { |
|
750 | - return $datetime; |
|
751 | - } |
|
752 | - } |
|
753 | - } |
|
754 | - return null; |
|
755 | - } |
|
756 | - |
|
757 | - |
|
758 | - /** |
|
759 | - * Gets the event's name that's related to the ticket, if this is for |
|
760 | - * a ticket |
|
761 | - * |
|
762 | - * @return string |
|
763 | - * @throws EE_Error |
|
764 | - * @throws InvalidArgumentException |
|
765 | - * @throws InvalidDataTypeException |
|
766 | - * @throws InvalidInterfaceException |
|
767 | - * @throws ReflectionException |
|
768 | - */ |
|
769 | - public function ticket_event_name() |
|
770 | - { |
|
771 | - $event_name = esc_html__('Unknown', 'event_espresso'); |
|
772 | - $event = $this->ticket_event(); |
|
773 | - if ($event instanceof EE_Event) { |
|
774 | - $event_name = $event->name(); |
|
775 | - } |
|
776 | - return $event_name; |
|
777 | - } |
|
778 | - |
|
779 | - |
|
780 | - /** |
|
781 | - * Gets the event that's related to the ticket, if this line item represents a ticket. |
|
782 | - * |
|
783 | - * @return EE_Event|null |
|
784 | - * @throws EE_Error |
|
785 | - * @throws InvalidArgumentException |
|
786 | - * @throws InvalidDataTypeException |
|
787 | - * @throws InvalidInterfaceException |
|
788 | - * @throws ReflectionException |
|
789 | - */ |
|
790 | - public function ticket_event() |
|
791 | - { |
|
792 | - $event = null; |
|
793 | - $ticket = $this->ticket(); |
|
794 | - if ($ticket instanceof EE_Ticket) { |
|
795 | - $datetime = $ticket->first_datetime(); |
|
796 | - if ($datetime instanceof EE_Datetime) { |
|
797 | - $event = $datetime->event(); |
|
798 | - } |
|
799 | - } |
|
800 | - return $event; |
|
801 | - } |
|
802 | - |
|
803 | - |
|
804 | - /** |
|
805 | - * Gets the first datetime for this lien item, assuming it's for a ticket |
|
806 | - * |
|
807 | - * @param string $date_format |
|
808 | - * @param string $time_format |
|
809 | - * @return string |
|
810 | - * @throws EE_Error |
|
811 | - * @throws InvalidArgumentException |
|
812 | - * @throws InvalidDataTypeException |
|
813 | - * @throws InvalidInterfaceException |
|
814 | - * @throws ReflectionException |
|
815 | - */ |
|
816 | - public function ticket_datetime_start($date_format = '', $time_format = '') |
|
817 | - { |
|
818 | - $first_datetime_string = esc_html__('Unknown', 'event_espresso'); |
|
819 | - $datetime = $this->get_ticket_datetime(); |
|
820 | - if ($datetime) { |
|
821 | - $first_datetime_string = $datetime->start_date_and_time($date_format, $time_format); |
|
822 | - } |
|
823 | - return $first_datetime_string; |
|
824 | - } |
|
825 | - |
|
826 | - |
|
827 | - /** |
|
828 | - * Adds the line item as a child to this line item. If there is another child line |
|
829 | - * item with the same LIN_code, it is overwritten by this new one |
|
830 | - * |
|
831 | - * @param EEI_Line_Item $line_item |
|
832 | - * @param bool $set_order |
|
833 | - * @return bool success |
|
834 | - * @throws EE_Error |
|
835 | - * @throws InvalidArgumentException |
|
836 | - * @throws InvalidDataTypeException |
|
837 | - * @throws InvalidInterfaceException |
|
838 | - * @throws ReflectionException |
|
839 | - */ |
|
840 | - public function add_child_line_item(EEI_Line_Item $line_item, $set_order = true) |
|
841 | - { |
|
842 | - // should we calculate the LIN_order for this line item ? |
|
843 | - if ($set_order || $line_item->order() === null) { |
|
844 | - $line_item->set_order(count($this->children())); |
|
845 | - } |
|
846 | - if ($this->ID()) { |
|
847 | - // check for any duplicate line items (with the same code), if so, this replaces it |
|
848 | - $line_item_with_same_code = $this->get_child_line_item($line_item->code()); |
|
849 | - if ($line_item_with_same_code instanceof EE_Line_Item && $line_item_with_same_code !== $line_item) { |
|
850 | - $this->delete_child_line_item($line_item_with_same_code->code()); |
|
851 | - } |
|
852 | - $line_item->set_parent_ID($this->ID()); |
|
853 | - if ($this->TXN_ID()) { |
|
854 | - $line_item->set_TXN_ID($this->TXN_ID()); |
|
855 | - } |
|
856 | - return $line_item->save(); |
|
857 | - } |
|
858 | - $this->_children[ $line_item->code() ] = $line_item; |
|
859 | - if ($line_item->parent() !== $this) { |
|
860 | - $line_item->set_parent($this); |
|
861 | - } |
|
862 | - return true; |
|
863 | - } |
|
864 | - |
|
865 | - |
|
866 | - /** |
|
867 | - * Similar to EE_Base_Class::_add_relation_to, except this isn't a normal relation. |
|
868 | - * If this line item is saved to the DB, this is just a wrapper for set_parent_ID() and save() |
|
869 | - * However, if this line item is NOT saved to the DB, this just caches the parent on |
|
870 | - * the EE_Line_Item::_parent property. |
|
871 | - * |
|
872 | - * @param EE_Line_Item $line_item |
|
873 | - * @throws EE_Error |
|
874 | - * @throws InvalidArgumentException |
|
875 | - * @throws InvalidDataTypeException |
|
876 | - * @throws InvalidInterfaceException |
|
877 | - * @throws ReflectionException |
|
878 | - */ |
|
879 | - public function set_parent($line_item) |
|
880 | - { |
|
881 | - if ($this->ID()) { |
|
882 | - if (! $line_item->ID()) { |
|
883 | - $line_item->save(); |
|
884 | - } |
|
885 | - $this->set_parent_ID($line_item->ID()); |
|
886 | - $this->save(); |
|
887 | - } else { |
|
888 | - $this->_parent = $line_item; |
|
889 | - $this->set_parent_ID($line_item->ID()); |
|
890 | - } |
|
891 | - } |
|
892 | - |
|
893 | - |
|
894 | - /** |
|
895 | - * Gets the child line item as specified by its code. Because this returns an object (by reference) |
|
896 | - * you can modify this child line item and the parent (this object) can know about them |
|
897 | - * because it also has a reference to that line item |
|
898 | - * |
|
899 | - * @param string $code |
|
900 | - * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
901 | - * @throws EE_Error |
|
902 | - * @throws InvalidArgumentException |
|
903 | - * @throws InvalidDataTypeException |
|
904 | - * @throws InvalidInterfaceException |
|
905 | - * @throws ReflectionException |
|
906 | - */ |
|
907 | - public function get_child_line_item($code) |
|
908 | - { |
|
909 | - if ($this->ID()) { |
|
910 | - return $this->get_model()->get_one( |
|
911 | - array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code)) |
|
912 | - ); |
|
913 | - } |
|
914 | - return isset($this->_children[ $code ]) |
|
915 | - ? $this->_children[ $code ] |
|
916 | - : null; |
|
917 | - } |
|
918 | - |
|
919 | - |
|
920 | - /** |
|
921 | - * Returns how many items are deleted (or, if this item has not been saved ot the DB yet, just how many it HAD |
|
922 | - * cached on it) |
|
923 | - * |
|
924 | - * @return int |
|
925 | - * @throws EE_Error |
|
926 | - * @throws InvalidArgumentException |
|
927 | - * @throws InvalidDataTypeException |
|
928 | - * @throws InvalidInterfaceException |
|
929 | - * @throws ReflectionException |
|
930 | - */ |
|
931 | - public function delete_children_line_items() |
|
932 | - { |
|
933 | - if ($this->ID()) { |
|
934 | - return $this->get_model()->delete(array(array('LIN_parent' => $this->ID()))); |
|
935 | - } |
|
936 | - $count = count($this->_children); |
|
937 | - $this->_children = array(); |
|
938 | - return $count; |
|
939 | - } |
|
940 | - |
|
941 | - |
|
942 | - /** |
|
943 | - * If this line item has been saved to the DB, deletes its child with LIN_code == $code. If this line |
|
944 | - * HAS NOT been saved to the DB, removes the child line item with index $code. |
|
945 | - * Also searches through the child's children for a matching line item. However, once a line item has been found |
|
946 | - * and deleted, stops searching (so if there are line items with duplicate codes, only the first one found will be |
|
947 | - * deleted) |
|
948 | - * |
|
949 | - * @param string $code |
|
950 | - * @param bool $stop_search_once_found |
|
951 | - * @return int count of items deleted (or simply removed from the line item's cache, if not has not been saved to |
|
952 | - * the DB yet) |
|
953 | - * @throws EE_Error |
|
954 | - * @throws InvalidArgumentException |
|
955 | - * @throws InvalidDataTypeException |
|
956 | - * @throws InvalidInterfaceException |
|
957 | - * @throws ReflectionException |
|
958 | - */ |
|
959 | - public function delete_child_line_item($code, $stop_search_once_found = true) |
|
960 | - { |
|
961 | - if ($this->ID()) { |
|
962 | - $items_deleted = 0; |
|
963 | - if ($this->code() === $code) { |
|
964 | - $items_deleted += EEH_Line_Item::delete_all_child_items($this); |
|
965 | - $items_deleted += (int) $this->delete(); |
|
966 | - if ($stop_search_once_found) { |
|
967 | - return $items_deleted; |
|
968 | - } |
|
969 | - } |
|
970 | - foreach ($this->children() as $child_line_item) { |
|
971 | - $items_deleted += $child_line_item->delete_child_line_item($code, $stop_search_once_found); |
|
972 | - } |
|
973 | - return $items_deleted; |
|
974 | - } |
|
975 | - if (isset($this->_children[ $code ])) { |
|
976 | - unset($this->_children[ $code ]); |
|
977 | - return 1; |
|
978 | - } |
|
979 | - return 0; |
|
980 | - } |
|
981 | - |
|
982 | - |
|
983 | - /** |
|
984 | - * If this line item is in the database, is of the type subtotal, and |
|
985 | - * has no children, why do we have it? It should be deleted so this function |
|
986 | - * does that |
|
987 | - * |
|
988 | - * @return boolean |
|
989 | - * @throws EE_Error |
|
990 | - * @throws InvalidArgumentException |
|
991 | - * @throws InvalidDataTypeException |
|
992 | - * @throws InvalidInterfaceException |
|
993 | - * @throws ReflectionException |
|
994 | - */ |
|
995 | - public function delete_if_childless_subtotal() |
|
996 | - { |
|
997 | - if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && ! $this->children()) { |
|
998 | - return $this->delete(); |
|
999 | - } |
|
1000 | - return false; |
|
1001 | - } |
|
1002 | - |
|
1003 | - |
|
1004 | - /** |
|
1005 | - * Creates a code and returns a string. doesn't assign the code to this model object |
|
1006 | - * |
|
1007 | - * @return string |
|
1008 | - * @throws EE_Error |
|
1009 | - * @throws InvalidArgumentException |
|
1010 | - * @throws InvalidDataTypeException |
|
1011 | - * @throws InvalidInterfaceException |
|
1012 | - * @throws ReflectionException |
|
1013 | - */ |
|
1014 | - public function generate_code() |
|
1015 | - { |
|
1016 | - // each line item in the cart requires a unique identifier |
|
1017 | - return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime()); |
|
1018 | - } |
|
1019 | - |
|
1020 | - |
|
1021 | - /** |
|
1022 | - * @return bool |
|
1023 | - * @throws EE_Error |
|
1024 | - * @throws InvalidArgumentException |
|
1025 | - * @throws InvalidDataTypeException |
|
1026 | - * @throws InvalidInterfaceException |
|
1027 | - * @throws ReflectionException |
|
1028 | - */ |
|
1029 | - public function is_tax() |
|
1030 | - { |
|
1031 | - return $this->type() === EEM_Line_Item::type_tax; |
|
1032 | - } |
|
1033 | - |
|
1034 | - |
|
1035 | - /** |
|
1036 | - * @return bool |
|
1037 | - * @throws EE_Error |
|
1038 | - * @throws InvalidArgumentException |
|
1039 | - * @throws InvalidDataTypeException |
|
1040 | - * @throws InvalidInterfaceException |
|
1041 | - * @throws ReflectionException |
|
1042 | - */ |
|
1043 | - public function is_tax_sub_total() |
|
1044 | - { |
|
1045 | - return $this->type() === EEM_Line_Item::type_tax_sub_total; |
|
1046 | - } |
|
1047 | - |
|
1048 | - |
|
1049 | - /** |
|
1050 | - * @return bool |
|
1051 | - * @throws EE_Error |
|
1052 | - * @throws InvalidArgumentException |
|
1053 | - * @throws InvalidDataTypeException |
|
1054 | - * @throws InvalidInterfaceException |
|
1055 | - * @throws ReflectionException |
|
1056 | - */ |
|
1057 | - public function is_line_item() |
|
1058 | - { |
|
1059 | - return $this->type() === EEM_Line_Item::type_line_item; |
|
1060 | - } |
|
1061 | - |
|
1062 | - |
|
1063 | - /** |
|
1064 | - * @return bool |
|
1065 | - * @throws EE_Error |
|
1066 | - * @throws InvalidArgumentException |
|
1067 | - * @throws InvalidDataTypeException |
|
1068 | - * @throws InvalidInterfaceException |
|
1069 | - * @throws ReflectionException |
|
1070 | - */ |
|
1071 | - public function is_sub_line_item() |
|
1072 | - { |
|
1073 | - return $this->type() === EEM_Line_Item::type_sub_line_item; |
|
1074 | - } |
|
1075 | - |
|
1076 | - |
|
1077 | - /** |
|
1078 | - * @return bool |
|
1079 | - * @throws EE_Error |
|
1080 | - * @throws InvalidArgumentException |
|
1081 | - * @throws InvalidDataTypeException |
|
1082 | - * @throws InvalidInterfaceException |
|
1083 | - * @throws ReflectionException |
|
1084 | - */ |
|
1085 | - public function is_sub_total() |
|
1086 | - { |
|
1087 | - return $this->type() === EEM_Line_Item::type_sub_total; |
|
1088 | - } |
|
1089 | - |
|
1090 | - |
|
1091 | - /** |
|
1092 | - * Whether or not this line item is a cancellation line item |
|
1093 | - * |
|
1094 | - * @return boolean |
|
1095 | - * @throws EE_Error |
|
1096 | - * @throws InvalidArgumentException |
|
1097 | - * @throws InvalidDataTypeException |
|
1098 | - * @throws InvalidInterfaceException |
|
1099 | - * @throws ReflectionException |
|
1100 | - */ |
|
1101 | - public function is_cancellation() |
|
1102 | - { |
|
1103 | - return EEM_Line_Item::type_cancellation === $this->type(); |
|
1104 | - } |
|
1105 | - |
|
1106 | - |
|
1107 | - /** |
|
1108 | - * @return bool |
|
1109 | - * @throws EE_Error |
|
1110 | - * @throws InvalidArgumentException |
|
1111 | - * @throws InvalidDataTypeException |
|
1112 | - * @throws InvalidInterfaceException |
|
1113 | - * @throws ReflectionException |
|
1114 | - */ |
|
1115 | - public function is_total() |
|
1116 | - { |
|
1117 | - return $this->type() === EEM_Line_Item::type_total; |
|
1118 | - } |
|
1119 | - |
|
1120 | - |
|
1121 | - /** |
|
1122 | - * @return bool |
|
1123 | - * @throws EE_Error |
|
1124 | - * @throws InvalidArgumentException |
|
1125 | - * @throws InvalidDataTypeException |
|
1126 | - * @throws InvalidInterfaceException |
|
1127 | - * @throws ReflectionException |
|
1128 | - */ |
|
1129 | - public function is_cancelled() |
|
1130 | - { |
|
1131 | - return $this->type() === EEM_Line_Item::type_cancellation; |
|
1132 | - } |
|
1133 | - |
|
1134 | - |
|
1135 | - /** |
|
1136 | - * @return string like '2, 004.00', formatted according to the localized currency |
|
1137 | - * @throws EE_Error |
|
1138 | - * @throws InvalidArgumentException |
|
1139 | - * @throws InvalidDataTypeException |
|
1140 | - * @throws InvalidInterfaceException |
|
1141 | - * @throws ReflectionException |
|
1142 | - */ |
|
1143 | - public function unit_price_no_code() |
|
1144 | - { |
|
1145 | - return $this->get_pretty('LIN_unit_price', 'no_currency_code'); |
|
1146 | - } |
|
1147 | - |
|
1148 | - |
|
1149 | - /** |
|
1150 | - * @return string like '2, 004.00', formatted according to the localized currency |
|
1151 | - * @throws EE_Error |
|
1152 | - * @throws InvalidArgumentException |
|
1153 | - * @throws InvalidDataTypeException |
|
1154 | - * @throws InvalidInterfaceException |
|
1155 | - * @throws ReflectionException |
|
1156 | - */ |
|
1157 | - public function total_no_code() |
|
1158 | - { |
|
1159 | - return $this->get_pretty('LIN_total', 'no_currency_code'); |
|
1160 | - } |
|
1161 | - |
|
1162 | - |
|
1163 | - /** |
|
1164 | - * Gets the final total on this item, taking taxes into account. |
|
1165 | - * Has the side-effect of setting the sub-total as it was just calculated. |
|
1166 | - * If this is used on a grand-total line item, also updates the transaction's |
|
1167 | - * TXN_total (provided this line item is allowed to persist, otherwise we don't |
|
1168 | - * want to change a persistable transaction with info from a non-persistent line item) |
|
1169 | - * |
|
1170 | - * @param bool $update_txn_status |
|
1171 | - * @return float |
|
1172 | - * @throws EE_Error |
|
1173 | - * @throws InvalidArgumentException |
|
1174 | - * @throws InvalidDataTypeException |
|
1175 | - * @throws InvalidInterfaceException |
|
1176 | - * @throws ReflectionException |
|
1177 | - * @throws RuntimeException |
|
1178 | - */ |
|
1179 | - public function recalculate_total_including_taxes($update_txn_status = false) |
|
1180 | - { |
|
1181 | - $pre_tax_total = $this->recalculate_pre_tax_total(); |
|
1182 | - $tax_total = $this->recalculate_taxes_and_tax_total(); |
|
1183 | - $total = $pre_tax_total + $tax_total; |
|
1184 | - // no negative totals plz |
|
1185 | - $total = max($total, 0); |
|
1186 | - $this->set_total($total); |
|
1187 | - // only update the related transaction's total |
|
1188 | - // if we intend to save this line item and its a grand total |
|
1189 | - if ( |
|
1190 | - $this->allow_persist() && $this->type() === EEM_Line_Item::type_total |
|
1191 | - && $this->transaction() |
|
1192 | - instanceof |
|
1193 | - EE_Transaction |
|
1194 | - ) { |
|
1195 | - $this->transaction()->set_total($total); |
|
1196 | - if ($update_txn_status) { |
|
1197 | - // don't save the TXN because that will be done below |
|
1198 | - // and the following method only saves if the status changes |
|
1199 | - $this->transaction()->update_status_based_on_total_paid(false); |
|
1200 | - } |
|
1201 | - if ($this->transaction()->ID()) { |
|
1202 | - $this->transaction()->save(); |
|
1203 | - } |
|
1204 | - } |
|
1205 | - $this->maybe_save(); |
|
1206 | - return $total; |
|
1207 | - } |
|
1208 | - |
|
1209 | - |
|
1210 | - /** |
|
1211 | - * Recursively goes through all the children and recalculates sub-totals EXCEPT for |
|
1212 | - * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its |
|
1213 | - * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and |
|
1214 | - * when this is called on the grand total |
|
1215 | - * |
|
1216 | - * @return float |
|
1217 | - * @throws EE_Error |
|
1218 | - * @throws InvalidArgumentException |
|
1219 | - * @throws InvalidDataTypeException |
|
1220 | - * @throws InvalidInterfaceException |
|
1221 | - * @throws ReflectionException |
|
1222 | - */ |
|
1223 | - public function recalculate_pre_tax_total() |
|
1224 | - { |
|
1225 | - $total = 0; |
|
1226 | - $my_children = $this->children(); |
|
1227 | - $has_children = ! empty($my_children); |
|
1228 | - if ($has_children && $this->is_line_item()) { |
|
1229 | - $total = $this->_recalculate_pretax_total_for_line_item($total, $my_children); |
|
1230 | - } elseif (! $has_children && ($this->is_sub_line_item() || $this->is_line_item())) { |
|
1231 | - $total = $this->unit_price() * $this->quantity(); |
|
1232 | - } elseif ($this->is_sub_total() || $this->is_total()) { |
|
1233 | - $total = $this->_recalculate_pretax_total_for_subtotal($total, $my_children); |
|
1234 | - } elseif ($this->is_tax_sub_total() || $this->is_tax() || $this->is_cancelled()) { |
|
1235 | - // completely ignore tax totals, tax sub-totals, and cancelled line items, when calculating the pre-tax-total |
|
1236 | - return 0; |
|
1237 | - } |
|
1238 | - // ensure all non-line items and non-sub-line-items have a quantity of 1 (except for Events) |
|
1239 | - if ( |
|
1240 | - ! $this->is_line_item() && ! $this->is_sub_line_item() && ! $this->is_cancellation() |
|
1241 | - ) { |
|
1242 | - if ($this->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_EVENT) { |
|
1243 | - $this->set_quantity(1); |
|
1244 | - } |
|
1245 | - if (! $this->is_percent()) { |
|
1246 | - $this->set_unit_price($total); |
|
1247 | - } |
|
1248 | - } |
|
1249 | - // we don't want to bother saving grand totals, because that needs to factor in taxes anyways |
|
1250 | - // so it ought to be |
|
1251 | - if (! $this->is_total()) { |
|
1252 | - $this->set_total($total); |
|
1253 | - // if not a percent line item, make sure we keep the unit price in sync |
|
1254 | - if ( |
|
1255 | - $has_children |
|
1256 | - && $this->is_line_item() |
|
1257 | - && ! $this->is_percent() |
|
1258 | - ) { |
|
1259 | - if ($this->quantity() === 0) { |
|
1260 | - $new_unit_price = 0; |
|
1261 | - } else { |
|
1262 | - $new_unit_price = $this->total() / $this->quantity(); |
|
1263 | - } |
|
1264 | - $this->set_unit_price($new_unit_price); |
|
1265 | - } |
|
1266 | - $this->maybe_save(); |
|
1267 | - } |
|
1268 | - return $total; |
|
1269 | - } |
|
1270 | - |
|
1271 | - |
|
1272 | - /** |
|
1273 | - * Calculates the pretax total when this line item is a subtotal or total line item. |
|
1274 | - * Basically does a sum-then-round approach (ie, any percent line item that are children |
|
1275 | - * will calculate their total based on the un-rounded total we're working with so far, and |
|
1276 | - * THEN round the result; instead of rounding as we go like with sub-line-items) |
|
1277 | - * |
|
1278 | - * @param float $calculated_total_so_far |
|
1279 | - * @param EE_Line_Item[] $my_children |
|
1280 | - * @return float |
|
1281 | - * @throws EE_Error |
|
1282 | - * @throws InvalidArgumentException |
|
1283 | - * @throws InvalidDataTypeException |
|
1284 | - * @throws InvalidInterfaceException |
|
1285 | - * @throws ReflectionException |
|
1286 | - */ |
|
1287 | - protected function _recalculate_pretax_total_for_subtotal($calculated_total_so_far, $my_children = null) |
|
1288 | - { |
|
1289 | - if ($my_children === null) { |
|
1290 | - $my_children = $this->children(); |
|
1291 | - } |
|
1292 | - $subtotal_quantity = 0; |
|
1293 | - // get the total of all its children |
|
1294 | - foreach ($my_children as $child_line_item) { |
|
1295 | - if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) { |
|
1296 | - // percentage line items are based on total so far |
|
1297 | - if ($child_line_item->is_percent()) { |
|
1298 | - // round as we go so that the line items add up ok |
|
1299 | - $percent_total = round( |
|
1300 | - $calculated_total_so_far * $child_line_item->percent() / 100, |
|
1301 | - EE_Registry::instance()->CFG->currency->dec_plc |
|
1302 | - ); |
|
1303 | - $child_line_item->set_total($percent_total); |
|
1304 | - // so far all percent line items should have a quantity of 1 |
|
1305 | - // (ie, no double percent discounts. Although that might be requested someday) |
|
1306 | - $child_line_item->set_quantity(1); |
|
1307 | - $child_line_item->maybe_save(); |
|
1308 | - $calculated_total_so_far += $percent_total; |
|
1309 | - } else { |
|
1310 | - // verify flat sub-line-item quantities match their parent |
|
1311 | - if ($child_line_item->is_sub_line_item()) { |
|
1312 | - $child_line_item->set_quantity($this->quantity()); |
|
1313 | - } |
|
1314 | - $calculated_total_so_far += $child_line_item->recalculate_pre_tax_total(); |
|
1315 | - $subtotal_quantity += $child_line_item->quantity(); |
|
1316 | - } |
|
1317 | - } |
|
1318 | - } |
|
1319 | - if ($this->is_sub_total()) { |
|
1320 | - // no negative totals plz |
|
1321 | - $calculated_total_so_far = max($calculated_total_so_far, 0); |
|
1322 | - $subtotal_quantity = $subtotal_quantity > 0 ? 1 : 0; |
|
1323 | - $this->set_quantity($subtotal_quantity); |
|
1324 | - $this->maybe_save(); |
|
1325 | - } |
|
1326 | - return $calculated_total_so_far; |
|
1327 | - } |
|
1328 | - |
|
1329 | - |
|
1330 | - /** |
|
1331 | - * Calculates the pretax total for a normal line item, in a round-then-sum approach |
|
1332 | - * (where each sub-line-item is applied to the base price for the line item |
|
1333 | - * and the result is immediately rounded, rather than summing all the sub-line-items |
|
1334 | - * then rounding, like we do when recalculating pretax totals on totals and subtotals). |
|
1335 | - * |
|
1336 | - * @param float $calculated_total_so_far |
|
1337 | - * @param EE_Line_Item[] $my_children |
|
1338 | - * @return float |
|
1339 | - * @throws EE_Error |
|
1340 | - * @throws InvalidArgumentException |
|
1341 | - * @throws InvalidDataTypeException |
|
1342 | - * @throws InvalidInterfaceException |
|
1343 | - * @throws ReflectionException |
|
1344 | - */ |
|
1345 | - protected function _recalculate_pretax_total_for_line_item($calculated_total_so_far, $my_children = null) |
|
1346 | - { |
|
1347 | - if ($my_children === null) { |
|
1348 | - $my_children = $this->children(); |
|
1349 | - } |
|
1350 | - // we need to keep track of the running total for a single item, |
|
1351 | - // because we need to round as we go |
|
1352 | - $unit_price_for_total = 0; |
|
1353 | - $quantity_for_total = 1; |
|
1354 | - // get the total of all its children |
|
1355 | - foreach ($my_children as $child_line_item) { |
|
1356 | - if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) { |
|
1357 | - if ($child_line_item->is_percent()) { |
|
1358 | - // it should be the unit-price-so-far multiplied by teh percent multiplied by the quantity |
|
1359 | - // not total multiplied by percent, because that ignores rounding along-the-way |
|
1360 | - $percent_unit_price = round( |
|
1361 | - $unit_price_for_total * $child_line_item->percent() / 100, |
|
1362 | - EE_Registry::instance()->CFG->currency->dec_plc |
|
1363 | - ); |
|
1364 | - $percent_total = $percent_unit_price * $quantity_for_total; |
|
1365 | - $child_line_item->set_total($percent_total); |
|
1366 | - // so far all percent line items should have a quantity of 1 |
|
1367 | - // (ie, no double percent discounts. Although that might be requested someday) |
|
1368 | - $child_line_item->set_quantity(1); |
|
1369 | - $child_line_item->maybe_save(); |
|
1370 | - $calculated_total_so_far += $percent_total; |
|
1371 | - $unit_price_for_total += $percent_unit_price; |
|
1372 | - } else { |
|
1373 | - // verify flat sub-line-item quantities match their parent |
|
1374 | - if ($child_line_item->is_sub_line_item()) { |
|
1375 | - $child_line_item->set_quantity($this->quantity()); |
|
1376 | - } |
|
1377 | - $quantity_for_total = $child_line_item->quantity(); |
|
1378 | - $calculated_total_so_far += $child_line_item->recalculate_pre_tax_total(); |
|
1379 | - $unit_price_for_total += $child_line_item->unit_price(); |
|
1380 | - } |
|
1381 | - } |
|
1382 | - } |
|
1383 | - return $calculated_total_so_far; |
|
1384 | - } |
|
1385 | - |
|
1386 | - |
|
1387 | - /** |
|
1388 | - * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets |
|
1389 | - * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items |
|
1390 | - * and tax sub-total if already in the DB |
|
1391 | - * |
|
1392 | - * @return float |
|
1393 | - * @throws EE_Error |
|
1394 | - * @throws InvalidArgumentException |
|
1395 | - * @throws InvalidDataTypeException |
|
1396 | - * @throws InvalidInterfaceException |
|
1397 | - * @throws ReflectionException |
|
1398 | - */ |
|
1399 | - public function recalculate_taxes_and_tax_total() |
|
1400 | - { |
|
1401 | - // get all taxes |
|
1402 | - $taxes = $this->tax_descendants(); |
|
1403 | - // calculate the pretax total |
|
1404 | - $taxable_total = $this->taxable_total(); |
|
1405 | - $tax_total = 0; |
|
1406 | - foreach ($taxes as $tax) { |
|
1407 | - $total_on_this_tax = $taxable_total * $tax->percent() / 100; |
|
1408 | - // remember the total on this line item |
|
1409 | - $tax->set_total($total_on_this_tax); |
|
1410 | - $tax->maybe_save(); |
|
1411 | - $tax_total += $tax->total(); |
|
1412 | - } |
|
1413 | - $this->_recalculate_tax_sub_total(); |
|
1414 | - return $tax_total; |
|
1415 | - } |
|
1416 | - |
|
1417 | - |
|
1418 | - /** |
|
1419 | - * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated |
|
1420 | - * |
|
1421 | - * @return void |
|
1422 | - * @throws EE_Error |
|
1423 | - * @throws InvalidArgumentException |
|
1424 | - * @throws InvalidDataTypeException |
|
1425 | - * @throws InvalidInterfaceException |
|
1426 | - * @throws ReflectionException |
|
1427 | - */ |
|
1428 | - private function _recalculate_tax_sub_total() |
|
1429 | - { |
|
1430 | - if ($this->is_tax_sub_total()) { |
|
1431 | - $total = 0; |
|
1432 | - $total_percent = 0; |
|
1433 | - // simply loop through all its children (which should be taxes) and sum their total |
|
1434 | - foreach ($this->children() as $child_tax) { |
|
1435 | - if ($child_tax instanceof EE_Line_Item) { |
|
1436 | - $total += $child_tax->total(); |
|
1437 | - $total_percent += $child_tax->percent(); |
|
1438 | - } |
|
1439 | - } |
|
1440 | - $this->set_total($total); |
|
1441 | - $this->set_percent($total_percent); |
|
1442 | - $this->maybe_save(); |
|
1443 | - } elseif ($this->is_total()) { |
|
1444 | - foreach ($this->children() as $maybe_tax_subtotal) { |
|
1445 | - if ($maybe_tax_subtotal instanceof EE_Line_Item) { |
|
1446 | - $maybe_tax_subtotal->_recalculate_tax_sub_total(); |
|
1447 | - } |
|
1448 | - } |
|
1449 | - } |
|
1450 | - } |
|
1451 | - |
|
1452 | - |
|
1453 | - /** |
|
1454 | - * Gets the total tax on this line item. Assumes taxes have already been calculated using |
|
1455 | - * recalculate_taxes_and_total |
|
1456 | - * |
|
1457 | - * @return float |
|
1458 | - * @throws EE_Error |
|
1459 | - * @throws InvalidArgumentException |
|
1460 | - * @throws InvalidDataTypeException |
|
1461 | - * @throws InvalidInterfaceException |
|
1462 | - * @throws ReflectionException |
|
1463 | - */ |
|
1464 | - public function get_total_tax() |
|
1465 | - { |
|
1466 | - $this->_recalculate_tax_sub_total(); |
|
1467 | - $total = 0; |
|
1468 | - foreach ($this->tax_descendants() as $tax_line_item) { |
|
1469 | - if ($tax_line_item instanceof EE_Line_Item) { |
|
1470 | - $total += $tax_line_item->total(); |
|
1471 | - } |
|
1472 | - } |
|
1473 | - return $total; |
|
1474 | - } |
|
1475 | - |
|
1476 | - |
|
1477 | - /** |
|
1478 | - * Gets the total for all the items purchased only |
|
1479 | - * |
|
1480 | - * @return float |
|
1481 | - * @throws EE_Error |
|
1482 | - * @throws InvalidArgumentException |
|
1483 | - * @throws InvalidDataTypeException |
|
1484 | - * @throws InvalidInterfaceException |
|
1485 | - * @throws ReflectionException |
|
1486 | - */ |
|
1487 | - public function get_items_total() |
|
1488 | - { |
|
1489 | - // by default, let's make sure we're consistent with the existing line item |
|
1490 | - if ($this->is_total()) { |
|
1491 | - $pretax_subtotal_li = EEH_Line_Item::get_pre_tax_subtotal($this); |
|
1492 | - if ($pretax_subtotal_li instanceof EE_Line_Item) { |
|
1493 | - return $pretax_subtotal_li->total(); |
|
1494 | - } |
|
1495 | - } |
|
1496 | - $total = 0; |
|
1497 | - foreach ($this->get_items() as $item) { |
|
1498 | - if ($item instanceof EE_Line_Item) { |
|
1499 | - $total += $item->total(); |
|
1500 | - } |
|
1501 | - } |
|
1502 | - return $total; |
|
1503 | - } |
|
1504 | - |
|
1505 | - |
|
1506 | - /** |
|
1507 | - * Gets all the descendants (ie, children or children of children etc) that |
|
1508 | - * are of the type 'tax' |
|
1509 | - * |
|
1510 | - * @return EE_Line_Item[] |
|
1511 | - * @throws EE_Error |
|
1512 | - */ |
|
1513 | - public function tax_descendants() |
|
1514 | - { |
|
1515 | - return EEH_Line_Item::get_tax_descendants($this); |
|
1516 | - } |
|
1517 | - |
|
1518 | - |
|
1519 | - /** |
|
1520 | - * Gets all the real items purchased which are children of this item |
|
1521 | - * |
|
1522 | - * @return EE_Line_Item[] |
|
1523 | - * @throws EE_Error |
|
1524 | - */ |
|
1525 | - public function get_items() |
|
1526 | - { |
|
1527 | - return EEH_Line_Item::get_line_item_descendants($this); |
|
1528 | - } |
|
1529 | - |
|
1530 | - |
|
1531 | - /** |
|
1532 | - * Returns the amount taxable among this line item's children (or if it has no children, |
|
1533 | - * how much of it is taxable). Does not recalculate totals or subtotals. |
|
1534 | - * If the taxable total is negative, (eg, if none of the tickets were taxable, |
|
1535 | - * but there is a "Taxable" discount), returns 0. |
|
1536 | - * |
|
1537 | - * @return float |
|
1538 | - * @throws EE_Error |
|
1539 | - * @throws InvalidArgumentException |
|
1540 | - * @throws InvalidDataTypeException |
|
1541 | - * @throws InvalidInterfaceException |
|
1542 | - * @throws ReflectionException |
|
1543 | - */ |
|
1544 | - public function taxable_total() |
|
1545 | - { |
|
1546 | - $total = 0; |
|
1547 | - if ($this->children()) { |
|
1548 | - foreach ($this->children() as $child_line_item) { |
|
1549 | - if ($child_line_item->type() === EEM_Line_Item::type_line_item && $child_line_item->is_taxable()) { |
|
1550 | - // if it's a percent item, only take into account the percent |
|
1551 | - // that's taxable too (the taxable total so far) |
|
1552 | - if ($child_line_item->is_percent()) { |
|
1553 | - $total += ($total * $child_line_item->percent() / 100); |
|
1554 | - } else { |
|
1555 | - $total += $child_line_item->total(); |
|
1556 | - } |
|
1557 | - } elseif ($child_line_item->type() === EEM_Line_Item::type_sub_total) { |
|
1558 | - $total += $child_line_item->taxable_total(); |
|
1559 | - } |
|
1560 | - } |
|
1561 | - } |
|
1562 | - return max($total, 0); |
|
1563 | - } |
|
1564 | - |
|
1565 | - |
|
1566 | - /** |
|
1567 | - * Gets the transaction for this line item |
|
1568 | - * |
|
1569 | - * @return EE_Base_Class|EE_Transaction |
|
1570 | - * @throws EE_Error |
|
1571 | - * @throws InvalidArgumentException |
|
1572 | - * @throws InvalidDataTypeException |
|
1573 | - * @throws InvalidInterfaceException |
|
1574 | - * @throws ReflectionException |
|
1575 | - */ |
|
1576 | - public function transaction() |
|
1577 | - { |
|
1578 | - return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TRANSACTION); |
|
1579 | - } |
|
1580 | - |
|
1581 | - |
|
1582 | - /** |
|
1583 | - * Saves this line item to the DB, and recursively saves its descendants. |
|
1584 | - * Because there currently is no proper parent-child relation on the model, |
|
1585 | - * save_this_and_cached() will NOT save the descendants. |
|
1586 | - * Also sets the transaction on this line item and all its descendants before saving |
|
1587 | - * |
|
1588 | - * @param int $txn_id if none is provided, assumes $this->TXN_ID() |
|
1589 | - * @return int count of items saved |
|
1590 | - * @throws EE_Error |
|
1591 | - * @throws InvalidArgumentException |
|
1592 | - * @throws InvalidDataTypeException |
|
1593 | - * @throws InvalidInterfaceException |
|
1594 | - * @throws ReflectionException |
|
1595 | - */ |
|
1596 | - public function save_this_and_descendants_to_txn($txn_id = null) |
|
1597 | - { |
|
1598 | - $count = 0; |
|
1599 | - if (! $txn_id) { |
|
1600 | - $txn_id = $this->TXN_ID(); |
|
1601 | - } |
|
1602 | - $this->set_TXN_ID($txn_id); |
|
1603 | - $children = $this->children(); |
|
1604 | - $count += $this->save() |
|
1605 | - ? 1 |
|
1606 | - : 0; |
|
1607 | - foreach ($children as $child_line_item) { |
|
1608 | - if ($child_line_item instanceof EE_Line_Item) { |
|
1609 | - $child_line_item->set_parent_ID($this->ID()); |
|
1610 | - $count += $child_line_item->save_this_and_descendants_to_txn($txn_id); |
|
1611 | - } |
|
1612 | - } |
|
1613 | - return $count; |
|
1614 | - } |
|
1615 | - |
|
1616 | - |
|
1617 | - /** |
|
1618 | - * Saves this line item to the DB, and recursively saves its descendants. |
|
1619 | - * |
|
1620 | - * @return int count of items saved |
|
1621 | - * @throws EE_Error |
|
1622 | - * @throws InvalidArgumentException |
|
1623 | - * @throws InvalidDataTypeException |
|
1624 | - * @throws InvalidInterfaceException |
|
1625 | - * @throws ReflectionException |
|
1626 | - */ |
|
1627 | - public function save_this_and_descendants() |
|
1628 | - { |
|
1629 | - $count = 0; |
|
1630 | - $children = $this->children(); |
|
1631 | - $count += $this->save() |
|
1632 | - ? 1 |
|
1633 | - : 0; |
|
1634 | - foreach ($children as $child_line_item) { |
|
1635 | - if ($child_line_item instanceof EE_Line_Item) { |
|
1636 | - $child_line_item->set_parent_ID($this->ID()); |
|
1637 | - $count += $child_line_item->save_this_and_descendants(); |
|
1638 | - } |
|
1639 | - } |
|
1640 | - return $count; |
|
1641 | - } |
|
1642 | - |
|
1643 | - |
|
1644 | - /** |
|
1645 | - * returns the cancellation line item if this item was cancelled |
|
1646 | - * |
|
1647 | - * @return EE_Line_Item[] |
|
1648 | - * @throws InvalidArgumentException |
|
1649 | - * @throws InvalidInterfaceException |
|
1650 | - * @throws InvalidDataTypeException |
|
1651 | - * @throws ReflectionException |
|
1652 | - * @throws EE_Error |
|
1653 | - */ |
|
1654 | - public function get_cancellations() |
|
1655 | - { |
|
1656 | - EE_Registry::instance()->load_helper('Line_Item'); |
|
1657 | - return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_cancellation); |
|
1658 | - } |
|
1659 | - |
|
1660 | - |
|
1661 | - /** |
|
1662 | - * If this item has an ID, then this saves it again to update the db |
|
1663 | - * |
|
1664 | - * @return int count of items saved |
|
1665 | - * @throws EE_Error |
|
1666 | - * @throws InvalidArgumentException |
|
1667 | - * @throws InvalidDataTypeException |
|
1668 | - * @throws InvalidInterfaceException |
|
1669 | - * @throws ReflectionException |
|
1670 | - */ |
|
1671 | - public function maybe_save() |
|
1672 | - { |
|
1673 | - if ($this->ID()) { |
|
1674 | - return $this->save(); |
|
1675 | - } |
|
1676 | - return false; |
|
1677 | - } |
|
1678 | - |
|
1679 | - |
|
1680 | - /** |
|
1681 | - * clears the cached children and parent from the line item |
|
1682 | - * |
|
1683 | - * @return void |
|
1684 | - */ |
|
1685 | - public function clear_related_line_item_cache() |
|
1686 | - { |
|
1687 | - $this->_children = array(); |
|
1688 | - $this->_parent = null; |
|
1689 | - } |
|
1690 | - |
|
1691 | - |
|
1692 | - /** |
|
1693 | - * @param bool $raw |
|
1694 | - * @return int |
|
1695 | - * @throws EE_Error |
|
1696 | - * @throws InvalidArgumentException |
|
1697 | - * @throws InvalidDataTypeException |
|
1698 | - * @throws InvalidInterfaceException |
|
1699 | - * @throws ReflectionException |
|
1700 | - */ |
|
1701 | - public function timestamp($raw = false) |
|
1702 | - { |
|
1703 | - return $raw |
|
1704 | - ? $this->get_raw('LIN_timestamp') |
|
1705 | - : $this->get('LIN_timestamp'); |
|
1706 | - } |
|
1707 | - |
|
1708 | - |
|
1709 | - |
|
1710 | - |
|
1711 | - /************************* DEPRECATED *************************/ |
|
1712 | - /** |
|
1713 | - * @deprecated 4.6.0 |
|
1714 | - * @param string $type one of the constants on EEM_Line_Item |
|
1715 | - * @return EE_Line_Item[] |
|
1716 | - * @throws EE_Error |
|
1717 | - */ |
|
1718 | - protected function _get_descendants_of_type($type) |
|
1719 | - { |
|
1720 | - EE_Error::doing_it_wrong( |
|
1721 | - 'EE_Line_Item::_get_descendants_of_type()', |
|
1722 | - sprintf( |
|
1723 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
1724 | - 'EEH_Line_Item::get_descendants_of_type()' |
|
1725 | - ), |
|
1726 | - '4.6.0' |
|
1727 | - ); |
|
1728 | - return EEH_Line_Item::get_descendants_of_type($this, $type); |
|
1729 | - } |
|
1730 | - |
|
1731 | - |
|
1732 | - /** |
|
1733 | - * @deprecated 4.6.0 |
|
1734 | - * @param string $type like one of the EEM_Line_Item::type_* |
|
1735 | - * @return EE_Line_Item |
|
1736 | - * @throws EE_Error |
|
1737 | - * @throws InvalidArgumentException |
|
1738 | - * @throws InvalidDataTypeException |
|
1739 | - * @throws InvalidInterfaceException |
|
1740 | - * @throws ReflectionException |
|
1741 | - */ |
|
1742 | - public function get_nearest_descendant_of_type($type) |
|
1743 | - { |
|
1744 | - EE_Error::doing_it_wrong( |
|
1745 | - 'EE_Line_Item::get_nearest_descendant_of_type()', |
|
1746 | - sprintf( |
|
1747 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
1748 | - 'EEH_Line_Item::get_nearest_descendant_of_type()' |
|
1749 | - ), |
|
1750 | - '4.6.0' |
|
1751 | - ); |
|
1752 | - return EEH_Line_Item::get_nearest_descendant_of_type($this, $type); |
|
1753 | - } |
|
16 | + /** |
|
17 | + * for children line items (currently not a normal relation) |
|
18 | + * |
|
19 | + * @type EE_Line_Item[] |
|
20 | + */ |
|
21 | + protected $_children = array(); |
|
22 | + |
|
23 | + /** |
|
24 | + * for the parent line item |
|
25 | + * |
|
26 | + * @var EE_Line_Item |
|
27 | + */ |
|
28 | + protected $_parent; |
|
29 | + |
|
30 | + |
|
31 | + /** |
|
32 | + * @param array $props_n_values incoming values |
|
33 | + * @param string $timezone incoming timezone (if not set the timezone set for the website will be |
|
34 | + * used.) |
|
35 | + * @param array $date_formats incoming date_formats in an array where the first value is the |
|
36 | + * date_format and the second value is the time format |
|
37 | + * @return EE_Line_Item |
|
38 | + * @throws EE_Error |
|
39 | + * @throws InvalidArgumentException |
|
40 | + * @throws InvalidDataTypeException |
|
41 | + * @throws InvalidInterfaceException |
|
42 | + * @throws ReflectionException |
|
43 | + */ |
|
44 | + public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) |
|
45 | + { |
|
46 | + $has_object = parent::_check_for_object( |
|
47 | + $props_n_values, |
|
48 | + __CLASS__, |
|
49 | + $timezone, |
|
50 | + $date_formats |
|
51 | + ); |
|
52 | + return $has_object |
|
53 | + ? $has_object |
|
54 | + : new self($props_n_values, false, $timezone); |
|
55 | + } |
|
56 | + |
|
57 | + |
|
58 | + /** |
|
59 | + * @param array $props_n_values incoming values from the database |
|
60 | + * @param string $timezone incoming timezone as set by the model. If not set the timezone for |
|
61 | + * the website will be used. |
|
62 | + * @return EE_Line_Item |
|
63 | + * @throws EE_Error |
|
64 | + * @throws InvalidArgumentException |
|
65 | + * @throws InvalidDataTypeException |
|
66 | + * @throws InvalidInterfaceException |
|
67 | + * @throws ReflectionException |
|
68 | + */ |
|
69 | + public static function new_instance_from_db($props_n_values = array(), $timezone = null) |
|
70 | + { |
|
71 | + return new self($props_n_values, true, $timezone); |
|
72 | + } |
|
73 | + |
|
74 | + |
|
75 | + /** |
|
76 | + * Adds some defaults if they're not specified |
|
77 | + * |
|
78 | + * @param array $fieldValues |
|
79 | + * @param bool $bydb |
|
80 | + * @param string $timezone |
|
81 | + * @throws EE_Error |
|
82 | + * @throws InvalidArgumentException |
|
83 | + * @throws InvalidDataTypeException |
|
84 | + * @throws InvalidInterfaceException |
|
85 | + * @throws ReflectionException |
|
86 | + */ |
|
87 | + protected function __construct($fieldValues = array(), $bydb = false, $timezone = '') |
|
88 | + { |
|
89 | + parent::__construct($fieldValues, $bydb, $timezone); |
|
90 | + if (! $this->get('LIN_code')) { |
|
91 | + $this->set_code($this->generate_code()); |
|
92 | + } |
|
93 | + } |
|
94 | + |
|
95 | + |
|
96 | + /** |
|
97 | + * Gets ID |
|
98 | + * |
|
99 | + * @return int |
|
100 | + * @throws EE_Error |
|
101 | + * @throws InvalidArgumentException |
|
102 | + * @throws InvalidDataTypeException |
|
103 | + * @throws InvalidInterfaceException |
|
104 | + * @throws ReflectionException |
|
105 | + */ |
|
106 | + public function ID() |
|
107 | + { |
|
108 | + return $this->get('LIN_ID'); |
|
109 | + } |
|
110 | + |
|
111 | + |
|
112 | + /** |
|
113 | + * Gets TXN_ID |
|
114 | + * |
|
115 | + * @return int |
|
116 | + * @throws EE_Error |
|
117 | + * @throws InvalidArgumentException |
|
118 | + * @throws InvalidDataTypeException |
|
119 | + * @throws InvalidInterfaceException |
|
120 | + * @throws ReflectionException |
|
121 | + */ |
|
122 | + public function TXN_ID() |
|
123 | + { |
|
124 | + return $this->get('TXN_ID'); |
|
125 | + } |
|
126 | + |
|
127 | + |
|
128 | + /** |
|
129 | + * Sets TXN_ID |
|
130 | + * |
|
131 | + * @param int $TXN_ID |
|
132 | + * @throws EE_Error |
|
133 | + * @throws InvalidArgumentException |
|
134 | + * @throws InvalidDataTypeException |
|
135 | + * @throws InvalidInterfaceException |
|
136 | + * @throws ReflectionException |
|
137 | + */ |
|
138 | + public function set_TXN_ID($TXN_ID) |
|
139 | + { |
|
140 | + $this->set('TXN_ID', $TXN_ID); |
|
141 | + } |
|
142 | + |
|
143 | + |
|
144 | + /** |
|
145 | + * Gets name |
|
146 | + * |
|
147 | + * @return string |
|
148 | + * @throws EE_Error |
|
149 | + * @throws InvalidArgumentException |
|
150 | + * @throws InvalidDataTypeException |
|
151 | + * @throws InvalidInterfaceException |
|
152 | + * @throws ReflectionException |
|
153 | + */ |
|
154 | + public function name() |
|
155 | + { |
|
156 | + $name = $this->get('LIN_name'); |
|
157 | + if (! $name) { |
|
158 | + $name = ucwords(str_replace('-', ' ', $this->type())); |
|
159 | + } |
|
160 | + return $name; |
|
161 | + } |
|
162 | + |
|
163 | + |
|
164 | + /** |
|
165 | + * Sets name |
|
166 | + * |
|
167 | + * @param string $name |
|
168 | + * @throws EE_Error |
|
169 | + * @throws InvalidArgumentException |
|
170 | + * @throws InvalidDataTypeException |
|
171 | + * @throws InvalidInterfaceException |
|
172 | + * @throws ReflectionException |
|
173 | + */ |
|
174 | + public function set_name($name) |
|
175 | + { |
|
176 | + $this->set('LIN_name', $name); |
|
177 | + } |
|
178 | + |
|
179 | + |
|
180 | + /** |
|
181 | + * Gets desc |
|
182 | + * |
|
183 | + * @return string |
|
184 | + * @throws EE_Error |
|
185 | + * @throws InvalidArgumentException |
|
186 | + * @throws InvalidDataTypeException |
|
187 | + * @throws InvalidInterfaceException |
|
188 | + * @throws ReflectionException |
|
189 | + */ |
|
190 | + public function desc() |
|
191 | + { |
|
192 | + return $this->get('LIN_desc'); |
|
193 | + } |
|
194 | + |
|
195 | + |
|
196 | + /** |
|
197 | + * Sets desc |
|
198 | + * |
|
199 | + * @param string $desc |
|
200 | + * @throws EE_Error |
|
201 | + * @throws InvalidArgumentException |
|
202 | + * @throws InvalidDataTypeException |
|
203 | + * @throws InvalidInterfaceException |
|
204 | + * @throws ReflectionException |
|
205 | + */ |
|
206 | + public function set_desc($desc) |
|
207 | + { |
|
208 | + $this->set('LIN_desc', $desc); |
|
209 | + } |
|
210 | + |
|
211 | + |
|
212 | + /** |
|
213 | + * Gets quantity |
|
214 | + * |
|
215 | + * @return int |
|
216 | + * @throws EE_Error |
|
217 | + * @throws InvalidArgumentException |
|
218 | + * @throws InvalidDataTypeException |
|
219 | + * @throws InvalidInterfaceException |
|
220 | + * @throws ReflectionException |
|
221 | + */ |
|
222 | + public function quantity() |
|
223 | + { |
|
224 | + return $this->get('LIN_quantity'); |
|
225 | + } |
|
226 | + |
|
227 | + |
|
228 | + /** |
|
229 | + * Sets quantity |
|
230 | + * |
|
231 | + * @param int $quantity |
|
232 | + * @throws EE_Error |
|
233 | + * @throws InvalidArgumentException |
|
234 | + * @throws InvalidDataTypeException |
|
235 | + * @throws InvalidInterfaceException |
|
236 | + * @throws ReflectionException |
|
237 | + */ |
|
238 | + public function set_quantity($quantity) |
|
239 | + { |
|
240 | + $this->set('LIN_quantity', max($quantity, 0)); |
|
241 | + } |
|
242 | + |
|
243 | + |
|
244 | + /** |
|
245 | + * Gets item_id |
|
246 | + * |
|
247 | + * @return string |
|
248 | + * @throws EE_Error |
|
249 | + * @throws InvalidArgumentException |
|
250 | + * @throws InvalidDataTypeException |
|
251 | + * @throws InvalidInterfaceException |
|
252 | + * @throws ReflectionException |
|
253 | + */ |
|
254 | + public function OBJ_ID() |
|
255 | + { |
|
256 | + return $this->get('OBJ_ID'); |
|
257 | + } |
|
258 | + |
|
259 | + |
|
260 | + /** |
|
261 | + * Sets item_id |
|
262 | + * |
|
263 | + * @param string $item_id |
|
264 | + * @throws EE_Error |
|
265 | + * @throws InvalidArgumentException |
|
266 | + * @throws InvalidDataTypeException |
|
267 | + * @throws InvalidInterfaceException |
|
268 | + * @throws ReflectionException |
|
269 | + */ |
|
270 | + public function set_OBJ_ID($item_id) |
|
271 | + { |
|
272 | + $this->set('OBJ_ID', $item_id); |
|
273 | + } |
|
274 | + |
|
275 | + |
|
276 | + /** |
|
277 | + * Gets item_type |
|
278 | + * |
|
279 | + * @return string |
|
280 | + * @throws EE_Error |
|
281 | + * @throws InvalidArgumentException |
|
282 | + * @throws InvalidDataTypeException |
|
283 | + * @throws InvalidInterfaceException |
|
284 | + * @throws ReflectionException |
|
285 | + */ |
|
286 | + public function OBJ_type() |
|
287 | + { |
|
288 | + return $this->get('OBJ_type'); |
|
289 | + } |
|
290 | + |
|
291 | + |
|
292 | + /** |
|
293 | + * Gets item_type |
|
294 | + * |
|
295 | + * @return string |
|
296 | + * @throws EE_Error |
|
297 | + * @throws InvalidArgumentException |
|
298 | + * @throws InvalidDataTypeException |
|
299 | + * @throws InvalidInterfaceException |
|
300 | + * @throws ReflectionException |
|
301 | + */ |
|
302 | + public function OBJ_type_i18n() |
|
303 | + { |
|
304 | + $obj_type = $this->OBJ_type(); |
|
305 | + switch ($obj_type) { |
|
306 | + case EEM_Line_Item::OBJ_TYPE_EVENT: |
|
307 | + $obj_type = esc_html__('Event', 'event_espresso'); |
|
308 | + break; |
|
309 | + case EEM_Line_Item::OBJ_TYPE_PRICE: |
|
310 | + $obj_type = esc_html__('Price', 'event_espresso'); |
|
311 | + break; |
|
312 | + case EEM_Line_Item::OBJ_TYPE_PROMOTION: |
|
313 | + $obj_type = esc_html__('Promotion', 'event_espresso'); |
|
314 | + break; |
|
315 | + case EEM_Line_Item::OBJ_TYPE_TICKET: |
|
316 | + $obj_type = esc_html__('Ticket', 'event_espresso'); |
|
317 | + break; |
|
318 | + case EEM_Line_Item::OBJ_TYPE_TRANSACTION: |
|
319 | + $obj_type = esc_html__('Transaction', 'event_espresso'); |
|
320 | + break; |
|
321 | + } |
|
322 | + return apply_filters('FHEE__EE_Line_Item__OBJ_type_i18n', $obj_type, $this); |
|
323 | + } |
|
324 | + |
|
325 | + |
|
326 | + /** |
|
327 | + * Sets item_type |
|
328 | + * |
|
329 | + * @param string $OBJ_type |
|
330 | + * @throws EE_Error |
|
331 | + * @throws InvalidArgumentException |
|
332 | + * @throws InvalidDataTypeException |
|
333 | + * @throws InvalidInterfaceException |
|
334 | + * @throws ReflectionException |
|
335 | + */ |
|
336 | + public function set_OBJ_type($OBJ_type) |
|
337 | + { |
|
338 | + $this->set('OBJ_type', $OBJ_type); |
|
339 | + } |
|
340 | + |
|
341 | + |
|
342 | + /** |
|
343 | + * Gets unit_price |
|
344 | + * |
|
345 | + * @return float |
|
346 | + * @throws EE_Error |
|
347 | + * @throws InvalidArgumentException |
|
348 | + * @throws InvalidDataTypeException |
|
349 | + * @throws InvalidInterfaceException |
|
350 | + * @throws ReflectionException |
|
351 | + */ |
|
352 | + public function unit_price() |
|
353 | + { |
|
354 | + return $this->get('LIN_unit_price'); |
|
355 | + } |
|
356 | + |
|
357 | + |
|
358 | + /** |
|
359 | + * Sets unit_price |
|
360 | + * |
|
361 | + * @param float $unit_price |
|
362 | + * @throws EE_Error |
|
363 | + * @throws InvalidArgumentException |
|
364 | + * @throws InvalidDataTypeException |
|
365 | + * @throws InvalidInterfaceException |
|
366 | + * @throws ReflectionException |
|
367 | + */ |
|
368 | + public function set_unit_price($unit_price) |
|
369 | + { |
|
370 | + $this->set('LIN_unit_price', $unit_price); |
|
371 | + } |
|
372 | + |
|
373 | + |
|
374 | + /** |
|
375 | + * Checks if this item is a percentage modifier or not |
|
376 | + * |
|
377 | + * @return boolean |
|
378 | + * @throws EE_Error |
|
379 | + * @throws InvalidArgumentException |
|
380 | + * @throws InvalidDataTypeException |
|
381 | + * @throws InvalidInterfaceException |
|
382 | + * @throws ReflectionException |
|
383 | + */ |
|
384 | + public function is_percent() |
|
385 | + { |
|
386 | + if ($this->is_tax_sub_total()) { |
|
387 | + // tax subtotals HAVE a percent on them, that percentage only applies |
|
388 | + // to taxable items, so its' an exception. Treat it like a flat line item |
|
389 | + return false; |
|
390 | + } |
|
391 | + $unit_price = abs($this->get('LIN_unit_price')); |
|
392 | + $percent = abs($this->get('LIN_percent')); |
|
393 | + if ($unit_price < .001 && $percent) { |
|
394 | + return true; |
|
395 | + } |
|
396 | + if ($unit_price >= .001 && ! $percent) { |
|
397 | + return false; |
|
398 | + } |
|
399 | + if ($unit_price >= .001 && $percent) { |
|
400 | + throw new EE_Error( |
|
401 | + sprintf( |
|
402 | + esc_html__( |
|
403 | + 'A Line Item can not have a unit price of (%s) AND a percent (%s)!', |
|
404 | + 'event_espresso' |
|
405 | + ), |
|
406 | + $unit_price, |
|
407 | + $percent |
|
408 | + ) |
|
409 | + ); |
|
410 | + } |
|
411 | + // if they're both 0, assume its not a percent item |
|
412 | + return false; |
|
413 | + } |
|
414 | + |
|
415 | + |
|
416 | + /** |
|
417 | + * Gets percent (between 100-.001) |
|
418 | + * |
|
419 | + * @return float |
|
420 | + * @throws EE_Error |
|
421 | + * @throws InvalidArgumentException |
|
422 | + * @throws InvalidDataTypeException |
|
423 | + * @throws InvalidInterfaceException |
|
424 | + * @throws ReflectionException |
|
425 | + */ |
|
426 | + public function percent() |
|
427 | + { |
|
428 | + return $this->get('LIN_percent'); |
|
429 | + } |
|
430 | + |
|
431 | + |
|
432 | + /** |
|
433 | + * Sets percent (between 100-0.01) |
|
434 | + * |
|
435 | + * @param float $percent |
|
436 | + * @throws EE_Error |
|
437 | + * @throws InvalidArgumentException |
|
438 | + * @throws InvalidDataTypeException |
|
439 | + * @throws InvalidInterfaceException |
|
440 | + * @throws ReflectionException |
|
441 | + */ |
|
442 | + public function set_percent($percent) |
|
443 | + { |
|
444 | + $this->set('LIN_percent', $percent); |
|
445 | + } |
|
446 | + |
|
447 | + |
|
448 | + /** |
|
449 | + * Gets total |
|
450 | + * |
|
451 | + * @return float |
|
452 | + * @throws EE_Error |
|
453 | + * @throws InvalidArgumentException |
|
454 | + * @throws InvalidDataTypeException |
|
455 | + * @throws InvalidInterfaceException |
|
456 | + * @throws ReflectionException |
|
457 | + */ |
|
458 | + public function total() |
|
459 | + { |
|
460 | + return $this->get('LIN_total'); |
|
461 | + } |
|
462 | + |
|
463 | + |
|
464 | + /** |
|
465 | + * Sets total |
|
466 | + * |
|
467 | + * @param float $total |
|
468 | + * @throws EE_Error |
|
469 | + * @throws InvalidArgumentException |
|
470 | + * @throws InvalidDataTypeException |
|
471 | + * @throws InvalidInterfaceException |
|
472 | + * @throws ReflectionException |
|
473 | + */ |
|
474 | + public function set_total($total) |
|
475 | + { |
|
476 | + $this->set('LIN_total', $total); |
|
477 | + } |
|
478 | + |
|
479 | + |
|
480 | + /** |
|
481 | + * Gets order |
|
482 | + * |
|
483 | + * @return int |
|
484 | + * @throws EE_Error |
|
485 | + * @throws InvalidArgumentException |
|
486 | + * @throws InvalidDataTypeException |
|
487 | + * @throws InvalidInterfaceException |
|
488 | + * @throws ReflectionException |
|
489 | + */ |
|
490 | + public function order() |
|
491 | + { |
|
492 | + return $this->get('LIN_order'); |
|
493 | + } |
|
494 | + |
|
495 | + |
|
496 | + /** |
|
497 | + * Sets order |
|
498 | + * |
|
499 | + * @param int $order |
|
500 | + * @throws EE_Error |
|
501 | + * @throws InvalidArgumentException |
|
502 | + * @throws InvalidDataTypeException |
|
503 | + * @throws InvalidInterfaceException |
|
504 | + * @throws ReflectionException |
|
505 | + */ |
|
506 | + public function set_order($order) |
|
507 | + { |
|
508 | + $this->set('LIN_order', $order); |
|
509 | + } |
|
510 | + |
|
511 | + |
|
512 | + /** |
|
513 | + * Gets parent |
|
514 | + * |
|
515 | + * @return int |
|
516 | + * @throws EE_Error |
|
517 | + * @throws InvalidArgumentException |
|
518 | + * @throws InvalidDataTypeException |
|
519 | + * @throws InvalidInterfaceException |
|
520 | + * @throws ReflectionException |
|
521 | + */ |
|
522 | + public function parent_ID() |
|
523 | + { |
|
524 | + return $this->get('LIN_parent'); |
|
525 | + } |
|
526 | + |
|
527 | + |
|
528 | + /** |
|
529 | + * Sets parent |
|
530 | + * |
|
531 | + * @param int $parent |
|
532 | + * @throws EE_Error |
|
533 | + * @throws InvalidArgumentException |
|
534 | + * @throws InvalidDataTypeException |
|
535 | + * @throws InvalidInterfaceException |
|
536 | + * @throws ReflectionException |
|
537 | + */ |
|
538 | + public function set_parent_ID($parent) |
|
539 | + { |
|
540 | + $this->set('LIN_parent', $parent); |
|
541 | + } |
|
542 | + |
|
543 | + |
|
544 | + /** |
|
545 | + * Gets type |
|
546 | + * |
|
547 | + * @return string |
|
548 | + * @throws EE_Error |
|
549 | + * @throws InvalidArgumentException |
|
550 | + * @throws InvalidDataTypeException |
|
551 | + * @throws InvalidInterfaceException |
|
552 | + * @throws ReflectionException |
|
553 | + */ |
|
554 | + public function type() |
|
555 | + { |
|
556 | + return $this->get('LIN_type'); |
|
557 | + } |
|
558 | + |
|
559 | + |
|
560 | + /** |
|
561 | + * Sets type |
|
562 | + * |
|
563 | + * @param string $type |
|
564 | + * @throws EE_Error |
|
565 | + * @throws InvalidArgumentException |
|
566 | + * @throws InvalidDataTypeException |
|
567 | + * @throws InvalidInterfaceException |
|
568 | + * @throws ReflectionException |
|
569 | + */ |
|
570 | + public function set_type($type) |
|
571 | + { |
|
572 | + $this->set('LIN_type', $type); |
|
573 | + } |
|
574 | + |
|
575 | + |
|
576 | + /** |
|
577 | + * Gets the line item of which this item is a composite. Eg, if this is a subtotal, the parent might be a total\ |
|
578 | + * If this line item is saved to the DB, fetches the parent from the DB. However, if this line item isn't in the DB |
|
579 | + * it uses its cached reference to its parent line item (which would have been set by `EE_Line_Item::set_parent()` |
|
580 | + * or indirectly by `EE_Line_item::add_child_line_item()`) |
|
581 | + * |
|
582 | + * @return EE_Base_Class|EE_Line_Item |
|
583 | + * @throws EE_Error |
|
584 | + * @throws InvalidArgumentException |
|
585 | + * @throws InvalidDataTypeException |
|
586 | + * @throws InvalidInterfaceException |
|
587 | + * @throws ReflectionException |
|
588 | + */ |
|
589 | + public function parent() |
|
590 | + { |
|
591 | + return $this->ID() |
|
592 | + ? $this->get_model()->get_one_by_ID($this->parent_ID()) |
|
593 | + : $this->_parent; |
|
594 | + } |
|
595 | + |
|
596 | + |
|
597 | + /** |
|
598 | + * Gets ALL the children of this line item (ie, all the parts that contribute towards this total). |
|
599 | + * |
|
600 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
601 | + * @throws EE_Error |
|
602 | + * @throws InvalidArgumentException |
|
603 | + * @throws InvalidDataTypeException |
|
604 | + * @throws InvalidInterfaceException |
|
605 | + * @throws ReflectionException |
|
606 | + */ |
|
607 | + public function children() |
|
608 | + { |
|
609 | + if ($this->ID()) { |
|
610 | + return $this->get_model()->get_all( |
|
611 | + array( |
|
612 | + array('LIN_parent' => $this->ID()), |
|
613 | + 'order_by' => array('LIN_order' => 'ASC'), |
|
614 | + ) |
|
615 | + ); |
|
616 | + } |
|
617 | + if (! is_array($this->_children)) { |
|
618 | + $this->_children = array(); |
|
619 | + } |
|
620 | + return $this->_children; |
|
621 | + } |
|
622 | + |
|
623 | + |
|
624 | + /** |
|
625 | + * Gets code |
|
626 | + * |
|
627 | + * @return string |
|
628 | + * @throws EE_Error |
|
629 | + * @throws InvalidArgumentException |
|
630 | + * @throws InvalidDataTypeException |
|
631 | + * @throws InvalidInterfaceException |
|
632 | + * @throws ReflectionException |
|
633 | + */ |
|
634 | + public function code() |
|
635 | + { |
|
636 | + return $this->get('LIN_code'); |
|
637 | + } |
|
638 | + |
|
639 | + |
|
640 | + /** |
|
641 | + * Sets code |
|
642 | + * |
|
643 | + * @param string $code |
|
644 | + * @throws EE_Error |
|
645 | + * @throws InvalidArgumentException |
|
646 | + * @throws InvalidDataTypeException |
|
647 | + * @throws InvalidInterfaceException |
|
648 | + * @throws ReflectionException |
|
649 | + */ |
|
650 | + public function set_code($code) |
|
651 | + { |
|
652 | + $this->set('LIN_code', $code); |
|
653 | + } |
|
654 | + |
|
655 | + |
|
656 | + /** |
|
657 | + * Gets is_taxable |
|
658 | + * |
|
659 | + * @return boolean |
|
660 | + * @throws EE_Error |
|
661 | + * @throws InvalidArgumentException |
|
662 | + * @throws InvalidDataTypeException |
|
663 | + * @throws InvalidInterfaceException |
|
664 | + * @throws ReflectionException |
|
665 | + */ |
|
666 | + public function is_taxable() |
|
667 | + { |
|
668 | + return $this->get('LIN_is_taxable'); |
|
669 | + } |
|
670 | + |
|
671 | + |
|
672 | + /** |
|
673 | + * Sets is_taxable |
|
674 | + * |
|
675 | + * @param boolean $is_taxable |
|
676 | + * @throws EE_Error |
|
677 | + * @throws InvalidArgumentException |
|
678 | + * @throws InvalidDataTypeException |
|
679 | + * @throws InvalidInterfaceException |
|
680 | + * @throws ReflectionException |
|
681 | + */ |
|
682 | + public function set_is_taxable($is_taxable) |
|
683 | + { |
|
684 | + $this->set('LIN_is_taxable', $is_taxable); |
|
685 | + } |
|
686 | + |
|
687 | + |
|
688 | + /** |
|
689 | + * Gets the object that this model-joins-to. |
|
690 | + * returns one of the model objects that the field OBJ_ID can point to... see the 'OBJ_ID' field on |
|
691 | + * EEM_Promotion_Object |
|
692 | + * Eg, if this line item join model object is for a ticket, this will return the EE_Ticket object |
|
693 | + * |
|
694 | + * @return EE_Base_Class | NULL |
|
695 | + * @throws EE_Error |
|
696 | + * @throws InvalidArgumentException |
|
697 | + * @throws InvalidDataTypeException |
|
698 | + * @throws InvalidInterfaceException |
|
699 | + * @throws ReflectionException |
|
700 | + */ |
|
701 | + public function get_object() |
|
702 | + { |
|
703 | + $model_name_of_related_obj = $this->OBJ_type(); |
|
704 | + return $this->get_model()->has_relation($model_name_of_related_obj) |
|
705 | + ? $this->get_first_related($model_name_of_related_obj) |
|
706 | + : null; |
|
707 | + } |
|
708 | + |
|
709 | + |
|
710 | + /** |
|
711 | + * Like EE_Line_Item::get_object(), but can only ever actually return an EE_Ticket. |
|
712 | + * (IE, if this line item is for a price or something else, will return NULL) |
|
713 | + * |
|
714 | + * @param array $query_params |
|
715 | + * @return EE_Base_Class|EE_Ticket |
|
716 | + * @throws EE_Error |
|
717 | + * @throws InvalidArgumentException |
|
718 | + * @throws InvalidDataTypeException |
|
719 | + * @throws InvalidInterfaceException |
|
720 | + * @throws ReflectionException |
|
721 | + */ |
|
722 | + public function ticket($query_params = array()) |
|
723 | + { |
|
724 | + // we're going to assume that when this method is called |
|
725 | + // we always want to receive the attached ticket EVEN if that ticket is archived. |
|
726 | + // This can be overridden via the incoming $query_params argument |
|
727 | + $remove_defaults = array('default_where_conditions' => 'none'); |
|
728 | + $query_params = array_merge($remove_defaults, $query_params); |
|
729 | + return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TICKET, $query_params); |
|
730 | + } |
|
731 | + |
|
732 | + |
|
733 | + /** |
|
734 | + * Gets the EE_Datetime that's related to the ticket, IF this is for a ticket |
|
735 | + * |
|
736 | + * @return EE_Datetime | NULL |
|
737 | + * @throws EE_Error |
|
738 | + * @throws InvalidArgumentException |
|
739 | + * @throws InvalidDataTypeException |
|
740 | + * @throws InvalidInterfaceException |
|
741 | + * @throws ReflectionException |
|
742 | + */ |
|
743 | + public function get_ticket_datetime() |
|
744 | + { |
|
745 | + if ($this->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
746 | + $ticket = $this->ticket(); |
|
747 | + if ($ticket instanceof EE_Ticket) { |
|
748 | + $datetime = $ticket->first_datetime(); |
|
749 | + if ($datetime instanceof EE_Datetime) { |
|
750 | + return $datetime; |
|
751 | + } |
|
752 | + } |
|
753 | + } |
|
754 | + return null; |
|
755 | + } |
|
756 | + |
|
757 | + |
|
758 | + /** |
|
759 | + * Gets the event's name that's related to the ticket, if this is for |
|
760 | + * a ticket |
|
761 | + * |
|
762 | + * @return string |
|
763 | + * @throws EE_Error |
|
764 | + * @throws InvalidArgumentException |
|
765 | + * @throws InvalidDataTypeException |
|
766 | + * @throws InvalidInterfaceException |
|
767 | + * @throws ReflectionException |
|
768 | + */ |
|
769 | + public function ticket_event_name() |
|
770 | + { |
|
771 | + $event_name = esc_html__('Unknown', 'event_espresso'); |
|
772 | + $event = $this->ticket_event(); |
|
773 | + if ($event instanceof EE_Event) { |
|
774 | + $event_name = $event->name(); |
|
775 | + } |
|
776 | + return $event_name; |
|
777 | + } |
|
778 | + |
|
779 | + |
|
780 | + /** |
|
781 | + * Gets the event that's related to the ticket, if this line item represents a ticket. |
|
782 | + * |
|
783 | + * @return EE_Event|null |
|
784 | + * @throws EE_Error |
|
785 | + * @throws InvalidArgumentException |
|
786 | + * @throws InvalidDataTypeException |
|
787 | + * @throws InvalidInterfaceException |
|
788 | + * @throws ReflectionException |
|
789 | + */ |
|
790 | + public function ticket_event() |
|
791 | + { |
|
792 | + $event = null; |
|
793 | + $ticket = $this->ticket(); |
|
794 | + if ($ticket instanceof EE_Ticket) { |
|
795 | + $datetime = $ticket->first_datetime(); |
|
796 | + if ($datetime instanceof EE_Datetime) { |
|
797 | + $event = $datetime->event(); |
|
798 | + } |
|
799 | + } |
|
800 | + return $event; |
|
801 | + } |
|
802 | + |
|
803 | + |
|
804 | + /** |
|
805 | + * Gets the first datetime for this lien item, assuming it's for a ticket |
|
806 | + * |
|
807 | + * @param string $date_format |
|
808 | + * @param string $time_format |
|
809 | + * @return string |
|
810 | + * @throws EE_Error |
|
811 | + * @throws InvalidArgumentException |
|
812 | + * @throws InvalidDataTypeException |
|
813 | + * @throws InvalidInterfaceException |
|
814 | + * @throws ReflectionException |
|
815 | + */ |
|
816 | + public function ticket_datetime_start($date_format = '', $time_format = '') |
|
817 | + { |
|
818 | + $first_datetime_string = esc_html__('Unknown', 'event_espresso'); |
|
819 | + $datetime = $this->get_ticket_datetime(); |
|
820 | + if ($datetime) { |
|
821 | + $first_datetime_string = $datetime->start_date_and_time($date_format, $time_format); |
|
822 | + } |
|
823 | + return $first_datetime_string; |
|
824 | + } |
|
825 | + |
|
826 | + |
|
827 | + /** |
|
828 | + * Adds the line item as a child to this line item. If there is another child line |
|
829 | + * item with the same LIN_code, it is overwritten by this new one |
|
830 | + * |
|
831 | + * @param EEI_Line_Item $line_item |
|
832 | + * @param bool $set_order |
|
833 | + * @return bool success |
|
834 | + * @throws EE_Error |
|
835 | + * @throws InvalidArgumentException |
|
836 | + * @throws InvalidDataTypeException |
|
837 | + * @throws InvalidInterfaceException |
|
838 | + * @throws ReflectionException |
|
839 | + */ |
|
840 | + public function add_child_line_item(EEI_Line_Item $line_item, $set_order = true) |
|
841 | + { |
|
842 | + // should we calculate the LIN_order for this line item ? |
|
843 | + if ($set_order || $line_item->order() === null) { |
|
844 | + $line_item->set_order(count($this->children())); |
|
845 | + } |
|
846 | + if ($this->ID()) { |
|
847 | + // check for any duplicate line items (with the same code), if so, this replaces it |
|
848 | + $line_item_with_same_code = $this->get_child_line_item($line_item->code()); |
|
849 | + if ($line_item_with_same_code instanceof EE_Line_Item && $line_item_with_same_code !== $line_item) { |
|
850 | + $this->delete_child_line_item($line_item_with_same_code->code()); |
|
851 | + } |
|
852 | + $line_item->set_parent_ID($this->ID()); |
|
853 | + if ($this->TXN_ID()) { |
|
854 | + $line_item->set_TXN_ID($this->TXN_ID()); |
|
855 | + } |
|
856 | + return $line_item->save(); |
|
857 | + } |
|
858 | + $this->_children[ $line_item->code() ] = $line_item; |
|
859 | + if ($line_item->parent() !== $this) { |
|
860 | + $line_item->set_parent($this); |
|
861 | + } |
|
862 | + return true; |
|
863 | + } |
|
864 | + |
|
865 | + |
|
866 | + /** |
|
867 | + * Similar to EE_Base_Class::_add_relation_to, except this isn't a normal relation. |
|
868 | + * If this line item is saved to the DB, this is just a wrapper for set_parent_ID() and save() |
|
869 | + * However, if this line item is NOT saved to the DB, this just caches the parent on |
|
870 | + * the EE_Line_Item::_parent property. |
|
871 | + * |
|
872 | + * @param EE_Line_Item $line_item |
|
873 | + * @throws EE_Error |
|
874 | + * @throws InvalidArgumentException |
|
875 | + * @throws InvalidDataTypeException |
|
876 | + * @throws InvalidInterfaceException |
|
877 | + * @throws ReflectionException |
|
878 | + */ |
|
879 | + public function set_parent($line_item) |
|
880 | + { |
|
881 | + if ($this->ID()) { |
|
882 | + if (! $line_item->ID()) { |
|
883 | + $line_item->save(); |
|
884 | + } |
|
885 | + $this->set_parent_ID($line_item->ID()); |
|
886 | + $this->save(); |
|
887 | + } else { |
|
888 | + $this->_parent = $line_item; |
|
889 | + $this->set_parent_ID($line_item->ID()); |
|
890 | + } |
|
891 | + } |
|
892 | + |
|
893 | + |
|
894 | + /** |
|
895 | + * Gets the child line item as specified by its code. Because this returns an object (by reference) |
|
896 | + * you can modify this child line item and the parent (this object) can know about them |
|
897 | + * because it also has a reference to that line item |
|
898 | + * |
|
899 | + * @param string $code |
|
900 | + * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
901 | + * @throws EE_Error |
|
902 | + * @throws InvalidArgumentException |
|
903 | + * @throws InvalidDataTypeException |
|
904 | + * @throws InvalidInterfaceException |
|
905 | + * @throws ReflectionException |
|
906 | + */ |
|
907 | + public function get_child_line_item($code) |
|
908 | + { |
|
909 | + if ($this->ID()) { |
|
910 | + return $this->get_model()->get_one( |
|
911 | + array(array('LIN_parent' => $this->ID(), 'LIN_code' => $code)) |
|
912 | + ); |
|
913 | + } |
|
914 | + return isset($this->_children[ $code ]) |
|
915 | + ? $this->_children[ $code ] |
|
916 | + : null; |
|
917 | + } |
|
918 | + |
|
919 | + |
|
920 | + /** |
|
921 | + * Returns how many items are deleted (or, if this item has not been saved ot the DB yet, just how many it HAD |
|
922 | + * cached on it) |
|
923 | + * |
|
924 | + * @return int |
|
925 | + * @throws EE_Error |
|
926 | + * @throws InvalidArgumentException |
|
927 | + * @throws InvalidDataTypeException |
|
928 | + * @throws InvalidInterfaceException |
|
929 | + * @throws ReflectionException |
|
930 | + */ |
|
931 | + public function delete_children_line_items() |
|
932 | + { |
|
933 | + if ($this->ID()) { |
|
934 | + return $this->get_model()->delete(array(array('LIN_parent' => $this->ID()))); |
|
935 | + } |
|
936 | + $count = count($this->_children); |
|
937 | + $this->_children = array(); |
|
938 | + return $count; |
|
939 | + } |
|
940 | + |
|
941 | + |
|
942 | + /** |
|
943 | + * If this line item has been saved to the DB, deletes its child with LIN_code == $code. If this line |
|
944 | + * HAS NOT been saved to the DB, removes the child line item with index $code. |
|
945 | + * Also searches through the child's children for a matching line item. However, once a line item has been found |
|
946 | + * and deleted, stops searching (so if there are line items with duplicate codes, only the first one found will be |
|
947 | + * deleted) |
|
948 | + * |
|
949 | + * @param string $code |
|
950 | + * @param bool $stop_search_once_found |
|
951 | + * @return int count of items deleted (or simply removed from the line item's cache, if not has not been saved to |
|
952 | + * the DB yet) |
|
953 | + * @throws EE_Error |
|
954 | + * @throws InvalidArgumentException |
|
955 | + * @throws InvalidDataTypeException |
|
956 | + * @throws InvalidInterfaceException |
|
957 | + * @throws ReflectionException |
|
958 | + */ |
|
959 | + public function delete_child_line_item($code, $stop_search_once_found = true) |
|
960 | + { |
|
961 | + if ($this->ID()) { |
|
962 | + $items_deleted = 0; |
|
963 | + if ($this->code() === $code) { |
|
964 | + $items_deleted += EEH_Line_Item::delete_all_child_items($this); |
|
965 | + $items_deleted += (int) $this->delete(); |
|
966 | + if ($stop_search_once_found) { |
|
967 | + return $items_deleted; |
|
968 | + } |
|
969 | + } |
|
970 | + foreach ($this->children() as $child_line_item) { |
|
971 | + $items_deleted += $child_line_item->delete_child_line_item($code, $stop_search_once_found); |
|
972 | + } |
|
973 | + return $items_deleted; |
|
974 | + } |
|
975 | + if (isset($this->_children[ $code ])) { |
|
976 | + unset($this->_children[ $code ]); |
|
977 | + return 1; |
|
978 | + } |
|
979 | + return 0; |
|
980 | + } |
|
981 | + |
|
982 | + |
|
983 | + /** |
|
984 | + * If this line item is in the database, is of the type subtotal, and |
|
985 | + * has no children, why do we have it? It should be deleted so this function |
|
986 | + * does that |
|
987 | + * |
|
988 | + * @return boolean |
|
989 | + * @throws EE_Error |
|
990 | + * @throws InvalidArgumentException |
|
991 | + * @throws InvalidDataTypeException |
|
992 | + * @throws InvalidInterfaceException |
|
993 | + * @throws ReflectionException |
|
994 | + */ |
|
995 | + public function delete_if_childless_subtotal() |
|
996 | + { |
|
997 | + if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && ! $this->children()) { |
|
998 | + return $this->delete(); |
|
999 | + } |
|
1000 | + return false; |
|
1001 | + } |
|
1002 | + |
|
1003 | + |
|
1004 | + /** |
|
1005 | + * Creates a code and returns a string. doesn't assign the code to this model object |
|
1006 | + * |
|
1007 | + * @return string |
|
1008 | + * @throws EE_Error |
|
1009 | + * @throws InvalidArgumentException |
|
1010 | + * @throws InvalidDataTypeException |
|
1011 | + * @throws InvalidInterfaceException |
|
1012 | + * @throws ReflectionException |
|
1013 | + */ |
|
1014 | + public function generate_code() |
|
1015 | + { |
|
1016 | + // each line item in the cart requires a unique identifier |
|
1017 | + return md5($this->get('OBJ_type') . $this->get('OBJ_ID') . microtime()); |
|
1018 | + } |
|
1019 | + |
|
1020 | + |
|
1021 | + /** |
|
1022 | + * @return bool |
|
1023 | + * @throws EE_Error |
|
1024 | + * @throws InvalidArgumentException |
|
1025 | + * @throws InvalidDataTypeException |
|
1026 | + * @throws InvalidInterfaceException |
|
1027 | + * @throws ReflectionException |
|
1028 | + */ |
|
1029 | + public function is_tax() |
|
1030 | + { |
|
1031 | + return $this->type() === EEM_Line_Item::type_tax; |
|
1032 | + } |
|
1033 | + |
|
1034 | + |
|
1035 | + /** |
|
1036 | + * @return bool |
|
1037 | + * @throws EE_Error |
|
1038 | + * @throws InvalidArgumentException |
|
1039 | + * @throws InvalidDataTypeException |
|
1040 | + * @throws InvalidInterfaceException |
|
1041 | + * @throws ReflectionException |
|
1042 | + */ |
|
1043 | + public function is_tax_sub_total() |
|
1044 | + { |
|
1045 | + return $this->type() === EEM_Line_Item::type_tax_sub_total; |
|
1046 | + } |
|
1047 | + |
|
1048 | + |
|
1049 | + /** |
|
1050 | + * @return bool |
|
1051 | + * @throws EE_Error |
|
1052 | + * @throws InvalidArgumentException |
|
1053 | + * @throws InvalidDataTypeException |
|
1054 | + * @throws InvalidInterfaceException |
|
1055 | + * @throws ReflectionException |
|
1056 | + */ |
|
1057 | + public function is_line_item() |
|
1058 | + { |
|
1059 | + return $this->type() === EEM_Line_Item::type_line_item; |
|
1060 | + } |
|
1061 | + |
|
1062 | + |
|
1063 | + /** |
|
1064 | + * @return bool |
|
1065 | + * @throws EE_Error |
|
1066 | + * @throws InvalidArgumentException |
|
1067 | + * @throws InvalidDataTypeException |
|
1068 | + * @throws InvalidInterfaceException |
|
1069 | + * @throws ReflectionException |
|
1070 | + */ |
|
1071 | + public function is_sub_line_item() |
|
1072 | + { |
|
1073 | + return $this->type() === EEM_Line_Item::type_sub_line_item; |
|
1074 | + } |
|
1075 | + |
|
1076 | + |
|
1077 | + /** |
|
1078 | + * @return bool |
|
1079 | + * @throws EE_Error |
|
1080 | + * @throws InvalidArgumentException |
|
1081 | + * @throws InvalidDataTypeException |
|
1082 | + * @throws InvalidInterfaceException |
|
1083 | + * @throws ReflectionException |
|
1084 | + */ |
|
1085 | + public function is_sub_total() |
|
1086 | + { |
|
1087 | + return $this->type() === EEM_Line_Item::type_sub_total; |
|
1088 | + } |
|
1089 | + |
|
1090 | + |
|
1091 | + /** |
|
1092 | + * Whether or not this line item is a cancellation line item |
|
1093 | + * |
|
1094 | + * @return boolean |
|
1095 | + * @throws EE_Error |
|
1096 | + * @throws InvalidArgumentException |
|
1097 | + * @throws InvalidDataTypeException |
|
1098 | + * @throws InvalidInterfaceException |
|
1099 | + * @throws ReflectionException |
|
1100 | + */ |
|
1101 | + public function is_cancellation() |
|
1102 | + { |
|
1103 | + return EEM_Line_Item::type_cancellation === $this->type(); |
|
1104 | + } |
|
1105 | + |
|
1106 | + |
|
1107 | + /** |
|
1108 | + * @return bool |
|
1109 | + * @throws EE_Error |
|
1110 | + * @throws InvalidArgumentException |
|
1111 | + * @throws InvalidDataTypeException |
|
1112 | + * @throws InvalidInterfaceException |
|
1113 | + * @throws ReflectionException |
|
1114 | + */ |
|
1115 | + public function is_total() |
|
1116 | + { |
|
1117 | + return $this->type() === EEM_Line_Item::type_total; |
|
1118 | + } |
|
1119 | + |
|
1120 | + |
|
1121 | + /** |
|
1122 | + * @return bool |
|
1123 | + * @throws EE_Error |
|
1124 | + * @throws InvalidArgumentException |
|
1125 | + * @throws InvalidDataTypeException |
|
1126 | + * @throws InvalidInterfaceException |
|
1127 | + * @throws ReflectionException |
|
1128 | + */ |
|
1129 | + public function is_cancelled() |
|
1130 | + { |
|
1131 | + return $this->type() === EEM_Line_Item::type_cancellation; |
|
1132 | + } |
|
1133 | + |
|
1134 | + |
|
1135 | + /** |
|
1136 | + * @return string like '2, 004.00', formatted according to the localized currency |
|
1137 | + * @throws EE_Error |
|
1138 | + * @throws InvalidArgumentException |
|
1139 | + * @throws InvalidDataTypeException |
|
1140 | + * @throws InvalidInterfaceException |
|
1141 | + * @throws ReflectionException |
|
1142 | + */ |
|
1143 | + public function unit_price_no_code() |
|
1144 | + { |
|
1145 | + return $this->get_pretty('LIN_unit_price', 'no_currency_code'); |
|
1146 | + } |
|
1147 | + |
|
1148 | + |
|
1149 | + /** |
|
1150 | + * @return string like '2, 004.00', formatted according to the localized currency |
|
1151 | + * @throws EE_Error |
|
1152 | + * @throws InvalidArgumentException |
|
1153 | + * @throws InvalidDataTypeException |
|
1154 | + * @throws InvalidInterfaceException |
|
1155 | + * @throws ReflectionException |
|
1156 | + */ |
|
1157 | + public function total_no_code() |
|
1158 | + { |
|
1159 | + return $this->get_pretty('LIN_total', 'no_currency_code'); |
|
1160 | + } |
|
1161 | + |
|
1162 | + |
|
1163 | + /** |
|
1164 | + * Gets the final total on this item, taking taxes into account. |
|
1165 | + * Has the side-effect of setting the sub-total as it was just calculated. |
|
1166 | + * If this is used on a grand-total line item, also updates the transaction's |
|
1167 | + * TXN_total (provided this line item is allowed to persist, otherwise we don't |
|
1168 | + * want to change a persistable transaction with info from a non-persistent line item) |
|
1169 | + * |
|
1170 | + * @param bool $update_txn_status |
|
1171 | + * @return float |
|
1172 | + * @throws EE_Error |
|
1173 | + * @throws InvalidArgumentException |
|
1174 | + * @throws InvalidDataTypeException |
|
1175 | + * @throws InvalidInterfaceException |
|
1176 | + * @throws ReflectionException |
|
1177 | + * @throws RuntimeException |
|
1178 | + */ |
|
1179 | + public function recalculate_total_including_taxes($update_txn_status = false) |
|
1180 | + { |
|
1181 | + $pre_tax_total = $this->recalculate_pre_tax_total(); |
|
1182 | + $tax_total = $this->recalculate_taxes_and_tax_total(); |
|
1183 | + $total = $pre_tax_total + $tax_total; |
|
1184 | + // no negative totals plz |
|
1185 | + $total = max($total, 0); |
|
1186 | + $this->set_total($total); |
|
1187 | + // only update the related transaction's total |
|
1188 | + // if we intend to save this line item and its a grand total |
|
1189 | + if ( |
|
1190 | + $this->allow_persist() && $this->type() === EEM_Line_Item::type_total |
|
1191 | + && $this->transaction() |
|
1192 | + instanceof |
|
1193 | + EE_Transaction |
|
1194 | + ) { |
|
1195 | + $this->transaction()->set_total($total); |
|
1196 | + if ($update_txn_status) { |
|
1197 | + // don't save the TXN because that will be done below |
|
1198 | + // and the following method only saves if the status changes |
|
1199 | + $this->transaction()->update_status_based_on_total_paid(false); |
|
1200 | + } |
|
1201 | + if ($this->transaction()->ID()) { |
|
1202 | + $this->transaction()->save(); |
|
1203 | + } |
|
1204 | + } |
|
1205 | + $this->maybe_save(); |
|
1206 | + return $total; |
|
1207 | + } |
|
1208 | + |
|
1209 | + |
|
1210 | + /** |
|
1211 | + * Recursively goes through all the children and recalculates sub-totals EXCEPT for |
|
1212 | + * tax-sub-totals (they're a an odd beast). Updates the 'total' on each line item according to either its |
|
1213 | + * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and |
|
1214 | + * when this is called on the grand total |
|
1215 | + * |
|
1216 | + * @return float |
|
1217 | + * @throws EE_Error |
|
1218 | + * @throws InvalidArgumentException |
|
1219 | + * @throws InvalidDataTypeException |
|
1220 | + * @throws InvalidInterfaceException |
|
1221 | + * @throws ReflectionException |
|
1222 | + */ |
|
1223 | + public function recalculate_pre_tax_total() |
|
1224 | + { |
|
1225 | + $total = 0; |
|
1226 | + $my_children = $this->children(); |
|
1227 | + $has_children = ! empty($my_children); |
|
1228 | + if ($has_children && $this->is_line_item()) { |
|
1229 | + $total = $this->_recalculate_pretax_total_for_line_item($total, $my_children); |
|
1230 | + } elseif (! $has_children && ($this->is_sub_line_item() || $this->is_line_item())) { |
|
1231 | + $total = $this->unit_price() * $this->quantity(); |
|
1232 | + } elseif ($this->is_sub_total() || $this->is_total()) { |
|
1233 | + $total = $this->_recalculate_pretax_total_for_subtotal($total, $my_children); |
|
1234 | + } elseif ($this->is_tax_sub_total() || $this->is_tax() || $this->is_cancelled()) { |
|
1235 | + // completely ignore tax totals, tax sub-totals, and cancelled line items, when calculating the pre-tax-total |
|
1236 | + return 0; |
|
1237 | + } |
|
1238 | + // ensure all non-line items and non-sub-line-items have a quantity of 1 (except for Events) |
|
1239 | + if ( |
|
1240 | + ! $this->is_line_item() && ! $this->is_sub_line_item() && ! $this->is_cancellation() |
|
1241 | + ) { |
|
1242 | + if ($this->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_EVENT) { |
|
1243 | + $this->set_quantity(1); |
|
1244 | + } |
|
1245 | + if (! $this->is_percent()) { |
|
1246 | + $this->set_unit_price($total); |
|
1247 | + } |
|
1248 | + } |
|
1249 | + // we don't want to bother saving grand totals, because that needs to factor in taxes anyways |
|
1250 | + // so it ought to be |
|
1251 | + if (! $this->is_total()) { |
|
1252 | + $this->set_total($total); |
|
1253 | + // if not a percent line item, make sure we keep the unit price in sync |
|
1254 | + if ( |
|
1255 | + $has_children |
|
1256 | + && $this->is_line_item() |
|
1257 | + && ! $this->is_percent() |
|
1258 | + ) { |
|
1259 | + if ($this->quantity() === 0) { |
|
1260 | + $new_unit_price = 0; |
|
1261 | + } else { |
|
1262 | + $new_unit_price = $this->total() / $this->quantity(); |
|
1263 | + } |
|
1264 | + $this->set_unit_price($new_unit_price); |
|
1265 | + } |
|
1266 | + $this->maybe_save(); |
|
1267 | + } |
|
1268 | + return $total; |
|
1269 | + } |
|
1270 | + |
|
1271 | + |
|
1272 | + /** |
|
1273 | + * Calculates the pretax total when this line item is a subtotal or total line item. |
|
1274 | + * Basically does a sum-then-round approach (ie, any percent line item that are children |
|
1275 | + * will calculate their total based on the un-rounded total we're working with so far, and |
|
1276 | + * THEN round the result; instead of rounding as we go like with sub-line-items) |
|
1277 | + * |
|
1278 | + * @param float $calculated_total_so_far |
|
1279 | + * @param EE_Line_Item[] $my_children |
|
1280 | + * @return float |
|
1281 | + * @throws EE_Error |
|
1282 | + * @throws InvalidArgumentException |
|
1283 | + * @throws InvalidDataTypeException |
|
1284 | + * @throws InvalidInterfaceException |
|
1285 | + * @throws ReflectionException |
|
1286 | + */ |
|
1287 | + protected function _recalculate_pretax_total_for_subtotal($calculated_total_so_far, $my_children = null) |
|
1288 | + { |
|
1289 | + if ($my_children === null) { |
|
1290 | + $my_children = $this->children(); |
|
1291 | + } |
|
1292 | + $subtotal_quantity = 0; |
|
1293 | + // get the total of all its children |
|
1294 | + foreach ($my_children as $child_line_item) { |
|
1295 | + if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) { |
|
1296 | + // percentage line items are based on total so far |
|
1297 | + if ($child_line_item->is_percent()) { |
|
1298 | + // round as we go so that the line items add up ok |
|
1299 | + $percent_total = round( |
|
1300 | + $calculated_total_so_far * $child_line_item->percent() / 100, |
|
1301 | + EE_Registry::instance()->CFG->currency->dec_plc |
|
1302 | + ); |
|
1303 | + $child_line_item->set_total($percent_total); |
|
1304 | + // so far all percent line items should have a quantity of 1 |
|
1305 | + // (ie, no double percent discounts. Although that might be requested someday) |
|
1306 | + $child_line_item->set_quantity(1); |
|
1307 | + $child_line_item->maybe_save(); |
|
1308 | + $calculated_total_so_far += $percent_total; |
|
1309 | + } else { |
|
1310 | + // verify flat sub-line-item quantities match their parent |
|
1311 | + if ($child_line_item->is_sub_line_item()) { |
|
1312 | + $child_line_item->set_quantity($this->quantity()); |
|
1313 | + } |
|
1314 | + $calculated_total_so_far += $child_line_item->recalculate_pre_tax_total(); |
|
1315 | + $subtotal_quantity += $child_line_item->quantity(); |
|
1316 | + } |
|
1317 | + } |
|
1318 | + } |
|
1319 | + if ($this->is_sub_total()) { |
|
1320 | + // no negative totals plz |
|
1321 | + $calculated_total_so_far = max($calculated_total_so_far, 0); |
|
1322 | + $subtotal_quantity = $subtotal_quantity > 0 ? 1 : 0; |
|
1323 | + $this->set_quantity($subtotal_quantity); |
|
1324 | + $this->maybe_save(); |
|
1325 | + } |
|
1326 | + return $calculated_total_so_far; |
|
1327 | + } |
|
1328 | + |
|
1329 | + |
|
1330 | + /** |
|
1331 | + * Calculates the pretax total for a normal line item, in a round-then-sum approach |
|
1332 | + * (where each sub-line-item is applied to the base price for the line item |
|
1333 | + * and the result is immediately rounded, rather than summing all the sub-line-items |
|
1334 | + * then rounding, like we do when recalculating pretax totals on totals and subtotals). |
|
1335 | + * |
|
1336 | + * @param float $calculated_total_so_far |
|
1337 | + * @param EE_Line_Item[] $my_children |
|
1338 | + * @return float |
|
1339 | + * @throws EE_Error |
|
1340 | + * @throws InvalidArgumentException |
|
1341 | + * @throws InvalidDataTypeException |
|
1342 | + * @throws InvalidInterfaceException |
|
1343 | + * @throws ReflectionException |
|
1344 | + */ |
|
1345 | + protected function _recalculate_pretax_total_for_line_item($calculated_total_so_far, $my_children = null) |
|
1346 | + { |
|
1347 | + if ($my_children === null) { |
|
1348 | + $my_children = $this->children(); |
|
1349 | + } |
|
1350 | + // we need to keep track of the running total for a single item, |
|
1351 | + // because we need to round as we go |
|
1352 | + $unit_price_for_total = 0; |
|
1353 | + $quantity_for_total = 1; |
|
1354 | + // get the total of all its children |
|
1355 | + foreach ($my_children as $child_line_item) { |
|
1356 | + if ($child_line_item instanceof EE_Line_Item && ! $child_line_item->is_cancellation()) { |
|
1357 | + if ($child_line_item->is_percent()) { |
|
1358 | + // it should be the unit-price-so-far multiplied by teh percent multiplied by the quantity |
|
1359 | + // not total multiplied by percent, because that ignores rounding along-the-way |
|
1360 | + $percent_unit_price = round( |
|
1361 | + $unit_price_for_total * $child_line_item->percent() / 100, |
|
1362 | + EE_Registry::instance()->CFG->currency->dec_plc |
|
1363 | + ); |
|
1364 | + $percent_total = $percent_unit_price * $quantity_for_total; |
|
1365 | + $child_line_item->set_total($percent_total); |
|
1366 | + // so far all percent line items should have a quantity of 1 |
|
1367 | + // (ie, no double percent discounts. Although that might be requested someday) |
|
1368 | + $child_line_item->set_quantity(1); |
|
1369 | + $child_line_item->maybe_save(); |
|
1370 | + $calculated_total_so_far += $percent_total; |
|
1371 | + $unit_price_for_total += $percent_unit_price; |
|
1372 | + } else { |
|
1373 | + // verify flat sub-line-item quantities match their parent |
|
1374 | + if ($child_line_item->is_sub_line_item()) { |
|
1375 | + $child_line_item->set_quantity($this->quantity()); |
|
1376 | + } |
|
1377 | + $quantity_for_total = $child_line_item->quantity(); |
|
1378 | + $calculated_total_so_far += $child_line_item->recalculate_pre_tax_total(); |
|
1379 | + $unit_price_for_total += $child_line_item->unit_price(); |
|
1380 | + } |
|
1381 | + } |
|
1382 | + } |
|
1383 | + return $calculated_total_so_far; |
|
1384 | + } |
|
1385 | + |
|
1386 | + |
|
1387 | + /** |
|
1388 | + * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets |
|
1389 | + * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items |
|
1390 | + * and tax sub-total if already in the DB |
|
1391 | + * |
|
1392 | + * @return float |
|
1393 | + * @throws EE_Error |
|
1394 | + * @throws InvalidArgumentException |
|
1395 | + * @throws InvalidDataTypeException |
|
1396 | + * @throws InvalidInterfaceException |
|
1397 | + * @throws ReflectionException |
|
1398 | + */ |
|
1399 | + public function recalculate_taxes_and_tax_total() |
|
1400 | + { |
|
1401 | + // get all taxes |
|
1402 | + $taxes = $this->tax_descendants(); |
|
1403 | + // calculate the pretax total |
|
1404 | + $taxable_total = $this->taxable_total(); |
|
1405 | + $tax_total = 0; |
|
1406 | + foreach ($taxes as $tax) { |
|
1407 | + $total_on_this_tax = $taxable_total * $tax->percent() / 100; |
|
1408 | + // remember the total on this line item |
|
1409 | + $tax->set_total($total_on_this_tax); |
|
1410 | + $tax->maybe_save(); |
|
1411 | + $tax_total += $tax->total(); |
|
1412 | + } |
|
1413 | + $this->_recalculate_tax_sub_total(); |
|
1414 | + return $tax_total; |
|
1415 | + } |
|
1416 | + |
|
1417 | + |
|
1418 | + /** |
|
1419 | + * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated |
|
1420 | + * |
|
1421 | + * @return void |
|
1422 | + * @throws EE_Error |
|
1423 | + * @throws InvalidArgumentException |
|
1424 | + * @throws InvalidDataTypeException |
|
1425 | + * @throws InvalidInterfaceException |
|
1426 | + * @throws ReflectionException |
|
1427 | + */ |
|
1428 | + private function _recalculate_tax_sub_total() |
|
1429 | + { |
|
1430 | + if ($this->is_tax_sub_total()) { |
|
1431 | + $total = 0; |
|
1432 | + $total_percent = 0; |
|
1433 | + // simply loop through all its children (which should be taxes) and sum their total |
|
1434 | + foreach ($this->children() as $child_tax) { |
|
1435 | + if ($child_tax instanceof EE_Line_Item) { |
|
1436 | + $total += $child_tax->total(); |
|
1437 | + $total_percent += $child_tax->percent(); |
|
1438 | + } |
|
1439 | + } |
|
1440 | + $this->set_total($total); |
|
1441 | + $this->set_percent($total_percent); |
|
1442 | + $this->maybe_save(); |
|
1443 | + } elseif ($this->is_total()) { |
|
1444 | + foreach ($this->children() as $maybe_tax_subtotal) { |
|
1445 | + if ($maybe_tax_subtotal instanceof EE_Line_Item) { |
|
1446 | + $maybe_tax_subtotal->_recalculate_tax_sub_total(); |
|
1447 | + } |
|
1448 | + } |
|
1449 | + } |
|
1450 | + } |
|
1451 | + |
|
1452 | + |
|
1453 | + /** |
|
1454 | + * Gets the total tax on this line item. Assumes taxes have already been calculated using |
|
1455 | + * recalculate_taxes_and_total |
|
1456 | + * |
|
1457 | + * @return float |
|
1458 | + * @throws EE_Error |
|
1459 | + * @throws InvalidArgumentException |
|
1460 | + * @throws InvalidDataTypeException |
|
1461 | + * @throws InvalidInterfaceException |
|
1462 | + * @throws ReflectionException |
|
1463 | + */ |
|
1464 | + public function get_total_tax() |
|
1465 | + { |
|
1466 | + $this->_recalculate_tax_sub_total(); |
|
1467 | + $total = 0; |
|
1468 | + foreach ($this->tax_descendants() as $tax_line_item) { |
|
1469 | + if ($tax_line_item instanceof EE_Line_Item) { |
|
1470 | + $total += $tax_line_item->total(); |
|
1471 | + } |
|
1472 | + } |
|
1473 | + return $total; |
|
1474 | + } |
|
1475 | + |
|
1476 | + |
|
1477 | + /** |
|
1478 | + * Gets the total for all the items purchased only |
|
1479 | + * |
|
1480 | + * @return float |
|
1481 | + * @throws EE_Error |
|
1482 | + * @throws InvalidArgumentException |
|
1483 | + * @throws InvalidDataTypeException |
|
1484 | + * @throws InvalidInterfaceException |
|
1485 | + * @throws ReflectionException |
|
1486 | + */ |
|
1487 | + public function get_items_total() |
|
1488 | + { |
|
1489 | + // by default, let's make sure we're consistent with the existing line item |
|
1490 | + if ($this->is_total()) { |
|
1491 | + $pretax_subtotal_li = EEH_Line_Item::get_pre_tax_subtotal($this); |
|
1492 | + if ($pretax_subtotal_li instanceof EE_Line_Item) { |
|
1493 | + return $pretax_subtotal_li->total(); |
|
1494 | + } |
|
1495 | + } |
|
1496 | + $total = 0; |
|
1497 | + foreach ($this->get_items() as $item) { |
|
1498 | + if ($item instanceof EE_Line_Item) { |
|
1499 | + $total += $item->total(); |
|
1500 | + } |
|
1501 | + } |
|
1502 | + return $total; |
|
1503 | + } |
|
1504 | + |
|
1505 | + |
|
1506 | + /** |
|
1507 | + * Gets all the descendants (ie, children or children of children etc) that |
|
1508 | + * are of the type 'tax' |
|
1509 | + * |
|
1510 | + * @return EE_Line_Item[] |
|
1511 | + * @throws EE_Error |
|
1512 | + */ |
|
1513 | + public function tax_descendants() |
|
1514 | + { |
|
1515 | + return EEH_Line_Item::get_tax_descendants($this); |
|
1516 | + } |
|
1517 | + |
|
1518 | + |
|
1519 | + /** |
|
1520 | + * Gets all the real items purchased which are children of this item |
|
1521 | + * |
|
1522 | + * @return EE_Line_Item[] |
|
1523 | + * @throws EE_Error |
|
1524 | + */ |
|
1525 | + public function get_items() |
|
1526 | + { |
|
1527 | + return EEH_Line_Item::get_line_item_descendants($this); |
|
1528 | + } |
|
1529 | + |
|
1530 | + |
|
1531 | + /** |
|
1532 | + * Returns the amount taxable among this line item's children (or if it has no children, |
|
1533 | + * how much of it is taxable). Does not recalculate totals or subtotals. |
|
1534 | + * If the taxable total is negative, (eg, if none of the tickets were taxable, |
|
1535 | + * but there is a "Taxable" discount), returns 0. |
|
1536 | + * |
|
1537 | + * @return float |
|
1538 | + * @throws EE_Error |
|
1539 | + * @throws InvalidArgumentException |
|
1540 | + * @throws InvalidDataTypeException |
|
1541 | + * @throws InvalidInterfaceException |
|
1542 | + * @throws ReflectionException |
|
1543 | + */ |
|
1544 | + public function taxable_total() |
|
1545 | + { |
|
1546 | + $total = 0; |
|
1547 | + if ($this->children()) { |
|
1548 | + foreach ($this->children() as $child_line_item) { |
|
1549 | + if ($child_line_item->type() === EEM_Line_Item::type_line_item && $child_line_item->is_taxable()) { |
|
1550 | + // if it's a percent item, only take into account the percent |
|
1551 | + // that's taxable too (the taxable total so far) |
|
1552 | + if ($child_line_item->is_percent()) { |
|
1553 | + $total += ($total * $child_line_item->percent() / 100); |
|
1554 | + } else { |
|
1555 | + $total += $child_line_item->total(); |
|
1556 | + } |
|
1557 | + } elseif ($child_line_item->type() === EEM_Line_Item::type_sub_total) { |
|
1558 | + $total += $child_line_item->taxable_total(); |
|
1559 | + } |
|
1560 | + } |
|
1561 | + } |
|
1562 | + return max($total, 0); |
|
1563 | + } |
|
1564 | + |
|
1565 | + |
|
1566 | + /** |
|
1567 | + * Gets the transaction for this line item |
|
1568 | + * |
|
1569 | + * @return EE_Base_Class|EE_Transaction |
|
1570 | + * @throws EE_Error |
|
1571 | + * @throws InvalidArgumentException |
|
1572 | + * @throws InvalidDataTypeException |
|
1573 | + * @throws InvalidInterfaceException |
|
1574 | + * @throws ReflectionException |
|
1575 | + */ |
|
1576 | + public function transaction() |
|
1577 | + { |
|
1578 | + return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TRANSACTION); |
|
1579 | + } |
|
1580 | + |
|
1581 | + |
|
1582 | + /** |
|
1583 | + * Saves this line item to the DB, and recursively saves its descendants. |
|
1584 | + * Because there currently is no proper parent-child relation on the model, |
|
1585 | + * save_this_and_cached() will NOT save the descendants. |
|
1586 | + * Also sets the transaction on this line item and all its descendants before saving |
|
1587 | + * |
|
1588 | + * @param int $txn_id if none is provided, assumes $this->TXN_ID() |
|
1589 | + * @return int count of items saved |
|
1590 | + * @throws EE_Error |
|
1591 | + * @throws InvalidArgumentException |
|
1592 | + * @throws InvalidDataTypeException |
|
1593 | + * @throws InvalidInterfaceException |
|
1594 | + * @throws ReflectionException |
|
1595 | + */ |
|
1596 | + public function save_this_and_descendants_to_txn($txn_id = null) |
|
1597 | + { |
|
1598 | + $count = 0; |
|
1599 | + if (! $txn_id) { |
|
1600 | + $txn_id = $this->TXN_ID(); |
|
1601 | + } |
|
1602 | + $this->set_TXN_ID($txn_id); |
|
1603 | + $children = $this->children(); |
|
1604 | + $count += $this->save() |
|
1605 | + ? 1 |
|
1606 | + : 0; |
|
1607 | + foreach ($children as $child_line_item) { |
|
1608 | + if ($child_line_item instanceof EE_Line_Item) { |
|
1609 | + $child_line_item->set_parent_ID($this->ID()); |
|
1610 | + $count += $child_line_item->save_this_and_descendants_to_txn($txn_id); |
|
1611 | + } |
|
1612 | + } |
|
1613 | + return $count; |
|
1614 | + } |
|
1615 | + |
|
1616 | + |
|
1617 | + /** |
|
1618 | + * Saves this line item to the DB, and recursively saves its descendants. |
|
1619 | + * |
|
1620 | + * @return int count of items saved |
|
1621 | + * @throws EE_Error |
|
1622 | + * @throws InvalidArgumentException |
|
1623 | + * @throws InvalidDataTypeException |
|
1624 | + * @throws InvalidInterfaceException |
|
1625 | + * @throws ReflectionException |
|
1626 | + */ |
|
1627 | + public function save_this_and_descendants() |
|
1628 | + { |
|
1629 | + $count = 0; |
|
1630 | + $children = $this->children(); |
|
1631 | + $count += $this->save() |
|
1632 | + ? 1 |
|
1633 | + : 0; |
|
1634 | + foreach ($children as $child_line_item) { |
|
1635 | + if ($child_line_item instanceof EE_Line_Item) { |
|
1636 | + $child_line_item->set_parent_ID($this->ID()); |
|
1637 | + $count += $child_line_item->save_this_and_descendants(); |
|
1638 | + } |
|
1639 | + } |
|
1640 | + return $count; |
|
1641 | + } |
|
1642 | + |
|
1643 | + |
|
1644 | + /** |
|
1645 | + * returns the cancellation line item if this item was cancelled |
|
1646 | + * |
|
1647 | + * @return EE_Line_Item[] |
|
1648 | + * @throws InvalidArgumentException |
|
1649 | + * @throws InvalidInterfaceException |
|
1650 | + * @throws InvalidDataTypeException |
|
1651 | + * @throws ReflectionException |
|
1652 | + * @throws EE_Error |
|
1653 | + */ |
|
1654 | + public function get_cancellations() |
|
1655 | + { |
|
1656 | + EE_Registry::instance()->load_helper('Line_Item'); |
|
1657 | + return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_cancellation); |
|
1658 | + } |
|
1659 | + |
|
1660 | + |
|
1661 | + /** |
|
1662 | + * If this item has an ID, then this saves it again to update the db |
|
1663 | + * |
|
1664 | + * @return int count of items saved |
|
1665 | + * @throws EE_Error |
|
1666 | + * @throws InvalidArgumentException |
|
1667 | + * @throws InvalidDataTypeException |
|
1668 | + * @throws InvalidInterfaceException |
|
1669 | + * @throws ReflectionException |
|
1670 | + */ |
|
1671 | + public function maybe_save() |
|
1672 | + { |
|
1673 | + if ($this->ID()) { |
|
1674 | + return $this->save(); |
|
1675 | + } |
|
1676 | + return false; |
|
1677 | + } |
|
1678 | + |
|
1679 | + |
|
1680 | + /** |
|
1681 | + * clears the cached children and parent from the line item |
|
1682 | + * |
|
1683 | + * @return void |
|
1684 | + */ |
|
1685 | + public function clear_related_line_item_cache() |
|
1686 | + { |
|
1687 | + $this->_children = array(); |
|
1688 | + $this->_parent = null; |
|
1689 | + } |
|
1690 | + |
|
1691 | + |
|
1692 | + /** |
|
1693 | + * @param bool $raw |
|
1694 | + * @return int |
|
1695 | + * @throws EE_Error |
|
1696 | + * @throws InvalidArgumentException |
|
1697 | + * @throws InvalidDataTypeException |
|
1698 | + * @throws InvalidInterfaceException |
|
1699 | + * @throws ReflectionException |
|
1700 | + */ |
|
1701 | + public function timestamp($raw = false) |
|
1702 | + { |
|
1703 | + return $raw |
|
1704 | + ? $this->get_raw('LIN_timestamp') |
|
1705 | + : $this->get('LIN_timestamp'); |
|
1706 | + } |
|
1707 | + |
|
1708 | + |
|
1709 | + |
|
1710 | + |
|
1711 | + /************************* DEPRECATED *************************/ |
|
1712 | + /** |
|
1713 | + * @deprecated 4.6.0 |
|
1714 | + * @param string $type one of the constants on EEM_Line_Item |
|
1715 | + * @return EE_Line_Item[] |
|
1716 | + * @throws EE_Error |
|
1717 | + */ |
|
1718 | + protected function _get_descendants_of_type($type) |
|
1719 | + { |
|
1720 | + EE_Error::doing_it_wrong( |
|
1721 | + 'EE_Line_Item::_get_descendants_of_type()', |
|
1722 | + sprintf( |
|
1723 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
1724 | + 'EEH_Line_Item::get_descendants_of_type()' |
|
1725 | + ), |
|
1726 | + '4.6.0' |
|
1727 | + ); |
|
1728 | + return EEH_Line_Item::get_descendants_of_type($this, $type); |
|
1729 | + } |
|
1730 | + |
|
1731 | + |
|
1732 | + /** |
|
1733 | + * @deprecated 4.6.0 |
|
1734 | + * @param string $type like one of the EEM_Line_Item::type_* |
|
1735 | + * @return EE_Line_Item |
|
1736 | + * @throws EE_Error |
|
1737 | + * @throws InvalidArgumentException |
|
1738 | + * @throws InvalidDataTypeException |
|
1739 | + * @throws InvalidInterfaceException |
|
1740 | + * @throws ReflectionException |
|
1741 | + */ |
|
1742 | + public function get_nearest_descendant_of_type($type) |
|
1743 | + { |
|
1744 | + EE_Error::doing_it_wrong( |
|
1745 | + 'EE_Line_Item::get_nearest_descendant_of_type()', |
|
1746 | + sprintf( |
|
1747 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
1748 | + 'EEH_Line_Item::get_nearest_descendant_of_type()' |
|
1749 | + ), |
|
1750 | + '4.6.0' |
|
1751 | + ); |
|
1752 | + return EEH_Line_Item::get_nearest_descendant_of_type($this, $type); |
|
1753 | + } |
|
1754 | 1754 | } |
@@ -154,19 +154,19 @@ |
||
154 | 154 | $sanitized_attributes = array(); |
155 | 155 | foreach ($attributes as $attribute => $value) { |
156 | 156 | $convert = $this->getAttributesMap(); |
157 | - if (isset($convert[ $attribute ])) { |
|
158 | - $sanitize = $convert[ $attribute ]; |
|
157 | + if (isset($convert[$attribute])) { |
|
158 | + $sanitize = $convert[$attribute]; |
|
159 | 159 | if ($sanitize === 'bool') { |
160 | - $sanitized_attributes[ $attribute ] = filter_var( |
|
160 | + $sanitized_attributes[$attribute] = filter_var( |
|
161 | 161 | $value, |
162 | 162 | FILTER_VALIDATE_BOOLEAN |
163 | 163 | ); |
164 | 164 | } else { |
165 | - $sanitized_attributes[ $attribute ] = $sanitize($value); |
|
165 | + $sanitized_attributes[$attribute] = $sanitize($value); |
|
166 | 166 | } |
167 | 167 | // don't pass along attributes with a 0 value |
168 | - if ($sanitized_attributes[ $attribute ] === 0) { |
|
169 | - unset($sanitized_attributes[ $attribute ]); |
|
168 | + if ($sanitized_attributes[$attribute] === 0) { |
|
169 | + unset($sanitized_attributes[$attribute]); |
|
170 | 170 | } |
171 | 171 | } |
172 | 172 | } |
@@ -20,172 +20,172 @@ |
||
20 | 20 | */ |
21 | 21 | class EventAttendees extends Block |
22 | 22 | { |
23 | - const BLOCK_TYPE = 'event-attendees'; |
|
23 | + const BLOCK_TYPE = 'event-attendees'; |
|
24 | 24 | |
25 | - /** |
|
26 | - * @var EventAttendeesBlockRenderer $renderer |
|
27 | - */ |
|
28 | - protected $renderer; |
|
25 | + /** |
|
26 | + * @var EventAttendeesBlockRenderer $renderer |
|
27 | + */ |
|
28 | + protected $renderer; |
|
29 | 29 | |
30 | 30 | |
31 | - /** |
|
32 | - * EventAttendees constructor. |
|
33 | - * |
|
34 | - * @param CoreBlocksAssetManager $block_asset_manager |
|
35 | - * @param RequestInterface $request |
|
36 | - * @param EventAttendeesBlockRenderer $renderer |
|
37 | - */ |
|
38 | - public function __construct( |
|
39 | - CoreBlocksAssetManager $block_asset_manager, |
|
40 | - RequestInterface $request, |
|
41 | - EventAttendeesBlockRenderer $renderer |
|
42 | - ) { |
|
43 | - parent::__construct($block_asset_manager, $request); |
|
44 | - $this->renderer = $renderer; |
|
45 | - } |
|
31 | + /** |
|
32 | + * EventAttendees constructor. |
|
33 | + * |
|
34 | + * @param CoreBlocksAssetManager $block_asset_manager |
|
35 | + * @param RequestInterface $request |
|
36 | + * @param EventAttendeesBlockRenderer $renderer |
|
37 | + */ |
|
38 | + public function __construct( |
|
39 | + CoreBlocksAssetManager $block_asset_manager, |
|
40 | + RequestInterface $request, |
|
41 | + EventAttendeesBlockRenderer $renderer |
|
42 | + ) { |
|
43 | + parent::__construct($block_asset_manager, $request); |
|
44 | + $this->renderer = $renderer; |
|
45 | + } |
|
46 | 46 | |
47 | 47 | |
48 | - /** |
|
49 | - * Perform any early setup required by the block |
|
50 | - * including setting the block type and supported post types |
|
51 | - * |
|
52 | - * @return void |
|
53 | - */ |
|
54 | - public function initialize() |
|
55 | - { |
|
56 | - $this->setBlockType(self::BLOCK_TYPE); |
|
57 | - $this->setSupportedRoutes( |
|
58 | - array( |
|
59 | - 'EventEspresso\core\domain\entities\route_match\specifications\admin\EspressoStandardPostTypeEditor', |
|
60 | - 'EventEspresso\core\domain\entities\route_match\specifications\admin\WordPressPostTypeEditor', |
|
61 | - 'EventEspresso\core\domain\entities\route_match\specifications\frontend\EspressoBlockRenderer', |
|
62 | - 'EventEspresso\core\domain\entities\route_match\specifications\frontend\AnyFrontendRequest' |
|
63 | - ) |
|
64 | - ); |
|
65 | - $EVT_ID = $this->request->getRequestParam('page') === 'espresso_events' |
|
66 | - ? $this->request->getRequestParam('post', 0, 'int') |
|
67 | - : 0; |
|
68 | - $this->setAttributes( |
|
69 | - array( |
|
70 | - 'eventId' => array( |
|
71 | - 'type' => 'number', |
|
72 | - 'default' => $EVT_ID, |
|
73 | - ), |
|
74 | - 'datetimeId' => array( |
|
75 | - 'type' => 'number', |
|
76 | - 'default' => 0, |
|
77 | - ), |
|
78 | - 'ticketId' => array( |
|
79 | - 'type' => 'number', |
|
80 | - 'default' => 0, |
|
81 | - ), |
|
82 | - 'status' => array( |
|
83 | - 'type' => 'string', |
|
84 | - 'default' => EEM_Registration::status_id_approved, |
|
85 | - ), |
|
86 | - 'limit' => array( |
|
87 | - 'type' => 'number', |
|
88 | - 'default' => 100, |
|
89 | - ), |
|
90 | - 'order' => array( |
|
91 | - 'type' => 'string', |
|
92 | - 'default' => 'ASC' |
|
93 | - ), |
|
94 | - 'orderBy' => array( |
|
95 | - 'type' => 'string', |
|
96 | - 'default' => 'lastThenFirstName', |
|
97 | - ), |
|
98 | - 'showGravatar' => array( |
|
99 | - 'type' => 'boolean', |
|
100 | - 'default' => false, |
|
101 | - ), |
|
102 | - 'avatarClass' => array( |
|
103 | - 'type' => 'string', |
|
104 | - 'default' => 'contact', |
|
105 | - ), |
|
106 | - 'avatarSize' => array( |
|
107 | - 'type' => 'number', |
|
108 | - 'default' => 24, |
|
109 | - ), |
|
110 | - 'displayOnArchives' => array( |
|
111 | - 'type' => 'boolean', |
|
112 | - 'default' => false, |
|
113 | - ), |
|
114 | - ) |
|
115 | - ); |
|
116 | - $this->setDynamic(); |
|
117 | - } |
|
48 | + /** |
|
49 | + * Perform any early setup required by the block |
|
50 | + * including setting the block type and supported post types |
|
51 | + * |
|
52 | + * @return void |
|
53 | + */ |
|
54 | + public function initialize() |
|
55 | + { |
|
56 | + $this->setBlockType(self::BLOCK_TYPE); |
|
57 | + $this->setSupportedRoutes( |
|
58 | + array( |
|
59 | + 'EventEspresso\core\domain\entities\route_match\specifications\admin\EspressoStandardPostTypeEditor', |
|
60 | + 'EventEspresso\core\domain\entities\route_match\specifications\admin\WordPressPostTypeEditor', |
|
61 | + 'EventEspresso\core\domain\entities\route_match\specifications\frontend\EspressoBlockRenderer', |
|
62 | + 'EventEspresso\core\domain\entities\route_match\specifications\frontend\AnyFrontendRequest' |
|
63 | + ) |
|
64 | + ); |
|
65 | + $EVT_ID = $this->request->getRequestParam('page') === 'espresso_events' |
|
66 | + ? $this->request->getRequestParam('post', 0, 'int') |
|
67 | + : 0; |
|
68 | + $this->setAttributes( |
|
69 | + array( |
|
70 | + 'eventId' => array( |
|
71 | + 'type' => 'number', |
|
72 | + 'default' => $EVT_ID, |
|
73 | + ), |
|
74 | + 'datetimeId' => array( |
|
75 | + 'type' => 'number', |
|
76 | + 'default' => 0, |
|
77 | + ), |
|
78 | + 'ticketId' => array( |
|
79 | + 'type' => 'number', |
|
80 | + 'default' => 0, |
|
81 | + ), |
|
82 | + 'status' => array( |
|
83 | + 'type' => 'string', |
|
84 | + 'default' => EEM_Registration::status_id_approved, |
|
85 | + ), |
|
86 | + 'limit' => array( |
|
87 | + 'type' => 'number', |
|
88 | + 'default' => 100, |
|
89 | + ), |
|
90 | + 'order' => array( |
|
91 | + 'type' => 'string', |
|
92 | + 'default' => 'ASC' |
|
93 | + ), |
|
94 | + 'orderBy' => array( |
|
95 | + 'type' => 'string', |
|
96 | + 'default' => 'lastThenFirstName', |
|
97 | + ), |
|
98 | + 'showGravatar' => array( |
|
99 | + 'type' => 'boolean', |
|
100 | + 'default' => false, |
|
101 | + ), |
|
102 | + 'avatarClass' => array( |
|
103 | + 'type' => 'string', |
|
104 | + 'default' => 'contact', |
|
105 | + ), |
|
106 | + 'avatarSize' => array( |
|
107 | + 'type' => 'number', |
|
108 | + 'default' => 24, |
|
109 | + ), |
|
110 | + 'displayOnArchives' => array( |
|
111 | + 'type' => 'boolean', |
|
112 | + 'default' => false, |
|
113 | + ), |
|
114 | + ) |
|
115 | + ); |
|
116 | + $this->setDynamic(); |
|
117 | + } |
|
118 | 118 | |
119 | 119 | |
120 | - /** |
|
121 | - * Returns an array where the key corresponds to the incoming attribute name from the WP block |
|
122 | - * and the value corresponds to the attribute name for the existing EspressoEventAttendees shortcode |
|
123 | - * |
|
124 | - * @since 4.9.71.p |
|
125 | - * @return array |
|
126 | - */ |
|
127 | - private function getAttributesMap() |
|
128 | - { |
|
129 | - return array( |
|
130 | - 'eventId' => 'absint', |
|
131 | - 'datetimeId' => 'absint', |
|
132 | - 'ticketId' => 'absint', |
|
133 | - 'status' => 'sanitize_text_field', |
|
134 | - 'limit' => 'intval', |
|
135 | - 'showGravatar' => 'bool', |
|
136 | - 'avatarClass' => 'sanitize_text_field', |
|
137 | - 'avatarSize' => 'absint', |
|
138 | - 'displayOnArchives' => 'bool', |
|
139 | - 'order' => 'sanitize_text_field', |
|
140 | - 'orderBy' => 'sanitize_text_field', |
|
141 | - ); |
|
142 | - } |
|
120 | + /** |
|
121 | + * Returns an array where the key corresponds to the incoming attribute name from the WP block |
|
122 | + * and the value corresponds to the attribute name for the existing EspressoEventAttendees shortcode |
|
123 | + * |
|
124 | + * @since 4.9.71.p |
|
125 | + * @return array |
|
126 | + */ |
|
127 | + private function getAttributesMap() |
|
128 | + { |
|
129 | + return array( |
|
130 | + 'eventId' => 'absint', |
|
131 | + 'datetimeId' => 'absint', |
|
132 | + 'ticketId' => 'absint', |
|
133 | + 'status' => 'sanitize_text_field', |
|
134 | + 'limit' => 'intval', |
|
135 | + 'showGravatar' => 'bool', |
|
136 | + 'avatarClass' => 'sanitize_text_field', |
|
137 | + 'avatarSize' => 'absint', |
|
138 | + 'displayOnArchives' => 'bool', |
|
139 | + 'order' => 'sanitize_text_field', |
|
140 | + 'orderBy' => 'sanitize_text_field', |
|
141 | + ); |
|
142 | + } |
|
143 | 143 | |
144 | 144 | |
145 | - /** |
|
146 | - * Sanitizes attributes. |
|
147 | - * |
|
148 | - * @param array $attributes |
|
149 | - * @return array |
|
150 | - */ |
|
151 | - private function sanitizeAttributes(array $attributes) |
|
152 | - { |
|
153 | - $sanitized_attributes = array(); |
|
154 | - foreach ($attributes as $attribute => $value) { |
|
155 | - $convert = $this->getAttributesMap(); |
|
156 | - if (isset($convert[ $attribute ])) { |
|
157 | - $sanitize = $convert[ $attribute ]; |
|
158 | - if ($sanitize === 'bool') { |
|
159 | - $sanitized_attributes[ $attribute ] = filter_var( |
|
160 | - $value, |
|
161 | - FILTER_VALIDATE_BOOLEAN |
|
162 | - ); |
|
163 | - } else { |
|
164 | - $sanitized_attributes[ $attribute ] = $sanitize($value); |
|
165 | - } |
|
166 | - // don't pass along attributes with a 0 value |
|
167 | - if ($sanitized_attributes[ $attribute ] === 0) { |
|
168 | - unset($sanitized_attributes[ $attribute ]); |
|
169 | - } |
|
170 | - } |
|
171 | - } |
|
172 | - return $attributes; |
|
173 | - } |
|
145 | + /** |
|
146 | + * Sanitizes attributes. |
|
147 | + * |
|
148 | + * @param array $attributes |
|
149 | + * @return array |
|
150 | + */ |
|
151 | + private function sanitizeAttributes(array $attributes) |
|
152 | + { |
|
153 | + $sanitized_attributes = array(); |
|
154 | + foreach ($attributes as $attribute => $value) { |
|
155 | + $convert = $this->getAttributesMap(); |
|
156 | + if (isset($convert[ $attribute ])) { |
|
157 | + $sanitize = $convert[ $attribute ]; |
|
158 | + if ($sanitize === 'bool') { |
|
159 | + $sanitized_attributes[ $attribute ] = filter_var( |
|
160 | + $value, |
|
161 | + FILTER_VALIDATE_BOOLEAN |
|
162 | + ); |
|
163 | + } else { |
|
164 | + $sanitized_attributes[ $attribute ] = $sanitize($value); |
|
165 | + } |
|
166 | + // don't pass along attributes with a 0 value |
|
167 | + if ($sanitized_attributes[ $attribute ] === 0) { |
|
168 | + unset($sanitized_attributes[ $attribute ]); |
|
169 | + } |
|
170 | + } |
|
171 | + } |
|
172 | + return $attributes; |
|
173 | + } |
|
174 | 174 | |
175 | 175 | |
176 | - /** |
|
177 | - * Returns the rendered HTML for the block |
|
178 | - * |
|
179 | - * @param array $attributes |
|
180 | - * @return string |
|
181 | - * @throws DomainException |
|
182 | - * @throws EE_Error |
|
183 | - */ |
|
184 | - public function renderBlock(array $attributes = array()) |
|
185 | - { |
|
186 | - $attributes = $this->sanitizeAttributes($attributes); |
|
187 | - return (is_archive() || is_front_page() || is_home()) && ! $attributes['displayOnArchives'] |
|
188 | - ? '' |
|
189 | - : $this->renderer->render($attributes); |
|
190 | - } |
|
176 | + /** |
|
177 | + * Returns the rendered HTML for the block |
|
178 | + * |
|
179 | + * @param array $attributes |
|
180 | + * @return string |
|
181 | + * @throws DomainException |
|
182 | + * @throws EE_Error |
|
183 | + */ |
|
184 | + public function renderBlock(array $attributes = array()) |
|
185 | + { |
|
186 | + $attributes = $this->sanitizeAttributes($attributes); |
|
187 | + return (is_archive() || is_front_page() || is_home()) && ! $attributes['displayOnArchives'] |
|
188 | + ? '' |
|
189 | + : $this->renderer->render($attributes); |
|
190 | + } |
|
191 | 191 | } |
@@ -17,85 +17,85 @@ |
||
17 | 17 | */ |
18 | 18 | class EE_Restriction_Generator_Default_Protected extends EE_Restriction_Generator_Base |
19 | 19 | { |
20 | - /** |
|
21 | - * Name of the field on this model (or a related model, including the model chain to it) |
|
22 | - * that is a boolean indicating whether or not a model object is considered "Default" or not |
|
23 | - * @var string |
|
24 | - */ |
|
25 | - protected $_default_field_name; |
|
20 | + /** |
|
21 | + * Name of the field on this model (or a related model, including the model chain to it) |
|
22 | + * that is a boolean indicating whether or not a model object is considered "Default" or not |
|
23 | + * @var string |
|
24 | + */ |
|
25 | + protected $_default_field_name; |
|
26 | 26 | |
27 | - /** |
|
28 | - * The model chain to follow to get to the event model, including the event model itself. |
|
29 | - * Eg 'Ticket.Datetime.Event' |
|
30 | - * @var string |
|
31 | - */ |
|
32 | - protected $_path_to_event_model; |
|
33 | - /** |
|
34 | - * |
|
35 | - * @param string $default_field_name the name of the field Name of the field on this model (or a related model, including the model chain to it) |
|
36 | - * that is a boolean indicating whether or not a model object is considered "Default" or not |
|
37 | - * @param string $path_to_event_model The model chain to follow to get to the event model, including the event model itself. |
|
38 | - * Eg 'Ticket.Datetime.Event' |
|
39 | - */ |
|
40 | - public function __construct($default_field_name, $path_to_event_model) |
|
41 | - { |
|
42 | - $this->_default_field_name = $default_field_name; |
|
43 | - if (substr($path_to_event_model, -1, 1) != '.') { |
|
44 | - $path_to_event_model .= '.'; |
|
45 | - } |
|
46 | - $this->_path_to_event_model = $path_to_event_model; |
|
47 | - } |
|
27 | + /** |
|
28 | + * The model chain to follow to get to the event model, including the event model itself. |
|
29 | + * Eg 'Ticket.Datetime.Event' |
|
30 | + * @var string |
|
31 | + */ |
|
32 | + protected $_path_to_event_model; |
|
33 | + /** |
|
34 | + * |
|
35 | + * @param string $default_field_name the name of the field Name of the field on this model (or a related model, including the model chain to it) |
|
36 | + * that is a boolean indicating whether or not a model object is considered "Default" or not |
|
37 | + * @param string $path_to_event_model The model chain to follow to get to the event model, including the event model itself. |
|
38 | + * Eg 'Ticket.Datetime.Event' |
|
39 | + */ |
|
40 | + public function __construct($default_field_name, $path_to_event_model) |
|
41 | + { |
|
42 | + $this->_default_field_name = $default_field_name; |
|
43 | + if (substr($path_to_event_model, -1, 1) != '.') { |
|
44 | + $path_to_event_model .= '.'; |
|
45 | + } |
|
46 | + $this->_path_to_event_model = $path_to_event_model; |
|
47 | + } |
|
48 | 48 | |
49 | 49 | |
50 | 50 | |
51 | - /** |
|
52 | - * |
|
53 | - * @return \EE_Default_Where_Conditions |
|
54 | - */ |
|
55 | - protected function _generate_restrictions() |
|
56 | - { |
|
57 | - // if there are no standard caps for this model, then for now all we know is |
|
58 | - // if they need the default cap to access this |
|
59 | - if (! $this->model()->cap_slug()) { |
|
60 | - return array( |
|
61 | - self::get_default_restrictions_cap() => new EE_Return_None_Where_Conditions() |
|
62 | - ); |
|
63 | - } |
|
51 | + /** |
|
52 | + * |
|
53 | + * @return \EE_Default_Where_Conditions |
|
54 | + */ |
|
55 | + protected function _generate_restrictions() |
|
56 | + { |
|
57 | + // if there are no standard caps for this model, then for now all we know is |
|
58 | + // if they need the default cap to access this |
|
59 | + if (! $this->model()->cap_slug()) { |
|
60 | + return array( |
|
61 | + self::get_default_restrictions_cap() => new EE_Return_None_Where_Conditions() |
|
62 | + ); |
|
63 | + } |
|
64 | 64 | |
65 | - $event_model = EEM_Event::instance(); |
|
65 | + $event_model = EEM_Event::instance(); |
|
66 | 66 | |
67 | - $restrictions = array( |
|
68 | - // first: basically access to non-defaults is essentially controlled by which events are accessible |
|
69 | - // if they don't have the basic event cap, they can't access ANY non-default items |
|
70 | - EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action()) => new EE_Default_Where_Conditions(array( $this->_default_field_name => true )), |
|
71 | - // if they don't have the others event cap, they can't access others' non-default items |
|
72 | - EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_others') => new EE_Default_Where_Conditions(array( |
|
73 | - 'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_others') => array( |
|
74 | - $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder ), |
|
75 | - $this->_default_field_name => true )), |
|
76 | - // if they have basic and others, but not private, they can't access others' private non-default items |
|
77 | - EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_private') => new EE_Default_Where_Conditions(array( |
|
78 | - 'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_private') => array( |
|
79 | - $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder, |
|
80 | - $this->_path_to_event_model . 'status' => array( '!=', 'private' ), |
|
81 | - $this->_default_field_name => true ) )), |
|
82 | - // second: access to defaults is controlled by the defaulty capabilities |
|
83 | - // if they don't have the default capability, restrict access to only non-default items |
|
84 | - EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_default') => new EE_Default_Where_Conditions(array( $this->_default_field_name => false )), |
|
85 | - // if they don't have the "others" default capability, restrict access to only their default ones, and non-default ones |
|
86 | - ); |
|
87 | - if (EE_Restriction_Generator_Base::is_cap($this->model(), $this->action() . '_others_default')) { |
|
88 | - $restrictions[ EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_others_default') ] = new EE_Default_Where_Conditions(array( |
|
89 | - // if they don't have the others default cap, they can't access others default items (but they can access |
|
90 | - // their own default items, and non-default items) |
|
91 | - 'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_others_default') => array( |
|
92 | - 'AND' => array( |
|
93 | - $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder, |
|
94 | - $this->_default_field_name => true |
|
95 | - ), |
|
96 | - $this->_default_field_name => false |
|
97 | - ) )); |
|
98 | - } |
|
99 | - return $restrictions; |
|
100 | - } |
|
67 | + $restrictions = array( |
|
68 | + // first: basically access to non-defaults is essentially controlled by which events are accessible |
|
69 | + // if they don't have the basic event cap, they can't access ANY non-default items |
|
70 | + EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action()) => new EE_Default_Where_Conditions(array( $this->_default_field_name => true )), |
|
71 | + // if they don't have the others event cap, they can't access others' non-default items |
|
72 | + EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_others') => new EE_Default_Where_Conditions(array( |
|
73 | + 'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_others') => array( |
|
74 | + $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder ), |
|
75 | + $this->_default_field_name => true )), |
|
76 | + // if they have basic and others, but not private, they can't access others' private non-default items |
|
77 | + EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_private') => new EE_Default_Where_Conditions(array( |
|
78 | + 'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_private') => array( |
|
79 | + $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder, |
|
80 | + $this->_path_to_event_model . 'status' => array( '!=', 'private' ), |
|
81 | + $this->_default_field_name => true ) )), |
|
82 | + // second: access to defaults is controlled by the defaulty capabilities |
|
83 | + // if they don't have the default capability, restrict access to only non-default items |
|
84 | + EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_default') => new EE_Default_Where_Conditions(array( $this->_default_field_name => false )), |
|
85 | + // if they don't have the "others" default capability, restrict access to only their default ones, and non-default ones |
|
86 | + ); |
|
87 | + if (EE_Restriction_Generator_Base::is_cap($this->model(), $this->action() . '_others_default')) { |
|
88 | + $restrictions[ EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_others_default') ] = new EE_Default_Where_Conditions(array( |
|
89 | + // if they don't have the others default cap, they can't access others default items (but they can access |
|
90 | + // their own default items, and non-default items) |
|
91 | + 'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_others_default') => array( |
|
92 | + 'AND' => array( |
|
93 | + $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder, |
|
94 | + $this->_default_field_name => true |
|
95 | + ), |
|
96 | + $this->_default_field_name => false |
|
97 | + ) )); |
|
98 | + } |
|
99 | + return $restrictions; |
|
100 | + } |
|
101 | 101 | } |
@@ -56,7 +56,7 @@ discard block |
||
56 | 56 | { |
57 | 57 | // if there are no standard caps for this model, then for now all we know is |
58 | 58 | // if they need the default cap to access this |
59 | - if (! $this->model()->cap_slug()) { |
|
59 | + if ( ! $this->model()->cap_slug()) { |
|
60 | 60 | return array( |
61 | 61 | self::get_default_restrictions_cap() => new EE_Return_None_Where_Conditions() |
62 | 62 | ); |
@@ -64,33 +64,33 @@ discard block |
||
64 | 64 | |
65 | 65 | $event_model = EEM_Event::instance(); |
66 | 66 | |
67 | - $restrictions = array( |
|
67 | + $restrictions = array( |
|
68 | 68 | // first: basically access to non-defaults is essentially controlled by which events are accessible |
69 | 69 | // if they don't have the basic event cap, they can't access ANY non-default items |
70 | - EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action()) => new EE_Default_Where_Conditions(array( $this->_default_field_name => true )), |
|
70 | + EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action()) => new EE_Default_Where_Conditions(array($this->_default_field_name => true)), |
|
71 | 71 | // if they don't have the others event cap, they can't access others' non-default items |
72 | - EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_others') => new EE_Default_Where_Conditions(array( |
|
73 | - 'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_others') => array( |
|
74 | - $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder ), |
|
72 | + EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action().'_others') => new EE_Default_Where_Conditions(array( |
|
73 | + 'OR*no_'.EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action().'_others') => array( |
|
74 | + $this->_path_to_event_model.'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder ), |
|
75 | 75 | $this->_default_field_name => true )), |
76 | 76 | // if they have basic and others, but not private, they can't access others' private non-default items |
77 | - EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_private') => new EE_Default_Where_Conditions(array( |
|
78 | - 'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action() . '_private') => array( |
|
79 | - $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder, |
|
80 | - $this->_path_to_event_model . 'status' => array( '!=', 'private' ), |
|
77 | + EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action().'_private') => new EE_Default_Where_Conditions(array( |
|
78 | + 'OR*no_'.EE_Restriction_Generator_Base::get_cap_name($event_model, $this->action().'_private') => array( |
|
79 | + $this->_path_to_event_model.'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder, |
|
80 | + $this->_path_to_event_model.'status' => array('!=', 'private'), |
|
81 | 81 | $this->_default_field_name => true ) )), |
82 | 82 | // second: access to defaults is controlled by the defaulty capabilities |
83 | 83 | // if they don't have the default capability, restrict access to only non-default items |
84 | - EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_default') => new EE_Default_Where_Conditions(array( $this->_default_field_name => false )), |
|
84 | + EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action().'_default') => new EE_Default_Where_Conditions(array($this->_default_field_name => false)), |
|
85 | 85 | // if they don't have the "others" default capability, restrict access to only their default ones, and non-default ones |
86 | 86 | ); |
87 | - if (EE_Restriction_Generator_Base::is_cap($this->model(), $this->action() . '_others_default')) { |
|
88 | - $restrictions[ EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_others_default') ] = new EE_Default_Where_Conditions(array( |
|
87 | + if (EE_Restriction_Generator_Base::is_cap($this->model(), $this->action().'_others_default')) { |
|
88 | + $restrictions[EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action().'_others_default')] = new EE_Default_Where_Conditions(array( |
|
89 | 89 | // if they don't have the others default cap, they can't access others default items (but they can access |
90 | 90 | // their own default items, and non-default items) |
91 | - 'OR*no_' . EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action() . '_others_default') => array( |
|
91 | + 'OR*no_'.EE_Restriction_Generator_Base::get_cap_name($this->model(), $this->action().'_others_default') => array( |
|
92 | 92 | 'AND' => array( |
93 | - $this->_path_to_event_model . 'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder, |
|
93 | + $this->_path_to_event_model.'EVT_wp_user' => EE_Default_Where_Conditions::current_user_placeholder, |
|
94 | 94 | $this->_default_field_name => true |
95 | 95 | ), |
96 | 96 | $this->_default_field_name => false |
@@ -216,7 +216,7 @@ discard block |
||
216 | 216 | { |
217 | 217 | if (EEH_Event_Query::apply_query_filters($wp_query)) { |
218 | 218 | global $wpdb; |
219 | - $clauses['groupby'] = $wpdb->posts . '.ID '; |
|
219 | + $clauses['groupby'] = $wpdb->posts.'.ID '; |
|
220 | 220 | } |
221 | 221 | return $clauses; |
222 | 222 | } |
@@ -251,23 +251,23 @@ discard block |
||
251 | 251 | */ |
252 | 252 | public static function posts_fields_sql_for_orderby(array $orderby_params = []) |
253 | 253 | { |
254 | - $SQL = ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date '; |
|
254 | + $SQL = ', MIN( '.EEM_Datetime::instance()->table().'.DTT_EVT_start ) as event_start_date '; |
|
255 | 255 | foreach ($orderby_params as $orderby) { |
256 | 256 | switch ($orderby) { |
257 | 257 | case 'ticket_start': |
258 | - $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_start_date'; |
|
258 | + $SQL .= ', '.EEM_Ticket::instance()->table().'.TKT_start_date'; |
|
259 | 259 | break; |
260 | 260 | case 'ticket_end': |
261 | - $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_end_date'; |
|
261 | + $SQL .= ', '.EEM_Ticket::instance()->table().'.TKT_end_date'; |
|
262 | 262 | break; |
263 | 263 | case 'venue_title': |
264 | 264 | $SQL .= ', Venue.post_title AS venue_title'; |
265 | 265 | break; |
266 | 266 | case 'city': |
267 | - $SQL .= ', ' . EEM_Venue::instance()->second_table() . '.VNU_city'; |
|
267 | + $SQL .= ', '.EEM_Venue::instance()->second_table().'.VNU_city'; |
|
268 | 268 | break; |
269 | 269 | case 'state': |
270 | - $SQL .= ', ' . EEM_State::instance()->table() . '.STA_name'; |
|
270 | + $SQL .= ', '.EEM_State::instance()->table().'.STA_name'; |
|
271 | 271 | break; |
272 | 272 | } |
273 | 273 | } |
@@ -307,12 +307,12 @@ discard block |
||
307 | 307 | */ |
308 | 308 | public static function posts_join_sql_for_show_expired($SQL = '', $show_expired = false) |
309 | 309 | { |
310 | - if (! $show_expired) { |
|
311 | - $join = EEM_Event::instance()->table() . '.ID = '; |
|
312 | - $join .= EEM_Datetime::instance()->table() . '.' . EEM_Event::instance()->primary_key_name(); |
|
310 | + if ( ! $show_expired) { |
|
311 | + $join = EEM_Event::instance()->table().'.ID = '; |
|
312 | + $join .= EEM_Datetime::instance()->table().'.'.EEM_Event::instance()->primary_key_name(); |
|
313 | 313 | // don't add if this is already in the SQL |
314 | 314 | if (strpos($SQL, $join) === false) { |
315 | - $SQL .= ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . $join . ' ) '; |
|
315 | + $SQL .= ' INNER JOIN '.EEM_Datetime::instance()->table().' ON ( '.$join.' ) '; |
|
316 | 316 | } |
317 | 317 | } |
318 | 318 | return $SQL; |
@@ -327,7 +327,7 @@ discard block |
||
327 | 327 | */ |
328 | 328 | public static function posts_join_sql_for_terms($SQL = '', $join_terms = '') |
329 | 329 | { |
330 | - if (! empty($join_terms)) { |
|
330 | + if ( ! empty($join_terms)) { |
|
331 | 331 | global $wpdb; |
332 | 332 | $SQL .= " LEFT JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)"; |
333 | 333 | $SQL .= " LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)"; |
@@ -356,13 +356,13 @@ discard block |
||
356 | 356 | case 'ticket_end': |
357 | 357 | $SQL .= EEH_Event_Query::_posts_join_for_datetime( |
358 | 358 | $SQL, |
359 | - EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Datetime::instance()->primary_key_name() |
|
359 | + EEM_Datetime_Ticket::instance()->table().'.'.EEM_Datetime::instance()->primary_key_name() |
|
360 | 360 | ); |
361 | - $SQL .= ' LEFT JOIN ' . EEM_Ticket::instance()->table(); |
|
361 | + $SQL .= ' LEFT JOIN '.EEM_Ticket::instance()->table(); |
|
362 | 362 | $SQL .= ' ON ('; |
363 | - $SQL .= EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Ticket::instance()->primary_key_name(); |
|
363 | + $SQL .= EEM_Datetime_Ticket::instance()->table().'.'.EEM_Ticket::instance()->primary_key_name(); |
|
364 | 364 | $SQL .= ' = '; |
365 | - $SQL .= EEM_Ticket::instance()->table() . '.' . EEM_Ticket::instance()->primary_key_name(); |
|
365 | + $SQL .= EEM_Ticket::instance()->table().'.'.EEM_Ticket::instance()->primary_key_name(); |
|
366 | 366 | $SQL .= ' )'; |
367 | 367 | break; |
368 | 368 | case 'venue_title': |
@@ -375,7 +375,7 @@ discard block |
||
375 | 375 | break; |
376 | 376 | case 'start_date': |
377 | 377 | default: |
378 | - $SQL .= EEH_Event_Query::_posts_join_for_datetime($SQL, EEM_Event::instance()->table() . '.ID'); |
|
378 | + $SQL .= EEH_Event_Query::_posts_join_for_datetime($SQL, EEM_Event::instance()->table().'.ID'); |
|
379 | 379 | break; |
380 | 380 | } |
381 | 381 | } |
@@ -394,10 +394,10 @@ discard block |
||
394 | 394 | */ |
395 | 395 | protected static function _posts_join_for_datetime($SQL = '', $join = '') |
396 | 396 | { |
397 | - if (! empty($join)) { |
|
398 | - $join .= ' = ' . EEM_Datetime::instance()->table() . '.' . EEM_Event::instance()->primary_key_name(); |
|
397 | + if ( ! empty($join)) { |
|
398 | + $join .= ' = '.EEM_Datetime::instance()->table().'.'.EEM_Event::instance()->primary_key_name(); |
|
399 | 399 | if (strpos($SQL, $join) === false) { |
400 | - return ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . $join . ' )'; |
|
400 | + return ' INNER JOIN '.EEM_Datetime::instance()->table().' ON ( '.$join.' )'; |
|
401 | 401 | } |
402 | 402 | } |
403 | 403 | return ''; |
@@ -417,8 +417,8 @@ discard block |
||
417 | 417 | // Event Venue table name |
418 | 418 | $event_venue_table = EEM_Event_Venue::instance()->table(); |
419 | 419 | // generate conditions for: Event <=> Event Venue JOIN clause |
420 | - $event_to_event_venue_join = EEM_Event::instance()->table() . '.ID = '; |
|
421 | - $event_to_event_venue_join .= $event_venue_table . '.' . EEM_Event::instance()->primary_key_name(); |
|
420 | + $event_to_event_venue_join = EEM_Event::instance()->table().'.ID = '; |
|
421 | + $event_to_event_venue_join .= $event_venue_table.'.'.EEM_Event::instance()->primary_key_name(); |
|
422 | 422 | // don't add joins if they have already been added |
423 | 423 | if (strpos($SQL, $event_to_event_venue_join) === false) { |
424 | 424 | // Venue table name |
@@ -506,7 +506,7 @@ discard block |
||
506 | 506 | public static function posts_where_sql_for_show_expired($show_expired = false) |
507 | 507 | { |
508 | 508 | return ! $show_expired |
509 | - ? ' AND ' . EEM_Datetime::instance()->table() . '.DTT_EVT_end > \'' . current_time('mysql', true) . '\' ' |
|
509 | + ? ' AND '.EEM_Datetime::instance()->table().'.DTT_EVT_end > \''.current_time('mysql', true).'\' ' |
|
510 | 510 | : ''; |
511 | 511 | } |
512 | 512 | |
@@ -518,7 +518,7 @@ discard block |
||
518 | 518 | public static function posts_where_sql_for_event_category_slug($event_category_slug = null) |
519 | 519 | { |
520 | 520 | global $wpdb; |
521 | - if (! empty($event_category_slug)) { |
|
521 | + if ( ! empty($event_category_slug)) { |
|
522 | 522 | $event_category_slugs_array = array_map('trim', explode(',', $event_category_slug)); |
523 | 523 | $event_category_slugs_prepare = implode(', ', array_fill(0, count($event_category_slugs_array), '%s')); |
524 | 524 | return $wpdb->prepare( |
@@ -541,14 +541,14 @@ discard block |
||
541 | 541 | public static function posts_where_sql_for_event_list_month($month = null) |
542 | 542 | { |
543 | 543 | $SQL = ''; |
544 | - if (! empty($month)) { |
|
544 | + if ( ! empty($month)) { |
|
545 | 545 | $datetime_table = EEM_Datetime::instance()->table(); |
546 | 546 | // event start date is LESS than the end of the month ( so nothing that doesn't start until next month ) |
547 | 547 | $SQL = " AND {$datetime_table}.DTT_EVT_start <= '"; |
548 | - $SQL .= date('Y-m-t 23:59:59', EEH_DTT_Helper::first_of_month_timestamp($month)) . "'"; |
|
548 | + $SQL .= date('Y-m-t 23:59:59', EEH_DTT_Helper::first_of_month_timestamp($month))."'"; |
|
549 | 549 | // event end date is GREATER than the start of the month ( so nothing that ended before this month ) |
550 | 550 | $SQL .= " AND {$datetime_table}.DTT_EVT_end >= '"; |
551 | - $SQL .= date('Y-m-01 0:0:00', EEH_DTT_Helper::first_of_month_timestamp($month)) . "' "; |
|
551 | + $SQL .= date('Y-m-01 0:0:00', EEH_DTT_Helper::first_of_month_timestamp($month))."' "; |
|
552 | 552 | } |
553 | 553 | return $SQL; |
554 | 554 | } |
@@ -609,15 +609,15 @@ discard block |
||
609 | 609 | ? strtoupper($sort) |
610 | 610 | : 'ASC'; |
611 | 611 | // make sure 'orderby' is set in query params |
612 | - if (! isset(self::$_query_params['orderby'])) { |
|
612 | + if ( ! isset(self::$_query_params['orderby'])) { |
|
613 | 613 | self::$_query_params['orderby'] = []; |
614 | 614 | } |
615 | 615 | // loop thru $orderby_params (type cast as array) |
616 | 616 | foreach ($orderby_params as $orderby) { |
617 | 617 | // check if we have already added this param |
618 | - if (isset(self::$_query_params['orderby'][ $orderby ])) { |
|
618 | + if (isset(self::$_query_params['orderby'][$orderby])) { |
|
619 | 619 | // if so then remove from the $orderby_params so that the count() method below is accurate |
620 | - unset($orderby_params[ $orderby ]); |
|
620 | + unset($orderby_params[$orderby]); |
|
621 | 621 | // then bump ahead to the next param |
622 | 622 | continue; |
623 | 623 | } |
@@ -627,39 +627,39 @@ discard block |
||
627 | 627 | switch ($orderby) { |
628 | 628 | case 'id': |
629 | 629 | case 'ID': |
630 | - $SQL .= $glue . $wpdb->posts . '.ID ' . $sort; |
|
630 | + $SQL .= $glue.$wpdb->posts.'.ID '.$sort; |
|
631 | 631 | break; |
632 | 632 | case 'end_date': |
633 | - $SQL .= $glue . EEM_Datetime::instance()->table() . '.DTT_EVT_end ' . $sort; |
|
633 | + $SQL .= $glue.EEM_Datetime::instance()->table().'.DTT_EVT_end '.$sort; |
|
634 | 634 | break; |
635 | 635 | case 'event_name': |
636 | - $SQL .= $glue . $wpdb->posts . '.post_title ' . $sort; |
|
636 | + $SQL .= $glue.$wpdb->posts.'.post_title '.$sort; |
|
637 | 637 | break; |
638 | 638 | case 'category_slug': |
639 | - $SQL .= $glue . $wpdb->terms . '.slug ' . $sort; |
|
639 | + $SQL .= $glue.$wpdb->terms.'.slug '.$sort; |
|
640 | 640 | break; |
641 | 641 | case 'ticket_start': |
642 | - $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_start_date ' . $sort; |
|
642 | + $SQL .= $glue.EEM_Ticket::instance()->table().'.TKT_start_date '.$sort; |
|
643 | 643 | break; |
644 | 644 | case 'ticket_end': |
645 | - $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_end_date ' . $sort; |
|
645 | + $SQL .= $glue.EEM_Ticket::instance()->table().'.TKT_end_date '.$sort; |
|
646 | 646 | break; |
647 | 647 | case 'venue_title': |
648 | - $SQL .= $glue . 'venue_title ' . $sort; |
|
648 | + $SQL .= $glue.'venue_title '.$sort; |
|
649 | 649 | break; |
650 | 650 | case 'city': |
651 | - $SQL .= $glue . EEM_Venue::instance()->second_table() . '.VNU_city ' . $sort; |
|
651 | + $SQL .= $glue.EEM_Venue::instance()->second_table().'.VNU_city '.$sort; |
|
652 | 652 | break; |
653 | 653 | case 'state': |
654 | - $SQL .= $glue . EEM_State::instance()->table() . '.STA_name ' . $sort; |
|
654 | + $SQL .= $glue.EEM_State::instance()->table().'.STA_name '.$sort; |
|
655 | 655 | break; |
656 | 656 | case 'start_date': |
657 | 657 | default: |
658 | - $SQL .= $glue . ' event_start_date ' . $sort; |
|
658 | + $SQL .= $glue.' event_start_date '.$sort; |
|
659 | 659 | break; |
660 | 660 | } |
661 | 661 | // add to array of orderby params that have been added |
662 | - self::$_query_params['orderby'][ $orderby ] = true; |
|
662 | + self::$_query_params['orderby'][$orderby] = true; |
|
663 | 663 | $counter++; |
664 | 664 | } |
665 | 665 | return $SQL; |
@@ -17,666 +17,666 @@ |
||
17 | 17 | */ |
18 | 18 | class EEH_Event_Query |
19 | 19 | { |
20 | - /** |
|
21 | - * Start Date |
|
22 | - * |
|
23 | - * @var $_event_query_month |
|
24 | - */ |
|
25 | - protected static $_event_query_month; |
|
26 | - |
|
27 | - /** |
|
28 | - * Category |
|
29 | - * |
|
30 | - * @var $_event_query_category |
|
31 | - */ |
|
32 | - protected static $_event_query_category; |
|
33 | - |
|
34 | - /** |
|
35 | - * whether to display expired events in the event list |
|
36 | - * |
|
37 | - * @var bool $_show_expired |
|
38 | - */ |
|
39 | - protected static $_event_query_show_expired = false; |
|
40 | - |
|
41 | - /** |
|
42 | - * list of params for controlling how the query results are ordered |
|
43 | - * |
|
44 | - * @var array $_event_query_orderby |
|
45 | - */ |
|
46 | - protected static $_event_query_orderby = []; |
|
47 | - |
|
48 | - /** |
|
49 | - * direction list is sorted |
|
50 | - * |
|
51 | - * @var string $_event_query_sort |
|
52 | - */ |
|
53 | - protected static $_event_query_sort; |
|
54 | - |
|
55 | - /** |
|
56 | - * list of params used to build the query's various clauses |
|
57 | - * |
|
58 | - * @var $_query_params |
|
59 | - */ |
|
60 | - protected static $_query_params = []; |
|
61 | - |
|
62 | - |
|
63 | - /** |
|
64 | - * @return void |
|
65 | - */ |
|
66 | - public static function add_query_filters() |
|
67 | - { |
|
68 | - // add query filters |
|
69 | - add_action('pre_get_posts', ['EEH_Event_Query', 'filter_query_parts'], 10, 1); |
|
70 | - } |
|
71 | - |
|
72 | - |
|
73 | - /** |
|
74 | - * @param WP_Query $WP_Query |
|
75 | - * @return bool |
|
76 | - */ |
|
77 | - public static function apply_query_filters(WP_Query $WP_Query) |
|
78 | - { |
|
79 | - return ( |
|
80 | - isset($WP_Query->query['post_type']) |
|
81 | - && $WP_Query->query['post_type'] === 'espresso_events' |
|
82 | - ) |
|
83 | - || apply_filters('FHEE__EEH_Event_Query__apply_query_filters', false); |
|
84 | - } |
|
85 | - |
|
86 | - |
|
87 | - /** |
|
88 | - * @param WP_Query $WP_Query |
|
89 | - */ |
|
90 | - public static function filter_query_parts(WP_Query $WP_Query) |
|
91 | - { |
|
92 | - // ONLY add our filters if this isn't the main wp_query, |
|
93 | - // because if this is the main wp_query we already have |
|
94 | - // our cpt strategies take care of adding things in. |
|
95 | - if ($WP_Query instanceof WP_Query && ! $WP_Query->is_main_query()) { |
|
96 | - // build event list query |
|
97 | - add_filter('posts_fields', ['EEH_Event_Query', 'posts_fields'], 10, 2); |
|
98 | - add_filter('posts_join', ['EEH_Event_Query', 'posts_join'], 10, 2); |
|
99 | - add_filter('posts_where', ['EEH_Event_Query', 'posts_where'], 10, 2); |
|
100 | - add_filter('posts_orderby', ['EEH_Event_Query', 'posts_orderby'], 10, 2); |
|
101 | - add_filter('posts_clauses_request', ['EEH_Event_Query', 'posts_clauses'], 10, 2); |
|
102 | - } |
|
103 | - } |
|
104 | - |
|
105 | - |
|
106 | - /** |
|
107 | - * @param string $month |
|
108 | - * @param string $category |
|
109 | - * @param bool $show_expired |
|
110 | - * @param array|string $orderby |
|
111 | - * @param string $sort |
|
112 | - * @throws InvalidArgumentException |
|
113 | - * @throws InvalidDataTypeException |
|
114 | - * @throws InvalidInterfaceException |
|
115 | - */ |
|
116 | - public static function set_query_params( |
|
117 | - $month = '', |
|
118 | - $category = '', |
|
119 | - $show_expired = false, |
|
120 | - $orderby = 'start_date', |
|
121 | - $sort = 'ASC' |
|
122 | - ) { |
|
123 | - self::$_query_params = []; |
|
124 | - EEH_Event_Query::$_event_query_month = EEH_Event_Query::_display_month($month); |
|
125 | - EEH_Event_Query::$_event_query_category = EEH_Event_Query::_event_category_slug($category); |
|
126 | - EEH_Event_Query::$_event_query_show_expired = EEH_Event_Query::_show_expired($show_expired); |
|
127 | - EEH_Event_Query::$_event_query_orderby = EEH_Event_Query::_orderby($orderby); |
|
128 | - EEH_Event_Query::$_event_query_sort = EEH_Event_Query::_sort($sort); |
|
129 | - } |
|
130 | - |
|
131 | - |
|
132 | - /** |
|
133 | - * what month should the event list display events for? |
|
134 | - * |
|
135 | - * @param string $month |
|
136 | - * @return string |
|
137 | - * @throws InvalidArgumentException |
|
138 | - * @throws InvalidDataTypeException |
|
139 | - * @throws InvalidInterfaceException |
|
140 | - */ |
|
141 | - private static function _display_month($month = '') |
|
142 | - { |
|
143 | - return self::getRequest()->getRequestParam('event_query_month', $month); |
|
144 | - } |
|
145 | - |
|
146 | - |
|
147 | - /** |
|
148 | - * @param string $category |
|
149 | - * @return string |
|
150 | - * @throws InvalidArgumentException |
|
151 | - * @throws InvalidDataTypeException |
|
152 | - * @throws InvalidInterfaceException |
|
153 | - */ |
|
154 | - private static function _event_category_slug($category = '') |
|
155 | - { |
|
156 | - return self::getRequest()->getRequestParam('event_query_category', $category); |
|
157 | - } |
|
158 | - |
|
159 | - |
|
160 | - /** |
|
161 | - * @param bool $show_expired |
|
162 | - * @return bool |
|
163 | - * @throws InvalidArgumentException |
|
164 | - * @throws InvalidDataTypeException |
|
165 | - * @throws InvalidInterfaceException |
|
166 | - */ |
|
167 | - private static function _show_expired($show_expired = false) |
|
168 | - { |
|
169 | - // override default expired option if set via filter |
|
170 | - return self::getRequest()->getRequestParam('event_query_show_expired', $show_expired, 'bool'); |
|
171 | - } |
|
172 | - |
|
173 | - |
|
174 | - /** |
|
175 | - * @param array|string $orderby |
|
176 | - * @return array |
|
177 | - * @throws InvalidArgumentException |
|
178 | - * @throws InvalidDataTypeException |
|
179 | - * @throws InvalidInterfaceException |
|
180 | - */ |
|
181 | - private static function _orderby($orderby = 'start_date') |
|
182 | - { |
|
183 | - $event_query_orderby = self::getRequest()->getRequestParam( |
|
184 | - 'event_query_orderby', |
|
185 | - (array) $orderby, |
|
186 | - DataType::STRING, |
|
187 | - true |
|
188 | - ); |
|
189 | - $event_query_orderby = is_array($event_query_orderby) |
|
190 | - ? $event_query_orderby |
|
191 | - : explode(',', $event_query_orderby); |
|
192 | - $event_query_orderby = array_map('trim', $event_query_orderby); |
|
193 | - return array_map('sanitize_text_field', $event_query_orderby); |
|
194 | - } |
|
195 | - |
|
196 | - |
|
197 | - /** |
|
198 | - * @param string $sort |
|
199 | - * @return string |
|
200 | - * @throws InvalidArgumentException |
|
201 | - * @throws InvalidDataTypeException |
|
202 | - * @throws InvalidInterfaceException |
|
203 | - */ |
|
204 | - private static function _sort($sort = 'ASC') |
|
205 | - { |
|
206 | - $sort = self::getRequest()->getRequestParam('event_query_sort', $sort); |
|
207 | - return in_array($sort, ['ASC', 'asc', 'DESC', 'desc'], true) |
|
208 | - ? strtoupper($sort) |
|
209 | - : 'ASC'; |
|
210 | - } |
|
211 | - |
|
212 | - |
|
213 | - /** |
|
214 | - * Filters the clauses for the WP_Query object |
|
215 | - * |
|
216 | - * @param array $clauses array of clauses |
|
217 | - * @param WP_Query $wp_query |
|
218 | - * @return array array of clauses |
|
219 | - */ |
|
220 | - public static function posts_clauses($clauses, WP_Query $wp_query) |
|
221 | - { |
|
222 | - if (EEH_Event_Query::apply_query_filters($wp_query)) { |
|
223 | - global $wpdb; |
|
224 | - $clauses['groupby'] = $wpdb->posts . '.ID '; |
|
225 | - } |
|
226 | - return $clauses; |
|
227 | - } |
|
228 | - |
|
229 | - |
|
230 | - /** |
|
231 | - * @param string $SQL |
|
232 | - * @param WP_Query $wp_query |
|
233 | - * @return string |
|
234 | - * @throws EE_Error |
|
235 | - * @throws InvalidArgumentException |
|
236 | - * @throws InvalidDataTypeException |
|
237 | - * @throws InvalidInterfaceException |
|
238 | - */ |
|
239 | - public static function posts_fields($SQL, WP_Query $wp_query) |
|
240 | - { |
|
241 | - if (EEH_Event_Query::apply_query_filters($wp_query)) { |
|
242 | - // adds something like ", wp_esp_datetime.* " to WP Query SELECT statement |
|
243 | - $SQL .= EEH_Event_Query::posts_fields_sql_for_orderby(EEH_Event_Query::$_event_query_orderby); |
|
244 | - } |
|
245 | - return $SQL; |
|
246 | - } |
|
247 | - |
|
248 | - |
|
249 | - /** |
|
250 | - * @param array $orderby_params |
|
251 | - * @return string |
|
252 | - * @throws EE_Error |
|
253 | - * @throws InvalidArgumentException |
|
254 | - * @throws InvalidDataTypeException |
|
255 | - * @throws InvalidInterfaceException |
|
256 | - */ |
|
257 | - public static function posts_fields_sql_for_orderby(array $orderby_params = []) |
|
258 | - { |
|
259 | - $SQL = ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date '; |
|
260 | - foreach ($orderby_params as $orderby) { |
|
261 | - switch ($orderby) { |
|
262 | - case 'ticket_start': |
|
263 | - $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_start_date'; |
|
264 | - break; |
|
265 | - case 'ticket_end': |
|
266 | - $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_end_date'; |
|
267 | - break; |
|
268 | - case 'venue_title': |
|
269 | - $SQL .= ', Venue.post_title AS venue_title'; |
|
270 | - break; |
|
271 | - case 'city': |
|
272 | - $SQL .= ', ' . EEM_Venue::instance()->second_table() . '.VNU_city'; |
|
273 | - break; |
|
274 | - case 'state': |
|
275 | - $SQL .= ', ' . EEM_State::instance()->table() . '.STA_name'; |
|
276 | - break; |
|
277 | - } |
|
278 | - } |
|
279 | - return $SQL; |
|
280 | - } |
|
281 | - |
|
282 | - |
|
283 | - /** |
|
284 | - * @param string $SQL |
|
285 | - * @param WP_Query $wp_query |
|
286 | - * @return string |
|
287 | - * @throws EE_Error |
|
288 | - * @throws InvalidArgumentException |
|
289 | - * @throws InvalidDataTypeException |
|
290 | - * @throws InvalidInterfaceException |
|
291 | - */ |
|
292 | - public static function posts_join($SQL, WP_Query $wp_query) |
|
293 | - { |
|
294 | - if (EEH_Event_Query::apply_query_filters($wp_query)) { |
|
295 | - // Category |
|
296 | - $SQL = EEH_Event_Query::posts_join_sql_for_show_expired($SQL, EEH_Event_Query::$_event_query_show_expired); |
|
297 | - $SQL = EEH_Event_Query::posts_join_sql_for_terms($SQL, EEH_Event_Query::$_event_query_category); |
|
298 | - $SQL = EEH_Event_Query::posts_join_for_orderby($SQL, EEH_Event_Query::$_event_query_orderby); |
|
299 | - } |
|
300 | - return $SQL; |
|
301 | - } |
|
302 | - |
|
303 | - |
|
304 | - /** |
|
305 | - * @param string $SQL |
|
306 | - * @param boolean $show_expired if TRUE, then displayed past events |
|
307 | - * @return string |
|
308 | - * @throws EE_Error |
|
309 | - * @throws InvalidArgumentException |
|
310 | - * @throws InvalidDataTypeException |
|
311 | - * @throws InvalidInterfaceException |
|
312 | - */ |
|
313 | - public static function posts_join_sql_for_show_expired($SQL = '', $show_expired = false) |
|
314 | - { |
|
315 | - if (! $show_expired) { |
|
316 | - $join = EEM_Event::instance()->table() . '.ID = '; |
|
317 | - $join .= EEM_Datetime::instance()->table() . '.' . EEM_Event::instance()->primary_key_name(); |
|
318 | - // don't add if this is already in the SQL |
|
319 | - if (strpos($SQL, $join) === false) { |
|
320 | - $SQL .= ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . $join . ' ) '; |
|
321 | - } |
|
322 | - } |
|
323 | - return $SQL; |
|
324 | - } |
|
325 | - |
|
326 | - |
|
327 | - /** |
|
328 | - * @param string $SQL |
|
329 | - * @param string $join_terms pass TRUE or term string, doesn't really matter since this value doesn't really get |
|
330 | - * used for anything yet |
|
331 | - * @return string |
|
332 | - */ |
|
333 | - public static function posts_join_sql_for_terms($SQL = '', $join_terms = '') |
|
334 | - { |
|
335 | - if (! empty($join_terms)) { |
|
336 | - global $wpdb; |
|
337 | - $SQL .= " LEFT JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)"; |
|
338 | - $SQL .= " LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)"; |
|
339 | - $SQL .= " LEFT JOIN $wpdb->terms ON ($wpdb->terms.term_id = $wpdb->term_taxonomy.term_id) "; |
|
340 | - } |
|
341 | - return $SQL; |
|
342 | - } |
|
343 | - |
|
344 | - |
|
345 | - /** |
|
346 | - * usage: $SQL .= EEH_Event_Query::posts_join_for_orderby( $orderby_params ); |
|
347 | - * |
|
348 | - * @param string $SQL |
|
349 | - * @param array $orderby_params |
|
350 | - * @return string |
|
351 | - * @throws EE_Error |
|
352 | - * @throws InvalidArgumentException |
|
353 | - * @throws InvalidDataTypeException |
|
354 | - * @throws InvalidInterfaceException |
|
355 | - */ |
|
356 | - public static function posts_join_for_orderby($SQL = '', array $orderby_params = []) |
|
357 | - { |
|
358 | - foreach ($orderby_params as $orderby) { |
|
359 | - switch ($orderby) { |
|
360 | - case 'ticket_start': |
|
361 | - case 'ticket_end': |
|
362 | - $SQL .= EEH_Event_Query::_posts_join_for_datetime( |
|
363 | - $SQL, |
|
364 | - EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Datetime::instance()->primary_key_name() |
|
365 | - ); |
|
366 | - $SQL .= ' LEFT JOIN ' . EEM_Ticket::instance()->table(); |
|
367 | - $SQL .= ' ON ('; |
|
368 | - $SQL .= EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Ticket::instance()->primary_key_name(); |
|
369 | - $SQL .= ' = '; |
|
370 | - $SQL .= EEM_Ticket::instance()->table() . '.' . EEM_Ticket::instance()->primary_key_name(); |
|
371 | - $SQL .= ' )'; |
|
372 | - break; |
|
373 | - case 'venue_title': |
|
374 | - case 'city': |
|
375 | - $SQL .= EEH_Event_Query::_posts_join_for_event_venue($SQL); |
|
376 | - break; |
|
377 | - case 'state': |
|
378 | - $SQL .= EEH_Event_Query::_posts_join_for_event_venue($SQL); |
|
379 | - $SQL .= EEH_Event_Query::_posts_join_for_venue_state($SQL); |
|
380 | - break; |
|
381 | - case 'start_date': |
|
382 | - default: |
|
383 | - $SQL .= EEH_Event_Query::_posts_join_for_datetime($SQL, EEM_Event::instance()->table() . '.ID'); |
|
384 | - break; |
|
385 | - } |
|
386 | - } |
|
387 | - return $SQL; |
|
388 | - } |
|
389 | - |
|
390 | - |
|
391 | - /** |
|
392 | - * @param string $SQL |
|
393 | - * @param string $join |
|
394 | - * @return string |
|
395 | - * @throws EE_Error |
|
396 | - * @throws InvalidArgumentException |
|
397 | - * @throws InvalidDataTypeException |
|
398 | - * @throws InvalidInterfaceException |
|
399 | - */ |
|
400 | - protected static function _posts_join_for_datetime($SQL = '', $join = '') |
|
401 | - { |
|
402 | - if (! empty($join)) { |
|
403 | - $join .= ' = ' . EEM_Datetime::instance()->table() . '.' . EEM_Event::instance()->primary_key_name(); |
|
404 | - if (strpos($SQL, $join) === false) { |
|
405 | - return ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . $join . ' )'; |
|
406 | - } |
|
407 | - } |
|
408 | - return ''; |
|
409 | - } |
|
410 | - |
|
411 | - |
|
412 | - /** |
|
413 | - * @param string $SQL |
|
414 | - * @return string |
|
415 | - * @throws EE_Error |
|
416 | - * @throws InvalidArgumentException |
|
417 | - * @throws InvalidDataTypeException |
|
418 | - * @throws InvalidInterfaceException |
|
419 | - */ |
|
420 | - protected static function _posts_join_for_event_venue($SQL = '') |
|
421 | - { |
|
422 | - // Event Venue table name |
|
423 | - $event_venue_table = EEM_Event_Venue::instance()->table(); |
|
424 | - // generate conditions for: Event <=> Event Venue JOIN clause |
|
425 | - $event_to_event_venue_join = EEM_Event::instance()->table() . '.ID = '; |
|
426 | - $event_to_event_venue_join .= $event_venue_table . '.' . EEM_Event::instance()->primary_key_name(); |
|
427 | - // don't add joins if they have already been added |
|
428 | - if (strpos($SQL, $event_to_event_venue_join) === false) { |
|
429 | - // Venue table name |
|
430 | - $venue_table = EEM_Venue::instance()->table(); |
|
431 | - // Venue table pk |
|
432 | - $venue_table_pk = EEM_Venue::instance()->primary_key_name(); |
|
433 | - // Venue Meta table name |
|
434 | - $venue_meta_table = EEM_Venue::instance()->second_table(); |
|
435 | - // generate JOIN clause for: Event <=> Event Venue |
|
436 | - $venue_SQL = " LEFT JOIN $event_venue_table ON ( $event_to_event_venue_join )"; |
|
437 | - // generate JOIN clause for: Event Venue <=> Venue |
|
438 | - $venue_SQL .= " LEFT JOIN $venue_table as Venue ON ( $event_venue_table.$venue_table_pk = Venue.ID )"; |
|
439 | - // generate JOIN clause for: Venue <=> Venue Meta |
|
440 | - $venue_SQL .= " LEFT JOIN $venue_meta_table ON ( Venue.ID = $venue_meta_table.$venue_table_pk )"; |
|
441 | - unset($event_venue_table, $event_to_event_venue_join, $venue_table, $venue_table_pk, $venue_meta_table); |
|
442 | - return $venue_SQL; |
|
443 | - } |
|
444 | - unset($event_venue_table, $event_to_event_venue_join); |
|
445 | - return ''; |
|
446 | - } |
|
447 | - |
|
448 | - |
|
449 | - /** |
|
450 | - * @param string $SQL |
|
451 | - * @return string |
|
452 | - * @throws EE_Error |
|
453 | - * @throws InvalidArgumentException |
|
454 | - * @throws InvalidDataTypeException |
|
455 | - * @throws InvalidInterfaceException |
|
456 | - */ |
|
457 | - protected static function _posts_join_for_venue_state($SQL = '') |
|
458 | - { |
|
459 | - // Venue Meta table name |
|
460 | - $venue_meta_table = EEM_Venue::instance()->second_table(); |
|
461 | - // State table name |
|
462 | - $state_table = EEM_State::instance()->table(); |
|
463 | - // State table pk |
|
464 | - $state_table_pk = EEM_State::instance()->primary_key_name(); |
|
465 | - // verify vars |
|
466 | - if ($venue_meta_table && $state_table && $state_table_pk) { |
|
467 | - // like: wp_esp_venue_meta.STA_ID = wp_esp_state.STA_ID |
|
468 | - $join = "$venue_meta_table.$state_table_pk = $state_table.$state_table_pk"; |
|
469 | - // don't add join if it has already been added |
|
470 | - if (strpos($SQL, $join) === false) { |
|
471 | - unset($state_table_pk, $venue_meta_table, $venue_table_pk); |
|
472 | - return " LEFT JOIN $state_table ON ( $join )"; |
|
473 | - } |
|
474 | - } |
|
475 | - unset($join, $state_table, $state_table_pk, $venue_meta_table, $venue_table_pk); |
|
476 | - return ''; |
|
477 | - } |
|
478 | - |
|
479 | - |
|
480 | - /** |
|
481 | - * @param string $SQL |
|
482 | - * @param WP_Query $wp_query |
|
483 | - * @return string |
|
484 | - * @throws EE_Error |
|
485 | - * @throws InvalidArgumentException |
|
486 | - * @throws InvalidDataTypeException |
|
487 | - * @throws InvalidInterfaceException |
|
488 | - */ |
|
489 | - public static function posts_where($SQL, WP_Query $wp_query) |
|
490 | - { |
|
491 | - if (EEH_Event_Query::apply_query_filters($wp_query)) { |
|
492 | - // Show Expired ? |
|
493 | - $SQL .= EEH_Event_Query::posts_where_sql_for_show_expired(EEH_Event_Query::$_event_query_show_expired); |
|
494 | - // Category |
|
495 | - $SQL .= EEH_Event_Query::posts_where_sql_for_event_category_slug(EEH_Event_Query::$_event_query_category); |
|
496 | - // Start Date |
|
497 | - $SQL .= EEH_Event_Query::posts_where_sql_for_event_list_month(EEH_Event_Query::$_event_query_month); |
|
498 | - } |
|
499 | - return $SQL; |
|
500 | - } |
|
501 | - |
|
502 | - |
|
503 | - /** |
|
504 | - * @param boolean $show_expired if TRUE, then displayed past events |
|
505 | - * @return string |
|
506 | - * @throws EE_Error |
|
507 | - * @throws InvalidArgumentException |
|
508 | - * @throws InvalidDataTypeException |
|
509 | - * @throws InvalidInterfaceException |
|
510 | - */ |
|
511 | - public static function posts_where_sql_for_show_expired($show_expired = false) |
|
512 | - { |
|
513 | - return ! $show_expired |
|
514 | - ? ' AND ' . EEM_Datetime::instance()->table() . '.DTT_EVT_end > \'' . current_time('mysql', true) . '\' ' |
|
515 | - : ''; |
|
516 | - } |
|
517 | - |
|
518 | - |
|
519 | - /** |
|
520 | - * @param boolean $event_category_slug |
|
521 | - * @return string |
|
522 | - */ |
|
523 | - public static function posts_where_sql_for_event_category_slug($event_category_slug = null) |
|
524 | - { |
|
525 | - global $wpdb; |
|
526 | - if (! empty($event_category_slug)) { |
|
527 | - $event_category_slugs_array = array_map('trim', explode(',', $event_category_slug)); |
|
528 | - $event_category_slugs_prepare = implode(', ', array_fill(0, count($event_category_slugs_array), '%s')); |
|
529 | - return $wpdb->prepare( |
|
530 | - " AND {$wpdb->terms}.slug IN ({$event_category_slugs_prepare}) ", |
|
531 | - $event_category_slugs_array |
|
532 | - ); |
|
533 | - } |
|
534 | - return ''; |
|
535 | - } |
|
536 | - |
|
537 | - |
|
538 | - /** |
|
539 | - * @param boolean $month |
|
540 | - * @return string |
|
541 | - * @throws EE_Error |
|
542 | - * @throws InvalidArgumentException |
|
543 | - * @throws InvalidDataTypeException |
|
544 | - * @throws InvalidInterfaceException |
|
545 | - */ |
|
546 | - public static function posts_where_sql_for_event_list_month($month = null) |
|
547 | - { |
|
548 | - $SQL = ''; |
|
549 | - if (! empty($month)) { |
|
550 | - $datetime_table = EEM_Datetime::instance()->table(); |
|
551 | - // event start date is LESS than the end of the month ( so nothing that doesn't start until next month ) |
|
552 | - $SQL = " AND {$datetime_table}.DTT_EVT_start <= '"; |
|
553 | - $SQL .= date('Y-m-t 23:59:59', EEH_DTT_Helper::first_of_month_timestamp($month)) . "'"; |
|
554 | - // event end date is GREATER than the start of the month ( so nothing that ended before this month ) |
|
555 | - $SQL .= " AND {$datetime_table}.DTT_EVT_end >= '"; |
|
556 | - $SQL .= date('Y-m-01 0:0:00', EEH_DTT_Helper::first_of_month_timestamp($month)) . "' "; |
|
557 | - } |
|
558 | - return $SQL; |
|
559 | - } |
|
560 | - |
|
561 | - |
|
562 | - /** |
|
563 | - * @param string $SQL |
|
564 | - * @param WP_Query $wp_query |
|
565 | - * @return string |
|
566 | - * @throws EE_Error |
|
567 | - * @throws InvalidArgumentException |
|
568 | - * @throws InvalidDataTypeException |
|
569 | - * @throws InvalidInterfaceException |
|
570 | - */ |
|
571 | - public static function posts_orderby($SQL, WP_Query $wp_query) |
|
572 | - { |
|
573 | - if (EEH_Event_Query::apply_query_filters($wp_query)) { |
|
574 | - $SQL = EEH_Event_Query::posts_orderby_sql( |
|
575 | - EEH_Event_Query::$_event_query_orderby, |
|
576 | - EEH_Event_Query::$_event_query_sort |
|
577 | - ); |
|
578 | - } |
|
579 | - return $SQL; |
|
580 | - } |
|
581 | - |
|
582 | - |
|
583 | - /** |
|
584 | - * posts_orderby_sql |
|
585 | - * possible parameters: |
|
586 | - * ID |
|
587 | - * start_date |
|
588 | - * end_date |
|
589 | - * event_name |
|
590 | - * category_slug |
|
591 | - * ticket_start |
|
592 | - * ticket_end |
|
593 | - * venue_title |
|
594 | - * city |
|
595 | - * state |
|
596 | - * **IMPORTANT** |
|
597 | - * make sure to also send the $orderby_params array to the posts_join_for_orderby() method |
|
598 | - * or else some of the table references below will result in MySQL errors |
|
599 | - * |
|
600 | - * @param array $orderby_params |
|
601 | - * @param string $sort |
|
602 | - * @return string |
|
603 | - * @throws EE_Error |
|
604 | - * @throws InvalidArgumentException |
|
605 | - * @throws InvalidDataTypeException |
|
606 | - * @throws InvalidInterfaceException |
|
607 | - */ |
|
608 | - public static function posts_orderby_sql(array $orderby_params = [], $sort = 'ASC') |
|
609 | - { |
|
610 | - global $wpdb; |
|
611 | - $SQL = ''; |
|
612 | - $counter = 0; |
|
613 | - $sort = in_array($sort, ['ASC', 'asc', 'DESC', 'desc'], true) |
|
614 | - ? strtoupper($sort) |
|
615 | - : 'ASC'; |
|
616 | - // make sure 'orderby' is set in query params |
|
617 | - if (! isset(self::$_query_params['orderby'])) { |
|
618 | - self::$_query_params['orderby'] = []; |
|
619 | - } |
|
620 | - // loop thru $orderby_params (type cast as array) |
|
621 | - foreach ($orderby_params as $orderby) { |
|
622 | - // check if we have already added this param |
|
623 | - if (isset(self::$_query_params['orderby'][ $orderby ])) { |
|
624 | - // if so then remove from the $orderby_params so that the count() method below is accurate |
|
625 | - unset($orderby_params[ $orderby ]); |
|
626 | - // then bump ahead to the next param |
|
627 | - continue; |
|
628 | - } |
|
629 | - // this will ad a comma depending on whether this is the first or last param |
|
630 | - $glue = $counter === 0 || $counter === count($orderby_params) ? ' ' : ', '; |
|
631 | - // ok what's we dealing with? |
|
632 | - switch ($orderby) { |
|
633 | - case 'id': |
|
634 | - case 'ID': |
|
635 | - $SQL .= $glue . $wpdb->posts . '.ID ' . $sort; |
|
636 | - break; |
|
637 | - case 'end_date': |
|
638 | - $SQL .= $glue . EEM_Datetime::instance()->table() . '.DTT_EVT_end ' . $sort; |
|
639 | - break; |
|
640 | - case 'event_name': |
|
641 | - $SQL .= $glue . $wpdb->posts . '.post_title ' . $sort; |
|
642 | - break; |
|
643 | - case 'category_slug': |
|
644 | - $SQL .= $glue . $wpdb->terms . '.slug ' . $sort; |
|
645 | - break; |
|
646 | - case 'ticket_start': |
|
647 | - $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_start_date ' . $sort; |
|
648 | - break; |
|
649 | - case 'ticket_end': |
|
650 | - $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_end_date ' . $sort; |
|
651 | - break; |
|
652 | - case 'venue_title': |
|
653 | - $SQL .= $glue . 'venue_title ' . $sort; |
|
654 | - break; |
|
655 | - case 'city': |
|
656 | - $SQL .= $glue . EEM_Venue::instance()->second_table() . '.VNU_city ' . $sort; |
|
657 | - break; |
|
658 | - case 'state': |
|
659 | - $SQL .= $glue . EEM_State::instance()->table() . '.STA_name ' . $sort; |
|
660 | - break; |
|
661 | - case 'start_date': |
|
662 | - default: |
|
663 | - $SQL .= $glue . ' event_start_date ' . $sort; |
|
664 | - break; |
|
665 | - } |
|
666 | - // add to array of orderby params that have been added |
|
667 | - self::$_query_params['orderby'][ $orderby ] = true; |
|
668 | - $counter++; |
|
669 | - } |
|
670 | - return $SQL; |
|
671 | - } |
|
672 | - |
|
673 | - |
|
674 | - /** |
|
675 | - * @return RequestInterface |
|
676 | - * @since 4.10.14.p |
|
677 | - */ |
|
678 | - private static function getRequest() |
|
679 | - { |
|
680 | - return LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
681 | - } |
|
20 | + /** |
|
21 | + * Start Date |
|
22 | + * |
|
23 | + * @var $_event_query_month |
|
24 | + */ |
|
25 | + protected static $_event_query_month; |
|
26 | + |
|
27 | + /** |
|
28 | + * Category |
|
29 | + * |
|
30 | + * @var $_event_query_category |
|
31 | + */ |
|
32 | + protected static $_event_query_category; |
|
33 | + |
|
34 | + /** |
|
35 | + * whether to display expired events in the event list |
|
36 | + * |
|
37 | + * @var bool $_show_expired |
|
38 | + */ |
|
39 | + protected static $_event_query_show_expired = false; |
|
40 | + |
|
41 | + /** |
|
42 | + * list of params for controlling how the query results are ordered |
|
43 | + * |
|
44 | + * @var array $_event_query_orderby |
|
45 | + */ |
|
46 | + protected static $_event_query_orderby = []; |
|
47 | + |
|
48 | + /** |
|
49 | + * direction list is sorted |
|
50 | + * |
|
51 | + * @var string $_event_query_sort |
|
52 | + */ |
|
53 | + protected static $_event_query_sort; |
|
54 | + |
|
55 | + /** |
|
56 | + * list of params used to build the query's various clauses |
|
57 | + * |
|
58 | + * @var $_query_params |
|
59 | + */ |
|
60 | + protected static $_query_params = []; |
|
61 | + |
|
62 | + |
|
63 | + /** |
|
64 | + * @return void |
|
65 | + */ |
|
66 | + public static function add_query_filters() |
|
67 | + { |
|
68 | + // add query filters |
|
69 | + add_action('pre_get_posts', ['EEH_Event_Query', 'filter_query_parts'], 10, 1); |
|
70 | + } |
|
71 | + |
|
72 | + |
|
73 | + /** |
|
74 | + * @param WP_Query $WP_Query |
|
75 | + * @return bool |
|
76 | + */ |
|
77 | + public static function apply_query_filters(WP_Query $WP_Query) |
|
78 | + { |
|
79 | + return ( |
|
80 | + isset($WP_Query->query['post_type']) |
|
81 | + && $WP_Query->query['post_type'] === 'espresso_events' |
|
82 | + ) |
|
83 | + || apply_filters('FHEE__EEH_Event_Query__apply_query_filters', false); |
|
84 | + } |
|
85 | + |
|
86 | + |
|
87 | + /** |
|
88 | + * @param WP_Query $WP_Query |
|
89 | + */ |
|
90 | + public static function filter_query_parts(WP_Query $WP_Query) |
|
91 | + { |
|
92 | + // ONLY add our filters if this isn't the main wp_query, |
|
93 | + // because if this is the main wp_query we already have |
|
94 | + // our cpt strategies take care of adding things in. |
|
95 | + if ($WP_Query instanceof WP_Query && ! $WP_Query->is_main_query()) { |
|
96 | + // build event list query |
|
97 | + add_filter('posts_fields', ['EEH_Event_Query', 'posts_fields'], 10, 2); |
|
98 | + add_filter('posts_join', ['EEH_Event_Query', 'posts_join'], 10, 2); |
|
99 | + add_filter('posts_where', ['EEH_Event_Query', 'posts_where'], 10, 2); |
|
100 | + add_filter('posts_orderby', ['EEH_Event_Query', 'posts_orderby'], 10, 2); |
|
101 | + add_filter('posts_clauses_request', ['EEH_Event_Query', 'posts_clauses'], 10, 2); |
|
102 | + } |
|
103 | + } |
|
104 | + |
|
105 | + |
|
106 | + /** |
|
107 | + * @param string $month |
|
108 | + * @param string $category |
|
109 | + * @param bool $show_expired |
|
110 | + * @param array|string $orderby |
|
111 | + * @param string $sort |
|
112 | + * @throws InvalidArgumentException |
|
113 | + * @throws InvalidDataTypeException |
|
114 | + * @throws InvalidInterfaceException |
|
115 | + */ |
|
116 | + public static function set_query_params( |
|
117 | + $month = '', |
|
118 | + $category = '', |
|
119 | + $show_expired = false, |
|
120 | + $orderby = 'start_date', |
|
121 | + $sort = 'ASC' |
|
122 | + ) { |
|
123 | + self::$_query_params = []; |
|
124 | + EEH_Event_Query::$_event_query_month = EEH_Event_Query::_display_month($month); |
|
125 | + EEH_Event_Query::$_event_query_category = EEH_Event_Query::_event_category_slug($category); |
|
126 | + EEH_Event_Query::$_event_query_show_expired = EEH_Event_Query::_show_expired($show_expired); |
|
127 | + EEH_Event_Query::$_event_query_orderby = EEH_Event_Query::_orderby($orderby); |
|
128 | + EEH_Event_Query::$_event_query_sort = EEH_Event_Query::_sort($sort); |
|
129 | + } |
|
130 | + |
|
131 | + |
|
132 | + /** |
|
133 | + * what month should the event list display events for? |
|
134 | + * |
|
135 | + * @param string $month |
|
136 | + * @return string |
|
137 | + * @throws InvalidArgumentException |
|
138 | + * @throws InvalidDataTypeException |
|
139 | + * @throws InvalidInterfaceException |
|
140 | + */ |
|
141 | + private static function _display_month($month = '') |
|
142 | + { |
|
143 | + return self::getRequest()->getRequestParam('event_query_month', $month); |
|
144 | + } |
|
145 | + |
|
146 | + |
|
147 | + /** |
|
148 | + * @param string $category |
|
149 | + * @return string |
|
150 | + * @throws InvalidArgumentException |
|
151 | + * @throws InvalidDataTypeException |
|
152 | + * @throws InvalidInterfaceException |
|
153 | + */ |
|
154 | + private static function _event_category_slug($category = '') |
|
155 | + { |
|
156 | + return self::getRequest()->getRequestParam('event_query_category', $category); |
|
157 | + } |
|
158 | + |
|
159 | + |
|
160 | + /** |
|
161 | + * @param bool $show_expired |
|
162 | + * @return bool |
|
163 | + * @throws InvalidArgumentException |
|
164 | + * @throws InvalidDataTypeException |
|
165 | + * @throws InvalidInterfaceException |
|
166 | + */ |
|
167 | + private static function _show_expired($show_expired = false) |
|
168 | + { |
|
169 | + // override default expired option if set via filter |
|
170 | + return self::getRequest()->getRequestParam('event_query_show_expired', $show_expired, 'bool'); |
|
171 | + } |
|
172 | + |
|
173 | + |
|
174 | + /** |
|
175 | + * @param array|string $orderby |
|
176 | + * @return array |
|
177 | + * @throws InvalidArgumentException |
|
178 | + * @throws InvalidDataTypeException |
|
179 | + * @throws InvalidInterfaceException |
|
180 | + */ |
|
181 | + private static function _orderby($orderby = 'start_date') |
|
182 | + { |
|
183 | + $event_query_orderby = self::getRequest()->getRequestParam( |
|
184 | + 'event_query_orderby', |
|
185 | + (array) $orderby, |
|
186 | + DataType::STRING, |
|
187 | + true |
|
188 | + ); |
|
189 | + $event_query_orderby = is_array($event_query_orderby) |
|
190 | + ? $event_query_orderby |
|
191 | + : explode(',', $event_query_orderby); |
|
192 | + $event_query_orderby = array_map('trim', $event_query_orderby); |
|
193 | + return array_map('sanitize_text_field', $event_query_orderby); |
|
194 | + } |
|
195 | + |
|
196 | + |
|
197 | + /** |
|
198 | + * @param string $sort |
|
199 | + * @return string |
|
200 | + * @throws InvalidArgumentException |
|
201 | + * @throws InvalidDataTypeException |
|
202 | + * @throws InvalidInterfaceException |
|
203 | + */ |
|
204 | + private static function _sort($sort = 'ASC') |
|
205 | + { |
|
206 | + $sort = self::getRequest()->getRequestParam('event_query_sort', $sort); |
|
207 | + return in_array($sort, ['ASC', 'asc', 'DESC', 'desc'], true) |
|
208 | + ? strtoupper($sort) |
|
209 | + : 'ASC'; |
|
210 | + } |
|
211 | + |
|
212 | + |
|
213 | + /** |
|
214 | + * Filters the clauses for the WP_Query object |
|
215 | + * |
|
216 | + * @param array $clauses array of clauses |
|
217 | + * @param WP_Query $wp_query |
|
218 | + * @return array array of clauses |
|
219 | + */ |
|
220 | + public static function posts_clauses($clauses, WP_Query $wp_query) |
|
221 | + { |
|
222 | + if (EEH_Event_Query::apply_query_filters($wp_query)) { |
|
223 | + global $wpdb; |
|
224 | + $clauses['groupby'] = $wpdb->posts . '.ID '; |
|
225 | + } |
|
226 | + return $clauses; |
|
227 | + } |
|
228 | + |
|
229 | + |
|
230 | + /** |
|
231 | + * @param string $SQL |
|
232 | + * @param WP_Query $wp_query |
|
233 | + * @return string |
|
234 | + * @throws EE_Error |
|
235 | + * @throws InvalidArgumentException |
|
236 | + * @throws InvalidDataTypeException |
|
237 | + * @throws InvalidInterfaceException |
|
238 | + */ |
|
239 | + public static function posts_fields($SQL, WP_Query $wp_query) |
|
240 | + { |
|
241 | + if (EEH_Event_Query::apply_query_filters($wp_query)) { |
|
242 | + // adds something like ", wp_esp_datetime.* " to WP Query SELECT statement |
|
243 | + $SQL .= EEH_Event_Query::posts_fields_sql_for_orderby(EEH_Event_Query::$_event_query_orderby); |
|
244 | + } |
|
245 | + return $SQL; |
|
246 | + } |
|
247 | + |
|
248 | + |
|
249 | + /** |
|
250 | + * @param array $orderby_params |
|
251 | + * @return string |
|
252 | + * @throws EE_Error |
|
253 | + * @throws InvalidArgumentException |
|
254 | + * @throws InvalidDataTypeException |
|
255 | + * @throws InvalidInterfaceException |
|
256 | + */ |
|
257 | + public static function posts_fields_sql_for_orderby(array $orderby_params = []) |
|
258 | + { |
|
259 | + $SQL = ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date '; |
|
260 | + foreach ($orderby_params as $orderby) { |
|
261 | + switch ($orderby) { |
|
262 | + case 'ticket_start': |
|
263 | + $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_start_date'; |
|
264 | + break; |
|
265 | + case 'ticket_end': |
|
266 | + $SQL .= ', ' . EEM_Ticket::instance()->table() . '.TKT_end_date'; |
|
267 | + break; |
|
268 | + case 'venue_title': |
|
269 | + $SQL .= ', Venue.post_title AS venue_title'; |
|
270 | + break; |
|
271 | + case 'city': |
|
272 | + $SQL .= ', ' . EEM_Venue::instance()->second_table() . '.VNU_city'; |
|
273 | + break; |
|
274 | + case 'state': |
|
275 | + $SQL .= ', ' . EEM_State::instance()->table() . '.STA_name'; |
|
276 | + break; |
|
277 | + } |
|
278 | + } |
|
279 | + return $SQL; |
|
280 | + } |
|
281 | + |
|
282 | + |
|
283 | + /** |
|
284 | + * @param string $SQL |
|
285 | + * @param WP_Query $wp_query |
|
286 | + * @return string |
|
287 | + * @throws EE_Error |
|
288 | + * @throws InvalidArgumentException |
|
289 | + * @throws InvalidDataTypeException |
|
290 | + * @throws InvalidInterfaceException |
|
291 | + */ |
|
292 | + public static function posts_join($SQL, WP_Query $wp_query) |
|
293 | + { |
|
294 | + if (EEH_Event_Query::apply_query_filters($wp_query)) { |
|
295 | + // Category |
|
296 | + $SQL = EEH_Event_Query::posts_join_sql_for_show_expired($SQL, EEH_Event_Query::$_event_query_show_expired); |
|
297 | + $SQL = EEH_Event_Query::posts_join_sql_for_terms($SQL, EEH_Event_Query::$_event_query_category); |
|
298 | + $SQL = EEH_Event_Query::posts_join_for_orderby($SQL, EEH_Event_Query::$_event_query_orderby); |
|
299 | + } |
|
300 | + return $SQL; |
|
301 | + } |
|
302 | + |
|
303 | + |
|
304 | + /** |
|
305 | + * @param string $SQL |
|
306 | + * @param boolean $show_expired if TRUE, then displayed past events |
|
307 | + * @return string |
|
308 | + * @throws EE_Error |
|
309 | + * @throws InvalidArgumentException |
|
310 | + * @throws InvalidDataTypeException |
|
311 | + * @throws InvalidInterfaceException |
|
312 | + */ |
|
313 | + public static function posts_join_sql_for_show_expired($SQL = '', $show_expired = false) |
|
314 | + { |
|
315 | + if (! $show_expired) { |
|
316 | + $join = EEM_Event::instance()->table() . '.ID = '; |
|
317 | + $join .= EEM_Datetime::instance()->table() . '.' . EEM_Event::instance()->primary_key_name(); |
|
318 | + // don't add if this is already in the SQL |
|
319 | + if (strpos($SQL, $join) === false) { |
|
320 | + $SQL .= ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . $join . ' ) '; |
|
321 | + } |
|
322 | + } |
|
323 | + return $SQL; |
|
324 | + } |
|
325 | + |
|
326 | + |
|
327 | + /** |
|
328 | + * @param string $SQL |
|
329 | + * @param string $join_terms pass TRUE or term string, doesn't really matter since this value doesn't really get |
|
330 | + * used for anything yet |
|
331 | + * @return string |
|
332 | + */ |
|
333 | + public static function posts_join_sql_for_terms($SQL = '', $join_terms = '') |
|
334 | + { |
|
335 | + if (! empty($join_terms)) { |
|
336 | + global $wpdb; |
|
337 | + $SQL .= " LEFT JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)"; |
|
338 | + $SQL .= " LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)"; |
|
339 | + $SQL .= " LEFT JOIN $wpdb->terms ON ($wpdb->terms.term_id = $wpdb->term_taxonomy.term_id) "; |
|
340 | + } |
|
341 | + return $SQL; |
|
342 | + } |
|
343 | + |
|
344 | + |
|
345 | + /** |
|
346 | + * usage: $SQL .= EEH_Event_Query::posts_join_for_orderby( $orderby_params ); |
|
347 | + * |
|
348 | + * @param string $SQL |
|
349 | + * @param array $orderby_params |
|
350 | + * @return string |
|
351 | + * @throws EE_Error |
|
352 | + * @throws InvalidArgumentException |
|
353 | + * @throws InvalidDataTypeException |
|
354 | + * @throws InvalidInterfaceException |
|
355 | + */ |
|
356 | + public static function posts_join_for_orderby($SQL = '', array $orderby_params = []) |
|
357 | + { |
|
358 | + foreach ($orderby_params as $orderby) { |
|
359 | + switch ($orderby) { |
|
360 | + case 'ticket_start': |
|
361 | + case 'ticket_end': |
|
362 | + $SQL .= EEH_Event_Query::_posts_join_for_datetime( |
|
363 | + $SQL, |
|
364 | + EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Datetime::instance()->primary_key_name() |
|
365 | + ); |
|
366 | + $SQL .= ' LEFT JOIN ' . EEM_Ticket::instance()->table(); |
|
367 | + $SQL .= ' ON ('; |
|
368 | + $SQL .= EEM_Datetime_Ticket::instance()->table() . '.' . EEM_Ticket::instance()->primary_key_name(); |
|
369 | + $SQL .= ' = '; |
|
370 | + $SQL .= EEM_Ticket::instance()->table() . '.' . EEM_Ticket::instance()->primary_key_name(); |
|
371 | + $SQL .= ' )'; |
|
372 | + break; |
|
373 | + case 'venue_title': |
|
374 | + case 'city': |
|
375 | + $SQL .= EEH_Event_Query::_posts_join_for_event_venue($SQL); |
|
376 | + break; |
|
377 | + case 'state': |
|
378 | + $SQL .= EEH_Event_Query::_posts_join_for_event_venue($SQL); |
|
379 | + $SQL .= EEH_Event_Query::_posts_join_for_venue_state($SQL); |
|
380 | + break; |
|
381 | + case 'start_date': |
|
382 | + default: |
|
383 | + $SQL .= EEH_Event_Query::_posts_join_for_datetime($SQL, EEM_Event::instance()->table() . '.ID'); |
|
384 | + break; |
|
385 | + } |
|
386 | + } |
|
387 | + return $SQL; |
|
388 | + } |
|
389 | + |
|
390 | + |
|
391 | + /** |
|
392 | + * @param string $SQL |
|
393 | + * @param string $join |
|
394 | + * @return string |
|
395 | + * @throws EE_Error |
|
396 | + * @throws InvalidArgumentException |
|
397 | + * @throws InvalidDataTypeException |
|
398 | + * @throws InvalidInterfaceException |
|
399 | + */ |
|
400 | + protected static function _posts_join_for_datetime($SQL = '', $join = '') |
|
401 | + { |
|
402 | + if (! empty($join)) { |
|
403 | + $join .= ' = ' . EEM_Datetime::instance()->table() . '.' . EEM_Event::instance()->primary_key_name(); |
|
404 | + if (strpos($SQL, $join) === false) { |
|
405 | + return ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . $join . ' )'; |
|
406 | + } |
|
407 | + } |
|
408 | + return ''; |
|
409 | + } |
|
410 | + |
|
411 | + |
|
412 | + /** |
|
413 | + * @param string $SQL |
|
414 | + * @return string |
|
415 | + * @throws EE_Error |
|
416 | + * @throws InvalidArgumentException |
|
417 | + * @throws InvalidDataTypeException |
|
418 | + * @throws InvalidInterfaceException |
|
419 | + */ |
|
420 | + protected static function _posts_join_for_event_venue($SQL = '') |
|
421 | + { |
|
422 | + // Event Venue table name |
|
423 | + $event_venue_table = EEM_Event_Venue::instance()->table(); |
|
424 | + // generate conditions for: Event <=> Event Venue JOIN clause |
|
425 | + $event_to_event_venue_join = EEM_Event::instance()->table() . '.ID = '; |
|
426 | + $event_to_event_venue_join .= $event_venue_table . '.' . EEM_Event::instance()->primary_key_name(); |
|
427 | + // don't add joins if they have already been added |
|
428 | + if (strpos($SQL, $event_to_event_venue_join) === false) { |
|
429 | + // Venue table name |
|
430 | + $venue_table = EEM_Venue::instance()->table(); |
|
431 | + // Venue table pk |
|
432 | + $venue_table_pk = EEM_Venue::instance()->primary_key_name(); |
|
433 | + // Venue Meta table name |
|
434 | + $venue_meta_table = EEM_Venue::instance()->second_table(); |
|
435 | + // generate JOIN clause for: Event <=> Event Venue |
|
436 | + $venue_SQL = " LEFT JOIN $event_venue_table ON ( $event_to_event_venue_join )"; |
|
437 | + // generate JOIN clause for: Event Venue <=> Venue |
|
438 | + $venue_SQL .= " LEFT JOIN $venue_table as Venue ON ( $event_venue_table.$venue_table_pk = Venue.ID )"; |
|
439 | + // generate JOIN clause for: Venue <=> Venue Meta |
|
440 | + $venue_SQL .= " LEFT JOIN $venue_meta_table ON ( Venue.ID = $venue_meta_table.$venue_table_pk )"; |
|
441 | + unset($event_venue_table, $event_to_event_venue_join, $venue_table, $venue_table_pk, $venue_meta_table); |
|
442 | + return $venue_SQL; |
|
443 | + } |
|
444 | + unset($event_venue_table, $event_to_event_venue_join); |
|
445 | + return ''; |
|
446 | + } |
|
447 | + |
|
448 | + |
|
449 | + /** |
|
450 | + * @param string $SQL |
|
451 | + * @return string |
|
452 | + * @throws EE_Error |
|
453 | + * @throws InvalidArgumentException |
|
454 | + * @throws InvalidDataTypeException |
|
455 | + * @throws InvalidInterfaceException |
|
456 | + */ |
|
457 | + protected static function _posts_join_for_venue_state($SQL = '') |
|
458 | + { |
|
459 | + // Venue Meta table name |
|
460 | + $venue_meta_table = EEM_Venue::instance()->second_table(); |
|
461 | + // State table name |
|
462 | + $state_table = EEM_State::instance()->table(); |
|
463 | + // State table pk |
|
464 | + $state_table_pk = EEM_State::instance()->primary_key_name(); |
|
465 | + // verify vars |
|
466 | + if ($venue_meta_table && $state_table && $state_table_pk) { |
|
467 | + // like: wp_esp_venue_meta.STA_ID = wp_esp_state.STA_ID |
|
468 | + $join = "$venue_meta_table.$state_table_pk = $state_table.$state_table_pk"; |
|
469 | + // don't add join if it has already been added |
|
470 | + if (strpos($SQL, $join) === false) { |
|
471 | + unset($state_table_pk, $venue_meta_table, $venue_table_pk); |
|
472 | + return " LEFT JOIN $state_table ON ( $join )"; |
|
473 | + } |
|
474 | + } |
|
475 | + unset($join, $state_table, $state_table_pk, $venue_meta_table, $venue_table_pk); |
|
476 | + return ''; |
|
477 | + } |
|
478 | + |
|
479 | + |
|
480 | + /** |
|
481 | + * @param string $SQL |
|
482 | + * @param WP_Query $wp_query |
|
483 | + * @return string |
|
484 | + * @throws EE_Error |
|
485 | + * @throws InvalidArgumentException |
|
486 | + * @throws InvalidDataTypeException |
|
487 | + * @throws InvalidInterfaceException |
|
488 | + */ |
|
489 | + public static function posts_where($SQL, WP_Query $wp_query) |
|
490 | + { |
|
491 | + if (EEH_Event_Query::apply_query_filters($wp_query)) { |
|
492 | + // Show Expired ? |
|
493 | + $SQL .= EEH_Event_Query::posts_where_sql_for_show_expired(EEH_Event_Query::$_event_query_show_expired); |
|
494 | + // Category |
|
495 | + $SQL .= EEH_Event_Query::posts_where_sql_for_event_category_slug(EEH_Event_Query::$_event_query_category); |
|
496 | + // Start Date |
|
497 | + $SQL .= EEH_Event_Query::posts_where_sql_for_event_list_month(EEH_Event_Query::$_event_query_month); |
|
498 | + } |
|
499 | + return $SQL; |
|
500 | + } |
|
501 | + |
|
502 | + |
|
503 | + /** |
|
504 | + * @param boolean $show_expired if TRUE, then displayed past events |
|
505 | + * @return string |
|
506 | + * @throws EE_Error |
|
507 | + * @throws InvalidArgumentException |
|
508 | + * @throws InvalidDataTypeException |
|
509 | + * @throws InvalidInterfaceException |
|
510 | + */ |
|
511 | + public static function posts_where_sql_for_show_expired($show_expired = false) |
|
512 | + { |
|
513 | + return ! $show_expired |
|
514 | + ? ' AND ' . EEM_Datetime::instance()->table() . '.DTT_EVT_end > \'' . current_time('mysql', true) . '\' ' |
|
515 | + : ''; |
|
516 | + } |
|
517 | + |
|
518 | + |
|
519 | + /** |
|
520 | + * @param boolean $event_category_slug |
|
521 | + * @return string |
|
522 | + */ |
|
523 | + public static function posts_where_sql_for_event_category_slug($event_category_slug = null) |
|
524 | + { |
|
525 | + global $wpdb; |
|
526 | + if (! empty($event_category_slug)) { |
|
527 | + $event_category_slugs_array = array_map('trim', explode(',', $event_category_slug)); |
|
528 | + $event_category_slugs_prepare = implode(', ', array_fill(0, count($event_category_slugs_array), '%s')); |
|
529 | + return $wpdb->prepare( |
|
530 | + " AND {$wpdb->terms}.slug IN ({$event_category_slugs_prepare}) ", |
|
531 | + $event_category_slugs_array |
|
532 | + ); |
|
533 | + } |
|
534 | + return ''; |
|
535 | + } |
|
536 | + |
|
537 | + |
|
538 | + /** |
|
539 | + * @param boolean $month |
|
540 | + * @return string |
|
541 | + * @throws EE_Error |
|
542 | + * @throws InvalidArgumentException |
|
543 | + * @throws InvalidDataTypeException |
|
544 | + * @throws InvalidInterfaceException |
|
545 | + */ |
|
546 | + public static function posts_where_sql_for_event_list_month($month = null) |
|
547 | + { |
|
548 | + $SQL = ''; |
|
549 | + if (! empty($month)) { |
|
550 | + $datetime_table = EEM_Datetime::instance()->table(); |
|
551 | + // event start date is LESS than the end of the month ( so nothing that doesn't start until next month ) |
|
552 | + $SQL = " AND {$datetime_table}.DTT_EVT_start <= '"; |
|
553 | + $SQL .= date('Y-m-t 23:59:59', EEH_DTT_Helper::first_of_month_timestamp($month)) . "'"; |
|
554 | + // event end date is GREATER than the start of the month ( so nothing that ended before this month ) |
|
555 | + $SQL .= " AND {$datetime_table}.DTT_EVT_end >= '"; |
|
556 | + $SQL .= date('Y-m-01 0:0:00', EEH_DTT_Helper::first_of_month_timestamp($month)) . "' "; |
|
557 | + } |
|
558 | + return $SQL; |
|
559 | + } |
|
560 | + |
|
561 | + |
|
562 | + /** |
|
563 | + * @param string $SQL |
|
564 | + * @param WP_Query $wp_query |
|
565 | + * @return string |
|
566 | + * @throws EE_Error |
|
567 | + * @throws InvalidArgumentException |
|
568 | + * @throws InvalidDataTypeException |
|
569 | + * @throws InvalidInterfaceException |
|
570 | + */ |
|
571 | + public static function posts_orderby($SQL, WP_Query $wp_query) |
|
572 | + { |
|
573 | + if (EEH_Event_Query::apply_query_filters($wp_query)) { |
|
574 | + $SQL = EEH_Event_Query::posts_orderby_sql( |
|
575 | + EEH_Event_Query::$_event_query_orderby, |
|
576 | + EEH_Event_Query::$_event_query_sort |
|
577 | + ); |
|
578 | + } |
|
579 | + return $SQL; |
|
580 | + } |
|
581 | + |
|
582 | + |
|
583 | + /** |
|
584 | + * posts_orderby_sql |
|
585 | + * possible parameters: |
|
586 | + * ID |
|
587 | + * start_date |
|
588 | + * end_date |
|
589 | + * event_name |
|
590 | + * category_slug |
|
591 | + * ticket_start |
|
592 | + * ticket_end |
|
593 | + * venue_title |
|
594 | + * city |
|
595 | + * state |
|
596 | + * **IMPORTANT** |
|
597 | + * make sure to also send the $orderby_params array to the posts_join_for_orderby() method |
|
598 | + * or else some of the table references below will result in MySQL errors |
|
599 | + * |
|
600 | + * @param array $orderby_params |
|
601 | + * @param string $sort |
|
602 | + * @return string |
|
603 | + * @throws EE_Error |
|
604 | + * @throws InvalidArgumentException |
|
605 | + * @throws InvalidDataTypeException |
|
606 | + * @throws InvalidInterfaceException |
|
607 | + */ |
|
608 | + public static function posts_orderby_sql(array $orderby_params = [], $sort = 'ASC') |
|
609 | + { |
|
610 | + global $wpdb; |
|
611 | + $SQL = ''; |
|
612 | + $counter = 0; |
|
613 | + $sort = in_array($sort, ['ASC', 'asc', 'DESC', 'desc'], true) |
|
614 | + ? strtoupper($sort) |
|
615 | + : 'ASC'; |
|
616 | + // make sure 'orderby' is set in query params |
|
617 | + if (! isset(self::$_query_params['orderby'])) { |
|
618 | + self::$_query_params['orderby'] = []; |
|
619 | + } |
|
620 | + // loop thru $orderby_params (type cast as array) |
|
621 | + foreach ($orderby_params as $orderby) { |
|
622 | + // check if we have already added this param |
|
623 | + if (isset(self::$_query_params['orderby'][ $orderby ])) { |
|
624 | + // if so then remove from the $orderby_params so that the count() method below is accurate |
|
625 | + unset($orderby_params[ $orderby ]); |
|
626 | + // then bump ahead to the next param |
|
627 | + continue; |
|
628 | + } |
|
629 | + // this will ad a comma depending on whether this is the first or last param |
|
630 | + $glue = $counter === 0 || $counter === count($orderby_params) ? ' ' : ', '; |
|
631 | + // ok what's we dealing with? |
|
632 | + switch ($orderby) { |
|
633 | + case 'id': |
|
634 | + case 'ID': |
|
635 | + $SQL .= $glue . $wpdb->posts . '.ID ' . $sort; |
|
636 | + break; |
|
637 | + case 'end_date': |
|
638 | + $SQL .= $glue . EEM_Datetime::instance()->table() . '.DTT_EVT_end ' . $sort; |
|
639 | + break; |
|
640 | + case 'event_name': |
|
641 | + $SQL .= $glue . $wpdb->posts . '.post_title ' . $sort; |
|
642 | + break; |
|
643 | + case 'category_slug': |
|
644 | + $SQL .= $glue . $wpdb->terms . '.slug ' . $sort; |
|
645 | + break; |
|
646 | + case 'ticket_start': |
|
647 | + $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_start_date ' . $sort; |
|
648 | + break; |
|
649 | + case 'ticket_end': |
|
650 | + $SQL .= $glue . EEM_Ticket::instance()->table() . '.TKT_end_date ' . $sort; |
|
651 | + break; |
|
652 | + case 'venue_title': |
|
653 | + $SQL .= $glue . 'venue_title ' . $sort; |
|
654 | + break; |
|
655 | + case 'city': |
|
656 | + $SQL .= $glue . EEM_Venue::instance()->second_table() . '.VNU_city ' . $sort; |
|
657 | + break; |
|
658 | + case 'state': |
|
659 | + $SQL .= $glue . EEM_State::instance()->table() . '.STA_name ' . $sort; |
|
660 | + break; |
|
661 | + case 'start_date': |
|
662 | + default: |
|
663 | + $SQL .= $glue . ' event_start_date ' . $sort; |
|
664 | + break; |
|
665 | + } |
|
666 | + // add to array of orderby params that have been added |
|
667 | + self::$_query_params['orderby'][ $orderby ] = true; |
|
668 | + $counter++; |
|
669 | + } |
|
670 | + return $SQL; |
|
671 | + } |
|
672 | + |
|
673 | + |
|
674 | + /** |
|
675 | + * @return RequestInterface |
|
676 | + * @since 4.10.14.p |
|
677 | + */ |
|
678 | + private static function getRequest() |
|
679 | + { |
|
680 | + return LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
681 | + } |
|
682 | 682 | } |