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