ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 라라벨 "hasOneThrough" 관계를 사용한 중첩된 모델 간 연결 설정
    백엔드/laravel 2024. 1. 26. 12:03

     

    Laravel에서 "hasOneThrough" 관계는 세 번째 중간 모델을 통해 두 모델 간의 직접적인 연관을 정의하는 것을 말합니다. 이 관계는 두 번째 모델의 데이터를 검색하기 위해 중간 모델의 데이터에 액세스해야 하는 경우에 유용합니다.

     

    예를 들어 사용자(User)가 회사(Company)에 속하고 회사가 전화번호(PhoneNumber)를 가지고 있는 상황을 가정해봅시다. 전화번호는 회사에 속하지만 해당 정보를 가져오려면 사용자를 통해야 합니다. 이때 "hasOneThrough" 관계가 유용하게 사용될 수 있습니다.

     

    먼저, 회사(Company)와 전화번호(PhoneNumber)에 대한 모델과 마이그레이션을 생성해야 합니다. 아래는 CLI에서 Artisan 명령어를 사용하여 모델과 마이그레이션을 생성하는 예시입니다.

     

    php artisan make:model Company -m
    php artisan make:model PhoneNumber -m

     

    그런 다음 생성된 마이그레이션 파일에서 각 테이블의 구조를 정의합니다.

    이 예시에서는 users, companies, phone_numbers 테이블이 있고,

    각 테이블 간의 외래 키(Foreign Key) 관계를 설정합니다.

     

    회사(Company) 테이블 마이그레이션:

     

            Schema::create('companies', function (Blueprint $table) {
                $table->id();
                $table->string(column: 'name');
                $table->foreignId(column: 'user_id')->constrained(table: 'users')->cascadeOnDelete();
                $table->timestamps();
            });

     

    전화번호(PhoneNumber) 테이블 마이그레이션:

     

            Schema::create('phone_numbers', function (Blueprint $table) {
                $table->id();
                $table->string(column: 'number')->unique();
                $table->foreignId(column: 'company_id')->constrained(table: 'companies')->cascadeOnDelete();
                $table->timestamps();
            });

     

    이제 각 모델에는 채워넣을 수 있는 속성이 필요합니다.

    따라서 CompanyPhoneNumber 모델에서 $fillable 속성을 정의합니다.

     

    Company 모델: 

     

        protected $fillable = ['name', 'user_id'];

     

    PhoneNumber 모델:

     

        protected $fillable = ['number', 'company_id'];

     

     

    이제 User 모델에서 "hasOneThrough" 관계를 정의합니다.

    User 모델의 메서드 이름은 두 관련 모델의 이름을 알파벳 순서로 결합한 것을 따라야 합니다.

    따라서 companyPhoneNumber 메서드를 다음과 같이 정의할 수 있습니다.

     

        public function companyPhoneNumber()
        {
            return $this->hasOneThrough(
                related: PhoneNumber::class,
                through: Company::class,
                firstKey: 'user_id', // 회사 테이블에서의 외래 키
                secondKey: 'company_id', // 전화번호 테이블에서의 외래 키
                localKey: 'id', // 사용자 모델의 로컬 키
                secondLocalKey: 'id' // 회사 모델의 로컬 키
            );
        }

     

       hasOneThrough 메서드의 각 옵션에 대한 설명은 다음과 같습니다:

    1. 관계를 설정할 모델 ($related):
      • 설명: 연결할 모델(여기서는 PhoneNumber 모델)의 fully qualified name(네임스페이스 포함)을 나타냅니다.
      • 예시: PhoneNumber::class
    2. 중간 모델 ($through):
      • 설명: 연결된 모델들 사이의 중간에 있는 모델(여기서는 Company 모델)의 fully qualified name(네임스페이스 포함)입니다.
      • 예시: Company::class
    3. 외래 키로 사용할 연결 모델의 외래 키 ($firstKey):
      • 설명: 중간 모델에서 연결 모델을 참조하는 외래 키의 이름입니다. 여기서는 중간 모델(Company 모델)의 외래 키인 'user_id'입니다.
      • 예시: 'user_id'
    4. 외래 키로 사용할 대상 모델의 외래 키 ($secondKey):
      • 설명: 중간 모델을 통해 연결 모델에 참조하는 외래 키의 이름입니다. 여기서는 연결 모델(PhoneNumber 모델)의 외래 키인 'company_id'입니다.
      • 예시: 'company_id'
    5. 로컬 모델의 기본 키 ($localKey):
      • 설명: 로컬 모델(여기서는 User 모델)의 기본 키입니다. 즉, 로컬 모델의 어떤 속성이 다른 모델들과 관계에서 사용되는지를 나타냅니다.
      • 예시: 'id'
    6. 대상 모델의 기본 키 ($secondLocalKey):
      • 설명: 대상 모델(여기서는 PhoneNumber 모델)의 기본 키입니다. 로컬 모델의 기본 키와 대상 모델의 외래 키를 매핑할 때 사용됩니다.
      • 예시: 'id'

    이러한 옵션들을 통해 hasOneThrough 메서드는 세 개의 모델 간의 연관 관계를 설정하며, 각 모델의 키와 관계를 정의합니다. 설정된 이 관계를 통해 Laravel은 중간 모델을 거쳐 로컬 모델과 대상 모델 간의 관련된 데이터를 검색할 수 있습니다.

     

     

    Laravel에서 "hasOneThrough" 관계를 정리하면,

    이 예시에서는 User 모델이 Company 모델을 통해 PhoneNumber 모델과 관련되어 있다고 가정합니다.

     

        class User extends Model
        {
            // ...

            /**
            * Define a hasOneThrough relationship.
            *
            * @return \Illuminate\Database\Eloquent\Relations\HasOneThrough
            */
            public function companyPhoneNumber()
            {
                return $this->hasOneThrough(
                    related: PhoneNumber::class,    // 1. 관계를 설정할 모델 (PhoneNumber 모델)
                    through: Company::class,          // 2. 중간 모델 (Company 모델)
                    firstKey: 'user_id',                   // 3. 중간 모델의 외래 키 (Company 모델의 외래 키)
                    secondKey: 'company_id',             // 4. 대상 모델의 외래 키 (PhoneNumber 모델의 외래 키)
                    localKey: 'id',                          // 5. 로컬 모델의 기본 키 (User 모델의 기본 키)
                    secondLocalKey: 'id'                           // 6. 대상 모델의 기본 키 (PhoneNumber 모델의 기본 키)
                );
            }
        }

     

    이 메서드는 User 모델이 PhoneNumber 모델과의 hasOneThrough 관계를 나타냅니다.

    여기서 각 인자는 다음을 의미합니다:

    1. PhoneNumber 모델: 관계를 설정할 모델.
    2. Company 모델: 중간 모델.
    3. user_id: 중간 모델의 외래 키.
    4. company_id: 대상 모델의 외래 키.
    5. id: 로컬 모델의 기본 키.
    6. id: 대상 모델의 기본 키.

    이를 통해 User 모델에서 companyPhoneNumber 메서드를 호출하면 PhoneNumer 모델과의 관련된 데이터를 조회할 수 있습니다.

     

    올바른 외래 키 이름으로 모든 테이블을 올바르게 설정했다면, 

                return $this->hasOneThrough(PhoneNumber::class, Company::class);

    이걸로 된다.

     

    <hr>

     

    php artisan tinker

    ---------------------------

     

    > $user = User::find(7);

    > $user->companyPhoneNumber()->get();

    > $user = User::find(7) >companyPhoneNumber()->get(); 

     

    > User::with('companyPhoneNumber')->get();

    댓글

Designed by Tistory.