classReferentialIntegrityEnforcer
final class ReferentialIntegrityEnforcer
Carries what a statement did outward through the constraints that declare it.
A write to a parent table does not stop at that table: a key declared ON DELETE CASCADE takes the children with it, and those children may themselves be parents. What happened is therefore followed outward until nothing more follows, and only then is the result checked for the references it has left dangling.
Type Aliases§
Row = import from TableDefinitionMethods§
public function __construct(private TableDefinitionRegistry $registry)Parameters
$registry | TableDefinitionRegistry | Answers what a table declares |
Test cases 28
ReferentialIntegrityEnforcerTest::testAcceptsExplicitReferenceToNonPrimaryCandidateKeycoversReferentialIntegrityEnforcerTest::testCascadeNormalizesSparseChildRowIndexescoversReferentialIntegrityEnforcerTest::testCompositeDeleteSetNullNormalizesEveryForeignKeyColumncoversReferentialIntegrityEnforcerTest::testCompositePrimaryKeyUpdateCascadesOnlyMatchingChildrencoversReferentialIntegrityEnforcerTest::testDeleteCascadePropagatesAcrossMultipleLevelscoversReferentialIntegrityEnforcerTest::testDeleteCascadeRemovesAllMatchingChildrenAndKeepsOtherscoversReferentialIntegrityEnforcerTest::testDeleteRestrictRejectsParentRemovalcoversReferentialIntegrityEnforcerTest::testDeleteSetNullCarriesOriginalRowIntoNextLevelcoversReferentialIntegrityEnforcerTest::testDeleteSetNullUpdatesChildcoversReferentialIntegrityEnforcerTest::testEmptySelfReferentialCascadeTerminatesWithoutSyntheticEventscoversReferentialIntegrityEnforcerTest::testExplicitReferencedColumnsAreNotReplacedByPrimaryKeycoversReferentialIntegrityEnforcerTest::testFallbackContinuesAfterIdentityMatchedRowcoversReferentialIntegrityEnforcerTest::testFallbackReferencedPrimaryKeyAppearsInUpdateViolationcoversReferentialIntegrityEnforcerTest::testFallbackTransitionPropagatesUpdateAndDeleteFromOneTablecoversReferentialIntegrityEnforcerTest::testIdentityTransitionSkipsIncompleteChangeAndProcessesFollowingChangecoversReferentialIntegrityEnforcerTest::testMatchingConstraintAfterUnrelatedConstraintStillCascadescoversReferentialIntegrityEnforcerTest::testMissingReferencedValuesDoNotStopLaterUpdateOrDeleteCascadescoversReferentialIntegrityEnforcerTest::testMultiTruncateCascadesFromEveryChangedParentTablecoversReferentialIntegrityEnforcerTest::testPrimaryKeyUpdateCascadesThroughOriginalRowIdentitycoversReferentialIntegrityEnforcerTest::testRejectsInsertWhoseParentDoesNotExistcoversReferentialIntegrityEnforcerTest::testRetainedOldKeyDoesNotStopFollowingUpdateCascadecoversReferentialIntegrityEnforcerTest::testRowsWithMissingPrimaryKeyCannotMatchRowsThatHaveTheKeycoversReferentialIntegrityEnforcerTest::testSchemaMutationDoesNotTriggerRowValidationcoversReferentialIntegrityEnforcerTest::testSchemaMutationSkipsRowIntegrityCheckscoversReferentialIntegrityEnforcerTest::testSynchronizeCascadesDeletedRowscoversReferentialIntegrityEnforcerTest::testUpdateCascadeCarriesOriginalRowIntoNextLevelcoversReferentialIntegrityEnforcerTest::testUpdateDoesNotCascadeWhileOldParentKeyStillExistscoversReferentialIntegrityEnforcerTest::testValidationContinuesPastMissingAndNullForeignKeyscovers
public function synchronize(
ShadowStore $before,
ShadowStore $after,
ShadowMutation $mutation,
array<int, Row> $resultRows,
string $sql,
): voidApplies every consequence of a statement, and refuses one it cannot.
Parameters
$before | ShadowStore | Shadow as it was |
$after | ShadowStore | Shadow as it became, written back in place |
$mutation | ShadowMutation | Statement that was simulated |
$resultRows | array<int, Row> | Rows the rewritten statement read back |
$sql | string | Statement being simulated, for the refusal |
Throws
ForeignKeyViolationException When a constraint forbids the statement or is left brokenTest cases 30
DataMutationTest::testAMutationThatChangesNoRowsCarriesNothingToTheChildrencallsDataMutationTest::testAMutationThatChangesRowsCarriesItsConsequencesToTheChildrencallsReferentialIntegrityEnforcerTest::testAcceptsExplicitReferenceToNonPrimaryCandidateKeycovers and callsReferentialIntegrityEnforcerTest::testCascadeNormalizesSparseChildRowIndexescovers and callsReferentialIntegrityEnforcerTest::testCompositeDeleteSetNullNormalizesEveryForeignKeyColumncovers and callsReferentialIntegrityEnforcerTest::testCompositePrimaryKeyUpdateCascadesOnlyMatchingChildrencovers and callsReferentialIntegrityEnforcerTest::testDeleteCascadePropagatesAcrossMultipleLevelscovers and callsReferentialIntegrityEnforcerTest::testDeleteCascadeRemovesAllMatchingChildrenAndKeepsOtherscovers and callsReferentialIntegrityEnforcerTest::testDeleteRestrictRejectsParentRemovalcovers and callsReferentialIntegrityEnforcerTest::testDeleteSetNullCarriesOriginalRowIntoNextLevelcovers and callsReferentialIntegrityEnforcerTest::testDeleteSetNullUpdatesChildcovers and callsReferentialIntegrityEnforcerTest::testEmptySelfReferentialCascadeTerminatesWithoutSyntheticEventscovers and callsReferentialIntegrityEnforcerTest::testExplicitReferencedColumnsAreNotReplacedByPrimaryKeycovers and callsReferentialIntegrityEnforcerTest::testFallbackContinuesAfterIdentityMatchedRowcovers and callsReferentialIntegrityEnforcerTest::testFallbackReferencedPrimaryKeyAppearsInUpdateViolationcovers and callsReferentialIntegrityEnforcerTest::testFallbackTransitionPropagatesUpdateAndDeleteFromOneTablecovers and callsReferentialIntegrityEnforcerTest::testIdentityTransitionSkipsIncompleteChangeAndProcessesFollowingChangecovers and callsReferentialIntegrityEnforcerTest::testMatchingConstraintAfterUnrelatedConstraintStillCascadescovers and callsReferentialIntegrityEnforcerTest::testMissingReferencedValuesDoNotStopLaterUpdateOrDeleteCascadescovers and callsReferentialIntegrityEnforcerTest::testMultiTruncateCascadesFromEveryChangedParentTablecovers and callsReferentialIntegrityEnforcerTest::testPrimaryKeyUpdateCascadesThroughOriginalRowIdentitycovers and callsReferentialIntegrityEnforcerTest::testRejectsInsertWhoseParentDoesNotExistcovers and callsReferentialIntegrityEnforcerTest::testRetainedOldKeyDoesNotStopFollowingUpdateCascadecovers and callsReferentialIntegrityEnforcerTest::testRowsWithMissingPrimaryKeyCannotMatchRowsThatHaveTheKeycovers and callsReferentialIntegrityEnforcerTest::testSchemaMutationDoesNotTriggerRowValidationcovers and callsReferentialIntegrityEnforcerTest::testSchemaMutationSkipsRowIntegrityCheckscovers and callsReferentialIntegrityEnforcerTest::testSynchronizeCascadesDeletedRowscovers and callsReferentialIntegrityEnforcerTest::testUpdateCascadeCarriesOriginalRowIntoNextLevelcovers and callsReferentialIntegrityEnforcerTest::testUpdateDoesNotCascadeWhileOldParentKeyStillExistscovers and callsReferentialIntegrityEnforcerTest::testValidationContinuesPastMissingAndNullForeignKeyscovers and calls
Called from 1
Calls 10
- new ForeignKeyEnds line 55
- new ForeignKeyCascade line 56
- method-call TableTransitions::of() line 58
- new TableTransitions line 58
- function-call
array_shiftline 60 - method-call TableDefinitionRegistry::getAll() line 61
- function-call
strcasecmpline 63 - method-call ForeignKeyCascade::of() line 66
- method-call ForeignKeyIntegrity::assertHolds() line 74
- new ForeignKeyIntegrity line 74
Private surface 1§
Implementation details, listed for orientation only.
private TableDefinitionRegistry $registryTest cases 39§
Test cases that cover or call this symbol, from the coverage report and from the analyzed test sources.
Dedicated tests 28
ReferentialIntegrityEnforcerTest::testAcceptsExplicitReferenceToNonPrimaryCandidateKeycovers and callsReferentialIntegrityEnforcerTest::testCascadeNormalizesSparseChildRowIndexescovers and callsReferentialIntegrityEnforcerTest::testCompositeDeleteSetNullNormalizesEveryForeignKeyColumncovers and callsReferentialIntegrityEnforcerTest::testCompositePrimaryKeyUpdateCascadesOnlyMatchingChildrencovers and callsReferentialIntegrityEnforcerTest::testDeleteCascadePropagatesAcrossMultipleLevelscovers and callsReferentialIntegrityEnforcerTest::testDeleteCascadeRemovesAllMatchingChildrenAndKeepsOtherscovers and callsReferentialIntegrityEnforcerTest::testDeleteRestrictRejectsParentRemovalcovers and callsReferentialIntegrityEnforcerTest::testDeleteSetNullCarriesOriginalRowIntoNextLevelcovers and callsReferentialIntegrityEnforcerTest::testDeleteSetNullUpdatesChildcovers and callsReferentialIntegrityEnforcerTest::testEmptySelfReferentialCascadeTerminatesWithoutSyntheticEventscovers and callsReferentialIntegrityEnforcerTest::testExplicitReferencedColumnsAreNotReplacedByPrimaryKeycovers and callsReferentialIntegrityEnforcerTest::testFallbackContinuesAfterIdentityMatchedRowcovers and callsReferentialIntegrityEnforcerTest::testFallbackReferencedPrimaryKeyAppearsInUpdateViolationcovers and callsReferentialIntegrityEnforcerTest::testFallbackTransitionPropagatesUpdateAndDeleteFromOneTablecovers and callsReferentialIntegrityEnforcerTest::testIdentityTransitionSkipsIncompleteChangeAndProcessesFollowingChangecovers and callsReferentialIntegrityEnforcerTest::testMatchingConstraintAfterUnrelatedConstraintStillCascadescovers and callsReferentialIntegrityEnforcerTest::testMissingReferencedValuesDoNotStopLaterUpdateOrDeleteCascadescovers and callsReferentialIntegrityEnforcerTest::testMultiTruncateCascadesFromEveryChangedParentTablecovers and callsReferentialIntegrityEnforcerTest::testPrimaryKeyUpdateCascadesThroughOriginalRowIdentitycovers and callsReferentialIntegrityEnforcerTest::testRejectsInsertWhoseParentDoesNotExistcovers and callsReferentialIntegrityEnforcerTest::testRetainedOldKeyDoesNotStopFollowingUpdateCascadecovers and callsReferentialIntegrityEnforcerTest::testRowsWithMissingPrimaryKeyCannotMatchRowsThatHaveTheKeycovers and callsReferentialIntegrityEnforcerTest::testSchemaMutationDoesNotTriggerRowValidationcovers and callsReferentialIntegrityEnforcerTest::testSchemaMutationSkipsRowIntegrityCheckscovers and callsReferentialIntegrityEnforcerTest::testSynchronizeCascadesDeletedRowscovers and callsReferentialIntegrityEnforcerTest::testUpdateCascadeCarriesOriginalRowIntoNextLevelcovers and callsReferentialIntegrityEnforcerTest::testUpdateDoesNotCascadeWhileOldParentKeyStillExistscovers and callsReferentialIntegrityEnforcerTest::testValidationContinuesPastMissingAndNullForeignKeyscovers and calls
Other tests reaching this symbol 11
SessionTestcallsDataMutationTest::testAMutationThatChangesNoRowsCarriesNothingToTheChildrencallsDataMutationTest::testAMutationThatChangesRowsCarriesItsConsequencesToTheChildrencallsShadowApplicationTest::testApplyAnswersWhatTheStatementCameTocallsShadowApplicationTest::testApplyLeavesTheShadowAsItWasWhenTheStatementIsRefusedcallsShadowApplicationTest::testApplyWritesTheRowsAMutationDescribesIntoTheShadowcallsShadowApplicationTest::testLastInsertIdOfAnswersTheIdentityTheTableSaysIsNumberedcallsShadowApplicationTest::testLastInsertIdOfFallsBackToASingleColumnKeycallsShadowApplicationTest::testLastInsertIdOfIsNothingForAStatementThatInsertedNothingcallsShadowApplicationTest::testLastInsertIdOfIsNothingWhereNoColumnIsNumberedcallsStatementSimulatorTestcalls