【问题标题】:Laravel package base relationship modelsLaravel 包基础关系模型
【发布时间】:2022-01-27 07:13:16
【问题描述】:

在我们的 Web 应用程序中,我们希望有一个简单的包库 cms,因为我们有 userspackagesfeaturesuser_package 数据库表

  1. 每个users 可以有一个我们创建的package user_package 为此
  2. 每个user_package 属于许多users
  3. 每个user_package 都有packages
  4. 每个packages可以有很多我们创建的features features
  5. 每个features 属于许多packages

当我尝试让用户打包它时,我认为它应该是:

user->user_package->package->[feature]

我的模型:

class User extends Authenticatable
{
    //...

    public function user_package()
    {
        return $this->hasOne(UserPackage::class);
    }
}

class UserPackage extends Model
{
    public function package()
    {
        return $this->belongsTo(Package::class);
    }
}

class Package extends Model
{
    public function feature(): HasMany
    {
        return $this->hasMany(Features::class);
    }
}

class Features extends Model
{
    public function package(): BelongsToMany
    {
        return $this->belongsToMany(Package::class);
    }
}

迁移:

Schema::create('packages', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->text('description')->nullable()->default('');
    $table->timestamp('created_at')->useCurrent();
    $table->timestamp('updated_at')->useCurrent();
});

Schema::create('features', function (Blueprint $table) {
    $table->id();
    $table->foreignId('packages_id')->nullable()
          ->constrained()->cascadeOnUpdate()
          ->cascadeOnDelete();
    $table->string('title');
    $table->text('description')->nullable()->default('');
    $table->timestamp('created_at')->useCurrent();
    $table->timestamp('updated_at')->useCurrent();
});


Schema::create('user_packages', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()
        ->cascadeOnUpdate()
        ->cascadeOnDelete();
    $table->foreignId('packages_id')->nullable()->constrained()
        ->cascadeOnUpdate()
        ->cascadeOnDelete();
    $table->longText('features')->nullable()->default('');
    $table->integer('price');
    $table->dateTime('start_date');
    $table->dateTime('end_date');
    $table->timestamp('created_at')->useCurrent();
    $table->timestamp('update_at')->useCurrent();
});

现在当我尝试获取数据时,我在package 关系中得到null

Route::get('/test',function(){
   dd(auth()->user()->with(['user_package'=>function($query){
       $query->with(['package'=>function($package){
           $package->with('feature')->get();
       }])->first();
   }])->first());
});

输出:

App\Models\User {#1319 ▼
  #hidden: array:2 [▶]
  #casts: array:1 [▶]
  #connection: "mysql"
  #table: "users"
  ...
  #relations: array:1 [▼
    "user_package" => App\Models\UserPackage {#1570 ▼
      #connection: "mysql"
      #table: "user_packages"
      ...
      #dispatchesEvents: []
      #observables: []
      #relations: array:1 [▼
        "package" => null
      ]
      ...
    }

【问题讨论】:

    标签: php laravel


    【解决方案1】:

    我认为您问题的症结在于获取嵌套关系,就像auth()->user()->with('user_package.package.feature') 一样简单,但是您的关系存在问题。

    PackageFeature 之间的关系已损坏;因为features 表有一个package_id 列,一个特性根据定义不能“属于许多”包。

    class User extends Authenticatable
    {
        public function user_package(): HasOne
        {
            return $this->hasOne(UserPackage::class);
        }
    }
    
    class UserPackage extends Model
    {
        public function user(): BelongsTo
        {
            return $this->belongsTo(User::class);
        }
    
        public function package(): BelongsTo
        {
            return $this->belongsTo(Package::class);
        }
    }
    
    class Package extends Model
    {
        public function features(): HasMany
        {
            return $this->hasMany(Feature::class);
        }
    
        /**
         * It never hurts to define both ends of the relationship
         * even if they aren't being used
         */
        public function user_packages(): HasMany
        {
            return $this->hasMany(UserPackage::class);
        }
    }
    
    class Feature extends Model
    {
        public function package(): BelongsTo
        {
            return $this->belongsTo(Package::class);
        }
    }
    

    现在,使用关系,你可以得到包的特征:

    dump(Auth::user()->load('user_package.package.features'))
    

    我在上面的示例中纠正了一些命名问题 - 返回单个模型的关系方法应该是单数,其他应该是复数。类名不应该是复数(即Feature 而不是Features。)

    一般来说,如果它所做的只是连接两个模型,则无需创建数据透视类。我不打算讨论这个问题,因为它会产生更长的答案,但请记住这一点。

    这是个人喜好问题,但你的类名应该只有一个单词(即Subscription 而不是UserPackage),因为这样可以更直观地找出关系名称之类的东西。

    【讨论】:

    • 非常感谢。在收到undefined relationship [packages] 错误后,我将packages 更改为package,不幸的是我在package 关系上得到了空值,您可以看到此链接paste.debian.net/1225068 我更改了类名
    • 你的意思是 load 不是 with 因为用户已经被检索到
    • @DolDurma 您确认数据库中的数据了吗?我在我的项目中使用了类似的关系,没有任何问题。
    • @miken32 对不起,你说得对
    猜你喜欢
    • 1970-01-01
    • 2018-02-18
    • 1970-01-01
    • 1970-01-01
    • 2019-04-04
    • 1970-01-01
    • 2020-04-02
    相关资源
    最近更新 更多