Laravel Model

이하루·2024년 7월 23일
0

MVC패턴 중 M에 해당하며 데이터베이스와의 상호작용을 통해 데이터의 관리를 담당하는 Model에 대해서 알아보고자 한다.

✅ Model?

Model은 주로 Controller에게 받은 요청에 따라 데이터베이스에 접근, 데이터를 조작(가공)하는 역할을 수행한다.

💻 Laravel의 Model

Laravel의 Model에서 데이터베이스와 상호작용을 하기 위한 방법으로는 크게 두가지, Query Builder와 Eloquent ORM로 나뉘어진다. 간단히 설명하자면 Query Builder는 직접 SQL을 작성하는 방식이며, Eloquent ORM은 각 테이블을 모델 클래스와 매핑하여 상호작용을 하는 방식이다.
이러한 개념을 토대로 데이터베이스를 사용, 세팅하기 위한 전처리 방법과 Query Builder, Eloquent ORM에 대해서 알아보자.

⚙️ Database 세팅

1. Database 설정

config/database.php

	// 기본 DB 연결 지정
    'default' => env('DB_CONNECTION', 'mysql'),
    
    // 각각의 DB 지정
    'connections' => [
        'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            ]) : [],
        ],
    ],

.env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

2. migration

migration은 데이터베이스의 테이블을 관리하는 기능으로, 데이터베이스의 테이블의 생성, 수정, 삭제 등의 작업을 PHP 코드로 정의한다. 이를 통해 팀원들간의 데이터베이스 구조 일관성 유지, 더 나은 데이터베이스 유지보수 및 배포 등의 장점이 있다.

Laravel에서의 migration은 아래의 Artisan 명령어를 통해서 추가할 수 있으며, database\migrations\ 하위에서 관리된다.

php artisan make:migration create_users_table

생성된 migration 파일

class CreateUsersTable extends Migration
{
	// 테이블 생성, 수정처리
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->rememberToken(); // 사용자 인증 관련 토큰 생성
            $table->timestamps();
        });
    }

	// 테이블 삭제
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

migration은 아래의 artisan을 통해 사용할 수 있다.

php artisan migrate // migration 실행
php artisan migrate:rollback // migration 되돌리기
php artisan migrate:status // 지금까지 실행된 migration 정보 출력
php artisan migrate:refresh // 모든 migration 되돌리고 재실행
// 지정한 migration 실행
php artisan migrate:refresh --path=/database/migrations/file.php

3. seeding

seeding은 데이터베이스의 테이블에 초기 데이터나 테스트 데이터를 삽입하기 위한 기능이다. migration과 마찬가지로 팀원들간의 초기 데이터의 일관성 유지, 초기 데이터 관리가 쉬운 점 등의 장점이 있다.

Laravel에서의 seeder은 아래의 Artisan 명령어를 통해서 추가할 수 있으며, database\seeders\ 하위에서 관리된다.

php artisan make:seeder UsersTableSeeder

// ※ 전체 migration + seed 처리를 전부 실행하는 명령어
php artisan migrate:fresh --seed

생성된 seeder파일

<?php
> 
namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class UsersTableSeeder extends Seeder
{
	// 데이터베이스에 삽입할 레코드의 정보 작성
    public function run()
    {
        DB::table('users')->insert([
            'name' => 'Kim',
            'email' => 'kim@example.com',
            'password' => bcrypt('password'),
        ]);
    }
}

정의된 seeder메소드는 아래의 artisan을 통해서 실행할 수 있다.

php artisan db:seed --class=UsersTableSeeder

✅ Query Builder

Query Builder는 PHP 메소드 체인을 활용한 데이터베이스와의 상호작용을 하기 위한 기능으로, 기존의 SQL작성방식보다 가독성과 유지보수성이 뛰어나다.

1. 사용법

DB::table('users')->get(); // 테이블 모든 레코드
DB::table('users')->where('name', 'John'); // where조건 지정(=)
	->where('name', 'like', 'T%'); // where조건 지정(like)
DB::table('users')->find(3); // 키를 통한 단일 행 검색
DB::table('orders')->exists() // 레코드 존재 유무 체크 

그 밖에도 Laravel collections의 기능을 제공해주기에, Query Builder와 더불어 collections의 자료도 참고해가며 작성하는 것이 좋다.
Query Builder : https://laravel.kr/docs/8.x/queries
Collection : https://laravel.kr/docs/8.x/collections

✅ Eloquent ORM

Eloquent ORM은 객체지향 방식을 통해 각 테이블을 모델화하여, 모델과 테이블의 매핑을 통해 데이터를 취급한다. 개발자가 테이블을 PHP 클래스를 활용해 보다 쉽게 접근할 수 있도록 해준다.

