@extends('layouts.docs') @section('title', 'Sistema de Traits - OG Framework') @section('body')
{{-- Floating shapes for styling --}}
{{-- Left Sidebar: Navigation --}} @include('docs.partials.sidebar') {{-- Main Content --}}
{{-- Page Header --}}
Voltar para Documentação

Arquitectura

Sistema de Traits

Composição de funcionalidades reutilizáveis através do padrão Mixin — 11 traits especializados organizados em 3 categorias para extensibilidade, debugging, gestão de memória e processamento de dados.

{{-- Visão Geral --}}

Visão Geral

O sistema de traits do OfficeGest implementa o padrão Mixin através de traits PHP 8.3+, permitindo composição de funcionalidades reutilizáveis entre classes sem herança múltipla.

{{-- Categories Overview SVG --}}
{{-- Core Traits --}} Core Traits Modules/Common/Traits/ Macroable Dumpable Filterable EnumCaseToArray MemoryOptimized ErrorHandling 8 traits {{-- Queue Traits --}} Queue Traits Modules/Common/Queue/Traits/ DeadLetterQueueTrait 1 trait {{-- Resource Traits --}} Resource Traits Modules/Common/Resource/Traits/ ConditionalAttributesTrait DateSerializerTrait 2 traits
{{-- Traits Overview Table --}}
Trait Responsabilidade
MacroableExtensão dinâmica de classes em runtime
DumpableDebugging com rastreamento de origem
FilterableNormalização de filtros de entrada
EnumCaseToArrayConversão de enums para arrays/SQL
MemoryOptimizedTraitProcessamento streaming de grandes datasets
MemoryManagementTraitGestão e monitoramento de memória
ErrorHandlingTraitHandling inteligente de erros em jobs
ResolvesDumpSourceResolução de origem em debugging
DeadLetterQueueTraitGestão de Dead Letter Queue
ConditionalAttributesTraitAtributos condicionais em Resources
DateSerializerTraitSerialização de datas em Resources
{{-- Arquitectura --}}

Arquitectura e Padrões

{{-- Mixin Pattern --}}

Mixin Pattern

Traits adicionam conjuntos coesos de métodos e propriedades sem estabelecer hierarquias rígidas.

{{-- Composition over Inheritance --}}

Composition over Inheritance

Classes combinam múltiplos traits para compor funcionalidades, evitando problemas de herança múltipla.

{{-- Composition Example --}}

Exemplo de Composição

<?php

class AdvancedProcessor
{
    use MemoryOptimizedTrait;      // Processamento de grandes dados
    use MemoryManagementTrait;     // Monitoramento de memória
    use ErrorHandlingTrait;        // Handling robusto de erros
    use Dumpable;                  // Debugging

    public function process(): void
    {
        $this->configureMemoryLimits('2G');

        $this->withLenientErrorHandling(function () {
            foreach ($this->processRecordsInChunks('data', ['*']) as $record) {
                $this->processRecord($record);
            }
        });
    }
}
{{-- Core Traits --}}

Core Traits

Localizados em Modules/Common/Traits/, são os traits fundamentais do framework.

{{-- Macroable --}}

Macroable

Implementa o padrão Macro, permitindo adicionar métodos a classes dinamicamente em runtime.

Método Descrição
macro(string $name, callable $macro)Regista nova macro
mixin(object $mixin, bool $replace)Adiciona todos os métodos de um objeto
hasMacro(string $name)Verifica se macro existe
// Extensão dinâmica em runtime
Request::macro('isApiRequest', function(): bool {
    return $this->wantsJson() || $this->expectsJson();
});

Request::macro('tenantId', function(): ?int {
    return $this->header('X-Tenant-ID') ?: session('tenant_id');
});

// Uso posterior
$request = Request::capture();
if ($request->isApiRequest()) {
    // Lógica específica para API
}
{{-- Dumpable --}}

Dumpable

Sistema avançado de debugging com rastreamento automático de origem (ficheiro + linha).

Método Retorno Descrição
dump(?string $message)$thisDump com mensagem, continua
dd(?string $message)voidDump e termina
dumpOnly(string ...$props)$thisDump de propriedades específicas
dumpWith(string $message)$thisDump com mensagem, continua
class CustomerService
{
    use Dumpable;

    private int $id;
    private string $name;

    public function process(): void
    {
        // Debug completo com contexto
        $this->dumpWith('Processing customer');
        // Output: "Processing customer"
        //         🔍 Called from: /path/to/file.php:42

        // Debug apenas propriedades específicas
        $this->dumpOnly('id', 'name');

        // Chaining para debug durante desenvolvimento
        $this->dumpWith('Before save')->save()->dumpWith('After save');
    }
}
{{-- EnumCaseToArray --}}

EnumCaseToArray

Trait especializado para enums PHP 8.1+ com conversões para arrays, SQL CASE statements e formatos específicos.

