PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.80
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.80
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 5.5.42 All 160 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.80, at WPDataProjects/Parent_Child/WPDP_Child_List_Table.php

516 lines 15.5 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 $columns = $this->get_sortable_columns();
365 $orderby_columns = explode( ',', $this->child['default_orderby'] );
366
367 $valid = false;
368 for ( $i = 0; $i < count( $orderby_columns ); $i++ ) {
369 foreach( $columns as $column_name => $column ) {
370 if (
371 $column_name === trim("{$orderby_columns[ $i ]}") ||
372 $column_name === trim("{$orderby_columns[ $i ]}asc") ||
373 $column_name === trim("{$orderby_columns[ $i ]}desc") ||
374 $column_name === trim("`{$orderby_columns[ $i ]}`asc") ||
375 $column_name === trim("`{$orderby_columns[ $i ]}`desc")
376 ) {
377 $valid = true;
378 }
379 }
380 }
381
382 $default_orderby = $valid
383 ? " order by {$this->child['default_orderby']} "
384 : '';
385 } else {
386 $default_orderby = '';
387 }
388
389 // Add default order by
390 return $default_orderby;
391 }
392
393 /**
394 * Overwrites method column_default_add_action
395 *
396 * Adds parent arguments
397 *
398 * @param array $item
399 * @param string $column_name
400 * @param array $actions
401 */
402 protected function column_default_add_action( $item, $column_name, &$actions ) {
403 $form_id = '_' . ( self::$list_number - 1 );
404 if ( isset( $this->child['relation_nm'] ) ) {
405 $link_label = __( 'Delete Relationship', 'wp-data-access' );
406 $link_title = __( 'Delete child row (this only affects the relationship table)', 'wp-data-access' );
407 } else {
408 $link_label = __( 'Delete', 'wp-data-access' );
409 $link_title = __( 'Delete child row', 'wp-data-access' );
410 }
411 $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' );
412 $actions['delete'] = sprintf(
413 '<a href="javascript:void(0)"
414 class="delete wpda_tooltip"
415 title="%s"
416 onclick="if (confirm(\'%s\')) jQuery(\'#%s\').submit()">
417 <span style="white-space:nowrap">
418 <i class="fas fa-trash wpda_icon_on_button"></i>
419 %s
420 </span>
421 </a>
422 ',
423 $link_title,
424 $warning,
425 "delete_form$form_id",
426 $link_label
427 );
428 }
429
430 /**
431 * Overwrites method get_bulk_actions
432 *
433 * Adds 'Delete Relationship' action for n:m relationships and 'Delete' action for 1:n relationships to bulk
434 * listbox.
435 *
436 * @return array|string
437 */
438 public function get_bulk_actions() {
439 if ( ! $this->bulk_actions_enabled ) {
440 // Bulk actions disabled.
441 return '';
442 }
443
444 if ( empty( $this->wpda_list_columns->get_table_primary_key() ) ) {
445 // Tables has no primary key: no bulk actions allowed!
446 // Primary key is necessary to ensure uniqueness.
447 return '';
448 }
449
450 $actions = parent::get_bulk_actions();
451
452 if ( isset( $this->child['relation_nm'] ) ) {
453 $actions['bulk-delete'] = __( 'Delete Relationship', 'wp-data-access' );
454 } else {
455 $actions['bulk-delete'] = __( 'Delete', 'wp-data-access' );
456 }
457
458 return $actions;
459 }
460
461 /**
462 * Overwrite method delete_row
463 *
464 * Adds parent arguments
465 *
466 * @param string $where where clause
467 * @param string $engine connect or empty
468 *
469 * @return mixed
470 */
471 public function delete_row( $where, $engine = '' ) {
472 // Expand named array with parent key for delete operation.
473 $next_row_to_be_deleted = array();
474 $i = 0;
475 foreach ( $where as $key => $value ) {
476 if ( isset( $this->child['relation_nm'] ) ) {
477 $next_row_to_be_deleted[ $this->child['relation_nm']['child_table_select'][ $i ] ] = $value;
478 $next_row_to_be_deleted[ $this->child['relation_nm']['child_table_where'][ $i ] ] =
479 $this->parent['parent_key_value'][ $this->parent['parent_key'][ $i ] ];
480 } else {
481 $next_row_to_be_deleted[ $key ] = $value;
482 }
483 $i ++;
484 }
485
486 if ( isset( $this->child['relation_nm'] ) ) {
487 $table_name = $this->child['relation_nm']['child_table'];
488 } else {
489 $table_name = $this->table_name;
490 }
491
492 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
493 if ( null === $wpdadb ) {
494 if ( is_admin() ) {
495 /* translators: %s = database name */
496 wp_die( sprintf( esc_attr__( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
497 } else {
498 /* translators: %s = database name */
499 die( sprintf( esc_attr__( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
500 }
501 }
502
503 $row_deleted = $wpdadb->delete( $table_name, $next_row_to_be_deleted ); // db call ok; no-cache ok.
504
505 if ( 'connect' === strtolower( $engine ) ) {
506 // Connect engine does not return number of rows deleted
507 // Presuming delete was successful when no error message was returned
508 return '' === $wpdadb->last_error;
509 }
510 return $row_deleted;
511 }
512
513 }
514
515 }
516