<?php namespace System\DB; abstract class Eloquent { /** * Indicates if the model exists in the database. * * @var bool */ public $exists = false; /** * The model attributes. * * @var array */ public $attributes = array(); /** * The model's dirty attributes. * * @var array */ public $dirty = array(); /** * The model's ignored attributes. * * Ignored attributes will not be saved to the database, and * are primarily used to hold relationships. * * @var array */ public $ignore = array(); /** * The relationships that should be eagerly loaded. * * @var array */ public $includes = array(); /** * The relationship type the model is currently resolving. * * @var string */ public $relating; /** * The foreign key of the "relating" relationship. * * @var string */ public $relating_key; /** * The table name of the model being resolved. Used during many-to-many eager loading. * * @var string */ public $relating_table; /** * The model query instance. * * @var Query */ public $query; /** * Create a new model instance and set the relationships * that should be eagerly loaded. * * @return mixed */ public static function with() { $model = Eloquent\Factory::make(get_called_class()); $model->includes = func_get_args(); return $model; } /** * Get a model by the primary key. * * @param int $id * @return mixed */ public static function find($id) { return Eloquent\Factory::make(get_called_class())->where('id', '=', $id)->first(); } /** * Get an array of models from the database. * * @return array */ private function _get() { return Eloquent\Hydrate::from($this); } /** * Get the first model result * * @return mixed */ private function _first() { $results = Eloquent\Hydrate::from($this->take(1)); if (count($results) > 0) { reset($results); return current($results); } } /** * Retrieve the query for a 1:1 relationship. * * @param string $model * @param string $foreign_key * @return mixed */ public function has_one($model, $foreign_key = null) { return Eloquent\Relate::has_one($model, $foreign_key, $this); } /** * Retrieve the query for a 1:* relationship. * * @param string $model * @param string $foreign_key * @return mixed */ public function has_many($model, $foreign_key = null) { return Eloquent\Relate::has_many($model, $foreign_key, $this); } /** * Retrieve the query for a 1:1 belonging relationship. * * @param string $model * @return mixed */ public function belongs_to($model) { // ----------------------------------------------------- // Get the calling function name. // ----------------------------------------------------- list(, $caller) = debug_backtrace(false); return Eloquent\Relate::belongs_to($caller, $model, $this); } /** * Retrieve the query for a *:* relationship. * * @param string $model * @param string $table * @return mixed */ public function has_many_and_belongs_to($model, $table = null) { return Eloquent\Relate::has_many_and_belongs_to($model, $table, $this); } /** * Save the model to the database. * * @return bool */ public function save() { // ----------------------------------------------------- // If the model doesn't have any dirty attributes, there // is no need to save it to the database. // ----------------------------------------------------- if ($this->exists and count($this->dirty) == 0) { return true; } $result = Eloquent\Warehouse::put($this); // ----------------------------------------------------- // The dirty attributes can be cleared after each save. // ----------------------------------------------------- $this->dirty = array(); return $result; } /** * Delete a model from the database. */ public function delete($id = null) { // ----------------------------------------------------- // If the method is being called from an existing model, // only delete that model from the database. // ----------------------------------------------------- if ($this->exists) { return Eloquent\Warehouse::forget($this); } return $this->query->delete($id); } /** * Magic method for retrieving model attributes. */ public function __get($key) { // ----------------------------------------------------- // Check the ignored attributes first. // ----------------------------------------------------- if (array_key_exists($key, $this->ignore)) { return $this->ignore[$key]; } // ----------------------------------------------------- // Is the attribute actually a relationship? // ----------------------------------------------------- if (method_exists($this, $key)) { // ----------------------------------------------------- // Get the query / model for the relationship. // ----------------------------------------------------- $model = $this->$key(); return ($this->relating == 'has_one' or $this->relating == 'belongs_to') ? $this->ignore[$key] = $model->first() : $this->ignore[$key] = $model->get(); } return (array_key_exists($key, $this->attributes)) ? $this->attributes[$key] : null; } /** * Magic Method for setting model attributes. */ public function __set($key, $value) { // ----------------------------------------------------- // Is the key actually a relationship? // ----------------------------------------------------- if (method_exists($this, $key)) { $this->ignore[$key] = $value; } else { $this->attributes[$key] = $value; $this->dirty[$key] = $value; } } /** * Magic Method for determining if a model attribute is set. */ public function __isset($key) { return (array_key_exists($key, $this->attributes) or array_key_exists($key, $this->ignore)); } /** * Magic Method for unsetting model attributes. */ public function __unset($key) { unset($this->attributes[$key]); unset($this->ignore[$key]); unset($this->dirty[$key]); } /** * Magic Method for handling dynamic method calls. */ public function __call($method, $parameters) { if ($method == 'get') { return $this->_get(); } if ($method == 'first') { return $this->_first(); } // ----------------------------------------------------- // If the method is an aggregate function, just return // the aggregate value from the query. // ----------------------------------------------------- if (in_array($method, array('count', 'sum', 'min', 'max', 'avg'))) { return call_user_func_array(array($this->query, $method), $parameters); } // ----------------------------------------------------- // Pass the method call to the query instance. // ----------------------------------------------------- call_user_func_array(array($this->query, $method), $parameters); return $this; } /** * Magic Method for handling dynamic static method calls. */ public static function __callStatic($method, $parameters) { $model = Eloquent\Factory::make(get_called_class()); if ($method == 'get') { return $model->_get(); } if ($method == 'first') { return $model->_first(); } // ----------------------------------------------------- // If the method is an aggregate function, just return // the aggregate value from the query. // ----------------------------------------------------- if (in_array($method, array('count', 'sum', 'min', 'max', 'avg'))) { return call_user_func_array(array($model->query, $method), $parameters); } // ----------------------------------------------------- // Pass the method call to the query instance. // ----------------------------------------------------- call_user_func_array(array($model->query, $method), $parameters); return $model; } }