Laravel의 쿼리빌더와 엘로퀀트 / 대량할당,fillable

1. 쿼리빌더

SQL을 쉽게작성하며 SQL injection방지를 위해 사용

인스턴스 생성

DB::table('테이블명')으로 쿼리빌더 인스턴스취득

결과추출예제

$results = DB::table('users')->where('votes', '>', 100)->get();
// select('컬럼명')은 where앞에 들어갈수있지만 선택사항이다

데이터 형태

Illuminate\Support\Collection 리스트 >> stdClass 객체의 인스턴스

2. ELOQUENT ORM

ORM이다

DB의 테이블을 모델 객체로 관리할수있게 함

모델은 대부분의 쿼리빌더의 메서드를 사용할수있다 (모델 == 쿼리빌더 인스턴스)

모델에 생성 및 사용

$users = User::where('votes', '>', 100)->get();

foreach ($users as $user) {
    echo $user->name;
}

데이터 형태

Illuminate\Database\Eloquent\Collection 리스트 >> 모델 인스턴스

3. 꼭 알면 좋은점

  • 쿼리빌더는 결과로 stdClass를 반환한다

  • 엘로퀀트는 결과로 모델인스턴스를 반환한다

  • 엘로퀀트의 모델은 쿼리빌더의 기능을 포함하기때문에 where등의 쿼리빌더 기능이 사용 가능하다

    ( → 그러나 같은 쿼리빌더를 사용하는 아님)

    둘다 where등의 기능은 같지만 쿼리빌더의 네임스페이스가 다르다

    그래서 기능은 같은데 반환하는 값이 다르다 (쿼리빌더면 stdClass, 엘로퀀트면 모델인스턴스)

    쿼리빌더의 DB::table('users')->where의 where과 
    엘로퀀트의 User::where의 where은 
    둘다 builder(쿼리빌더)인스턴스를 반환한다
    
    그러나 이 둘은 각자 다른 쿼리빌더의 인스턴스이다
    쿼리빌더 -> Illuminate\Database\Query\Builder
    엘로퀀트 -> Illuminate\Database\Eloquent\Builder
    
    동작하는 기능은 둘다 쿼리빌더의 where과 동일하지만 반환하는 값은 다르다
    쿼리빌더 -> Illuminate\Database\Query\Builder -> get()사용시 -> stdClass
    엘로퀀트 -> Illuminate\Database\Eloquent\Builder -> get()사용시 -> 모델인스턴스

    같은 기능의 where이지만 각각 쿼리와 엘로퀀트에 속하는 where이라서 get()을 사용하는 경우 반환 받는 값이 쿼리는 stdClass와 엘로퀀트는 model인스턴스로 달라진다


3. 대량할당과 fillable

일반적인 데이터 저장 vs 대량할당

// 일반데이터 저장
$user = new User();
$user->name = 'John Doe';
$user->email = 'johndoe@example.com';
$user->password = 'secret';
$user->save();

// 대량할당 1
$user = User::create([
    'name' => 'John Doe',
    'email' => 'johndoe@example.com',
    'password' => 'secret'
]);

// 대량할당 2
$user = new User();
$user->fill([
    'name' => 'John Doe',
    'email' => 'johndoe@example.com',
    'password' => 'secret'
]);
$user->save();

일반적인 데이터의 저장은 하나하나 객체의 프로퍼티를 지정한뒤 저장해야한다

그러나 대량할당같은 경우는 (키/값)배열의 형태로 저장이 가능하다

그렇기 때문에 대량할당이 매우 간단하지만 보안적으로 취약하다

보안적으로 예방하기 위해 $fillable을 사용한다

// name과 email은 대량할당을 허용한다는 뜻임 (화이트리스트방법)
// 반대로 $guarded를 사용해서 특정칼럼만 막을수있다(블랙리스트방법)
class User extends Model
{
    protected $fillable = ['name', 'email'];
}

엘로퀀트 모델의 이벤

  • 엘로퀀트의 모델이 등록,수정,검색등의 처리가 일어날때 발생됨

    retrieved, creating, created, updating, updated, saving, saved, deleting, deleted

  • create를 예로 들면 -ing로 끝나는 경우 새로운 모델객체가 생성된기 전

    -ed로 끝나는건 새로운 모델객체가 생성된 후에 발생한다는 뜻이다

    아래의 예제를 새로운 게시글 모델이 생성되기 전 단계에서 postId라는 컬럼에 uuid를 생성한다는 의미가 된다

protected static function booted()
{
    // 게시글의 생성되기전에 호출됨
    static::creating(function ($posts) {
        $posts->postId = Str::uuid()->toString();
    });
}

취득 가능한 사용자 컬럼 추가

엘로퀀트 모델의 Accessors기능이며 해당 컬럼의 값을 조회할시 사용자 정의가 가능하다

contentShort라는 메서드명이라면 $post->content_short로 취득가능하다

