Laravel 常見問題: Specified key was too long

Laravel 在 5.4 版之後為了支援 emoji , 因此將資料編碼改為 utf8mb4. 由於 utf8mb4 的儲存空間需求膨脹了4倍, 導致預設長度無法正常寫入資料庫.

這個問題會在 MySQL 5.7.6 以下與 MariaDB 的環境中出現以下錯誤

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

在 Migrate 過程中出現這個問題的解決方法有兩種

  1. 更新到 MySQL 5.7.7 以上版本
  2. 調整 Laravel 的預設資料長度

升級 MySQL 的方法就不細說了, 接下來主要說明調整 Laravel 預設值的方法

首先, 編輯專案目錄下的 app/Providers/AppServiceProvider.php

新增一個引用

use Illuminate\Support\Facades\Schema;

接著修改 boot function, 將預設長度定為 191

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

重新執行 php artisan migrate 就不會有問題了

最後附上完整的 AppServiceProvider.php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Schema::defaultStringLength(191);
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Laravel 電話長度與選填欄位的實作筆記

最近在處理計畫的網站, 計畫的網站當中有一個選填電話的欄位, 在使用 Laravel 內建 Validation 進行長度檢查時意外踩到坑, 仔細查閱手冊後才發現 Max, Min 的行為與心中所有有所差距, 因此做個筆記避免往後夥伴踩到一樣的坑

Laravel 的 Validation 非常強大, 若要讓欄位選填並且只有在有填寫內容時才進行其他驗證, 可以使用內建的 nullable 達到效果, 而不需要使用 required

$rules = [ 'phone'=>'nullable' ];

針對數字的部分可以用 numeric 來達到驗證

$rules = [ 'phone'=>'nullable|numeric' ];

在長度檢查的部分我一開始是用了 min 與 max 來檢查, 結果無論如何都會觸發長度過長的錯誤, 仔細看過手冊後發現 Laravel 會去猜輸入的型別, 如果猜測結果是數字則 min, max 會變成比大小(min < x < max) 而不是預期的長度檢查, 正確長度檢查要使用 digits_between 這個規則才對

$rules = [ 'phone'=>'nullable|numeric|digits_between:10,12' ];