Completed
Branch fix-dummy-related-question-qst... (e5efcf)
by
unknown
07:49 queued 03:45
created
core/libraries/plugin_api/EE_Register_Admin_Page.lib.php 2 patches
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -44,7 +44,7 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
     }
Please login to merge, or discard this patch.
Indentation   +135 added lines, -135 removed lines patch added patch discarded remove patch
@@ -10,139 +10,139 @@
 block discarded – undo
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
 }
Please login to merge, or discard this patch.
core/libraries/shortcodes/EE_Ticket_Shortcodes.lib.php 2 patches
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -47,20 +47,20 @@  discard block
 block discarded – undo
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 &infin; 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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 
Please login to merge, or discard this patch.
Indentation   +119 added lines, -119 removed lines patch added patch discarded remove patch
@@ -17,123 +17,123 @@
 block discarded – undo
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 &infin; 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 &infin; 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
 }
Please login to merge, or discard this patch.
core/libraries/shortcodes/EE_Payment_List_Shortcodes.lib.php 2 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -29,15 +29,15 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 
Please login to merge, or discard this patch.
Indentation   +84 added lines, -84 removed lines patch added patch discarded remove patch
@@ -18,88 +18,88 @@
 block discarded – undo
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
 }
Please login to merge, or discard this patch.
core/libraries/shortcodes/EE_Messenger_Shortcodes.lib.php 2 patches
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -61,7 +61,7 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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;
Please login to merge, or discard this patch.
Indentation   +149 added lines, -149 removed lines patch added patch discarded remove patch
@@ -22,157 +22,157 @@
 block discarded – undo
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
 }
Please login to merge, or discard this patch.
core/libraries/payment_methods/EE_PMT_Base.lib.php 2 patches
Spacing   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -118,7 +118,7 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
     }
Please login to merge, or discard this patch.
Indentation   +810 added lines, -810 removed lines patch added patch discarded remove patch
@@ -21,814 +21,814 @@
 block discarded – undo
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
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Base.php 2 patches
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -50,7 +50,7 @@  discard block
 block discarded – undo
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
 block discarded – undo
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(
Please login to merge, or discard this patch.
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -18,95 +18,95 @@
 block discarded – undo
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
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Read.php 2 patches
Spacing   +63 added lines, -63 removed lines patch added patch discarded remove patch
@@ -86,7 +86,7 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
             }
Please login to merge, or discard this patch.
Indentation   +1625 added lines, -1625 removed lines patch added patch discarded remove patch
@@ -49,1629 +49,1629 @@
 block discarded – undo
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
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Write.php 2 patches
Spacing   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -134,9 +134,9 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
     /**
Please login to merge, or discard this patch.
Indentation   +546 added lines, -546 removed lines patch added patch discarded remove patch
@@ -37,573 +37,573 @@
 block discarded – undo
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
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/changes/ChangesInBase.php 2 patches
Indentation   +64 added lines, -64 removed lines patch added patch discarded remove patch
@@ -37,74 +37,74 @@
 block discarded – undo
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
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -94,7 +94,7 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
     }
Please login to merge, or discard this patch.