Commit f037b6ae authored by Jens Segers's avatar Jens Segers

Testing new 2-way-relationships

parent 765e6670
...@@ -13,6 +13,7 @@ services: mongodb ...@@ -13,6 +13,7 @@ services: mongodb
before_script: before_script:
- echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- mysql -e 'create database phpunit;'
- composer self-update - composer self-update
- composer install --dev --no-interaction - composer install --dev --no-interaction
......
...@@ -21,7 +21,8 @@ ...@@ -21,7 +21,8 @@
}, },
"autoload": { "autoload": {
"psr-0": { "psr-0": {
"Jenssegers\\Mongodb": "src/" "Jenssegers\\Mongodb": "src/",
"Jenssegers\\Eloquent": "src/"
} }
}, },
"minimum-stability": "dev" "minimum-stability": "dev"
......
<?php namespace Jenssegers\Eloquent;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jenssegers\Mongodb\Relations\BelongsTo;
use Jenssegers\Mongodb\Relations\BelongsToMany;
use Jenssegers\Mongodb\Query\Builder as QueryBuilder;
abstract class Model extends \Illuminate\Database\Eloquent\Model {
/**
* Define a one-to-one relationship.
*
* @param string $related
* @param string $foreignKey
* @param string $localKey
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function hasOne($related, $foreignKey = null, $localKey = null)
{
// Check if it is a relation with an original model.
if (!is_subclass_of($related, 'Jenssegers\Mongodb\Model'))
{
return parent::hasOne($related, $foreignKey, $localKey);
}
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
$localKey = $localKey ?: $this->getKeyName();
return new HasOne($instance->newQuery(), $this, $foreignKey, $localKey);
}
/**
* Define a one-to-many relationship.
*
* @param string $related
* @param string $foreignKey
* @param string $localKey
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function hasMany($related, $foreignKey = null, $localKey = null)
{
// Check if it is a relation with an original model.
if (!is_subclass_of($related, 'Jenssegers\Mongodb\Model'))
{
return parent::hasMany($related, $foreignKey, $localKey);
}
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
$localKey = $localKey ?: $this->getKeyName();
return new HasMany($instance->newQuery(), $this, $foreignKey, $localKey);
}
/**
* Define an inverse one-to-one or many relationship.
*
* @param string $related
* @param string $foreignKey
* @param string $otherKey
* @param string $relation
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function belongsTo($related, $foreignKey = null, $otherKey = null, $relation = null)
{
// Check if it is a relation with an original model.
if (!is_subclass_of($related, 'Jenssegers\Mongodb\Model'))
{
return parent::belongsTo($related, $foreignKey, $otherKey, $relation);
}
// If no relation name was given, we will use this debug backtrace to extract
// the calling method's name and use that as the relationship name as most
// of the time this will be what we desire to use for the relatinoships.
if (is_null($relation))
{
list(, $caller) = debug_backtrace(false);
$relation = $caller['function'];
}
// If no foreign key was supplied, we can use a backtrace to guess the proper
// foreign key name by using the name of the relationship function, which
// when combined with an "_id" should conventionally match the columns.
if (is_null($foreignKey))
{
$foreignKey = snake_case($relation).'_id';
}
$instance = new $related;
// Once we have the foreign key names, we'll just create a new Eloquent query
// for the related models and returns the relationship instance which will
// actually be responsible for retrieving and hydrating every relations.
$query = $instance->newQuery();
$otherKey = $otherKey ?: $instance->getKeyName();
return new BelongsTo($query, $this, $foreignKey, $otherKey, $relation);
}
/**
* Define a many-to-many relationship.
*
* @param string $related
* @param string $collection
* @param string $foreignKey
* @param string $otherKey
* @param string $relation
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function belongsToMany($related, $collection = null, $foreignKey = null, $otherKey = null, $relation = null)
{
// Check if it is a relation with an original model.
if (!is_subclass_of($related, 'Jenssegers\Mongodb\Model'))
{
return parent::belongsToMany($related, $collection, $foreignKey, $otherKey, $relation);
}
// If no relationship name was passed, we will pull backtraces to get the
// name of the calling function. We will use that function name as the
// title of this relation since that is a great convention to apply.
if (is_null($relation))
{
$caller = $this->getBelongsToManyCaller();
$name = $caller['function'];
}
// First, we'll need to determine the foreign key and "other key" for the
// relationship. Once we have determined the keys we'll make the query
// instances as well as the relationship instances we need for this.
$foreignKey = $foreignKey ?: $this->getForeignKey() . 's';
$instance = new $related;
$otherKey = $otherKey ?: $instance->getForeignKey() . 's';
// If no table name was provided, we can guess it by concatenating the two
// models using underscores in alphabetical order. The two model names
// are transformed to snake case from their default CamelCase also.
if (is_null($collection))
{
$collection = $instance->getTable();
}
// Now we're ready to create a new query builder for the related model and
// the relationship instances for the relation. The relations will set
// appropriate query constraint and entirely manages the hydrations.
$query = $instance->newQuery();
return new BelongsToMany($query, $this, $collection, $foreignKey, $otherKey, $relation);
}
/**
* Get a new query builder instance for the connection.
*
* @return Builder
*/
protected function newBaseQueryBuilder()
{
$connection = $this->getConnection();
// Check the connection type
if ($connection instanceof \Jenssegers\Mongodb\Connection)
{
return new QueryBuilder($connection);
}
return parent::newBaseQueryBuilder();
}
}
...@@ -14,7 +14,7 @@ use DateTime; ...@@ -14,7 +14,7 @@ use DateTime;
use MongoId; use MongoId;
use MongoDate; use MongoDate;
abstract class Model extends \Illuminate\Database\Eloquent\Model { abstract class Model extends \Jenssegers\Eloquent\Model {
/** /**
* The collection associated with the model. * The collection associated with the model.
...@@ -121,166 +121,6 @@ abstract class Model extends \Illuminate\Database\Eloquent\Model { ...@@ -121,166 +121,6 @@ abstract class Model extends \Illuminate\Database\Eloquent\Model {
return parent::getTable(); return parent::getTable();
} }
/**
* Define a one-to-one relationship.
*
* @param string $related
* @param string $foreignKey
* @param string $localKey
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function hasOne($related, $foreignKey = null, $localKey = null)
{
// Check if it is a relation with an original model.
if (!is_subclass_of($related, 'Jenssegers\Mongodb\Model'))
{
return parent::hasOne($related, $foreignKey, $localKey);
}
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
$localKey = $localKey ?: $this->getKeyName();
return new HasOne($instance->newQuery(), $this, $foreignKey, $localKey);
}
/**
* Define a one-to-many relationship.
*
* @param string $related
* @param string $foreignKey
* @param string $localKey
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function hasMany($related, $foreignKey = null, $localKey = null)
{
// Check if it is a relation with an original model.
if (!is_subclass_of($related, 'Jenssegers\Mongodb\Model'))
{
return parent::hasMany($related, $foreignKey, $localKey);
}
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
$localKey = $localKey ?: $this->getKeyName();
return new HasMany($instance->newQuery(), $this, $foreignKey, $localKey);
}
/**
* Define an inverse one-to-one or many relationship.
*
* @param string $related
* @param string $foreignKey
* @param string $otherKey
* @param string $relation
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function belongsTo($related, $foreignKey = null, $otherKey = null, $relation = null)
{
// Check if it is a relation with an original model.
if (!is_subclass_of($related, 'Jenssegers\Mongodb\Model'))
{
return parent::belongsTo($related, $foreignKey, $otherKey, $relation);
}
// If no relation name was given, we will use this debug backtrace to extract
// the calling method's name and use that as the relationship name as most
// of the time this will be what we desire to use for the relatinoships.
if (is_null($relation))
{
list(, $caller) = debug_backtrace(false);
$relation = $caller['function'];
}
// If no foreign key was supplied, we can use a backtrace to guess the proper
// foreign key name by using the name of the relationship function, which
// when combined with an "_id" should conventionally match the columns.
if (is_null($foreignKey))
{
$foreignKey = snake_case($relation).'_id';
}
$instance = new $related;
// Once we have the foreign key names, we'll just create a new Eloquent query
// for the related models and returns the relationship instance which will
// actually be responsible for retrieving and hydrating every relations.
$query = $instance->newQuery();
$otherKey = $otherKey ?: $instance->getKeyName();
return new BelongsTo($query, $this, $foreignKey, $otherKey, $relation);
}
/**
* Define a many-to-many relationship.
*
* @param string $related
* @param string $collection
* @param string $foreignKey
* @param string $otherKey
* @param string $relation
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function belongsToMany($related, $collection = null, $foreignKey = null, $otherKey = null, $relation = null)
{
// Check if it is a relation with an original model.
if (!is_subclass_of($related, 'Jenssegers\Mongodb\Model'))
{
return parent::belongsToMany($related, $collection, $foreignKey, $otherKey, $relation);
}
// If no relationship name was passed, we will pull backtraces to get the
// name of the calling function. We will use that function name as the
// title of this relation since that is a great convention to apply.
if (is_null($relation))
{
$caller = $this->getBelongsToManyCaller();
$name = $caller['function'];
}
// First, we'll need to determine the foreign key and "other key" for the
// relationship. Once we have determined the keys we'll make the query
// instances as well as the relationship instances we need for this.
$foreignKey = $foreignKey ?: $this->getForeignKey() . 's';
$instance = new $related;
$otherKey = $otherKey ?: $instance->getForeignKey() . 's';
// If no table name was provided, we can guess it by concatenating the two
// models using underscores in alphabetical order. The two model names
// are transformed to snake case from their default CamelCase also.
if (is_null($collection))
{
$collection = $instance->getTable();
}
// Now we're ready to create a new query builder for the related model and
// the relationship instances for the relation. The relations will set
// appropriate query constraint and entirely manages the hydrations.
$query = $instance->newQuery();
return new BelongsToMany($query, $this, $collection, $foreignKey, $otherKey, $relation);
}
/**
* Get a new query builder instance for the connection.
*
* @return Builder
*/
protected function newBaseQueryBuilder()
{
return new QueryBuilder($this->getConnection());
}
/** /**
* Set the array of model attributes. No checking is done. * Set the array of model attributes. No checking is done.
* *
......
...@@ -16,6 +16,7 @@ class ModelTest extends PHPUnit_Framework_TestCase { ...@@ -16,6 +16,7 @@ class ModelTest extends PHPUnit_Framework_TestCase {
{ {
$user = new User; $user = new User;
$this->assertInstanceOf('Jenssegers\Mongodb\Model', $user); $this->assertInstanceOf('Jenssegers\Mongodb\Model', $user);
$this->assertInstanceOf('Jenssegers\Mongodb\Connection', $user->getConnection());
$this->assertEquals(false, $user->exists); $this->assertEquals(false, $user->exists);
$this->assertEquals('users', $user->getTable()); $this->assertEquals('users', $user->getTable());
$this->assertEquals('_id', $user->getKeyName()); $this->assertEquals('_id', $user->getKeyName());
......
...@@ -13,6 +13,7 @@ class RelationsTest extends PHPUnit_Framework_TestCase { ...@@ -13,6 +13,7 @@ class RelationsTest extends PHPUnit_Framework_TestCase {
Role::truncate(); Role::truncate();
Client::truncate(); Client::truncate();
Group::truncate(); Group::truncate();
MysqlUser::truncate();
} }
public function testHasMany() public function testHasMany()
...@@ -259,4 +260,40 @@ class RelationsTest extends PHPUnit_Framework_TestCase { ...@@ -259,4 +260,40 @@ class RelationsTest extends PHPUnit_Framework_TestCase {
$this->assertEquals($group->_id, $user->groups()->first()->_id); $this->assertEquals($group->_id, $user->groups()->first()->_id);
$this->assertEquals($user->_id, $group->users()->first()->_id); $this->assertEquals($user->_id, $group->users()->first()->_id);
} }
public function testMysqlModel()
{
// A bit dirty
MysqlUser::executeSchema();
$user = new MysqlUser;
$this->assertInstanceOf('MysqlUser', $user);
$this->assertInstanceOf('Illuminate\Database\MySqlConnection', $user->getConnection());
$user->name = "John Doe";
$user->save();
$this->assertTrue(is_int($user->id));
// Has many
$book = new Book(array('title' => 'Game of Thrones'));
$user->books()->save($book);
$user = MysqlUser::find($user->id); // refetch
$this->assertEquals(1, count($user->books));
$book = $user->books()->first(); // refetch
$this->assertEquals('John Doe', $book->mysqlAuthor->name);
// Has one
$role = new Role(array('type' => 'admin'));
$user->role()->save($role);
$user = MysqlUser::find($user->id); // refetch
$this->assertEquals('admin', $user->role->type);
$role = $user->role()->first(); // refetch
$this->assertEquals('John Doe', $role->mysqlUser->name);
// belongsToMany DOES NOT WORK YET
/*$client = new Client(array('name' => 'Pork Pies Ltd.'));
$user->clients()->save($client);
$user = MysqlUser::find($user->id); // refetch
$this->assertEquals(1, count($user->clients));*/
}
} }
...@@ -42,5 +42,6 @@ $reflection = new ReflectionClass('Jenssegers\Mongodb\Connection'); ...@@ -42,5 +42,6 @@ $reflection = new ReflectionClass('Jenssegers\Mongodb\Connection');
$app['db']->extend('mongodb', array($reflection, 'newInstance')); $app['db']->extend('mongodb', array($reflection, 'newInstance'));
# Static setup # Static setup
Model::setConnectionResolver($app['db']); \Jenssegers\Mongodb\Model::setConnectionResolver($app['db']);
\Jenssegers\Eloquent\Model::setConnectionResolver($app['db']);
DB::setFacadeApplication($app); DB::setFacadeApplication($app);
...@@ -12,6 +12,17 @@ return array( ...@@ -12,6 +12,17 @@ return array(
'host' => 'localhost', 'host' => 'localhost',
'database' => 'unittest', 'database' => 'unittest',
), ),
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'unittest',
'username' => 'travis',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
) )
); );
...@@ -14,4 +14,9 @@ class Book extends Eloquent { ...@@ -14,4 +14,9 @@ class Book extends Eloquent {
{ {
return $this->belongsTo('User', 'author_id'); return $this->belongsTo('User', 'author_id');
} }
public function mysqlAuthor()
{
return $this->belongsTo('MysqlUser', 'author_id');
}
} }
<?php
use \Illuminate\Support\Facades\Schema;
use Jenssegers\Eloquent\Model as Eloquent;
class MysqlUser extends Eloquent {
protected $connection = 'mysql';
protected $table = 'users';
protected static $unguarded = true;
public function books()
{
return $this->hasMany('Book', 'author_id');
}
public function items()
{
return $this->hasMany('Item');
}
public function role()
{
return $this->hasOne('Role', 'role_id');
}
public function clients()
{
return $this->belongsToMany('Client');
}
public function groups()
{
return $this->belongsToMany('Group', null, 'users', 'groups');
}
/**
* Check if we need to run the schema
* @return [type] [description]
*/
public static function executeSchema()
{
$schema = Schema::connection('mysql');
if (!$schema->hasColumn('users', 'id'))
{
Schema::connection('mysql')->table('users', function($table)
{
$table->increments('id');
});
}
if (!$schema->hasColumn('users', 'name'))
{
Schema::connection('mysql')->table('users', function($table)
{
$table->string('name');
});
}
}
}
...@@ -13,4 +13,9 @@ class Role extends Eloquent { ...@@ -13,4 +13,9 @@ class Role extends Eloquent {
return $this->belongsTo('User'); return $this->belongsTo('User');
} }
public function mysqlUser()
{
return $this->belongsTo('MysqlUser', 'role_id');
}
} }
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