diff --git a/laravel/database/eloquent/model.php b/laravel/database/eloquent/model.php index 8946bce5..bde5ac46 100644 --- a/laravel/database/eloquent/model.php +++ b/laravel/database/eloquent/model.php @@ -82,6 +82,13 @@ abstract class Model { */ public static $sequence; + /** + * The default number of models to show per page when paginating. + * + * @var int + */ + public static $per_page = 20; + /** * Create a new Eloquent model instance. * @@ -150,6 +157,23 @@ public function fill($attributes) return $this; } + /** + * Create a new model and store it in the database. + * + * If save is successful, the model will be returned, otherwise false. + * + * @param array $attributes + * @return Model|false + */ + public static function create($attributes) + { + $model = new static($attributes); + + $success = $model->save(); + + return ($success) ? $model : false; + } + /** * Find a model by its primary key. * @@ -320,7 +344,7 @@ public function save() */ protected function timestamp() { - $this->updated_at = static::get_timestamp(); + $this->updated_at = $this->get_timestamp(); if ( ! $this->exists) $this->created_at = $this->updated_at; } @@ -330,7 +354,7 @@ protected function timestamp() * * @return mixed */ - protected static function get_timestamp() + public function get_timestamp() { return date('Y-m-d H:i:s'); } @@ -502,7 +526,7 @@ public function __call($method, $parameters) // If the method is actually the name of a static property on the model we'll // return the value of the static property. This makes it convenient for // relationships to access these values off of the instances. - if (in_array($method, array('key', 'table', 'connection', 'sequence'))) + if (in_array($method, array('key', 'table', 'connection', 'sequence', 'per_page'))) { return static::$$method; } diff --git a/laravel/database/eloquent/pivot.php b/laravel/database/eloquent/pivot.php index 92ea2e46..b98fc226 100644 --- a/laravel/database/eloquent/pivot.php +++ b/laravel/database/eloquent/pivot.php @@ -9,6 +9,13 @@ class Pivot extends Model { */ public $pivot_table; + /** + * Indicates if the model has update and creation timestamps. + * + * @var bool + */ + public static $timestamps = true; + /** * Create a new pivot table instance. * diff --git a/laravel/database/eloquent/query.php b/laravel/database/eloquent/query.php index c4848b2e..1894fe5f 100644 --- a/laravel/database/eloquent/query.php +++ b/laravel/database/eloquent/query.php @@ -29,8 +29,8 @@ class Query { * @var array */ public $passthru = array( - 'lists', 'only', 'insert', 'update', 'increment', 'decrement', - 'count', 'min', 'max', 'avg', 'sum' + 'lists', 'only', 'insert', 'insert_get_id', 'update', 'increment', + 'decrement', 'count', 'min', 'max', 'avg', 'sum', ); /** @@ -68,33 +68,28 @@ public function first($columns = array('*')) */ public function get($columns = array('*'), $include = true) { - $results = $this->hydrate($this->model, $this->table->get($columns)); + return $this->hydrate($this->model, $this->table->get($columns), $include); + } - if ($include) - { - foreach ($this->model_includes() as $relationship => $constraints) - { - // If the relationship is nested, we will skip laoding it here and let - // the load method parse and set the nested eager loads on the right - // relationship when it is getting ready to eager laod. - if (str_contains($relationship, '.')) - { - continue; - } + /** + * Get an array of paginated model results. + * + * @param int $per_page + * @param array $columns + * @return Paginator + */ + public function paginate($per_page = null, $columns = array('*')) + { + $per_page = $per_page ?: $this->model->per_page(); - $this->load($results, $relationship, $constraints); - } - } + // First we'll grab the Paginator instance and get the results. Then we can + // feed those raw database results into the hydrate method to get models + // for the results, which we'll set on the paginator and return it. + $paginator = $this->table->paginate($per_page, $columns); - // The many to many relationships may have pivot table column on them - // so we will call the "clean" method on the relationship to remove - // any pivot columns that are on the model. - if ($this instanceof Relationships\Has_Many_And_Belongs_To) - { - $this->pivot($results); - } + $paginator->results = $this->hydrate($this->model, $paginator->results); - return $results; + return $paginator; } /** @@ -104,7 +99,7 @@ public function get($columns = array('*'), $include = true) * @param array $results * @return array */ - public function hydrate($model, $results) + public function hydrate($model, $results, $include = true) { $class = get_class($model); @@ -120,6 +115,30 @@ public function hydrate($model, $results) $models[$result[$this->model->key()]] = new $class($result, true); } + if ($include and count($results) > 0) + { + foreach ($this->model_includes() as $relationship => $constraints) + { + // If the relationship is nested, we will skip laoding it here and let + // the load method parse and set the nested eager loads on the right + // relationship when it is getting ready to eager laod. + if (str_contains($relationship, '.')) + { + continue; + } + + $this->load($models, $relationship, $constraints); + } + } + + // The many to many relationships may have pivot table column on them + // so we will call the "clean" method on the relationship to remove + // any pivot columns that are on the model. + if ($this instanceof Relationships\Has_Many_And_Belongs_To) + { + $this->pivot($models); + } + return $models; } diff --git a/laravel/database/eloquent/relationships/has_many_and_belongs_to.php b/laravel/database/eloquent/relationships/has_many_and_belongs_to.php index 4ac55570..8c8abee1 100644 --- a/laravel/database/eloquent/relationships/has_many_and_belongs_to.php +++ b/laravel/database/eloquent/relationships/has_many_and_belongs_to.php @@ -23,7 +23,7 @@ class Has_Many_And_Belongs_To extends Relationship { * * @var array */ - protected $with = array(); + protected $with = array('created_at', 'updated_at'); /** * Create a new many to many relationship instance. @@ -73,25 +73,29 @@ public function results() /** * Insert a new record into the joining table of the association. * - * @param int $id + * @param int $id + * @param array $joining * @return bool */ - public function add($id) + public function add($id, $attributes = array()) { - return $this->insert_joining($this->join_record($id)); + $joining = array_merge($this->join_record($id), $attributes); + + return $this->insert_joining($joining); } /** * Insert a new record for the association. * * @param array $attributes + * @param array $joining * @return bool */ - public function insert($attributes) + public function insert($attributes, $joining = array()) { $id = $this->table->insert_get_id($attributes, $this->model->sequence()); - $result = $this->insert_joining($this->join_record($id)); + $result = $this->insert_joining(array_merge($this->join_record($id), $joining)); return is_numeric($id) and $result; } @@ -125,6 +129,13 @@ protected function join_record($id) */ protected function insert_joining($attributes) { + // All joining tables get creation and update timestamps automatically even though + // some developers may not need them. This just provides them if necessary since + // it would be a pain for the developer to maintain them manually. + $attributes['created_at'] = $this->model->get_timestamp(); + + $attributes['updated_at'] = $attributes['created_at']; + return $this->joining_table()->insert($attributes); } @@ -292,7 +303,12 @@ protected function pivot(&$results) */ public function with($columns) { - $this->with = (is_array($columns)) ? $columns : func_get_args(); + $columns = (is_array($columns)) ? $columns : func_get_args(); + + // The "with" array contains a couple of columns by default, so we will + // just merge in the developer specified columns here, and we'll make + // sure the values of the array are unique. + $this->with = array_unique(array_merge($this->with, $columns)); $this->set_select($this->foreign_key(), $this->other_key());