Commit b9e4cdae authored by Jens Segers's avatar Jens Segers

Tweaking relations and MongoId conversion

parent 9443e8b4
......@@ -169,27 +169,23 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
}
/**
* Set the array of model attributes. No checking is done.
* Get an attribute from the model.
*
* @param array $attributes
* @param bool $sync
* @return void
* @param string $key
* @return mixed
*/
public function setRawAttributes(array $attributes, $sync = false)
public function getAttribute($key)
{
foreach($attributes as $key => &$value)
$attribute = parent::getAttribute($key);
// If the attribute is a MongoId object, return it as a string.
// This is makes Eloquent relations a lot easier.
if ($attribute instanceof MongoId)
{
/**
* MongoIds are converted to string to make it easier to pass
* the id to other instances or relations.
*/
if ($value instanceof MongoId)
{
$value = (string) $value;
}
return (string) $attribute;
}
parent::setRawAttributes($attributes, $sync);
return $attribute;
}
/**
......@@ -223,7 +219,7 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
* @param mixed $columns
* @return int
*/
public function dropColumn($columns)
public function drop($columns)
{
if (!is_array($columns)) $columns = array($columns);
......@@ -234,7 +230,7 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
}
// Perform unset only on current document
return $query = $this->newQuery()->where($this->getKeyName(), $this->getKey())->unset($columns);
return $this->newQuery()->where($this->getKeyName(), $this->getKey())->unset($columns);
}
/**
......@@ -289,7 +285,7 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
// Unset method
if ($method == 'unset')
{
return call_user_func_array(array($this, 'dropColumn'), $parameters);
return call_user_func_array(array($this, 'drop'), $parameters);
}
return parent::__call($method, $parameters);
......
......@@ -59,7 +59,7 @@ class Builder extends \Illuminate\Database\Query\Builder {
/**
* Execute a query for a single record by ID.
*
* @param int $id
* @param mixed $id
* @param array $columns
* @return mixed
*/
......@@ -377,8 +377,8 @@ class Builder extends \Illuminate\Database\Query\Builder {
$sequence = '_id';
}
// Return id as a string
return (string) $values[$sequence];
// Return id
return $values[$sequence];
}
}
......@@ -585,7 +585,7 @@ class Builder extends \Illuminate\Database\Query\Builder {
* @param mixed $columns
* @return int
*/
public function dropColumn($columns)
public function drop($columns)
{
if (!is_array($columns)) $columns = array($columns);
......@@ -846,7 +846,7 @@ class Builder extends \Illuminate\Database\Query\Builder {
{
if ($method == 'unset')
{
return call_user_func_array(array($this, 'dropColumn'), $parameters);
return call_user_func_array(array($this, 'drop'), $parameters);
}
return parent::__call($method, $parameters);
......
<?php namespace Jenssegers\Mongodb\Relations;
use Illuminate\Database\Eloquent\Collection;
use Jenssegers\Mongodb\Model;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\BelongsToMany as EloquentBelongsToMany;
class BelongsToMany extends EloquentBelongsToMany {
......@@ -36,12 +36,12 @@ class BelongsToMany extends EloquentBelongsToMany {
{
if (static::$constraints)
{
$this->query->where($this->foreignKey, $this->parent->getKey());
$this->query->where($this->getForeignKey(), '=', $this->parent->getKey());
}
}
/**
* Sync the intermediate tables with a list of IDs.
* Sync the intermediate tables with a list of IDs or collection of models.
*
* @param array $ids
* @param bool $detaching
......@@ -49,14 +49,12 @@ class BelongsToMany extends EloquentBelongsToMany {
*/
public function sync(array $ids, $detaching = true)
{
if ($ids instanceof Collection) $ids = $ids->modelKeys();
// First we need to attach any of the associated models that are not currently
// in this joining table. We'll spin through the given IDs, checking to see
// if they exist in the array of current ones, and if not we will insert.
$current = $this->parent->{$this->otherKey};
// Check if the current array exists or not on the parent model and create it
// if it does not exist
if (is_null($current)) $current = array();
$current = $this->parent->{$this->otherKey} ?: array();
$records = $this->formatSyncList($ids);
......@@ -133,27 +131,6 @@ class BelongsToMany extends EloquentBelongsToMany {
if ($touch) $this->touchIfTouching();
}
/**
* Create an array of records to insert into the pivot table.
*
* @param array $ids
* @return void
*/
protected function createAttachRecords($ids, array $attributes)
{
$records = array();
// To create the attachment records, we will simply spin through the IDs given
// and create a new record to insert for each ID. Each ID may actually be a
// key in the array, with extra attributes to be placed in other columns.
foreach ($ids as $key => $value)
{
$records[] = $this->attacher($key, $value, $attributes, false);
}
return $records;
}
/**
* Detach models from the relationship.
*
......@@ -165,6 +142,8 @@ class BelongsToMany extends EloquentBelongsToMany {
{
if ($ids instanceof Model) $ids = (array) $ids->getKey();
$query = $this->getNewRelatedQuery();
// 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.
......@@ -176,9 +155,6 @@ class BelongsToMany extends EloquentBelongsToMany {
$this->parent->pull($this->otherKey, $id);
}
// Get a new related query.
$query = $this->getNewRelatedQuery();
// Prepare the query to select all related objects.
if (count($ids) > 0)
{
......
<?php namespace Jenssegers\Mongodb\Relations;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Collection as BaseCollection;
use Illuminate\Database\Eloquent\Relations\MorphTo as EloquentMorphTo;
class MorphTo extends BelongsTo {
class MorphTo extends EloquentMorphTo {
/**
* The type of the polymorphic relation.
*
* @var string
*/
protected $morphType;
/**
* The models whose relations are being eager loaded.
*
* @var \Illuminate\Database\Eloquent\Collection
*/
protected $models;
/**
* All of the models keyed by ID.
*
* @var array
*/
protected $dictionary = array();
/**
* Create a new belongs to relationship instance.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Model $parent
* @param string $foreignKey
* @param string $otherKey
* @param string $type
* @param string $relation
* @return void
*/
public function __construct(Builder $query, Model $parent, $foreignKey, $otherKey, $type, $relation)
* Set the base constraints on the relation query.
*
* @return void
*/
public function addConstraints()
{
$this->morphType = $type;
parent::__construct($query, $parent, $foreignKey, $otherKey, $relation);
if (static::$constraints)
{
// For belongs to relationships, which are essentially the inverse of has one
// or has many relationships, we need to actually query on the primary key
// of the related models matching on the foreign key that's on a parent.
$this->query->where($this->otherKey, '=', $this->parent->{$this->foreignKey});
}
}
/**
......@@ -58,125 +32,4 @@ class MorphTo extends BelongsTo {
$this->buildDictionary($this->models = Collection::make($models));
}
/**
* Buiild a dictionary with the models.
*
* @param \Illuminate\Database\Eloquent\Models $models
* @return void
*/
protected function buildDictionary(Collection $models)
{
foreach ($models as $model)
{
if ($model->{$this->morphType})
{
$this->dictionary[$model->{$this->morphType}][$model->{$this->foreignKey}][] = $model;
}
}
}
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
return $models;
}
/**
* Get the results of the relationship.
*
* Called via eager load method of Eloquent query builder.
*
* @return mixed
*/
public function getEager()
{
foreach (array_keys($this->dictionary) as $type)
{
$this->matchToMorphParents($type, $this->getResultsByType($type));
}
return $this->models;
}
/**
* Match the results for a given type to their parents.
*
* @param string $type
* @param \Illuminate\Database\Eloquent\Collection $results
* @return void
*/
protected function matchToMorphParents($type, Collection $results)
{
foreach ($results as $result)
{
if (isset($this->dictionary[$type][$result->getKey()]))
{
foreach ($this->dictionary[$type][$result->getKey()] as $model)
{
$model->setRelation($this->relation, $result);
}
}
}
}
/**
* Get all of the relation results for a type.
*
* @param string $type
* @return \Illuminate\Database\Eloquent\Collection
*/
protected function getResultsByType($type)
{
$instance = $this->createModelByType($type);
$key = $instance->getKeyName();
return $instance->whereIn($key, $this->gatherKeysByType($type)->all())->get();
}
/**
* Gather all of the foreign keys for a given type.
*
* @param string $type
* @return array
*/
protected function gatherKeysByType($type)
{
$foreign = $this->foreignKey;
return BaseCollection::make($this->dictionary[$type])->map(function($models) use ($foreign)
{
return head($models)->{$foreign};
})->unique();
}
/**
* Create a new model instance by type.
*
* @param string $type
* @return \Illuminate\Database\Eloquent\Model
*/
public function createModelByType($type)
{
return new $type;
}
/**
* Get the dictionary used by the relationship.
*
* @return array
*/
public function getDictionary()
{
return $this->dictionary;
}
}
......@@ -34,10 +34,14 @@ class ModelTest extends TestCase {
$this->assertEquals(1, User::count());
$this->assertTrue(isset($user->_id));
$this->assertTrue(is_string($user->_id));
$this->assertNotEquals('', (string) $user->_id);
$this->assertNotEquals(0, strlen((string) $user->_id));
$this->assertInstanceOf('Carbon\Carbon', $user->created_at);
$raw = $user->getAttributes();
$this->assertInstanceOf('MongoId', $raw['_id']);
$this->assertEquals('John Doe', $user->name);
$this->assertEquals(35, $user->age);
}
......@@ -50,6 +54,9 @@ class ModelTest extends TestCase {
$user->age = 35;
$user->save();
$raw = $user->getAttributes();
$this->assertInstanceOf('MongoId', $raw['_id']);
$check = User::find($user->_id);
$check->age = 36;
......@@ -65,6 +72,9 @@ class ModelTest extends TestCase {
$user->update(array('age' => 20));
$raw = $user->getAttributes();
$this->assertInstanceOf('MongoId', $raw['_id']);
$check = User::find($user->_id);
$this->assertEquals(20, $check->age);
}
......
......@@ -54,9 +54,7 @@ class QueryBuilderTest extends TestCase {
public function testInsertGetId()
{
$id = DB::collection('users')->insertGetId(array('name' => 'John Doe'));
$this->assertTrue(is_string($id));
$this->assertEquals(24, strlen($id));
$this->assertInstanceOf('MongoId', $id);
}
public function testBatchInsert()
......
......@@ -308,6 +308,10 @@ class RelationsTest extends TestCase {
$this->assertInstanceOf('DateTime', $address->created_at);
$this->assertInstanceOf('DateTime', $address->updated_at);
$this->assertNotNull($address->_id);
$this->assertTrue(is_string($address->_id));
$raw = $address->getAttributes();
$this->assertInstanceOf('MongoId', $raw['_id']);
$address = $user->addresses()->save(new Address(array('city' => 'Paris')));
......@@ -410,15 +414,21 @@ class RelationsTest extends TestCase {
$user = User::create(array());
$address = $user->addresses()->create(array('city' => 'Bruxelles'));
$this->assertInstanceOf('Address', $address);
$this->assertInstanceOf('MongoID', $address->_id);
$this->assertTrue(is_string($address->_id));
$this->assertEquals(array('Bruxelles'), $user->addresses->lists('city'));
$raw = $address->getAttributes();
$this->assertInstanceOf('MongoId', $raw['_id']);
$freshUser = User::find($user->id);
$this->assertEquals(array('Bruxelles'), $freshUser->addresses->lists('city'));
$user = User::create(array());
$address = $user->addresses()->create(array('_id' => '', 'city' => 'Bruxelles'));
$this->assertInstanceOf('MongoID', $address->_id);
$this->assertTrue(is_string($address->_id));
$raw = $address->getAttributes();
$this->assertInstanceOf('MongoId', $raw['_id']);
}
public function testEmbedsManyCreateMany()
......@@ -553,4 +563,20 @@ class RelationsTest extends TestCase {
$address->unsetEventDispatcher();
}
public function testEmbedsManyFindOrContains()
{
$user = User::create(array('name' => 'John Doe'));
$address1 = $user->addresses()->save(new Address(array('city' => 'New York')));
$address2 = $user->addresses()->save(new Address(array('city' => 'Paris')));
$address = $user->addresses()->find($address1->_id);
$this->assertEquals($address->city, $address1->city);
$address = $user->addresses()->find($address2->_id);
$this->assertEquals($address->city, $address2->city);
$this->assertTrue($user->addresses()->contains($address2->_id));
$this->assertFalse($user->addresses()->contains('123'));
}
}
......@@ -32,6 +32,9 @@ class TestCase extends Orchestra\Testbench\TestCase {
// overwrite database configuration
$app['config']->set('database.connections.mysql', $config['connections']['mysql']);
$app['config']->set('database.connections.mongodb', $config['connections']['mongodb']);
// overwrite cache configuration
$app['config']->set('cache.driver', 'array');
}
}
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