PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.77
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.77
5.5.85 5.5.84 5.5.83 5.5.82 5.5.81 5.5.80 5.5.79 5.5.77 5.5.76 5.5.75 5.5.73 5.5.72 5.5.22 5.5.23 5.5.29 5.5.3 5.5.31 5.5.32 5.5.34 5.5.35 5.5.36 5.5.37 5.5.4 5.5.40 5.5.41 All 161 releases
wp-data-access / WPDataProjects / Parent_Child / WPDP_Child_List_Table.php

WPDP_Child_List_Table.php in WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards 5.5.77, at WPDataProjects/Parent_Child/WPDP_Child_List_Table.php

496 lines 14.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Suppress "error - 0 - No summary was found for this file" on phpdoc generation
5 *
6 * @package WPDataProjects\Parent_Child
7 */
8
9 namespace WPDataProjects\Parent_Child {
10
11 use WPDataAccess\Connection\WPDADB;
12 use WPDataAccess\WPDA;
13 use WPDataProjects\List_Table\WPDP_List_Table_Lookup;
14
15 /**
16 * Class WPDP_Child_List_Table extends WPDP_List_Table_Lookup
17 *
18 * @see WPDP_List_Table_Lookup
19 *
20 * @author Peter Schulz
21 * @since 2.0.0
22 */
23 class WPDP_Child_List_Table extends WPDP_List_Table_Lookup {
24
25 /**
26 * Possible values: edit and view
27 *
28 * @var string
29 */
30 protected $mode;
31
32 /**
33 * Parent key values
34 *
35 * @var array
36 */
37 protected $parent;
38
39 /**
40 * Child relationships (for actual parent)
41 *
42 * @var array
43 */
44 protected $child;
45
46 /**
47 * Tab value of actual child
48 *
49 * @var string
50 */
51 protected $child_tab = '';
52
53 /**
54 * Flexible usage of IN and NOT IN :-o
55 *
56 * @var string
57 */
58 protected $where_in = 'in'; // Just to save code! (opposite using in WPDP_Child_List_Table_Selection: not in)
59
60 /**
61 * Indicates that this is a list table for a child
62 *
63 * Parent and stand-alone list tables do not have this property.
64 *
65 * @var bool
66 */
67 public $is_child = true;
68
69 /**
70 * Overwrites WPDP_Child_List_Table constructor
71 *
72 * @param array $args
73 */
74 public function __construct( $args = array() ) {
75 if ( isset( $args['mode'] ) ) {
76 $this->mode = $args['mode'];
77 } else {
78 wp_die( esc_attr__( 'ERROR: Wrong arguments [missing mode]', 'wp-data-access' ) );
79 }
80
81 if ( isset( $args['parent'] ) ) {
82 $this->parent = $args['parent'];
83 } else {
84 wp_die( esc_attr__( 'ERROR: Wrong arguments [missing parent]', 'wp-data-access' ) );
85 }
86
87 if ( isset( $args['child'] ) ) {
88 $this->child = $args['child'];
89 } else {
90 wp_die( esc_attr__( 'ERROR: Wrong arguments [missing child]', 'wp-data-access' ) );
91 }
92
93 $args['child_request'] = true;
94 $args['allow_insert'] = 'off';
95
96 if ( 'view' === $this->mode ) {
97 $args['allow_delete'] = 'off';
98 } else {
99 $args['allow_delete'] = 'on';
100 }
101
102 if ( 'edit' === $this->mode ) {
103 $args['bulk_actions_enabled'] = true;
104 } else {
105 $args['bulk_actions_enabled'] = false;
106 }
107
108 if ( isset( $_REQUEST['child_tab'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- already verified
109 $this->child_tab = sanitize_text_field( wp_unslash( $_REQUEST['child_tab'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- already verified
110 }
111
112 $this->page_number_item_name = 'child_page_number';
113
114 parent::__construct( $args );
115
116 }
117
118 /**
119 * Overwrite method get_search_value to add parent arguments
120 *
121 * @param null $param_cookie_name
122 *
123 * @return string
124 */
125 protected function get_search_value( $param_cookie_name = null ) {
126 $parent_key_values = '';
127 foreach ( $this->parent['parent_key_value'] as $parent_key_value ) {
128 $parent_key_values .= esc_attr( $parent_key_value );
129 }
130
131 return parent::get_search_value(
132 $this->page . '_search_child_' . $parent_key_values .
133 str_replace( '.', '_', $this->table_name )
134 );
135 }
136
137 /**
138 * Overwrites method search_box to add parent arguments
139 *
140 * @param string $text
141 * @param string $input_id
142 */
143 public function search_box( $text, $input_id ) {
144 parent::search_box( $text, $input_id );
145
146 $this->add_parent_args();
147 }
148
149 /**
150 * Add parent arguments as hidden items
151 */
152 protected function add_parent_args() {
153 foreach ( $this->parent['parent_key'] as $parent_key ) {
154 ?>
155 <input type='hidden'
156 name='WPDA_PARENT_KEY*<?php echo( esc_attr( $parent_key ) ); ?>'
157 value='<?php echo( esc_attr( $this->parent['parent_key_value'][ $parent_key ] ) ); ?>'
158 />
159 <?php
160 }
161 ?>
162 <input type="hidden" name="mode" value="<?php echo esc_attr( $this->mode ); ?>">
163 <input type='hidden' name='child_request' value='TRUE'/>
164 <input type='hidden' name='child_tab' value='<?php echo esc_attr( $this->child_tab ); ?>'/>
165 <?php
166 if ( ! $this->has_items() ) {
167 ?>
168 <input type='hidden' name='action' value='-1'/>
169 <input type='hidden' name='action2' value='-1'/>
170 <input type='hidden' name='paged' value='1'/>
171 <?php
172 }
173 }
174
175 /**
176 * Add parent arguments as string
177 */
178 protected function add_parent_args_as_string( $item ) {
179 $parent_args = '';
180
181 foreach ( $this->parent['parent_key'] as $parent_key ) {
182 $p_key = esc_attr( $parent_key );
183 $p_val = esc_attr( $this->parent['parent_key_value'][ $parent_key ] );
184 $parent_args .= "<input type='hidden' name='WPDA_PARENT_KEY*$p_key' value='$p_val'/>";
185 }
186
187 $mode = esc_attr( $this->mode );
188 $child_tab = esc_attr( $this->child_tab );
189
190 $parent_args .= "<input type='hidden' name='mode' value='$mode'>";
191 $parent_args .= "<input type='hidden' name='child_request' value='TRUE'/>";
192 $parent_args .= "<input type='hidden' name='child_tab' value='$child_tab'/>";
193
194 if ( ! $this->has_items() ) {
195 $parent_args .= "<input type='hidden' name='action' value='-1'/>";
196 $parent_args .= "<input type='hidden' name='action2' value='-1'/>";
197 $parent_args .= "<input type='hidden' name='paged' value='1'/>";
198 }
199
200 return $parent_args;
201 }
202
203 /**
204 * Constructs the where clause depending on the relationship type
205 *
206 * Adds a subquery for n:m relationships. Adds parent key value comparison for 1:n relationships.
207 */
208 protected function construct_where_clause() {
209 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
210 if ( null === $wpdadb ) {
211 if ( is_admin() ) {
212 /* translators: %s = database name */
213 wp_die( sprintf( esc_attr__( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
214 } else {
215 /* translators: %s = database name */
216 die( sprintf( esc_attr__( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
217 }
218 }
219
220 if (
221 isset( $this->child['default_where'] ) &&
222 null !== $this->child['default_where'] &&
223 '' !== trim( $this->child['default_where'] )
224 ) {
225 $default_where = " and ( {$this->child['default_where']} ) ";
226 $default_where = WPDA::substitute_environment_vars( $default_where );
227 } else {
228 $default_where = '';
229 }
230
231 if ( isset( $this->child['relation_nm'] ) ) {
232 $child_table = $this->child['relation_nm']['child_table'];
233 $parent_key = $this->child['relation_nm']['parent_key'];
234 $child_table_select = $this->child['relation_nm']['child_table_select'];
235 $child_table_where = $this->child['relation_nm']['child_table_where'];
236 $data_type = $this->child['relation_nm']['data_type'];
237
238 $parent_key_column_names = '';
239 $select_column_names = '';
240 $index = 0;
241
242 foreach ( $parent_key as $key ) {
243 if ( $key === reset( $parent_key ) ) { // phpcs:ignore -- 8.1 proof
244 $parent_key_column_names .= "(`$key`";
245 $select_column_names .= '`' . $child_table_select[ $index ] . '`';
246 } else {
247 $parent_key_column_names .= ",`$key`";
248 $select_column_names .= ', `' . $child_table_select[ $index ] . '`';
249 }
250 $index ++;
251 }
252 $parent_key_column_names .= ')';
253
254 $index = 0;
255 $where = '';
256
257 foreach ( $child_table_where as $child_where ) {
258 if ( $child_where === reset( $child_table_where ) ) { // phpcs:ignore -- 8.1 proof
259 $and = '';
260 } else {
261 $and = ' and ';
262 }
263 if ( 'number' === strtolower( $data_type[ $index ] ) ) {
264 $where .=
265 $wpdadb->prepare(
266 " $and `$child_where` = %f ",
267 $this->parent['parent_key_value'][ $this->parent['parent_key'][ $index ] ]
268 );
269 } else {
270 $where .=
271 $wpdadb->prepare(
272 " $and `$child_where` = %s ",
273 $this->parent['parent_key_value'][ $this->parent['parent_key'][ $index ] ]
274 );
275 }
276 $index ++;
277 }
278
279 if ( '' === $this->schema_name ) {
280 $schema_table_name = "`$child_table`";
281 } else {
282 $schema_table_name = "`{$wpdadb->dbname}`.`$child_table`";
283 }
284
285 $this->where =
286 " where ($parent_key_column_names {$this->where_in} " .
287 " (select $select_column_names from $schema_table_name where $where)) ";
288 } elseif ( isset( $this->child['relation_1n'] ) ) {
289 $child_key = $this->child['relation_1n']['child_key'];
290 $data_type = $this->child['relation_1n']['data_type'];
291
292 if (
293 isset( $this->child['relation_1n']['parent_key'] ) &&
294 is_array( $this->child['relation_1n']['parent_key'] )
295 ) {
296 $parent_key = $this->child['relation_1n']['parent_key'];
297 } else {
298 $parent_key = null;
299 }
300
301 $index = 0;
302 $where = '';
303
304 foreach ( $child_key as $key ) {
305 if ( $key === reset( $child_key ) ) { // phpcs:ignore -- 8.1 proof
306 $and = '';
307 } else {
308 $and = ' and ';
309 }
310
311 if ( null === $parent_key ) {
312 $parent_key_value = $this->parent['parent_key_value'][ $this->parent['parent_key'][ $index ] ];
313 } else {
314 if ( $parent_key == $this->parent['parent_key'] ) {
315 $parent_key_value = $this->parent['parent_key_value'][ $this->parent['parent_key'][ $index ] ];
316 } else {
317 // phpcs:disable WordPress.Security.NonceVerification.Recommended -- already verified
318 if ( isset( $_REQUEST[ 'WPDA_PARENT_KEY*' . $parent_key[ $index ] ] ) ) {
319 $parent_key_value = sanitize_text_field( wp_unslash( $_REQUEST[ 'WPDA_PARENT_KEY*' . $parent_key[ $index ] ] ) ); // input var okay.
320 } elseif ( isset( $_REQUEST[ $parent_key[ $index ] ] ) ) {
321 $parent_key_value = sanitize_text_field( wp_unslash( $_REQUEST[ $parent_key[ $index ] ] ) ); // input var okay.
322 } else {
323 wp_die( '<p style="clear: both; padding: 10px;">' . esc_attr__( 'ERROR: No value for parent key found', 'wp-data-access' ) . '</p>' );
324 }
325 // phpcs:enable WordPress.Security.NonceVerification.Recommended
326 }
327 }
328
329 if ( isset( $data_type[ $index ] ) && 'number' === strtolower( $data_type[ $index ] ) ) {
330 $where .= $wpdadb->prepare(
331 " $and `$key` = %f ",
332 $parent_key_value
333 );
334 } else {
335 $where .= $wpdadb->prepare(
336 " $and `$key` = %s ",
337 $parent_key_value
338 );
339 }
340
341 $index++;
342 }
343
344 $this->where = " where ($where) ";
345 }
346
347 // Add default where
348 $this->where .= $default_where;
349
350 parent::construct_where_clause();
351 }
352
353 protected function get_order_by() {
354 $orderby = parent::get_order_by();
355 if ( '' !== $orderby ) {
356 return $orderby;
357 }
358
359 if (
360 isset( $this->child['default_orderby'] ) &&
361 null !== $this->child['default_orderby'] &&
362 '' !== trim( $this->child['default_orderby'] )
363 ) {
364 $default_orderby = " order by {$this->child['default_orderby']} ";
365 } else {
366 $default_orderby = '';
367 }
368
369 // Add default order by
370 return $default_orderby;
371 }
372
373 /**
374 * Overwrites method column_default_add_action
375 *
376 * Adds parent arguments
377 *
378 * @param array $item
379 * @param string $column_name
380 * @param array $actions
381 */
382 protected function column_default_add_action( $item, $column_name, &$actions ) {
383 $form_id = '_' . ( self::$list_number - 1 );
384 if ( isset( $this->child['relation_nm'] ) ) {
385 $link_label = __( 'Delete Relationship', 'wp-data-access' );
386 $link_title = __( 'Delete child row (this only affects the relationship table)', 'wp-data-access' );
387 } else {
388 $link_label = __( 'Delete', 'wp-data-access' );
389 $link_title = __( 'Delete child row', 'wp-data-access' );
390 }
391 $warning = __( "You are about to permanently delete these items from your site.\\nThis action cannot be undone.\\n\\'Cancel\\' to stop, \\'OK\\' to delete.", 'wp-data-access' );
392 $actions['delete'] = sprintf(
393 '<a href="javascript:void(0)"
394 class="delete wpda_tooltip"
395 title="%s"
396 onclick="if (confirm(\'%s\')) jQuery(\'#%s\').submit()">
397 <span style="white-space:nowrap">
398 <i class="fas fa-trash wpda_icon_on_button"></i>
399 %s
400 </span>
401 </a>
402 ',
403 $link_title,
404 $warning,
405 "delete_form$form_id",
406 $link_label
407 );
408 }
409
410 /**
411 * Overwrites method get_bulk_actions
412 *
413 * Adds 'Delete Relationship' action for n:m relationships and 'Delete' action for 1:n relationships to bulk
414 * listbox.
415 *
416 * @return array|string
417 */
418 public function get_bulk_actions() {
419 if ( ! $this->bulk_actions_enabled ) {
420 // Bulk actions disabled.
421 return '';
422 }
423
424 if ( empty( $this->wpda_list_columns->get_table_primary_key() ) ) {
425 // Tables has no primary key: no bulk actions allowed!
426 // Primary key is necessary to ensure uniqueness.
427 return '';
428 }
429
430 $actions = parent::get_bulk_actions();
431
432 if ( isset( $this->child['relation_nm'] ) ) {
433 $actions['bulk-delete'] = __( 'Delete Relationship', 'wp-data-access' );
434 } else {
435 $actions['bulk-delete'] = __( 'Delete', 'wp-data-access' );
436 }
437
438 return $actions;
439 }
440
441 /**
442 * Overwrite method delete_row
443 *
444 * Adds parent arguments
445 *
446 * @param string $where where clause
447 * @param string $engine connect or empty
448 *
449 * @return mixed
450 */
451 public function delete_row( $where, $engine = '' ) {
452 // Expand named array with parent key for delete operation.
453 $next_row_to_be_deleted = array();
454 $i = 0;
455 foreach ( $where as $key => $value ) {
456 if ( isset( $this->child['relation_nm'] ) ) {
457 $next_row_to_be_deleted[ $this->child['relation_nm']['child_table_select'][ $i ] ] = $value;
458 $next_row_to_be_deleted[ $this->child['relation_nm']['child_table_where'][ $i ] ] =
459 $this->parent['parent_key_value'][ $this->parent['parent_key'][ $i ] ];
460 } else {
461 $next_row_to_be_deleted[ $key ] = $value;
462 }
463 $i ++;
464 }
465
466 if ( isset( $this->child['relation_nm'] ) ) {
467 $table_name = $this->child['relation_nm']['child_table'];
468 } else {
469 $table_name = $this->table_name;
470 }
471
472 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
473 if ( null === $wpdadb ) {
474 if ( is_admin() ) {
475 /* translators: %s = database name */
476 wp_die( sprintf( esc_attr__( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
477 } else {
478 /* translators: %s = database name */
479 die( sprintf( esc_attr__( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
480 }
481 }
482
483 $row_deleted = $wpdadb->delete( $table_name, $next_row_to_be_deleted ); // db call ok; no-cache ok.
484
485 if ( 'connect' === strtolower( $engine ) ) {
486 // Connect engine does not return number of rows deleted
487 // Presuming delete was successful when no error message was returned
488 return '' === $wpdadb->last_error;
489 }
490 return $row_deleted;
491 }
492
493 }
494
495 }
496