Repository navigation
Route the Adapter throw sites through named constructors and remove VunerablePlatformQuoteException - #194
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
simon-mundy
force-pushed
the
exception/pr-5-adapter
branch
from
September 28, 2026 06:56
9870e98 to
be6922d
Compare
simon-mundy
force-pushed
the
exception/pr-5-adapter
branch
from
September 28, 2026 22:52
be6922d to
db83a9b
Compare
simon-mundy
added a commit
to simon-mundy/phpdb
that referenced
this pull request
Sep 28, 2026
… constructors The last 5 throw sites outside the components covered by php-db#191 to php-db#194. Message text is byte-identical, verified template by template against the originals. - Add ResultSet\Exception\RuntimeException::forUnbufferedIteration() - Add forNonAdapterAwareDelegate() to Exception\ContainerException, and give the three reasons that AdapterInterfaceFactory and AbstractAdapterInterfaceFactory passed as inline strings their own factories: forMissingConfigService(), forMissingConfiguration() and forMissingDriver(), each composing the reason into the SERVICE template - Retype the delegator's non-AdapterAware guard from the root Exception\RuntimeException to ContainerException, which extends it, so the failure carries PSR-11's ContainerExceptionInterface as a container failure should - Own the "not found in container" wording as ContainerException::MISSING_SERVICE while still throwing the ServiceManager's own ServiceNotFoundException. Laminas annotates that class @Final, so this package cannot own it; the throw site renders the template itself, which docs/book/exceptions.md now records as the single documented exception to the convention - Derive the message assertions in the six test files the earlier PRs do not touch from the templates rather than restating them One literal assertion is deliberately left in test/unit/Container/TableIdentifierFactoryFactoryTest.php: it asserts Sql\Exception\InvalidArgumentException::EMPTY_SEPARATOR, a constant php-db#192 introduces, so it can only be migrated once that has landed. Signed-off-by: Simon Mundy <simon.mundy@peptolab.com>
…unerablePlatformQuoteException All 26 throw sites in src/Adapter now call a named constructor. Message text is byte-identical, verified template by template against the originals. - Add 13 templates and factories to Adapter\Exception\RuntimeException, 6 to its InvalidArgumentException and 2 to InvalidQueryException - Converge the drifted PDO param message on the quoted form, per php-db#189 - Collapse the four "Data does not exist for this name/position" copies in ParameterContainer onto one template - Remove VunerablePlatformQuoteException. It held no state, implemented no external contract and reported a fail-fast setup error, so it met none of the three tests for a condition earning its own class. Its two throw sites now call RuntimeException::forVulnerablePlatformQuote(), which renders the same message, and the misspelling goes with the class - Drop the class from ExceptionHierarchyTest's EXCEPTION_CLASSES map and retire the guard's exemption, which existed only for that class, so no exception class is exempt from the constant naming rule any more - Give the two driver-error passthroughs a DRIVER_ERROR template of '%s', documented as carrying the driver's own wording verbatim - Cover every factory with a template test, and derive the 16 Adapter message assertions from the templates rather than restating them - Declare CoversMethod for Adapter::executeQuery(), which four tests exercise but none declared, so PHPUnit recorded no coverage for the method - Re-attribute three baselined entries to the factories and class that now carry them, exclude src/Adapter/Exception/ from too-many-methods, and baseline the halstead reading Pdo\Statement shifts InvalidConnectionParametersException keeps its constructor rather than gaining a named constructor: its message is supplied by the adapter that throws it, so there is no template for core to own. It earns its own class on the extra state it carries. BC: removing VunerablePlatformQuoteException breaks any catch of that exact type. It extended Adapter\Exception\RuntimeException, so a catch of that is unaffected. The tests in phpdb-pgsql and phpdb-sqlite that name the class need updating in their own repositories. Signed-off-by: Simon Mundy <simon.mundy@peptolab.com>
simon-mundy
force-pushed
the
exception/pr-5-adapter
branch
from
September 29, 2026 03:35
db83a9b to
583033b
Compare
simon-mundy
added a commit
to simon-mundy/phpdb
that referenced
this pull request
Sep 29, 2026
… constructors The last 5 throw sites outside the components covered by php-db#191 to php-db#194. Message text is byte-identical, verified template by template against the originals. - Add ResultSet\Exception\RuntimeException::forUnbufferedIteration() - Add forNonAdapterAwareDelegate() to Exception\ContainerException, and give the three reasons that AdapterInterfaceFactory and AbstractAdapterInterfaceFactory passed as inline strings their own factories: forMissingConfigService(), forMissingConfiguration() and forMissingDriver(), each composing the reason into the SERVICE template - Retype the delegator's non-AdapterAware guard from the root Exception\RuntimeException to ContainerException, which extends it, so the failure carries PSR-11's ContainerExceptionInterface as a container failure should - Own the "not found in container" wording as ContainerException::MISSING_SERVICE while still throwing the ServiceManager's own ServiceNotFoundException. Laminas annotates that class @Final, so this package cannot own it; the throw site renders the template itself, which docs/book/exceptions.md now records as the single documented exception to the convention - Derive the message assertions in the six test files the earlier PRs do not touch from the templates rather than restating them One literal assertion is deliberately left in test/unit/Container/TableIdentifierFactoryFactoryTest.php: it asserts Sql\Exception\InvalidArgumentException::EMPTY_SEPARATOR, a constant php-db#192 introduces, so it can only be migrated once that has landed. Signed-off-by: Simon Mundy <simon.mundy@peptolab.com>
Signed-off-by: Simon Mundy <simon.mundy@peptolab.com>
tyrsson
approved these changes
Sep 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Types of changes
Checklist:
Description
PR 5 of 6 from #189: all 26 throw sites in
src/Adapter, and the removal ofVunerablePlatformQuoteException.Message text is byte-identical, verified template by template against the original literals.
Adapter\Exception\RuntimeException, 6 on itsInvalidArgumentException, 2 onInvalidQueryException.%s.'Data does not exist for this name/position'copies inParameterContainercollapse onto one template.VunerablePlatformQuoteExceptionis removedIt held no state, implemented no external contract, and reported a fail-fast setup error a caller cannot recover from, so it met none of the three tests for a condition earning its own class. Its two throw sites now call
RuntimeException::forVulnerablePlatformQuote(), which renders the identical message, and the misspelling goes with the class.That also retires the one exemption in
ExceptionHierarchyTest, which existed solely for this class. No exception class is exempt from the constant naming rule any more.There is no BC shim, deliberately. The class was
final, so nobody can have subclassed it, but aclass_alias()toAdapter\Exception\RuntimeExceptionwould be worse than the break:catch (VunerablePlatformQuoteException)would silently start catching every adapter runtime failure. It already extendedAdapter\Exception\RuntimeException, so anything catching that is unaffected.The driver-error passthroughs
Pdo\StatementandPdo\AbstractPdoConnectionthrow with PDO's own error text as the whole message. Both now use aDRIVER_ERRORtemplate of'%s', documented on the constant as carrying the driver's wording verbatim. It is a thin template, but it keeps the throw site free of message assembly and keeps every factory under the naming guard.One deviation from the plan on #189
InvalidConnectionParametersExceptionkeeps its constructor rather than gaining a named constructor. Its message is supplied by the adapter that throws it, so there is no template for core to own — an adapter-specific message does not belong in a core constant. It earns its own class on the extra state it carries.Motivation and Context
Refs #189. Depends on #190.
Downstream work this creates.
phpdb-pgsqlandphpdb-sqliteeach have one test file naming the removed class (3 and 2 references). Those need a one-line import swap andexpectException(RuntimeException::class)in their own repositories. Both already requirephp-db/phpdb: ^0.6.0, which is unreleased, so those changes cannot go green until 0.6.0 ships — they should follow this merge, not precede it.phpdb-mysqlhas no references.How has this been tested?
mago format --check,mago lintandmago analyzeall exit 0. Full unit suite passes: 1681 tests, 3581 assertions.Every factory is covered: 13/13, 6/6 and 2/2. All 21 templates verified byte-identical against the original literals by a throwaway script before the call sites were touched, including a check that
forVulnerablePlatformQuote()reproduces the removed class's message exactly.Baseline and configuration changes
Three baselined entries are re-attributed, not added to, because the same findings moved rather than appeared:
mixed-argumentonException::__constructinAbstractPdoConnectionInvalidQueryException::forDriverErrorunhandled-thrown-typeVunerablePlatformQuoteExceptioninSql92::quoteValueRuntimeExceptionunhandled-thrown-typeVunerablePlatformQuoteExceptioninAbstractPlatform::quoteValueRuntimeExceptionsrc/Adapter/Exception/is added to thetoo-many-methodsexclude inmago.toml, as Route the Sql throw sites through named constructors #192 and Route the TableGateway and RowGateway throw sites through named constructors #193 do for their components. The threshold is 10 and the catalogue holds 13. This will conflict with Route the Sql throw sites through named constructors #192 and Route the TableGateway and RowGateway throw sites through named constructors #193 on the same line — the paths need merging into one array as they land.halsteadreading onPdo\Statementis baselined. Removing long string literals reduces distinct operands, which raises halstead difficulty.