Laravel Rules for Cursor Editor

1 Rule
PHP Framework
.mdc Format

About These Rules

These Laravel coding rules are specifically formatted for the Cursor Editor as .mdc files, focusing on Laravel 10+ features and modern architectural patterns. Each rule is designed to help you write more maintainable Laravel applications while leveraging Cursor's AI capabilities for enhanced development.

1. Service Layer and Repository Pattern

Implement a clean service layer architecture with repository pattern for better code organization and maintainability. This approach demonstrates modern Laravel patterns including dependency injection, repositories, and service classes.

laravel-service-repository.mdc
model->find($id);
    }

    public function create(array $data): User
    {
        return $this->model->create($data);
    }

    public function update(User $user, array $data): bool
    {
        return $user->update($data);
    }

    public function delete(User $user): bool
    {
        return $user->delete();
    }
}

namespace App\Services;

use App\DTOs\UserData;
use App\Events\UserCreated;
use App\Exceptions\UserServiceException;
use App\Models\User;
use App\Repositories\Contracts\UserRepositoryInterface;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;

class UserService
{
    public function __construct(
        private UserRepositoryInterface $userRepository
    ) {
    }

    public function createUser(UserData $userData): User
    {
        try {
            DB::beginTransaction();

            $user = $this->userRepository->create([
                'name' => $userData->name,
                'email' => $userData->email,
                'password' => Hash::make($userData->password),
            ]);

            // Create associated profile
            $user->profile()->create([
                'bio' => $userData->bio ?? '',
                'avatar' => $userData->avatar ?? null,
            ]);

            event(new UserCreated($user));

            DB::commit();
            return $user;
        } catch (\Exception $e) {
            DB::rollBack();
            throw new UserServiceException(
                'Failed to create user: ' . $e->getMessage(),
                previous: $e
            );
        }
    }

    public function updateUser(User $user, UserData $userData): bool
    {
        try {
            DB::beginTransaction();

            $updated = $this->userRepository->update($user, [
                'name' => $userData->name,
                'email' => $userData->email,
            ]);

            if ($userData->password) {
                $this->userRepository->update($user, [
                    'password' => Hash::make($userData->password),
                ]);
            }

            // Update profile
            $user->profile->update([
                'bio' => $userData->bio ?? $user->profile->bio,
                'avatar' => $userData->avatar ?? $user->profile->avatar,
            ]);

            DB::commit();
            return $updated;
        } catch (\Exception $e) {
            DB::rollBack();
            throw new UserServiceException(
                'Failed to update user: ' . $e->getMessage(),
                previous: $e
            );
        }
    }
}

namespace App\DTOs;

class UserData
{
    public function __construct(
        public readonly string $name,
        public readonly string $email,
        public readonly ?string $password = null,
        public readonly ?string $bio = null,
        public readonly ?string $avatar = null,
    ) {
    }

    public static function fromRequest(Request $request): self
    {
        return new self(
            name: $request->input('name'),
            email: $request->input('email'),
            password: $request->input('password'),
            bio: $request->input('bio'),
            avatar: $request->input('avatar'),
        );
    }
}

namespace App\Http\Controllers;

use App\DTOs\UserData;
use App\Services\UserService;
use App\Http\Requests\CreateUserRequest;
use App\Http\Resources\UserResource;

class UserController extends Controller
{
    public function __construct(
        private UserService $userService
    ) {
    }

    public function store(CreateUserRequest $request)
    {
        $userData = UserData::fromRequest($request);
        $user = $this->userService->createUser($userData);

        return new UserResource($user);
    }

    public function update(UpdateUserRequest $request, User $user)
    {
        $userData = UserData::fromRequest($request);
        $updated = $this->userService->updateUser($user, $userData);

        return response()->json([
            'success' => $updated,
            'user' => new UserResource($user->fresh()),
        ]);
    }
}

Why This Rule Matters

  • Separates business logic from controllers
  • Makes code more testable with dependency injection
  • Improves maintainability with clear architectural boundaries
  • Enables better error handling and transaction management
  • Makes the codebase more scalable

Using with Cursor

Cursor's AI capabilities can help you:

  • Generate repository and service class templates
  • Suggest appropriate method signatures and return types
  • Identify opportunities for code extraction into services
  • Debug dependency injection issues
  • Convert controller logic to service layer patterns