Create initial structure and classes
This commit is contained in:
commit
4984f44d0a
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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user