How to set up Psalm

Has anyone successfully set Psalm up with Kirby? I’m seeing a bunch of errors like UndefinedClass or PropertyNotSetInConstructor which makes me think it is an autoloading issue.

I think Psalm automatically uses Composer’s autoloader, but apparently that isn’t sufficient. I know index.php is the entry file for Kirby, so I tried adding autoloader="index.php" to my psalm.xml file. However, that resulted in a lot of DuplicateClass errors. I also tried using autoloader="kirby/bootstrap.php" but I still got the undefined type of errors.

So, has anyone figured out the right configuration for Psalm when making a Kirby site?

It doesn’t need any special setup to work if you require it via composer

The Merx e-commerce Starterkit uses Psalm, maybe that helps: GitHub - wagnerwagner/merx-starterkit: Complete demo shop. Ideal to explore many of Merx’s possibilities.

Thanks for providing the example! I hadn’t been able to find one myself. However, even with copying some of that, I don’t think it is working quite right. Also, I’m doing this for a Kirby site (the starterkit), not in a plugin.

Here is my psalm.xml

<?xml version="1.0"?>
<psalm
        errorLevel="4"
        resolveFromConfigFile="true"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="https://getpsalm.org/schema/config"
        xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
        findUnusedBaselineEntry="true"
        findUnusedCode="true"
>
    <projectFiles>
        <file name="index.php"/>
        <directory name="site"/>
        <directory name="content"/>
        <ignoreFiles>
            <directory name="vendor"/>
            <directory name="site/plugins"/>
        </ignoreFiles>
    </projectFiles>
    <extraFiles>
        <directory name="kirby"/>
        <directory name="site/plugins"/>
    </extraFiles>
    <globals>
        <var name="page" type="Kirby\Cms\Page"/>
        <var name="site" type="Kirby\Cms\Site"/>
        <var name="kirby" type="Kirby\Cms\App"/>
    </globals>
    <issueHandlers>
        <!-- Don't warn about "$this in a non-class context" in the config dir -->
        <InvalidScope>
            <errorLevel type="suppress">
                <directory name="site/config"/>
            </errorLevel>
        </InvalidScope>
    </issueHandlers>
</psalm>

Here is my composer.json from the starterkit:

{
  "name": "getkirby/starterkit",
  "description": "Kirby Starterkit",
  "type": "project",
  "keywords": [
    "kirby",
    "cms",
    "starterkit"
  ],
  "authors": [
    {
      "name": "Bastian Allgeier",
      "email": "bastian@getkirby.com",
      "homepage": "https://getkirby.com"
    }
  ],
  "homepage": "https://getkirby.com",
  "support": {
    "email": "support@getkirby.com",
    "issues": "https://github.com/getkirby/starterkit/issues",
    "forum": "https://forum.getkirby.com",
    "source": "https://github.com/getkirby/starterkit"
  },
  "require": {
    "php": "~8.1.0 || ~8.2.0 || ~8.3.0",
    "getkirby/cms": "5.0.0-alpha.1"
  },
  "config": {
    "allow-plugins": {
      "getkirby/composer-installer": true
    },
    "optimize-autoloader": true
  },
  "scripts": {
    "start": [
      "Composer\\Config::disableProcessTimeout",
      "@php -S localhost:8000 kirby/router.php"
    ]
  },
  "require-dev": {
    "vimeo/psalm": "^5.25",
    "lukaskleinschmidt/kirby-types": "^2.0"
  }
}

And, here are the errors in /models/note.php from the starterkit:

If I add autoloader="index.php" to psalm.xml then I get a different problem:

Looks like part of it might be a PhpStorm issue: https://youtrack.jetbrains.com/issue/WI-57977#focus=Comments-27-4635845.0-0

If I run Psalm through the command line, the behavior seems more consistent as I change parameters in psalm.xml. So, it seems like the command line is the most reliable way to test Psalm.

I did find adding autoloader="index.php" to be helpful for analyzing individual files through the command line (I think this was helpful because I have a custom auto loader in a plugin). Unfortunately, autoloader="index.php" makes the GUI based single-file inspections in PhpStorm’s buggy since they no longer match the output from the command line.

So, the final solution was to add autoloader="site/plugins/my-pluging-with-custom-autoloader/index.php" to my psalm.xml.

I’ve also created a scope in PhpStorm for the site folder recursively (excluding the plugins folder recursively), and now I can now run full code analysis on that scope.