PageRenderTime 73ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/xandra.org/www/modules/orm/classes/Kohana/ORM.php

https://bitbucket.org/ekkl/tanora
PHP | 2354 lines | 1163 code | 336 blank | 855 comment | 73 complexity | e6e68995559c6e86adc6273c024c7203 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. <?php defined('SYSPATH') OR die('No direct script access.');
  2. /**
  3. * [Object Relational Mapping][ref-orm] (ORM) is a method of abstracting database
  4. * access to standard PHP calls. All table rows are represented as model objects,
  5. * with object properties representing row data. ORM in Kohana generally follows
  6. * the [Active Record][ref-act] pattern.
  7. *
  8. * [ref-orm]: http://wikipedia.org/wiki/Object-relational_mapping
  9. * [ref-act]: http://wikipedia.org/wiki/Active_record
  10. *
  11. * @package Kohana/ORM
  12. * @author Kohana Team
  13. * @copyright (c) 2007-2012 Kohana Team
  14. * @license http://kohanaframework.org/license
  15. */
  16. class Kohana_ORM extends Model implements serializable {
  17. /**
  18. * Stores column information for ORM models
  19. * @var array
  20. */
  21. protected static $_column_cache = array();
  22. /**
  23. * Initialization storage for ORM models
  24. * @var array
  25. */
  26. protected static $_init_cache = array();
  27. /**
  28. * Creates and returns a new model.
  29. * Model name must be passed with its' original casing, e.g.
  30. *
  31. * $model = ORM::factory('User_Token');
  32. *
  33. * @chainable
  34. * @param string $model Model name
  35. * @param mixed $id Parameter for find()
  36. * @return ORM
  37. */
  38. public static function factory($model, $id = NULL)
  39. {
  40. // Set class name
  41. $model = 'Model_'.$model;
  42. return new $model($id);
  43. }
  44. /**
  45. * "Has one" relationships
  46. * @var array
  47. */
  48. protected $_has_one = array();
  49. /**
  50. * "Belongs to" relationships
  51. * @var array
  52. */
  53. protected $_belongs_to = array();
  54. /**
  55. * "Has many" relationships
  56. * @var array
  57. */
  58. protected $_has_many = array();
  59. /**
  60. * Relationships that should always be joined
  61. * @var array
  62. */
  63. protected $_load_with = array();
  64. /**
  65. * Validation object created before saving/updating
  66. * @var Validation
  67. */
  68. protected $_validation = NULL;
  69. /**
  70. * Current object
  71. * @var array
  72. */
  73. protected $_object = array();
  74. /**
  75. * @var array
  76. */
  77. protected $_changed = array();
  78. /**
  79. * @var array
  80. */
  81. protected $_original_values = array();
  82. /**
  83. * @var array
  84. */
  85. protected $_related = array();
  86. /**
  87. * @var bool
  88. */
  89. protected $_valid = FALSE;
  90. /**
  91. * @var bool
  92. */
  93. protected $_loaded = FALSE;
  94. /**
  95. * @var bool
  96. */
  97. protected $_saved = FALSE;
  98. /**
  99. * @var array
  100. */
  101. protected $_sorting;
  102. /**
  103. * Foreign key suffix
  104. * @var string
  105. */
  106. protected $_foreign_key_suffix = '_id';
  107. /**
  108. * Model name
  109. * @var string
  110. */
  111. protected $_object_name;
  112. /**
  113. * Plural model name
  114. * @var string
  115. */
  116. protected $_object_plural;
  117. /**
  118. * Table name
  119. * @var string
  120. */
  121. protected $_table_name;
  122. /**
  123. * Table columns
  124. * @var array
  125. */
  126. protected $_table_columns;
  127. /**
  128. * Auto-update columns for updates
  129. * @var string
  130. */
  131. protected $_updated_column = NULL;
  132. /**
  133. * Auto-update columns for creation
  134. * @var string
  135. */
  136. protected $_created_column = NULL;
  137. /**
  138. * Auto-serialize and unserialize columns on get/set
  139. * @var array
  140. */
  141. protected $_serialize_columns = array();
  142. /**
  143. * Table primary key
  144. * @var string
  145. */
  146. protected $_primary_key = 'id';
  147. /**
  148. * Primary key value
  149. * @var mixed
  150. */
  151. protected $_primary_key_value;
  152. /**
  153. * Model configuration, table names plural?
  154. * @var bool
  155. */
  156. protected $_table_names_plural = TRUE;
  157. /**
  158. * Model configuration, reload on wakeup?
  159. * @var bool
  160. */
  161. protected $_reload_on_wakeup = TRUE;
  162. /**
  163. * Database Object
  164. * @var Database
  165. */
  166. protected $_db = NULL;
  167. /**
  168. * Database config group
  169. * @var String
  170. */
  171. protected $_db_group = NULL;
  172. /**
  173. * Database methods applied
  174. * @var array
  175. */
  176. protected $_db_applied = array();
  177. /**
  178. * Database methods pending
  179. * @var array
  180. */
  181. protected $_db_pending = array();
  182. /**
  183. * Reset builder
  184. * @var bool
  185. */
  186. protected $_db_reset = TRUE;
  187. /**
  188. * Database query builder
  189. * @var Database_Query_Builder_Select
  190. */
  191. protected $_db_builder;
  192. /**
  193. * With calls already applied
  194. * @var array
  195. */
  196. protected $_with_applied = array();
  197. /**
  198. * Data to be loaded into the model from a database call cast
  199. * @var array
  200. */
  201. protected $_cast_data = array();
  202. /**
  203. * The message filename used for validation errors.
  204. * Defaults to ORM::$_object_name
  205. * @var string
  206. */
  207. protected $_errors_filename = NULL;
  208. /**
  209. * Constructs a new model and loads a record if given
  210. *
  211. * @param mixed $id Parameter for find or object to load
  212. */
  213. public function __construct($id = NULL)
  214. {
  215. $this->_initialize();
  216. if ($id !== NULL)
  217. {
  218. if (is_array($id))
  219. {
  220. foreach ($id as $column => $value)
  221. {
  222. // Passing an array of column => values
  223. $this->where($column, '=', $value);
  224. }
  225. $this->find();
  226. }
  227. else
  228. {
  229. // Passing the primary key
  230. $this->where($this->_object_name.'.'.$this->_primary_key, '=', $id)->find();
  231. }
  232. }
  233. elseif ( ! empty($this->_cast_data))
  234. {
  235. // Load preloaded data from a database call cast
  236. $this->_load_values($this->_cast_data);
  237. $this->_cast_data = array();
  238. }
  239. }
  240. /**
  241. * Prepares the model database connection, determines the table name,
  242. * and loads column information.
  243. *
  244. * @return void
  245. */
  246. protected function _initialize()
  247. {
  248. // Set the object name and plural name
  249. $this->_object_name = strtolower(substr(get_class($this), 6));
  250. // Check if this model has already been initialized
  251. if ( ! $init = Arr::get(ORM::$_init_cache, $this->_object_name, FALSE))
  252. {
  253. $init = array(
  254. '_belongs_to' => array(),
  255. '_has_one' => array(),
  256. '_has_many' => array(),
  257. );
  258. // Set the object plural name if none predefined
  259. if ( ! isset($this->_object_plural))
  260. {
  261. $init['_object_plural'] = Inflector::plural($this->_object_name);
  262. }
  263. if ( ! $this->_errors_filename)
  264. {
  265. $init['_errors_filename'] = $this->_object_name;
  266. }
  267. if ( ! is_object($this->_db))
  268. {
  269. // Get database instance
  270. $init['_db'] = Database::instance($this->_db_group);
  271. }
  272. if (empty($this->_table_name))
  273. {
  274. // Table name is the same as the object name
  275. $init['_table_name'] = $this->_object_name;
  276. if ($this->_table_names_plural === TRUE)
  277. {
  278. // Make the table name plural
  279. $init['_table_name'] = Arr::get($init, '_object_plural', $this->_object_plural);
  280. }
  281. }
  282. $defaults = array();
  283. foreach ($this->_belongs_to as $alias => $details)
  284. {
  285. if ( ! isset($details['model']))
  286. {
  287. $defaults['model'] = str_replace(' ', '_', ucwords(str_replace('_', ' ', $alias)));
  288. }
  289. $defaults['foreign_key'] = $alias.$this->_foreign_key_suffix;
  290. $init['_belongs_to'][$alias] = array_merge($defaults, $details);
  291. }
  292. foreach ($this->_has_one as $alias => $details)
  293. {
  294. if ( ! isset($details['model']))
  295. {
  296. $defaults['model'] = str_replace(' ', '_', ucwords(str_replace('_', ' ', $alias)));
  297. }
  298. $defaults['foreign_key'] = $this->_object_name.$this->_foreign_key_suffix;
  299. $init['_has_one'][$alias] = array_merge($defaults, $details);
  300. }
  301. foreach ($this->_has_many as $alias => $details)
  302. {
  303. if ( ! isset($details['model']))
  304. {
  305. $defaults['model'] = str_replace(' ', '_', ucwords(str_replace('_', ' ', Inflector::singular($alias))));
  306. }
  307. $defaults['foreign_key'] = $this->_object_name.$this->_foreign_key_suffix;
  308. $defaults['through'] = NULL;
  309. if ( ! isset($details['far_key']))
  310. {
  311. $defaults['far_key'] = Inflector::singular($alias).$this->_foreign_key_suffix;
  312. }
  313. $init['_has_many'][$alias] = array_merge($defaults, $details);
  314. }
  315. ORM::$_init_cache[$this->_object_name] = $init;
  316. }
  317. // Assign initialized properties to the current object
  318. foreach ($init as $property => $value)
  319. {
  320. $this->{$property} = $value;
  321. }
  322. // Load column information
  323. $this->reload_columns();
  324. // Clear initial model state
  325. $this->clear();
  326. }
  327. /**
  328. * Initializes validation rules, and labels
  329. *
  330. * @return void
  331. */
  332. protected function _validation()
  333. {
  334. // Build the validation object with its rules
  335. $this->_validation = Validation::factory($this->_object)
  336. ->bind(':model', $this)
  337. ->bind(':original_values', $this->_original_values)
  338. ->bind(':changed', $this->_changed);
  339. foreach ($this->rules() as $field => $rules)
  340. {
  341. $this->_validation->rules($field, $rules);
  342. }
  343. // Use column names by default for labels
  344. $columns = array_keys($this->_table_columns);
  345. // Merge user-defined labels
  346. $labels = array_merge(array_combine($columns, $columns), $this->labels());
  347. foreach ($labels as $field => $label)
  348. {
  349. $this->_validation->label($field, $label);
  350. }
  351. }
  352. /**
  353. * Reload column definitions.
  354. *
  355. * @chainable
  356. * @param boolean $force Force reloading
  357. * @return ORM
  358. */
  359. public function reload_columns($force = FALSE)
  360. {
  361. if ($force === TRUE OR empty($this->_table_columns))
  362. {
  363. if (isset(ORM::$_column_cache[$this->_object_name]))
  364. {
  365. // Use cached column information
  366. $this->_table_columns = ORM::$_column_cache[$this->_object_name];
  367. }
  368. else
  369. {
  370. // Grab column information from database
  371. $this->_table_columns = $this->list_columns();
  372. // Load column cache
  373. ORM::$_column_cache[$this->_object_name] = $this->_table_columns;
  374. }
  375. }
  376. return $this;
  377. }
  378. /**
  379. * Unloads the current object and clears the status.
  380. *
  381. * @chainable
  382. * @return ORM
  383. */
  384. public function clear()
  385. {
  386. // Create an array with all the columns set to NULL
  387. $values = array_combine(array_keys($this->_table_columns), array_fill(0, count($this->_table_columns), NULL));
  388. // Replace the object and reset the object status
  389. $this->_object = $this->_changed = $this->_related = $this->_original_values = array();
  390. // Replace the current object with an empty one
  391. $this->_load_values($values);
  392. // Reset primary key
  393. $this->_primary_key_value = NULL;
  394. // Reset the loaded state
  395. $this->_loaded = FALSE;
  396. $this->reset();
  397. return $this;
  398. }
  399. /**
  400. * Reloads the current object from the database.
  401. *
  402. * @chainable
  403. * @return ORM
  404. */
  405. public function reload()
  406. {
  407. $primary_key = $this->pk();
  408. // Replace the object and reset the object status
  409. $this->_object = $this->_changed = $this->_related = $this->_original_values = array();
  410. // Only reload the object if we have one to reload
  411. if ($this->_loaded)
  412. return $this->clear()
  413. ->where($this->_object_name.'.'.$this->_primary_key, '=', $primary_key)
  414. ->find();
  415. else
  416. return $this->clear();
  417. }
  418. /**
  419. * Checks if object data is set.
  420. *
  421. * @param string $column Column name
  422. * @return boolean
  423. */
  424. public function __isset($column)
  425. {
  426. return (isset($this->_object[$column]) OR
  427. isset($this->_related[$column]) OR
  428. isset($this->_has_one[$column]) OR
  429. isset($this->_belongs_to[$column]) OR
  430. isset($this->_has_many[$column]));
  431. }
  432. /**
  433. * Unsets object data.
  434. *
  435. * @param string $column Column name
  436. * @return void
  437. */
  438. public function __unset($column)
  439. {
  440. unset($this->_object[$column], $this->_changed[$column], $this->_related[$column]);
  441. }
  442. /**
  443. * Displays the primary key of a model when it is converted to a string.
  444. *
  445. * @return string
  446. */
  447. public function __toString()
  448. {
  449. return (string) $this->pk();
  450. }
  451. /**
  452. * Allows serialization of only the object data and state, to prevent
  453. * "stale" objects being unserialized, which also requires less memory.
  454. *
  455. * @return string
  456. */
  457. public function serialize()
  458. {
  459. // Store only information about the object
  460. foreach (array('_primary_key_value', '_object', '_changed', '_loaded', '_saved', '_sorting', '_original_values') as $var)
  461. {
  462. $data[$var] = $this->{$var};
  463. }
  464. return serialize($data);
  465. }
  466. /**
  467. * Check whether the model data has been modified.
  468. * If $field is specified, checks whether that field was modified.
  469. *
  470. * @param string $field field to check for changes
  471. * @return bool Whether or not the field has changed
  472. */
  473. public function changed($field = NULL)
  474. {
  475. return ($field === NULL)
  476. ? $this->_changed
  477. : Arr::get($this->_changed, $field);
  478. }
  479. /**
  480. * Prepares the database connection and reloads the object.
  481. *
  482. * @param string $data String for unserialization
  483. * @return void
  484. */
  485. public function unserialize($data)
  486. {
  487. // Initialize model
  488. $this->_initialize();
  489. foreach (unserialize($data) as $name => $var)
  490. {
  491. $this->{$name} = $var;
  492. }
  493. if ($this->_reload_on_wakeup === TRUE)
  494. {
  495. // Reload the object
  496. $this->reload();
  497. }
  498. }
  499. /**
  500. * Handles retrieval of all model values, relationships, and metadata.
  501. * [!!] This should not be overridden.
  502. *
  503. * @param string $column Column name
  504. * @return mixed
  505. */
  506. public function __get($column)
  507. {
  508. return $this->get($column);
  509. }
  510. /**
  511. * Handles getting of column
  512. * Override this method to add custom get behavior
  513. *
  514. * @param string $column Column name
  515. * @throws Kohana_Exception
  516. * @return mixed
  517. */
  518. public function get($column)
  519. {
  520. if (array_key_exists($column, $this->_object))
  521. {
  522. return (in_array($column, $this->_serialize_columns))
  523. ? $this->_unserialize_value($this->_object[$column])
  524. : $this->_object[$column];
  525. }
  526. elseif (isset($this->_related[$column]))
  527. {
  528. // Return related model that has already been fetched
  529. return $this->_related[$column];
  530. }
  531. elseif (isset($this->_belongs_to[$column]))
  532. {
  533. $model = $this->_related($column);
  534. // Use this model's column and foreign model's primary key
  535. $col = $model->_object_name.'.'.$model->_primary_key;
  536. $val = $this->_object[$this->_belongs_to[$column]['foreign_key']];
  537. // Make sure we don't run WHERE "AUTO_INCREMENT column" = NULL queries. This would
  538. // return the last inserted record instead of an empty result.
  539. // See: http://mysql.localhost.net.ar/doc/refman/5.1/en/server-session-variables.html#sysvar_sql_auto_is_null
  540. if ($val !== NULL)
  541. {
  542. $model->where($col, '=', $val)->find();
  543. }
  544. return $this->_related[$column] = $model;
  545. }
  546. elseif (isset($this->_has_one[$column]))
  547. {
  548. $model = $this->_related($column);
  549. // Use this model's primary key value and foreign model's column
  550. $col = $model->_object_name.'.'.$this->_has_one[$column]['foreign_key'];
  551. $val = $this->pk();
  552. $model->where($col, '=', $val)->find();
  553. return $this->_related[$column] = $model;
  554. }
  555. elseif (isset($this->_has_many[$column]))
  556. {
  557. $model = ORM::factory($this->_has_many[$column]['model']);
  558. if (isset($this->_has_many[$column]['through']))
  559. {
  560. // Grab has_many "through" relationship table
  561. $through = $this->_has_many[$column]['through'];
  562. // Join on through model's target foreign key (far_key) and target model's primary key
  563. $join_col1 = $through.'.'.$this->_has_many[$column]['far_key'];
  564. $join_col2 = $model->_object_name.'.'.$model->_primary_key;
  565. $model->join($through)->on($join_col1, '=', $join_col2);
  566. // Through table's source foreign key (foreign_key) should be this model's primary key
  567. $col = $through.'.'.$this->_has_many[$column]['foreign_key'];
  568. $val = $this->pk();
  569. }
  570. else
  571. {
  572. // Simple has_many relationship, search where target model's foreign key is this model's primary key
  573. $col = $model->_object_name.'.'.$this->_has_many[$column]['foreign_key'];
  574. $val = $this->pk();
  575. }
  576. return $model->where($col, '=', $val);
  577. }
  578. else
  579. {
  580. throw new Kohana_Exception('The :property property does not exist in the :class class',
  581. array(':property' => $column, ':class' => get_class($this)));
  582. }
  583. }
  584. /**
  585. * Base set method.
  586. * [!!] This should not be overridden.
  587. *
  588. * @param string $column Column name
  589. * @param mixed $value Column value
  590. * @return void
  591. */
  592. public function __set($column, $value)
  593. {
  594. $this->set($column, $value);
  595. }
  596. /**
  597. * Handles setting of columns
  598. * Override this method to add custom set behavior
  599. *
  600. * @param string $column Column name
  601. * @param mixed $value Column value
  602. * @throws Kohana_Exception
  603. * @return ORM
  604. */
  605. public function set($column, $value)
  606. {
  607. if ( ! isset($this->_object_name))
  608. {
  609. // Object not yet constructed, so we're loading data from a database call cast
  610. $this->_cast_data[$column] = $value;
  611. return $this;
  612. }
  613. if (in_array($column, $this->_serialize_columns))
  614. {
  615. $value = $this->_serialize_value($value);
  616. }
  617. if (array_key_exists($column, $this->_object))
  618. {
  619. // Filter the data
  620. $value = $this->run_filter($column, $value);
  621. // See if the data really changed
  622. if ($value !== $this->_object[$column])
  623. {
  624. $this->_object[$column] = $value;
  625. // Data has changed
  626. $this->_changed[$column] = $column;
  627. // Object is no longer saved or valid
  628. $this->_saved = $this->_valid = FALSE;
  629. }
  630. }
  631. elseif (isset($this->_belongs_to[$column]))
  632. {
  633. // Update related object itself
  634. $this->_related[$column] = $value;
  635. // Update the foreign key of this model
  636. $this->_object[$this->_belongs_to[$column]['foreign_key']] = ($value instanceof ORM)
  637. ? $value->pk()
  638. : NULL;
  639. $this->_changed[$column] = $this->_belongs_to[$column]['foreign_key'];
  640. }
  641. else
  642. {
  643. throw new Kohana_Exception('The :property: property does not exist in the :class: class',
  644. array(':property:' => $column, ':class:' => get_class($this)));
  645. }
  646. return $this;
  647. }
  648. /**
  649. * Set values from an array with support for one-one relationships. This method should be used
  650. * for loading in post data, etc.
  651. *
  652. * @param array $values Array of column => val
  653. * @param array $expected Array of keys to take from $values
  654. * @return ORM
  655. */
  656. public function values(array $values, array $expected = NULL)
  657. {
  658. // Default to expecting everything except the primary key
  659. if ($expected === NULL)
  660. {
  661. $expected = array_keys($this->_table_columns);
  662. // Don't set the primary key by default
  663. unset($values[$this->_primary_key]);
  664. }
  665. foreach ($expected as $key => $column)
  666. {
  667. if (is_string($key))
  668. {
  669. // isset() fails when the value is NULL (we want it to pass)
  670. if ( ! array_key_exists($key, $values))
  671. continue;
  672. // Try to set values to a related model
  673. $this->{$key}->values($values[$key], $column);
  674. }
  675. else
  676. {
  677. // isset() fails when the value is NULL (we want it to pass)
  678. if ( ! array_key_exists($column, $values))
  679. continue;
  680. // Update the column, respects __set()
  681. $this->$column = $values[$column];
  682. }
  683. }
  684. return $this;
  685. }
  686. /**
  687. * Returns the values of this object as an array, including any related one-one
  688. * models that have already been loaded using with()
  689. *
  690. * @return array
  691. */
  692. public function as_array()
  693. {
  694. $object = array();
  695. foreach ($this->_object as $column => $value)
  696. {
  697. // Call __get for any user processing
  698. $object[$column] = $this->__get($column);
  699. }
  700. foreach ($this->_related as $column => $model)
  701. {
  702. // Include any related objects that are already loaded
  703. $object[$column] = $model->as_array();
  704. }
  705. return $object;
  706. }
  707. /**
  708. * Binds another one-to-one object to this model. One-to-one objects
  709. * can be nested using 'object1:object2' syntax
  710. *
  711. * @param string $target_path Target model to bind to
  712. * @return ORM
  713. */
  714. public function with($target_path)
  715. {
  716. if (isset($this->_with_applied[$target_path]))
  717. {
  718. // Don't join anything already joined
  719. return $this;
  720. }
  721. // Split object parts
  722. $aliases = explode(':', $target_path);
  723. $target = $this;
  724. foreach ($aliases as $alias)
  725. {
  726. // Go down the line of objects to find the given target
  727. $parent = $target;
  728. $target = $parent->_related($alias);
  729. if ( ! $target)
  730. {
  731. // Can't find related object
  732. return $this;
  733. }
  734. }
  735. // Target alias is at the end
  736. $target_alias = $alias;
  737. // Pop-off top alias to get the parent path (user:photo:tag becomes user:photo - the parent table prefix)
  738. array_pop($aliases);
  739. $parent_path = implode(':', $aliases);
  740. if (empty($parent_path))
  741. {
  742. // Use this table name itself for the parent path
  743. $parent_path = $this->_object_name;
  744. }
  745. else
  746. {
  747. if ( ! isset($this->_with_applied[$parent_path]))
  748. {
  749. // If the parent path hasn't been joined yet, do it first (otherwise LEFT JOINs fail)
  750. $this->with($parent_path);
  751. }
  752. }
  753. // Add to with_applied to prevent duplicate joins
  754. $this->_with_applied[$target_path] = TRUE;
  755. // Use the keys of the empty object to determine the columns
  756. foreach (array_keys($target->_object) as $column)
  757. {
  758. $name = $target_path.'.'.$column;
  759. $alias = $target_path.':'.$column;
  760. // Add the prefix so that load_result can determine the relationship
  761. $this->select(array($name, $alias));
  762. }
  763. if (isset($parent->_belongs_to[$target_alias]))
  764. {
  765. // Parent belongs_to target, use target's primary key and parent's foreign key
  766. $join_col1 = $target_path.'.'.$target->_primary_key;
  767. $join_col2 = $parent_path.'.'.$parent->_belongs_to[$target_alias]['foreign_key'];
  768. }
  769. else
  770. {
  771. // Parent has_one target, use parent's primary key as target's foreign key
  772. $join_col1 = $parent_path.'.'.$parent->_primary_key;
  773. $join_col2 = $target_path.'.'.$parent->_has_one[$target_alias]['foreign_key'];
  774. }
  775. // Join the related object into the result
  776. $this->join(array($target->_table_name, $target_path), 'LEFT')->on($join_col1, '=', $join_col2);
  777. return $this;
  778. }
  779. /**
  780. * Initializes the Database Builder to given query type
  781. *
  782. * @param integer $type Type of Database query
  783. * @return ORM
  784. */
  785. protected function _build($type)
  786. {
  787. // Construct new builder object based on query type
  788. switch ($type)
  789. {
  790. case Database::SELECT:
  791. $this->_db_builder = DB::select();
  792. break;
  793. case Database::UPDATE:
  794. $this->_db_builder = DB::update(array($this->_table_name, $this->_object_name));
  795. break;
  796. case Database::DELETE:
  797. // Cannot use an alias for DELETE queries
  798. $this->_db_builder = DB::delete($this->_table_name);
  799. }
  800. // Process pending database method calls
  801. foreach ($this->_db_pending as $method)
  802. {
  803. $name = $method['name'];
  804. $args = $method['args'];
  805. $this->_db_applied[$name] = $name;
  806. call_user_func_array(array($this->_db_builder, $name), $args);
  807. }
  808. return $this;
  809. }
  810. /**
  811. * Finds and loads a single database row into the object.
  812. *
  813. * @chainable
  814. * @throws Kohana_Exception
  815. * @return ORM
  816. */
  817. public function find()
  818. {
  819. if ($this->_loaded)
  820. throw new Kohana_Exception('Method find() cannot be called on loaded objects');
  821. if ( ! empty($this->_load_with))
  822. {
  823. foreach ($this->_load_with as $alias)
  824. {
  825. // Bind auto relationships
  826. $this->with($alias);
  827. }
  828. }
  829. $this->_build(Database::SELECT);
  830. return $this->_load_result(FALSE);
  831. }
  832. /**
  833. * Finds multiple database rows and returns an iterator of the rows found.
  834. *
  835. * @throws Kohana_Exception
  836. * @return Database_Result
  837. */
  838. public function find_all()
  839. {
  840. if ($this->_loaded)
  841. throw new Kohana_Exception('Method find_all() cannot be called on loaded objects');
  842. if ( ! empty($this->_load_with))
  843. {
  844. foreach ($this->_load_with as $alias)
  845. {
  846. // Bind auto relationships
  847. $this->with($alias);
  848. }
  849. }
  850. $this->_build(Database::SELECT);
  851. return $this->_load_result(TRUE);
  852. }
  853. /**
  854. * Returns an array of columns to include in the select query. This method
  855. * can be overridden to change the default select behavior.
  856. *
  857. * @return array Columns to select
  858. */
  859. protected function _build_select()
  860. {
  861. $columns = array();
  862. foreach ($this->_table_columns as $column => $_)
  863. {
  864. $columns[] = array($this->_object_name.'.'.$column, $column);
  865. }
  866. return $columns;
  867. }
  868. /**
  869. * Loads a database result, either as a new record for this model, or as
  870. * an iterator for multiple rows.
  871. *
  872. * @chainable
  873. * @param bool $multiple Return an iterator or load a single row
  874. * @return ORM|Database_Result
  875. */
  876. protected function _load_result($multiple = FALSE)
  877. {
  878. $this->_db_builder->from(array($this->_table_name, $this->_object_name));
  879. if ($multiple === FALSE)
  880. {
  881. // Only fetch 1 record
  882. $this->_db_builder->limit(1);
  883. }
  884. // Select all columns by default
  885. $this->_db_builder->select_array($this->_build_select());
  886. if ( ! isset($this->_db_applied['order_by']) AND ! empty($this->_sorting))
  887. {
  888. foreach ($this->_sorting as $column => $direction)
  889. {
  890. if (strpos($column, '.') === FALSE)
  891. {
  892. // Sorting column for use in JOINs
  893. $column = $this->_object_name.'.'.$column;
  894. }
  895. $this->_db_builder->order_by($column, $direction);
  896. }
  897. }
  898. if ($multiple === TRUE)
  899. {
  900. // Return database iterator casting to this object type
  901. $result = $this->_db_builder->as_object(get_class($this))->execute($this->_db);
  902. $this->reset();
  903. return $result;
  904. }
  905. else
  906. {
  907. // Load the result as an associative array
  908. $result = $this->_db_builder->as_assoc()->execute($this->_db);
  909. $this->reset();
  910. if ($result->count() === 1)
  911. {
  912. // Load object values
  913. $this->_load_values($result->current());
  914. }
  915. else
  916. {
  917. // Clear the object, nothing was found
  918. $this->clear();
  919. }
  920. return $this;
  921. }
  922. }
  923. /**
  924. * Loads an array of values into into the current object.
  925. *
  926. * @chainable
  927. * @param array $values Values to load
  928. * @return ORM
  929. */
  930. protected function _load_values(array $values)
  931. {
  932. if (array_key_exists($this->_primary_key, $values))
  933. {
  934. if ($values[$this->_primary_key] !== NULL)
  935. {
  936. // Flag as loaded and valid
  937. $this->_loaded = $this->_valid = TRUE;
  938. // Store primary key
  939. $this->_primary_key_value = $values[$this->_primary_key];
  940. }
  941. else
  942. {
  943. // Not loaded or valid
  944. $this->_loaded = $this->_valid = FALSE;
  945. }
  946. }
  947. // Related objects
  948. $related = array();
  949. foreach ($values as $column => $value)
  950. {
  951. if (strpos($column, ':') === FALSE)
  952. {
  953. // Load the value to this model
  954. $this->_object[$column] = $value;
  955. }
  956. else
  957. {
  958. // Column belongs to a related model
  959. list ($prefix, $column) = explode(':', $column, 2);
  960. $related[$prefix][$column] = $value;
  961. }
  962. }
  963. if ( ! empty($related))
  964. {
  965. foreach ($related as $object => $values)
  966. {
  967. // Load the related objects with the values in the result
  968. $this->_related($object)->_load_values($values);
  969. }
  970. }
  971. if ($this->_loaded)
  972. {
  973. // Store the object in its original state
  974. $this->_original_values = $this->_object;
  975. }
  976. return $this;
  977. }
  978. /**
  979. * Rule definitions for validation
  980. *
  981. * @return array
  982. */
  983. public function rules()
  984. {
  985. return array();
  986. }
  987. /**
  988. * Filters a value for a specific column
  989. *
  990. * @param string $field The column name
  991. * @param string $value The value to filter
  992. * @return string
  993. */
  994. protected function run_filter($field, $value)
  995. {
  996. $filters = $this->filters();
  997. // Get the filters for this column
  998. $wildcards = empty($filters[TRUE]) ? array() : $filters[TRUE];
  999. // Merge in the wildcards
  1000. $filters = empty($filters[$field]) ? $wildcards : array_merge($wildcards, $filters[$field]);
  1001. // Bind the field name and model so they can be used in the filter method
  1002. $_bound = array
  1003. (
  1004. ':field' => $field,
  1005. ':model' => $this,
  1006. );
  1007. foreach ($filters as $array)
  1008. {
  1009. // Value needs to be bound inside the loop so we are always using the
  1010. // version that was modified by the filters that already ran
  1011. $_bound[':value'] = $value;
  1012. // Filters are defined as array($filter, $params)
  1013. $filter = $array[0];
  1014. $params = Arr::get($array, 1, array(':value'));
  1015. foreach ($params as $key => $param)
  1016. {
  1017. if (is_string($param) AND array_key_exists($param, $_bound))
  1018. {
  1019. // Replace with bound value
  1020. $params[$key] = $_bound[$param];
  1021. }
  1022. }
  1023. if (is_array($filter) OR ! is_string($filter))
  1024. {
  1025. // This is either a callback as an array or a lambda
  1026. $value = call_user_func_array($filter, $params);
  1027. }
  1028. elseif (strpos($filter, '::') === FALSE)
  1029. {
  1030. // Use a function call
  1031. $function = new ReflectionFunction($filter);
  1032. // Call $function($this[$field], $param, ...) with Reflection
  1033. $value = $function->invokeArgs($params);
  1034. }
  1035. else
  1036. {
  1037. // Split the class and method of the rule
  1038. list($class, $method) = explode('::', $filter, 2);
  1039. // Use a static method call
  1040. $method = new ReflectionMethod($class, $method);
  1041. // Call $Class::$method($this[$field], $param, ...) with Reflection
  1042. $value = $method->invokeArgs(NULL, $params);
  1043. }
  1044. }
  1045. return $value;
  1046. }
  1047. /**
  1048. * Filter definitions for validation
  1049. *
  1050. * @return array
  1051. */
  1052. public function filters()
  1053. {
  1054. return array();
  1055. }
  1056. /**
  1057. * Label definitions for validation
  1058. *
  1059. * @return array
  1060. */
  1061. public function labels()
  1062. {
  1063. return array();
  1064. }
  1065. /**
  1066. * Validates the current model's data
  1067. *
  1068. * @param Validation $extra_validation Validation object
  1069. * @throws ORM_Validation_Exception
  1070. * @return ORM
  1071. */
  1072. public function check(Validation $extra_validation = NULL)
  1073. {
  1074. // Determine if any external validation failed
  1075. $extra_errors = ($extra_validation AND ! $extra_validation->check());
  1076. // Always build a new validation object
  1077. $this->_validation();
  1078. $array = $this->_validation;
  1079. if (($this->_valid = $array->check()) === FALSE OR $extra_errors)
  1080. {
  1081. $exception = new ORM_Validation_Exception($this->errors_filename(), $array);
  1082. if ($extra_errors)
  1083. {
  1084. // Merge any possible errors from the external object
  1085. $exception->add_object('_external', $extra_validation);
  1086. }
  1087. throw $exception;
  1088. }
  1089. return $this;
  1090. }
  1091. /**
  1092. * Insert a new object to the database
  1093. * @param Validation $validation Validation object
  1094. * @throws Kohana_Exception
  1095. * @return ORM
  1096. */
  1097. public function create(Validation $validation = NULL)
  1098. {
  1099. if ($this->_loaded)
  1100. throw new Kohana_Exception('Cannot create :model model because it is already loaded.', array(':model' => $this->_object_name));
  1101. // Require model validation before saving
  1102. if ( ! $this->_valid OR $validation)
  1103. {
  1104. $this->check($validation);
  1105. }
  1106. $data = array();
  1107. foreach ($this->_changed as $column)
  1108. {
  1109. // Generate list of column => values
  1110. $data[$column] = $this->_object[$column];
  1111. }
  1112. if (is_array($this->_created_column))
  1113. {
  1114. // Fill the created column
  1115. $column = $this->_created_column['column'];
  1116. $format = $this->_created_column['format'];
  1117. $data[$column] = $this->_object[$column] = ($format === TRUE) ? time() : date($format);
  1118. }
  1119. $result = DB::insert($this->_table_name)
  1120. ->columns(array_keys($data))
  1121. ->values(array_values($data))
  1122. ->execute($this->_db);
  1123. if ( ! array_key_exists($this->_primary_key, $data))
  1124. {
  1125. // Load the insert id as the primary key if it was left out
  1126. $this->_object[$this->_primary_key] = $this->_primary_key_value = $result[0];
  1127. }
  1128. else
  1129. {
  1130. $this->_primary_key_value = $this->_object[$this->_primary_key];
  1131. }
  1132. // Object is now loaded and saved
  1133. $this->_loaded = $this->_saved = TRUE;
  1134. // All changes have been saved
  1135. $this->_changed = array();
  1136. $this->_original_values = $this->_object;
  1137. return $this;
  1138. }
  1139. /**
  1140. * Updates a single record or multiple records
  1141. *
  1142. * @chainable
  1143. * @param Validation $validation Validation object
  1144. * @throws Kohana_Exception
  1145. * @return ORM
  1146. */
  1147. public function update(Validation $validation = NULL)
  1148. {
  1149. if ( ! $this->_loaded)
  1150. throw new Kohana_Exception('Cannot update :model model because it is not loaded.', array(':model' => $this->_object_name));
  1151. // Run validation if the model isn't valid or we have additional validation rules.
  1152. if ( ! $this->_valid OR $validation)
  1153. {
  1154. $this->check($validation);
  1155. }
  1156. if (empty($this->_changed))
  1157. {
  1158. // Nothing to update
  1159. return $this;
  1160. }
  1161. $data = array();
  1162. foreach ($this->_changed as $column)
  1163. {
  1164. // Compile changed data
  1165. $data[$column] = $this->_object[$column];
  1166. }
  1167. if (is_array($this->_updated_column))
  1168. {
  1169. // Fill the updated column
  1170. $column = $this->_updated_column['column'];
  1171. $format = $this->_updated_column['format'];
  1172. $data[$column] = $this->_object[$column] = ($format === TRUE) ? time() : date($format);
  1173. }
  1174. // Use primary key value
  1175. $id = $this->pk();
  1176. // Update a single record
  1177. DB::update($this->_table_name)
  1178. ->set($data)
  1179. ->where($this->_primary_key, '=', $id)
  1180. ->execute($this->_db);
  1181. if (isset($data[$this->_primary_key]))
  1182. {
  1183. // Primary key was changed, reflect it
  1184. $this->_primary_key_value = $data[$this->_primary_key];
  1185. }
  1186. // Object has been saved
  1187. $this->_saved = TRUE;
  1188. // All changes have been saved
  1189. $this->_changed = array();
  1190. $this->_original_values = $this->_object;
  1191. return $this;
  1192. }
  1193. /**
  1194. * Updates or Creates the record depending on loaded()
  1195. *
  1196. * @chainable
  1197. * @param Validation $validation Validation object
  1198. * @return ORM
  1199. */
  1200. public function save(Validation $validation = NULL)
  1201. {
  1202. return $this->loaded() ? $this->update($validation) : $this->create($validation);
  1203. }
  1204. /**
  1205. * Deletes a single record while ignoring relationships.
  1206. *
  1207. * @chainable
  1208. * @throws Kohana_Exception
  1209. * @return ORM
  1210. */
  1211. public function delete()
  1212. {
  1213. if ( ! $this->_loaded)
  1214. throw new Kohana_Exception('Cannot delete :model model because it is not loaded.', array(':model' => $this->_object_name));
  1215. // Use primary key value
  1216. $id = $this->pk();
  1217. // Delete the object
  1218. DB::delete($this->_table_name)
  1219. ->where($this->_primary_key, '=', $id)
  1220. ->execute($this->_db);
  1221. return $this->clear();
  1222. }
  1223. /**
  1224. * Tests if this object has a relationship to a different model,
  1225. * or an array of different models. When providing far keys, the number
  1226. * of relations must equal the number of keys.
  1227. *
  1228. *
  1229. * // Check if $model has the login role
  1230. * $model->has('roles', ORM::factory('role', array('name' => 'login')));
  1231. * // Check for the login role if you know the roles.id is 5
  1232. * $model->has('roles', 5);
  1233. * // Check for all of the following roles
  1234. * $model->has('roles', array(1, 2, 3, 4));
  1235. * // Check if $model has any roles
  1236. * $model->has('roles')
  1237. *
  1238. * @param string $alias Alias of the has_many "through" relationship
  1239. * @param mixed $far_keys Related model, primary key, or an array of primary keys
  1240. * @return boolean
  1241. */
  1242. public function has($alias, $far_keys = NULL)
  1243. {
  1244. $count = $this->count_relations($alias, $far_keys);
  1245. if ($far_keys === NULL)
  1246. {
  1247. return (bool) $count;
  1248. }
  1249. else
  1250. {
  1251. return $count === count($far_keys);
  1252. }
  1253. }
  1254. /**
  1255. * Tests if this object has a relationship to a different model,
  1256. * or an array of different models. When providing far keys, this function
  1257. * only checks that at least one of the relationships is satisfied.
  1258. *
  1259. * // Check if $model has the login role
  1260. * $model->has('roles', ORM::factory('role', array('name' => 'login')));
  1261. * // Check for the login role if you know the roles.id is 5
  1262. * $model->has('roles', 5);
  1263. * // Check for any of the following roles
  1264. * $model->has('roles', array(1, 2, 3, 4));
  1265. * // Check if $model has any roles
  1266. * $model->has('roles')
  1267. *
  1268. * @param string $alias Alias of the has_many "through" relationship
  1269. * @param mixed $far_keys Related model, primary key, or an array of primary keys
  1270. * @return boolean
  1271. */
  1272. public function has_any($alias, $far_keys = NULL)
  1273. {
  1274. return (bool) $this->count_relations($alias, $far_keys);
  1275. }
  1276. /**
  1277. * Returns the number of relationships
  1278. *
  1279. * // Counts the number of times the login role is attached to $model
  1280. * $model->has('roles', ORM::factory('role', array('name' => 'login')));
  1281. * // Counts the number of times role 5 is attached to $model
  1282. * $model->has('roles', 5);
  1283. * // Counts the number of times any of roles 1, 2, 3, or 4 are attached to
  1284. * // $model
  1285. * $model->has('roles', array(1, 2, 3, 4));
  1286. * // Counts the number roles attached to $model
  1287. * $model->has('roles')
  1288. *
  1289. * @param string $alias Alias of the has_many "through" relationship
  1290. * @param mixed $far_keys Related model, primary key, or an array of primary keys
  1291. * @return integer
  1292. */
  1293. public function count_relations($alias, $far_keys = NULL)
  1294. {
  1295. if ($far_keys === NULL)
  1296. {
  1297. return (int) DB::select(array(DB::expr('COUNT(*)'), 'records_found'))
  1298. ->from($this->_has_many[$alias]['through'])
  1299. ->where($this->_has_many[$alias]['foreign_key'], '=', $this->pk())
  1300. ->execute($this->_db)->get('records_found');
  1301. }
  1302. $far_keys = ($far_keys instanceof ORM) ? $far_keys->pk() : $far_keys;
  1303. // We need an array to simplify the logic
  1304. $far_keys = (array) $far_keys;
  1305. // Nothing to check if the model isn't loaded or we don't have any far_keys
  1306. if ( ! $far_keys OR ! $this->_loaded)
  1307. return 0;
  1308. $count = (int) DB::select(array(DB::expr('COUNT(*)'), 'records_found'))
  1309. ->from($this->_has_many[$alias]['through'])
  1310. ->where($this->_has_many[$alias]['foreign_key'], '=', $this->pk())
  1311. ->where($this->_has_many[$alias]['far_key'], 'IN', $far_keys)
  1312. ->execute($this->_db)->get('records_found');
  1313. // Rows found need to match the rows searched
  1314. return (int) $count;
  1315. }
  1316. /**
  1317. * Adds a new relationship to between this model and another.
  1318. *
  1319. * // Add the login role using a model instance
  1320. * $model->add('roles', ORM::factory('role', array('name' => 'login')));
  1321. * // Add the login role if you know the roles.id is 5
  1322. * $model->add('roles', 5);
  1323. * // Add multiple roles (for example, from checkboxes on a form)
  1324. * $model->add('roles', array(1, 2, 3, 4));
  1325. *
  1326. * @param string $alias Alias of the has_many "through" relationship
  1327. * @param mixed $far_keys Related model, primary key, or an array of primary keys
  1328. * @return ORM
  1329. */
  1330. public function add($alias, $far_keys)
  1331. {
  1332. $far_keys = ($far_keys instanceof ORM) ? $far_keys->pk() : $far_keys;
  1333. $columns = array($this->_has_many[$alias]['foreign_key'], $this->_has_many[$alias]['far_key']);
  1334. $foreign_key = $this->pk();
  1335. $query = DB::insert($this->_has_many[$alias]['through'], $columns);
  1336. foreach ( (array) $far_keys as $key)
  1337. {
  1338. $query->values(array($foreign_key, $key));
  1339. }
  1340. $query->execute($this->_db);
  1341. return $this;
  1342. }
  1343. /**
  1344. * Removes a relationship between this model and another.
  1345. *
  1346. * // Remove a role using a model instance
  1347. * $model->remove('roles', ORM::factory('role', array('name' => 'login')));
  1348. * // Remove the role knowing the primary key
  1349. * $model->remove('roles', 5);
  1350. * // Remove multiple roles (for example, from checkboxes on a form)
  1351. * $model->remove('roles', array(1, 2, 3, 4));
  1352. * // Remove all related roles
  1353. * $model->remove('roles');
  1354. *
  1355. * @param string $alias Alias of the has_many "through" relationship
  1356. * @param mixed $far_keys Related model, primary key, or an array of primary keys
  1357. * @return ORM
  1358. */
  1359. public function remove($alias, $far_keys = NULL)
  1360. {
  1361. $far_keys = ($far_keys instanceof ORM) ? $far_keys->pk() : $far_keys;
  1362. $query = DB::delete($this->_has_many[$alias]['through'])
  1363. ->where($this->_has_many[$alias]['foreign_key'], '=', $this->pk());
  1364. if ($far_keys !== NULL)
  1365. {
  1366. // Remove all the relationships in the array
  1367. $query->where($this->_has_many[$alias]['far_key'], 'IN', (array) $far_keys);
  1368. }
  1369. $query->execute($this->_db);
  1370. return $this;
  1371. }
  1372. /**
  1373. * Count the number of records in the table.
  1374. *
  1375. * @return integer
  1376. */
  1377. public function count_all()
  1378. {
  1379. $selects = array();
  1380. foreach ($this->_db_pending as $key => $method)
  1381. {
  1382. if ($method['name'] == 'select')
  1383. {
  1384. // Ignore any selected columns for now
  1385. $selects[] = $method;
  1386. unset($this->_db_pending[$key]);
  1387. }
  1388. }
  1389. if ( ! empty($this->_load_with))
  1390. {
  1391. foreach ($this->_load_with as $alias)
  1392. {
  1393. // Bind relationship
  1394. $this->with($alias);
  1395. }
  1396. }
  1397. $this->_build(Database::SELECT);
  1398. $records = $this->_db_builder->from(array($this->_table_name, $this->_object_name))
  1399. ->select(array(DB::expr('COUNT(*)'), 'records_found'))
  1400. ->execute($this->_db)
  1401. ->get('records_found');
  1402. // Add back in selected columns
  1403. $this->_db_pending += $selects;
  1404. $this->reset();
  1405. // Return the total number of records in a table
  1406. return $records;
  1407. }
  1408. /**
  1409. * Proxy method to Database list_columns.
  1410. *
  1411. * @return array
  1412. */
  1413. public function list_columns()
  1414. {
  1415. // Proxy to database
  1416. return $this->_db->list_columns($this->_table_name);
  1417. }
  1418. /**
  1419. * Returns an ORM model for the given one-one related alias
  1420. *
  1421. * @param string $alias Alias name
  1422. * @return ORM
  1423. */
  1424. protected function _related($alias)
  1425. {
  1426. if (isset($this->_related[$alias]))
  1427. {
  1428. return $this->_related[$alias];
  1429. }
  1430. elseif (isset($this->_has_one[$alias]))
  1431. {
  1432. return $this->_related[$alias] = ORM::factory($this->_has_one[$alias]['model']);
  1433. }
  1434. elseif (isset($this->_belongs_to[$alias]))
  1435. {
  1436. return $this->_related[$alias] = ORM::factory($this->_belongs_to[$alias]['model']);
  1437. }
  1438. else
  1439. {
  1440. return FALSE;
  1441. }
  1442. }
  1443. /**
  1444. * Returns the value of the primary key
  1445. *
  1446. * @return mixed Primary key
  1447. */
  1448. public function pk()
  1449. {
  1450. return $this->_primary_key_value;
  1451. }
  1452. /**
  1453. * Returns last executed query
  1454. *
  1455. * @return string
  1456. */
  1457. public function last_query()
  1458. {
  1459. return $this->_db->last_query;
  1460. }
  1461. /**
  1462. * Clears query builder. Passing FALSE is useful to keep the existing
  1463. * query conditions for another query.
  1464. *
  1465. * @param bool $next Pass FALSE to avoid resetting on the next call
  1466. * @return ORM
  1467. */
  1468. public function reset($next = TRUE)
  1469. {
  1470. if ($next AND $this->_db_reset)
  1471. {
  1472. $this->_db_pending = array();
  1473. $this->_db_applied = array();
  1474. $this->_db_builder = NULL;
  1475. $this->_with_applied = array();
  1476. }
  1477. // Reset on the next call?
  1478. $this->_db_reset = $next;
  1479. return $this;
  1480. }
  1481. protected function _serialize_value($value)
  1482. {
  1483. return json_encode($value);
  1484. }
  1485. protected function _unserialize_value($value)
  1486. {
  1487. return json_decode($value, TRUE);
  1488. }
  1489. public function object_name()
  1490. {
  1491. return $this->_object_name;
  1492. }
  1493. public function object_plural()
  1494. {
  1495. return $this->_object_plural;
  1496. }
  1497. public function loaded()
  1498. {
  1499. return $this->_loaded;
  1500. }
  1501. public function saved()
  1502. {
  1503. return $this->_saved;
  1504. }
  1505. public function primary_key()
  1506. {
  1507. return $this->_primary_key;
  1508. }
  1509. public function table_name()
  1510. {
  1511. return $this->_table_name;
  1512. }
  1513. public function table_columns()
  1514. {
  1515. return $this->_table_columns;
  1516. }
  1517. public function has_one()
  1518. {
  1519. return $this->_has_one;
  1520. }
  1521. public function belongs_to()
  1522. {
  1523. return $this->_belongs_to;
  1524. }
  1525. public function has_many()
  1526. {
  1527. return $this->_has_many;
  1528. }
  1529. public function load_with()
  1530. {
  1531. return $this->_load_with;
  1532. }
  1533. public function original_values()
  1534. {
  1535. return $this->_original_values;
  1536. }
  1537. public function created_column()
  1538. {
  1539. return $this->_created_column;
  1540. }
  1541. public function updated_column()
  1542. {
  1543. return $this->_updated_column;
  1544. }
  1545. public function validation()
  1546. {
  1547. if ( ! isset($this->_validation))
  1548. {
  1549. // Initialize the validation object
  1550. $this->_validation();
  1551. }
  1552. return $this->_validation;
  1553. }
  1554. public function object()
  1555. {
  1556. return $this->_object;
  1557. }
  1558. public function errors_filename()
  1559. {
  1560. return $this->_errors_filename;
  1561. }
  1562. /**
  1563. * Alias of and_where()
  1564. *
  1565. * @param mixed $column column name or array($column, $alias) or object
  1566. * @param string $op logic operator
  1567. * @param mixed $value column value
  1568. * @return $this
  1569. */
  1570. public function where($column, $op, $value)
  1571. {
  1572. // Add pending database call which is executed after query type is determined
  1573. $this->_db_pending[] = array(
  1574. 'name' => 'where',
  1575. 'args' => array($column, $op, $value),
  1576. );
  1577. return $this;
  1578. }
  1579. /**
  1580. * Creates a new "AND WHERE" condition for the query.
  1581. *
  1582. * @param mixed $column column name or array($column, $alias) or object
  1583. * @param string $op logic operator
  1584. * @param mixed $value column value
  1585. * @return $this
  1586. */
  1587. public function and_where($column, $op, $value)
  1588. {
  1589. // Add pending database call which is executed after query type is determined
  1590. $this->_db_pending[] = array(
  1591. 'name' => 'and_where',
  1592. 'args' => array($column, $op, $value),
  1593. );
  1594. return $this;
  1595. }
  1596. /**
  1597. * Creates a new "OR WHERE" condition for the query.
  1598. *
  1599. * @param mixed $column column name or array($column, $alias) or object
  1600. * @param string $op logic operator
  1601. * @param mixed $value column value
  1602. * @return $this
  1603. */
  1604. public function or_where($column, $op, $value)
  1605. {
  1606. // Add pending database call which is executed after query type is determined
  1607. $this->_db_pending[] = array(
  1608. 'name' => 'or_where',
  1609. 'args' => array($column, $op, $value),
  1610. );
  1611. return $this;
  1612. }
  1613. /**
  1614. * Alias of and_where_open()
  1615. *
  1616. * @return $this
  1617. */
  1618. public function where_open()
  1619. {
  1620. return $this->and_where_open();
  1621. }
  1622. /**
  1623. * Opens a new "AND WHERE (...)" grouping.
  1624. *
  1625. * @return $this
  1626. */
  1627. public function and_where_open()
  1628. {
  1629. // Add pending database call which is executed after query type is determined
  1630. $this->_db_pending[] = array(
  1631. 'name' => 'and_where_open',
  1632. 'args' => array(),
  1633. );
  1634. return $this;
  1635. }
  1636. /**
  1637. * Opens a new "OR WHERE (...)" grouping.
  1638. *
  1639. * @return $this
  1640. */
  1641. public function or_where_open()
  1642. {
  1643. // Add pending database call which is executed after query type is determined
  1644. $this->_db_pending[] = array(
  1645. 'name' => 'or_where_open',
  1646. 'args' => array(),
  1647. );
  1648. return $this;
  1649. }
  1650. /**
  1651. * Closes an open "AND WHERE (...)" grouping.
  1652. *
  1653. * @return $this
  1654. */
  1655. public function where_close()
  1656. {
  1657. return $this->and_where_close();
  1658. }
  1659. /**
  1660. * Closes an open "AND WHERE (...)" grouping.
  1661. *
  1662. * @return $this
  1663. */
  1664. public function and_where_close()
  1665. {
  1666. // Add pending database call which is executed after query type is determined
  1667. $this->_db_pending[] = array(
  1668. 'name' => 'and_where_close',
  1669. 'args' => array(),
  1670. );
  1671. return $this;
  1672. }
  1673. /**
  1674. * Closes an open "OR WHERE (...)" grouping.
  1675. *
  1676. * @return $this
  1677. */
  1678. public function or_where_close()
  1679. {
  1680. // Add pending database call which is executed after query type is determined
  1681. $this->_db_pending[] = array(
  1682. 'name' => 'or_where_close',
  1683. 'args' => array(),
  1684. );
  1685. return $this;
  1686. }
  1687. /**
  1688. * Applies sorting with "ORDER BY ..."
  1689. *
  1690. * @param mixed $column column name or array($column, $alias) or object
  1691. * @param string $direction direction of sorting
  1692. * @return $this
  1693. */
  1694. public function order_by($column, $direction = NULL)
  1695. {
  1696. // Add pending database call which is executed after query type is determined
  1697. $this->_db_pending[] = array(
  1698. 'name' => 'order_by',
  1699. 'args' => array($column, $direction),
  1700. );
  1701. return $this;
  1702. }
  1703. /**
  1704. * Return up to "LIMIT ..." results
  1705. *
  1706. * @param integer $number maximum results to return
  1707. * @return $this
  1708. */
  1709. public function limit($number)
  1710. {
  1711. // Add pending database call which is executed after query type is determined
  1712. $this->_db_pending[] = array(
  1713. 'name' => 'limit',
  1714. 'args' => array($number),
  1715. );
  1716. return $this;
  1717. }
  1718. /**
  1719. * Enables or disables selecting only unique columns using "SELECT DISTINCT"
  1720. *
  1721. * @param boolean $value enable or disable distinct columns
  1722. * @return $this
  1723. */
  1724. public function distinct($value)
  1725. {
  1726. // Add pending database call which is executed after query type is determined
  1727. $this->_db_pending[] = array(
  1728. 'name' => 'distinct',
  1729. 'args' => array($value),
  1730. );
  1731. return $this;
  1732. }
  1733. /**
  1734. * Choose the columns to select from.
  1735. *
  1736. * @param mixed $columns column name or array($column, $alias) or object
  1737. * @param ...
  1738. * @return $this
  1739. */
  1740. public function select($columns = NULL)
  1741. {
  1742. $columns = func_get_args();
  1743. // Add pending database call which is executed after query type is determined
  1744. $this->_db_pending[] = array(
  1745. 'name' => 'select',
  1746. 'args' => $columns,
  1747. );
  1748. return $this;
  1749. }
  1750. /**
  1751. * Choose the tables to select "FROM ..."
  1752. *
  1753. * @param mixed $tables table name or array($table, $alias) or object
  1754. * @param ...
  1755. * @return $this
  1756. */
  1757. public function from($tables)
  1758. {
  1759. $tables = func_get_args();
  1760. // Add pending database call which is executed after query type is determined
  1761. $this->_db_pending[] = array(
  1762. 'name' => 'from',
  1763. 'args' => $tables,
  1764. );
  1765. return $this;
  1766. }
  1767. /**
  1768. * Adds addition tables to "JOIN ...".
  1769. *
  1770. * @param mixed $table column name or array($column, $alias) or object
  1771. * @param string $type join type (LEFT, RIGHT, INNER, etc)
  1772. * @return $this
  1773. */
  1774. public function join($table, $type = NULL)
  1775. {
  1776. // Add pending database call which is executed after query type is determined
  1777. $this->_db_pending[] = array(
  1778. 'name' => 'join',
  1779. 'args' => array($table, $type),
  1780. );
  1781. return $this;
  1782. }
  1783. /**
  1784. * Adds "ON ..." conditions for the last created JOIN statement.
  1785. *
  1786. * @param mixed $c1 column name or array($column, $alias) or object
  1787. * @param string $op logic operator
  1788. * @param mixed $c2 column name or array($column, $alias) or object
  1789. * @return $this
  1790. */
  1791. public function on($c1, $op, $c2)
  1792. {
  1793. // Add pending database call which is executed after query type is determined
  1794. $this->_db_pending[] = array(
  1795. 'name' => 'on',
  1796. 'args' => array($c1, $op, $c2),
  1797. );
  1798. return $this;
  1799. }
  1800. /**
  1801. * Creates a "GROUP BY ..." filter.
  1802. *
  1803. * @param mixed $columns column name or array($column, $alias) or object
  1804. * @param ...
  1805. * @return $this
  1806. */
  1807. public function group_by($columns)
  1808. {
  1809. $columns = func_get_args();
  1810. // Add pending database call which is executed after query type is determined
  1811. $this->_db_pending[] = array(
  1812. 'name' => 'group_by',
  1813. 'args' => $columns,
  1814. );
  1815. return $this;
  1816. }
  1817. /**
  1818. * Alias of and_having()
  1819. *
  1820. * @param mixed $column column name or array($column, $alias) or object
  1821. * @param string $op logic operator
  1822. * @param mixed $value column value
  1823. * @return $this
  1824. */
  1825. public function having($column, $op, $value = NULL)
  1826. {
  1827. return $this->and_having($column, $op, $value);
  1828. }
  1829. /**
  1830. * Creates a new "AND HAVING" condition for the query.
  1831. *
  1832. * @param mixed $column column name or array($column, $alias) or object
  1833. * @param string $op logic operator
  1834. * @param mixed $value column value
  1835. * @return $this
  1836. */
  1837. public function and_having($column, $op, $value = NULL)
  1838. {
  1839. // Ad…

Large files files are truncated, but you can click here to view the full file