The easiest way to match data structures like JSON/PlainText/XML against readable patterns. Sandbox:

Overview

PHP Matcher

Type Coverage

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.

Latest Stable Version Total Downloads Latest Unstable Version License

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": "Norbert"}', '{"name": "@string@"}');
    }
}

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": "Norbert"}', '{"name": "@string@"}');
    }
}

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, requires symfony/expression-language: ^2.3|^3.0|^4.0|^5.0 to be present
  • @uuid@
  • @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 "@[email protected]('Y-m-d H:i:s')
  • before(string $date) - example "@[email protected]().before(\"2020-01-01 00:00:00\")"
  • after(string $date) - example "@[email protected]().after(\"2020-01-01 00:00:00\")"
  • isTzOffset()
  • isTzIdentifier()
  • isTzAbbreviation()
  • isEmail()
  • isUrl()
  • isIp()
  • isEmpty()
  • isNotEmpty()
  • lowerThan($boundry)
  • greaterThan($boundry)
  • inArray($value)
  • hasProperty($propertyName) - example "@[email protected](\"property_name\")"
  • oneOf(...$expanders) - example "@[email protected](contains('foo'), contains('bar'), contains('baz'))"
  • matchRegex($regex) - example "@[email protected]('/^lorem.+/')"
  • optional() - work's only with ArrayMatcher, JsonMatcher and XmlMatcher
  • count() - work's only with ArrayMatcher - example "@[email protected](5)"
  • repeat($pattern, $isStrict = true) - example '@[email protected]({"name": "foe"})' or "@[email protected]('@string@')"
  • match($pattern) - example {"image":"@[email protected]({\"url\":\"@[email protected]()\"})"}

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", "@[email protected]('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', '@[email protected]("00:00:00")');
$matcher->match('00:00:00', '@[email protected]("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', '@[email protected]("2016-08-19")');
$matcher->match('2014-08-19', '@[email protected]("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', '@[email protected]("2016-08-19")');
$matcher->match('2014-08-19', '@[email protected]("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', '@[email protected]()');
$matcher->match('GMT', '@[email protected]()');
$matcher->match('Europe/Warsaw', '@[email protected]()');

Integer matching

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match(100, '@integer@');
$matcher->match(100, '@[email protected](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, "@[email protected](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@');

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' => '@[email protected](0)',
              'firstName' => '@string@',
              'lastName' => 'Orzechowicz',
              'roles' => '@array@',
              'position' => '@[email protected]()'
          ),
          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' => '@[email protected](0)',
              'firstName' => '@string@',
              'lastName' => 'Orzechowicz',
              'roles' => '@array@',
              'position' => '@[email protected]()'
          ),
          '@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' => '@[email protected](0)',
              'firstName' => '@string@',
              'lastName' => 'Orzechowicz',
              'roles' => '@array@',
              'position' => '@[email protected]()'
          ),
          '@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": "@[email protected]()",
        "roles": "@array@",
        "position": "@[email protected]()"
      }
    ]
  }'
);

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": "@[email protected]()",
        "roles": [
            "ROLE_USER",
            "@...@"
        ],
        "attributes": {
          "isAdmin": @boolean@,
          "@*@": "@*@"
        },
        "avatar": "@[email protected]({\"url\":\"@[email protected]()\"})"
      }
      ,
      @...@
    ]
  }'
);

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>@[email protected]()</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

