PHP code example of phphd / exceptional-validation

1. Go to this page and download the library: Download phphd/exceptional-validation library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

phphd / exceptional-validation example snippets


    PhPhD\ExceptionalValidation\Bundle\PhdExceptionalValidationBundle::class => ['all' => true],
    PhPhD\ExceptionToolkit\Bundle\PhdExceptionToolkitBundle::class => ['all' => true],
    

use PhPhD\ExceptionalValidation;
use PhPhD\ExceptionalValidation\Capture;

#[ExceptionalValidation]
class RegisterUserCommand
{
    #[Capture(LoginAlreadyTakenException::class, 'auth.login.already_taken')]
    public string $login;

    #[Capture(WeakPasswordException::class, 'auth.password.weak')]
    public string $password;
}

$command = new RegisterUserCommand($login, $password);

try {
    $this->commandBus->dispatch($command);
} catch (ExceptionalValidationFailedException $exception) {
    $violationList = $exception->getViolationList();

    return $this->render('registrationForm.html.twig', ['errors' => $violationList]);
} 

use Symfony\Component\Validator\Constraints as Assert;
use App\Validator\Constraints as AppAssert;

class RegisterUserCommand
{
    #[AppAssert\UniqueLogin]
    public string $login;

    #[Assert\PasswordStrength(minScore: 2)]
    public string $password;
}

// RegisterUserService

if ($this->userRepository->loginExists($command->login)) {
    throw new LoginAlreadyTakenException($command->login);
}

use PhPhD\ExceptionalValidation;
use PhPhD\ExceptionalValidation\Capture;

#[ExceptionalValidation]
class PublishMessageCommand
{
    #[Capture(MessageNotFoundException::class)]
    public string $messageId;
}

use PhPhD\ExceptionalValidation;
use PhPhD\ExceptionalValidation\Capture;
use Symfony\Component\Uid\Uuid;

#[ExceptionalValidation]
class ConfirmPackageCommand
{
    #[Capture(\InvalidArgumentException::class, from: [Uuid::class, 'fromString'])]
    public string $uid;
}

use PhPhD\ExceptionalValidation;
use PhPhD\ExceptionalValidation\Capture;

#[ExceptionalValidation]
class TransferMoneyCommand
{
    #[Capture(BlockedCardException::class, when: [self::class, 'isWithdrawalCardBlocked'])]
    public int $withdrawalCardId;

    #[Capture(BlockedCardException::class, when: [self::class, 'isDepositCardBlocked'])]
    public int $depositCardId;

    public function isWithdrawalCardBlocked(BlockedCardException $exception): bool
    {
        return $exception->getCardId() === $this->withdrawalCardId;
    }

    public function isDepositCardBlocked(BlockedCardException $exception): bool
    {
        return $exception->getCardId() === $this->depositCardId;
    }
}

use PhPhD\ExceptionalValidation;
use PhPhD\ExceptionalValidation\Capture;
use PhPhD\ExceptionalValidation\Rule\Object\Property\Capture\Condition\Value\ExceptionValueMatchCondition;

#[ExceptionalValidation]
class TransferMoneyCommand
{
    #[Capture(BlockedCardException::class, condition: ExceptionValueMatchCondition::class)]
    public int $withdrawalCardId;

    #[Capture(BlockedCardException::class, condition: ExceptionValueMatchCondition::class)]
    public int $depositCardId;
}

use PhPhD\ExceptionalValidation\Rule\Object\Property\Capture\Condition\Value\ValueException;

class BlockedCardException extends DomainException implements ValueException
{
    public function __construct(private Card $card) 
    {
        parent::__construct('card.blocked');
    }

    public function getValue(): int
    {
        return $this->card->getId();    
    }
}

use PhPhD\ExceptionalValidation;
use PhPhD\ExceptionalValidation\Capture;
use PhPhD\ExceptionalValidation\Rule\Object\Property\Capture\Condition\Validator\ValidationFailedExceptionMatchCondition;
use Symfony\Component\Validator\Exception\ValidationFailedException;

