Subversion Repositories PHPX

Rev

Rev 61 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 61 Rev 74
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
    /* FIXME: What about tables from different databases? */
135
        $class = \get_class($this);
136
        $class = \get_class($this);
136
    if (\is_string($class::$_database))
137
    if (\is_string($class::$_database))
137
    {
138
    {
138
      /* Call setter to convert to Database */
139
      /* Call setter to convert to Database */
139
      $this->setDatabase($class::$_database);
140
      $this->setDatabase($class::$_database);
140
    }
141
    }
141
142
142
    return $class::$_database;
143
    return $class::$_database;
143
  }
144
  }
144
145
145
  /**
146
  /**
146
   * @param Database|string $value
147
   * @param Database|string $value
147
   * @throws InvalidArgumentException
148
   * @throws InvalidArgumentException
148
   */
149
   */
149
  public function setDatabase ($value)
150
  public function setDatabase ($value)
150
  {
151
  {
151
        $class = \get_class($this);
152
        $class = \get_class($this);
152
        if ($value instanceof Database)
153
        if ($value instanceof Database)
153
        {
154
        {
154
                $class::$_database = $value;
155
                $class::$_database = $value;
155
        }
156
        }
156
        else if ($value !== null)
157
        else if ($value !== null)
157
        {
158
        {
158
                $database = new $value();
159
                $database = new $value();
159
                if (!($database instanceof Database))
160
                if (!($database instanceof Database))
160
                {
161
                {
161
                        throw new \InvalidArgumentException(
162
                        throw new \InvalidArgumentException(
162
                                'Expected Database instance or string for class name, saw '
163
                                'Expected Database instance or string for class name, saw '
163
                                        . (\is_object($value) ? \get_class($value) : \gettype($value))
164
                                        . (\is_object($value) ? \get_class($value) : \gettype($value))
164
                        );
165
                        );
165
                }
166
                }
166
167
167
                $class::$_database = $database;
168
                $class::$_database = $database;
168
        }
169
        }
169
  }
170
  }
170
171
171
  /**
172
  /**
172
   * @param string $value
173
   * @param string $value
173
   */
174
   */
174
  public function setId ($value)
175
  public function setId ($value)
175
  {
176
  {
176
        $class = \get_class($this);
177
        $class = \get_class($this);
177
        $class::$_id = (string) $value;
178
        $class::$_id = (string) $value;
178
  }
179
  }
179
180
180
  /**
181
  /**
181
   * @return string
182
   * @return string
182
   */
183
   */
183
  public function getId ()
184
  public function getId ()
184
  {
185
  {
185
        $class = \get_class($this);
186
        $class = \get_class($this);
186
        return $class::$_id;
187
        return $class::$_id;
187
  }
188
  }
188
189
189
  /**
190
  /**
190
   * Returns the <var>options</var> array for {@link Database::createTable}
191
   * Returns the <var>options</var> array for {@link Database::createTable}
191
   *
192
   *
192
   * Should be called and overridden by inheriting classes.
193
   * Should be called and overridden by inheriting classes.
193
   *
194
   *
194
   * @return array
195
   * @return array
195
   */
196
   */
196
  protected function _createOptions ()
197
  protected function _createOptions ()
197
  {
198
  {
198
        $options = array();
199
        $options = array();
199
200
200
        foreach (array('indexes', 'constraints') as $option)
201
        foreach (array('indexes', 'constraints') as $option)
201
        {
202
        {
202
                if ($class::${"_$option"})
203
                if ($class::${"_$option"})
203
                {
204
                {
204
                        $options[$option] = $class::${"_$option"};
205
                        $options[$option] = $class::${"_$option"};
205
                }
206
                }
206
        }
207
        }
207
208
208
        return $options;
209
        return $options;
209
  }
210
  }
210
211
211
  /**
212
  /**
212
   * Creates the table for this model
213
   * Creates the table for this model
213
   *
214
   *
214
   * @return bool
215
   * @return bool
215
   */
216
   */
216
  public function create ()
217
  public function create ()
217
  {
218
  {
218
        $class = \get_class($this);
219
        $class = \get_class($this);
219
                return $this->database->createTable(
220
                return $this->database->createTable(
220
                        $class::$_name, $class::$_columns, $this->_createOptions());
221
                        $class::$_name, $class::$_columns, $this->_createOptions());
221
  }
222
  }
222
223
223
  /**
224
  /**
224
   * Initiates a transaction
225
   * Initiates a transaction
225
   *
226
   *
226
   * @return bool
227
   * @return bool
227
   * @see Database::beginTransaction()
228
   * @see Database::beginTransaction()
228
   */
