Files
2026-04-28 21:14:25 +03:00

250 lines
8.4 KiB
PHP

<?php
namespace App\Services\WeldLogTriggers;
use Illuminate\Support\Facades\Log;
use App\Helpers\TransactionHelper;
/**
* WeldLog Trigger Manager
*
* Manages the execution of all weld log triggers
* Handles trigger execution order, timing, and error handling
*/
class WeldLogTriggerManager
{
/**
* @var WeldLogTriggerRegistry Trigger registry
*/
protected $registry;
/**
* @var float Overall start time
*/
protected $overallStartTime;
/**
* Constructor
*
* @param WeldLogTriggerRegistry $registry
*/
public function __construct(WeldLogTriggerRegistry $registry)
{
$this->registry = $registry;
}
/**
* Execute all applicable triggers
*
* @param object $weldLogData Current weld log data
* @param object|null $beforeData Previous weld log data (null for new records)
* @param array $changedFields List of changed field names
* @param bool $isNewRecord Whether this is a new record
* @return array Execution results
*/
public function executeTriggers(
$weldLogData,
$beforeData = null,
array $changedFields = [],
bool $isNewRecord = false,
?string $action = null
): array {
$this->overallStartTime = microtime(true);
Log::info("=== WELD LOG SAVE TRIGGER STARTED ===", [
'weld_log_id' => $weldLogData->id,
'timestamp' => now()->toDateTimeString(),
'is_new_record' => $isNewRecord,
'changed_fields_count' => count($changedFields),
'changed_fields' => $changedFields,
'action' => $action,
'memory_usage_start' => round(memory_get_usage(true) / 1024 / 1024, 2) . ' MB'
]);
// Set database timeouts and memory limits
TransactionHelper::setDatabaseTimeouts(300, 600, 600);
ini_set('memory_limit', '2G');
ini_set('max_execution_time', 600); // 10 minutes
$results = [];
$triggers = $this->registry->getTriggersInOrder();
Log::info("Total triggers registered: " . count($triggers), [
'trigger_names' => array_map(function($t) { return $t->getName(); }, $triggers)
]);
foreach ($triggers as $trigger) {
// Check if trigger should run
if (!$trigger->shouldRun($changedFields, $isNewRecord)) {
Log::info("Skipping trigger: {$trigger->getName()}", [
'reason' => 'shouldRun returned false',
'order' => $trigger->getOrder(),
'dependent_fields' => $trigger->getDependentFields()
]);
$results[$trigger->getName()] = [
'skipped' => true,
'reason' => 'shouldRun returned false'
];
continue;
}
// Execute sync or async
if ($trigger->isAsync()) {
$this->executeAsync($trigger, $weldLogData, $beforeData, $changedFields);
$results[$trigger->getName()] = [
'queued' => true,
'execution' => 'async'
];
} else {
try {
$result = $trigger->execute($weldLogData, $beforeData, [
'changed_fields' => $changedFields,
'is_new_record' => $isNewRecord,
'action' => $action
]);
$results[$trigger->getName()] = array_merge($result, [
'executed' => true,
'execution' => 'sync'
]);
} catch (\Throwable $th) {
Log::error("Trigger execution failed: {$trigger->getName()}", [
'error' => $th->getMessage(),
'file' => $th->getFile(),
'line' => $th->getLine(),
'trace' => $th->getTraceAsString()
]);
$results[$trigger->getName()] = [
'executed' => false,
'error' => $th->getMessage(),
'execution' => 'sync'
];
// Re-throw critical errors, log others
if ($this->isCriticalTrigger($trigger->getName())) {
throw $th;
}
}
}
}
$this->logOverallCompletion($weldLogData->id, $results);
return $results;
}
/**
* Execute trigger asynchronously (via queue)
*
* @param \App\Services\WeldLogTriggers\Contracts\WeldLogTriggerInterface $trigger
* @param object $weldLogData
* @param object|null $beforeData
* @param array $changedFields
*/
protected function executeAsync($trigger, $weldLogData, $beforeData, $changedFields)
{
// Future implementation: Dispatch job to queue
// \App\Jobs\WeldLogTriggerJob::dispatch(
// get_class($trigger),
// $weldLogData->id,
// $beforeData,
// $changedFields
// );
Log::info("Trigger queued (async execution): {$trigger->getName()}", [
'weld_log_id' => $weldLogData->id,
'note' => 'Async execution not yet implemented, falling back to sync'
]);
// Fallback to sync execution for now
try {
$trigger->execute($weldLogData, $beforeData, [
'changed_fields' => $changedFields,
'is_new_record' => false,
// $action is not available here in the current signature, but async isn't used yet anyway
]);
} catch (\Throwable $th) {
Log::error("Async trigger execution failed: {$trigger->getName()}", [
'error' => $th->getMessage()
]);
}
}
/**
* Check if a trigger is critical (should stop execution on failure)
*
* @param string $triggerName
* @return bool
*/
protected function isCriticalTrigger(string $triggerName): bool
{
// Define which triggers are critical
$criticalTriggers = [
'Spool Status Changer',
'Line Lists Update',
'NDE Matrix Update',
'Construction Paint Logs Sync',
'Paint Follow Ups Sync',
];
return in_array($triggerName, $criticalTriggers);
}
/**
* Log overall execution completion
*
* @param int $weldLogId
* @param array $results
*/
protected function logOverallCompletion($weldLogId, array $results)
{
$overallDuration = round((microtime(true) - $this->overallStartTime) * 1000, 2);
// Count execution statistics
$executedCount = 0;
$skippedCount = 0;
$queuedCount = 0;
$failedCount = 0;
foreach ($results as $triggerName => $result) {
if (isset($result['executed']) && $result['executed']) {
$executedCount++;
} elseif (isset($result['skipped']) && $result['skipped']) {
$skippedCount++;
} elseif (isset($result['queued']) && $result['queued']) {
$queuedCount++;
} elseif (isset($result['executed']) && !$result['executed']) {
$failedCount++;
}
}
Log::info("=== WELD LOG SAVE TRIGGER COMPLETED ===", [
'weld_log_id' => $weldLogId,
'timestamp' => now()->toDateTimeString(),
'total_execution_time_ms' => $overallDuration,
'total_execution_time_sec' => round($overallDuration / 1000, 3),
'peak_memory_usage_mb' => round(memory_get_peak_usage(true) / 1024 / 1024, 2),
'final_memory_usage_mb' => round(memory_get_usage(true) / 1024 / 1024, 2),
'statistics' => [
'total_triggers' => count($results),
'executed' => $executedCount,
'skipped' => $skippedCount,
'queued' => $queuedCount,
'failed' => $failedCount
]
]);
}
/**
* Get the registry instance
*
* @return WeldLogTriggerRegistry
*/
public function getRegistry(): WeldLogTriggerRegistry
{
return $this->registry;
}
}