AgentSkillsCN

laravel-coding-standards

基于Spatie的编码规范,统一Laravel与PHP的代码风格,确保代码的一致性与高质量。

SKILL.md
--- frontmatter
name: laravel-coding-standards
description: Padrões de código Laravel e PHP baseados nas diretrizes da Spatie para manter consistência e qualidade
license: MIT
compatibility: Requer PHP 8.2+ e Laravel 11+
metadata:
  author: aronpc
  version: 1.0.0
  category: development
allowed-tools:
  - Read
  - Write
  - Edit
  - Bash

Laravel Coding Standards

Quando usar esta skill

Use esta skill sempre que:

  • Escrever qualquer código PHP/Laravel
  • Revisar código existente
  • Aplicar formatação com composer fix
  • Manter consistência no estilo do código
  • Revisar pull requests

Princípios Fundamentais

Core Laravel Principle

Siga as convenções do Laravel primeiro. Se o Laravel tem uma forma documentada de fazer algo, use-a. Só desvie quando tiver justificativa clara.

PHP Standards

  • Siga PSR-1, PSR-2 e PSR-12
  • Use camelCase para strings não-públicas
  • Use notação curta para nullable: ?string não string|null
  • Sempre especifique tipos de retorno void quando métodos não retornam nada

Estrutura de Classes

Propriedades Tipadas

Use propriedades tipadas, não docblocks:

php
final class UserService
{
    public function __construct(
        private readonly UserRepository $repository,
        private readonly Cache $cache,
    ) {}
}

Constructor Property Promotion

Use quando todas as propriedades podem ser promovidas:

php
// ✅ TODAS as propriedades podem ser promovidas
final class UserService
{
    public function __construct(
        private readonly UserRepository $repository,
        private readonly Cache $cache,
    ) {}
}

// ❌ Algumas propriedades não podem ser promovidas
final class UserService
{
    private UserRepository $repository;
    private array $config;

    public function __construct(
        UserRepository $repository,
        array $config,
    ) {
        $this->repository = $repository;
        $this->config = $config;
    }
}

Traits

Um trait por linha:

php
final class Business extends Model
{
    use HasFactory;
    use SoftDeletes;
    use Notifiable;
}

Declarações de Tipo e Docblocks

Tipos vs Docblocks

  • Use propriedades tipadas sobre docblocks
  • Especifique tipos de retorno incluindo void
  • Use sintaxe curta de nullable: ?Type não Type|null
  • Documente iterables com generics:
php
/** @return Collection<int, User> */
public function getUsers(): Collection
{
    return User::all();
}

Regras de Docblock

  • Não use docblocks para métodos totalmente tipados (a menos que descrição seja necessária)
  • Sempre importe nomes de classes em docblocks - nunca use nomes totalmente qualificados:
php
use Spatie\Url\Url;

/** @return Url */
public function getUrl(): Url
{
    return Url::fromString($this->url);
}
  • Use docblocks de uma linha quando possível: /** @var string */
  • Tipo mais comum deve ser primeiro em docblocks multi-tipo:
php
/** @var Collection|SomeWeirdVendor\Collection */
  • Se um parâmetro precisa de docblock, adicione docblocks para todos os parâmetros
  • Para iterables, sempre especifique tipos de chave e valor:
php
/**
 * @param array<int, MyObject> $myArray
 * @param int $typedArgument
 */
function someFunction(array $myArray, int $typedArgument) {}
  • Use notação de shape de array para chaves fixas, cada chave em sua própria linha:
php
/** @return array{
 *   first: SomeClass,
 *   second: SomeClass
 * } */

Fluxo de Controle

Happy Path Last

Trate condições de erro primeiro, caso de sucesso último:

php
// ✅ GOOD - Happy path last
if (!$user) {
    return null;
}

if (!$user->isActive()) {
    return null;
}

// Process active user...
return $this->processUser($user);

Early Returns

Use early returns em vez de condições aninhadas:

php
// ❌ BAD - Aninhado
if ($user) {
    if ($user->isActive()) {
        if ($user->hasPermission()) {
            return $this->processUser($user);
        }
    }
}

// ✅ GOOD - Early returns
if (!$user) {
    return null;
}

if (!$user->isActive()) {
    return null;
}

if (!$user->hasPermission()) {
    return null;
}

return $this->processUser($user);

Separe Condições

Preira múltiplas instruções if sobre condições compostas:

php
// ❌ BAD - Condição composta
if ($user && $user->isActive() && $user->hasPermission()) {
    return $this->processUser($user);
}

// ✅ GOOD - Condições separadas
if (!$user) {
    return null;
}

if (!$user->isActive()) {
    return null;
}

if (!$user->hasPermission()) {
    return null;
}

return $this->processUser($user);

Chaves e Operadores Ternários

  • Sempre use chaves mesmo para instruções simples
  • Operadores ternários: cada parte em sua própria linha a menos que muito curto
php
// Ternário curto
$name = $isFoo ? 'foo' : 'bar';

// Ternário multi-linha
$result = $object instanceof Model
    ? $object->name
    : 'A default value';

// Ternário em vez de else
$condition
    ? $this->doSomething()
    : $this->doSomethingElse();

