Repository navigation
chore(php): backed enums for log/ban/web-permission columns (#1290) - #1297
Merged
Merged
Conversation
…ms (#1290) Phase D from #1290 — backed PHP-side enums wrapping the on-disk column types. Schema is unchanged. - D.1: LogType enum (string-backed, letter codes match :prefix_log.type varchar(1)). Log::add(string $type) signature now takes LogType. Call sites converted across pages and handlers. Log.php's switch-based search WHERE builder refactored to a LogSearchType enum + whereClause() method. - D.2: BanType enum (int-backed, wraps :prefix_bans.type tinyint). Steam=0, Ip=1. Writers/readers in bans.php / page.banlist.php / page.home.php / admin.edit.ban.php migrated. - D.3: BanRemoval enum (string-backed, wraps the RemoveType varchar(3) column on :prefix_bans / :prefix_comms — Deleted='D', Unbanned='U', Expired='E'). String-backed because the column is varchar(3) on disk; the issue's umbrella prompt described it as int but the schema is varchar — the enum job is to mirror the on-disk type, so string is correct. - D.4: WebPermission enum (int-backed, wraps the ADMIN_* bitmask constants from init.php). HasAccess() now accepts WebPermission|int|string. WebPermission::mask(...) assembles multi-flag bitmasks; WebPermission::fromMask(int) decodes one. The ADMIN_* defines stay for procedural back-compat. Call sites migrated across 36 files (admin.edit.adminperms.php carries the largest single-file blast radius at 34 sites). The on-disk schema is untouched — every enum's value mirrors the existing column type. PHPStan-dba sees \$enum->value at every bind site, so column types still match the live MariaDB schema. Wire format unchanged (api-contract clean). Plus AGENTS.md (Conventions: new "Backed enums for column-typed fields" subsection; Anti-patterns: rows for Log::add letter codes, HasAccess(ADMIN_*|...) bitmasks, RemoveType='U'|'D'|'E' SQL literals, \$row['type']==0|1 ban-type branches; Where to find what: row for the new enum files) and ARCHITECTURE.md (Database schema → new "Column-typed PHP enums" subsection cataloguing all five enums and the wrap-around-existing-columns contract).
- M1: WebPermission class docblock + AGENTS.md anti-pattern row
updated to use the correct WebPermission::mask(...) shape
(HasAccess is not variadic — second arg is $aid).
- M2: regression test pinning WebPermission enum cases to
web/configs/permissions/web.json. Drift now fails the gate.
- M3: unit tests for WebPermission::fromMask covering known-bit
round-trips, zero, unknown-bit silent drop, and 2^31 high-bit
on 64-bit PHP.
- m1: docblock truth — cases are ordered numerically, not
web.json-grouped.
- m2: replace "varchar(1)" with "enum('m','w','e')" in LogType,
Log, AGENTS.md, ARCHITECTURE.md.
- m3: resolveDateRange docblock now documents the time-component
fallback.
- m4: Log::getCount drops the unused $search parameter.
PHPStan + PHPUnit + api-contract still clean.
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.
Summary
Closes part of #1290. Phase D from the umbrella — backed PHP-side enums wrapping the on-disk column types. Schema is unchanged.
LogType(string-backed) wraps:prefix_log.type enum('m','w','e').Log::add(string $type)signature now takesLogType. Log.php's switch-based search WHERE builder also refactored to aLogSearchTypeenum +whereClause()method.BanType(int-backed) wraps:prefix_bans.type tinyint.BanRemoval(string-backed; departure from the issue body — the on-disk column isvarchar(3) NULLnotint) wraps:prefix_bans.RemoveTypeand:prefix_comms.RemoveType. CasesD/U/E.WebPermission(int-backed) wraps theADMIN_*integer-bitmask flags fromweb/configs/permissions/web.json(mirrorsinit.php'sdefined constants — both shapes coexist for backward compatibility). 31 cases. Static helpersWebPermission::mask(...$flags)andWebPermission::fromMask(int).HasAccess()signature nowWebPermission|int|string $flags— the legacyHasAccess(ADMIN_OWNER | ADMIN_X)shape and the modernHasAccess(WebPermission::mask(...))shape both work.Wire-format unchanged
composer api-contractclean — noPerms.ADMIN_*shape change; the JS contract still emits the same constants (the enum is purely a PHP-side wrapper).Notable decisions (from the review)
BanRemovalis string-backed, not int — the on-disk column isvarchar(3) NULL. Reading from disk:null/''means the ban is still active;D/U/Eare terminal states. Helper docblocks call this out so future readers know the contract.HasAccess()is NOT variadic — the docblock + AGENTS.md anti-pattern row use the correctWebPermission::mask(...)shape (NOTHasAccess(WebPermission::Owner, WebPermission::AddBan), which would bind the second flag as$aidand crash).WebPermissioncases toweb/configs/permissions/web.json(WebPermissionTest::testWebPermissionEnumMatchesWebJson). Drift now fails the gate.WebPermission::fromMaskcovering known-bit round-trip, zero, unknown-bit silent drop, and 2^31 high-bit on 64-bit PHP.HasAccess(ALL_WEB, $aid)—ALL_WEBis a derived rolled-up bitmask, not a flag.HasAccess(SM_RCON . SM_ROOT)— SourceMod char-flag string, not an int bitmask.HasAccess($flag)inAdminTabs,SmartyCustomFunctions,View/Perms, etc. — value is computed at runtime from JSON config.RemoveType = 'E'literals inPruneBans/PruneCommsstatic SQL strings (inline predicates, not bound values).sbError() now maps to LogType cases
Closing invariants
Test plan
./sbpp.sh phpstanclean (225 files)./sbpp.sh test393 tests pass (5 newWebPermissionTestcases)./sbpp.sh ts-checkclean./sbpp.sh composer api-contractbyte-identicalmktimehour/minute args)