Skip to content

chore: PHPStan level 8 typing pass + bugfixes - #34

Merged
bmfmancini merged 2 commits into
developfrom
chore/phpstan-level-8-typing
Sep 25, 2026
Merged

bmfmancini merged 2 commits into
developfrom
chore/phpstan-level-8-typing

Conversation

@TheWitness

Copy link
Copy Markdown
Member

Summary

PHPStan level 8 + PHPDoc/native typing pass for plugin_apcupsd, following the same process as the prior repos in this rollout. Native return types added where a function's own body guarantees a single type; PHPDoc-only types kept at Cacti hook-boundary functions (apcupsd_replicate_out, apcupsd_draw_navigation_text) whose arguments are supplied by an external dispatcher.

(a) Error count

PHPStan level 8: 38 -> 0 errors.

(b) Genuine bugs fixed

  • poller_apcupsd.php: both calls to add_ups_device($ups, $host_template_id, ...) referenced $host_template_id, which is never defined anywhere in the script - every newly-discovered UPS device was created with a null/undefined host template id instead of the imported APC UPS Host Template. Fixed by resolving the real template id via the same host_template.hash = APCUPSD_HOST_TEMPLATE_HASH query already used (existence-only) by apcupsd_host_template_imported().
  • setup.php: plugin_apcupsd_install() registered the replicate_out hook twice (an apparent copy/paste leftover, one labeled "hook for table replication"), which would run apcupsd_replicate_out() twice per replication event; removed the duplicate registration.
  • setup.php: apcupsd_config_arrays() added the "UPSes" menu entry with the wrong text domain ('webseer' instead of 'apcupsd'), silently breaking translation for that one menu label. Fixed.
  • upses.php: the Location filter dropdown's "selected" check compared against get_request_var('site_id') instead of get_request_var('location') - a copy/paste bug from the adjacent Site dropdown block - so the Location dropdown never correctly reflected the currently-selected location. Fixed.
  • upses.php: form_actions()'s $save_html was only assigned inside the 3 known drp_action branches (1-3), and $ups_actions[get_nfilter_request_var('drp_action')] was indexed with the same unrestricted value, but drp_action is only regex-validated (any alphanumeric string is accepted) - matches the exact same bug shape Copilot flagged in the plugin_tags PR earlier in this rollout. Fixed proactively with the same "reject any value outside the known set up front" pattern.
  • upses.php's edit form field array ($fields_ups_edit['host_id']) had a duplicate 'none_value' key (__('None') immediately overwritten by __('Autocreate on First Poll', 'apcupsd') two lines later) - removed the dead first occurrence.
  • poller_apcupsd.php: collect_ups_data() appended to $sql_params[] without initializing it first - works via PHP's array auto-vivification but raises an "Undefined variable" warning on every apcaccess-based poll; added the missing $sql_params = array();.
  • db_fetch_row_prepared()/db_fetch_row() results (which can be false) narrowed to arrays before offset access in form_save(), ups_edit(), and duplicate_ups().
  • setup.php: parse_ini_file() result narrowed before array access (can return false).
  • setup.php/upses.php: $config/superglobal narrowing at include boundaries and one always-true isset($_POST) simplification, matching the recurring pattern from every prior repo in this rollout.
  • upses.php: html_start_box() $div/$cell_padding args fixed to native bool/int in 4 call sites.

(c) Stubs added/verified