229
   */
229
  public function beginTransaction()
230
  public function beginTransaction()
230
  {
231
  {
231
    return $this->database->beginTransaction();
232
    return $this->database->beginTransaction();
232
  }
233
  }
233
234
234
  /**
235
  /**
235
   * Rolls back a transaction
236
   * Rolls back a transaction
236
   *
237
   *
237
   * @return bool
238
   * @return bool
238
   * @see Database::rollBack()
239
   * @see Database::rollBack()
239
   */
240
   */
240
  public function rollBack()
241
  public function rollBack()
241
  {
242
  {
242
    return $this->database->rollBack();
243
    return $this->database->rollBack();
243
  }
244
  }
244
245
245
  /**
246
  /**
246
   * Commits a transaction
247
   * Commits a transaction
247
   *
248
   *
248
   * @return bool
249
   * @return bool
249
   * @see Database::commit()
250
   * @see Database::commit()
250
   */
251
   */
251
  public function commit()
252
  public function commit()
252
  {
253
  {
253
    return $this->database->commit();
254
    return $this->database->commit();
254
  }
255
  }
255
256
256
  /**
257
  /**
257
   * Retrieves all rows from the table
258
   * Retrieves all rows from the table
258
   *
259
   *
259
   * @return array
260
   * @return array
260
   * @see Database::fetchAll()
261
   * @see Database::fetchAll()
261
   */
262
   */
262
  public function fetchAll($fetch_style = null, $column_index = null, array $ctor_args = null)
263
  public function fetchAll($fetch_style = null, $column_index = null, array $ctor_args = null)
263
  {
264
  {
264
    return $this->database->fetchAll($this->name, $fetch_style, $column_index, $ctor_args);
265
    return $this->database->fetchAll($this->name, $fetch_style, $column_index, $ctor_args);
265
  }
266
  }
266
267
267
  /**
268
  /**
268
   * Selects data from one or more tables
269
   * Selects data from one or more tables
269
   *
270
   *
270
   * @return array
271
   * @return array
271
   * @see Database::select()
272
   * @see Database::select()
272
   */
273
   */
273
  public function select($columns = null, $where = null, $order = null, $limit = null)
274
  public function select($columns = null, $where = null, $order = null, $limit = null)
274
  {
275
  {
275
    return $this->database->select($this->name, $columns, $where, $order, $limit);
276
    return $this->database->select($this->name, $columns, $where, $order, $limit);
276
  }
277
  }
277
278
278
  /**
279
  /**
279
   * Updates records in one or more tables
280
   * Updates records in one or more tables
280
   *
281
   *
281
   * @return bool
282
   * @return bool
282
   * @see Database::update()
283
   * @see Database::update()
283
   */
284
   */
284
  public function update($data, $condition)
285
  public function update($data, $condition)
285
  {
286
  {
286
    return $this->database->update($this->name, $data, $condition);
287
    return $this->database->update($this->name, $data, $condition);
287
  }
288
  }
288
289
289
  /**
290
  /**
290
   * Inserts a record into the table
291
   * Inserts a record into the table
291
   *
292
   *
292
   * @return bool
293
   * @return bool
293
   * @see Database::insert()
294
   * @see Database::insert()
294
   */
295
   */
295
  public function insert($data, $cols = null)
296
  public function insert($data, $cols = null)
296
  {
297
  {
297
    return $this->database->insert($this->name, $data, $cols);
298
    return $this->database->insert($this->name, $data, $cols);
298
  }
299
  }
299
300
300
  /**
301
  /**
301
   * Returns the ID of the last inserted row, or the last value from
302
   * Returns the ID of the last inserted row, or the last value from
302
   * a sequence object, depending on the underlying driver.
303
   * a sequence object, depending on the underlying driver.
303
   *
304
   *
304
   * @return int
305
   * @return int
305
   * @see Database::getLastInsertId()
306
   * @see Database::getLastInsertId()
306
   */
307
   */
307
  public function getLastInsertId()
308
  public function getLastInsertId()
308
  {
309
  {
309
    return $this->database->lastInsertId;
310
    return $this->database->lastInsertId;
310
  }
311
  }
