private final function execute($method_name, $arg_list, $call_parent = FALSE) { $execution_record = []; $execution_id = Debug::addExecutionRecord($execution_record); Debug::pushExecutionId($execution_id); try { $execution_record = $this->prepareExecutionRecord($method_name, $arg_list, $call_parent); $class_name = $execution_record['class']; $declaring_class_name = $execution_record['declaring_class']; $method_accessibility = $execution_record['method_accessibility']; $handler_prefix = $execution_record['handler_prefix']; $handler_suffix = $execution_record['handler_suffix']; Debug::updateExecutionRecord($execution_id, $execution_record); if (($count = Debug::countExecutionRecord()) > 3000000) { throw new UserException('Abnormal execution record count.', $count); } if (FALSE === $method_accessibility) { throw new UserException("Handler({$declaring_class_name} :: {$method_name}) is not accessible.", $execution_record); } $config_model_name = $this->loadConfig(Loader::getModelPath($declaring_class_name)); // Method validateModelPrivilege should throw exception if the validation fails. $execution_record['validateModelPrivilege'] = $this->{$config_model_name}->validateModelPrivilege($handler_suffix, $method_name); $data_model_name = $this->loadData(Loader::getModelPath($declaring_class_name)); // Method validateArgs should throw exception if the validation fails, // and it should load the config model and fetch the config info itself. $args_validation_result = $execution_record['validateArgs'] = $this->{$data_model_name}->validateArgs($handler_suffix, $method_name, $arg_list); // Now the validation passed. // Method sanitizeArgs should load the config model and fetch the config info itself. $args_sanitization_result = $execution_record['sanitizeArgs'] = $this->{$data_model_name}->sanitizeArgs($handler_suffix, $method_name, $arg_list, $args_validation_result); // @TODO: check it, can be called with context info? // so that XCollection will work correctly. // $method = new ReflectionMethod($declaring_class_name, $method_name); // $method->setAccessible(TRUE); $result = $execution_record['result'] = call_user_func_array([$declaring_class_name, $method_name], $args_sanitization_result); // Method validateResult should throw exception if the validation fails, // and it should load the config model and fetch the config info itself. $result_validation_result = $execution_record['validateResult'] = $this->{$data_model_name}->validateResult($handler_suffix, $method_name, $result); // Now the validation passed. // Method sanitizeResult should load the config model and fetch the config info itself. $result_sanitization_result = $execution_record['sanitizeResult'] = $this->{$data_model_name}->sanitizeResult($handler_suffix, $method_name, $result, $result_validation_result); $execution_record['success'] = TRUE; Debug::updateExecutionRecord($execution_id, $execution_record); Debug::popExecutionId($execution_id); return $result; } catch (Exception $e) { $execution_record['success'] = FALSE; Debug::updateExecutionRecord($execution_id, $execution_record); Debug::popExecutionId($execution_id); throw new UserException('Model execution failed.', $execution_record, $e); } }