Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fix-permission: ## fix permission for docker env

.PHONY: build
build: ## build environment and initialize composer and project dependencies
docker build .docker/php$(DOCKER_PHP_VERSION)-cli/ -t $(DOCKER_SERVER_HOST):$(DOCKER_SERVER_PORT)/$(DOCKER_PROJECT_PATH)/php$(DOCKER_PHP_VERSION)-cli:$(DOCKER_IMAGE_VERSION) \
docker build .docker/php$(DOCKER_PHP_VERSION)-dev/ -t $(DOCKER_SERVER_HOST):$(DOCKER_SERVER_PORT)/$(DOCKER_PROJECT_PATH)/php$(DOCKER_PHP_VERSION)-dev:$(DOCKER_IMAGE_VERSION) \
--build-arg DOCKER_SERVER_HOST=$(DOCKER_SERVER_HOST) \
--build-arg DOCKER_SERVER_PORT=$(DOCKER_SERVER_PORT) \
--build-arg DOCKER_PROJECT_PATH=$(DOCKER_PROJECT_PATH) \
Expand Down
2 changes: 0 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ includes:

parameters:
ignoreErrors:
- '#Call to method PHPUnit\\Framework\\Assert::assertSame\(\) with .IPv.. and AdgoalCommon\\ValueObject\\Web\\IPAddressVersion will always evaluate to false\.#'
- '#Parameter \#1 \$value of class AdgoalCommon\\ValueObject\\Geography\\Latitude constructor expects float, string given.#'
- '#Parameter \#1 \$value of class AdgoalCommon\\ValueObject\\Geography\\Longitude constructor expects float, string given.#'
- '#Parameter \#1 \$value of class AdgoalCommon\\ValueObject\\Number\\Real constructor expects float, string given.#'
Expand All @@ -13,5 +12,4 @@ parameters:
- '#Call to an undefined static method.*#'
- '#Static call to instance method.*#'
- '#Parameter \#1 \$value of class AdgoalCommon\\ValueObject\\Number\\Integer constructor expects int, float given.#'
- '#PHPDoc tag \@param for parameter $value with type float|int is not subtype of native type float\.#'

6 changes: 6 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
</testsuite>
</testsuites>

<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
</whitelist>
</filter>

<logging>
<log type="coverage-html" target="var/report/html" lowUpperBound="35" highLowerBound="70"/>
</logging>
Expand Down
2 changes: 1 addition & 1 deletion src/DateTime/Date.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public function __construct(Year $year, Month $month, MonthDay $day)
$nativeDateErrors = DateTime::getLastErrors();

if ($nativeDateErrors['warning_count'] > 0 || $nativeDateErrors['error_count'] > 0) {
throw new InvalidDateException($year->toNative(), $month->toNative(), $day->toNative());
throw new InvalidDateException($year->toNative(), $month->getNumericValue(), $day->toNative());
}

$this->year = $year;
Expand Down
2 changes: 1 addition & 1 deletion src/DateTime/DateTimeWithTimeZone.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public function sameTimestampAs(ValueObjectInterface $dateTimeWithTimeZone): boo
return false;
}

return $this->toNativeDateTime() === $dateTimeWithTimeZone->toNativeDateTime();
return $this->toNativeDateTime()->getTimestamp() === $dateTimeWithTimeZone->toNativeDateTime()->getTimestamp();
}

/**
Expand Down
33 changes: 33 additions & 0 deletions src/Identity/HashedPassword.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace AdgoalCommon\ValueObject\Identity;

use AdgoalCommon\ValueObject\Exception\InvalidNativeArgumentException;
use AdgoalCommon\ValueObject\StringLiteral\StringLiteral;

class HashedPassword extends StringLiteral
{
/**
* @param string $value
*/
public function __construct(string $value)
{
if (empty($value)) {
throw new InvalidNativeArgumentException('hash', ['string (not empty)']);
}

parent::__construct($value);
}

/**
* @param PlainPassword $plainPassword
*
* @return bool
*/
public function isPasswordValid(PlainPassword $plainPassword): bool
{
return password_verify((string) $plainPassword, $this->value);
}
}
83 changes: 83 additions & 0 deletions src/Identity/PlainPassword.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

declare(strict_types=1);

namespace AdgoalCommon\ValueObject\Identity;

use AdgoalCommon\ValueObject\Exception\InvalidNativeArgumentException;
use AdgoalCommon\ValueObject\StringLiteral\StringLiteral;

