# 라라벨 팁 한국어

라라벨 개발자들을 위한 멋진 Laravel 팁과 트릭 모음입니다. PR 및 아이디어를 환영합니다! \
이 문서는 [PovilasKorop](https://github.com/PovilasKorop) 과 [MarceauKa](https://github.com/MarceauKa) 의 아이디어를 번역한 문서입니다.

**2021 년 1 월 29 일 업데이트** : 현재 **125 개의 팁** 이 14 개 섹션으로 나뉩니다.

## 목차

* [DB 모델 및 Eloquent](#db-models-and-eloquent) (31 개)
* [모델 관계](#models-relations) (22 개)
* [마이그레이션](#migrations) (8 개)
* [뷰](#views) (8 개)
* [라우팅](#routing) (13 개)
* [유효성 검사](#validation) (7 개)
* [컬렉션](#collections) (4 개)
* [인증](#auth) (5 개)
* [메일](#mail) (4 개)
* [Artisan](#artisan) (5 개)
* [팩토리](#factories) (2 개)
* [로그 및 디버그](#log-and-debug) (2 개)
* [API](#api) (2 개)
* [기타](#other) (12 개)

## DB 모델 및 Eloquent <a href="#db-models-and-eloquent" id="db-models-and-eloquent"></a>

⬆️ [맨 위로 이동](#laravel-tips) ➡️ [다음 (모델 관계)](#models-relations)

* [Eloquent 날짜 관련 검색 메서드](#eloquent-where-date-methods)
* [값의 증가 및 감소](#increments-and-decrements)
* [타임 스탬프 컬럼이 없을 때](#no-timestamp-columns)
* [옵저버로 로그인 한 사용자 지정](#set-logged-in-user-with-observers)
* [소프트 삭제 : 다중 복원](#soft-deletes-multiple-restore)
* [Model::all의 컬럼 지정](#model-all-columns)
* [실패하거나 실패하지 않기](#to-fail-or-not-to-fail)
* [열 이름 변경](#column-name-change)
* [쿼리 결과에 대한 개별 수정](#map-query-results)
* [기본 타임 스탬프 필드 변경](#change-default-timestamp-fields)
* [created\_at을 손쉽게 정렬하기](#quick-order-by-created_at)
* [레코드 생성시 자동으로 생성되는 열 값](#automatic-column-value-when-creating-records)
* [DB Raw 쿼리 계산을 더 빠르게](#db-raw-query-calculations-run-faster)
* [한개 이상의 스코프](#more-than-one-scope)
* [카본을 전환해줄 필요가 없습니다](#no-need-to-convert-carbon)
* [첫 글자로 그룹화](#grouping-by-first-letter)
* [열 업데이트 안 함](#never-update-the-column)
* [여러개를 찾기](#find-many)
* [Key로 찾기](#find-by-key)
* [자동 증가 대신 UUID 사용](#use-uuid-instead-of-auto-increment)
* [Laravel에서 sub select 사용법](#sub-selects-in-laravel-way)
* [일부 열 숨기기](#hide-some-columns)
* [정확한 DB 오류](#exact-db-error)
* [쿼리 빌더에서의 소프트 삭제](#soft-deletes-with-query-builder)
* [올바른 오래된 SQL 쿼리](#good-old-sql-query)
* [DB 트랜잭션 사용](#use-db-transactions)
* [업데이트 또는 생성](#update-or-create)
* [저장시 캐시 삭제](#forget-cache-on-save)
* [Created\_at 및 Updated\_at 형식 변경](#change-format-of-created_at-and-updated_at)
* [JSON에 배열 유형 저장](#storing-array-type-into-json)
* [모델 사본 만들기](#make-a-copy-of-the-model)

### Eloquent 날짜 관련 검색 메서드 <a href="#eloquent-where-date-methods" id="eloquent-where-date-methods"></a>

`whereDay()` , `whereMonth()` , `whereYear()` , `whereDate()` 및 `whereTime()` 함수로 날짜를 검색하십시오.

```php
$products = Product::whereDate('created_at', '2018-01-31')->get();
$products = Product::whereMonth('created_at', '12')->get();
$products = Product::whereDay('created_at', '31')->get();
$products = Product::whereYear('created_at', date('Y'))->get();
$products = Product::whereTime('created_at', '=', '14:13:58')->get();
```

### 값의 증가 및 감소 <a href="#increments-and-decrements" id="increments-and-decrements"></a>

일부 테이블에서 일부 DB 컬럼의 값을 증가 시키려면 `increment()` 함수를 사용하십시오. 아, 그리고 당신은 1만큼 증가시킬 수있을뿐만 아니라 50과 같은 어떤 숫자도 증가시킬 수 있습니다.

```php
Post::find($post_id)->increment('view_count');
User::find($user_id)->increment('points', 50);
```

### 타임 스탬프 컬럼이 없을 때 <a href="#no-timestamp-columns" id="no-timestamp-columns"></a>

DB 테이블에 타임 스탬프 필드 `created_at` 및 `updated_at`가 포함되어 있지 않은 경우, `$timestamps = false`를 사용하여 Eloquent 모델이 이 속성을 사용하지 않도록 지정할 수 있습니다.

```php
class Company extends Model
{
    public $timestamps = false;
}
```

### 옵저버로 로그인 한 사용자 지정 <a href="#set-logged-in-user-with-observers" id="set-logged-in-user-with-observers"></a>

현재 로그인 한 사용자를 `user_id` 필드에 자동으로 지정되게하려면 `make:observer` 를 사용하고 `creating()` 메서드를 추가합니다.

```php
class PostObserver
{
    public function creating(Post $post)
    {
        $post->user_id = auth()->id();
    }
}
```

### 소프트 삭제 : 다중 복원 <a href="#soft-deletes-multiple-restore" id="soft-deletes-multiple-restore"></a>

소프트 삭제를 사용하면 한 문장으로 여러 행을 복원 할 수 있습니다.

```php
Post::withTrashed()->where('author_id', 1)->restore();
```

### Model::all의 컬럼 지정 <a href="#model-all-columns" id="model-all-columns"></a>

Eloquent의 `Model::all()` 호출 할 때 반환 할 열을 지정할 수 있습니다.

```php
$users = User::all(['id', 'name', 'email']);
```

### 실패하거나 실패하지 않기 <a href="#to-fail-or-not-to-fail" id="to-fail-or-not-to-fail"></a>

`findOrFail()` 외에도 쿼리에 대한 레코드가없는 경우 404 페이지를 반환하는 Eloquent 메서드 `firstOrFail()`도 있습니다.

```php
$user = User::where('email', 'povilas@laraveldaily.com')->firstOrFail();
```

### 열 이름 변경 <a href="#column-name-change" id="column-name-change"></a>

Eloquent Query Builder에서 "as"를 지정하여 일반 SQL 쿼리처럼 다른 이름을 가진 열을 반환 할 수 있습니다.

```php
$users = DB::table('users')->select('name', 'email as user_email')->get();
```

### 쿼리 결과에 대한 개별 수정 <a href="#map-query-results" id="map-query-results"></a>

Eloquent 쿼리 후에 Collections에서 `map()` 함수를 사용하여 행을 수정할 수 있습니다.

```php
$users = User::where('role_id', 1)->get()->map(function (User $user) {
    $user->some_column = some_function($user);
    return $user;
});
```

### 기본 타임 스탬프 필드 변경 <a href="#change-default-timestamp-fields" id="change-default-timestamp-fields"></a>

Laravel이 아닌 데이터베이스로 작업하고 있고 타임스탬프 열의 이름이 다르다면 어떻게 해야할까요? 아마도 create\_time 이나 update\_time 같은 열이 있을 겁니다. 다행히도 모델에서 변경 할 수 있습니다.

```php
class Role extends Model
{
    const CREATED_AT = 'create_time';
    const UPDATED_AT = 'update_time';
}
```

### created\_at을 손쉽게 정렬하기 <a href="#quick-order-by-created_at" id="quick-order-by-created_at"></a>

이것을

```php
User::orderBy('created_at', 'desc')->get();
```

더 쉽게 할 수 있습니다.

```php
User::latest()->get();
```

기본적으로 `latest()` 는 `created_at`을 이용하여 정렬합니다.

`created_at` 오름차순으로 정렬하는, 반대 메소드 `oldest()`도 있습니다.

```php
User::oldest()->get();
```

또한 정렬할 열을 바꿀 수도 있습니다. 예를 들어 `updated_at` 를 사용하려면 아래처럼 사용하면 됩니다.

```php
$lastUpdatedUser = User::latest('updated_at')->first();
```

### 레코드 생성시 자동으로 생성되는 열 값 <a href="#automatic-column-value-when-creating-records" id="automatic-column-value-when-creating-records"></a>

레코드 생성시 DB 컬럼 값을 생성하려면 모델의 `boot()` 메소드에 추가합니다. 예를 들어 "position"필드가 있고 사용 가능한 다음 위치를 새 레코드에 할당하려면 (예 `Country::max('position') + 1)` 과 같이하십시오.

```php
class Country extends Model {
    protected static function boot()
    {
        parent::boot();

        Country::creating(function($model) {
            $model->position = Country::max('position') + 1;
        });
    }
}
```

### DB Raw 쿼리 계산을 더 빠르게 <a href="#db-raw-query-calculations-run-faster" id="db-raw-query-calculations-run-faster"></a>

`whereRaw()` 메서드와 같은 SQL 원시 쿼리를 사용하여 일부 DB 특정 계산을 Laravel이 아닌 쿼리에서 직접 수행하면 일반적으로 결과가 더 빠릅니다. 예를 들어, 등록 후 30 일 이상 활성 상태였던 사용자를 얻으려면 다음 코드를 사용하십시오. (역자: 단 이 경우는 ORM의 장점인 추상화의 이점을 얻지 못하고 특정 데이터베이스에 종속되는 사이드이펙트가 생길 수 있습니다. 이 부분을 감안하고 사용하시기 바랍니다. 이것은 사용하지 말라는 의미가 아닌 주의를 필요로 하는 의미로 남기는 글입니다.)

```php
User::where('active', 1)
    ->whereRaw('TIMESTAMPDIFF(DAY, created_at, updated_at) > ?', 30)
    ->get();
```

### 한개 이상의 스코프 <a href="#more-than-one-scope" id="more-than-one-scope"></a>

쿼리에서 하나 이상의 스코프를 사용하여 Eloquent에서 쿼리 스코프를 결합하고 연결할 수 있습니다.

모델:

```php
public function scopeActive($query) {
    return $query->where('active', 1);
}

public function scopeRegisteredWithinDays($query, $days) {
    return $query->where('created_at', '>=', now()->subDays($days));
}
```

일부 컨트롤러 :

```php
$users = User::registeredWithinDays(30)->active()->get();
```

### 카본을 전환해줄 필요가 없습니다 <a href="#no-need-to-convert-carbon" id="no-need-to-convert-carbon"></a>

`whereDate()`를 이용해 오늘 기준의 레코드를 조회할 경우 Carbon의 `now()`를 사용할 수 있으며, 자동으로 날짜 형식으로 변환됩니다. 이때 `->toDateString()`를 해줄 필요가 없습니다.

```php
// 이럴땐
$todayUsers = User::whereDate('created_at', now()->toDateString())->get();
// 전환할 필요가 없습니다. 그냥 now()를 쓰세요
$todayUsers = User::whereDate('created_at', now())->get();
```

### 첫 글자로 그룹화 <a href="#grouping-by-first-letter" id="grouping-by-first-letter"></a>

사용자 지정 조건별로 Eloquent 결과를 그룹화 할 수 있습니다. 사용자 이름의 첫 글자로 그룹화하는 방법은 다음과 같습니다.

```php
$users = User::all()->groupBy(function($item) {
    return $item->name[0];
});
```

### 열 업데이트 안 함 <a href="#never-update-the-column" id="never-update-the-column"></a>

한 번만 설정하고 다시 업데이트하지 않으려는 DB 열이있는 경우 뮤 테이터를 사용하여 Eloquent Model에 해당 제한을 설정할 수 있습니다.

```php
class User extends Model
{
    public function setEmailAttribute($value)
    {
        if ($this->email) {
            return;
        }

        $this->attributes['email'] = $value;
    }
}
```

### 여러개를 찾기 <a href="#find-many" id="find-many"></a>

Eloquent 메소드 `find()` 는 여러 매개 변수를 받아 들일 수 있으며, 하나의 모델이 아닌 발견 된 모든 레코드의 컬렉션을 반환합니다.

```php
// Eloquent Model을 반환합니다
$user = User::find(1);
// Eloquent Collection을 반환합니다
$users = User::find([1,2,3]);
```

### Key로 찾기 <a href="#find-by-key" id="find-by-key"></a>

정확히 어떤 필드가 기본 키인지에 따라 자동으로 처리하는 `whereKey()` 메서드를 사용하여 여러 레코드를 찾을 수도 있습니다 ( 기본값은 `id` 지만 Eloquent 모델에서 재정의 할 수 있습니다).

```php
$users = User::whereKey([1,2,3])->get();
```

### 자동 증가 대신 UUID 사용 <a href="#use-uuid-instead-of-auto-increment" id="use-uuid-instead-of-auto-increment"></a>

모델에서 자동 증분 ID를 사용하고 싶지 않습니까?

마이그레이션:

```php
Schema::create('users', function (Blueprint $table) {
    // $table->increments('id');
    $table->uuid('id')->unique();
});
```

모델:

```php
class User extends Model
{
    public $incrementing = false;
    protected $keyType = 'string';

    protected static function boot()
    {
        parent::boot();

        User::creating(function ($model) {
            $model->setId();
        });
    }

    public function setId()
    {
        $this->attributes['id'] = Str::uuid();
    }
}
```

### Laravel에서 sub select 사용법 <a href="#sub-selects-in-laravel-way" id="sub-selects-in-laravel-way"></a>

Laravel 6에서는 Eloquent 문에서 addSelect()를 사용하여 추가 된 열에 대해 계산을 할 수 있습니다.

```php
return Destination::addSelect(['last_flight' => Flight::select('name')
    ->whereColumn('destination_id', 'destinations.id')
    ->orderBy('arrived_at', 'desc')
    ->limit(1)
])->get();
```

### 일부 열 숨기기 <a href="#hide-some-columns" id="hide-some-columns"></a>

Eloquent 쿼리를 수행 할 때 특정 필드가 반환되는 것을 숨기려면 가장 빠른 방법 중 하나는 Collection 결과에 `->makeHidden()` 을 추가하는 것입니다.

```php
$users = User::all()->makeHidden(['email_verified_at', 'deleted_at']);
```

### 정확한 DB 오류 <a href="#exact-db-error" id="exact-db-error"></a>

Eloquent Query 예외를 잡으려면 기본 Exception 클래스 대신 특정 `QueryException`을 사용하면 오류의 정확한 SQL 코드를 얻을 수 있습니다.

```php
try {
    // Some Eloquent/SQL statement
} catch (\Illuminate\Database\QueryException $e) {
    if ($e->getCode() === '23000') { // integrity constraint violation
        return back()->withError('Invalid data');
    }
}
```

### 쿼리 빌더에서의 소프트 삭제 <a href="#soft-deletes-with-query-builder" id="soft-deletes-with-query-builder"></a>

소프트 삭제는 Eloquent를 사용할 때는 삭제된 항목을 제외하지만 Query Builder를 사용하면 작동하지 않는다는 것을 잊지 마십시오.

```php
// Will exclude soft-deleted entries
$users = User::all();

// Will NOT exclude soft-deleted entries
$users = DB::table('users')->get();
```

### 올바른 오래된 SQL 쿼리 <a href="#good-old-sql-query" id="good-old-sql-query"></a>

DB 스키마에서 무언가를 변경하는 것과 같은 결과를 얻지 않고 간단한 SQL 쿼리를 실행해야하는 경우 `DB::statement()` 됩니다.

```
DB::statement('DROP TABLE users');
DB::statement('ALTER TABLE projects AUTO_INCREMENT=123');
```

### DB 트랜잭션 사용 \<a id="use-db-transactions>\</a>

두 개의 DB 작업을 수행하고 두 번째 작업에서 오류가 발생할 수있는 경우 첫 번째 작업을 롤백해야합니다.

이를 위해 DB 트랜잭션을 사용하는 것이 좋습니다. Laravel에서는 정말 쉽습니다.

```php
DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);

    DB::table('posts')->delete();
});
```

### 업데이트 또는 생성 <a href="#update-or-create" id="update-or-create"></a>

레코드가 있는지 확인한 다음 업데이트하거나 새 레코드를 만들어야하는 경우 한 문장으로 수행 할 수 있습니다. Eloquent 메서드 `updateOrCreate()`를 사용합니다.

```php
// Instead of this
$flight = Flight::where('departure', 'Oakland')
    ->where('destination', 'San Diego')
    ->first();
if ($flight) {
    $flight->update(['price' => 99, 'discounted' => 1]);
} else {
    $flight = Flight::create([
        'departure' => 'Oakland',
        'destination' => 'San Diego',
        'price' => 99,
        'discounted' => 1
    ]);
}
// Do it in ONE sentence
$flight = Flight::updateOrCreate(
    ['departure' => 'Oakland', 'destination' => 'San Diego'],
    ['price' => 99, 'discounted' => 1]
);
```

### 저장시 캐시 삭제 <a href="#forget-cache-on-save" id="forget-cache-on-save"></a>

[@pratiksh404](https://github.com/pratiksh404) 가 제공 한 팁

컬렉션을 제공하는 `posts` 과 같은 캐시 키가 있고 새 저장소 또는 업데이트에서 해당 캐시 키를 잊고 싶다면 모델에서 정적 `saving` 기능을 호출 할 수 있습니다.

```php
class Post extends Model
{
    // Forget cache key on storing or updating
    public static function boot()
    {
        parent::boot();
        static::saving(function () {
           Cache::forget('posts');
        });
    }
}
```

### Created\_at 및 Updated\_at의 형식 변경

[@syofyanzuhad](https://github.com/syofyanzuhad) 가 제공 한 팁

`created_at` 형식을 변경하려면 다음과 같이 모델에 메소드를 추가 할 수 있습니다.

```
public function getCreatedAtFormattedAttribute()
{
   return $this->created_at->format('H:i d, M Y');
}
```

따라서 필요할 때 `$entry->created_at_formatted` 사용할 수 있습니다. 다음과 같이 `created_at` 속성이 반환됩니다 : `04:19 23, Aug 2020` .

또한 `updated_at` 속성의 형식을 변경하려면 다음 메소드를 추가 할 수 있습니다.

```
public function getUpdatedAtFormattedAttribute()
{
   return $this->updated_at->format('H:i d, M Y');
}
```

따라서 필요할 때 `$entry->updated_at_formatted` 사용할 수 있습니다. 다음과 같이 `updated_at` 속성이 반환됩니다 : `04:19 23, Aug 2020` .

### JSON에 배열 유형 저장 <a href="#storing-array-type-into-json" id="storing-array-type-into-json"></a>

[@pratiksh404](https://github.com/pratiksh404) 가 제공 한 팁

배열을 사용하는 입력 필드가 있고이를 JSON으로 저장해야하는 경우 모델에서 `$casts` 속성을 사용할 수 있습니다. 여기 `images` 는 JSON 속성입니다.

```
protected $casts = [
    'images' => 'array',
];
```

따라서 JSON으로 저장할 수 있지만 DB에서 검색하면 배열로 사용할 수 있습니다.

### 모델 사본 만들기 <a href="#make-a-copy-of-the-model" id="make-a-copy-of-the-model"></a>

두 개의 매우 유사한 모델 (배송 주소 및 청구 주소)이 있고 서로 사본을 만들어야하는 경우 `replicate()` 메서드를 사용하고 그 후에 일부 속성을 변경할 수 있습니다.

[공식 문서의](https://laravel.com/docs/8.x/eloquent#replicating-models) 예 :

```php
$shipping = Address::create([
    'type' => 'shipping',
    'line_1' => '123 Example Street',
    'city' => 'Victorville',
    'state' => 'CA',
    'postcode' => '90001',
]);

$billing = $shipping->replicate()->fill([
    'type' => 'billing'
]);

$billing->save();
```

## 모델 관계 <a href="#models-relations" id="models-relations"></a>

⬆️ [맨 위로 이동](#laravel-tips) ⬅️ [이전 (DB 모델 및 Eloquent)](#db-models-and-eloquent) ➡️ [다음 (마이그레이션)](#migrations)

* [Eloquent 관계에 대한 OrderBy](#orderby-on-eloquent-relationships)
* [조건부 관계](#conditional-relationships)
* [Raw DB 쿼리: havingRaw()](#raw-db-queries-havingraw)
* [Eloquent has()를 더 깊게](#eloquent-has-deeper)
* [Has Many. 정확히 얼마나 많은 것을 원하나요?](#has-many-how-many-exactly)
* [기본 모델](#default-model)
* [hasMany를 이용한 다중 생성](#use-hasmany-to-create-many)
* [빠른 로딩에서 필요한 컬럼만 사용하기](#eager-loading-with-exact-columns)
* [쉽게 상위 모델의 updated\_at 갱신하기](#touch-parent-updated_at-easily)
* [관계가 존재하는지 항상 확인하세요](#always-check-if-relationship-exists)
* [withCount()를 사용하여 하위 관계 레코드의 갯수 확인](#use-withcount-to-calculate-child-relationships-records)
* [관계에서 필터 쿼리 추가하기](#extra-filter-query-on-relationships)
* [관계를 항상 로드하지만 동적으로도 로드하기](#load-relationships-always-but-dynamically)
* [belongsTo 대신 hasMany를 사용하세요.](#instead-of-belongsto-use-hasmany)
* [피벗 테이블 이름 바꾸기](#rename-pivot-table)
* [한 줄로 상위 모델 업데이트](#update-parent-in-one-line)
* [Laravel 7이상에서 외래 키](#laravel-7-foreign-keys)
* [두 "whereHas"결합](#combine-two-wherehas)
* [관계 메서드가 있는지 확인하기](#check-if-relationship-method-exists)
* [추가 관계가 있는 피벗 테이블](#pivot-table-with-extra-relations)
* [즉석으로 관계 갯수 구해오기](#load-count-on-the-fly)
* [관계 순서 무작위 화](#randomize-relationship-order)

### Eloquent 관계에 대한 OrderBy <a href="#orderby-on-eloquent-relationships" id="orderby-on-eloquent-relationships"></a>

Eloquent 관계에서 직접 orderBy()를 지정할 수 있습니다.

```php
public function products()
{
    return $this->hasMany(Product::class);
}

public function productsByName()
{
    return $this->hasMany(Product::class)->orderBy('name');
}
```

### 조건부 관계 <a href="#conditional-relationships" id="conditional-relationships"></a>

추가 "where"조건과 함께 동일한 관계를 자주 사용하는 경우 별도의 관계 방법을 만들 수 있습니다.

모델:

```php
public function comments()
{
    return $this->hasMany(Comment::class);
}

public function approved_comments()
{
    return $this->hasMany(Comment::class)->where('approved', 1);
}
```

### Raw DB 쿼리: havingRaw() <a href="#raw-db-queries-havingraw" id="raw-db-queries-havingraw"></a>

`havingRaw()` 이후의 `groupBy()` 함수를 포함하여 다양한 위치에서 RAW DB 쿼리를 사용할 수 있습니다.

```php
Product::groupBy('category_id')->havingRaw('COUNT(*) > 1')->get();
```

### Eloquent has()를 더 깊게 <a href="#eloquent-has-deeper" id="eloquent-has-deeper"></a>

Eloquent `has()` 함수를 사용하여 두 단계의 관계를 쿼리 할 수 있습니다!

```php
// Author -> hasMany(Book::class);
// Book -> hasMany(Rating::class);
$authors = Author::has('books.ratings')->get();
```

### Has Many. 정확히 얼마나 많은 것을 원하나요? <a href="#has-many-how-many-exactly" id="has-many-how-many-exactly"></a>

Eloquent `hasMany()` 관계에서 지정한 양의 하위 레코드가 있는 레코드를 필터링 할 수 있습니다.

```php
// Author -> hasMany(Book::class)
$authors = Author::has('books', '>', 5)->get();
```

### 기본 모델 <a href="#default-model" id="default-model"></a>

$post->user가 존재하지 않는 경우 `{{ $post->user->name }}` 과 같이 호출 할 때 치명적인 오류를 방지하기 위해 `belongsTo` 관계에 기본 모델을 할당 할 수 있습니다.

```php
public function user()
{
    return $this->belongsTo('App\User')->withDefault();
}
```

### hasMany를 이용한 다중 생성 <a href="#use-hasmany-to-create-many" id="use-hasmany-to-create-many"></a>

`hasMany()` 관계가있는 경우 `saveMany()` 를 사용하여 "부모"개체의 여러 "자식"항목을 모두 한 문장으로 저장할 수 있습니다.

```php
$post = Post::find(1);
$post->comments()->saveMany([
    new Comment(['message' => 'First comment']),
    new Comment(['message' => 'Second comment']),
]);
```

### 빠른 로딩에서 필요한 컬럼만 사용하기 <a href="#eager-loading-with-exact-columns" id="eager-loading-with-exact-columns"></a>

Laravel Eager Loading을 실행할 때 관계에서 필요한 컬럼만 가져올 수 있습니다.

```php
$users = App\Book::with('author:id,name')->get();
```

한단계를 거치는 관계에서도 사용 할 수 있습니다.

```php
$users = App\Book::with('author.country:id,name')->get();
```

### 쉽게 상위 모델의 updated\_at 갱신하기 <a href="#touch-parent-updated_at-easily" id="touch-parent-updated_at-easily"></a>

레코드를 업데이트하고 상위 관계의 `updated_at` 열을 갱신하려면 (예 : 새 댓글을 추가하고 게시글 `posts.updated_at`를 갱신하려는 경우) 자식 모델에 `$touches = ['post'];`속성을 추가.

```php
class Comment extends Model
{
    protected $touches = ['post'];
}
```

### 관계가 존재하는지 항상 확인하세요 <a href="#always-check-if-relationship-exists" id="always-check-if-relationship-exists"></a>

**지금까지는** `$model->relationship->field`처럼 관계 객체가 여전히 존재하는지 확인하지 않고 사용했습니다.

현재 동작하는 코드 외부, 즉 다른 사람의 대기열 작업 등 어떤 이유로든 관계는 삭제 될 수 있습니다. `if-else` , 또는 `{{ $model->relationship->field ?? '' }}` 또는 (블레이드)`{{ optional($model->relationship)->field }}`를 사용하세요.

### withCount()를 사용하여 하위 관계 레코드의 갯수 확인 <a href="#use-withcount-to-calculate-child-relationships-records" id="use-withcount-to-calculate-child-relationships-records"></a>

`hasMany()` 관계에서 "자식"항목을 갯수를 확인하려면 쿼리를 따로 작성하지 마세요. 예를 들어, User 모델에 대한 게시물과 댓글이 있을 경우 `withCount()` 사용하세요.

```php
public function index()
{
    $users = User::withCount(['posts', 'comments'])->get();
    return view('users', compact('users'));
}
```

그런 다음 블레이드 파일에서 `{relationship}_count` 속성을 사용하여 해당 갯수를 가져올 수 있습니다.

```
@foreach ($users as $user)
<tr>
    <td>{{ $user->name }}</td>
    <td class="text-center">{{ $user->posts_count }}</td>
    <td class="text-center">{{ $user->comments_count }}</td>
</tr>
@endforeach
```

해당 필드로 정렬할 수도 있습니다.

```php
User::withCount('comments')->orderBy('comments_count', 'desc')->get();
```

### 관계에서 필터 쿼리 추가하기 <a href="#extra-filter-query-on-relationships" id="extra-filter-query-on-relationships"></a>

관계 데이터를 불러올때 클로저 함수에서 몇 가지 제한 또는 순서를 지정할 수 있습니다. 예를 들어, 가장 큰 도시가 3 개만 있는 국가를 얻으려면 다음과 같이 코드를 작성하면 됩니다.

```php
$countries = Country::with(['cities' => function($query) {
    $query->orderBy('population', 'desc');
    $query->take(3);
}])->get();
```

### 관계를 항상 로드하지만 동적으로도 로드하기 <a href="#load-relationships-always-but-dynamically" id="load-relationships-always-but-dynamically"></a>

모델과 함께 항상 로드 할 관계를 지정할 수 있을 뿐만 아니라 생성자 메서드에서 동적으로 처리할 수도 있습니다.

```php
class ProductTag extends Model
{
    protected $with = ['product'];

    public function __construct() {
        parent::__construct();
        $this->with = ['product'];

        if (auth()->check()) {
            $this->with[] = 'user';
        }
    }
}
```

### belongsTo 대신 hasMany를 사용하세요. <a href="#instead-of-belongsto-use-hasmany" id="instead-of-belongsto-use-hasmany"></a>

`belongsTo` 관계에서 하위 레코드를 만들 때 부모의 ID를 전달하는 방식 대신, `hasMany` 관계를 사용하여 더 짧은 문장을 만들 수 있습니다.

```php
// 만약 Post -> belongsTo(User)이고, User -> hasMany(Post) 라면...
// user_id를 넘겨주는 대신...
Post::create([
    'user_id' => auth()->id(),
    'title' => request()->input('title'),
    'post_text' => request()->input('post_text'),
]);

// 이렇게 사용하세요
auth()->user()->posts()->create([
    'title' => request()->input('title'),
    'post_text' => request()->input('post_text'),
]);
```

### 피벗 테이블 이름 바꾸기 <a href="#rename-pivot-table" id="rename-pivot-table"></a>

"pivot"단어의 이름을 바꾸고 관계를 다른 이름으로 부르려면 관계에서 `->as('name')` 를 사용하면됩니다.

모델:

```php
public function podcasts() {
    return $this->belongsToMany('App\Podcast')
        ->as('subscription')
        ->withTimestamps();
}
```

컨트롤러:

```php
$podcasts = $user->podcasts();
foreach ($podcasts as $podcast) {
    // $podcast->pivot->created_at 대신에...
    echo $podcast->subscription->created_at;
}
```

### 한 줄로 상위 모델 업데이트 <a href="#update-parent-in-one-line" id="update-parent-in-one-line"></a>

`belongsTo()` 관계일 경우 한 문장으로 Eloquent 관계 데이터를 업데이트 할 수 있습니다.

```php
// 만약 Project -> belongsTo(User::class)이라면
$project->user->update(['email' => 'some@gmail.com']);
```

### Laravel 7이상에서 외래 키 <a href="#laravel-7-foreign-keys" id="laravel-7-foreign-keys"></a>

Laravel 7부터 마이그레이션시 관계 필드에 대해 두 줄을 작성할 필요가 없습니다. 하나는 필드 용이고 다른 하나는 외래 키용입니다. `foreignId()` 메소드를 사용하십시오.

```php
// Laravel 7 이전
Schema::table('posts', function (Blueprint $table)) {
    $table->unsignedBigInteger('user_id');
    $table->foreign('user_id')->references('id')->on('users');
}

// Laravel 7 부터
Schema::table('posts', function (Blueprint $table)) {
    $table->foreignId('user_id')->constrained();
}

// 또는, 필드가 참조 테이블과 다른 경우
Schema::table('posts', function (Blueprint $table)) {
    $table->foreignId('created_by_id')->constrained('users', 'column');
}
```

### 두 "whereHas"결합 <a href="#combine-two-wherehas" id="combine-two-wherehas"></a>

Eloquent에서는 `whereHas()`과 `orDoesntHave()`을 한 문장으로 결합 할 수 있습니다.

```php
User::whereHas('roles', function($query) {
    $query->where('id', 1);
})
->orDoesntHave('roles')
->get();
```

### 관계 메서드가 있는지 확인하기 <a href="#check-if-relationship-method-exists" id="check-if-relationship-method-exists"></a>

Eloquent 관계 이름이 동적이고 해당 이름과의 관계가 객체에 존재하는지 확인해야 하는 경우 PHP 함수 `method_exists($object, $methodName)`를 사용하세요.

```php
$user = User::first();
if (method_exists($user, 'roles')) {
    // $user->roles()-> 와 함께 관계 메서드 사용하기...
}
```

### 추가 관계가 있는 피벗 테이블 <a href="#pivot-table-with-extra-relations" id="pivot-table-with-extra-relations"></a>

다대다 관계에서 피벗 테이블에는 추가 필드 및 다른 모델에 대한 추가 관계가 포함될 수 있습니다.

다음과 같이 별도의 피벗 모델을 생성합니다.

```
php artisan make:model RoleUser --pivot
```

그다음 `->using()` 메서드를 사용하여 `belongsToMany()`에 지정합니다. 그러면 다음 예제와 같이 쩌는 것을 할 수 있습니다.

```php
// app/Models/User.php 에서
public function roles()
{
    return $this->belongsToMany(Role::class)
        ->using(RoleUser::class)
        ->withPivot(['team_id']);
}

// app/Models/RoleUser.php 모델은 Model이 아닌 Illuminate\Database\Eloquent\Relations\Pivot을 확장하여 사용합니다;

class RoleUser extends Pivot
{
    public function team()
    {
        return $this->belongsTo(Team::class);
    }
}

// 그러면 Controller에서 아래와 같이 실행할 수 있습니다.
$firstTeam = auth()->user()->roles()->first()->pivot->team->name;
```

### 즉석으로 관계 갯수 구해오기 <a href="#load-count-on-the-fly" id="load-count-on-the-fly"></a>

관련 레코드의 갯수를 가져오기 위해 Eloquent의 `withCount()` 메서드 외에도 `loadCount()`를 사용하여 즉석으로 갯수를 가져올 수 도 있습니다.

```php
// 만약 Book이 여러개의 Reviews를 가지고 있다면...
$book = App\Book::first();

$book->loadCount('reviews');
// $book->reviews_count; 를 사용할 수 있습니다

// 또 추가 조건과 함께도 가능합니다
$book->loadCount(['reviews' => function ($query) {
    $query->where('rating', 5);
}]);
```

### 관계 순서 무작위 화 <a href="#randomize-relationship-order" id="randomize-relationship-order"></a>

`inRandomOrder()`를 사용하여 Eloquent 쿼리 결과를 무작위화 할 수 있지만 이를 사용하여 쿼리로 로드하는 **relationship** 항목을 무작위화 할 수도 있습니다.

```php
// 퀴즈가 있고 질문을 무작위로 선택하려는 경우...

// 1. 무작위 순서로 질문을 받고 싶다면
$questions = Question::inRandomOrder()->get();

// 2. 무작위 순서로 질문 옵션을 가져오려면 다음과 같이 사용하세요.
$questions = Question::with(['answers' => function($q) {
    $q->inRandomOrder();
}])->inRandomOrder()->get();
```

## 마이그레이션 <a href="#migrations" id="migrations"></a>

⬆️ [맨 위로 이동](#laravel-tips) ⬅️ [이전 (모델 관계)](#models-relations) ➡️ [다음 (보기)](#views)

* [부호없는 정수](#unsigned-integer)
* [마이그레이션 순서](#order-of-migrations)
* [시간대가있는 마이그레이션 필드](#migration-fields-with-timezones)
* [데이터베이스 마이그레이션 열 유형](#database-migrations-column-types)
* [기본 타임 스탬프](#default-timestamp)
* [마이그레이션 상태](#migration-status)
* [공백과 함께 마이그레이션 만들기](#create-migration-with-spaces)
* [다른 열 뒤에 열 만들기](#create-column-after-another-column)

### 부호없는 정수 <a href="#unsigned-integer" id="unsigned-integer"></a>

외래 키 마이그레이션의 경우 `integer()` 대신 `unsignedInteger()` 유형 또는 `integer()->unsigned()`를 사용하세요 . 그렇지 않으면 SQL 오류가 발생할 수 있습니다.

```php
Schema::create('employees', function (Blueprint $table) {
    $table->unsignedInteger('company_id');
    $table->foreign('company_id')->references('id')->on('companies');
    // ...
});
```

다른 열이 `bigInteger()` 유형 인 경우 `unsignedBigInteger()` 사용할 수도 있습니다.

```php
Schema::create('employees', function (Blueprint $table) {
    $table->unsignedBigInteger('company_id');
});
```

### 마이그레이션 순서 <a href="#order-of-migrations" id="order-of-migrations"></a>

당신은 DB 마이그레이션의 순서를 변경하려면, 단지 다음과 같이 파일에서 타임 스탬프만 바꾸면 됩니다. `2018_08_04_070443_create_posts_table.php` 에서 `2018_07_04_070443_create_posts_table.php` 로 변경. (`2018_08_04` 에서 `2018_07_04` 로 변경).

마이그레이션은 알파벳 순서로 실행됩니다.

### 시간대가 있는 마이그레이션 필드 <a href="#migration-fields-with-timezones" id="migration-fields-with-timezones"></a>

마이그레이션에서 timezone에 대한 timetamps `timestamps()` 뿐만 아니라 `timestampsTz()` 도 있다는 것을 알고 계셨습니까?

```php
Schema::create('employees', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('email');
    $table->timestampsTz();
});
```

또한 `dateTimeTz()` , `timeTz()` , `timestampTz()` , `softDeletesTz()` 도 있습니다.

### 데이터베이스 마이그레이션 열 유형 <a href="#database-migrations-column-types" id="database-migrations-column-types"></a>

마이그레이션을 위한 재밌는 열 유형이 있습니다. 몇 가지 예를 보여드리겠습니다.

```php
$table->geometry('positions');
$table->ipAddress('visitor');
$table->macAddress('device');
$table->point('position');
$table->uuid('id');
```

[공식 문서](https://laravel.com/docs/master/migrations#creating-columns) 에서 모든 열 유형을 참조하십시오.

### 기본 타임 스탬프 <a href="#default-timestamp" id="default-timestamp"></a>

마이그레이션을 생성하는 동안 `useCurrent()` 옵션과 함께 `timestamp()` 열 유형을 사용할 수 있으며 `CURRENT_TIMESTAMP` 를 기본값으로 설정합니다.

```php
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->useCurrent();
```

### 마이그레이션 상태 <a href="#migration-status" id="migration-status"></a>

어떤 마이그레이션이 아직 실행되지 않았는지 확인하고 싶을때, 굳이 데이터베이스에서 "migrations"테이블을 볼 필요가 없습니다. `php artisan migrate:status` 명령을 실행해보세요.

결과 예 :

```
+------+------------------------------------------------+-------+
| Ran? | Migration                                      | Batch |
+------+------------------------------------------------+-------+
| Yes  | 2014_10_12_000000_create_users_table           | 1     |
| Yes  | 2014_10_12_100000_create_password_resets_table | 1     |
| No   | 2019_08_19_000000_create_failed_jobs_table     |       |
+------+------------------------------------------------+-------+
```

### 공백과 함께 마이그레이션 만들기 <a href="#create-migration-with-spaces" id="create-migration-with-spaces"></a>

`make:migration` 명령어를 입력 할 때 `create_transactions_table`과 같이 부분 사이에 반드시 밑줄 `_` 기호를 사용할 필요는 없습니다. 이름을 따옴표로 묶은 다음 밑줄 대신 공백을 사용할 수 있습니다.

```php
// This works
php artisan make:migration create_transactions_table

// But this works too
php artisan make:migration "create transactions table"
```

출처 : [Twitter의 Steve O](https://twitter.com/stephenoldham/status/1353647972991578120)

### 다른 열 뒤에 열 만들기 <a href="#create-column-after-another-column" id="create-column-after-another-column"></a>

기존 테이블에 새 열을 추가할 때 반드시 마지막 열로 만들 필요는 없습니다. 생성해야 하는 열을 특정 열의 뒤로 지정할 수 있습니다.

```php
Schema::table('users', function (Blueprint $table) {
    $table->string('phone')->after('email');
});
```

## 뷰 <a href="#views" id="views"></a>

⬆️ [맨 위로 이동](#laravel-tips) ⬅️ [이전 (마이그레이션)](#migrations) ➡️ [다음 (라우팅)](#routing)

* [foreach의 $loop 변수](#loop-variable-in-foreach)
* [뷰 파일이 있습니까?](#does-view-file-exist)
* [오류 코드 블레이드 페이지](#error-code-blade-pages)
* [컨트롤러 없이 뷰 사용하기](#view-without-controllers)
* [블레이드 @auth](#blade-auth)
* [블레이드의 2 단계 $loop 변수](#two-level-loop-variable-in-blade)
* [나만의 블레이드 지시문 만들기](#create-your-own-blade-directive)
* [블레이드 지시문 : IncludeIf, IncludeWhen, IncludeFirst](#blade-directives-includeif-includewhen-includefirst)

### foreach의 $loop 변수 <a href="#loop-variable-in-foreach" id="loop-variable-in-foreach"></a>

foreach 루프 내에서 `$loop` 변수를 사용하여 현재 항목이 처음 / 마지막인지 확인합니다.

```
@foreach ($users as $user)
     @if ($loop->first)
        This is the first iteration.
     @endif

     @if ($loop->last)
        This is the last iteration.
     @endif

     <p>This is user {{ $user->id }}</p>
@endforeach
```

`$loop->iteration` 또는 `$loop->count` 와 같은 다른 속성도 있습니다. [공식 문서](https://laravel.com/docs/master/blade#the-loop-variable) 에서 자세히 알아보십시오.

### 뷰 파일이 있습니까? <a href="#does-view-file-exist" id="does-view-file-exist"></a>

실제로 뷰를 로드하기 전에 해당 뷰 파일이 있는지 확인할 수 있습니다.

```php
if (view()->exists('custom.page')) {
 // Load the view
}
```

로드 할 뷰 배열을 사용 할 수도 있으며, 이때는 처음 존재하는 뷰만 실제로 로드됩니다.

```php
return view()->first(['custom.dashboard', 'dashboard'], $data);
```

### 오류 코드 블레이드 페이지 <a href="#error-code-blade-pages" id="error-code-blade-pages"></a>

500과 같은 일부 HTTP 코드에 대한 특정 오류 페이지를 생성하려면 이 코드를 파일 이름으로 `resources/views/errors/500.blade.php` 또는 `403.blade.php` 등으로 블레이드 파일을 만드세요. 해당 오류 코드에 맞게 자동으로 로드됩니다.

### 컨트롤러 없이 뷰 사용하기 <a href="#view-without-controllers" id="view-without-controllers"></a>

라우트가 특정 뷰만 보여준다면 Controller를 생성하지 말고 `Route::view()` 함수를 사용하십시오.

```php
// 이것처럼 되어있거나
Route::get('about', 'TextsController@about');
// 이것처럼 되어있다면
class TextsController extends Controller
{
    public function about()
    {
        return view('texts.about');
    }
}
// 이렇게 사용하세요
Route::view('about', 'texts.about');
```

### 블레이드 @auth <a href="#blade-auth" id="blade-auth"></a>

로그인 한 사용자를 확인하기위해 if 문 대신 `@auth` 지시문을 사용하세요.

일반적인 방법 :

```
@if(auth()->user())
    // The user is authenticated.
@endif
```

짧게 :

```
@auth
    // The user is authenticated.
@endauth
```

반대는 `@guest` 지시문입니다.

```
@guest
    // The user is not authenticated.
@endguest
```

### 블레이드의 2 단계 $loop 변수 <a href="#two-level-loop-variable-in-blade" id="two-level-loop-variable-in-blade"></a>

Blade의 foreach에서는 2 단계 루프에서도 $loop 변수를 사용하여 상위 변수에 접근 할 수 있습니다.

```
@foreach ($users as $user)
    @foreach ($user->posts as $post)
        @if ($loop->parent->first)
            This is first iteration of the parent loop.
        @endif
    @endforeach
@endforeach
```

### 나만의 블레이드 지시문 만들기 <a href="#create-your-own-blade-directive" id="create-your-own-blade-directive"></a>

진짜 쉽습니다. `app/Providers/AppServiceProvider.php` 에 자신만의 메서드를 추가하기만 하면됩니다. 예를 들어, `<br>` 태그를 엔터로 바꾸려면 다음과 같이하십시오.

```
// 블레이드에서
<textarea>@br2nl($post->post_text)</textarea>
```

이 지시문을 AppServiceProvider의 `boot()` 메서드에 추가합니다.

```php
public function boot()
{
    Blade::directive('br2nl', function ($string) {
        return "<?php echo preg_replace('/\<br(\s*)?\/?\>/i', \"\n\", $string); ?>";
    });
}
```

### 블레이드 지시문 : IncludeIf, IncludeWhen, IncludeFirst <a href="#blade-directives-includeif-includewhen-includefirst" id="blade-directives-includeif-includewhen-includefirst"></a>

Blade 부분적으로 사용하는 파일이 실제로 존재하는지 확실하지 않은 경우 다음 조건 명령을 사용할 수 있습니다.

블레이드 파일이 있는 경우에만 헤더를 로드합니다.

```
@includeIf('partials.header')
```

role\_id가 1 인 사용자에 대해서만 헤더를로드합니다.

```
@includeWhen(auth()->user()->role_id == 1, 'partials.header')
```

adminlte.header를 로드하려고 시도합니다. 해당 파일이 없을 경우에만 default.header를 로드합니다.

```
@includeFirst('adminlte.header', 'default.header')
```

## 라우팅 <a href="#routing" id="routing"></a>

⬆️ [맨 위로 이동](#laravel-tips) ⬅️ [이전 (뷰)](#views) ➡️ [다음 (유효성 검사)](#validation)

* [그룹 내의 라우팅 그룹](#route-group-within-a-group)
* [와일드 카드 하위 도메인](#wildcard-subdomains)
* [라우트 뒤에는 무엇이 있을까요?](#whats-behind-the-routes)
* [라우트에서 모델 바인딩 : 키를 지정 할 수 있습니다.](#route-model-binding-you-can-define-a-key)
* [Routes 파일에서 컨트롤러로 빠르게 이동](#quickly-navigate-from-routes-file-to-controller)
* [대체 라우트 : 일치하는 다른 경로가 없는 경우](#route-fallback-when-no-other-route-is-matched)
* [정규식을 사용한 라우트 매개 변수 유효성 검사](#route-parameters-validation-with-regexp)
* [속도 제한 : 글로벌 및 게스트 / 사용자 용](#rate-limiting-global-and-for-guestsusers)
* [라우트에 매개 변수로 쿼리스트링을 추가하기](#query-string-parameters-to-routes)
* [파일별로 라우트 분리](#separate-routes-by-files)
* [리소스 동사 번역](#translate-resource-verbs)
* [커스텀 리소스 라우트 네임](#custom-resource-route-names)
* [더 읽기 쉬운 라우트 목록](#more-readable-route-list)

### 그룹 내의 라우팅 그룹 <a href="#route-group-within-a-group" id="route-group-within-a-group"></a>

라우트에서 그룹 내 그룹을 생성하여, 특정 미들웨어를 "상위"그룹의 일부 URL에만 할당 할 수 있습니다.

```php
Route::group(['prefix' => 'account', 'as' => 'account.'], function() {
    Route::get('login', 'AccountController@login');
    Route::get('register', 'AccountController@register');

    Route::group(['middleware' => 'auth'], function() {
        Route::get('edit', 'AccountController@edit');
    });
});
```

### 와일드 카드 하위 도메인 <a href="#wildcard-subdomains" id="wildcard-subdomains"></a>

동적인 하위 도메인 이름으로 라우트 그룹을 생성하고 해당 값을 모든 경로에 전달할 수 있습니다.

```php
Route::domain('{username}.workspace.com')->group(function () {
    Route::get('user/{id}', function ($username, $id) {
        //
    });
});
```

### 라우트 뒤에는 무엇이 있을까요? <a href="#whats-behind-the-routes" id="whats-behind-the-routes"></a>

`Auth::routes()` 에 실제로 어떤 경로들이 있는지 알고 싶나요? Laravel 7부터는 별도의 패키지에 있는 `/vendor/laravel/ui/src/AuthRouteMethods.php` 파일을 확인해보세요.

```php
public function auth()
{
    return function ($options = []) {
        // Authentication Routes...
        $this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
        $this->post('login', 'Auth\LoginController@login');
        $this->post('logout', 'Auth\LoginController@logout')->name('logout');
        // Registration Routes...
        if ($options['register'] ?? true) {
            $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
            $this->post('register', 'Auth\RegisterController@register');
        }
        // Password Reset Routes...
        if ($options['reset'] ?? true) {
            $this->resetPassword();
        }
        // Password Confirmation Routes...
        if ($options['confirm'] ?? class_exists($this->prependGroupNamespace('Auth\ConfirmPasswordController'))) {
            $this->confirmPassword();
        }
        // Email Verification Routes...
        if ($options['verify'] ?? false) {
            $this->emailVerification();
        }
    };
}
```

Laravel 7 이전이라면 `/vendor/laravel/framework/src/illuminate/Routing/Router.php` 파일을 확인해보세요.

### 라우트에서 모델 바인딩 : 키를 지정 할 수 있습니다. <a href="#route-model-binding-you-can-define-a-key" id="route-model-binding-you-can-define-a-key"></a>

라우트에 모델을 `Route::get('api/users/{user}', function (App\User $user) { … }` 이런식으로 ID 필드를 기준으로 바인딩 할 수 있을 뿐만 아니라, `{user}`를 `username` 필드로 변경하고 싶다면 다음과 같이 모델에 입력하면 됩니다.

```php
public function getRouteKeyName() {
    return 'username';
}
```

### Routes 파일에서 컨트롤러로 빠르게 이동 <a href="#quickly-navigate-from-routes-file-to-controller" id="quickly-navigate-from-routes-file-to-controller"></a>

이것은 Laravel 8 이전에는 선택 사항이었으며 Laravel 8에서 라우팅의 표준 기본 구문이되었습니다.

다음과 같이 라우팅하는 대신

```php
Route::get('page', 'PageController@action');
```

컨트롤러를 클래스로 지정할 수 있습니다.

```php
Route::get('page', [\App\Http\Controllers\PageController::class, 'action']);
```

그런 다음 PhpStorm에서 **PageController** 를 클릭하고 수동으로 검색하는 대신 Controller로 직접 이동할 수 있습니다.

또 길이를 줄이려면 다음과 같이 Routes 파일의 맨 위에 use 구분을 추가하십시오.

```php
use App\Http\Controllers\PageController;

// 요롷게~
Route::get('page', [PageController::class, 'action']);
```

### 대체 라우트 : 일치하는 다른 경로가 없는 경우 <a href="#route-fallback-when-no-other-route-is-matched" id="route-fallback-when-no-other-route-is-matched"></a>

찾을 수 없는 경로에 대한 추가 로직을 지정하려면 기본 404 페이지를 표시하는 대신 라우트 파일의 맨 끝에 특수 경로를 만들 수 있습니다.

```php
Route::group(['middleware' => ['auth'], 'prefix' => 'admin', 'as' => 'admin.'], function () {
    Route::get('/home', 'HomeController@index');
    Route::resource('tasks', 'Admin\TasksController');
});

// Some more routes....
Route::fallback(function() {
    return 'Hm, why did you land here somehow?';
});
```

### 정규식을 사용한 라우트 매개 변수 유효성 검사 <a href="#route-parameters-validation-with-regexp" id="route-parameters-validation-with-regexp"></a>

"where"매개 변수를 사용하여 경로에서 직접 매개 변수를 검증 할 수 있습니다. 일반적으로 경로에 `fr/blog` 및 `en/article/333` 과 같이 언어 로케일로 접두사를 지정하는 경우가 있습니다. 이때 두 개의 첫 글자가 영어가 아닌 다른 언어가 사용되지 않도록하려면 어떻게해야 할까요?

`routes/web.php` :

```php
Route::group([
    'prefix' => '{locale}',
    'where' => ['locale' => '[a-zA-Z]{2}']
], function () {
    Route::get('/', 'HomeController@index');
    Route::get('article/{id}', 'ArticleController@show');
});
```

### 속도 제한 : 글로벌 및 게스트 / 사용자 용 <a href="#rate-limiting-global-and-for-guestsusers" id="rate-limiting-global-and-for-guestsusers"></a>

`throttle:60,1`을 사용하여 일부 URL은 분당 최대 60 회 호출되도록 제한 할 수 있습니다.

```php
Route::middleware('auth:api', 'throttle:60,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});
```

또한 게스트 및 로그인 한 사용자에 대해 별도로 지정 할 수 있습니다.

```php
// 게스트에 대해 최대 10 개의 요청, 인증 된 사용자에 대해 60 개
Route::middleware('throttle:10|60,1')->group(function () {
    //
});
```

또한 DB 필드 users.rate\_limit를 사용해 특정 사용자에 대한 제한 지정 할 수 있습니다.

```php
Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});
```

### 라우트에 매개 변수로 쿼리스트링을 추가하기 <a href="#query-string-parameters-to-routes" id="query-string-parameters-to-routes"></a>

라우트에 추가 매개 변수를 전달하면 배열의 키/값이 생성 될 URL의 쿼리 문자열에 자동으로 추가됩니다.

```php
Route::get('user/{id}/profile', function ($id) {
    //
})->name('profile');

$url = route('profile', ['id' => 1, 'photos' => 'yes']); // Result: /user/1/profile?photos=yes
```

### 파일별로 라우트 분리 <a href="#separate-routes-by-files" id="separate-routes-by-files"></a>

특정 "섹션"에 관한 경로가 셋트로 있는 경우, 별도의 `routes/XXXXX.php` 같은 파일로 분리해서 `routes/web.php`에 포함시킬 수 있습니다

Taylor Otwell이 직접 만든 [Laravel Breeze](https://github.com/laravel/breeze/blob/1.x/stubs/routes/web.php)의 `routes/auth.php` 예제 :

```php
Route::get('/', function () {
    return view('welcome');
});

Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth'])->name('dashboard');

require __DIR__.'/auth.php';
```

그런 다음, `routes/auth.php` :

```php
use App\Http\Controllers\Auth\AuthenticatedSessionController;
use App\Http\Controllers\Auth\RegisteredUserController;
// ... more controllers

use Illuminate\Support\Facades\Route;

Route::get('/register', [RegisteredUserController::class, 'create'])
                ->middleware('guest')
                ->name('register');

Route::post('/register', [RegisteredUserController::class, 'store'])
                ->middleware('guest');

// ... A dozen more routes
```

하지만 이 `include()`는 별도의 라우트 파일에 접두사 / 미들웨어에 대해 동일한 설정일 경우에만 사용해야합니다. 그렇지 않으면 `app/Providers/RouteServiceProvider`에서 그룹화하는 것이 좋습니다.

```php
public function boot()
{
    $this->configureRateLimiting();

    $this->routes(function () {
        Route::prefix('api')
            ->middleware('api')
            ->namespace($this->namespace)
            ->group(base_path('routes/api.php'));

        Route::middleware('web')
            ->namespace($this->namespace)
            ->group(base_path('routes/web.php'));

        // ... Your routes file listed next here
    });
}
```

### 리소스 동사 번역 <a href="#translate-resource-verbs" id="translate-resource-verbs"></a>

리소스 컨트롤러를 사용하지만 SEO 목적으로 URL 동사를 영어가 아닌 것으로 변경하려는 경우 `/create` 대신 스페인어 `/crear` 를 원하면 `App\Providers\RouteServiceProvider` `Route::resourceVerbs()` 메서드를 사용하여 변경 할 수 있습니다.

```php
public function boot()
{
    Route::resourceVerbs([
        'create' => 'crear',
        'edit' => 'editar',
    ]);

    // ...
}
```

### 사용자 지정 리소스 경로 이름 <a href="#custom-resource-route-names" id="custom-resource-route-names"></a>

리소스 컨트롤러를 사용할 때 `routes/web.php` 에서 `->names()` 매개 변수를 지정할 수 있으므로 브라우저의 URL 접두사와 Laravel 프로젝트 전체에서 사용하는 경로 이름 접두사가 다를 수 있습니다.

```php
Route::resource('p', ProductController::class)->names('products');
```

따라서 위의 코드는 `/p` , `/p/{id}` , `/p/{id}/edit` 등과 같은 URL을 생성합니다.하지만 코드에서 `route('products.index')` , `route('products.create')` 등

### 더 읽기 쉬운 라우트 목록 <a href="#more-readable-route-list" id="more-readable-route-list"></a>

"php artisan route : list"를 실행 한 다음 목록이 너무 많은 공간을 차지하고 읽기 어렵다는 것을 깨달은 적이 있습니까?

해결책은 다음과 같습니다 : `php artisan route:list --compact`

그러면 6 개 열 대신 3 개 열이 표시됩니다. Method / URI / Action 만 표시됩니다.

```
+----------+---------------------------------+-------------------------------------------------------------------------+
| Method   | URI                             | Action                                                                  |
+----------+---------------------------------+-------------------------------------------------------------------------+
| GET|HEAD | /                               | Closure                                                                 |
| GET|HEAD | api/user                        | Closure                                                                 |
| POST     | confirm-password                | App\Http\Controllers\Auth\ConfirmablePasswordController@store           |
| GET|HEAD | confirm-password                | App\Http\Controllers\Auth\ConfirmablePasswordController@show            |
| GET|HEAD | dashboard                       | Closure                                                                 |
| POST     | email/verification-notification | App\Http\Controllers\Auth\EmailVerificationNotificationController@store |
| POST     | forgot-password                 | App\Http\Controllers\Auth\PasswordResetLinkController@store             |
| GET|HEAD | forgot-password                 | App\Http\Controllers\Auth\PasswordResetLinkController@create            |
| POST     | login                           | App\Http\Controllers\Auth\AuthenticatedSessionController@store          |
| GET|HEAD | login                           | App\Http\Controllers\Auth\AuthenticatedSessionController@create         |
| POST     | logout                          | App\Http\Controllers\Auth\AuthenticatedSessionController@destroy        |
| POST     | register                        | App\Http\Controllers\Auth\RegisteredUserController@store                |
| GET|HEAD | register                        | App\Http\Controllers\Auth\RegisteredUserController@create               |
| POST     | reset-password                  | App\Http\Controllers\Auth\NewPasswordController@store                   |
| GET|HEAD | reset-password/{token}          | App\Http\Controllers\Auth\NewPasswordController@create                  |
| GET|HEAD | verify-email                    | App\Http\Controllers\Auth\EmailVerificationPromptController@__invoke    |
| GET|HEAD | verify-email/{id}/{hash}        | App\Http\Controllers\Auth\VerifyEmailController@__invoke                |
+----------+---------------------------------+-------------------------------------------------------------------------+
```

원하는 정확한 열을 지정할 수도 있습니다.

`php artisan route:list --columns=Method,URI,Name`

```
+----------+---------------------------------+---------------------+
| Method   | URI                             | Name                |
+----------+---------------------------------+---------------------+
| GET|HEAD | /                               |                     |
| GET|HEAD | api/user                        |                     |
| POST     | confirm-password                |                     |
| GET|HEAD | confirm-password                | password.confirm    |
| GET|HEAD | dashboard                       | dashboard           |
| POST     | email/verification-notification | verification.send   |
| POST     | forgot-password                 | password.email      |
| GET|HEAD | forgot-password                 | password.request    |
| POST     | login                           |                     |
| GET|HEAD | login                           | login               |
| POST     | logout                          | logout              |
| POST     | register                        |                     |
| GET|HEAD | register                        | register            |
| POST     | reset-password                  | password.update     |
| GET|HEAD | reset-password/{token}          | password.reset      |
| GET|HEAD | verify-email                    | verification.notice |
| GET|HEAD | verify-email/{id}/{hash}        | verification.verify |
+----------+---------------------------------+---------------------+
```

## 유효성 검사 <a href="#validation" id="validation"></a>

⬆️ [맨 위로 이동](#laravel-tips) ⬅️ [이전 (라우팅)](#routing) ➡️ [다음 (컬렉션)](#collections)

* [이미지 유효성 검사](#image-validation)
* [사용자 지정 유효성 검사 오류 메시지](#custom-validation-error-messages)
* ["지금"또는 "어제"단어로 날짜 확인](#validate-dates-with-now-or-yesterday-words)
* [일부 조건이있는 유효성 검사 규칙](#validation-rule-with-some-conditions)
* [기본 검증 메시지 변경](#change-default-validation-messages)
* [검증 준비](#prepare-for-validation)
* [첫 번째 유효성 검사 오류시 중지](#stop-on-first-validation-error)

### 이미지 유효성 검사 <a href="#image-validation" id="image-validation"></a>

업로드 된 이미지의 유효성을 검사하는 동안 필요한 크기를 지정할 수 있습니다.

```php
['photo' => 'dimensions:max_width=4096,max_height=4096']
```

### 사용자 지정 유효성 검사 오류 메시지 <a href="#custom-validation-error-messages" id="custom-validation-error-messages"></a>

**필드** , **규칙** 및 **언어** 별로 유효성 검사 오류 메시지를 사용자 정의 할 수 있습니다. 적절한 배열 구조로 특정 언어 파일 `resources/lang/xx/validation.php` 를 생성하기 만하면됩니다.

```php
'custom' => [
     'email' => [
        'required' => 'We need to know your e-mail address!',
     ],
],
```

### "지금"또는 "어제"단어로 날짜 확인 <a href="#validate-dates-with-now-or-yesterday-words" id="validate-dates-with-now-or-yesterday-words"></a>

이전 / 이후 규칙에 따라 날짜의 유효성을 검사하고 `tomorrow` , `now` , `yesterday` 와 같은 다양한 문자열을 매개 변수로 전달할 수 있습니다. 예 : `'start_date' => 'after:now'` . 내부적으로는 strtotime()을 사용하고 있습니다.

```php
$rules = [
    'start_date' => 'after:tomorrow',
    'end_date' => 'after:start_date'
];
```

### 일부 조건이있는 유효성 검사 규칙 <a href="#validation-rule-with-some-conditions" id="validation-rule-with-some-conditions"></a>

유효성 검사 규칙이 일부 조건에 의존하는 경우 `FormRequest` 클래스에 `withValidator()` 를 추가하여 규칙을 수정하고 여기에서 사용자 지정 논리를 지정할 수 있습니다. 예를 들어 일부 사용자 역할에 대해서만 유효성 검사 규칙을 추가하려는 경우입니다.

```php
use Illuminate\Validation\Validator;
class StoreBlogCategoryRequest extends FormRequest {
    public function withValidator(Validator $validator) {
        if (auth()->user()->is_admin) {
            $validator->addRules(['some_secret_password' => 'required']);
        }
    }
}
```

### 기본 검증 메시지 변경 <a href="#change-default-validation-messages" id="change-default-validation-messages"></a>

특정 필드 및 특정 유효성 검사 규칙에 대한 기본 유효성 검사 오류 메시지를 변경하려면 `FormRequest` 클래스에 `messages()` 메서드를 추가하면됩니다.

```php
class StoreUserRequest extends FormRequest
{
    public function rules()
    {
        return ['name' => 'required'];
    }

    public function messages()
    {
        return ['name.required' => 'User name should be real name'];
    }
}
```

### 검증 준비 <a href="#prepare-for-validation" id="prepare-for-validation"></a>

기본 Laravel 유효성 검사 전에 일부 필드를 수정하려는 경우, 즉 해당 필드를 "준비"하려면 무엇을 추측해야합니다. 이것을 위한`FormRequest` 클래스에 `prepareForValidation()` 메소드가 있습니다.

```php
protected function prepareForValidation()
{
    $this->merge([
        'slug' => Illuminate\Support\Str::slug($this->slug),
    ]);
}
```

### 첫 번째 유효성 검사 오류시 중지 <a href="#stop-on-first-validation-error" id="stop-on-first-validation-error"></a>

기본적으로 Laravel 유효성 검사 오류는 모든 유효성 검사 규칙을 확인하여 목록으로 반환됩니다. 그러나 첫 번째 오류 후에 프로세스를 중지하려면 `bail` 이라는 유효성 검사 규칙을 사용하십시오.

```php
$request->validate([
    'title' => 'bail|required|unique:posts|max:255',
    'body' => 'required',
]);
```

## 컬렉션 <a href="#collections" id="collections"></a>

⬆️ [맨 위로 이동](#laravel-tips) ⬅️ [이전 (검증)](#validation) ➡️ [다음 (인증)](#auth)

* [컬렉션에서 NULL로 필터링하지 마십시오.](#dont-filter-by-null-in-collections)
* [사용자 정의 콜백 함수가있는 콜렉션에서 groupBy 사용](#use-groupby-on-collections-with-custom-callback-function)
* [한 행의 여러 수집 방법](#multiple-collection-methods-in-a-row)
* [페이지네이션 합계 계산](#calculate-sum-with-pagination)

### 컬렉션에서 NULL로 필터링하지 마십시오. <a href="#dont-filter-by-null-in-collections" id="dont-filter-by-null-in-collections"></a>

Eloquent에서 NULL로 필터링 할 수 있지만 **컬렉션을** 추가로 필터링하는 경우 빈 문자열로 필터링하면 해당 필드에 더 이상 "null"이 없습니다.

```php
// This works
$messages = Message::where('read_at is null')->get();

// Won’t work - will return 0 messages
$messages = Message::all();
$unread_messages = $messages->where('read_at is null')->count();

// Will work
$unread_messages = $messages->where('read_at', '')->count();
```

### 사용자 정의 콜백 함수가있는 콜렉션에서 groupBy 사용 <a href="#use-groupby-on-collections-with-custom-callback-function" id="use-groupby-on-collections-with-custom-callback-function"></a>

데이터베이스의 직접 열이 아닌 일부 조건에 따라 결과를 그룹화하려면 클로저 기능을 제공하여 수행 할 수 있습니다.

예를 들어, 등록일별로 사용자를 그룹화하려는 경우 코드는 다음과 같습니다.

```php
$users = User::all()->groupBy(function($item) {
    return $item->created_at->format('Y-m-d');
});
```

⚠️주의 : `Collection` 클래스에서 수행되므로 데이터베이스에서 결과를 가져온 **후에** 수행됩니다.

### 한 행의 여러 수집 방법 <a href="#multiple-collection-methods-in-a-row" id="multiple-collection-methods-in-a-row"></a>

`->all()` 또는 `->get()` 모든 결과를 쿼리하면 동일한 결과에 대해 다양한 Collection 작업을 수행 할 수 있으며 매번 데이터베이스를 쿼리하지 않습니다.

```php
$users = User::all();
echo 'Max ID: ' . $users->max('id');
echo 'Average age: ' . $users->avg('age');
echo 'Total budget: ' . $users->sum('budget');
```

### 페이이지네이션 합계 계산 <a href="#calculate-sum-with-pagination" id="calculate-sum-with-pagination"></a>

PAGINATED 컬렉션 만있는 경우 모든 레코드의 합계를 계산하는 방법은 무엇입니까? 동일한 쿼리에서 페이지네이션 전에 계산을 실행하십시오.

```php
// How to get sum of post_views with pagination?
$posts = Post::paginate(10);
// This will be only for page 1, not ALL posts
$sum = $posts->sum('post_views');

// Do this with Query Builder
$query = Post::query();
// Calculate sum
$sum = $query->sum('post_views');
// And then do the pagination from the same query
$posts = $query->paginate(10);
```

## 인증 <a href="#auth" id="auth"></a>

⬆️ [맨 위로 이동](#laravel-tips) ⬅️ [이전 (컬렉션)](#collections) ➡️ [다음 (메일)](#mail)

* [한 번에 여러 권한 확인](#check-multiple-permissions-at-once)
* [사용자 등록에 대한 추가 이벤트](#more-events-on-user-registration)
* [Auth::once()에 대해 알고 계셨습니까?](#did-you-know-about-authonce)
* [사용자 비밀번호 업데이트시 API 토큰 변경](#change-api-token-on-users-password-update)
* [최고 관리자에 대한 권한 재정의](#override-permissions-for-super-admin)

### 한 번에 여러 권한 확인 <a href="#check-multiple-permissions-at-once" id="check-multiple-permissions-at-once"></a>

`@can` Blade 지시문 외에도 `@canany` 지시문으로 한 번에 여러 권한을 확인할 수 있다는 것을 알고 계셨습니까?

```
@canany(['update', 'view', 'delete'], $post)
    // The current user can update, view, or delete the post
@elsecanany(['create'], \App\Post::class)
    // The current user can create a post
@endcanany
```

### 사용자 등록에 대한 추가 이벤트 <a href="#more-events-on-user-registration" id="more-events-on-user-registration"></a>

신규 사용자 등록 후 몇 가지 작업을 수행하고 싶으십니까? `app/Providers/EventServiceProvider.php` 하여 Listeners 클래스를 더 추가 한 다음 해당 클래스에서 `$event->user` 객체로 `handle()` 메서드를 구현합니다.

```php
class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,

            // You can add any Listener class here
            // With handle() method inside of that class
        ],
    ];
```

### Auth::once()에 대해 알고 계셨습니까? <a href="#did-you-know-about-authonce" id="did-you-know-about-authonce"></a>

`Auth::once()` 메소드를 사용하여 ONE REQUEST에 대해서만 사용자로 로그인 할 수 있습니다. 세션이나 쿠키가 사용되지 않으므로 이 방법은 상태를 저장하지 않는 API를 구축 할 때 유용 할 수 있습니다.

```php
if (Auth::once($credentials)) {
    //
}
```

### 사용자 비밀번호 업데이트시 API 토큰 변경 <a href="#change-api-token-on-users-password-update" id="change-api-token-on-users-password-update"></a>

비밀번호가 변경되면 사용자의 API 토큰을 변경하는 것이 편리합니다.

모델:

```php
public function setPasswordAttribute($value)
{
    $this->attributes['password'] = $value;
    $this->attributes['api_token'] = Str::random(100);
}
```

### 최고 관리자에 대한 권한 재정의 <a href="#override-permissions-for-super-admin" id="override-permissions-for-super-admin"></a>

Gates를 정의했지만 SUPER ADMIN 사용자의 모든 권한을 재정의하려는 경우 해당 superadmin ALL 권한을 부여하려면 `AuthServiceProvider.php` 파일에서 `Gate::before()`문을 사용하여 게이트를 가로 챌 수 있습니다.

```php
// Intercept any Gate and check if it's super admin
Gate::before(function($user, $ability) {
    if ($user->is_super_admin == 1) {
        return true;
    }
});

// Or if you use some permissions package...
Gate::before(function($user, $ability) {
    if ($user->hasPermission('root')) {
        return true;
    }
});
```

## 메일 <a href="#mail" id="mail"></a>

⬆️ [맨 위로 이동](#laravel-tips) ⬅️ [이전 (인증)](#auth) ➡️ [다음 (Artisan)](#artisan)

* [laravel.log로 이메일 테스트](#testing-email-into-laravellog)
* [이메일 미리보기](#preview-mailables)
* [Laravel 알림의 기본 이메일 제목](#default-email-subject-in-laravel-notifications)
* [누구에게나 알림 보내기](#send-notifications-to-anyone)

### laravel.log로 이메일 테스트 <a href="#testing-email-into-laravellog" id="testing-email-into-laravellog"></a>

앱에서 이메일 콘텐츠를 테스트하고 싶지만 Mailgun과 같은 설정을 할 수 없거나 설정하지 않으려는 경우 `.env` 매개 변수 `MAIL_DRIVER=log` 를 사용하면 모든 이메일이 실제로 전송되는 대신 `storage/logs/laravel.log` 파일에 저장됩니다. .

### 이메일 미리보기 <a href="#preview-mailables" id="preview-mailables"></a>

Mailables를 사용하여 이메일을 보내는 경우 브라우저에서 직접 보내지 않고 결과를 미리 볼 수 있습니다. 경로 결과로 Mailable을 반환하십시오.

```php
Route::get('/mailable', function () {
    $invoice = App\Invoice::find(1);
    return new App\Mail\InvoicePaid($invoice);
});
```

### Laravel 알림의 기본 이메일 제목 <a href="#default-email-subject-in-laravel-notifications" id="default-email-subject-in-laravel-notifications"></a>

Laravel 알림을 보내고 **toMail()에** subject를 지정하지 않으면 기본 제목은 알림 클래스 이름 인 CamelCased into Spaces입니다.

따라서 다음과 같은 경우 :

```php
class UserRegistrationEmail extends Notification {
    //
}
```

그러면 제목이 **User Registration Email**인 이메일을 받게됩니다.

### 누구에게나 알림 보내기 <a href="#send-notifications-to-anyone" id="send-notifications-to-anyone"></a>

`$user->notify()`를 사용하여 특정 사용자에게뿐만 아니라 `Notification::route()`을 통해 원하는 모든 사람에게 소위 "주문형" Laravel 알림을 보낼 수 있습니다.

```php
Notification::route('mail', 'taylor@example.com')
        ->route('nexmo', '5555555555')
        ->route('slack', 'https://hooks.slack.com/services/...')
        ->notify(new InvoicePaid($invoice));
```

## Artisan <a href="#artisan" id="artisan"></a>

⬆️ [맨 위로 이동](#laravel-tips) ⬅️ [이전 (메일)](#mail) ➡️ [다음 (팩토리)](#factories)

* [Artisan 명령 매개 변수](#artisan-command-parameters)
* [유지보수 모드](#maintenance-mode)
* [Artisan 명령 도움말](#artisan-command-help)
* [정확한 Laravel 버전](#exact-laravel-version)
* [어디서나 Artisan 명령 실행](#launch-artisan-command-from-anywhere)

### Artisan 명령 매개 변수 <a href="#artisan-command-parameters" id="artisan-command-parameters"></a>

Artisan 명령을 생성 할 때 다양한 방법으로 입력을 요청할 수 있습니다 : `$this->confirm()` , `$this->anticipate()` , `$this->choice()` .

```php
// Yes or no?
if ($this->confirm('Do you wish to continue?')) {
    //
}

// Open question with auto-complete options
$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);

// One of the listed options with default index
$name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $defaultIndex);
```

### 유지보수 모드 <a href="#maintenance-mode" id="maintenance-mode"></a>

유지보수 모드를 활성화하려면 artisan down 명령을 실행하십시오.

```bash
php artisan down
```

그러면 사람들은 기본 503 상태 페이지를 보게됩니다.

라라벨 8에서 플래그를 제공 할 수도 있습니다.

* 사용자가 리디렉션되어야하는 경로
* 미리 렌더링되어야하는 뷰
* 유지 관리 모드를 우회하는 비밀 문구
* 유지 관리 모드 중 상태 코드
* X 초마다 페이지 다시로드 재시도

```bash
php artisan down --redirect="/" --render="errors::503" --secret="1630542a-246b-4b66-afa1-dd72a4c43515" --status=200 --retry=60
```

라라벨 8 이전 :

* 표시 될 메시지
* X 초마다 페이지 다시로드 재시도
* 여전히 일부 IP 주소에 대한 액세스 허용

```bash
php artisan down --message="Upgrading Database" --retry=60 --allow=127.0.0.1
```

유지보수 작업을 마쳤으면 다음을 실행하십시오.

```bash
php artisan up
```

### Artisan 명령 도움말 <a href="#artisan-command-help" id="artisan-command-help"></a>

artisan 명령의 옵션을 확인하려면 `--help` 플래그로 artisan 명령을 실행하십시오. 예를 들어, `php artisan make:model --help` 및 몇 가지 옵션이 있는지 확인하십시오.

```
Options:
  -a, --all             Generate a migration, seeder, factory, and resource controller for the model
  -c, --controller      Create a new controller for the model
  -f, --factory         Create a new factory for the model
      --force           Create the class even if the model already exists
  -m, --migration       Create a new migration file for the model
  -s, --seed            Create a new seeder file for the model
  -p, --pivot           Indicates if the generated model should be a custom intermediate table model
  -r, --resource        Indicates if the generated controller should be a resource controller
      --api             Indicates if the generated controller should be an API controller
  -h, --help            Display this help message
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
      --env[=ENV]       The environment the command should run under
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
```

### 정확한 Laravel 버전 <a href="#exact-laravel-version" id="exact-laravel-version"></a>

`php artisan --version` 명령을 실행하여 앱에있는 Laravel 버전을 정확히 확인하십시오.

### 어디서나 Artisan 명령 실행 <a href="#launch-artisan-command-from-anywhere" id="launch-artisan-command-from-anywhere"></a>

Artisan 명령의 경우 터미널 뿐만 아니라 Artisan::call() 메서드 사용하여 매개 변수와 함께 코드의 어느 곳에서나 실행할 수 있습니다.

```php
Route::get('/foo', function () {
    $exitCode = Artisan::call('email:send', [
        'user' => 1, '--queue' => 'default'
    ]);

    //
});
```

## 팩토리 <a href="#factories" id="factories"></a>

⬆️ [맨 위로 이동](#laravel-tips) ⬅️ [이전 (Artisan)](#artisan) ➡️ [다음 (로그 및 디버그)](#log-and-debug)

* [팩토리 콜백](#factory-callbacks)
* [Seeder / 팩토리로 이미지 생성](#generate-images-with-seedsfactories)

### 팩토리 콜백 <a href="#factory-callbacks" id="factory-callbacks"></a>

데이터를 시드하기 위해 팩토리를 사용하는 동안 레코드 삽입 후 일부 작업을 수행하는 팩토리 콜백 기능을 사용 할 수 있습니다.

```php
$factory->afterCreating(App\User::class, function ($user, $faker) {
    $user->accounts()->save(factory(App\Account::class)->make());
});
```

### Seeder / 팩토리로 이미지 생성 <a href="#generate-images-with-seedsfactories" id="generate-images-with-seedsfactories"></a>

Faker가 텍스트 값뿐만 아니라 이미지도 생성 할 수 있다는 것을 알고 계셨습니까? 아래의 `avatar` 필드를 참고해보세요. 50x50 이미지가 생성됩니다.

```php
$factory->define(User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'email_verified_at' => now(),
        'password' => bcrypt('password'),
        'remember_token' => Str::random(10),
        'avatar' => $faker->image(storage_path('images'), 50, 50)
    ];
});
```

## 로그 및 디버그 <a href="#log-and-debug" id="log-and-debug"></a>

⬆️ [맨 위로 이동](#laravel-tips) ⬅️ [이전 (팩토리)](#factories) ➡️ [다음 (API)](#api)

* [매개 변수로 로깅](#logging-with-parameters)
* [더 편리한 DD](#more-convenient-dd)

### 매개 변수로 로깅 <a href="#logging-with-parameters" id="logging-with-parameters"></a>

`Log::info()` 또는 추가 매개 변수가있는 더 짧은 `info()` 메시지를 작성하여 발생한 상황에 대한 자세한 내용을 볼 수 있습니다.

```php
Log::info('User failed to login.', ['id' => $user->id]);
```

### 더 편리한 DD <a href="#more-convenient-dd" id="more-convenient-dd"></a>

`dd($result)` 를 수행하는 대신 Eloquent 문장이나 컬렉션의 끝에 직접 `->dd()` 를 메소드로 넣을 수 있습니다.

```php
// 이것 대신
$users = User::where('name', 'Taylor')->get();
dd($users);
// 이렇게 할 수 있습니다
$users = User::where('name', 'Taylor')->get()->dd();
```

## API <a href="#api" id="api"></a>

⬆️ [맨 위로 이동](#laravel-tips) ⬅️ [이전 (로그 및 디버그)](#log-and-debug) ➡️ [다음 (기타)](#other)

* [API 리소스 : "데이터"유무?](#api-resources-with-or-without-data)
* [API에서 "모든 것이 정상입니다"를 반환하기](#api-return-everything-went-ok)

### API 리소스 : "데이터"유무? <a href="#api-resources-with-or-without-data" id="api-resources-with-or-without-data"></a>

Eloquent API 리소스를 사용하여 데이터를 반환하면 자동으로 '데이터'에 래핑됩니다. 제거하려면 `app/Providers/AppServiceProvider.php`에 `JsonResource::withoutWrapping();` 를 보면 됩니다

```php
class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        JsonResource::withoutWrapping();
    }
}
```

### API에서 "모든 것이 정상입니다"를 반환하기 <a href="#api-return-everything-went-ok" id="api-return-everything-went-ok"></a>

일부 작업을 수행하지만 응답이 없는 API 엔드포인트라서 "모든 것이 정상입니다"만 반환하려는 경우 204 상태 코드 "No content"를 반환 할 수 있습니다. 라라벨에서는 이것을 쉽게 처리할 수 있습니다. `return response()->noContent();`

```php
public function reorder(Request $request)
{
    foreach ($request->input('rows', []) as $row) {
        Country::find($row['id'])->update(['position' => $row['position']]);
    }

    return response()->noContent();
}
```

## 기타 <a href="#other" id="other"></a>

⬆️ [맨 위로 이동](#laravel-tips) ⬅️ [이전 (API)](#api)

* [.env의 로컬 호스트](#localhost-in-env)
* ["컴포저 업데이트"를 실행할 때 (또는 실행하지 않을 때)](#when-not-to-run-composer-update)
* [Composer : 최신 버전 확인](#composer-check-for-newer-versions)
* [자동 대문자 번역](#auto-capitalize-translations)
* [시간만 사용하는 카본(Carbon)](#carbon-with-only-hours)
* [단일 액션 컨트롤러](#single-action-controllers)
* [특정 컨트롤러 메서드로 이동](#redirect-to-specific-controller-method)
* [이전 Laravel 버전 사용](#use-older-laravel-version)
* [페이지네이션 링크에 매개 변수 추가](#add-parameters-to-pagination-links)
* [반복 가능한 콜백 함수](#repeatable-callback-functions)
* [리퀘스트 : hasAny](#request-has-any)
* [간단한 페이지네이션](#simple-pagination)

### .env의 로컬 호스트 <a href="#localhost-in-env" id="localhost-in-env"></a>

`.env` 파일의 `APP_URL` 을 `http://localhost` 에서 실제 URL로 변경하는 것을 잊지 마십시오. 이메일 알림 및 다른 곳에 있는 모든 링크의 기반이됩니다.

```
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:9PHz3TL5C4YrdV6Gg/Xkkmx9btaE93j7rQTUZWm2MqU=
APP_DEBUG=true
APP_URL=http://localhost
```

### "컴포저 업데이트"를 실행할 때 (또는 실행하지 않을 때) <a href="#when-not-to-run-composer-update" id="when-not-to-run-composer-update"></a>

Laravel에 관해 중요한 내용은 아니지만... 프로덕션 라이브 서버에서 `composer update` 를 실행하지 마십시오. 느리고 저장소가 "깨질"것입니다. 항상 `composer update` 컴퓨터에서 로컬로 실행하고 새 `composer.lock` 을 리포지토리에 커밋하고 라이브 서버에서는 `composer install` 를 실행하십시오.

### Composer : 최신 버전 확인 <a href="#composer-check-for-newer-versions" id="composer-check-for-newer-versions"></a>

`composer.json` 패키지 중 어떤 패키지가 최신 버전을 출시했는지 확인하려면 `composer outdated` 실행하십시오. 다음과 같은 모든 정보가 포함 된 전체 목록이 표시됩니다.

```
phpdocumentor/type-resolver 0.4.0 0.7.1
phpunit/php-code-coverage   6.1.4 7.0.3 Library that provides collection, processing, and rende...
phpunit/phpunit             7.5.9 8.1.3 The PHP Unit Testing framework.
ralouphie/getallheaders     2.0.5 3.0.3 A polyfill for getallheaders.
sebastian/global-state      2.0.0 3.0.0 Snapshotting of global state
```

### 자동 대문자 번역 <a href="#auto-capitalize-translations" id="auto-capitalize-translations"></a>

번역 파일 ( `resources/lang` )에서 변수를 `:variable` 로 지정할 수있을 뿐만 아니라 `:VARIABLE` 또는 `:Variable` 로 대문자로 지정할 수도 있습니다. 그러면 전달하는 값도 자동으로 대문자로 표시됩니다.

```php
// resources/lang/en/messages.php
'welcome' => 'Welcome, :Name'

// Result: "Welcome, Taylor"
echo __('messages.welcome', ['name' => 'taylor']);
```

### 시간만 사용하는 카본(Carbon) <a href="#carbon-with-only-hours" id="carbon-with-only-hours"></a>

초 또는 분없이 현재 날짜를 보려면 `setSeconds(0)` 또는 `setMinutes(0)`과 같은 Carbon의 메서드를 사용하세요.

```php
// 2020-04-20 08:12:34
echo now();

// 2020-04-20 08:12:00
echo now()->setSeconds(0);

// 2020-04-20 08:00:00
echo now()->setSeconds(0)->setMinutes(0);

// Another way - even shorter
echo now()->startOfHour();
```

### 단일 액션 컨트롤러 <a href="#single-action-controllers" id="single-action-controllers"></a>

하나의 액션으로 컨트롤러를 만들고 싶다면 `__invoke()` 메서드를 사용하고 "invokable"컨트롤러를 만들 수도 있습니다.

라우트:

```php
Route::get('user/{id}', 'ShowProfile');
```

Artisan:

```bash
php artisan make:controller ShowProfile --invokable
```

컨트롤러:

```php
class ShowProfile extends Controller
{
    public function __invoke($id)
    {
        return view('user.profile', [
            'user' => User::findOrFail($id)
        ]);
    }
}
```

### 특정 컨트롤러 메서드로 이동 <a href="#redirect-to-specific-controller-method" id="redirect-to-specific-controller-method"></a>

URL이나 특정 경로뿐만 아니라 특정 컨트롤러의 특정 메서드로 `redirect()` 하고 매개 변수를 전달할 수도 있습니다. 이것을 사용하십시오 :

```php
return redirect()->action('SomeController@method', ['param' => $value]);
```

### 이전 Laravel 버전 사용 <a href="#use-older-laravel-version" id="use-older-laravel-version"></a>

최신 Laravel 대신 OLDER 버전을 사용하려면 다음 명령을 사용하십시오.

```
composer create-project --prefer-dist laravel/laravel project "7.*"
```

\*를 원하는 버전으로 변경하십시오.

### 페이지네이션 링크에 매개 변수 추가 <a href="#add-parameters-to-pagination-links" id="add-parameters-to-pagination-links"></a>

기본 페이지네이션 링크에서 추가 매개 변수를 전달하거나 원래 쿼리 문자열을 보존하거나 특정 `#xxxxx` 앵커를 가리킬 수도 있습니다.

```
{{ $users->appends(['sort' => 'votes'])->links() }}

{{ $users->withQueryString()->links() }}

{{ $users->fragment('foo')->links() }}
```

### 반복 가능한 콜백 함수 <a href="#repeatable-callback-functions" id="repeatable-callback-functions"></a>

여러 번 재사용해야하는 콜백 함수가 있는 경우 변수에 할당 한 다음 다시 사용할 수 있습니다.

```php
$userCondition = function ($query) {
    $query->where('user_id', auth()->id());
};

// 이 사용자의 댓글이 있는 게시글 가져 오기
// 그리고 이 사용자의 댓글 만 반환
$articles = Article::with(['comments' => $userCondition])
    ->whereHas('comments', $userCondition)
    ->get();
```

### 리퀘스트 : hasAny <a href="#request-has-any" id="request-has-any"></a>

`$request->has()` 메서드로 하나의 매개 변수를 확인할 수있을 뿐만 아니라 `$request->hasAny()`를 사용하여 여러 매개 변수가 있는지 확인할 수도 있습니다.

```php
public function store(Request $request)
{
    if ($request->hasAny(['api_key', 'token'])) {
        echo 'We have API key passed';
    } else {
        echo 'No authorization parameter';
    }
}
```

### 간단한 페이지네이션 <a href="#simple-pagination" id="simple-pagination"></a>

페이지네이션에서 모든 페이지 번호 대신 "이전 / 다음"링크 만 갖고 싶다면 (그리고 그로 인해 DB 쿼리 수가 더 적길 바라면) `paginate()`대신 `simplePaginate()` 를 사용하세요.

```php
// Instead of
$users = User::paginate(10);

// You can do this
$users = User::simplePaginate(10);
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://laravel-tips.kkame.net/master.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
