今回、Laravelを本番環境に移した時に起きたこと
まずローカルのLaravelで上手く動いていたのを確認してから本番環境に移すと、移した途端エラーが発生しました。
一言でいうと、原因は全て
ローカルだと寛容に動いてくれるのに本番環境だと厳しくコードを見られて動かない
というのが原因でした。
命名規則のエラー
まず、Laravelのルート\storage\logs\laravel.log
を確認すると以下のようなエラーが発生しました。
Class "App\Methods\UserList" not found
at /app/Http/Controllers/ApiController.php:129
エラーの内容は
App\Methods\UserList クラスが存在しない
つまり、ApiController の中で以下のような処理をしているはずです
use App\Methods\UserList;
...
$userList = new UserList(); // ← ここでクラッシュ!
でも Laravel はその UserList クラスを 読み込めない(存在していない or オートロードできない) というエラーです。
次に、以下のコードで実行すると
composer dump-autoload
[XXX123@XXXXXX.com]$ composer dump-autoload
Generating optimized autoload files
Class App\Methods\PrintData located in ./app/Methods/printData.php does not comply with psr-4 autoloading standard. Skipping.
Class App\Methods\UserList located in ./app/Methods/userList.php does not comply with psr-4 autoloading standard. Skipping.
Class App\Models\DeshioKiroku located in ./app/Models/Deshiokiroku.php does not comply with psr-4 autoloading standard. Skipping.
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
INFO Discovering packages.
anourvalar/eloquent-serialize ............................................. DONE
blade-ui-kit/blade-heroicons .............................................. DONE
blade-ui-kit/blade-icons .................................................. DONE
filament/actions .......................................................... DONE
filament/filament ......................................................... DONE
filament/forms ............................................................ DONE
filament/infolists ........................................................ DONE
filament/notifications .................................................... DONE
filament/support .......................................................... DONE
filament/tables ........................................................... DONE
filament/widgets .......................................................... DONE
kirschbaum-development/eloquent-power-joins ............................... DONE
laravel/pail .............................................................. DONE
laravel/sail .............................................................. DONE
laravel/sanctum ........................................................... DONE
laravel/tinker ............................................................ DONE
livewire/livewire ......................................................... DONE
nesbot/carbon ............................................................. DONE
nunomaduro/collision ...................................................... DONE
nunomaduro/termwind ....................................................... DONE
ryangjchandler/blade-capture-directive .................................... DONE
spatie/laravel-permission ................................................. DONE
tymon/jwt-auth ............................................................ DONE
> @php artisan filament:upgrade
⇂ public/js/filament/forms/components/color-picker.js
⇂ public/js/filament/forms/components/date-time-picker.js
⇂ public/js/filament/forms/components/file-upload.js
⇂ public/js/filament/forms/components/key-value.js
⇂ public/js/filament/forms/components/markdown-editor.js
⇂ public/js/filament/forms/components/rich-editor.js
⇂ public/js/filament/forms/components/select.js
⇂ public/js/filament/forms/components/tags-input.js
⇂ public/js/filament/forms/components/textarea.js
⇂ public/js/filament/tables/components/table.js
⇂ public/js/filament/widgets/components/chart.js
⇂ public/js/filament/widgets/components/stats-overview/stat/chart.js
⇂ public/js/filament/filament/app.js
⇂ public/js/filament/filament/echo.js
⇂ public/js/filament/notifications/notifications.js
⇂ public/js/filament/support/support.js
⇂ public/css/filament/forms/forms.css
⇂ public/css/filament/support/support.css
⇂ public/css/filament/filament/app.css
INFO Successfully published assets!
INFO Configuration cache cleared successfully.
INFO Route cache cleared successfully.
INFO Compiled views cleared successfully.
INFO Successfully upgraded!
Generated optimized autoload files containing 8082 classes
❌ 問題:PSR-4オートロード規約違反
Class App\Methods\PrintData located in ./app/Methods/printData.php does not comply with psr-4 autoloading standard. Skipping.
Class App\Methods\UserList located in ./app/Methods/userList.php does not comply with psr-4 autoloading standard. Skipping.
つまり、クラス名とファイル名の大文字小文字が一致していないため、Laravel が読み込んでくれないことが原因でした。
実際に保存していたファイル名はuserList.php
とprintData.php
でした。
ローカルのLaravelではそれでも問題なく動くのですがXserverの場合だとそこを厳しく見られたので注意が必要でした。
フィラメントの管理画面が上手く表示されない原因
ローカルのLaravelでは問題なく動くのに本番環境ではログインした後に何も表示されないという現象が起きました。
最初は、ローカルで動かすときと比べて、パスがズレているのだと思い込み、自分では原因を特定出来ませんでした。
ルートの.htacceass
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(.*)$ public/$1 [QSA,L]
</IfModule>
ですが、実際は、認証に使っているModelのファイルの記述が古い書き方だったことが原因のようでした。
ルート\app\Models\User.php
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Database\Eloquent\Model;
class User extends Authenticatable implements JWTSubject
{
use Notifiable;
protected $fillable = ['name', 'login_code', 'password', 'email', 'staff_id', 'is_admin'];
protected $hidden = ['password'];
// モデルの作成時にデフォルト値を設定
protected static function boot()
{
parent::boot();
static::creating(function ($user) {
// is_adminが設定されていない場合、デフォルトで管理者権限を付与
if (!isset($user->is_admin)) {
$user->is_admin = 1;
}
});
}
// ✅ JWT の識別子を取得
public function getJWTIdentifier()
{
return $this->getKey();
}
// ✅ JWT に追加するカスタムクレーム
public function getJWTCustomClaims()
{
return [];
}
/**
* Filament へのアクセス権限を判定するメソッド
*
* @return bool
*/
public function canAccessFilament(): bool
{
return $this->is_admin === 1; // `is_admin` が 1 の場合のみ Filament にアクセス可能
}
}
修正後
<?php
namespace App\Models;
use Filament\Panel;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Filament\Models\Contracts\FilamentUser;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Database\Eloquent\Model;
class User extends Authenticatable implements JWTSubject, FilamentUser
{
use Notifiable;
// laravel_db接続を指定
protected $connection = 'mysql';
protected $fillable = ['name', 'login_code', 'password', 'email', 'staff_id', 'is_admin'];
protected $hidden = ['password'];
// モデルの作成時にデフォルト値を設定
protected static function boot()
{
parent::boot();
static::creating(function ($user) {
// is_adminが設定されていない場合、デフォルトで管理者権限を付与
if (!isset($user->is_admin)) {
$user->is_admin = 1;
}
});
}
// ✅ JWT の識別子を取得
public function getJWTIdentifier()
{
return $this->getKey();
}
// ✅ JWT に追加するカスタムクレーム
public function getJWTCustomClaims()
{
return [];
}
/**
* Filament へのアクセス権限を判定するメソッド
*
* @return bool
*/
public function canAccessPanel(Panel $panel): bool
{
return $this->is_admin === 1; // `is_admin` が 1 の場合のみ Filament にアクセス可能
}
}
✅ 主な変更点の解説
① FilamentUser インターフェースの追加
use Filament\Models\Contracts\FilamentUser;
目的:
Filament v3 以降では、ユーザーモデルが管理画面(Filament)にアクセスできるかを判定するために、FilamentUser インターフェースの実装が必要になりました。
② canAccessFilament() → canAccessPanel(Panel $panel) へ変更
変更前:
public function canAccessFilament(): bool
変更後
public function canAccessPanel(Panel $panel): bool
変更理由:
Filament の仕様変更により、ユーザーがアクセスできる「パネル(Panel)」が複数存在することを想定した構成に変わったため、どの Panel にアクセスするかを引数として受け取る必要が出てきました。
③ protected $connection = 'mysql'; の追加
protected $connection = 'mysql';
目的:
Laravel では、デフォルト以外のデータベース接続をモデル単位で指定することができます。
今回はデフォルトのデータベース以外にもう一つのデータベースとの連携をUsersテーブルにさせるために
デフォルトのデータベースのUserテーブルを使うことを
User モデルに対して mysql 接続を明示的に指定しています
(laravel_db がデフォルトのデータベース)
④protected $connection = 'mysql';の mysql
はどこで設定した文字列なのか
ルート\config\database.php
に記述した設定を使用しています。
<?php
use Illuminate\Support\Str;
return [
'default' => env('DB_CONNECTION', 'mysql'),
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'url' => env('DB_URL'),
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
'busy_timeout' => null,
'journal_mode' => null,
'synchronous' => null,
],
// ✅ デフォルトの MySQL 接続(LaravelのメインDB)
'mysql' => [
'driver' => 'mysql',
'host' => env('XXXXXXX', '127.0.0.1'),
'port' => env('XXXXXXX', '3306'),
'database' => env('XXXXX_DB_DATABASE', 'XXXXXXX'),
'username' => env('XXXXX_DB_USERNAME', 'XXXX'),
'password' => env('XXXX_DB_PASSWORD', 'XXXX'),
'charset' => env('XXXXX_DB_CHARSET', 'utf8mb4'),
'collation' => env('XXXXXX_DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'strict' => true,
'engine' => null,
],
// ✅ もう一つのMySQL 接続(外部のデータベース)
'XXXXXXXX' => [
'driver' => 'mysql',
'host' => env('XXXXXXX', '127.0.0.1'),
'port' => env('XXXXXXX', '3306'),
'database' => env('XXXXX_DB_DATABASE', 'XXXXXXX'),
'username' => env('XXXXX_DB_USERNAME', 'XXXX'),
'password' => env('XXXX_DB_PASSWORD', 'XXXX'),
'charset' => env('XXXXX_DB_CHARSET', 'utf8mb4'),
'collation' => env('XXXXXX_DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'strict' => true,
'engine' => null,
],
'mariadb' => [
'driver' => 'mariadb',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'pgsql' => [
'driver' => 'pgsql',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '5432'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8'),
'prefix' => '',
'prefix_indexes' => true,
'search_path' => 'public',
'sslmode' => 'prefer',
],
'sqlsrv' => [
'driver' => 'sqlsrv',
'url' => env('DB_URL'),
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '1433'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8'),
'prefix' => '',
'prefix_indexes' => true,
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
],
],
/*
|--------------------------------------------------------------------------
| Migration Repository Table
|--------------------------------------------------------------------------
|
| This table keeps track of all the migrations that have already run for
| your application. Using this information, we can determine which of
| the migrations on disk haven't actually been run on the database.
|
*/
'migrations' => [
'table' => 'migrations',
'update_date_on_publish' => true,
],
/*
|--------------------------------------------------------------------------
| Redis Databases
|--------------------------------------------------------------------------
|
| Redis is an open source, fast, and advanced key-value store that also
| provides a richer body of commands than a typical key-value system
| such as Memcached. You may define your connection settings here.
|
*/
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
],
],
];
下記の 'mysql'が先ほどの Model/User.php
で指定した文字列になります。(デフォルトのデータベースはmysql
に初期状態はなっている)
'mysql' => [
'driver' => 'mysql',
.....
別の ✅ もう一つのMySQL 接続(外部のデータベース)
をしたい場合は XXXXXXXX' => [
の XXXXXXXX
を使用します。
外部のデータベース使用例
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class StaffLaravelLink extends Model
{
use HasFactory;
// 'XXXXXXXX' という接続先を利用
protected $connection = 'XXXXXXXX';
protected $table = 'staff';
'host' => env('XXXXXXX', '127.0.0.1'),
の記述の意味
これは.env
ファイルのキーがなければ右のデフォルト値を使用するという意味です
env('キー名', 'デフォルト値')
🛠 その他は同じ内容(JWT関連、fillableなど)
以下の記述は、旧コードと変更なしです:
getJWTIdentifier() と getJWTCustomClaims() → JWT認証に必要な定義
$fillable, $hidden → Eloquentモデルの基本
boot() 内の creating() → モデル作成時に is_admin にデフォルト値を設定する処理
🎯 まとめ
変更点 理由・背景
FilamentUser 実装 Filament v3 対応のため必要
canAccessFilament() → canAccessPanel(Panel $panel) マルチパネル対応の新仕様
$connection = 'mysql' データベース接続を明示的に指定
このように、LaravelやFilamentのアップデートに伴って、モデルの書き方も少しずつ変わっていきます。特に認証や管理画面に関する部分はバージョン依存が強いので、ドキュメントやリリースノートをこまめに確認するのが大切です。
参考:Filament v3 ドキュメント