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.

ruleseloquent-accessors-mutators.md

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

Eloquent Accessors and Mutators

Impact: MEDIUM (Clean data transformation at model layer)

Use accessors and mutators to transform attribute values when getting or setting them.

Bad Example

// Manual transformations scattered in code
class UserController extends Controller
{
    public function show(User $user)
    {
        // Manual formatting everywhere
        $fullName = $user->first_name . ' ' . $user->last_name;
        $formattedPhone = preg_replace('/(\d{3})(\d{3})(\d{4})/', '($1) $2-$3', $user->phone);

        return view('users.show', [
            'fullName' => $fullName,
            'formattedPhone' => $formattedPhone,
        ]);
    }

    public function store(Request $request)
    {
        // Manual normalization
        User::create([
            'email' => strtolower(trim($request->email)),
            'phone' => preg_replace('/[^0-9]/', '', $request->phone),
            'name' => ucwords(strtolower($request->name)),
        ]);
    }
}

In views, more manual formatting:

<p>{{ strtoupper($user->first_name) }} {{ strtoupper($user->last_name) }}</p>

Good Example

// Modern accessors and mutators (Laravel 9+)
namespace App\Models;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    // Accessor - computed attribute
    protected function fullName(): Attribute
    {
        return Attribute::make(
            get: fn () => "{$this->first_name} {$this->last_name}",
        );
    }

    // Mutator - transform on set
    protected function email(): Attribute
    {
        return Attribute::make(
            get: fn (string $value) => $value,
            set: fn (string $value) => strtolower(trim($value)),
        );
    }

    // Accessor with formatting
    protected function phone(): Attribute
    {
        return Attribute::make(
            get: function (string $value) {
                return preg_replace('/(\d{3})(\d{3})(\d{4})/', '($1) $2-$3', $value);
            },
            set: function (string $value) {
                return preg_replace('/[^0-9]/', '', $value);
            },
        );
    }

    // Accessor for formatted dates
    protected function birthDate(): Attribute
    {
        return Attribute::make(
            get: fn ($value) => Carbon::parse($value)->format('F j, Y'),
        );
    }

    // Accessor with caching for expensive operations
    protected function profileCompleteness(): Attribute
    {
        return Attribute::make(
            get: function () {
                $fields = ['name', 'email', 'phone', 'avatar', 'bio'];
                $filled = collect($fields)->filter(fn ($field) => !empty($this->$field))->count();
                return ($filled / count($fields)) * 100;
            },
        )->shouldCache();
    }

    // Accessor that depends on relationships
    protected function totalOrders(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->orders()->count(),
        );
    }

    // Make accessors available in JSON/arrays
    protected $appends = ['full_name', 'profile_completeness'];
}

// Usage is clean and consistent
$user = User::find(1);

echo $user->full_name;           // "John Doe"
echo $user->phone;               // "(555) 123-4567"
echo $user->profile_completeness; // 80

// Mutators work automatically on assignment
$user->email = '  JOHN@EXAMPLE.COM  ';
$user->save();
// Stored as: john@example.com

In views — just use attributes directly:

<p>{{ $user->full_name }}</p>
<p>{{ $user->phone }}</p>
// Legacy syntax (still works but not recommended for new code)
class User extends Model
{
    // Legacy accessor
    public function getFullNameAttribute(): string
    {
        return "{$this->first_name} {$this->last_name}";
    }

    // Legacy mutator
    public function setEmailAttribute(string $value): void
    {
        $this->attributes['email'] = strtolower(trim($value));
    }
}

Why

  • Consistency: Data transformation happens in one place
  • Clean code: No repeated formatting logic in views or controllers
  • Encapsulation: Models handle their own data presentation
  • Automatic: Works on assignment and retrieval without extra code
  • Computed attributes: Create virtual attributes from existing data
  • Serialization: Appended accessors included in JSON automatically

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