odan / slim4-skeleton

A Slim 4 Skeleton
https://odan.github.io/slim4-skeleton/
MIT License
439 stars 80 forks source link

The validateUserUpdate() function of UserValidator service does not return the error message, only the status code (422) #77

Closed esallum-iluminare closed 3 years ago

esallum-iluminare commented 3 years ago

Hi @odan, how are you?

In my tests, the ValidationException of validateUserUpdate() does not return the 'User not found' error message. Returns only the 422 error, but without the error message.

The validateUser() returns with the error message, and indicates which field is incorrect.

What is the correct way to solve this?

Thanks in advanced.

odan commented 3 years ago

Hi @esallum-iluminare Can you show some code?

esallum-iluminare commented 3 years ago

Hi @odan! Follows the code of the function that is equivalent to validateUserUpdate():

public function validateUnidadeAtendimentoUpdate(string $uuid_conveniado, string $uuid_conveniado_matriz, array $data): void
    {
        if (!$this->repository->existsUnidadeAtendimentoId($uuid_conveniado)) {
            throw new ValidationException(sprintf('UnidadeAtendimento não encontrada: %s', $uuid_conveniado));
        }
        if (!$this->repository->UAisValid($uuid_conveniado, $uuid_conveniado_matriz)) {
            throw new ValidationException(sprintf('Unidade de Atendimento (%s) informada não pertence a Matriz (%s)', $uuid_conveniado, $uuid_conveniado_matriz));
        }

        $this->validateUnidadeAtendimento($data);
    }
odan commented 3 years ago

What happens when you fetch the error message from the exception like $exception->getMessage();. Is it still empty?

esallum-iluminare commented 3 years ago

In the var_dump I used the message appears the way I want

   public function __construct(
        string $message,
        ValidationResult $validationResult = null,
        int $code = 422,
        Throwable $previous = null
    ) {
        parent::__construct($message, $code, $previous);
        var_dump($message);
        $this->validationResult = $validationResult;
    }
odan commented 3 years ago

Ok, then the message should work as expected: echo $exception->getMessage();. Correct? Please show me your test code.

esallum-iluminare commented 3 years ago
 public function validateUnidadeAtendimentoReader(string $uuid_conveniado, string $uuid_conveniado_matriz): void
    {

        if (true) {
            throw new ValidationException(sprintf('Unidade de Atendimento (%s) informada não pertence a Matriz (%s)', $uuid_conveniado, $uuid_conveniado_matriz));
        }
    }

\vendor\selective\validation\src\Exception:

<?php

namespace Selective\Validation\Exception;

use DomainException;
use Selective\Validation\ValidationResult;
use Throwable;

/**
 * Validation Exception.
 */
final class ValidationException extends DomainException
{
    /**
     * @var ValidationResult|null
     */
    private $validationResult;

    /**
     * Construct the exception.
     *
     * @param string $message The Exception message to throw
     * @param ValidationResult|null $validationResult The validation result object
     * @param int $code The Exception code
     * @param Throwable|null $previous The previous throwable used for the exception chaining
     */
    public function __construct(
        string $message,
        ValidationResult $validationResult = null,
        int $code = 422,
        Throwable $previous = null
    ) {
        parent::__construct($message, $code, $previous);
        echo $message;
        $this->validationResult = $validationResult;
    }

    /**
     * Get the validation result.
     *
     * @return ValidationResult|null The validation result
     */
    public function getValidationResult(): ?ValidationResult
    {
        return $this->validationResult;
    }
}

Output: 'test'

odan commented 3 years ago

I must have mistakenly understood that you meant unit tests.

Anyway, I guess I know what you are asking for now. When you just throw a ValidationException, whout passing a ValidationResult object then there is no information about the fields and the error messages.

Example:

throw new ValidationException('Validation failed');

When you create have a ValidationResult object you can pass it as the second parameter. Example:

$validationResult = new ValidationResult();
$validationResult->addError('fieldname', 'error message');
$validationResult->addError('fieldname2', 'error message 2');

throw new ValidationException('Validation failed', $validationResult);

Documentation

esallum-iluminare commented 3 years ago

Thanks @odan It is correct to think that an error of type ValidationException (422) occurs when in the body request I send some parameter that is wrong according to the system requirements (via POST and PUT), and DomainException (400) when the variables of my route are incorrect? It's just that sometimes I'm in doubt between using the ValidationException and DomainException.

Can I have my repository perform any validation that is not represented in my Validation Service?

odan commented 3 years ago

DomainException can be thrown when something in the Domain does not exist e.g. a Customer-ID, User-ID, etc. Whether you use it or not depends on your specific use case.

Within a validation context, the ValidationException makes the most sense. If you have a specific field that you can refer to, then better use a ValidationException.

Outside the validation context, a DomainException, UnexcpectedValueException or any other exception would make more sense.

esallum-iluminare commented 3 years ago

Thanks @odan !