1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* This file contains only a single class. |
4
|
|
|
* |
5
|
|
|
* @file |
6
|
|
|
* @package Tabulate |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace WordPress\Tabulate\DB; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* A record is a single row from a database table. |
13
|
|
|
*/ |
14
|
|
|
class Record { |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* The table that this record belongs to. |
18
|
|
|
* |
19
|
|
|
* @var Table |
20
|
|
|
*/ |
21
|
|
|
protected $table; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* The raw data of this database row. |
25
|
|
|
* |
26
|
|
|
* @var \stdClass |
27
|
|
|
*/ |
28
|
|
|
protected $data; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* The suffix that is added to foreign keys when we want to get their |
32
|
|
|
* 'title' value instead of their raw integer (or whatever) form. |
33
|
|
|
*/ |
34
|
|
|
const FKTITLE = 'FKTITLE'; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Create a new Record object. |
38
|
|
|
* |
39
|
|
|
* @param Table $table The table object. |
40
|
|
|
* @param array $data The data of this record. |
41
|
|
|
*/ |
42
|
|
|
public function __construct( $table, $data = array() ) { |
43
|
|
|
$this->table = $table; |
44
|
|
|
$this->data = (object) $data; |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Magic method to set one item in the data object. |
49
|
|
|
* |
50
|
|
|
* @param string $name The name of the column. |
51
|
|
|
* @param mixed $value The value to set. |
52
|
|
|
*/ |
53
|
|
|
public function __set( $name, $value ) { |
54
|
|
|
$this->data->{$name} = $value; |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Set multiple columns' values. |
59
|
|
|
* |
60
|
|
|
* @param mixed[] $data An array of column names to data values. |
61
|
|
|
*/ |
62
|
|
|
public function set_multiple( $data ) { |
63
|
|
|
if ( ! is_array( $data ) ) { |
64
|
|
|
return; |
65
|
|
|
} |
66
|
|
|
foreach ( $data as $col => $datum ) { |
67
|
|
|
$this->$col = $datum; |
68
|
|
|
} |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Get a column's value. If suffixed with 'FKTITLE', then get the title of |
73
|
|
|
* the foreign record (where applicable). |
74
|
|
|
* |
75
|
|
|
* @param string $name The column name. |
76
|
|
|
* @param mixed [] $args Parameter not used. |
77
|
|
|
* @return string|boolean |
78
|
|
|
* @throws Exception If any arguments are passed (as there should never be any). |
79
|
|
|
*/ |
80
|
|
|
public function __call( $name, $args ) { |
81
|
|
|
if ( ! empty( $args ) ) { |
82
|
|
|
throw new Exception( 'Record::colname() functions take no arguments.' ); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
// Foreign key 'title' values. |
86
|
|
|
$use_title = substr( $name, -strlen( self::FKTITLE ) ) === self::FKTITLE; |
87
|
|
|
if ( $use_title ) { |
88
|
|
|
$name = substr( $name, 0, -strlen( self::FKTITLE ) ); |
89
|
|
|
$col = $this->get_col( $name ); |
90
|
|
|
if ( $col->is_foreign_key() && ! empty( $this->data->$name ) ) { |
91
|
|
|
$referenced_table = $col->get_referenced_table(); |
92
|
|
|
$fk_record = $referenced_table->get_record( $this->data->$name ); |
93
|
|
|
$fk_title_col = $referenced_table->get_title_column(); |
94
|
|
|
$fk_title_col_name = $fk_title_col->get_name(); |
95
|
|
|
if ( $fk_title_col->is_foreign_key() ) { |
96
|
|
|
// Use title if the FK's title column is also an FK. |
97
|
|
|
$fk_title_col_name .= self::FKTITLE; |
98
|
|
|
} |
99
|
|
|
return $fk_record->$fk_title_col_name(); |
100
|
|
|
} |
101
|
|
|
} |
102
|
|
|
$col = $this->get_col( $name ); |
103
|
|
|
|
104
|
|
|
// Booleans. |
105
|
|
|
if ( $col->is_boolean() ) { |
106
|
|
|
// Numbers are fetched from the DB as strings. |
107
|
|
|
if ( '1' === $this->data->$name ) { |
108
|
|
|
return true; |
109
|
|
|
} elseif ( '0' === $this->data->$name ) { |
110
|
|
|
return false; |
111
|
|
|
} else { |
112
|
|
|
return null; |
113
|
|
|
} |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
// Standard column values. |
117
|
|
|
if ( isset( $this->data->$name ) ) { |
118
|
|
|
return $this->data->$name; |
119
|
|
|
} |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Get a column of this record's table, optionally throwing an Exception if |
124
|
|
|
* it doesn't exist. |
125
|
|
|
* |
126
|
|
|
* @param string $name The name of the column. |
127
|
|
|
* @param boolean $required True if this should throw an Exception. |
128
|
|
|
* @return \WordPress\Tabulate\DB\Column The column. |
129
|
|
|
* @throws \Exception If the column named doesn't exist. |
130
|
|
|
*/ |
131
|
|
|
protected function get_col( $name, $required = true ) { |
132
|
|
|
$col = $this->table->get_column( $name ); |
|
|
|
|
133
|
|
|
if ( $required && false === $col ) { |
134
|
|
|
throw new \Exception( "Unable to get column $name on table " . $this->table->get_name() ); |
135
|
|
|
} |
136
|
|
|
return $col; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Get a string representation of this record. |
141
|
|
|
* |
142
|
|
|
* @return string |
143
|
|
|
*/ |
144
|
|
|
public function __toString() { |
145
|
|
|
return join( ', ', $this->data ); |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Get the value of this record's primary key, or false if it doesn't have |
150
|
|
|
* one. |
151
|
|
|
* |
152
|
|
|
* @return string|false |
153
|
|
|
*/ |
154
|
|
|
public function get_primary_key() { |
155
|
|
|
if ( $this->table->get_pk_column() ) { |
156
|
|
|
$pk_col_name = $this->table->get_pk_column()->get_name(); |
157
|
|
|
if ( isset( $this->data->$pk_col_name ) ) { |
158
|
|
|
return $this->data->$pk_col_name; |
159
|
|
|
} |
160
|
|
|
} |
161
|
|
|
return false; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* Get the value of this Record's title column. |
166
|
|
|
* |
167
|
|
|
* @return string |
168
|
|
|
*/ |
169
|
|
|
public function get_title() { |
170
|
|
|
$title_col = $this->table->get_title_column(); |
171
|
|
|
if ( $title_col !== $this->table->get_pk_column() ) { |
172
|
|
|
$title_col_name = $title_col->get_name(); |
173
|
|
|
return $this->data->$title_col_name; |
174
|
|
|
} else { |
175
|
|
|
$title_parts = array(); |
176
|
|
|
foreach ( $this->table->get_columns() as $col ) { |
177
|
|
|
$col_name = $col->get_name() . self::FKTITLE; |
178
|
|
|
$title_parts[] = $this->$col_name(); |
179
|
|
|
} |
180
|
|
|
return '[ ' . join( ' | ', $title_parts ) . ' ]'; |
181
|
|
|
} |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* Get the record that is referenced by this one from the column given. |
186
|
|
|
* |
187
|
|
|
* @param string $column_name The name of the column. |
188
|
|
|
* @return boolean|\WordPress\Tabulate\DB\Record |
189
|
|
|
*/ |
190
|
|
|
public function get_referenced_record( $column_name ) { |
191
|
|
|
if ( ! isset( $this->data->$column_name ) ) { |
192
|
|
|
return false; |
193
|
|
|
} |
194
|
|
|
return $this->table |
195
|
|
|
->get_column( $column_name ) |
196
|
|
|
->get_referenced_table() |
197
|
|
|
->get_record( $this->data->$column_name ); |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* Get a list of records that reference this record in one of their columns. |
202
|
|
|
* |
203
|
|
|
* @param string|\WordPress\Tabulate\DB\Table $foreign_table The foreign table. |
204
|
|
|
* @param string|\WordPress\Tabulate\DB\Column $foreign_column The column in the foreign table that references this record's table. |
205
|
|
|
* @param boolean $with_pagination Whether to only return the top N records. |
206
|
|
|
* @return \WordPress\Tabulate\DB\Record[] |
207
|
|
|
*/ |
208
|
|
|
public function get_referencing_records( $foreign_table, $foreign_column, $with_pagination = true ) { |
209
|
|
|
$foreign_table->reset_filters(); |
210
|
|
|
$foreign_table->add_filter( $foreign_column, '=', $this->get_primary_key(), true ); |
211
|
|
|
return $foreign_table->get_records( $with_pagination ); |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Get an Admin Area URL. |
216
|
|
|
* |
217
|
|
|
* @param string $action The action. |
218
|
|
|
* @param boolean $include_ident Whether to include the record Primary Key. |
219
|
|
|
* @param string[] $extra_params Other parameters to append to the URL. |
220
|
|
|
* @return string The URL. |
221
|
|
|
*/ |
222
|
|
|
public function get_url( $action = 'index', $include_ident = true, $extra_params = false ) { |
223
|
|
|
$params = array( |
224
|
|
|
'page' => 'tabulate', |
225
|
|
|
'controller' => 'record', |
226
|
|
|
'action' => $action, |
227
|
|
|
'table' => $this->table->get_name(), |
228
|
|
|
); |
229
|
|
|
if ( $include_ident && false !== $this->get_primary_key() ) { |
230
|
|
|
$params['ident'] = $this->get_primary_key(); |
231
|
|
|
} |
232
|
|
|
if ( is_array( $extra_params ) ) { |
233
|
|
|
$params = array_merge( $params, $extra_params ); |
234
|
|
|
} |
235
|
|
|
return admin_url( 'admin.php?' . http_build_query( $params ) ); |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
/** |
239
|
|
|
* Get most recent changes. |
240
|
|
|
* |
241
|
|
|
* @return string[] |
242
|
|
|
*/ |
243
|
|
|
public function get_changes() { |
244
|
|
|
$wpdb = $this->table->get_database()->get_wpdb(); |
245
|
|
|
$sql = "SELECT cs.id AS changeset_id, c.id AS change_id, date_and_time, " |
246
|
|
|
. "user_nicename, table_name, record_ident, column_name, old_value, " |
247
|
|
|
. "new_value, comment " |
248
|
|
|
. "FROM " . ChangeTracker::changes_name() . " c " |
249
|
|
|
. " JOIN " . ChangeTracker::changesets_name() . " cs ON (c.changeset_id=cs.id) " |
250
|
|
|
. " JOIN {$wpdb->prefix}users u ON (u.ID=cs.user_id) " |
251
|
|
|
. "WHERE table_name = %s AND record_ident = %s" |
252
|
|
|
. "ORDER BY date_and_time DESC, cs.id DESC " |
253
|
|
|
. "LIMIT 15 "; |
254
|
|
|
$params = array( $this->table->get_name(), $this->get_primary_key() ); |
255
|
|
|
return $wpdb->get_results( $wpdb->prepare( $sql, $params ) ); |
256
|
|
|
} |
257
|
|
|
} |
258
|
|
|
|