Comments
  • Adds NonStrictArrayMatcher which will matches softly value and pattern

    Adds NonStrictArrayMatcher which will matches softly value and pattern

    After studying a bit issue #39 , I found out that the only thing required to be able to match softly a JSON, would be having a new ArrayMatcher, being able to keep going through the array instead of returning an error when there is a value not contained in the pattern. So here it is my proposal of creating a new NonStrictArrayMatcher, a subtype of the ArrayMatcher, where only changes the iterateMatch() method.

    So, to get what I requested on issue #39 it would be only needed to create a JsonMatcher containing a NonStrictArrayMatcher.

    opened by javierseixas 23
  • TextMatcher should not match @null@ inside pattern

    TextMatcher should not match @null@ inside pattern

    The TextMatcher currently reports that it matches against all strings. During matching against strings with @null@ in them an UnknownTypeException will be thrown - after all a pattern like this should be @null@ makes no sense in a text context.

    This prevents other matchers from being able to match, so I've changed it to not match in this case.

    Reproduce code:

    <?php
    
    use Coduo\PHPMatcher\Factory\SimpleFactory;
    
    require_once __DIR__ . '/vendor/autoload.php';
    
    $expected = <<<JSON
    {
        "a": @null@,
        "b": 4
    }
    JSON;
    
    
    $actual = <<<JSON
    {
        "a": null,
        "b": 5
    }
    JSON;
    
    
    $matcher = (new SimpleFactory())->createMatcher();
    
    
    echo $matcher->match($actual, $expected)
        ? 'Match found' :
        'Match not found: ' . $matcher->getError()
    ;
    
    opened by adamquaile 18
  • Multiple elements JSON matching

    Multiple elements JSON matching

    Given I have a JSON response witch returns an array of 10 elements, like:

    [
          {
            "id": 1,
            "name": "Posiłek @integer@",
            "date": @string@
          },
          {
            "id": 2,
            "name": "Posiłek @integer@",
            "date": @string@
          },
          {
            "id": 3,
            "name": "Posiłek @integer@",
            "date": @string@
          },
          @repeat@
    ]
    

    I'd like to point somehow that there's one unique pattern which should be matched 10 times in JSON response, becouse array has 10 items. Are you thinking about such feature?

    feature request 
    opened by piotrjura 16
  • PHP 8.0 compability.

    PHP 8.0 compability.

    As php 8.0 introduces new "match" keyword, library fails to run because of one class:

    Coduo\PHPMatcher\Matcher\Pattern\Expander\Match

    I renamed class to:

    Coduo\PHPMatcher\Matcher\Pattern\Expander\ExpanderMatch

    And all errors is gone. tests pass on php8.0 + phpunit 9.4 (phpunit 8.x does not support php 8.x)

    opened by dotdevpro 10
  • 2.0.0 Release cycle

    2.0.0 Release cycle

    Version 2.0.0-alpha1 was just released. From now on, every monday I will release next version in order to finish with stable release 2.0.0

    • [x] 2.0.0-alpha1 - 25.01.2016
    • [x] 2.0.0-alpha2 - (will be skipped in case of no changes) - 01.02.2015
    • [x] 2.0.0-beta - 08.02.2016 (beta1 and beta2 are merged to beta)
    • [x] 2.0.0-rc - 15.02.2016
    • [x] 2.0.0-rc1 - 03.03.2016 - solved #71
    • [x] 2.0.0-rc2 - 18.03.2016 - finally solved #71
    • [x] 2.0.0 - 25.03.2016

    So in the worse scenario I will release stable version 2.0.0 on 29.02.2015. But in case of no problems with 2.0.0-alpha1 I will skip to beta1 and then to rc1 so 2.0.0 can be possibly released on 22.02.2015

    Also from version we are going to follow semantic versioning guidelines. changelog and upgrade documents should be from now updated after each PR that require it.

    release 
    opened by norberttech 10
  • More details with JsonMatcher

    More details with JsonMatcher

    Hello there,

    using version 4.0 of coduo/php-matcher

    Is there a way to get more details when JSON values do not match ? Like the line that differ maybe ?

    Because right now I have something like that :

    Value {BIG_CHUNK_OF_JSON} does not match {BIG_CHUNK_OF_JSON}
    

    Which is kind of difficult to debug.

    Any suggestions ?

    feature request 
    opened by Linkinou 8
  • Diff of PHPMatcherConstraint ignores patterns

    Diff of PHPMatcherConstraint ignores patterns

    Hey, we are using this library for asserting the content of JSON responses in our functional tests. Apart from a few minor issues, this is working great. So thanks for your effort!

    As we are using the library for testing API responses, we need to use a lot of value-patterns to match values such as autogenerated ids and timestamps. This works great as long as the response matches our response-pattern. Unfortunately, if the response does not match our response-pattern, the PHPMatcherConstraint includes all lines that use a value-pattern in its diff. This makes it hard to find out what line actually contains an error.

    For example, the diff of the following test-case includes "name": "@string@" even though "name": "test-2" would match the pattern:

        public function testPattern(): void
        {
            $pattern = <<<EOF
                {
                    "name": "@string@",
                    "description": "test-1"
                }
    EOF;
    
            $value = <<<EOF
                {
                    "name": "test-2",
                    "description": "test-2"
                }
    EOF;
    
            TestCase::assertThat(
                $value,
                new PHPMatcherConstraint($pattern)
            );
        }
    
    --- Expected
    +++ Actual
    @@ @@
     {
    -    "name": "@string@",
    -    "description": "test-1"
    +    "name": "test-2",
    +    "description": "test-2"
     }
    

    Is it possible somehow to exclude the lines that do match the pattern from the diff?

    Thanks in advance!

    feature request 
    opened by niklasnatter 7
  • Match specific fields in a JSON (ignoring the others)

    Match specific fields in a JSON (ignoring the others)

    Hello! Given a JSON like this:

    {
        "id": "@string@",
        "title": "My Title",
        "short_description": "@string@",
        "campaign_start": "@string@",
        "campaign_end": "@string@",
        "status": "@integer@",
        "_links": "@wildcard@",
        "_embedded": {
            "account": {
                "id": "@string@",
                "name": "@string@",
                "society_name": "@string@",
                "_links": "@wildcard@"
            }
        }
    }
    

    I would like to check that title equals to "My Title", but I don't care about the other fields. There is any way to ignore them? I want to do that because the structure of the expected JSON is already tested before, so if I could write something like following would make my features cleaner and focused on what I'm testing each scenario.

    What I'm figuring out would be like this:

    {
        "title": "My title",
        "@whatever@"
    }
    
    feature request 
    opened by javierseixas 7
  • Replaced PHPMatcher facade with implementation that makes possible to access backtrace

    Replaced PHPMatcher facade with implementation that makes possible to access backtrace

    PHPMatcher API cleanup that replaces facade with regular class allowing to access last message/backtrace.

    Changes

    Creating Matcher:

    -$factory = new MatcherFactory();
    -$matcher = $factory->createMatcher();
    +$matcher = new PHPMatcher();
    

    Using Matcher

    -PHPMatcher::match($value, $pattern, $error)
    +$matcher = (new PHPMatcher())->match($value, $pattern);;
    

    Accessing last error/backtrace

    +$matcher = new PHPMatcher();
    +$matcher->match($value, $pattern);
    +echo $matcher->error();
    +echo $matcher->backtrace();
    
    opened by norberttech 6
  • Matcher modifiers

    Matcher modifiers

    Introduces idea described here with two modifiers: CaseInsensitive and IgnoreExtraKeys.

    #126 is included in this PR, I will rebase after it is merged.

    opened by mateuszsip 6
  • Fatal error on version 3.0: Argument 1 passed to Parser::unexpectedSyntaxError() must be of the type array, null given

    Fatal error on version 3.0: Argument 1 passed to Parser::unexpectedSyntaxError() must be of the type array, null given

    Hi, I'm using PHP Matcher 3.0 on PHP 7.2.

    The following script:

    <?php
    
    require 'vendor/autoload.php';
    
    use Coduo\PHPMatcher\Factory\SimpleFactory;
    
    $matcher = (new SimpleFactory)->createMatcher();
    
    $a = '{"foo": "","bar": "baz"}';
    $b = '{"foo": "","bar": "bazz"}';
    
    $match = $matcher->match($a, $b);
    

    results in the following exception:

    PHP Fatal error:  Uncaught TypeError: Argument 1 passed to Coduo\PHPMatcher\Parser::unexpectedSyntaxError() must be of the type array, null given, called in vendor/coduo/php-matcher/src/Parser.php on line 62 and defined in vendor/coduo/php-matcher/src/Parser.php:248
    Stack trace:
    #0 vendor/coduo/php-matcher/src/Parser.php(62): Coduo\PHPMatcher\Parser->unexpectedSyntaxError(NULL, '@type@ pattern')
    #1 vendor/coduo/php-matcher/src/Parser.php(50): Coduo\PHPMatcher\Parser->getPattern()
    #2 vendor/coduo/php-matcher/src/Parser.php(29): Coduo\PHPMatcher\Parser->getAST('')
    #3 vendor/coduo/php-matcher/src/Matcher/StringMatcher.php(43): Coduo\PHPMatcher\Parser->hasValidSyntax('')
    #4 vendor/coduo/php-matcher/src/Matcher/ChainMatcher.php(32): Coduo\PHPMatcher\Matcher\StringMatcher->canMatch('')
    #5  in vendor/coduo/php-matcher/src/Parser.php on line 248
    

    With PHP Matcher 2.4 works as expected, returning false.

    bug 
    opened by emodric 6
  • Bump phpstan/phpstan from 1.9.4 to 1.9.7 in /tools

    Bump phpstan/phpstan from 1.9.4 to 1.9.7 in /tools

    Bumps phpstan/phpstan from 1.9.4 to 1.9.7.

    Release notes

    Sourced from phpstan/phpstan's releases.

    1.9.7

    Bleeding edge 🔪

    If you want to see the shape of things to come and adopt bleeding edge features early, you can include this config file in your project's phpstan.neon:

    includes:
    	- vendor/phpstan/phpstan/conf/bleedingEdge.neon
    

    Of course, there are no backwards compatibility guarantees when you include this file. The behaviour and reported errors can change in minor versions with this file included. Learn more

    Improvements 🔧

    Bugfixes 🐛

    Function signature fixes 🤖

    Internals 🔍

    1.9.6

    Improvements 🔧

    Bugfixes 🐛

    1.9.5

    ... (truncated)

    Commits
    • 0501435 PHPStan 1.9.7
    • 707c831 Updated PHPStan to commit d279f388f5a1cb7a6f821dbecc4052a9ebbb8417
    • 23daeff Updated PHPStan to commit 091fcafb07ac0b3eb261285c049d9c0f214a535c
    • 1a28725 Updated Composer baseline
    • af72eaa Updated PHPUnit baseline
    • c0d39c1 Updated PHPStan to commit 28c2c79b16cac6ba6b01f1b4d211541dd49d8a77
    • 45dbb01 Updated PHPStan to commit 752baaf49f65586b79ab24d5beb4b385c65a281c
    • 7f88292 Updated PHPStan to commit 02753c6883677edd87d40f397f057daddd103a05
    • b4c0d3f Updated PHPStan to commit 6debffdb5892f7fb311a60634ec9cda79b6e3154
    • 92ac649 Reproduce progress bar crash if all passed paths to analyse are excluded
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Bump friendsofphp/php-cs-fixer from 3.13.0 to 3.13.2 in /tools

    Bump friendsofphp/php-cs-fixer from 3.13.0 to 3.13.2 in /tools

    Bumps friendsofphp/php-cs-fixer from 3.13.0 to 3.13.2.

    Release notes

    Sourced from friendsofphp/php-cs-fixer's releases.

    v3.13.2 Oliva

    • bug: Fix type error when using paths intersection mode (#6734)

    v3.13.1 Oliva

    • bug: Align all the arrows inside the same array (#6590)
    • bug: Fix priority between modernize_types_casting and no_unneeded_control_parentheses (#6687)
    • bug: TrailingCommaInMultilineFixer - do not add trailing comma when there is no break line after last element (#6677)
    • docs: Fix docs for disabled rules in rulesets (#6679)
    • docs: fix the cookbook_fixers.rst (#6672)
    • docs: Update installation recommended commands for mkdir argument (-p insteadof --parents). (#6689)
    • Make static data providers that are not using dynamic calls (#6696)
    • minor: displaying number of checked files (#6674)
    Changelog

    Sourced from friendsofphp/php-cs-fixer's changelog.

    Changelog for v3.13.2

    • bug: Fix type error when using paths intersection mode (#6734)

    Changelog for v3.13.1

    • bug: Align all the arrows inside the same array (#6590)
    • bug: Fix priority between modernize_types_casting and no_unneeded_control_parentheses (#6687)
    • bug: TrailingCommaInMultilineFixer - do not add trailing comma when there is no break line after last element (#6677)
    • docs: Fix docs for disabled rules in rulesets (#6679)
    • docs: fix the cookbook_fixers.rst (#6672)
    • docs: Update installation recommended commands for mkdir argument (-p insteadof --parents). (#6689)
    • Make static data providers that are not using dynamic calls (#6696)
    • minor: displaying number of checked files (#6674)
    Commits
    • 3952f08 prepared the 3.13.2 release
    • 936edf0 bug: Fix type error when using paths intersection mode (#6734)
    • 5120e61 bumped version
    • 78d2251 prepared the 3.13.1 release
    • a2bdba3 Make static data providers that are not using dynamic calls (#6696)
    • ad0a87e bug: Align all the arrows inside the same array (#6590)
    • 663f3fc docs: Update installation recommended commands for mkdir argument (-p ins...
    • 9c7070b bug: Fix priority between modernize_types_casting and `no_unneeded_control_...
    • 046ff90 docs: Fix docs for disabled rules in rulesets (#6679)
    • b577444 minor: displaying number of checked files (#6674)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Bump doctrine/lexer from 1.2.3 to 2.1.0

    Bump doctrine/lexer from 1.2.3 to 2.1.0

    Bumps doctrine/lexer from 1.2.3 to 2.1.0.

    Release notes

    Sourced from doctrine/lexer's releases.

    2.1.0

    Release Notes for 2.1.0

    Feature release (minor)

    2.1.0

    • Total issues resolved: 0
    • Total pull requests resolved: 3
    • Total contributors: 1

    Static analysis

    2.0.0

    Release Notes for 2.0.0

    Backwards incompatible release (major)

    2.0.0

    Upgrade guide

    Sourced from doctrine/lexer's upgrade guide.

    Note about upgrading: Doctrine uses static and runtime mechanisms to raise awareness about deprecated code.

    • Use of @deprecated docblock that is detected by IDEs (like PHPStorm) or Static Analysis tools (like Psalm, phpstan)
    • Use of our low-overhead runtime deprecation API, details: https://github.com/doctrine/deprecations/

    Upgrade to 2.0.0

    AbstractLexer::glimpse() and AbstractLexer::peek() now return instances of Doctrine\Common\Lexer\Token, which is an array-like class Using it as an array is deprecated in favor of using properties of that class. Using count() on it is deprecated with no replacement.

    Commits
    • 39ab8fc Merge pull request #102 from greg0ire/templatable-value
    • c7b693a Merge pull request #103 from greg0ire/fix-assertions
    • 7788860 Use correct syntax for assertions
    • abac4f6 Make the value of tokens templatable
    • 49e0c1c Merge pull request #99 from greg0ire/conditional-types
    • 83417d6 Leverage conditional types
    • 8275278 Merge pull request #95 from greg0ire/add-asserts
    • ab64387 Add psalm assertions
    • 3cf140b Merge pull request #93 from doctrine/1.3.x
    • de6022e Merge pull request #92 from doctrine/1.2.x
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Use of mutation testing in php-matcher - Help needed

    Use of mutation testing in php-matcher - Help needed

    Hello there!

    My name is Ana. I noted that you use the mutation testing tool in the project. I am a postdoctoral researcher at the University of Seville (Spain), and my colleagues and I are studying how mutation testing tools are used in practice. With this aim in mind, we have analysed over 3,500 public GitHub repositories using mutation testing tools, including yours! This work has recently been published in a journal paper available at https://link.springer.com/content/pdf/10.1007/s10664-022-10177-8.pdf.

    To complete this study, we are asking for your help to understand better how mutation testing is used in practice, please! We would be extremely grateful if you could contribute to this study by answering a brief survey of 21 simple questions (no more than 6 minutes). This is the link to the questionnaire https://forms.gle/FvXNrimWAsJYC1zB9.

    Drop me an e-mail if you have any questions or comments ([email protected]). Thank you very much in advance!!

    opened by belene 0
  • ValueError: array_fill(): Argument #2 ($count) must be greater than or equal to 0

    ValueError: array_fill(): Argument #2 ($count) must be greater than or equal to 0

    ValueError: array_fill(): Argument #2 ($count) must be greater than or equal to 0
       │
       ╵ /Users/Aerendir/Documents/path/to/app/vendor/coduo/php-matcher/src/Matcher/ArrayMatcher.php:123
       ╵ /Users/Aerendir/Documents/path/to/app/vendor/coduo/php-matcher/src/Matcher/ArrayMatcher.php:176
       ╵ /Users/Aerendir/Documents/path/to/app/vendor/coduo/php-matcher/src/Matcher/ArrayMatcher.php:176
       ╵ /Users/Aerendir/Documents/path/to/app/vendor/coduo/php-matcher/src/Matcher/ArrayMatcher.php:176
       ╵ /Users/Aerendir/Documents/path/to/app/vendor/coduo/php-matcher/src/Matcher/ArrayMatcher.php:75
       ╵ /Users/Aerendir/Documents/path/to/app/vendor/coduo/php-matcher/src/Matcher/ChainMatcher.php:45
       ╵ /Users/Aerendir/Documents/path/to/app/vendor/coduo/php-matcher/src/Matcher.php:25
       ╵ /Users/Aerendir/Documents/path/to/app/vendor/coduo/php-matcher/src/PHPMatcher.php:27
       ╵ /Users/Aerendir/Documents/path/to/app/vendor/coduo/php-matcher/src/PHPUnit/PHPMatcherConstraint.php:55
       ╵ /Users/Aerendir/Documents/path/to/app/vendor/coduo/php-matcher/src/PHPUnit/PHPMatcherAssertions.php:21
       ╵ /Users/Aerendir/Documents/path/to/app/tests/App/TestCase.php:77
       ╵ /Users/Aerendir/Documents/path/to/app/tests/App/MyTest.php:64
    

    The problem is that it is not well handled the case of zero, one or more array elements to validate when using @array_previous_repeat@.

    Maybe I'm configuring wrong the pattern, but, anyway, the error should be catch and a proper error message should be shown to the developer.

    What I'm trying to do is to validate an array that can contain zero, one or more elements.

    With the pattern I'm using, I'm able to only validate more elements while with only one element I get the reported error. I didn't tested the pattern with zero elements.

    This is the payload:

    {
        "@context":"\/api\/contexts\/Item",
        "@id":"\/api\/accounts\/2\/items",
        "@type":"hydra:Collection",
        "hydra:member":[
            {
                "@id":"\/api\/accounts\/2\/items\/1",
                "@type":"Item",
                "id":1,
                "account":"\/api\/accounts\/2",
                "sku":"A SKU",
                "title":"The title",
                "shortDescription":"The short description",
                "description":"The long description",
                "variable":false,
                "itemVariants":[
    
                ],
                "images":[
                    {
                        "@id":"\/api\/accounts\/2\/items\/1\/images\/1",
                        "@type":"ItemImage",
                        "account":"\/api\/accounts\/2",
                        "file":{
                            "@id":"\/api\/accounts\/2\/files\/images\/1",
                            "@type":"https:\/\/schema.org\/MediaObject",
                            "dimensions":[
                                "3295",
                                "2698"
                            ],
                            "type":"item_image",
                            "id":1,
                            "account":"\/api\/accounts\/2",
                            "name":"63495ac9a8688_60283-min.jpg",
                            "originalName":"60283-min.jpg",
                            "size":291983,
                            "mimeType":"image\/jpeg",
                            "publicPaths":{
                                "product_thumb_in_list":"https:\/\/example.com\/media\/cache\/resolve\/product_thumb_in_list\/63495ac9a8688_60283-min.jpg"
                            }
                        },
                        "item":"\/api\/accounts\/2\/items\/1"
                    },
                    {
                        "@id":"\/api\/accounts\/2\/items\/1\/images\/2",
                        "@type":"ItemImage",
                        "account":"\/api\/accounts\/2",
                        "file":{
                            "@id":"\/api\/accounts\/2\/files\/images\/2",
                            "@type":"https:\/\/schema.org\/MediaObject",
                            "dimensions":[
                                "3107",
                                "2668"
                            ],
                            "type":"item_image",
                            "id":2,
                            "account":"\/api\/accounts\/2",
                            "name":"63495ac9ab8b9_60283_alt1-min.jpg",
                            "originalName":"60283_alt1-min.jpg",
                            "size":783721,
                            "mimeType":"image\/jpeg",
                            "publicPaths":{
                                "product_thumb_in_list":"https:\/\/example.com\/media\/cache\/resolve\/product_thumb_in_list\/63495ac9ab8b9_60283_alt1-min.jpg"
                            }
                        },
                        "item":"\/api\/accounts\/2\/items\/1"
                    }
                ],
                "specifics":[
    
                ]
            }
        ],
        "hydra:totalItems":1
    }
    

    This is the pattern:

    {
       "@context":"\/api\/contexts\/Item",
       "@id":"\/api\/accounts\/2\/items",
       "@type":"hydra:Collection",
       "hydra:totalItems":12,
       "hydra:member":[
          {
             "@id":"@[email protected](\"\/api\/accounts\/2\/items\/\")",
             "@type":"Item",
             "id":"@integer@",
             "account":"\/api\/accounts\/2",
             "sku":"@string@",
             "title":"@string@",
             "shortDescription":"@string@",
             "description":"@string@",
             "variable":"@boolean@",
             "itemVariants":[
                
             ],
             "images":[
                {
                   "@id":"@[email protected](\"#\/api\/accounts\/2\/items\/\\d+\/images\/\\d+#\")",
                   "@type":"ItemImage",
                   "account":"\/api\/accounts\/2",
                   "file":{
                      "@id":"@[email protected](\"#\/api\/accounts\/2\/files\/images\/\\d+#\")",
                      "@type":"https:\/\/schema.org\/MediaObject",
                      "dimensions":[
                         "@string@",
                         "@string@"
                      ],
                      "type":"item_image",
                      "id":"@integer@",
                      "account":"\/api\/accounts\/2",
                      "name":"@string@",
                      "originalName":"@string@",
                      "size":"@integer@",
                      "mimeType":"@string@",
                      "publicPaths":{
                         "product_thumb_in_list":"@[email protected]()"
                      }
                   },
                   "item":"@[email protected](\"\/api\/accounts\/2\/items\/\")"
                },
                "@array_previous_repeat@"
             ],
             "specifics":[
                
             ]
          },
          "@array_previous_repeat@"
       ]
    }
    
    opened by Aerendir 0
  • generate php-matcher checking rules from Open API swagger annotation

    generate php-matcher checking rules from Open API swagger annotation

    Usecase: I build REST-API and generate documentation with an OA3 swagger file (JSON or yaml). In this file I describe data structures with type hints

    https://petstore.swagger.io/v2/swagger.json (example).

    I need to check the data structures in my responses with documentation, now I have a choice:

    1. add manually data structures with yours notation and use php-matcher
    2. use https://github.com/thephpleague/openapi-psr7-validator
    opened by mesilov 0
Releases(6.0.9)
laminas-xml2json provides functionality for converting XML structures to JSON

laminas-xml2json This package is considered feature-complete, and is now in security-only maintenance mode, following a decision by the Technical Stee

Laminas Project 13 Dec 28, 2022
A Tinder-like experience for Plex Watchlist: swipe and match with another person and find the movie you're gonna watch tonight.

Plex Finder This app's goal is to help choose a film to watch when neither you nor your SO/friend/roommate/whatever is any good at choosing anything.

Guillaume Hartemann-Piollet 3 Aug 13, 2022
JSONFinder - a library that can find json values in a mixed text or html documents, can filter and search the json tree, and converts php objects to json without 'ext-json' extension.

JSONFinder - a library that can find json values in a mixed text or html documents, can filter and search the json tree, and converts php objects to json without 'ext-json' extension.

Eboubaker Eboubaker 2 Jul 31, 2022
Parsica - PHP Parser Combinators - The easiest way to build robust parsers.

Parsica The easiest way to build robust parsers in PHP. composer require parsica-php/parsica Documentation & API: parsica-php.github.io <?php $parser

null 350 Dec 27, 2022
Laravel Blog Package. Easiest way to add a blog to your Laravel website. A package which adds wordpress functionality to your website and is compatible with laravel 8.

Laravel Blog Have you worked with Wordpress? Developers call this package wordpress-like laravel blog. Give our package a Star to support us ⭐ ?? Inst

Binshops 279 Dec 28, 2022
The Easiest way to start using PHP CS Fixer and PHP_CodeSniffer with 0-knowledge

The Easiest Way to Use Any Coding Standard Features Blazing fast Parallel run Use PHP_CodeSniffer || PHP-CS-Fixer - anything you like 2nd run under fe

null 1.1k Jan 6, 2023
Lightweight PHP wrapper for OVH APIs. That's the easiest way to use OVH.com APIs in your PHP applications.

This PHP package is a lightweight wrapper for OVH APIs. That's the easiest way to use OVH.com APIs in your PHP applications.

OVHcloud 263 Dec 14, 2022
The easiest way to get started with event sourcing in Laravel

Event sourcing for Artisans ?? This package aims to be the entry point to get started with event sourcing in Laravel. It can help you with setting up

Spatie 591 Jan 4, 2023
Sandbox project for the PHPStan workshop

Sandbox project for a PHPStan workshop Installation Requirements Docker Engine Docker Compose Git Bash Getting started Clone this repository (git clon

Matthias Noback 4 Oct 17, 2022
Sandbox for figuring out why the Alpine + Turbo bridge is broken

Podcaster A Turn-Key Podcasting Starter Kit for Statamic 3 Features This kit is deceptively simple – it may look like a 3 page site but there's a whol

Jack McDade 1 Mar 25, 2022
Tentative Extra Data Structures for php

Teds Introduction Teds is a another collection of data structures. (Tentative Extra Data Structures) Installation This extension requires php 8.0 or n

Tyson Andre 26 Nov 21, 2022
A collection of type-safe functional data structures

lamphpda A collection of type-safe functional data structures Aim The aim of this library is to provide a collection of functional data structures in

Marco Perone 99 Nov 11, 2022
Learning about - Basic HTML & CSS, JSON, XML, Session & Cookies, CRUD Operations in Php using MySQL and Create MVC from scratch

This Project is based on course CSC 3215. Learning about - Basic HTML & CSS, JSON, XML, Session & Cookies, CRUD Operations in Php using MySQL and Create MVC (Model–View–Controller) from scratch. Just learning about web technologies, Not focusing on UI (Bootstrap or other 3rd-Party UI libraries or frameworks).

Alvi Hasan 5 Sep 21, 2022
Improve default Magento 2 Import / Export features - cron jobs, CSV , XML , JSON , Excel

Improve default Magento 2 Import / Export features - cron jobs, CSV , XML , JSON , Excel , mapping of any format, Google Sheet, data and price modification, improved speed and a lot more!

Firebear Studio 173 Dec 17, 2022
Sistema disema con aplicación de consultas en XML y JSON

disema-XML-JSON Sistema web para empresa de diseño "Disema", con operaciones básicas CRUD y uso de html, JQ, JS, php y css. Incluye aplicación de cons

null 1 Jan 12, 2022
The main website source code based on php , html/css/js and an independent db system using xml/json.

jsm33t.com Well umm, a neat website LIVE SITE » View Demo · Report Bug · Request a feature About The Project Desc.. Built Using Php UI Frameworks Boot

Jasmeet Singh 5 Nov 23, 2022
A small CLI tool to check missing dependency declarations in the composer.json and module.xml

Integrity checker Package allows to run static analysis on Magento 2 Module Packages to provide an integrity check of package. Supported tools: Compos

run_as_root GmbH 13 Dec 19, 2022
Provide CSV, JSON, XML and YAML files as an Import Source for the Icinga Director and optionally ship hand-crafted additional Icinga2 config files

Icinga Web 2 Fileshipper module The main purpose of this module is to extend Icinga Director using some of it's exported hooks. Based on them it offer

Icinga 25 Sep 18, 2022
World countries - available in multiple languages, in CSV, JSON, PHP, SQL and XML formats

Constantly updated lists of world countries and their associated alpha-2, alpha-3 and numeric country codes as defined by the ISO 3166 standard, available in CSV, JSON , PHP, SQL and XML formats, in multiple languages and with national flags included; also available are the ISO 3166-2 codes of provinces/ states associated with the countries

Stefan Gabos 1k Dec 29, 2022