Ін'єкція сервісів у Blade: Прямий доступ до сервісів у шаблонах Laravel

0
Перекладено ШІ
Оригінал: Laravel News
Оновлено: 25 липня, 2025
Laravel надає потужні можливості ін'єкції сервісів через движок шаблонів Blade за допомогою директиви @inject, яка дозволяє легко отримувати доступ до сервісів із контейнера Laravel без перевантаження контролерів. Які переваги це може надати у вашій розробці? Читайте про те, як зменшити складність контролерів та покращити структуризацію коду!

Шаблонізатор Blade у Laravel пропонує потужні можливості для впровадження сервісів за допомогою директиви @inject, що дозволяє отримувати доступ до сервісів з контейнера Laravel без зайвих ускладнень у контролерах.

Впровадження сервісів дає змогу отримувати будь-який сервіс з контейнера Laravel безпосередньо у ваших вьюхах, що знижує складність контролера та забезпечує чітке розділення обов'язків:

@inject('analytics', 'App\Services\AnalyticsService')
 
<div>
    Загальний дохід: {{ $analytics->getTotalRevenue() }}
</div>

Ця директива приймає два параметри: ім'я змінної для сервісу та назву класу або інтерфейсу, який потрібно отримати з контейнера.

@inject('userStats', 'App\Services\UserStatisticsService')
@inject('reportGenerator', 'App\Services\ReportGeneratorService')

<div class="statistics-panel">
    <h3>Статистика користувачів</h3>
    <p>Активні користувачі: {{ number_format($userStats->getActiveUserCount()) }}</p>
    <p>Нові реєстрації: {{ number_format($userStats->getNewRegistrations()) }}</p>
</div>

<div class="reports-section">
    <h3>Доступні звіти</h3>
    @foreach($reportGenerator->getAvailableReports() as $report)
        <a href="{{ $report['url'] }}" class="report-link">
            {{ $report['title'] }}
        </a>
    @endforeach
</div>

Ось приклад адміністративної панелі, що демонструє різні сценарії впровадження сервісів:

{{-- app/Services/SystemHealthService.php --}}
namespace App\Services;

class SystemHealthService
{
    public function getCpuUsage(): float
    {
        return sys_getloadavg()[0] * 100;
    }

    public function getMemoryUsage(): array
    {
        $memoryUsage = memory_get_usage(true);
        $memoryLimit = $this->convertToBytes(ini_get('memory_limit'));

        return [
            'used' => $memoryUsage,
            'limit' => $memoryLimit,
            'percentage' => ($memoryUsage / $memoryLimit) * 100
        ];
    }

    public function getDiskUsage(): array
    {
        $totalSpace = disk_total_space('/');
        $freeSpace = disk_free_space('/');
        $usedSpace = $totalSpace - $freeSpace;

        return [
            'total' => $totalSpace,
            'used' => $usedSpace,
            'free' => $freeSpace,
            'percentage' => ($usedSpace / $totalSpace) * 100
        ];
    }

    private function convertToBytes(string $value): int
    {
        $unit = strtolower(substr($value, -1));
        $number = (int) substr($value, 0, -1);

        return match($unit) {
            'g' => $number * 1024 ** 3,
            'm' => $number * 1024 ** 2,
            'k' => $number * 1024,
            default => $number
        };
    }
}

{{-- app/Services/ActivityMonitorService.php --}}
namespace App\Services;

class ActivityMonitorService
{
    public function getRecentActivities(int $limit = 10): array
    {
        return \App\Models\ActivityLog::latest()
            ->with('user')
            ->limit($limit)
            ->get()
            ->map(function ($activity) {
                return [
                    'user' => $activity->user->name,
                    'action' => $activity->description,
                    'timestamp' => $activity->created_at->diffForHumans(),
                    'ip_address' => $activity->ip_address
                ];
            })
            ->toArray();
    }

    public function getActiveSessionCount(): int
    {
        return \Illuminate\Support\Facades\DB::table('sessions')
            ->where('last_activity', '>', now()->subMinutes(5)->timestamp)
            ->count();
    }

    public function getFailedLoginAttempts(): int
    {
        return \App\Models\FailedLogin::where('created_at', '>', now()->subHour())->count();
    }
}

Ось шаблон Blade з впровадженням сервісів:

{{-- resources/views/admin/dashboard.blade.php --}}
@inject('systemHealth', 'App\Services\SystemHealthService')
@inject('activityMonitor', 'App\Services\ActivityMonitorService')
@inject('userAnalytics', 'App\Services\UserAnalyticsService')

