Commit 828a490d authored by Jens Segers's avatar Jens Segers

Merge pull request #137 from neoxia/master-embeds-many

[Proposal] Add embedsMany relationship to Eloquent Model
parents b95dbb15 3609c3ab
<?php namespace Jenssegers\Eloquent;
use LogicException;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\Relation;
use Jenssegers\Mongodb\Relations\BelongsTo;
use Jenssegers\Mongodb\Relations\BelongsToMany;
use Jenssegers\Mongodb\Relations\EmbedsMany;
use Jenssegers\Mongodb\Relations\EmbeddedRelation;
use Jenssegers\Mongodb\Query\Builder as QueryBuilder;
abstract class Model extends \Illuminate\Database\Eloquent\Model {
......@@ -219,6 +223,45 @@ abstract class Model extends \Illuminate\Database\Eloquent\Model {
return new BelongsToMany($query, $this, $collection, $foreignKey, $otherKey, $relation);
}
/**
* Define an embedded one-to-many relationship.
*
* @param string $related
* @param string $collection
* @return \Illuminate\Database\Eloquent\Relations\EmbedsMany
*/
protected function embedsMany($related, $collection = null)
{
// If no collection name was provided, we assume that the standard is the
// related model camel_cased, pluralized and suffixed with '_ids'
if (is_null($collection))
{
$collection = str_plural(snake_case($related)) . '_ids';
}
return new EmbedsMany($this, $related, $collection);
}
/**
* Get a relationship value from a method.
*
* @param string $key
* @param string $camelKey
* @return mixed
*/
protected function getRelationshipFromMethod($key, $camelKey)
{
$relations = $this->$camelKey();
if ( ! $relations instanceof Relation and ! $relations instanceof EmbeddedRelation)
{
throw new LogicException('Relationship method must return an object of type '
. 'Illuminate\Database\Eloquent\Relations\Relation or Jenssegers\Mongodb\Relations\EmbeddedRelation');
}
return $this->relations[$key] = $relations->getResults();
}
/**
* Get a new query builder instance for the connection.
*
......
<?php namespace Jenssegers\Mongodb\Relations;
use Illuminate\Database\Eloquent\Model;
abstract class EmbeddedRelation {
/**
* The parent model instance.
*
* @var \Illuminate\Database\Eloquent\Model
*/
protected $parent;
/**
* The related model class name.
*
* @var string
*/
protected $related;
/**
* Create a new has many relationship instance.
*
* @param \Illuminate\Database\Eloquent\Model $parent
* @param string $related
* @param string $collection
* @return void
*/
public function __construct(Model $parent, $related)
{
$this->parent = $parent;
$this->related = $related;
}
/**
* Get the results of the relationship.
*
* @return mixed
*/
abstract public function getResults();
}
<?php namespace Jenssegers\Mongodb\Relations;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Collection;
use MongoId;
class EmbedsMany extends EmbeddedRelation {
/**
* The parent collection attribute where the related are stored.
*
* @var string
*/
protected $collection;
/**
* Create a new has many relationship instance.
*
* @param \Illuminate\Database\Eloquent\Model $parent
* @param string $related
* @param string $collection
* @return void
*/
public function __construct(Model $parent, $related, $collection)
{
$this->collection = $collection;
parent::__construct($parent, $related);
}
/**
* Get the results of the relationship.
*
* @return Illuminate\Database\Eloquent\Collection
*/
public function getResults()
{
$models = new Collection();
$modelsAttributes = $this->parent->getAttribute($this->collection);
if (is_array($modelsAttributes))
{
foreach ($modelsAttributes as $attributes)
{
$models->push(new $this->related($attributes));
}
}
return $models;
}
/**
* Create a new instance and attach it to the parent model.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*/
public function build(array $attributes)
{
if ( ! isset($attributes['_id'])) $attributes['_id'] = new MongoId;
$collection = $this->parent->getAttribute($this->collection);
$collection[''.$attributes['_id']] = $attributes;
$this->parent->setAttribute($this->collection, $collection);
return new $this->related($attributes);
}
/**
* Attach an instance to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function add($model)
{
return $this->build($model->toArray());
}
/**
* Create a new instance, attach it to the parent model and save this model.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*/
public function create(array $attributes)
{
$instance = $this->build($attributes);
$this->parent->save();
return $instance;
}
/**
* Attach a model instance to the parent model and save this model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function push($model)
{
return $this->create($model->toArray());
}
/**
* Create an array of new instances and attach them to the parent model.
*
* @param array|Traversable $modelsAttributes
* @return array
*/
public function buildMany($modelsAttributes)
{
$instances = array();
foreach ($modelsAttributes as $attributes)
{
$instances[] = $this->build($attributes);
}
return $instances;
}
/**
* Attach an array of new instances to the parent model.
*
* @param array|Traversable $models
* @return array
*/
public function addMany($models)
{
$modelsAttributes = $this->getAttributesOf($models);
return $this->buildMany($modelsAttributes);
}
/**
* Create an array of new instances, attach them to the parent model and save this model.
*
* @param array|Traversable $modelsAttributes
* @return array
*/
public function createMany($modelsAttributes)
{
$instances = $this->buildMany($modelsAttributes);
$this->parent->save();
return $instances;
}
/**
* Attach an array of new instances to the parent model and save this model.
*
* @param array|Traversable $models
* @return array
*/
public function pushMany($models)
{
$modelsAttributes = $this->getAttributesOf($models);
return $this->createMany($modelsAttributes);
}
/**
* Transform a list of models to a list of models' attributes
*
* @param array|Traversable $models
* @return array
*/
protected function getAttributesOf($models)
{
$modelsAttributes = array();
foreach ($models as $key => $model)
{
$modelsAttributes[$key] = $model->getAttributes();
}
return $modelsAttributes;
}
}
<?php
use Illuminate\Database\Eloquent\Collection;
class RelationsTest extends PHPUnit_Framework_TestCase {
public function setUp() {
......@@ -279,4 +281,50 @@ class RelationsTest extends PHPUnit_Framework_TestCase {
$photo = Photo::first();
$this->assertEquals($photo->imageable->name, $user->name);
}
public function testEmbedsManySaveOneRelated()
{
$user = User::create(array('name' => 'John Doe'));
$user->addresses()->create(array('city' => 'Paris'));
$user->addresses()->push(new Address(array('city' => 'London')));
$user->addresses()->build(array('city' => 'Bruxelles'));
$user->addresses()->add(new Address(array('city' => 'New-York')));
$freshUser = User::find($user->id);
$this->assertEquals(array('Paris', 'London', 'Bruxelles', 'New-York'), $user->addresses->lists('city'));
$this->assertEquals(array('Paris', 'London'), $freshUser->addresses->lists('city'));
$user->save();
$freshUser = User::find($user->id);
$this->assertEquals(array('Paris', 'London', 'Bruxelles', 'New-York'), $freshUser->addresses->lists('city'));
}
public function testEmbedsManySaveManyRelated()
{
$user = User::create(array('name' => 'John Doe'));
$user->addresses()->createMany(array(array('city' => 'Paris'), array('city' => 'Rouen')));
$user->addresses()->pushMany(array(new Address(array('city' => 'London')), new Address(array('city' => 'Bristol'))));
$user->addresses()->buildMany(array(array('city' => 'Bruxelles')));
$user->addresses()->addMany(new Collection(array(new Address(array('city' => 'New-York')))));
$freshUser = User::find($user->id);
$this->assertEquals(array('Paris', 'Rouen', 'London', 'Bristol', 'Bruxelles', 'New-York'), $user->addresses->lists('city'));
$this->assertEquals(array('Paris', 'Rouen', 'London', 'Bristol'), $freshUser->addresses->lists('city'));
$user->save();
$freshUser = User::find($user->id);
$this->assertEquals(array('Paris', 'Rouen', 'London', 'Bristol', 'Bruxelles', 'New-York'), $freshUser->addresses->lists('city'));
}
public function testEmbedsManyCreateId()
{
$user = new User(array('name' => 'John Doe'));
$user->addresses()->build(array('city' => 'Bruxelles'));
$this->assertInstanceOf('MongoId', $user->addresses->first()->_id);
}
}
<?php
use Jenssegers\Mongodb\Model as Eloquent;
class Address extends Eloquent {
protected static $unguarded = true;
}
......@@ -51,6 +51,11 @@ class User extends Eloquent implements UserInterface, RemindableInterface {
return $this->morphMany('Photo', 'imageable');
}
public function addresses()
{
return $this->embedsMany('Address');
}
/**
* Get the unique identifier for the user.
*
......
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