diff --git a/CHANGELOG.md b/CHANGELOG.md index d9dfde6..0a91860 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. ### Added - Add support for enum default arguments using enum cases. [#1464 / d8vjork](https://github.com/barryvdh/laravel-ide-helper/pull/1464) - Add support for real-time facades in the helper file. [#1455 / filipac](https://github.com/barryvdh/laravel-ide-helper/pull/1455) +- Add support for relations with composite keys. [#1479 / calebdw](https://github.com/barryvdh/laravel-ide-helper/pull/1479) 2024-02-05, 2.14.0 ------------------ diff --git a/config/ide-helper.php b/config/ide-helper.php index 80afdb2..cec91c6 100644 --- a/config/ide-helper.php +++ b/config/ide-helper.php @@ -322,7 +322,8 @@ return [ | | When using custom relation types its possible for the class name to not contain | the proper return type of the relation. The key of the array is the relationship - | method name. The value of the array is the return type of the relation. + | method name. The value of the array is the return type of the relation ('many' + | or 'morphTo'). | e.g. `'relationName' => 'many'`. | */ diff --git a/src/Console/ModelsCommand.php b/src/Console/ModelsCommand.php index 8759a34..b5cb107 100644 --- a/src/Console/ModelsCommand.php +++ b/src/Console/ModelsCommand.php @@ -38,6 +38,7 @@ use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\MorphToMany; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Filesystem\Filesystem; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Str; use phpDocumentor\Reflection\Types\ContextFactory; @@ -843,12 +844,17 @@ class ModelsCommand extends Command $fkProp = $reflectionObj->getProperty('foreignKey'); $fkProp->setAccessible(true); - if ($relation === 'belongsTo') { - return isset($this->nullableColumns[$fkProp->getValue($relationObj)]) || - !in_array($fkProp->getValue($relationObj), $this->foreignKeyConstraintsColumns, true); + foreach (Arr::wrap($fkProp->getValue($relationObj)) as $foreignKey) { + if (isset($this->nullableColumns[$foreignKey])) { + return true; + } + + if (!in_array($foreignKey, $this->foreignKeyConstraintsColumns, true)) { + return true; + } } - return isset($this->nullableColumns[$fkProp->getValue($relationObj)]); + return false; } /** diff --git a/tests/Console/ModelsCommand/Relations/Models/CompositeBelongsToVariation.php b/tests/Console/ModelsCommand/Relations/Models/CompositeBelongsToVariation.php new file mode 100644 index 0000000..5fb041d --- /dev/null +++ b/tests/Console/ModelsCommand/Relations/Models/CompositeBelongsToVariation.php @@ -0,0 +1,41 @@ +belongsTo( + self::class, + ['not_null_column_with_foreign_key_constraint', 'not_null_column_with_foreign_key_constraint'], + ['not_null_column_with_foreign_key_constraint', 'not_null_column_with_foreign_key_constraint'], + ); + } + + public function nonNullableMixedWithoutForeignKeyConstraint(): BelongsTo + { + return $this->belongsTo( + self::class, + ['not_null_column_with_foreign_key_constraint', 'not_null_column_with_no_foreign_key_constraint'], + ['not_null_column_with_foreign_key_constraint', 'not_null_column_with_no_foreign_key_constraint'], + ); + } + + public function nullableMixedWithForeignKeyConstraint(): BelongsTo + { + return $this->belongsTo( + self::class, + ['nullable_column_with_no_foreign_key_constraint', 'not_null_column_with_foreign_key_constraint'], + ['nullable_column_with_no_foreign_key_constraint', 'not_null_column_with_foreign_key_constraint'], + ); + } +} diff --git a/tests/Console/ModelsCommand/Relations/Test.php b/tests/Console/ModelsCommand/Relations/Test.php index fd94d23..3995747 100644 --- a/tests/Console/ModelsCommand/Relations/Test.php +++ b/tests/Console/ModelsCommand/Relations/Test.php @@ -6,6 +6,7 @@ namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations; use Barryvdh\LaravelIdeHelper\Console\ModelsCommand; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\AbstractModelsCommand; +use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToAnyMorphedRelationType; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToAnyRelationType; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToManyRelationType; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToOneRelationType; diff --git a/tests/Console/ModelsCommand/Relations/__snapshots__/Test__test__1.php b/tests/Console/ModelsCommand/Relations/__snapshots__/Test__test__1.php index 863b180..2412f14 100644 --- a/tests/Console/ModelsCommand/Relations/__snapshots__/Test__test__1.php +++ b/tests/Console/ModelsCommand/Relations/__snapshots__/Test__test__1.php @@ -57,6 +57,68 @@ declare(strict_types=1); namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Models; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; + +/** + * Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Models\CompositeBelongsToVariation + * + * @property integer $id + * @property integer $not_null_column_with_foreign_key_constraint + * @property integer $not_null_column_with_no_foreign_key_constraint + * @property integer|null $nullable_column_with_foreign_key_constraint + * @property integer|null $nullable_column_with_no_foreign_key_constraint + * @property-read CompositeBelongsToVariation $bothNonNullableWithForeignKeyConstraint + * @property-read CompositeBelongsToVariation|null $nonNullableMixedWithoutForeignKeyConstraint + * @property-read CompositeBelongsToVariation|null $nullableMixedWithForeignKeyConstraint + * @method static \Illuminate\Database\Eloquent\Builder|CompositeBelongsToVariation newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|CompositeBelongsToVariation newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|CompositeBelongsToVariation query() + * @method static \Illuminate\Database\Eloquent\Builder|CompositeBelongsToVariation whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|CompositeBelongsToVariation whereNotNullColumnWithForeignKeyConstraint($value) + * @method static \Illuminate\Database\Eloquent\Builder|CompositeBelongsToVariation whereNotNullColumnWithNoForeignKeyConstraint($value) + * @method static \Illuminate\Database\Eloquent\Builder|CompositeBelongsToVariation whereNullableColumnWithForeignKeyConstraint($value) + * @method static \Illuminate\Database\Eloquent\Builder|CompositeBelongsToVariation whereNullableColumnWithNoForeignKeyConstraint($value) + * @mixin \Eloquent + */ +class CompositeBelongsToVariation extends Model +{ + public $table = 'belongs_to_variations'; + + public function bothNonNullableWithForeignKeyConstraint(): BelongsTo + { + // Note, duplicating the keys here for simplicity. + return $this->belongsTo( + self::class, + ['not_null_column_with_foreign_key_constraint', 'not_null_column_with_foreign_key_constraint'], + ['not_null_column_with_foreign_key_constraint', 'not_null_column_with_foreign_key_constraint'], + ); + } + + public function nonNullableMixedWithoutForeignKeyConstraint(): BelongsTo + { + return $this->belongsTo( + self::class, + ['not_null_column_with_foreign_key_constraint', 'not_null_column_with_no_foreign_key_constraint'], + ['not_null_column_with_foreign_key_constraint', 'not_null_column_with_no_foreign_key_constraint'], + ); + } + + public function nullableMixedWithForeignKeyConstraint(): BelongsTo + { + return $this->belongsTo( + self::class, + ['nullable_column_with_no_foreign_key_constraint', 'not_null_column_with_foreign_key_constraint'], + ['nullable_column_with_no_foreign_key_constraint', 'not_null_column_with_foreign_key_constraint'], + ); + } +} +