記事の内容
概要
アクセサとミューテタは、Eloquentモデルの属性を自動的に変換・取得・設定する便利な機能です。
【productsテーブル】アクセサとミューテタを確認
mysql> select * from products;
+----+-----------+-------+---------------------+---------------------+
| id | name | price | created_at | updated_at |
+----+-----------+-------+---------------------+---------------------+
| 1 | PRODUCT 1 | 1500 | 2024-08-24 10:42:44 | 2024-08-24 10:42:44 |
| 2 | PRODUCT 2 | 2500 | 2024-08-24 10:42:45 | 2024-08-24 10:42:45 |
| 3 | PRODUCT 3 | 1000 | 2024-08-24 10:42:45 | 2024-08-24 10:42:45 |
+----+-----------+-------+---------------------+---------------------+
3 rows in set (0.01 sec)
アクセサ
データベースから取得した属性を自動的に加工します。
Laravel9以前
【ファイル先】app/Models/Product.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
/**
* アクセサ: priceを取得する際に自動的にフォーマット
*/
public function getPriceAttribute($value)
{
// 例: "1000" -> "1,000.00"
return number_format($value, 2);
}
}
Laravel9以降
【ファイル先】app/Models/Product.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Product extends Model
{
/**
* アクセサ: priceを取得する際に自動的にフォーマット
*/
protected function price(): Attribute
{
// 例: "1000" -> "1,000.00"
return Attribute::make(
get: fn($value) => number_format($value, 2),
);
}
}
Laravel9以降でもLaravel9以前の指定でアクセサは使用可能
【ファイル先】app/Http/Controllers/ProductController.php
<?php
namespace App\Http\Controllers;
use App\Models\Product;
class ProductController extends Controller
{
===========================
省略
===========================
/**
* 商品の詳細を表示
*/
public function show($id)
{
// 指定IDの商品を取得($idが2の場合)
$product = Product::findOrFail($id);
$price = $product->price;
// DDでprice変数の中身をチェック
dd($price);
return view('products.show', compact('product'));
}
===========================
省略
===========================
}
【price変数の中身】
"2,500.00" // app/Http/Controllers/ProductController.php:29
ミューテタ
データベースに保存する前に属性を加工します。
Laravel9以前
【ファイル先】app/Models/Product.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
/**
* 商品名を大文字に変換して保存
*/
public function setNameAttribute($value)
{
$this->attributes['name'] = strtoupper($value);
}
}
Laravel9以降
【ファイル先】app/Models/Product.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Product extends Model
{
/**
* 商品名を大文字に変換して保存
*/
protected function name(): Attribute
{
return Attribute::make(
set: fn($value) => strtoupper($value)
);
}
}
Laravel9以降でもLaravel9以前の指定でミューテタは使用可能
【ファイル先】app/Http/Controllers/ProductController.php
<?php
namespace App\Http\Controllers;
use App\Models\Product;
class ProductController extends Controller
{
===========================
省略
===========================
/**
* 商品を保存
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'price' => 'required|numeric',
]);
// 商品をデータベースに保存(nameをproductと仮定する)
$product = Product::create($validatedData);
// DDでproduct変数の中身をチェック
dd($product);
return redirect()->route('products.index')->with('success', '商品を追加しました!');
}
===========================
省略
===========================
}
【product変数の中身】
App\Models\Product {#318 ▼ // app/Http/Controllers/ProductController.php:47
===========================
省略
===========================
#attributes: array:7 [▼
"name" => "PRODUCT"
"price" => "2000"
"updated_at" => "2024-01-01 00:01:23"
"created_at" => "2024-01-01 00:01:23"
"id" => 1
]
===========================
省略
===========================
}
その他
デフォルト値設定
【ファイル先】app/Models/Product.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Support\Facades\Cache;
class Product extends Model
{
protected $fillable = [
'name',
'price',
'options',
'status',
];
// デフォルト値の設定
protected function status(): Attribute
{
// 値がnullの場合にデフォルトで'pending'を返す
return Attribute::make(
get: fn($value) => $value ?? 'pending'
);
}
}
キャスト組み合わせ
【ファイル先】app/Models/Product.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Support\Facades\Cache;
class Product extends Model
{
protected $fillable = [
'name',
'price',
'options',
'status',
];
// キャストとアクセサ/ミューテタの組み合わせ
protected function options(): Attribute
{
return Attribute::make(
get: fn($value) => json_decode($value, true), // JSONを配列に変換
set: fn($value) => json_encode($value) // 配列をJSONに変換して保存
);
}
}
動的表示
【ファイル先】app/Models/Product.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Product extends Model
{
protected $fillable = [
'name',
'price',
'status',
];
// 動的に割引後の価格を計算するメソッド
protected function discountedPrice(): Attribute
{
// 割引率を変数として定義(例: 10%の割引 = 0.9)
$discountRate = 0.9;
return Attribute::make(
// 割引後の価格を計算
get: fn() => $this->price * $discountRate
);
}
}