Skip to content
Merged
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
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"require": {
"php": "^7.1",

"webmozart/assert": "^1.3",
"beberlei/assert": "^3.1",

"symfony/property-access": "^3.1 || ^4.0",

Expand Down Expand Up @@ -62,6 +62,7 @@
"symfony/var-dumper": "^2.8 || ^3.3 || ^4.0",

"phpstan/phpstan": "^0.10",
"phpstan/phpstan-strict-rules": "^0.10"
"phpstan/phpstan-strict-rules": "^0.10",
"phpstan/phpstan-beberlei-assert": "^0.10"
}
}
16 changes: 9 additions & 7 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ parameters:
# and stuff like that for (almost) every line.
- '{^Cannot call method arrayNode\\() on Symfony\Component\Config\Definition\Builder\NodeParentInterface|null.$}'

# Waiting for https://github.com/phpstan/phpstan/issues/1615 to be solved
# and then this ignore pattern can be gone.
#
# As there is some sort of "magic" with nette / neon, we kinda have to make
# a magic pattern so we can't focus this ignore on the Assert lib
# specifically. But as it should temporary, who cares, amiritte ?
- "{^Trying to invoke array\\('Webmozart[\\\\].+?', 'notSame'|'same'\\) but it might not be a callable.$}"
# Waiting for https://github.com/beberlei/assert/pull/264 to be merged
# and released, so that this ignore pattern can be removed.
- '{^Parameter #3 \\$offset of function mb_strpos expects int, null given.$}'
- '{^Parameter #1 \$format of function sprintf expects string, string|null given.$}'

# phpstan doesn't detect well assertions with function_exists,
# method_exists and class_exists, so we have to ignore them...
- '{^Function is_countable not found.$}'

includes:
- vendor/phpstan/phpstan-strict-rules/rules.neon
- vendor/phpstan/phpstan-beberlei-assert/extension.neon
25 changes: 25 additions & 0 deletions src/Assert/Assert.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php declare(strict_types=1);
namespace Behapi\Assert;

use Assert\Assert as Beberlei;

/**
* While the PR in links are not merged and released, let's use this assertion
* class to satisfy our needs...
*
* @link https://github.com/beberlei/assert/pull/264
* @link https://github.com/beberlei/assert/pull/265
* @link https://github.com/beberlei/assert/pull/266
* @link https://github.com/beberlei/assert/pull/267
*/
abstract class Assert extends Beberlei
{
protected static $assertionClass = Assertion::class;

public static function that($value, $defaultMessage = null, $defaultPropertyPath = null)
{
$assertionChain = new AssertionChain($value, $defaultMessage, $defaultPropertyPath);

return $assertionChain->setAssertionClassName(static::$assertionClass);
}
}
146 changes: 146 additions & 0 deletions src/Assert/Assertion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php declare(strict_types=1);
namespace Behapi\Assert;

use Assert\Assertion as Beberlei;

use function sprintf;
use function mb_strpos;

