@@ -44,7 +44,7 @@ discard block |
||
44 | 44 | { |
45 | 45 | |
46 | 46 | // check that an admin_page has not already been registered with that name |
47 | - if (isset(self::$_ee_admin_page_registry[ $identifier ])) { |
|
47 | + if (isset(self::$_ee_admin_page_registry[$identifier])) { |
|
48 | 48 | throw new EE_Error( |
49 | 49 | sprintf( |
50 | 50 | esc_html__( |
@@ -67,11 +67,11 @@ discard block |
||
67 | 67 | } |
68 | 68 | |
69 | 69 | // make sure we don't register twice |
70 | - if (isset(self::$_ee_admin_page_registry[ $identifier ])) { |
|
70 | + if (isset(self::$_ee_admin_page_registry[$identifier])) { |
|
71 | 71 | return; |
72 | 72 | } |
73 | 73 | |
74 | - if (! did_action('AHEE__EE_System__load_espresso_addons') || did_action('AHEE__EE_Admin__loaded')) { |
|
74 | + if ( ! did_action('AHEE__EE_System__load_espresso_addons') || did_action('AHEE__EE_Admin__loaded')) { |
|
75 | 75 | EE_Error::doing_it_wrong( |
76 | 76 | __METHOD__, |
77 | 77 | sprintf( |
@@ -86,7 +86,7 @@ discard block |
||
86 | 86 | } |
87 | 87 | |
88 | 88 | // add incoming stuff to our registry property |
89 | - self::$_ee_admin_page_registry[ $identifier ] = [ |
|
89 | + self::$_ee_admin_page_registry[$identifier] = [ |
|
90 | 90 | 'page_path' => $setup_args['page_path'], |
91 | 91 | 'config' => $setup_args, |
92 | 92 | ]; |
@@ -113,7 +113,7 @@ discard block |
||
113 | 113 | */ |
114 | 114 | public static function deregister($identifier = '') |
115 | 115 | { |
116 | - unset(self::$_ee_admin_page_registry[ $identifier ]); |
|
116 | + unset(self::$_ee_admin_page_registry[$identifier]); |
|
117 | 117 | } |
118 | 118 | |
119 | 119 | |
@@ -125,9 +125,9 @@ discard block |
||
125 | 125 | */ |
126 | 126 | public static function set_page_basename($installed_refs) |
127 | 127 | { |
128 | - if (! empty(self::$_ee_admin_page_registry)) { |
|
128 | + if ( ! empty(self::$_ee_admin_page_registry)) { |
|
129 | 129 | foreach (self::$_ee_admin_page_registry as $basename => $args) { |
130 | - $installed_refs[ $basename ] = $args['page_path']; |
|
130 | + $installed_refs[$basename] = $args['page_path']; |
|
131 | 131 | } |
132 | 132 | } |
133 | 133 | return $installed_refs; |
@@ -143,7 +143,7 @@ discard block |
||
143 | 143 | public static function set_page_path($paths) |
144 | 144 | { |
145 | 145 | foreach (self::$_ee_admin_page_registry as $basename => $args) { |
146 | - $paths[ $basename ] = $args['page_path']; |
|
146 | + $paths[$basename] = $args['page_path']; |
|
147 | 147 | } |
148 | 148 | return $paths; |
149 | 149 | } |
@@ -10,139 +10,139 @@ |
||
10 | 10 | */ |
11 | 11 | class EE_Register_Admin_Page implements EEI_Plugin_API |
12 | 12 | { |
13 | - /** |
|
14 | - * Holds registered EE_Admin_Pages |
|
15 | - * |
|
16 | - * @var array |
|
17 | - */ |
|
18 | - protected static $_ee_admin_page_registry = []; |
|
19 | - |
|
20 | - |
|
21 | - /** |
|
22 | - * The purpose of this method is to provide an easy way for addons to register their admin pages (using the EE |
|
23 | - * Admin Page loader system). |
|
24 | - * |
|
25 | - * @param string $identifier This string represents the basename of the Admin |
|
26 | - * Page init. The init file must use this basename |
|
27 | - * in its name and class (i.e. |
|
28 | - * {page_basename}_Admin_Page_Init.core.php). |
|
29 | - * @param array $setup_args { An array of configuration options |
|
30 | - * that will be used in different circumstances |
|
31 | - * |
|
32 | - * @type string $page_path This is the path where the registered admin pages |
|
33 | - * reside ( used to setup autoloaders). |
|
34 | - * |
|
35 | - * } |
|
36 | - * @return void |
|
37 | - * @throws EE_Error |
|
38 | - * @since 4.3.0 |
|
39 | - * |
|
40 | - */ |
|
41 | - public static function register($identifier = '', array $setup_args = []) |
|
42 | - { |
|
43 | - |
|
44 | - // check that an admin_page has not already been registered with that name |
|
45 | - if (isset(self::$_ee_admin_page_registry[ $identifier ])) { |
|
46 | - throw new EE_Error( |
|
47 | - sprintf( |
|
48 | - esc_html__( |
|
49 | - 'An Admin Page with the name "%s" has already been registered and each Admin Page requires a unique name.', |
|
50 | - 'event_espresso' |
|
51 | - ), |
|
52 | - $identifier |
|
53 | - ) |
|
54 | - ); |
|
55 | - } |
|
56 | - |
|
57 | - // required fields MUST be present, so let's make sure they are. |
|
58 | - if (empty($identifier) || ! is_array($setup_args) || empty($setup_args['page_path'])) { |
|
59 | - throw new EE_Error( |
|
60 | - esc_html__( |
|
61 | - 'In order to register an Admin Page with EE_Register_Admin_Page::register(), you must include the "page_basename" (the class name of the page), and an array containing the following keys: "page_path" (the path where the registered admin pages reside)', |
|
62 | - 'event_espresso' |
|
63 | - ) |
|
64 | - ); |
|
65 | - } |
|
66 | - |
|
67 | - // make sure we don't register twice |
|
68 | - if (isset(self::$_ee_admin_page_registry[ $identifier ])) { |
|
69 | - return; |
|
70 | - } |
|
71 | - |
|
72 | - if (! did_action('AHEE__EE_System__load_espresso_addons') || did_action('AHEE__EE_Admin__loaded')) { |
|
73 | - EE_Error::doing_it_wrong( |
|
74 | - __METHOD__, |
|
75 | - sprintf( |
|
76 | - esc_html__( |
|
77 | - 'An attempt was made to register "%s" as an EE Admin page has failed because it was not registered at the correct time. Please use the "AHEE__EE_Admin__loaded" hook to register Admin pages.', |
|
78 | - 'event_espresso' |
|
79 | - ), |
|
80 | - $identifier |
|
81 | - ), |
|
82 | - '4.3' |
|
83 | - ); |
|
84 | - } |
|
85 | - |
|
86 | - // add incoming stuff to our registry property |
|
87 | - self::$_ee_admin_page_registry[ $identifier ] = [ |
|
88 | - 'page_path' => $setup_args['page_path'], |
|
89 | - 'config' => $setup_args, |
|
90 | - ]; |
|
91 | - |
|
92 | - // add filters |
|
93 | - |
|
94 | - add_filter( |
|
95 | - 'FHEE__EE_Admin_Page_Loader___get_installed_pages__installed_refs', |
|
96 | - ['EE_Register_Admin_Page', 'set_page_basename'], |
|
97 | - 10 |
|
98 | - ); |
|
99 | - add_filter('FHEE__EEH_Autoloader__load_admin_core', ['EE_Register_Admin_Page', 'set_page_path'], 10); |
|
100 | - } |
|
101 | - |
|
102 | - |
|
103 | - /** |
|
104 | - * This deregisters a EE_Admin page that is already registered. Note, this MUST be loaded after the |
|
105 | - * page being deregistered is loaded. |
|
106 | - * |
|
107 | - * @param string $identifier Use whatever string was used to register the admin page. |
|
108 | - * @return void |
|
109 | - * @since 4.3.0 |
|
110 | - * |
|
111 | - */ |
|
112 | - public static function deregister($identifier = '') |
|
113 | - { |
|
114 | - unset(self::$_ee_admin_page_registry[ $identifier ]); |
|
115 | - } |
|
116 | - |
|
117 | - |
|
118 | - /** |
|
119 | - * set_page_basename |
|
120 | - * |
|
121 | - * @param $installed_refs |
|
122 | - * @return mixed |
|
123 | - */ |
|
124 | - public static function set_page_basename($installed_refs) |
|
125 | - { |
|
126 | - if (! empty(self::$_ee_admin_page_registry)) { |
|
127 | - foreach (self::$_ee_admin_page_registry as $basename => $args) { |
|
128 | - $installed_refs[ $basename ] = $args['page_path']; |
|
129 | - } |
|
130 | - } |
|
131 | - return $installed_refs; |
|
132 | - } |
|
133 | - |
|
134 | - |
|
135 | - /** |
|
136 | - * set_page_path |
|
137 | - * |
|
138 | - * @param $paths |
|
139 | - * @return mixed |
|
140 | - */ |
|
141 | - public static function set_page_path($paths) |
|
142 | - { |
|
143 | - foreach (self::$_ee_admin_page_registry as $basename => $args) { |
|
144 | - $paths[ $basename ] = $args['page_path']; |
|
145 | - } |
|
146 | - return $paths; |
|
147 | - } |
|
13 | + /** |
|
14 | + * Holds registered EE_Admin_Pages |
|
15 | + * |
|
16 | + * @var array |
|
17 | + */ |
|
18 | + protected static $_ee_admin_page_registry = []; |
|
19 | + |
|
20 | + |
|
21 | + /** |
|
22 | + * The purpose of this method is to provide an easy way for addons to register their admin pages (using the EE |
|
23 | + * Admin Page loader system). |
|
24 | + * |
|
25 | + * @param string $identifier This string represents the basename of the Admin |
|
26 | + * Page init. The init file must use this basename |
|
27 | + * in its name and class (i.e. |
|
28 | + * {page_basename}_Admin_Page_Init.core.php). |
|
29 | + * @param array $setup_args { An array of configuration options |
|
30 | + * that will be used in different circumstances |
|
31 | + * |
|
32 | + * @type string $page_path This is the path where the registered admin pages |
|
33 | + * reside ( used to setup autoloaders). |
|
34 | + * |
|
35 | + * } |
|
36 | + * @return void |
|
37 | + * @throws EE_Error |
|
38 | + * @since 4.3.0 |
|
39 | + * |
|
40 | + */ |
|
41 | + public static function register($identifier = '', array $setup_args = []) |
|
42 | + { |
|
43 | + |
|
44 | + // check that an admin_page has not already been registered with that name |
|
45 | + if (isset(self::$_ee_admin_page_registry[ $identifier ])) { |
|
46 | + throw new EE_Error( |
|
47 | + sprintf( |
|
48 | + esc_html__( |
|
49 | + 'An Admin Page with the name "%s" has already been registered and each Admin Page requires a unique name.', |
|
50 | + 'event_espresso' |
|
51 | + ), |
|
52 | + $identifier |
|
53 | + ) |
|
54 | + ); |
|
55 | + } |
|
56 | + |
|
57 | + // required fields MUST be present, so let's make sure they are. |
|
58 | + if (empty($identifier) || ! is_array($setup_args) || empty($setup_args['page_path'])) { |
|
59 | + throw new EE_Error( |
|
60 | + esc_html__( |
|
61 | + 'In order to register an Admin Page with EE_Register_Admin_Page::register(), you must include the "page_basename" (the class name of the page), and an array containing the following keys: "page_path" (the path where the registered admin pages reside)', |
|
62 | + 'event_espresso' |
|
63 | + ) |
|
64 | + ); |
|
65 | + } |
|
66 | + |
|
67 | + // make sure we don't register twice |
|
68 | + if (isset(self::$_ee_admin_page_registry[ $identifier ])) { |
|
69 | + return; |
|
70 | + } |
|
71 | + |
|
72 | + if (! did_action('AHEE__EE_System__load_espresso_addons') || did_action('AHEE__EE_Admin__loaded')) { |
|
73 | + EE_Error::doing_it_wrong( |
|
74 | + __METHOD__, |
|
75 | + sprintf( |
|
76 | + esc_html__( |
|
77 | + 'An attempt was made to register "%s" as an EE Admin page has failed because it was not registered at the correct time. Please use the "AHEE__EE_Admin__loaded" hook to register Admin pages.', |
|
78 | + 'event_espresso' |
|
79 | + ), |
|
80 | + $identifier |
|
81 | + ), |
|
82 | + '4.3' |
|
83 | + ); |
|
84 | + } |
|
85 | + |
|
86 | + // add incoming stuff to our registry property |
|
87 | + self::$_ee_admin_page_registry[ $identifier ] = [ |
|
88 | + 'page_path' => $setup_args['page_path'], |
|
89 | + 'config' => $setup_args, |
|
90 | + ]; |
|
91 | + |
|
92 | + // add filters |
|
93 | + |
|
94 | + add_filter( |
|
95 | + 'FHEE__EE_Admin_Page_Loader___get_installed_pages__installed_refs', |
|
96 | + ['EE_Register_Admin_Page', 'set_page_basename'], |
|
97 | + 10 |
|
98 | + ); |
|
99 | + add_filter('FHEE__EEH_Autoloader__load_admin_core', ['EE_Register_Admin_Page', 'set_page_path'], 10); |
|
100 | + } |
|
101 | + |
|
102 | + |
|
103 | + /** |
|
104 | + * This deregisters a EE_Admin page that is already registered. Note, this MUST be loaded after the |
|
105 | + * page being deregistered is loaded. |
|
106 | + * |
|
107 | + * @param string $identifier Use whatever string was used to register the admin page. |
|
108 | + * @return void |
|
109 | + * @since 4.3.0 |
|
110 | + * |
|
111 | + */ |
|
112 | + public static function deregister($identifier = '') |
|
113 | + { |
|
114 | + unset(self::$_ee_admin_page_registry[ $identifier ]); |
|
115 | + } |
|
116 | + |
|
117 | + |
|
118 | + /** |
|
119 | + * set_page_basename |
|
120 | + * |
|
121 | + * @param $installed_refs |
|
122 | + * @return mixed |
|
123 | + */ |
|
124 | + public static function set_page_basename($installed_refs) |
|
125 | + { |
|
126 | + if (! empty(self::$_ee_admin_page_registry)) { |
|
127 | + foreach (self::$_ee_admin_page_registry as $basename => $args) { |
|
128 | + $installed_refs[ $basename ] = $args['page_path']; |
|
129 | + } |
|
130 | + } |
|
131 | + return $installed_refs; |
|
132 | + } |
|
133 | + |
|
134 | + |
|
135 | + /** |
|
136 | + * set_page_path |
|
137 | + * |
|
138 | + * @param $paths |
|
139 | + * @return mixed |
|
140 | + */ |
|
141 | + public static function set_page_path($paths) |
|
142 | + { |
|
143 | + foreach (self::$_ee_admin_page_registry as $basename => $args) { |
|
144 | + $paths[ $basename ] = $args['page_path']; |
|
145 | + } |
|
146 | + return $paths; |
|
147 | + } |
|
148 | 148 | } |
@@ -47,20 +47,20 @@ discard block |
||
47 | 47 | '[TKT_USES_*]' => esc_html__( |
48 | 48 | 'This attribute based shortcode parses to show the number of uses the ticket has. The optional "schema" attribute can be used to indicate what schema is used when the uses is infinite. Options are:', |
49 | 49 | 'event_espresso' |
50 | - ) . |
|
51 | - '<p><ul>' . |
|
52 | - '<li><strong>symbol</strong>:' . esc_html__( |
|
50 | + ). |
|
51 | + '<p><ul>'. |
|
52 | + '<li><strong>symbol</strong>:'.esc_html__( |
|
53 | 53 | 'This returns the ∞ symbol.', |
54 | 54 | 'event_espresso' |
55 | - ) . '</li>' . |
|
56 | - '<li><strong>text</strong>:' . esc_html__( |
|
55 | + ).'</li>'. |
|
56 | + '<li><strong>text</strong>:'.esc_html__( |
|
57 | 57 | 'This returns the word, "Unlimited". This is also the default if the "schema" attribute is not used.', |
58 | 58 | 'event_espresso' |
59 | - ) . '</li>' . |
|
60 | - '<li><strong>{custom}</strong>:' . esc_html__( |
|
59 | + ).'</li>'. |
|
60 | + '<li><strong>{custom}</strong>:'.esc_html__( |
|
61 | 61 | 'You can put anything you want as a string instead and that will be used. So you could have the world "any" and whenever uses for a ticket is infinity, this shortcode will parse to "any".', |
62 | 62 | 'event_espresso' |
63 | - ) . '</li>' . |
|
63 | + ).'</li>'. |
|
64 | 64 | '</ul></p>', |
65 | 65 | ); |
66 | 66 | } |
@@ -82,9 +82,9 @@ discard block |
||
82 | 82 | $this->_ticket = empty($this->_ticket) |
83 | 83 | && $this->_data instanceof EE_Line_Item |
84 | 84 | && $aee instanceof EE_Messages_Addressee |
85 | - && ! empty($aee->line_items_with_children[ $this->_data->ID() ]['EE_Ticket']) |
|
86 | - && $aee->line_items_with_children[ $this->_data->ID() ]['EE_Ticket'] instanceof EE_Ticket |
|
87 | - ? $aee->line_items_with_children[ $this->_data->ID() ]['EE_Ticket'] |
|
85 | + && ! empty($aee->line_items_with_children[$this->_data->ID()]['EE_Ticket']) |
|
86 | + && $aee->line_items_with_children[$this->_data->ID()]['EE_Ticket'] instanceof EE_Ticket |
|
87 | + ? $aee->line_items_with_children[$this->_data->ID()]['EE_Ticket'] |
|
88 | 88 | : $this->_ticket; |
89 | 89 | |
90 | 90 | // if still no ticket, then let's see if there is a reg_obj. If there IS, then we'll try and grab the ticket from the reg_obj instead. |
@@ -95,7 +95,7 @@ discard block |
||
95 | 95 | |
96 | 96 | |
97 | 97 | // If there is no event object by now then get out. |
98 | - if (! $this->_ticket instanceof EE_Ticket) { |
|
98 | + if ( ! $this->_ticket instanceof EE_Ticket) { |
|
99 | 99 | return ''; |
100 | 100 | } |
101 | 101 | |
@@ -121,7 +121,7 @@ discard block |
||
121 | 121 | break; |
122 | 122 | |
123 | 123 | case '[TKT_QTY_PURCHASED]': |
124 | - return $aee instanceof EE_Messages_Addressee ? $aee->tickets[ $this->_ticket->ID() ]['count'] : ''; |
|
124 | + return $aee instanceof EE_Messages_Addressee ? $aee->tickets[$this->_ticket->ID()]['count'] : ''; |
|
125 | 125 | break; |
126 | 126 | } |
127 | 127 |
@@ -17,123 +17,123 @@ |
||
17 | 17 | */ |
18 | 18 | class EE_Ticket_Shortcodes extends EE_Shortcodes |
19 | 19 | { |
20 | - /** |
|
21 | - * Will hold the EE_Ticket if available |
|
22 | - * |
|
23 | - * @var EE_Ticket |
|
24 | - */ |
|
25 | - protected $_ticket; |
|
26 | - |
|
27 | - |
|
28 | - protected function _init_props() |
|
29 | - { |
|
30 | - $this->label = esc_html__('Ticket Shortcodes', 'event_espresso'); |
|
31 | - $this->description = esc_html__('All shortcodes specific to ticket related data', 'event_espresso'); |
|
32 | - $this->_shortcodes = array( |
|
33 | - '[TICKET_ID]' => esc_html__('Will be replaced by the ticket ID of a ticket', 'event_espresso'), |
|
34 | - '[TICKET_NAME]' => esc_html__('The name of the ticket', 'event_espresso'), |
|
35 | - '[TICKET_DESCRIPTION]' => esc_html__('The description of the ticket', 'event_espresso'), |
|
36 | - '[TICKET_PRICE]' => esc_html__('The price of the ticket', 'event_espresso'), |
|
37 | - '[TICKET_PRICE_WITH_TAXES]' => esc_html__( |
|
38 | - 'The price of the ticket including any taxes that might be on the ticket', |
|
39 | - 'event_espresso' |
|
40 | - ), |
|
41 | - '[TKT_QTY_PURCHASED]' => esc_html__( |
|
42 | - 'The total quantity of the current ticket in the list that has been purchased in this transaction', |
|
43 | - 'event_espresso' |
|
44 | - ), |
|
45 | - '[TKT_USES_*]' => esc_html__( |
|
46 | - 'This attribute based shortcode parses to show the number of uses the ticket has. The optional "schema" attribute can be used to indicate what schema is used when the uses is infinite. Options are:', |
|
47 | - 'event_espresso' |
|
48 | - ) . |
|
49 | - '<p><ul>' . |
|
50 | - '<li><strong>symbol</strong>:' . esc_html__( |
|
51 | - 'This returns the ∞ symbol.', |
|
52 | - 'event_espresso' |
|
53 | - ) . '</li>' . |
|
54 | - '<li><strong>text</strong>:' . esc_html__( |
|
55 | - 'This returns the word, "Unlimited". This is also the default if the "schema" attribute is not used.', |
|
56 | - 'event_espresso' |
|
57 | - ) . '</li>' . |
|
58 | - '<li><strong>{custom}</strong>:' . esc_html__( |
|
59 | - 'You can put anything you want as a string instead and that will be used. So you could have the world "any" and whenever uses for a ticket is infinity, this shortcode will parse to "any".', |
|
60 | - 'event_espresso' |
|
61 | - ) . '</li>' . |
|
62 | - '</ul></p>', |
|
63 | - ); |
|
64 | - } |
|
65 | - |
|
66 | - |
|
67 | - protected function _parser($shortcode) |
|
68 | - { |
|
69 | - |
|
70 | - $this->_ticket = $this->_data instanceof EE_Ticket ? $this->_data : null; |
|
71 | - |
|
72 | - $aee = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null; |
|
73 | - $aee = ! $aee instanceof EE_Messages_Addressee && is_array( |
|
74 | - $this->_extra_data |
|
75 | - ) && isset($this->_extra_data['data']) && $this->_extra_data['data'] instanceof EE_Messages_Addressee |
|
76 | - ? $this->_extra_data['data'] : $aee; |
|
77 | - |
|
78 | - |
|
79 | - // possible EE_Line_Item may be incoming data |
|
80 | - $this->_ticket = empty($this->_ticket) |
|
81 | - && $this->_data instanceof EE_Line_Item |
|
82 | - && $aee instanceof EE_Messages_Addressee |
|
83 | - && ! empty($aee->line_items_with_children[ $this->_data->ID() ]['EE_Ticket']) |
|
84 | - && $aee->line_items_with_children[ $this->_data->ID() ]['EE_Ticket'] instanceof EE_Ticket |
|
85 | - ? $aee->line_items_with_children[ $this->_data->ID() ]['EE_Ticket'] |
|
86 | - : $this->_ticket; |
|
87 | - |
|
88 | - // if still no ticket, then let's see if there is a reg_obj. If there IS, then we'll try and grab the ticket from the reg_obj instead. |
|
89 | - if (empty($this->_ticket)) { |
|
90 | - $this->_ticket = $aee instanceof EE_Messages_Addressee && $aee->reg_obj instanceof EE_Registration |
|
91 | - ? $aee->reg_obj->ticket() : null; |
|
92 | - } |
|
93 | - |
|
94 | - |
|
95 | - // If there is no event object by now then get out. |
|
96 | - if (! $this->_ticket instanceof EE_Ticket) { |
|
97 | - return ''; |
|
98 | - } |
|
99 | - |
|
100 | - switch ($shortcode) { |
|
101 | - case '[TICKET_ID]': |
|
102 | - return $this->_ticket->ID(); |
|
103 | - break; |
|
104 | - |
|
105 | - case '[TICKET_NAME]': |
|
106 | - return $this->_ticket->get('TKT_name'); |
|
107 | - break; |
|
108 | - |
|
109 | - case '[TICKET_DESCRIPTION]': |
|
110 | - return $this->_ticket->get('TKT_description'); |
|
111 | - break; |
|
112 | - |
|
113 | - case '[TICKET_PRICE]': |
|
114 | - return EEH_Template::format_currency($this->_ticket->get('TKT_price')); |
|
115 | - break; |
|
116 | - |
|
117 | - case '[TICKET_PRICE_WITH_TAXES]': |
|
118 | - return EEH_Template::format_currency($this->_ticket->get_ticket_total_with_taxes()); |
|
119 | - break; |
|
120 | - |
|
121 | - case '[TKT_QTY_PURCHASED]': |
|
122 | - return $aee instanceof EE_Messages_Addressee ? $aee->tickets[ $this->_ticket->ID() ]['count'] : ''; |
|
123 | - break; |
|
124 | - } |
|
125 | - |
|
126 | - if (strpos($shortcode, '[TKT_USES_*') !== false) { |
|
127 | - $attrs = $this->_get_shortcode_attrs($shortcode); |
|
128 | - $schema = empty($attrs['schema']) ? null : $attrs['schema']; |
|
129 | - return $this->_ticket->get_pretty('TKT_uses', $schema); |
|
130 | - } |
|
131 | - return ''; |
|
132 | - } |
|
133 | - |
|
134 | - |
|
135 | - public function get_ticket_set() |
|
136 | - { |
|
137 | - return $this->_ticket; |
|
138 | - } |
|
20 | + /** |
|
21 | + * Will hold the EE_Ticket if available |
|
22 | + * |
|
23 | + * @var EE_Ticket |
|
24 | + */ |
|
25 | + protected $_ticket; |
|
26 | + |
|
27 | + |
|
28 | + protected function _init_props() |
|
29 | + { |
|
30 | + $this->label = esc_html__('Ticket Shortcodes', 'event_espresso'); |
|
31 | + $this->description = esc_html__('All shortcodes specific to ticket related data', 'event_espresso'); |
|
32 | + $this->_shortcodes = array( |
|
33 | + '[TICKET_ID]' => esc_html__('Will be replaced by the ticket ID of a ticket', 'event_espresso'), |
|
34 | + '[TICKET_NAME]' => esc_html__('The name of the ticket', 'event_espresso'), |
|
35 | + '[TICKET_DESCRIPTION]' => esc_html__('The description of the ticket', 'event_espresso'), |
|
36 | + '[TICKET_PRICE]' => esc_html__('The price of the ticket', 'event_espresso'), |
|
37 | + '[TICKET_PRICE_WITH_TAXES]' => esc_html__( |
|
38 | + 'The price of the ticket including any taxes that might be on the ticket', |
|
39 | + 'event_espresso' |
|
40 | + ), |
|
41 | + '[TKT_QTY_PURCHASED]' => esc_html__( |
|
42 | + 'The total quantity of the current ticket in the list that has been purchased in this transaction', |
|
43 | + 'event_espresso' |
|
44 | + ), |
|
45 | + '[TKT_USES_*]' => esc_html__( |
|
46 | + 'This attribute based shortcode parses to show the number of uses the ticket has. The optional "schema" attribute can be used to indicate what schema is used when the uses is infinite. Options are:', |
|
47 | + 'event_espresso' |
|
48 | + ) . |
|
49 | + '<p><ul>' . |
|
50 | + '<li><strong>symbol</strong>:' . esc_html__( |
|
51 | + 'This returns the ∞ symbol.', |
|
52 | + 'event_espresso' |
|
53 | + ) . '</li>' . |
|
54 | + '<li><strong>text</strong>:' . esc_html__( |
|
55 | + 'This returns the word, "Unlimited". This is also the default if the "schema" attribute is not used.', |
|
56 | + 'event_espresso' |
|
57 | + ) . '</li>' . |
|
58 | + '<li><strong>{custom}</strong>:' . esc_html__( |
|
59 | + 'You can put anything you want as a string instead and that will be used. So you could have the world "any" and whenever uses for a ticket is infinity, this shortcode will parse to "any".', |
|
60 | + 'event_espresso' |
|
61 | + ) . '</li>' . |
|
62 | + '</ul></p>', |
|
63 | + ); |
|
64 | + } |
|
65 | + |
|
66 | + |
|
67 | + protected function _parser($shortcode) |
|
68 | + { |
|
69 | + |
|
70 | + $this->_ticket = $this->_data instanceof EE_Ticket ? $this->_data : null; |
|
71 | + |
|
72 | + $aee = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null; |
|
73 | + $aee = ! $aee instanceof EE_Messages_Addressee && is_array( |
|
74 | + $this->_extra_data |
|
75 | + ) && isset($this->_extra_data['data']) && $this->_extra_data['data'] instanceof EE_Messages_Addressee |
|
76 | + ? $this->_extra_data['data'] : $aee; |
|
77 | + |
|
78 | + |
|
79 | + // possible EE_Line_Item may be incoming data |
|
80 | + $this->_ticket = empty($this->_ticket) |
|
81 | + && $this->_data instanceof EE_Line_Item |
|
82 | + && $aee instanceof EE_Messages_Addressee |
|
83 | + && ! empty($aee->line_items_with_children[ $this->_data->ID() ]['EE_Ticket']) |
|
84 | + && $aee->line_items_with_children[ $this->_data->ID() ]['EE_Ticket'] instanceof EE_Ticket |
|
85 | + ? $aee->line_items_with_children[ $this->_data->ID() ]['EE_Ticket'] |
|
86 | + : $this->_ticket; |
|
87 | + |
|
88 | + // if still no ticket, then let's see if there is a reg_obj. If there IS, then we'll try and grab the ticket from the reg_obj instead. |
|
89 | + if (empty($this->_ticket)) { |
|
90 | + $this->_ticket = $aee instanceof EE_Messages_Addressee && $aee->reg_obj instanceof EE_Registration |
|
91 | + ? $aee->reg_obj->ticket() : null; |
|
92 | + } |
|
93 | + |
|
94 | + |
|
95 | + // If there is no event object by now then get out. |
|
96 | + if (! $this->_ticket instanceof EE_Ticket) { |
|
97 | + return ''; |
|
98 | + } |
|
99 | + |
|
100 | + switch ($shortcode) { |
|
101 | + case '[TICKET_ID]': |
|
102 | + return $this->_ticket->ID(); |
|
103 | + break; |
|
104 | + |
|
105 | + case '[TICKET_NAME]': |
|
106 | + return $this->_ticket->get('TKT_name'); |
|
107 | + break; |
|
108 | + |
|
109 | + case '[TICKET_DESCRIPTION]': |
|
110 | + return $this->_ticket->get('TKT_description'); |
|
111 | + break; |
|
112 | + |
|
113 | + case '[TICKET_PRICE]': |
|
114 | + return EEH_Template::format_currency($this->_ticket->get('TKT_price')); |
|
115 | + break; |
|
116 | + |
|
117 | + case '[TICKET_PRICE_WITH_TAXES]': |
|
118 | + return EEH_Template::format_currency($this->_ticket->get_ticket_total_with_taxes()); |
|
119 | + break; |
|
120 | + |
|
121 | + case '[TKT_QTY_PURCHASED]': |
|
122 | + return $aee instanceof EE_Messages_Addressee ? $aee->tickets[ $this->_ticket->ID() ]['count'] : ''; |
|
123 | + break; |
|
124 | + } |
|
125 | + |
|
126 | + if (strpos($shortcode, '[TKT_USES_*') !== false) { |
|
127 | + $attrs = $this->_get_shortcode_attrs($shortcode); |
|
128 | + $schema = empty($attrs['schema']) ? null : $attrs['schema']; |
|
129 | + return $this->_ticket->get_pretty('TKT_uses', $schema); |
|
130 | + } |
|
131 | + return ''; |
|
132 | + } |
|
133 | + |
|
134 | + |
|
135 | + public function get_ticket_set() |
|
136 | + { |
|
137 | + return $this->_ticket; |
|
138 | + } |
|
139 | 139 | } |
@@ -29,15 +29,15 @@ discard block |
||
29 | 29 | 'Outputs a list of payment items. Note, this is a dynamic shortcode in that it accepts some attributes for setting certain defaults. Attributes that are available are:', |
30 | 30 | 'event_espresso' |
31 | 31 | ) |
32 | - . '<p><ul>' . |
|
33 | - '<li><strong>no_payments</strong>:' . sprintf( |
|
32 | + . '<p><ul>'. |
|
33 | + '<li><strong>no_payments</strong>:'.sprintf( |
|
34 | 34 | esc_html__( |
35 | 35 | 'Indicate with this attribute what will be used if there are no payments present. Default is: "%sNo approved payments have been received.%s"', |
36 | 36 | 'event_espresso' |
37 | 37 | ), |
38 | 38 | htmlspecialchars('<td class="aln-cntr" colspan="6">'), |
39 | 39 | htmlspecialchars('</td>') |
40 | - ) . '</li>' . |
|
40 | + ).'</li>'. |
|
41 | 41 | '</ul></p>', |
42 | 42 | ); |
43 | 43 | } |
@@ -67,7 +67,7 @@ discard block |
||
67 | 67 | $this->_validate_list_requirements(); |
68 | 68 | |
69 | 69 | |
70 | - if (! $this->_data['data'] instanceof EE_Messages_Addressee) { |
|
70 | + if ( ! $this->_data['data'] instanceof EE_Messages_Addressee) { |
|
71 | 71 | return ''; |
72 | 72 | } |
73 | 73 |
@@ -18,88 +18,88 @@ |
||
18 | 18 | */ |
19 | 19 | class EE_Payment_List_Shortcodes extends EE_Shortcodes |
20 | 20 | { |
21 | - protected function _init_props() |
|
22 | - { |
|
23 | - $this->label = esc_html__('Payment List Shortcodes', 'event_espresso'); |
|
24 | - $this->description = esc_html__('All shortcodes specific to payment lists', 'event_espresso'); |
|
25 | - $this->_shortcodes = array( |
|
26 | - '[PAYMENT_LIST_*]' => esc_html__( |
|
27 | - 'Outputs a list of payment items. Note, this is a dynamic shortcode in that it accepts some attributes for setting certain defaults. Attributes that are available are:', |
|
28 | - 'event_espresso' |
|
29 | - ) |
|
30 | - . '<p><ul>' . |
|
31 | - '<li><strong>no_payments</strong>:' . sprintf( |
|
32 | - esc_html__( |
|
33 | - 'Indicate with this attribute what will be used if there are no payments present. Default is: "%sNo approved payments have been received.%s"', |
|
34 | - 'event_espresso' |
|
35 | - ), |
|
36 | - htmlspecialchars('<td class="aln-cntr" colspan="6">'), |
|
37 | - htmlspecialchars('</td>') |
|
38 | - ) . '</li>' . |
|
39 | - '</ul></p>', |
|
40 | - ); |
|
41 | - } |
|
42 | - |
|
43 | - |
|
44 | - protected function _parser($shortcode) |
|
45 | - { |
|
46 | - |
|
47 | - if (strpos($shortcode, '[PAYMENT_LIST_*') !== false) { |
|
48 | - return $this->_get_payment_list($shortcode); |
|
49 | - } |
|
50 | - return ''; |
|
51 | - } |
|
52 | - |
|
53 | - |
|
54 | - /** |
|
55 | - * verify incoming data contains what is needed for retrieving and parsing each payment for transaction. |
|
56 | - * |
|
57 | - * @since 4.5.0 |
|
58 | - * |
|
59 | - * @param string $shortcode The incoming shortcode. |
|
60 | - * |
|
61 | - * @return string parsed ticket line item list. |
|
62 | - */ |
|
63 | - private function _get_payment_list($shortcode) |
|
64 | - { |
|
65 | - $this->_validate_list_requirements(); |
|
66 | - |
|
67 | - |
|
68 | - if (! $this->_data['data'] instanceof EE_Messages_Addressee) { |
|
69 | - return ''; |
|
70 | - } |
|
71 | - |
|
72 | - $valid_shortcodes = array('payment'); |
|
73 | - |
|
74 | - $addressee_obj = $this->_data['data']; |
|
75 | - $templates = $this->_extra_data['template']; |
|
76 | - $payments = apply_filters( |
|
77 | - 'FHEE__Payment_List_Shortcodes___get_payments_list__payments', |
|
78 | - $addressee_obj->payments |
|
79 | - ); |
|
80 | - |
|
81 | - // let's get any attributes that may be present and set the defaults. |
|
82 | - $atts = $this->_get_shortcode_attrs($shortcode); |
|
83 | - |
|
84 | - $no_payments_msg = empty($atts['no_payments']) ? esc_html__( |
|
85 | - 'No approved payments have been received.', |
|
86 | - 'event_espresso' |
|
87 | - ) : $atts['no_payments']; |
|
88 | - |
|
89 | - // made it here so we have an array of paymnets, so we should have what we need. |
|
90 | - $payment_content = empty($payments) ? $no_payments_msg : ''; |
|
91 | - |
|
92 | - $payments = (array) $payments; |
|
93 | - |
|
94 | - foreach ($payments as $payment) { |
|
95 | - $payment_content .= $this->_shortcode_helper->parse_payment_list_template( |
|
96 | - $templates['payment_list'], |
|
97 | - $payment, |
|
98 | - $valid_shortcodes, |
|
99 | - $this->_extra_data |
|
100 | - ); |
|
101 | - } |
|
102 | - |
|
103 | - return $payment_content; |
|
104 | - } |
|
21 | + protected function _init_props() |
|
22 | + { |
|
23 | + $this->label = esc_html__('Payment List Shortcodes', 'event_espresso'); |
|
24 | + $this->description = esc_html__('All shortcodes specific to payment lists', 'event_espresso'); |
|
25 | + $this->_shortcodes = array( |
|
26 | + '[PAYMENT_LIST_*]' => esc_html__( |
|
27 | + 'Outputs a list of payment items. Note, this is a dynamic shortcode in that it accepts some attributes for setting certain defaults. Attributes that are available are:', |
|
28 | + 'event_espresso' |
|
29 | + ) |
|
30 | + . '<p><ul>' . |
|
31 | + '<li><strong>no_payments</strong>:' . sprintf( |
|
32 | + esc_html__( |
|
33 | + 'Indicate with this attribute what will be used if there are no payments present. Default is: "%sNo approved payments have been received.%s"', |
|
34 | + 'event_espresso' |
|
35 | + ), |
|
36 | + htmlspecialchars('<td class="aln-cntr" colspan="6">'), |
|
37 | + htmlspecialchars('</td>') |
|
38 | + ) . '</li>' . |
|
39 | + '</ul></p>', |
|
40 | + ); |
|
41 | + } |
|
42 | + |
|
43 | + |
|
44 | + protected function _parser($shortcode) |
|
45 | + { |
|
46 | + |
|
47 | + if (strpos($shortcode, '[PAYMENT_LIST_*') !== false) { |
|
48 | + return $this->_get_payment_list($shortcode); |
|
49 | + } |
|
50 | + return ''; |
|
51 | + } |
|
52 | + |
|
53 | + |
|
54 | + /** |
|
55 | + * verify incoming data contains what is needed for retrieving and parsing each payment for transaction. |
|
56 | + * |
|
57 | + * @since 4.5.0 |
|
58 | + * |
|
59 | + * @param string $shortcode The incoming shortcode. |
|
60 | + * |
|
61 | + * @return string parsed ticket line item list. |
|
62 | + */ |
|
63 | + private function _get_payment_list($shortcode) |
|
64 | + { |
|
65 | + $this->_validate_list_requirements(); |
|
66 | + |
|
67 | + |
|
68 | + if (! $this->_data['data'] instanceof EE_Messages_Addressee) { |
|
69 | + return ''; |
|
70 | + } |
|
71 | + |
|
72 | + $valid_shortcodes = array('payment'); |
|
73 | + |
|
74 | + $addressee_obj = $this->_data['data']; |
|
75 | + $templates = $this->_extra_data['template']; |
|
76 | + $payments = apply_filters( |
|
77 | + 'FHEE__Payment_List_Shortcodes___get_payments_list__payments', |
|
78 | + $addressee_obj->payments |
|
79 | + ); |
|
80 | + |
|
81 | + // let's get any attributes that may be present and set the defaults. |
|
82 | + $atts = $this->_get_shortcode_attrs($shortcode); |
|
83 | + |
|
84 | + $no_payments_msg = empty($atts['no_payments']) ? esc_html__( |
|
85 | + 'No approved payments have been received.', |
|
86 | + 'event_espresso' |
|
87 | + ) : $atts['no_payments']; |
|
88 | + |
|
89 | + // made it here so we have an array of paymnets, so we should have what we need. |
|
90 | + $payment_content = empty($payments) ? $no_payments_msg : ''; |
|
91 | + |
|
92 | + $payments = (array) $payments; |
|
93 | + |
|
94 | + foreach ($payments as $payment) { |
|
95 | + $payment_content .= $this->_shortcode_helper->parse_payment_list_template( |
|
96 | + $templates['payment_list'], |
|
97 | + $payment, |
|
98 | + $valid_shortcodes, |
|
99 | + $this->_extra_data |
|
100 | + ); |
|
101 | + } |
|
102 | + |
|
103 | + return $payment_content; |
|
104 | + } |
|
105 | 105 | } |
@@ -61,7 +61,7 @@ discard block |
||
61 | 61 | $action = $request->getRequestParam('action'); |
62 | 62 | // show error message about buttons/urls not working as expected if messenger deactivated. |
63 | 63 | if ($action === 'update_message_template' && is_admin()) { |
64 | - if (! isset($this->_active_messengers['pdf'])) { |
|
64 | + if ( ! isset($this->_active_messengers['pdf'])) { |
|
65 | 65 | EE_Error::add_attention( |
66 | 66 | esc_html__( |
67 | 67 | 'Be aware that the pdf messenger is inactive. This means that any pdf related shortcodes will parse to an empty string.', |
@@ -70,7 +70,7 @@ discard block |
||
70 | 70 | ); |
71 | 71 | } |
72 | 72 | |
73 | - if (! isset($this->_active_messengers['html'])) { |
|
73 | + if ( ! isset($this->_active_messengers['html'])) { |
|
74 | 74 | EE_Error::add_attention( |
75 | 75 | esc_html__( |
76 | 76 | 'Be aware that the html messenger is inactive. This means that any html related shortcodes will parse to an empty string.', |
@@ -93,7 +93,7 @@ discard block |
||
93 | 93 | $recipient = ! $recipient instanceof EE_Messages_Addressee && ! empty($this->_extra_data['data']) && $this->_extra_data['data'] instanceof EE_Messages_Addressee |
94 | 94 | ? $this->_extra_data['data'] : $recipient; |
95 | 95 | |
96 | - if (! $recipient instanceof EE_Messages_Addressee) { |
|
96 | + if ( ! $recipient instanceof EE_Messages_Addressee) { |
|
97 | 97 | return ''; |
98 | 98 | } |
99 | 99 | |
@@ -132,8 +132,8 @@ discard block |
||
132 | 132 | 'event_espresso' |
133 | 133 | ); |
134 | 134 | $content = ' |
135 | -<form method="post" action="' . $this->_get_url($recipient, $sending_messenger) . '" > |
|
136 | - <input class="print_button" type="submit" value="' . $download_text . '" /> |
|
135 | +<form method="post" action="' . $this->_get_url($recipient, $sending_messenger).'" > |
|
136 | + <input class="print_button" type="submit" value="' . $download_text.'" /> |
|
137 | 137 | </form> |
138 | 138 | '; |
139 | 139 | return $content; |
@@ -22,157 +22,157 @@ |
||
22 | 22 | */ |
23 | 23 | class EE_Messenger_Shortcodes extends EE_Shortcodes |
24 | 24 | { |
25 | - /** |
|
26 | - * Hold array of active messengers indexed by messenger name. |
|
27 | - * |
|
28 | - * @since 4.5.0 |
|
29 | - * |
|
30 | - * @var EE_messenger[] |
|
31 | - */ |
|
32 | - protected $_active_messengers = array(); |
|
33 | - |
|
34 | - |
|
35 | - protected function _init_props() |
|
36 | - { |
|
37 | - $this->label = esc_html__('Messenger Shortcodes', 'event_espresso'); |
|
38 | - $this->description = esc_html__('All shortcodes that are messenger specific.', 'event_espresso'); |
|
39 | - /** @type EE_Message_Resource_Manager $message_resource_manager */ |
|
40 | - $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager'); |
|
41 | - // add messages about what happens when the messenger is active. |
|
42 | - $this->_active_messengers = $message_resource_manager->active_messengers(); |
|
43 | - |
|
44 | - $this->_shortcodes['[DISPLAY_HTML_URL]'] = esc_html__( |
|
45 | - 'This will return a link to view the template in a browser if the html messenger is active.', |
|
46 | - 'event_espresso' |
|
47 | - ); |
|
48 | - $this->_shortcodes['[DISPLAY_PDF_URL]'] = esc_html__( |
|
49 | - 'This will return a link to generate a pdf for the template if the pdf messenger is active.', |
|
50 | - 'event_espresso' |
|
51 | - ); |
|
52 | - $this->_shortcodes['[DISPLAY_PDF_BUTTON]'] = esc_html__( |
|
53 | - 'This will return html for a download pdf button trigger if the pdf messenger is active.', |
|
54 | - 'event_espresso' |
|
55 | - ); |
|
56 | - |
|
57 | - /** @var RequestInterface $request */ |
|
58 | - $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
59 | - $action = $request->getRequestParam('action'); |
|
60 | - // show error message about buttons/urls not working as expected if messenger deactivated. |
|
61 | - if ($action === 'update_message_template' && is_admin()) { |
|
62 | - if (! isset($this->_active_messengers['pdf'])) { |
|
63 | - EE_Error::add_attention( |
|
64 | - esc_html__( |
|
65 | - 'Be aware that the pdf messenger is inactive. This means that any pdf related shortcodes will parse to an empty string.', |
|
66 | - 'event_espresso' |
|
67 | - ) |
|
68 | - ); |
|
69 | - } |
|
70 | - |
|
71 | - if (! isset($this->_active_messengers['html'])) { |
|
72 | - EE_Error::add_attention( |
|
73 | - esc_html__( |
|
74 | - 'Be aware that the html messenger is inactive. This means that any html related shortcodes will parse to an empty string.', |
|
75 | - 'event_espresso' |
|
76 | - ) |
|
77 | - ); |
|
78 | - } |
|
79 | - } |
|
80 | - } |
|
81 | - |
|
82 | - |
|
83 | - protected function _parser($shortcode) |
|
84 | - { |
|
85 | - // make sure we end up with a copy of the EE_Messages_Addressee object |
|
86 | - $recipient = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null; |
|
87 | - $recipient = ! $recipient instanceof EE_Messages_Addressee && is_array( |
|
88 | - $this->_data |
|
89 | - ) && isset($this->_data['data']) && $this->_data['data'] instanceof EE_Messages_Addressee ? $this->_data['data'] |
|
90 | - : $recipient; |
|
91 | - $recipient = ! $recipient instanceof EE_Messages_Addressee && ! empty($this->_extra_data['data']) && $this->_extra_data['data'] instanceof EE_Messages_Addressee |
|
92 | - ? $this->_extra_data['data'] : $recipient; |
|
93 | - |
|
94 | - if (! $recipient instanceof EE_Messages_Addressee) { |
|
95 | - return ''; |
|
96 | - } |
|
97 | - |
|
98 | - switch ($shortcode) { |
|
99 | - case '[DISPLAY_HTML_URL]': |
|
100 | - return isset($this->_active_messengers['html']) ? $this->_get_url($recipient, 'html') : ''; |
|
101 | - break; |
|
102 | - case '[DISPLAY_PDF_URL]': |
|
103 | - return isset($this->_active_messengers['pdf']) ? $this->_get_url($recipient, 'pdf') : ''; |
|
104 | - break; |
|
105 | - case '[DISPLAY_PDF_BUTTON]': |
|
106 | - return isset($this->_active_messengers['pdf']) ? $this->_get_button($recipient, 'pdf') : ''; |
|
107 | - break; |
|
108 | - } |
|
109 | - return ''; |
|
110 | - } |
|
111 | - |
|
112 | - |
|
113 | - /** |
|
114 | - * This method takes the incoming data and figures out from it what the message type is and evt_id/grp_id and uses |
|
115 | - * that to generate the html for a button in the template. |
|
116 | - * |
|
117 | - * @since 4.5.0 |
|
118 | - * |
|
119 | - * @param EE_Messages_Addressee $recipient |
|
120 | - * @param string $sending_messenger 'html' or 'pdf' |
|
121 | - * |
|
122 | - * @return string Generated html |
|
123 | - */ |
|
124 | - private function _get_button(EE_Messages_Addressee $recipient, $sending_messenger) |
|
125 | - { |
|
126 | - $download_text = $sending_messenger == 'pdf' |
|
127 | - ? esc_html__('Download PDF', 'event_espresso') |
|
128 | - : esc_html__( |
|
129 | - 'Show HTML', |
|
130 | - 'event_espresso' |
|
131 | - ); |
|
132 | - $content = ' |
|
25 | + /** |
|
26 | + * Hold array of active messengers indexed by messenger name. |
|
27 | + * |
|
28 | + * @since 4.5.0 |
|
29 | + * |
|
30 | + * @var EE_messenger[] |
|
31 | + */ |
|
32 | + protected $_active_messengers = array(); |
|
33 | + |
|
34 | + |
|
35 | + protected function _init_props() |
|
36 | + { |
|
37 | + $this->label = esc_html__('Messenger Shortcodes', 'event_espresso'); |
|
38 | + $this->description = esc_html__('All shortcodes that are messenger specific.', 'event_espresso'); |
|
39 | + /** @type EE_Message_Resource_Manager $message_resource_manager */ |
|
40 | + $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager'); |
|
41 | + // add messages about what happens when the messenger is active. |
|
42 | + $this->_active_messengers = $message_resource_manager->active_messengers(); |
|
43 | + |
|
44 | + $this->_shortcodes['[DISPLAY_HTML_URL]'] = esc_html__( |
|
45 | + 'This will return a link to view the template in a browser if the html messenger is active.', |
|
46 | + 'event_espresso' |
|
47 | + ); |
|
48 | + $this->_shortcodes['[DISPLAY_PDF_URL]'] = esc_html__( |
|
49 | + 'This will return a link to generate a pdf for the template if the pdf messenger is active.', |
|
50 | + 'event_espresso' |
|
51 | + ); |
|
52 | + $this->_shortcodes['[DISPLAY_PDF_BUTTON]'] = esc_html__( |
|
53 | + 'This will return html for a download pdf button trigger if the pdf messenger is active.', |
|
54 | + 'event_espresso' |
|
55 | + ); |
|
56 | + |
|
57 | + /** @var RequestInterface $request */ |
|
58 | + $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
59 | + $action = $request->getRequestParam('action'); |
|
60 | + // show error message about buttons/urls not working as expected if messenger deactivated. |
|
61 | + if ($action === 'update_message_template' && is_admin()) { |
|
62 | + if (! isset($this->_active_messengers['pdf'])) { |
|
63 | + EE_Error::add_attention( |
|
64 | + esc_html__( |
|
65 | + 'Be aware that the pdf messenger is inactive. This means that any pdf related shortcodes will parse to an empty string.', |
|
66 | + 'event_espresso' |
|
67 | + ) |
|
68 | + ); |
|
69 | + } |
|
70 | + |
|
71 | + if (! isset($this->_active_messengers['html'])) { |
|
72 | + EE_Error::add_attention( |
|
73 | + esc_html__( |
|
74 | + 'Be aware that the html messenger is inactive. This means that any html related shortcodes will parse to an empty string.', |
|
75 | + 'event_espresso' |
|
76 | + ) |
|
77 | + ); |
|
78 | + } |
|
79 | + } |
|
80 | + } |
|
81 | + |
|
82 | + |
|
83 | + protected function _parser($shortcode) |
|
84 | + { |
|
85 | + // make sure we end up with a copy of the EE_Messages_Addressee object |
|
86 | + $recipient = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null; |
|
87 | + $recipient = ! $recipient instanceof EE_Messages_Addressee && is_array( |
|
88 | + $this->_data |
|
89 | + ) && isset($this->_data['data']) && $this->_data['data'] instanceof EE_Messages_Addressee ? $this->_data['data'] |
|
90 | + : $recipient; |
|
91 | + $recipient = ! $recipient instanceof EE_Messages_Addressee && ! empty($this->_extra_data['data']) && $this->_extra_data['data'] instanceof EE_Messages_Addressee |
|
92 | + ? $this->_extra_data['data'] : $recipient; |
|
93 | + |
|
94 | + if (! $recipient instanceof EE_Messages_Addressee) { |
|
95 | + return ''; |
|
96 | + } |
|
97 | + |
|
98 | + switch ($shortcode) { |
|
99 | + case '[DISPLAY_HTML_URL]': |
|
100 | + return isset($this->_active_messengers['html']) ? $this->_get_url($recipient, 'html') : ''; |
|
101 | + break; |
|
102 | + case '[DISPLAY_PDF_URL]': |
|
103 | + return isset($this->_active_messengers['pdf']) ? $this->_get_url($recipient, 'pdf') : ''; |
|
104 | + break; |
|
105 | + case '[DISPLAY_PDF_BUTTON]': |
|
106 | + return isset($this->_active_messengers['pdf']) ? $this->_get_button($recipient, 'pdf') : ''; |
|
107 | + break; |
|
108 | + } |
|
109 | + return ''; |
|
110 | + } |
|
111 | + |
|
112 | + |
|
113 | + /** |
|
114 | + * This method takes the incoming data and figures out from it what the message type is and evt_id/grp_id and uses |
|
115 | + * that to generate the html for a button in the template. |
|
116 | + * |
|
117 | + * @since 4.5.0 |
|
118 | + * |
|
119 | + * @param EE_Messages_Addressee $recipient |
|
120 | + * @param string $sending_messenger 'html' or 'pdf' |
|
121 | + * |
|
122 | + * @return string Generated html |
|
123 | + */ |
|
124 | + private function _get_button(EE_Messages_Addressee $recipient, $sending_messenger) |
|
125 | + { |
|
126 | + $download_text = $sending_messenger == 'pdf' |
|
127 | + ? esc_html__('Download PDF', 'event_espresso') |
|
128 | + : esc_html__( |
|
129 | + 'Show HTML', |
|
130 | + 'event_espresso' |
|
131 | + ); |
|
132 | + $content = ' |
|
133 | 133 | <form method="post" action="' . $this->_get_url($recipient, $sending_messenger) . '" > |
134 | 134 | <input class="print_button" type="submit" value="' . $download_text . '" /> |
135 | 135 | </form> |
136 | 136 | '; |
137 | - return $content; |
|
138 | - } |
|
139 | - |
|
140 | - |
|
141 | - /** |
|
142 | - * This method takes the incoming data and figures out from it what the message type is and |
|
143 | - * evt_id/grp_id and uses that to generate the url for displaying the template in a browser. |
|
144 | - * |
|
145 | - * @since 4.5.0 |
|
146 | - * |
|
147 | - * @param EE_Messages_Addressee $recipient |
|
148 | - * @param string $sending_messenger |
|
149 | - * |
|
150 | - * @return string The generated url for displaying the link. |
|
151 | - * @throws EE_Error |
|
152 | - */ |
|
153 | - private function _get_url(EE_Messages_Addressee $recipient, $sending_messenger) |
|
154 | - { |
|
155 | - |
|
156 | - $reg = $recipient->reg_obj; |
|
157 | - $reg = ! $reg instanceof EE_Registration ? $recipient->primary_reg_obj : $reg; |
|
158 | - |
|
159 | - |
|
160 | - if ($this->_message_type instanceof EE_message_type && $this->_message instanceof EE_Message) { |
|
161 | - EE_Registry::instance()->load_helper('MSG_Template'); |
|
162 | - try { |
|
163 | - return EEH_MSG_Template::get_url_trigger( |
|
164 | - $this->_message_type, |
|
165 | - $this->_message, |
|
166 | - $reg, |
|
167 | - $sending_messenger |
|
168 | - ); |
|
169 | - } catch (EE_Error $e) { |
|
170 | - if (WP_DEBUG) { |
|
171 | - $e->get_error(); |
|
172 | - } |
|
173 | - } |
|
174 | - } |
|
175 | - |
|
176 | - return ''; |
|
177 | - } |
|
137 | + return $content; |
|
138 | + } |
|
139 | + |
|
140 | + |
|
141 | + /** |
|
142 | + * This method takes the incoming data and figures out from it what the message type is and |
|
143 | + * evt_id/grp_id and uses that to generate the url for displaying the template in a browser. |
|
144 | + * |
|
145 | + * @since 4.5.0 |
|
146 | + * |
|
147 | + * @param EE_Messages_Addressee $recipient |
|
148 | + * @param string $sending_messenger |
|
149 | + * |
|
150 | + * @return string The generated url for displaying the link. |
|
151 | + * @throws EE_Error |
|
152 | + */ |
|
153 | + private function _get_url(EE_Messages_Addressee $recipient, $sending_messenger) |
|
154 | + { |
|
155 | + |
|
156 | + $reg = $recipient->reg_obj; |
|
157 | + $reg = ! $reg instanceof EE_Registration ? $recipient->primary_reg_obj : $reg; |
|
158 | + |
|
159 | + |
|
160 | + if ($this->_message_type instanceof EE_message_type && $this->_message instanceof EE_Message) { |
|
161 | + EE_Registry::instance()->load_helper('MSG_Template'); |
|
162 | + try { |
|
163 | + return EEH_MSG_Template::get_url_trigger( |
|
164 | + $this->_message_type, |
|
165 | + $this->_message, |
|
166 | + $reg, |
|
167 | + $sending_messenger |
|
168 | + ); |
|
169 | + } catch (EE_Error $e) { |
|
170 | + if (WP_DEBUG) { |
|
171 | + $e->get_error(); |
|
172 | + } |
|
173 | + } |
|
174 | + } |
|
175 | + |
|
176 | + return ''; |
|
177 | + } |
|
178 | 178 | } |
@@ -118,7 +118,7 @@ discard block |
||
118 | 118 | $this->_gateway->set_unsupported_character_remover(new AsciiOnly()); |
119 | 119 | do_action('AHEE__EE_PMT_Base___construct__done_initializing_gateway_class', $this, $this->_gateway); |
120 | 120 | } |
121 | - if (! isset($this->_has_billing_form)) { |
|
121 | + if ( ! isset($this->_has_billing_form)) { |
|
122 | 122 | // by default, On Site gateways have a billing form |
123 | 123 | if ($this->payment_occurs() == EE_PMT_Base::onsite) { |
124 | 124 | $this->set_has_billing_form(true); |
@@ -127,7 +127,7 @@ discard block |
||
127 | 127 | } |
128 | 128 | } |
129 | 129 | |
130 | - if (! $this->_pretty_name) { |
|
130 | + if ( ! $this->_pretty_name) { |
|
131 | 131 | throw new EE_Error( |
132 | 132 | sprintf( |
133 | 133 | esc_html__( |
@@ -139,7 +139,7 @@ discard block |
||
139 | 139 | } |
140 | 140 | // if the child didn't specify a default button, use the credit card one |
141 | 141 | if ($this->_default_button_url === null) { |
142 | - $this->_default_button_url = EE_PLUGIN_DIR_URL . 'payment_methods/pay-by-credit-card.png'; |
|
142 | + $this->_default_button_url = EE_PLUGIN_DIR_URL.'payment_methods/pay-by-credit-card.png'; |
|
143 | 143 | } |
144 | 144 | } |
145 | 145 | |
@@ -160,7 +160,7 @@ discard block |
||
160 | 160 | { |
161 | 161 | $reflector = new ReflectionClass(get_class($this)); |
162 | 162 | $fn = $reflector->getFileName(); |
163 | - $this->_file_folder = dirname($fn) . '/'; |
|
163 | + $this->_file_folder = dirname($fn).'/'; |
|
164 | 164 | } |
165 | 165 | |
166 | 166 | |
@@ -193,7 +193,7 @@ discard block |
||
193 | 193 | */ |
194 | 194 | public function file_folder() |
195 | 195 | { |
196 | - if (! $this->_file_folder) { |
|
196 | + if ( ! $this->_file_folder) { |
|
197 | 197 | $this->_set_file_folder(); |
198 | 198 | } |
199 | 199 | return $this->_file_folder; |
@@ -205,7 +205,7 @@ discard block |
||
205 | 205 | */ |
206 | 206 | public function file_url() |
207 | 207 | { |
208 | - if (! $this->_file_url) { |
|
208 | + if ( ! $this->_file_url) { |
|
209 | 209 | $this->_set_file_url(); |
210 | 210 | } |
211 | 211 | return $this->_file_url; |
@@ -239,7 +239,7 @@ discard block |
||
239 | 239 | */ |
240 | 240 | public function settings_form() |
241 | 241 | { |
242 | - if (! $this->_settings_form) { |
|
242 | + if ( ! $this->_settings_form) { |
|
243 | 243 | $this->_settings_form = $this->generate_new_settings_form(); |
244 | 244 | $this->_settings_form->set_payment_method_type($this); |
245 | 245 | // if we have already assigned a model object to this pmt, make |
@@ -293,7 +293,7 @@ discard block |
||
293 | 293 | public function billing_form(EE_Transaction $transaction = null, $extra_args = array()) |
294 | 294 | { |
295 | 295 | // has billing form already been regenerated ? or overwrite cache? |
296 | - if (! $this->_billing_form instanceof EE_Billing_Info_Form || ! $this->_cache_billing_form) { |
|
296 | + if ( ! $this->_billing_form instanceof EE_Billing_Info_Form || ! $this->_cache_billing_form) { |
|
297 | 297 | $this->_billing_form = $this->generate_new_billing_form($transaction, $extra_args); |
298 | 298 | } |
299 | 299 | // if we know who the attendee is, and this is a billing form |
@@ -397,7 +397,7 @@ discard block |
||
397 | 397 | $payment = EEM_Payment::instance()->get_one(array($duplicate_properties)); |
398 | 398 | // if we didn't already have a payment in progress for the same thing, |
399 | 399 | // then we actually want to make a new payment |
400 | - if (! $payment instanceof EE_Payment) { |
|
400 | + if ( ! $payment instanceof EE_Payment) { |
|
401 | 401 | $payment = EE_Payment::new_instance( |
402 | 402 | array_merge( |
403 | 403 | $duplicate_properties, |
@@ -498,7 +498,7 @@ discard block |
||
498 | 498 | public function handle_ipn($req_data, $transaction) |
499 | 499 | { |
500 | 500 | $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); |
501 | - if (! $this->_gateway instanceof EE_Offsite_Gateway) { |
|
501 | + if ( ! $this->_gateway instanceof EE_Offsite_Gateway) { |
|
502 | 502 | throw new EE_Error( |
503 | 503 | sprintf( |
504 | 504 | esc_html__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"), |
@@ -521,7 +521,7 @@ discard block |
||
521 | 521 | */ |
522 | 522 | protected function _save_billing_info_to_attendee($billing_form, $transaction) |
523 | 523 | { |
524 | - if (! $transaction || ! $transaction instanceof EE_Transaction) { |
|
524 | + if ( ! $transaction || ! $transaction instanceof EE_Transaction) { |
|
525 | 525 | EE_Error::add_error( |
526 | 526 | esc_html__("Cannot save billing info because no transaction was specified", "event_espresso"), |
527 | 527 | __FILE__, |
@@ -531,7 +531,7 @@ discard block |
||
531 | 531 | return false; |
532 | 532 | } |
533 | 533 | $primary_reg = $transaction->primary_registration(); |
534 | - if (! $primary_reg) { |
|
534 | + if ( ! $primary_reg) { |
|
535 | 535 | EE_Error::add_error( |
536 | 536 | esc_html__("Cannot save billing info because the transaction has no primary registration", "event_espresso"), |
537 | 537 | __FILE__, |
@@ -541,7 +541,7 @@ discard block |
||
541 | 541 | return false; |
542 | 542 | } |
543 | 543 | $attendee = $primary_reg->attendee(); |
544 | - if (! $attendee) { |
|
544 | + if ( ! $attendee) { |
|
545 | 545 | EE_Error::add_error( |
546 | 546 | esc_html__( |
547 | 547 | "Cannot save billing info because the transaction's primary registration has no attendee!", |
@@ -654,7 +654,7 @@ discard block |
||
654 | 654 | */ |
655 | 655 | public function payment_occurs() |
656 | 656 | { |
657 | - if (! $this->_gateway) { |
|
657 | + if ( ! $this->_gateway) { |
|
658 | 658 | return EE_PMT_Base::offline; |
659 | 659 | } elseif ($this->_gateway instanceof EE_Onsite_Gateway) { |
660 | 660 | return EE_PMT_Base::onsite; |
@@ -685,7 +685,7 @@ discard block |
||
685 | 685 | public function payment_overview_content(EE_Payment $payment) |
686 | 686 | { |
687 | 687 | return EEH_Template::display_template( |
688 | - EE_LIBRARIES . 'payment_methods/templates/payment_details_content.template.php', |
|
688 | + EE_LIBRARIES.'payment_methods/templates/payment_details_content.template.php', |
|
689 | 689 | array('payment_method' => $this->_pm_instance, 'payment' => $payment), |
690 | 690 | true |
691 | 691 | ); |
@@ -783,7 +783,7 @@ discard block |
||
783 | 783 | */ |
784 | 784 | public function get_help_tab_name() |
785 | 785 | { |
786 | - return 'ee_' . strtolower($this->system_name()) . '_help_tab'; |
|
786 | + return 'ee_'.strtolower($this->system_name()).'_help_tab'; |
|
787 | 787 | } |
788 | 788 | |
789 | 789 | /** |
@@ -794,7 +794,7 @@ discard block |
||
794 | 794 | */ |
795 | 795 | public function cap_name() |
796 | 796 | { |
797 | - return 'ee_payment_method_' . strtolower($this->system_name()); |
|
797 | + return 'ee_payment_method_'.strtolower($this->system_name()); |
|
798 | 798 | } |
799 | 799 | |
800 | 800 | /** |
@@ -828,7 +828,7 @@ discard block |
||
828 | 828 | public function introductory_html() |
829 | 829 | { |
830 | 830 | return EEH_Template::locate_template( |
831 | - $this->file_folder() . 'templates/' . strtolower($this->system_name()) . '_intro.template.php', |
|
831 | + $this->file_folder().'templates/'.strtolower($this->system_name()).'_intro.template.php', |
|
832 | 832 | array('pmt_obj' => $this, 'pm_instance' => $this->_pm_instance) |
833 | 833 | ); |
834 | 834 | } |
@@ -21,814 +21,814 @@ |
||
21 | 21 | */ |
22 | 22 | abstract class EE_PMT_Base |
23 | 23 | { |
24 | - const onsite = 'on-site'; |
|
25 | - const offsite = 'off-site'; |
|
26 | - const offline = 'off-line'; |
|
27 | - |
|
28 | - /** |
|
29 | - * @var EE_Payment_Method |
|
30 | - */ |
|
31 | - protected $_pm_instance = null; |
|
32 | - |
|
33 | - /** |
|
34 | - * @var boolean |
|
35 | - */ |
|
36 | - protected $_requires_https = false; |
|
37 | - |
|
38 | - /** |
|
39 | - * @var boolean |
|
40 | - */ |
|
41 | - protected $_has_billing_form; |
|
42 | - |
|
43 | - /** |
|
44 | - * @var EE_Gateway |
|
45 | - */ |
|
46 | - protected $_gateway = null; |
|
47 | - |
|
48 | - /** |
|
49 | - * @var EE_Payment_Method_Form |
|
50 | - */ |
|
51 | - protected $_settings_form = null; |
|
52 | - |
|
53 | - /** |
|
54 | - * @var EE_Form_Section_Proper |
|
55 | - */ |
|
56 | - protected $_billing_form = null; |
|
57 | - |
|
58 | - /** |
|
59 | - * @var boolean |
|
60 | - */ |
|
61 | - protected $_cache_billing_form = true; |
|
62 | - |
|
63 | - /** |
|
64 | - * String of the absolute path to the folder containing this file, with a trailing slash. |
|
65 | - * eg '/public_html/wp-site/wp-content/plugins/event-espresso/payment_methods/Invoice/' |
|
66 | - * |
|
67 | - * @var string |
|
68 | - */ |
|
69 | - protected $_file_folder = null; |
|
70 | - |
|
71 | - /** |
|
72 | - * String to the absolute URL to this file (useful for getting its web-accessible resources |
|
73 | - * like images, js, or css) |
|
74 | - * |
|
75 | - * @var string |
|
76 | - */ |
|
77 | - protected $_file_url = null; |
|
78 | - |
|
79 | - /** |
|
80 | - * Pretty name for the payment method |
|
81 | - * |
|
82 | - * @var string |
|
83 | - */ |
|
84 | - protected $_pretty_name = null; |
|
85 | - |
|
86 | - /** |
|
87 | - * |
|
88 | - * @var string |
|
89 | - */ |
|
90 | - protected $_default_button_url = null; |
|
91 | - |
|
92 | - /** |
|
93 | - * |
|
94 | - * @var string |
|
95 | - */ |
|
96 | - protected $_default_description = null; |
|
97 | - |
|
98 | - |
|
99 | - /** |
|
100 | - * |
|
101 | - * @param EE_Payment_Method $pm_instance |
|
102 | - * @throws EE_Error |
|
103 | - * @return EE_PMT_Base |
|
104 | - */ |
|
105 | - public function __construct($pm_instance = null) |
|
106 | - { |
|
107 | - if ($pm_instance instanceof EE_Payment_Method) { |
|
108 | - $this->set_instance($pm_instance); |
|
109 | - } |
|
110 | - if ($this->_gateway) { |
|
111 | - $this->_gateway->set_payment_model(EEM_Payment::instance()); |
|
112 | - $this->_gateway->set_payment_log(EEM_Change_Log::instance()); |
|
113 | - $this->_gateway->set_template_helper(new EEH_Template()); |
|
114 | - $this->_gateway->set_line_item_helper(new EEH_Line_Item()); |
|
115 | - $this->_gateway->set_money_helper(new EEH_Money()); |
|
116 | - $this->_gateway->set_gateway_data_formatter(new GatewayDataFormatter()); |
|
117 | - $this->_gateway->set_unsupported_character_remover(new AsciiOnly()); |
|
118 | - do_action('AHEE__EE_PMT_Base___construct__done_initializing_gateway_class', $this, $this->_gateway); |
|
119 | - } |
|
120 | - if (! isset($this->_has_billing_form)) { |
|
121 | - // by default, On Site gateways have a billing form |
|
122 | - if ($this->payment_occurs() == EE_PMT_Base::onsite) { |
|
123 | - $this->set_has_billing_form(true); |
|
124 | - } else { |
|
125 | - $this->set_has_billing_form(false); |
|
126 | - } |
|
127 | - } |
|
128 | - |
|
129 | - if (! $this->_pretty_name) { |
|
130 | - throw new EE_Error( |
|
131 | - sprintf( |
|
132 | - esc_html__( |
|
133 | - "You must set the pretty name for the Payment Method Type in the constructor (_pretty_name), and please make it internationalized", |
|
134 | - "event_espresso" |
|
135 | - ) |
|
136 | - ) |
|
137 | - ); |
|
138 | - } |
|
139 | - // if the child didn't specify a default button, use the credit card one |
|
140 | - if ($this->_default_button_url === null) { |
|
141 | - $this->_default_button_url = EE_PLUGIN_DIR_URL . 'payment_methods/pay-by-credit-card.png'; |
|
142 | - } |
|
143 | - } |
|
144 | - |
|
145 | - |
|
146 | - /** |
|
147 | - * @param boolean $has_billing_form |
|
148 | - */ |
|
149 | - public function set_has_billing_form($has_billing_form) |
|
150 | - { |
|
151 | - $this->_has_billing_form = filter_var($has_billing_form, FILTER_VALIDATE_BOOLEAN); |
|
152 | - } |
|
153 | - |
|
154 | - |
|
155 | - /** |
|
156 | - * sets the file_folder property |
|
157 | - */ |
|
158 | - protected function _set_file_folder() |
|
159 | - { |
|
160 | - $reflector = new ReflectionClass(get_class($this)); |
|
161 | - $fn = $reflector->getFileName(); |
|
162 | - $this->_file_folder = dirname($fn) . '/'; |
|
163 | - } |
|
164 | - |
|
165 | - |
|
166 | - /** |
|
167 | - * sets the file URL with a trailing slash for this PMT |
|
168 | - */ |
|
169 | - protected function _set_file_url() |
|
170 | - { |
|
171 | - $plugins_dir_fixed = str_replace('\\', '/', WP_PLUGIN_DIR); |
|
172 | - $file_folder_fixed = str_replace('\\', '/', $this->file_folder()); |
|
173 | - $file_path = str_replace($plugins_dir_fixed, WP_PLUGIN_URL, $file_folder_fixed); |
|
174 | - $this->_file_url = set_url_scheme($file_path); |
|
175 | - } |
|
176 | - |
|
177 | - /** |
|
178 | - * Gets the default description on all payment methods of this type |
|
179 | - * |
|
180 | - * @return string |
|
181 | - */ |
|
182 | - public function default_description() |
|
183 | - { |
|
184 | - return $this->_default_description; |
|
185 | - } |
|
186 | - |
|
187 | - |
|
188 | - /** |
|
189 | - * Returns the folder containing the PMT child class, with a trailing slash |
|
190 | - * |
|
191 | - * @return string |
|
192 | - */ |
|
193 | - public function file_folder() |
|
194 | - { |
|
195 | - if (! $this->_file_folder) { |
|
196 | - $this->_set_file_folder(); |
|
197 | - } |
|
198 | - return $this->_file_folder; |
|
199 | - } |
|
200 | - |
|
201 | - |
|
202 | - /** |
|
203 | - * @return string |
|
204 | - */ |
|
205 | - public function file_url() |
|
206 | - { |
|
207 | - if (! $this->_file_url) { |
|
208 | - $this->_set_file_url(); |
|
209 | - } |
|
210 | - return $this->_file_url; |
|
211 | - } |
|
212 | - |
|
213 | - |
|
214 | - /** |
|
215 | - * Sets the payment method instance this payment method type is for. |
|
216 | - * Its important teh payment method instance is set before |
|
217 | - * |
|
218 | - * @param EE_Payment_Method $payment_method_instance |
|
219 | - */ |
|
220 | - public function set_instance($payment_method_instance) |
|
221 | - { |
|
222 | - $this->_pm_instance = $payment_method_instance; |
|
223 | - // if they have already requested the settings form, make sure its |
|
224 | - // data matches this model object |
|
225 | - if ($this->_settings_form) { |
|
226 | - $this->settings_form()->populate_model_obj($payment_method_instance); |
|
227 | - } |
|
228 | - if ($this->_gateway && $this->_gateway instanceof EE_Gateway) { |
|
229 | - $this->_gateway->set_settings($payment_method_instance->settings_array()); |
|
230 | - } |
|
231 | - } |
|
232 | - |
|
233 | - |
|
234 | - /** |
|
235 | - * Gets teh form for displaying to admins where they setup the payment method |
|
236 | - * |
|
237 | - * @return EE_Payment_Method_Form |
|
238 | - */ |
|
239 | - public function settings_form() |
|
240 | - { |
|
241 | - if (! $this->_settings_form) { |
|
242 | - $this->_settings_form = $this->generate_new_settings_form(); |
|
243 | - $this->_settings_form->set_payment_method_type($this); |
|
244 | - // if we have already assigned a model object to this pmt, make |
|
245 | - // sure its reflected in teh form we just generated |
|
246 | - if ($this->_pm_instance) { |
|
247 | - $this->_settings_form->populate_model_obj($this->_pm_instance); |
|
248 | - } |
|
249 | - } |
|
250 | - return $this->_settings_form; |
|
251 | - } |
|
252 | - |
|
253 | - |
|
254 | - /** |
|
255 | - * Gets the form for all the settings related to this payment method type |
|
256 | - * |
|
257 | - * @return EE_Payment_Method_Form |
|
258 | - */ |
|
259 | - abstract public function generate_new_settings_form(); |
|
260 | - |
|
261 | - |
|
262 | - /** |
|
263 | - * Sets the form for settings. This may be useful if we have already received |
|
264 | - * a form submission and have form data it in, and want to use it anytime we're showing |
|
265 | - * this payment method type's settings form later in the request |
|
266 | - * |
|
267 | - * @param EE_Payment_Method_Form $form |
|
268 | - */ |
|
269 | - public function set_settings_form($form) |
|
270 | - { |
|
271 | - $this->_settings_form = $form; |
|
272 | - } |
|
273 | - |
|
274 | - |
|
275 | - /** |
|
276 | - * @return boolean |
|
277 | - */ |
|
278 | - public function has_billing_form() |
|
279 | - { |
|
280 | - return $this->_has_billing_form; |
|
281 | - } |
|
282 | - |
|
283 | - |
|
284 | - /** |
|
285 | - * Gets the form for displaying to attendees where they can enter their billing info |
|
286 | - * which will be sent to teh gateway (can be null) |
|
287 | - * |
|
288 | - * @param \EE_Transaction $transaction |
|
289 | - * @param array $extra_args |
|
290 | - * @return \EE_Billing_Attendee_Info_Form|\EE_Billing_Info_Form|null |
|
291 | - */ |
|
292 | - public function billing_form(EE_Transaction $transaction = null, $extra_args = array()) |
|
293 | - { |
|
294 | - // has billing form already been regenerated ? or overwrite cache? |
|
295 | - if (! $this->_billing_form instanceof EE_Billing_Info_Form || ! $this->_cache_billing_form) { |
|
296 | - $this->_billing_form = $this->generate_new_billing_form($transaction, $extra_args); |
|
297 | - } |
|
298 | - // if we know who the attendee is, and this is a billing form |
|
299 | - // that uses attendee info, populate it |
|
300 | - if ( |
|
301 | - apply_filters( |
|
302 | - 'FHEE__populate_billing_form_fields_from_attendee', |
|
303 | - ($this->_billing_form instanceof EE_Billing_Attendee_Info_Form |
|
304 | - && $transaction instanceof EE_Transaction |
|
305 | - && $transaction->primary_registration() instanceof EE_Registration |
|
306 | - && $transaction->primary_registration()->attendee() instanceof EE_Attendee |
|
307 | - ), |
|
308 | - $this->_billing_form, |
|
309 | - $transaction |
|
310 | - ) |
|
311 | - ) { |
|
312 | - $this->_billing_form->populate_from_attendee($transaction->primary_registration()->attendee()); |
|
313 | - } |
|
314 | - return $this->_billing_form; |
|
315 | - } |
|
316 | - |
|
317 | - |
|
318 | - /** |
|
319 | - * Creates the billing form for this payment method type |
|
320 | - * |
|
321 | - * @param \EE_Transaction $transaction |
|
322 | - * @return \EE_Billing_Info_Form |
|
323 | - */ |
|
324 | - abstract public function generate_new_billing_form(EE_Transaction $transaction = null); |
|
325 | - |
|
326 | - |
|
327 | - /** |
|
328 | - * apply_billing_form_debug_settings |
|
329 | - * applies debug data to the form |
|
330 | - * |
|
331 | - * @param \EE_Billing_Info_Form $billing_form |
|
332 | - * @return \EE_Billing_Info_Form |
|
333 | - */ |
|
334 | - public function apply_billing_form_debug_settings(EE_Billing_Info_Form $billing_form) |
|
335 | - { |
|
336 | - return $billing_form; |
|
337 | - } |
|
338 | - |
|
339 | - |
|
340 | - /** |
|
341 | - * Sets the billing form for this payment method type. You may want to use this |
|
342 | - * if you have form |
|
343 | - * |
|
344 | - * @param EE_Payment_Method $form |
|
345 | - */ |
|
346 | - public function set_billing_form($form) |
|
347 | - { |
|
348 | - $this->_billing_form = $form; |
|
349 | - } |
|
350 | - |
|
351 | - |
|
352 | - /** |
|
353 | - * Returns whether or not this payment method requires HTTPS to be used |
|
354 | - * |
|
355 | - * @return boolean |
|
356 | - */ |
|
357 | - public function requires_https() |
|
358 | - { |
|
359 | - return $this->_requires_https; |
|
360 | - } |
|
361 | - |
|
362 | - |
|
363 | - /** |
|
364 | - * |
|
365 | - * @param EE_Transaction $transaction |
|
366 | - * @param float $amount |
|
367 | - * @param EE_Billing_Info_Form $billing_info |
|
368 | - * @param string $return_url |
|
369 | - * @param string $fail_url |
|
370 | - * @param string $method |
|
371 | - * @param bool $by_admin |
|
372 | - * @return EE_Payment |
|
373 | - * @throws EE_Error |
|
374 | - */ |
|
375 | - public function process_payment( |
|
376 | - EE_Transaction $transaction, |
|
377 | - $amount = null, |
|
378 | - $billing_info = null, |
|
379 | - $return_url = null, |
|
380 | - $fail_url = '', |
|
381 | - $method = 'CART', |
|
382 | - $by_admin = false |
|
383 | - ) { |
|
384 | - // @todo: add surcharge for the payment method, if any |
|
385 | - if ($this->_gateway) { |
|
386 | - // there is a gateway, so we're going to make a payment object |
|
387 | - // but wait! do they already have a payment in progress that we thought was failed? |
|
388 | - $duplicate_properties = array( |
|
389 | - 'STS_ID' => EEM_Payment::status_id_failed, |
|
390 | - 'TXN_ID' => $transaction->ID(), |
|
391 | - 'PMD_ID' => $this->_pm_instance->ID(), |
|
392 | - 'PAY_source' => $method, |
|
393 | - 'PAY_amount' => $amount !== null ? $amount : $transaction->remaining(), |
|
394 | - 'PAY_gateway_response' => null, |
|
395 | - ); |
|
396 | - $payment = EEM_Payment::instance()->get_one(array($duplicate_properties)); |
|
397 | - // if we didn't already have a payment in progress for the same thing, |
|
398 | - // then we actually want to make a new payment |
|
399 | - if (! $payment instanceof EE_Payment) { |
|
400 | - $payment = EE_Payment::new_instance( |
|
401 | - array_merge( |
|
402 | - $duplicate_properties, |
|
403 | - array( |
|
404 | - 'PAY_timestamp' => time(), |
|
405 | - 'PAY_txn_id_chq_nmbr' => null, |
|
406 | - 'PAY_po_number' => null, |
|
407 | - 'PAY_extra_accntng' => null, |
|
408 | - 'PAY_details' => null, |
|
409 | - ) |
|
410 | - ) |
|
411 | - ); |
|
412 | - } |
|
413 | - // make sure the payment has been saved to show we started it, and so it has an ID should the gateway try to log it |
|
414 | - $payment->save(); |
|
415 | - $billing_values = $this->_get_billing_values_from_form($billing_info); |
|
416 | - |
|
417 | - // Offsite Gateway |
|
418 | - if ($this->_gateway instanceof EE_Offsite_Gateway) { |
|
419 | - $payment = $this->_gateway->set_redirection_info( |
|
420 | - $payment, |
|
421 | - $billing_values, |
|
422 | - $return_url, |
|
423 | - EE_Config::instance()->core->txn_page_url( |
|
424 | - array( |
|
425 | - 'e_reg_url_link' => $transaction->primary_registration()->reg_url_link(), |
|
426 | - 'ee_payment_method' => $this->_pm_instance->slug(), |
|
427 | - ) |
|
428 | - ), |
|
429 | - $fail_url |
|
430 | - ); |
|
431 | - $payment->save(); |
|
432 | - // Onsite Gateway |
|
433 | - } elseif ($this->_gateway instanceof EE_Onsite_Gateway) { |
|
434 | - $payment = $this->_gateway->do_direct_payment($payment, $billing_values); |
|
435 | - $payment->save(); |
|
436 | - } else { |
|
437 | - throw new EE_Error( |
|
438 | - sprintf( |
|
439 | - esc_html__( |
|
440 | - 'Gateway for payment method type "%s" is "%s", not a subclass of either EE_Offsite_Gateway or EE_Onsite_Gateway, or null (to indicate NO gateway)', |
|
441 | - 'event_espresso' |
|
442 | - ), |
|
443 | - get_class($this), |
|
444 | - gettype($this->_gateway) |
|
445 | - ) |
|
446 | - ); |
|
447 | - } |
|
448 | - } else { |
|
449 | - // no gateway provided |
|
450 | - // there is no payment. Must be an offline gateway |
|
451 | - // create a payment object anyways, but dont save it |
|
452 | - $payment = EE_Payment::new_instance( |
|
453 | - array( |
|
454 | - 'STS_ID' => EEM_Payment::status_id_pending, |
|
455 | - 'TXN_ID' => $transaction->ID(), |
|
456 | - 'PMD_ID' => $transaction->payment_method_ID(), |
|
457 | - 'PAY_amount' => 0.00, |
|
458 | - 'PAY_timestamp' => time(), |
|
459 | - ) |
|
460 | - ); |
|
461 | - } |
|
462 | - |
|
463 | - // if there is billing info, clean it and save it now |
|
464 | - if ($billing_info instanceof EE_Billing_Attendee_Info_Form) { |
|
465 | - $this->_save_billing_info_to_attendee($billing_info, $transaction); |
|
466 | - } |
|
467 | - |
|
468 | - return $payment; |
|
469 | - } |
|
470 | - |
|
471 | - /** |
|
472 | - * Gets the values we want to pass onto the gateway. Normally these |
|
473 | - * are just the 'pretty' values, but there may be times the data may need |
|
474 | - * a little massaging. Proper subsections will become arrays of inputs |
|
475 | - * |
|
476 | - * @param EE_Billing_Info_Form $billing_form |
|
477 | - * @return array |
|
478 | - */ |
|
479 | - protected function _get_billing_values_from_form($billing_form) |
|
480 | - { |
|
481 | - if ($billing_form instanceof EE_Form_Section_Proper) { |
|
482 | - return $billing_form->input_pretty_values(true); |
|
483 | - } else { |
|
484 | - return null; |
|
485 | - } |
|
486 | - } |
|
487 | - |
|
488 | - |
|
489 | - /** |
|
490 | - * Handles an instant payment notification when the transaction is known (by default). |
|
491 | - * |
|
492 | - * @param array $req_data |
|
493 | - * @param EE_Transaction $transaction |
|
494 | - * @return EE_Payment |
|
495 | - * @throws EE_Error |
|
496 | - */ |
|
497 | - public function handle_ipn($req_data, $transaction) |
|
498 | - { |
|
499 | - $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); |
|
500 | - if (! $this->_gateway instanceof EE_Offsite_Gateway) { |
|
501 | - throw new EE_Error( |
|
502 | - sprintf( |
|
503 | - esc_html__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"), |
|
504 | - print_r($this->_gateway, true) |
|
505 | - ) |
|
506 | - ); |
|
507 | - } |
|
508 | - $payment = $this->_gateway->handle_payment_update($req_data, $transaction); |
|
509 | - return $payment; |
|
510 | - } |
|
511 | - |
|
512 | - |
|
513 | - /** |
|
514 | - * Saves the billing info onto the attendee of the primary registrant on this transaction, and |
|
515 | - * cleans it first. |
|
516 | - * |
|
517 | - * @param EE_Billing_Attendee_Info_Form $billing_form |
|
518 | - * @param EE_Transaction $transaction |
|
519 | - * @return boolean success |
|
520 | - */ |
|
521 | - protected function _save_billing_info_to_attendee($billing_form, $transaction) |
|
522 | - { |
|
523 | - if (! $transaction || ! $transaction instanceof EE_Transaction) { |
|
524 | - EE_Error::add_error( |
|
525 | - esc_html__("Cannot save billing info because no transaction was specified", "event_espresso"), |
|
526 | - __FILE__, |
|
527 | - __FUNCTION__, |
|
528 | - __LINE__ |
|
529 | - ); |
|
530 | - return false; |
|
531 | - } |
|
532 | - $primary_reg = $transaction->primary_registration(); |
|
533 | - if (! $primary_reg) { |
|
534 | - EE_Error::add_error( |
|
535 | - esc_html__("Cannot save billing info because the transaction has no primary registration", "event_espresso"), |
|
536 | - __FILE__, |
|
537 | - __FUNCTION__, |
|
538 | - __LINE__ |
|
539 | - ); |
|
540 | - return false; |
|
541 | - } |
|
542 | - $attendee = $primary_reg->attendee(); |
|
543 | - if (! $attendee) { |
|
544 | - EE_Error::add_error( |
|
545 | - esc_html__( |
|
546 | - "Cannot save billing info because the transaction's primary registration has no attendee!", |
|
547 | - "event_espresso" |
|
548 | - ), |
|
549 | - __FILE__, |
|
550 | - __FUNCTION__, |
|
551 | - __LINE__ |
|
552 | - ); |
|
553 | - return false; |
|
554 | - } |
|
555 | - return $attendee->save_and_clean_billing_info_for_payment_method($billing_form, $transaction->payment_method()); |
|
556 | - } |
|
557 | - |
|
558 | - |
|
559 | - /** |
|
560 | - * Gets the payment this IPN is for. Children may often want to |
|
561 | - * override this to inspect the request |
|
562 | - * |
|
563 | - * @param EE_Transaction $transaction |
|
564 | - * @param array $req_data |
|
565 | - * @return EE_Payment |
|
566 | - */ |
|
567 | - protected function find_payment_for_ipn(EE_Transaction $transaction, $req_data = array()) |
|
568 | - { |
|
569 | - return $transaction->last_payment(); |
|
570 | - } |
|
571 | - |
|
572 | - |
|
573 | - /** |
|
574 | - * In case generic code cannot provide the payment processor with a specific payment method |
|
575 | - * and transaction, it will try calling this method on each activate payment method. |
|
576 | - * If the payment method is able to identify the request as being for it, it should fetch |
|
577 | - * the payment its for and return it. If not, it should throw an EE_Error to indicate it cannot |
|
578 | - * handle the IPN |
|
579 | - * |
|
580 | - * @param array $req_data |
|
581 | - * @return EE_Payment only if this payment method can find the info its needs from $req_data |
|
582 | - * and identifies the IPN as being for this payment method (not just fo ra payment method of this type) |
|
583 | - * @throws EE_Error |
|
584 | - */ |
|
585 | - public function handle_unclaimed_ipn($req_data = array()) |
|
586 | - { |
|
587 | - throw new EE_Error( |
|
588 | - sprintf(esc_html__("Payment Method '%s' cannot handle unclaimed IPNs", "event_espresso"), get_class($this)) |
|
589 | - ); |
|
590 | - } |
|
591 | - |
|
592 | - |
|
593 | - /** |
|
594 | - * Logic to be accomplished when the payment attempt is complete. |
|
595 | - * Most payment methods don't need to do anything at this point; but some, like Mijireh, do. |
|
596 | - * (Mijireh is an offsite gateway which doesn't send an IPN. So when the user returns to EE from |
|
597 | - * mijireh, this method needs to be called so the Mijireh PM can ping Mijireh to know the status |
|
598 | - * of the payment). Fed a transaction because it's always assumed to be the last payment that |
|
599 | - * we're dealing with. Returns that last payment (if there is one) |
|
600 | - * |
|
601 | - * @param EE_Transaction $transaction |
|
602 | - * @return EE_Payment |
|
603 | - */ |
|
604 | - public function finalize_payment_for($transaction) |
|
605 | - { |
|
606 | - return $transaction->last_payment(); |
|
607 | - } |
|
608 | - |
|
609 | - |
|
610 | - /** |
|
611 | - * Whether or not this payment method's gateway supports sending refund requests |
|
612 | - * |
|
613 | - * @return boolean |
|
614 | - */ |
|
615 | - public function supports_sending_refunds() |
|
616 | - { |
|
617 | - if ($this->_gateway && $this->_gateway instanceof EE_Gateway) { |
|
618 | - return $this->_gateway->supports_sending_refunds(); |
|
619 | - } else { |
|
620 | - return false; |
|
621 | - } |
|
622 | - } |
|
623 | - |
|
624 | - |
|
625 | - /** |
|
626 | - * |
|
627 | - * @param EE_Payment $payment |
|
628 | - * @param array $refund_info |
|
629 | - * @throws EE_Error |
|
630 | - * @return EE_Payment |
|
631 | - */ |
|
632 | - public function process_refund(EE_Payment $payment, $refund_info = array()) |
|
633 | - { |
|
634 | - if ($this->_gateway && $this->_gateway instanceof EE_Gateway) { |
|
635 | - return $this->_gateway->do_direct_refund($payment, $refund_info); |
|
636 | - } else { |
|
637 | - throw new EE_Error( |
|
638 | - sprintf( |
|
639 | - esc_html__('Payment Method Type "%s" does not support sending refund requests', 'event_espresso'), |
|
640 | - get_class($this) |
|
641 | - ) |
|
642 | - ); |
|
643 | - } |
|
644 | - } |
|
645 | - |
|
646 | - |
|
647 | - /** |
|
648 | - * Returns one the class's constants onsite,offsite, or offline, depending on this |
|
649 | - * payment method's gateway. |
|
650 | - * |
|
651 | - * @return string |
|
652 | - * @throws EE_Error |
|
653 | - */ |
|
654 | - public function payment_occurs() |
|
655 | - { |
|
656 | - if (! $this->_gateway) { |
|
657 | - return EE_PMT_Base::offline; |
|
658 | - } elseif ($this->_gateway instanceof EE_Onsite_Gateway) { |
|
659 | - return EE_PMT_Base::onsite; |
|
660 | - } elseif ($this->_gateway instanceof EE_Offsite_Gateway) { |
|
661 | - return EE_PMT_Base::offsite; |
|
662 | - } else { |
|
663 | - throw new EE_Error( |
|
664 | - sprintf( |
|
665 | - esc_html__( |
|
666 | - "Payment method type '%s's gateway isn't an instance of EE_Onsite_Gateway, EE_Offsite_Gateway, or null. It must be one of those", |
|
667 | - "event_espresso" |
|
668 | - ), |
|
669 | - get_class($this) |
|
670 | - ) |
|
671 | - ); |
|
672 | - } |
|
673 | - } |
|
674 | - |
|
675 | - |
|
676 | - /** |
|
677 | - * For adding any html output ab ove the payment overview. |
|
678 | - * Many gateways won't want ot display anything, so this function just returns an empty string. |
|
679 | - * Other gateways may want to override this, such as offline gateways. |
|
680 | - * |
|
681 | - * @param EE_Payment $payment |
|
682 | - * @return string |
|
683 | - */ |
|
684 | - public function payment_overview_content(EE_Payment $payment) |
|
685 | - { |
|
686 | - return EEH_Template::display_template( |
|
687 | - EE_LIBRARIES . 'payment_methods/templates/payment_details_content.template.php', |
|
688 | - array('payment_method' => $this->_pm_instance, 'payment' => $payment), |
|
689 | - true |
|
690 | - ); |
|
691 | - } |
|
692 | - |
|
693 | - |
|
694 | - /** |
|
695 | - * @return array where keys are the help tab name, |
|
696 | - * values are: array { |
|
697 | - * @type string $title i18n name for the help tab |
|
698 | - * @type string $filename name of the file located in ./help_tabs/ (ie, in a folder next to this file) |
|
699 | - * @type array $template_args any arguments you want passed to the template file while rendering. |
|
700 | - * Keys will be variable names and values with be their values. |
|
701 | - */ |
|
702 | - public function help_tabs_config() |
|
703 | - { |
|
704 | - return array(); |
|
705 | - } |
|
706 | - |
|
707 | - |
|
708 | - /** |
|
709 | - * The system name for this PMT (eg AIM, Paypal_Pro, Invoice... what gets put into |
|
710 | - * the payment method's table's PMT_type column) |
|
711 | - * |
|
712 | - * @return string |
|
713 | - */ |
|
714 | - public function system_name() |
|
715 | - { |
|
716 | - $classname = get_class($this); |
|
717 | - return str_replace("EE_PMT_", '', $classname); |
|
718 | - } |
|
719 | - |
|
720 | - |
|
721 | - /** |
|
722 | - * A pretty i18n version of the PMT name. Often the same as the "pretty_name", but you can change it by overriding |
|
723 | - * this method. |
|
724 | - * @return string |
|
725 | - */ |
|
726 | - public function defaultFrontendName() |
|
727 | - { |
|
728 | - return $this->pretty_name(); |
|
729 | - } |
|
730 | - |
|
731 | - |
|
732 | - /** |
|
733 | - * A pretty i18n version of the PMT name |
|
734 | - * |
|
735 | - * @return string |
|
736 | - */ |
|
737 | - public function pretty_name() |
|
738 | - { |
|
739 | - return $this->_pretty_name; |
|
740 | - } |
|
741 | - |
|
742 | - |
|
743 | - /** |
|
744 | - * Gets the default absolute URL to the payment method type's button |
|
745 | - * |
|
746 | - * @return string |
|
747 | - */ |
|
748 | - public function default_button_url() |
|
749 | - { |
|
750 | - return $this->_default_button_url; |
|
751 | - } |
|
752 | - |
|
753 | - |
|
754 | - /** |
|
755 | - * Gets the gateway used by this payment method (if any) |
|
756 | - * |
|
757 | - * @return EE_Gateway |
|
758 | - */ |
|
759 | - public function get_gateway() |
|
760 | - { |
|
761 | - return $this->_gateway; |
|
762 | - } |
|
763 | - |
|
764 | - |
|
765 | - /** |
|
766 | - * @return string html for the link to a help tab |
|
767 | - */ |
|
768 | - public function get_help_tab_link() |
|
769 | - { |
|
770 | - return EEH_Template::get_help_tab_link( |
|
771 | - $this->get_help_tab_name(), |
|
772 | - 'espresso_payment_settings', |
|
773 | - 'default' |
|
774 | - ); |
|
775 | - } |
|
776 | - |
|
777 | - |
|
778 | - /** |
|
779 | - * Returns the name of the help tab for this PMT |
|
780 | - * |
|
781 | - * @return string |
|
782 | - */ |
|
783 | - public function get_help_tab_name() |
|
784 | - { |
|
785 | - return 'ee_' . strtolower($this->system_name()) . '_help_tab'; |
|
786 | - } |
|
787 | - |
|
788 | - /** |
|
789 | - * The name of the wp capability that should be associated with the usage of |
|
790 | - * this PMT by an admin |
|
791 | - * |
|
792 | - * @return string |
|
793 | - */ |
|
794 | - public function cap_name() |
|
795 | - { |
|
796 | - return 'ee_payment_method_' . strtolower($this->system_name()); |
|
797 | - } |
|
798 | - |
|
799 | - /** |
|
800 | - * Called by client code to tell the gateway that if it wants to change |
|
801 | - * the transaction or line items or registrations related to teh payment it already |
|
802 | - * processed (we think, but possibly not) that now's the time to do it. |
|
803 | - * It is expected that gateways will store any info they need for this on the PAY_details, |
|
804 | - * or maybe an extra meta value |
|
805 | - * |
|
806 | - * @param EE_Payment $payment |
|
807 | - * @return void |
|
808 | - */ |
|
809 | - public function update_txn_based_on_payment($payment) |
|
810 | - { |
|
811 | - if ($this->_gateway instanceof EE_Gateway) { |
|
812 | - $this->_gateway->update_txn_based_on_payment($payment); |
|
813 | - } |
|
814 | - } |
|
815 | - |
|
816 | - /** |
|
817 | - * Returns a string of HTML describing this payment method type for an admin, |
|
818 | - * primarily intended for them to read before activating it. |
|
819 | - * The easiest way to set this is to create a folder 'templates' alongside |
|
820 | - * your EE_PMT_{System_Name} file, and in it create a file named "{system_name}_intro.template.php". |
|
821 | - * Eg, if your payment method file is named "EE_PMT_Foo_Bar.pm.php", |
|
822 | - * then you'd create a file named "templates" in the same folder as it, and name the file |
|
823 | - * "foo_bar_intro.template.php", and its content will be returned by this method |
|
824 | - * |
|
825 | - * @return string |
|
826 | - */ |
|
827 | - public function introductory_html() |
|
828 | - { |
|
829 | - return EEH_Template::locate_template( |
|
830 | - $this->file_folder() . 'templates/' . strtolower($this->system_name()) . '_intro.template.php', |
|
831 | - array('pmt_obj' => $this, 'pm_instance' => $this->_pm_instance) |
|
832 | - ); |
|
833 | - } |
|
24 | + const onsite = 'on-site'; |
|
25 | + const offsite = 'off-site'; |
|
26 | + const offline = 'off-line'; |
|
27 | + |
|
28 | + /** |
|
29 | + * @var EE_Payment_Method |
|
30 | + */ |
|
31 | + protected $_pm_instance = null; |
|
32 | + |
|
33 | + /** |
|
34 | + * @var boolean |
|
35 | + */ |
|
36 | + protected $_requires_https = false; |
|
37 | + |
|
38 | + /** |
|
39 | + * @var boolean |
|
40 | + */ |
|
41 | + protected $_has_billing_form; |
|
42 | + |
|
43 | + /** |
|
44 | + * @var EE_Gateway |
|
45 | + */ |
|
46 | + protected $_gateway = null; |
|
47 | + |
|
48 | + /** |
|
49 | + * @var EE_Payment_Method_Form |
|
50 | + */ |
|
51 | + protected $_settings_form = null; |
|
52 | + |
|
53 | + /** |
|
54 | + * @var EE_Form_Section_Proper |
|
55 | + */ |
|
56 | + protected $_billing_form = null; |
|
57 | + |
|
58 | + /** |
|
59 | + * @var boolean |
|
60 | + */ |
|
61 | + protected $_cache_billing_form = true; |
|
62 | + |
|
63 | + /** |
|
64 | + * String of the absolute path to the folder containing this file, with a trailing slash. |
|
65 | + * eg '/public_html/wp-site/wp-content/plugins/event-espresso/payment_methods/Invoice/' |
|
66 | + * |
|
67 | + * @var string |
|
68 | + */ |
|
69 | + protected $_file_folder = null; |
|
70 | + |
|
71 | + /** |
|
72 | + * String to the absolute URL to this file (useful for getting its web-accessible resources |
|
73 | + * like images, js, or css) |
|
74 | + * |
|
75 | + * @var string |
|
76 | + */ |
|
77 | + protected $_file_url = null; |
|
78 | + |
|
79 | + /** |
|
80 | + * Pretty name for the payment method |
|
81 | + * |
|
82 | + * @var string |
|
83 | + */ |
|
84 | + protected $_pretty_name = null; |
|
85 | + |
|
86 | + /** |
|
87 | + * |
|
88 | + * @var string |
|
89 | + */ |
|
90 | + protected $_default_button_url = null; |
|
91 | + |
|
92 | + /** |
|
93 | + * |
|
94 | + * @var string |
|
95 | + */ |
|
96 | + protected $_default_description = null; |
|
97 | + |
|
98 | + |
|
99 | + /** |
|
100 | + * |
|
101 | + * @param EE_Payment_Method $pm_instance |
|
102 | + * @throws EE_Error |
|
103 | + * @return EE_PMT_Base |
|
104 | + */ |
|
105 | + public function __construct($pm_instance = null) |
|
106 | + { |
|
107 | + if ($pm_instance instanceof EE_Payment_Method) { |
|
108 | + $this->set_instance($pm_instance); |
|
109 | + } |
|
110 | + if ($this->_gateway) { |
|
111 | + $this->_gateway->set_payment_model(EEM_Payment::instance()); |
|
112 | + $this->_gateway->set_payment_log(EEM_Change_Log::instance()); |
|
113 | + $this->_gateway->set_template_helper(new EEH_Template()); |
|
114 | + $this->_gateway->set_line_item_helper(new EEH_Line_Item()); |
|
115 | + $this->_gateway->set_money_helper(new EEH_Money()); |
|
116 | + $this->_gateway->set_gateway_data_formatter(new GatewayDataFormatter()); |
|
117 | + $this->_gateway->set_unsupported_character_remover(new AsciiOnly()); |
|
118 | + do_action('AHEE__EE_PMT_Base___construct__done_initializing_gateway_class', $this, $this->_gateway); |
|
119 | + } |
|
120 | + if (! isset($this->_has_billing_form)) { |
|
121 | + // by default, On Site gateways have a billing form |
|
122 | + if ($this->payment_occurs() == EE_PMT_Base::onsite) { |
|
123 | + $this->set_has_billing_form(true); |
|
124 | + } else { |
|
125 | + $this->set_has_billing_form(false); |
|
126 | + } |
|
127 | + } |
|
128 | + |
|
129 | + if (! $this->_pretty_name) { |
|
130 | + throw new EE_Error( |
|
131 | + sprintf( |
|
132 | + esc_html__( |
|
133 | + "You must set the pretty name for the Payment Method Type in the constructor (_pretty_name), and please make it internationalized", |
|
134 | + "event_espresso" |
|
135 | + ) |
|
136 | + ) |
|
137 | + ); |
|
138 | + } |
|
139 | + // if the child didn't specify a default button, use the credit card one |
|
140 | + if ($this->_default_button_url === null) { |
|
141 | + $this->_default_button_url = EE_PLUGIN_DIR_URL . 'payment_methods/pay-by-credit-card.png'; |
|
142 | + } |
|
143 | + } |
|
144 | + |
|
145 | + |
|
146 | + /** |
|
147 | + * @param boolean $has_billing_form |
|
148 | + */ |
|
149 | + public function set_has_billing_form($has_billing_form) |
|
150 | + { |
|
151 | + $this->_has_billing_form = filter_var($has_billing_form, FILTER_VALIDATE_BOOLEAN); |
|
152 | + } |
|
153 | + |
|
154 | + |
|
155 | + /** |
|
156 | + * sets the file_folder property |
|
157 | + */ |
|
158 | + protected function _set_file_folder() |
|
159 | + { |
|
160 | + $reflector = new ReflectionClass(get_class($this)); |
|
161 | + $fn = $reflector->getFileName(); |
|
162 | + $this->_file_folder = dirname($fn) . '/'; |
|
163 | + } |
|
164 | + |
|
165 | + |
|
166 | + /** |
|
167 | + * sets the file URL with a trailing slash for this PMT |
|
168 | + */ |
|
169 | + protected function _set_file_url() |
|
170 | + { |
|
171 | + $plugins_dir_fixed = str_replace('\\', '/', WP_PLUGIN_DIR); |
|
172 | + $file_folder_fixed = str_replace('\\', '/', $this->file_folder()); |
|
173 | + $file_path = str_replace($plugins_dir_fixed, WP_PLUGIN_URL, $file_folder_fixed); |
|
174 | + $this->_file_url = set_url_scheme($file_path); |
|
175 | + } |
|
176 | + |
|
177 | + /** |
|
178 | + * Gets the default description on all payment methods of this type |
|
179 | + * |
|
180 | + * @return string |
|
181 | + */ |
|
182 | + public function default_description() |
|
183 | + { |
|
184 | + return $this->_default_description; |
|
185 | + } |
|
186 | + |
|
187 | + |
|
188 | + /** |
|
189 | + * Returns the folder containing the PMT child class, with a trailing slash |
|
190 | + * |
|
191 | + * @return string |
|
192 | + */ |
|
193 | + public function file_folder() |
|
194 | + { |
|
195 | + if (! $this->_file_folder) { |
|
196 | + $this->_set_file_folder(); |
|
197 | + } |
|
198 | + return $this->_file_folder; |
|
199 | + } |
|
200 | + |
|
201 | + |
|
202 | + /** |
|
203 | + * @return string |
|
204 | + */ |
|
205 | + public function file_url() |
|
206 | + { |
|
207 | + if (! $this->_file_url) { |
|
208 | + $this->_set_file_url(); |
|
209 | + } |
|
210 | + return $this->_file_url; |
|
211 | + } |
|
212 | + |
|
213 | + |
|
214 | + /** |
|
215 | + * Sets the payment method instance this payment method type is for. |
|
216 | + * Its important teh payment method instance is set before |
|
217 | + * |
|
218 | + * @param EE_Payment_Method $payment_method_instance |
|
219 | + */ |
|
220 | + public function set_instance($payment_method_instance) |
|
221 | + { |
|
222 | + $this->_pm_instance = $payment_method_instance; |
|
223 | + // if they have already requested the settings form, make sure its |
|
224 | + // data matches this model object |
|
225 | + if ($this->_settings_form) { |
|
226 | + $this->settings_form()->populate_model_obj($payment_method_instance); |
|
227 | + } |
|
228 | + if ($this->_gateway && $this->_gateway instanceof EE_Gateway) { |
|
229 | + $this->_gateway->set_settings($payment_method_instance->settings_array()); |
|
230 | + } |
|
231 | + } |
|
232 | + |
|
233 | + |
|
234 | + /** |
|
235 | + * Gets teh form for displaying to admins where they setup the payment method |
|
236 | + * |
|
237 | + * @return EE_Payment_Method_Form |
|
238 | + */ |
|
239 | + public function settings_form() |
|
240 | + { |
|
241 | + if (! $this->_settings_form) { |
|
242 | + $this->_settings_form = $this->generate_new_settings_form(); |
|
243 | + $this->_settings_form->set_payment_method_type($this); |
|
244 | + // if we have already assigned a model object to this pmt, make |
|
245 | + // sure its reflected in teh form we just generated |
|
246 | + if ($this->_pm_instance) { |
|
247 | + $this->_settings_form->populate_model_obj($this->_pm_instance); |
|
248 | + } |
|
249 | + } |
|
250 | + return $this->_settings_form; |
|
251 | + } |
|
252 | + |
|
253 | + |
|
254 | + /** |
|
255 | + * Gets the form for all the settings related to this payment method type |
|
256 | + * |
|
257 | + * @return EE_Payment_Method_Form |
|
258 | + */ |
|
259 | + abstract public function generate_new_settings_form(); |
|
260 | + |
|
261 | + |
|
262 | + /** |
|
263 | + * Sets the form for settings. This may be useful if we have already received |
|
264 | + * a form submission and have form data it in, and want to use it anytime we're showing |
|
265 | + * this payment method type's settings form later in the request |
|
266 | + * |
|
267 | + * @param EE_Payment_Method_Form $form |
|
268 | + */ |
|
269 | + public function set_settings_form($form) |
|
270 | + { |
|
271 | + $this->_settings_form = $form; |
|
272 | + } |
|
273 | + |
|
274 | + |
|
275 | + /** |
|
276 | + * @return boolean |
|
277 | + */ |
|
278 | + public function has_billing_form() |
|
279 | + { |
|
280 | + return $this->_has_billing_form; |
|
281 | + } |
|
282 | + |
|
283 | + |
|
284 | + /** |
|
285 | + * Gets the form for displaying to attendees where they can enter their billing info |
|
286 | + * which will be sent to teh gateway (can be null) |
|
287 | + * |
|
288 | + * @param \EE_Transaction $transaction |
|
289 | + * @param array $extra_args |
|
290 | + * @return \EE_Billing_Attendee_Info_Form|\EE_Billing_Info_Form|null |
|
291 | + */ |
|
292 | + public function billing_form(EE_Transaction $transaction = null, $extra_args = array()) |
|
293 | + { |
|
294 | + // has billing form already been regenerated ? or overwrite cache? |
|
295 | + if (! $this->_billing_form instanceof EE_Billing_Info_Form || ! $this->_cache_billing_form) { |
|
296 | + $this->_billing_form = $this->generate_new_billing_form($transaction, $extra_args); |
|
297 | + } |
|
298 | + // if we know who the attendee is, and this is a billing form |
|
299 | + // that uses attendee info, populate it |
|
300 | + if ( |
|
301 | + apply_filters( |
|
302 | + 'FHEE__populate_billing_form_fields_from_attendee', |
|
303 | + ($this->_billing_form instanceof EE_Billing_Attendee_Info_Form |
|
304 | + && $transaction instanceof EE_Transaction |
|
305 | + && $transaction->primary_registration() instanceof EE_Registration |
|
306 | + && $transaction->primary_registration()->attendee() instanceof EE_Attendee |
|
307 | + ), |
|
308 | + $this->_billing_form, |
|
309 | + $transaction |
|
310 | + ) |
|
311 | + ) { |
|
312 | + $this->_billing_form->populate_from_attendee($transaction->primary_registration()->attendee()); |
|
313 | + } |
|
314 | + return $this->_billing_form; |
|
315 | + } |
|
316 | + |
|
317 | + |
|
318 | + /** |
|
319 | + * Creates the billing form for this payment method type |
|
320 | + * |
|
321 | + * @param \EE_Transaction $transaction |
|
322 | + * @return \EE_Billing_Info_Form |
|
323 | + */ |
|
324 | + abstract public function generate_new_billing_form(EE_Transaction $transaction = null); |
|
325 | + |
|
326 | + |
|
327 | + /** |
|
328 | + * apply_billing_form_debug_settings |
|
329 | + * applies debug data to the form |
|
330 | + * |
|
331 | + * @param \EE_Billing_Info_Form $billing_form |
|
332 | + * @return \EE_Billing_Info_Form |
|
333 | + */ |
|
334 | + public function apply_billing_form_debug_settings(EE_Billing_Info_Form $billing_form) |
|
335 | + { |
|
336 | + return $billing_form; |
|
337 | + } |
|
338 | + |
|
339 | + |
|
340 | + /** |
|
341 | + * Sets the billing form for this payment method type. You may want to use this |
|
342 | + * if you have form |
|
343 | + * |
|
344 | + * @param EE_Payment_Method $form |
|
345 | + */ |
|
346 | + public function set_billing_form($form) |
|
347 | + { |
|
348 | + $this->_billing_form = $form; |
|
349 | + } |
|
350 | + |
|
351 | + |
|
352 | + /** |
|
353 | + * Returns whether or not this payment method requires HTTPS to be used |
|
354 | + * |
|
355 | + * @return boolean |
|
356 | + */ |
|
357 | + public function requires_https() |
|
358 | + { |
|
359 | + return $this->_requires_https; |
|
360 | + } |
|
361 | + |
|
362 | + |
|
363 | + /** |
|
364 | + * |
|
365 | + * @param EE_Transaction $transaction |
|
366 | + * @param float $amount |
|
367 | + * @param EE_Billing_Info_Form $billing_info |
|
368 | + * @param string $return_url |
|
369 | + * @param string $fail_url |
|
370 | + * @param string $method |
|
371 | + * @param bool $by_admin |
|
372 | + * @return EE_Payment |
|
373 | + * @throws EE_Error |
|
374 | + */ |
|
375 | + public function process_payment( |
|
376 | + EE_Transaction $transaction, |
|
377 | + $amount = null, |
|
378 | + $billing_info = null, |
|
379 | + $return_url = null, |
|
380 | + $fail_url = '', |
|
381 | + $method = 'CART', |
|
382 | + $by_admin = false |
|
383 | + ) { |
|
384 | + // @todo: add surcharge for the payment method, if any |
|
385 | + if ($this->_gateway) { |
|
386 | + // there is a gateway, so we're going to make a payment object |
|
387 | + // but wait! do they already have a payment in progress that we thought was failed? |
|
388 | + $duplicate_properties = array( |
|
389 | + 'STS_ID' => EEM_Payment::status_id_failed, |
|
390 | + 'TXN_ID' => $transaction->ID(), |
|
391 | + 'PMD_ID' => $this->_pm_instance->ID(), |
|
392 | + 'PAY_source' => $method, |
|
393 | + 'PAY_amount' => $amount !== null ? $amount : $transaction->remaining(), |
|
394 | + 'PAY_gateway_response' => null, |
|
395 | + ); |
|
396 | + $payment = EEM_Payment::instance()->get_one(array($duplicate_properties)); |
|
397 | + // if we didn't already have a payment in progress for the same thing, |
|
398 | + // then we actually want to make a new payment |
|
399 | + if (! $payment instanceof EE_Payment) { |
|
400 | + $payment = EE_Payment::new_instance( |
|
401 | + array_merge( |
|
402 | + $duplicate_properties, |
|
403 | + array( |
|
404 | + 'PAY_timestamp' => time(), |
|
405 | + 'PAY_txn_id_chq_nmbr' => null, |
|
406 | + 'PAY_po_number' => null, |
|
407 | + 'PAY_extra_accntng' => null, |
|
408 | + 'PAY_details' => null, |
|
409 | + ) |
|
410 | + ) |
|
411 | + ); |
|
412 | + } |
|
413 | + // make sure the payment has been saved to show we started it, and so it has an ID should the gateway try to log it |
|
414 | + $payment->save(); |
|
415 | + $billing_values = $this->_get_billing_values_from_form($billing_info); |
|
416 | + |
|
417 | + // Offsite Gateway |
|
418 | + if ($this->_gateway instanceof EE_Offsite_Gateway) { |
|
419 | + $payment = $this->_gateway->set_redirection_info( |
|
420 | + $payment, |
|
421 | + $billing_values, |
|
422 | + $return_url, |
|
423 | + EE_Config::instance()->core->txn_page_url( |
|
424 | + array( |
|
425 | + 'e_reg_url_link' => $transaction->primary_registration()->reg_url_link(), |
|
426 | + 'ee_payment_method' => $this->_pm_instance->slug(), |
|
427 | + ) |
|
428 | + ), |
|
429 | + $fail_url |
|
430 | + ); |
|
431 | + $payment->save(); |
|
432 | + // Onsite Gateway |
|
433 | + } elseif ($this->_gateway instanceof EE_Onsite_Gateway) { |
|
434 | + $payment = $this->_gateway->do_direct_payment($payment, $billing_values); |
|
435 | + $payment->save(); |
|
436 | + } else { |
|
437 | + throw new EE_Error( |
|
438 | + sprintf( |
|
439 | + esc_html__( |
|
440 | + 'Gateway for payment method type "%s" is "%s", not a subclass of either EE_Offsite_Gateway or EE_Onsite_Gateway, or null (to indicate NO gateway)', |
|
441 | + 'event_espresso' |
|
442 | + ), |
|
443 | + get_class($this), |
|
444 | + gettype($this->_gateway) |
|
445 | + ) |
|
446 | + ); |
|
447 | + } |
|
448 | + } else { |
|
449 | + // no gateway provided |
|
450 | + // there is no payment. Must be an offline gateway |
|
451 | + // create a payment object anyways, but dont save it |
|
452 | + $payment = EE_Payment::new_instance( |
|
453 | + array( |
|
454 | + 'STS_ID' => EEM_Payment::status_id_pending, |
|
455 | + 'TXN_ID' => $transaction->ID(), |
|
456 | + 'PMD_ID' => $transaction->payment_method_ID(), |
|
457 | + 'PAY_amount' => 0.00, |
|
458 | + 'PAY_timestamp' => time(), |
|
459 | + ) |
|
460 | + ); |
|
461 | + } |
|
462 | + |
|
463 | + // if there is billing info, clean it and save it now |
|
464 | + if ($billing_info instanceof EE_Billing_Attendee_Info_Form) { |
|
465 | + $this->_save_billing_info_to_attendee($billing_info, $transaction); |
|
466 | + } |
|
467 | + |
|
468 | + return $payment; |
|
469 | + } |
|
470 | + |
|
471 | + /** |
|
472 | + * Gets the values we want to pass onto the gateway. Normally these |
|
473 | + * are just the 'pretty' values, but there may be times the data may need |
|
474 | + * a little massaging. Proper subsections will become arrays of inputs |
|
475 | + * |
|
476 | + * @param EE_Billing_Info_Form $billing_form |
|
477 | + * @return array |
|
478 | + */ |
|
479 | + protected function _get_billing_values_from_form($billing_form) |
|
480 | + { |
|
481 | + if ($billing_form instanceof EE_Form_Section_Proper) { |
|
482 | + return $billing_form->input_pretty_values(true); |
|
483 | + } else { |
|
484 | + return null; |
|
485 | + } |
|
486 | + } |
|
487 | + |
|
488 | + |
|
489 | + /** |
|
490 | + * Handles an instant payment notification when the transaction is known (by default). |
|
491 | + * |
|
492 | + * @param array $req_data |
|
493 | + * @param EE_Transaction $transaction |
|
494 | + * @return EE_Payment |
|
495 | + * @throws EE_Error |
|
496 | + */ |
|
497 | + public function handle_ipn($req_data, $transaction) |
|
498 | + { |
|
499 | + $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction); |
|
500 | + if (! $this->_gateway instanceof EE_Offsite_Gateway) { |
|
501 | + throw new EE_Error( |
|
502 | + sprintf( |
|
503 | + esc_html__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"), |
|
504 | + print_r($this->_gateway, true) |
|
505 | + ) |
|
506 | + ); |
|
507 | + } |
|
508 | + $payment = $this->_gateway->handle_payment_update($req_data, $transaction); |
|
509 | + return $payment; |
|
510 | + } |
|
511 | + |
|
512 | + |
|
513 | + /** |
|
514 | + * Saves the billing info onto the attendee of the primary registrant on this transaction, and |
|
515 | + * cleans it first. |
|
516 | + * |
|
517 | + * @param EE_Billing_Attendee_Info_Form $billing_form |
|
518 | + * @param EE_Transaction $transaction |
|
519 | + * @return boolean success |
|
520 | + */ |
|
521 | + protected function _save_billing_info_to_attendee($billing_form, $transaction) |
|
522 | + { |
|
523 | + if (! $transaction || ! $transaction instanceof EE_Transaction) { |
|
524 | + EE_Error::add_error( |
|
525 | + esc_html__("Cannot save billing info because no transaction was specified", "event_espresso"), |
|
526 | + __FILE__, |
|
527 | + __FUNCTION__, |
|
528 | + __LINE__ |
|
529 | + ); |
|
530 | + return false; |
|
531 | + } |
|
532 | + $primary_reg = $transaction->primary_registration(); |
|
533 | + if (! $primary_reg) { |
|
534 | + EE_Error::add_error( |
|
535 | + esc_html__("Cannot save billing info because the transaction has no primary registration", "event_espresso"), |
|
536 | + __FILE__, |
|
537 | + __FUNCTION__, |
|
538 | + __LINE__ |
|
539 | + ); |
|
540 | + return false; |
|
541 | + } |
|
542 | + $attendee = $primary_reg->attendee(); |
|
543 | + if (! $attendee) { |
|
544 | + EE_Error::add_error( |
|
545 | + esc_html__( |
|
546 | + "Cannot save billing info because the transaction's primary registration has no attendee!", |
|
547 | + "event_espresso" |
|
548 | + ), |
|
549 | + __FILE__, |
|
550 | + __FUNCTION__, |
|
551 | + __LINE__ |
|
552 | + ); |
|
553 | + return false; |
|
554 | + } |
|
555 | + return $attendee->save_and_clean_billing_info_for_payment_method($billing_form, $transaction->payment_method()); |
|
556 | + } |
|
557 | + |
|
558 | + |
|
559 | + /** |
|
560 | + * Gets the payment this IPN is for. Children may often want to |
|
561 | + * override this to inspect the request |
|
562 | + * |
|
563 | + * @param EE_Transaction $transaction |
|
564 | + * @param array $req_data |
|
565 | + * @return EE_Payment |
|
566 | + */ |
|
567 | + protected function find_payment_for_ipn(EE_Transaction $transaction, $req_data = array()) |
|
568 | + { |
|
569 | + return $transaction->last_payment(); |
|
570 | + } |
|
571 | + |
|
572 | + |
|
573 | + /** |
|
574 | + * In case generic code cannot provide the payment processor with a specific payment method |
|
575 | + * and transaction, it will try calling this method on each activate payment method. |
|
576 | + * If the payment method is able to identify the request as being for it, it should fetch |
|
577 | + * the payment its for and return it. If not, it should throw an EE_Error to indicate it cannot |
|
578 | + * handle the IPN |
|
579 | + * |
|
580 | + * @param array $req_data |
|
581 | + * @return EE_Payment only if this payment method can find the info its needs from $req_data |
|
582 | + * and identifies the IPN as being for this payment method (not just fo ra payment method of this type) |
|
583 | + * @throws EE_Error |
|
584 | + */ |
|
585 | + public function handle_unclaimed_ipn($req_data = array()) |
|
586 | + { |
|
587 | + throw new EE_Error( |
|
588 | + sprintf(esc_html__("Payment Method '%s' cannot handle unclaimed IPNs", "event_espresso"), get_class($this)) |
|
589 | + ); |
|
590 | + } |
|
591 | + |
|
592 | + |
|
593 | + /** |
|
594 | + * Logic to be accomplished when the payment attempt is complete. |
|
595 | + * Most payment methods don't need to do anything at this point; but some, like Mijireh, do. |
|
596 | + * (Mijireh is an offsite gateway which doesn't send an IPN. So when the user returns to EE from |
|
597 | + * mijireh, this method needs to be called so the Mijireh PM can ping Mijireh to know the status |
|
598 | + * of the payment). Fed a transaction because it's always assumed to be the last payment that |
|
599 | + * we're dealing with. Returns that last payment (if there is one) |
|
600 | + * |
|
601 | + * @param EE_Transaction $transaction |
|
602 | + * @return EE_Payment |
|
603 | + */ |
|
604 | + public function finalize_payment_for($transaction) |
|
605 | + { |
|
606 | + return $transaction->last_payment(); |
|
607 | + } |
|
608 | + |
|
609 | + |
|
610 | + /** |
|
611 | + * Whether or not this payment method's gateway supports sending refund requests |
|
612 | + * |
|
613 | + * @return boolean |
|
614 | + */ |
|
615 | + public function supports_sending_refunds() |
|
616 | + { |
|
617 | + if ($this->_gateway && $this->_gateway instanceof EE_Gateway) { |
|
618 | + return $this->_gateway->supports_sending_refunds(); |
|
619 | + } else { |
|
620 | + return false; |
|
621 | + } |
|
622 | + } |
|
623 | + |
|
624 | + |
|
625 | + /** |
|
626 | + * |
|
627 | + * @param EE_Payment $payment |
|
628 | + * @param array $refund_info |
|
629 | + * @throws EE_Error |
|
630 | + * @return EE_Payment |
|
631 | + */ |
|
632 | + public function process_refund(EE_Payment $payment, $refund_info = array()) |
|
633 | + { |
|
634 | + if ($this->_gateway && $this->_gateway instanceof EE_Gateway) { |
|
635 | + return $this->_gateway->do_direct_refund($payment, $refund_info); |
|
636 | + } else { |
|
637 | + throw new EE_Error( |
|
638 | + sprintf( |
|
639 | + esc_html__('Payment Method Type "%s" does not support sending refund requests', 'event_espresso'), |
|
640 | + get_class($this) |
|
641 | + ) |
|
642 | + ); |
|
643 | + } |
|
644 | + } |
|
645 | + |
|
646 | + |
|
647 | + /** |
|
648 | + * Returns one the class's constants onsite,offsite, or offline, depending on this |
|
649 | + * payment method's gateway. |
|
650 | + * |
|
651 | + * @return string |
|
652 | + * @throws EE_Error |
|
653 | + */ |
|
654 | + public function payment_occurs() |
|
655 | + { |
|
656 | + if (! $this->_gateway) { |
|
657 | + return EE_PMT_Base::offline; |
|
658 | + } elseif ($this->_gateway instanceof EE_Onsite_Gateway) { |
|
659 | + return EE_PMT_Base::onsite; |
|
660 | + } elseif ($this->_gateway instanceof EE_Offsite_Gateway) { |
|
661 | + return EE_PMT_Base::offsite; |
|
662 | + } else { |
|
663 | + throw new EE_Error( |
|
664 | + sprintf( |
|
665 | + esc_html__( |
|
666 | + "Payment method type '%s's gateway isn't an instance of EE_Onsite_Gateway, EE_Offsite_Gateway, or null. It must be one of those", |
|
667 | + "event_espresso" |
|
668 | + ), |
|
669 | + get_class($this) |
|
670 | + ) |
|
671 | + ); |
|
672 | + } |
|
673 | + } |
|
674 | + |
|
675 | + |
|
676 | + /** |
|
677 | + * For adding any html output ab ove the payment overview. |
|
678 | + * Many gateways won't want ot display anything, so this function just returns an empty string. |
|
679 | + * Other gateways may want to override this, such as offline gateways. |
|
680 | + * |
|
681 | + * @param EE_Payment $payment |
|
682 | + * @return string |
|
683 | + */ |
|
684 | + public function payment_overview_content(EE_Payment $payment) |
|
685 | + { |
|
686 | + return EEH_Template::display_template( |
|
687 | + EE_LIBRARIES . 'payment_methods/templates/payment_details_content.template.php', |
|
688 | + array('payment_method' => $this->_pm_instance, 'payment' => $payment), |
|
689 | + true |
|
690 | + ); |
|
691 | + } |
|
692 | + |
|
693 | + |
|
694 | + /** |
|
695 | + * @return array where keys are the help tab name, |
|
696 | + * values are: array { |
|
697 | + * @type string $title i18n name for the help tab |
|
698 | + * @type string $filename name of the file located in ./help_tabs/ (ie, in a folder next to this file) |
|
699 | + * @type array $template_args any arguments you want passed to the template file while rendering. |
|
700 | + * Keys will be variable names and values with be their values. |
|
701 | + */ |
|
702 | + public function help_tabs_config() |
|
703 | + { |
|
704 | + return array(); |
|
705 | + } |
|
706 | + |
|
707 | + |
|
708 | + /** |
|
709 | + * The system name for this PMT (eg AIM, Paypal_Pro, Invoice... what gets put into |
|
710 | + * the payment method's table's PMT_type column) |
|
711 | + * |
|
712 | + * @return string |
|
713 | + */ |
|
714 | + public function system_name() |
|
715 | + { |
|
716 | + $classname = get_class($this); |
|
717 | + return str_replace("EE_PMT_", '', $classname); |
|
718 | + } |
|
719 | + |
|
720 | + |
|
721 | + /** |
|
722 | + * A pretty i18n version of the PMT name. Often the same as the "pretty_name", but you can change it by overriding |
|
723 | + * this method. |
|
724 | + * @return string |
|
725 | + */ |
|
726 | + public function defaultFrontendName() |
|
727 | + { |
|
728 | + return $this->pretty_name(); |
|
729 | + } |
|
730 | + |
|
731 | + |
|
732 | + /** |
|
733 | + * A pretty i18n version of the PMT name |
|
734 | + * |
|
735 | + * @return string |
|
736 | + */ |
|
737 | + public function pretty_name() |
|
738 | + { |
|
739 | + return $this->_pretty_name; |
|
740 | + } |
|
741 | + |
|
742 | + |
|
743 | + /** |
|
744 | + * Gets the default absolute URL to the payment method type's button |
|
745 | + * |
|
746 | + * @return string |
|
747 | + */ |
|
748 | + public function default_button_url() |
|
749 | + { |
|
750 | + return $this->_default_button_url; |
|
751 | + } |
|
752 | + |
|
753 | + |
|
754 | + /** |
|
755 | + * Gets the gateway used by this payment method (if any) |
|
756 | + * |
|
757 | + * @return EE_Gateway |
|
758 | + */ |
|
759 | + public function get_gateway() |
|
760 | + { |
|
761 | + return $this->_gateway; |
|
762 | + } |
|
763 | + |
|
764 | + |
|
765 | + /** |
|
766 | + * @return string html for the link to a help tab |
|
767 | + */ |
|
768 | + public function get_help_tab_link() |
|
769 | + { |
|
770 | + return EEH_Template::get_help_tab_link( |
|
771 | + $this->get_help_tab_name(), |
|
772 | + 'espresso_payment_settings', |
|
773 | + 'default' |
|
774 | + ); |
|
775 | + } |
|
776 | + |
|
777 | + |
|
778 | + /** |
|
779 | + * Returns the name of the help tab for this PMT |
|
780 | + * |
|
781 | + * @return string |
|
782 | + */ |
|
783 | + public function get_help_tab_name() |
|
784 | + { |
|
785 | + return 'ee_' . strtolower($this->system_name()) . '_help_tab'; |
|
786 | + } |
|
787 | + |
|
788 | + /** |
|
789 | + * The name of the wp capability that should be associated with the usage of |
|
790 | + * this PMT by an admin |
|
791 | + * |
|
792 | + * @return string |
|
793 | + */ |
|
794 | + public function cap_name() |
|
795 | + { |
|
796 | + return 'ee_payment_method_' . strtolower($this->system_name()); |
|
797 | + } |
|
798 | + |
|
799 | + /** |
|
800 | + * Called by client code to tell the gateway that if it wants to change |
|
801 | + * the transaction or line items or registrations related to teh payment it already |
|
802 | + * processed (we think, but possibly not) that now's the time to do it. |
|
803 | + * It is expected that gateways will store any info they need for this on the PAY_details, |
|
804 | + * or maybe an extra meta value |
|
805 | + * |
|
806 | + * @param EE_Payment $payment |
|
807 | + * @return void |
|
808 | + */ |
|
809 | + public function update_txn_based_on_payment($payment) |
|
810 | + { |
|
811 | + if ($this->_gateway instanceof EE_Gateway) { |
|
812 | + $this->_gateway->update_txn_based_on_payment($payment); |
|
813 | + } |
|
814 | + } |
|
815 | + |
|
816 | + /** |
|
817 | + * Returns a string of HTML describing this payment method type for an admin, |
|
818 | + * primarily intended for them to read before activating it. |
|
819 | + * The easiest way to set this is to create a folder 'templates' alongside |
|
820 | + * your EE_PMT_{System_Name} file, and in it create a file named "{system_name}_intro.template.php". |
|
821 | + * Eg, if your payment method file is named "EE_PMT_Foo_Bar.pm.php", |
|
822 | + * then you'd create a file named "templates" in the same folder as it, and name the file |
|
823 | + * "foo_bar_intro.template.php", and its content will be returned by this method |
|
824 | + * |
|
825 | + * @return string |
|
826 | + */ |
|
827 | + public function introductory_html() |
|
828 | + { |
|
829 | + return EEH_Template::locate_template( |
|
830 | + $this->file_folder() . 'templates/' . strtolower($this->system_name()) . '_intro.template.php', |
|
831 | + array('pmt_obj' => $this, 'pm_instance' => $this->_pm_instance) |
|
832 | + ); |
|
833 | + } |
|
834 | 834 | } |
@@ -50,7 +50,7 @@ discard block |
||
50 | 50 | */ |
51 | 51 | public function getModelVersionInfo() |
52 | 52 | { |
53 | - if (! $this->model_version_info) { |
|
53 | + if ( ! $this->model_version_info) { |
|
54 | 54 | throw new EE_Error( |
55 | 55 | sprintf( |
56 | 56 | esc_html__( |
@@ -95,7 +95,7 @@ discard block |
||
95 | 95 | */ |
96 | 96 | protected function validateModel($model_name) |
97 | 97 | { |
98 | - if (! $this->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
98 | + if ( ! $this->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
99 | 99 | throw new RestException( |
100 | 100 | 'endpoint_parsing_error', |
101 | 101 | sprintf( |
@@ -18,95 +18,95 @@ |
||
18 | 18 | */ |
19 | 19 | class Base extends Controller_Base |
20 | 20 | { |
21 | - /** |
|
22 | - * Holds reference to the model version info, which knows the requested version |
|
23 | - * |
|
24 | - * @var ModelVersionInfo |
|
25 | - */ |
|
26 | - protected $model_version_info; |
|
21 | + /** |
|
22 | + * Holds reference to the model version info, which knows the requested version |
|
23 | + * |
|
24 | + * @var ModelVersionInfo |
|
25 | + */ |
|
26 | + protected $model_version_info; |
|
27 | 27 | |
28 | 28 | |
29 | 29 | |
30 | - /** |
|
31 | - * Sets the version the user requested |
|
32 | - * |
|
33 | - * @param string $version eg '4.8' |
|
34 | - */ |
|
35 | - public function setRequestedVersion($version) |
|
36 | - { |
|
37 | - parent::setRequestedVersion($version); |
|
38 | - $this->model_version_info = new ModelVersionInfo($version); |
|
39 | - } |
|
30 | + /** |
|
31 | + * Sets the version the user requested |
|
32 | + * |
|
33 | + * @param string $version eg '4.8' |
|
34 | + */ |
|
35 | + public function setRequestedVersion($version) |
|
36 | + { |
|
37 | + parent::setRequestedVersion($version); |
|
38 | + $this->model_version_info = new ModelVersionInfo($version); |
|
39 | + } |
|
40 | 40 | |
41 | 41 | |
42 | 42 | |
43 | - /** |
|
44 | - * Gets the object that should be used for getting any info from the models, |
|
45 | - * because it's takes the requested and current core version into account |
|
46 | - * |
|
47 | - * @return \EventEspresso\core\libraries\rest_api\ModelVersionInfo |
|
48 | - * @throws EE_Error |
|
49 | - */ |
|
50 | - public function getModelVersionInfo() |
|
51 | - { |
|
52 | - if (! $this->model_version_info) { |
|
53 | - throw new EE_Error( |
|
54 | - sprintf( |
|
55 | - esc_html__( |
|
56 | - 'Cannot use model version info before setting the requested version in the controller', |
|
57 | - 'event_espresso' |
|
58 | - ) |
|
59 | - ) |
|
60 | - ); |
|
61 | - } |
|
62 | - return $this->model_version_info; |
|
63 | - } |
|
43 | + /** |
|
44 | + * Gets the object that should be used for getting any info from the models, |
|
45 | + * because it's takes the requested and current core version into account |
|
46 | + * |
|
47 | + * @return \EventEspresso\core\libraries\rest_api\ModelVersionInfo |
|
48 | + * @throws EE_Error |
|
49 | + */ |
|
50 | + public function getModelVersionInfo() |
|
51 | + { |
|
52 | + if (! $this->model_version_info) { |
|
53 | + throw new EE_Error( |
|
54 | + sprintf( |
|
55 | + esc_html__( |
|
56 | + 'Cannot use model version info before setting the requested version in the controller', |
|
57 | + 'event_espresso' |
|
58 | + ) |
|
59 | + ) |
|
60 | + ); |
|
61 | + } |
|
62 | + return $this->model_version_info; |
|
63 | + } |
|
64 | 64 | |
65 | 65 | |
66 | 66 | |
67 | - /** |
|
68 | - * Determines if $object is of one of the classes of $classes. Similar to |
|
69 | - * in_array(), except this checks if $object is a subclass of the classnames provided |
|
70 | - * in $classnames |
|
71 | - * |
|
72 | - * @param object $object |
|
73 | - * @param array $classnames |
|
74 | - * @return boolean |
|
75 | - */ |
|
76 | - public function isSubclassOfOne($object, $classnames) |
|
77 | - { |
|
78 | - foreach ($classnames as $classname) { |
|
79 | - if (is_a($object, $classname)) { |
|
80 | - return true; |
|
81 | - } |
|
82 | - } |
|
83 | - return false; |
|
84 | - } |
|
67 | + /** |
|
68 | + * Determines if $object is of one of the classes of $classes. Similar to |
|
69 | + * in_array(), except this checks if $object is a subclass of the classnames provided |
|
70 | + * in $classnames |
|
71 | + * |
|
72 | + * @param object $object |
|
73 | + * @param array $classnames |
|
74 | + * @return boolean |
|
75 | + */ |
|
76 | + public function isSubclassOfOne($object, $classnames) |
|
77 | + { |
|
78 | + foreach ($classnames as $classname) { |
|
79 | + if (is_a($object, $classname)) { |
|
80 | + return true; |
|
81 | + } |
|
82 | + } |
|
83 | + return false; |
|
84 | + } |
|
85 | 85 | |
86 | - /** |
|
87 | - * Verifies the model name provided was valid. If so, returns the model (as an object). Otherwise, throws an |
|
88 | - * exception. Must be called after `setRequestedVersion()`. |
|
89 | - * @since 4.9.76.p |
|
90 | - * @param $model_name |
|
91 | - * @return EEM_Base |
|
92 | - * @throws EE_Error |
|
93 | - * @throws RestException |
|
94 | - */ |
|
95 | - protected function validateModel($model_name) |
|
96 | - { |
|
97 | - if (! $this->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
98 | - throw new RestException( |
|
99 | - 'endpoint_parsing_error', |
|
100 | - sprintf( |
|
101 | - esc_html__( |
|
102 | - 'There is no model for endpoint %s. Please contact event espresso support', |
|
103 | - 'event_espresso' |
|
104 | - ), |
|
105 | - $model_name |
|
106 | - ) |
|
107 | - ); |
|
108 | - } |
|
109 | - return $this->getModelVersionInfo()->loadModel($model_name); |
|
110 | - } |
|
86 | + /** |
|
87 | + * Verifies the model name provided was valid. If so, returns the model (as an object). Otherwise, throws an |
|
88 | + * exception. Must be called after `setRequestedVersion()`. |
|
89 | + * @since 4.9.76.p |
|
90 | + * @param $model_name |
|
91 | + * @return EEM_Base |
|
92 | + * @throws EE_Error |
|
93 | + * @throws RestException |
|
94 | + */ |
|
95 | + protected function validateModel($model_name) |
|
96 | + { |
|
97 | + if (! $this->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
98 | + throw new RestException( |
|
99 | + 'endpoint_parsing_error', |
|
100 | + sprintf( |
|
101 | + esc_html__( |
|
102 | + 'There is no model for endpoint %s. Please contact event espresso support', |
|
103 | + 'event_espresso' |
|
104 | + ), |
|
105 | + $model_name |
|
106 | + ) |
|
107 | + ); |
|
108 | + } |
|
109 | + return $this->getModelVersionInfo()->loadModel($model_name); |
|
110 | + } |
|
111 | 111 | } |
112 | 112 | // End of file Base.php |
@@ -86,7 +86,7 @@ discard block |
||
86 | 86 | LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
87 | 87 | try { |
88 | 88 | $controller->setRequestedVersion($version); |
89 | - if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
89 | + if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
90 | 90 | return $controller->sendResponse( |
91 | 91 | new WP_Error( |
92 | 92 | 'endpoint_parsing_error', |
@@ -128,7 +128,7 @@ discard block |
||
128 | 128 | LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
129 | 129 | try { |
130 | 130 | $controller->setRequestedVersion($version); |
131 | - if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
131 | + if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
132 | 132 | return []; |
133 | 133 | } |
134 | 134 | // get the model for this version |
@@ -192,11 +192,11 @@ discard block |
||
192 | 192 | */ |
193 | 193 | protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema) |
194 | 194 | { |
195 | - if (isset($schema['properties'][ $field_name ]['default'])) { |
|
196 | - if (is_array($schema['properties'][ $field_name ]['default'])) { |
|
197 | - foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) { |
|
195 | + if (isset($schema['properties'][$field_name]['default'])) { |
|
196 | + if (is_array($schema['properties'][$field_name]['default'])) { |
|
197 | + foreach ($schema['properties'][$field_name]['default'] as $default_key => $default_value) { |
|
198 | 198 | if ($default_key === 'raw') { |
199 | - $schema['properties'][ $field_name ]['default'][ $default_key ] = |
|
199 | + $schema['properties'][$field_name]['default'][$default_key] = |
|
200 | 200 | ModelDataTranslator::prepareFieldValueForJson( |
201 | 201 | $field, |
202 | 202 | $default_value, |
@@ -205,9 +205,9 @@ discard block |
||
205 | 205 | } |
206 | 206 | } |
207 | 207 | } else { |
208 | - $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson( |
|
208 | + $schema['properties'][$field_name]['default'] = ModelDataTranslator::prepareFieldValueForJson( |
|
209 | 209 | $field, |
210 | - $schema['properties'][ $field_name ]['default'], |
|
210 | + $schema['properties'][$field_name]['default'], |
|
211 | 211 | $this->getModelVersionInfo()->requestedVersion() |
212 | 212 | ); |
213 | 213 | } |
@@ -229,9 +229,9 @@ discard block |
||
229 | 229 | protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema) |
230 | 230 | { |
231 | 231 | if ($field instanceof EE_Datetime_Field) { |
232 | - $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema(); |
|
232 | + $schema['properties'][$field_name.'_gmt'] = $field->getSchema(); |
|
233 | 233 | // modify the description |
234 | - $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf( |
|
234 | + $schema['properties'][$field_name.'_gmt']['description'] = sprintf( |
|
235 | 235 | esc_html__('%s - the value for this field is in GMT.', 'event_espresso'), |
236 | 236 | wp_specialchars_decode($field->get_nicename(), ENT_QUOTES) |
237 | 237 | ); |
@@ -280,7 +280,7 @@ discard block |
||
280 | 280 | LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
281 | 281 | try { |
282 | 282 | $controller->setRequestedVersion($version); |
283 | - if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
283 | + if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
284 | 284 | return $controller->sendResponse( |
285 | 285 | new WP_Error( |
286 | 286 | 'endpoint_parsing_error', |
@@ -360,7 +360,7 @@ discard block |
||
360 | 360 | public function getEntitiesFromModel($model, $request) |
361 | 361 | { |
362 | 362 | $query_params = $this->createModelQueryParams($model, $request->get_params()); |
363 | - if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) { |
|
363 | + if ( ! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) { |
|
364 | 364 | $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name()); |
365 | 365 | throw new RestException( |
366 | 366 | sprintf('rest_%s_cannot_list', $model_name_plural), |
@@ -372,7 +372,7 @@ discard block |
||
372 | 372 | ['status' => 403] |
373 | 373 | ); |
374 | 374 | } |
375 | - if (! $request->get_header('no_rest_headers')) { |
|
375 | + if ( ! $request->get_header('no_rest_headers')) { |
|
376 | 376 | $this->setHeadersFromQueryParams($model, $query_params); |
377 | 377 | } |
378 | 378 | /** @type array $results */ |
@@ -413,7 +413,7 @@ discard block |
||
413 | 413 | $context = $this->validateContext($request->get_param('caps')); |
414 | 414 | $model = $relation->get_this_model(); |
415 | 415 | $related_model = $relation->get_other_model(); |
416 | - if (! isset($primary_model_query_params[0])) { |
|
416 | + if ( ! isset($primary_model_query_params[0])) { |
|
417 | 417 | $primary_model_query_params[0] = []; |
418 | 418 | } |
419 | 419 | // check if they can access the 1st model object |
@@ -477,13 +477,13 @@ discard block |
||
477 | 477 | ); |
478 | 478 | $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params()); |
479 | 479 | foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) { |
480 | - $query_params[0][ $relation->get_this_model()->get_this_model_name() |
|
480 | + $query_params[0][$relation->get_this_model()->get_this_model_name() |
|
481 | 481 | . '.' |
482 | - . $where_condition_key ] = $where_condition_value; |
|
482 | + . $where_condition_key] = $where_condition_value; |
|
483 | 483 | } |
484 | 484 | $query_params['default_where_conditions'] = 'none'; |
485 | 485 | $query_params['caps'] = $context; |
486 | - if (! $request->get_header('no_rest_headers')) { |
|
486 | + if ( ! $request->get_header('no_rest_headers')) { |
|
487 | 487 | $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params); |
488 | 488 | } |
489 | 489 | /** @type array $results */ |
@@ -503,7 +503,7 @@ discard block |
||
503 | 503 | $result, |
504 | 504 | $request |
505 | 505 | ); |
506 | - $joined_result = array_merge($join_model_result, $nice_result); |
|
506 | + $joined_result = array_merge($join_model_result, $nice_result); |
|
507 | 507 | // but keep the meta stuff from the main model |
508 | 508 | if (isset($nice_result['meta'])) { |
509 | 509 | $joined_result['meta'] = $nice_result['meta']; |
@@ -535,7 +535,7 @@ discard block |
||
535 | 535 | */ |
536 | 536 | public function getEntitiesFromRelation($id, $relation, $request) |
537 | 537 | { |
538 | - if (! $relation->get_this_model()->has_primary_key_field()) { |
|
538 | + if ( ! $relation->get_this_model()->has_primary_key_field()) { |
|
539 | 539 | throw new EE_Error( |
540 | 540 | sprintf( |
541 | 541 | esc_html__( |
@@ -582,7 +582,7 @@ discard block |
||
582 | 582 | Capabilities::getMissingPermissionsString($model, $query_params['caps']) |
583 | 583 | ); |
584 | 584 | // normally the limit to a 2-part array, where the 2nd item is the limit |
585 | - if (! isset($query_params['limit'])) { |
|
585 | + if ( ! isset($query_params['limit'])) { |
|
586 | 586 | $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit(); |
587 | 587 | } |
588 | 588 | if (is_array($query_params['limit'])) { |
@@ -621,7 +621,7 @@ discard block |
||
621 | 621 | */ |
622 | 622 | public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null) |
623 | 623 | { |
624 | - if (! $rest_request instanceof WP_REST_Request) { |
|
624 | + if ( ! $rest_request instanceof WP_REST_Request) { |
|
625 | 625 | // ok so this was called in the old style, where the 3rd arg was |
626 | 626 | // $include, and the 4th arg was $context |
627 | 627 | // now setup the request just to avoid fatal errors, although we won't be able |
@@ -698,7 +698,7 @@ discard block |
||
698 | 698 | $rest_request, |
699 | 699 | $this |
700 | 700 | ); |
701 | - if (! $current_user_full_access_to_entity) { |
|
701 | + if ( ! $current_user_full_access_to_entity) { |
|
702 | 702 | $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields( |
703 | 703 | $entity_array, |
704 | 704 | $model, |
@@ -733,7 +733,7 @@ discard block |
||
733 | 733 | */ |
734 | 734 | protected function addProtectedProperty(EEM_Base $model, $results_so_far, $protected) |
735 | 735 | { |
736 | - if (! $model->hasPassword() || ! $protected) { |
|
736 | + if ( ! $model->hasPassword() || ! $protected) { |
|
737 | 737 | return $results_so_far; |
738 | 738 | } |
739 | 739 | $password_field = $model->getPasswordField(); |
@@ -782,8 +782,8 @@ discard block |
||
782 | 782 | if ($do_chevy_shuffle) { |
783 | 783 | global $post; |
784 | 784 | $old_post = $post; |
785 | - $post = get_post($result[ $model->primary_key_name() ]); |
|
786 | - if (! $post instanceof WP_Post) { |
|
785 | + $post = get_post($result[$model->primary_key_name()]); |
|
786 | + if ( ! $post instanceof WP_Post) { |
|
787 | 787 | // well that's weird, because $result is what we JUST fetched from the database |
788 | 788 | throw new RestException( |
789 | 789 | 'error_fetching_post_from_database_results', |
@@ -793,7 +793,7 @@ discard block |
||
793 | 793 | ) |
794 | 794 | ); |
795 | 795 | } |
796 | - $model_object_classname = 'EE_' . $model->get_this_model_name(); |
|
796 | + $model_object_classname = 'EE_'.$model->get_this_model_name(); |
|
797 | 797 | $post->{$model_object_classname} = EE_Registry::instance()->load_class( |
798 | 798 | $model_object_classname, |
799 | 799 | $result, |
@@ -804,14 +804,14 @@ discard block |
||
804 | 804 | foreach ($result as $field_name => $field_value) { |
805 | 805 | $field_obj = $model->field_settings_for($field_name); |
806 | 806 | if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) { |
807 | - unset($result[ $field_name ]); |
|
807 | + unset($result[$field_name]); |
|
808 | 808 | } elseif ( |
809 | 809 | $this->isSubclassOfOne( |
810 | 810 | $field_obj, |
811 | 811 | $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat() |
812 | 812 | ) |
813 | 813 | ) { |
814 | - $result[ $field_name ] = [ |
|
814 | + $result[$field_name] = [ |
|
815 | 815 | 'raw' => $this->prepareFieldObjValueForJson($field_obj, $field_value), |
816 | 816 | 'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'), |
817 | 817 | ]; |
@@ -821,7 +821,7 @@ discard block |
||
821 | 821 | $this->getModelVersionInfo()->fieldsThatHavePrettyFormat() |
822 | 822 | ) |
823 | 823 | ) { |
824 | - $result[ $field_name ] = [ |
|
824 | + $result[$field_name] = [ |
|
825 | 825 | 'raw' => $this->prepareFieldObjValueForJson($field_obj, $field_value), |
826 | 826 | 'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'), |
827 | 827 | ]; |
@@ -852,10 +852,10 @@ discard block |
||
852 | 852 | $this->getModelVersionInfo()->requestedVersion() |
853 | 853 | ); |
854 | 854 | } |
855 | - $result[ $field_name . '_gmt' ] = $gmt_date; |
|
856 | - $result[ $field_name ] = $local_date; |
|
855 | + $result[$field_name.'_gmt'] = $gmt_date; |
|
856 | + $result[$field_name] = $local_date; |
|
857 | 857 | } else { |
858 | - $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value); |
|
858 | + $result[$field_name] = $this->prepareFieldObjValueForJson($field_obj, $field_value); |
|
859 | 859 | } |
860 | 860 | } |
861 | 861 | if ($do_chevy_shuffle) { |
@@ -910,7 +910,7 @@ discard block |
||
910 | 910 | protected function addExtraFields(EEM_Base $model, $db_row, $entity_array) |
911 | 911 | { |
912 | 912 | if ($model instanceof EEM_CPT_Base) { |
913 | - $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]); |
|
913 | + $entity_array['link'] = get_permalink($db_row[$model->get_primary_key_field()->get_qualified_column()]); |
|
914 | 914 | } |
915 | 915 | return $entity_array; |
916 | 916 | } |
@@ -937,7 +937,7 @@ discard block |
||
937 | 937 | 'href' => $this->getVersionedLinkTo( |
938 | 938 | EEH_Inflector::pluralize_and_lower($model->get_this_model_name()) |
939 | 939 | . '/' |
940 | - . $entity_array[ $model->primary_key_name() ] |
|
940 | + . $entity_array[$model->primary_key_name()] |
|
941 | 941 | ), |
942 | 942 | ], |
943 | 943 | ]; |
@@ -954,12 +954,12 @@ discard block |
||
954 | 954 | foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) { |
955 | 955 | $related_model_part = |
956 | 956 | Read::getRelatedEntityName($relation_name, $relation_obj); |
957 | - $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = [ |
|
957 | + $links[EED_Core_Rest_Api::ee_api_link_namespace.$related_model_part] = [ |
|
958 | 958 | [ |
959 | 959 | 'href' => $this->getVersionedLinkTo( |
960 | 960 | EEH_Inflector::pluralize_and_lower($model->get_this_model_name()) |
961 | 961 | . '/' |
962 | - . $entity_array[ $model->primary_key_name() ] |
|
962 | + . $entity_array[$model->primary_key_name()] |
|
963 | 963 | . '/' |
964 | 964 | . $related_model_part |
965 | 965 | ), |
@@ -993,12 +993,12 @@ discard block |
||
993 | 993 | $included_items_protected = false |
994 | 994 | ) { |
995 | 995 | // if $db_row not included, hope the entity array has what we need |
996 | - if (! $db_row) { |
|
996 | + if ( ! $db_row) { |
|
997 | 997 | $db_row = $entity_array; |
998 | 998 | } |
999 | 999 | $relation_settings = $this->getModelVersionInfo()->relationSettings($model); |
1000 | 1000 | foreach ($relation_settings as $relation_name => $relation_obj) { |
1001 | - $related_fields_to_include = $this->explodeAndGetItemsPrefixedWith( |
|
1001 | + $related_fields_to_include = $this->explodeAndGetItemsPrefixedWith( |
|
1002 | 1002 | $rest_request->get_param('include'), |
1003 | 1003 | $relation_name |
1004 | 1004 | ); |
@@ -1026,7 +1026,7 @@ discard block |
||
1026 | 1026 | $model->deduce_fields_n_values_from_cols_n_values($db_row) |
1027 | 1027 | ) |
1028 | 1028 | ); |
1029 | - if (! $included_items_protected) { |
|
1029 | + if ( ! $included_items_protected) { |
|
1030 | 1030 | try { |
1031 | 1031 | $related_results = $this->getEntitiesFromRelationUsingModelQueryParams( |
1032 | 1032 | $primary_model_query_params, |
@@ -1047,7 +1047,7 @@ discard block |
||
1047 | 1047 | ? null |
1048 | 1048 | : []; |
1049 | 1049 | } |
1050 | - $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results; |
|
1050 | + $entity_array[Read::getRelatedEntityName($relation_name, $relation_obj)] = $related_results; |
|
1051 | 1051 | } |
1052 | 1052 | } |
1053 | 1053 | return $entity_array; |
@@ -1131,13 +1131,13 @@ discard block |
||
1131 | 1131 | $schema = $this->fields_calculator->getJsonSchemaForModel($model); |
1132 | 1132 | if ( |
1133 | 1133 | $row_is_protected |
1134 | - && isset($schema['properties'][ $field_to_calculate ]['protected']) |
|
1135 | - && $schema['properties'][ $field_to_calculate ]['protected'] |
|
1134 | + && isset($schema['properties'][$field_to_calculate]['protected']) |
|
1135 | + && $schema['properties'][$field_to_calculate]['protected'] |
|
1136 | 1136 | ) { |
1137 | 1137 | $calculated_value = null; |
1138 | 1138 | $protected_fields[] = $field_to_calculate; |
1139 | - if ($schema['properties'][ $field_to_calculate ]['type']) { |
|
1140 | - switch ($schema['properties'][ $field_to_calculate ]['type']) { |
|
1139 | + if ($schema['properties'][$field_to_calculate]['type']) { |
|
1140 | + switch ($schema['properties'][$field_to_calculate]['type']) { |
|
1141 | 1141 | case 'boolean': |
1142 | 1142 | $calculated_value = false; |
1143 | 1143 | break; |
@@ -1252,7 +1252,7 @@ discard block |
||
1252 | 1252 | */ |
1253 | 1253 | public function validateContext($context) |
1254 | 1254 | { |
1255 | - if (! $context) { |
|
1255 | + if ( ! $context) { |
|
1256 | 1256 | $context = EEM_Base::caps_read; |
1257 | 1257 | } |
1258 | 1258 | $valid_contexts = EEM_Base::valid_cap_contexts(); |
@@ -1277,7 +1277,7 @@ discard block |
||
1277 | 1277 | EEM_Base::default_where_conditions_minimum_all, |
1278 | 1278 | EEM_Base::default_where_conditions_minimum_others, |
1279 | 1279 | ]; |
1280 | - if (! $default_query_params) { |
|
1280 | + if ( ! $default_query_params) { |
|
1281 | 1281 | $default_query_params = EEM_Base::default_where_conditions_all; |
1282 | 1282 | } |
1283 | 1283 | if ( |
@@ -1363,14 +1363,14 @@ discard block |
||
1363 | 1363 | } |
1364 | 1364 | if (isset($query_params['limit'])) { |
1365 | 1365 | // limit should be either a string like '23' or '23,43', or an array with two items in it |
1366 | - if (! is_array($query_params['limit'])) { |
|
1366 | + if ( ! is_array($query_params['limit'])) { |
|
1367 | 1367 | $limit_array = explode(',', (string) $query_params['limit']); |
1368 | 1368 | } else { |
1369 | 1369 | $limit_array = $query_params['limit']; |
1370 | 1370 | } |
1371 | 1371 | $sanitized_limit = []; |
1372 | 1372 | foreach ($limit_array as $limit_part) { |
1373 | - if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) { |
|
1373 | + if ($this->debug_mode && ( ! is_numeric($limit_part) || count($sanitized_limit) > 2)) { |
|
1374 | 1374 | throw new EE_Error( |
1375 | 1375 | sprintf( |
1376 | 1376 | esc_html__( |
@@ -1428,7 +1428,7 @@ discard block |
||
1428 | 1428 | { |
1429 | 1429 | $model_ready_query_params = []; |
1430 | 1430 | foreach ($query_params as $key => $value) { |
1431 | - $model_ready_query_params[ $key ] = is_array($value) |
|
1431 | + $model_ready_query_params[$key] = is_array($value) |
|
1432 | 1432 | ? $this->prepareRestQueryParamsKeyForModels($model, $value) |
1433 | 1433 | : $value; |
1434 | 1434 | } |
@@ -1447,9 +1447,9 @@ discard block |
||
1447 | 1447 | $model_ready_query_params = []; |
1448 | 1448 | foreach ($query_params as $key => $value) { |
1449 | 1449 | if (is_array($value)) { |
1450 | - $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value); |
|
1450 | + $model_ready_query_params[$key] = $this->prepareRestQueryParamsValuesForModels($model, $value); |
|
1451 | 1451 | } else { |
1452 | - $model_ready_query_params[ $key ] = $value; |
|
1452 | + $model_ready_query_params[$key] = $value; |
|
1453 | 1453 | } |
1454 | 1454 | } |
1455 | 1455 | return $model_ready_query_params; |
@@ -1481,17 +1481,17 @@ discard block |
||
1481 | 1481 | foreach ($exploded_contents as $item) { |
1482 | 1482 | $item = trim($item); |
1483 | 1483 | // if no prefix was provided, so we look for items with no "." in them |
1484 | - if (! $prefix) { |
|
1484 | + if ( ! $prefix) { |
|
1485 | 1485 | // does this item have a period? |
1486 | 1486 | if (strpos($item, '.') === false) { |
1487 | 1487 | // if not, then its what we're looking for |
1488 | 1488 | $contents_with_prefix[] = $item; |
1489 | 1489 | } |
1490 | - } elseif (strpos($item, $prefix . '.') === 0) { |
|
1490 | + } elseif (strpos($item, $prefix.'.') === 0) { |
|
1491 | 1491 | // this item has the prefix and a period, grab it |
1492 | 1492 | $contents_with_prefix[] = substr( |
1493 | 1493 | $item, |
1494 | - strpos($item, $prefix . '.') + strlen($prefix . '.') |
|
1494 | + strpos($item, $prefix.'.') + strlen($prefix.'.') |
|
1495 | 1495 | ); |
1496 | 1496 | } elseif ($item === $prefix) { |
1497 | 1497 | // this item is JUST the prefix |
@@ -1533,9 +1533,9 @@ discard block |
||
1533 | 1533 | if ($model_name) { |
1534 | 1534 | foreach ($includes as $field_to_include) { |
1535 | 1535 | $field_to_include = trim($field_to_include); |
1536 | - if (strpos($field_to_include, $model_name . '.') === 0) { |
|
1536 | + if (strpos($field_to_include, $model_name.'.') === 0) { |
|
1537 | 1537 | // found the model name at the exact start |
1538 | - $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include); |
|
1538 | + $field_sans_model_name = str_replace($model_name.'.', '', $field_to_include); |
|
1539 | 1539 | $extracted_fields_to_include[] = $field_sans_model_name; |
1540 | 1540 | } elseif ($field_to_include == $model_name) { |
1541 | 1541 | $extracted_fields_to_include[] = '*'; |
@@ -1578,7 +1578,7 @@ discard block |
||
1578 | 1578 | $restricted_query_params['caps'] = $context; |
1579 | 1579 | $this->setDebugInfo('model query params', $restricted_query_params); |
1580 | 1580 | $model_rows = $model->get_all_wpdb_results($restricted_query_params); |
1581 | - if (! empty($model_rows)) { |
|
1581 | + if ( ! empty($model_rows)) { |
|
1582 | 1582 | return $this->createEntityFromWpdbResult( |
1583 | 1583 | $model, |
1584 | 1584 | reset($model_rows), |
@@ -1590,7 +1590,7 @@ discard block |
||
1590 | 1590 | if ($model->exists($query_params)) { |
1591 | 1591 | // you got shafted- it existed but we didn't want to tell you! |
1592 | 1592 | throw new RestException( |
1593 | - 'rest_user_cannot_' . $context, |
|
1593 | + 'rest_user_cannot_'.$context, |
|
1594 | 1594 | sprintf( |
1595 | 1595 | esc_html__('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'), |
1596 | 1596 | $context, |
@@ -1644,14 +1644,14 @@ discard block |
||
1644 | 1644 | // if this entity requires a password, they better give it and it better be right! |
1645 | 1645 | if ( |
1646 | 1646 | $model->hasPassword() |
1647 | - && $model_row[ $model->getPasswordField()->get_qualified_column() ] !== '' |
|
1647 | + && $model_row[$model->getPasswordField()->get_qualified_column()] !== '' |
|
1648 | 1648 | ) { |
1649 | 1649 | if (empty($request['password'])) { |
1650 | 1650 | throw new RestPasswordRequiredException(); |
1651 | 1651 | } |
1652 | 1652 | if ( |
1653 | 1653 | ! hash_equals( |
1654 | - $model_row[ $model->getPasswordField()->get_qualified_column() ], |
|
1654 | + $model_row[$model->getPasswordField()->get_qualified_column()], |
|
1655 | 1655 | $request['password'] |
1656 | 1656 | ) |
1657 | 1657 | ) { |
@@ -1665,12 +1665,12 @@ discard block |
||
1665 | 1665 | $password_supplied = $request->get_param('password'); |
1666 | 1666 | if (empty($password_supplied)) { |
1667 | 1667 | $query_params['exclude_protected'] = true; |
1668 | - if (! $model->exists($query_params)) { |
|
1668 | + if ( ! $model->exists($query_params)) { |
|
1669 | 1669 | throw new RestPasswordRequiredException(); |
1670 | 1670 | } |
1671 | 1671 | } else { |
1672 | - $query_params[0][ $model->modelChainAndPassword() ] = $password_supplied; |
|
1673 | - if (! $model->exists($query_params)) { |
|
1672 | + $query_params[0][$model->modelChainAndPassword()] = $password_supplied; |
|
1673 | + if ( ! $model->exists($query_params)) { |
|
1674 | 1674 | throw new RestPasswordIncorrectException(); |
1675 | 1675 | } |
1676 | 1676 | } |
@@ -49,1629 +49,1629 @@ |
||
49 | 49 | */ |
50 | 50 | class Read extends Base |
51 | 51 | { |
52 | - /** |
|
53 | - * @var CalculatedModelFields |
|
54 | - */ |
|
55 | - protected $fields_calculator; |
|
56 | - |
|
57 | - |
|
58 | - /** |
|
59 | - * Read constructor. |
|
60 | - * |
|
61 | - * @param CalculatedModelFields $fields_calculator |
|
62 | - */ |
|
63 | - public function __construct(CalculatedModelFields $fields_calculator) |
|
64 | - { |
|
65 | - parent::__construct(); |
|
66 | - $this->fields_calculator = $fields_calculator; |
|
67 | - } |
|
68 | - |
|
69 | - |
|
70 | - /** |
|
71 | - * Handles requests to get all (or a filtered subset) of entities for a particular model |
|
72 | - * |
|
73 | - * @param WP_REST_Request $request |
|
74 | - * @param string $version |
|
75 | - * @param string $model_name |
|
76 | - * @return WP_REST_Response|WP_Error |
|
77 | - * @throws InvalidArgumentException |
|
78 | - * @throws InvalidDataTypeException |
|
79 | - * @throws InvalidInterfaceException |
|
80 | - */ |
|
81 | - public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name) |
|
82 | - { |
|
83 | - $controller = |
|
84 | - LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
|
85 | - try { |
|
86 | - $controller->setRequestedVersion($version); |
|
87 | - if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
88 | - return $controller->sendResponse( |
|
89 | - new WP_Error( |
|
90 | - 'endpoint_parsing_error', |
|
91 | - sprintf( |
|
92 | - esc_html__( |
|
93 | - 'There is no model for endpoint %s. Please contact event espresso support', |
|
94 | - 'event_espresso' |
|
95 | - ), |
|
96 | - $model_name |
|
97 | - ) |
|
98 | - ) |
|
99 | - ); |
|
100 | - } |
|
101 | - return $controller->sendResponse( |
|
102 | - $controller->getEntitiesFromModel( |
|
103 | - $controller->getModelVersionInfo()->loadModel($model_name), |
|
104 | - $request |
|
105 | - ) |
|
106 | - ); |
|
107 | - } catch (Exception $e) { |
|
108 | - return $controller->sendResponse($e); |
|
109 | - } |
|
110 | - } |
|
111 | - |
|
112 | - |
|
113 | - /** |
|
114 | - * Prepares and returns schema for any OPTIONS request. |
|
115 | - * |
|
116 | - * @param string $version The API endpoint version being used. |
|
117 | - * @param string $model_name Something like `Event` or `Registration` |
|
118 | - * @return array |
|
119 | - * @throws InvalidArgumentException |
|
120 | - * @throws InvalidDataTypeException |
|
121 | - * @throws InvalidInterfaceException |
|
122 | - */ |
|
123 | - public static function handleSchemaRequest($version, $model_name) |
|
124 | - { |
|
125 | - $controller = |
|
126 | - LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
|
127 | - try { |
|
128 | - $controller->setRequestedVersion($version); |
|
129 | - if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
130 | - return []; |
|
131 | - } |
|
132 | - // get the model for this version |
|
133 | - $model = $controller->getModelVersionInfo()->loadModel($model_name); |
|
134 | - $model_schema = new JsonModelSchema( |
|
135 | - $model, |
|
136 | - LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields') |
|
137 | - ); |
|
138 | - return $model_schema->getModelSchemaForRelations( |
|
139 | - $controller->getModelVersionInfo()->relationSettings($model), |
|
140 | - $controller->customizeSchemaForRestResponse( |
|
141 | - $model, |
|
142 | - $model_schema->getModelSchemaForFields( |
|
143 | - $controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model), |
|
144 | - $model_schema->getInitialSchemaStructure() |
|
145 | - ) |
|
146 | - ) |
|
147 | - ); |
|
148 | - } catch (Exception $e) { |
|
149 | - return []; |
|
150 | - } |
|
151 | - } |
|
152 | - |
|
153 | - |
|
154 | - /** |
|
155 | - * This loops through each field in the given schema for the model and does the following: |
|
156 | - * - add any extra fields that are REST API specific and related to existing fields. |
|
157 | - * - transform default values into the correct format for a REST API response. |
|
158 | - * |
|
159 | - * @param EEM_Base $model |
|
160 | - * @param array $schema |
|
161 | - * @return array The final schema. |
|
162 | - * @throws EE_Error |
|
163 | - * @throws EE_Error |
|
164 | - */ |
|
165 | - protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema) |
|
166 | - { |
|
167 | - foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) { |
|
168 | - $schema = $this->translateDefaultsForRestResponse( |
|
169 | - $field_name, |
|
170 | - $field, |
|
171 | - $this->maybeAddExtraFieldsToSchema($field_name, $field, $schema) |
|
172 | - ); |
|
173 | - } |
|
174 | - return $schema; |
|
175 | - } |
|
176 | - |
|
177 | - |
|
178 | - /** |
|
179 | - * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST |
|
180 | - * response. |
|
181 | - * |
|
182 | - * @param $field_name |
|
183 | - * @param EE_Model_Field_Base $field |
|
184 | - * @param array $schema |
|
185 | - * @return array |
|
186 | - * @throws RestException if a default value has a PHP object, which we should never do |
|
187 | - * (but if we did, let's know about it ASAP, so let the exception bubble up) |
|
188 | - * @throws EE_Error |
|
189 | - * |
|
190 | - */ |
|
191 | - protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema) |
|
192 | - { |
|
193 | - if (isset($schema['properties'][ $field_name ]['default'])) { |
|
194 | - if (is_array($schema['properties'][ $field_name ]['default'])) { |
|
195 | - foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) { |
|
196 | - if ($default_key === 'raw') { |
|
197 | - $schema['properties'][ $field_name ]['default'][ $default_key ] = |
|
198 | - ModelDataTranslator::prepareFieldValueForJson( |
|
199 | - $field, |
|
200 | - $default_value, |
|
201 | - $this->getModelVersionInfo()->requestedVersion() |
|
202 | - ); |
|
203 | - } |
|
204 | - } |
|
205 | - } else { |
|
206 | - $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson( |
|
207 | - $field, |
|
208 | - $schema['properties'][ $field_name ]['default'], |
|
209 | - $this->getModelVersionInfo()->requestedVersion() |
|
210 | - ); |
|
211 | - } |
|
212 | - } |
|
213 | - return $schema; |
|
214 | - } |
|
215 | - |
|
216 | - |
|
217 | - /** |
|
218 | - * Adds additional fields to the schema |
|
219 | - * The REST API returns a GMT value field for each datetime field in the resource. Thus the description about this |
|
220 | - * needs to be added to the schema. |
|
221 | - * |
|
222 | - * @param $field_name |
|
223 | - * @param EE_Model_Field_Base $field |
|
224 | - * @param array $schema |
|
225 | - * @return array |
|
226 | - */ |
|
227 | - protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema) |
|
228 | - { |
|
229 | - if ($field instanceof EE_Datetime_Field) { |
|
230 | - $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema(); |
|
231 | - // modify the description |
|
232 | - $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf( |
|
233 | - esc_html__('%s - the value for this field is in GMT.', 'event_espresso'), |
|
234 | - wp_specialchars_decode($field->get_nicename(), ENT_QUOTES) |
|
235 | - ); |
|
236 | - } |
|
237 | - return $schema; |
|
238 | - } |
|
239 | - |
|
240 | - |
|
241 | - /** |
|
242 | - * Used to figure out the route from the request when a `WP_REST_Request` object is not available |
|
243 | - * |
|
244 | - * @return string |
|
245 | - */ |
|
246 | - protected function getRouteFromRequest() |
|
247 | - { |
|
248 | - if ( |
|
249 | - isset($GLOBALS['wp']) |
|
250 | - && $GLOBALS['wp'] instanceof WP |
|
251 | - && isset($GLOBALS['wp']->query_vars['rest_route']) |
|
252 | - ) { |
|
253 | - return $GLOBALS['wp']->query_vars['rest_route']; |
|
254 | - } else { |
|
255 | - /** @var RequestInterface $request */ |
|
256 | - $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
257 | - return $request->serverParamIsSet('PATH_INFO') |
|
258 | - ? $request->getServerParam('PATH_INFO') |
|
259 | - : '/'; |
|
260 | - } |
|
261 | - } |
|
262 | - |
|
263 | - |
|
264 | - /** |
|
265 | - * Gets a single entity related to the model indicated in the path and its id |
|
266 | - * |
|
267 | - * @param WP_REST_Request $request |
|
268 | - * @param string $version |
|
269 | - * @param string $model_name |
|
270 | - * @return WP_REST_Response|WP_Error |
|
271 | - * @throws InvalidDataTypeException |
|
272 | - * @throws InvalidInterfaceException |
|
273 | - * @throws InvalidArgumentException |
|
274 | - */ |
|
275 | - public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name) |
|
276 | - { |
|
277 | - $controller = |
|
278 | - LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
|
279 | - try { |
|
280 | - $controller->setRequestedVersion($version); |
|
281 | - if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
282 | - return $controller->sendResponse( |
|
283 | - new WP_Error( |
|
284 | - 'endpoint_parsing_error', |
|
285 | - sprintf( |
|
286 | - esc_html__( |
|
287 | - 'There is no model for endpoint %s. Please contact event espresso support', |
|
288 | - 'event_espresso' |
|
289 | - ), |
|
290 | - $model_name |
|
291 | - ) |
|
292 | - ) |
|
293 | - ); |
|
294 | - } |
|
295 | - return $controller->sendResponse( |
|
296 | - $controller->getEntityFromModel( |
|
297 | - $controller->getModelVersionInfo()->loadModel($model_name), |
|
298 | - $request |
|
299 | - ) |
|
300 | - ); |
|
301 | - } catch (Exception $e) { |
|
302 | - return $controller->sendResponse($e); |
|
303 | - } |
|
304 | - } |
|
305 | - |
|
306 | - |
|
307 | - /** |
|
308 | - * Gets all the related entities (or if its a belongs-to relation just the one) |
|
309 | - * to the item with the given id |
|
310 | - * |
|
311 | - * @param WP_REST_Request $request |
|
312 | - * @param string $version |
|
313 | - * @param string $model_name |
|
314 | - * @param string $related_model_name |
|
315 | - * @return WP_REST_Response|WP_Error |
|
316 | - * @throws InvalidDataTypeException |
|
317 | - * @throws InvalidInterfaceException |
|
318 | - * @throws InvalidArgumentException |
|
319 | - */ |
|
320 | - public static function handleRequestGetRelated( |
|
321 | - WP_REST_Request $request, |
|
322 | - $version, |
|
323 | - $model_name, |
|
324 | - $related_model_name |
|
325 | - ) { |
|
326 | - $controller = |
|
327 | - LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
|
328 | - try { |
|
329 | - $controller->setRequestedVersion($version); |
|
330 | - $main_model = $controller->validateModel($model_name); |
|
331 | - $controller->validateModel($related_model_name); |
|
332 | - return $controller->sendResponse( |
|
333 | - $controller->getEntitiesFromRelation( |
|
334 | - $request->get_param('id'), |
|
335 | - $main_model->related_settings_for($related_model_name), |
|
336 | - $request |
|
337 | - ) |
|
338 | - ); |
|
339 | - } catch (Exception $e) { |
|
340 | - return $controller->sendResponse($e); |
|
341 | - } |
|
342 | - } |
|
343 | - |
|
344 | - |
|
345 | - /** |
|
346 | - * Gets a collection for the given model and filters |
|
347 | - * |
|
348 | - * @param EEM_Base $model |
|
349 | - * @param WP_REST_Request $request |
|
350 | - * @return array |
|
351 | - * @throws EE_Error |
|
352 | - * @throws InvalidArgumentException |
|
353 | - * @throws InvalidDataTypeException |
|
354 | - * @throws InvalidInterfaceException |
|
355 | - * @throws ReflectionException |
|
356 | - * @throws RestException |
|
357 | - */ |
|
358 | - public function getEntitiesFromModel($model, $request) |
|
359 | - { |
|
360 | - $query_params = $this->createModelQueryParams($model, $request->get_params()); |
|
361 | - if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) { |
|
362 | - $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name()); |
|
363 | - throw new RestException( |
|
364 | - sprintf('rest_%s_cannot_list', $model_name_plural), |
|
365 | - sprintf( |
|
366 | - esc_html__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'), |
|
367 | - $model_name_plural, |
|
368 | - Capabilities::getMissingPermissionsString($model, $query_params['caps']) |
|
369 | - ), |
|
370 | - ['status' => 403] |
|
371 | - ); |
|
372 | - } |
|
373 | - if (! $request->get_header('no_rest_headers')) { |
|
374 | - $this->setHeadersFromQueryParams($model, $query_params); |
|
375 | - } |
|
376 | - /** @type array $results */ |
|
377 | - $results = $model->get_all_wpdb_results($query_params); |
|
378 | - $nice_results = []; |
|
379 | - foreach ($results as $result) { |
|
380 | - $nice_results[] = $this->createEntityFromWpdbResult( |
|
381 | - $model, |
|
382 | - $result, |
|
383 | - $request |
|
384 | - ); |
|
385 | - } |
|
386 | - return $nice_results; |
|
387 | - } |
|
388 | - |
|
389 | - |
|
390 | - /** |
|
391 | - * Gets the collection for given relation object |
|
392 | - * The same as Read::get_entities_from_model(), except if the relation |
|
393 | - * is a HABTM relation, in which case it merges any non-foreign-key fields from |
|
394 | - * the join-model-object into the results |
|
395 | - * |
|
396 | - * @param array $primary_model_query_params query params for finding the item from which |
|
397 | - * relations will be based |
|
398 | - * @param EE_Model_Relation_Base $relation |
|
399 | - * @param WP_REST_Request $request |
|
400 | - * @return array |
|
401 | - * @throws EE_Error |
|
402 | - * @throws InvalidArgumentException |
|
403 | - * @throws InvalidDataTypeException |
|
404 | - * @throws InvalidInterfaceException |
|
405 | - * @throws ReflectionException |
|
406 | - * @throws RestException |
|
407 | - * @throws ModelConfigurationException |
|
408 | - */ |
|
409 | - protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request) |
|
410 | - { |
|
411 | - $context = $this->validateContext($request->get_param('caps')); |
|
412 | - $model = $relation->get_this_model(); |
|
413 | - $related_model = $relation->get_other_model(); |
|
414 | - if (! isset($primary_model_query_params[0])) { |
|
415 | - $primary_model_query_params[0] = []; |
|
416 | - } |
|
417 | - // check if they can access the 1st model object |
|
418 | - $primary_model_query_params = [ |
|
419 | - 0 => $primary_model_query_params[0], |
|
420 | - 'limit' => 1, |
|
421 | - ]; |
|
422 | - if ($model instanceof EEM_Soft_Delete_Base) { |
|
423 | - $primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included( |
|
424 | - $primary_model_query_params |
|
425 | - ); |
|
426 | - } |
|
427 | - $restricted_query_params = $primary_model_query_params; |
|
428 | - $restricted_query_params['caps'] = $context; |
|
429 | - $restricted_query_params['limit'] = 1; |
|
430 | - $this->setDebugInfo('main model query params', $restricted_query_params); |
|
431 | - $this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context)); |
|
432 | - $primary_model_rows = $model->get_all_wpdb_results($restricted_query_params); |
|
433 | - $primary_model_row = null; |
|
434 | - if (is_array($primary_model_rows)) { |
|
435 | - $primary_model_row = reset($primary_model_rows); |
|
436 | - } |
|
437 | - if ( |
|
438 | - ! ( |
|
439 | - $primary_model_row |
|
440 | - && Capabilities::currentUserHasPartialAccessTo($related_model, $context) |
|
441 | - ) |
|
442 | - ) { |
|
443 | - if ($relation instanceof EE_Belongs_To_Relation) { |
|
444 | - $related_model_name_maybe_plural = strtolower($related_model->get_this_model_name()); |
|
445 | - } else { |
|
446 | - $related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower( |
|
447 | - $related_model->get_this_model_name() |
|
448 | - ); |
|
449 | - } |
|
450 | - throw new RestException( |
|
451 | - sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural), |
|
452 | - sprintf( |
|
453 | - esc_html__( |
|
454 | - 'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s', |
|
455 | - 'event_espresso' |
|
456 | - ), |
|
457 | - $related_model_name_maybe_plural, |
|
458 | - $relation->get_this_model()->get_this_model_name(), |
|
459 | - implode( |
|
460 | - ',', |
|
461 | - array_keys( |
|
462 | - Capabilities::getMissingPermissions($related_model, $context) |
|
463 | - ) |
|
464 | - ) |
|
465 | - ), |
|
466 | - ['status' => 403] |
|
467 | - ); |
|
468 | - } |
|
469 | - |
|
470 | - $this->checkPassword( |
|
471 | - $model, |
|
472 | - $primary_model_row, |
|
473 | - $restricted_query_params, |
|
474 | - $request |
|
475 | - ); |
|
476 | - $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params()); |
|
477 | - foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) { |
|
478 | - $query_params[0][ $relation->get_this_model()->get_this_model_name() |
|
479 | - . '.' |
|
480 | - . $where_condition_key ] = $where_condition_value; |
|
481 | - } |
|
482 | - $query_params['default_where_conditions'] = 'none'; |
|
483 | - $query_params['caps'] = $context; |
|
484 | - if (! $request->get_header('no_rest_headers')) { |
|
485 | - $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params); |
|
486 | - } |
|
487 | - /** @type array $results */ |
|
488 | - $results = $relation->get_other_model()->get_all_wpdb_results($query_params); |
|
489 | - $nice_results = []; |
|
490 | - foreach ($results as $result) { |
|
491 | - $nice_result = $this->createEntityFromWpdbResult( |
|
492 | - $relation->get_other_model(), |
|
493 | - $result, |
|
494 | - $request |
|
495 | - ); |
|
496 | - if ($relation instanceof EE_HABTM_Relation) { |
|
497 | - // put the unusual stuff (properties from the HABTM relation) first, and make sure |
|
498 | - // if there are conflicts we prefer the properties from the main model |
|
499 | - $join_model_result = $this->createEntityFromWpdbResult( |
|
500 | - $relation->get_join_model(), |
|
501 | - $result, |
|
502 | - $request |
|
503 | - ); |
|
504 | - $joined_result = array_merge($join_model_result, $nice_result); |
|
505 | - // but keep the meta stuff from the main model |
|
506 | - if (isset($nice_result['meta'])) { |
|
507 | - $joined_result['meta'] = $nice_result['meta']; |
|
508 | - } |
|
509 | - $nice_result = $joined_result; |
|
510 | - } |
|
511 | - $nice_results[] = $nice_result; |
|
512 | - } |
|
513 | - if ($relation instanceof EE_Belongs_To_Relation) { |
|
514 | - return array_shift($nice_results); |
|
515 | - } else { |
|
516 | - return $nice_results; |
|
517 | - } |
|
518 | - } |
|
519 | - |
|
520 | - |
|
521 | - /** |
|
522 | - * Gets the collection for given relation object |
|
523 | - * The same as Read::get_entities_from_model(), except if the relation |
|
524 | - * is a HABTM relation, in which case it merges any non-foreign-key fields from |
|
525 | - * the join-model-object into the results |
|
526 | - * |
|
527 | - * @param string $id the ID of the thing we are fetching related stuff from |
|
528 | - * @param EE_Model_Relation_Base $relation |
|
529 | - * @param WP_REST_Request $request |
|
530 | - * @return array |
|
531 | - * @throws EE_Error |
|
532 | - * @throws ReflectionException |
|
533 | - */ |
|
534 | - public function getEntitiesFromRelation($id, $relation, $request) |
|
535 | - { |
|
536 | - if (! $relation->get_this_model()->has_primary_key_field()) { |
|
537 | - throw new EE_Error( |
|
538 | - sprintf( |
|
539 | - esc_html__( |
|
540 | - // @codingStandardsIgnoreStart |
|
541 | - 'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s', |
|
542 | - // @codingStandardsIgnoreEnd |
|
543 | - 'event_espresso' |
|
544 | - ), |
|
545 | - $relation->get_this_model()->get_this_model_name() |
|
546 | - ) |
|
547 | - ); |
|
548 | - } |
|
549 | - // can we edit that main item? |
|
550 | - // if not, show nothing but an error |
|
551 | - // otherwise, please proceed |
|
552 | - return $this->getEntitiesFromRelationUsingModelQueryParams( |
|
553 | - [ |
|
554 | - [ |
|
555 | - $relation->get_this_model()->primary_key_name() => $id, |
|
556 | - ], |
|
557 | - ], |
|
558 | - $relation, |
|
559 | - $request |
|
560 | - ); |
|
561 | - } |
|
562 | - |
|
563 | - |
|
564 | - /** |
|
565 | - * Sets the headers that are based on the model and query params, |
|
566 | - * like the total records. This should only be called on the original request |
|
567 | - * from the client, not on subsequent internal |
|
568 | - * |
|
569 | - * @param EEM_Base $model |
|
570 | - * @param array $query_params |
|
571 | - * @return void |
|
572 | - * @throws EE_Error |
|
573 | - * @throws EE_Error |
|
574 | - */ |
|
575 | - protected function setHeadersFromQueryParams($model, $query_params) |
|
576 | - { |
|
577 | - $this->setDebugInfo('model query params', $query_params); |
|
578 | - $this->setDebugInfo( |
|
579 | - 'missing caps', |
|
580 | - Capabilities::getMissingPermissionsString($model, $query_params['caps']) |
|
581 | - ); |
|
582 | - // normally the limit to a 2-part array, where the 2nd item is the limit |
|
583 | - if (! isset($query_params['limit'])) { |
|
584 | - $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit(); |
|
585 | - } |
|
586 | - if (is_array($query_params['limit'])) { |
|
587 | - $limit_parts = $query_params['limit']; |
|
588 | - } else { |
|
589 | - $limit_parts = explode(',', $query_params['limit']); |
|
590 | - if (count($limit_parts) == 1) { |
|
591 | - $limit_parts = [0, $limit_parts[0]]; |
|
592 | - } |
|
593 | - } |
|
594 | - // remove the group by and having parts of the query, as those will |
|
595 | - // make the sql query return an array of values, instead of just a single value |
|
596 | - unset($query_params['group_by'], $query_params['having'], $query_params['limit']); |
|
597 | - $count = $model->count($query_params, null, true); |
|
598 | - $pages = $count / $limit_parts[1]; |
|
599 | - $this->setResponseHeader('Total', $count, false); |
|
600 | - $this->setResponseHeader('PageSize', $limit_parts[1], false); |
|
601 | - $this->setResponseHeader('TotalPages', ceil($pages), false); |
|
602 | - } |
|
603 | - |
|
604 | - |
|
605 | - /** |
|
606 | - * Changes database results into REST API entities |
|
607 | - * |
|
608 | - * @param EEM_Base $model |
|
609 | - * @param array $db_row like results from $wpdb->get_results() |
|
610 | - * @param WP_REST_Request $rest_request |
|
611 | - * @param string $deprecated no longer used |
|
612 | - * @return array ready for being converted into json for sending to client |
|
613 | - * @throws EE_Error |
|
614 | - * @throws RestException |
|
615 | - * @throws InvalidDataTypeException |
|
616 | - * @throws InvalidInterfaceException |
|
617 | - * @throws InvalidArgumentException |
|
618 | - * @throws ReflectionException |
|
619 | - */ |
|
620 | - public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null) |
|
621 | - { |
|
622 | - if (! $rest_request instanceof WP_REST_Request) { |
|
623 | - // ok so this was called in the old style, where the 3rd arg was |
|
624 | - // $include, and the 4th arg was $context |
|
625 | - // now setup the request just to avoid fatal errors, although we won't be able |
|
626 | - // to truly make use of it because it's kinda devoid of info |
|
627 | - $rest_request = new WP_REST_Request(); |
|
628 | - $rest_request->set_param('include', $rest_request); |
|
629 | - $rest_request->set_param('caps', $deprecated); |
|
630 | - } |
|
631 | - if ($rest_request->get_param('caps') == null) { |
|
632 | - $rest_request->set_param('caps', EEM_Base::caps_read); |
|
633 | - } |
|
634 | - $current_user_full_access_to_entity = $model->currentUserCan( |
|
635 | - EEM_Base::caps_read_admin, |
|
636 | - $model->deduce_fields_n_values_from_cols_n_values($db_row) |
|
637 | - ); |
|
638 | - $entity_array = $this->createBareEntityFromWpdbResults($model, $db_row); |
|
639 | - $entity_array = $this->addExtraFields($model, $db_row, $entity_array); |
|
640 | - $entity_array['_links'] = $this->getEntityLinks($model, $db_row, $entity_array); |
|
641 | - // when it's a regular read request for a model with a password and the password wasn't provided |
|
642 | - // remove the password protected fields |
|
643 | - $has_protected_fields = false; |
|
644 | - try { |
|
645 | - $this->checkPassword( |
|
646 | - $model, |
|
647 | - $db_row, |
|
648 | - $model->alter_query_params_to_restrict_by_ID( |
|
649 | - $model->get_index_primary_key_string( |
|
650 | - $model->deduce_fields_n_values_from_cols_n_values($db_row) |
|
651 | - ) |
|
652 | - ), |
|
653 | - $rest_request |
|
654 | - ); |
|
655 | - } catch (RestPasswordRequiredException $e) { |
|
656 | - if ($model->hasPassword()) { |
|
657 | - // just remove protected fields |
|
658 | - $has_protected_fields = true; |
|
659 | - $entity_array = Capabilities::filterOutPasswordProtectedFields( |
|
660 | - $entity_array, |
|
661 | - $model, |
|
662 | - $this->getModelVersionInfo() |
|
663 | - ); |
|
664 | - } else { |
|
665 | - // that's a problem. None of this should be accessible if no password was provided |
|
666 | - throw $e; |
|
667 | - } |
|
668 | - } |
|
669 | - |
|
670 | - $entity_array['_calculated_fields'] = |
|
671 | - $this->getEntityCalculations($model, $db_row, $rest_request, $has_protected_fields); |
|
672 | - $entity_array = apply_filters( |
|
673 | - 'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models', |
|
674 | - $entity_array, |
|
675 | - $model, |
|
676 | - $rest_request->get_param('caps'), |
|
677 | - $rest_request, |
|
678 | - $this |
|
679 | - ); |
|
680 | - // add an empty protected property for now. If it's still around after we remove everything the request didn't |
|
681 | - // want, we'll populate it then. k? |
|
682 | - $entity_array['_protected'] = []; |
|
683 | - // remove any properties the request didn't want. This way _protected won't bother mentioning them |
|
684 | - $entity_array = $this->includeOnlyRequestedProperties($model, $rest_request, $entity_array); |
|
685 | - $entity_array = |
|
686 | - $this->includeRequestedModels($model, $rest_request, $entity_array, $db_row, $has_protected_fields); |
|
687 | - // if they still wanted the _protected property, add it. |
|
688 | - if (isset($entity_array['_protected'])) { |
|
689 | - $entity_array = $this->addProtectedProperty($model, $entity_array, $has_protected_fields); |
|
690 | - } |
|
691 | - $entity_array = apply_filters( |
|
692 | - 'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal', |
|
693 | - $entity_array, |
|
694 | - $model, |
|
695 | - $rest_request->get_param('caps'), |
|
696 | - $rest_request, |
|
697 | - $this |
|
698 | - ); |
|
699 | - if (! $current_user_full_access_to_entity) { |
|
700 | - $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields( |
|
701 | - $entity_array, |
|
702 | - $model, |
|
703 | - $rest_request->get_param('caps'), |
|
704 | - $this->getModelVersionInfo() |
|
705 | - ); |
|
706 | - } else { |
|
707 | - $result_without_inaccessible_fields = $entity_array; |
|
708 | - } |
|
709 | - $this->setDebugInfo( |
|
710 | - 'inaccessible fields', |
|
711 | - array_keys(array_diff_key((array) $entity_array, (array) $result_without_inaccessible_fields)) |
|
712 | - ); |
|
713 | - return apply_filters( |
|
714 | - 'FHEE__Read__create_entity_from_wpdb_results__entity_return', |
|
715 | - $result_without_inaccessible_fields, |
|
716 | - $model, |
|
717 | - $rest_request->get_param('caps') |
|
718 | - ); |
|
719 | - } |
|
720 | - |
|
721 | - |
|
722 | - /** |
|
723 | - * Returns an array describing which fields can be protected, and which actually were removed this request |
|
724 | - * |
|
725 | - * @param EEM_Base $model |
|
726 | - * @param array $results_so_far |
|
727 | - * @param bool $protected |
|
728 | - * @return array results |
|
729 | - * @throws EE_Error |
|
730 | - * @since 4.9.74.p |
|
731 | - */ |
|
732 | - protected function addProtectedProperty(EEM_Base $model, $results_so_far, $protected) |
|
733 | - { |
|
734 | - if (! $model->hasPassword() || ! $protected) { |
|
735 | - return $results_so_far; |
|
736 | - } |
|
737 | - $password_field = $model->getPasswordField(); |
|
738 | - $all_protected = array_merge( |
|
739 | - [$password_field->get_name()], |
|
740 | - $password_field->protectedFields() |
|
741 | - ); |
|
742 | - $fields_included = array_keys($results_so_far); |
|
743 | - $fields_included = array_intersect( |
|
744 | - $all_protected, |
|
745 | - $fields_included |
|
746 | - ); |
|
747 | - foreach ($fields_included as $field_name) { |
|
748 | - $results_so_far['_protected'][] = $field_name; |
|
749 | - } |
|
750 | - return $results_so_far; |
|
751 | - } |
|
752 | - |
|
753 | - |
|
754 | - /** |
|
755 | - * Creates a REST entity array (JSON object we're going to return in the response, but |
|
756 | - * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry), |
|
757 | - * from $wpdb->get_row( $sql, ARRAY_A) |
|
758 | - * |
|
759 | - * @param EEM_Base $model |
|
760 | - * @param array $db_row |
|
761 | - * @return array entity mostly ready for converting to JSON and sending in the response |
|
762 | - * @throws EE_Error |
|
763 | - * @throws ReflectionException |
|
764 | - * @throws RestException |
|
765 | - */ |
|
766 | - protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row) |
|
767 | - { |
|
768 | - $result = $model->deduce_fields_n_values_from_cols_n_values($db_row); |
|
769 | - $result = array_intersect_key( |
|
770 | - $result, |
|
771 | - $this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) |
|
772 | - ); |
|
773 | - // if this is a CPT, we need to set the global $post to it, |
|
774 | - // otherwise shortcodes etc won't work properly while rendering it |
|
775 | - if ($model instanceof EEM_CPT_Base) { |
|
776 | - $do_chevy_shuffle = true; |
|
777 | - } else { |
|
778 | - $do_chevy_shuffle = false; |
|
779 | - } |
|
780 | - if ($do_chevy_shuffle) { |
|
781 | - global $post; |
|
782 | - $old_post = $post; |
|
783 | - $post = get_post($result[ $model->primary_key_name() ]); |
|
784 | - if (! $post instanceof WP_Post) { |
|
785 | - // well that's weird, because $result is what we JUST fetched from the database |
|
786 | - throw new RestException( |
|
787 | - 'error_fetching_post_from_database_results', |
|
788 | - esc_html__( |
|
789 | - 'An item was retrieved from the database but it\'s not a WP_Post like it should be.', |
|
790 | - 'event_espresso' |
|
791 | - ) |
|
792 | - ); |
|
793 | - } |
|
794 | - $model_object_classname = 'EE_' . $model->get_this_model_name(); |
|
795 | - $post->{$model_object_classname} = EE_Registry::instance()->load_class( |
|
796 | - $model_object_classname, |
|
797 | - $result, |
|
798 | - false, |
|
799 | - false |
|
800 | - ); |
|
801 | - } |
|
802 | - foreach ($result as $field_name => $field_value) { |
|
803 | - $field_obj = $model->field_settings_for($field_name); |
|
804 | - if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) { |
|
805 | - unset($result[ $field_name ]); |
|
806 | - } elseif ( |
|
807 | - $this->isSubclassOfOne( |
|
808 | - $field_obj, |
|
809 | - $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat() |
|
810 | - ) |
|
811 | - ) { |
|
812 | - $result[ $field_name ] = [ |
|
813 | - 'raw' => $this->prepareFieldObjValueForJson($field_obj, $field_value), |
|
814 | - 'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'), |
|
815 | - ]; |
|
816 | - } elseif ( |
|
817 | - $this->isSubclassOfOne( |
|
818 | - $field_obj, |
|
819 | - $this->getModelVersionInfo()->fieldsThatHavePrettyFormat() |
|
820 | - ) |
|
821 | - ) { |
|
822 | - $result[ $field_name ] = [ |
|
823 | - 'raw' => $this->prepareFieldObjValueForJson($field_obj, $field_value), |
|
824 | - 'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'), |
|
825 | - ]; |
|
826 | - } elseif ($field_obj instanceof EE_Datetime_Field) { |
|
827 | - $field_value = $field_obj->prepare_for_set_from_db($field_value); |
|
828 | - // if the value is null, but we're not supposed to permit null, then set to the field's default |
|
829 | - if (is_null($field_value)) { |
|
830 | - $field_value = $field_obj->getDefaultDateTimeObj(); |
|
831 | - } |
|
832 | - if (is_null($field_value)) { |
|
833 | - $gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson( |
|
834 | - $field_obj, |
|
835 | - $field_value, |
|
836 | - $this->getModelVersionInfo()->requestedVersion() |
|
837 | - ); |
|
838 | - } else { |
|
839 | - $timezone = $field_value->getTimezone(); |
|
840 | - EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC')); |
|
841 | - $gmt_date = ModelDataTranslator::prepareFieldValuesForJson( |
|
842 | - $field_obj, |
|
843 | - $field_value, |
|
844 | - $this->getModelVersionInfo()->requestedVersion() |
|
845 | - ); |
|
846 | - EEH_DTT_Helper::setTimezone($field_value, $timezone); |
|
847 | - $local_date = ModelDataTranslator::prepareFieldValuesForJson( |
|
848 | - $field_obj, |
|
849 | - $field_value, |
|
850 | - $this->getModelVersionInfo()->requestedVersion() |
|
851 | - ); |
|
852 | - } |
|
853 | - $result[ $field_name . '_gmt' ] = $gmt_date; |
|
854 | - $result[ $field_name ] = $local_date; |
|
855 | - } else { |
|
856 | - $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value); |
|
857 | - } |
|
858 | - } |
|
859 | - if ($do_chevy_shuffle) { |
|
860 | - $post = $old_post; |
|
861 | - } |
|
862 | - return $result; |
|
863 | - } |
|
864 | - |
|
865 | - |
|
866 | - /** |
|
867 | - * Takes a value all the way from the DB representation, to the model object's representation, to the |
|
868 | - * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB |
|
869 | - * representation using $field_obj->prepare_for_set_from_db()) |
|
870 | - * |
|
871 | - * @param EE_Model_Field_Base $field_obj |
|
872 | - * @param mixed $value as it's stored on a model object |
|
873 | - * @param string $format valid values are 'normal' (default), 'pretty', 'datetime_obj' |
|
874 | - * @return array |
|
875 | - * @throws RestException if $value contains a PHP object |
|
876 | - * @throws EE_Error |
|
877 | - */ |
|
878 | - protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal') |
|
879 | - { |
|
880 | - $value = $field_obj->prepare_for_set_from_db($value); |
|
881 | - switch ($format) { |
|
882 | - case 'pretty': |
|
883 | - $value = $field_obj->prepare_for_pretty_echoing($value); |
|
884 | - break; |
|
885 | - case 'normal': |
|
886 | - default: |
|
887 | - $value = $field_obj->prepare_for_get($value); |
|
888 | - break; |
|
889 | - } |
|
890 | - return ModelDataTranslator::prepareFieldValuesForJson( |
|
891 | - $field_obj, |
|
892 | - $value, |
|
893 | - $this->getModelVersionInfo()->requestedVersion() |
|
894 | - ); |
|
895 | - } |
|
896 | - |
|
897 | - |
|
898 | - /** |
|
899 | - * Adds a few extra fields to the entity response |
|
900 | - * |
|
901 | - * @param EEM_Base $model |
|
902 | - * @param array $db_row |
|
903 | - * @param array $entity_array |
|
904 | - * @return array modified entity |
|
905 | - * @throws EE_Error |
|
906 | - * @throws EE_Error |
|
907 | - */ |
|
908 | - protected function addExtraFields(EEM_Base $model, $db_row, $entity_array) |
|
909 | - { |
|
910 | - if ($model instanceof EEM_CPT_Base) { |
|
911 | - $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]); |
|
912 | - } |
|
913 | - return $entity_array; |
|
914 | - } |
|
915 | - |
|
916 | - |
|
917 | - /** |
|
918 | - * Gets links we want to add to the response |
|
919 | - * |
|
920 | - * @param EEM_Base $model |
|
921 | - * @param array $db_row |
|
922 | - * @param array $entity_array |
|
923 | - * @return array the _links item in the entity |
|
924 | - * @throws EE_Error |
|
925 | - * @throws EE_Error |
|
926 | - * @global WP_REST_Server $wp_rest_server |
|
927 | - */ |
|
928 | - protected function getEntityLinks($model, $db_row, $entity_array) |
|
929 | - { |
|
930 | - // add basic links |
|
931 | - $links = []; |
|
932 | - if ($model->has_primary_key_field()) { |
|
933 | - $links['self'] = [ |
|
934 | - [ |
|
935 | - 'href' => $this->getVersionedLinkTo( |
|
936 | - EEH_Inflector::pluralize_and_lower($model->get_this_model_name()) |
|
937 | - . '/' |
|
938 | - . $entity_array[ $model->primary_key_name() ] |
|
939 | - ), |
|
940 | - ], |
|
941 | - ]; |
|
942 | - } |
|
943 | - $links['collection'] = [ |
|
944 | - [ |
|
945 | - 'href' => $this->getVersionedLinkTo( |
|
946 | - EEH_Inflector::pluralize_and_lower($model->get_this_model_name()) |
|
947 | - ), |
|
948 | - ], |
|
949 | - ]; |
|
950 | - // add links to related models |
|
951 | - if ($model->has_primary_key_field()) { |
|
952 | - foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) { |
|
953 | - $related_model_part = |
|
954 | - Read::getRelatedEntityName($relation_name, $relation_obj); |
|
955 | - $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = [ |
|
956 | - [ |
|
957 | - 'href' => $this->getVersionedLinkTo( |
|
958 | - EEH_Inflector::pluralize_and_lower($model->get_this_model_name()) |
|
959 | - . '/' |
|
960 | - . $entity_array[ $model->primary_key_name() ] |
|
961 | - . '/' |
|
962 | - . $related_model_part |
|
963 | - ), |
|
964 | - 'single' => $relation_obj instanceof EE_Belongs_To_Relation, |
|
965 | - ], |
|
966 | - ]; |
|
967 | - } |
|
968 | - } |
|
969 | - return $links; |
|
970 | - } |
|
971 | - |
|
972 | - |
|
973 | - /** |
|
974 | - * Adds the included models indicated in the request to the entity provided |
|
975 | - * |
|
976 | - * @param EEM_Base $model |
|
977 | - * @param WP_REST_Request $rest_request |
|
978 | - * @param array $entity_array |
|
979 | - * @param array $db_row |
|
980 | - * @param boolean $included_items_protected if the original item is password protected, don't include any |
|
981 | - * related models. |
|
982 | - * @return array the modified entity |
|
983 | - * @throws EE_Error |
|
984 | - * @throws ReflectionException |
|
985 | - */ |
|
986 | - protected function includeRequestedModels( |
|
987 | - EEM_Base $model, |
|
988 | - WP_REST_Request $rest_request, |
|
989 | - $entity_array, |
|
990 | - $db_row = [], |
|
991 | - $included_items_protected = false |
|
992 | - ) { |
|
993 | - // if $db_row not included, hope the entity array has what we need |
|
994 | - if (! $db_row) { |
|
995 | - $db_row = $entity_array; |
|
996 | - } |
|
997 | - $relation_settings = $this->getModelVersionInfo()->relationSettings($model); |
|
998 | - foreach ($relation_settings as $relation_name => $relation_obj) { |
|
999 | - $related_fields_to_include = $this->explodeAndGetItemsPrefixedWith( |
|
1000 | - $rest_request->get_param('include'), |
|
1001 | - $relation_name |
|
1002 | - ); |
|
1003 | - $related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith( |
|
1004 | - $rest_request->get_param('calculate'), |
|
1005 | - $relation_name |
|
1006 | - ); |
|
1007 | - // did they specify they wanted to include a related model, or |
|
1008 | - // specific fields from a related model? |
|
1009 | - // or did they specify to calculate a field from a related model? |
|
1010 | - if ($related_fields_to_include || $related_fields_to_calculate) { |
|
1011 | - // if so, we should include at least some part of the related model |
|
1012 | - $pretend_related_request = new WP_REST_Request(); |
|
1013 | - $pretend_related_request->set_query_params( |
|
1014 | - [ |
|
1015 | - 'caps' => $rest_request->get_param('caps'), |
|
1016 | - 'include' => $related_fields_to_include, |
|
1017 | - 'calculate' => $related_fields_to_calculate, |
|
1018 | - 'password' => $rest_request->get_param('password'), |
|
1019 | - ] |
|
1020 | - ); |
|
1021 | - $pretend_related_request->add_header('no_rest_headers', true); |
|
1022 | - $primary_model_query_params = $model->alter_query_params_to_restrict_by_ID( |
|
1023 | - $model->get_index_primary_key_string( |
|
1024 | - $model->deduce_fields_n_values_from_cols_n_values($db_row) |
|
1025 | - ) |
|
1026 | - ); |
|
1027 | - if (! $included_items_protected) { |
|
1028 | - try { |
|
1029 | - $related_results = $this->getEntitiesFromRelationUsingModelQueryParams( |
|
1030 | - $primary_model_query_params, |
|
1031 | - $relation_obj, |
|
1032 | - $pretend_related_request |
|
1033 | - ); |
|
1034 | - } catch (RestException $e) { |
|
1035 | - $related_results = null; |
|
1036 | - } |
|
1037 | - } else { |
|
1038 | - // they're protected, hide them. |
|
1039 | - $related_results = null; |
|
1040 | - $entity_array['_protected'][] = Read::getRelatedEntityName($relation_name, $relation_obj); |
|
1041 | - } |
|
1042 | - if ($related_results instanceof WP_Error || $related_results === null) { |
|
1043 | - $related_results = |
|
1044 | - $relation_obj instanceof EE_Belongs_To_Relation |
|
1045 | - ? null |
|
1046 | - : []; |
|
1047 | - } |
|
1048 | - $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results; |
|
1049 | - } |
|
1050 | - } |
|
1051 | - return $entity_array; |
|
1052 | - } |
|
1053 | - |
|
1054 | - |
|
1055 | - /** |
|
1056 | - * If the user has requested only specific properties (including meta properties like _links or _protected) |
|
1057 | - * remove everything else. |
|
1058 | - * |
|
1059 | - * @param EEM_Base $model |
|
1060 | - * @param WP_REST_Request $rest_request |
|
1061 | - * @param $entity_array |
|
1062 | - * @return array |
|
1063 | - * @throws EE_Error |
|
1064 | - * @since 4.9.74.p |
|
1065 | - */ |
|
1066 | - protected function includeOnlyRequestedProperties( |
|
1067 | - EEM_Base $model, |
|
1068 | - WP_REST_Request $rest_request, |
|
1069 | - $entity_array |
|
1070 | - ) { |
|
1071 | - |
|
1072 | - $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), ''); |
|
1073 | - $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model); |
|
1074 | - // if they passed in * or didn't specify any includes, return everything |
|
1075 | - if ( |
|
1076 | - ! in_array('*', $includes_for_this_model) |
|
1077 | - && ! empty($includes_for_this_model) |
|
1078 | - ) { |
|
1079 | - if ($model->has_primary_key_field()) { |
|
1080 | - // always include the primary key. ya just gotta know that at least |
|
1081 | - $includes_for_this_model[] = $model->primary_key_name(); |
|
1082 | - } |
|
1083 | - if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) { |
|
1084 | - $includes_for_this_model[] = '_calculated_fields'; |
|
1085 | - } |
|
1086 | - $entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model)); |
|
1087 | - } |
|
1088 | - return $entity_array; |
|
1089 | - } |
|
1090 | - |
|
1091 | - |
|
1092 | - /** |
|
1093 | - * Returns a new array with all the names of models removed. Eg |
|
1094 | - * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' ) |
|
1095 | - * |
|
1096 | - * @param array $arr |
|
1097 | - * @return array |
|
1098 | - */ |
|
1099 | - private function removeModelNamesFromArray($arr) |
|
1100 | - { |
|
1101 | - return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models)); |
|
1102 | - } |
|
1103 | - |
|
1104 | - |
|
1105 | - /** |
|
1106 | - * Gets the calculated fields for the response |
|
1107 | - * |
|
1108 | - * @param EEM_Base $model |
|
1109 | - * @param array $wpdb_row |
|
1110 | - * @param WP_REST_Request $rest_request |
|
1111 | - * @param boolean $row_is_protected whether this row is password protected or not |
|
1112 | - * @return stdClass the _calculations item in the entity |
|
1113 | - * @throws RestException if a default value has a PHP object, which should never do (and if we |
|
1114 | - * @throws EE_Error |
|
1115 | - * did, let's know about it ASAP, so let the exception bubble up) |
|
1116 | - */ |
|
1117 | - protected function getEntityCalculations($model, $wpdb_row, $rest_request, $row_is_protected = false) |
|
1118 | - { |
|
1119 | - $calculated_fields = $this->explodeAndGetItemsPrefixedWith( |
|
1120 | - $rest_request->get_param('calculate'), |
|
1121 | - '' |
|
1122 | - ); |
|
1123 | - // note: setting calculate=* doesn't do anything |
|
1124 | - $calculated_fields_to_return = new stdClass(); |
|
1125 | - $protected_fields = []; |
|
1126 | - foreach ($calculated_fields as $field_to_calculate) { |
|
1127 | - try { |
|
1128 | - // it's password protected, so they shouldn't be able to read this. Remove the value |
|
1129 | - $schema = $this->fields_calculator->getJsonSchemaForModel($model); |
|
1130 | - if ( |
|
1131 | - $row_is_protected |
|
1132 | - && isset($schema['properties'][ $field_to_calculate ]['protected']) |
|
1133 | - && $schema['properties'][ $field_to_calculate ]['protected'] |
|
1134 | - ) { |
|
1135 | - $calculated_value = null; |
|
1136 | - $protected_fields[] = $field_to_calculate; |
|
1137 | - if ($schema['properties'][ $field_to_calculate ]['type']) { |
|
1138 | - switch ($schema['properties'][ $field_to_calculate ]['type']) { |
|
1139 | - case 'boolean': |
|
1140 | - $calculated_value = false; |
|
1141 | - break; |
|
1142 | - case 'integer': |
|
1143 | - $calculated_value = 0; |
|
1144 | - break; |
|
1145 | - case 'string': |
|
1146 | - $calculated_value = ''; |
|
1147 | - break; |
|
1148 | - case 'array': |
|
1149 | - $calculated_value = []; |
|
1150 | - break; |
|
1151 | - case 'object': |
|
1152 | - $calculated_value = new stdClass(); |
|
1153 | - break; |
|
1154 | - } |
|
1155 | - } |
|
1156 | - } else { |
|
1157 | - $calculated_value = ModelDataTranslator::prepareFieldValueForJson( |
|
1158 | - null, |
|
1159 | - $this->fields_calculator->retrieveCalculatedFieldValue( |
|
1160 | - $model, |
|
1161 | - $field_to_calculate, |
|
1162 | - $wpdb_row, |
|
1163 | - $rest_request, |
|
1164 | - $this |
|
1165 | - ), |
|
1166 | - $this->getModelVersionInfo()->requestedVersion() |
|
1167 | - ); |
|
1168 | - } |
|
1169 | - $calculated_fields_to_return->{$field_to_calculate} = $calculated_value; |
|
1170 | - } catch (RestException $e) { |
|
1171 | - // if we don't have permission to read it, just leave it out. but let devs know about the problem |
|
1172 | - $this->setResponseHeader( |
|
1173 | - 'Notices-Field-Calculation-Errors[' |
|
1174 | - . $e->getStringCode() |
|
1175 | - . '][' |
|
1176 | - . $model->get_this_model_name() |
|
1177 | - . '][' |
|
1178 | - . $field_to_calculate |
|
1179 | - . ']', |
|
1180 | - $e->getMessage(), |
|
1181 | - true |
|
1182 | - ); |
|
1183 | - } |
|
1184 | - } |
|
1185 | - $calculated_fields_to_return->_protected = $protected_fields; |
|
1186 | - return $calculated_fields_to_return; |
|
1187 | - } |
|
1188 | - |
|
1189 | - |
|
1190 | - /** |
|
1191 | - * Gets the full URL to the resource, taking the requested version into account |
|
1192 | - * |
|
1193 | - * @param string $link_part_after_version_and_slash eg "events/10/datetimes" |
|
1194 | - * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes" |
|
1195 | - * @throws EE_Error |
|
1196 | - * @throws EE_Error |
|
1197 | - */ |
|
1198 | - public function getVersionedLinkTo($link_part_after_version_and_slash) |
|
1199 | - { |
|
1200 | - return rest_url( |
|
1201 | - EED_Core_Rest_Api::get_versioned_route_to( |
|
1202 | - $link_part_after_version_and_slash, |
|
1203 | - $this->getModelVersionInfo()->requestedVersion() |
|
1204 | - ) |
|
1205 | - ); |
|
1206 | - } |
|
1207 | - |
|
1208 | - |
|
1209 | - /** |
|
1210 | - * Gets the correct lowercase name for the relation in the API according |
|
1211 | - * to the relation's type |
|
1212 | - * |
|
1213 | - * @param string $relation_name |
|
1214 | - * @param EE_Model_Relation_Base $relation_obj |
|
1215 | - * @return string |
|
1216 | - */ |
|
1217 | - public static function getRelatedEntityName($relation_name, $relation_obj) |
|
1218 | - { |
|
1219 | - if ($relation_obj instanceof EE_Belongs_To_Relation) { |
|
1220 | - return strtolower($relation_name); |
|
1221 | - } else { |
|
1222 | - return EEH_Inflector::pluralize_and_lower($relation_name); |
|
1223 | - } |
|
1224 | - } |
|
1225 | - |
|
1226 | - |
|
1227 | - /** |
|
1228 | - * Gets the one model object with the specified id for the specified model |
|
1229 | - * |
|
1230 | - * @param EEM_Base $model |
|
1231 | - * @param WP_REST_Request $request |
|
1232 | - * @return array |
|
1233 | - * @throws EE_Error |
|
1234 | - * @throws EE_Error |
|
1235 | - * @throws ReflectionException |
|
1236 | - */ |
|
1237 | - public function getEntityFromModel($model, $request) |
|
1238 | - { |
|
1239 | - $context = $this->validateContext($request->get_param('caps')); |
|
1240 | - return $this->getOneOrReportPermissionError($model, $request, $context); |
|
1241 | - } |
|
1242 | - |
|
1243 | - |
|
1244 | - /** |
|
1245 | - * If a context is provided which isn't valid, maybe it was added in a future |
|
1246 | - * version so just treat it as a default read |
|
1247 | - * |
|
1248 | - * @param string $context |
|
1249 | - * @return string array key of EEM_Base::cap_contexts_to_cap_action_map() |
|
1250 | - */ |
|
1251 | - public function validateContext($context) |
|
1252 | - { |
|
1253 | - if (! $context) { |
|
1254 | - $context = EEM_Base::caps_read; |
|
1255 | - } |
|
1256 | - $valid_contexts = EEM_Base::valid_cap_contexts(); |
|
1257 | - if (in_array($context, $valid_contexts)) { |
|
1258 | - return $context; |
|
1259 | - } else { |
|
1260 | - return EEM_Base::caps_read; |
|
1261 | - } |
|
1262 | - } |
|
1263 | - |
|
1264 | - |
|
1265 | - /** |
|
1266 | - * Verifies the passed in value is an allowable default where conditions value. |
|
1267 | - * |
|
1268 | - * @param $default_query_params |
|
1269 | - * @return string |
|
1270 | - */ |
|
1271 | - public function validateDefaultQueryParams($default_query_params) |
|
1272 | - { |
|
1273 | - $valid_default_where_conditions_for_api_calls = [ |
|
1274 | - EEM_Base::default_where_conditions_all, |
|
1275 | - EEM_Base::default_where_conditions_minimum_all, |
|
1276 | - EEM_Base::default_where_conditions_minimum_others, |
|
1277 | - ]; |
|
1278 | - if (! $default_query_params) { |
|
1279 | - $default_query_params = EEM_Base::default_where_conditions_all; |
|
1280 | - } |
|
1281 | - if ( |
|
1282 | - in_array( |
|
1283 | - $default_query_params, |
|
1284 | - $valid_default_where_conditions_for_api_calls, |
|
1285 | - true |
|
1286 | - ) |
|
1287 | - ) { |
|
1288 | - return $default_query_params; |
|
1289 | - } |
|
1290 | - return EEM_Base::default_where_conditions_all; |
|
1291 | - } |
|
1292 | - |
|
1293 | - |
|
1294 | - /** |
|
1295 | - * Translates API filter get parameter into model query params @see |
|
1296 | - * https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions. |
|
1297 | - * Note: right now the query parameter keys for fields (and related fields) can be left as-is, but it's quite |
|
1298 | - * possible this will change someday. Also, this method's contents might be candidate for moving to |
|
1299 | - * Model_Data_Translator |
|
1300 | - * |
|
1301 | - * @param EEM_Base $model |
|
1302 | - * @param array $query_params |
|
1303 | - * @return array model query params (@see |
|
1304 | - * https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions) |
|
1305 | - * or FALSE to indicate that absolutely no results should be returned |
|
1306 | - * @throws EE_Error |
|
1307 | - * @throws RestException |
|
1308 | - */ |
|
1309 | - public function createModelQueryParams($model, $query_params) |
|
1310 | - { |
|
1311 | - $model_query_params = []; |
|
1312 | - if (isset($query_params['where'])) { |
|
1313 | - $model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
1314 | - $query_params['where'], |
|
1315 | - $model, |
|
1316 | - $this->getModelVersionInfo()->requestedVersion() |
|
1317 | - ); |
|
1318 | - } |
|
1319 | - if (isset($query_params['order_by'])) { |
|
1320 | - $order_by = $query_params['order_by']; |
|
1321 | - } elseif (isset($query_params['orderby'])) { |
|
1322 | - $order_by = $query_params['orderby']; |
|
1323 | - } else { |
|
1324 | - $order_by = null; |
|
1325 | - } |
|
1326 | - if ($order_by !== null) { |
|
1327 | - if (is_array($order_by)) { |
|
1328 | - $order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by); |
|
1329 | - } else { |
|
1330 | - // it's a single item |
|
1331 | - $order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by); |
|
1332 | - } |
|
1333 | - $model_query_params['order_by'] = $order_by; |
|
1334 | - } |
|
1335 | - if (isset($query_params['group_by'])) { |
|
1336 | - $group_by = $query_params['group_by']; |
|
1337 | - } elseif (isset($query_params['groupby'])) { |
|
1338 | - $group_by = $query_params['groupby']; |
|
1339 | - } else { |
|
1340 | - $group_by = array_keys($model->get_combined_primary_key_fields()); |
|
1341 | - } |
|
1342 | - // make sure they're all real names |
|
1343 | - if (is_array($group_by)) { |
|
1344 | - $group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by); |
|
1345 | - } |
|
1346 | - if ($group_by !== null) { |
|
1347 | - $model_query_params['group_by'] = $group_by; |
|
1348 | - } |
|
1349 | - if (isset($query_params['having'])) { |
|
1350 | - $model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
1351 | - $query_params['having'], |
|
1352 | - $model, |
|
1353 | - $this->getModelVersionInfo()->requestedVersion() |
|
1354 | - ); |
|
1355 | - } |
|
1356 | - if (isset($query_params['order'])) { |
|
1357 | - $model_query_params['order'] = $query_params['order']; |
|
1358 | - } |
|
1359 | - if (isset($query_params['mine'])) { |
|
1360 | - $model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params); |
|
1361 | - } |
|
1362 | - if (isset($query_params['limit'])) { |
|
1363 | - // limit should be either a string like '23' or '23,43', or an array with two items in it |
|
1364 | - if (! is_array($query_params['limit'])) { |
|
1365 | - $limit_array = explode(',', (string) $query_params['limit']); |
|
1366 | - } else { |
|
1367 | - $limit_array = $query_params['limit']; |
|
1368 | - } |
|
1369 | - $sanitized_limit = []; |
|
1370 | - foreach ($limit_array as $limit_part) { |
|
1371 | - if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) { |
|
1372 | - throw new EE_Error( |
|
1373 | - sprintf( |
|
1374 | - esc_html__( |
|
1375 | - // @codingStandardsIgnoreStart |
|
1376 | - 'An invalid limit filter was provided. It was: %s. If the EE4 JSON REST API weren\'t in debug mode, this message would not appear.', |
|
1377 | - // @codingStandardsIgnoreEnd |
|
1378 | - 'event_espresso' |
|
1379 | - ), |
|
1380 | - wp_json_encode($query_params['limit']) |
|
1381 | - ) |
|
1382 | - ); |
|
1383 | - } |
|
1384 | - $sanitized_limit[] = (int) $limit_part; |
|
1385 | - } |
|
1386 | - $model_query_params['limit'] = implode(',', $sanitized_limit); |
|
1387 | - } else { |
|
1388 | - $model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit(); |
|
1389 | - } |
|
1390 | - if (isset($query_params['caps'])) { |
|
1391 | - $model_query_params['caps'] = $this->validateContext($query_params['caps']); |
|
1392 | - } else { |
|
1393 | - $model_query_params['caps'] = EEM_Base::caps_read; |
|
1394 | - } |
|
1395 | - if (isset($query_params['default_where_conditions'])) { |
|
1396 | - $model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams( |
|
1397 | - $query_params['default_where_conditions'] |
|
1398 | - ); |
|
1399 | - } |
|
1400 | - // if this is a model protected by a password on another model, exclude the password protected |
|
1401 | - // entities by default. But if they passed in a password, try to show them all. If the password is wrong, |
|
1402 | - // though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword) |
|
1403 | - if ( |
|
1404 | - ! $model->hasPassword() |
|
1405 | - && $model->restrictedByRelatedModelPassword() |
|
1406 | - && $model_query_params['caps'] === EEM_Base::caps_read |
|
1407 | - ) { |
|
1408 | - if (empty($query_params['password'])) { |
|
1409 | - $model_query_params['exclude_protected'] = true; |
|
1410 | - } |
|
1411 | - } |
|
1412 | - |
|
1413 | - return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_params, $model); |
|
1414 | - } |
|
1415 | - |
|
1416 | - |
|
1417 | - /** |
|
1418 | - * Changes the REST-style query params for use in the models |
|
1419 | - * |
|
1420 | - * @param EEM_Base $model |
|
1421 | - * @param array $query_params sub-array from @see EEM_Base::get_all() |
|
1422 | - * @return array |
|
1423 | - * @deprecated |
|
1424 | - */ |
|
1425 | - public function prepareRestQueryParamsKeyForModels($model, $query_params) |
|
1426 | - { |
|
1427 | - $model_ready_query_params = []; |
|
1428 | - foreach ($query_params as $key => $value) { |
|
1429 | - $model_ready_query_params[ $key ] = is_array($value) |
|
1430 | - ? $this->prepareRestQueryParamsKeyForModels($model, $value) |
|
1431 | - : $value; |
|
1432 | - } |
|
1433 | - return $model_ready_query_params; |
|
1434 | - } |
|
1435 | - |
|
1436 | - |
|
1437 | - /** |
|
1438 | - * @param $model |
|
1439 | - * @param $query_params |
|
1440 | - * @return array |
|
1441 | - * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson() |
|
1442 | - */ |
|
1443 | - public function prepareRestQueryParamsValuesForModels($model, $query_params) |
|
1444 | - { |
|
1445 | - $model_ready_query_params = []; |
|
1446 | - foreach ($query_params as $key => $value) { |
|
1447 | - if (is_array($value)) { |
|
1448 | - $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value); |
|
1449 | - } else { |
|
1450 | - $model_ready_query_params[ $key ] = $value; |
|
1451 | - } |
|
1452 | - } |
|
1453 | - return $model_ready_query_params; |
|
1454 | - } |
|
1455 | - |
|
1456 | - |
|
1457 | - /** |
|
1458 | - * Explodes the string on commas, and only returns items with $prefix followed by a period. |
|
1459 | - * If no prefix is specified, returns items with no period. |
|
1460 | - * |
|
1461 | - * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' ) |
|
1462 | - * @param string $prefix "Event" or "foobar" |
|
1463 | - * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified |
|
1464 | - * we only return strings starting with that and a period; if no prefix was |
|
1465 | - * specified we return all items containing NO periods |
|
1466 | - */ |
|
1467 | - public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix) |
|
1468 | - { |
|
1469 | - if (is_string($string_to_explode)) { |
|
1470 | - $exploded_contents = explode(',', $string_to_explode); |
|
1471 | - } elseif (is_array($string_to_explode)) { |
|
1472 | - $exploded_contents = $string_to_explode; |
|
1473 | - } else { |
|
1474 | - $exploded_contents = []; |
|
1475 | - } |
|
1476 | - // if the string was empty, we want an empty array |
|
1477 | - $exploded_contents = array_filter($exploded_contents); |
|
1478 | - $contents_with_prefix = []; |
|
1479 | - foreach ($exploded_contents as $item) { |
|
1480 | - $item = trim($item); |
|
1481 | - // if no prefix was provided, so we look for items with no "." in them |
|
1482 | - if (! $prefix) { |
|
1483 | - // does this item have a period? |
|
1484 | - if (strpos($item, '.') === false) { |
|
1485 | - // if not, then its what we're looking for |
|
1486 | - $contents_with_prefix[] = $item; |
|
1487 | - } |
|
1488 | - } elseif (strpos($item, $prefix . '.') === 0) { |
|
1489 | - // this item has the prefix and a period, grab it |
|
1490 | - $contents_with_prefix[] = substr( |
|
1491 | - $item, |
|
1492 | - strpos($item, $prefix . '.') + strlen($prefix . '.') |
|
1493 | - ); |
|
1494 | - } elseif ($item === $prefix) { |
|
1495 | - // this item is JUST the prefix |
|
1496 | - // so let's grab everything after, which is a blank string |
|
1497 | - $contents_with_prefix[] = ''; |
|
1498 | - } |
|
1499 | - } |
|
1500 | - return $contents_with_prefix; |
|
1501 | - } |
|
1502 | - |
|
1503 | - |
|
1504 | - /** |
|
1505 | - * @param string $include_string @see Read:handle_request_get_all |
|
1506 | - * @param string $model_name |
|
1507 | - * @return array of fields for this model. If $model_name is provided, then |
|
1508 | - * the fields for that model, with the model's name removed from each. |
|
1509 | - * If $include_string was blank or '*' returns an empty array |
|
1510 | - * @throws EE_Error |
|
1511 | - * @throws EE_Error |
|
1512 | - * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with. |
|
1513 | - * Deprecated because its return values were really quite confusing- sometimes it |
|
1514 | - * returned an empty array (when the include string was blank or '*') or sometimes it |
|
1515 | - * returned array('*') (when you provided a model and a model of that kind was |
|
1516 | - * found). Parses the $include_string so we fetch all the field names relating to |
|
1517 | - * THIS model |
|
1518 | - * (ie have NO period in them), or for the provided model (ie start with the model |
|
1519 | - * name and then a period). |
|
1520 | - */ |
|
1521 | - public function extractIncludesForThisModel($include_string, $model_name = null) |
|
1522 | - { |
|
1523 | - if (is_array($include_string)) { |
|
1524 | - $include_string = implode(',', $include_string); |
|
1525 | - } |
|
1526 | - if ($include_string === '*' || $include_string === '') { |
|
1527 | - return []; |
|
1528 | - } |
|
1529 | - $includes = explode(',', $include_string); |
|
1530 | - $extracted_fields_to_include = []; |
|
1531 | - if ($model_name) { |
|
1532 | - foreach ($includes as $field_to_include) { |
|
1533 | - $field_to_include = trim($field_to_include); |
|
1534 | - if (strpos($field_to_include, $model_name . '.') === 0) { |
|
1535 | - // found the model name at the exact start |
|
1536 | - $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include); |
|
1537 | - $extracted_fields_to_include[] = $field_sans_model_name; |
|
1538 | - } elseif ($field_to_include == $model_name) { |
|
1539 | - $extracted_fields_to_include[] = '*'; |
|
1540 | - } |
|
1541 | - } |
|
1542 | - } else { |
|
1543 | - // look for ones with no period |
|
1544 | - foreach ($includes as $field_to_include) { |
|
1545 | - $field_to_include = trim($field_to_include); |
|
1546 | - if ( |
|
1547 | - strpos($field_to_include, '.') === false |
|
1548 | - && ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include) |
|
1549 | - ) { |
|
1550 | - $extracted_fields_to_include[] = $field_to_include; |
|
1551 | - } |
|
1552 | - } |
|
1553 | - } |
|
1554 | - return $extracted_fields_to_include; |
|
1555 | - } |
|
1556 | - |
|
1557 | - |
|
1558 | - /** |
|
1559 | - * Gets the single item using the model according to the request in the context given, otherwise |
|
1560 | - * returns that it's inaccessible to the current user |
|
1561 | - * |
|
1562 | - * @param EEM_Base $model |
|
1563 | - * @param WP_REST_Request $request |
|
1564 | - * @param null $context |
|
1565 | - * @return array |
|
1566 | - * @throws EE_Error |
|
1567 | - * @throws ReflectionException |
|
1568 | - */ |
|
1569 | - public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null) |
|
1570 | - { |
|
1571 | - $query_params = [[$model->primary_key_name() => $request->get_param('id')], 'limit' => 1]; |
|
1572 | - if ($model instanceof EEM_Soft_Delete_Base) { |
|
1573 | - $query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params); |
|
1574 | - } |
|
1575 | - $restricted_query_params = $query_params; |
|
1576 | - $restricted_query_params['caps'] = $context; |
|
1577 | - $this->setDebugInfo('model query params', $restricted_query_params); |
|
1578 | - $model_rows = $model->get_all_wpdb_results($restricted_query_params); |
|
1579 | - if (! empty($model_rows)) { |
|
1580 | - return $this->createEntityFromWpdbResult( |
|
1581 | - $model, |
|
1582 | - reset($model_rows), |
|
1583 | - $request |
|
1584 | - ); |
|
1585 | - } else { |
|
1586 | - // ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities |
|
1587 | - $lowercase_model_name = strtolower($model->get_this_model_name()); |
|
1588 | - if ($model->exists($query_params)) { |
|
1589 | - // you got shafted- it existed but we didn't want to tell you! |
|
1590 | - throw new RestException( |
|
1591 | - 'rest_user_cannot_' . $context, |
|
1592 | - sprintf( |
|
1593 | - esc_html__('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'), |
|
1594 | - $context, |
|
1595 | - $lowercase_model_name, |
|
1596 | - Capabilities::getMissingPermissionsString( |
|
1597 | - $model, |
|
1598 | - $context |
|
1599 | - ) |
|
1600 | - ), |
|
1601 | - ['status' => 403] |
|
1602 | - ); |
|
1603 | - } else { |
|
1604 | - // it's not you. It just doesn't exist |
|
1605 | - throw new RestException( |
|
1606 | - sprintf('rest_%s_invalid_id', $lowercase_model_name), |
|
1607 | - sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name), |
|
1608 | - ['status' => 404] |
|
1609 | - ); |
|
1610 | - } |
|
1611 | - } |
|
1612 | - } |
|
1613 | - |
|
1614 | - |
|
1615 | - /** |
|
1616 | - * Checks that if this content requires a password to be read, that it's been provided and is correct. |
|
1617 | - * |
|
1618 | - * @param EEM_Base $model |
|
1619 | - * @param array $model_row |
|
1620 | - * @param array $query_params Adds 'default_where_conditions' => 'minimum' |
|
1621 | - * to ensure we don't confuse trashed with password protected. |
|
1622 | - * @param WP_REST_Request $request |
|
1623 | - * @throws EE_Error |
|
1624 | - * @throws InvalidArgumentException |
|
1625 | - * @throws InvalidDataTypeException |
|
1626 | - * @throws InvalidInterfaceException |
|
1627 | - * @throws RestPasswordRequiredException |
|
1628 | - * @throws RestPasswordIncorrectException |
|
1629 | - * @throws ModelConfigurationException |
|
1630 | - * @throws ReflectionException |
|
1631 | - * @since 4.9.74.p |
|
1632 | - */ |
|
1633 | - protected function checkPassword(EEM_Base $model, $model_row, $query_params, WP_REST_Request $request) |
|
1634 | - { |
|
1635 | - $query_params['default_where_conditions'] = 'minimum'; |
|
1636 | - // stuff is only "protected" for front-end requests. Elsewhere, you either get full permission to access the object |
|
1637 | - // or you don't. |
|
1638 | - $request_caps = $request->get_param('caps'); |
|
1639 | - if (isset($request_caps) && $request_caps !== EEM_Base::caps_read) { |
|
1640 | - return; |
|
1641 | - } |
|
1642 | - // if this entity requires a password, they better give it and it better be right! |
|
1643 | - if ( |
|
1644 | - $model->hasPassword() |
|
1645 | - && $model_row[ $model->getPasswordField()->get_qualified_column() ] !== '' |
|
1646 | - ) { |
|
1647 | - if (empty($request['password'])) { |
|
1648 | - throw new RestPasswordRequiredException(); |
|
1649 | - } |
|
1650 | - if ( |
|
1651 | - ! hash_equals( |
|
1652 | - $model_row[ $model->getPasswordField()->get_qualified_column() ], |
|
1653 | - $request['password'] |
|
1654 | - ) |
|
1655 | - ) { |
|
1656 | - throw new RestPasswordIncorrectException(); |
|
1657 | - } |
|
1658 | - } elseif ( |
|
1659 | - // wait! maybe this content is password protected |
|
1660 | - $model->restrictedByRelatedModelPassword() |
|
1661 | - && $request->get_param('caps') === EEM_Base::caps_read |
|
1662 | - ) { |
|
1663 | - $password_supplied = $request->get_param('password'); |
|
1664 | - if (empty($password_supplied)) { |
|
1665 | - $query_params['exclude_protected'] = true; |
|
1666 | - if (! $model->exists($query_params)) { |
|
1667 | - throw new RestPasswordRequiredException(); |
|
1668 | - } |
|
1669 | - } else { |
|
1670 | - $query_params[0][ $model->modelChainAndPassword() ] = $password_supplied; |
|
1671 | - if (! $model->exists($query_params)) { |
|
1672 | - throw new RestPasswordIncorrectException(); |
|
1673 | - } |
|
1674 | - } |
|
1675 | - } |
|
1676 | - } |
|
52 | + /** |
|
53 | + * @var CalculatedModelFields |
|
54 | + */ |
|
55 | + protected $fields_calculator; |
|
56 | + |
|
57 | + |
|
58 | + /** |
|
59 | + * Read constructor. |
|
60 | + * |
|
61 | + * @param CalculatedModelFields $fields_calculator |
|
62 | + */ |
|
63 | + public function __construct(CalculatedModelFields $fields_calculator) |
|
64 | + { |
|
65 | + parent::__construct(); |
|
66 | + $this->fields_calculator = $fields_calculator; |
|
67 | + } |
|
68 | + |
|
69 | + |
|
70 | + /** |
|
71 | + * Handles requests to get all (or a filtered subset) of entities for a particular model |
|
72 | + * |
|
73 | + * @param WP_REST_Request $request |
|
74 | + * @param string $version |
|
75 | + * @param string $model_name |
|
76 | + * @return WP_REST_Response|WP_Error |
|
77 | + * @throws InvalidArgumentException |
|
78 | + * @throws InvalidDataTypeException |
|
79 | + * @throws InvalidInterfaceException |
|
80 | + */ |
|
81 | + public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name) |
|
82 | + { |
|
83 | + $controller = |
|
84 | + LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
|
85 | + try { |
|
86 | + $controller->setRequestedVersion($version); |
|
87 | + if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
88 | + return $controller->sendResponse( |
|
89 | + new WP_Error( |
|
90 | + 'endpoint_parsing_error', |
|
91 | + sprintf( |
|
92 | + esc_html__( |
|
93 | + 'There is no model for endpoint %s. Please contact event espresso support', |
|
94 | + 'event_espresso' |
|
95 | + ), |
|
96 | + $model_name |
|
97 | + ) |
|
98 | + ) |
|
99 | + ); |
|
100 | + } |
|
101 | + return $controller->sendResponse( |
|
102 | + $controller->getEntitiesFromModel( |
|
103 | + $controller->getModelVersionInfo()->loadModel($model_name), |
|
104 | + $request |
|
105 | + ) |
|
106 | + ); |
|
107 | + } catch (Exception $e) { |
|
108 | + return $controller->sendResponse($e); |
|
109 | + } |
|
110 | + } |
|
111 | + |
|
112 | + |
|
113 | + /** |
|
114 | + * Prepares and returns schema for any OPTIONS request. |
|
115 | + * |
|
116 | + * @param string $version The API endpoint version being used. |
|
117 | + * @param string $model_name Something like `Event` or `Registration` |
|
118 | + * @return array |
|
119 | + * @throws InvalidArgumentException |
|
120 | + * @throws InvalidDataTypeException |
|
121 | + * @throws InvalidInterfaceException |
|
122 | + */ |
|
123 | + public static function handleSchemaRequest($version, $model_name) |
|
124 | + { |
|
125 | + $controller = |
|
126 | + LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
|
127 | + try { |
|
128 | + $controller->setRequestedVersion($version); |
|
129 | + if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
130 | + return []; |
|
131 | + } |
|
132 | + // get the model for this version |
|
133 | + $model = $controller->getModelVersionInfo()->loadModel($model_name); |
|
134 | + $model_schema = new JsonModelSchema( |
|
135 | + $model, |
|
136 | + LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields') |
|
137 | + ); |
|
138 | + return $model_schema->getModelSchemaForRelations( |
|
139 | + $controller->getModelVersionInfo()->relationSettings($model), |
|
140 | + $controller->customizeSchemaForRestResponse( |
|
141 | + $model, |
|
142 | + $model_schema->getModelSchemaForFields( |
|
143 | + $controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model), |
|
144 | + $model_schema->getInitialSchemaStructure() |
|
145 | + ) |
|
146 | + ) |
|
147 | + ); |
|
148 | + } catch (Exception $e) { |
|
149 | + return []; |
|
150 | + } |
|
151 | + } |
|
152 | + |
|
153 | + |
|
154 | + /** |
|
155 | + * This loops through each field in the given schema for the model and does the following: |
|
156 | + * - add any extra fields that are REST API specific and related to existing fields. |
|
157 | + * - transform default values into the correct format for a REST API response. |
|
158 | + * |
|
159 | + * @param EEM_Base $model |
|
160 | + * @param array $schema |
|
161 | + * @return array The final schema. |
|
162 | + * @throws EE_Error |
|
163 | + * @throws EE_Error |
|
164 | + */ |
|
165 | + protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema) |
|
166 | + { |
|
167 | + foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) { |
|
168 | + $schema = $this->translateDefaultsForRestResponse( |
|
169 | + $field_name, |
|
170 | + $field, |
|
171 | + $this->maybeAddExtraFieldsToSchema($field_name, $field, $schema) |
|
172 | + ); |
|
173 | + } |
|
174 | + return $schema; |
|
175 | + } |
|
176 | + |
|
177 | + |
|
178 | + /** |
|
179 | + * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST |
|
180 | + * response. |
|
181 | + * |
|
182 | + * @param $field_name |
|
183 | + * @param EE_Model_Field_Base $field |
|
184 | + * @param array $schema |
|
185 | + * @return array |
|
186 | + * @throws RestException if a default value has a PHP object, which we should never do |
|
187 | + * (but if we did, let's know about it ASAP, so let the exception bubble up) |
|
188 | + * @throws EE_Error |
|
189 | + * |
|
190 | + */ |
|
191 | + protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema) |
|
192 | + { |
|
193 | + if (isset($schema['properties'][ $field_name ]['default'])) { |
|
194 | + if (is_array($schema['properties'][ $field_name ]['default'])) { |
|
195 | + foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) { |
|
196 | + if ($default_key === 'raw') { |
|
197 | + $schema['properties'][ $field_name ]['default'][ $default_key ] = |
|
198 | + ModelDataTranslator::prepareFieldValueForJson( |
|
199 | + $field, |
|
200 | + $default_value, |
|
201 | + $this->getModelVersionInfo()->requestedVersion() |
|
202 | + ); |
|
203 | + } |
|
204 | + } |
|
205 | + } else { |
|
206 | + $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson( |
|
207 | + $field, |
|
208 | + $schema['properties'][ $field_name ]['default'], |
|
209 | + $this->getModelVersionInfo()->requestedVersion() |
|
210 | + ); |
|
211 | + } |
|
212 | + } |
|
213 | + return $schema; |
|
214 | + } |
|
215 | + |
|
216 | + |
|
217 | + /** |
|
218 | + * Adds additional fields to the schema |
|
219 | + * The REST API returns a GMT value field for each datetime field in the resource. Thus the description about this |
|
220 | + * needs to be added to the schema. |
|
221 | + * |
|
222 | + * @param $field_name |
|
223 | + * @param EE_Model_Field_Base $field |
|
224 | + * @param array $schema |
|
225 | + * @return array |
|
226 | + */ |
|
227 | + protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema) |
|
228 | + { |
|
229 | + if ($field instanceof EE_Datetime_Field) { |
|
230 | + $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema(); |
|
231 | + // modify the description |
|
232 | + $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf( |
|
233 | + esc_html__('%s - the value for this field is in GMT.', 'event_espresso'), |
|
234 | + wp_specialchars_decode($field->get_nicename(), ENT_QUOTES) |
|
235 | + ); |
|
236 | + } |
|
237 | + return $schema; |
|
238 | + } |
|
239 | + |
|
240 | + |
|
241 | + /** |
|
242 | + * Used to figure out the route from the request when a `WP_REST_Request` object is not available |
|
243 | + * |
|
244 | + * @return string |
|
245 | + */ |
|
246 | + protected function getRouteFromRequest() |
|
247 | + { |
|
248 | + if ( |
|
249 | + isset($GLOBALS['wp']) |
|
250 | + && $GLOBALS['wp'] instanceof WP |
|
251 | + && isset($GLOBALS['wp']->query_vars['rest_route']) |
|
252 | + ) { |
|
253 | + return $GLOBALS['wp']->query_vars['rest_route']; |
|
254 | + } else { |
|
255 | + /** @var RequestInterface $request */ |
|
256 | + $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
257 | + return $request->serverParamIsSet('PATH_INFO') |
|
258 | + ? $request->getServerParam('PATH_INFO') |
|
259 | + : '/'; |
|
260 | + } |
|
261 | + } |
|
262 | + |
|
263 | + |
|
264 | + /** |
|
265 | + * Gets a single entity related to the model indicated in the path and its id |
|
266 | + * |
|
267 | + * @param WP_REST_Request $request |
|
268 | + * @param string $version |
|
269 | + * @param string $model_name |
|
270 | + * @return WP_REST_Response|WP_Error |
|
271 | + * @throws InvalidDataTypeException |
|
272 | + * @throws InvalidInterfaceException |
|
273 | + * @throws InvalidArgumentException |
|
274 | + */ |
|
275 | + public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name) |
|
276 | + { |
|
277 | + $controller = |
|
278 | + LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
|
279 | + try { |
|
280 | + $controller->setRequestedVersion($version); |
|
281 | + if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) { |
|
282 | + return $controller->sendResponse( |
|
283 | + new WP_Error( |
|
284 | + 'endpoint_parsing_error', |
|
285 | + sprintf( |
|
286 | + esc_html__( |
|
287 | + 'There is no model for endpoint %s. Please contact event espresso support', |
|
288 | + 'event_espresso' |
|
289 | + ), |
|
290 | + $model_name |
|
291 | + ) |
|
292 | + ) |
|
293 | + ); |
|
294 | + } |
|
295 | + return $controller->sendResponse( |
|
296 | + $controller->getEntityFromModel( |
|
297 | + $controller->getModelVersionInfo()->loadModel($model_name), |
|
298 | + $request |
|
299 | + ) |
|
300 | + ); |
|
301 | + } catch (Exception $e) { |
|
302 | + return $controller->sendResponse($e); |
|
303 | + } |
|
304 | + } |
|
305 | + |
|
306 | + |
|
307 | + /** |
|
308 | + * Gets all the related entities (or if its a belongs-to relation just the one) |
|
309 | + * to the item with the given id |
|
310 | + * |
|
311 | + * @param WP_REST_Request $request |
|
312 | + * @param string $version |
|
313 | + * @param string $model_name |
|
314 | + * @param string $related_model_name |
|
315 | + * @return WP_REST_Response|WP_Error |
|
316 | + * @throws InvalidDataTypeException |
|
317 | + * @throws InvalidInterfaceException |
|
318 | + * @throws InvalidArgumentException |
|
319 | + */ |
|
320 | + public static function handleRequestGetRelated( |
|
321 | + WP_REST_Request $request, |
|
322 | + $version, |
|
323 | + $model_name, |
|
324 | + $related_model_name |
|
325 | + ) { |
|
326 | + $controller = |
|
327 | + LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
|
328 | + try { |
|
329 | + $controller->setRequestedVersion($version); |
|
330 | + $main_model = $controller->validateModel($model_name); |
|
331 | + $controller->validateModel($related_model_name); |
|
332 | + return $controller->sendResponse( |
|
333 | + $controller->getEntitiesFromRelation( |
|
334 | + $request->get_param('id'), |
|
335 | + $main_model->related_settings_for($related_model_name), |
|
336 | + $request |
|
337 | + ) |
|
338 | + ); |
|
339 | + } catch (Exception $e) { |
|
340 | + return $controller->sendResponse($e); |
|
341 | + } |
|
342 | + } |
|
343 | + |
|
344 | + |
|
345 | + /** |
|
346 | + * Gets a collection for the given model and filters |
|
347 | + * |
|
348 | + * @param EEM_Base $model |
|
349 | + * @param WP_REST_Request $request |
|
350 | + * @return array |
|
351 | + * @throws EE_Error |
|
352 | + * @throws InvalidArgumentException |
|
353 | + * @throws InvalidDataTypeException |
|
354 | + * @throws InvalidInterfaceException |
|
355 | + * @throws ReflectionException |
|
356 | + * @throws RestException |
|
357 | + */ |
|
358 | + public function getEntitiesFromModel($model, $request) |
|
359 | + { |
|
360 | + $query_params = $this->createModelQueryParams($model, $request->get_params()); |
|
361 | + if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) { |
|
362 | + $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name()); |
|
363 | + throw new RestException( |
|
364 | + sprintf('rest_%s_cannot_list', $model_name_plural), |
|
365 | + sprintf( |
|
366 | + esc_html__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'), |
|
367 | + $model_name_plural, |
|
368 | + Capabilities::getMissingPermissionsString($model, $query_params['caps']) |
|
369 | + ), |
|
370 | + ['status' => 403] |
|
371 | + ); |
|
372 | + } |
|
373 | + if (! $request->get_header('no_rest_headers')) { |
|
374 | + $this->setHeadersFromQueryParams($model, $query_params); |
|
375 | + } |
|
376 | + /** @type array $results */ |
|
377 | + $results = $model->get_all_wpdb_results($query_params); |
|
378 | + $nice_results = []; |
|
379 | + foreach ($results as $result) { |
|
380 | + $nice_results[] = $this->createEntityFromWpdbResult( |
|
381 | + $model, |
|
382 | + $result, |
|
383 | + $request |
|
384 | + ); |
|
385 | + } |
|
386 | + return $nice_results; |
|
387 | + } |
|
388 | + |
|
389 | + |
|
390 | + /** |
|
391 | + * Gets the collection for given relation object |
|
392 | + * The same as Read::get_entities_from_model(), except if the relation |
|
393 | + * is a HABTM relation, in which case it merges any non-foreign-key fields from |
|
394 | + * the join-model-object into the results |
|
395 | + * |
|
396 | + * @param array $primary_model_query_params query params for finding the item from which |
|
397 | + * relations will be based |
|
398 | + * @param EE_Model_Relation_Base $relation |
|
399 | + * @param WP_REST_Request $request |
|
400 | + * @return array |
|
401 | + * @throws EE_Error |
|
402 | + * @throws InvalidArgumentException |
|
403 | + * @throws InvalidDataTypeException |
|
404 | + * @throws InvalidInterfaceException |
|
405 | + * @throws ReflectionException |
|
406 | + * @throws RestException |
|
407 | + * @throws ModelConfigurationException |
|
408 | + */ |
|
409 | + protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request) |
|
410 | + { |
|
411 | + $context = $this->validateContext($request->get_param('caps')); |
|
412 | + $model = $relation->get_this_model(); |
|
413 | + $related_model = $relation->get_other_model(); |
|
414 | + if (! isset($primary_model_query_params[0])) { |
|
415 | + $primary_model_query_params[0] = []; |
|
416 | + } |
|
417 | + // check if they can access the 1st model object |
|
418 | + $primary_model_query_params = [ |
|
419 | + 0 => $primary_model_query_params[0], |
|
420 | + 'limit' => 1, |
|
421 | + ]; |
|
422 | + if ($model instanceof EEM_Soft_Delete_Base) { |
|
423 | + $primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included( |
|
424 | + $primary_model_query_params |
|
425 | + ); |
|
426 | + } |
|
427 | + $restricted_query_params = $primary_model_query_params; |
|
428 | + $restricted_query_params['caps'] = $context; |
|
429 | + $restricted_query_params['limit'] = 1; |
|
430 | + $this->setDebugInfo('main model query params', $restricted_query_params); |
|
431 | + $this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context)); |
|
432 | + $primary_model_rows = $model->get_all_wpdb_results($restricted_query_params); |
|
433 | + $primary_model_row = null; |
|
434 | + if (is_array($primary_model_rows)) { |
|
435 | + $primary_model_row = reset($primary_model_rows); |
|
436 | + } |
|
437 | + if ( |
|
438 | + ! ( |
|
439 | + $primary_model_row |
|
440 | + && Capabilities::currentUserHasPartialAccessTo($related_model, $context) |
|
441 | + ) |
|
442 | + ) { |
|
443 | + if ($relation instanceof EE_Belongs_To_Relation) { |
|
444 | + $related_model_name_maybe_plural = strtolower($related_model->get_this_model_name()); |
|
445 | + } else { |
|
446 | + $related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower( |
|
447 | + $related_model->get_this_model_name() |
|
448 | + ); |
|
449 | + } |
|
450 | + throw new RestException( |
|
451 | + sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural), |
|
452 | + sprintf( |
|
453 | + esc_html__( |
|
454 | + 'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s', |
|
455 | + 'event_espresso' |
|
456 | + ), |
|
457 | + $related_model_name_maybe_plural, |
|
458 | + $relation->get_this_model()->get_this_model_name(), |
|
459 | + implode( |
|
460 | + ',', |
|
461 | + array_keys( |
|
462 | + Capabilities::getMissingPermissions($related_model, $context) |
|
463 | + ) |
|
464 | + ) |
|
465 | + ), |
|
466 | + ['status' => 403] |
|
467 | + ); |
|
468 | + } |
|
469 | + |
|
470 | + $this->checkPassword( |
|
471 | + $model, |
|
472 | + $primary_model_row, |
|
473 | + $restricted_query_params, |
|
474 | + $request |
|
475 | + ); |
|
476 | + $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params()); |
|
477 | + foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) { |
|
478 | + $query_params[0][ $relation->get_this_model()->get_this_model_name() |
|
479 | + . '.' |
|
480 | + . $where_condition_key ] = $where_condition_value; |
|
481 | + } |
|
482 | + $query_params['default_where_conditions'] = 'none'; |
|
483 | + $query_params['caps'] = $context; |
|
484 | + if (! $request->get_header('no_rest_headers')) { |
|
485 | + $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params); |
|
486 | + } |
|
487 | + /** @type array $results */ |
|
488 | + $results = $relation->get_other_model()->get_all_wpdb_results($query_params); |
|
489 | + $nice_results = []; |
|
490 | + foreach ($results as $result) { |
|
491 | + $nice_result = $this->createEntityFromWpdbResult( |
|
492 | + $relation->get_other_model(), |
|
493 | + $result, |
|
494 | + $request |
|
495 | + ); |
|
496 | + if ($relation instanceof EE_HABTM_Relation) { |
|
497 | + // put the unusual stuff (properties from the HABTM relation) first, and make sure |
|
498 | + // if there are conflicts we prefer the properties from the main model |
|
499 | + $join_model_result = $this->createEntityFromWpdbResult( |
|
500 | + $relation->get_join_model(), |
|
501 | + $result, |
|
502 | + $request |
|
503 | + ); |
|
504 | + $joined_result = array_merge($join_model_result, $nice_result); |
|
505 | + // but keep the meta stuff from the main model |
|
506 | + if (isset($nice_result['meta'])) { |
|
507 | + $joined_result['meta'] = $nice_result['meta']; |
|
508 | + } |
|
509 | + $nice_result = $joined_result; |
|
510 | + } |
|
511 | + $nice_results[] = $nice_result; |
|
512 | + } |
|
513 | + if ($relation instanceof EE_Belongs_To_Relation) { |
|
514 | + return array_shift($nice_results); |
|
515 | + } else { |
|
516 | + return $nice_results; |
|
517 | + } |
|
518 | + } |
|
519 | + |
|
520 | + |
|
521 | + /** |
|
522 | + * Gets the collection for given relation object |
|
523 | + * The same as Read::get_entities_from_model(), except if the relation |
|
524 | + * is a HABTM relation, in which case it merges any non-foreign-key fields from |
|
525 | + * the join-model-object into the results |
|
526 | + * |
|
527 | + * @param string $id the ID of the thing we are fetching related stuff from |
|
528 | + * @param EE_Model_Relation_Base $relation |
|
529 | + * @param WP_REST_Request $request |
|
530 | + * @return array |
|
531 | + * @throws EE_Error |
|
532 | + * @throws ReflectionException |
|
533 | + */ |
|
534 | + public function getEntitiesFromRelation($id, $relation, $request) |
|
535 | + { |
|
536 | + if (! $relation->get_this_model()->has_primary_key_field()) { |
|
537 | + throw new EE_Error( |
|
538 | + sprintf( |
|
539 | + esc_html__( |
|
540 | + // @codingStandardsIgnoreStart |
|
541 | + 'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s', |
|
542 | + // @codingStandardsIgnoreEnd |
|
543 | + 'event_espresso' |
|
544 | + ), |
|
545 | + $relation->get_this_model()->get_this_model_name() |
|
546 | + ) |
|
547 | + ); |
|
548 | + } |
|
549 | + // can we edit that main item? |
|
550 | + // if not, show nothing but an error |
|
551 | + // otherwise, please proceed |
|
552 | + return $this->getEntitiesFromRelationUsingModelQueryParams( |
|
553 | + [ |
|
554 | + [ |
|
555 | + $relation->get_this_model()->primary_key_name() => $id, |
|
556 | + ], |
|
557 | + ], |
|
558 | + $relation, |
|
559 | + $request |
|
560 | + ); |
|
561 | + } |
|
562 | + |
|
563 | + |
|
564 | + /** |
|
565 | + * Sets the headers that are based on the model and query params, |
|
566 | + * like the total records. This should only be called on the original request |
|
567 | + * from the client, not on subsequent internal |
|
568 | + * |
|
569 | + * @param EEM_Base $model |
|
570 | + * @param array $query_params |
|
571 | + * @return void |
|
572 | + * @throws EE_Error |
|
573 | + * @throws EE_Error |
|
574 | + */ |
|
575 | + protected function setHeadersFromQueryParams($model, $query_params) |
|
576 | + { |
|
577 | + $this->setDebugInfo('model query params', $query_params); |
|
578 | + $this->setDebugInfo( |
|
579 | + 'missing caps', |
|
580 | + Capabilities::getMissingPermissionsString($model, $query_params['caps']) |
|
581 | + ); |
|
582 | + // normally the limit to a 2-part array, where the 2nd item is the limit |
|
583 | + if (! isset($query_params['limit'])) { |
|
584 | + $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit(); |
|
585 | + } |
|
586 | + if (is_array($query_params['limit'])) { |
|
587 | + $limit_parts = $query_params['limit']; |
|
588 | + } else { |
|
589 | + $limit_parts = explode(',', $query_params['limit']); |
|
590 | + if (count($limit_parts) == 1) { |
|
591 | + $limit_parts = [0, $limit_parts[0]]; |
|
592 | + } |
|
593 | + } |
|
594 | + // remove the group by and having parts of the query, as those will |
|
595 | + // make the sql query return an array of values, instead of just a single value |
|
596 | + unset($query_params['group_by'], $query_params['having'], $query_params['limit']); |
|
597 | + $count = $model->count($query_params, null, true); |
|
598 | + $pages = $count / $limit_parts[1]; |
|
599 | + $this->setResponseHeader('Total', $count, false); |
|
600 | + $this->setResponseHeader('PageSize', $limit_parts[1], false); |
|
601 | + $this->setResponseHeader('TotalPages', ceil($pages), false); |
|
602 | + } |
|
603 | + |
|
604 | + |
|
605 | + /** |
|
606 | + * Changes database results into REST API entities |
|
607 | + * |
|
608 | + * @param EEM_Base $model |
|
609 | + * @param array $db_row like results from $wpdb->get_results() |
|
610 | + * @param WP_REST_Request $rest_request |
|
611 | + * @param string $deprecated no longer used |
|
612 | + * @return array ready for being converted into json for sending to client |
|
613 | + * @throws EE_Error |
|
614 | + * @throws RestException |
|
615 | + * @throws InvalidDataTypeException |
|
616 | + * @throws InvalidInterfaceException |
|
617 | + * @throws InvalidArgumentException |
|
618 | + * @throws ReflectionException |
|
619 | + */ |
|
620 | + public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null) |
|
621 | + { |
|
622 | + if (! $rest_request instanceof WP_REST_Request) { |
|
623 | + // ok so this was called in the old style, where the 3rd arg was |
|
624 | + // $include, and the 4th arg was $context |
|
625 | + // now setup the request just to avoid fatal errors, although we won't be able |
|
626 | + // to truly make use of it because it's kinda devoid of info |
|
627 | + $rest_request = new WP_REST_Request(); |
|
628 | + $rest_request->set_param('include', $rest_request); |
|
629 | + $rest_request->set_param('caps', $deprecated); |
|
630 | + } |
|
631 | + if ($rest_request->get_param('caps') == null) { |
|
632 | + $rest_request->set_param('caps', EEM_Base::caps_read); |
|
633 | + } |
|
634 | + $current_user_full_access_to_entity = $model->currentUserCan( |
|
635 | + EEM_Base::caps_read_admin, |
|
636 | + $model->deduce_fields_n_values_from_cols_n_values($db_row) |
|
637 | + ); |
|
638 | + $entity_array = $this->createBareEntityFromWpdbResults($model, $db_row); |
|
639 | + $entity_array = $this->addExtraFields($model, $db_row, $entity_array); |
|
640 | + $entity_array['_links'] = $this->getEntityLinks($model, $db_row, $entity_array); |
|
641 | + // when it's a regular read request for a model with a password and the password wasn't provided |
|
642 | + // remove the password protected fields |
|
643 | + $has_protected_fields = false; |
|
644 | + try { |
|
645 | + $this->checkPassword( |
|
646 | + $model, |
|
647 | + $db_row, |
|
648 | + $model->alter_query_params_to_restrict_by_ID( |
|
649 | + $model->get_index_primary_key_string( |
|
650 | + $model->deduce_fields_n_values_from_cols_n_values($db_row) |
|
651 | + ) |
|
652 | + ), |
|
653 | + $rest_request |
|
654 | + ); |
|
655 | + } catch (RestPasswordRequiredException $e) { |
|
656 | + if ($model->hasPassword()) { |
|
657 | + // just remove protected fields |
|
658 | + $has_protected_fields = true; |
|
659 | + $entity_array = Capabilities::filterOutPasswordProtectedFields( |
|
660 | + $entity_array, |
|
661 | + $model, |
|
662 | + $this->getModelVersionInfo() |
|
663 | + ); |
|
664 | + } else { |
|
665 | + // that's a problem. None of this should be accessible if no password was provided |
|
666 | + throw $e; |
|
667 | + } |
|
668 | + } |
|
669 | + |
|
670 | + $entity_array['_calculated_fields'] = |
|
671 | + $this->getEntityCalculations($model, $db_row, $rest_request, $has_protected_fields); |
|
672 | + $entity_array = apply_filters( |
|
673 | + 'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models', |
|
674 | + $entity_array, |
|
675 | + $model, |
|
676 | + $rest_request->get_param('caps'), |
|
677 | + $rest_request, |
|
678 | + $this |
|
679 | + ); |
|
680 | + // add an empty protected property for now. If it's still around after we remove everything the request didn't |
|
681 | + // want, we'll populate it then. k? |
|
682 | + $entity_array['_protected'] = []; |
|
683 | + // remove any properties the request didn't want. This way _protected won't bother mentioning them |
|
684 | + $entity_array = $this->includeOnlyRequestedProperties($model, $rest_request, $entity_array); |
|
685 | + $entity_array = |
|
686 | + $this->includeRequestedModels($model, $rest_request, $entity_array, $db_row, $has_protected_fields); |
|
687 | + // if they still wanted the _protected property, add it. |
|
688 | + if (isset($entity_array['_protected'])) { |
|
689 | + $entity_array = $this->addProtectedProperty($model, $entity_array, $has_protected_fields); |
|
690 | + } |
|
691 | + $entity_array = apply_filters( |
|
692 | + 'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal', |
|
693 | + $entity_array, |
|
694 | + $model, |
|
695 | + $rest_request->get_param('caps'), |
|
696 | + $rest_request, |
|
697 | + $this |
|
698 | + ); |
|
699 | + if (! $current_user_full_access_to_entity) { |
|
700 | + $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields( |
|
701 | + $entity_array, |
|
702 | + $model, |
|
703 | + $rest_request->get_param('caps'), |
|
704 | + $this->getModelVersionInfo() |
|
705 | + ); |
|
706 | + } else { |
|
707 | + $result_without_inaccessible_fields = $entity_array; |
|
708 | + } |
|
709 | + $this->setDebugInfo( |
|
710 | + 'inaccessible fields', |
|
711 | + array_keys(array_diff_key((array) $entity_array, (array) $result_without_inaccessible_fields)) |
|
712 | + ); |
|
713 | + return apply_filters( |
|
714 | + 'FHEE__Read__create_entity_from_wpdb_results__entity_return', |
|
715 | + $result_without_inaccessible_fields, |
|
716 | + $model, |
|
717 | + $rest_request->get_param('caps') |
|
718 | + ); |
|
719 | + } |
|
720 | + |
|
721 | + |
|
722 | + /** |
|
723 | + * Returns an array describing which fields can be protected, and which actually were removed this request |
|
724 | + * |
|
725 | + * @param EEM_Base $model |
|
726 | + * @param array $results_so_far |
|
727 | + * @param bool $protected |
|
728 | + * @return array results |
|
729 | + * @throws EE_Error |
|
730 | + * @since 4.9.74.p |
|
731 | + */ |
|
732 | + protected function addProtectedProperty(EEM_Base $model, $results_so_far, $protected) |
|
733 | + { |
|
734 | + if (! $model->hasPassword() || ! $protected) { |
|
735 | + return $results_so_far; |
|
736 | + } |
|
737 | + $password_field = $model->getPasswordField(); |
|
738 | + $all_protected = array_merge( |
|
739 | + [$password_field->get_name()], |
|
740 | + $password_field->protectedFields() |
|
741 | + ); |
|
742 | + $fields_included = array_keys($results_so_far); |
|
743 | + $fields_included = array_intersect( |
|
744 | + $all_protected, |
|
745 | + $fields_included |
|
746 | + ); |
|
747 | + foreach ($fields_included as $field_name) { |
|
748 | + $results_so_far['_protected'][] = $field_name; |
|
749 | + } |
|
750 | + return $results_so_far; |
|
751 | + } |
|
752 | + |
|
753 | + |
|
754 | + /** |
|
755 | + * Creates a REST entity array (JSON object we're going to return in the response, but |
|
756 | + * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry), |
|
757 | + * from $wpdb->get_row( $sql, ARRAY_A) |
|
758 | + * |
|
759 | + * @param EEM_Base $model |
|
760 | + * @param array $db_row |
|
761 | + * @return array entity mostly ready for converting to JSON and sending in the response |
|
762 | + * @throws EE_Error |
|
763 | + * @throws ReflectionException |
|
764 | + * @throws RestException |
|
765 | + */ |
|
766 | + protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row) |
|
767 | + { |
|
768 | + $result = $model->deduce_fields_n_values_from_cols_n_values($db_row); |
|
769 | + $result = array_intersect_key( |
|
770 | + $result, |
|
771 | + $this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) |
|
772 | + ); |
|
773 | + // if this is a CPT, we need to set the global $post to it, |
|
774 | + // otherwise shortcodes etc won't work properly while rendering it |
|
775 | + if ($model instanceof EEM_CPT_Base) { |
|
776 | + $do_chevy_shuffle = true; |
|
777 | + } else { |
|
778 | + $do_chevy_shuffle = false; |
|
779 | + } |
|
780 | + if ($do_chevy_shuffle) { |
|
781 | + global $post; |
|
782 | + $old_post = $post; |
|
783 | + $post = get_post($result[ $model->primary_key_name() ]); |
|
784 | + if (! $post instanceof WP_Post) { |
|
785 | + // well that's weird, because $result is what we JUST fetched from the database |
|
786 | + throw new RestException( |
|
787 | + 'error_fetching_post_from_database_results', |
|
788 | + esc_html__( |
|
789 | + 'An item was retrieved from the database but it\'s not a WP_Post like it should be.', |
|
790 | + 'event_espresso' |
|
791 | + ) |
|
792 | + ); |
|
793 | + } |
|
794 | + $model_object_classname = 'EE_' . $model->get_this_model_name(); |
|
795 | + $post->{$model_object_classname} = EE_Registry::instance()->load_class( |
|
796 | + $model_object_classname, |
|
797 | + $result, |
|
798 | + false, |
|
799 | + false |
|
800 | + ); |
|
801 | + } |
|
802 | + foreach ($result as $field_name => $field_value) { |
|
803 | + $field_obj = $model->field_settings_for($field_name); |
|
804 | + if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) { |
|
805 | + unset($result[ $field_name ]); |
|
806 | + } elseif ( |
|
807 | + $this->isSubclassOfOne( |
|
808 | + $field_obj, |
|
809 | + $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat() |
|
810 | + ) |
|
811 | + ) { |
|
812 | + $result[ $field_name ] = [ |
|
813 | + 'raw' => $this->prepareFieldObjValueForJson($field_obj, $field_value), |
|
814 | + 'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'), |
|
815 | + ]; |
|
816 | + } elseif ( |
|
817 | + $this->isSubclassOfOne( |
|
818 | + $field_obj, |
|
819 | + $this->getModelVersionInfo()->fieldsThatHavePrettyFormat() |
|
820 | + ) |
|
821 | + ) { |
|
822 | + $result[ $field_name ] = [ |
|
823 | + 'raw' => $this->prepareFieldObjValueForJson($field_obj, $field_value), |
|
824 | + 'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'), |
|
825 | + ]; |
|
826 | + } elseif ($field_obj instanceof EE_Datetime_Field) { |
|
827 | + $field_value = $field_obj->prepare_for_set_from_db($field_value); |
|
828 | + // if the value is null, but we're not supposed to permit null, then set to the field's default |
|
829 | + if (is_null($field_value)) { |
|
830 | + $field_value = $field_obj->getDefaultDateTimeObj(); |
|
831 | + } |
|
832 | + if (is_null($field_value)) { |
|
833 | + $gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson( |
|
834 | + $field_obj, |
|
835 | + $field_value, |
|
836 | + $this->getModelVersionInfo()->requestedVersion() |
|
837 | + ); |
|
838 | + } else { |
|
839 | + $timezone = $field_value->getTimezone(); |
|
840 | + EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC')); |
|
841 | + $gmt_date = ModelDataTranslator::prepareFieldValuesForJson( |
|
842 | + $field_obj, |
|
843 | + $field_value, |
|
844 | + $this->getModelVersionInfo()->requestedVersion() |
|
845 | + ); |
|
846 | + EEH_DTT_Helper::setTimezone($field_value, $timezone); |
|
847 | + $local_date = ModelDataTranslator::prepareFieldValuesForJson( |
|
848 | + $field_obj, |
|
849 | + $field_value, |
|
850 | + $this->getModelVersionInfo()->requestedVersion() |
|
851 | + ); |
|
852 | + } |
|
853 | + $result[ $field_name . '_gmt' ] = $gmt_date; |
|
854 | + $result[ $field_name ] = $local_date; |
|
855 | + } else { |
|
856 | + $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value); |
|
857 | + } |
|
858 | + } |
|
859 | + if ($do_chevy_shuffle) { |
|
860 | + $post = $old_post; |
|
861 | + } |
|
862 | + return $result; |
|
863 | + } |
|
864 | + |
|
865 | + |
|
866 | + /** |
|
867 | + * Takes a value all the way from the DB representation, to the model object's representation, to the |
|
868 | + * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB |
|
869 | + * representation using $field_obj->prepare_for_set_from_db()) |
|
870 | + * |
|
871 | + * @param EE_Model_Field_Base $field_obj |
|
872 | + * @param mixed $value as it's stored on a model object |
|
873 | + * @param string $format valid values are 'normal' (default), 'pretty', 'datetime_obj' |
|
874 | + * @return array |
|
875 | + * @throws RestException if $value contains a PHP object |
|
876 | + * @throws EE_Error |
|
877 | + */ |
|
878 | + protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal') |
|
879 | + { |
|
880 | + $value = $field_obj->prepare_for_set_from_db($value); |
|
881 | + switch ($format) { |
|
882 | + case 'pretty': |
|
883 | + $value = $field_obj->prepare_for_pretty_echoing($value); |
|
884 | + break; |
|
885 | + case 'normal': |
|
886 | + default: |
|
887 | + $value = $field_obj->prepare_for_get($value); |
|
888 | + break; |
|
889 | + } |
|
890 | + return ModelDataTranslator::prepareFieldValuesForJson( |
|
891 | + $field_obj, |
|
892 | + $value, |
|
893 | + $this->getModelVersionInfo()->requestedVersion() |
|
894 | + ); |
|
895 | + } |
|
896 | + |
|
897 | + |
|
898 | + /** |
|
899 | + * Adds a few extra fields to the entity response |
|
900 | + * |
|
901 | + * @param EEM_Base $model |
|
902 | + * @param array $db_row |
|
903 | + * @param array $entity_array |
|
904 | + * @return array modified entity |
|
905 | + * @throws EE_Error |
|
906 | + * @throws EE_Error |
|
907 | + */ |
|
908 | + protected function addExtraFields(EEM_Base $model, $db_row, $entity_array) |
|
909 | + { |
|
910 | + if ($model instanceof EEM_CPT_Base) { |
|
911 | + $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]); |
|
912 | + } |
|
913 | + return $entity_array; |
|
914 | + } |
|
915 | + |
|
916 | + |
|
917 | + /** |
|
918 | + * Gets links we want to add to the response |
|
919 | + * |
|
920 | + * @param EEM_Base $model |
|
921 | + * @param array $db_row |
|
922 | + * @param array $entity_array |
|
923 | + * @return array the _links item in the entity |
|
924 | + * @throws EE_Error |
|
925 | + * @throws EE_Error |
|
926 | + * @global WP_REST_Server $wp_rest_server |
|
927 | + */ |
|
928 | + protected function getEntityLinks($model, $db_row, $entity_array) |
|
929 | + { |
|
930 | + // add basic links |
|
931 | + $links = []; |
|
932 | + if ($model->has_primary_key_field()) { |
|
933 | + $links['self'] = [ |
|
934 | + [ |
|
935 | + 'href' => $this->getVersionedLinkTo( |
|
936 | + EEH_Inflector::pluralize_and_lower($model->get_this_model_name()) |
|
937 | + . '/' |
|
938 | + . $entity_array[ $model->primary_key_name() ] |
|
939 | + ), |
|
940 | + ], |
|
941 | + ]; |
|
942 | + } |
|
943 | + $links['collection'] = [ |
|
944 | + [ |
|
945 | + 'href' => $this->getVersionedLinkTo( |
|
946 | + EEH_Inflector::pluralize_and_lower($model->get_this_model_name()) |
|
947 | + ), |
|
948 | + ], |
|
949 | + ]; |
|
950 | + // add links to related models |
|
951 | + if ($model->has_primary_key_field()) { |
|
952 | + foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) { |
|
953 | + $related_model_part = |
|
954 | + Read::getRelatedEntityName($relation_name, $relation_obj); |
|
955 | + $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = [ |
|
956 | + [ |
|
957 | + 'href' => $this->getVersionedLinkTo( |
|
958 | + EEH_Inflector::pluralize_and_lower($model->get_this_model_name()) |
|
959 | + . '/' |
|
960 | + . $entity_array[ $model->primary_key_name() ] |
|
961 | + . '/' |
|
962 | + . $related_model_part |
|
963 | + ), |
|
964 | + 'single' => $relation_obj instanceof EE_Belongs_To_Relation, |
|
965 | + ], |
|
966 | + ]; |
|
967 | + } |
|
968 | + } |
|
969 | + return $links; |
|
970 | + } |
|
971 | + |
|
972 | + |
|
973 | + /** |
|
974 | + * Adds the included models indicated in the request to the entity provided |
|
975 | + * |
|
976 | + * @param EEM_Base $model |
|
977 | + * @param WP_REST_Request $rest_request |
|
978 | + * @param array $entity_array |
|
979 | + * @param array $db_row |
|
980 | + * @param boolean $included_items_protected if the original item is password protected, don't include any |
|
981 | + * related models. |
|
982 | + * @return array the modified entity |
|
983 | + * @throws EE_Error |
|
984 | + * @throws ReflectionException |
|
985 | + */ |
|
986 | + protected function includeRequestedModels( |
|
987 | + EEM_Base $model, |
|
988 | + WP_REST_Request $rest_request, |
|
989 | + $entity_array, |
|
990 | + $db_row = [], |
|
991 | + $included_items_protected = false |
|
992 | + ) { |
|
993 | + // if $db_row not included, hope the entity array has what we need |
|
994 | + if (! $db_row) { |
|
995 | + $db_row = $entity_array; |
|
996 | + } |
|
997 | + $relation_settings = $this->getModelVersionInfo()->relationSettings($model); |
|
998 | + foreach ($relation_settings as $relation_name => $relation_obj) { |
|
999 | + $related_fields_to_include = $this->explodeAndGetItemsPrefixedWith( |
|
1000 | + $rest_request->get_param('include'), |
|
1001 | + $relation_name |
|
1002 | + ); |
|
1003 | + $related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith( |
|
1004 | + $rest_request->get_param('calculate'), |
|
1005 | + $relation_name |
|
1006 | + ); |
|
1007 | + // did they specify they wanted to include a related model, or |
|
1008 | + // specific fields from a related model? |
|
1009 | + // or did they specify to calculate a field from a related model? |
|
1010 | + if ($related_fields_to_include || $related_fields_to_calculate) { |
|
1011 | + // if so, we should include at least some part of the related model |
|
1012 | + $pretend_related_request = new WP_REST_Request(); |
|
1013 | + $pretend_related_request->set_query_params( |
|
1014 | + [ |
|
1015 | + 'caps' => $rest_request->get_param('caps'), |
|
1016 | + 'include' => $related_fields_to_include, |
|
1017 | + 'calculate' => $related_fields_to_calculate, |
|
1018 | + 'password' => $rest_request->get_param('password'), |
|
1019 | + ] |
|
1020 | + ); |
|
1021 | + $pretend_related_request->add_header('no_rest_headers', true); |
|
1022 | + $primary_model_query_params = $model->alter_query_params_to_restrict_by_ID( |
|
1023 | + $model->get_index_primary_key_string( |
|
1024 | + $model->deduce_fields_n_values_from_cols_n_values($db_row) |
|
1025 | + ) |
|
1026 | + ); |
|
1027 | + if (! $included_items_protected) { |
|
1028 | + try { |
|
1029 | + $related_results = $this->getEntitiesFromRelationUsingModelQueryParams( |
|
1030 | + $primary_model_query_params, |
|
1031 | + $relation_obj, |
|
1032 | + $pretend_related_request |
|
1033 | + ); |
|
1034 | + } catch (RestException $e) { |
|
1035 | + $related_results = null; |
|
1036 | + } |
|
1037 | + } else { |
|
1038 | + // they're protected, hide them. |
|
1039 | + $related_results = null; |
|
1040 | + $entity_array['_protected'][] = Read::getRelatedEntityName($relation_name, $relation_obj); |
|
1041 | + } |
|
1042 | + if ($related_results instanceof WP_Error || $related_results === null) { |
|
1043 | + $related_results = |
|
1044 | + $relation_obj instanceof EE_Belongs_To_Relation |
|
1045 | + ? null |
|
1046 | + : []; |
|
1047 | + } |
|
1048 | + $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results; |
|
1049 | + } |
|
1050 | + } |
|
1051 | + return $entity_array; |
|
1052 | + } |
|
1053 | + |
|
1054 | + |
|
1055 | + /** |
|
1056 | + * If the user has requested only specific properties (including meta properties like _links or _protected) |
|
1057 | + * remove everything else. |
|
1058 | + * |
|
1059 | + * @param EEM_Base $model |
|
1060 | + * @param WP_REST_Request $rest_request |
|
1061 | + * @param $entity_array |
|
1062 | + * @return array |
|
1063 | + * @throws EE_Error |
|
1064 | + * @since 4.9.74.p |
|
1065 | + */ |
|
1066 | + protected function includeOnlyRequestedProperties( |
|
1067 | + EEM_Base $model, |
|
1068 | + WP_REST_Request $rest_request, |
|
1069 | + $entity_array |
|
1070 | + ) { |
|
1071 | + |
|
1072 | + $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), ''); |
|
1073 | + $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model); |
|
1074 | + // if they passed in * or didn't specify any includes, return everything |
|
1075 | + if ( |
|
1076 | + ! in_array('*', $includes_for_this_model) |
|
1077 | + && ! empty($includes_for_this_model) |
|
1078 | + ) { |
|
1079 | + if ($model->has_primary_key_field()) { |
|
1080 | + // always include the primary key. ya just gotta know that at least |
|
1081 | + $includes_for_this_model[] = $model->primary_key_name(); |
|
1082 | + } |
|
1083 | + if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) { |
|
1084 | + $includes_for_this_model[] = '_calculated_fields'; |
|
1085 | + } |
|
1086 | + $entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model)); |
|
1087 | + } |
|
1088 | + return $entity_array; |
|
1089 | + } |
|
1090 | + |
|
1091 | + |
|
1092 | + /** |
|
1093 | + * Returns a new array with all the names of models removed. Eg |
|
1094 | + * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' ) |
|
1095 | + * |
|
1096 | + * @param array $arr |
|
1097 | + * @return array |
|
1098 | + */ |
|
1099 | + private function removeModelNamesFromArray($arr) |
|
1100 | + { |
|
1101 | + return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models)); |
|
1102 | + } |
|
1103 | + |
|
1104 | + |
|
1105 | + /** |
|
1106 | + * Gets the calculated fields for the response |
|
1107 | + * |
|
1108 | + * @param EEM_Base $model |
|
1109 | + * @param array $wpdb_row |
|
1110 | + * @param WP_REST_Request $rest_request |
|
1111 | + * @param boolean $row_is_protected whether this row is password protected or not |
|
1112 | + * @return stdClass the _calculations item in the entity |
|
1113 | + * @throws RestException if a default value has a PHP object, which should never do (and if we |
|
1114 | + * @throws EE_Error |
|
1115 | + * did, let's know about it ASAP, so let the exception bubble up) |
|
1116 | + */ |
|
1117 | + protected function getEntityCalculations($model, $wpdb_row, $rest_request, $row_is_protected = false) |
|
1118 | + { |
|
1119 | + $calculated_fields = $this->explodeAndGetItemsPrefixedWith( |
|
1120 | + $rest_request->get_param('calculate'), |
|
1121 | + '' |
|
1122 | + ); |
|
1123 | + // note: setting calculate=* doesn't do anything |
|
1124 | + $calculated_fields_to_return = new stdClass(); |
|
1125 | + $protected_fields = []; |
|
1126 | + foreach ($calculated_fields as $field_to_calculate) { |
|
1127 | + try { |
|
1128 | + // it's password protected, so they shouldn't be able to read this. Remove the value |
|
1129 | + $schema = $this->fields_calculator->getJsonSchemaForModel($model); |
|
1130 | + if ( |
|
1131 | + $row_is_protected |
|
1132 | + && isset($schema['properties'][ $field_to_calculate ]['protected']) |
|
1133 | + && $schema['properties'][ $field_to_calculate ]['protected'] |
|
1134 | + ) { |
|
1135 | + $calculated_value = null; |
|
1136 | + $protected_fields[] = $field_to_calculate; |
|
1137 | + if ($schema['properties'][ $field_to_calculate ]['type']) { |
|
1138 | + switch ($schema['properties'][ $field_to_calculate ]['type']) { |
|
1139 | + case 'boolean': |
|
1140 | + $calculated_value = false; |
|
1141 | + break; |
|
1142 | + case 'integer': |
|
1143 | + $calculated_value = 0; |
|
1144 | + break; |
|
1145 | + case 'string': |
|
1146 | + $calculated_value = ''; |
|
1147 | + break; |
|
1148 | + case 'array': |
|
1149 | + $calculated_value = []; |
|
1150 | + break; |
|
1151 | + case 'object': |
|
1152 | + $calculated_value = new stdClass(); |
|
1153 | + break; |
|
1154 | + } |
|
1155 | + } |
|
1156 | + } else { |
|
1157 | + $calculated_value = ModelDataTranslator::prepareFieldValueForJson( |
|
1158 | + null, |
|
1159 | + $this->fields_calculator->retrieveCalculatedFieldValue( |
|
1160 | + $model, |
|
1161 | + $field_to_calculate, |
|
1162 | + $wpdb_row, |
|
1163 | + $rest_request, |
|
1164 | + $this |
|
1165 | + ), |
|
1166 | + $this->getModelVersionInfo()->requestedVersion() |
|
1167 | + ); |
|
1168 | + } |
|
1169 | + $calculated_fields_to_return->{$field_to_calculate} = $calculated_value; |
|
1170 | + } catch (RestException $e) { |
|
1171 | + // if we don't have permission to read it, just leave it out. but let devs know about the problem |
|
1172 | + $this->setResponseHeader( |
|
1173 | + 'Notices-Field-Calculation-Errors[' |
|
1174 | + . $e->getStringCode() |
|
1175 | + . '][' |
|
1176 | + . $model->get_this_model_name() |
|
1177 | + . '][' |
|
1178 | + . $field_to_calculate |
|
1179 | + . ']', |
|
1180 | + $e->getMessage(), |
|
1181 | + true |
|
1182 | + ); |
|
1183 | + } |
|
1184 | + } |
|
1185 | + $calculated_fields_to_return->_protected = $protected_fields; |
|
1186 | + return $calculated_fields_to_return; |
|
1187 | + } |
|
1188 | + |
|
1189 | + |
|
1190 | + /** |
|
1191 | + * Gets the full URL to the resource, taking the requested version into account |
|
1192 | + * |
|
1193 | + * @param string $link_part_after_version_and_slash eg "events/10/datetimes" |
|
1194 | + * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes" |
|
1195 | + * @throws EE_Error |
|
1196 | + * @throws EE_Error |
|
1197 | + */ |
|
1198 | + public function getVersionedLinkTo($link_part_after_version_and_slash) |
|
1199 | + { |
|
1200 | + return rest_url( |
|
1201 | + EED_Core_Rest_Api::get_versioned_route_to( |
|
1202 | + $link_part_after_version_and_slash, |
|
1203 | + $this->getModelVersionInfo()->requestedVersion() |
|
1204 | + ) |
|
1205 | + ); |
|
1206 | + } |
|
1207 | + |
|
1208 | + |
|
1209 | + /** |
|
1210 | + * Gets the correct lowercase name for the relation in the API according |
|
1211 | + * to the relation's type |
|
1212 | + * |
|
1213 | + * @param string $relation_name |
|
1214 | + * @param EE_Model_Relation_Base $relation_obj |
|
1215 | + * @return string |
|
1216 | + */ |
|
1217 | + public static function getRelatedEntityName($relation_name, $relation_obj) |
|
1218 | + { |
|
1219 | + if ($relation_obj instanceof EE_Belongs_To_Relation) { |
|
1220 | + return strtolower($relation_name); |
|
1221 | + } else { |
|
1222 | + return EEH_Inflector::pluralize_and_lower($relation_name); |
|
1223 | + } |
|
1224 | + } |
|
1225 | + |
|
1226 | + |
|
1227 | + /** |
|
1228 | + * Gets the one model object with the specified id for the specified model |
|
1229 | + * |
|
1230 | + * @param EEM_Base $model |
|
1231 | + * @param WP_REST_Request $request |
|
1232 | + * @return array |
|
1233 | + * @throws EE_Error |
|
1234 | + * @throws EE_Error |
|
1235 | + * @throws ReflectionException |
|
1236 | + */ |
|
1237 | + public function getEntityFromModel($model, $request) |
|
1238 | + { |
|
1239 | + $context = $this->validateContext($request->get_param('caps')); |
|
1240 | + return $this->getOneOrReportPermissionError($model, $request, $context); |
|
1241 | + } |
|
1242 | + |
|
1243 | + |
|
1244 | + /** |
|
1245 | + * If a context is provided which isn't valid, maybe it was added in a future |
|
1246 | + * version so just treat it as a default read |
|
1247 | + * |
|
1248 | + * @param string $context |
|
1249 | + * @return string array key of EEM_Base::cap_contexts_to_cap_action_map() |
|
1250 | + */ |
|
1251 | + public function validateContext($context) |
|
1252 | + { |
|
1253 | + if (! $context) { |
|
1254 | + $context = EEM_Base::caps_read; |
|
1255 | + } |
|
1256 | + $valid_contexts = EEM_Base::valid_cap_contexts(); |
|
1257 | + if (in_array($context, $valid_contexts)) { |
|
1258 | + return $context; |
|
1259 | + } else { |
|
1260 | + return EEM_Base::caps_read; |
|
1261 | + } |
|
1262 | + } |
|
1263 | + |
|
1264 | + |
|
1265 | + /** |
|
1266 | + * Verifies the passed in value is an allowable default where conditions value. |
|
1267 | + * |
|
1268 | + * @param $default_query_params |
|
1269 | + * @return string |
|
1270 | + */ |
|
1271 | + public function validateDefaultQueryParams($default_query_params) |
|
1272 | + { |
|
1273 | + $valid_default_where_conditions_for_api_calls = [ |
|
1274 | + EEM_Base::default_where_conditions_all, |
|
1275 | + EEM_Base::default_where_conditions_minimum_all, |
|
1276 | + EEM_Base::default_where_conditions_minimum_others, |
|
1277 | + ]; |
|
1278 | + if (! $default_query_params) { |
|
1279 | + $default_query_params = EEM_Base::default_where_conditions_all; |
|
1280 | + } |
|
1281 | + if ( |
|
1282 | + in_array( |
|
1283 | + $default_query_params, |
|
1284 | + $valid_default_where_conditions_for_api_calls, |
|
1285 | + true |
|
1286 | + ) |
|
1287 | + ) { |
|
1288 | + return $default_query_params; |
|
1289 | + } |
|
1290 | + return EEM_Base::default_where_conditions_all; |
|
1291 | + } |
|
1292 | + |
|
1293 | + |
|
1294 | + /** |
|
1295 | + * Translates API filter get parameter into model query params @see |
|
1296 | + * https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions. |
|
1297 | + * Note: right now the query parameter keys for fields (and related fields) can be left as-is, but it's quite |
|
1298 | + * possible this will change someday. Also, this method's contents might be candidate for moving to |
|
1299 | + * Model_Data_Translator |
|
1300 | + * |
|
1301 | + * @param EEM_Base $model |
|
1302 | + * @param array $query_params |
|
1303 | + * @return array model query params (@see |
|
1304 | + * https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions) |
|
1305 | + * or FALSE to indicate that absolutely no results should be returned |
|
1306 | + * @throws EE_Error |
|
1307 | + * @throws RestException |
|
1308 | + */ |
|
1309 | + public function createModelQueryParams($model, $query_params) |
|
1310 | + { |
|
1311 | + $model_query_params = []; |
|
1312 | + if (isset($query_params['where'])) { |
|
1313 | + $model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
1314 | + $query_params['where'], |
|
1315 | + $model, |
|
1316 | + $this->getModelVersionInfo()->requestedVersion() |
|
1317 | + ); |
|
1318 | + } |
|
1319 | + if (isset($query_params['order_by'])) { |
|
1320 | + $order_by = $query_params['order_by']; |
|
1321 | + } elseif (isset($query_params['orderby'])) { |
|
1322 | + $order_by = $query_params['orderby']; |
|
1323 | + } else { |
|
1324 | + $order_by = null; |
|
1325 | + } |
|
1326 | + if ($order_by !== null) { |
|
1327 | + if (is_array($order_by)) { |
|
1328 | + $order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by); |
|
1329 | + } else { |
|
1330 | + // it's a single item |
|
1331 | + $order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by); |
|
1332 | + } |
|
1333 | + $model_query_params['order_by'] = $order_by; |
|
1334 | + } |
|
1335 | + if (isset($query_params['group_by'])) { |
|
1336 | + $group_by = $query_params['group_by']; |
|
1337 | + } elseif (isset($query_params['groupby'])) { |
|
1338 | + $group_by = $query_params['groupby']; |
|
1339 | + } else { |
|
1340 | + $group_by = array_keys($model->get_combined_primary_key_fields()); |
|
1341 | + } |
|
1342 | + // make sure they're all real names |
|
1343 | + if (is_array($group_by)) { |
|
1344 | + $group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by); |
|
1345 | + } |
|
1346 | + if ($group_by !== null) { |
|
1347 | + $model_query_params['group_by'] = $group_by; |
|
1348 | + } |
|
1349 | + if (isset($query_params['having'])) { |
|
1350 | + $model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
1351 | + $query_params['having'], |
|
1352 | + $model, |
|
1353 | + $this->getModelVersionInfo()->requestedVersion() |
|
1354 | + ); |
|
1355 | + } |
|
1356 | + if (isset($query_params['order'])) { |
|
1357 | + $model_query_params['order'] = $query_params['order']; |
|
1358 | + } |
|
1359 | + if (isset($query_params['mine'])) { |
|
1360 | + $model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params); |
|
1361 | + } |
|
1362 | + if (isset($query_params['limit'])) { |
|
1363 | + // limit should be either a string like '23' or '23,43', or an array with two items in it |
|
1364 | + if (! is_array($query_params['limit'])) { |
|
1365 | + $limit_array = explode(',', (string) $query_params['limit']); |
|
1366 | + } else { |
|
1367 | + $limit_array = $query_params['limit']; |
|
1368 | + } |
|
1369 | + $sanitized_limit = []; |
|
1370 | + foreach ($limit_array as $limit_part) { |
|
1371 | + if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) { |
|
1372 | + throw new EE_Error( |
|
1373 | + sprintf( |
|
1374 | + esc_html__( |
|
1375 | + // @codingStandardsIgnoreStart |
|
1376 | + 'An invalid limit filter was provided. It was: %s. If the EE4 JSON REST API weren\'t in debug mode, this message would not appear.', |
|
1377 | + // @codingStandardsIgnoreEnd |
|
1378 | + 'event_espresso' |
|
1379 | + ), |
|
1380 | + wp_json_encode($query_params['limit']) |
|
1381 | + ) |
|
1382 | + ); |
|
1383 | + } |
|
1384 | + $sanitized_limit[] = (int) $limit_part; |
|
1385 | + } |
|
1386 | + $model_query_params['limit'] = implode(',', $sanitized_limit); |
|
1387 | + } else { |
|
1388 | + $model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit(); |
|
1389 | + } |
|
1390 | + if (isset($query_params['caps'])) { |
|
1391 | + $model_query_params['caps'] = $this->validateContext($query_params['caps']); |
|
1392 | + } else { |
|
1393 | + $model_query_params['caps'] = EEM_Base::caps_read; |
|
1394 | + } |
|
1395 | + if (isset($query_params['default_where_conditions'])) { |
|
1396 | + $model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams( |
|
1397 | + $query_params['default_where_conditions'] |
|
1398 | + ); |
|
1399 | + } |
|
1400 | + // if this is a model protected by a password on another model, exclude the password protected |
|
1401 | + // entities by default. But if they passed in a password, try to show them all. If the password is wrong, |
|
1402 | + // though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword) |
|
1403 | + if ( |
|
1404 | + ! $model->hasPassword() |
|
1405 | + && $model->restrictedByRelatedModelPassword() |
|
1406 | + && $model_query_params['caps'] === EEM_Base::caps_read |
|
1407 | + ) { |
|
1408 | + if (empty($query_params['password'])) { |
|
1409 | + $model_query_params['exclude_protected'] = true; |
|
1410 | + } |
|
1411 | + } |
|
1412 | + |
|
1413 | + return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_params, $model); |
|
1414 | + } |
|
1415 | + |
|
1416 | + |
|
1417 | + /** |
|
1418 | + * Changes the REST-style query params for use in the models |
|
1419 | + * |
|
1420 | + * @param EEM_Base $model |
|
1421 | + * @param array $query_params sub-array from @see EEM_Base::get_all() |
|
1422 | + * @return array |
|
1423 | + * @deprecated |
|
1424 | + */ |
|
1425 | + public function prepareRestQueryParamsKeyForModels($model, $query_params) |
|
1426 | + { |
|
1427 | + $model_ready_query_params = []; |
|
1428 | + foreach ($query_params as $key => $value) { |
|
1429 | + $model_ready_query_params[ $key ] = is_array($value) |
|
1430 | + ? $this->prepareRestQueryParamsKeyForModels($model, $value) |
|
1431 | + : $value; |
|
1432 | + } |
|
1433 | + return $model_ready_query_params; |
|
1434 | + } |
|
1435 | + |
|
1436 | + |
|
1437 | + /** |
|
1438 | + * @param $model |
|
1439 | + * @param $query_params |
|
1440 | + * @return array |
|
1441 | + * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson() |
|
1442 | + */ |
|
1443 | + public function prepareRestQueryParamsValuesForModels($model, $query_params) |
|
1444 | + { |
|
1445 | + $model_ready_query_params = []; |
|
1446 | + foreach ($query_params as $key => $value) { |
|
1447 | + if (is_array($value)) { |
|
1448 | + $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value); |
|
1449 | + } else { |
|
1450 | + $model_ready_query_params[ $key ] = $value; |
|
1451 | + } |
|
1452 | + } |
|
1453 | + return $model_ready_query_params; |
|
1454 | + } |
|
1455 | + |
|
1456 | + |
|
1457 | + /** |
|
1458 | + * Explodes the string on commas, and only returns items with $prefix followed by a period. |
|
1459 | + * If no prefix is specified, returns items with no period. |
|
1460 | + * |
|
1461 | + * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' ) |
|
1462 | + * @param string $prefix "Event" or "foobar" |
|
1463 | + * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified |
|
1464 | + * we only return strings starting with that and a period; if no prefix was |
|
1465 | + * specified we return all items containing NO periods |
|
1466 | + */ |
|
1467 | + public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix) |
|
1468 | + { |
|
1469 | + if (is_string($string_to_explode)) { |
|
1470 | + $exploded_contents = explode(',', $string_to_explode); |
|
1471 | + } elseif (is_array($string_to_explode)) { |
|
1472 | + $exploded_contents = $string_to_explode; |
|
1473 | + } else { |
|
1474 | + $exploded_contents = []; |
|
1475 | + } |
|
1476 | + // if the string was empty, we want an empty array |
|
1477 | + $exploded_contents = array_filter($exploded_contents); |
|
1478 | + $contents_with_prefix = []; |
|
1479 | + foreach ($exploded_contents as $item) { |
|
1480 | + $item = trim($item); |
|
1481 | + // if no prefix was provided, so we look for items with no "." in them |
|
1482 | + if (! $prefix) { |
|
1483 | + // does this item have a period? |
|
1484 | + if (strpos($item, '.') === false) { |
|
1485 | + // if not, then its what we're looking for |
|
1486 | + $contents_with_prefix[] = $item; |
|
1487 | + } |
|
1488 | + } elseif (strpos($item, $prefix . '.') === 0) { |
|
1489 | + // this item has the prefix and a period, grab it |
|
1490 | + $contents_with_prefix[] = substr( |
|
1491 | + $item, |
|
1492 | + strpos($item, $prefix . '.') + strlen($prefix . '.') |
|
1493 | + ); |
|
1494 | + } elseif ($item === $prefix) { |
|
1495 | + // this item is JUST the prefix |
|
1496 | + // so let's grab everything after, which is a blank string |
|
1497 | + $contents_with_prefix[] = ''; |
|
1498 | + } |
|
1499 | + } |
|
1500 | + return $contents_with_prefix; |
|
1501 | + } |
|
1502 | + |
|
1503 | + |
|
1504 | + /** |
|
1505 | + * @param string $include_string @see Read:handle_request_get_all |
|
1506 | + * @param string $model_name |
|
1507 | + * @return array of fields for this model. If $model_name is provided, then |
|
1508 | + * the fields for that model, with the model's name removed from each. |
|
1509 | + * If $include_string was blank or '*' returns an empty array |
|
1510 | + * @throws EE_Error |
|
1511 | + * @throws EE_Error |
|
1512 | + * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with. |
|
1513 | + * Deprecated because its return values were really quite confusing- sometimes it |
|
1514 | + * returned an empty array (when the include string was blank or '*') or sometimes it |
|
1515 | + * returned array('*') (when you provided a model and a model of that kind was |
|
1516 | + * found). Parses the $include_string so we fetch all the field names relating to |
|
1517 | + * THIS model |
|
1518 | + * (ie have NO period in them), or for the provided model (ie start with the model |
|
1519 | + * name and then a period). |
|
1520 | + */ |
|
1521 | + public function extractIncludesForThisModel($include_string, $model_name = null) |
|
1522 | + { |
|
1523 | + if (is_array($include_string)) { |
|
1524 | + $include_string = implode(',', $include_string); |
|
1525 | + } |
|
1526 | + if ($include_string === '*' || $include_string === '') { |
|
1527 | + return []; |
|
1528 | + } |
|
1529 | + $includes = explode(',', $include_string); |
|
1530 | + $extracted_fields_to_include = []; |
|
1531 | + if ($model_name) { |
|
1532 | + foreach ($includes as $field_to_include) { |
|
1533 | + $field_to_include = trim($field_to_include); |
|
1534 | + if (strpos($field_to_include, $model_name . '.') === 0) { |
|
1535 | + // found the model name at the exact start |
|
1536 | + $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include); |
|
1537 | + $extracted_fields_to_include[] = $field_sans_model_name; |
|
1538 | + } elseif ($field_to_include == $model_name) { |
|
1539 | + $extracted_fields_to_include[] = '*'; |
|
1540 | + } |
|
1541 | + } |
|
1542 | + } else { |
|
1543 | + // look for ones with no period |
|
1544 | + foreach ($includes as $field_to_include) { |
|
1545 | + $field_to_include = trim($field_to_include); |
|
1546 | + if ( |
|
1547 | + strpos($field_to_include, '.') === false |
|
1548 | + && ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include) |
|
1549 | + ) { |
|
1550 | + $extracted_fields_to_include[] = $field_to_include; |
|
1551 | + } |
|
1552 | + } |
|
1553 | + } |
|
1554 | + return $extracted_fields_to_include; |
|
1555 | + } |
|
1556 | + |
|
1557 | + |
|
1558 | + /** |
|
1559 | + * Gets the single item using the model according to the request in the context given, otherwise |
|
1560 | + * returns that it's inaccessible to the current user |
|
1561 | + * |
|
1562 | + * @param EEM_Base $model |
|
1563 | + * @param WP_REST_Request $request |
|
1564 | + * @param null $context |
|
1565 | + * @return array |
|
1566 | + * @throws EE_Error |
|
1567 | + * @throws ReflectionException |
|
1568 | + */ |
|
1569 | + public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null) |
|
1570 | + { |
|
1571 | + $query_params = [[$model->primary_key_name() => $request->get_param('id')], 'limit' => 1]; |
|
1572 | + if ($model instanceof EEM_Soft_Delete_Base) { |
|
1573 | + $query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params); |
|
1574 | + } |
|
1575 | + $restricted_query_params = $query_params; |
|
1576 | + $restricted_query_params['caps'] = $context; |
|
1577 | + $this->setDebugInfo('model query params', $restricted_query_params); |
|
1578 | + $model_rows = $model->get_all_wpdb_results($restricted_query_params); |
|
1579 | + if (! empty($model_rows)) { |
|
1580 | + return $this->createEntityFromWpdbResult( |
|
1581 | + $model, |
|
1582 | + reset($model_rows), |
|
1583 | + $request |
|
1584 | + ); |
|
1585 | + } else { |
|
1586 | + // ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities |
|
1587 | + $lowercase_model_name = strtolower($model->get_this_model_name()); |
|
1588 | + if ($model->exists($query_params)) { |
|
1589 | + // you got shafted- it existed but we didn't want to tell you! |
|
1590 | + throw new RestException( |
|
1591 | + 'rest_user_cannot_' . $context, |
|
1592 | + sprintf( |
|
1593 | + esc_html__('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'), |
|
1594 | + $context, |
|
1595 | + $lowercase_model_name, |
|
1596 | + Capabilities::getMissingPermissionsString( |
|
1597 | + $model, |
|
1598 | + $context |
|
1599 | + ) |
|
1600 | + ), |
|
1601 | + ['status' => 403] |
|
1602 | + ); |
|
1603 | + } else { |
|
1604 | + // it's not you. It just doesn't exist |
|
1605 | + throw new RestException( |
|
1606 | + sprintf('rest_%s_invalid_id', $lowercase_model_name), |
|
1607 | + sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name), |
|
1608 | + ['status' => 404] |
|
1609 | + ); |
|
1610 | + } |
|
1611 | + } |
|
1612 | + } |
|
1613 | + |
|
1614 | + |
|
1615 | + /** |
|
1616 | + * Checks that if this content requires a password to be read, that it's been provided and is correct. |
|
1617 | + * |
|
1618 | + * @param EEM_Base $model |
|
1619 | + * @param array $model_row |
|
1620 | + * @param array $query_params Adds 'default_where_conditions' => 'minimum' |
|
1621 | + * to ensure we don't confuse trashed with password protected. |
|
1622 | + * @param WP_REST_Request $request |
|
1623 | + * @throws EE_Error |
|
1624 | + * @throws InvalidArgumentException |
|
1625 | + * @throws InvalidDataTypeException |
|
1626 | + * @throws InvalidInterfaceException |
|
1627 | + * @throws RestPasswordRequiredException |
|
1628 | + * @throws RestPasswordIncorrectException |
|
1629 | + * @throws ModelConfigurationException |
|
1630 | + * @throws ReflectionException |
|
1631 | + * @since 4.9.74.p |
|
1632 | + */ |
|
1633 | + protected function checkPassword(EEM_Base $model, $model_row, $query_params, WP_REST_Request $request) |
|
1634 | + { |
|
1635 | + $query_params['default_where_conditions'] = 'minimum'; |
|
1636 | + // stuff is only "protected" for front-end requests. Elsewhere, you either get full permission to access the object |
|
1637 | + // or you don't. |
|
1638 | + $request_caps = $request->get_param('caps'); |
|
1639 | + if (isset($request_caps) && $request_caps !== EEM_Base::caps_read) { |
|
1640 | + return; |
|
1641 | + } |
|
1642 | + // if this entity requires a password, they better give it and it better be right! |
|
1643 | + if ( |
|
1644 | + $model->hasPassword() |
|
1645 | + && $model_row[ $model->getPasswordField()->get_qualified_column() ] !== '' |
|
1646 | + ) { |
|
1647 | + if (empty($request['password'])) { |
|
1648 | + throw new RestPasswordRequiredException(); |
|
1649 | + } |
|
1650 | + if ( |
|
1651 | + ! hash_equals( |
|
1652 | + $model_row[ $model->getPasswordField()->get_qualified_column() ], |
|
1653 | + $request['password'] |
|
1654 | + ) |
|
1655 | + ) { |
|
1656 | + throw new RestPasswordIncorrectException(); |
|
1657 | + } |
|
1658 | + } elseif ( |
|
1659 | + // wait! maybe this content is password protected |
|
1660 | + $model->restrictedByRelatedModelPassword() |
|
1661 | + && $request->get_param('caps') === EEM_Base::caps_read |
|
1662 | + ) { |
|
1663 | + $password_supplied = $request->get_param('password'); |
|
1664 | + if (empty($password_supplied)) { |
|
1665 | + $query_params['exclude_protected'] = true; |
|
1666 | + if (! $model->exists($query_params)) { |
|
1667 | + throw new RestPasswordRequiredException(); |
|
1668 | + } |
|
1669 | + } else { |
|
1670 | + $query_params[0][ $model->modelChainAndPassword() ] = $password_supplied; |
|
1671 | + if (! $model->exists($query_params)) { |
|
1672 | + throw new RestPasswordIncorrectException(); |
|
1673 | + } |
|
1674 | + } |
|
1675 | + } |
|
1676 | + } |
|
1677 | 1677 | } |
@@ -134,9 +134,9 @@ discard block |
||
134 | 134 | { |
135 | 135 | Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'create'); |
136 | 136 | $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap(); |
137 | - if (! current_user_can($default_cap_to_check_for)) { |
|
137 | + if ( ! current_user_can($default_cap_to_check_for)) { |
|
138 | 138 | throw new RestException( |
139 | - 'rest_cannot_create_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
139 | + 'rest_cannot_create_'.EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
140 | 140 | sprintf( |
141 | 141 | esc_html__( |
142 | 142 | // @codingStandardsIgnoreStart |
@@ -164,7 +164,7 @@ discard block |
||
164 | 164 | ); |
165 | 165 | $model_obj->save(); |
166 | 166 | $new_id = $model_obj->ID(); |
167 | - if (! $new_id) { |
|
167 | + if ( ! $new_id) { |
|
168 | 168 | throw new RestException( |
169 | 169 | 'rest_insertion_failed', |
170 | 170 | sprintf(esc_html__('Could not insert new %1$s', 'event_espresso'), $model->get_this_model_name()) |
@@ -186,9 +186,9 @@ discard block |
||
186 | 186 | { |
187 | 187 | Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit'); |
188 | 188 | $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap(); |
189 | - if (! current_user_can($default_cap_to_check_for)) { |
|
189 | + if ( ! current_user_can($default_cap_to_check_for)) { |
|
190 | 190 | throw new RestException( |
191 | - 'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
191 | + 'rest_cannot_edit_'.EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
192 | 192 | sprintf( |
193 | 193 | esc_html__( |
194 | 194 | // @codingStandardsIgnoreStart |
@@ -202,7 +202,7 @@ discard block |
||
202 | 202 | ); |
203 | 203 | } |
204 | 204 | $obj_id = $request->get_param('id'); |
205 | - if (! $obj_id) { |
|
205 | + if ( ! $obj_id) { |
|
206 | 206 | throw new RestException( |
207 | 207 | 'rest_edit_failed', |
208 | 208 | sprintf(esc_html__('Could not edit %1$s', 'event_espresso'), $model->get_this_model_name()) |
@@ -215,7 +215,7 @@ discard block |
||
215 | 215 | true |
216 | 216 | ); |
217 | 217 | $model_obj = $model->get_one_by_ID($obj_id); |
218 | - if (! $model_obj instanceof EE_Base_Class) { |
|
218 | + if ( ! $model_obj instanceof EE_Base_Class) { |
|
219 | 219 | $lowercase_model_name = strtolower($model->get_this_model_name()); |
220 | 220 | throw new RestException( |
221 | 221 | sprintf('rest_%s_invalid_id', $lowercase_model_name), |
@@ -240,9 +240,9 @@ discard block |
||
240 | 240 | { |
241 | 241 | Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_delete, 'delete'); |
242 | 242 | $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap(); |
243 | - if (! current_user_can($default_cap_to_check_for)) { |
|
243 | + if ( ! current_user_can($default_cap_to_check_for)) { |
|
244 | 244 | throw new RestException( |
245 | - 'rest_cannot_delete_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
245 | + 'rest_cannot_delete_'.EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
246 | 246 | sprintf( |
247 | 247 | esc_html__( |
248 | 248 | // @codingStandardsIgnoreStart |
@@ -258,7 +258,7 @@ discard block |
||
258 | 258 | $obj_id = $request->get_param('id'); |
259 | 259 | // this is where we would apply more fine-grained caps |
260 | 260 | $model_obj = $model->get_one_by_ID($obj_id); |
261 | - if (! $model_obj instanceof EE_Base_Class) { |
|
261 | + if ( ! $model_obj instanceof EE_Base_Class) { |
|
262 | 262 | $lowercase_model_name = strtolower($model->get_this_model_name()); |
263 | 263 | throw new RestException( |
264 | 264 | sprintf('rest_%s_invalid_id', $lowercase_model_name), |
@@ -316,7 +316,7 @@ discard block |
||
316 | 316 | } else { |
317 | 317 | $raw_value = $model_obj->get_raw($field_name); |
318 | 318 | } |
319 | - $simulated_db_row[ $field_obj->get_qualified_column() ] = $field_obj->prepare_for_use_in_db($raw_value); |
|
319 | + $simulated_db_row[$field_obj->get_qualified_column()] = $field_obj->prepare_for_use_in_db($raw_value); |
|
320 | 320 | } |
321 | 321 | $read_controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
322 | 322 | $read_controller->setRequestedVersion($this->getRequestedVersion()); |
@@ -447,7 +447,7 @@ discard block |
||
447 | 447 | ) |
448 | 448 | ) |
449 | 449 | ); |
450 | - $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request); |
|
450 | + $response['join'][strtolower($relation->get_join_model()->get_this_model_name())] = $this->returnModelObjAsJsonResponse($join_model_obj, $request); |
|
451 | 451 | } |
452 | 452 | return $response; |
453 | 453 | } |
@@ -495,7 +495,7 @@ discard block |
||
495 | 495 | { |
496 | 496 | // This endpoint doesn't accept body parameters (it's understandable to think it might, so let developers know |
497 | 497 | // up-front that it doesn't.) |
498 | - if (!empty($request->get_body_params())) { |
|
498 | + if ( ! empty($request->get_body_params())) { |
|
499 | 499 | $body_params = $request->get_body_params(); |
500 | 500 | throw new RestException( |
501 | 501 | 'invalid_field', |
@@ -537,9 +537,9 @@ discard block |
||
537 | 537 | ) |
538 | 538 | ); |
539 | 539 | if ($join_model_obj instanceof EE_Base_Class) { |
540 | - $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request); |
|
540 | + $response['join'][strtolower($relation->get_join_model()->get_this_model_name())] = $this->returnModelObjAsJsonResponse($join_model_obj, $request); |
|
541 | 541 | } else { |
542 | - $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = null; |
|
542 | + $response['join'][strtolower($relation->get_join_model()->get_this_model_name())] = null; |
|
543 | 543 | } |
544 | 544 | } |
545 | 545 | return $response; |
@@ -564,9 +564,9 @@ discard block |
||
564 | 564 | // Check generic caps. For now, we're only allowing access to this endpoint to full admins. |
565 | 565 | Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit'); |
566 | 566 | $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap(); |
567 | - if (! current_user_can($default_cap_to_check_for)) { |
|
567 | + if ( ! current_user_can($default_cap_to_check_for)) { |
|
568 | 568 | throw new RestException( |
569 | - 'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
569 | + 'rest_cannot_edit_'.EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
570 | 570 | sprintf( |
571 | 571 | esc_html__( |
572 | 572 | // @codingStandardsIgnoreStart |
@@ -583,7 +583,7 @@ discard block |
||
583 | 583 | $model_obj = $this->getOneOrThrowException($model, $request->get_param('id')); |
584 | 584 | // For now, we require the other model object to exist too. This might be relaxed later. |
585 | 585 | $other_obj = $this->getOneOrThrowException($relation->get_other_model(), $request->get_param('related_id')); |
586 | - return array($model_obj,$other_obj); |
|
586 | + return array($model_obj, $other_obj); |
|
587 | 587 | } |
588 | 588 | |
589 | 589 | /** |
@@ -37,573 +37,573 @@ |
||
37 | 37 | */ |
38 | 38 | class Write extends Base |
39 | 39 | { |
40 | - public function __construct() |
|
41 | - { |
|
42 | - parent::__construct(); |
|
43 | - EE_Registry::instance()->load_helper('Inflector'); |
|
44 | - } |
|
40 | + public function __construct() |
|
41 | + { |
|
42 | + parent::__construct(); |
|
43 | + EE_Registry::instance()->load_helper('Inflector'); |
|
44 | + } |
|
45 | 45 | |
46 | 46 | |
47 | - /** |
|
48 | - * Handles requests to get all (or a filtered subset) of entities for a particular model |
|
49 | - * |
|
50 | - * @param WP_REST_Request $request |
|
51 | - * @param string $version |
|
52 | - * @param string $model_name |
|
53 | - * @return WP_REST_Response|\WP_Error |
|
54 | - */ |
|
55 | - public static function handleRequestInsert(WP_REST_Request $request, $version, $model_name) |
|
56 | - { |
|
57 | - $controller = new Write(); |
|
58 | - try { |
|
59 | - $controller->setRequestedVersion($version); |
|
60 | - return $controller->sendResponse( |
|
61 | - $controller->insert( |
|
62 | - $controller->getModelVersionInfo()->loadModel($model_name), |
|
63 | - $request |
|
64 | - ) |
|
65 | - ); |
|
66 | - } catch (Exception $e) { |
|
67 | - return $controller->sendResponse($e); |
|
68 | - } |
|
69 | - } |
|
47 | + /** |
|
48 | + * Handles requests to get all (or a filtered subset) of entities for a particular model |
|
49 | + * |
|
50 | + * @param WP_REST_Request $request |
|
51 | + * @param string $version |
|
52 | + * @param string $model_name |
|
53 | + * @return WP_REST_Response|\WP_Error |
|
54 | + */ |
|
55 | + public static function handleRequestInsert(WP_REST_Request $request, $version, $model_name) |
|
56 | + { |
|
57 | + $controller = new Write(); |
|
58 | + try { |
|
59 | + $controller->setRequestedVersion($version); |
|
60 | + return $controller->sendResponse( |
|
61 | + $controller->insert( |
|
62 | + $controller->getModelVersionInfo()->loadModel($model_name), |
|
63 | + $request |
|
64 | + ) |
|
65 | + ); |
|
66 | + } catch (Exception $e) { |
|
67 | + return $controller->sendResponse($e); |
|
68 | + } |
|
69 | + } |
|
70 | 70 | |
71 | 71 | |
72 | - /** |
|
73 | - * Handles a request from \WP_REST_Server to update an EE model |
|
74 | - * |
|
75 | - * @param WP_REST_Request $request |
|
76 | - * @param string $version |
|
77 | - * @param string $model_name |
|
78 | - * @return WP_REST_Response|\WP_Error |
|
79 | - */ |
|
80 | - public static function handleRequestUpdate(WP_REST_Request $request, $version, $model_name) |
|
81 | - { |
|
82 | - $controller = new Write(); |
|
83 | - try { |
|
84 | - $controller->setRequestedVersion($version); |
|
85 | - return $controller->sendResponse( |
|
86 | - $controller->update( |
|
87 | - $controller->getModelVersionInfo()->loadModel($model_name), |
|
88 | - $request |
|
89 | - ) |
|
90 | - ); |
|
91 | - } catch (Exception $e) { |
|
92 | - return $controller->sendResponse($e); |
|
93 | - } |
|
94 | - } |
|
72 | + /** |
|
73 | + * Handles a request from \WP_REST_Server to update an EE model |
|
74 | + * |
|
75 | + * @param WP_REST_Request $request |
|
76 | + * @param string $version |
|
77 | + * @param string $model_name |
|
78 | + * @return WP_REST_Response|\WP_Error |
|
79 | + */ |
|
80 | + public static function handleRequestUpdate(WP_REST_Request $request, $version, $model_name) |
|
81 | + { |
|
82 | + $controller = new Write(); |
|
83 | + try { |
|
84 | + $controller->setRequestedVersion($version); |
|
85 | + return $controller->sendResponse( |
|
86 | + $controller->update( |
|
87 | + $controller->getModelVersionInfo()->loadModel($model_name), |
|
88 | + $request |
|
89 | + ) |
|
90 | + ); |
|
91 | + } catch (Exception $e) { |
|
92 | + return $controller->sendResponse($e); |
|
93 | + } |
|
94 | + } |
|
95 | 95 | |
96 | 96 | |
97 | - /** |
|
98 | - * Deletes a single model object and returns it. Unless |
|
99 | - * |
|
100 | - * @param WP_REST_Request $request |
|
101 | - * @param string $version |
|
102 | - * @param string $model_name |
|
103 | - * @return WP_REST_Response|\WP_Error |
|
104 | - */ |
|
105 | - public static function handleRequestDelete(WP_REST_Request $request, $version, $model_name) |
|
106 | - { |
|
107 | - $controller = new Write(); |
|
108 | - try { |
|
109 | - $controller->setRequestedVersion($version); |
|
110 | - return $controller->sendResponse( |
|
111 | - $controller->delete( |
|
112 | - $controller->getModelVersionInfo()->loadModel($model_name), |
|
113 | - $request |
|
114 | - ) |
|
115 | - ); |
|
116 | - } catch (Exception $e) { |
|
117 | - return $controller->sendResponse($e); |
|
118 | - } |
|
119 | - } |
|
97 | + /** |
|
98 | + * Deletes a single model object and returns it. Unless |
|
99 | + * |
|
100 | + * @param WP_REST_Request $request |
|
101 | + * @param string $version |
|
102 | + * @param string $model_name |
|
103 | + * @return WP_REST_Response|\WP_Error |
|
104 | + */ |
|
105 | + public static function handleRequestDelete(WP_REST_Request $request, $version, $model_name) |
|
106 | + { |
|
107 | + $controller = new Write(); |
|
108 | + try { |
|
109 | + $controller->setRequestedVersion($version); |
|
110 | + return $controller->sendResponse( |
|
111 | + $controller->delete( |
|
112 | + $controller->getModelVersionInfo()->loadModel($model_name), |
|
113 | + $request |
|
114 | + ) |
|
115 | + ); |
|
116 | + } catch (Exception $e) { |
|
117 | + return $controller->sendResponse($e); |
|
118 | + } |
|
119 | + } |
|
120 | 120 | |
121 | 121 | |
122 | - /** |
|
123 | - * Inserts a new model object according to the $request |
|
124 | - * |
|
125 | - * @param EEM_Base $model |
|
126 | - * @param WP_REST_Request $request |
|
127 | - * @return array |
|
128 | - * @throws EE_Error |
|
129 | - * @throws RestException |
|
130 | - */ |
|
131 | - public function insert(EEM_Base $model, WP_REST_Request $request) |
|
132 | - { |
|
133 | - Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'create'); |
|
134 | - $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap(); |
|
135 | - if (! current_user_can($default_cap_to_check_for)) { |
|
136 | - throw new RestException( |
|
137 | - 'rest_cannot_create_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
138 | - sprintf( |
|
139 | - esc_html__( |
|
140 | - // @codingStandardsIgnoreStart |
|
141 | - 'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to insert data into Event Espresso.', |
|
142 | - // @codingStandardsIgnoreEnd |
|
143 | - 'event_espresso' |
|
144 | - ), |
|
145 | - $default_cap_to_check_for |
|
146 | - ), |
|
147 | - array('status' => 403) |
|
148 | - ); |
|
149 | - } |
|
150 | - $submitted_json_data = array_merge((array) $request->get_body_params(), (array) $request->get_json_params()); |
|
151 | - $model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
152 | - $submitted_json_data, |
|
153 | - $model, |
|
154 | - $this->getModelVersionInfo()->requestedVersion(), |
|
155 | - true |
|
156 | - ); |
|
157 | - $model_obj = EE_Registry::instance()->load_class( |
|
158 | - $model->get_this_model_name(), |
|
159 | - array($model_data, $model->get_timezone()), |
|
160 | - false, |
|
161 | - false |
|
162 | - ); |
|
163 | - $model_obj->save(); |
|
164 | - $new_id = $model_obj->ID(); |
|
165 | - if (! $new_id) { |
|
166 | - throw new RestException( |
|
167 | - 'rest_insertion_failed', |
|
168 | - sprintf(esc_html__('Could not insert new %1$s', 'event_espresso'), $model->get_this_model_name()) |
|
169 | - ); |
|
170 | - } |
|
171 | - return $this->returnModelObjAsJsonResponse($model_obj, $request); |
|
172 | - } |
|
122 | + /** |
|
123 | + * Inserts a new model object according to the $request |
|
124 | + * |
|
125 | + * @param EEM_Base $model |
|
126 | + * @param WP_REST_Request $request |
|
127 | + * @return array |
|
128 | + * @throws EE_Error |
|
129 | + * @throws RestException |
|
130 | + */ |
|
131 | + public function insert(EEM_Base $model, WP_REST_Request $request) |
|
132 | + { |
|
133 | + Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'create'); |
|
134 | + $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap(); |
|
135 | + if (! current_user_can($default_cap_to_check_for)) { |
|
136 | + throw new RestException( |
|
137 | + 'rest_cannot_create_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
138 | + sprintf( |
|
139 | + esc_html__( |
|
140 | + // @codingStandardsIgnoreStart |
|
141 | + 'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to insert data into Event Espresso.', |
|
142 | + // @codingStandardsIgnoreEnd |
|
143 | + 'event_espresso' |
|
144 | + ), |
|
145 | + $default_cap_to_check_for |
|
146 | + ), |
|
147 | + array('status' => 403) |
|
148 | + ); |
|
149 | + } |
|
150 | + $submitted_json_data = array_merge((array) $request->get_body_params(), (array) $request->get_json_params()); |
|
151 | + $model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
152 | + $submitted_json_data, |
|
153 | + $model, |
|
154 | + $this->getModelVersionInfo()->requestedVersion(), |
|
155 | + true |
|
156 | + ); |
|
157 | + $model_obj = EE_Registry::instance()->load_class( |
|
158 | + $model->get_this_model_name(), |
|
159 | + array($model_data, $model->get_timezone()), |
|
160 | + false, |
|
161 | + false |
|
162 | + ); |
|
163 | + $model_obj->save(); |
|
164 | + $new_id = $model_obj->ID(); |
|
165 | + if (! $new_id) { |
|
166 | + throw new RestException( |
|
167 | + 'rest_insertion_failed', |
|
168 | + sprintf(esc_html__('Could not insert new %1$s', 'event_espresso'), $model->get_this_model_name()) |
|
169 | + ); |
|
170 | + } |
|
171 | + return $this->returnModelObjAsJsonResponse($model_obj, $request); |
|
172 | + } |
|
173 | 173 | |
174 | 174 | |
175 | - /** |
|
176 | - * Updates an existing model object according to the $request |
|
177 | - * |
|
178 | - * @param EEM_Base $model |
|
179 | - * @param WP_REST_Request $request |
|
180 | - * @return array |
|
181 | - * @throws EE_Error |
|
182 | - */ |
|
183 | - public function update(EEM_Base $model, WP_REST_Request $request) |
|
184 | - { |
|
185 | - Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit'); |
|
186 | - $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap(); |
|
187 | - if (! current_user_can($default_cap_to_check_for)) { |
|
188 | - throw new RestException( |
|
189 | - 'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
190 | - sprintf( |
|
191 | - esc_html__( |
|
192 | - // @codingStandardsIgnoreStart |
|
193 | - 'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to update data into Event Espresso.', |
|
194 | - // @codingStandardsIgnoreEnd |
|
195 | - 'event_espresso' |
|
196 | - ), |
|
197 | - $default_cap_to_check_for |
|
198 | - ), |
|
199 | - array('status' => 403) |
|
200 | - ); |
|
201 | - } |
|
202 | - $obj_id = $request->get_param('id'); |
|
203 | - if (! $obj_id) { |
|
204 | - throw new RestException( |
|
205 | - 'rest_edit_failed', |
|
206 | - sprintf(esc_html__('Could not edit %1$s', 'event_espresso'), $model->get_this_model_name()) |
|
207 | - ); |
|
208 | - } |
|
209 | - $model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
210 | - $this->getBodyParams($request), |
|
211 | - $model, |
|
212 | - $this->getModelVersionInfo()->requestedVersion(), |
|
213 | - true |
|
214 | - ); |
|
215 | - $model_obj = $model->get_one_by_ID($obj_id); |
|
216 | - if (! $model_obj instanceof EE_Base_Class) { |
|
217 | - $lowercase_model_name = strtolower($model->get_this_model_name()); |
|
218 | - throw new RestException( |
|
219 | - sprintf('rest_%s_invalid_id', $lowercase_model_name), |
|
220 | - sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name), |
|
221 | - array('status' => 404) |
|
222 | - ); |
|
223 | - } |
|
224 | - $model_obj->save($model_data); |
|
225 | - return $this->returnModelObjAsJsonResponse($model_obj, $request); |
|
226 | - } |
|
175 | + /** |
|
176 | + * Updates an existing model object according to the $request |
|
177 | + * |
|
178 | + * @param EEM_Base $model |
|
179 | + * @param WP_REST_Request $request |
|
180 | + * @return array |
|
181 | + * @throws EE_Error |
|
182 | + */ |
|
183 | + public function update(EEM_Base $model, WP_REST_Request $request) |
|
184 | + { |
|
185 | + Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit'); |
|
186 | + $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap(); |
|
187 | + if (! current_user_can($default_cap_to_check_for)) { |
|
188 | + throw new RestException( |
|
189 | + 'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
190 | + sprintf( |
|
191 | + esc_html__( |
|
192 | + // @codingStandardsIgnoreStart |
|
193 | + 'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to update data into Event Espresso.', |
|
194 | + // @codingStandardsIgnoreEnd |
|
195 | + 'event_espresso' |
|
196 | + ), |
|
197 | + $default_cap_to_check_for |
|
198 | + ), |
|
199 | + array('status' => 403) |
|
200 | + ); |
|
201 | + } |
|
202 | + $obj_id = $request->get_param('id'); |
|
203 | + if (! $obj_id) { |
|
204 | + throw new RestException( |
|
205 | + 'rest_edit_failed', |
|
206 | + sprintf(esc_html__('Could not edit %1$s', 'event_espresso'), $model->get_this_model_name()) |
|
207 | + ); |
|
208 | + } |
|
209 | + $model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
210 | + $this->getBodyParams($request), |
|
211 | + $model, |
|
212 | + $this->getModelVersionInfo()->requestedVersion(), |
|
213 | + true |
|
214 | + ); |
|
215 | + $model_obj = $model->get_one_by_ID($obj_id); |
|
216 | + if (! $model_obj instanceof EE_Base_Class) { |
|
217 | + $lowercase_model_name = strtolower($model->get_this_model_name()); |
|
218 | + throw new RestException( |
|
219 | + sprintf('rest_%s_invalid_id', $lowercase_model_name), |
|
220 | + sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name), |
|
221 | + array('status' => 404) |
|
222 | + ); |
|
223 | + } |
|
224 | + $model_obj->save($model_data); |
|
225 | + return $this->returnModelObjAsJsonResponse($model_obj, $request); |
|
226 | + } |
|
227 | 227 | |
228 | 228 | |
229 | - /** |
|
230 | - * Updates an existing model object according to the $request |
|
231 | - * |
|
232 | - * @param EEM_Base $model |
|
233 | - * @param WP_REST_Request $request |
|
234 | - * @return array of either the soft-deleted item, or |
|
235 | - * @throws EE_Error |
|
236 | - */ |
|
237 | - public function delete(EEM_Base $model, WP_REST_Request $request) |
|
238 | - { |
|
239 | - Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_delete, 'delete'); |
|
240 | - $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap(); |
|
241 | - if (! current_user_can($default_cap_to_check_for)) { |
|
242 | - throw new RestException( |
|
243 | - 'rest_cannot_delete_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
244 | - sprintf( |
|
245 | - esc_html__( |
|
246 | - // @codingStandardsIgnoreStart |
|
247 | - 'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to delete data into Event Espresso.', |
|
248 | - // @codingStandardsIgnoreEnd |
|
249 | - 'event_espresso' |
|
250 | - ), |
|
251 | - $default_cap_to_check_for |
|
252 | - ), |
|
253 | - array('status' => 403) |
|
254 | - ); |
|
255 | - } |
|
256 | - $obj_id = $request->get_param('id'); |
|
257 | - // this is where we would apply more fine-grained caps |
|
258 | - $model_obj = $model->get_one_by_ID($obj_id); |
|
259 | - if (! $model_obj instanceof EE_Base_Class) { |
|
260 | - $lowercase_model_name = strtolower($model->get_this_model_name()); |
|
261 | - throw new RestException( |
|
262 | - sprintf('rest_%s_invalid_id', $lowercase_model_name), |
|
263 | - sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name), |
|
264 | - array('status' => 404) |
|
265 | - ); |
|
266 | - } |
|
267 | - $requested_permanent_delete = filter_var($request->get_param('force'), FILTER_VALIDATE_BOOLEAN); |
|
268 | - $requested_allow_blocking = filter_var($request->get_param('allow_blocking'), FILTER_VALIDATE_BOOLEAN); |
|
269 | - if ($requested_permanent_delete) { |
|
270 | - $previous = $this->returnModelObjAsJsonResponse($model_obj, $request); |
|
271 | - $deleted = (bool) $model->delete_permanently_by_ID($obj_id, $requested_allow_blocking); |
|
272 | - return array( |
|
273 | - 'deleted' => $deleted, |
|
274 | - 'previous' => $previous, |
|
275 | - ); |
|
276 | - } else { |
|
277 | - if ($model instanceof EEM_Soft_Delete_Base) { |
|
278 | - $model->delete_by_ID($obj_id, $requested_allow_blocking); |
|
279 | - return $this->returnModelObjAsJsonResponse($model_obj, $request); |
|
280 | - } else { |
|
281 | - throw new RestException( |
|
282 | - 'rest_trash_not_supported', |
|
283 | - 501, |
|
284 | - sprintf( |
|
285 | - esc_html__('%1$s do not support trashing. Set force=1 to delete.', 'event_espresso'), |
|
286 | - EEH_Inflector::pluralize($model->get_this_model_name()) |
|
287 | - ) |
|
288 | - ); |
|
289 | - } |
|
290 | - } |
|
291 | - } |
|
229 | + /** |
|
230 | + * Updates an existing model object according to the $request |
|
231 | + * |
|
232 | + * @param EEM_Base $model |
|
233 | + * @param WP_REST_Request $request |
|
234 | + * @return array of either the soft-deleted item, or |
|
235 | + * @throws EE_Error |
|
236 | + */ |
|
237 | + public function delete(EEM_Base $model, WP_REST_Request $request) |
|
238 | + { |
|
239 | + Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_delete, 'delete'); |
|
240 | + $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap(); |
|
241 | + if (! current_user_can($default_cap_to_check_for)) { |
|
242 | + throw new RestException( |
|
243 | + 'rest_cannot_delete_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
244 | + sprintf( |
|
245 | + esc_html__( |
|
246 | + // @codingStandardsIgnoreStart |
|
247 | + 'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to delete data into Event Espresso.', |
|
248 | + // @codingStandardsIgnoreEnd |
|
249 | + 'event_espresso' |
|
250 | + ), |
|
251 | + $default_cap_to_check_for |
|
252 | + ), |
|
253 | + array('status' => 403) |
|
254 | + ); |
|
255 | + } |
|
256 | + $obj_id = $request->get_param('id'); |
|
257 | + // this is where we would apply more fine-grained caps |
|
258 | + $model_obj = $model->get_one_by_ID($obj_id); |
|
259 | + if (! $model_obj instanceof EE_Base_Class) { |
|
260 | + $lowercase_model_name = strtolower($model->get_this_model_name()); |
|
261 | + throw new RestException( |
|
262 | + sprintf('rest_%s_invalid_id', $lowercase_model_name), |
|
263 | + sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name), |
|
264 | + array('status' => 404) |
|
265 | + ); |
|
266 | + } |
|
267 | + $requested_permanent_delete = filter_var($request->get_param('force'), FILTER_VALIDATE_BOOLEAN); |
|
268 | + $requested_allow_blocking = filter_var($request->get_param('allow_blocking'), FILTER_VALIDATE_BOOLEAN); |
|
269 | + if ($requested_permanent_delete) { |
|
270 | + $previous = $this->returnModelObjAsJsonResponse($model_obj, $request); |
|
271 | + $deleted = (bool) $model->delete_permanently_by_ID($obj_id, $requested_allow_blocking); |
|
272 | + return array( |
|
273 | + 'deleted' => $deleted, |
|
274 | + 'previous' => $previous, |
|
275 | + ); |
|
276 | + } else { |
|
277 | + if ($model instanceof EEM_Soft_Delete_Base) { |
|
278 | + $model->delete_by_ID($obj_id, $requested_allow_blocking); |
|
279 | + return $this->returnModelObjAsJsonResponse($model_obj, $request); |
|
280 | + } else { |
|
281 | + throw new RestException( |
|
282 | + 'rest_trash_not_supported', |
|
283 | + 501, |
|
284 | + sprintf( |
|
285 | + esc_html__('%1$s do not support trashing. Set force=1 to delete.', 'event_espresso'), |
|
286 | + EEH_Inflector::pluralize($model->get_this_model_name()) |
|
287 | + ) |
|
288 | + ); |
|
289 | + } |
|
290 | + } |
|
291 | + } |
|
292 | 292 | |
293 | 293 | |
294 | - /** |
|
295 | - * Returns an array ready to be converted into a JSON response, based solely on the model object |
|
296 | - * |
|
297 | - * @param EE_Base_Class $model_obj |
|
298 | - * @param WP_REST_Request $request |
|
299 | - * @return array ready for a response |
|
300 | - */ |
|
301 | - protected function returnModelObjAsJsonResponse(EE_Base_Class $model_obj, WP_REST_Request $request) |
|
302 | - { |
|
303 | - $model = $model_obj->get_model(); |
|
304 | - // create an array exactly like the wpdb results row, |
|
305 | - // so we can pass it to controllers/model/Read::create_entity_from_wpdb_result() |
|
306 | - $simulated_db_row = array(); |
|
307 | - foreach ($model->field_settings(true) as $field_name => $field_obj) { |
|
308 | - // we need to reconstruct the normal wpdb results, including the db-only fields |
|
309 | - // like a secondary table's primary key. The models expect those (but don't care what value they have) |
|
310 | - if ($field_obj instanceof EE_DB_Only_Field_Base) { |
|
311 | - $raw_value = true; |
|
312 | - } elseif ($field_obj instanceof EE_Datetime_Field) { |
|
313 | - $raw_value = $model_obj->get_DateTime_object($field_name); |
|
314 | - } else { |
|
315 | - $raw_value = $model_obj->get_raw($field_name); |
|
316 | - } |
|
317 | - $simulated_db_row[ $field_obj->get_qualified_column() ] = $field_obj->prepare_for_use_in_db($raw_value); |
|
318 | - } |
|
319 | - $read_controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
|
320 | - $read_controller->setRequestedVersion($this->getRequestedVersion()); |
|
321 | - // the simulates request really doesn't need any info downstream |
|
322 | - $simulated_request = new WP_REST_Request('GET'); |
|
323 | - // set the caps context on the simulated according to the original request. |
|
324 | - switch ($request->get_method()) { |
|
325 | - case 'POST': |
|
326 | - case 'PUT': |
|
327 | - $caps_context = EEM_Base::caps_edit; |
|
328 | - break; |
|
329 | - case 'DELETE': |
|
330 | - $caps_context = EEM_Base::caps_delete; |
|
331 | - break; |
|
332 | - default: |
|
333 | - $caps_context = EEM_Base::caps_read_admin; |
|
334 | - } |
|
335 | - $simulated_request->set_param('caps', $caps_context); |
|
336 | - return $read_controller->createEntityFromWpdbResult( |
|
337 | - $model_obj->get_model(), |
|
338 | - $simulated_db_row, |
|
339 | - $simulated_request |
|
340 | - ); |
|
341 | - } |
|
294 | + /** |
|
295 | + * Returns an array ready to be converted into a JSON response, based solely on the model object |
|
296 | + * |
|
297 | + * @param EE_Base_Class $model_obj |
|
298 | + * @param WP_REST_Request $request |
|
299 | + * @return array ready for a response |
|
300 | + */ |
|
301 | + protected function returnModelObjAsJsonResponse(EE_Base_Class $model_obj, WP_REST_Request $request) |
|
302 | + { |
|
303 | + $model = $model_obj->get_model(); |
|
304 | + // create an array exactly like the wpdb results row, |
|
305 | + // so we can pass it to controllers/model/Read::create_entity_from_wpdb_result() |
|
306 | + $simulated_db_row = array(); |
|
307 | + foreach ($model->field_settings(true) as $field_name => $field_obj) { |
|
308 | + // we need to reconstruct the normal wpdb results, including the db-only fields |
|
309 | + // like a secondary table's primary key. The models expect those (but don't care what value they have) |
|
310 | + if ($field_obj instanceof EE_DB_Only_Field_Base) { |
|
311 | + $raw_value = true; |
|
312 | + } elseif ($field_obj instanceof EE_Datetime_Field) { |
|
313 | + $raw_value = $model_obj->get_DateTime_object($field_name); |
|
314 | + } else { |
|
315 | + $raw_value = $model_obj->get_raw($field_name); |
|
316 | + } |
|
317 | + $simulated_db_row[ $field_obj->get_qualified_column() ] = $field_obj->prepare_for_use_in_db($raw_value); |
|
318 | + } |
|
319 | + $read_controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read'); |
|
320 | + $read_controller->setRequestedVersion($this->getRequestedVersion()); |
|
321 | + // the simulates request really doesn't need any info downstream |
|
322 | + $simulated_request = new WP_REST_Request('GET'); |
|
323 | + // set the caps context on the simulated according to the original request. |
|
324 | + switch ($request->get_method()) { |
|
325 | + case 'POST': |
|
326 | + case 'PUT': |
|
327 | + $caps_context = EEM_Base::caps_edit; |
|
328 | + break; |
|
329 | + case 'DELETE': |
|
330 | + $caps_context = EEM_Base::caps_delete; |
|
331 | + break; |
|
332 | + default: |
|
333 | + $caps_context = EEM_Base::caps_read_admin; |
|
334 | + } |
|
335 | + $simulated_request->set_param('caps', $caps_context); |
|
336 | + return $read_controller->createEntityFromWpdbResult( |
|
337 | + $model_obj->get_model(), |
|
338 | + $simulated_db_row, |
|
339 | + $simulated_request |
|
340 | + ); |
|
341 | + } |
|
342 | 342 | |
343 | 343 | |
344 | - /** |
|
345 | - * Gets the item affected by this request |
|
346 | - * |
|
347 | - * @param EEM_Base $model |
|
348 | - * @param WP_REST_Request $request |
|
349 | - * @param int|string $obj_id |
|
350 | - * @return \WP_Error|array |
|
351 | - */ |
|
352 | - protected function getOneBasedOnRequest(EEM_Base $model, WP_REST_Request $request, $obj_id) |
|
353 | - { |
|
354 | - $requested_version = $this->getRequestedVersion($request->get_route()); |
|
355 | - $get_request = new WP_REST_Request( |
|
356 | - 'GET', |
|
357 | - EED_Core_Rest_Api::ee_api_namespace |
|
358 | - . $requested_version |
|
359 | - . '/' |
|
360 | - . EEH_Inflector::pluralize_and_lower($model->get_this_model_name()) |
|
361 | - . '/' |
|
362 | - . $obj_id |
|
363 | - ); |
|
364 | - $get_request->set_url_params( |
|
365 | - array( |
|
366 | - 'id' => $obj_id, |
|
367 | - 'include' => $request->get_param('include'), |
|
368 | - ) |
|
369 | - ); |
|
370 | - $read_controller = new Read(); |
|
371 | - $read_controller->setRequestedVersion($this->getRequestedVersion()); |
|
372 | - return $read_controller->getEntityFromModel($model, $get_request); |
|
373 | - } |
|
344 | + /** |
|
345 | + * Gets the item affected by this request |
|
346 | + * |
|
347 | + * @param EEM_Base $model |
|
348 | + * @param WP_REST_Request $request |
|
349 | + * @param int|string $obj_id |
|
350 | + * @return \WP_Error|array |
|
351 | + */ |
|
352 | + protected function getOneBasedOnRequest(EEM_Base $model, WP_REST_Request $request, $obj_id) |
|
353 | + { |
|
354 | + $requested_version = $this->getRequestedVersion($request->get_route()); |
|
355 | + $get_request = new WP_REST_Request( |
|
356 | + 'GET', |
|
357 | + EED_Core_Rest_Api::ee_api_namespace |
|
358 | + . $requested_version |
|
359 | + . '/' |
|
360 | + . EEH_Inflector::pluralize_and_lower($model->get_this_model_name()) |
|
361 | + . '/' |
|
362 | + . $obj_id |
|
363 | + ); |
|
364 | + $get_request->set_url_params( |
|
365 | + array( |
|
366 | + 'id' => $obj_id, |
|
367 | + 'include' => $request->get_param('include'), |
|
368 | + ) |
|
369 | + ); |
|
370 | + $read_controller = new Read(); |
|
371 | + $read_controller->setRequestedVersion($this->getRequestedVersion()); |
|
372 | + return $read_controller->getEntityFromModel($model, $get_request); |
|
373 | + } |
|
374 | 374 | |
375 | - /** |
|
376 | - * Adds a relation between the specified models (if it doesn't already exist.) |
|
377 | - * @since 4.9.76.p |
|
378 | - * @param WP_REST_Request $request |
|
379 | - * @return WP_REST_Response |
|
380 | - */ |
|
381 | - public static function handleRequestAddRelation(WP_REST_Request $request, $version, $model_name, $related_model_name) |
|
382 | - { |
|
383 | - $controller = new Write(); |
|
384 | - try { |
|
385 | - $controller->setRequestedVersion($version); |
|
386 | - $main_model = $controller->validateModel($model_name); |
|
387 | - $controller->validateModel($related_model_name); |
|
388 | - return $controller->sendResponse( |
|
389 | - $controller->addRelation( |
|
390 | - $main_model, |
|
391 | - $main_model->related_settings_for($related_model_name), |
|
392 | - $request |
|
393 | - ) |
|
394 | - ); |
|
395 | - } catch (Exception $e) { |
|
396 | - return $controller->sendResponse($e); |
|
397 | - } |
|
398 | - } |
|
375 | + /** |
|
376 | + * Adds a relation between the specified models (if it doesn't already exist.) |
|
377 | + * @since 4.9.76.p |
|
378 | + * @param WP_REST_Request $request |
|
379 | + * @return WP_REST_Response |
|
380 | + */ |
|
381 | + public static function handleRequestAddRelation(WP_REST_Request $request, $version, $model_name, $related_model_name) |
|
382 | + { |
|
383 | + $controller = new Write(); |
|
384 | + try { |
|
385 | + $controller->setRequestedVersion($version); |
|
386 | + $main_model = $controller->validateModel($model_name); |
|
387 | + $controller->validateModel($related_model_name); |
|
388 | + return $controller->sendResponse( |
|
389 | + $controller->addRelation( |
|
390 | + $main_model, |
|
391 | + $main_model->related_settings_for($related_model_name), |
|
392 | + $request |
|
393 | + ) |
|
394 | + ); |
|
395 | + } catch (Exception $e) { |
|
396 | + return $controller->sendResponse($e); |
|
397 | + } |
|
398 | + } |
|
399 | 399 | |
400 | - /** |
|
401 | - * Adds a relation between the two model specified model objects. |
|
402 | - * @since 4.9.76.p |
|
403 | - * @param EEM_Base $model |
|
404 | - * @param EE_Model_Relation_Base $relation |
|
405 | - * @param WP_REST_Request $request |
|
406 | - * @return array |
|
407 | - * @throws EE_Error |
|
408 | - * @throws InvalidArgumentException |
|
409 | - * @throws InvalidDataTypeException |
|
410 | - * @throws InvalidInterfaceException |
|
411 | - * @throws RestException |
|
412 | - * @throws DomainException |
|
413 | - */ |
|
414 | - public function addRelation(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request) |
|
415 | - { |
|
416 | - list($model_obj, $other_obj) = $this->getBothModelObjects($model, $relation, $request); |
|
417 | - $extra_params = array(); |
|
418 | - if ($relation instanceof EE_HABTM_Relation) { |
|
419 | - $extra_params = array_intersect_key( |
|
420 | - ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
421 | - $request->get_body_params(), |
|
422 | - $relation->get_join_model(), |
|
423 | - $this->getModelVersionInfo()->requestedVersion(), |
|
424 | - true |
|
425 | - ), |
|
426 | - $relation->getNonKeyFields() |
|
427 | - ); |
|
428 | - } |
|
429 | - // Add a relation. |
|
430 | - $related_obj = $model_obj->_add_relation_to( |
|
431 | - $other_obj, |
|
432 | - $relation->get_other_model()->get_this_model_name(), |
|
433 | - $extra_params |
|
434 | - ); |
|
435 | - $response = array( |
|
436 | - strtolower($model->get_this_model_name()) => $this->returnModelObjAsJsonResponse($model_obj, $request), |
|
437 | - strtolower($relation->get_other_model()->get_this_model_name()) => $this->returnModelObjAsJsonResponse($related_obj, $request), |
|
438 | - ); |
|
439 | - if ($relation instanceof EE_HABTM_Relation) { |
|
440 | - $join_model_obj = $relation->get_join_model()->get_one( |
|
441 | - array( |
|
442 | - array( |
|
443 | - $relation->get_join_model()->get_foreign_key_to($model->get_this_model_name())->get_name() => $model_obj->ID(), |
|
444 | - $relation->get_join_model()->get_foreign_key_to($relation->get_other_model()->get_this_model_name())->get_name() => $related_obj->ID() |
|
445 | - ) |
|
446 | - ) |
|
447 | - ); |
|
448 | - $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request); |
|
449 | - } |
|
450 | - return $response; |
|
451 | - } |
|
400 | + /** |
|
401 | + * Adds a relation between the two model specified model objects. |
|
402 | + * @since 4.9.76.p |
|
403 | + * @param EEM_Base $model |
|
404 | + * @param EE_Model_Relation_Base $relation |
|
405 | + * @param WP_REST_Request $request |
|
406 | + * @return array |
|
407 | + * @throws EE_Error |
|
408 | + * @throws InvalidArgumentException |
|
409 | + * @throws InvalidDataTypeException |
|
410 | + * @throws InvalidInterfaceException |
|
411 | + * @throws RestException |
|
412 | + * @throws DomainException |
|
413 | + */ |
|
414 | + public function addRelation(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request) |
|
415 | + { |
|
416 | + list($model_obj, $other_obj) = $this->getBothModelObjects($model, $relation, $request); |
|
417 | + $extra_params = array(); |
|
418 | + if ($relation instanceof EE_HABTM_Relation) { |
|
419 | + $extra_params = array_intersect_key( |
|
420 | + ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
421 | + $request->get_body_params(), |
|
422 | + $relation->get_join_model(), |
|
423 | + $this->getModelVersionInfo()->requestedVersion(), |
|
424 | + true |
|
425 | + ), |
|
426 | + $relation->getNonKeyFields() |
|
427 | + ); |
|
428 | + } |
|
429 | + // Add a relation. |
|
430 | + $related_obj = $model_obj->_add_relation_to( |
|
431 | + $other_obj, |
|
432 | + $relation->get_other_model()->get_this_model_name(), |
|
433 | + $extra_params |
|
434 | + ); |
|
435 | + $response = array( |
|
436 | + strtolower($model->get_this_model_name()) => $this->returnModelObjAsJsonResponse($model_obj, $request), |
|
437 | + strtolower($relation->get_other_model()->get_this_model_name()) => $this->returnModelObjAsJsonResponse($related_obj, $request), |
|
438 | + ); |
|
439 | + if ($relation instanceof EE_HABTM_Relation) { |
|
440 | + $join_model_obj = $relation->get_join_model()->get_one( |
|
441 | + array( |
|
442 | + array( |
|
443 | + $relation->get_join_model()->get_foreign_key_to($model->get_this_model_name())->get_name() => $model_obj->ID(), |
|
444 | + $relation->get_join_model()->get_foreign_key_to($relation->get_other_model()->get_this_model_name())->get_name() => $related_obj->ID() |
|
445 | + ) |
|
446 | + ) |
|
447 | + ); |
|
448 | + $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request); |
|
449 | + } |
|
450 | + return $response; |
|
451 | + } |
|
452 | 452 | |
453 | 453 | |
454 | - /** |
|
455 | - * Removes the relation between the specified models (if it exists). |
|
456 | - * @since 4.9.76.p |
|
457 | - * @param WP_REST_Request $request |
|
458 | - * @return WP_REST_Response |
|
459 | - */ |
|
460 | - public static function handleRequestRemoveRelation(WP_REST_Request $request, $version, $model_name, $related_model_name) |
|
461 | - { |
|
462 | - $controller = new Write(); |
|
463 | - try { |
|
464 | - $controller->setRequestedVersion($version); |
|
465 | - $main_model = $controller->getModelVersionInfo()->loadModel($model_name); |
|
466 | - return $controller->sendResponse( |
|
467 | - $controller->removeRelation( |
|
468 | - $main_model, |
|
469 | - $main_model->related_settings_for($related_model_name), |
|
470 | - $request |
|
471 | - ) |
|
472 | - ); |
|
473 | - } catch (Exception $e) { |
|
474 | - return $controller->sendResponse($e); |
|
475 | - } |
|
476 | - } |
|
454 | + /** |
|
455 | + * Removes the relation between the specified models (if it exists). |
|
456 | + * @since 4.9.76.p |
|
457 | + * @param WP_REST_Request $request |
|
458 | + * @return WP_REST_Response |
|
459 | + */ |
|
460 | + public static function handleRequestRemoveRelation(WP_REST_Request $request, $version, $model_name, $related_model_name) |
|
461 | + { |
|
462 | + $controller = new Write(); |
|
463 | + try { |
|
464 | + $controller->setRequestedVersion($version); |
|
465 | + $main_model = $controller->getModelVersionInfo()->loadModel($model_name); |
|
466 | + return $controller->sendResponse( |
|
467 | + $controller->removeRelation( |
|
468 | + $main_model, |
|
469 | + $main_model->related_settings_for($related_model_name), |
|
470 | + $request |
|
471 | + ) |
|
472 | + ); |
|
473 | + } catch (Exception $e) { |
|
474 | + return $controller->sendResponse($e); |
|
475 | + } |
|
476 | + } |
|
477 | 477 | |
478 | - /** |
|
479 | - * Adds a relation between the two model specified model objects. |
|
480 | - * @since 4.9.76.p |
|
481 | - * @param EEM_Base $model |
|
482 | - * @param EE_Model_Relation_Base $relation |
|
483 | - * @param WP_REST_Request $request |
|
484 | - * @return array |
|
485 | - * @throws DomainException |
|
486 | - * @throws EE_Error |
|
487 | - * @throws InvalidArgumentException |
|
488 | - * @throws InvalidDataTypeException |
|
489 | - * @throws InvalidInterfaceException |
|
490 | - * @throws RestException |
|
491 | - */ |
|
492 | - public function removeRelation(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request) |
|
493 | - { |
|
494 | - // This endpoint doesn't accept body parameters (it's understandable to think it might, so let developers know |
|
495 | - // up-front that it doesn't.) |
|
496 | - if (!empty($request->get_body_params())) { |
|
497 | - $body_params = $request->get_body_params(); |
|
498 | - throw new RestException( |
|
499 | - 'invalid_field', |
|
500 | - sprintf( |
|
501 | - esc_html__('This endpoint doesn\'t accept post body arguments, you sent in %1$s', 'event_espresso'), |
|
502 | - implode(array_keys($body_params)) |
|
503 | - ) |
|
504 | - ); |
|
505 | - } |
|
506 | - list($model_obj, $other_obj) = $this->getBothModelObjects($model, $relation, $request); |
|
507 | - // Remember the old relation, if it used a join entry. |
|
508 | - $join_model_obj = null; |
|
509 | - if ($relation instanceof EE_HABTM_Relation) { |
|
510 | - $join_model_obj = $relation->get_join_model()->get_one( |
|
511 | - array( |
|
512 | - array( |
|
513 | - $model->primary_key_name() => $model_obj->ID(), |
|
514 | - $relation->get_other_model()->primary_key_name() => $other_obj->ID() |
|
515 | - ) |
|
516 | - ) |
|
517 | - ); |
|
518 | - } |
|
519 | - // Remove the relation. |
|
520 | - $related_obj = $model_obj->_remove_relation_to( |
|
521 | - $other_obj, |
|
522 | - $relation->get_other_model()->get_this_model_name() |
|
523 | - ); |
|
524 | - $response = array( |
|
525 | - strtolower($model->get_this_model_name()) => $this->returnModelObjAsJsonResponse($model_obj, $request), |
|
526 | - strtolower($relation->get_other_model()->get_this_model_name()) => $this->returnModelObjAsJsonResponse($related_obj, $request), |
|
527 | - ); |
|
528 | - if ($relation instanceof EE_HABTM_Relation) { |
|
529 | - $join_model_obj_after_removal = $relation->get_join_model()->get_one( |
|
530 | - array( |
|
531 | - array( |
|
532 | - $model->primary_key_name() => $model_obj->ID(), |
|
533 | - $relation->get_other_model()->primary_key_name() => $other_obj->ID() |
|
534 | - ) |
|
535 | - ) |
|
536 | - ); |
|
537 | - if ($join_model_obj instanceof EE_Base_Class) { |
|
538 | - $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request); |
|
539 | - } else { |
|
540 | - $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = null; |
|
541 | - } |
|
542 | - } |
|
543 | - return $response; |
|
544 | - } |
|
478 | + /** |
|
479 | + * Adds a relation between the two model specified model objects. |
|
480 | + * @since 4.9.76.p |
|
481 | + * @param EEM_Base $model |
|
482 | + * @param EE_Model_Relation_Base $relation |
|
483 | + * @param WP_REST_Request $request |
|
484 | + * @return array |
|
485 | + * @throws DomainException |
|
486 | + * @throws EE_Error |
|
487 | + * @throws InvalidArgumentException |
|
488 | + * @throws InvalidDataTypeException |
|
489 | + * @throws InvalidInterfaceException |
|
490 | + * @throws RestException |
|
491 | + */ |
|
492 | + public function removeRelation(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request) |
|
493 | + { |
|
494 | + // This endpoint doesn't accept body parameters (it's understandable to think it might, so let developers know |
|
495 | + // up-front that it doesn't.) |
|
496 | + if (!empty($request->get_body_params())) { |
|
497 | + $body_params = $request->get_body_params(); |
|
498 | + throw new RestException( |
|
499 | + 'invalid_field', |
|
500 | + sprintf( |
|
501 | + esc_html__('This endpoint doesn\'t accept post body arguments, you sent in %1$s', 'event_espresso'), |
|
502 | + implode(array_keys($body_params)) |
|
503 | + ) |
|
504 | + ); |
|
505 | + } |
|
506 | + list($model_obj, $other_obj) = $this->getBothModelObjects($model, $relation, $request); |
|
507 | + // Remember the old relation, if it used a join entry. |
|
508 | + $join_model_obj = null; |
|
509 | + if ($relation instanceof EE_HABTM_Relation) { |
|
510 | + $join_model_obj = $relation->get_join_model()->get_one( |
|
511 | + array( |
|
512 | + array( |
|
513 | + $model->primary_key_name() => $model_obj->ID(), |
|
514 | + $relation->get_other_model()->primary_key_name() => $other_obj->ID() |
|
515 | + ) |
|
516 | + ) |
|
517 | + ); |
|
518 | + } |
|
519 | + // Remove the relation. |
|
520 | + $related_obj = $model_obj->_remove_relation_to( |
|
521 | + $other_obj, |
|
522 | + $relation->get_other_model()->get_this_model_name() |
|
523 | + ); |
|
524 | + $response = array( |
|
525 | + strtolower($model->get_this_model_name()) => $this->returnModelObjAsJsonResponse($model_obj, $request), |
|
526 | + strtolower($relation->get_other_model()->get_this_model_name()) => $this->returnModelObjAsJsonResponse($related_obj, $request), |
|
527 | + ); |
|
528 | + if ($relation instanceof EE_HABTM_Relation) { |
|
529 | + $join_model_obj_after_removal = $relation->get_join_model()->get_one( |
|
530 | + array( |
|
531 | + array( |
|
532 | + $model->primary_key_name() => $model_obj->ID(), |
|
533 | + $relation->get_other_model()->primary_key_name() => $other_obj->ID() |
|
534 | + ) |
|
535 | + ) |
|
536 | + ); |
|
537 | + if ($join_model_obj instanceof EE_Base_Class) { |
|
538 | + $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request); |
|
539 | + } else { |
|
540 | + $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = null; |
|
541 | + } |
|
542 | + } |
|
543 | + return $response; |
|
544 | + } |
|
545 | 545 | |
546 | - /** |
|
547 | - * Gets the model objects indicated by the model, relation object, and request. |
|
548 | - * Throws an exception if the first object doesn't exist, and currently if the related object also doesn't exist. |
|
549 | - * However, this behaviour may change, as we may add support for simultaneously creating and relating data. |
|
550 | - * @since 4.9.76.p |
|
551 | - * @param EEM_Base $model |
|
552 | - * @param EE_Model_Relation_Base $relation |
|
553 | - * @param WP_REST_Request $request |
|
554 | - * @return array { |
|
555 | - * @type EE_Base_Class $model_obj |
|
556 | - * @type EE_Base_Class|null $other_model_obj |
|
557 | - * } |
|
558 | - * @throws RestException |
|
559 | - */ |
|
560 | - protected function getBothModelObjects(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request) |
|
561 | - { |
|
562 | - // Check generic caps. For now, we're only allowing access to this endpoint to full admins. |
|
563 | - Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit'); |
|
564 | - $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap(); |
|
565 | - if (! current_user_can($default_cap_to_check_for)) { |
|
566 | - throw new RestException( |
|
567 | - 'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
568 | - sprintf( |
|
569 | - esc_html__( |
|
570 | - // @codingStandardsIgnoreStart |
|
571 | - 'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to add relations in Event Espresso.', |
|
572 | - // @codingStandardsIgnoreEnd |
|
573 | - 'event_espresso' |
|
574 | - ), |
|
575 | - $default_cap_to_check_for |
|
576 | - ), |
|
577 | - array('status' => 403) |
|
578 | - ); |
|
579 | - } |
|
580 | - // Get the main model object. |
|
581 | - $model_obj = $this->getOneOrThrowException($model, $request->get_param('id')); |
|
582 | - // For now, we require the other model object to exist too. This might be relaxed later. |
|
583 | - $other_obj = $this->getOneOrThrowException($relation->get_other_model(), $request->get_param('related_id')); |
|
584 | - return array($model_obj,$other_obj); |
|
585 | - } |
|
546 | + /** |
|
547 | + * Gets the model objects indicated by the model, relation object, and request. |
|
548 | + * Throws an exception if the first object doesn't exist, and currently if the related object also doesn't exist. |
|
549 | + * However, this behaviour may change, as we may add support for simultaneously creating and relating data. |
|
550 | + * @since 4.9.76.p |
|
551 | + * @param EEM_Base $model |
|
552 | + * @param EE_Model_Relation_Base $relation |
|
553 | + * @param WP_REST_Request $request |
|
554 | + * @return array { |
|
555 | + * @type EE_Base_Class $model_obj |
|
556 | + * @type EE_Base_Class|null $other_model_obj |
|
557 | + * } |
|
558 | + * @throws RestException |
|
559 | + */ |
|
560 | + protected function getBothModelObjects(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request) |
|
561 | + { |
|
562 | + // Check generic caps. For now, we're only allowing access to this endpoint to full admins. |
|
563 | + Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit'); |
|
564 | + $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap(); |
|
565 | + if (! current_user_can($default_cap_to_check_for)) { |
|
566 | + throw new RestException( |
|
567 | + 'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())), |
|
568 | + sprintf( |
|
569 | + esc_html__( |
|
570 | + // @codingStandardsIgnoreStart |
|
571 | + 'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to add relations in Event Espresso.', |
|
572 | + // @codingStandardsIgnoreEnd |
|
573 | + 'event_espresso' |
|
574 | + ), |
|
575 | + $default_cap_to_check_for |
|
576 | + ), |
|
577 | + array('status' => 403) |
|
578 | + ); |
|
579 | + } |
|
580 | + // Get the main model object. |
|
581 | + $model_obj = $this->getOneOrThrowException($model, $request->get_param('id')); |
|
582 | + // For now, we require the other model object to exist too. This might be relaxed later. |
|
583 | + $other_obj = $this->getOneOrThrowException($relation->get_other_model(), $request->get_param('related_id')); |
|
584 | + return array($model_obj,$other_obj); |
|
585 | + } |
|
586 | 586 | |
587 | - /** |
|
588 | - * Gets the model with that ID or throws a REST exception. |
|
589 | - * @since 4.9.76.p |
|
590 | - * @param EEM_Base $model |
|
591 | - * @param $id |
|
592 | - * @return EE_Base_Class |
|
593 | - * @throws RestException |
|
594 | - */ |
|
595 | - protected function getOneOrThrowException(EEM_Base $model, $id) |
|
596 | - { |
|
597 | - $model_obj = $model->get_one_by_ID($id); |
|
598 | - // @todo: check they can permission for it. For now unnecessary because only full admins can use this endpoint. |
|
599 | - if ($model_obj instanceof EE_Base_Class) { |
|
600 | - return $model_obj; |
|
601 | - } |
|
602 | - $lowercase_model_name = strtolower($model->get_this_model_name()); |
|
603 | - throw new RestException( |
|
604 | - sprintf('rest_%s_invalid_id', $lowercase_model_name), |
|
605 | - sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name), |
|
606 | - array('status' => 404) |
|
607 | - ); |
|
608 | - } |
|
587 | + /** |
|
588 | + * Gets the model with that ID or throws a REST exception. |
|
589 | + * @since 4.9.76.p |
|
590 | + * @param EEM_Base $model |
|
591 | + * @param $id |
|
592 | + * @return EE_Base_Class |
|
593 | + * @throws RestException |
|
594 | + */ |
|
595 | + protected function getOneOrThrowException(EEM_Base $model, $id) |
|
596 | + { |
|
597 | + $model_obj = $model->get_one_by_ID($id); |
|
598 | + // @todo: check they can permission for it. For now unnecessary because only full admins can use this endpoint. |
|
599 | + if ($model_obj instanceof EE_Base_Class) { |
|
600 | + return $model_obj; |
|
601 | + } |
|
602 | + $lowercase_model_name = strtolower($model->get_this_model_name()); |
|
603 | + throw new RestException( |
|
604 | + sprintf('rest_%s_invalid_id', $lowercase_model_name), |
|
605 | + sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name), |
|
606 | + array('status' => 404) |
|
607 | + ); |
|
608 | + } |
|
609 | 609 | } |
@@ -37,74 +37,74 @@ |
||
37 | 37 | abstract class ChangesInBase |
38 | 38 | { |
39 | 39 | |
40 | - /** |
|
41 | - * The version that these changes happened |
|
42 | - * |
|
43 | - * @var string |
|
44 | - */ |
|
45 | - protected $version = null; |
|
40 | + /** |
|
41 | + * The version that these changes happened |
|
42 | + * |
|
43 | + * @var string |
|
44 | + */ |
|
45 | + protected $version = null; |
|
46 | 46 | |
47 | 47 | |
48 | - /** |
|
49 | - * Called when an EE4 REST API request is made to an earlier version than |
|
50 | - * what is indicated in this class' name. |
|
51 | - * Uses WordPress' add_filter and add_action to modify the EE4 REST API's response |
|
52 | - * so that regardless of what version of EE4 core is running, API clients |
|
53 | - * will have a consistent response |
|
54 | - * |
|
55 | - * @return void |
|
56 | - */ |
|
57 | - abstract public function setHooks(); |
|
48 | + /** |
|
49 | + * Called when an EE4 REST API request is made to an earlier version than |
|
50 | + * what is indicated in this class' name. |
|
51 | + * Uses WordPress' add_filter and add_action to modify the EE4 REST API's response |
|
52 | + * so that regardless of what version of EE4 core is running, API clients |
|
53 | + * will have a consistent response |
|
54 | + * |
|
55 | + * @return void |
|
56 | + */ |
|
57 | + abstract public function setHooks(); |
|
58 | 58 | |
59 | 59 | |
60 | - /** |
|
61 | - * Returns whether or not this class' name indicates its hooks should |
|
62 | - * apply when a request comes in for $requested_version. A class can use |
|
63 | - * other conditions when determining whether to perform their callbacks or not, |
|
64 | - * but this will typically be enough |
|
65 | - * |
|
66 | - * @param string $requested_version eg "4.8.33" |
|
67 | - * @return boolean true: this class' name indicates its filters and actions |
|
68 | - * should take effect. False: this class' name indicates it shouldn't do anything |
|
69 | - */ |
|
70 | - public function appliesToVersion($requested_version) |
|
71 | - { |
|
72 | - if ($this->version() > $requested_version) { |
|
73 | - return true; |
|
74 | - } |
|
75 | - return false; |
|
76 | - } |
|
60 | + /** |
|
61 | + * Returns whether or not this class' name indicates its hooks should |
|
62 | + * apply when a request comes in for $requested_version. A class can use |
|
63 | + * other conditions when determining whether to perform their callbacks or not, |
|
64 | + * but this will typically be enough |
|
65 | + * |
|
66 | + * @param string $requested_version eg "4.8.33" |
|
67 | + * @return boolean true: this class' name indicates its filters and actions |
|
68 | + * should take effect. False: this class' name indicates it shouldn't do anything |
|
69 | + */ |
|
70 | + public function appliesToVersion($requested_version) |
|
71 | + { |
|
72 | + if ($this->version() > $requested_version) { |
|
73 | + return true; |
|
74 | + } |
|
75 | + return false; |
|
76 | + } |
|
77 | 77 | |
78 | 78 | |
79 | - /** |
|
80 | - * Gets the EE core version when this changes were made to the rest api. |
|
81 | - * Any requests to earlier versions should have modifications made to them |
|
82 | - * by the callbacks of this class. |
|
83 | - * |
|
84 | - * @return string eg "4.8.33" |
|
85 | - * @throws EE_Error |
|
86 | - */ |
|
87 | - public function version() |
|
88 | - { |
|
89 | - if ($this->version === null) { |
|
90 | - $matches = array(); |
|
91 | - $regex = '~ChangesIn(\d)(\d\d)(\d\d)$~'; |
|
92 | - $success = preg_match( |
|
93 | - $regex, |
|
94 | - get_class($this), |
|
95 | - $matches |
|
96 | - ); |
|
97 | - if (! $success) { |
|
98 | - throw new EE_Error( |
|
99 | - sprintf( |
|
100 | - esc_html__('The class %1$s was misnamed. It name should match the regex "%2$s"', 'event_espresso'), |
|
101 | - get_class($this), |
|
102 | - $regex |
|
103 | - ) |
|
104 | - ); |
|
105 | - } |
|
106 | - $this->version = (int) $matches[1] . '.' . (int) $matches[2] . '.' . (int) $matches[3]; |
|
107 | - } |
|
108 | - return $this->version; |
|
109 | - } |
|
79 | + /** |
|
80 | + * Gets the EE core version when this changes were made to the rest api. |
|
81 | + * Any requests to earlier versions should have modifications made to them |
|
82 | + * by the callbacks of this class. |
|
83 | + * |
|
84 | + * @return string eg "4.8.33" |
|
85 | + * @throws EE_Error |
|
86 | + */ |
|
87 | + public function version() |
|
88 | + { |
|
89 | + if ($this->version === null) { |
|
90 | + $matches = array(); |
|
91 | + $regex = '~ChangesIn(\d)(\d\d)(\d\d)$~'; |
|
92 | + $success = preg_match( |
|
93 | + $regex, |
|
94 | + get_class($this), |
|
95 | + $matches |
|
96 | + ); |
|
97 | + if (! $success) { |
|
98 | + throw new EE_Error( |
|
99 | + sprintf( |
|
100 | + esc_html__('The class %1$s was misnamed. It name should match the regex "%2$s"', 'event_espresso'), |
|
101 | + get_class($this), |
|
102 | + $regex |
|
103 | + ) |
|
104 | + ); |
|
105 | + } |
|
106 | + $this->version = (int) $matches[1] . '.' . (int) $matches[2] . '.' . (int) $matches[3]; |
|
107 | + } |
|
108 | + return $this->version; |
|
109 | + } |
|
110 | 110 | } |
@@ -94,7 +94,7 @@ discard block |
||
94 | 94 | get_class($this), |
95 | 95 | $matches |
96 | 96 | ); |
97 | - if (! $success) { |
|
97 | + if ( ! $success) { |
|
98 | 98 | throw new EE_Error( |
99 | 99 | sprintf( |
100 | 100 | esc_html__('The class %1$s was misnamed. It name should match the regex "%2$s"', 'event_espresso'), |
@@ -103,7 +103,7 @@ discard block |
||
103 | 103 | ) |
104 | 104 | ); |
105 | 105 | } |
106 | - $this->version = (int) $matches[1] . '.' . (int) $matches[2] . '.' . (int) $matches[3]; |
|
106 | + $this->version = (int) $matches[1].'.'.(int) $matches[2].'.'.(int) $matches[3]; |
|
107 | 107 | } |
108 | 108 | return $this->version; |
109 | 109 | } |