user(); if (!$user) { return []; } $svc = app(TicketFieldSettingsService::class); // Built-in field rules — wrap any 'required' with 'sometimes' for partial updates $rules = []; $baseRules = $svc->getValidationRules($user); unset($baseRules['custom_data']); foreach ($baseRules as $key => $rule) { $ruleArr = is_string($rule) ? explode('|', $rule) : (array) $rule; if (($idx = array_search('required', $ruleArr)) !== false) { array_splice($ruleArr, $idx, 1); array_unshift($ruleArr, 'sometimes'); } $rules[$key] = $ruleArr; } // Flat rules for visible custom fields (all optional on update) foreach ($svc->getEffectiveFields($user) as $field) { if (!($field['is_custom'] ?? false) || !($field['visible'] ?? false)) { continue; } $rule = ['sometimes', 'nullable']; $type = $field['type'] ?? 'text'; if ($type === 'number') { $rule[] = 'numeric'; } elseif ($type === 'email') { $rule[] = 'email'; } elseif ($type === 'date') { $rule[] = 'date'; } elseif ($type === 'datetime') { $rule[] = 'date'; } elseif (is_int($field['max_length'] ?? null)) { $rule[] = 'string'; $rule[] = 'max:' . $field['max_length']; } $rules[$field['key']] = $rule; } // Relation constraints $relations = [ 'ticket_status_id' => 'tickets_dict_status', 'ticket_priority_id' => 'tickets_dict_priority', 'ticket_severity_id' => 'tickets_dict_severity', 'ticket_category_id' => 'tickets_dict_category', 'contact_id' => 'contacts', 'account_id' => 'accounts', 'lead_id' => 'leads', 'parent_id' => 'tickets', 'ticket_owner_id' => 'users', ]; foreach ($relations as $field => $table) { $rules[$field] = ['sometimes', 'nullable', 'integer', "exists:{$table},id"]; } return $rules; } protected function failedValidation(Validator $validator): void { throw new HttpResponseException(response()->json([ 'status' => false, 'errors' => $validator->errors(), 'message' => 'Validation failed', ], 422)); } }