Skip to content

Commit 1d067bf

Browse files
Ability to customize pivot table name (#234)
1 parent fcb2cfe commit 1d067bf

10 files changed

+287
-6
lines changed

src/Generators/MigrationGenerator.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ protected function buildPivotTableDefinition(array $segments)
204204
$definition = '';
205205

206206
foreach ($segments as $segment) {
207-
$column = Str::lower($segment);
207+
$column = Str::before(Str::lower($segment), ':');
208208
$references = 'id';
209209
$on = Str::plural($column);
210210
$foreign = Str::singular($column) . '_' . $references;
@@ -292,10 +292,22 @@ protected function getPivotClassName(array $segments)
292292

293293
protected function getPivotTableName(array $segments)
294294
{
295+
$isCustom = collect($segments)
296+
->filter(function ($segment) {
297+
return Str::contains($segment, ':');
298+
})->first();
299+
300+
if ($isCustom) {
301+
$table = Str::after($isCustom, ':');
302+
303+
return $table;
304+
}
305+
295306
$segments = array_map(function ($name) {
296307
return Str::snake($name);
297308
}, $segments);
298309
sort($segments);
310+
299311
return strtolower(implode('_', $segments));
300312
}
301313

src/Generators/ModelGenerator.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -160,21 +160,24 @@ private function buildRelationships(Model $model)
160160
}
161161
}
162162

163-
$class = Str::studly($class ?? $method_name);
163+
$class_name = Str::studly($class ?? $method_name);
164164

165165
if ($type === 'morphTo') {
166166
$relationship = sprintf('$this->%s()', $type);
167167
} elseif ($type === 'morphMany' || $type === 'morphOne') {
168168
$relation = Str::lower(Str::singular($column_name)) . 'able';
169-
$relationship = sprintf('$this->%s(%s::class, \'%s\')', $type, '\\' . $model->fullyQualifiedNamespace() . '\\' . $class, $relation);
169+
$relationship = sprintf('$this->%s(%s::class, \'%s\')', $type, '\\' . $model->fullyQualifiedNamespace() . '\\' . $class_name, $relation);
170170
} elseif (!is_null($key)) {
171-
$relationship = sprintf('$this->%s(%s::class, \'%s\', \'%s\')', $type, '\\' . $model->fullyQualifiedNamespace() . '\\' . $class, $column_name, $key);
171+
$relationship = sprintf('$this->%s(%s::class, \'%s\', \'%s\')', $type, '\\' . $model->fullyQualifiedNamespace() . '\\' . $class_name, $column_name, $key);
172+
} elseif (!is_null($class) && $type === 'belongsToMany') {
173+
$relationship = sprintf('$this->%s(%s::class, \'%s\')', $type, '\\' . $model->fullyQualifiedNamespace() . '\\' . $class_name, $column_name);
174+
$column_name = $class;
172175
} else {
173-
$relationship = sprintf('$this->%s(%s::class)', $type, '\\' . $model->fullyQualifiedNamespace() . '\\' . $class);
176+
$relationship = sprintf('$this->%s(%s::class)', $type, '\\' . $model->fullyQualifiedNamespace() . '\\' . $class_name);
174177
}
175178

176179
if ($type === 'morphTo') {
177-
$method_name = Str::lower($class);
180+
$method_name = Str::lower($class_name);
178181
} elseif (in_array($type, ['hasMany', 'belongsToMany', 'morphMany'])) {
179182
$method_name = Str::plural($column_name);
180183
}

tests/Feature/Generator/MigrationGeneratorTest.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,64 @@ public function output_does_not_duplicate_pivot_table_migration_laravel6()
390390
$this->assertEquals(['created' => [$company_migration, $people_migration, $pivot_migration]], $this->subject->output($tree));
391391
}
392392

393+
/**
394+
* @test
395+
*/
396+
public function output_also_creates_pivot_table_migration_with_custom_name()
397+
{
398+
$this->files->expects('stub')
399+
->with('migration.stub')
400+
->andReturn(file_get_contents('stubs/migration.stub'));
401+
402+
$now = Carbon::now();
403+
Carbon::setTestNow($now);
404+
405+
$model_migration = str_replace('timestamp', $now->format('Y_m_d_His'), 'database/migrations/timestamp_create_users_table.php');
406+
$pivot_migration = str_replace('timestamp', $now->format('Y_m_d_His'), 'database/migrations/timestamp_create_test_table.php');
407+
408+
$this->files->expects('put')
409+
->with($model_migration, $this->fixture('migrations/custom-pivot-table-name-user.php'));
410+
$this->files->expects('put')
411+
->with($pivot_migration, $this->fixture('migrations/custom-pivot-table-name-test.php'));
412+
413+
$tokens = $this->blueprint->parse($this->fixture('definitions/custom-pivot-table-name.bp'));
414+
$tree = $this->blueprint->analyze($tokens);
415+
416+
$this->assertEquals(['created' => [$model_migration, $pivot_migration]], $this->subject->output($tree));
417+
}
418+
419+
/**
420+
* @test
421+
*/
422+
public function output_also_creates_pivot_table_migration_with_custom_name_laravel6()
423+
{
424+
$app = \Mockery::mock();
425+
$app->shouldReceive('version')
426+
->withNoArgs()
427+
->andReturn('6.0.0');
428+
App::swap($app);
429+
430+
$this->files->expects('stub')
431+
->with('migration.stub')
432+
->andReturn(file_get_contents('stubs/migration.stub'));
433+
434+
$now = Carbon::now();
435+
Carbon::setTestNow($now);
436+
437+
$model_migration = str_replace('timestamp', $now->format('Y_m_d_His'), 'database/migrations/timestamp_create_users_table.php');
438+
$pivot_migration = str_replace('timestamp', $now->format('Y_m_d_His'), 'database/migrations/timestamp_create_test_table.php');
439+
440+
$this->files->expects('put')
441+
->with($model_migration, $this->fixture('migrations/custom-pivot-table-name-user-laravel6.php'));
442+
$this->files->expects('put')
443+
->with($pivot_migration, $this->fixture('migrations/custom-pivot-table-name-test-laravel6.php'));
444+
445+
$tokens = $this->blueprint->parse($this->fixture('definitions/custom-pivot-table-name.bp'));
446+
$tree = $this->blueprint->analyze($tokens);
447+
448+
$this->assertEquals(['created' => [$model_migration, $pivot_migration]], $this->subject->output($tree));
449+
}
450+
393451
/**
394452
* @test
395453
*/

