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