Create initial structure and classes

This commit is contained in:
Anton Vakhrushev 2017-03-08 11:37:15 +03:00
commit 4984f44d0a
8 changed files with 1587 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/log/
/vendor/
.php_cs.cache

20
composer.json Normal file
View 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

File diff suppressed because it is too large Load Diff

16
phpunit.xml.dist Normal file
View 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
View 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;
}
}

View 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;
}

View 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;
}
}

View 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());
}
}