Покращення JSON-відповідей за допомогою Laravel Model Appends

0
Перекладено ШІ
Оригінал: Laravel News
Оновлено: 10 липня, 2025
Завдяки функції додавання моделей у Laravel ви можете включати обчислювані атрибути в JSON-відповіді, збагачуючи ваш API. Чи знаєте ви, як створити ці атрибути за допомогою класу Attribute? Читайте далі, щоб дізнатися, як максимально використати цю потужну функцію

Функція додавання атрибутів у 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-відповіді, які надають клієнтам обчислені дані, зберігаючи чистий розподіл між збереженою та виведеною інформацією

Популярні

Logomark Logotype

Створення CLI-додатка за допомогою Laravel та Docker

Зазирніть у світ Laravel, де потужний CLI-фреймворк відкриває нові можливості для розробки командного інтерфейсу. Дізнайтеся, як створити просту утиліту для перевірки акцій, яка працює з Docker, та які переваги це може принести у вашому проєкті!

Logomark Logotype

Оптимізація запитів до бази даних за допомогою скорочених методів Laravel

Laravel пропонує зручні методи для роботи з датами, які значно спрощують запити до бази даних. Досліджуйте, як ці інтуїтивно зрозумілі функції допомагають створювати чіткі та зрозумілі умови для роботи з часовими даними!

Logomark Logotype

Перетворення даних у типобезпечні DTO за допомогою пакету Data Model

Досліджуйте новий пакет Data Model для PHP, який спрощує процес гідратації об'єктів без зайвих складнощів! Дізнайтеся, як впровадження типобезпечних об'єктів може революціонізувати ваш підхід до розробки, читаючи нашу статтю