<div class="admin-dashboard">
    <div class="dashboard-header">
        <h1>Панель адміністрування системи</h1>
        <span class="last-updated">Останнє оновлення: {{ now()->format('M j, Y g:i A') }}</span>
    </div>

    <div class="metrics-grid">
        <div class="metric-card system-health">
            <h3>Стан системи</h3>
            <div class="health-indicators">
                <div class="indicator">
                    <label>Використання CPU</label>
                    <div class="progress-bar">
                        <div class="progress" style="width: {{ $systemHealth->getCpuUsage() }}%"></div>
                    </div>
                    <span>{{ number_format($systemHealth->getCpuUsage(), 1) }}%</span>
                </div>

                @php $memory = $systemHealth->getMemoryUsage() @endphp
                <div class="indicator">
                    <label>Використання пам'яті</label>
                    <div class="progress-bar">
                        <div class="progress" style="width: {{ $memory['percentage'] }}%"></div>
                    </div>
                    <span>{{ number_format($memory['percentage'], 1) }}%</span>
                </div>

                @php $disk = $systemHealth->getDiskUsage() @endphp
                <div class="indicator">
                    <label>Використання диска</label>
                    <div class="progress-bar">
                        <div class="progress" style="width: {{ $disk['percentage'] }}%"></div>
                    </div>
                    <span>{{ number_format($disk['percentage'], 1) }}%</span>
                </div>
            </div>
        </div>

        <div class="metric-card user-analytics">
            <h3>Аналіз користувачів</h3>
            <div class="analytics-summary">
                <div class="stat">
                    <span class="value">{{ number_format($userAnalytics->getTotalUsers()) }}</span>
                    <span class="label">Загальна кількість користувачів</span>
                </div>
                <div class="stat">
                    <span class="value">{{ number_format($userAnalytics->getActiveUsersToday()) }}</span>
                    <span class="label">Активні сьогодні</span>
                </div>
                <div class="stat">
                    <span class="value">{{ number_format($userAnalytics->getNewUsersThisWeek()) }}</span>
                    <span class="label">Нові цього тижня</span>
                </div>
                <div class="stat">
                    <span class="value">{{ number_format($activityMonitor->getActiveSessionCount()) }}</span>
                    <span class="label">Активні сесії</span>
                </div>
            </div>
        </div>

        <div class="metric-card security-monitor">
            <h3>Монітор безпеки</h3>
            <div class="security-alerts">
                <div class="alert-item">
                    <span class="alert-icon">🔒</span>
                    <div class="alert-content">
                        <span class="alert-title">Неуспішні спроби входу (Остання година)</span>
                        <span class="alert-value">{{ $activityMonitor->getFailedLoginAttempts() }}</span>
                    </div>
                </div>

                @if($activityMonitor->getFailedLoginAttempts() > 10)
                    <div class="alert-item warning">
                        <span class="alert-icon">⚠️</span>
                        <div class="alert-content">
                            <span class="alert-title">Висока активність неуспішних спроб входу</span>
                            <span class="alert-description">Рекомендуємо переглянути журнали безпеки</span>
                        </div>
                    </div>
                @endif
            </div>
        </div>
    </div>

    <div class="activity-section">
        <h3>Остання діяльність системи</h3>
        <div class="activity-list">
            @foreach($activityMonitor->getRecentActivities(15) as $activity)
                <div class="activity-item">
                    <div class="activity-user">{{ $activity['user'] }}</div>
                    <div class="activity-action">{{ $activity['action'] }}</div>
                    <div class="activity-time">{{ $activity['timestamp'] }}</div>
                    <div class="activity-ip">{{ $activity['ip_address'] }}</div>
                </div>
            @endforeach
        </div>
    </div>

    <div class="quick-actions">
        <h3>Швидкі дії</h3>
        <div class="action-buttons">
            <button onclick="refreshMetrics()" class="btn btn-primary">
                Оновити метрики
            </button>
            <button onclick="exportReport()" class="btn btn-secondary">
                Експортувати звіт
            </button>
            <button onclick="viewLogs()" class="btn btn-outline">
                Переглянути журнали системи
            </button>
        </div>
    </div>
</div>

<style>
.admin-dashboard {
    padding: 20px;
    max-width: 1200px;
    margin: 0 auto;
}

.metrics-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 20px;
    margin: 20px 0;
}

.metric-card {
    background: white;
    border-radius: 8px;
    padding: 20px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.progress-bar {
    width: 100%;
    height: 8px;
    background: #e2e8f0;
    border-radius: 4px;
    overflow: hidden;
    margin: 5px 0;
}

.progress {
    height: 100%;
    background: linear-gradient(90deg, #4ade80, #eab308, #ef4444);
    transition: width 0.3s ease;
}

.analytics-summary {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 15px;
}

.stat {
    text-align: center;
    padding: 10px;
}

.stat .value {
    display: block;
    font-size: 24px;
    font-weight: bold;
    color: #1f2937;
}

.stat .label {
    font-size: 12px;
    color: #6b7280;
    text-transform: uppercase;
}

.activity-list {
    max-height: 400px;
    overflow-y: auto;
}

.activity-item {
    display: grid;
    grid-template-columns: 150px 1fr 120px 100px;
    gap: 10px;
    padding: 10px;
    border-bottom: 1px solid #e5e7eb;
}
</style>

Впровадження сервісів – це елегантне рішення для доступу до утилітних сервісів безпосередньо у шаблонах, що зменшує навантаження на контролери, зберігаючи чітке розділення між бізнес-логікою та елементами представлення

Популярні

Logomark Logotype

Laravel Boost — ваш стартовий набір для програмування з використанням штучного інтелекту

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

Logomark Logotype

Журнал аудиту в Laravel

Хочете забезпечити повну прозорість у своїх Laravel-додатках? Пакет Laravel Audit Log допоможе вам детально відстежувати всі зміни моделей Eloquent та відповідати вимогам регуляторів. Читайте далі, щоб дізнатися, як цей потужний інструмент може підвищити надійність вашого проєкту

Logomark Logotype

Інтеграція Laravel Socialite з бібліотекою Google Client PHP

Ви хочете навчитися, як інтегрувати Google OAuth у вашому проекті Laravel, використовуючи Socialite? Дізнайтеся, як налаштувати доступ до сервісів Google, таких як Календар, у нашій сьогоднішній статті