diff --git a/src/Generators/ModelGenerator.php b/src/Generators/ModelGenerator.php index bb64a830..b4d394de 100644 --- a/src/Generators/ModelGenerator.php +++ b/src/Generators/ModelGenerator.php @@ -190,16 +190,20 @@ protected function buildRelationships(Model $model) foreach ($model->relationships() as $type => $references) { foreach ($references as $reference) { + // if reference starts with \ , we assume developer is using a fully namespaced model + $is_model_fqn = Str::startsWith($reference, '\\'); + $custom_template = $template; $key = null; $class = null; $column_name = $reference; - $method_name = Str::beforeLast($reference, '_id'); + $method_name = $is_model_fqn ? Str::afterLast($reference, '\\') : Str::beforeLast($reference, '_id'); if (Str::contains($reference, ':')) { [$foreign_reference, $column_name] = explode(':', $reference); - $method_name = Str::beforeLast($column_name, '_id'); + + $method_name = $is_model_fqn ? Str::afterLast($foreign_reference, '\\') : Str::beforeLast($column_name, '_id'); if (Str::contains($foreign_reference, '.')) { [$class, $key] = explode('.', $foreign_reference); @@ -207,34 +211,43 @@ protected function buildRelationships(Model $model) if ($key === 'id') { $key = null; } else { - $method_name = Str::lower($class); + $method_name = $is_model_fqn ? Str::lower(Str::afterLast($class, '\\')) : Str::lower($class); } } else { $class = $foreign_reference; } } - $class_name = Str::studly($class ?? $method_name); - $fqcn = $this->fullyQualifyModelReference($class_name) ?? $model->fullyQualifiedNamespace() . '\\' . $class_name; + // if full model namespace is proviced we will not try to infer it, + // we use the namespace as developer gives us + if ($is_model_fqn) { + $fqcn = $class ?? $column_name; + $class_name = Str::afterLast($fqcn, '\\'); + }else{ + $class_name = Str::studly($class ?? $method_name); + $fqcn = $this->fullyQualifyModelReference($class_name) ?? $model->fullyQualifiedNamespace() . '\\' . $class_name; + } + + $fqcn = Str::startsWith($fqcn, '\\') ? $fqcn : '\\'.$fqcn; if ($type === 'morphTo') { $relationship = sprintf('$this->%s()', $type); } elseif ($type === 'morphMany' || $type === 'morphOne') { $relation = Str::lower(Str::singular($column_name)) . 'able'; - $relationship = sprintf('$this->%s(%s::class, \'%s\')', $type, '\\' . $fqcn, $relation); + $relationship = sprintf('$this->%s(%s::class, \'%s\')', $type, $fqcn, $relation); } elseif (!is_null($key)) { - $relationship = sprintf('$this->%s(%s::class, \'%s\', \'%s\')', $type, '\\' . $fqcn, $column_name, $key); + $relationship = sprintf('$this->%s(%s::class, \'%s\', \'%s\')', $type, $fqcn, $column_name, $key); } elseif (!is_null($class) && $type === 'belongsToMany') { - $relationship = sprintf('$this->%s(%s::class, \'%s\')', $type, '\\' . $fqcn, $column_name); + $relationship = sprintf('$this->%s(%s::class, \'%s\')', $type, $fqcn, $column_name); $column_name = $class; } else { - $relationship = sprintf('$this->%s(%s::class)', $type, '\\' . $fqcn); + $relationship = sprintf('$this->%s(%s::class)', $type, $fqcn); } if ($type === 'morphTo') { $method_name = Str::lower($class_name); } elseif (in_array($type, ['hasMany', 'belongsToMany', 'morphMany'])) { - $method_name = Str::plural($column_name); + $method_name = Str::plural($is_model_fqn ? Str::afterLast($column_name, '\\') : $column_name); } if (Blueprint::supportsReturnTypeHits()) { diff --git a/tests/Feature/Generators/ModelGeneratorTest.php b/tests/Feature/Generators/ModelGeneratorTest.php index 33b2805e..07f66595 100644 --- a/tests/Feature/Generators/ModelGeneratorTest.php +++ b/tests/Feature/Generators/ModelGeneratorTest.php @@ -268,6 +268,38 @@ public function output_generates_relationships() $this->assertEquals(['created' => ['app/Subscription.php']], $this->subject->output($tree)); } + /** + * @test + * @environment-setup useLaravel8 + */ + public function output_generates_relationships_added_with_full_model_namespace() + { + $this->files->expects('stub') + ->with($this->modelStub) + ->andReturn($this->stub($this->modelStub)); + $this->files->expects('stub') + ->with('model.fillable.stub') + ->andReturn($this->stub('model.fillable.stub')); + $this->files->expects('stub') + ->with('model.casts.stub') + ->andReturn($this->stub('model.casts.stub')); + $this->files->expects('stub') + ->with('model.method.stub') + ->andReturn($this->stub('model.method.stub')); + + $this->files->expects('exists') + ->with('app') + ->andReturnTrue(); + + $this->files->expects('put') + ->with('app/Recurrency.php', $this->fixture('models/model-relationships-with-full-namespace-laravel8.php')); + + $tokens = $this->blueprint->parse($this->fixture('drafts/model-relationships-with-full-model-namespaces.yaml')); + $tree = $this->blueprint->analyze($tokens); + + $this->assertEquals(['created' => ['app/Recurrency.php']], $this->subject->output($tree)); + } + /** * @test * @environment-setup useLaravel8 diff --git a/tests/fixtures/drafts/model-relationships-with-full-model-namespaces.yaml b/tests/fixtures/drafts/model-relationships-with-full-model-namespaces.yaml new file mode 100644 index 00000000..7d016045 --- /dev/null +++ b/tests/fixtures/drafts/model-relationships-with-full-model-namespaces.yaml @@ -0,0 +1,8 @@ +models: + Recurrency: + user_id: id + product_id: uuid + relationships: + belongsToMany: \Some\Package\Team + hasMany: \Other\Package\Order + hasOne: \Other\Package\Duration, \App\MyCustom\Folder\Transaction diff --git a/tests/fixtures/models/model-relationships-with-full-namespace-laravel8.php b/tests/fixtures/models/model-relationships-with-full-namespace-laravel8.php new file mode 100644 index 00000000..6a50df69 --- /dev/null +++ b/tests/fixtures/models/model-relationships-with-full-namespace-laravel8.php @@ -0,0 +1,62 @@ + 'integer', + 'user_id' => 'integer', + ]; + + + public function teams() + { + return $this->belongsToMany(\Some\Package\Team::class); + } + + public function orders() + { + return $this->hasMany(\Other\Package\Order::class); + } + + public function duration() + { + return $this->hasOne(\Other\Package\Duration::class); + } + + public function transaction() + { + return $this->hasOne(\App\MyCustom\Folder\Transaction::class); + } + + public function user() + { + return $this->belongsTo(\App\User::class); + } + + public function product() + { + return $this->belongsTo(\App\Product::class); + } +}