tests/Feature/Generator/ModelGeneratorTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,39 @@ public function output_generates_models_with_custom_namespace_correctly()
406406
$this->assertEquals(['created' => [$path]], $this->subject->output($tree));
407407
}
408408

409+
/**
410+
* @test
411+
*/
412+
public function output_generates_models_with_custom_pivot_columns()
413+
{
414+
$this->files->expects('stub')
415+
->with('model/class.stub')
416+
->andReturn(file_get_contents('stubs/model/class.stub'));
417+
$this->files->expects('stub')
418+
->with('model/fillable.stub')
419+
->andReturn(file_get_contents('stubs/model/fillable.stub'));
420+
$this->files->expects('stub')
421+
->with('model/casts.stub')
422+
->andReturn(file_get_contents('stubs/model/casts.stub'));
423+
$this->files->expects('stub')
424+
->with('model/method.stub')
425+
->andReturn(file_get_contents('stubs/model/method.stub'));
426+
$this->files->expects('stub')
427+
->with('model/hidden.stub')
428+
->andReturn(file_get_contents('stubs/model/hidden.stub'));
429+
430+
$this->files->expects('exists')
431+
->with('app')
432+
->andReturnTrue();
433+
$this->files->expects('put')
434+
->with('app/User.php', $this->fixture('models/custom-pivot-table-name.php'));
435+
436+
$tokens = $this->blueprint->parse($this->fixture('definitions/custom-pivot-table-name.bp'));
437+
$tree = $this->blueprint->analyze($tokens);
438+
439+
$this->assertEquals(['created' => ['app/User.php']], $this->subject->output($tree));
440+
}
441+
409442
public function modelTreeDataProvider()
410443
{
411444
return [
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
models:
2+
User:
3+
name: string
4+
remember_token: remembertoken
5+
relationships:
6+
belongsToMany: Account:test
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class CreateTestTable extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::create('test', function (Blueprint $table) {
17+
$table->unsignedBigInteger('account_id');
18+
$table->unsignedBigInteger('user_id');
19+
});
20+
}
21+
22+
/**
23+
* Reverse the migrations.
24+
*
25+
* @return void
26+
*/
27+
public function down()
28+
{
29+
Schema::dropIfExists('test');
30+
}
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class CreateTestTable extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::create('test', function (Blueprint $table) {
17+
$table->foreignId('account_id');
18+
$table->foreignId('user_id');
19+
});
20+
}
21+
22+
/**
23+
* Reverse the migrations.
24+
*
25+
* @return void
26+
*/
27+
public function down()
28+
{
29+
Schema::dropIfExists('test');
30+
}
31+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class CreateUsersTable extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::create('users', function (Blueprint $table) {
17+
$table->bigIncrements('id');
18+
$table->string('name');
19+
$table->rememberToken();
20+
$table->timestamps();
21+
});
22+
}
23+
24+
/**
25+
* Reverse the migrations.
26+
*
27+
* @return void
28+
*/
29+
public function down()
30+
{
31+
Schema::dropIfExists('users');
32+
}
33+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class CreateUsersTable extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::create('users', function (Blueprint $table) {
17+
$table->id();
18+
$table->string('name');
19+
$table->rememberToken();
20+
$table->timestamps();
21+
});
22+
}
23+
24+
/**
25+
* Reverse the migrations.
26+
*
27+
* @return void
28+
*/
29+
public function down()
30+
{
31+
Schema::dropIfExists('users');
32+
}
33+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace App;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
7+
class User extends Model
8+
{
9+
/**
10+
* The attributes that are mass assignable.
11+
*
12+
* @var array
13+
*/
14+
protected $fillable = [
15+
'name',
16+
];
17+
18+
/**
19+
* The attributes that should be hidden for serialization.
20+
*
21+
* @var array
22+
*/
23+
protected $hidden = [
24+
'remember_token',
25+
];
26+
27+
/**
28+
* The attributes that should be cast to native types.
29+
*
30+
* @var array
31+
*/
32+
protected $casts = [
33+
'id' => 'integer',
34+
];
35+
36+
37+
public function accounts()
38+
{
39+
return $this->belongsToMany(\App\Account::class, 'test');
40+
}
41+
}

0 commit comments

Comments
 (0)