/**
* While the PR in links are not merged and released, let's use this assertion
* class to satisfy our needs...
*
* @method static bool allEmpty(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is empty for all values.
* @method static bool allIsCountable(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is countable for all values.
* @method static bool allMaxCount(array|\Countable $countable, int $count, string $message = null, string $propertyPath = null) Assert that the countable does not have more than $count elements for all values.
* @method static bool allMinCount(array|\Countable $countable, int $count, string $message = null, string $propertyPath = null) Assert that the countable has at least $count elements for all values.
* @method static bool allNotContains(mixed $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars for all values.
* @method static bool nullOrEmpty(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is empty or that the value is null.
* @method static bool nullOrIsCountable(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is countable or that the value is null.
* @method static bool nullOrMaxCount(array|\Countable $countable, int $count, string $message = null, string $propertyPath = null) Assert that the countable does not have more than $count elements or that the value is null.
* @method static bool nullOrMinCount(array|\Countable $countable, int $count, string $message = null, string $propertyPath = null) Assert that the countable has at least $count elements or that the value is null.
* @method static bool nullOrNotContains(mixed $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars or that the value is null.
*
* @link https://github.com/beberlei/assert/pull/264
* @link https://github.com/beberlei/assert/pull/266
* @link https://github.com/beberlei/assert/pull/267
*/
abstract class Assertion extends Beberlei
{
const INVALID_STRING_NOT_CONTAINS = 226;
const INVALID_COUNTABLE = 227;
const INVALID_MIN_COUNT = 228;
const INVALID_MAX_COUNT = 229;

/**
* Assert that string does not contains a sequence of chars.
*
* @param mixed $string
* @param string $needle
* @param string|callable|null $message
* @param string|null $propertyPath
* @param string $encoding
*
* @return bool
*/
public static function notContains($string, $needle, $message = null, $propertyPath = null, $encoding = 'utf8')
{
static::string($string, $message, $propertyPath);

if (false !== mb_strpos($string, $needle, null, $encoding)) {
$message = sprintf(
static::generateMessage($message ?: 'Value "%s" contains "%s".'),
static::stringify($string),
static::stringify($needle)
);

throw static::createException($string, $message, static::INVALID_STRING_NOT_CONTAINS, $propertyPath, ['needle' => $needle, 'encoding' => $encoding]);
}

return true;
}

/**
* Assert that value is countable.
*
* @param mixed $value
* @param string|callable|null $message
* @param string|null $propertyPath
*
* @return bool
*/
public static function isCountable($value, $message = null, $propertyPath = null)
{
if (function_exists('is_countable')) {
$assert = is_countable($value);
} else {
$assert = is_array($value) || $value instanceof \Countable;
}

if (!$assert) {
$message = \sprintf(
static::generateMessage($message ?: 'Value "%s" is not an array and does not implement Countable.'),
static::stringify($value)
);

throw static::createException($value, $message, static::INVALID_COUNTABLE, $propertyPath);
}

return true;
}

/**
* Assert that the countable has at least $count elements.
*
* @param array|\Countable $countable
* @param int $count
* @param string|null $message
* @param string|null $propertyPath
*
* @return bool
*/
public static function minCount($countable, $count, $message = null, $propertyPath = null)
{
if ($count > \count($countable)) {
$message = \sprintf(
static::generateMessage($message ?: 'List should have at least %d elements, but only has %d elements.'),
static::stringify($count),
static::stringify(\count($countable))
);

throw static::createException($countable, $message, static::INVALID_MIN_COUNT, $propertyPath, ['count' => $count]);
}

return true;
}

/**
* Assert that the countable does not have more than $count elements.
*
* @param array|\Countable $countable
* @param int $count
* @param string|null $message
* @param string|null $propertyPath
*
* @return bool
*/
public static function maxCount($countable, $count, $message = null, $propertyPath = null)
{
if ($count < \count($countable)) {
$message = \sprintf(
static::generateMessage($message ?: 'List should have no more than %d elements, but has %d elements.'),
static::stringify($count),
static::stringify(\count($countable))
);

throw static::createException($countable, $message, static::INVALID_MAX_COUNT, $propertyPath, ['count' => $count]);
}

return true;
}

public static function empty($value, $message = null, $propertyPath = null)
{
parent::noContent($value, $message, $propertyPath);
}
}
48 changes: 48 additions & 0 deletions src/Assert/AssertionChain.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php declare(strict_types=1);
namespace Behapi\Assert;

use Assert\AssertionChain as Beberlei;

/**
* PR needed while some PRs are not merged and released on upstream. :}
*
* @method AssertionChain empty(string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string is empty.
* @method AssertionChain maxCount(int $count, string $message = null, string $propertyPath = null) Assert that the countable does not have more than $count elements.
* @method AssertionChain minCount(int $count, string $message = null, string $propertyPath = null) Assert that the countable has at least $count elements.
* @method AssertionChain notContains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars.
* @method AssertionChain isCountable(string|callable $message = null, string $propertyPath = null) Assert that value is countable.
*
* @link https://github.com/beberlei/assert/pull/264
* @link https://github.com/beberlei/assert/pull/265
* @link https://github.com/beberlei/assert/pull/266
* @link https://github.com/beberlei/assert/pull/267
*/
class AssertionChain extends Beberlei
{
/**
* Perform a negative assertion.
*
* @var bool
*/
private $not = false;

public function __call($methodName, $args)
{
if ($this->not) {
$methodName = "not{$methodName}";
}

return parent::__call($methodName, $args);
}

/**
* Switch chain into negative mode.
*
* @return AssertionChain
*/
public function not()
{
$this->not = true;
return $this;
}
}
Loading