From c8cbdad97134c2cd74b2f3d48775fb16513f3ec1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 12:11:35 +0000 Subject: [PATCH 1/8] Initial plan From 0e05daf0527239b9f809d82920328dcc60fa0f30 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 12:16:25 +0000 Subject: [PATCH 2/8] Fix PHP 8.2+ trait property conflict, fix test bootstrap, add GitHub CI Co-authored-by: daedeloth <1168599+daedeloth@users.noreply.github.com> --- .github/workflows/ci.yml | 34 +++++++++++++++++++ .../Routing/Parameters/Base/Parameter.php | 6 +--- tests/bootstrap.php | 2 +- 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e15ddfe --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + tests: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + php-version: ['8.1', '8.2', '8.3', '8.4'] + + name: PHP ${{ matrix.php-version }} + + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: mbstring + coverage: none + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + - name: Run tests + run: vendor/bin/phpunit diff --git a/src/Models/Routing/Parameters/Base/Parameter.php b/src/Models/Routing/Parameters/Base/Parameter.php index fbff198..91c537f 100644 --- a/src/Models/Routing/Parameters/Base/Parameter.php +++ b/src/Models/Routing/Parameters/Base/Parameter.php @@ -54,11 +54,6 @@ class Parameter implements RouteMutator, Property */ protected $in; - /** - * @var string - */ - protected $type = 'string'; - /** * @var Route */ @@ -103,6 +98,7 @@ public function __construct($name, $type) { $this->name = $name; $this->in = $type; + $this->type = 'string'; } /** diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 79c43b5..06fdcb4 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -2,4 +2,4 @@ declare(strict_types=1); -require __DIR__ . '/vendor/autoload.php'; +require __DIR__ . '/../vendor/autoload.php'; From 48ebcdfa10c8e9b03989dbc47591dbf9d5599b29 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 12:17:32 +0000 Subject: [PATCH 3/8] Add permissions block to CI workflow Co-authored-by: daedeloth <1168599+daedeloth@users.noreply.github.com> --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e15ddfe..c277c6e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ master ] +permissions: + contents: read + jobs: tests: runs-on: ubuntu-latest From 893f72a95b283ef6775dbbc1d9c1e16ccd83b630 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 12:35:02 +0000 Subject: [PATCH 4/8] Fix failing tests: parameter separator, method visibility, null guard, update swagger fixture Co-authored-by: daedeloth <1168599+daedeloth@users.noreply.github.com> --- src/Resolvers/ResolverBase.php | 6 +++- tests/Models/MockPropertyResolver.php | 2 +- tests/swagger/description.json | 47 ++++++++++++++++----------- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/Resolvers/ResolverBase.php b/src/Resolvers/ResolverBase.php index c1cfb7f..f59b8c0 100644 --- a/src/Resolvers/ResolverBase.php +++ b/src/Resolvers/ResolverBase.php @@ -23,7 +23,7 @@ class ResolverBase { public const CHILDPATH_PATH_SEPARATOR = '.'; - public const CHILDPATH_PARAMETER_SEPARATOR = '|'; + public const CHILDPATH_PARAMETER_SEPARATOR = ':'; public const CHILDPATH_VARIABLE_OPEN = '{'; @@ -177,6 +177,10 @@ protected function parseParameters( */ protected function getValueFromEntity($entity, $name, array $getterParameters, Context $context) { + if ($entity === null) { + return null; + } + // Check for get method if ($this->methodExists($entity, 'get'.ucfirst($name))) { return call_user_func_array([$entity, 'get'.ucfirst($name)], $getterParameters); diff --git a/tests/Models/MockPropertyResolver.php b/tests/Models/MockPropertyResolver.php index 0a0a9e7..965cdf2 100644 --- a/tests/Models/MockPropertyResolver.php +++ b/tests/Models/MockPropertyResolver.php @@ -10,7 +10,7 @@ class MockPropertyResolver extends \CatLab\Charon\Resolvers\PropertyResolver * @param string $path * @return mixed */ - protected function splitPathParameters(string $path): array + public function splitPathParameters(string $path): array { return parent::splitPathParameters($path); } diff --git a/tests/swagger/description.json b/tests/swagger/description.json index 3ccf9a7..46749b4 100644 --- a/tests/swagger/description.json +++ b/tests/swagger/description.json @@ -1,19 +1,19 @@ { "swagger": "2.0", "host": "localhost", - "basePath": "\/", + "basePath": "/", "info": { "title": "Pet store API", "description": "This pet store api allows you to buy pets", "contact": { "name": "CatLab Interactive", - "url": "https:\/\/www.catlab.eu\/", + "url": "https://www.catlab.eu/", "email": "info@catlab.eu" }, "version": "1.0" }, "paths": { - "api\/v1\/description.{format}": { + "api/v1/description.{format}": { "get": { "responses": { "403": { @@ -47,12 +47,12 @@ } } }, - "api\/v1\/pets.{format}": { + "api/v1/pets.{format}": { "get": { "responses": { "200": { "schema": { - "$ref": "#\/definitions\/Pet_index_items" + "$ref": "#/definitions/Pet_index_items" }, "description": "Returns many Tests\\Petstore\\Models\\Pet" }, @@ -135,7 +135,7 @@ "type": "array", "in": "query", "required": false, - "description": "Define fields to return. Separate multiple values with comma. Values: *, pet-id, name, category, category.*, category.name, category.category-description, photos, photos.*, photos.url, tags, tags.*, tags.name, status", + "description": "Define fields to return. Separate multiple values with comma. Values: *, pet-id, name, category, category.*, category.category-id, category.name, category.category-description, photos, photos.*, photos.photo-id, photos.url, tags, tags.*, tags.tag-id, tags.name, status", "items": { "type": "string" }, @@ -145,13 +145,16 @@ "name", "category", "category.*", + "category.category-id", "category.name", "category.category-description", "photos", "photos.*", + "photos.photo-id", "photos.url", "tags", "tags.*", + "tags.tag-id", "tags.name", "status" ] @@ -164,12 +167,12 @@ } } }, - "api\/v1\/pets\/{id}.{format}": { + "api/v1/pets/{id}.{format}": { "get": { "responses": { "200": { "schema": { - "$ref": "#\/definitions\/Pet_view" + "$ref": "#/definitions/Pet_view" }, "description": "Returns one Tests\\Petstore\\Models\\Pet" }, @@ -219,7 +222,7 @@ "type": "array", "in": "query", "required": false, - "description": "Define fields to return. Separate multiple values with comma. Values: *, pet-id, name, category, category.*, category.name, category.category-description, photos, photos.*, photos.url, tags, tags.*, tags.name, status", + "description": "Define fields to return. Separate multiple values with comma. Values: *, pet-id, name, category, category.*, category.category-id, category.name, category.category-description, photos, photos.*, photos.photo-id, photos.url, tags, tags.*, tags.tag-id, tags.name, status", "items": { "type": "string" }, @@ -229,13 +232,16 @@ "name", "category", "category.*", + "category.category-id", "category.name", "category.category-description", "photos", "photos.*", + "photos.photo-id", "photos.url", "tags", "tags.*", + "tags.tag-id", "tags.name", "status" ] @@ -251,7 +257,7 @@ "responses": { "200": { "schema": { - "$ref": "#\/definitions\/Pet_view" + "$ref": "#/definitions/Pet_view" }, "description": "Returns one Tests\\Petstore\\Models\\Pet" }, @@ -286,7 +292,7 @@ "in": "body", "required": false, "schema": { - "$ref": "#\/definitions\/Pet_edit" + "$ref": "#/definitions/Pet_edit" } }, { @@ -309,7 +315,7 @@ "type": "array", "in": "query", "required": false, - "description": "Define fields to return. Separate multiple values with comma. Values: *, pet-id, name, category, category.*, category.name, category.category-description, photos, photos.*, photos.url, tags, tags.*, tags.name, status", + "description": "Define fields to return. Separate multiple values with comma. Values: *, pet-id, name, category, category.*, category.category-id, category.name, category.category-description, photos, photos.*, photos.photo-id, photos.url, tags, tags.*, tags.tag-id, tags.name, status", "items": { "type": "string" }, @@ -319,20 +325,23 @@ "name", "category", "category.*", + "category.category-id", "category.name", "category.category-description", "photos", "photos.*", + "photos.photo-id", "photos.url", "tags", "tags.*", + "tags.tag-id", "tags.name", "status" ] } ], "consumes": [ - "application\/json" + "application/json" ], "security": { "oauth2": [ @@ -357,7 +366,7 @@ "items": { "type": "array", "items": { - "$ref": "#\/definitions\/Pet_index" + "$ref": "#/definitions/Pet_index" } } } @@ -407,10 +416,10 @@ "type": "string" }, "photos": { - "$ref": "#\/definitions\/Photo_create_items" + "$ref": "#/definitions/Photo_create_items" }, "tags": { - "$ref": "#\/definitions\/Tag_identifier_items" + "$ref": "#/definitions/Tag_identifier_items" } } }, @@ -428,7 +437,7 @@ "items": { "type": "array", "items": { - "$ref": "#\/definitions\/Photo_create" + "$ref": "#/definitions/Photo_create" } } } @@ -447,7 +456,7 @@ "items": { "type": "array", "items": { - "$ref": "#\/definitions\/Tag_identifier" + "$ref": "#/definitions/Tag_identifier" } } } @@ -456,7 +465,7 @@ "securityDefinitions": { "oauth2": { "type": "oauth2", - "authorizationUrl": "oauth\/authorize", + "authorizationUrl": "oauth/authorize", "flow": "implicit", "scopes": { "full": "Full access" From 24803b9fbbe87576a3049111505f7d5e5e7569c7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 12:42:55 +0000 Subject: [PATCH 5/8] Revert CHILDPATH_PARAMETER_SEPARATOR to | and update tests to use pipe syntax Co-authored-by: daedeloth <1168599+daedeloth@users.noreply.github.com> --- src/Resolvers/ResolverBase.php | 2 +- tests/Models/MockResourceDefinition.php | 4 ++-- tests/PropertyResolverTest.php | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Resolvers/ResolverBase.php b/src/Resolvers/ResolverBase.php index f59b8c0..e3a9f0e 100644 --- a/src/Resolvers/ResolverBase.php +++ b/src/Resolvers/ResolverBase.php @@ -23,7 +23,7 @@ class ResolverBase { public const CHILDPATH_PATH_SEPARATOR = '.'; - public const CHILDPATH_PARAMETER_SEPARATOR = ':'; + public const CHILDPATH_PARAMETER_SEPARATOR = '|'; public const CHILDPATH_VARIABLE_OPEN = '{'; diff --git a/tests/Models/MockResourceDefinition.php b/tests/Models/MockResourceDefinition.php index fd8a681..4c3ea28 100644 --- a/tests/Models/MockResourceDefinition.php +++ b/tests/Models/MockResourceDefinition.php @@ -15,13 +15,13 @@ public function __construct() ->display('name') ->visible(true) - ->relationship('nthChild:0', MockResourceDefinition::class) + ->relationship('nthChild|0', MockResourceDefinition::class) ->display('firstChild') ->expanded() ->visible() ->one() - ->relationship('nthChild:{context.childNumber}', MockResourceDefinition::class) + ->relationship('nthChild|{context.childNumber}', MockResourceDefinition::class) ->display('nthChild') ->expanded() ->visible() diff --git a/tests/PropertyResolverTest.php b/tests/PropertyResolverTest.php index 4f200bb..5141d8c 100644 --- a/tests/PropertyResolverTest.php +++ b/tests/PropertyResolverTest.php @@ -40,8 +40,8 @@ public function testPathParameters(): void ); $this->assertEquals( - [ 'filteredAttachments:{context.revision}:{context.currentUser}' ], - $propertyResolver->splitPathParameters('filteredAttachments:{context.revision}:{context.currentUser}') + [ 'filteredAttachments|{context.revision}|{context.currentUser}' ], + $propertyResolver->splitPathParameters('filteredAttachments|{context.revision}|{context.currentUser}') ); } @@ -58,8 +58,8 @@ public function testPathParametersWithSubtypes(): void ); $this->assertEquals( - [ 'method:{variable.subtype}', 'parameter' ], - $propertyResolver->splitPathParameters('method:{variable.subtype}.parameter') + [ 'method|{variable.subtype}', 'parameter' ], + $propertyResolver->splitPathParameters('method|{variable.subtype}.parameter') ); } @@ -85,7 +85,7 @@ public function testResolvePathParameters(): void $this->assertEquals( '/url/2', - $propertyResolver->resolvePathParameters($transformer, $model, '/url/{model.nthChild:0.id}', $context) + $propertyResolver->resolvePathParameters($transformer, $model, '/url/{model.nthChild|0.id}', $context) ); $this->assertEquals( From edc2cd017eb9754ffad2fcb01ad1a2f39f539a17 Mon Sep 17 00:00:00 2001 From: Thijs Van der Schaeghe Date: Thu, 19 Feb 2026 13:55:14 +0100 Subject: [PATCH 6/8] Revert back to original parameter separator --- src/Resolvers/ResolverBase.php | 2 +- tests/Models/MockResourceDefinition.php | 4 ++-- tests/PropertyResolverTest.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Resolvers/ResolverBase.php b/src/Resolvers/ResolverBase.php index e3a9f0e..f59b8c0 100644 --- a/src/Resolvers/ResolverBase.php +++ b/src/Resolvers/ResolverBase.php @@ -23,7 +23,7 @@ class ResolverBase { public const CHILDPATH_PATH_SEPARATOR = '.'; - public const CHILDPATH_PARAMETER_SEPARATOR = '|'; + public const CHILDPATH_PARAMETER_SEPARATOR = ':'; public const CHILDPATH_VARIABLE_OPEN = '{'; diff --git a/tests/Models/MockResourceDefinition.php b/tests/Models/MockResourceDefinition.php index 4c3ea28..fd8a681 100644 --- a/tests/Models/MockResourceDefinition.php +++ b/tests/Models/MockResourceDefinition.php @@ -15,13 +15,13 @@ public function __construct() ->display('name') ->visible(true) - ->relationship('nthChild|0', MockResourceDefinition::class) + ->relationship('nthChild:0', MockResourceDefinition::class) ->display('firstChild') ->expanded() ->visible() ->one() - ->relationship('nthChild|{context.childNumber}', MockResourceDefinition::class) + ->relationship('nthChild:{context.childNumber}', MockResourceDefinition::class) ->display('nthChild') ->expanded() ->visible() diff --git a/tests/PropertyResolverTest.php b/tests/PropertyResolverTest.php index 5141d8c..ac4c161 100644 --- a/tests/PropertyResolverTest.php +++ b/tests/PropertyResolverTest.php @@ -40,7 +40,7 @@ public function testPathParameters(): void ); $this->assertEquals( - [ 'filteredAttachments|{context.revision}|{context.currentUser}' ], + [ 'filteredAttachments:{context.revision}:{context.currentUser}' ], $propertyResolver->splitPathParameters('filteredAttachments|{context.revision}|{context.currentUser}') ); } From 6baa10a1afc650d73886f2568e90f4c3297ae284 Mon Sep 17 00:00:00 2001 From: Thijs Van der Schaeghe Date: Thu, 19 Feb 2026 13:58:38 +0100 Subject: [PATCH 7/8] Revert back to original parameter separator --- tests/PropertyResolverTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/PropertyResolverTest.php b/tests/PropertyResolverTest.php index ac4c161..03263ef 100644 --- a/tests/PropertyResolverTest.php +++ b/tests/PropertyResolverTest.php @@ -41,7 +41,7 @@ public function testPathParameters(): void $this->assertEquals( [ 'filteredAttachments:{context.revision}:{context.currentUser}' ], - $propertyResolver->splitPathParameters('filteredAttachments|{context.revision}|{context.currentUser}') + $propertyResolver->splitPathParameters('filteredAttachments:{context.revision}:{context.currentUser}') ); } @@ -58,8 +58,8 @@ public function testPathParametersWithSubtypes(): void ); $this->assertEquals( - [ 'method|{variable.subtype}', 'parameter' ], - $propertyResolver->splitPathParameters('method|{variable.subtype}.parameter') + [ 'method:{variable.subtype}', 'parameter' ], + $propertyResolver->splitPathParameters('method:{variable.subtype}.parameter') ); } @@ -85,7 +85,7 @@ public function testResolvePathParameters(): void $this->assertEquals( '/url/2', - $propertyResolver->resolvePathParameters($transformer, $model, '/url/{model.nthChild|0.id}', $context) + $propertyResolver->resolvePathParameters($transformer, $model, '/url/{model.nthChild:"0.id}', $context) ); $this->assertEquals( From 0cc8e29742f2d95c48f6543e68c52f1ef22bc1ee Mon Sep 17 00:00:00 2001 From: Thijs Van der Schaeghe Date: Thu, 19 Feb 2026 14:01:47 +0100 Subject: [PATCH 8/8] Revert back to original parameter separator --- tests/PropertyResolverTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PropertyResolverTest.php b/tests/PropertyResolverTest.php index 03263ef..4f200bb 100644 --- a/tests/PropertyResolverTest.php +++ b/tests/PropertyResolverTest.php @@ -85,7 +85,7 @@ public function testResolvePathParameters(): void $this->assertEquals( '/url/2', - $propertyResolver->resolvePathParameters($transformer, $model, '/url/{model.nthChild:"0.id}', $context) + $propertyResolver->resolvePathParameters($transformer, $model, '/url/{model.nthChild:0.id}', $context) ); $this->assertEquals(