Create initial structure and classes
This commit is contained in:
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | /log/ | ||||||
|  | /vendor/ | ||||||
|  |  | ||||||
|  | .php_cs.cache | ||||||
							
								
								
									
										20
									
								
								composer.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								composer.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | { | ||||||
|  |     "name": "anwinged/reason", | ||||||
|  |     "type": "library", | ||||||
|  |     "require": {}, | ||||||
|  |     "require-dev": { | ||||||
|  |         "phpunit/phpunit": "^6.0" | ||||||
|  |     }, | ||||||
|  |     "license": "MIT", | ||||||
|  |     "authors": [ | ||||||
|  |         { | ||||||
|  |             "name": "Anton Vakhrushev", | ||||||
|  |             "email": "anwinged@ya.ru" | ||||||
|  |         } | ||||||
|  |     ], | ||||||
|  |     "autoload": { | ||||||
|  |         "psr-4": { | ||||||
|  |             "Anwinged\\Reason\\": "src/" | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										1276
									
								
								composer.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										1276
									
								
								composer.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										16
									
								
								phpunit.xml.dist
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								phpunit.xml.dist
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | <phpunit bootstrap="vendor/autoload.php"> | ||||||
|  |     <testsuites> | ||||||
|  |         <testsuite name="reason"> | ||||||
|  |             <directory>tests</directory> | ||||||
|  |         </testsuite> | ||||||
|  |     </testsuites> | ||||||
|  |     <filter> | ||||||
|  |         <whitelist> | ||||||
|  |             <directory suffix=".php">src</directory> | ||||||
|  |         </whitelist> | ||||||
|  |     </filter> | ||||||
|  |     <logging> | ||||||
|  |         <log type="coverage-html" target="log/coverage" /> | ||||||
|  |         <log type="testdox-html" target="log/testdox.html" /> | ||||||
|  |     </logging> | ||||||
|  | </phpunit> | ||||||
							
								
								
									
										119
									
								
								src/Reason.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								src/Reason.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace Anwinged\Reason; | ||||||
|  |  | ||||||
|  | class Reason | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @var ReasonStatusInterface | ||||||
|  |      */ | ||||||
|  |     private $status; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string[] | ||||||
|  |      */ | ||||||
|  |     private $messages; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param ReasonStatusInterface $status | ||||||
|  |      * @param string[]              $messages | ||||||
|  |      */ | ||||||
|  |     public function __construct(ReasonStatusInterface $status, array $messages) | ||||||
|  |     { | ||||||
|  |         $this->status = $status; | ||||||
|  |         $this->messages = $messages; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Clones the reason. | ||||||
|  |      */ | ||||||
|  |     public function __clone() | ||||||
|  |     { | ||||||
|  |         $this->status = clone $this->status; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return ReasonStatusInterface | ||||||
|  |      */ | ||||||
|  |     public function getStatus(): ReasonStatusInterface | ||||||
|  |     { | ||||||
|  |         return clone $this->status; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return string[] | ||||||
|  |      */ | ||||||
|  |     public function getMessages(): array | ||||||
|  |     { | ||||||
|  |         return $this->messages; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Appends reason to current and returns new reason. | ||||||
|  |      * | ||||||
|  |      * Reason with highest weighs wins. | ||||||
|  |      * | ||||||
|  |      * If other reason has highest weight, then it will be returned without changes. | ||||||
|  |      * If weights are equal, then messages will be merged. Otherwise, | ||||||
|  |      * returns current reason. | ||||||
|  |      * | ||||||
|  |      * Don't change original objects. | ||||||
|  |      * | ||||||
|  |      * @param Reason $other | ||||||
|  |      * | ||||||
|  |      * @return self | ||||||
|  |      */ | ||||||
|  |     public function andX(Reason $other): self | ||||||
|  |     { | ||||||
|  |         if ($other->getStatus()->getWeight() > $this->status->getWeight()) { | ||||||
|  |             return clone $other; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($other->getStatus()->getWeight() === $this->status->getWeight()) { | ||||||
|  |             return $this->withMessages($other->getMessages()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return clone $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Join reason to current and return new reason. | ||||||
|  |      * | ||||||
|  |      * Reason with lowest weight wins. | ||||||
|  |      * | ||||||
|  |      * If other reason has lowest weight, then it will be returned without changes. | ||||||
|  |      * If weights are equal, then messages will be merged. Otherwise, | ||||||
|  |      * returns current reason. | ||||||
|  |      * | ||||||
|  |      * @param Reason $other | ||||||
|  |      * | ||||||
|  |      * @return self | ||||||
|  |      */ | ||||||
|  |     public function orX(Reason $other): self | ||||||
|  |     { | ||||||
|  |         if ($other->getStatus()->getWeight() < $this->status->getWeight()) { | ||||||
|  |             return clone $other; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($other->getStatus()->getWeight() === $this->status->getWeight()) { | ||||||
|  |             return $this->withMessages($other->getMessages()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return clone $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string[] $messages | ||||||
|  |      * | ||||||
|  |      * @return self | ||||||
|  |      */ | ||||||
|  |     private function withMessages(array $messages): self | ||||||
|  |     { | ||||||
|  |         $reason = clone $this; | ||||||
|  |         $reason->messages = array_merge($reason->messages, $messages); | ||||||
|  |  | ||||||
|  |         return $reason; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								src/ReasonStatusInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/ReasonStatusInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace Anwinged\Reason; | ||||||
|  |  | ||||||
|  | interface ReasonStatusInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public function isSuccess(): bool; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public function isFail(): bool; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return int | ||||||
|  |      */ | ||||||
|  |     public function getWeight(): int; | ||||||
|  | } | ||||||
							
								
								
									
										47
									
								
								src/Status/BooleanStatus.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/Status/BooleanStatus.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace Anwinged\Reason\Status; | ||||||
|  |  | ||||||
|  | use Anwinged\Reason\ReasonStatusInterface; | ||||||
|  |  | ||||||
|  | class BooleanStatus implements ReasonStatusInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @var bool | ||||||
|  |      */ | ||||||
|  |     private $value; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param bool $value | ||||||
|  |      */ | ||||||
|  |     public function __construct(bool $value) | ||||||
|  |     { | ||||||
|  |         $this->value = $value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public function isSuccess(): bool | ||||||
|  |     { | ||||||
|  |         return $this->value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public function isFail(): bool | ||||||
|  |     { | ||||||
|  |         return !$this->value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return int | ||||||
|  |      */ | ||||||
|  |     public function getWeight(): int | ||||||
|  |     { | ||||||
|  |         return $this->value ? 0 : 1; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										82
									
								
								tests/BooleanReasonTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								tests/BooleanReasonTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace Anwinged\Reason; | ||||||
|  |  | ||||||
|  | use Anwinged\Reason\Status\BooleanStatus; | ||||||
|  | use PHPUnit\Framework\TestCase; | ||||||
|  |  | ||||||
|  | class BooleanReasonTest extends TestCase | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @var Reason | ||||||
|  |      */ | ||||||
|  |     private $trueReason; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var Reason | ||||||
|  |      */ | ||||||
|  |     private $falseReason; | ||||||
|  |  | ||||||
|  |     public function setUp() | ||||||
|  |     { | ||||||
|  |         $this->trueReason = new Reason(new BooleanStatus(true), ['yes', 'ok']); | ||||||
|  |         $this->falseReason = new Reason(new BooleanStatus(false), ['no', 'fail']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testCanBeCloned() | ||||||
|  |     { | ||||||
|  |         $cloned = clone $this->trueReason; | ||||||
|  |  | ||||||
|  |         $this->assertNotSame($cloned, $this->trueReason); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testCanBeAppended() | ||||||
|  |     { | ||||||
|  |         $first = $this->trueReason->orX($this->falseReason); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($first->getStatus()->isSuccess()); | ||||||
|  |         $this->assertEquals(['yes', 'ok'], $first->getMessages()); | ||||||
|  |  | ||||||
|  |         $second = $this->falseReason->orX($this->trueReason); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($second->getStatus()->isSuccess()); | ||||||
|  |         $this->assertEquals(['yes', 'ok'], $second->getMessages()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testCanBeJoined() | ||||||
|  |     { | ||||||
|  |         $first = $this->trueReason->andX($this->falseReason); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($first->getStatus()->isFail()); | ||||||
|  |         $this->assertEquals(['no', 'fail'], $first->getMessages()); | ||||||
|  |  | ||||||
|  |         $second = $this->falseReason->andX($this->trueReason); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($second->getStatus()->isFail()); | ||||||
|  |         $this->assertEquals(['no', 'fail'], $second->getMessages()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testMessageMergedWhileReasonsAppended() | ||||||
|  |     { | ||||||
|  |         $first = new Reason(new BooleanStatus(true), ['yes', 'ok']); | ||||||
|  |         $second = new Reason(new BooleanStatus(true), ['good', 'success']); | ||||||
|  |  | ||||||
|  |         $appended = $first->orX($second); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($appended->getStatus()->isSuccess()); | ||||||
|  |         $this->assertEquals(['yes', 'ok', 'good', 'success'], $appended->getMessages()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testMessageMergedWhileReasonsJoined() | ||||||
|  |     { | ||||||
|  |         $first = new Reason(new BooleanStatus(true), ['yes', 'ok']); | ||||||
|  |         $second = new Reason(new BooleanStatus(true), ['good', 'success']); | ||||||
|  |  | ||||||
|  |         $joined = $first->andX($second); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($joined->getStatus()->isSuccess()); | ||||||
|  |         $this->assertEquals(['yes', 'ok', 'good', 'success'], $joined->getMessages()); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user