daikon-cqrs/interop

View on GitHub
src/LazyAssertion.php

Summary

Maintainability
A
0 mins
Test Coverage
F
0%
<?php declare(strict_types=1);
/**
 * This file is part of the daikon-cqrs/interop project.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Daikon\Interop;

use Assert\AssertionChain;
use Assert\LazyAssertion as BaseLazyAssertion;
use LogicException;

class LazyAssertion extends BaseLazyAssertion
{
    /** @var bool */
    private $currentChainFailed = false;

    /** @var bool */
    private $alwaysTryAll = false;

    /** @var bool */
    private $thisChainTryAll = false;

    /** @var null|AssertionChain */
    private $currentChain;

    /** @var array */
    private $errors = [];

    /** @var string The class to use as AssertionChain factory */
    private $assertClass = Assert::class;

    /** @var string|LazyAssertionException The class to use for exceptions */
    private $exceptionClass = LazyAssertionException::class;

    /**
     * @param mixed $value
     * @param string|callable|null $defaultMessage
     * @return static
     */
    public function that($value, string $propertyPath = null, $defaultMessage = null)
    {
        $this->currentChainFailed = false;
        $this->thisChainTryAll = false;
        $assertClass = $this->assertClass;
        $this->currentChain = $assertClass::that($value, $defaultMessage, $propertyPath);

        return $this;
    }

    /** @return static */
    public function tryAll()
    {
        if (!$this->currentChain) {
            $this->alwaysTryAll = true;
        }

        $this->thisChainTryAll = true;

        return $this;
    }

    /**
     * @param string $method
     * @param array $args
     * @return static
     */
    public function __call($method, $args)
    {
        if (false === $this->alwaysTryAll
            && false === $this->thisChainTryAll
            && true === $this->currentChainFailed
        ) {
            return $this;
        }

        try {
            call_user_func_array([$this->currentChain, $method], $args);
        } catch (AssertionFailedException $e) {
            $this->errors[] = $e;
            $this->currentChainFailed = true;
        }

        return $this;
    }

    /** @throws LazyAssertionException */
    public function verifyNow(): bool
    {
        if ($this->errors) {
            throw call_user_func([$this->exceptionClass, 'fromErrors'], $this->errors);
        }

        return true;
    }

    /** @return static */
    public function setAssertClass(string $className): LazyAssertion
    {
        if (Assert::class !== $className && !is_subclass_of($className, Assert::class)) {
            throw new LogicException($className.' is not (a subclass of) '.Assert::class);
        }

        $this->assertClass = $className;

        return $this;
    }

    /** @return static */
    public function setExceptionClass(string $className): LazyAssertion
    {
        if (LazyAssertionException::class !== $className
            && !is_subclass_of($className, LazyAssertionException::class)
        ) {
            throw new LogicException($className.' is not (a subclass of) '.LazyAssertionException::class);
        }

        $this->exceptionClass = $className;

        return $this;
    }
}