Método da relação e propriedade carregada
Em Team, tickets() devolve uma relação que permite construir a consulta; tickets acede aos modelos relacionados e pode desencadear o seu carregamento. Acrescentar where antes de get restringe a consulta. Aplicar where à coleção depois de get filtra em memória os modelos já obtidos.
Num relatório da equipa, Ticket::where sem a condição da equipa perde o âmbito fornecido pela relação. Antes de otimizar, identifica onde termina a construção da consulta e começa o consumo dos resultados.
Carregar o necessário e consumir os agregados
Se cada linha de uma lista consulta owner sem carregamento antecipado, o custo pode crescer com o número de linhas. with permite obter a relação antecipadamente. Quando só é necessária uma contagem, withCount acrescenta tickets_count sem hidratar todos os tickets.
Lê esse atributo: tickets()->count() em cada linha volta a consultar. preventLazyLoading ajuda a detetar carregamento implícito, mas não impede estas consultas explícitas. Mede consultas e volume de dados; o método escolhido não garante um número universal de consultas para qualquer relação.
Selecionar colunas sem perder a associação
Uma seleção reduzida deve preservar o contrato da relação. Para associar tickets às equipas, mantém a chave primária dos tickets e a chave estrangeira relevante, além dos campos apresentados. Selecionar apenas subject pode devolver valores sem permitir reconstruir a associação esperada.
Também não basta mudar team_id para um alias que a relação desconhece. No exemplo, os tickets conservam as suas colunas e owner mantém id; a relação belongsTo usa owner_id presente no ticket. Confirma as chaves reais de modelos personalizados.
Conservar o âmbito e interpretar a visibilidade
A relação acrescenta a condição da equipa, mas team_id=X AND open=1 OR urgent=1 admite tickets urgentes de outras equipas. Agrupa a alternativa numa closure where para obter team_id=X AND (open=1 OR urgent=1). Verifica também os âmbitos do modelo: SoftDeletes mantém a linha com deleted_at e exclui-a das consultas normais; withTrashed permite incluí-la intencionalmente.
A ausência de um resultado não prova eliminação física. Nem o agrupamento nem a inclusão de linhas removidas dispensam a autorização de acesso.
Limitar os atributos atribuídos em massa
Uma atualização de nome de perfil não deve aceitar automaticamente todos os campos enviados. Define os atributos atribuíveis no modelo, por exemplo com o atributo Fillable documentado nesta versão, e passa apenas dados validados e permitidos para a operação.
Estes limites complementam-se: a autenticação não autoriza alterar qualquer propriedade e o nome de um campo sensível não o protege. Atribuição direta e atualizações ao nível da consulta têm contratos próprios; não generalizes a proteção de mass assignment a qualquer escrita.
Eventos e evidência de uma atualização em massa
Ticket::where(...)->update(...) altera linhas sem obter cada modelo. Os eventos saving, saved, updating e updated desses modelos não são emitidos por essa operação em massa. Um observer updated que escreve auditoria pode, por isso, ficar sem registos apesar de as linhas mudarem.
Antes de aceitar o processo, escolhe atualizações de instâncias com os eventos necessários ou uma escrita explícita da evidência. Em ambos os casos, define transação, falhas e repetição; emitir um evento, só por si, não prova entrega durável da auditoria.
Percorrer um conjunto que muda
Um processo que lê pendentes e os passa a concluídos reduz o conjunto entre páginas. Com offsets, avançar a posição pode saltar linhas que passaram a ocupar posições anteriores. chunkById ou lazyById progride pela chave e evita depender desse deslocamento.
Mantém estável a chave de progressão e agrupa alternativas OR, porque o método acrescenta condições próprias ao ID. Alterar chaves durante o percurso pode omitir registos. Esta estratégia de paginação não cria, por si só, um snapshot imutável nem autorização para processar qualquer linha.
<?php
// Reading excerpts: imports, models and authorization are omitted.
// $accountId and $team come from an already authorized application context.
$teams = Team::query()->where('account_id', $accountId)
->withCount('tickets')->get();
foreach ($teams as $item) {
$counts[$item->id] = $item->tickets_count;
}
// Team::tickets() is a hasMany relation using team_id.
$tickets = $team->tickets()
->where(fn ($q) => $q->where('open', 1)->orWhere('urgent', 1))
->with('owner:id,name')
->get();
// Tickets retain their columns; owner uses id and belongsTo owner_id.
O primeiro excerto obtém contagens e lê tickets_count, sem executar count em cada relação. O segundo mantém a alternativa open ou urgent dentro da equipa e carrega os proprietários em conjunto. São excertos para leitura: os modelos, a autorização, os imports e a apresentação não estão fornecidos.
Não se pede execução nem se deduz que uma consulta limitada à conta substitua a policy da aplicação.
Armadilhas comuns
Filtrar apenas depois de get; carregar todos os tickets para contar; omitir chaves de uma seleção; deixar orWhere escapar ao âmbito da equipa; tratar Fillable como autorização; esperar updated por modelo numa atualização em massa.
Tópicos relacionados: Validação e contratos dos pedidos · Transações, concorrência e migrações · Autenticação, autorização e sessões
A forma da consulta determina dados obtidos, custo e eventos disponíveis. Lê os agregados que já pediste, preserva as chaves e os parênteses necessários e especifica a evidência de cada alteração. Proteções de lazy loading e mass assignment resolvem problemas distintos.
Referência: Relationship queries and loaded properties · Laravel 13.x; PHP 8.3+