311
312
312
  /**
313
  /**
313
   * Delete a record from the table
314
   * Delete a record from the table
314
   *
315
   *
315
   * @param int $id
316
   * @param int $id
316
   *   ID of the record to delete.  May be <code>null</code>,
317
   *   ID of the record to delete.  May be <code>null</code>,
317
   *   in which case <var>$condition</var> must specify
318
   *   in which case <var>$condition</var> must specify
318
   *   the records to be deleted.
319
   *   the records to be deleted.
319
   * @param array[optional] $condition
320
   * @param array[optional] $condition
320
   *   Conditions that must be met for a record to be deleted.
321
   *   Conditions that must be met for a record to be deleted.
321
   *   Ignored if <var>$id</var> is not <code>null</code>.
322
   *   Ignored if <var>$id</var> is not <code>null</code>.
322
   * @return bool
323
   * @return bool
323
   * @throws InvalidArgumentException if both <var>$id</var> and
324
   * @throws InvalidArgumentException if both <var>$id</var> and
324
   *     <var>$condition</var> are <code>null</code>.
325
   *     <var>$condition</var> are <code>null</code>.
325
   * @see Database::delete()
326
   * @see Database::delete()
326
   */
327
   */
327
  public function delete ($id, array $condition = null)
328
  public function delete ($id, array $condition = null)
328
  {
329
  {
329
    if ($id !== null)
330
    if ($id !== null)
330
    {
331
    {
331
      $condition = array($this->id => $id);
332
      $condition = array($this->id => $id);
332
    }
333
    }
333
    else if ($condition === null)
334
    else if ($condition === null)
334
    {
335
    {
335
      throw new InvalidArgumentException(
336
      throw new InvalidArgumentException(
336
        '$id and $condition cannot both be null');
337
        '$id and $condition cannot both be null');
337
    }
338
    }
338
339
339
    return $this->database->delete($this->name, $condition);
340
    return $this->database->delete($this->name, $condition);
340
  }
341
  }
341
342
342
 /**
343
 /**
343
  * Inserts a row into the table or updates an existing one
344
  * Inserts a row into the table or updates an existing one
344
  *
345
  *
345
  * @param array $data
346
  * @param array $data
346
  *   Associative array of column-value pairs to be updated/inserted
347
  *   Associative array of column-value pairs to be updated/inserted
347
  * @param string|array $condition
348
  * @param string|array $condition
348
  *   If there are no records matching this condition, a row
349
  *   If there are no records matching this condition, a row
349
  *   will be inserted; otherwise matching records are updated.
350
  *   will be inserted; otherwise matching records are updated.
350
  * @return bool
351
  * @return bool
351
  *   The return value of Table::update() or Table::insert()
352
  *   The return value of Table::update() or Table::insert()
352
  * @see Table::update()
353
  * @see Table::update()
353
  * @see Table::insert()
354
  * @see Table::insert()
354
  */
355
  */
355
  public function updateOrInsert($data, array $condition = null)
356
  public function updateOrInsert($data, array $condition = null)
356
  {
357
  {
357
    if ($this->select($this->id, $condition))
358
    if ($this->select($this->id, $condition))
358
    {
359
    {
359
      return $this->update($data, $condition);
360
      return $this->update($data, $condition);
360
    }
361
    }
361
362
362
        return $this->insert($data);
363
        return $this->insert($data);
363
  }
364
  }
364
365
365
  /**
366
  /**
366
   * Finds a record by ID
367
   * Finds a record by ID
367
   *
368
   *
368
   * @param mixed $id
369
   * @param mixed $id
369
   * @return array
370
   * @return array
370
   */
371
   */
371
  public function find ($id)
372
  public function find ($id)
372
  {
373
  {
373
    /* DEBUG */
374
    /* DEBUG */
374
    if (defined('DEBUG') && DEBUG > 0)
375
    if (defined('DEBUG') && DEBUG > 0)
375
    {
376
    {
376
      debug($id);
377
      debug($id);
377
    }
378
    }
378
379
379
    $result = $this->select(null, array($this->id => $id));
380
    $result = $this->select(null, array($this->id => $id));
380
381
381
    if ($result)
382
    if ($result)
382
    {
383
    {
383
      $result = $result[0];
384
      $result = $result[0];
384
    }
385
    }
385
386
386
    return $result;
387
    return $result;
387
  }
388
  }
-
 
389
-
 
390
  /**
-
 
391
   * Returns the date of last modification of this table.
-
 
392
   *
-
 
393
   * @return int|null
-
 
394
   *   Timestamp of last modification, or <code>null</code> if
-
 
395
   *   unavailable.
-
 
396
   */
-
 
397
  public function getLastModified ()
-
 
398
  {
-
 
399
    return $this->database->getLastModified($this->name);
-
 
400
  }
388
}
401
}
389
402