fix: [message handling] of error messages

- correctly handle beforeSave / afterSave failures in ajax contexts

- until now it was just silently failing giving cryptic messages to the user
pull/187/head
iglocska 2024-11-22 12:40:21 +01:00
parent 5d0b7715db
commit ac33e90f0c
No known key found for this signature in database
GPG Key ID: BEA224F1FEF113AC
2 changed files with 132 additions and 74 deletions

View File

@ -465,51 +465,73 @@ class CRUDComponent extends Component
}
}
$data = $this->Table->patchEntity($data, $input, $patchEntityParams);
$break = false;
if (isset($params['beforeSave'])) {
$data = $params['beforeSave']($data);
try {
$data = $params['beforeSave']($data);
} catch (\Exception $e) {
$message = $e->getMessage();
$break = true;
$this->__raiseErrorToUser(__('Could not save {0}.', $this->ObjectAlias), ['Custom checks' => ['Custom checks' => $message]]);
}
if ($data === false) {
throw new NotFoundException(__('Could not save {0} due to the input failing to meet expectations. Your input is bad and you should feel bad.', $this->ObjectAlias));
$break = true;
$this->__raiseErrorToUser(__('Could not save {0} due to the input failing to meet expectations. Your input is bad and you should feel bad.', $this->ObjectAlias));
}
}
$savedData = $this->Table->save($data);
if ($savedData !== false) {
if (isset($params['afterSave'])) {
$params['afterSave']($data);
}
$message = __('{0} added.', $this->ObjectAlias);
if ($this->Controller->ParamHandler->isRest()) {
$this->Controller->restResponsePayload = $this->RestResponse->viewData($savedData, 'json');
} else if ($this->Controller->ParamHandler->isAjax()) {
if (!empty($params['displayOnSuccess'])) {
$displayOnSuccess = $this->renderViewInVariable($params['displayOnSuccess'], ['entity' => $data]);
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'add', $savedData, $message, ['displayOnSuccess' => $displayOnSuccess]);
} else {
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'add', $savedData, $message);
if (!$break) {
$savedData = $this->Table->save($data);
if ($savedData !== false) {
if (isset($params['afterSave'])) {
try {
$data = $params['afterSave']($data);
} catch (\Exception $e) {
$message = $e->getMessage();
$break = true;
$this->__raiseErrorToUser(__('Saved {0}, but could not execute post-save actions.', $this->ObjectAlias), ['Custom checks' => ['Custom checks' => $message]]);
}
if ($data === false) {
$break = true;
$this->__raiseErrorToUser(__('Saved {0}, but the post-save actons failed.', $this->ObjectAlias));
}
}
if (!$break) {
$message = __('{0} added.', $this->ObjectAlias);
if ($this->Controller->ParamHandler->isRest()) {
$this->Controller->restResponsePayload = $this->RestResponse->viewData($savedData, 'json');
} else if ($this->Controller->ParamHandler->isAjax()) {
if (!empty($params['displayOnSuccess'])) {
$displayOnSuccess = $this->renderViewInVariable($params['displayOnSuccess'], ['entity' => $data]);
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'add', $savedData, $message, ['displayOnSuccess' => $displayOnSuccess]);
} else {
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'add', $savedData, $message);
}
} else {
$this->Controller->Flash->success($message);
if (empty($params['redirect'])) {
$this->Controller->redirect(['action' => 'view', $data->id]);
} else {
$this->Controller->redirect($params['redirect']);
}
}
}
} else {
$this->Controller->Flash->success($message);
if (empty($params['redirect'])) {
$this->Controller->redirect(['action' => 'view', $data->id]);
$this->Controller->isFailResponse = true;
$validationErrors = $data->getErrors();
$validationMessage = $this->prepareValidationMessage($validationErrors);
$message = __(
'{0} could not be added.{1}',
$this->ObjectAlias,
empty($validationMessage) ? '' : PHP_EOL . __('Reason: {0}', $validationMessage)
);
if ($this->Controller->ParamHandler->isRest()) {
$this->Controller->restResponsePayload = $this->RestResponse->viewData($message, 'json');
} else if ($this->Controller->ParamHandler->isAjax()) {
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'add', $data, $message, $validationErrors);
} else {
$this->Controller->redirect($params['redirect']);
$this->Controller->Flash->error($message);
}
}
} else {
$this->Controller->isFailResponse = true;
$validationErrors = $data->getErrors();
$validationMessage = $this->prepareValidationMessage($validationErrors);
$message = __(
'{0} could not be added.{1}',
$this->ObjectAlias,
empty($validationMessage) ? '' : PHP_EOL . __('Reason: {0}', $validationMessage)
);
if ($this->Controller->ParamHandler->isRest()) {
$this->Controller->restResponsePayload = $this->RestResponse->viewData($message, 'json');
} else if ($this->Controller->ParamHandler->isAjax()) {
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'add', $data, $message, $validationErrors);
} else {
$this->Controller->Flash->error($message);
}
}
}
if (!empty($params['fields'])) {
@ -723,6 +745,16 @@ class CRUDComponent extends Component
return $input;
}
private function __raiseErrorToUser($title, $message = null)
{
if ($this->Controller->ParamHandler->isRest()) {
} else if ($this->Controller->ParamHandler->isAjax()) {
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'edit', [], $title, $message);
} else {
throw new NotFoundException($message);
}
}
public function edit(int $id, array $params = []): void
{
if (empty($id)) {
@ -800,54 +832,79 @@ class CRUDComponent extends Component
}
}
$data = $this->Table->patchEntity($data, $input, $patchEntityParams);
$break = false;
if (isset($params['beforeSave'])) {
$data = $params['beforeSave']($data);
try {
$data = $params['beforeSave']($data);
} catch (\Exception $e) {
$message = $e->getMessage();
$break = true;
$this->__raiseErrorToUser(__('Could not save {0}.', $this->ObjectAlias), ['Custom checks' => ['Custom checks' => $message]]);
}
if ($data === false) {
throw new NotFoundException(__('Could not save {0} due to the input failing to meet expectations. Your input is bad and you should feel bad.', $this->ObjectAlias));
$break = true;
$this->__raiseErrorToUser(__('Could not save {0} due to the input failing to meet expectations.', $this->ObjectAlias), __('Your input is bad and you should feel bad.'));
}
}
$savedData = $this->Table->save($data);
if ($savedData !== false) {
if ($metaFieldsEnabled && !empty($metaFieldsToDelete)) {
foreach ($metaFieldsToDelete as $k => $v) {
if ($v === null) {
unset($metaFieldsToDelete[$k]);
if (!$break) {
$savedData = $this->Table->save($data);
if ($savedData !== false) {
if ($metaFieldsEnabled && !empty($metaFieldsToDelete)) {
foreach ($metaFieldsToDelete as $k => $v) {
if ($v === null) {
unset($metaFieldsToDelete[$k]);
}
}
if (!empty($metaFieldsToDelete)) {
$this->Table->MetaFields->unlink($savedData, $metaFieldsToDelete);
}
}
if (!empty($metaFieldsToDelete)) {
$this->Table->MetaFields->unlink($savedData, $metaFieldsToDelete);
$break = false;
if (isset($params['afterSave'])) {
if (isset($params['afterSave'])) {
try {
$data = $params['afterSave']($data);
} catch (\Exception $e) {
$message = $e->getMessage();
$break = true;
$this->__raiseErrorToUser(__('Saved {0} `{1}`, but could not execute post-save actions.', $this->ObjectAlias, $savedData->{$this->Table->getDisplayField()}), ['Custom checks' => ['Custom checks' => $message]]);
}
if ($data === false) {
$break = true;
$this->__raiseErrorToUser(__('Saved {0} `{1}`, but the post-save actons failed.', $this->ObjectAlias, $savedData->{$this->Table->getDisplayField()}));
}
}
}
if (!$break) {
$message = __('{0} `{1}` updated.', $this->ObjectAlias, $savedData->{$this->Table->getDisplayField()});
if ($this->Controller->ParamHandler->isRest()) {
$this->Controller->restResponsePayload = $this->RestResponse->viewData($savedData, 'json');
} else if ($this->Controller->ParamHandler->isAjax()) {
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'edit', $savedData, $message);
} else {
$this->Controller->Flash->success($message);
if (empty($params['redirect'])) {
$this->Controller->redirect(['action' => 'view', $id]);
} else {
$this->Controller->redirect($params['redirect']);
}
}
}
}
if (isset($params['afterSave'])) {
$params['afterSave']($data);
}
$message = __('{0} `{1}` updated.', $this->ObjectAlias, $savedData->{$this->Table->getDisplayField()});
if ($this->Controller->ParamHandler->isRest()) {
$this->Controller->restResponsePayload = $this->RestResponse->viewData($savedData, 'json');
} else if ($this->Controller->ParamHandler->isAjax()) {
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'edit', $savedData, $message);
} else {
$this->Controller->Flash->success($message);
if (empty($params['redirect'])) {
$this->Controller->redirect(['action' => 'view', $id]);
$validationErrors = $data->getErrors();
$validationMessage = $this->prepareValidationError($data);
$message = __(
'{0} could not be modified.{1}',
$this->ObjectAlias,
empty($validationMessage) ? '' : PHP_EOL . __('Reason: {0}', $validationMessage)
);
if ($this->Controller->ParamHandler->isRest()) {
} else if ($this->Controller->ParamHandler->isAjax()) {
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'edit', $data, $message, $validationErrors);
} else {
$this->Controller->redirect($params['redirect']);
$this->Controller->Flash->error($message);
}
}
} else {
$validationErrors = $data->getErrors();
$validationMessage = $this->prepareValidationError($data);
$message = __(
'{0} could not be modified.{1}',
$this->ObjectAlias,
empty($validationMessage) ? '' : PHP_EOL . __('Reason: {0}', $validationMessage)
);
if ($this->Controller->ParamHandler->isRest()) {
} else if ($this->Controller->ParamHandler->isAjax()) {
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'edit', $data, $message, $validationErrors);
} else {
$this->Controller->Flash->error($message);
}
}
}
if (!empty($params['fields'])) {

View File

@ -440,7 +440,7 @@ class RestResponseComponent extends Component
return $this->viewData($response);
}
public function ajaxFailResponse($ObjectAlias, $action, $entity, $message, $errors = [])
public function ajaxFailResponse($ObjectAlias, $action, $entity, $message, $errors = [], $description = '')
{
$action = $this->__dissectAdminRouting($action);
$entity = is_array($entity) ? $entity : $entity->toArray();
@ -448,6 +448,7 @@ class RestResponseComponent extends Component
'success' => false,
'message' => $message,
'errors' => $errors,
'description' => $description,
'url' => !empty($entity['id']) ? $this->__generateURL($action, $ObjectAlias, $entity['id']) : ''
];
return $this->viewData($response);