class PlainPassword extends StringLiteral
{
public const MUST_CONTAINS_LOWER_LETTER = 1;
public const MUST_CONTAINS_UPPER_LETTER = 2;
public const MUST_CONTAINS_DIGIT = 3;
public const MUST_CONTAINS_SPECIAL_SYMBOL = 4;

private const MIN_CHARS = 8;
private const MAX_CHARS = 16;

/**
* @param string $value
* @param int $minChars
* @param int $maxChars
* @param int[] $rules
*/
public function __construct(
string $value,
int $minChars = self::MIN_CHARS,
int $maxChars = self::MAX_CHARS,
array $rules = []
) {
if (empty($value)) {
throw new InvalidNativeArgumentException('password', ['string (not empty)']);
}

$this->validateContentLength($value, $minChars, $maxChars);
$this->validateContent($value, $rules);

parent::__construct($value);
}

/**
* @param string $value
* @param int $minChars
* @param int $maxChars
*/
private function validateContentLength(string $value, int $minChars, int $maxChars): void
{
if ($minChars > $maxChars) {
throw new InvalidNativeArgumentException($minChars, ['int (min should be <= max']);
}

if (mb_strlen($value) < $minChars || mb_strlen($value) > $maxChars) {
throw new InvalidNativeArgumentException(
'password',
[sprintf('string (length: >= %d, <=%d)', $minChars, $maxChars)]
);
}
}

/**
* @param string $value
* @param int[] $rules
*/
private function validateContent(string $value, array $rules): void
{
if (in_array(self::MUST_CONTAINS_LOWER_LETTER, $rules) && !preg_match('/[a-z]/', $value)) {
throw new InvalidNativeArgumentException('password', ['string (lower letter required)']);
}

if (in_array(self::MUST_CONTAINS_UPPER_LETTER, $rules) && !preg_match('/[A-Z]/', $value)) {
throw new InvalidNativeArgumentException('password', ['string (upper letter required)']);
}

if (in_array(self::MUST_CONTAINS_DIGIT, $rules) && !preg_match('/[0-9]/', $value)) {
throw new InvalidNativeArgumentException('password', ['string (digit required)']);
}

if (in_array(self::MUST_CONTAINS_SPECIAL_SYMBOL, $rules) && !preg_match('/[^a-z0-9 ]/i', $value)) {
throw new InvalidNativeArgumentException('password', ['string (special symbol required)']);
}
}
}
1 change: 0 additions & 1 deletion src/Identity/UUID.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace AdgoalCommon\ValueObject\Identity;

use AdgoalCommon\ValueObject\Exception\InvalidNativeArgumentException;
use AdgoalCommon\ValueObject\StringLiteral\StringLiteral;
use AdgoalCommon\ValueObject\ValueObjectInterface;
use Exception;
use Ramsey\Uuid\Uuid as BaseUuid;
Expand Down
2 changes: 1 addition & 1 deletion src/Money/Money.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public function multiply(Real $multiplier, ?RoundingMode $roundingMode = null):
}

$amount = $this->getAmount()->toNative() * $multiplier->toNative();
$roundedAmount = new IntegerValueObject(round($amount, 0, $roundingMode->toNative()));
$roundedAmount = new IntegerValueObject((int) round($amount, 0, $roundingMode->toNative()));

