Skip to content

06: Conflict policy constants - #6

Merged
nikolaystrikhar merged 5 commits into
mainfrom
06-conflict-policy
Aug 11, 2026
Merged

06: Conflict policy constants#6
nikolaystrikhar merged 5 commits into
mainfrom
06-conflict-policy

Conversation

@nikolaystrikhar

@nikolaystrikhar nikolaystrikhar commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Adds the three conflict-policy string constants, plus all() and is_valid().

Stacked on #5.

'conflict_policy' => Conflict_Policy::DEACTIVATE,  // or DEFER, or NOTICE_ONLY
  • String constants, not an enum. PHP floor is 7.4. Not bare strings either, since a host may persist one in an option — so the test asserts the literal values, which are a public contract.
  • is_valid() closes a destructive default. Nothing validated a policy before: the resolver's default: fell into deactivate(), so 'defered' from a typo or someone else's filter would deactivate a plugin the site owner deliberately turned on. Unknown is now its own case, falling back to NOTICE_ONLY.
  • Constant set pinned by reflection. Catches an added fourth policy that the same default: would otherwise swallow.
  • DEACTIVATE description corrected in the README and docblock. The bundled copy does not load on that request — the standalone has already defined the guard constant before plugins_loaded, so the request ends at the redirect and the load happens next request.

@nikolaystrikhar nikolaystrikhar mentioned this pull request Aug 3, 2026
Nothing validated a policy string. The resolver switches on it with a
default branch that deactivates, so a typo or a stale filter return would
turn off a plugin the site owner deliberately activated -- the most
surprising of the three outcomes to arrive at by accident. all() and
is_valid() give callers a way to tell unknown from DEACTIVATE.

Also pin the constant set by reflection, so a fourth policy cannot be added
without the resolver's switch being revisited, and correct the DEACTIVATE
description: the bundled copy loads on the next request, not this one, since
the standalone has already defined the guard constant and the request ends
at the redirect.
Comment thread src/Conflict_Policy.php Outdated
Comment on lines +44 to +57
/**
* Every policy this library understands.
*
* @since 1.0.0
*
* @return string[]
*/
public static function all(): array {
return [
self::DEACTIVATE,
self::DEFER,
self::NOTICE_ONLY,
];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Does this need to be public?

Comment thread tests/unit/ConflictPolicyTest.php Outdated

public function test_all_returns_every_policy(): void {
$this->assertSame(
[ 'deactivate', 'defer', 'notice_only' ],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It would probably be a good idea to use the same reflection getConstants() call here used in test_no_policy_is_added_or_removed_unnoticed() instead of hardcoding them. This way we're able to assert that Conflict_Policy::all() returns all the Constant values rather than that it matches a hardcoded list.

Comment on lines +55 to +64
/**
* @return array<string,array{0:string}>
*/
public function valid_policies(): array {
return [
'deactivate' => [ Conflict_Policy::DEACTIVATE ],
'defer' => [ Conflict_Policy::DEFER ],
'notice_only' => [ Conflict_Policy::NOTICE_ONLY ],
];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Generator would be better :)

Comment on lines +75 to +85
/**
* @return array<string,array{0:string}>
*/
public function invalid_policies(): array {
return [
'typo' => [ 'defered' ],
'empty' => [ '' ],
'wrong case' => [ 'DEACTIVATE' ],
'constant' => [ 'Conflict_Policy::DEFER' ],
];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Generator would be better :)

Base automatically changed from 05-ci-static-analysis to main August 11, 2026 09:05
…generators

- Changed the visibility of the `all()` method in `Conflict_Policy` to private, ensuring it is only used internally.
- Updated the `is_valid()` method to rely on the private `all()` method for policy validation.
- Refactored tests in `ConflictPolicyTest` and `ConfigTest` to utilize generators for data providers, improving performance and readability.
- Removed the public `all()` method test, as it is no longer accessible outside the class.
ConfigTest was the only conflict. Main had already converted its data
providers to generators and gone further — static providers, and the
empty prefix folded into invalid_hook_prefixes as a data set rather than
a test of its own — so main's file is taken whole.

Conflict_Policy's providers follow suit and become static, now that
PHPStan analyses tests/ at level 8.
@nikolaystrikhar
nikolaystrikhar merged commit 9aa6016 into main Aug 11, 2026
5 checks passed
@nikolaystrikhar
nikolaystrikhar deleted the 06-conflict-policy branch August 11, 2026 09:17
nikolaystrikhar added a commit that referenced this pull request Aug 11, 2026
README keeps the docs-index structure from 08-registrar; this branch's
notices documentation moves to docs/notices.md rather than growing the
README back.

In the plan, the Task 11 teardown takes one line from each side:
all_admin_notices is this branch's deliberate hook change, and
Loader_State::reset() is 08-registrar's fix for the no-test-seams rule.

Tasks 1-6 shipped in PRs #1-#6, so their plan sections are removed and
the rule for doing so is recorded in CLAUDE.md. CLAUDE.md's collaborator
table, boot lifecycle and Keys section are corrected to match the split
Notices\ classes and the option-backed queue.
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.

2 participants