Scratch PHPStan bootstrap stubs added for this repo's many Cacti core dependencies (api_device_save, automation_update_device, cacti_snmp_get, push_out_host, array_rekey, api_reapply_suggested_graph_title, update_graph_title_cache, api_reapply_suggested_data_source_data, update_data_source_title_cache, get_colored_device_status, form_text_box, api_plugin_is_enabled, api_plugin_enable_hooks, db_column_exists, replicate_out_table, auth_augment_roles, form_selectable_ecell, cacti_escapeshellcmd, cacti_escapeshellarg, plus the already-established reusable base set), all sourced from Cacti/cacti's develop branch. $fields_snmp_item (a real Cacti core global from include/global_form.php, loaded transitively via upses.php's own auth.php bootstrap at runtime) stubbed as an empty array for static-analysis purposes only.

(d) Test result

Full Pest suite: 68 passed (176 assertions), run against the real 1.2.x host via bind-mount, unchanged before and after this pass. php-cs-fixer (Cacti develop config, array() -> [] shorthand applied) and php -l both clean on all touched files.

(e) Unresolved / flagged for maintainer judgement

None.

Files changed

apcupsd_functions.php, database.php (cs-fixer style only), poller_apcupsd.php, setup.php, ui_helpers.php, upses.php, locales/po/cacti.pot (translation template refresh only; per-language .po/.mo files reverted to avoid Weblate churn).

Adds native param/return types where safe, PHPDoc-only types at Cacti
hook boundaries, and fixes several genuine bugs surfaced during the
typing pass:

- poller_apcupsd.php: both add_ups_device() calls referenced
  $host_template_id, never defined anywhere in the script - every
  newly-discovered UPS device was created with a null host template.
  Fixed by resolving the real template id via the same
  host_template.hash query already used (existence-only) by
  apcupsd_host_template_imported().
- setup.php: plugin_apcupsd_install() registered the replicate_out
  hook twice - removed the duplicate.
- setup.php: apcupsd_config_arrays()'s "UPSes" menu entry used the
  wrong text domain ('webseer' instead of 'apcupsd').
- upses.php: the Location filter dropdown's "selected" check compared
  against site_id instead of location (copy/paste from the adjacent
  Site dropdown) - the Location dropdown never reflected the current
  selection.
- upses.php: form_actions()'s $save_html/$ups_actions index was only
  guarded for the 3 known drp_action values, but drp_action is only
  regex-validated - same bug shape Copilot flagged in plugin_tags
  earlier in this rollout; fixed proactively with the same
  reject-invalid-values-early pattern.
- upses.php: removed a duplicate 'none_value' key in the host_id edit
  field (dead, immediately overwritten).
- poller_apcupsd.php: collect_ups_data() appended to $sql_params[]
  without initializing it first (works via auto-vivification but warns
  on every poll) - added the missing initialization.
- db_fetch_row_prepared()/db_fetch_row() results narrowed before array
  access in form_save(), ups_edit(), and duplicate_ups().
- parse_ini_file() narrowing, $config narrowing at include boundaries,
  one always-true isset($_POST) simplification, and 4 html_start_box()
  call sites fixed to native bool/int args.

Result: PHPStan level 8 clean (38 -> 0 errors), php-cs-fixer clean
(Cacti develop config, array() -> [] shorthand applied), php -l clean,
full Pest suite (68/68) passing against the 1.2.x baseline.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The duplicate-hook migration and malformed configuration-section handling remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 High severity · 1 Medium severity · 1 Low severity

Open (3)
What changed in this PR

Adds PHPStan level 8 typing and fixes polling, setup, filtering, validation, and translation issues in the APCUPSD plugin.

Changes:

  • Adds native typing and modernizes array syntax.
  • Fixes host-template resolution, duplicate hooks, filters, and bulk-action validation.
  • Refreshes translation references and poller initialization.
File Summary
upses.php Form handling, filtering, validation, and UI fixes
ui_helpers.php Layout helper typing
setup.php Lifecycle, hook, menu, and configuration updates
poller_apcupsd.php Poller typing and host-template resolution
locales/​po/​cacti.pot Translation template refresh
database.php Array syntax modernization
apcupsd_functions.php Helper return typing

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread setup.php
Comment thread setup.php Outdated
Comment thread setup.php Outdated
- setup.php: apcupsd_check_upgrade() now cleans up any stale duplicate
  'replicate_out' plugin_hooks row (from installations that ran the
  old, double-registering install routine) instead of only preventing
  new duplicates on fresh installs.
- setup.php: plugin_apcupsd_version() now also validates that the
  parsed INFO file actually has an 'info' section before returning it,
  instead of assuming it exists once the top-level parse succeeded -
  the previous narrowing could otherwise return null from a function
  declared to return array, a hard TypeError.
- setup.php: converted a raw sizeof() to cacti_sizeof() to match this
  plugin's own established convention.

Re-verified: PHPStan level 8 clean, php-cs-fixer clean, php -l clean,
full Pest suite (68/68) passing against the 1.2.x baseline.
@bmfmancini
bmfmancini merged commit a40e2e3 into develop Sep 25, 2026
3 checks passed
@bmfmancini
bmfmancini deleted the chore/phpstan-level-8-typing branch September 25, 2026 16:29
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.

3 participants