Mutators 사용 시 "laravel Trying to get property 'name' of non-object" 에러 해결법

Laravel Mutators를 이용하여 Relationships 관계에 있는 컬럼의 값을 포함하고자 하는 경우 getAttribute() Magic 메서드로 포함하고자 할 컬럼을 지정해주고 $appends 프로퍼티에 명시하여야 한다.

다음 코드는 Post 모델에 Category 모델의 name 컬럼을 Post 모델의 category_name 프로퍼티로 포함하는 예제이다.

class Post extends Model
{
    protected $appends = [
        'category_name',
    ];

    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    public function getCategoryNameAttribute()
    {
        return $this->category->name;
    }

}

하지만, 중간중간 해당하는 Category 모델이 없는 경우 (카테고리가 삭제 된 경우) "laravel Trying to get property 'name' of non-object" 에러가 발생한다.

당연히 해당 모델이 없기 때문에 $this->category는 null이 되고,  $this->user->name 프로퍼티에 접근할 수 없기 때문에 발생하는 문제이다.

이럴 경우 다음과 같이 null 여부를 체크하면 된다.

public function getCategoryNameAttribute()
{
    return $this->user !== null ? $this->user->name : null;
}

뿐만 아니라, 개발에 있어서 이와 같은 방어적 코딩을 습관화 하는 것이 좋다.

Develop Laravel Mutators Troubleshooting

MariaDB에서 artisan migrate 시 Syntax Error 문제 해결 방법

Laravel에서 artisan migrate 명령을 실행 시 MariaDB에서는 다음과 같은 에러가 발생하는 경우가 있다.

[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table users add unique users_email_unique(email))

[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes

이럴 경우 AppServiceProvider.php의 boot() 메서드에 다음 구문을 추가하여 해결할 수 있다.

use Illuminate\Support\Facades\Schema;

public function boot()
{
    Schema::defaultStringLength(191);
}

 

Laravel migrate MariaDB Troubleshooting

Eloquent Result에 순번 추가하기

Laravel에서 Eloquent ORM을 다룰 때 Resultset에 커스텀 필드를 추가해야 할 경우가 있다.

대표적으로 순번 필드가 있는데, 고유번호(id) 필드와는 별도로 item마다 순번을 부여하여 취급하고자 하는 경우이다.

간단한 필드의 경우 Mutators를 이용할 수 있지만, 순번과 같이 아이템의 개수와 페이지에 따라 동적으로 값이 부여되어야 할 경우 Controller에서 생성해주어야 한다.

 

다음은 User 모델의 항목들을 10개 단위로 Pagination 하는 예제이다.

public function index()
{
    $users = User::paginate(10);

    $response = [
        'pagination' => [
            'total' => $users->total(),
            'per_page' => $users->perPage(),
            'current_page' => $users->currentPage(),
            'last_page' => $users->lastPage(),
            'from' => $users->firstItem(),
            'to' => $users->lastItem()
        ],
        'data' => $users
    ];

    return response()->json($response);
}

여기서 number라는 순번 필드를 $users에 추가하고자 하는 경우 다음과 같이 코드를 수정한다.

public function index()
{
    $users = User::paginate(10);

    $total = $users->total();
    $per_page = $users->perPage();
    $current_page = $users->currentPage();
    $count = 0;

    // 순번 필드를 추가하여 transform
    $users->getCollection()->transform(function ($user) use ($total, $per_page, $current_page, &$count) {
        $user->number = ($total - ($per_page * ($current_page - 1))) - $count;
        $count++;
        return $user;
    });

    $response = [
        'pagination' => [
            'total' => $total,
            'per_page' => $per_page,
            'current_page' => $current_page,
            'last_page' => $users->lastPage(),
            'from' => $users->firstItem(),
            'to' => $users->lastItem()
        ],
        'data' => $users
    ];

    return response()->json($response);
}

이렇게 하면 고유번호와는 별개로 순번 필드인 number가 각 item마다 추가된다. 페이지를 이동하여도 각 페이지에 맞게 순번이 올바르게 부여되는 것을 확인할 수 있다.

 

view에서 출력할 때 해당 필드를 적절히 이용하면 된다.

Laravel Eloquent ORM transform