Convenções Laravel

Rotas

  • URLs: kebab-case (/open-source)
  • Nomes de rotas: camelCase (->name('openSource'))
  • Parâmetros: camelCase ({userId})
  • Use notação de tupla: [Controller::class, 'method']

Controllers

  • Nomes de recursos no plural (PostsController)
  • Mantenha métodos CRUD (index, create, store, show, edit, update, destroy)
  • Extraia novos controllers para ações não-CRUD

Configuração

  • Arquivos: kebab-case (pdf-generator.php)
  • Chaves: snake_case (chrome_path)
  • Adicione configs de serviço a config/services.php, não crie novos arquivos
  • Use helper config(), evite env() fora de arquivos de config

Artisan Commands

  • Nomes: kebab-case (delete-old-records)
  • Sempre fornecer feedback ($this->comment('All ok!'))
  • Mostre progresso para loops, resumo no fim
  • Coloque output ANTES de processar item (mais fácil para debug):
php
$items->each(function (Item $item) {
    $this->info("Processing item id `{$item->id}`...");
    $this->processItem($item);
});

$this->comment("Processed {$items->count()} items.");

Strings e Formatação

Interpolação de Strings

Use interpolação de strings sobre concatenação:

php
// ❌ BAD - Concatenação
$name = 'Hello, ' . $user->name . '!';

// ✅ GOOD - Interpolação
$name = "Hello, {$user->name}!";

Enums

Use PascalCase para valores de enum:

php
enum BusinessTypeEnum: string
{
    case RESTAURANT = 'restaurant';
    case CAFE = 'cafe';
    case BAR = 'bar';
}

Comentários

Evite Comentários

Escreva código expressivo em vez de comentários:

php
// ❌ BAD - Comentário explicando o quê
// Check if user is active
if ($user->isActive()) {
    return $user;
}

// ✅ GOOD - Código auto-explicativo
if ($user->isActive()) {
    return $user;
}

Quando Usar Comentários

Use formatação adequada quando necessário:

php
// Single line with space after //

/*
 * Multi-line blocks start with single *
 */
  • Refatore comentários em nomes de funções descritivas

Espaço em Branco

  • Adicione linhas em branco entre instruções para legibilidade
  • Exceção: sequências de operações single-line equivalentes
  • Sem linhas extras extras entre chaves {}
  • Deixe o código "respirar" - evite formatação apertada

Validação

Use notação de array para múltiplas regras (mais fácil para classes de regra customizadas):

php
public function rules(): array
{
    return [
        'email' => ['required', 'email'],
        'password' => ['required', 'min:8', 'confirmed'],
    ];
}

Regras de validação customizadas usam snake_case:

php
Validator::extend('organisation_type', function ($attribute, $value) {
    return OrganisationType::isValid($value);
});

Templates Blade

  • Indente com 4 espaços
  • Sem espaços após estruturas de controle:
blade
@if($condition)
    Something
@endif

Autorização

  • Policies usam camelCase: Gate::define('editPost', ...)
  • Use palavras CRUD, mas view em vez de show

Traduções

Use função __() sobre @lang:

blade
{{ __('messages.welcome') }}

Rotas API

  • Use nomes de recursos no plural: /errors
  • Use kebab-case: /error-occurrences
  • Limite aninhamento profundo para simplicidade:
php
// ✅ GOOD
/error-occurrences/1
/errors/1/occurrences

// ❌ BAD - Muito aninhado
/tenants/1/businesses/1/locations/1/menu-items/1

Testes

  • Mantenha classes de teste no mesmo arquivo quando possível
  • Use nomes de métodos de teste descritivos
  • Siga padrão arrange-act-assert

Referência Rápida

Convenções de Nomenclatura

TipoConvençãoExemplo
ClassesPascalCaseUserController, OrderStatus
Methods/VariablescamelCasegetUserName, $firstName
Routeskebab-case/open-source, /user-profile
Config fileskebab-casepdf-generator.php
Config keyssnake_casechrome_path
Artisan commandskebab-casephp artisan delete-old-records

Estrutura de Arquivos

TipoConvençãoExemplo
Controllersplural resource name + ControllerPostsController
ViewscamelCaseopenSource.blade.php
Jobsaction-basedCreateUser, SendEmailNotification
Eventstense-basedUserRegistering, UserRegistered
Listenersaction + Listener suffixSendInvitationMailListener
Commandsaction + Command suffixPublishScheduledPostsCommand
Mailablespurpose + Mail suffixAccountActivatedMail
Resources/Transformersplural + Resource/TransformerUsersResource
Enumsdescriptive name, no prefixOrderStatus, BookingType

Migrations

Não escreva métodos down em migrations, apenas métodos up:

php
public function up(): void
{
    Schema::create('table', function (Blueprint $table) {
        // ...
    });
}

Lembrete de Qualidade de Código

PHP

  • Use propriedades tipadas sobre docblocks
  • Prefira early returns sobre if/else aninhados
  • Use constructor property promotion quando todas as propriedades podem ser promovidas
  • Evite instruções else
  • Use interpolação de strings sobre concatenação
  • Sempre use chaves para estruturas de controle

Referências