enum CustomerType: string
{
    use EnumCaseToArray;

    case COMPANY = 'E';
    case PRIVATE = 'P';

    public function label(): string
    {
        return match($this) {
            self::COMPANY => 'Empresa',
            self::PRIVATE => 'Particular',
        };
    }
}
// Array de valores
CustomerType::valuesToArray();
// ['E', 'P']

// Labels para UI
CustomerType::labels();
// ['COMPANY' => 'Empresa', ...]

// Formato Select2
CustomerType::toArraySelect2();
// [['value' => 'E', 'text' => 'Empresa'], ...]

// SQL CASE
CustomerType::toSqlCase('type', '= ?');
{{-- ErrorHandlingTrait --}}

ErrorHandlingTrait

Sistema robusto de handling de erros para jobs críticos. Categoriza erros, notifica via Mattermost e fornece logging estruturado.

class SaftExportJob extends Job
{
    use ErrorHandlingTrait;

    public function handle(): void
    {
        $this->withLenientErrorHandling(function () {
            // Erros menores (array offset, undefined key) são ignorados
            // Erros críticos (connection refused, API error) param o job
            // Notificações Mattermost enviadas automaticamente

            $result = app('saftpt.export')->execute($this->data);

            if (!$result['success']) {
                throw new \Exception(json_encode($result['errors']));
            }
        });
    }
}

Padrões de Erro: O trait define 28+ padrões fatais (undefined function, memory exhausted, connection refused) e keywords críticos que triggeram notificações automáticas.

{{-- MemoryOptimizedTrait --}}

MemoryOptimizedTrait

Processamento usando Generators para grandes datasets. Processa milhões de registos sem esgotar memória.

Método Descrição
processRecordsInChunks()Processa registos DB em chunks via generator
processCustomQueryInChunks()Processa SQL customizado em chunks
streamCSVFromGenerator()Gera CSV streaming
writeDataToFile()Escreve dataset grande para ficheiro
getOptimalChunkSize()Calcula chunk size ideal baseado na memória
class LargeReportGenerator
{
    use MemoryOptimizedTrait;

    public function generateOrdersReport(): array
    {
        // Processa 100k+ orders sem esgotar memória
        $generator = $this->processRecordsInChunks(
            table: 'orders',
            select: ['id', 'customer_id', 'total'],
            conditions: ['status' => 'completed'],
            chunkSize: 1000
        );

        // Escreve para ficheiro CSV
        return $this->writeDataToFile(
            dataGenerator: $generator,
            filePath: '/tmp/orders_report.csv',
            format: 'csv'
        );
        // Retorna: ['records_written' => 150000, 'file_size_bytes' => 8500000]
    }
}
{{-- MemoryManagementTrait --}}

MemoryManagementTrait

Gestão completa de memória com monitoring, thresholds (75% warning, 90% critical) e optimização automática.

Método Descrição
configureMemoryLimits()Define limite PHP
checkMemoryThreshold()Verifica threshold
optimizeMemoryUsage()Força GC
getMemoryStats()Estatísticas atuais
processInBatches()Lotes com optimização
$this->configureMemoryLimits('2G');
$this->logMemoryUsage('Start');

$this->processInBatches(
    data: $records,
    processor: fn($record) => $this->migrate($record),
    batchSize: 100
);

$stats = $this->getMemoryStats();
// ['current_mb' => 245.5, 'peak_mb' => 512.3]
{{-- Filterable --}}

Filterable

Normaliza parâmetros de filtro em requests, transformando formatos simples em estruturas padronizadas.

// Input simples
['filter' => ['status' => 'active']]

// Normalizado para
['filter' => ['status' => ['value' => 'active', 'operator' => 'equal']]]
{{-- ResolvesDumpSource --}}

ResolvesDumpSource

Resolve a origem real de dumps através de call stacks complexos. Usado pelos custom CliDumper e HtmlDumper para integração com Symfony VarDumper.

{{-- Queue Traits --}}

Queue Traits

Localizados em Modules/Common/Queue/Traits/.

{{-- DeadLetterQueueTrait --}}

DeadLetterQueueTrait

Gestão de jobs que falham permanentemente, movendo-os para uma Dead Letter Queue para análise posterior.

Método Descrição
moveToDeadLetter()Move job falhado para DLQ
retryDeadLetter(string $id)Tenta reprocessar job da DLQ
purgeDeadLetters(int $maxAge)Remove jobs antigos da DLQ (default: 7 dias)
protected function moveToDeadLetter(
    string $jobId,
    string $queue,
    string $payload,
    Throwable $exception
): void {
    $dlq = app(DeadLetterQueueInterface::class);
    $dlq->store($connection, $queue, $payload, $originalPayload, $exception);
}

