coduo / php-matcher
PHP Matcher enables you to match values with patterns
Installs: 9 353 533
Dependents: 41
Suggesters: 0
Security: 0
Stars: 817
Watchers: 21
Forks: 86
Open Issues: 6
Requires
- php: ~8.1 || ~8.2 || ~8.3 || ~8.4
- ext-filter: *
- ext-json: *
- ext-simplexml: *
- aeon-php/calendar: ^1.0.6
- coduo/php-to-string: ^3
- doctrine/lexer: ^3.0
Requires (Dev)
- nikic/php-parser: ^4.0
- openlss/lib-array2xml: ^1.0
- phpunit/phpunit: ^10.4
- symfony/cache: ^5.4|^6.4
- symfony/expression-language: ^5.4|^6.4|^7.0
- symfony/var-exporter: ^5.4|^6.4|^7.0
Suggests
- openlss/lib-array2xml: In order ot use Coduo\PHPMatcher\Matcher\XmlMatcher
- symfony/expression-language: In order to use Coduo\PHPMatcher\Matcher\ExpressionMatcher
- 6.x-dev
- 6.0.17
- 6.0.16
- 6.0.15
- 6.0.14
- 6.0.13
- 6.0.12
- 6.0.11
- 6.0.10
- 6.0.9
- 6.0.8
- 6.0.7
- 6.0.6
- 6.0.5
- 6.0.4
- 6.0.3
- 6.0.2
- 6.0.1
- 6.0.0
- 5.x-dev
- 5.0.x-dev
- 5.0.1
- 5.0.0
- 4.0.x-dev
- 4.0.2
- 4.0.1
- 4.0.0
- 3.2.x-dev
- 3.2.3
- 3.2.2
- 3.2.1
- 3.2.0
- 3.1.x-dev
- 3.1.3
- 3.1.2
- 3.1.1
- 3.1.0
- 3.0.x-dev
- 3.0.1
- 3.0.0
- 2.4.x-dev
- 2.4.0
- 2.3.x-dev
- 2.3.0
- 2.2.x-dev
- 2.2.0
- 2.1.x-dev
- 2.1.0
- 2.0.x-dev
- 2.0.1
- 2.0.0
- 2.0.0-rc2
- 2.0.0-rc1
- 2.0.0-rc
- 2.0.0-beta
- 2.0.0-alpha2
- 2.0.0-alpha1
- 1.1.x-dev
- 1.1.8
- 1.1.7
- 1.1.6
- 1.1.5
- 1.1.4
- 1.1.3
- 1.1.1
- 1.1.0
- 1.0.x-dev
- 1.0.9
- 1.0.8
- 1.0.7
- 1.0.6
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- v1.0.0
- dev-dependabot/composer/nikic/php-parser-5.3.1
- dev-dependabot/composer/tools/phpstan/phpstan/phpstan-2.0.4
- dev-dependabot/composer/tools/phpstan/phpstan/phpstan-2.0.3
- dev-dependabot/composer/tools/cs-fixer/friendsofphp/php-cs-fixer-3.65.0
This package is auto-updated.
Last update: 2024-12-20 11:04:45 UTC
README
Library created for testing all kinds of JSON/XML/TXT/Scalar values against patterns.
API:
PHPMatcher::match($value = '{"foo": "bar"}', $pattern = '{"foo": "@string@"}') : bool; PHPMatcher::backtrace() : Backtrace; PHPMatcher::error() : ?string;
It was built to simplify API's functional testing.
- - 6.x README PHP >= 8.1 <= 8.3
- 5.x README PHP >= 7.2 < 8.0
- 5.0 README PHP >= 7.2 < 8.0
- 4.0.* README PHP >= 7.2 < 8.0
- 3.2.* README PHP >= 7.0 < 8.0
- 3.1.* README PHP >= 7.0 < 8.0
We Stand Against Terror
On Feb. 24, 2022, Russia declared an unprovoked war on Ukraine and launched a full-scale invasion. Russia is currently bombing peaceful Ukrainian cities, including schools and hospitals and attacking civilians who are fleeing conflict zones.
On Oct. 7, 2023, the national holiday of Simchat Torah, Hamas terrorists initiated an attack on Israel in the early hours, targeting civilians. They unleashed violence that resulted in at least 1,400 casualties and abducted at least 200 individuals, not limited to Israelis.
Sandbox
Feel free to play first with Sandbox
Installation
Require new dev dependency using composer:
composer require --dev "coduo/php-matcher"
Basic usage
Direct PHPMatcher usage
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $match = $matcher->match("lorem ipsum dolor", "@string@"); if (!$match) { echo "Error: " . $matcher->error(); echo "Backtrace: \n"; echo (string) $matcher->backtrace(); }
PHPUnit extending PHPMatcherTestCase
<?php use Coduo\PHPMatcher\PHPUnit\PHPMatcherTestCase; class MatcherTest extends PHPMatcherTestCase { public function test_matcher_that_value_matches_pattern() { $this->assertMatchesPattern('{"name": "@string@"}', '{"name": "Norbert"}'); } }
PHPUnit using PHPMatcherAssertions trait
<?php use Coduo\PHPMatcher\PHPUnit\PHPMatcherAssertions; use PHPUnit\Framework\TestCase; class MatcherTest extends TestCase { use PHPMatcherAssertions; public function test_matcher_that_value_matches_pattern() { $this->assertMatchesPattern('{"name": "@string@"}', '{"name": "Norbert"}'); } }
Available patterns
@string@
@integer@
@number@
@double@
@boolean@
@time@
@date@
@datetime@
@timezone@
||@tz
@array@
@array_previous@
- match next array element using pattern from previous element@array_previous_repeat@
- match all remaining array elements using pattern from previous element@...@
- unbounded array, once used matcher will skip any further array elements@null@
@*@
||@wildcard@
expr(expression)
- optional, requiressymfony/expression-language: ^2.3|^3.0|^4.0|^5.0
to be present@uuid@
@ulid@
@json@
@string@||@integer@
- string OR integer
Available pattern expanders
startsWith($stringBeginning, $ignoreCase = false)
endsWith($stringEnding, $ignoreCase = false)
contains($string, $ignoreCase = false)
notContains($string, $ignoreCase = false)
isDateTime()
isInDateFormat($format)
- example"@datetime@.isInDateFormat('Y-m-d H:i:s')
before(string $date)
- example"@string@.isDateTime().before(\"2020-01-01 00:00:00\")"
after(string $date)
- example"@string@.isDateTime().after(\"2020-01-01 00:00:00\")"
isTzOffset()
isTzIdentifier()
isTzAbbreviation()
isEmail()
isUrl()
isIp()
isEmpty()
isNotEmpty()
lowerThan($boundry)
greaterThan($boundry)
inArray($value)
- example"@array@.inArray(\"ROLE_USER\")"
hasProperty($propertyName)
- example"@json@.hasProperty(\"property_name\")"
oneOf(...$expanders)
- example"@string@.oneOf(contains('foo'), contains('bar'), contains('baz'))"
matchRegex($regex)
- example"@string@.matchRegex('/^lorem.+/')"
optional()
- work's only withArrayMatcher
,JsonMatcher
andXmlMatcher
count()
- work's only withArrayMatcher
- example"@array@.count(5)"
repeat($pattern, $isStrict = true)
- example'@array@.repeat({"name": "foe"})'
or"@array@.repeat('@string@')"
match($pattern)
- example{"image":"@json@.match({\"url\":\"@string@.isUrl()\"})"}
Example usage
Scalar matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match(1, 1); $matcher->match('string', 'string');
String matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match('Norbert', '@string@'); $matcher->match("lorem ipsum dolor", "@string@.startsWith('lorem').contains('ipsum').endsWith('dolor')");
Time matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match('00:00:00', '@time@'); $matcher->match('00:01:00.000000', '@time@'); $matcher->match('00:01:00', '@time@.after("00:00:00")'); $matcher->match('00:00:00', '@time@.before("01:00:00")');
Date matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match('2014-08-19', '@date@'); $matcher->match('2020-01-11', '@date@'); $matcher->match('2014-08-19', '@date@.before("2016-08-19")'); $matcher->match('2014-08-19', '@date@.before("today").after("+ 100year")');
DateTime matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match('2014-08-19', '@datetime@'); $matcher->match('2020-01-11 00:00:00', '@datetime@'); $matcher->match('2014-08-19', '@datetime@.before("2016-08-19")'); $matcher->match('2014-08-19', '@datetime@.before("today").after("+ 100year")');
TimeZone matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match('Europe/Warsaw', '@timezone@'); $matcher->match('Europe/Warsaw', '@tz@'); $matcher->match('GMT', '@tz@'); $matcher->match('01:00', '@tz@'); $matcher->match('01:00', '@tz@.isTzOffset()'); $matcher->match('GMT', '@tz@.isTzAbbreviation()'); $matcher->match('Europe/Warsaw', '@tz@.isTzIdentifier()');
Integer matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match(100, '@integer@'); $matcher->match(100, '@integer@.lowerThan(200).greaterThan(10)');
Number matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match(100, '@number@'); $matcher->match('200', '@number@'); $matcher->match(1.25, '@number@'); $matcher->match('1.25', '@number@'); $matcher->match(0b10100111001, '@number@');
Double matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match(10.1, "@double@"); $matcher->match(10.1, "@double@.lowerThan(50.12).greaterThan(10)");
Boolean matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match(true, "@boolean@"); $matcher->match(false, "@boolean@");
Wildcard matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match("@integer@", "@*@"); $matcher->match("foobar", "@*@"); $matcher->match(true, "@*@"); $matcher->match(6.66, "@*@"); $matcher->match(array("bar"), "@wildcard@"); $matcher->match(new \stdClass, "@wildcard@");
Expression matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match(new \DateTime('2014-04-01'), "expr(value.format('Y-m-d') == '2014-04-01'"); $matcher->match("Norbert", "expr(value === 'Norbert')");
UUID matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match('9f4db639-0e87-4367-9beb-d64e3f42ae18', '@uuid@');
ULID matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match('01BX5ZZKBKACTAV9WEVGEMMVS0', '@ulid@');
Array matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match( array( 'users' => array( array( 'id' => 1, 'firstName' => 'Norbert', 'lastName' => 'Orzechowicz', 'roles' => array('ROLE_USER'), 'position' => 'Developer', ), array( 'id' => 2, 'firstName' => 'Michał', 'lastName' => 'Dąbrowski', 'roles' => array('ROLE_USER') ), array( 'id' => 3, 'firstName' => 'Johnny', 'lastName' => 'DąbrowsBravoki', 'roles' => array('ROLE_HANDSOME_GUY') ) ), true, 6.66 ), array( 'users' => array( array( 'id' => '@integer@.greaterThan(0)', 'firstName' => '@string@', 'lastName' => 'Orzechowicz', 'roles' => '@array@', 'position' => '@string@.optional()' ), array( 'id' => '@integer@', 'firstName' => '@string@', 'lastName' => 'Dąbrowski', 'roles' => '@array@' ), '@...@' ), '@boolean@', '@double@' ) );
Array Previous
@array_previous@ can also be used when matching JSON's and XML's
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match( array( 'users' => array( array( 'id' => 1, 'firstName' => 'Norbert', 'lastName' => 'Orzechowicz', 'roles' => array('ROLE_USER'), 'position' => 'Developer', ), array( 'id' => 2, 'firstName' => 'Michał', 'lastName' => 'Dąbrowski', 'roles' => array('ROLE_USER') ), array( 'id' => 3, 'firstName' => 'Johnny', 'lastName' => 'DąbrowsBravoki', 'roles' => array('ROLE_HANDSOME_GUY') ) ), true, 6.66 ), array( 'users' => array( array( 'id' => '@integer@.greaterThan(0)', 'firstName' => '@string@', 'lastName' => 'Orzechowicz', 'roles' => '@array@', 'position' => '@string@.optional()' ), '@array_previous@', '@array_previous@' ), '@boolean@', '@double@' ) );
Array Previous Repeat
@array_previous_repeat@ can also be used when matching JSON's and XML's
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match( array( 'users' => array( array( 'id' => 1, 'firstName' => 'Norbert', 'lastName' => 'Orzechowicz', 'roles' => array('ROLE_USER'), 'position' => 'Developer', ), array( 'id' => 2, 'firstName' => 'Michał', 'lastName' => 'Dąbrowski', 'roles' => array('ROLE_USER') ), array( 'id' => 3, 'firstName' => 'Johnny', 'lastName' => 'DąbrowsBravoki', 'roles' => array('ROLE_HANDSOME_GUY') ) ), true, 6.66 ), array( 'users' => array( array( 'id' => '@integer@.greaterThan(0)', 'firstName' => '@string@', 'lastName' => 'Orzechowicz', 'roles' => '@array@', 'position' => '@string@.optional()' ), '@array_previous_repeat@' ), '@boolean@', '@double@' ) );
Json matching
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match( '{ "users":[ { "firstName": "Norbert", "lastName": "Orzechowicz", "created": "2014-01-01", "roles":["ROLE_USER", "ROLE_DEVELOPER"] } ] }', '{ "users":[ { "firstName": "@string@", "lastName": "@string@", "created": "@string@.isDateTime()", "roles": "@array@", "position": "@string@.optional()" } ] }' );
Json matching with unbounded arrays and objects
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match( '{ "users":[ { "firstName": "Norbert", "lastName": "Orzechowicz", "created": "2014-01-01", "roles":["ROLE_USER", "ROLE_DEVELOPER"], "attributes": { "isAdmin": false, "dateOfBirth": null, "hasEmailVerified": true }, "avatar": { "url": "http://avatar-image.com/avatar.png" } }, { "firstName": "Michał", "lastName": "Dąbrowski", "created": "2014-01-01", "roles":["ROLE_USER", "ROLE_DEVELOPER", "ROLE_ADMIN"], "attributes": { "isAdmin": true, "dateOfBirth": null, "hasEmailVerified": true }, "avatar": null } ] }', '{ "users":[ { "firstName": "@string@", "lastName": "@string@", "created": "@string@.isDateTime()", "roles": [ "ROLE_USER", "@...@" ], "attributes": { "isAdmin": @boolean@, "@*@": "@*@" }, "avatar": "@json@.match({\"url\":\"@string@.isUrl()\"})" } , @...@ ] }' );
Xml matching
Optional - requires openlss/lib-array2xml: ^1.0
to be present.
<?php use Coduo\PHPMatcher\PHPMatcher; $matcher = new PHPMatcher(); $matcher->match(<<<XML <?xml version="1.0"?> <soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope" soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding"> <soap:Body xmlns:m="http://www.example.org/stock"> <m:GetStockPrice> <m:StockName>IBM</m:StockName> <m:StockValue>Any Value</m:StockValue> </m:GetStockPrice> </soap:Body> </soap:Envelope> XML , <<<XML <?xml version="1.0"?> <soap:Envelope xmlns:soap="@string@" soap:encodingStyle="@string@"> <soap:Body xmlns:m="@string@"> <m:GetStockPrice> <m:StockName>@string@</m:StockName> <m:StockValue>@string@</m:StockValue> <m:StockQty>@integer@.optional()</m:StockQty> </m:GetStockPrice> </soap:Body> </soap:Envelope> XML );
Example scenario for api in behat using mongo.
@profile, @user Feature: Listing user toys As a user I want to list my toys Background: Given I send and accept JSON Scenario: Listing toys Given the following users exist: | firstName | lastName | | Chuck | Norris | And the following toys user "Chuck Norris" exist: | name | | Barbie | | GI Joe | | Optimus Prime | When I set valid authorization code oauth header for user "Chuck Norris" And I send a GET request on "/api/toys" Then the response status code should be 200 And the JSON response should match: """ [ { "id": "@string@", "name": "Barbie", "_links: "@*@" }, { "id": "@string@", "name": "GI Joe", "_links": "@*@" }, { "id": "@string@", "name": "Optimus Prime", "_links": "@*@" } ] """
PHPUnit integration
The assertMatchesPattern()
is a handy assertion that matches values in PHPUnit tests.
To use it either include the Coduo\PHPMatcher\PHPUnit\PHPMatcherAssertions
trait,
or extend the Coduo\PHPMatcher\PHPUnit\PHPMatcherTestCase
:
namespace Coduo\PHPMatcher\Tests\PHPUnit; use Coduo\PHPMatcher\PHPUnit\PHPMatcherAssertions; use PHPUnit\Framework\TestCase; class PHPMatcherAssertionsTest extends TestCase { use PHPMatcherAssertions; public function test_it_asserts_if_a_value_matches_the_pattern() { $this->assertMatchesPattern('@string@', 'foo'); } }
The matchesPattern()
method can be used in PHPUnit stubs or mocks:
$mock = $this->createMock(Foo::class); $mock->method('bar') ->with($this->matchesPattern('@string@')) ->willReturn('foo');
License
This library is distributed under the MIT license. Please see the LICENSE file.
Credits
This lib was inspired by JSON Expressions gem && Behat RestExtension