All skills
asyrafhussin avatar

/laravel-best-practices

@ef59186

Laravel 13 conventions and best practices. Use when creating controllers, models, migrations, validation, services, or structuring Laravel applications. Triggers on tasks involving Laravel architecture, Eloquent, database, API development, or PHP patterns.

Use this Skill: https://skilld.dev/gh/asyrafhussin/agent-skills/laravel-best-practices

This session only. Nothing lands on disk.

rulescontroller-dependency-injection.md

≈1.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Dependency Injection in Controllers

Impact: HIGH (Testable and loosely coupled controllers)

Use constructor and method injection to provide dependencies instead of using facades or creating instances.

Bad Example

// Using facades and manual instantiation
class OrderController extends Controller
{
    public function store(Request $request)
    {
        // Tight coupling to concrete classes
        $paymentGateway = new StripePaymentGateway();
        $result = $paymentGateway->charge($request->total);

        // Static facade calls - hard to mock
        $order = Order::create($request->validated());
        Mail::to($order->user)->send(new OrderConfirmation($order));
        Log::info('Order created', ['order_id' => $order->id]);
        Cache::forget('user-orders-' . auth()->id());

        return redirect()->route('orders.show', $order);
    }

    public function export()
    {
        // Creating services manually
        $exporter = new CsvExporter();
        $orders = Order::all();

        return $exporter->export($orders);
    }
}

Good Example

// Constructor injection for shared dependencies
class OrderController extends Controller
{
    public function __construct(
        private readonly PaymentGatewayInterface $paymentGateway,
        private readonly OrderService $orderService,
    ) {}

    // Method injection for action-specific dependencies
    public function store(
        StoreOrderRequest $request,
        NotificationService $notifications
    ) {
        $order = $this->orderService->create(
            $request->validated(),
            auth()->user()
        );

        $notifications->sendOrderConfirmation($order);

        return redirect()->route('orders.show', $order);
    }

    public function export(CsvExporter $exporter)
    {
        $orders = Order::with('items')->get();

        return $exporter->export($orders);
    }
}
// Interface binding in service provider
class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(
            PaymentGatewayInterface::class,
            StripePaymentGateway::class
        );

        // Conditional binding
        $this->app->bind(PaymentGatewayInterface::class, function ($app) {
            return match (config('payments.default')) {
                'stripe' => new StripePaymentGateway(config('payments.stripe')),
                'paypal' => new PayPalPaymentGateway(config('payments.paypal')),
                default => throw new InvalidArgumentException('Invalid payment gateway'),
            };
        });
    }
}
// Service class with injected dependencies
namespace App\Services;

use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\DB;

class OrderService
{
    public function __construct(
        private readonly PaymentGatewayInterface $payment,
        private readonly InventoryService $inventory,
        private readonly LoggerInterface $logger,
    ) {}

    public function create(array $data, User $user): Order
    {
        return DB::transaction(function () use ($data, $user) {
            $order = Order::create([
                'user_id' => $user->id,
                ...$data,
            ]);

            $this->inventory->reserve($order->items);
            $this->logger->info('Order created', ['order_id' => $order->id]);

            return $order;
        });
    }
}
// Testing with injected dependencies
class OrderControllerTest extends TestCase
{
    public function test_store_creates_order_and_charges_payment()
    {
        // Mock the payment gateway
        $mockGateway = $this->mock(PaymentGatewayInterface::class);
        $mockGateway->expects('charge')
            ->once()
            ->with(100.00)
            ->andReturn(new PaymentResult(success: true));

        $response = $this->actingAs($user)
            ->post('/orders', [
                'items' => [...],
                'total' => 100.00,
            ]);

        $response->assertRedirect();
    }
}
// Route model binding is also dependency injection
class PostController extends Controller
{
    // Laravel automatically resolves {post} from the route
    public function show(Post $post)
    {
        return view('posts.show', compact('post'));
    }

    // Custom resolution
    public function showBySlug(Post $post)
    {
        return view('posts.show', compact('post'));
    }
}

// In RouteServiceProvider or model
public function resolveRouteBinding($value, $field = null)
{
    return $this->where($field ?? 'slug', $value)->firstOrFail();
}

Why

  • Testability: Dependencies easily mocked in tests
  • Loose coupling: Code depends on interfaces, not implementations
  • Flexibility: Swap implementations via configuration
  • Explicit dependencies: Clear what a class needs to function
  • Single responsibility: Controller doesn't create its dependencies
  • IDE support: Type hints enable autocompletion and refactoring

Source: SKILL.md on GitHub

No alerts16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill is a comprehensive guide to Laravel 13 best practices, providing safe and standard architectural, database, and security patterns for PHP development. No malicious behavior or security risks were detected.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    1/37 files flagged

  • ZeroLeaks5mo

    2 findings · Score: 80/100

Signed by skilld at ef59186. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated 7 months ago
Other metadata
metadata
{
  "author": "Laravel Community",
  "version": "2.1.0",
  "laravelVersion": "13.x",
  "phpVersion": "8.3+"
}

README badge

README badge for asyrafhussin/agent-skills/laravel-best-practices