Subversion Repositories PHPX

Rev

Rev 58 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 58 Rev 61
1
<?php
1
<?php
2
2
3
namespace PointedEars\PHPX\Db;
3
namespace PointedEars\PHPX\Db;
4
4
5
use \PointedEars\PHPX\Application;
5
use \PointedEars\PHPX\Application;
6
6
7
/**
7
/**
8
 * Generic database table model class
8
 * Generic database table model class
9
 *
9
 *
10
 * @author Thomas Lahn
10
 * @author Thomas Lahn
11
 * @property Database $database
11
 * @property Database $database
12
 * @property-read int $lastInsertId
12
 * @property-read int $lastInsertId
13
 *   ID of the last inserted row, or the last value from
13
 *   ID of the last inserted row, or the last value from
14
     a sequence object, depending on the underlying driver.
14
     a sequence object, depending on the underlying driver.
15
 */
15
 */
16
class Table extends \PointedEars\PHPX\AbstractModel
16
class Table extends \PointedEars\PHPX\AbstractModel
17
{
17
{
18
  /**
18
  /**
19
   * Name of the table
19
   * Name of the table
20
   * @var string
20
   * @var string
21
   */
21
   */
22
  protected static $_name = '';
22
  protected static $_name = '';
23
23
24
  /**
24
  /**
25
   * Columns definition
25
   * Columns definition
26
   * @var array
26
   * @var array
27
         * @see Table::create()
27
         * @see Table::create()
28
   */
28
   */
29
  protected static $_columns;
29
  protected static $_columns;
30
30
31
  /**
31
  /**
32
   * Indexes definition
32
   * Indexes definition
33
   * @var array
33
   * @var array
34
         * @see Table::create()
34
         * @see Table::create()
35
   */
35
   */
36
  protected static $_indexes;
36
  protected static $_indexes;
37
37
38
  /**
38
  /**
39
   * Constraints definition
39
   * Constraints definition
40
   * @var array
40
   * @var array
41
         * @see Table::create()
41
         * @see Table::create()
42
   */
42
   */
43
  protected static $_constraints;
43
  protected static $_constraints;
44
44
45
  /**
45
  /**
46
   * Database of the table
46
   * Database of the table
47
   * @var Database|string
47
   * @var Database|string
48
         * @see Table::create()
48
         * @see Table::create()
49
   */
49
   */
50
  protected static $_database;
50
  protected static $_database;
51
51
52
  /**
52
  /**
53
   * Name of the primary key column of the table
53
   * Name of the primary key column of the table
54
   * @var string
54
   * @var string
55
   */
55
   */
56
  protected static $_id = 'id';
56
  protected static $_id = 'id';
57
57
58
  /**
58
  /**
59
   * Creates a new <code>Table</code> instance.
59
   * Creates a new <code>Table</code> instance.
60
   *
60
   *
61
   * Each of the parameters is optional and can also be given
61
   * Each of the parameters is optional and can also be given
62
   * by a protected property where the parameter name is preceded
62
   * by a protected property where the parameter name is preceded
63
   * by <code>_</code>.  Parameter values overwrite the default
63
   * by <code>_</code>.  Parameter values overwrite the default
64
   * property values.  It is recommended to use default property
64
   * property values.  It is recommended to use default property
65
   * values of inheriting classes except for small applications
65
   * values of inheriting classes except for small applications
66
   * and testing purposes.
66
   * and testing purposes.
67
   *
67
   *
68
   * @param Database $database
68
   * @param Database $database
69
   *   Database of the table (required in order to use a fitting
69
   *   Database of the table (required in order to use a fitting
70
   *   query language)
70
   *   query language)
71
   * @param string $name
71
   * @param string $name
72
   *   Table name
72
   *   Table name
73
   * @param string $id
73
   * @param string $id
74
   *   Name of the primary key column
74
   *   Name of the primary key column
75
   * @throws InvalidArgumentException
75
   * @throws InvalidArgumentException
76
   */
76
   */
77
  public function __construct ($database = null, $name = '', $id = '')
77
  public function __construct ($database = null, $name = '', $id = '')
78
  {
78
  {
79
    if ($database === null)
79
    if ($database === null)
80
    {
80
    {
81
                /* Call getter to convert to Database if possible */
81
                /* Call getter to convert to Database if possible */
82
        if ($this->database === null)
82
        if ($this->database === null)
83
        {
83
        {
84
                $this->database = Application::getInstance()->getDefaultDatabase();
84
                $this->database = Application::getInstance()->getDefaultDatabase();
85
        }
85
        }
86
    }
86
    }
87
    else
87
    else
88
    {
88
    {
89
      $this->database = $database;
89
      $this->database = $database;
90
    }
90
    }
91
91
92
    if ($name !== '')
92
    if ($name !== '')
93
    {
93
    {
94
      $this->name = $name;
94
      $this->name = $name;
95
    }
95
    }
96
96
97
    $name = $this->name;
97
    $name = $this->name;
98
    if (!\is_string($name))
98
    if (!\is_string($name))
99
    {
99
    {
100
      throw new \InvalidArgumentException(
100
      throw new \InvalidArgumentException(
101
        'Expected string for table name, saw '
101
        'Expected string for table name, saw '
102
                                . (\is_object($name) ? \get_class($name) : \gettype($name)));
102
                                . (\is_object($name) ? \get_class($name) : \gettype($name)));
103
    }
103
    }
104
104
105
    if ($id !== '')
105
    if ($id !== '')
106
    {
106
    {
107
      $this->id = $id;
107
      $this->id = $id;
108
    }
108
    }
109
  }
109
  }
110
110
111
  /**
111
  /**
112
   * @param string $value
112
   * @param string $value
113
   */
113
   */
114
  public function setName ($value)
114
  public function setName ($value)
115
  {
115
  {
116
        $class = \get_class($this);
116
        $class = \get_class($this);
117
        $class::$_name = (string) $value;
117
        $class::$_name = (string) $value;
118
  }
118
  }
119
119
120
  /**
120
  /**
121
   * @return string
121
   * @return string
122
   */
122
   */
123
  public function getName ()
123
  public function getName ()
124
  {
124
  {
125
        $class = \get_class($this);
125
        $class = \get_class($this);
126
        return $class::$_name;
126
        return $class::$_name;
127
  }
127
  }
128
128
129
  /**
129
  /**
130
   * Returns the database for the table
130
   * Returns the database for the table
131
   * @return Database
131
   * @return Database
132
   */
132
   */
133
  public function getDatabase()
133
  public function getDatabase()
134
  {
134
  {
135
        $class = \get_class($this);
135
        $class = \get_class($this);
136
    if (\is_string($class::$_database))
136
    if (\is_string($class::$_database))
137
    {
137
    {
138
      /* Call setter to convert to Database */
138
      /* Call setter to convert to Database */
139
      $this->setDatabase($class::$_database);
139
      $this->setDatabase($class::$_database);
140
    }
140
    }
141
141
142
    return $class::$_database;
142
    return $class::$_database;
143
  }
143
  }
144
144
145
  /**
145
  /**
146
   * @param Database|string $value
146
   * @param Database|string $value
147
   * @throws InvalidArgumentException
147
   * @throws InvalidArgumentException
148
   */
148
   */
149
  public function setDatabase ($value)
149
  public function setDatabase ($value)
150
  {
150
  {
151
        $class = \get_class($this);
151
        $class = \get_class($this);
152
        if ($value instanceof Database)
152
        if ($value instanceof Database)
153
        {
153
        {
154
                $class::$_database = $value;
154
                $class::$_database = $value;
155
        }
155
        }
156
        else if ($value !== null)
156
        else if ($value !== null)
157
        {
157
        {
158
                $database = new $value();
158
                $database = new $value();
159
                if (!($database instanceof Database))
159
                if (!($database instanceof Database))
160
                {
160
                {
161
                        throw new \InvalidArgumentException(
161
                        throw new \InvalidArgumentException(
162
                                'Expected Database instance or string for class name, saw '
162
                                'Expected Database instance or string for class name, saw '
163
                                        . (\is_object($value) ? \get_class($value) : \gettype($value))
163
                                        . (\is_object($value) ? \get_class($value) : \gettype($value))
164
                        );
164
                        );
165
                }
165
                }
166
166
167
                $class::$_database = $database;
167
                $class::$_database = $database;
168
        }
168
        }
169
  }
169
  }
170
170
171
  /**
171
  /**
172
   * @param string $value
172
   * @param string $value
173
   */
173
   */
174
  public function setId ($value)
174
  public function setId ($value)
175
  {
175
  {
176
        $class = \get_class($this);
176
        $class = \get_class($this);
177
        $class::$_id = (string) $value;
177
        $class::$_id = (string) $value;
178
  }
178
  }
179
179
180
  /**
180
  /**
181
   * @return string
181
   * @return string
182
   */
182
   */
183
  public function getId ()
183
  public function getId ()
184
  {
184
  {
185
        $class = \get_class($this);
185
        $class = \get_class($this);
186
        return $class::$_id;
186
        return $class::$_id;
187
  }
187
  }
188
188
189
  /**
189
  /**
190
   * Returns the <var>options</var> array for {@link Database::createTable}
190
   * Returns the <var>options</var> array for {@link Database::createTable}
191
   *
191
   *
192
   * Should be called and overridden by inheriting classes.
192
   * Should be called and overridden by inheriting classes.
193
   *
193
   *
194
   * @return array
194
   * @return array
195
   */
195
   */
196
  protected function _createOptions ()
196
  protected function _createOptions ()
197
  {
197
  {
198
        $options = array();
198
        $options = array();
199
199
200
        foreach (array('indexes', 'constraints') as $option)
200
        foreach (array('indexes', 'constraints') as $option)
201
        {
201
        {
202
                if ($class::${"_$option"})
202
                if ($class::${"_$option"})
203
                {
203
                {
204
                        $options[$option] = $class::${"_$option"};
204
                        $options[$option] = $class::${"_$option"};
205
                }
205
                }
206
        }
206
        }
207
207
208
        return $options;
208
        return $options;
209
  }
209
  }
210
210
211
  /**
211
  /**
212
   * Creates the table for this model
212
   * Creates the table for this model
213
   *
213
   *
214
   * @return bool
214
   * @return bool
215
   */
215
   */
216
  public function create ()
216
  public function create ()
217
  {
217
  {
218
        $class = \get_class($this);
218
        $class = \get_class($this);
219
                return $this->database->createTable(
219
                return $this->database->createTable(
220
                        $class::$_name, $class::$_columns, $this->_createOptions());
220
                        $class::$_name, $class::$_columns, $this->_createOptions());
221
  }
221
  }
222
222
223
  /**
223
  /**
224
   * Initiates a transaction
224
   * Initiates a transaction
225
   *
225
   *
226
   * @return bool
226
   * @return bool
227
   * @see Database::beginTransaction()
227
   * @see Database::beginTransaction()
228
   */
228
   */
229
  public function beginTransaction()
229
  public function beginTransaction()
230
  {
230
  {
231
    return $this->database->beginTransaction();
231
    return $this->database->beginTransaction();
232
  }
232
  }
233
233
234
  /**
234
  /**
235
   * Rolls back a transaction
235
   * Rolls back a transaction
236
   *
236
   *
237
   * @return bool
237
   * @return bool
238
   * @see Database::rollBack()
238
   * @see Database::rollBack()
239
   */
239
   */
240
  public function rollBack()
240
  public function rollBack()
241
  {
241
  {
242
    return $this->database->rollBack();
242
    return $this->database->rollBack();
243
  }
243
  }
244
244
245
  /**
245
  /**
246
   * Commits a transaction
246
   * Commits a transaction
247
   *
247
   *
248
   * @return bool
248
   * @return bool
249
   * @see Database::commit()
249
   * @see Database::commit()
250
   */
250
   */
251
  public function commit()
251
  public function commit()
252
  {
252
  {
253
    return $this->database->commit();
253
    return $this->database->commit();
254
  }
254
  }
255
255
256
  /**
256
  /**
257
   * Retrieves all rows from the table
257
   * Retrieves all rows from the table
258
   *
258
   *
259
   * @return array
259
   * @return array
260
   * @see Database::fetchAll()
260
   * @see Database::fetchAll()
261
   */
261
   */
262
  public function fetchAll($fetch_style = null, $column_index = null, array $ctor_args = null)
262
  public function fetchAll($fetch_style = null, $column_index = null, array $ctor_args = null)
263
  {
263
  {
264
    return $this->database->fetchAll($this->name, $fetch_style, $column_index, $ctor_args);
264
    return $this->database->fetchAll($this->name, $fetch_style, $column_index, $ctor_args);
265
  }
265
  }
266
266
267
  /**
267
  /**
268
   * Selects data from one or more tables
268
   * Selects data from one or more tables
269
   *
269
   *
270
   * @return array
270
   * @return array
271
   * @see Database::select()
271
   * @see Database::select()
272
   */
272
   */
273
  public function select($columns = null, $where = null, $order = null, $limit = null)
273
  public function select($columns = null, $where = null, $order = null, $limit = null)
274
  {
274
  {
275
    return $this->database->select($this->name, $columns, $where, $order, $limit);
275
    return $this->database->select($this->name, $columns, $where, $order, $limit);
276
  }
276
  }
277
277
278
  /**
278
  /**
279
   * Updates records in one or more tables
279
   * Updates records in one or more tables
280
   *
280
   *
281
   * @return bool
281
   * @return bool
282
   * @see Database::update()
282
   * @see Database::update()
283
   */
283
   */
284
  public function update($data, $condition)
284
  public function update($data, $condition)
285
  {
285
  {
286
    return $this->database->update($this->name, $data, $condition);
286
    return $this->database->update($this->name, $data, $condition);
287
  }
287
  }
288
288
289
  /**
289
  /**
290
   * Inserts a record into the table
290
   * Inserts a record into the table
291
   *
291
   *
292
   * @return bool
292
   * @return bool
293
   * @see Database::insert()
293
   * @see Database::insert()
294
   */
294
   */
295
  public function insert($data, $cols = null)
295
  public function insert($data, $cols = null)
296
  {
296
  {
297
    return $this->database->insert($this->name, $data, $cols);
297
    return $this->database->insert($this->name, $data, $cols);
298
  }
298
  }
299
299
300
  /**
300
  /**
301
   * Returns the ID of the last inserted row, or the last value from
301
   * Returns the ID of the last inserted row, or the last value from
302
   * a sequence object, depending on the underlying driver.
302
   * a sequence object, depending on the underlying driver.
303
   *
303
   *
304
   * @return int
304
   * @return int
305
   * @see Database::getLastInsertId()
305
   * @see Database::getLastInsertId()
306
   */
306
   */
307
  public function getLastInsertId()
307
  public function getLastInsertId()
308
  {
308
  {
309
    return $this->database->lastInsertId;
309
    return $this->database->lastInsertId;
310
  }
310
  }
311
311
312
  /**
312
  /**
313
   * Delete a record from the table
313
   * Delete a record from the table
314
   *
314
   *
315
   * @param int $id
315
   * @param int $id
316
   *   ID of the record to delete.  May be <code>null</code>,
316
   *   ID of the record to delete.  May be <code>null</code>,
317
   *   in which case <var>$condition</var> must specify
317
   *   in which case <var>$condition</var> must specify
318
   *   the records to be deleted.
318
   *   the records to be deleted.
319
   * @param array[optional] $condition
319
   * @param array[optional] $condition
320
   *   Conditions that must be met for a record to be deleted.
320
   *   Conditions that must be met for a record to be deleted.
321
   *   Ignored if <var>$id</var> is not <code>null</code>.
321
   *   Ignored if <var>$id</var> is not <code>null</code>.
322
   * @return bool
322
   * @return bool
323
   * @throws InvalidArgumentException if both <var>$id</var> and
323
   * @throws InvalidArgumentException if both <var>$id</var> and
324
   *     <var>$condition</var> are <code>null</code>.
324
   *     <var>$condition</var> are <code>null</code>.
325
   * @see Database::delete()
325
   * @see Database::delete()
326
   */
326
   */
327
  public function delete ($id, array $condition = null)
327
  public function delete ($id, array $condition = null)
328
  {
328
  {
329
    if ($id !== null)
329
    if ($id !== null)
330
    {
330
    {
331
      $condition = array($this->id => $id);
331
      $condition = array($this->id => $id);
332
    }
332
    }
333
    else if ($condition === null)
333
    else if ($condition === null)
334
    {
334
    {
335
      throw new InvalidArgumentException(
335
      throw new InvalidArgumentException(
336
        '$id and $condition cannot both be null');
336
        '$id and $condition cannot both be null');
337
    }
337
    }
338
338
339
    return $this->database->delete($this->name, $condition);
339
    return $this->database->delete($this->name, $condition);
340
  }
340
  }
341
341
342
 /**
342
 /**
343
  * Inserts a row into the table or updates an existing one
343
  * Inserts a row into the table or updates an existing one
344
  *
344
  *
345
  * @param array $data
345
  * @param array $data
346
  *   Associative array of column-value pairs to be updated/inserted
346
  *   Associative array of column-value pairs to be updated/inserted
347
  * @param string|array $condition
347
  * @param string|array $condition
348
  *   If there are no records matching this condition, a row will be inserted;
348
  *   If there are no records matching this condition, a row
349
  *   otherwise matching records are updated
349
  *   will be inserted; otherwise matching records are updated.
350
  * @return bool
350
  * @return bool
-
 
351
  *   The return value of Table::update() or Table::insert()
351
  * @see Table::update()
352
  * @see Table::update()
352
  * @see Table::insert()
353
  * @see Table::insert()
353
  */
354
  */
354
  public function updateOrInsert($data, array $condition = null)
355
  public function updateOrInsert($data, array $condition = null)
355
  {
356
  {
356
    if ($this->select($this->id, $condition))
357
    if ($this->select($this->id, $condition))
357
    {
358
    {
358
      return $this->update($data, $condition);
359
      return $this->update($data, $condition);
359
    }
360
    }
360
361
361
        return $this->insert($data);
362
        return $this->insert($data);
362
  }
363
  }
363
364
364
  /**
365
  /**
365
   * Finds a record by ID
366
   * Finds a record by ID
366
   *
367
   *
367
   * @param mixed $id
368
   * @param mixed $id
368
   * @return array
369
   * @return array
369
   */
370
   */
370
  public function find ($id)
371
  public function find ($id)
371
  {
372
  {
372
    /* DEBUG */
373
    /* DEBUG */
373
    if (defined('DEBUG') && DEBUG > 0)
374
    if (defined('DEBUG') && DEBUG > 0)
374
    {
375
    {
375
      debug($id);
376
      debug($id);
376
    }
377
    }
377
378
378
    $result = $this->select(null, array($this->id => $id));
379
    $result = $this->select(null, array($this->id => $id));
379
380
380
    if ($result)
381
    if ($result)
381
    {
382
    {
382
      $result = $result[0];
383
      $result = $result[0];
383
    }
384
    }
384
385
385
    return $result;
386
    return $result;
386
  }
387
  }
387
}
388
}