Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ permissions:
contents: read

jobs:
minimal-install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: '8.5'
coverage: none
- uses: ramsey/composer-install@v3
with:
dependency-versions: locked
composer-options: --no-dev
- name: Enforce the HTTP kernel dependency boundary
run: |
test ! -d vendor/illuminate
php -r "require 'vendor/autoload.php'; new Pam\\App(); fwrite(STDOUT, \"minimal-boot-ok\\n\");"

verify:
runs-on: ubuntu-latest
strategy:
Expand All @@ -23,4 +40,3 @@ jobs:
coverage: none
- uses: ramsey/composer-install@v3
- run: composer verify

12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Express-like routing. Laravel-like application structure. PAM-native execution.
**[Official documentation](https://push-in.github.io/pam-docs/packages/http/) ·
[PAM introduction](https://push-in.github.io/pam-docs/introduction/) ·
[Upgrade guide](UPGRADE.md) · [Changelog](CHANGELOG.md) ·
[Architecture](docs/ARCHITECTURE.md) ·
[Report an issue](https://github.com/push-in/pam-http/issues)**

## Start here
Expand Down Expand Up @@ -47,9 +48,16 @@ final readonly class LoginController
}
```

## Eloquent ORM (default)
## Eloquent ORM (optional)

PAM API ships with Laravel's Eloquent as its official ORM. The integration
PAM HTTP keeps its kernel independent from any database. Install Eloquent only
when the application needs the legacy built-in integration:

```bash
pam composer require illuminate/database illuminate/events illuminate/filesystem illuminate/pagination
```

The integration
keeps a separate connection manager per request Fiber, so connections,
transactions and mutable database state cannot leak between persistent-worker
requests.
Expand Down
5 changes: 4 additions & 1 deletion benchmarks/router.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
const MAXIMUM_P99_NANOSECONDS = 500_000;
const MAXIMUM_PEAK_MEMORY_BYTES = 67_108_864;

$assertBudget = in_array('--assert', array_slice($argv, 1), true);
$arguments = isset($_SERVER['argv']) && is_array($_SERVER['argv'])
? array_values(array_filter($_SERVER['argv'], is_string(...)))
: [];
$assertBudget = in_array('--assert', array_slice($arguments, 1), true);
$router = new Router();
for ($index = 1; $index <= 100; ++$index) {
$router->add('GET', "/static/{$index}", static fn (): null => null);
Expand Down
22 changes: 18 additions & 4 deletions bin/api-compat
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,18 @@ enum PublicApiChangeCode: int
$root = dirname(__DIR__);
require $root . '/vendor/autoload.php';

$mode = $argv[1] ?? 'check';
if (!in_array($mode, ['check', 'update'], true) || count($argv) > 3) {
$arguments = isset($_SERVER['argv']) && is_array($_SERVER['argv'])
? array_values(array_filter($_SERVER['argv'], is_string(...)))
: [];
$mode = $arguments[1] ?? 'check';
if (!in_array($mode, ['check', 'update'], true) || count($arguments) > 3) {
fwrite(STDERR, "Usage: bin/api-compat [check|update] [baseline.json]\n");
exit(2);
}

try {
$current = snapshot($root . '/src');
$baselinePath = $argv[2] ?? $root . '/api-surface.json';
$baselinePath = $arguments[2] ?? $root . '/api-surface.json';
if ($baselinePath === '' || strlen($baselinePath) > 4_096) {
throw new RuntimeException('Public API baseline path is invalid.');
}
Expand Down Expand Up @@ -415,7 +418,13 @@ function compareMethods(array &$changes, string $symbol, array $before, array $a
continue;
}
foreach (['static', 'abstract', 'returnsReference', 'return'] as $field) {
if (($oldMethod[$field] ?? null) !== ($newMethod[$field] ?? null)) {
$oldValue = $oldMethod[$field] ?? null;
$newValue = $newMethod[$field] ?? null;
if ($field === 'return') {
$oldValue = canonicalMethodReturn($oldValue, $symbol);
$newValue = canonicalMethodReturn($newValue, $symbol);
}
if ($oldValue !== $newValue) {
$changes[] = change(PublicApiChangeCode::ChangedMember, $path, "method {$field} changed");
}
}
Expand All @@ -439,6 +448,11 @@ function compareMethods(array &$changes, string $symbol, array $before, array $a
}
}

function canonicalMethodReturn(mixed $returnType, string $declaringClass): mixed
{
return $returnType === 'self' ? $declaringClass : $returnType;
}

/**
* @param array<string, mixed> $value
* @return list<string>
Expand Down
9 changes: 6 additions & 3 deletions bin/api-reference
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ declare(strict_types=1);

const MAXIMUM_REFERENCE_BASELINE_BYTES = 4_194_304;

$mode = $argv[1] ?? '--check';
$output = $argv[2] ?? dirname(__DIR__) . '/docs/PUBLIC-API.md';
if (!in_array($mode, ['--check', '--write'], true) || count($argv) > 3) {
$arguments = isset($_SERVER['argv']) && is_array($_SERVER['argv'])
? array_values(array_filter($_SERVER['argv'], is_string(...)))
: [];
$mode = $arguments[1] ?? '--check';
$output = $arguments[2] ?? dirname(__DIR__) . '/docs/PUBLIC-API.md';
if (!in_array($mode, ['--check', '--write'], true) || count($arguments) > 3) {
fwrite(STDERR, "Usage: bin/api-reference [--check|--write] [output.md]\n");
exit(2);
}
Expand Down
16 changes: 10 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@
"router",
"validation"
],
"homepage": "https://github.com/push-in/pam",
"homepage": "https://github.com/push-in/pam-http",
"support": {
"docs": "https://push-in.github.io/pam-docs/packages/http/",
"issues": "https://github.com/push-in/pam/issues",
"issues": "https://github.com/push-in/pam-http/issues",
"source": "https://github.com/push-in/pam-http"
},
"require": {
"php": "^8.4",
"illuminate/database": "^13.0",
"illuminate/events": "^13.0",
"illuminate/filesystem": "^13.0",
"illuminate/pagination": "^13.0",
"pushinbr/pam-contracts": "^1.1"
},
"suggest": {
"illuminate/database": "Required by the deprecated built-in Eloquent bridge; use the dedicated PAM database adapter when available.",
"illuminate/events": "Required by the deprecated built-in Eloquent bridge.",
"illuminate/filesystem": "Required by the deprecated built-in migration bridge.",
"illuminate/pagination": "Required by the deprecated built-in Eloquent resource pagination bridge.",
"pushinbr/pam-psr": "PSR-7, PSR-15 and PSR-17 interoperability.",
"pushinbr/pam-socket": "High-level event and room APIs for Pam WebSockets."
},
Expand Down Expand Up @@ -68,6 +68,10 @@
"sort-packages": true
},
"require-dev": {
"illuminate/database": "^13.0",
"illuminate/events": "^13.0",
"illuminate/filesystem": "^13.0",
"illuminate/pagination": "^13.0",
"phpstan/phpstan": "^2.1",
"phpunit/phpunit": "^11.5"
}
Expand Down
Loading
Loading