Skip to content

Add PHPStan query contract checks#104

Open
koriym wants to merge 3 commits into
1.xfrom
add-phpstan-contract-rule
Open

Add PHPStan query contract checks#104
koriym wants to merge 3 commits into
1.xfrom
add-phpstan-contract-rule

Conversation

@koriym

@koriym koriym commented Jun 9, 2026

Copy link
Copy Markdown
Member

Summary

  • add bundled optional PHPStan rules for #[DbQuery] contracts under src-sa
  • validate SQL file existence/emptiness, Pager return consistency, and factory class/method existence
  • wire the extension into root Composer/PHPStan config while keeping PHPStan as a dev-only/suggested dependency

Self-review

  • confirmed the extension remains an optional bundled feature, not a runtime dependency
  • confirmed interface fixtures are covered by RuleTestCase
  • checked SQL-only cache behavior is documented
  • checked ComposerRequireChecker ignores only the optional PHPStan extension symbols
  • checked diff for whitespace issues with git diff --check

Tests

  • composer test:phpstan
  • composer sa
  • composer tests
  • composer validate --no-check-all --strict
  • vendor-bin/tools/vendor/bin/composer-require-checker check ./composer.json --config-file=./composer-require-checker.json

Summary by CodeRabbit

  • New Features

    • Added a PHPStan extension that validates database query attributes, including SQL file existence, pagination return type contracts, and factory configuration validation.
  • Documentation

    • Added comprehensive documentation for the new PHPStan extension with configuration instructions and validation rule coverage details.
  • Chores

    • Updated development tooling configuration and autoloading to support the PHPStan extension workflow.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a PHPStan extension for Ray.MediaQuery that enforces query contract validation through attributes. The extension scans decorated methods for #[DbQuery] and #[Pager] annotations, validates associated SQL files exist and are non-empty, and checks factory method configurations.

Changes

PHPStan Rule Extension for Query Contracts

