PageRenderTime 38ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/fuel/packages/activerecord/classes/model.php

https://github.com/mubashariqbal/fuel
PHP | 993 lines | 762 code | 55 blank | 176 comment | 33 complexity | 56e199a954c6724e307178f7cda5bdee MD5 | raw file
Possible License(s): MIT, BSD-3-Clause
  1. <?php
  2. /**
  3. * Fuel
  4. *
  5. * Fuel is a fast, lightweight, community driven PHP5 framework.
  6. *
  7. * @package Fuel
  8. * @version 1.0
  9. * @author Fuel Development Team
  10. * @license MIT License
  11. * @copyright 2010 Dan Horrigan
  12. * @link http://fuelphp.com
  13. */
  14. namespace ActiveRecord;
  15. use Fuel\App as App;
  16. use Fuel\App\DB;
  17. use Fuel\App\Database;
  18. use Fuel\App\Inflector;
  19. class Model {
  20. /**
  21. * Queries the table for the given primary key value ($id). $id can also
  22. * contain 2 special values:
  23. *
  24. * <ul>
  25. * <li>'all' - Will return all of the records in the table</li>
  26. * <li>'first' - Will return the first record. This will set automatically
  27. * set the 'limit' option to 1.</li>
  28. * </ul>
  29. *
  30. * The following options are available to use in the $options parameter:
  31. *
  32. * <ul>
  33. * <li>include - an array of associations to include in the query. Example:
  34. * <code>array('group', 'posts')</code></li>
  35. * <li>select - an array of columns to select (defaults to '*'). Example:
  36. * <code>array('first_name', 'last_name')</code></li>
  37. * <li>limit - the maximum number of records to fetch</li>
  38. * <li>offset - the offset to start from</li>
  39. * <li>order - an array containing the ORDER BY clause. Example:
  40. * <code>array('last_name', 'ASC')</code></li>
  41. * <li>where - an array of arrays containing the where clauses. Example:
  42. * <code>array(array('enabled', '=', 1), array('blacklisted', '=', 0))</code>
  43. * <li>or_where - identical to 'where' except these are OR WHERE statements.</li>
  44. *
  45. * Usage:
  46. *
  47. * <code>$user = User::find(2, array('include' => array('group')));</code>
  48. *
  49. * @param int|string $id the primary key value
  50. * @param srray $options the find options
  51. * @return object the result
  52. */
  53. public static function find($id, $options = array())
  54. {
  55. $instance = new static;
  56. $results = $instance->run_find($id, $options);
  57. unset($instance);
  58. return $results;
  59. }
  60. /**
  61. * This allows for queries called by a static method on the model class. It
  62. * supports both 'and' and 'or' queries, or a mixture of both. You can also
  63. * set the last parameter to an array of option. see {@link find} for
  64. * available options.
  65. *
  66. * Usage:
  67. *
  68. * <code>
  69. * Model_User::find_by_group_id(2);
  70. * Model_User::find_by_username_and_password('demo', 'password');
  71. * Model_User::find_by_username_or_group_id('demo', 2);
  72. * Model_User::find_by_email_and_password_or_group_id('demo@example.com', 'password', 2);
  73. * </code>
  74. *
  75. * @param string $name the method name called
  76. * @param array $arguments the method arguments
  77. * @return object|array an instance or array of instances found
  78. */
  79. public static function __callStatic($name, $arguments)
  80. {
  81. if ($name == '_init')
  82. {
  83. return;
  84. }
  85. if (strncmp($name, 'find_by_', 8) !== 0 && $name != '_init')
  86. {
  87. throw new App\Exception('Invalid method call. Method '.$name.' does not exist.', 0);
  88. }
  89. $name = substr($name, 8);
  90. $and_parts = explode('_and_', $name);
  91. $temp_model = new static;
  92. $table_name = $temp_model->table_name;
  93. unset($temp_model);
  94. $where = array();
  95. $or_where = array();
  96. foreach ($and_parts as $and_part)
  97. {
  98. $or_parts = explode('_or_', $and_part);
  99. if (count($or_parts) == 1)
  100. {
  101. $where[] = array(
  102. $table_name.'.'.$or_parts[0], '=', array_shift($arguments)
  103. );
  104. }
  105. else
  106. {
  107. foreach($or_parts as $or_part)
  108. {
  109. $or_where[] = array(
  110. $table_name.'.'.$or_part, '=', array_shift($arguments)
  111. );
  112. }
  113. }
  114. }
  115. $options = count($arguments) > 0 ? array_pop($arguments) : array();
  116. if ( ! array_key_exists('where', $options))
  117. {
  118. $options['where'] = $where;
  119. }
  120. else
  121. {
  122. $options['where'] = $options['where'] + $where;
  123. }
  124. if ( ! array_key_exists('or_where', $options))
  125. {
  126. $options['or_where'] = $or_where;
  127. }
  128. else
  129. {
  130. $options['or_where'] = $options['or_where'] + $or_where;
  131. }
  132. return static::find('all', $options);
  133. }
  134. /**
  135. * This function is used to re-format the given $row into the $col_lookup
  136. * format.
  137. *
  138. * @param array $row the record
  139. * @param array $col_lookup the lookup schema
  140. * @return array the new $row
  141. */
  142. protected static function transform_row($row, $lookup)
  143. {
  144. $object = array();
  145. foreach ($row as $name => $value)
  146. {
  147. $object[$lookup[$name]["table"]][$lookup[$name]["column"]] = $value;
  148. }
  149. return $object;
  150. }
  151. /**
  152. * The table name of the model. If this is not set in the model, then it
  153. * is guessed based on the class name.
  154. *
  155. * @var string the table name
  156. */
  157. protected $table_name = null;
  158. /**
  159. * Holds the class name of the child object that extends ActiveRecord\Model
  160. *
  161. * @var string the class name
  162. */
  163. protected $class_name = null;
  164. /**
  165. * Holds the primary key for the table associated with this model
  166. *
  167. * @var string the primary key
  168. */
  169. public $primary_key = 'id';
  170. /**
  171. * Holds all the columns for this model. If this is not set in the model,
  172. * it attempts to read them in from the table.
  173. *
  174. * @var array the columns
  175. */
  176. protected $columns = array();
  177. /**
  178. * Holds all the data for the record
  179. *
  180. * @var array the date
  181. */
  182. protected $data = array();
  183. /**
  184. * Holds all the associations for the model
  185. *
  186. * @var array the associations
  187. */
  188. protected $associations = array();
  189. /**
  190. * Holds the modified state of the current model.
  191. *
  192. * @var bool the state
  193. */
  194. protected $is_modified = false;
  195. /**
  196. * Holds the frozen state of the model object. An object is frozen once
  197. * it has been destroyed.
  198. *
  199. * @var bool the state
  200. */
  201. protected $frozen = false;
  202. /**
  203. * Holds if this is a new record or not.
  204. *
  205. * @var bool the status
  206. */
  207. public $new_record = true;
  208. /**
  209. * The association types that ActiveRecord supports.
  210. *
  211. * @var array the types
  212. */
  213. private $assoc_types = array('belongs_to', 'has_many', 'has_one');
  214. /**
  215. * The constructor takes $params which can be data to set for the record.
  216. *
  217. * Usage:
  218. *
  219. * <code>
  220. * $user = new User;
  221. * $user = new User(array('name' => 'Dan'));
  222. * </code>
  223. *
  224. * @param array $params any data to set
  225. * @param bool $new_record if this is a new record
  226. * @param bool $is_modified if this record is modified
  227. */
  228. public function __construct($params = null, $new_record = true, $is_modified = false)
  229. {
  230. $this->class_name = get_class($this);
  231. // Setup all the associations
  232. foreach ($this->assoc_types as $type)
  233. {
  234. if (isset($this->{$type}))
  235. {
  236. $class_name = 'ActiveRecord\\'.Inflector::classify($type);
  237. foreach ($this->{$type} as $assoc)
  238. {
  239. /* handle association sent in as array with options */
  240. if (is_array($assoc))
  241. {
  242. $key = key($assoc);
  243. $this->{$key} = new $class_name($this, $key, current($assoc));
  244. }
  245. else
  246. {
  247. $this->{$assoc} = new $class_name($this, $assoc);
  248. }
  249. }
  250. }
  251. }
  252. if ($this->table_name === null)
  253. {
  254. $this->table_name = Inflector::tableize($this->class_name);
  255. }
  256. if (empty($this->columns))
  257. {
  258. $this->columns = array_keys(Database::instance()->list_columns($this->table_name));
  259. }
  260. if (is_array($params))
  261. {
  262. foreach ($params as $key => $value)
  263. {
  264. $this->{$key} = $value;
  265. }
  266. $this->is_modified = $is_modified;
  267. $this->new_record = $new_record;
  268. }
  269. }
  270. /**
  271. * Attempts to retrieve the column or association given.
  272. *
  273. * Usage:
  274. *
  275. * <code>
  276. * $user = User::find(1, array('include' => array('group'));
  277. * $user->first_name;
  278. * $user->group->name;
  279. *
  280. * $group = Group::find(1, array('include' => array('users'));
  281. * $group->users[0]->name;
  282. * </code>
  283. *
  284. * @param string $name the key to retrieve
  285. * @return mixed the column or association object
  286. * @throws ActiveRecord\Exception
  287. */
  288. public function __get($name)
  289. {
  290. if (array_key_exists($name, $this->data))
  291. {
  292. return $this->data[$name];
  293. }
  294. elseif (array_key_exists($name, $this->associations))
  295. {
  296. return $this->associations[$name]->get($this);
  297. }
  298. elseif (in_array($name, $this->columns))
  299. {
  300. return null;
  301. }
  302. elseif (preg_match('/^(.+?)_ids$/', $name, $matches))
  303. {
  304. $assoc_name = Inflector::pluralize($matches[1]);
  305. if ($this->associations[$assoc_name] instanceof HasMany)
  306. {
  307. return $this->associations[$assoc_name]->get_ids($this);
  308. }
  309. }
  310. throw new App\Exception("attribute called '$name' doesn't exist", Exception::AttributeNotFound);
  311. }
  312. /**
  313. * Attempts to set the column or association to the geven value.
  314. *
  315. * Usage:
  316. *
  317. * <code>
  318. * $user = User::find(1, array('include' => array('group'));
  319. * $user->first_name = 'Joe';
  320. *
  321. * $group = Group::find(1, array('include' => array('users'));
  322. * $group->users[0]->first_name = 'Dave';
  323. * </code>
  324. *
  325. * @param string $name the key to set
  326. * @param mixed $value the value to set
  327. * @throws ActiveRecord\Exception
  328. */
  329. public function __set($name, $value)
  330. {
  331. if ($this->frozen)
  332. {
  333. throw new App\Exception("Can not update $name as object is frozen.", Exception::ObjectFrozen);
  334. }
  335. if (preg_match('#(.+?)_ids$#', $name, $matches))
  336. {
  337. $assoc_name = Inflector::pluralize($matches[1]);
  338. }
  339. if (in_array($name, $this->columns))
  340. {
  341. $this->data[$name] = $value;
  342. $this->is_modified = true;
  343. }
  344. elseif ($value instanceof Association)
  345. {
  346. $this->associations[$name] = $value;
  347. }
  348. elseif (array_key_exists($name, $this->associations))
  349. {
  350. /* call like $comment->post = $mypost */
  351. $this->associations[$name]->set($value, $this);
  352. }
  353. elseif (isset($assoc_name)
  354. && array_key_exists($assoc_name, $this->associations)
  355. && $this->associations[$assoc_name] instanceof HasMany)
  356. {
  357. /* allow for $p->comment_ids type sets on HasMany associations */
  358. $this->associations[$assoc_name]->set_ids($value, $this);
  359. }
  360. else
  361. {
  362. throw new App\Exception("attribute called '$name' doesn't exist", Exception::AttributeNotFound);
  363. }
  364. }
  365. /**
  366. * On any ActiveRecord object we can make method calls to a specific assoc.
  367. *
  368. * Usage:
  369. *
  370. * <code>
  371. * $p = Post::find(1, array('include' => array('comments'));
  372. * $p->comments_push($comment);
  373. * </code>
  374. *
  375. * @param string $name the method name called
  376. * @param array $args the method arguments
  377. * @return mixed the result of the called method
  378. * @throws ActiveRecord\Exception
  379. */
  380. public function __call($name, $args)
  381. {
  382. // find longest available association that matches beginning of method
  383. $longest_assoc = '';
  384. foreach (array_keys($this->associations) as $assoc)
  385. {
  386. if (strpos($name, $assoc) === 0 &&
  387. strlen($assoc) > strlen($longest_assoc))
  388. {
  389. $longest_assoc = $assoc;
  390. }
  391. }
  392. if ($longest_assoc !== '')
  393. {
  394. list($null, $func) = explode($longest_assoc . '_', $name, 2);
  395. return $this->associations[$longest_assoc]->$func($args, $this);
  396. }
  397. else
  398. {
  399. throw new App\Exception("method or association not found for ($name)", Exception::MethodOrAssocationNotFound);
  400. }
  401. }
  402. /**
  403. * Gets tbe columns for the current model
  404. *
  405. * Usage:
  406. *
  407. * <code>
  408. * $user = new User;
  409. * $user->get_columns();
  410. * </code>
  411. *
  412. * @return array the columns
  413. */
  414. public function get_columns()
  415. {
  416. return $this->columns;
  417. }
  418. /**
  419. * Gets tbe primary key for the current model
  420. *
  421. * Usage:
  422. *
  423. * <code>
  424. * $user = new User;
  425. * $user->get_primary_key();
  426. * </code>
  427. *
  428. * @return string the primary key
  429. */
  430. public function get_primary_key()
  431. {
  432. return $this->primary_key;
  433. }
  434. /**
  435. * Checks if the instance is frozen or not
  436. *
  437. * Usage:
  438. *
  439. * <code>
  440. * $user = User::find(3);
  441. * $user->destroy();
  442. * $user->is_frozen(); // Returns true
  443. * </code>
  444. *
  445. * @return bool frozen status
  446. */
  447. public function is_frozen()
  448. {
  449. return $this->frozen;
  450. }
  451. /**
  452. * Checks if the instance is a new record or not
  453. *
  454. * Usage:
  455. *
  456. * <code>
  457. * $user = new User;
  458. * $user->is_new_record(); // Returns true
  459. * </code>
  460. *
  461. * @return bool new record status
  462. */
  463. public function is_new_record()
  464. {
  465. return $this->new_record;
  466. }
  467. /**
  468. * Checks if the intance has been modified
  469. *
  470. * Usage:
  471. *
  472. * <code>
  473. * $user = User::find(2);
  474. * $user->is_modified(); // Returns false
  475. *
  476. * $user->name = "Joe";
  477. * $user->is_modified(); // Returns true
  478. * </code>
  479. *
  480. * @return array the columns
  481. */
  482. public function is_modified()
  483. {
  484. return $this->is_modified;
  485. }
  486. /**
  487. * Sets the modified status
  488. *
  489. * Usage:
  490. *
  491. * <code>
  492. * $user = User::find(2);
  493. * $user->set_modified(true);
  494. * </code>
  495. */
  496. public function set_modified($val)
  497. {
  498. $this->is_modified = $val;
  499. }
  500. /**
  501. * Turns the current record as well as all associations into an accociative
  502. * array.
  503. *
  504. * Usage:
  505. *
  506. * <code>
  507. * $user = User::find(2);
  508. * $user_array = $user->as_array();
  509. * </code>
  510. *
  511. * @return array the object in the form of an array
  512. */
  513. public function as_array()
  514. {
  515. $return = $this->data;
  516. foreach ($this->associations as $key => $val)
  517. {
  518. $assoc = $this->associations[$key]->get($this);
  519. if ( ! is_array($assoc))
  520. {
  521. $return[$key] = $assoc;
  522. }
  523. else
  524. {
  525. foreach ($assoc as $row)
  526. {
  527. $return[$key][] = $row->data;
  528. }
  529. }
  530. }
  531. return $return;
  532. }
  533. /**
  534. * Updates the given data then saves the record
  535. *
  536. * Usage:
  537. *
  538. * <code>
  539. * $user = User::find(2);
  540. * $user->update(array('name' => 'Joe'));
  541. * </code>
  542. *
  543. * @return bool save status
  544. */
  545. public function update($attributes)
  546. {
  547. foreach ($attributes as $key => $value)
  548. {
  549. $this->$key = $value;
  550. }
  551. return $this->save();
  552. }
  553. /**
  554. * Saves the current record and any associations. This method will call 6
  555. * "hook" methods that you can use to modify the data, run extra validation
  556. * or anything else you want. They are as follows:
  557. *
  558. * <ul>
  559. * <li>before_save() - runs before anything</li>
  560. * <li>before_create() - runs before any new record is entered</li>
  561. * <li>after_create() - runs after new record creation</li>
  562. * <li>before_update() - runs before a modified record is saved</li>
  563. * <li>after_update() - runs after a modified record is saved</li>
  564. * <li>after_save() - runs after everything, new or modified records</li>
  565. * </ul>
  566. *
  567. * Usage:
  568. *
  569. * <code>
  570. * $user = User::find(3);
  571. * $user->first_name = 'Dan';
  572. * $user->save();
  573. * </code>
  574. *
  575. * @return bool the status of the operation
  576. */
  577. public function save()
  578. {
  579. if (method_exists($this, 'before_save'))
  580. {
  581. $this->before_save();
  582. }
  583. foreach ($this->associations as $name => $assoc)
  584. {
  585. if ($assoc instanceOf BelongsTo && $assoc->needs_saving())
  586. {
  587. $this->$name->save();
  588. /* after our save, $this->$name might have new id;
  589. we want to update the foreign key of $this to match;
  590. we update this foreign key already as a side-effect
  591. when calling set() on an association
  592. */
  593. $this->$name = $this->$name;
  594. }
  595. }
  596. if ($this->new_record)
  597. {
  598. if (method_exists($this, 'before_create'))
  599. {
  600. $this->before_create();
  601. }
  602. $columns = array();
  603. foreach ($this->columns as $column)
  604. {
  605. if ($column == $this->primary_key)
  606. {
  607. continue;
  608. }
  609. $columns[] = $column;
  610. if (is_null($this->$column))
  611. {
  612. $values[] = 'NULL';
  613. }
  614. else
  615. {
  616. $values[] = $this->$column;
  617. }
  618. }
  619. $res = DB::insert($this->table_name, $columns)
  620. ->values($values)
  621. ->execute();
  622. // Failed to save the new record
  623. if ($res[0] === 0)
  624. {
  625. return false;
  626. }
  627. $this->{$this->primary_key} = $res[0];
  628. $this->new_record = false;
  629. $this->is_modified = false;
  630. if (method_exists($this, 'after_create'))
  631. {
  632. $this->after_create();
  633. }
  634. }
  635. elseif ($this->is_modified)
  636. {
  637. if (method_exists($this, 'before_update'))
  638. {
  639. $this->before_update();
  640. }
  641. $values = array();
  642. foreach ($this->columns as $column)
  643. {
  644. if ($column == $this->primary_key)
  645. {
  646. continue;
  647. }
  648. $values[$column] = is_null($this->$column) ? 'NULL' : $this->$column;
  649. }
  650. $res = DB::update($this->table_name)
  651. ->set($values)
  652. ->where($this->primary_key, '=', $this->{$this->primary_key})
  653. ->limit(1)
  654. ->execute();
  655. $this->new_record = false;
  656. $this->is_modified = false;
  657. if (method_exists($this, 'after_update'))
  658. {
  659. $this->after_update();
  660. }
  661. }
  662. foreach ($this->associations as $name => $assoc)
  663. {
  664. if ($assoc instanceOf HasOne && $assoc->needs_saving())
  665. {
  666. /* again sorta weird, this will update foreign key as needed */
  667. $this->$name = $this->$name;
  668. /* save the object referenced by this association */
  669. $this->$name->save();
  670. }
  671. elseif ($assoc instanceOf HasMany && $assoc->needs_saving())
  672. {
  673. $assoc->save_as_needed($this);
  674. }
  675. }
  676. if (method_exists($this, 'after_save'))
  677. {
  678. $this->after_save();
  679. }
  680. return true;
  681. }
  682. /**
  683. * Destroys (deletes) the current record and any associations, then freezes
  684. * the record so it cannot be modified again. This method will call 2
  685. * "hook" methods that you can use to doanything else you want. They are as
  686. * follows:
  687. *
  688. * <ul>
  689. * <li>before_destroy() - runs before the record is destroyed</li>
  690. * <li>after_destroy() - runs after the record is destroyed</li>
  691. * </ul>
  692. *
  693. * Usage:
  694. *
  695. * <code>
  696. * $user = User::find(3);
  697. * $user->destroy();
  698. * </code>
  699. *
  700. * @return bool the status of the operation
  701. */
  702. public function destroy()
  703. {
  704. if (method_exists($this, 'before_destroy'))
  705. {
  706. $this->before_destroy();
  707. }
  708. foreach ($this->associations as $name => $assoc)
  709. {
  710. $assoc->destroy($this);
  711. }
  712. DB::delete($this->table_name)
  713. ->where($this->primary_key, '=', $this->{$this->primary_key})
  714. ->limit(1)
  715. ->execute();
  716. $this->frozen = true;
  717. if (method_exists($this, 'after_destroy'))
  718. {
  719. $this->after_destroy();
  720. }
  721. return true;
  722. }
  723. /**
  724. * Runs the find query. This is called and used by the {@link find} method,
  725. * and is separated out for simplicity.
  726. *
  727. * @param int|string|array $id the primary key(s) to look up
  728. * @param array $options a myriad of options
  729. * @return array the array of rows
  730. */
  731. protected function run_find($id, $options = array())
  732. {
  733. $query = $this->find_query($id, $options);
  734. $rows = $query['result']->as_array();
  735. $base_objects = array();
  736. foreach ($rows as $row)
  737. {
  738. if (count($query['column_lookup']) > 0)
  739. {
  740. $foreign_keys = array();
  741. $objects = static::transform_row($row, $query['column_lookup']);
  742. $ob_key = md5(serialize($objects[$this->table_name]));
  743. /* set cur_object to base object for this row; reusing if possible */
  744. if (array_key_exists($ob_key, $base_objects))
  745. {
  746. $cur_object = $base_objects[$ob_key];
  747. }
  748. else
  749. {
  750. $cur_object = new $this->class_name($objects[$this->table_name], false);
  751. $base_objects[$ob_key] = $cur_object;
  752. }
  753. foreach ($objects as $table => $attributes)
  754. {
  755. if ($table == $this->table_name)
  756. {
  757. continue;
  758. }
  759. foreach ($cur_object->associations as $assoc_name => $assoc)
  760. {
  761. $assoc->populate_from_find($attributes);
  762. }
  763. }
  764. }
  765. else
  766. {
  767. $item = new $this->class_name($row, false);
  768. array_push($base_objects, $item);
  769. }
  770. }
  771. if (count($base_objects) == 0 && (is_array($id) || is_numeric($id)))
  772. {
  773. throw new App\Exception("Couldn't find anything.", Exception::RecordNotFound);
  774. }
  775. return (is_array($id) || $id == 'all')
  776. ? array_values($base_objects)
  777. : array_shift($base_objects);
  778. }
  779. /**
  780. * Generates then executes the find query. This is used by {@link run_find}.
  781. * Please see {@link find} for parameter options and usage.
  782. *
  783. * @param string|int $id the primary key to find
  784. * @param array $options the array of options
  785. * @return array an array containing the query and column lookup map
  786. */
  787. protected function find_query($id, $options = array())
  788. {
  789. $item = new $this->class_name;
  790. ($id == 'first') and $options['limit'] = 1;
  791. $select = array_key_exists('select', $options) ? $options['select'] : array();
  792. $joins = array();
  793. $column_lookup = array();
  794. if (isset($options['include']))
  795. {
  796. $tables_to_columns = array();
  797. if (is_string($options['include']))
  798. {
  799. $includes = array_map('trim', explode(',', $options['include']));
  800. }
  801. else
  802. {
  803. $includes = $options['include'];
  804. }
  805. array_push($tables_to_columns, array(
  806. $this->table_name => $item->get_columns()
  807. ));
  808. // get join part of query from association and column names
  809. foreach ($includes as $include)
  810. {
  811. if (isset($item->associations[$include]))
  812. {
  813. list($cols, $join) = $item->associations[$include]->join();
  814. array_push($joins, $join);
  815. array_push($tables_to_columns, $cols);
  816. }
  817. }
  818. foreach ($tables_to_columns as $table_key => $columns)
  819. {
  820. foreach ($columns as $table => $cols)
  821. {
  822. foreach ($cols as $key => $col)
  823. {
  824. // Add this to the select array
  825. array_push($select, array($table.'.'.$col, "t{$table_key}_r$key"));
  826. $column_lookup["t{$table_key}_r{$key}"]["table"] = $table;
  827. $column_lookup["t{$table_key}_r{$key}"]["column"] = $col;
  828. }
  829. }
  830. }
  831. }
  832. // Start building the query
  833. $query = call_user_func_array('DB::select', $select);
  834. $query->from($this->table_name);
  835. foreach ($joins as $join)
  836. {
  837. if ( ! array_key_exists('table', $join))
  838. {
  839. foreach ($join as $j)
  840. {
  841. $query->join($j['table'], $j['type'])
  842. ->on($j['on'][0], $j['on'][1], $j['on'][2]);
  843. }
  844. }
  845. else
  846. {
  847. $query->join($join['table'], $join['type'])
  848. ->on($join['on'][0], $join['on'][1], $join['on'][2]);
  849. }
  850. }
  851. // Get the limit
  852. if (array_key_exists('limit', $options) and is_numeric($options['limit']))
  853. {
  854. $query->limit($options['limit']);
  855. }
  856. // Get the offset
  857. if (array_key_exists('offset', $options) and is_numeric($options['offset']))
  858. {
  859. $query->offset($options['offset']);
  860. }
  861. // Get the order
  862. if (array_key_exists('order', $options) && is_array($options['order']))
  863. {
  864. $query->order_by($options['order'][0], $options['order'][1]);
  865. }
  866. // Get the group
  867. if (array_key_exists('group', $options))
  868. {
  869. $query->group_by($options['group']);
  870. }
  871. if (is_array($id))
  872. {
  873. $query->where($item->primary_key, 'IN', $id);
  874. }
  875. elseif ($id != 'all' && $id != 'first')
  876. {
  877. $query->where($this->table_name.'.'.$item->primary_key, '=', $id);;
  878. }
  879. if (array_key_exists('where', $options) and is_array($options['where']))
  880. {
  881. foreach ($options['where'] as $conditional)
  882. {
  883. $query->where($conditional[0], $conditional[1], $conditional[2]);
  884. }
  885. }
  886. if (array_key_exists('or_where', $options) and is_array($options['or_where']))
  887. {
  888. foreach ($options['or_where'] as $conditional)
  889. {
  890. $query->or_where($conditional[0], $conditional[1], $conditional[2]);
  891. }
  892. }
  893. // It's all built, now lets execute
  894. $result = $query->execute();
  895. return array('result' => $result, 'column_lookup' => $column_lookup);
  896. }
  897. }
  898. /* End of file model.php */