return new self($roundedAmount, $this->getCurrency());
}
Expand Down
35 changes: 30 additions & 5 deletions src/Number/Integer.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,25 @@
/**
* Class Integer.
*/
class Integer extends Real
class Integer implements ValueObjectInterface, NumberInterface
{
/**
* @var int
*/
protected $value;

/**
* Returns a Real object given a PHP native float as parameter.
*
* @return static
*/
public static function fromNative(): ValueObjectInterface
{
$value = func_get_arg(0);

return new static($value);
}

/**
* Returns a Integer object given a PHP native int as parameter.
*
Expand All @@ -25,7 +42,7 @@ public function __construct(int $value)
throw new InvalidNativeArgumentException($value, ['int']);
}

parent::__construct($value);
$this->value = $value;
}

/**
Expand All @@ -51,9 +68,7 @@ public function sameValueAs(ValueObjectInterface $integer): bool
*/
public function toNative()
{
$value = parent::toNative();

return (int) $value;
return $this->value;
}

/**
Expand Down Expand Up @@ -91,4 +106,14 @@ public function decr(): self

return $this;
}

/**
* Returns the string representation of the real value.
*
* @return string
*/
public function __toString(): string
{
return (string) $this->toNative();
}
}
29 changes: 21 additions & 8 deletions src/Number/Real.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
class Real implements ValueObjectInterface, NumberInterface
{
/**
* @var float|int
* @var float
*/
protected $value;

Expand All @@ -33,7 +33,7 @@ public static function fromNative(): ValueObjectInterface
/**
* Returns a Real object given a PHP native float as parameter.
*
* @param float|int $value
* @param float $value
*/
public function __construct(float $value)
{
Expand All @@ -49,27 +49,40 @@ public function __construct(float $value)
/**
* Returns the native value of the real number.
*
* @return float|int
* @return float
*/
public function toNative()
public function toNative(): float
{
return $this->value;
}

/**
* Tells whether two Real are equal by comparing their values.
*
* @param ValueObjectInterface $real
* @param ValueObjectInterface $value
* @param int $scale
*
* @return bool
*/
public function sameValueAs(ValueObjectInterface $real): bool
public function sameValueAs(ValueObjectInterface $value, int $scale = 0): bool
{
if (!$real instanceof static) {
if (!$value instanceof static) {
return false;
}

return $this->toNative() === $real->toNative();
if (extension_loaded('bcmath')) {
return 0 === bccomp((string) $this->toNative(), (string) $value->toNative(), $scale);
}

if ($scale > 0) {
$ratio = pow(10, $scale);
$selfValue = (new self($this->toNative() * $ratio))->toInteger();
$incomeValue = (new self($value->toNative() * $ratio))->toInteger();

return $selfValue->toNative() === $incomeValue->toNative();
}

return (string) $this->toNative() === (string) $value->toNative();
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/Web/EmailAddress.php → src/Person/EmailAddress.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

declare(strict_types=1);

namespace AdgoalCommon\ValueObject\Web;
namespace AdgoalCommon\ValueObject\Person;

use AdgoalCommon\ValueObject\Exception\InvalidNativeArgumentException;
use AdgoalCommon\ValueObject\StringLiteral\StringLiteral;
use AdgoalCommon\ValueObject\Web\Domain;

/**
* Class EmailAddress.
Expand Down
2 changes: 1 addition & 1 deletion src/Person/Name.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public function sameValueAs(ValueObjectInterface $name): bool
return false;
}

return $this->getFullName() === $name->getFullName();
return $this->getFullName() == $name->getFullName();
}

/**
Expand Down
23 changes: 23 additions & 0 deletions src/Person/PhoneNumber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace AdgoalCommon\ValueObject\Person;

use AdgoalCommon\ValueObject\Exception\InvalidNativeArgumentException;
use AdgoalCommon\ValueObject\StringLiteral\StringLiteral;

/**
* Class PhoneNumber.
*/
class PhoneNumber extends StringLiteral
{
public function __construct(string $value)
{
if (0 === preg_match('/^([0-9]+)$/i', $value)) {
throw new InvalidNativeArgumentException($value, ['string (valid phone number)']);
}

parent::__construct($value);
}
}
2 changes: 1 addition & 1 deletion src/Structure/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ protected static function makeValueObject($item): ValueObjectInterface
}

if (is_iterable($item)) {
return self::isAssocArray($item) ? Dictionary::fromNative($item) : self::fromNative($item);
return self::isAssocArray($item) ? Dictionary::fromNative($item) : static::fromNative($item);
}

if (is_int($item)) {
Expand Down
2 changes: 1 addition & 1 deletion src/Structure/Dictionary.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public static function fromNative(): ValueObjectInterface
*/
public function __construct(SplFixedArray $keyValuePairs)
{
foreach ($keyValuePairs as $keyValuePair) {
foreach ($keyValuePairs as $key => $keyValuePair) {
if (false === $keyValuePair instanceof KeyValuePair) {
$type = is_object($keyValuePair) ? get_class($keyValuePair) : gettype($keyValuePair);

Expand Down
2 changes: 1 addition & 1 deletion src/Structure/KeyValuePair.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,6 @@ public function __toString(): string
*/
public function toArray(): array
{
return[$this->getKey()->toNative(), $this->getValue()->toNative()];
return [$this->getKey()->toNative() => $this->getValue()->toNative()];
}
}
Loading