Layer / File(s) Summary
Project configuration and dependency wiring
.gitignore, composer.json, composer-require-checker.json, phpcs.xml, phpstan.neon
Added PHPStan and tooling dependencies, configured autoload PSR-4 mappings for the Ray\MediaQuery\PHPStan\* namespaces, updated code analysis scope to include src-sa/ directories, and registered whitelisted symbols for static analysis.
PHPStan extension configuration and documentation
src-sa/extension.neon, src-sa/README.md
Defined the extension NEON service for DbQueryContractRule with configurable sqlDirectories and factoryMethod parameters, and documented the extension purpose, installation, configuration, rule coverage, and cache-clearing behavior.
Core rule and support utilities
src-sa/src/Rules/DbQueryContractRule.php, src-sa/src/Support/*
Implemented DbQueryContractRule to extract #[DbQuery] and #[Pager] attributes, validate SQL file existence/non-emptiness via SqlFileResolver, check return-type contracts against PagesInterface, and verify factory class/method presence via reflection. Added SqlFileResolver for path resolution and NamedParameterExtractor for SQL parameter parsing (unused in rule but provided as utility). Also added DbQueryMetadata value object for attribute data.
Test infrastructure setup
src-sa/phpunit.xml.dist, src-sa/tests/bootstrap.php, src-sa/tests/phpstan-rule-tests.neon
Configured PHPUnit with bootstrap autoloader and cache directory, registered custom SPL autoloader for test namespaces, and defined PHPStan rule test fixture scan paths.
Test data fixtures
src-sa/tests/Rules/Data/valid.php, src-sa/tests/Rules/Data/invalid.php, src-sa/tests/Rules/Data/*.php, src-sa/tests/Rules/Data/sql/valid.sql
Created valid and invalid interface fixtures with attribute-annotated methods covering correct annotations, pagination mismatches, missing SQL, missing factory classes/methods, and a SQL fixture file for resolver testing.
Rule and utility tests
src-sa/tests/Rules/DbQueryContractRuleTest.php, src-sa/tests/Support/NamedParameterExtractorTest.php
Added rule tests asserting no errors on valid fixtures and specific error counts/line numbers on invalid fixtures; added unit tests for NamedParameterExtractor across various SQL syntaxes, comments, and quoted regions.

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • NaokiTsuchiya
  • jingu

🐰 A PHPStan guardian awakens,
Query contracts now have teeth,
SQL files must exist—
Factories dance in strict type's light,
Pagination finds its home.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.68% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add PHPStan query contract checks' accurately describes the main addition: bundled PHPStan rules validating #[DbQuery] contracts, Pager return types, and factory configurations.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-phpstan-contract-rule

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 PHPStan (2.2.1)

PHPStan was skipped because the config uses disallowed bootstrapFiles, bootstrapFile, or includes directives.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@koriym koriym marked this pull request as ready for review June 9, 2026 05:52

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src-sa/src/Support/SqlFileResolver.php (1)

35-46: 💤 Low value

Consider guarding against getcwd() failure.

getcwd() returns string|false but is cast to string without checking for failure. If the current working directory becomes inaccessible, casting false to string produces an empty string, leading to incorrect path resolution.

While this scenario is rare in static analysis contexts, adding a guard would improve robustness.

🛡️ Defensive handling option
 private function absolutePath(string $path): string
 {
+    $cwd = getcwd();
+    if ($cwd === false) {
+        throw new \RuntimeException('Unable to determine current working directory');
+    }
+
     if ($path === '') {
-        return (string) getcwd();
+        return $cwd;
     }

     if (preg_match('#^([A-Za-z]:)?/#', $path) === 1) {
         return $path;
     }

-    return (string) getcwd() . '/' . ltrim($path, '/');
+    return $cwd . '/' . ltrim($path, '/');
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-sa/src/Support/SqlFileResolver.php` around lines 35 - 46, The
absolutePath method should guard against getcwd() returning false: in
absolutePath(string $path) call getcwd() once into a variable, check if it ===
false and handle it (throw a RuntimeException or use a sensible fallback like
dirname(__DIR__) or PATH_ROOT) before casting/concatenating; update both the
empty-path branch and the final return to use this safe cwd value and keep the
existing path normalization (preg_match and ltrim) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src-sa/src/Support/SqlFileResolver.php`:
- Around line 35-46: The absolutePath method should guard against getcwd()
returning false: in absolutePath(string $path) call getcwd() once into a
variable, check if it === false and handle it (throw a RuntimeException or use a
sensible fallback like dirname(__DIR__) or PATH_ROOT) before
casting/concatenating; update both the empty-path branch and the final return to
use this safe cwd value and keep the existing path normalization (preg_match and
ltrim) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dd2d0acb-1bb3-484d-893c-5138240779e2

📥 Commits

Reviewing files that changed from the base of the PR and between 001b3ce and ca18001.

📒 Files selected for processing (24)
  • .gitignore
  • composer-require-checker.json
  • composer.json
  • phpcs.xml
  • phpstan.neon
  • src-sa/README.md
  • src-sa/extension.neon
  • src-sa/phpunit.xml.dist
  • src-sa/src/Rules/DbQueryContractRule.php
  • src-sa/src/Support/DbQueryMetadata.php
  • src-sa/src/Support/NamedParameterExtractor.php
  • src-sa/src/Support/SqlFileResolver.php
  • src-sa/tests/Rules/Data/FactoryWithoutFactoryMethod.php
  • src-sa/tests/Rules/Data/ValidInstanceFactory.php
  • src-sa/tests/Rules/Data/ValidPostQueryResult.php
  • src-sa/tests/Rules/Data/ValidStaticFactory.php
  • src-sa/tests/Rules/Data/invalid.php
  • src-sa/tests/Rules/Data/sql/empty.sql
  • src-sa/tests/Rules/Data/sql/valid.sql
  • src-sa/tests/Rules/Data/valid.php
  • src-sa/tests/Rules/DbQueryContractRuleTest.php
  • src-sa/tests/Support/NamedParameterExtractorTest.php
  • src-sa/tests/bootstrap.php
  • src-sa/tests/phpstan-rule-tests.neon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant