Skip to content

Commit 56c5ebc

Browse files
authored
Merge pull request #9 from llm-agents-php/feature/refactr
refactor: Add coding standards and static analysis workflows
2 parents 7ac8c0a + 6fd662e commit 56c5ebc

25 files changed

+486
-436
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
3+
on: # yamllint disable-line rule:truthy
4+
pull_request:
5+
branches:
6+
- main
7+
push:
8+
branches:
9+
- main
10+
11+
name: 🧹 Fix PHP coding standards
12+
13+
jobs:
14+
coding-standards:
15+
permissions:
16+
contents: write
17+
uses: spiral/gh-actions/.github/workflows/cs-fix.yml@master

.github/workflows/refactoring.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
3+
on: # yamllint disable-line rule:truthy
4+
pull_request:
5+
paths:
6+
- 'src/**'
7+
- 'tests/**'
8+
- 'composer.*'
9+
push:
10+
paths:
11+
- 'src/**'
12+
- 'tests/**'
13+
- 'composer.*'
14+
15+
name: ⚙️ Refactoring
16+
17+
jobs:
18+
rector:
19+
timeout-minutes: 4
20+
runs-on: ${{ matrix.os }}
21+
concurrency:
22+
cancel-in-progress: true
23+
group: rector-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
24+
strategy:
25+
fail-fast: true
26+
matrix:
27+
os:
28+
- ubuntu-latest
29+
php-version:
30+
- '8.3'
31+
dependencies:
32+
- locked
33+
steps:
34+
- name: 📦 Check out the codebase
35+
uses: actions/checkout@v4
36+
37+
- name: 🛠️ Setup PHP
38+
uses: shivammathur/setup-php@2.32.0
39+
with:
40+
php-version: ${{ matrix.php-version }}
41+
extensions: none, ctype, curl, dom, json, mbstring, phar, simplexml, tokenizer, xml, xmlwriter, sockets, opcache, pcntl, posix, fileinfo
42+
ini-values: error_reporting=E_ALL
43+
coverage: none
44+
45+
- name: 🛠️ Setup problem matchers
46+
run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
47+
48+
- name: 🤖 Validate composer.json and composer.lock
49+
run: composer validate --ansi --strict
50+
51+
- name: 🔍 Get composer cache directory
52+
uses: wayofdev/gh-actions/actions/composer/get-cache-directory@v3.2.0
53+
54+
- name: ♻️ Restore cached dependencies installed with composer
55+
uses: actions/cache@v4
56+
with:
57+
path: ${{ env.COMPOSER_CACHE_DIR }}
58+
key: php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}
59+
restore-keys: php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-
60+
61+
- name: 📥 Install "${{ matrix.dependencies }}" dependencies
62+
uses: wayofdev/gh-actions/actions/composer/install@v3.2.0
63+
with:
64+
dependencies: ${{ matrix.dependencies }}
65+
66+
- name: 🔍 Run static analysis using rector/rector
67+
run: composer refactor:ci
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
3+
on: # yamllint disable-line rule:truthy
4+
pull_request:
5+
paths:
6+
- 'src/**'
7+
- 'composer.*'
8+
push:
9+
paths:
10+
- 'src/**'
11+
- 'composer.*'
12+
13+
name: 🔍 Static analysis
14+
15+
jobs:
16+
psalm:
17+
timeout-minutes: 4
18+
runs-on: ${{ matrix.os }}
19+
concurrency:
20+
cancel-in-progress: true
21+
group: psalm-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
22+
strategy:
23+
fail-fast: true
24+
matrix:
25+
os:
26+
- ubuntu-latest
27+
php-version:
28+
- '8.3'
29+
dependencies:
30+
- locked
31+
steps:
32+
- name: 📦 Check out the codebase
33+
uses: actions/checkout@v4
34+
35+
- name: 🛠️ Setup PHP
36+
uses: shivammathur/setup-php@2.32.0
37+
with:
38+
php-version: ${{ matrix.php-version }}
39+
extensions: none, ctype, curl, dom, json, mbstring, phar, simplexml, tokenizer, xml, xmlwriter, sockets, opcache, pcntl, posix, fileinfo
40+
ini-values: error_reporting=E_ALL
41+
coverage: none
42+
43+
- name: 🛠️ Setup problem matchers
44+
run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
45+
46+
- name: 🤖 Validate composer.json and composer.lock
47+
run: composer validate --ansi --strict
48+
49+
- name: 🔍 Get composer cache directory
50+
uses: wayofdev/gh-actions/actions/composer/get-cache-directory@v3.2.0
51+
52+
- name: ♻️ Restore cached dependencies installed with composer
53+
uses: actions/cache@v4
54+
with:
55+
path: ${{ env.COMPOSER_CACHE_DIR }}
56+
key: php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}
57+
restore-keys: php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-
58+
59+
- name: 📥 Install "${{ matrix.dependencies }}" dependencies
60+
uses: wayofdev/gh-actions/actions/composer/install@v3.2.0
61+
with:
62+
dependencies: ${{ matrix.dependencies }}
63+
64+
- name: 🔍 Run static analysis using vimeo/psalm
65+
run: composer psalm:ci

composer.json

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"php-mcp/schema": "^1.0",
2020
"psr/clock": "^1.0",
2121
"psr/container": "^1.0 || ^2.0",
22-
"psr/container-implementation": "*",
22+
"psr/container-implementation": "^1.0",
2323
"psr/log": "^1.0 || ^2.0 || ^3.0",
2424
"psr/http-server-middleware": "^1.0 || ^2.0 || ^3.0",
2525
"psr/simple-cache": "^1.0 || ^2.0 || ^3.0",
@@ -52,13 +52,17 @@
5252
}
5353
},
5454
"scripts": {
55-
"cs:fix": "php-cs-fixer fix -v",
56-
"psalm": "psalm",
57-
"psalm:baseline": "psalm --set-baseline=psalm-baseline.xml",
55+
"cs-check": "vendor/bin/php-cs-fixer fix --dry-run",
56+
"cs-fix": "vendor/bin/php-cs-fixer fix",
57+
"psalm": "vendor/bin/psalm --config=psalm.xml ./src",
58+
"psalm:ci": "vendor/bin/psalm --config=psalm.xml ./src --output-format=github --shepherd --show-info=false --stats --threads=4 --no-cache",
5859
"refactor": "rector process --config=rector.php",
5960
"refactor:ci": "rector process --config=rector.php --dry-run --ansi",
60-
"test": "phpunit",
61-
"test-coverage": "phpunit --coverage"
61+
"test": "vendor/bin/phpunit",
62+
"test:cc": [
63+
"@putenv XDEBUG_MODE=coverage",
64+
"phpunit --coverage-clover=.build/phpunit/logs/clover.xml --color=always"
65+
]
6266
},
6367
"config": {
6468
"sort-packages": true

psalm.xml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0"?>
2+
<psalm
3+
errorLevel="4"
4+
resolveFromConfigFile="true"
5+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6+
xmlns="https://getpsalm.org/schema/config"
7+
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
8+
findUnusedBaselineEntry="true"
9+
findUnusedCode="false"
10+
findUnusedVariablesAndParams="true"
11+
ensureOverrideAttribute="false"
12+
>
13+
<projectFiles>
14+
<directory name="src"/>
15+
<ignoreFiles>
16+
<file name="src/Transports/StreamableHttpServerTransport.php"/>
17+
<file name="src/Transports/HttpServerTransport.php"/>
18+
<directory name="vendor"/>
19+
<directory name="tests"/>
20+
</ignoreFiles>
21+
</projectFiles>
22+
</psalm>

src/Contracts/ReferenceProviderInterface.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Mcp\Server\Elements\RegisteredResourceTemplate;
1010
use Mcp\Server\Elements\RegisteredTool;
1111
use PhpMcp\Schema\Prompt;
12+
use PhpMcp\Schema\Resource;
1213
use PhpMcp\Schema\ResourceTemplate;
1314
use PhpMcp\Schema\Tool;
1415

src/Defaults/ArrayCache.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,7 @@ private function calculateExpiry(\DateInterval|int|null $ttl): ?int
9999
if (\is_int($ttl)) {
100100
return \time() + $ttl;
101101
}
102-
if ($ttl instanceof \DateInterval) {
103-
return (new \DateTime())->add($ttl)->getTimestamp();
104-
}
105102

106-
// Invalid TTL type, treat as no expiry
107-
return null;
103+
return (new \DateTime())->add($ttl)->getTimestamp();
108104
}
109105
}

src/Defaults/EnumCompletionProvider.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public function __construct(string $enumClass)
2222
}
2323

2424
$this->values = \array_map(
25-
static fn($case) => isset($case->value) && \is_string($case->value) ? $case->value : $case->name,
25+
static fn($case) => $case->value && \is_string($case->value) ? $case->value : $case->name,
2626
$enumClass::cases(),
2727
);
2828
}

src/Defaults/FileCache.php

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -213,20 +213,14 @@ private function readCacheFile(): array
213213

214214
return $data;
215215
} finally {
216-
if (\is_resource($handle)) {
217-
\fclose($handle);
218-
}
216+
\fclose($handle);
219217
}
220218
}
221219

222220
private function writeCacheFile(array $data): bool
223221
{
224222
$jsonData = \serialize($data);
225223

226-
if ($jsonData === false) {
227-
return false;
228-
}
229-
230224
$handle = @\fopen($this->cacheFile, 'cb');
231225
if ($handle === false) {
232226
return false;
@@ -252,9 +246,7 @@ private function writeCacheFile(array $data): bool
252246

253247
return false;
254248
} finally {
255-
if (\is_resource($handle)) {
256-
\fclose($handle);
257-
}
249+
\fclose($handle);
258250
}
259251
}
260252

@@ -276,17 +268,16 @@ private function calculateExpiry(\DateInterval|int|null $ttl): ?int
276268
return null;
277269
}
278270
$now = \time();
271+
279272
if (\is_int($ttl)) {
280273
return $ttl <= 0 ? $now - 1 : $now + $ttl;
281274
}
282-
if ($ttl instanceof \DateInterval) {
283-
try {
284-
return (new \DateTimeImmutable())->add($ttl)->getTimestamp();
285-
} catch (\Throwable) {
286-
return null;
287-
}
275+
276+
try {
277+
return (new \DateTimeImmutable())->add($ttl)->getTimestamp();
278+
} catch (\Throwable) {
279+
return null;
288280
}
289-
throw new \InvalidArgumentException('Invalid TTL type provided. Must be null, int, or DateInterval.');
290281
}
291282

292283
private function isExpired(?int $expiry): bool

src/Defaults/InMemoryEventStore.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Mcp\Server\Defaults;
66

77
use Mcp\Server\Contracts\EventStoreInterface;
8+
use Random\RandomException;
89

910
/**
1011
* Simple in-memory implementation of the EventStore interface for resumability
@@ -65,9 +66,12 @@ public function replayEventsAfter(string $lastEventId, callable $sendCallback):
6566
}
6667
}
6768

69+
/**
70+
* @throws RandomException
71+
*/
6872
private function generateEventId(string $streamId): string
6973
{
70-
return $streamId . '_' . (int) (\microtime(true) * 1000) . '_' . \bin2hex(\random_bytes(4));
74+
return $streamId . '_' . ((int) \microtime(true) * 1000) . '_' . \bin2hex(\random_bytes(4));
7175
}
7276

7377
private function getStreamIdFromEventId(string $eventId): ?string

0 commit comments

Comments
 (0)