Skip to content

Commit

Permalink
Support table aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
staudenmeir committed Dec 24, 2019
1 parent 74263ea commit ce2af1c
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 12 deletions.
31 changes: 31 additions & 0 deletions README.md
Expand Up @@ -81,6 +81,37 @@ class Comment extends Model
}
```

### Table Aliases

If your relationship path contains the same model multiple times, you can specify a table alias (Laravel 6+):

```php
class Comment extends Model
{
use \Znck\Eloquent\Traits\BelongsToThrough;

public function grandparent()
{
return $this->belongsToThrough(
'App\Comment',
'App\Comment as alias',
null,
'',
['App\Comment' => 'parent_id']
);
}
}
```

Use the `HasTableAlias` trait in the models you are aliasing:

```php
class Comment extends Model
{
use \Znck\Eloquent\Traits\HasTableAlias;
}
```

### Soft Deleting

By default, soft-deleted intermediate models will be excluded from the result. Use `withTrashed()` to include them:
Expand Down
8 changes: 3 additions & 5 deletions src/Relations/BelongsToThrough.php
Expand Up @@ -89,15 +89,13 @@ protected function performJoins(Builder $query = null)
$query = $query ?: $this->query;

foreach ($this->throughParents as $i => $model) {
$table = $model->getTable();

$predecessor = $i > 0 ? $this->throughParents[$i - 1] : $this->related;

$first = $table.'.'.$this->getForeignKeyName($predecessor);
$first = $model->qualifyColumn($this->getForeignKeyName($predecessor));

$second = $predecessor->getQualifiedKeyName();

$query->join($table, $first, '=', $second);
$query->join($model->getTable(), $first, '=', $second);

if ($this->hasSoftDeletes($model)) {
$this->query->whereNull($model->getQualifiedDeletedAtColumn());
Expand All @@ -113,7 +111,7 @@ protected function performJoins(Builder $query = null)
*/
protected function getForeignKeyName(Model $model)
{
$table = $model->getTable();
$table = explode(' as ', $model->getTable())[0];

if (array_key_exists($table, $this->foreignKeyLookup)) {
return $this->foreignKeyLookup[$table];
Expand Down
23 changes: 21 additions & 2 deletions src/Traits/BelongsToThrough.php
Expand Up @@ -33,8 +33,7 @@ public function belongsToThrough($related, $through, $localKey = null, $prefix =
$model = $model[0];
}

/** @var \Illuminate\Database\Eloquent\Model $instance */
$instance = new $model;
$instance = $this->belongsToThroughParentInstance($model);

if ($foreignKey) {
$foreignKeys[$instance->getTable()] = $foreignKey;
Expand All @@ -54,6 +53,26 @@ public function belongsToThrough($related, $through, $localKey = null, $prefix =
return $this->newBelongsToThrough($relatedInstance->newQuery(), $this, $throughParents, $localKey, $prefix, $foreignKeys);
}

/**
* Create a through parent instance for a belongs-to-through relationship.
*
* @param string $model
* @return \Illuminate\Database\Eloquent\Model
*/
protected function belongsToThroughParentInstance($model)
{
$segments = preg_split('/\s+as\s+/i', $model);

/** @var \Illuminate\Database\Eloquent\Model $instance */
$instance = new $segments[0];

if (isset($segments[1])) {
$instance->setTable($instance->getTable().' as '.$segments[1]);
}

return $instance;
}

/**
* Instantiate a new BelongsToThrough relationship.
*
Expand Down
29 changes: 29 additions & 0 deletions src/Traits/HasTableAlias.php
@@ -0,0 +1,29 @@
<?php

namespace Znck\Eloquent\Traits;

use Illuminate\Support\Str;

trait HasTableAlias
{
/**
* Qualify the given column name by the model's table.
*
* @param string $column
* @return string
*/
public function qualifyColumn($column)
{
if (Str::contains($column, '.')) {
return $column;
}

$table = $this->getTable();

if (Str::contains($table, ' as ')) {
$table = explode(' as ', $table)[1];
}

return $table.'.'.$column;
}
}
7 changes: 7 additions & 0 deletions tests/BelongsToThroughTest.php
Expand Up @@ -50,6 +50,13 @@ public function testLazyLoadingWithDefault()
$this->assertFalse($country->exists);
}

public function testLazyLoadingWithAlias()
{
$comment = Comment::find(35)->grandparent;

$this->assertEquals(33, $comment->id);
}

public function testEagerLoading()
{
$comments = Comment::with('country')->get();
Expand Down
9 changes: 9 additions & 0 deletions tests/Models/Comment.php
Expand Up @@ -2,8 +2,12 @@

namespace Tests\Models;

use Znck\Eloquent\Traits\HasTableAlias;

class Comment extends Model
{
use HasTableAlias;

public function country()
{
return $this->belongsToThrough(Country::class, [User::class, Post::class])->withDefault();
Expand All @@ -25,6 +29,11 @@ public function countryWithPrefix()
return $this->belongsToThrough(Country::class, [User::class, Post::class], null, 'custom_');
}

public function grandparent()
{
return $this->belongsToThrough(self::class, self::class.' as alias', null, '', [self::class => 'parent_id']);
}

public function user()
{
return $this->belongsToThrough(User::class, Post::class);
Expand Down
11 changes: 6 additions & 5 deletions tests/TestCase.php
Expand Up @@ -59,6 +59,7 @@ protected function migrate()
$table->increments('id');
$table->unsignedInteger('post_id')->nullable();
$table->unsignedInteger('custom_post_id')->nullable();
$table->unsignedInteger('parent_id')->nullable();
});
}

Expand All @@ -84,11 +85,11 @@ protected function seed()
Post::create(['id' => 23, 'user_id' => 13, 'custom_user_id' => null]);
Post::create(['id' => 24, 'user_id' => null, 'custom_user_id' => 11]);

Comment::create(['id' => 31, 'post_id' => 21, 'custom_post_id' => null]);
Comment::create(['id' => 32, 'post_id' => 22, 'custom_post_id' => null]);
Comment::create(['id' => 33, 'post_id' => 23, 'custom_post_id' => null]);
Comment::create(['id' => 34, 'post_id' => null, 'custom_post_id' => 21]);
Comment::create(['id' => 35, 'post_id' => null, 'custom_post_id' => 24]);
Comment::create(['id' => 31, 'post_id' => 21, 'custom_post_id' => null, 'parent_id' => null]);
Comment::create(['id' => 32, 'post_id' => 22, 'custom_post_id' => null, 'parent_id' => null]);
Comment::create(['id' => 33, 'post_id' => 23, 'custom_post_id' => null, 'parent_id' => null]);
Comment::create(['id' => 34, 'post_id' => null, 'custom_post_id' => 21, 'parent_id' => 33]);
Comment::create(['id' => 35, 'post_id' => null, 'custom_post_id' => 24, 'parent_id' => 34]);

Model::reguard();
}
Expand Down

0 comments on commit ce2af1c

Please sign in to comment.