// Retry de job específico
public function retryDeadLetter(string $deadLetterId): ?string
{
    $dlq = app(DeadLetterQueueInterface::class);
    return $dlq->retry((int)$deadLetterId) ? $deadLetterId : null;
}
{{-- Resource Traits --}}

Resource Traits

Localizados em Modules/Common/Resource/Traits/, para transformação de dados em API Resources.

{{-- ConditionalAttributesTrait --}}

ConditionalAttributesTrait

Sistema de atributos condicionais para API Resources, inspirado no Laravel.

Método Descrição
whenHas(mixed $value, callable $cb)Inclui se existe e não está vazio
when(mixed $condition, callable $cb)Inclui condicionalmente
mergeWhen(mixed $cond, mixed $value)Merge condicional de arrays
class CustomerResource extends Resource
{
    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,

            // Incluir apenas se existe
            'email' => $this->whenHas('email'),

            // Com transformação
            'phone' => $this->whenHas('phone', fn($phone) => "+351 {$phone}"),

            // Merge condicional de relacionamentos
            ...$this->mergeWhen($this->relationLoaded('orders'), [
                'orders_count' => $this->orders->count(),
                'total_spent' => $this->orders->sum('total'),
            ]),
        ];
    }
}
{{-- DateSerializerTrait --}}

DateSerializerTrait

Serialização consistente de datas em Resources, usando o formato configurado em config('app.date_format').

protected static function serializeValue($value)
{
    // Carbon formata para string
    if ($value instanceof Carbon) {
        return $value->format(config('app.date_format') ?? 'Y-m-d H:i:s');
    }

    // Collections recursivas
    if ($value instanceof Collection) {
        return $value->map(fn($item) => self::serializeValue($item));
    }

    // Arrays recursivos (remove MissingValues)
    if (is_array($value)) {
        return array_filter(
            array_map(fn($item) => self::serializeValue($item), $value),
            fn($item) => !($item instanceof MissingValue)
        );
    }

    return $value;
}
{{-- Boas Práticas --}}

Boas Práticas

✅ Recomendações

  • Single Responsibility: Cada trait com uma função clara
  • Nomes únicos: Prefixar métodos se necessário
  • Propriedades privadas: Evitar conflitos
  • Documentar dependências: Se trait precisa de propriedades da classe
  • Retornar $this: Para method chaining

❌ Evitar

  • • Sobrescrever métodos sem verificar existência
  • • Propriedades públicas que podem conflitar
  • • Nomes genéricos (get, set, process)
  • • Dependências não documentadas
  • • Traits com múltiplas responsabilidades
{{-- Template --}}

Template para Novos Traits

<?php

namespace Og\Modules\Common\Traits;

/**
 * Trait ExampleTrait
 *
 * Descrição clara do propósito do trait.
 */
trait ExampleTrait
{
    /**
     * Propriedades devem ser privadas quando possível
     */
    private int $counter = 0;

    /**
     * Métodos públicos bem documentados
     *
     * @param mixed $input Descrição do parâmetro
     * @return self Para method chaining
     */
    public function publicMethod(mixed $input): self
    {
        $this->internalHelper($input);
        return $this;
    }

    /**
     * Verificar existência de métodos/propriedades opcionais
     */
    protected function optionalIntegration(): void
    {
        if (method_exists($this, 'optionalMethod')) {
            $this->optionalMethod();
        }
    }

    private function internalHelper(mixed $input): void
    {
        // Lógica interna
    }
}
{{-- Referência Rápida --}}

Referência Rápida

Trait Namespace Uso Principal
MacroableOg\Modules\Common\TraitsExtensão dinâmica de classes
DumpableOg\Modules\Common\TraitsDebugging com contexto
FilterableOg\Modules\Common\TraitsNormalização de filtros API
EnumCaseToArrayOg\Modules\Common\TraitsConversão de enums
ErrorHandlingTraitOg\Modules\Common\TraitsHandling de erros em jobs
MemoryOptimizedTraitOg\Modules\Common\TraitsProcessamento streaming
MemoryManagementTraitOg\Modules\Common\TraitsGestão de memória
ResolvesDumpSourceOg\Modules\Common\TraitsOrigem de dumps
DeadLetterQueueTraitOg\Modules\Common\Queue\TraitsDead Letter Queue
ConditionalAttributesTraitOg\Modules\Common\Resource\TraitsAtributos condicionais
DateSerializerTraitOg\Modules\Common\Resource\TraitsSerialização de datas
{{-- Navigation --}}
{{-- Right Sidebar: Table of Contents --}} @include('docs.partials.toc', ['sections' => [ 'visao-geral' => 'Visão Geral', 'arquitectura' => 'Arquitectura', 'core-traits' => 'Core Traits', 'queue-traits' => 'Queue Traits', 'resource-traits' => 'Resource Traits', 'boas-praticas' => 'Boas Práticas', 'referencia' => 'Referência Rápida', ]])
@endsection