Функція додавання атрибутів у Laravel дозволяє включати обчислені значення в JSON-відповіді, збагачуючи ваш API результатами без зміни структури бази даних
Визначте доступи за допомогою класу Attribute для створення обчислених властивостей:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
protected function totalWithTax(): Attribute
{
return new Attribute(
get: fn () => $this->subtotal * (1 + $this->tax_rate),
);
}
}
Щоб включити ці обчислені значення у JSON-вихід, додайте їх до властивості $appends
class Order extends Model
{
protected $appends = ['total_with_tax', 'status_label'];
protected function statusLabel(): Attribute
{
return new Attribute(
get: fn () => match($this->status) {
'pending' => 'Очікує оплати',
'processing' => 'Готується',
'shipped' => 'В дорозі',
'delivered' => 'Завершено',
default => 'Невідомий статус'
}
);
}
}
Ось приклад моделі продукту для електронної комерції, що демонструє різні техніки додавання атрибутів:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $appends = [
'display_price',
'availability_status',
'discount_percentage',
'rating_summary'
];
protected function displayPrice(): Attribute
{
return new Attribute(
get: function () {
if ($this->sale_price & $this->sale_price < $this->regular_price) {
return [
'current' => '$' . number_format($this->sale_price, 2),
'original' => '$' . number_format($this->regular_price, 2),
'on_sale' => true
];
}
return [
'current' => '$' . number_format($this->regular_price, 2),
'original' => null,
'on_sale' => false
];
}
);
}
protected function availabilityStatus(): Attribute
{
return new Attribute(
get: function () {
if ($this->inventory_count <= 0) {
return 'out_of_stock';
}
if ($this->inventory_count <= 5) {
return 'low_stock';
}
return 'in_stock';
}
);
}
protected function discountPercentage(): Attribute
{
return new Attribute(
get: function () {
if (!$this->sale_price || $this->sale_price >= $this->regular_price) {
return 0;
}
return round((($this->regular_price - $this->sale_price) / $this->regular_price) * 100);
}
);
}
protected function ratingSummary(): Attribute
{
return new Attribute(
get: function () {
$reviewsCount = $this->whenCounted('reviews');
$averageRating = $this->reviews_avg_rating ?? 0;
return [
'average' => round($averageRating, 1),
'count' => $reviewsCount,
'stars' => $this->generateStarRating($averageRating)
];
}
);
}
public function reviews()
{
return $this->hasMany(Review::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
private function generateStarRating($rating)
{
$fullStars = floor($rating);
$halfStar = ($rating - $fullStars) >= 0.5 ? 1 : 0;
$emptyStars = 5 - $fullStars - $halfStar;
return [
'full' => $fullStars,
'half' => $halfStar,
'empty' => $emptyStars
];
}
public function scopeWithReviewStats($query)
{
return $query->withCount('reviews')
->withAvg('reviews', 'rating');
}
}
Також можна додавати атрибути умовно, використовуючи метод append
для динамічних сценаріїв:
$products = Product::withReviewStats()->get();
foreach ($products as $product) {
if ($user->isAdmin()) {
$product->append(['cost_analysis', 'profit_margin']);
}
}
return response()->json($products);
Додавання атрибутів у моделі створює багатофункціональні API-відповіді, які надають клієнтам обчислені дані, зберігаючи чистий розподіл між збереженою та виведеною інформацією