Commit 0a256970 authored by Jens Segers's avatar Jens Segers

Merge pull request #279 from jenssegers/embedded-models

New v2 release
parents 7534e6f9 94314570
This diff is collapsed.
<?php namespace Jenssegers\Mongodb\Auth;
use DateTime;
use MongoDate;
class DatabaseReminderRepository extends \Illuminate\Auth\Reminders\DatabaseReminderRepository {
/**
* Build the record payload for the table.
*
* @param string $email
* @param string $token
* @return array
*/
protected function getPayload($email, $token)
{
return array('email' => $email, 'token' => $token, 'created_at' => new MongoDate);
}
/**
* Determine if the reminder has expired.
*
......@@ -10,16 +25,22 @@ class DatabaseReminderRepository extends \Illuminate\Auth\Reminders\DatabaseRemi
*/
protected function reminderExpired($reminder)
{
// Convert to array so that we can pass it to the parent method
if (is_object($reminder))
// Convert MongoDate to a date string.
if ($reminder['created_at'] instanceof MongoDate)
{
$reminder = (array) $reminder;
$date = new DateTime;
$date->setTimestamp($reminder['created_at']->sec);
$reminder['created_at'] = $date->format('Y-m-d H:i:s');
}
// Convert the DateTime object that got saved to MongoDB
if (is_array($reminder['created_at']))
// Convert DateTime to a date string (backwards compatibility).
elseif (is_array($reminder['created_at']))
{
$reminder['created_at'] = $reminder['created_at']['date'] + $reminder['created_at']['timezone'];
$date = DateTime::__set_state($reminder['created_at']);
$reminder['created_at'] = $date->format('Y-m-d H:i:s');
}
return parent::reminderExpired($reminder);
......
......@@ -26,6 +26,7 @@ class Collection {
public function __construct(Connection $connection, MongoCollection $collection)
{
$this->connection = $connection;
$this->collection = $collection;
}
......@@ -38,29 +39,34 @@ class Collection {
*/
public function __call($method, $parameters)
{
$query = array();
// Build the query string.
$query = $parameters;
foreach ($query as &$param)
foreach ($parameters as $parameter)
{
try
{
$param = json_encode($param);
$query[] = json_encode($parameter);
}
catch (Exception $e)
{
$param = '{...}';
$query[] = '{...}';
}
}
$start = microtime(true);
// Execute the query.
$result = call_user_func_array(array($this->collection, $method), $parameters);
// Log the query.
$this->connection->logQuery(
$this->collection->getName() . '.' . $method . '(' . join(',', $query) . ')',
array(), $this->connection->getElapsedTime($start));
// Once we have run the query we will calculate the time that it took to run and
// then log the query, bindings, and execution time so we will report them on
// the event that the developer needs them. We'll log time in milliseconds.
$time = $this->connection->getElapsedTime($start);
// Convert the query to a readable string.
$queryString = $this->collection->getName() . '.' . $method . '(' . join(',', $query) . ')';
$this->connection->logQuery($queryString, array(), $time);
return $result;
}
......
......@@ -16,6 +16,146 @@ class Builder extends EloquentBuilder {
'count', 'min', 'max', 'avg', 'sum', 'exists', 'push', 'pull'
);
/**
* Update a record in the database.
*
* @param array $values
* @return int
*/
public function update(array $values)
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
if ($relation = $this->model->getParentRelation())
{
$relation->performUpdate($this->model, $values);
return 1;
}
return parent::update($values);
}
/**
* Insert a new record into the database.
*
* @param array $values
* @return bool
*/
public function insert(array $values)
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
if ($relation = $this->model->getParentRelation())
{
$relation->performInsert($this->model, $values);
return true;
}
return parent::insert($values);
}
/**
* Insert a new record and get the value of the primary key.
*
* @param array $values
* @param string $sequence
* @return int
*/
public function insertGetId(array $values, $sequence = null)
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
if ($relation = $this->model->getParentRelation())
{
$relation->performInsert($this->model, $values);
return $this->model->getKey();
}
return parent::insertGetId($values, $sequence);
}
/**
* Delete a record from the database.
*
* @return mixed
*/
public function delete()
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
if ($relation = $this->model->getParentRelation())
{
$relation->performDelete($this->model);
return $this->model->getKey();
}
return parent::delete();
}
/**
* Increment a column's value by a given amount.
*
* @param string $column
* @param int $amount
* @param array $extra
* @return int
*/
public function increment($column, $amount = 1, array $extra = array())
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
if ($relation = $this->model->getParentRelation())
{
$value = $this->model->{$column};
// When doing increment and decrements, Eloquent will automatically
// sync the original attributes. We need to change the attribute
// temporary in order to trigger an update query.
$this->model->{$column} = null;
$this->model->syncOriginalAttribute($column);
$result = $this->model->update(array($column => $value));
return $result;
}
return parent::increment($column, $amount, $extra);
}
/**
* Decrement a column's value by a given amount.
*
* @param string $column
* @param int $amount
* @param array $extra
* @return int
*/
public function decrement($column, $amount = 1, array $extra = array())
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
if ($relation = $this->model->getParentRelation())
{
$value = $this->model->{$column};
// When doing increment and decrements, Eloquent will automatically
// sync the original attributes. We need to change the attribute
// temporary in order to trigger an update query.
$this->model->{$column} = null;
$this->model->syncOriginalAttribute($column);
return $this->model->update(array($column => $value));
}
return parent::decrement($column, $amount, $extra);
}
/**
* Add the "has" condition where clause to the query.
*
......@@ -77,26 +217,12 @@ class Builder extends EloquentBuilder {
// Get raw results from the query builder.
$results = $this->query->raw($expression);
$connection = $this->model->getConnectionName();
// Convert MongoCursor results to a collection of models.
if ($results instanceof MongoCursor)
{
$results = iterator_to_array($results, false);
$models = array();
// Once we have the results, we can spin through them and instantiate a fresh
// model instance for each records we retrieved from the database. We will
// also set the proper connection name for the model after we create it.
foreach ($results as $result)
{
$models[] = $model = $this->model->newFromBuilder($result);
$model->setConnection($connection);
}
return $this->model->newCollection($models);
return $this->model->hydrate($results);
}
// The result is a single object.
......@@ -104,7 +230,7 @@ class Builder extends EloquentBuilder {
{
$model = $this->model->newFromBuilder($results);
$model->setConnection($connection);
$model->setConnection($this->model->getConnection());
return $model;
}
......
<?php namespace Jenssegers\Mongodb\Eloquent;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
class Collection extends EloquentCollection {
/**
* Simulate a get clause on the collection.
*
* @param mixed $key
* @param mixed $default
* @return mixed
*/
public function get($key = null, $default = null)
{
if (is_null($key) and is_null($default))
{
return $this;
}
return parent::get($key, $default);
}
/**
* Simulate a basic where clause on the collection.
*
* @param string $key
* @param string $operator
* @param mixed $value
* @param string $boolean
* @return $this
*/
public function where($key, $operator = null, $value = null)
{
// Here we will make some assumptions about the operator. If only 2 values are
// passed to the method, we will assume that the operator is an equals sign
// and keep going.
if (func_num_args() == 2)
{
list($value, $operator) = array($operator, '=');
}
return $this->filter(function($item) use ($key, $operator, $value)
{
$actual = $item->{$key};
switch ($operator)
{
case '<>':
case '!=':
return $actual != $value;
break;
case '>':
return $actual > $value;
break;
case '<':
return $actual < $value;
break;
case '>=':
return $actual >= $value;
break;
case '<=':
return $actual <= $value;
break;
case 'between':
return $actual >= $value[0] and $actual <= $value[1];
break;
case 'not between':
return $actual < $value[0] or $actual > $value[1];
break;
case 'in':
return in_array($actual, $value);
break;
case 'not in':
return ! in_array($actual, $value);
break;
case '=':
default:
return $actual == $value;
break;
}
});
}
/**
* Add a where between statement to the query.
*
* @param string $column
* @param array $values
* @param string $boolean
* @param bool $not
* @return $this
*/
public function whereBetween($column, array $values, $boolean = 'and', $not = false)
{
$type = $not ? 'not between' : 'between';
return $this->where($column, $type, $values);
}
/**
* Add a where not between statement to the query.
*
* @param string $column
* @param array $values
* @param string $boolean
* @return $this
*/
public function whereNotBetween($column, array $values, $boolean = 'and')
{
return $this->whereBetween($column, $values, $boolean, true);
}
/**
* Add a "where in" clause to the query.
*
* @param string $column
* @param mixed $values
* @param string $boolean
* @param bool $not
* @return $this
*/
public function whereIn($column, $values, $boolean = 'and', $not = false)
{
$type = $not ? 'not in' : 'in';
return $this->where($column, $type, $values);
}
/**
* Add a "where not in" clause to the query.
*
* @param string $column
* @param mixed $values
* @param string $boolean
* @return $this
*/
public function whereNotIn($column, $values, $boolean = 'and')
{
return $this->whereIn($column, $values, $boolean, true);
}
/**
* Add a "where null" clause to the query.
*
* @param string $column
* @param string $boolean
* @param bool $not
* @return $this
*/
public function whereNull($column, $boolean = 'and', $not = false)
{
return $this->where($column, '=', null);
}
/**
* Add a "where not null" clause to the query.
*
* @param string $column
* @param string $boolean
* @return $this
*/
public function whereNotNull($column, $boolean = 'and')
{
return $this->where($column, '!=', null);
}
/**
* Simulate order by clause on the collection.
*
* @param string $key
* @param string $direction
* @return $this
*/
public function orderBy($key, $direction = 'asc')
{
$descending = strtolower($direction) == 'desc';
return $this->sortBy($key, SORT_REGULAR, $descending);
}
/**
* Add an "order by" clause for a timestamp to the query.
*
* @param string $column
* @return $this
*/
public function latest($column = 'created_at')
{
return $this->orderBy($column, 'desc');
}
/**
* Add an "order by" clause for a timestamp to the query.
*
* @param string $column
* @return $this
*/
public function oldest($column = 'created_at')
{
return $this->orderBy($column, 'asc');
}
/**
* Set the "offset" value of the query.
*
* @param int $value
* @return $this
*/
public function offset($value)
{
$offset = max(0, $value);
return $this->slice($offset);
}
/**
* Alias to set the "offset" value of the query.
*
* @param int $value
* @return $this
*/
public function skip($value)
{
return $this->offset($value);
}
/**
* Set the "limit" value of the query.
*
* @param int $value
* @return $this
*/
public function limit($value)
{
return $this->take($value);
}
}
......@@ -4,6 +4,8 @@ use Illuminate\Database\Eloquent\Collection;
use Jenssegers\Mongodb\DatabaseManager as Resolver;
use Jenssegers\Mongodb\Eloquent\Builder;
use Jenssegers\Mongodb\Query\Builder as QueryBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Jenssegers\Mongodb\Relations\EmbedsOneOrMany;
use Jenssegers\Mongodb\Relations\EmbedsMany;
use Jenssegers\Mongodb\Relations\EmbedsOne;
......@@ -29,11 +31,11 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
protected $primaryKey = '_id';
/**
* The attributes that should be exposed for toArray and toJson.
* The parent relation instance.
*
* @var array
* @var Relation
*/
protected $exposed = array();
protected $parentRelation;
/**
* The connection resolver instance.
......@@ -88,7 +90,7 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
if (is_null($localKey))
{
$localKey = '_' . $relation;
$localKey = $relation;
}
if (is_null($foreignKey))
......@@ -124,7 +126,7 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
if (is_null($localKey))
{
$localKey = '_' . $relation;
$localKey = $relation;
}
if (is_null($foreignKey))
......@@ -220,7 +222,7 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
public function getAttribute($key)
{
// Check if the key is an array dot notation.
if (strpos($key, '.') !== false)
if (str_contains($key, '.'))
{
$attributes = array_dot($this->attributes);
......@@ -230,6 +232,32 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
}
}
$camelKey = camel_case($key);
// If the "attribute" exists as a method on the model, it may be an
// embedded model. If so, we need to return the result before it
// is handled by the parent method.
if (method_exists($this, $camelKey))
{
$relations = $this->$camelKey();
// This attribute matches an embedsOne or embedsMany relation so we need
// to return the relation results instead of the interal attributes.
if ($relations instanceof EmbedsOneOrMany)
{
// If the key already exists in the relationships array, it just means the
// relationship has already been loaded, so we'll just return it out of
// here because there is no need to query within the relations twice.
if (array_key_exists($key, $this->relations))
{
return $this->relations[$key];
}
// Get the relation results.
return $this->getRelationshipFromMethod($key, $camelKey);
}
}
return parent::getAttribute($key);
}
......@@ -241,12 +269,8 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
*/
protected function getAttributeFromArray($key)
{
if (array_key_exists($key, $this->attributes))
{
return $this->attributes[$key];
}
else if (strpos($key, '.') !== false)
// Support keys in dot notation.
if (str_contains($key, '.'))
{
$attributes = array_dot($this->attributes);
......@@ -255,6 +279,8 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
return $attributes[$key];
}
}
return parent::getAttributeFromArray($key);
}
/**
......@@ -270,9 +296,21 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
if ($key == '_id' and is_string($value))
{
$builder = $this->newBaseQueryBuilder();
$value = $builder->convertKey($value);
}
// Support keys in dot notation.
elseif (str_contains($key, '.'))
{
if (in_array($key, $this->getDates()) && $value)
{
$value = $this->fromDateTime($value);
}
array_set($this->attributes, $key, $value); return;
}
parent::setAttribute($key, $value);
}
......@@ -295,22 +333,6 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
{
$value = (string) $value;
}
// If the attribute starts with an underscore, it might be the
// internal array of embedded documents. In that case, we need
// to hide these from the output so that the relation-based
// attribute can take over.
else if (starts_with($key, '_') and ! in_array($key, $this->exposed))
{
$camelKey = camel_case($key);
// If we can find a method that responds to this relation we
// will remove it from the output.
if (method_exists($this, $camelKey))
{
unset($attributes[$key]);
}
}
}
return $attributes;
......@@ -345,9 +367,25 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
{
if ($parameters = func_get_args())
{
$unique = false;
if (count($parameters) == 3)
{
list($column, $values, $unique) = $parameters;
}
else
{
list($column, $values) = $parameters;
}
// Do batch push by default.
if ( ! is_array($values)) $values = array($values);
$query = $this->setKeysForSaveQuery($this->newQuery());
return call_user_func_array(array($query, 'push'), $parameters);
$this->pushAttributeValues($column, $values, $unique);
return $query->push($column, $values, $unique);
}
return parent::push();
......@@ -358,22 +396,87 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
*
* @return mixed
*/
public function pull()
public function pull($column, $values)
{
// Do batch pull by default.
if ( ! is_array($values)) $values = array($values);
$query = $this->setKeysForSaveQuery($this->newQuery());
return call_user_func_array(array($query, 'pull'), func_get_args());
$this->pullAttributeValues($column, $values);
return $query->pull($column, $values);
}
/**
* Set the exposed attributes for the model.
* Append one or more values to the underlying attribute value and sync with original.
*
* @param array $exposed
* @param string $column
* @param array $values
* @param bool $unique
* @return void
*/
public function setExposed(array $exposed)
protected function pushAttributeValues($column, array $values, $unique = false)
{
$current = $this->getAttributeFromArray($column) ?: array();
foreach ($values as $value)
{
// Don't add duplicate values when we only want unique values.
if ($unique and in_array($value, $current)) continue;
array_push($current, $value);
}
$this->attributes[$column] = $current;
$this->syncOriginalAttribute($column);
}
/**
* Rempove one or more values to the underlying attribute value and sync with original.
*
* @param string $column
* @param array $values
* @return void
*/
protected function pullAttributeValues($column, array $values)
{
$current = $this->getAttributeFromArray($column) ?: array();
foreach ($values as $value)
{
$keys = array_keys($current, $value);
foreach ($keys as $key)
{
unset($current[$key]);
}
}
$this->attributes[$column] = array_values($current);
$this->syncOriginalAttribute($column);
}
/**
* Set the parent relation.
*
* @param Relation $relation
*/
public function setParentRelation(Relation $relation)
{
$this->parentRelation = $relation;
}
/**
* Get the parent relation.
*
* @return Relation
*/
public function getParentRelation()
{
$this->exposed = $exposed;
return $this->parentRelation;
}
/**
......
......@@ -6,10 +6,11 @@ use MongoDate;
use DateTime;
use Closure;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Database\Query\Expression;
use Jenssegers\Mongodb\Connection;
class Builder extends \Illuminate\Database\Query\Builder {
class Builder extends QueryBuilder {
/**
* The database collection
......@@ -18,6 +19,20 @@ class Builder extends \Illuminate\Database\Query\Builder {
*/
protected $collection;
/**
* The column projections.
*
* @var array
*/
public $projections;
/**
* The cursor timeout value.
*
* @var int
*/
public $timeout;
/**
* All of the available clause operators.
*
......@@ -59,6 +74,32 @@ class Builder extends \Illuminate\Database\Query\Builder {
$this->connection = $connection;
}
/**
* Set the projections.
*
* @param array $columns
* @return $this
*/
public function project($columns)
{
$this->projections = is_array($columns) ? $columns : func_get_args();
return $this;
}
/**
* Set the cursor timeout in seconds.
*
* @param int $seconds
* @return $this
*/
public function timeout($seconds)
{
$this->timeout = $seconds;
return $this;
}
/**
* Execute a query for a single record by ID.
*
......@@ -71,6 +112,17 @@ class Builder extends \Illuminate\Database\Query\Builder {
return $this->where('_id', '=', $this->convertKey($id))->first($columns);
}
/**
* Execute the query as a "select" statement.
*
* @param array $columns
* @return array|static[]
*/
public function get($columns = array())
{
return parent::get($columns);
}
/**
* Execute the query as a fresh "select" statement.
*
......@@ -142,6 +194,7 @@ class Builder extends \Illuminate\Database\Query\Builder {
foreach ($this->columns as $column)
{
$key = str_replace('.', '_', $column);
$group[$key] = array('$last' => '$' . $column);
}
}
......@@ -155,6 +208,7 @@ class Builder extends \Illuminate\Database\Query\Builder {
if ($this->orders) $pipeline[] = array('$sort' => $this->orders);
if ($this->offset) $pipeline[] = array('$skip' => $this->offset);
if ($this->limit) $pipeline[] = array('$limit' => $this->limit);
if ($this->projections) $pipeline[] = array('$project' => $this->projections);
// Execute aggregation
$results = $this->collection->aggregate($pipeline);
......@@ -179,15 +233,24 @@ class Builder extends \Illuminate\Database\Query\Builder {
else
{
$columns = array();
// Convert select columns to simple projections.
foreach ($this->columns as $column)
{
$columns[$column] = true;
}
// Add custom projections.
if ($this->projections)
{
$columns = array_merge($columns, $this->projections);
}
// Execute query and get MongoCursor
$cursor = $this->collection->find($wheres, $columns);
// Apply order, offset and limit
if ($this->timeout) $cursor->timeout($this->timeout);
if ($this->orders) $cursor->sort($this->orders);
if ($this->offset) $cursor->skip($this->offset);
if ($this->limit) $cursor->limit($this->limit);
......@@ -313,17 +376,18 @@ class Builder extends \Illuminate\Database\Query\Builder {
// Since every insert gets treated like a batch insert, we will have to detect
// if the user is inserting a single document or an array of documents.
$batch = true;
foreach ($values as $value)
{
// As soon as we find a value that is not an array we assume the user is
// inserting a single document.
if (!is_array($value))
if ( ! is_array($value))
{
$batch = false; break;
}
}
if (!$batch) $values = array($values);
if ( ! $batch) $values = array($values);
// Batch insert
$result = $this->collection->batchInsert($values);
......@@ -344,7 +408,7 @@ class Builder extends \Illuminate\Database\Query\Builder {
if (1 == (int) $result['ok'])
{
if (!$sequence)
if (is_null($sequence))
{
$sequence = '_id';
}
......@@ -363,7 +427,13 @@ class Builder extends \Illuminate\Database\Query\Builder {
*/
public function update(array $values, array $options = array())
{
return $this->performUpdate(array('$set' => $values), $options);
// Use $set as default operator.
if ( ! starts_with(key($values), '$'))
{
$values = array('$set' => $values);
}
return $this->performUpdate($values, $options);
}
/**
......@@ -376,11 +446,9 @@ class Builder extends \Illuminate\Database\Query\Builder {
*/
public function increment($column, $amount = 1, array $extra = array(), array $options = array())
{
$query = array(
'$inc' => array($column => $amount)
);
$query = array('$inc' => array($column => $amount));
if (!empty($extra))
if ( ! empty($extra))
{
$query['$set'] = $extra;
}
......@@ -389,6 +457,7 @@ class Builder extends \Illuminate\Database\Query\Builder {
$this->where(function($query) use ($column)
{
$query->where($column, 'exists', false);
$query->orWhereNotNull($column);
});
......@@ -437,6 +506,7 @@ class Builder extends \Illuminate\Database\Query\Builder {
public function delete($id = null)
{
$wheres = $this->compileWheres();
$result = $this->collection->remove($wheres);
if (1 == (int) $result['ok'])
......@@ -490,7 +560,7 @@ class Builder extends \Illuminate\Database\Query\Builder {
}
// Create an expression for the given value
else if (!is_null($expression))
else if ( ! is_null($expression))
{
return new Expression($expression);
}
......@@ -511,10 +581,17 @@ class Builder extends \Illuminate\Database\Query\Builder {
// Use the addToSet operator in case we only want unique items.
$operator = $unique ? '$addToSet' : '$push';
// Check if we are pushing multiple values.
$batch = (is_array($value) and array_keys($value) === range(0, count($value) - 1));
if (is_array($column))
{
$query = array($operator => $column);
}
else if ($batch)
{
$query = array($operator => array($column => array('$each' => $value)));
}
else
{
$query = array($operator => array($column => $value));
......@@ -532,13 +609,19 @@ class Builder extends \Illuminate\Database\Query\Builder {
*/
public function pull($column, $value = null)
{
// Check if we passed an associative array.
$batch = (is_array($value) and array_keys($value) === range(0, count($value) - 1));
// If we are pulling multiple values, we need to use $pullAll.
$operator = $batch ? '$pullAll' : '$pull';
if (is_array($column))
{
$query = array('$pull' => $column);
$query = array($operator => $column);
}
else
{
$query = array('$pull' => array($column => $value));
$query = array($operator => array($column => $value));
}
return $this->performUpdate($query);
......@@ -552,7 +635,7 @@ class Builder extends \Illuminate\Database\Query\Builder {
*/
public function drop($columns)
{
if (!is_array($columns)) $columns = array($columns);
if ( ! is_array($columns)) $columns = array($columns);
$fields = array();
......@@ -585,13 +668,14 @@ class Builder extends \Illuminate\Database\Query\Builder {
*/
protected function performUpdate($query, array $options = array())
{
// Default options
$default = array('multiple' => true);
// Merge options and override default options
$options = array_merge($default, $options);
// Update multiple items by default.
if ( ! array_key_exists('multiple', $options))
{
$options['multiple'] = true;
}
$wheres = $this->compileWheres();
$result = $this->collection->update($wheres, $query, $options);
if (1 == (int) $result['ok'])
......@@ -682,7 +766,7 @@ class Builder extends \Illuminate\Database\Query\Builder {
}
// Convert id's.
if (isset($where['column']) and $where['column'] == '_id')
if (isset($where['column']) and ($where['column'] == '_id' or ends_with($where['column'], '._id')))
{
// Multiple values.
if (isset($where['values']))
......
<?php namespace Jenssegers\Mongodb\Relations;
use Jenssegers\Mongodb\Model;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\BelongsToMany as EloquentBelongsToMany;
......@@ -40,15 +40,58 @@ class BelongsToMany extends EloquentBelongsToMany {
}
}
/**
* Save a new model and attach it to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param array $joining
* @param bool $touch
* @return \Illuminate\Database\Eloquent\Model
*/
public function save(Model $model, array $joining = array(), $touch = true)
{
$model->save(array('touch' => false));
$this->attach($model, $joining, $touch);
return $model;
}
/**
* Create a new instance of the related model.
*
* @param array $attributes
* @param array $joining
* @param bool $touch
* @return \Illuminate\Database\Eloquent\Model
*/
public function create(array $attributes, array $joining = array(), $touch = true)
{
$instance = $this->related->newInstance($attributes);
// Once we save the related model, we need to attach it to the base model via
// through intermediate table so we'll use the existing "attach" method to
// accomplish this which will insert the record and any more attributes.
$instance->save(array('touch' => false));
$this->attach($instance, $joining, $touch);
return $instance;
}
/**
* Sync the intermediate tables with a list of IDs or collection of models.
*
* @param array $ids
* @param mixed $ids
* @param bool $detaching
* @return void
* @return array
*/
public function sync($ids, $detaching = true)
{
$changes = array(
'attached' => array(), 'detached' => array(), 'updated' => array()
);
if ($ids instanceof Collection) $ids = $ids->modelKeys();
// First we need to attach any of the associated models that are not currently
......@@ -56,6 +99,9 @@ class BelongsToMany extends EloquentBelongsToMany {
// if they exist in the array of current ones, and if not we will insert.
$current = $this->parent->{$this->otherKey} ?: array();
// See issue #256.
if ($current instanceof Collection) $current = $ids->modelKeys();
$records = $this->formatSyncList($ids);
$detach = array_diff($current, array_keys($records));
......@@ -66,36 +112,36 @@ class BelongsToMany extends EloquentBelongsToMany {
if ($detaching and count($detach) > 0)
{
$this->detach($detach);
$changes['detached'] = (array) array_map('intval', $detach);
}
// Now we are finally ready to attach the new records. Note that we'll disable
// touching until after the entire operation is complete so we don't fire a
// ton of touch operations until we are totally done syncing the records.
$this->attachNew($records, $current, false);
$changes = array_merge(
$changes, $this->attachNew($records, $current, false)
);
if (count($changes['attached']) || count($changes['updated']))
{
$this->touchIfTouching();
}
return $changes;
}
/**
* Attach all of the IDs that aren't in the current array.
* Update an existing pivot record on the table.
*
* @param array $records
* @param array $current
* @param mixed $id
* @param array $attributes
* @param bool $touch
* @return void
*/
protected function attachNew(array $records, array $current, $touch = true)
{
foreach ($records as $id => $attributes)
public function updateExistingPivot($id, array $attributes, $touch = true)
{
// If the ID is not in the list of existing pivot IDs, we will insert a new pivot
// record, otherwise, we will just update this existing record on this joining
// table, so that the developers will easily update these records pain free.
if ( ! in_array($id, $current))
{
$this->attach($id, $attributes, $touch);
}
}
// Do nothing, we have no pivot table.
}
/**
......@@ -108,25 +154,37 @@ class BelongsToMany extends EloquentBelongsToMany {
*/
public function attach($id, array $attributes = array(), $touch = true)
{
if ($id instanceof Model) $id = $id->getKey();
if ($id instanceof Model)
{
$model = $id; $id = $model->getKey();
}
$records = $this->createAttachRecords((array) $id, $attributes);
// Get the ID's to attach to the two documents
// Get the ids to attach to the parent and related model.
$otherIds = array_pluck($records, $this->otherKey);
$foreignIds = array_pluck($records, $this->foreignKey);
// Attach to the parent model
$this->parent->push($this->otherKey, $otherIds[0]);
// Attach the new ids to the parent model.
$this->parent->push($this->otherKey, $otherIds, true);
// Generate a new related query instance
$query = $this->getNewRelatedQuery();
// If we have a model instance, we can psuh the ids to that model,
// so that the internal attributes are updated as well. Otherwise,
// we will just perform a regular database query.
if (isset($model))
{
// Attach the new ids to the related model.
$model->push($this->foreignKey, $foreignIds, true);
}
else
{
$query = $this->newRelatedQuery();
// Set contraints on the related query
$query->where($this->related->getKeyName(), $id);
// Attach to the related model
$query->push($this->foreignKey, $foreignIds[0]);
// Attach the new ids to the related model.
$query->push($this->foreignKey, $foreignIds, true);
}
if ($touch) $this->touchIfTouching();
}
......@@ -142,18 +200,15 @@ class BelongsToMany extends EloquentBelongsToMany {
{
if ($ids instanceof Model) $ids = (array) $ids->getKey();
$query = $this->getNewRelatedQuery();
$query = $this->newRelatedQuery();
// If associated IDs were passed to the method we will only delete those
// associations, otherwise all of the association ties will be broken.
// We'll return the numbers of affected rows when we do the deletes.
$ids = (array) $ids;
// Pull each id from the parent.
foreach ($ids as $id)
{
$this->parent->pull($this->otherKey, $id);
}
// Detach all ids from the parent model.
$this->parent->pull($this->otherKey, $ids);
// Prepare the query to select all related objects.
if (count($ids) > 0)
......@@ -196,11 +251,21 @@ class BelongsToMany extends EloquentBelongsToMany {
}
/**
* Get a new related query.
* Create a new query builder for the related model.
*
* @return \Illuminate\Database\Query\Builder
*/
protected function newPivotQuery()
{
return $this->newRelatedQuery();
}
/**
* Create a new query builder for the related model.
*
* @return \Illuminate\Database\Query\Builder
*/
public function getNewRelatedQuery()
public function newRelatedQuery()
{
return $this->related->newQuery();
}
......
<?php namespace Jenssegers\Mongodb\Relations;
use MongoId;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\Collection;
use MongoId;
class EmbedsOne extends EmbedsOneOrMany {
/**
* Get the results of the relationship.
*
* @return Illuminate\Database\Eloquent\Collection
* @return \Illuminate\Database\Eloquent\Model
*/
public function getResults()
{
......@@ -19,75 +18,105 @@ class EmbedsOne extends EmbedsOneOrMany {
}
/**
* Check if a model is already embedded.
* Save a new model and attach it to the parent model.
*
* @param mixed $key
* @return bool
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function contains($key)
public function performInsert(Model $model, array $values)
{
// Generate a new key if needed.
if ($model->getKeyName() == '_id' and ! $model->getKey())
{
if ($key instanceof Model) $key = $key->getKey();
$model->setAttribute('_id', new MongoId);
}
$embedded = $this->getEmbedded();
// For deeply nested documents, let the parent handle the changes.
if ($this->isNested())
{
$this->associate($model);
$primaryKey = $this->related->getKeyName();
return $this->parent->save();
}
$result = $this->getBaseQuery()->update(array($this->localKey => $model->getAttributes()));
// Attach the model to its parent.
if ($result) $this->associate($model);
return ($embedded and $embedded[$primaryKey] == $key);
return $result ? $model : false;
}
/**
* Associate the model instance to the given parent, without saving it to the database.
* Save an existing model and attach it to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
* @return Model|bool
*/
public function associate(Model $model)
public function performUpdate(Model $model, array $values)
{
// Create a new key if needed.
if ( ! $model->getAttribute('_id'))
if ($this->isNested())
{
$model->setAttribute('_id', new MongoId);
$this->associate($model);
return $this->parent->save();
}
$this->setEmbedded($model->getAttributes());
// Use array dot notation for better update behavior.
$values = array_dot($model->getDirty(), $this->localKey . '.');
return $model;
$result = $this->getBaseQuery()->update($values);
// Attach the model to its parent.
if ($result) $this->associate($model);
return $result ? $model : false;
}
/**
* Save a new model and attach it to the parent model.
* Delete an existing model and detach it from the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
* @param Model $model
* @return int
*/
protected function performInsert(Model $model)
public function performDelete(Model $model)
{
// Create a new key if needed.
if ( ! $model->getAttribute('_id'))
// For deeply nested documents, let the parent handle the changes.
if ($this->isNested())
{
$model->setAttribute('_id', new MongoId);
$this->dissociate($model);
return $this->parent->save();
}
$result = $this->query->update(array($this->localKey => $model->getAttributes()));
// Overwrite the local key with an empty array.
$result = $this->getBaseQuery()->update(array($this->localKey => null));
if ($result) $this->associate($model);
// Detach the model from its parent.
if ($result) $this->dissociate();
return $result ? $model : false;
return $result;
}
/**
* Save an existing model and attach it to the parent model.
* Attach the model to its parent.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return Model|bool
* @return \Illuminate\Database\Eloquent\Model
*/
protected function performUpdate(Model $model)
public function associate(Model $model)
{
$result = $this->query->update(array($this->localKey => $model->getAttributes()));
if ($result) $this->associate($model);
return $this->setEmbedded($model->getAttributes());
}
return $result ? $model : false;
/**
* Detach the model from its parent.
*
* @return \Illuminate\Database\Eloquent\Model
*/
public function dissociate()
{
return $this->setEmbedded(null);
}
/**
......@@ -97,22 +126,9 @@ class EmbedsOne extends EmbedsOneOrMany {
*/
public function delete()
{
// Overwrite the local key with an empty array.
$result = $this->query->update(array($this->localKey => null));
$model = $this->getResults();
// If the update query was successful, we will remove the embedded records
// of the parent instance.
if ($result)
{
$count = $this->count();
$this->setEmbedded(null);
// Return the number of deleted embedded records.
return $count;
}
return $result;
return $this->performDelete($model);
}
}
......@@ -20,4 +20,14 @@ class HasMany extends EloquentHasMany {
return $query->select($this->getHasCompareKey())->where($this->getHasCompareKey(), 'exists', true);
}
/**
* Get the plain foreign key.
*
* @return string
*/
public function getPlainForeignKey()
{
return $this->getForeignKey();
}
}
......@@ -20,4 +20,14 @@ class HasOne extends EloquentHasOne {
return $query->select($this->getHasCompareKey())->where($this->getHasCompareKey(), 'exists', true);
}
/**
* Get the plain foreign key.
*
* @return string
*/
public function getPlainForeignKey()
{
return $this->getForeignKey();
}
}
......@@ -36,6 +36,7 @@ class Blueprint extends \Illuminate\Database\Schema\Blueprint {
public function __construct(Connection $connection, $collection)
{
$this->connection = $connection;
$this->collection = $connection->getCollection($collection);
}
......@@ -50,11 +51,12 @@ class Blueprint extends \Illuminate\Database\Schema\Blueprint {
{
$columns = $this->fluent($columns);
// Columns are passed as a default array
// Columns are passed as a default array.
if (is_array($columns) && is_int(key($columns)))
{
// Transform the columns to the required array format
// Transform the columns to the required array format.
$transform = array();
foreach ($columns as $column)
{
$transform[$column] = 1;
......@@ -78,11 +80,12 @@ class Blueprint extends \Illuminate\Database\Schema\Blueprint {
{
$columns = $this->fluent($columns);
// Columns are passed as a default array
// Columns are passed as a default array.
if (is_array($columns) && is_int(key($columns)))
{
// Transform the columns to the required array format
// Transform the columns to the required array format.
$transform = array();
foreach ($columns as $column)
{
$transform[$column] = 1;
......@@ -105,6 +108,7 @@ class Blueprint extends \Illuminate\Database\Schema\Blueprint {
public function unique($columns = null, $name = null)
{
$columns = $this->fluent($columns);
$this->index($columns, array('unique' => true));
return $this;
......@@ -119,6 +123,7 @@ class Blueprint extends \Illuminate\Database\Schema\Blueprint {
public function background($columns = null)
{
$columns = $this->fluent($columns);
$this->index($columns, array('background' => true));
return $this;
......@@ -149,6 +154,7 @@ class Blueprint extends \Illuminate\Database\Schema\Blueprint {
public function expire($columns, $seconds)
{
$columns = $this->fluent($columns);
$this->index($columns, array('expireAfterSeconds' => $seconds));
return $this;
......@@ -163,8 +169,9 @@ class Blueprint extends \Illuminate\Database\Schema\Blueprint {
{
$collection = $this->collection->getName();
// Ensure the collection is created
$db = $this->connection->getMongoDB();
// Ensure the collection is created.
$db->createCollection($collection);
}
......@@ -189,6 +196,7 @@ class Blueprint extends \Illuminate\Database\Schema\Blueprint {
protected function addColumn($type, $name, array $parameters = array())
{
$this->fluent($name);
return $this;
}
......@@ -221,6 +229,7 @@ class Blueprint extends \Illuminate\Database\Schema\Blueprint {
*/
public function __call($method, $args)
{
// Dummy.
return $this;
}
......
<?php
class AuthTest extends TestCase {
public function tearDown()
{
User::truncate();
DB::collection('password_reminders')->truncate();
}
public function testAuthAttempt()
{
$user = User::create(array(
'name' => 'John Doe',
'email' => 'john@doe.com',
'password' => Hash::make('foobar')
));
$this->assertTrue(Auth::attempt(array('email' => 'john@doe.com', 'password' => 'foobar'), true));
$this->assertTrue(Auth::check());
}
public function testRemind()
{
$mailer = Mockery::mock('Illuminate\Mail\Mailer');
$this->app->instance('mailer', $mailer);
$user = User::create(array(
'name' => 'John Doe',
'email' => 'john@doe.com',
'password' => Hash::make('foobar')
));
$mailer->shouldReceive('send')->once();
Password::remind(array('email' => 'john@doe.com'));
$this->assertEquals(1, DB::collection('password_reminders')->count());
$reminder = DB::collection('password_reminders')->first();
$this->assertEquals('john@doe.com', $reminder['email']);
$this->assertNotNull($reminder['token']);
$this->assertInstanceOf('MongoDate', $reminder['created_at']);
$credentials = array(
'email' => 'john@doe.com',
'password' => 'foobar',
'password_confirmation' => 'foobar',
'token' => $reminder['token']
);
$response = Password::reset($credentials, function($user, $password)
{
$user->password = Hash::make($password);
$user->save();
});
$this->assertEquals('reminders.reset', $response);
$this->assertEquals(0, DB::collection('password_reminders')->count());
}
public function testDeprecatedRemind()
{
$mailer = Mockery::mock('Illuminate\Mail\Mailer');
$this->app->instance('mailer', $mailer);
$user = User::create(array(
'name' => 'John Doe',
'email' => 'john@doe.com',
'password' => Hash::make('foobar')
));
$mailer->shouldReceive('send')->once();
Password::remind(array('email' => 'john@doe.com'));
DB::collection('password_reminders')->update(array('created_at' => new DateTime));
$reminder = DB::collection('password_reminders')->first();
$this->assertTrue(is_array($reminder['created_at']));
$credentials = array(
'email' => 'john@doe.com',
'password' => 'foobar',
'password_confirmation' => 'foobar',
'token' => $reminder['token']
);
$response = Password::reset($credentials, function($user, $password)
{
$user->password = Hash::make($password);
$user->save();
});
$this->assertEquals('reminders.reset', $response);
$this->assertEquals(0, DB::collection('password_reminders')->count());
}
}
This diff is collapsed.
......@@ -267,29 +267,33 @@ class ModelTest extends TestCase {
public function testSoftDelete()
{
$user = new Soft;
$user->name = 'Softy';
$user->save();
Soft::create(array('name' => 'John Doe'));
Soft::create(array('name' => 'Jane Doe'));
$this->assertEquals(2, Soft::count());
$user = Soft::where('name', 'John Doe')->first();
$this->assertEquals(true, $user->exists);
$this->assertEquals(false, $user->trashed());
$this->assertNull($user->deleted_at);
$user->delete();
$this->assertEquals(true, $user->trashed());
$this->assertNotNull($user->deleted_at);
$check = Soft::find($user->_id);
$this->assertEquals(null, $check);
$all = Soft::get();
$this->assertEquals(0, $all->count());
$user = Soft::where('name', 'John Doe')->first();
$this->assertNull($user);
$all = Soft::withTrashed()->get();
$this->assertEquals(1, $all->count());
$this->assertEquals(1, Soft::count());
$this->assertEquals(2, Soft::withTrashed()->count());
$check = $all[0];
$this->assertInstanceOf('Carbon\Carbon', $check->deleted_at);
$this->assertEquals(true, $check->trashed());
$user = Soft::withTrashed()->where('name', 'John Doe')->first();
$this->assertNotNull($user);
$this->assertInstanceOf('Carbon\Carbon', $user->deleted_at);
$this->assertEquals(true, $user->trashed());
$check->restore();
$all = Soft::get();
$this->assertEquals(1, $all->count());
$user->restore();
$this->assertEquals(2, Soft::count());
}
public function testPrimaryKey()
......@@ -393,6 +397,12 @@ class ModelTest extends TestCase {
$user = User::create(array('name' => 'Jane Doe', 'birthday' => '2005-08-08'));
$this->assertInstanceOf('Carbon\Carbon', $user->birthday);
$user = User::create(array('name' => 'Jane Doe', 'entry' => array('date' => '2005-08-08')));
$this->assertInstanceOf('Carbon\Carbon', $user->getAttribute('entry.date'));
$user->setAttribute('entry.date', new DateTime);
$this->assertInstanceOf('Carbon\Carbon', $user->getAttribute('entry.date'));
}
public function testIdAttribute()
......@@ -406,14 +416,28 @@ class ModelTest extends TestCase {
public function testPushPull()
{
$user = User::create(array('name' => 'John Doe', 'tags' => array()));
$user = User::create(array('name' => 'John Doe'));
$result = User::where('_id', $user->_id)->push('tags', 'tag1');
$user->push('tags', 'tag1');
$user->push('tags', array('tag1', 'tag2'));
$user->push('tags', 'tag2', true);
$this->assertEquals(array('tag1', 'tag1', 'tag2'), $user->tags);
$user = User::where('_id', $user->_id)->first();
$this->assertEquals(array('tag1', 'tag1', 'tag2'), $user->tags);
$user->pull('tags', 'tag1');
$this->assertEquals(array('tag2'), $user->tags);
$user = User::where('_id', $user->_id)->first();
$this->assertEquals(array('tag2'), $user->tags);
$user->push('tags', 'tag3');
$user->pull('tags', array('tag2', 'tag3'));
$this->assertTrue(is_int($result));
$this->assertTrue(is_array($user->tags));
$this->assertEquals(1, count($user->tags));
$this->assertEquals(array(), $user->tags);
$user = User::where('_id', $user->_id)->first();
$this->assertEquals(array(), $user->tags);
}
public function testRaw()
......
......@@ -611,4 +611,20 @@ class QueryBuilderTest extends TestCase {
$this->assertEquals(1, $user['age']);
}
public function testProjections()
{
DB::collection('items')->insert(array(
array('name' => 'fork', 'tags' => array('sharp', 'pointy')),
array('name' => 'spork', 'tags' => array('sharp', 'pointy', 'round', 'bowl')),
array('name' => 'spoon', 'tags' => array('round', 'bowl')),
));
$results = DB::collection('items')->project(array('tags' => array('$slice' => 1)))->get();
foreach ($results as $result)
{
$this->assertEquals(1, count($result['tags']));
}
}
}
......@@ -239,6 +239,31 @@ class QueryTest extends TestCase {
->get();
$this->assertEquals(5, count($users));
$users = User::whereNull('deleted_at')
->where('title', 'admin')
->where(function($query)
{
$query->where('age', '>', 15)
->orWhere('name', 'Harry Hoe');
})
->get();
$this->assertEquals(3, $users->count());
$users = User::whereNull('deleted_at')
->where(function($query)
{
$query->where('name', 'Harry Hoe')
->orWhere(function($query)
{
$query->where('age', '>', 15)
->where('title', '<>', 'admin');
});
})
->get();
$this->assertEquals(5, $users->count());
}
public function testWhereRaw()
......@@ -280,4 +305,15 @@ class QueryTest extends TestCase {
$this->assertEquals(2, count($users));
}
public function testPaginate()
{
$results = User::paginate(2);
$this->assertEquals(2, $results->count());
$this->assertNotNull($results->first()->title);
$results = User::paginate(2, array('name', 'age'));
$this->assertEquals(2, $results->count());
$this->assertNull($results->first()->title);
}
}
......@@ -131,6 +131,7 @@ class RelationsTest extends TestCase {
$items = $user->items;
$this->assertEquals(1, count($items));
$this->assertInstanceOf('Item', $items[0]);
$this->assertEquals($user->_id, $items[0]->user_id);
// Has one
$user = User::create(array('name' => 'John Doe'));
......@@ -141,6 +142,7 @@ class RelationsTest extends TestCase {
$role = $user->role;
$this->assertInstanceOf('Role', $role);
$this->assertEquals('admin', $role->type);
$this->assertEquals($user->_id, $role->user_id);
}
public function testBelongsToMany()
......@@ -415,6 +417,59 @@ class RelationsTest extends TestCase {
$address = $client->addresses->first();
$this->assertEquals('Paris', $address->data['city']);
$client = Client::with('addresses')->first();
$this->assertEquals('Paris', $client->addresses->first()->data['city']);
}
public function testDoubleSaveOneToMany()
{
$author = User::create(array('name' => 'George R. R. Martin'));
$book = Book::create(array('title' => 'A Game of Thrones'));
$author->books()->save($book);
$author->books()->save($book);
$author->save();
$this->assertEquals(1, $author->books()->count());
$this->assertEquals($author->_id, $book->author_id);
$author = User::where('name', 'George R. R. Martin')->first();
$book = Book::where('title', 'A Game of Thrones')->first();
$this->assertEquals(1, $author->books()->count());
$this->assertEquals($author->_id, $book->author_id);
$author->books()->save($book);
$author->books()->save($book);
$author->save();
$this->assertEquals(1, $author->books()->count());
$this->assertEquals($author->_id, $book->author_id);
}
public function testDoubleSaveManyToMany()
{
$user = User::create(array('name' => 'John Doe'));
$client = Client::create(array('name' => 'Admins'));
$user->clients()->save($client);
$user->clients()->save($client);
$user->save();
$this->assertEquals(1, $user->clients()->count());
$this->assertEquals(array($user->_id), $client->user_ids);
$this->assertEquals(array($client->_id), $user->client_ids);
$user = User::where('name', 'John Doe')->first();
$client = Client::where('name', 'Admins')->first();
$this->assertEquals(1, $user->clients()->count());
$this->assertEquals(array($user->_id), $client->user_ids);
$this->assertEquals(array($client->_id), $user->client_ids);
$user->clients()->save($client);
$user->clients()->save($client);
$user->save();
$this->assertEquals(1, $user->clients()->count());
$this->assertEquals(array($user->_id), $client->user_ids);
$this->assertEquals(array($client->_id), $user->client_ids);
}
}
......@@ -9,7 +9,10 @@ class TestCase extends Orchestra\Testbench\TestCase {
*/
protected function getPackageProviders()
{
return array('Jenssegers\Mongodb\MongodbServiceProvider');
return array(
'Jenssegers\Mongodb\MongodbServiceProvider',
'Jenssegers\Mongodb\Auth\ReminderServiceProvider',
);
}
/**
......
......@@ -6,4 +6,9 @@ class Address extends Eloquent {
protected static $unguarded = true;
public function addresses()
{
return $this->embedsMany('Address');
}
}
......@@ -19,6 +19,6 @@ class Client extends Eloquent {
public function addresses()
{
return $this->hasMany('Address', 'data.client_id', 'data.address_id');
return $this->hasMany('Address', 'data.address_id', 'data.client_id');
}
}
......@@ -8,6 +8,7 @@ class Soft extends Eloquent {
use SoftDeletingTrait;
protected $collection = 'soft';
protected static $unguarded = true;
protected $dates = array('deleted_at');
}
......@@ -2,12 +2,16 @@
use Jenssegers\Mongodb\Model as Eloquent;
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;
class User extends Eloquent implements UserInterface, RemindableInterface {
protected $dates = array('birthday');
use UserTrait, RemindableTrait;
protected $dates = array('birthday', 'entry.date');
protected static $unguarded = true;
public function books()
......@@ -60,66 +64,6 @@ class User extends Eloquent implements UserInterface, RemindableInterface {
return $this->embedsOne('User');
}
/**
* Get the unique identifier for the user.
*
* @return mixed
*/
public function getAuthIdentifier()
{
return $this->getKey();
}
/**
* Get the password for the user.
*
* @return string
*/
public function getAuthPassword()
{
return $this->password;
}
/**
* Get the e-mail address where password reminders are sent.
*
* @return string
*/
public function getReminderEmail()
{
return $this->email;
}
/**
* Get the token value for the "remember me" session.
*
* @return string
*/
public function getRememberToken()
{
return $this->rememberToken;
}
/**
* Set the token value for the "remember me" session.
*
* @param string $value
* @return void
*/
public function setRememberToken($value)
{
$this->rememberToken = $value;
}
/**
* Get the column name for the "remember me" token.
*
* @return string
*/
public function getRememberTokenName() {
return 'remember_token';
}
protected function getDateFormat()
{
return 'l jS \of F Y h:i:s A';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment