'decimal:6', 'is_active' => 'boolean', 'priority' => 'integer', ]; /** * 조건 규칙이 속한 모델 */ public function designModel() { return $this->belongsTo(DesignModel::class, 'model_id'); } /** * 조건식 평가 */ public function evaluateCondition(array $parameters): bool { $expression = $this->condition_expression; // 매개변수 값으로 치환 foreach ($parameters as $param => $value) { // 문자열 값은 따옴표로 감싸기 if (is_string($value)) { $value = "'" . addslashes($value) . "'"; } elseif (is_bool($value)) { $value = $value ? 'true' : 'false'; } $expression = str_replace($param, (string) $value, $expression); } // 안전한 조건식 평가 return $this->evaluateSimpleCondition($expression); } /** * 간단한 조건식 평가기 */ private function evaluateSimpleCondition(string $expression): bool { // 공백 제거 $expression = trim($expression); // 간단한 비교 연산자들 처리 $operators = ['==', '!=', '>=', '<=', '>', '<']; foreach ($operators as $operator) { if (strpos($expression, $operator) !== false) { $parts = explode($operator, $expression, 2); if (count($parts) === 2) { $left = trim($parts[0]); $right = trim($parts[1]); // 따옴표 제거 $left = trim($left, "'\""); $right = trim($right, "'\""); // 숫자 변환 시도 if (is_numeric($left)) $left = (float) $left; if (is_numeric($right)) $right = (float) $right; switch ($operator) { case '==': return $left == $right; case '!=': return $left != $right; case '>=': return $left >= $right; case '<=': return $left <= $right; case '>': return $left > $right; case '<': return $left < $right; } } } } // IN 연산자 처리 if (preg_match('/(.+)\s+IN\s+\((.+)\)/i', $expression, $matches)) { $value = trim($matches[1], "'\""); $list = array_map('trim', explode(',', $matches[2])); $list = array_map(function($item) { return trim($item, "'\""); }, $list); return in_array($value, $list); } // NOT IN 연산자 처리 if (preg_match('/(.+)\s+NOT\s+IN\s+\((.+)\)/i', $expression, $matches)) { $value = trim($matches[1], "'\""); $list = array_map('trim', explode(',', $matches[2])); $list = array_map(function($item) { return trim($item, "'\""); }, $list); return !in_array($value, $list); } // 불린 값 처리 if (in_array(strtolower($expression), ['true', '1'])) { return true; } if (in_array(strtolower($expression), ['false', '0'])) { return false; } throw new \InvalidArgumentException('Invalid condition expression: ' . $this->condition_expression); } /** * 조건 규칙 액션 실행 */ public function executeAction(array $currentBom): array { switch ($this->action_type) { case 'INCLUDE': // 아이템 포함 $currentBom[] = [ 'target_type' => $this->target_type, 'target_id' => $this->target_id, 'quantity' => $this->quantity_multiplier ?? 1, 'reason' => $this->rule_name, ]; break; case 'EXCLUDE': // 아이템 제외 $currentBom = array_filter($currentBom, function($item) { return !($item['target_type'] === $this->target_type && $item['target_id'] === $this->target_id); }); break; case 'MODIFY_QUANTITY': // 수량 변경 foreach ($currentBom as &$item) { if ($item['target_type'] === $this->target_type && $item['target_id'] === $this->target_id) { $item['quantity'] = ($item['quantity'] ?? 1) * ($this->quantity_multiplier ?? 1); $item['reason'] = $this->rule_name; } } break; } return array_values($currentBom); // 인덱스 재정렬 } }