Last active
August 29, 2015 14:17
-
-
Save massimoselvi/44190a8fd0f544a85158 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace app\support\stubs; | |
/** | |
* Fix relations | |
* @see https://github.com/laravel/framework/pull/6576 | |
* | |
*/ | |
use Illuminate\Database\Eloquent\Relations\HasOne; | |
use Illuminate\Database\Eloquent\Relations\HasMany; | |
use Illuminate\Database\Eloquent\Relations\MorphTo; | |
use Illuminate\Database\Eloquent\Relations\MorphOne; | |
use Illuminate\Database\Eloquent\Relations\MorphMany; | |
use Illuminate\Database\Eloquent\Relations\BelongsTo; | |
use Illuminate\Database\Eloquent\Relations\MorphToMany; | |
use Illuminate\Database\Eloquent\Model as OriginalModel; | |
use Illuminate\Database\Eloquent\Relations\BelongsToMany; | |
use Illuminate\Database\Eloquent\Relations\HasManyThrough; | |
abstract class Model extends OriginalModel | |
{ | |
/** | |
* Override connection of relations | |
* | |
* @var bool | |
*/ | |
protected $overrideConnection = false; | |
/** | |
* Begin querying the model on a given connection. | |
* | |
* @param string $connection | |
* @param bool $override | |
* @return \Illuminate\Database\Eloquent\Builder | |
*/ | |
public static function on($connection = null, $override = false) | |
{ | |
// First we will just create a fresh instance of this model, and then we can | |
// set the connection on the model so that it is be used for the queries | |
// we execute, as well as being set on each relationship we retrieve. | |
$instance = new static; | |
$instance->setConnection($connection, $override); | |
return $instance->newQuery(); | |
} | |
/** | |
* 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) | |
{ | |
$foreignKey = $foreignKey ?: $this->getForeignKey(); | |
$instance = new $related; | |
if ($this->overrideConnection) { | |
$instance->setConnection($this->getConnectionName()); | |
} | |
$localKey = $localKey ?: $this->getKeyName(); | |
return new HasOne($instance->newQuery(), $this, $instance->getTable() . '.' . $foreignKey, $localKey); | |
} | |
/** | |
* Define a polymorphic one-to-one relationship. | |
* | |
* @param string $related | |
* @param string $name | |
* @param string $type | |
* @param string $id | |
* @param string $localKey | |
* @return \Illuminate\Database\Eloquent\Relations\MorphOne | |
*/ | |
public function morphOne($related, $name, $type = null, $id = null, $localKey = null) | |
{ | |
$instance = new $related; | |
if ($this->overrideConnection) { | |
$instance->setConnection($this->getConnectionName()); | |
} | |
list($type, $id) = $this->getMorphs($name, $type, $id); | |
$table = $instance->getTable(); | |
$localKey = $localKey ?: $this->getKeyName(); | |
return new MorphOne($instance->newQuery(), $this, $table . '.' . $type, $table . '.' . $id, $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) | |
{ | |
// 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 relationships. | |
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; | |
if ($this->overrideConnection) { | |
$instance->setConnection($this->getConnectionName()); | |
} | |
// 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 polymorphic, inverse one-to-one or many relationship. | |
* | |
* @param string $name | |
* @param string $type | |
* @param string $id | |
* @return \Illuminate\Database\Eloquent\Relations\MorphTo | |
*/ | |
public function morphTo($name = null, $type = null, $id = null) | |
{ | |
// If no name is provided, we will use the backtrace to get the function name | |
// since that is most likely the name of the polymorphic interface. We can | |
// use that to get both the class and foreign key that will be utilized. | |
if (is_null($name)) { | |
list(, $caller) = debug_backtrace(false); | |
$name = snake_case($caller['function']); | |
} | |
list($type, $id) = $this->getMorphs($name, $type, $id); | |
// If the type value is null it is probably safe to assume we're eager loading | |
// the relationship. When that is the case we will pass in a dummy query as | |
// there are multiple types in the morph and we can't use single queries. | |
if (is_null($class = $this->$type)) { | |
return new MorphTo( | |
$this->newQuery(), $this, $id, null, $type, $name | |
); | |
} | |
// If we are not eager loading the relationship we will essentially treat this | |
// as a belongs-to style relationship since morph-to extends that class and | |
// we will pass in the appropriate values so that it behaves as expected. | |
else { | |
$instance = new $class; | |
if ($this->overrideConnection) { | |
$instance->setConnection($this->getConnectionName()); | |
} | |
return new MorphTo( | |
$instance->newQuery(), $this, $id, $instance->getKeyName(), $type, $name | |
); | |
} | |
} | |
/** | |
* 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) | |
{ | |
$foreignKey = $foreignKey ?: $this->getForeignKey(); | |
$instance = new $related; | |
if ($this->overrideConnection) { | |
$instance->setConnection($this->getConnectionName()); | |
} | |
$localKey = $localKey ?: $this->getKeyName(); | |
return new HasMany($instance->newQuery(), $this, $instance->getTable() . '.' . $foreignKey, $localKey); | |
} | |
/** | |
* Define a has-many-through relationship. | |
* | |
* @param string $related | |
* @param string $through | |
* @param string|null $firstKey | |
* @param string|null $secondKey | |
* @return \Illuminate\Database\Eloquent\Relations\HasManyThrough | |
*/ | |
public function hasManyThrough($related, $through, $firstKey = null, $secondKey = null) | |
{ | |
$through = new $through; | |
$related = new $related; | |
if ($this->overrideConnection) { | |
$through->setConnection($this->getConnectionName()); | |
$related->setConnection($this->getConnectionName()); | |
} | |
$firstKey = $firstKey ?: $this->getForeignKey(); | |
$secondKey = $secondKey ?: $through->getForeignKey(); | |
return new HasManyThrough($related->newQuery(), $this, $through, $firstKey, $secondKey); | |
} | |
/** | |
* Define a polymorphic one-to-many relationship. | |
* | |
* @param string $related | |
* @param string $name | |
* @param string $type | |
* @param string $id | |
* @param string $localKey | |
* @return \Illuminate\Database\Eloquent\Relations\MorphMany | |
*/ | |
public function morphMany($related, $name, $type = null, $id = null, $localKey = null) | |
{ | |
$instance = new $related; | |
if ($this->overrideConnection) { | |
$instance->setConnection($this->getConnectionName()); | |
} | |
// Here we will gather up the morph type and ID for the relationship so that we | |
// can properly query the intermediate table of a relation. Finally, we will | |
// get the table and create the relationship instances for the developers. | |
list($type, $id) = $this->getMorphs($name, $type, $id); | |
$table = $instance->getTable(); | |
$localKey = $localKey ?: $this->getKeyName(); | |
return new MorphMany($instance->newQuery(), $this, $table . '.' . $type, $table . '.' . $id, $localKey); | |
} | |
/** | |
* Define a many-to-many relationship. | |
* | |
* @param string $related | |
* @param string $table | |
* @param string $foreignKey | |
* @param string $otherKey | |
* @param string $relation | |
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany | |
*/ | |
public function belongsToMany($related, $table = null, $foreignKey = null, $otherKey = null, $relation = null) | |
{ | |
// 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)) { | |
$relation = $this->getBelongsToManyCaller(); | |
} | |
// 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(); | |
$instance = new $related; | |
if ($this->overrideConnection) { | |
$instance->setConnection($this->getConnectionName()); | |
} | |
$otherKey = $otherKey ?: $instance->getForeignKey(); | |
// 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($table)) { | |
$table = $this->joiningTable($related); | |
} | |
// 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, $table, $foreignKey, $otherKey, $relation); | |
} | |
/** | |
* Define a polymorphic many-to-many relationship. | |
* | |
* @param string $related | |
* @param string $name | |
* @param string $table | |
* @param string $foreignKey | |
* @param string $otherKey | |
* @param bool $inverse | |
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany | |
*/ | |
public function morphToMany($related, $name, $table = null, $foreignKey = null, $otherKey = null, $inverse = false) | |
{ | |
$caller = $this->getBelongsToManyCaller(); | |
// First, we will need to determine the foreign key and "other key" for the | |
// relationship. Once we have determined the keys we will make the query | |
// instances, as well as the relationship instances we need for these. | |
$foreignKey = $foreignKey ?: $name . '_id'; | |
$instance = new $related; | |
if ($this->overrideConnection) { | |
$instance->setConnection($this->getConnectionName()); | |
} | |
$otherKey = $otherKey ?: $instance->getForeignKey(); | |
// Now we're ready to create a new query builder for this related model and | |
// the relationship instances for this relation. This relations will set | |
// appropriate query constraints then entirely manages the hydrations. | |
$query = $instance->newQuery(); | |
$table = $table ?: str_plural($name); | |
return new MorphToMany( | |
$query, $this, $name, $table, $foreignKey, | |
$otherKey, $caller, $inverse | |
); | |
} | |
/** | |
* Set the connection associated with the model. | |
* | |
* @param string $name | |
* @param bool $override | |
* @return $this | |
*/ | |
public function setConnection($name, $override = false) | |
{ | |
$this->overrideConnection = $override; | |
$this->connection = $name; | |
return $this; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment