PluginProbe ʕ •ᴥ•ʔ
WP All Export – Drag & Drop Export to Any Custom CSV, XML & Excel / trunk
WP All Export – Drag & Drop Export to Any Custom CSV, XML & Excel vtrunk
trunk 0.9.0 0.9.1 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0 1.2.1 1.2.10 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 1.4.13 1.4.14 1.4.15 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0
wp-all-export / models / model.php
wp-all-export / models Last commit date
export 3 weeks ago model 3 weeks ago post 10 years ago template 10 years ago model.php 3 weeks ago
model.php
202 lines
1 <?php
2 /**
3 * Base class for models
4 *
5 * @author Pavel Kulbakin <p.kulbakin@gmail.com>
6 */
7 abstract class PMXE_Model extends ArrayObject {
8 /**
9 * WPDB instance
10 * @var wpdb
11 */
12 protected $wpdb;
13 /**
14 * Table name the model is linked to
15 * @var string
16 */
17 protected $table;
18 /**
19 * Array of columns representing primary key
20 * @var array
21 */
22 protected $primary = array('id');
23 /**
24 * Wether key field is auto_increment (sure make scence only if key s
25 * @var bool
26 */
27 protected $auto_increment = FALSE;
28
29 /**
30 * Cached data retrieved from database
31 * @var array
32 */
33 private static $meta_cache = array();
34
35 /**
36 * Initialize model
37 * @param array[optional] $data Array of record data to initialize object with
38 */
39 public function __construct() {
40 $this->wpdb = $GLOBALS['wpdb'];
41 }
42
43 /**
44 * Read records from database by specified fields and values
45 * When 1st parameter is an array, it expected to be an associative array of field => value pairs to read data by
46 * If 2 parameters are set, first one is expected to be a field name and second - it's value
47 *
48 * @param string|array $field
49 * @param mixed[optional] $value
50 * @return PMXE_Model
51 */
52 abstract public function getBy($field = NULL, $value = NULL);
53
54 /**
55 * Magic function to automatically resolve calls like $obj->getBy%FIELD_NAME%
56 * @param string $method
57 * @param array $args
58 * @return PMXE_Model
59 */
60 public function __call($method, $args) {
61 if (preg_match('%^get_?by_?(.+)%i', $method, $mtch)) {
62 array_unshift($args, $mtch[1]);
63 return call_user_func_array(array($this, 'getBy'), $args);
64 } else {
65 throw new Exception( esc_html( "Requested method " . get_class($this) . "::$method doesn't exist." ) );
66 }
67 }
68
69 /**
70 * Bind model to database table
71 * @param string $tableName
72 * @return PMXE_Model
73 */
74 public function setTable($tableName) {
75 if ( ! is_null($this->table)) {
76 throw new Exception('Table name cannot be changed once being set.');
77 }
78 $this->table = $tableName;
79 if ( ! isset(self::$meta_cache[$this->table])) {
80 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- table name set internally via setTable() with values derived from $wpdb->prefix; not user input
81 $tableMeta = $this->wpdb->get_results("SHOW COLUMNS FROM $this->table", ARRAY_A);
82 $primary = array();
83 $auto_increment = false;
84 foreach ($tableMeta as $colMeta) {
85 if ('PRI' == $colMeta['Key']) {
86 $primary[] = $colMeta['Field'];
87 }
88 if ('auto_increment' == $colMeta['Extra']) {
89 $auto_increment = true;
90 break; // no point to iterate futher since auto_increment means corresponding primary key is simple
91 }
92 }
93 self::$meta_cache[$this->table] = array('primary' => $primary, 'auto_increment' => $auto_increment);
94 }
95 $this->primary = self::$meta_cache[$this->table]['primary'];
96 $this->auto_increment = self::$meta_cache[$this->table]['auto_increment'];
97
98 return $this;
99 }
100
101 /**
102 * Return database table name this object is bound to
103 * @return string
104 */
105 public function getTable() {
106 return $this->table;
107 }
108 /**
109 * Return column name with table name
110 * @param string $col
111 * @return string
112 */
113 public function getFieldName($col) {
114 return $this->table . '.' . $col;
115 }
116
117 /**
118 * Compose WHERE clause based on parameters provided
119 * @param string|array $field
120 * @param mixed[optional] $value
121 * @param string[optional] $operator AND or OR string, 'AND' by default
122 * @return string
123 */
124 protected function buildWhere($field, $value = NULL, $operator = NULL) {
125 if ( ! is_array($field)) {
126 $field = array($field => $value);
127 } else { // shift arguments
128 $operator = $value;
129 }
130 ! is_null($operator) or $operator = 'AND'; // apply default operator value
131
132 $where = array();
133 foreach ($field as $key => $val) {
134 if (is_int($key)) {
135 $where[] = '(' . call_user_func_array(array($this, 'buildWhere'), $val) . ')';
136 } else {
137 if ( ! preg_match('%^(.+?) *(=|<>|!=|<|>|<=|>=| (NOT +)?(IN|(LIKE|REGEXP|RLIKE)( BINARY)?))?$%i', trim($key), $mtch)) {
138 throw new Exception('Wrong field name format.');
139 }
140 $key = $mtch[1];
141 if (is_array($val) and (empty($mtch[2]) or 'IN' == strtoupper($mtch[4]))) {
142 $op = empty($mtch[2]) ? 'IN' : strtoupper(trim($mtch[2]));
143 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $key validated by regex above; $op limited to whitelist (=, <>, !=, <, >, <=, >=, IN, LIKE, REGEXP, RLIKE, NOT IN, etc.); values bound via prepare()
144 if (count($val)) $where[] = $this->wpdb->prepare("$key $op (" . implode(', ', array_fill(0, count($val), "%s")) . ")", $val);
145 } else {
146 $op = empty($mtch[2]) ? '=' : strtoupper(trim($mtch[2]));
147 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $key validated by regex above; $op limited to whitelist; value bound via prepare()
148 $where[] = $this->wpdb->prepare("$key $op %s", $val);
149 }
150 }
151 }
152 return implode(" $operator ", $where);
153 }
154
155
156 /**
157 * Return associative array with record data
158 * @param bool[optional] $serialize Whether returned fields should be serialized
159 * @return array
160 */
161 public function toArray($serialize = FALSE) {
162 $result = (array)$this;
163 if ($serialize) {
164 foreach ($result as $k => $v) {
165 if ( ! is_scalar($v)) {
166 $result[$k] = serialize($v);
167 }
168 }
169 }
170 return $result;
171 }
172
173 /**
174 * Check whether object data is empty
175 * @return bool
176 */
177 public function isEmpty() {
178 return $this->count() == 0;
179 }
180
181 /**
182 * Empty object data
183 * @return PMXE_Model
184 */
185 public function clear() {
186 $this->exchangeArray(array());
187 return $this;
188 }
189
190 /**
191 * Delete all content from model's table
192 * @return PMXE_Model
193 */
194 public function truncateTable() {
195 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- table name set internally via setTable() with values derived from $wpdb->prefix; not user input
196 if (FALSE !== $this->wpdb->query("TRUNCATE $this->table")) {
197 return $this;
198 } else {
199 throw new Exception( esc_html( $this->wpdb->last_error ) );
200 }
201 }
202 }