#[ExceptionalValidation]
class RegisterUserCommand
{
    #[Capture(ValidationFailedException::class, from: Password::class, condition: ValidationFailedExceptionMatchCondition::class)]
    public string $password;
}

use PhPhD\ExceptionalValidation;
use PhPhD\ExceptionalValidation\Capture;
use Symfony\Component\Validator\Constraints as Assert;

#[ExceptionalValidation]
class CreateOrderCommand
{
    /** @var OrderItemDto[] */
    #[Assert\Valid]
    public array $items;
}

#[ExceptionalValidation]
class OrderItemDto
{
    public int $productId;

    #[Capture(InsufficientStockException::class, when: [self::class, 'isStockExceptionForThisItem'])]
    public string $quantity;

    public function isStockExceptionForThisItem(InsufficientStockException $exception): bool
    {
        return $exception->getProductId() === $this->productId;
    }
}

/**
 * @var Login $login 
 * @var Password $password 
 */
[$login, $password] = await([
    // validate and create an instance of Login
    async($this->createLogin(...), $command->getLogin()),
    // validate and create an instance of Password
    async($this->createPassword(...), $command->getPassword()),
]);

use PhPhD\ExceptionalValidation\Mapper\Validator\Formatter\Item\ViolationList\ViolationListException;
use Symfony\Component\Validator\ConstraintViolationListInterface;

final class CardNumberValidationFailedException extends \RuntimeException implements ViolationListException
{
    public function __construct(
        private readonly string $cardNumber,
        private readonly ConstraintViolationListInterface $violationList,
    ) {
        parent::__construct((string)$this->violationList);
    }

    public function getViolationList(): ConstraintViolationListInterface
    {
        return $this->violationList;
    }
}

use PhPhD\ExceptionalValidation;
use PhPhD\ExceptionalValidation\Capture;
use PhPhD\ExceptionalValidation\Mapper\Validator\Formatter\Item\ViolationList\ViolationListExceptionFormatter;

#[ExceptionalValidation]
class IssueCreditCardCommand
{
    #[Capture(
        exception: CardNumberValidationFailedException::class, 
        formatter: ViolationListExceptionFormatter::class,
    )]
    private string $cardNumber;
}

use PhPhD\ExceptionalValidation\Mapper\Validator\Formatter\Item\ExceptionViolationFormatter;
use PhPhD\ExceptionalValidation\Rule\Exception\CapturedException;
use Symfony\Component\Validator\ConstraintViolationInterface;

final class RegistrationViolationsFormatter implements ExceptionViolationFormatter
{
    public function __construct(
        #[Autowire('@phd_exceptional_validation.violation_formatter.default')]
        private ExceptionViolationFormatter $defaultFormatter,
    ) {
    }

    /** @return array{ConstraintViolationInterface} */
    public function format(CapturedException $capturedException): ConstraintViolationInterface
    {
        // format violation with the default formatter
        // and then adjust only the necessary parts
        [$violation] = $this->defaultFormatter->format($capturedException);

        $exception = $capturedException->getException();

        if ($exception instanceof LoginAlreadyTakenException) {
            $violation = new ConstraintViolation(
                $violation->getMessage(),
                $violation->getMessageTemplate(),
                ['loginHolder' => $exception->getLoginHolder()],
                // ...
            );
        }

        if ($exception instanceof WeakPasswordException) {
            // ...
        }

        return [$violation];
    }
}

use PhPhD\ExceptionalValidation;
use PhPhD\ExceptionalValidation\Capture;

#[ExceptionalValidation]
final class RegisterUserCommand
{
    #[Capture(
        LoginAlreadyTakenException::class, 
        'auth.login.already_taken', 
        formatter: RegistrationViolationsFormatter::class,
    )]
    private string $login;

    #[Capture(
        WeakPasswordException::class, 
        'auth.password.weak', 
        formatter: RegistrationViolationsFormatter::class,
    )]
    private string $password;
}

return RectorConfig::configure()
    ->withPaths([ __DIR__ . '/src'])
    ->withImportNames(removeUnusedImports: true)
    // Upgrading from the version 1.4 to the latest version
    ->withSets(ExceptionalValidationSetList::fromVersion('1.4')->getSetList());