Skip to content

About

XOOPS Support Plugin for PhpStorm

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

XOOPS Support — PhpStorm plugin (PSI rebuild)

Kotlin, IntelliJ Platform Gradle Plugin 2.x, PhpStorm 2024.3+ (no until-build cap). Version 0.4.0 is a PSI-first rebuild driven by the Publisher field review in ../xoops-support/00_docs/ (Addendum §B is the plan this release implements).

  • TUTORIAL.md — feature-by-feature walkthrough with expected results
  • CHANGELOG.md — release history; rendered into the plugin's "What's New" panel at build time
  • tasks/todo.md — the 0.4.0 plan and its review

The contract

The sibling xoops-support plugin applied 1,043 findings to a real module and left it broken in seven different ways while every file still passed php -l. The cause was structural: inspections and fixes worked on regex over file text. This plugin is built so that class of failure cannot ship:

  1. PSI, not text. Receivers, statement boundaries, include targets, attribute context, comment/string/injected-fragment status all come from PhpStorm's PHP parser.
  2. No stored offsets. A fix gets the problem's PSI element and computes its edit from the live tree at apply time, after whatever earlier fixes in the batch did. Every fix re-validates the condition before editing and declines silently if it no longer holds.
  3. Golden files. Each inspection ships with a fixture module tree, an asserted problem count, a whole-file *.after.php once every fix of the family has been applied through the IDE, and a second highlighting pass that must offer no further fix (idempotence). gradlew test runs the lot (src/test/kotlin/org/xoops/support/XoopsQuickFixTest.kt, fixtures generated by tools/gen_fixtures.py).
  4. Unknown is not a finding. A $sql the plugin cannot resolve is not a "mutating query"; a header file it has not read does not "already call" anything.

Dev loop without IDE restarts

PhpStorm 2025.3 never hot-swaps an installed plugin through "Install Plugin from Disk": in PluginInstaller.installFromDisk the dynamic path is taken only when no previous install exists (oldPath == null && DynamicPlugins.allowLoadUnloadWithoutRestart(...)), otherwise the zip is staged for the next restart. The plugin itself is unload-safe (every extension point it uses is dynamic; idea.log shows "loaded without restart in 69 ms" on enable). Two ways to stay live:

  1. Uninstall, then install from disk. Both steps are dynamic for this plugin.
  2. Local plugin repository. updatePlugins.xml in this folder points at the current dev zip. Settings > Plugins > gear > Manage Plugin Repositories > add file:///<path to this folder>/updatePlugins.xml, then the Installed tab offers "Update", which unloads the old version and loads the new one in place. Each build needs a higher version: gradlew buildPlugin -PbuildNumber=N produces 0.7.2.N; update the version and url in updatePlugins.xml to match.

Project features (rebuilt from 1.0.0 Alpha 3)

Feature Where What it does
Settings page Settings → Languages & Frameworks → XOOPS Support Enable switch for the project, startup balloon, tool-window auto-scan (off by default), Core version override. Auto reads include/version.php of the nearest web root and the page shows what it found; a value such as 2.5.9 is what the version-gated quick-fixes (isResultSet() 2.5.11, exec() 2.5.12) see - the only way to tell the plugin about the target core of a standalone module checkout.
New → XOOPS Module… (also Tools → XOOPS Support) project view context menu Dialog with dirname validation and a layout choice. Legacy: manifest, index page, English language files, index template. Hybrid adds preloads/autoloader.php (PSR-4 XoopsModules\Cap\ → class/), class/Helper.php on Xmf\Module\Helper, include/common.php, and an Xmf\Module\Admin admin side. Every generated file passes this plugin's inspections; a test asserts it for both layouts.
Tools → XOOPS Support main menu Show XOOPS Project Info (scanner summary), Refresh XOOPS Overview (opens the tool window and rescans), New XOOPS Module….
Ctrl+B / Find Usages on language constants PHP strings, Smarty templates '_MI_DEMO_NAME' as a string (manifest options, constant(), defined()) and $smarty.const._MD_X in a template navigate to the define(); several language packs give a chooser, same module and English first. Find Usages on the define() lists those uses. A bare _MI_X in PHP already resolves through PhpStorm.

Inspections (Settings → Editor → Inspections → PHP → XOOPS)

The plugin registers 52 inspections: security (CSRF, superglobals, SQL concatenation, escaping, tokens), the database layer (queryF(), exec() vs query(), isResultSet() guards, installer SQL), module files and bootstrap (XOOPS_ROOT_PATH guard, admin/menu.php autoloader, form loader, preload globals), templates and Smarty (delimiters, registration, Smarty 3 / 5 migrations), language files, and deprecated core APIs.

INSPECTIONS.md lists every one of them with its default level, what it reports, what the quick-fix changes and when it stays silent. It is written from the same descriptions PhpStorm shows in the inspection settings (src/main/resources/inspectionDescriptions/), so the two stay in step.

Plus, unchanged from 0.3: project detection, the XOOPS tool window, language-constant completion and five live templates.

Building and testing

cd phpstorm-plugin
./gradlew test            # golden-file suite + descriptor consistency
./gradlew buildPlugin     # build/distributions/xoops-support-1.0.0-alpha.5.zip
./gradlew runIde          # sandboxed PhpStorm with the plugin installed

Requirements: a JDK on PATH (the build provisions its own JDK 21 toolchain through the Foojay resolver) and network access on the first build (PhpStorm 2024.3.5 platform, cached afterwards). Install the zip with Settings → Plugins → gear → Install Plugin from Disk….

Adding an inspection

  1. Write it in src/main/kotlin/org/xoops/support/inspections/ on top of XoopsInspection, psi/Php.kt and fix/Edits.kt. A fix derives everything from descriptor.psiElement and re-checks its precondition before editing.
  2. Register it in META-INF/plugin.xml, add its page to tools/gen_descriptions.py and run the script.
  3. Add a fixture case to tools/gen_fixtures.py (a real module layout, the .after.php whole file) and a check(...) line to XoopsQuickFixTest. The descriptor test fails until step 2 is complete; the golden test fails until the fix is right and idempotent.

Layout

build.gradle.kts                                  platform 2024.3.5, PHP plugin, test framework
src/main/kotlin/org/xoops/support/
    psi/Php.kt, psi/XoopsPaths.kt                 shared PSI queries and path policy
    fix/Edits.kt                                  live-PSI document edits, XoopsFix base
    inspections/                                  one file per inspection family
    completion/, toolwindow/, XoopsProjectDetector.kt, XoopsSettings.kt
src/main/resources/META-INF/plugin.xml           registrations
src/main/resources/inspectionDescriptions/       generated by tools/gen_descriptions.py
src/test/kotlin/org/xoops/support/                 XoopsQuickFixTest, PluginDescriptorTest
src/test/resources/fixtures/                      generated by tools/gen_fixtures.py

About

XOOPS Support Plugin for PhpStorm

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages