امیر
2 سال پیش توسط امیر مطرح شد
6 پاسخ

مشکل eloquent در لاراول

سلام و وقت بخیر
ساختار جداول :

users
    id
    name

roles
    id
    name

properties
    id
    description

role_user
    id
    user_id
    role_id
    property_id

و روابط :

class User extends Model{
    public function roles(){
        return $this->belongsToMany(Role::class , 'role_user')->withPivot(['property_id']);
    }
}
class Role extends Model{
    public function users(){
        return $this->belongsToMany(User::class , 'role_user')->withPivot(['property_id']);
    }
}
class RoleUser extends Pivot{
    public function property(){
        return $this->belongsTo(Property::class);
    }
}

همه چیز اوکیه ولی وقتی میخوام role های یه user رو به اینصورت بگیرم به مشکل میخورم :

$result = User::with('roles')->findOrFail(1);

در واقع درسته ولی من میخوام property هم لود شه که نمیشه
حتی اینم تست کردم ولی نشد :

$result = User::with('roles.property')->findOrFail(1);

در واقع یه همچین چیزی میخوام برگرده :

{
    "data": {
        "id": 1,
        "name": "ali",
        "roles": [
            {
                "id": 1,
                "name": "test",
                "pivot": {
                    "user_id": 1,
                    "role_id": 1,
                    "property_id": 1 , 
                    "property" : {
                        "id" : 1 ,
                        "description" : "test"
                    }                   
                }
            }
        ]
    },
    "status": "success"
}

ممنون میشم کمک کنید


ثبت پرسش جدید
رضا پارسیان
تخصص : توسعه دهنده Php , Laravel
@Rp76 2 سال پیش مطرح شد
0

وقتی میزنی roles.property یعنی توی relation roles یک رابطه‌ای هست به اسم property که شما نداری.

اگر خروجی زیر رو می‌خوای باید اینکار رو بکنی

[
  {
    "id": 1,
    "name": "reza",
    "email": "info@rp76.ir",
    "email_verified_at": null,
    "created_at": null,
    "updated_at": null,
    "roles": [
      {
        "id": 1,
        "name": "admin",
        "created_at": null,
        "updated_at": null,
        "pivot": {
          "user_id": 1,
          "role_id": 1,
          "property_id": 1
        },
        "property": {
          "id": 1,
          "description": "zizigolo\r\n",
          "created_at": null,
          "updated_at": null,
          "laravel_through_key": 1
        }
      }
    ]
  }
]
class Role extends Model
{
    use HasFactory;

    public function users(){
        return $this->belongsToMany(User::class , 'role_user')->withPivot(['property_id']);
    }

    public function property(){
        return $this->hasOneThrough(Property::class,RoleUser::class,'property_id','id');
    }
}

البته من عادت دارم برای جداول pivot هم مدل درست می‌کنم.
ولی شما اینکار رو نمی‌کنید.

نکته‌ای که باید بهش توجه کنی اینه که اطلا این ساختار خراب و اشتباه هست.

چرا گفتم خرابه؟
شما گفتی یه کاربر هست که Role شماره یک رو داره به اسم Admin و امدی توی جدول دیگه‌ای گفتی این کاربر با اون role وصل بشه به این property ها توی جدول واسط!

خب Admin همیشه ادمین هست نیاز نیست براش به ازای هر کاربر توی جدول واسط یکسری اطلاعات ایجاد کنی.

وارد مباحث پیشفرته این تسک نمی‌شم چون من دقیقا نمیدونم شما چی نیاز دارید. مثلا اگر بگید خب شاید بخواد یه property اضافه بده بهش یا یچیزی ازش بگیره و .... اینطوری خیلی طولانی میشه بحث.

راحت ترین کار اینه شما بیاید
بگید این role هارو داریم و این role ها این property هارو داره.
حالا هر یوزر در یک لحظه فقط می‌تونی یک role داشته باشه.

دیتابیس:

    Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('role_id')->default('3');
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });

 Schema::create('role_properties', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('role_id');
            $table->unsignedBigInteger('property_id');
            $table->timestamps();
        });

البته باز هم این که یه جدول باشه برای role فقط توش اسم باشه و یه جدول دیگه برای property ها که باز یه اسم توشه اضافه کاریه ولی خب اگر دوست داری اینطوری پیش بری مشکلی نیست.

امیدوارم همین ها کافی باشه و نیاز به رابطه هاش نداشته باشید و خودتون بتونید اون رو اضافه کنید.

سیستم پیشنهادی خودم:

Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('role_id')->default('3');
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });

Schema::create('roles', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('scopes',4184);
            $table->timestamps();
        });

توی سیستم من چون همه چیز کاربر هست و توی هر درخواست نیازه اطلاعات مربوط به سطح دسترسی رو فراخوانی کنم ترجیح میدم با کمترین درخواست بهش برسم و دیتابیس رو مشغولش نکنم.

اطلاعات scope به صورت ارایه ذخیره شده!


رضا پارسیان
تخصص : توسعه دهنده Php , Laravel
@Rp76 2 سال پیش مطرح شد
0

سلام وقتتون بخیر!

خب خطا رو بذارید شاید کمکی کرد!


امیر
تخصص : دانش آموز
@amiramir1412E 2 سال پیش مطرح شد
0

@Rp76
ممنون از وقتی که گذاشتین.
وقتی این رو میزنم :

$result = User::with('roles')->findOrFail(1);

منطقا خطایی نداره ولی نمیره property رو بیاره صرفا role هارو میاره
و وقتی اینطوری میزنم :

$result = User::with('roles.property')->findOrFail(1);

این ارور میده و میگه رابطه ای به نام property در User وجود نداره که منطقیه چون این رابطه داخل pivot تعریف شده
حالا من میخوام property رو بیاره یعنی یه چیزی مثل همون json ای که پیام قبلی فرستادم و دقیقا نمیدونم چی بزنم تا همچین چیزی خروجی بده
البته پیشتر یه پکیج پیدا کردم ولی میخوام بدونم بدون پکیج چطوری پیاده کنم؟
https://github.com/ajcastro/eager-load-pivot-relations


مهدی
تخصص : Backend Developer
@mahdidv 2 سال پیش مطرح شد
0

خوب بهتر نیست اول find کنید کابر رو وقتی پیدا کرد بگین رابطه های اونو نشون بده؟
شما ظاهرا اول گفتیم راطه نشون بده بعد کاربر پیدا کردین


امیر
تخصص : دانش آموز
@amiramir1412E 2 سال پیش مطرح شد
0

@mahdidv
بله اینم میشه ولی در نهایت بازم همون مشکل وجود داره


رضا پارسیان
تخصص : توسعه دهنده Php , Laravel
@Rp76 2 سال پیش مطرح شد
0

وقتی میزنی roles.property یعنی توی relation roles یک رابطه‌ای هست به اسم property که شما نداری.

اگر خروجی زیر رو می‌خوای باید اینکار رو بکنی

[
  {
    "id": 1,
    "name": "reza",
    "email": "info@rp76.ir",
    "email_verified_at": null,
    "created_at": null,
    "updated_at": null,
    "roles": [
      {
        "id": 1,
        "name": "admin",
        "created_at": null,
        "updated_at": null,
        "pivot": {
          "user_id": 1,
          "role_id": 1,
          "property_id": 1
        },
        "property": {
          "id": 1,
          "description": "zizigolo\r\n",
          "created_at": null,
          "updated_at": null,
          "laravel_through_key": 1
        }
      }
    ]
  }
]
class Role extends Model
{
    use HasFactory;

    public function users(){
        return $this->belongsToMany(User::class , 'role_user')->withPivot(['property_id']);
    }

    public function property(){
        return $this->hasOneThrough(Property::class,RoleUser::class,'property_id','id');
    }
}

البته من عادت دارم برای جداول pivot هم مدل درست می‌کنم.
ولی شما اینکار رو نمی‌کنید.

نکته‌ای که باید بهش توجه کنی اینه که اطلا این ساختار خراب و اشتباه هست.

چرا گفتم خرابه؟
شما گفتی یه کاربر هست که Role شماره یک رو داره به اسم Admin و امدی توی جدول دیگه‌ای گفتی این کاربر با اون role وصل بشه به این property ها توی جدول واسط!

خب Admin همیشه ادمین هست نیاز نیست براش به ازای هر کاربر توی جدول واسط یکسری اطلاعات ایجاد کنی.

وارد مباحث پیشفرته این تسک نمی‌شم چون من دقیقا نمیدونم شما چی نیاز دارید. مثلا اگر بگید خب شاید بخواد یه property اضافه بده بهش یا یچیزی ازش بگیره و .... اینطوری خیلی طولانی میشه بحث.

راحت ترین کار اینه شما بیاید
بگید این role هارو داریم و این role ها این property هارو داره.
حالا هر یوزر در یک لحظه فقط می‌تونی یک role داشته باشه.

دیتابیس:

    Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('role_id')->default('3');
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });

 Schema::create('role_properties', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('role_id');
            $table->unsignedBigInteger('property_id');
            $table->timestamps();
        });

البته باز هم این که یه جدول باشه برای role فقط توش اسم باشه و یه جدول دیگه برای property ها که باز یه اسم توشه اضافه کاریه ولی خب اگر دوست داری اینطوری پیش بری مشکلی نیست.

امیدوارم همین ها کافی باشه و نیاز به رابطه هاش نداشته باشید و خودتون بتونید اون رو اضافه کنید.

سیستم پیشنهادی خودم:

Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('role_id')->default('3');
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });

Schema::create('roles', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('scopes',4184);
            $table->timestamps();
        });

توی سیستم من چون همه چیز کاربر هست و توی هر درخواست نیازه اطلاعات مربوط به سطح دسترسی رو فراخوانی کنم ترجیح میدم با کمترین درخواست بهش برسم و دیتابیس رو مشغولش نکنم.

اطلاعات scope به صورت ارایه ذخیره شده!


امیر
تخصص : دانش آموز
@amiramir1412E 2 سال پیش مطرح شد
0

@Rp76
خیلی ممنون بابت پاسختون
در مورد ساختار هم باید بگم که در واقع این جداولی که گفتم صرفا تستی بودن و اصل چیز دیگه ای بوده ولی ساختارش همینه وگرنه حرف شما درسته ولی خب این چیزی که من گفتم مثال بوده و صرفا ساختارش با اصل موضوع یکی بود.


برای ارسال پاسخ لازم است وارد شده یا ثبت‌نام کنید

ورود یا ثبت‌نام