// 취득가능한 사용자 칼럼 추가 (Accessors)
protected function contentShort(): Attribute
{
    return Attribute::make(
        get: function () {
            // HTML태그제거후 HTML엔터티도 제거후,첫 100글자만 저장
            return mb_substr(html_entity_decode(strip_tags($this->attributes['content'])), 0, 150);
        },
    );
}

칼럼의 기본값 설정

postViewCount컬럼이 있다는 가정하에 해당 컬럼의 기본값으 0이 된다

// 칼럼 기본값 설정
protected $attributes = [
    'postViewCount' => 0,
];

엘로퀀트가 기본적으로 제공하는 데이터 컬럼변경

created_at,updated_at등의 기본 데이터 컬럼이 테이블과 연동이 되어있는데

해당 제공 컬럼이 아니라 내가 작성한 createdDate컬럼등과 연동하고싶을때 사용

    // 기본 날짜 속성명 변경
    const CREATED_AT = 'createdDate';
    const UPDATED_AT = 'updatedDate';

테이블 생성시 기억하면 좋은점

아래를 지키면 엘로퀀트를 사용하기 좋다

  1. 테이블명은 복수형

  2. 기본키명은 id가 좋다 (1:N등의 연관관계 추정시 편리 // id)

  3. 칼럼명은 스네이크 케이스 (1:N등의 연관관계시 자동으로 추정해서 연관시켜줌 // 외래키등록시 자동으로 post_id등으로 찾음)

  4. 생성시간,수정시간은 자동으로 생성해준다 (created_at컬럼명 안쓰면 모델에 const CREATED_AT = 'createdDate';등으로 직접적어야함)

  5. 마이그레이션사용

엘로퀀트 관련 자주쓰이는 함수 (쿼리빌더가 아님/쿼리빌더랑 중복해서 사용되는 함수있음)

1. `all()`: 모델에 해당하는 모든 레코드를 가져옵니다.
// 쿼리빌더에선 get()가 같은 기능을 한다

2. `find($id)`: 주어진 기본 키(id)에 해당하는 레코드를 가져옵니다.
// 쿼리빌더에선 where()이 같은 기능을 한다
// DB::table('posts')->where('id', 1)->first(); // id가 1인 레코드를 검색

3. `findOrFail($id)`: 주어진 기본 키에 해당하는 레코드를 가져오지만, 레코드가 없을 경우 `ModelNotFoundException` 예외를 발생시킵니다.

4. `create(array $attributes)`: 새로운 레코드를 생성하고 데이터베이스에 저장합니다.

5. `update(array $attributes)`: 기존 레코드의 속성을 업데이트합니다.

6. `delete()`: 레코드를 삭제합니다.

7. `where($column, $operator = null, $value =
`: 조건절을 추가하여 레코드를 필터링합니다.

8. `first()`: 첫 번째 레코드를 가져옵니다.

9. `pluck($column)`: 지정된 컬럼의 값들을 배열로 반환합니다.

10. `count()`: 조회된 레코드의 수를 반환합니다.

11. `orderBy($column, $direction = 'asc')`: 지정된 컬럼을 기준으로 정렬합니다.

12. `limit($value)`: 결과의 개수를 제한합니다.

13. `with($relationship)`: Eager Loading을 사용하여 관계를 사전에 로드합니다.

14. `whereHas($relationship, $callback)`: 관계를 사용하여 서브 쿼리를 수행합니다.

15. `has($relationship)`: 지정된 관계가 있는 레코드만 가져옵니다.

16. `firstOrCreate($attributes)`: 주어진 속성으로 레코드를 검색하고, 없으면 새로운 레코드를 생성하여 저장합니다.
(디비에 저장하고 반환)

17. `firstOrNew($attributes)`: 주어진 속성으로 레코드를 검색하고, 없으면 새로운 모델 인스턴스를 생성합니다. 저장은 하지 않습니다. 
(디비에 저장은 안하고 생성한 모델인스턴스만 반환)

18. increment('컬럼명') // 해당컬럼명의 데이터를 1씩 증가시킨다
$post->increment('postViewCount');

참조

https://zetawiki.com/wiki/Laravel_%EC%BF%BC%EB%A6%AC%EB%B9%8C%EB%8D%94

https://zetawiki.com/wiki/Laravel_%EC%97%98%EB%A1%9C%ED%80%80%ED%8A%B8_%EB%AA%A8%EB%8D%B8

https://zetawiki.com/wiki/Laravel_%EC%97%98%EB%A1%9C%ED%80%80%ED%8A%B8%EC%99%80_%EC%BF%BC%EB%A6%AC%EB%B9%8C%EB%8D%94_%EC%B0%A8%EC%9D%B4%EC%A0%90

https://laravel.kr/docs/9.x/eloquent-relationships#1:N(%EC%9D%BC%EB%8C%80%EB%8B%A4)%20%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84%20%EC%A0%95%EC%9D%98%ED%95%98%EA%B8%B0

Jun 21, 2023 Views 553