Subversion Repositories PHPX

Rev

Rev 61 | Details | Compare with Previous | Last modification | View Log | RSS feed

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