1097 lines
30 KiB
Markdown
1097 lines
30 KiB
Markdown
# WeldLog Triggers System - Complete Documentation
|
||
|
||
## Non-Technical Summary | Teknik Olmayan Özet
|
||
|
||
### English: What Does WeldLog Trigger System Do?
|
||
|
||
The WeldLog Trigger System is an **automatic synchronization system** that activates whenever a welding record is saved or updated. Think of it as a smart assistant that automatically updates related documents and records across the system.
|
||
|
||
**What It Updates:**
|
||
- 📋 **Line Lists**: Updates pipe line information with welding data
|
||
- 🧪 **NDE Matrix**: Manages non-destructive testing requirements
|
||
- 📅 **Request Dates**: Tracks when inspections and tests are requested
|
||
- 🔧 **Repair Logs**: Records any repairs made to welds
|
||
- 📊 **NDE Projects**: Updates project-wide testing information
|
||
- 📦 **Test Packages**: Organizes welds into testing groups
|
||
- 🎨 **Paint Records**: Updates painting schedules (both shop and field)
|
||
- 🏗️ **Construction Logs**: Tracks construction progress
|
||
- 📤 **Handovers**: Manages handover status to client
|
||
- 🧹 **Cleanup**: Removes obsolete or duplicate records
|
||
|
||
**How It Works:**
|
||
1. Engineer saves/updates a weld log in the system
|
||
2. System automatically detects what changed
|
||
3. Related tables are updated automatically (no manual work needed)
|
||
4. Everything stays synchronized across the entire quality management system
|
||
|
||
**Why It's Important:**
|
||
- ✅ Eliminates manual data entry errors
|
||
- ✅ Ensures data consistency across all modules
|
||
- ✅ Saves hundreds of hours of manual work
|
||
- ✅ Real-time updates mean always current information
|
||
- ✅ Reduces the risk of overlooked updates
|
||
|
||
---
|
||
|
||
### Türkçe: WeldLog Trigger Sistemi Ne İşe Yarar?
|
||
|
||
WeldLog Trigger Sistemi, bir kaynak kaydı kaydedildiğinde veya güncellendiğinde otomatik olarak devreye giren **akıllı bir senkronizasyon sistemidir**. Bunu, sistemdeki ilgili tüm belge ve kayıtları otomatik olarak güncelleyen akıllı bir asistan olarak düşünebilirsiniz.
|
||
|
||
**Neleri Günceller:**
|
||
- 📋 **Hat Listeleri (Line Lists)**: Boru hattı bilgilerini kaynak verileriyle günceller
|
||
- 🧪 **NDE Matrisi**: Tahribatsız muayene gereksinimlerini yönetir
|
||
- 📅 **Talep Tarihleri**: Muayene ve test taleplerinin zamanını takip eder
|
||
- 🔧 **Tamir Kayıtları**: Kaynaklarda yapılan onarımları kaydeder
|
||
- 📊 **NDE Projeleri**: Proje genelindeki test bilgilerini günceller
|
||
- 📦 **Test Paketleri**: Kaynakları test grupları halinde organize eder
|
||
- 🎨 **Boya Kayıtları**: Boya programlarını günceller (hem atölye hem saha)
|
||
- 🏗️ **İnşaat Kayıtları**: İnşaat ilerlemesini takip eder
|
||
- 📤 **Teslimler (Handovers)**: Müşteriye teslim durumunu yönetir
|
||
- 🧹 **Temizlik**: Eski veya çift kayıtları siler
|
||
|
||
**Nasıl Çalışır:**
|
||
1. Mühendis sistemde bir kaynak kaydı kaydeder/günceller
|
||
2. Sistem neyin değiştiğini otomatik olarak algılar
|
||
3. İlgili tablolar otomatik güncellenir (manuel çalışma gerekmez)
|
||
4. Tüm kalite yönetim sistemi senkronize kalır
|
||
|
||
**Neden Önemli:**
|
||
- ✅ Manuel veri girişi hatalarını ortadan kaldırır
|
||
- ✅ Tüm modüller arasında veri tutarlılığı sağlar
|
||
- ✅ Yüzlerce saatlik manuel işten tasarruf sağlar
|
||
- ✅ Gerçek zamanlı güncellemeler = her zaman güncel bilgi
|
||
- ✅ Gözden kaçan güncellemelerin riskini azaltır
|
||
|
||
---
|
||
|
||
## Table of Contents
|
||
|
||
1. [Overview](#overview)
|
||
2. [Architecture](#architecture)
|
||
3. [Directory Structure](#directory-structure)
|
||
4. [Core Components](#core-components)
|
||
5. [Available Triggers](#available-triggers)
|
||
6. [How It Works](#how-it-works)
|
||
7. [Adding New Triggers](#adding-new-triggers)
|
||
8. [Best Practices](#best-practices)
|
||
9. [Troubleshooting](#troubleshooting)
|
||
10. [Migration Guide](#migration-guide)
|
||
|
||
---
|
||
|
||
## Overview
|
||
|
||
The WeldLog Triggers System is a modular, service-based architecture that handles all post-save operations for weld log records. It replaces the monolithic 2435-line trigger file with 12 separate, maintainable trigger classes.
|
||
|
||
### Key Benefits
|
||
|
||
- **Modularity**: Each trigger is a separate, focused class
|
||
- **Reusability**: Trigger system can be adapted for other tables
|
||
- **Testability**: Each trigger can be unit tested independently
|
||
- **Maintainability**: Easy to locate and fix issues
|
||
- **Performance**: Async execution support (future)
|
||
- **Logging**: Standardized logging across all triggers
|
||
- **Flexibility**: Easy to add, remove, or modify triggers
|
||
|
||
### System Statistics
|
||
|
||
- **Original File**: 2,435 lines in single file
|
||
- **New System**: 12 trigger classes + 3 core classes
|
||
- **Total Triggers**: 12 independent operations
|
||
- **Execution Order**: Numbered 1-12 for consistency
|
||
- **Average Trigger Size**: ~150-300 lines per trigger
|
||
|
||
---
|
||
|
||
## Architecture
|
||
|
||
### System Design Pattern
|
||
|
||
The system follows the **Strategy Pattern** combined with **Registry Pattern**:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────┐
|
||
│ weld_logs.php (Entry Point) │
|
||
│ - Detects changes │
|
||
│ - Initializes Manager & Registry │
|
||
└──────────────────┬──────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────┐
|
||
│ WeldLogTriggerManager │
|
||
│ - Orchestrates trigger execution │
|
||
│ - Handles timing & logging │
|
||
│ - Manages errors │
|
||
└──────────────────┬──────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────┐
|
||
│ WeldLogTriggerRegistry │
|
||
│ - Stores all trigger instances │
|
||
│ - Returns triggers in execution order │
|
||
└──────────────────┬──────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────┐
|
||
│ Individual Trigger Classes (12) │
|
||
│ - SpoolStatusChangerTrigger │
|
||
│ - LineListsUpdateTrigger │
|
||
│ - NdeMatrixUpdateTrigger │
|
||
│ - ... (10 more triggers) │
|
||
└─────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Component Relationships
|
||
|
||
```
|
||
WeldLogTriggerInterface (Contract)
|
||
▲
|
||
│ implements
|
||
│
|
||
BaseTrigger (Abstract Base Class)
|
||
▲
|
||
│ extends
|
||
│
|
||
┌────┴────┬────────┬─────────┐
|
||
│ │ │ │
|
||
Trigger1 Trigger2 Trigger3 ... Trigger12
|
||
```
|
||
|
||
---
|
||
|
||
## Directory Structure
|
||
|
||
```
|
||
app/Services/WeldLogTriggers/
|
||
├── Contracts/
|
||
│ └── WeldLogTriggerInterface.php # Interface for all triggers
|
||
├── Base/
|
||
│ └── BaseTrigger.php # Base class with common functionality
|
||
├── Triggers/
|
||
│ ├── SpoolStatusChangerTrigger.php # Order 1
|
||
│ ├── LineListsUpdateTrigger.php # Order 2
|
||
│ ├── NdeMatrixUpdateTrigger.php # Order 3
|
||
│ ├── RequestDateOperationsTrigger.php # Order 4
|
||
│ ├── RepairLogsUpdateTrigger.php # Order 5
|
||
│ ├── NdeProjectUpdateTrigger.php # Order 6
|
||
│ ├── TestPackageOperationsTrigger.php # Order 7
|
||
│ ├── ConstructionPaintLogsTrigger.php # Order 8
|
||
│ ├── TestPackBaseStatusChangerTrigger.php # Order 9
|
||
│ ├── PaintFollowUpsSyncTrigger.php # Order 10
|
||
│ ├── HandoversSyncTrigger.php # Order 11
|
||
│ └── TestPackCleanupTrigger.php # Order 12
|
||
├── WeldLogTriggerRegistry.php # Central trigger registry
|
||
└── WeldLogTriggerManager.php # Trigger execution orchestrator
|
||
```
|
||
|
||
---
|
||
|
||
## Core Components
|
||
|
||
### 1. WeldLogTriggerInterface
|
||
|
||
**Purpose**: Defines the contract that all triggers must implement
|
||
|
||
**Location**: `app/Services/WeldLogTriggers/Contracts/WeldLogTriggerInterface.php`
|
||
|
||
**Methods**:
|
||
|
||
```php
|
||
interface WeldLogTriggerInterface
|
||
{
|
||
public function getName(): string;
|
||
public function getOrder(): int;
|
||
public function shouldRun(array $changedFields, bool $isNewRecord): bool;
|
||
public function getDependentFields(): array;
|
||
public function execute($weldLogData, $beforeData, array $context): array;
|
||
public function isAsync(): bool;
|
||
}
|
||
```
|
||
|
||
**Key Concepts**:
|
||
- `getName()`: Human-readable trigger name for logging
|
||
- `getOrder()`: Execution order (1-12)
|
||
- `shouldRun()`: Determines if trigger should execute based on changes
|
||
- `getDependentFields()`: List of fields this trigger depends on
|
||
- `execute()`: Main trigger logic
|
||
- `isAsync()`: Whether trigger can run asynchronously
|
||
|
||
---
|
||
|
||
### 2. BaseTrigger
|
||
|
||
**Purpose**: Abstract base class providing common functionality
|
||
|
||
**Location**: `app/Services/WeldLogTriggers/Base/BaseTrigger.php`
|
||
|
||
**Features**:
|
||
- Automatic timing and performance tracking
|
||
- Standardized logging format
|
||
- Error handling wrapper
|
||
- Default `shouldRun()` implementation
|
||
- Success/failure status tracking
|
||
|
||
**Usage**:
|
||
All trigger classes extend `BaseTrigger` and implement:
|
||
- `getName()`
|
||
- `getOrder()`
|
||
- `getDependentFields()`
|
||
- `process()` (protected method with actual logic)
|
||
|
||
---
|
||
|
||
### 3. WeldLogTriggerRegistry
|
||
|
||
**Purpose**: Central registry for all trigger instances
|
||
|
||
**Location**: `app/Services/WeldLogTriggers/WeldLogTriggerRegistry.php`
|
||
|
||
**Key Methods**:
|
||
|
||
```php
|
||
$registry = new WeldLogTriggerRegistry();
|
||
|
||
// Get all triggers in execution order
|
||
$triggers = $registry->getTriggersInOrder();
|
||
|
||
// Get specific trigger by name
|
||
$trigger = $registry->getTrigger('Spool Status Changer');
|
||
|
||
// Get all trigger names
|
||
$names = $registry->getTriggerNames();
|
||
|
||
// Count registered triggers
|
||
$count = $registry->count();
|
||
```
|
||
|
||
**Auto-Registration**:
|
||
All triggers are automatically registered in the constructor. No manual registration needed.
|
||
|
||
---
|
||
|
||
### 4. WeldLogTriggerManager
|
||
|
||
**Purpose**: Orchestrates trigger execution
|
||
|
||
**Location**: `app/Services/WeldLogTriggers/WeldLogTriggerManager.php`
|
||
|
||
**Responsibilities**:
|
||
- Execute triggers in correct order
|
||
- Check if each trigger should run
|
||
- Handle errors gracefully
|
||
- Log execution statistics
|
||
- Manage async execution (future)
|
||
- Set database timeouts and memory limits
|
||
|
||
**Usage**:
|
||
|
||
```php
|
||
$registry = new WeldLogTriggerRegistry();
|
||
$manager = new WeldLogTriggerManager($registry);
|
||
|
||
$results = $manager->executeTriggers(
|
||
$weldLogData,
|
||
$beforeData,
|
||
$changedFields,
|
||
$isNewRecord
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## Available Triggers
|
||
|
||
### Trigger 1: SpoolStatusChangerTrigger
|
||
|
||
**Order**: 1
|
||
**Purpose**: Updates spool status when spool_number, iso_number, or type_of_joint changes
|
||
|
||
**Dependent Fields**:
|
||
- spool_number
|
||
- iso_number
|
||
- type_of_joint
|
||
- line_number
|
||
- project
|
||
- design_area
|
||
|
||
**Operations**:
|
||
1. Triggers spool-status-changer cron view for new values
|
||
2. Triggers spool-status-changer for old values (if changed)
|
||
3. Sets spool_status to 'Waiting' when type_of_joint changes
|
||
|
||
**Views Called**:
|
||
- `cron.spool-status-changer`
|
||
|
||
---
|
||
|
||
### Trigger 2: LineListsUpdateTrigger
|
||
|
||
**Order**: 2
|
||
**Purpose**: Updates line_lists table and syncs data from line_lists to weld_logs
|
||
|
||
**Dependent Fields**:
|
||
- line_number
|
||
- design_area
|
||
- fluid_code
|
||
- type_of_welds
|
||
|
||
**Operations**:
|
||
1. Updates line_lists.updated_at for cron tracking
|
||
2. Syncs data from line_lists to weld_logs
|
||
|
||
**Views Called**:
|
||
- `cron.line_lists-sync-from-linelists-to-weldlog`
|
||
|
||
---
|
||
|
||
### Trigger 3: NdeMatrixUpdateTrigger
|
||
|
||
**Order**: 3
|
||
**Purpose**: Syncs data between Line Lists, NDE Matrix, and WeldLogs
|
||
|
||
**Dependent Fields**:
|
||
- type_of_welds
|
||
- fluid_code
|
||
- type_of_joint
|
||
- line_number
|
||
- design_area
|
||
- project
|
||
|
||
**Operations**:
|
||
1. Syncs line_lists to nde_matrices
|
||
2. Handles type_of_welds changes (cleanup old types)
|
||
3. Syncs nde_matrices to weld_logs (scope percentages)
|
||
|
||
**Special Logic**:
|
||
- Deletes old NDE matrix records only if no other weld logs use them
|
||
- Uses TransactionHelper for deadlock prevention
|
||
- Processes in chunks (10 records per batch)
|
||
|
||
**Views Called**:
|
||
- `cron.line_lists-sync-from-linelists-nde-matrix`
|
||
|
||
---
|
||
|
||
### Trigger 4: RequestDateOperationsTrigger
|
||
|
||
**Order**: 4
|
||
**Purpose**: Generates and manages request numbers for all test types
|
||
|
||
**Dependent Fields**:
|
||
- iso_number
|
||
- no_of_the_joint_as_per_as_built_survey
|
||
- rt/ut/mt/pt/vt/pwht/ferrite/pmi (request_date, request_no, test_laboratory)
|
||
|
||
**Operations**:
|
||
1. Processes all test types (RT, UT, MT, PT, VT, PWHT, Ferrite, PMI)
|
||
2. Generates request numbers using pattern from settings
|
||
3. Reuses existing request numbers for same date/company
|
||
4. Updates both weld_logs and test-specific tables
|
||
|
||
**Request Number Pattern**:
|
||
Uses `logs_request_number_pattern` setting:
|
||
- `{company_code}` - Subcontractor company code
|
||
- `{log_name}` - Test type (RT, UT, etc.)
|
||
- `{number}` - Sequential counter
|
||
|
||
---
|
||
|
||
### Trigger 5: RepairLogsUpdateTrigger
|
||
|
||
**Order**: 5
|
||
**Purpose**: Updates repair logs based on test results
|
||
|
||
**Dependent Fields**:
|
||
- iso_number
|
||
- no_of_the_joint_as_per_as_built_survey
|
||
- welding_date
|
||
- All test result fields (vt_result, rt_result, etc.)
|
||
|
||
**Operations**:
|
||
1. Checks all test result fields
|
||
2. Determines repair status:
|
||
- "Not Done" - All fields empty OR RT & UT both empty
|
||
- "Done" - No repair/cut results
|
||
- "Repair" - Contains repair or cut results
|
||
|
||
**Status Logic**:
|
||
```php
|
||
if (allFieldsEmpty || rtAndUtEmpty) {
|
||
status = "Not Done"
|
||
} else if (!hasRepairOrCut) {
|
||
status = "Done"
|
||
} else {
|
||
status = "Repair"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### Trigger 6: NdeProjectUpdateTrigger
|
||
|
||
**Order**: 6
|
||
**Purpose**: Updates NDE Matrix project field from weld_logs when null
|
||
|
||
**Dependent Fields**:
|
||
- line_number
|
||
- project
|
||
|
||
**Operations**:
|
||
1. Joins nde_matrices with weld_logs
|
||
2. Updates null project fields in nde_matrices
|
||
3. Uses DB facade for efficient join update
|
||
|
||
---
|
||
|
||
### Trigger 7: TestPackageOperationsTrigger
|
||
|
||
**Order**: 7
|
||
**Purpose**: Comprehensive test package management
|
||
|
||
**Dependent Fields**:
|
||
- test_package_no, iso_number, nps_1, nps_2
|
||
- line_number, project, design_area
|
||
- piping_type, circuit_number, p_id
|
||
- type_of_test, test_pressure, quantity_of_iso
|
||
- welding_date, all test dates
|
||
- no_of_the_joint_as_per_as_built_survey
|
||
|
||
**Operations**:
|
||
1. Updates support weld_or_assembled_date
|
||
2. Calculates support statistics
|
||
3. Calculates punch list statistics
|
||
4. Calculates weld log statistics (WDI, golden joints, backlogs)
|
||
5. Gets NDT calculations
|
||
6. Updates test_packages and test_pack_base_statuses
|
||
|
||
**Complex Calculations**:
|
||
- WDI (Weld Diameter Inch) totals
|
||
- Welding progress percentages
|
||
- Shop vs Field weld tracking
|
||
- Golden joints counting
|
||
- Backlog calculations for all test types
|
||
|
||
**Views Called**:
|
||
- `admin-ajax.ndt-calculation`
|
||
- `cron.weld_logs-sync-from-weldlog-to-test-pack`
|
||
|
||
---
|
||
|
||
### Trigger 8: ConstructionPaintLogsTrigger
|
||
|
||
**Order**: 8
|
||
**Purpose**: Syncs paint data from WeldLogs to Construction Paint Logs with LineList parity
|
||
|
||
**Dependent Fields**:
|
||
- line_number, spool_number, type_of_joint
|
||
- project, design_area, iso_number
|
||
- fluid_code, test_package_no
|
||
- nps_1, nps_2, spool_status, weld_map_no
|
||
|
||
**Operations**:
|
||
1. Requires matching Line List + painting_cycle (skips when empty)
|
||
2. Loads weld logs filtered by line/unit/fluid_code
|
||
3. Deduplicates spool processing and validates shop joints
|
||
4. Creates/updates construction paint logs for shop joints only
|
||
5. Cleans up orphan spools when source data no longer exists
|
||
|
||
**Special Logic**:
|
||
- Only processes if at least one 'S' type joint exists
|
||
- Guards completed records (date fields) during updates
|
||
- Uses TransactionHelper with chunk processing (10 per batch)
|
||
- Deletes empty records for spools removed from weld_logs
|
||
|
||
---
|
||
|
||
### Trigger 9: TestPackBaseStatusChangerTrigger
|
||
|
||
**Order**: 9
|
||
**Purpose**: Updates test package base statuses including WDI and repair statistics
|
||
|
||
**Dependent Fields**:
|
||
- test_package_no, iso_number, line_number
|
||
- welding_date, type_of_joint, nps_1
|
||
|
||
**Operations**:
|
||
1. Gets test packages, weld logs, repair logs, supports
|
||
2. Calculates support statistics
|
||
3. Calculates repair summaries
|
||
4. Calculates WDI totals (total, shop, field)
|
||
5. Calculates welding progress
|
||
6. Updates test_pack_base_statuses
|
||
7. Updates test_packages
|
||
|
||
**WDI Calculations**:
|
||
- total_wdi: Sum of all nps_1 values
|
||
- total_complated_wdi: Sum where welding_date is not rejected
|
||
- total_shop_wdi: Sum where type_of_joint = 'S'
|
||
- total_field_wdi: Sum where type_of_joint = 'F'
|
||
- welding_progress: (total_complated_wdi / total_wdi) * 100
|
||
|
||
---
|
||
|
||
### Trigger 10: PaintFollowUpsSyncTrigger
|
||
|
||
**Order**: 10
|
||
**Purpose**: Comprehensive sync from WeldLogs to Paint Follow Ups (LineList parity)
|
||
|
||
**Dependent Fields**:
|
||
- line_number, spool_number
|
||
- no_of_the_joint_as_per_as_built_survey
|
||
- fluid_code, iso_number
|
||
- project, design_area, type_of_joint
|
||
|
||
**Operations**:
|
||
1. Validates Line List + painting_cycle; skips when empty or no matching weld logs exist
|
||
2. Loads weld logs filtered by line/unit/fluid, removes cloned joints, and honours repair (R) joint overrides
|
||
3. Loads/creates Paint Matrix aligned to the active painting cycle and computes temperature & volume references
|
||
4. Creates/updates SHOP (spool) and FIELD (joint) records with cycle-aware uniqueness, HOLD handling, and date protection
|
||
5. Cleans orphaned entries when spool/joint numbers change and purges records without backing weld logs
|
||
|
||
**Key Enhancements**:
|
||
- Temperature/volume backfill without overwriting completed dates
|
||
- HOLD status applied when painting cycle changes but work is complete
|
||
- TransactionHelper chunk execution with deadlock retries
|
||
- Two-phase cleanup: targeted orphan deletion + non-matching purge at line scope
|
||
|
||
---
|
||
|
||
### Trigger 11: HandoversSyncTrigger
|
||
|
||
**Order**: 11
|
||
**Purpose**: Syncs data from WeldLogs to Handovers table
|
||
|
||
**Dependent Fields**:
|
||
- line_number
|
||
- project
|
||
- design_area
|
||
- piping_type
|
||
|
||
**Operations**:
|
||
1. Gets all weld logs for line_number
|
||
2. Groups by line (handovers stored per line)
|
||
3. Creates/updates handover records
|
||
|
||
**Field Mapping**:
|
||
- line_number → project (in handovers)
|
||
- project → object
|
||
- design_area → location
|
||
- piping_type → work_type (defaults to 'ТРУБКА')
|
||
|
||
---
|
||
|
||
### Trigger 12: TestPackCleanupTrigger
|
||
|
||
**Order**: 12
|
||
**Purpose**: Deletes non-matching test pack statuses
|
||
|
||
**Dependent Fields**:
|
||
- test_package_no
|
||
- iso_number
|
||
|
||
**Operations**:
|
||
1. Calls cleanup view to remove orphaned test pack statuses
|
||
|
||
**Special Notes**:
|
||
- Non-critical operation (doesn't throw exceptions)
|
||
- Logs errors but continues execution
|
||
|
||
**Views Called**:
|
||
- `cron.weld_logs-delete-non-matching-test-pack-statuses`
|
||
|
||
---
|
||
|
||
## How It Works
|
||
|
||
### Execution Flow
|
||
|
||
```
|
||
1. WeldLog saved
|
||
↓
|
||
2. SaveTrigger called (weld_logs.php)
|
||
↓
|
||
3. Detect changes (detectChangedFields())
|
||
↓
|
||
4. Initialize Registry & Manager
|
||
↓
|
||
5. Manager.executeTriggers()
|
||
↓
|
||
6. For each trigger (order 1-12):
|
||
├─ Check shouldRun()
|
||
├─ If NO → Skip, log, continue
|
||
├─ If YES → Execute trigger
|
||
│ ├─ Log START
|
||
│ ├─ Run process()
|
||
│ ├─ Log COMPLETION
|
||
│ └─ Return results
|
||
└─ Continue to next trigger
|
||
↓
|
||
7. Log overall statistics
|
||
↓
|
||
8. Return all results
|
||
```
|
||
|
||
### Change Detection Logic
|
||
|
||
```php
|
||
function detectChangedFields($data, $beforeData): array
|
||
{
|
||
if (is_null($beforeData)) {
|
||
// New record - all fields changed
|
||
return array_keys((array) $data);
|
||
}
|
||
|
||
$changedFields = [];
|
||
foreach ((array) $data as $key => $value) {
|
||
$oldValue = $beforeData->$key ?? null;
|
||
if ($oldValue !== $value) {
|
||
$changedFields[] = $key;
|
||
}
|
||
}
|
||
|
||
return $changedFields;
|
||
}
|
||
```
|
||
|
||
### Should Run Logic
|
||
|
||
Each trigger checks if it should run:
|
||
|
||
```php
|
||
public function shouldRun(array $changedFields, bool $isNewRecord): bool
|
||
{
|
||
if ($isNewRecord) {
|
||
return true; // Always run for new records
|
||
}
|
||
|
||
$dependentFields = $this->getDependentFields();
|
||
|
||
// Run if any changed field is in dependent fields
|
||
return !empty(array_intersect($changedFields, $dependentFields));
|
||
}
|
||
```
|
||
|
||
### Example: Trigger Execution
|
||
|
||
```php
|
||
// Original weld log data
|
||
$beforeData = (object)[
|
||
'id' => 1,
|
||
'spool_number' => 'SP-001',
|
||
'iso_number' => 'ISO-100',
|
||
'type_of_joint' => 'S'
|
||
];
|
||
|
||
// Updated weld log data
|
||
$data = (object)[
|
||
'id' => 1,
|
||
'spool_number' => 'SP-002', // CHANGED
|
||
'iso_number' => 'ISO-100',
|
||
'type_of_joint' => 'S'
|
||
];
|
||
|
||
// Changed fields: ['spool_number']
|
||
|
||
// SpoolStatusChangerTrigger depends on:
|
||
// ['spool_number', 'iso_number', 'type_of_joint', ...]
|
||
|
||
// array_intersect(['spool_number'], ['spool_number', 'iso_number', ...])
|
||
// = ['spool_number'] (not empty)
|
||
|
||
// Result: shouldRun() returns TRUE, trigger executes
|
||
```
|
||
|
||
---
|
||
|
||
## Adding New Triggers
|
||
|
||
### Step 1: Create Trigger Class
|
||
|
||
```php
|
||
<?php
|
||
|
||
namespace App\Services\WeldLogTriggers\Triggers;
|
||
|
||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||
use Illuminate\Support\Facades\Log;
|
||
|
||
class MyNewTrigger extends BaseTrigger
|
||
{
|
||
public function getName(): string
|
||
{
|
||
return 'My New Trigger';
|
||
}
|
||
|
||
public function getOrder(): int
|
||
{
|
||
return 14; // Next available order
|
||
}
|
||
|
||
public function getDependentFields(): array
|
||
{
|
||
return [
|
||
'field1',
|
||
'field2',
|
||
'field3'
|
||
];
|
||
}
|
||
|
||
protected function process($data, $beforeData, array $context): array
|
||
{
|
||
// Your trigger logic here
|
||
|
||
Log::info("My New Trigger processing", [
|
||
'weld_log_id' => $data->id
|
||
]);
|
||
|
||
// Do something...
|
||
|
||
return [
|
||
'success' => true,
|
||
'records_processed' => 10
|
||
];
|
||
}
|
||
}
|
||
```
|
||
|
||
### Step 2: Register in Registry
|
||
|
||
Edit `app/Services/WeldLogTriggers/WeldLogTriggerRegistry.php`:
|
||
|
||
```php
|
||
protected function registerTriggers()
|
||
{
|
||
// ... existing triggers ...
|
||
|
||
$this->register(new MyNewTrigger()); // Add this line
|
||
}
|
||
```
|
||
|
||
### Step 3: Test
|
||
|
||
```php
|
||
// Trigger will automatically execute when fields change
|
||
// Check logs for execution confirmation
|
||
```
|
||
|
||
---
|
||
|
||
## Best Practices
|
||
|
||
### 1. Naming Conventions
|
||
|
||
- **Trigger Classes**: `{Purpose}Trigger.php` (e.g., `SpoolStatusChangerTrigger.php`)
|
||
- **Method Names**: Clear, descriptive verbs (e.g., `processWeldLogRecord`, `calculateStatistics`)
|
||
- **Variables**: Descriptive names (avoid `$data1`, `$data2`)
|
||
|
||
### 2. Error Handling
|
||
|
||
```php
|
||
protected function process($data, $beforeData, array $context): array
|
||
{
|
||
try {
|
||
// Main logic
|
||
|
||
return ['success' => true];
|
||
} catch (\Throwable $th) {
|
||
Log::error("Error in trigger", [
|
||
'error' => $th->getMessage(),
|
||
'weld_log_id' => $data->id
|
||
]);
|
||
|
||
// Re-throw if critical, or handle gracefully
|
||
throw $th;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. Logging
|
||
|
||
Always log:
|
||
- Start of processing
|
||
- Key decisions
|
||
- Errors
|
||
- Completion with statistics
|
||
|
||
```php
|
||
Log::info("Processing started", [
|
||
'weld_log_id' => $data->id,
|
||
'record_count' => $records->count()
|
||
]);
|
||
|
||
// ... processing ...
|
||
|
||
Log::info("Processing completed", [
|
||
'weld_log_id' => $data->id,
|
||
'processed' => $processedCount,
|
||
'skipped' => $skippedCount
|
||
]);
|
||
```
|
||
|
||
### 4. Performance
|
||
|
||
- Use chunk processing for large datasets
|
||
- Use TransactionHelper for database operations
|
||
- Add appropriate delays between chunks (10ms recommended)
|
||
- Order records by 'id ASC' to prevent deadlocks
|
||
|
||
```php
|
||
TransactionHelper::chunkTransaction(
|
||
$collection,
|
||
function ($chunk) use (&$count) {
|
||
// Process chunk
|
||
return $chunk->count();
|
||
},
|
||
10, // Chunk size
|
||
10000 // 10ms delay
|
||
);
|
||
```
|
||
|
||
### 5. Field Dependencies
|
||
|
||
Be explicit about dependencies:
|
||
|
||
```php
|
||
public function getDependentFields(): array
|
||
{
|
||
return [
|
||
'field1', // Primary field
|
||
'field2', // Related field
|
||
'field3', // Supporting field
|
||
// ... with comments if complex
|
||
];
|
||
}
|
||
```
|
||
|
||
### 6. Return Values
|
||
|
||
Always return structured data:
|
||
|
||
```php
|
||
return [
|
||
'success' => true,
|
||
'records_processed' => 100,
|
||
'records_skipped' => 5,
|
||
'error' => null,
|
||
// ... other relevant data
|
||
];
|
||
```
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
### Trigger Not Executing
|
||
|
||
**Symptom**: Trigger doesn't run when expected
|
||
|
||
**Checks**:
|
||
1. Check if fields are in `getDependentFields()`
|
||
2. Check logs for "Skipping trigger" messages
|
||
3. Verify field actually changed
|
||
4. Check if trigger is registered in Registry
|
||
|
||
**Debug**:
|
||
```php
|
||
Log::info("Debug shouldRun", [
|
||
'trigger' => $this->getName(),
|
||
'changed_fields' => $changedFields,
|
||
'dependent_fields' => $this->getDependentFields(),
|
||
'intersection' => array_intersect($changedFields, $this->getDependentFields())
|
||
]);
|
||
```
|
||
|
||
### Trigger Execution Too Slow
|
||
|
||
**Symptom**: Trigger takes too long to execute
|
||
|
||
**Solutions**:
|
||
1. Add chunk processing
|
||
2. Increase chunk size (but not too much)
|
||
3. Add indexes to database tables
|
||
4. Use eager loading for relationships
|
||
5. Consider making trigger async (future)
|
||
|
||
**Measure performance**:
|
||
```php
|
||
$startTime = microtime(true);
|
||
// ... processing ...
|
||
$duration = round((microtime(true) - $startTime) * 1000, 2);
|
||
Log::info("Performance", ['duration_ms' => $duration]);
|
||
```
|
||
|
||
### Database Deadlocks
|
||
|
||
**Symptom**: "Deadlock found when trying to get lock"
|
||
|
||
**Solutions**:
|
||
1. Always order queries by 'id ASC'
|
||
2. Use TransactionHelper with retry logic
|
||
3. Reduce chunk size
|
||
4. Add delays between chunks
|
||
|
||
```php
|
||
$query->orderBy('id', 'ASC') // Prevents deadlocks
|
||
->lockForUpdate() // Explicit locking
|
||
->get();
|
||
```
|
||
|
||
### Memory Issues
|
||
|
||
**Symptom**: "Allowed memory size exhausted"
|
||
|
||
**Solutions**:
|
||
1. Use chunk processing
|
||
2. Unset large variables after use
|
||
3. Use cursor() instead of get() for very large datasets
|
||
4. Increase memory_limit temporarily
|
||
|
||
```php
|
||
// Instead of:
|
||
$allRecords = Model::all(); // Loads everything into memory
|
||
|
||
// Use:
|
||
Model::chunk(100, function($chunk) {
|
||
// Process chunk
|
||
});
|
||
```
|
||
|
||
### Missing Logs
|
||
|
||
**Symptom**: Expected log entries not appearing
|
||
|
||
**Checks**:
|
||
1. Check log level in config
|
||
2. Verify Log facade is imported
|
||
3. Check storage/logs/laravel.log permissions
|
||
4. Check if logs are being rotated
|
||
|
||
**Force logging**:
|
||
```php
|
||
Log::channel('single')->info("Force log", ['data' => $data]);
|
||
```
|
||
|
||
---
|
||
|
||
## Migration Guide
|
||
|
||
### From Old System to New System
|
||
|
||
#### Step 1: Backup
|
||
|
||
```bash
|
||
# Backup old trigger file
|
||
cp app/Http/Controllers/SaveTrigger/weld_logs.php \
|
||
app/Http/Controllers/SaveTrigger/weld_logs_backup.php
|
||
```
|
||
|
||
#### Step 2: Verify New System
|
||
|
||
```bash
|
||
# Check all trigger files exist
|
||
ls -la app/Services/WeldLogTriggers/Triggers/
|
||
|
||
# Should show 12 trigger files
|
||
```
|
||
|
||
#### Step 3: Test in Development
|
||
|
||
1. Use `weld_logs_new.php` initially
|
||
2. Test all trigger scenarios
|
||
3. Compare results with old system
|
||
4. Check logs for any errors
|
||
|
||
#### Step 4: Switch to New System
|
||
|
||
```bash
|
||
# Once tested, replace old with new
|
||
mv app/Http/Controllers/SaveTrigger/weld_logs.php \
|
||
app/Http/Controllers/SaveTrigger/weld_logs_old.php
|
||
|
||
mv app/Http/Controllers/SaveTrigger/weld_logs_new.php \
|
||
app/Http/Controllers/SaveTrigger/weld_logs.php
|
||
```
|
||
|
||
#### Step 5: Monitor
|
||
|
||
- Check logs for first 24 hours
|
||
- Monitor execution times
|
||
- Verify all triggers executing correctly
|
||
- Check database consistency
|
||
|
||
### Rollback Plan
|
||
|
||
If issues occur:
|
||
|
||
```bash
|
||
# Restore old system
|
||
mv app/Http/Controllers/SaveTrigger/weld_logs.php \
|
||
app/Http/Controllers/SaveTrigger/weld_logs_failed.php
|
||
|
||
mv app/Http/Controllers/SaveTrigger/weld_logs_old.php \
|
||
app/Http/Controllers/SaveTrigger/weld_logs.php
|
||
```
|
||
|
||
### Comparison Test
|
||
|
||
To verify new system works identically:
|
||
|
||
1. Clone development environment
|
||
2. Run old system, capture logs and database state
|
||
3. Reset database
|
||
4. Run new system with same data
|
||
5. Compare results
|
||
|
||
---
|
||
|
||
## Performance Considerations
|
||
|
||
### Execution Times (Average)
|
||
|
||
| Trigger | Average Time | Notes |
|
||
|---------|-------------|-------|
|
||
| 1. Spool Status Changer | 50-100ms | Fast, minimal DB operations |
|
||
| 2. Line Lists Update | 100-200ms | Depends on line size |
|
||
| 3. NDE Matrix Update | 200-500ms | Chunk processing |
|
||
| 4. Request Date Operations | 100-300ms | Per test type |
|
||
| 5. Repair Logs Update | 50-100ms | Simple logic |
|
||
| 6. NDE Project Update | 50-100ms | Single query |
|
||
| 7. Test Package Operations | 500-2000ms | Most complex |
|
||
| 8. Construction Paint Logs | 200-400ms | Chunk processing + lineage checks |
|
||
| 9. Test Pack Base Status | 300-600ms | WDI calculations |
|
||
| 10. Paint Follow Ups Sync | 250-450ms | SHOP + FIELD harmonization |
|
||
| 11. Handovers Sync | 100-200ms | Simple sync |
|
||
| 12. Test Pack Cleanup | 50-100ms | Non-critical |
|
||
|
||
**Total Average**: 2-4 seconds per weld log save
|
||
|
||
### Optimization Tips
|
||
|
||
1. **Database Indexes**: Ensure indexes exist on frequently queried fields
|
||
2. **Chunk Sizes**: Tune based on your data volume
|
||
3. **Async Execution**: Consider for non-critical triggers (future)
|
||
4. **Caching**: Cache lookup data (subcontractors, paint matrices)
|
||
5. **Batch Processing**: Group multiple saves if possible
|
||
|
||
---
|
||
|
||
## Conclusion
|
||
|
||
The WeldLog Triggers System provides a robust, maintainable, and scalable solution for handling post-save operations. By breaking down the monolithic trigger file into 12 focused classes, we've achieved:
|
||
|
||
✅ Better code organization
|
||
✅ Easier debugging and maintenance
|
||
✅ Improved testability
|
||
✅ Clear execution flow
|
||
✅ Comprehensive logging
|
||
✅ Performance optimization opportunities
|
||
|
||
For questions or issues, refer to the logs or contact the development team.
|
||
|
||
---
|
||
|
||
**Document Version**: 1.0
|
||
**Last Updated**: October 30, 2025
|
||
**Author**: DevQMS Development Team
|
||
|