1. Model

Model은 테이블과 매핑하여 데이터를 다루기 위한 클래스를 의미한다. 모델 클래스에서 테이블의 각각의 레코드는 하나의 인스턴스로 대응되며 보다 객체지향적인 방식으로 데이터를 다룰 수 있도록 도와준다.

아래의 Artisan 명령어를 통해서 Model을 추가할 수 있으며, App\Models\ 하위에서 관리된다.

php artisan make:model SampleModel
// migration과 함께 생성한다면 --migration옵션을 사용한다.
php artisan make:model SampleModel --migration

생성된 모델 클래스 및 기본 설정에 대한 내용은 아래와 같다.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Sample extends Model
{
	// 테이블명
    protected $table = 'table_sample';

    // 기본키
    protected $primaryKey = 'sample_id';
    
    // 각각의 칼럼을 지정
    protected $fillable = [
    	'name', 'email', 'password'
    ];    
    
    // 숨기고 싶은 칼럼 지정 (조회시, 해당 칼럼 표시X)
	protected $hidden = [
        'password',
        'remember_token',
    ];

    // 모델의 해당 칼럼의 데이터타입을 캐스팅(형변환)
	protected $casts = [
        'email_verified_at' => 'datetime',
    ];

	// auto increament 사용유무 (default : true)
    public $incrementing = false;
    
    // 기본키가 정수가 아닐 경우, 타입 지정이 필요
    protected $keyType = 'string';
    
    // 타임스탬프 (created_at, updated_at) 자동 설정유무 (default : true)
    public $timestamps = false;
    
    // 타임스탬프 명칭 (created_at, updated_at) 커스텀
    const CREATED_AT = 'creation_date';
    const UPDATED_AT = 'updated_date';
    
    // 해당 모델에서 다른 DB 사용시 대상DB 정의
    protected $connection = 'sqlite';
    
    // 모델의 각 칼럼별 default 정의
	protected $attributes = [
        'del_flg' => false,
    ];

}

2. Model Relationship

생성된 모델 간의 관계가 존재하는 경우, 각 모델 클래스에 해당 관계에 대한 내용도 명시해야 한다.

  • 테이블 정보
// User 테이블
Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->timestamps();
});

// Profiles 테이블
Schema::create('profiles', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('user_id')->unique();
    $table->string('phone');
    $table->timestamps();

    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});

// posts 테이블
Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('user_id');
    $table->string('title');
    $table->text('content');
    $table->timestamps();

    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});

// roles 테이블
Schema::create('roles', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->timestamps();
});

// role_user 테이블 (다대다 관계를 위한 중간테이블)
Schema::create('role_user', function (Blueprint $table) {
    $table->unsignedBigInteger('user_id');
    $table->unsignedBigInteger('role_id');
    $table->timestamps();

    $table->primary(['user_id', 'role_id']);

    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
});
  • 일대일 관계
// User 모델
class User extends Model
{
    public function profile()
    {
        return $this->hasOne(Profile::class);
    }
}

// Profile 모델
class Profile extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}
  • 일대다 관계
// User 모델
class User extends Model
{
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

// Post 모델
class Post extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}
  • 다대다 관계
// User 모델
class User extends Model
{
    public function roles()
    {
        return $this->belongsToMany(Role::class);
    }
}

// Role 모델
class Role extends Model
{
    public function users()
    {
        return $this->belongsToMany(User::class);
    }
}
  • hasManyThrough : 세개의 다른 모델간의 관계를 정의할 때, 중간 테이블을 거치지 않고 지정하는 방법 ※ A→B(일대다) , B→C(일대다) 관계에서 A→C의 접근을 위한 개념이라고 볼 수 있다.
class Category extends Model
{
    public function products()
    {
    	// 카테고리에 여러 주문이 있고 각 주문에는 여러 상품이 존재
        // = 카테고리는 주문이라는 중간테이블 없이는 상품 확인이 불가
        return $this->hasManyThrough(Product::class, Order::class);
    }
}

// 사용 사례
$category = Category::find(1); // id가 1인 카테고리
$products = $category->products;    // 해당 카테고리의 모든 상품정보
  • morphTo / morphMany / morphToMany : 다형 관계를 정의하기 위한 방법이다.
    • 사례 : 댓글은 유튜브 커뮤니티에도 영상에도 작성할 수 있다.
      → 댓글 : morphTo, 커뮤니티/영상 : morphMany

3. Eloquent ORM

profile
어제보다 더 나은 하루

0개의 댓글