diff --git a/src/Aspect/AbstractContractAspect.php b/src/Aspect/AbstractContractAspect.php new file mode 100644 index 0000000..14e70e4 --- /dev/null +++ b/src/Aspect/AbstractContractAspect.php @@ -0,0 +1,97 @@ + + * + * This source file is subject to the license that is bundled + * with this source code in the file LICENSE. + */ + +namespace PhpDeal\Aspect; + +use Doctrine\Common\Annotations\Annotation; +use Doctrine\Common\Annotations\Reader; +use DomainException; +use Go\Aop\Intercept\MethodInvocation; +use PhpDeal\Exception\ContractViolation; + +abstract class AbstractContractAspect +{ + /** + * @var Reader + */ + protected $reader; + + /** + * @param Reader $reader Annotation reader + */ + public function __construct(Reader $reader) + { + $this->reader = $reader; + } + + /** + * Returns an associative list of arguments for the method invocation + * + * @param MethodInvocation $invocation + * @return array + */ + protected function fetchMethodArguments(MethodInvocation $invocation) + { + $parameters = $invocation->getMethod()->getParameters(); + $argumentNames = array_map(function (\ReflectionParameter $parameter) { + return $parameter->name; + }, $parameters); + $parameters = array_combine($argumentNames, $invocation->getArguments()); + + return $parameters; + } + + /** + * Performs verification of contracts for given invocation + * + * @param MethodInvocation $invocation Current invocation + * @param array|Annotation[] $contracts Contract annotation + * @param object|string $instance Invocation instance or string for static class + * @param string $scope Scope of method + * @param array $args List of arguments for the method + * + * @throws DomainException + */ + protected function ensureContracts(MethodInvocation $invocation, array $contracts, $instance, $scope, array $args) + { + static $invoker = null; + if (!$invoker) { + $invoker = function () { + extract(func_get_arg(0)); + + return eval('return ' . func_get_arg(1) . '; ?>'); + }; + } + + $instance = is_object($instance) ? $instance : null; + $boundInvoker = $invoker->bindTo($instance, $scope); + + foreach ($contracts as $contract) { + $contractExpression = $contract->value; + try { + $invocationResult = $boundInvoker->__invoke($args, $contractExpression); + + // we accept as a result only true or null + // null may be a result of assertions from beberlei/assert which passed + if ($invocationResult !== null && $invocationResult !== true) { + $errorMessage = 'Invalid return value received from the assertion body,' + . ' only boolean or void can be returned'; + throw new DomainException($errorMessage); + } + + } catch (\Error $internalError) { + // PHP-7 friendly interceptor for fatal errors + throw new ContractViolation($invocation, $contractExpression, $internalError); + } catch (\Exception $internalException) { + throw new ContractViolation($invocation, $contractExpression, $internalException); + } + } + } +} diff --git a/src/Aspect/InvariantCheckerAspect.php b/src/Aspect/InvariantCheckerAspect.php index b78d44e..e10bb8a 100644 --- a/src/Aspect/InvariantCheckerAspect.php +++ b/src/Aspect/InvariantCheckerAspect.php @@ -13,20 +13,23 @@ use Doctrine\Common\Annotations\Reader; use Go\Aop\Aspect; use Go\Aop\Intercept\MethodInvocation; -use PhpDeal\Contract\InvariantContract; +use PhpDeal\Annotation\Invariant; +use PhpDeal\Contract\Fetcher\ParentClass\InvariantFetcher; use PhpDeal\Exception\ContractViolation; use Go\Lang\Annotation\Around; +use ReflectionClass; -class InvariantCheckerAspect implements Aspect +class InvariantCheckerAspect extends AbstractContractAspect implements Aspect { /** - * @var InvariantContract + * @var InvariantFetcher */ - private $contractChecker; + private $invariantFetcher; public function __construct(Reader $reader) { - $this->contractChecker = new InvariantContract($reader); + parent::__construct($reader); + $this->invariantFetcher = new InvariantFetcher(Invariant::class, $reader); } /** @@ -40,6 +43,35 @@ public function __construct(Reader $reader) */ public function invariantContract(MethodInvocation $invocation) { - return $this->contractChecker->check($invocation); + $object = $invocation->getThis(); + $args = $this->fetchMethodArguments($invocation); + $class = $invocation->getMethod()->getDeclaringClass(); + if ($class->isCloneable()) { + $args['__old'] = clone $object; + } + + $result = $invocation->proceed(); + $args['__result'] = $result; + + $allContracts = $this->fetchAllContracts($class); + $this->ensureContracts($invocation, $allContracts, $object, $class->name, $args); + + return $result; + } + + /** + * @param ReflectionClass $class + * @return array + */ + private function fetchAllContracts(ReflectionClass $class) + { + $allContracts = $this->invariantFetcher->getConditions($class); + foreach ($this->reader->getClassAnnotations($class) as $annotation) { + if ($annotation instanceof Invariant) { + $allContracts[] = $annotation; + } + } + + return array_unique($allContracts); } } diff --git a/src/Aspect/PostconditionCheckerAspect.php b/src/Aspect/PostconditionCheckerAspect.php index b125f92..a24c5c3 100644 --- a/src/Aspect/PostconditionCheckerAspect.php +++ b/src/Aspect/PostconditionCheckerAspect.php @@ -13,20 +13,22 @@ use Doctrine\Common\Annotations\Reader; use Go\Aop\Aspect; use Go\Aop\Intercept\MethodInvocation; -use PhpDeal\Contract\PostconditionContract; +use PhpDeal\Annotation\Ensure; +use PhpDeal\Contract\Fetcher\ParentClass\MethodConditionFetcher; use PhpDeal\Exception\ContractViolation; use Go\Lang\Annotation\Around; -class PostconditionCheckerAspect implements Aspect +class PostconditionCheckerAspect extends AbstractContractAspect implements Aspect { /** - * @var PostconditionContract + * @var MethodConditionFetcher */ - private $contractChecker; + private $methodConditionFetcher; public function __construct(Reader $reader) { - $this->contractChecker = new PostconditionContract($reader); + parent::__construct($reader); + $this->methodConditionFetcher = new MethodConditionFetcher(Ensure::class, $reader); } /** @@ -40,6 +42,47 @@ public function __construct(Reader $reader) */ public function postConditionContract(MethodInvocation $invocation) { - return $this->contractChecker->check($invocation); + $object = $invocation->getThis(); + $args = $this->fetchMethodArguments($invocation); + $class = $invocation->getMethod()->getDeclaringClass(); + if ($class->isCloneable()) { + $args['__old'] = clone $object; + } + + $result = $invocation->proceed(); + $args['__result'] = $result; + $allContracts = $this->fetchAllContracts($invocation); + + $this->ensureContracts($invocation, $allContracts, $object, $class->name, $args); + + return $result; + } + + /** + * @param MethodInvocation $invocation + * @return array + */ + private function fetchAllContracts(MethodInvocation $invocation) + { + $allContracts = $this->fetchParentsContracts($invocation); + foreach ($invocation->getMethod()->getAnnotations() as $annotation) { + if ($annotation instanceof Ensure) { + $allContracts[] = $annotation; + } + } + + return array_unique($allContracts); + } + + /** + * @param MethodInvocation $invocation + * @return array + */ + private function fetchParentsContracts(MethodInvocation $invocation) + { + return $this->methodConditionFetcher->getConditions( + $invocation->getMethod()->getDeclaringClass(), + $invocation->getMethod()->name + ); } } diff --git a/src/Aspect/PreconditionCheckerAspect.php b/src/Aspect/PreconditionCheckerAspect.php index 2bc7aec..4346d07 100644 --- a/src/Aspect/PreconditionCheckerAspect.php +++ b/src/Aspect/PreconditionCheckerAspect.php @@ -13,20 +13,22 @@ use Doctrine\Common\Annotations\Reader; use Go\Aop\Aspect; use Go\Aop\Intercept\MethodInvocation; -use PhpDeal\Contract\PreconditionContract; +use PhpDeal\Annotation\Verify; +use PhpDeal\Contract\Fetcher\ParentClass\MethodConditionWithInheritDocFetcher; use PhpDeal\Exception\ContractViolation; use Go\Lang\Annotation\Before; -class PreconditionCheckerAspect implements Aspect +class PreconditionCheckerAspect extends AbstractContractAspect implements Aspect { /** - * @var PreconditionContract + * @var MethodConditionWithInheritDocFetcher */ - private $contractChecker; + private $methodConditionFetcher; public function __construct(Reader $reader) { - $this->contractChecker = new PreconditionContract($reader); + parent::__construct($reader); + $this->methodConditionFetcher = new MethodConditionWithInheritDocFetcher(Verify::class, $reader); } /** @@ -39,6 +41,40 @@ public function __construct(Reader $reader) */ public function preConditionContract(MethodInvocation $invocation) { - $this->contractChecker->check($invocation); + $object = $invocation->getThis(); + $args = $this->fetchMethodArguments($invocation); + $scope = $invocation->getMethod()->getDeclaringClass()->name; + + $allContracts = $this->fetchAllContracts($invocation); + $this->ensureContracts($invocation, $allContracts, $object, $scope, $args); + } + + /** + * @param MethodInvocation $invocation + * @return array + */ + private function fetchAllContracts(MethodInvocation $invocation) + { + $allContracts = $this->fetchParentsContracts($invocation); + + foreach ($invocation->getMethod()->getAnnotations() as $annotation) { + if ($annotation instanceof Verify) { + $allContracts[] = $annotation; + } + } + + return array_unique($allContracts); + } + + /** + * @param MethodInvocation $invocation + * @return array + */ + private function fetchParentsContracts(MethodInvocation $invocation) + { + return $this->methodConditionFetcher->getConditions( + $invocation->getMethod()->getDeclaringClass(), + $invocation->getMethod()->name + ); } } diff --git a/src/Contract/Contract.php b/src/Contract/Contract.php deleted file mode 100644 index 04bba17..0000000 --- a/src/Contract/Contract.php +++ /dev/null @@ -1,101 +0,0 @@ - - * - * This source file is subject to the license that is bundled - * with this source code in the file LICENSE. - */ - -namespace PhpDeal\Contract; - -use Doctrine\Common\Annotations\Annotation; -use Doctrine\Common\Annotations\Reader; -use DomainException; -use Go\Aop\Intercept\MethodInvocation; -use PhpDeal\Contract\Fetcher\MethodArgument; -use PhpDeal\Exception\ContractViolation; - -abstract class Contract -{ - /** - * @var Reader - */ - protected $reader; - - /** - * @param Reader $reader Annotation reader - */ - public function __construct(Reader $reader) - { - $this->reader = $reader; - } - - /** - * @param MethodInvocation $invocation - * @return array - */ - protected function getMethodArguments(MethodInvocation $invocation) - { - return (new MethodArgument())->fetch($invocation); - } - - /** - * @param array $allContracts - * @return array - */ - protected function makeContractsUnique(array $allContracts) - { - return array_unique($allContracts); - } - - /** - * @param array $allContracts - * @param object|string $instance - * @param string $scope - * @param array $args - * @param MethodInvocation $invocation - */ - protected function fulfillContracts($allContracts, $instance, $scope, array $args, MethodInvocation $invocation) - { - foreach ($allContracts as $contract) { - try { - $this->ensureContractSatisfied($instance, $scope, $args, $contract); - } catch (\Exception $e) { - throw new ContractViolation($invocation, $contract->value, $e); - } - } - } - - /** - * Returns a result of contract verification - * - * @param object|string $instance Invocation instance or string for static class - * @param string $scope Scope of method - * @param array $args List of arguments for the method - * @param Annotation $annotation Contract annotation - * @throws DomainException - */ - public function ensureContractSatisfied($instance, $scope, array $args, $annotation) - { - static $invoker = null; - if (!$invoker) { - $invoker = function () { - extract(func_get_arg(0)); - - return eval('return ' . func_get_arg(1) . '; ?>'); - }; - } - - $instance = is_object($instance) ? $instance : null; - $invocationResult = $invoker->bindTo($instance, $scope)->__invoke($args, $annotation->value); - - // we accept as a result only true or null - // null may be a result of assertions from beberlei/assert which passed - if ($invocationResult !== null && $invocationResult !== true) { - $errorMessage = 'Invalid return value received from the assertion body, only boolean or void accepted'; - throw new DomainException($errorMessage); - } - } -} diff --git a/src/Contract/Fetcher/MethodArgument.php b/src/Contract/Fetcher/MethodArgument.php deleted file mode 100644 index f1329d5..0000000 --- a/src/Contract/Fetcher/MethodArgument.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * This source file is subject to the license that is bundled - * with this source code in the file LICENSE. - */ - -namespace PhpDeal\Contract\Fetcher; - -use Go\Aop\Intercept\MethodInvocation; - -class MethodArgument -{ - /** - * Returns an associative list of arguments for the method invocation - * - * @param MethodInvocation $invocation - * @return array - */ - public function fetch(MethodInvocation $invocation) - { - $parameters = $invocation->getMethod()->getParameters(); - $argumentNames = array_map(function (\ReflectionParameter $parameter) { - return $parameter->name; - }, $parameters); - $parameters = array_combine($argumentNames, $invocation->getArguments()); - - return $parameters; - } -} diff --git a/src/Contract/Fetcher/ParentClass/Fetcher.php b/src/Contract/Fetcher/ParentClass/AbstractFetcher.php similarity index 60% rename from src/Contract/Fetcher/ParentClass/Fetcher.php rename to src/Contract/Fetcher/ParentClass/AbstractFetcher.php index b7e31fb..1727bee 100644 --- a/src/Contract/Fetcher/ParentClass/Fetcher.php +++ b/src/Contract/Fetcher/ParentClass/AbstractFetcher.php @@ -10,31 +10,42 @@ namespace PhpDeal\Contract\Fetcher\ParentClass; -class Fetcher +use Doctrine\Common\Annotations\Reader; + +abstract class AbstractFetcher { /** * @var string */ protected $expectedAnnotationType; + /** + * @var Reader + */ + protected $annotationReader; + /** * @param string $expectedAnnotationType + * @param Reader $reader */ - public function __construct($expectedAnnotationType) + public function __construct($expectedAnnotationType, Reader $reader) { $this->expectedAnnotationType = $expectedAnnotationType; + $this->annotationReader = $reader; } /** + * Performs filtering of annotations by the requested class name + * * @param array $annotations * @return array */ - protected function getContractAnnotations(array $annotations) + protected function filterContractAnnotation(array $annotations) { $contractAnnotations = []; foreach ($annotations as $annotation) { - if (is_a($annotation, $this->expectedAnnotationType)) { + if ($annotation instanceof $this->expectedAnnotationType) { $contractAnnotations[] = $annotation; } } diff --git a/src/Contract/Fetcher/ParentClass/InvariantFetcher.php b/src/Contract/Fetcher/ParentClass/InvariantFetcher.php index bee48d4..7638452 100644 --- a/src/Contract/Fetcher/ParentClass/InvariantFetcher.php +++ b/src/Contract/Fetcher/ParentClass/InvariantFetcher.php @@ -10,29 +10,30 @@ namespace PhpDeal\Contract\Fetcher\ParentClass; -use Doctrine\Common\Annotations\Reader; use ReflectionClass; -class InvariantFetcher extends Fetcher +class InvariantFetcher extends AbstractFetcher { /** + * Fetches conditions from all parent classes recursively + * * @param ReflectionClass $class - * @param Reader $reader - * @param array $contracts + * * @return array */ - public function getConditions(ReflectionClass $class, Reader $reader, array $contracts = []) + public function getConditions(ReflectionClass $class) { - $parentClass = $class->getParentClass(); - - if (!$parentClass) { - return $contracts; + $annotations = []; + $parentClasses = []; + while ($class = $class->getParentClass()) { + $parentClasses[] = $class; } - $annotations = $reader->getClassAnnotations($parentClass); - $contractAnnotations = $this->getContractAnnotations($annotations); - $contracts = array_merge($contracts, $contractAnnotations); + foreach ($parentClasses as $parentClass) { + $annotations = array_merge($annotations, $this->annotationReader->getClassAnnotations($parentClass)); + } + $contracts = $this->filterContractAnnotation($annotations); - return $this->getConditions($parentClass, $reader, $contracts); + return $contracts; } } diff --git a/src/Contract/Fetcher/ParentClass/MethodConditionFetcher.php b/src/Contract/Fetcher/ParentClass/MethodConditionFetcher.php index c654fe9..87d6069 100644 --- a/src/Contract/Fetcher/ParentClass/MethodConditionFetcher.php +++ b/src/Contract/Fetcher/ParentClass/MethodConditionFetcher.php @@ -10,31 +10,31 @@ namespace PhpDeal\Contract\Fetcher\ParentClass; -use Doctrine\Common\Annotations\Reader; use ReflectionClass; -class MethodConditionFetcher extends Fetcher +class MethodConditionFetcher extends AbstractFetcher { /** + * Fetches conditions from all parent method prototypes recursively + * * @param ReflectionClass $class - * @param Reader $reader * @param string $methodName - * @param array $contracts + * * @return array */ - public function getConditions(ReflectionClass $class, Reader $reader, $methodName, array $contracts = []) + public function getConditions(ReflectionClass $class, $methodName) { - $parentClass = $class->getParentClass(); - - if (!$parentClass) { - return $contracts; + $annotations = []; + $parentMethods = []; + while (($class = $class->getParentClass()) && $class->hasMethod($methodName)) { + $parentMethods[] = $class->getMethod($methodName); } - $parentMethod = $parentClass->getMethod($methodName); - $annotations = $reader->getMethodAnnotations($parentMethod); - $contractAnnotations = $this->getContractAnnotations($annotations); - $contracts = array_merge($contracts, $contractAnnotations); + foreach ($parentMethods as $parentMethod) { + $annotations = array_merge($annotations, $this->annotationReader->getMethodAnnotations($parentMethod)); + } + $contracts = $this->filterContractAnnotation($annotations); - return $this->getConditions($parentClass, $reader, $methodName, $contracts); + return $contracts; } } diff --git a/src/Contract/Fetcher/ParentClass/MethodConditionWithInheritDocFetcher.php b/src/Contract/Fetcher/ParentClass/MethodConditionWithInheritDocFetcher.php index 8803bfb..7d70388 100644 --- a/src/Contract/Fetcher/ParentClass/MethodConditionWithInheritDocFetcher.php +++ b/src/Contract/Fetcher/ParentClass/MethodConditionWithInheritDocFetcher.php @@ -10,60 +10,35 @@ namespace PhpDeal\Contract\Fetcher\ParentClass; -use Doctrine\Common\Annotations\Reader; use ReflectionClass; -use ReflectionMethod; -class MethodConditionWithInheritDocFetcher extends Fetcher +class MethodConditionWithInheritDocFetcher extends AbstractFetcher { /** + * Fetches conditions from all parent method prototypes recursively + * * @param ReflectionClass $class - * @param Reader $reader * @param string $methodName - * @param array $contracts + * * @return array */ - public function getConditions(ReflectionClass $class, Reader $reader, $methodName, array $contracts = []) + public function getConditions(ReflectionClass $class, $methodName) { - if ($this->hasInheritDoc($class->getMethod($methodName))) { - return $this->getConditionsWithInheritDoc($class, $reader, $methodName, $contracts); + $annotations = []; + $parentMethods = []; + while ( + preg_match('/\@inheritdoc/i', $class->getMethod($methodName)->getDocComment()) + && ($class = $class->getParentClass()) + && $class->hasMethod($methodName) + ) { + $parentMethods[] = $class->getMethod($methodName); } - return $contracts; - } - - /** - * @param ReflectionClass $class - * @param Reader $reader - * @param string $methodName - * @param array $contracts - * @return array - */ - private function getConditionsWithInheritDoc(ReflectionClass $class, Reader $reader, $methodName, array $contracts) - { - $parentClass = $class->getParentClass(); - if (!$parentClass) { - return $contracts; - } - - $parentMethod = $parentClass->getMethod($methodName); - $annotations = $reader->getMethodAnnotations($parentMethod); - $contractAnnotations = $this->getContractAnnotations($annotations); - $contracts = array_merge($contracts, $contractAnnotations); - - if ($this->hasInheritDoc($parentMethod)) { - return $this->getConditionsWithInheritDoc($parentClass, $reader, $methodName, $contracts); + foreach ($parentMethods as $parentMethod) { + $annotations = array_merge($annotations, $this->annotationReader->getMethodAnnotations($parentMethod)); } + $contracts = $this->filterContractAnnotation($annotations); return $contracts; } - - /** - * @param ReflectionMethod $method - * @return bool - */ - private function hasInheritDoc(ReflectionMethod $method) - { - return preg_match('/\@inheritdoc/i', $method->getDocComment()) > 0; - } } diff --git a/src/Contract/InvariantContract.php b/src/Contract/InvariantContract.php deleted file mode 100644 index 2e179d8..0000000 --- a/src/Contract/InvariantContract.php +++ /dev/null @@ -1,86 +0,0 @@ - - * - * This source file is subject to the license that is bundled - * with this source code in the file LICENSE. - */ - -namespace PhpDeal\Contract; - -use Doctrine\Common\Annotations\Reader; -use Go\Aop\Intercept\MethodInvocation; -use PhpDeal\Contract\Fetcher\ParentClass\InvariantFetcher; -use PhpDeal\Exception\ContractViolation; -use PhpDeal\Annotation\Invariant; -use ReflectionClass; - -class InvariantContract extends Contract -{ - /** - * @var InvariantFetcher - */ - private $invariantFetcher; - - public function __construct(Reader $reader) - { - parent::__construct($reader); - $this->invariantFetcher = new InvariantFetcher(Invariant::class); - } - - /** - * Verifies invariants for contract class - * - * @Around("@within(PhpDeal\Annotation\Invariant) && execution(public **->*(*))") - * @param MethodInvocation $invocation - * @throws ContractViolation - * @return mixed - */ - public function check(MethodInvocation $invocation) - { - $object = $invocation->getThis(); - $args = $this->getMethodArguments($invocation); - $class = $invocation->getMethod()->getDeclaringClass(); - if ($class->isCloneable()) { - $args['__old'] = clone $object; - } - - $result = $invocation->proceed(); - $args['__result'] = $result; - - $allContracts = $this->makeContractsUnique($this->fetchAllContracts($class)); - $this->fulfillContracts($allContracts, $object, $class->name, $args, $invocation); - - return $result; - } - - /** - * @param ReflectionClass $class - * @return array - */ - private function fetchAllContracts(ReflectionClass $class) - { - $allContracts = $this->fetchParentsContracts($class); - foreach ($this->reader->getClassAnnotations($class) as $annotation) { - if ($annotation instanceof Invariant) { - $allContracts[] = $annotation; - } - } - - return $allContracts; - } - - /** - * @param ReflectionClass $class - * @return array - */ - private function fetchParentsContracts(ReflectionClass $class) - { - return $this->invariantFetcher->getConditions( - $class, - $this->reader - ); - } -} diff --git a/src/Contract/PostconditionContract.php b/src/Contract/PostconditionContract.php deleted file mode 100644 index cf93e5e..0000000 --- a/src/Contract/PostconditionContract.php +++ /dev/null @@ -1,83 +0,0 @@ - - * - * This source file is subject to the license that is bundled - * with this source code in the file LICENSE. - */ - -namespace PhpDeal\Contract; - -use Doctrine\Common\Annotations\Reader; -use Go\Aop\Intercept\MethodInvocation; -use PhpDeal\Contract\Fetcher\ParentClass\MethodConditionFetcher; -use PhpDeal\Exception\ContractViolation; -use PhpDeal\Annotation\Ensure; - -class PostconditionContract extends Contract -{ - /** - * @var MethodConditionFetcher - */ - private $methodConditionFetcher; - - public function __construct(Reader $reader) - { - parent::__construct($reader); - $this->methodConditionFetcher = new MethodConditionFetcher(Ensure::class); - } - - /** - * @param MethodInvocation $invocation - * @throws ContractViolation - * @return mixed - */ - public function check(MethodInvocation $invocation) - { - $object = $invocation->getThis(); - $args = $this->getMethodArguments($invocation); - $class = $invocation->getMethod()->getDeclaringClass(); - if ($class->isCloneable()) { - $args['__old'] = clone $object; - } - - $result = $invocation->proceed(); - $args['__result'] = $result; - $allContracts = $this->makeContractsUnique($this->fetchAllContracts($invocation)); - - $this->fulfillContracts($allContracts, $object, $class->name, $args, $invocation); - - return $result; - } - - /** - * @param MethodInvocation $invocation - * @return array - */ - private function fetchAllContracts(MethodInvocation $invocation) - { - $allContracts = $this->fetchParentsContracts($invocation); - foreach ($invocation->getMethod()->getAnnotations() as $annotation) { - if ($annotation instanceof Ensure) { - $allContracts[] = $annotation; - } - } - - return $allContracts; - } - - /** - * @param MethodInvocation $invocation - * @return array - */ - private function fetchParentsContracts(MethodInvocation $invocation) - { - return $this->methodConditionFetcher->getConditions( - $invocation->getMethod()->getDeclaringClass(), - $this->reader, - $invocation->getMethod()->name - ); - } -} diff --git a/src/Contract/PreconditionContract.php b/src/Contract/PreconditionContract.php deleted file mode 100644 index c2ad95c..0000000 --- a/src/Contract/PreconditionContract.php +++ /dev/null @@ -1,76 +0,0 @@ - - * - * This source file is subject to the license that is bundled - * with this source code in the file LICENSE. - */ - -namespace PhpDeal\Contract; - -use Doctrine\Common\Annotations\Reader; -use Go\Aop\Intercept\MethodInvocation; -use PhpDeal\Contract\Fetcher\ParentClass\MethodConditionWithInheritDocFetcher; -use PhpDeal\Exception\ContractViolation; -use PhpDeal\Annotation\Verify; - -class PreconditionContract extends Contract -{ - /** - * @var MethodConditionWithInheritDocFetcher - */ - private $methodConditionFetcher; - - public function __construct(Reader $reader) - { - parent::__construct($reader); - $this->methodConditionFetcher = new MethodConditionWithInheritDocFetcher(Verify::class); - } - - /** - * @param MethodInvocation $invocation - * @Before("@execution(PhpDeal\Annotation\Verify)") - * @throws ContractViolation - */ - public function check(MethodInvocation $invocation) - { - $object = $invocation->getThis(); - $args = $this->getMethodArguments($invocation); - $scope = $invocation->getMethod()->getDeclaringClass()->name; - - $allContracts = $this->makeContractsUnique($this->fetchAllContracts($invocation)); - $this->fulfillContracts($allContracts, $object, $scope, $args, $invocation); - } - - /** - * @param MethodInvocation $invocation - * @return array - */ - private function fetchAllContracts(MethodInvocation $invocation) - { - $allContracts = $this->fetchParentsContracts($invocation); - - foreach ($invocation->getMethod()->getAnnotations() as $annotation) { - if ($annotation instanceof Verify) { - $allContracts[] = $annotation; - } - } - - return $allContracts; - } - - /** - * @param MethodInvocation $invocation - * @return array - */ - private function fetchParentsContracts(MethodInvocation $invocation) - { - return $this->methodConditionFetcher->getConditions( - $invocation->getMethod()->getDeclaringClass(), - $this->reader, - $invocation->getMethod()->name - ); - } -}