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/ */
use PhPhD\ExceptionalMatcher\Rule\Object\Try_;
use PhPhD\ExceptionalMatcher\Rule\Object\Property\Catch_;
#[Try_]
class UserRegistration
{
#[Catch_(LoginAlreadyTakenException::class)]
public string $login;
#[Catch_(PasswordCompromisedException::class)]
public string $password;
public function process(UserRegistrationServices $services): void
{
$userWithTheSameLogin = $services->userRepository->whereLogin($this->login)->firstOrNull();
if (null !== $userWithTheSameLogin) {
throw new LoginAlreadyTakenException($this->login);
}
if ($services->passwordSecurity->isCompromised($this->password)) {
throw new PasswordCompromisedException($this->password);
}
$services->entityManager->persist(new User($this->login, $this->password));
$services->entityManager->flush();
}
}
use PhPhD\ExceptionalMatcher\ExceptionMatcher;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Validator\ConstraintViolationListInterface;
#[AsController]
class RegisterUserApiPoint
{
public function __construct(
/** @var ExceptionMatcher<ConstraintViolationListInterface> */
#[Autowire(service: ExceptionMatcher::class.'<'.ConstraintViolationListInterface::class.'>')]
private ExceptionMatcher $matcher,
private UserRegistrationServices $services,
) { }
#[Route(
path: '/register',
name: 'user_register',
methods: ['POST'],
)]
public function __invoke(
#[MapRequestPayload] UserRegistration $registration,
): Response {
try {
$registration->process($this->services);
} catch (Throwable $exception) {
return $this->handleError($exception, $registration);
}
return new Response(status: HTTP_CREATED);
}
private function handleError(Throwable $exception, UserRegistration $registration): Response
{
/** @var ?ConstraintViolationListInterface $violationList */
$violationList = $this->matcher->match($exception, $registration);
if (null === $violationList) {
throw $exception;
}
return new JsonResponse($violationList, HTTP_UNPROCESSABLE_ENTITY);
}
}
#[UniqueEntity(
fields: ['login'],
entityClass: User::class,
identifierFieldNames: ['user' => 'id'],
)]
class UserProfileUpdate
{
public string $login;
@@
#[Try_]
class UserProfileUpdate
{
#[Catch_(LoginAlreadyTakenException::class)]
public string $login;
@@
use PhPhD\ExceptionalMatcher\Rule\Object\Try_;
use PhPhD\ExceptionalMatcher\Rule\Object\Property\Catch_;
#[Try_]
class UserProfileUpdate
{
#[Catch_(LoginAlreadyTakenException::class)]
public string $login;
#[Catch_(PasswordCompromisedException::class)]
#[Catch_(PasswordCannotBeReusedException::class)]
public string $password;
public function process(User $user, UserProfileUpdateServices $services): void
{
$userWithTheSameLogin = $services->userRepository->whereLogin($this->login)->firstOrNull();
if ($userWithTheSameLogin?->is($user) === false) {
throw new LoginAlreadyTakenException($this->login);
}
if ($services->passwordSecurity->isCompromised($this->password)) {
throw new PasswordCompromisedException($this->password);
}
// Could throw PasswordCannotBeReusedException
$user->updateProfile($this->login, $this->password);
$services->entityManager->flush();
}
}
use PhPhD\ExceptionalMatcher\Rule\Object\Property\Catch_;
use PhPhD\ExceptionalMatcher\Rule\Object\Try_;
use Symfony\Component\Uid\Exception\InvalidArgumentException as InvalidUidException;
use Symfony\Component\Validator\Exception\ValidationFailedException;
use const PhPhD\ExceptionalMatcher\Rule\Object\Property\Match\Condition\Enum\enum_value;
use const PhPhD\ExceptionalMatcher\Rule\Object\Property\Match\Condition\Uid\uid_value;
use const PhPhD\ExceptionalMatcher\Rule\Object\Property\Match\Condition\Value\exception_value;
use const PhPhD\ExceptionalMatcher\Rule\Object\Property\Match\Condition\Validator\validated_value;
use const PhPhD\ExceptionalMatcher\Validator\Formatter\Validator\validator_violations;
#[Try_]
class ImportProductDto
{
#[Catch_(InvalidUidException::class, match: uid_value, message: 'This is not a valid UUID.')]
public string $id;
#[Catch_(CategoryNotFoundException::class, match: exception_value)] // Message is derived from Exception
public string $categoryId;
#[Catch_(\ValueError::class, from: ProductStatus::class, match: enum_value, message: 'The value you selected is not a valid choice.')]
public string $status;
#[Catch_(ValidationFailedException::class, from: ProductDescription::class, match: validated_value, format: validator_violations)]
public string $description;
#[Catch_(BackorderDisabledForCategoryException::class, if: [self::class, 'thisProductViolatesBackorder'])]
public ?int $backorderLimit;
/**
* Needed in case of deep analysis.
*
* If this method returns TRUE, the exception is linked to $backorderLimit of *this object*;
* otherwise this exception has nothing to do with this object.
*/
public function thisProductViolatesBackorder(BackorderDisabledForCategoryException $exception): bool
{
if ($exception->categoryId !== $this->categoryId) {
return false; // Backorder configuration of the given category has nothing to do with this category.
}
if (null === $this->backorderLimit) {
return false; // The product didn't even enable backorder, much less violated it.
}
return true;
}
}
use PhPhD\ExceptionalMatcher\Rule\Object\Try_;
use PhPhD\ExceptionalMatcher\Rule\Object\Property\Catch_;
use Symfony\Component\Validator\Constraints as Assert;
#[Try_]
class ImportProductBatchDto
{
/** @var ImportProductDto[] */
public array $items;
}
if ($exception->categoryId !== $this->categoryId) {
// not my backpack
}
if (null === $this->backorderLimit) {
// It's not my BackorderDisabledForCategoryException! I didn't enable backorder!
}
use PhPhD\ExceptionalMatcher\Bundle\DependencyInjection\PhdExceptionalMatcherExtension;
use PhPhD\ExceptionalMatcher\ExceptionMatcher;
use PhPhD\ExceptionalMatcher\Exception\MatchedExceptionList;
$container = (new PhdExceptionalMatcherExtension())->getContainer([
// These are not used but still
use PhPhD\ExceptionalMatcher\Upgrade\ExceptionalMatcherSetList;
return RectorConfig::configure()
->withPaths([ __DIR__ . '/src'])
->withImportNames(removeUnusedImports: true)
// Upgrading from your version (e.g. 1.4) to the latest version
->withSets(ExceptionalMatcherSetList::fromVersion('1.4')->getSetList());
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.