Pierwsze procesy
This commit is contained in:
parent
3b1a26adc9
commit
4674e7458b
@ -404,13 +404,20 @@ class WorkflowEngine {
|
|||||||
$stmt->execute([$instanceId, $eventType, $message, $nodeId, json_encode($payload), $userId]);
|
$stmt->execute([$instanceId, $eventType, $message, $nodeId, json_encode($payload), $userId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOrCreateInstanceByDefId(int $personId, int $processDefinitionId, int $userId): ?array {
|
public function getOrCreateInstanceByDefId(int $personId, int $processDefinitionId, int $userId): ?array {
|
||||||
|
if (!is_int($processDefinitionId) || $processDefinitionId <= 0) {
|
||||||
|
throw new InvalidArgumentException("processDefinitionId must be a positive integer.");
|
||||||
|
}
|
||||||
|
if (!is_int($personId) || $personId <= 0) {
|
||||||
|
throw new InvalidArgumentException("personId must be a positive integer.");
|
||||||
|
}
|
||||||
|
|
||||||
$stmt = $this->pdo->prepare("SELECT * FROM process_instances WHERE `person_id` = ? AND `process_definition_id` = ?");
|
$stmt = $this->pdo->prepare("SELECT * FROM process_instances WHERE `person_id` = ? AND `process_definition_id` = ?");
|
||||||
$stmt->execute([$personId, $processDefinitionId]);
|
$stmt->execute([$personId, $processDefinitionId]);
|
||||||
$instance = $stmt->fetch(PDO::FETCH_ASSOC);
|
$instance = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if (!$instance) {
|
if (!$instance) {
|
||||||
$stmt_def = $this->pdo->prepare("SELECT definition_json, code FROM process_definitions WHERE id = ?");
|
$stmt_def = $this->pdo->prepare("SELECT definition_json, code, is_active FROM process_definitions WHERE id = ?");
|
||||||
$stmt_def->execute([$processDefinitionId]);
|
$stmt_def->execute([$processDefinitionId]);
|
||||||
$definition = $stmt_def->fetch(PDO::FETCH_ASSOC);
|
$definition = $stmt_def->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
@ -418,7 +425,14 @@ class WorkflowEngine {
|
|||||||
throw new WorkflowNotFoundException("Process definition #$processDefinitionId not found.");
|
throw new WorkflowNotFoundException("Process definition #$processDefinitionId not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->checkEligibility($personId, $definition);
|
if (empty($definition['is_active'])) {
|
||||||
|
throw new WorkflowNotAllowedException("Process is not active and cannot be started.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$eligibility = $this->checkEligibility($personId, $processDefinitionId);
|
||||||
|
if (!$eligibility['is_eligible']) {
|
||||||
|
throw new WorkflowEligibilityException("Person is not eligible to start this process.", $eligibility['reasons']);
|
||||||
|
}
|
||||||
|
|
||||||
$definition_json = !empty($definition['definition_json']) ? json_decode($definition['definition_json'], true) : [];
|
$definition_json = !empty($definition['definition_json']) ? json_decode($definition['definition_json'], true) : [];
|
||||||
|
|
||||||
@ -426,9 +440,9 @@ class WorkflowEngine {
|
|||||||
? (string) $processDefinitionId
|
? (string) $processDefinitionId
|
||||||
: $definition['code'];
|
: $definition['code'];
|
||||||
|
|
||||||
if($processCode) {
|
if ($processCode) {
|
||||||
$instanceId = $this->startProcess($processCode, $personId, $userId);
|
$instanceId = $this->startProcess($processCode, $personId, $userId);
|
||||||
if($instanceId) {
|
if ($instanceId) {
|
||||||
$stmt->execute([$personId, $processDefinitionId]);
|
$stmt->execute([$personId, $processDefinitionId]);
|
||||||
$instance = $stmt->fetch(PDO::FETCH_ASSOC);
|
$instance = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,29 +1,44 @@
|
|||||||
<?php
|
<?php
|
||||||
session_start();
|
|
||||||
require_once 'WorkflowEngine.php';
|
|
||||||
require_once 'lib/ErrorHandler.php';
|
require_once 'lib/ErrorHandler.php';
|
||||||
require_once 'lib/WorkflowExceptions.php';
|
register_error_handler();
|
||||||
|
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'WorkflowEngine.php';
|
||||||
|
|
||||||
|
if (session_status() == PHP_SESSION_NONE) {
|
||||||
|
session_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
if (!isset($_SESSION['user_id'])) {
|
if (!isset($_SESSION['user_id'])) {
|
||||||
throw new WorkflowNotAllowedException('Authentication required.');
|
http_response_code(401);
|
||||||
|
echo json_encode(['error' => ['message' => 'Authentication required.']]);
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
$userId = $_SESSION['user_id'];
|
|
||||||
|
|
||||||
$personId = $_GET['personId'] ?? null;
|
$userId = $_SESSION['user_id'];
|
||||||
$processDefinitionId = $_GET['processId'] ?? null;
|
$personId = filter_input(INPUT_POST, 'person_id', FILTER_VALIDATE_INT);
|
||||||
|
$processDefinitionId = filter_input(INPUT_POST, 'process_id', FILTER_VALIDATE_INT);
|
||||||
|
|
||||||
if (!$personId || !$processDefinitionId) {
|
if (!$personId || !$processDefinitionId) {
|
||||||
throw new WorkflowRuleFailedException('Missing parameters for process initialization.');
|
// InvalidArgumentException will be caught by the handler and result in a 400 Bad Request
|
||||||
|
throw new InvalidArgumentException('Invalid or missing person_id or process_id.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$engine = new WorkflowEngine();
|
$engine = new WorkflowEngine();
|
||||||
|
|
||||||
|
// The getOrCreateInstanceByDefId method is now responsible for all checks:
|
||||||
|
// 1. Validating the process definition exists.
|
||||||
|
// 2. Checking if the process is active.
|
||||||
|
// 3. Checking if the person is eligible.
|
||||||
|
// 4. Creating the instance if it doesn't exist.
|
||||||
|
// It will throw specific exceptions (WorkflowNotFoundException, WorkflowNotAllowedException, WorkflowEligibilityException) which our ErrorHandler will turn into 404, 409, and 422 responses.
|
||||||
$instance = $engine->getOrCreateInstanceByDefId($personId, $processDefinitionId, $userId);
|
$instance = $engine->getOrCreateInstanceByDefId($personId, $processDefinitionId, $userId);
|
||||||
|
|
||||||
if ($instance) {
|
if ($instance) {
|
||||||
$_SESSION['success_message'] = "Process initialized successfully.";
|
echo json_encode(['success' => true, 'message' => 'Process initialized successfully.', 'instance_id' => $instance['id']]);
|
||||||
} else {
|
} else {
|
||||||
$_SESSION['error_message'] = "Failed to initialize process.";
|
// This case should not be reached if the engine works as expected, as failures should throw exceptions.
|
||||||
|
throw new Exception("Failed to initialize process for an unknown reason.");
|
||||||
}
|
}
|
||||||
|
|
||||||
header('Location: index.php');
|
|
||||||
exit();
|
|
||||||
|
|||||||
66
index.php
66
index.php
@ -607,6 +607,12 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
handleAddNote(noteBtn);
|
handleAddNote(noteBtn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const startBtn = event.target.closest('#startProcessBtn');
|
||||||
|
if (startBtn) {
|
||||||
|
handleStartProcess(startBtn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
instanceModal.addEventListener('change', function(event) {
|
instanceModal.addEventListener('change', function(event) {
|
||||||
@ -708,6 +714,22 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
submitRequestAndReloadModal('_apply_transition.php', formData);
|
submitRequestAndReloadModal('_apply_transition.php', formData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleStartProcess(button) {
|
||||||
|
const personId = button.dataset.personId;
|
||||||
|
const processId = button.dataset.processId;
|
||||||
|
|
||||||
|
if (!personId || !processId) {
|
||||||
|
alert('Missing data for starting process. Please close the modal and try again.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('person_id', personId);
|
||||||
|
formData.append('process_id', processId);
|
||||||
|
|
||||||
|
submitRequestAndReloadModal('_init_single_instance.php', formData);
|
||||||
|
}
|
||||||
|
|
||||||
function submitRequestAndReloadModal(url, formData) {
|
function submitRequestAndReloadModal(url, formData) {
|
||||||
const modalBody = instanceModal.querySelector('.modal-body');
|
const modalBody = instanceModal.querySelector('.modal-body');
|
||||||
showLoading(modalBody);
|
showLoading(modalBody);
|
||||||
@ -718,14 +740,50 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Network response was not ok');
|
// If response is not OK, it's an error. Clone the response to read it twice.
|
||||||
|
const clone = response.clone();
|
||||||
|
return response.json()
|
||||||
|
.then(json => {
|
||||||
|
// We have a JSON error body, throw a custom error with its details
|
||||||
|
const error = new Error(json.error?.message || 'An unkown error occurred.');
|
||||||
|
error.correlation_id = json.correlation_id;
|
||||||
|
error.response = response; // Attach full response
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
// If JSON parsing fails, fall back to the text body
|
||||||
|
return clone.text().then(text => {
|
||||||
|
const error = new Error(text || 'Network response was not ok and could not parse error body.');
|
||||||
|
error.response = response;
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return response.json(); // On success, just parse the JSON
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
// Reload modal content for the same person/process after successful submission
|
||||||
|
fetchAndRenderModalContent(currentPersonId, currentProcessId);
|
||||||
|
} else {
|
||||||
|
// Handle cases where the server returns 200 OK but with success: false
|
||||||
|
const error = new Error(data.message || 'An unknown error occurred.');
|
||||||
|
if (data.correlation_id) {
|
||||||
|
error.correlation_id = data.correlation_id;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
// Reload modal content after successful submission
|
|
||||||
fetchAndRenderModalContent(currentPersonId, currentProcessId);
|
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error submitting request:', error);
|
console.error('Error submitting request:', error);
|
||||||
modalBody.innerHTML = `<div class="alert alert-danger">Wystąpił błąd sieciowy.</div>`;
|
|
||||||
|
let errorMessage = `<div class="alert alert-danger">`;
|
||||||
|
errorMessage += `<strong>Error:</strong> ${error.message}`;
|
||||||
|
if (error.correlation_id) {
|
||||||
|
errorMessage += `<br><small class="text-muted">Correlation ID: ${error.correlation_id}</small>`;
|
||||||
|
}
|
||||||
|
errorMessage += `</div>`;
|
||||||
|
modalBody.innerHTML = errorMessage;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,44 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
class WorkflowException extends Exception {
|
class WorkflowNotFoundException extends Exception {}
|
||||||
protected $httpCode;
|
class WorkflowNotAllowedException extends Exception {}
|
||||||
protected $details;
|
class WorkflowRuleFailedException extends Exception {}
|
||||||
|
|
||||||
public function __construct($message = "", $code = 0, $httpCode = 500, $details = [], Throwable $previous = null) {
|
class WorkflowEligibilityException extends Exception {
|
||||||
|
private $reasons;
|
||||||
|
|
||||||
|
public function __construct($message = "", $reasons = [], $code = 0, Throwable $previous = null) {
|
||||||
parent::__construct($message, $code, $previous);
|
parent::__construct($message, $code, $previous);
|
||||||
$this->httpCode = $httpCode;
|
$this->reasons = $reasons;
|
||||||
$this->details = $details;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHttpCode() {
|
public function getReasons() {
|
||||||
return $this->httpCode;
|
return $this->reasons;
|
||||||
}
|
|
||||||
|
|
||||||
public function getDetails() {
|
|
||||||
return $this->details;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WorkflowNotFoundException extends WorkflowException {
|
|
||||||
public function __construct($message = "Not Found", $details = [], Throwable $previous = null) {
|
|
||||||
parent::__construct($message, 404, 404, $details, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WorkflowNotAllowedException extends WorkflowException {
|
|
||||||
public function __construct($message = "Bad Request", $details = [], Throwable $previous = null) {
|
|
||||||
parent::__construct($message, 400, 400, $details, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WorkflowRuleFailedException extends WorkflowException {
|
|
||||||
public function __construct($message = "Unprocessable Entity", $details = [], Throwable $previous = null) {
|
|
||||||
parent::__construct($message, 422, 422, $details, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WorkflowConflictException extends WorkflowException {
|
|
||||||
public function __construct($message = "Conflict", $details = [], Throwable $previous = null) {
|
|
||||||
parent::__construct($message, 409, 409, $details, $previous);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user