Getting better code completion in your editor with Kirby

Looking at the forum FAQ it looks like linking to your own article is okay if it’s relevant to the community, so here goes. I’ll try to summarize the article here so busy readers don’t have to click through!

Kirby 3 is using PHP 7’s type annotations extensively in its source code, but oftentimes your code editor or IDE cannot show you that information because it doesn’t know what $page or $kirby means in different contexts, like templates and controllers.

I wrote an article on type hints for Kirby which explains the explains the problem — basically, Kirby is a bit too magical for your IDE’s taste — and some solutions I found.

Type hints for templates

We can use PHPDoc syntax to declare the type of the variables injected by Kirby or by your controllers:

<?php // site/templates/article.php

/** @var Kirby\Cms\Page $page */
/** @var Kirby\Cms\Site $site */

$htmlTitle = $page->title() . ' – ' . $site->title();

Now we can work with the $page variable and a good PHP IDE will offer autocompletions, parameter names and types, etc.

Type annotations for controllers

Since controllers are functions, we can use type annotations in the function signature:

<?php // site/controllers/article.php

use Kirby\Cms\Page;
use Kirby\Cms\Site;

return function (Page $page, Site $site) {
  return [
    'htmlTitle' => $page->title() . ' – ' . $site->title()
  ];
}

Okay but what’s a good code editor for this?

I’ve mostly used PhpStorm, which is great but not cheap. Other IDEs like Netbeans or Visual Studio might work well too.

VS Code doesn’t have much PHP support out of the box, but I tried the PHP Intelephense extension and it seems to work well (make sure to follow the “Quick Start” steps).

5 Likes

Hi!

I just tried this for Visual Code v1.71.2 and PHP Intelephense v1.8.2 with PHP8. It can resolve some Kirby 3.7 helpers but variables like $page are not resolved in my controllers or templates within the PHP open/end tags. Is there nowadays a way to get this to work without adding Type hints or Type Annotations by hand in your custom code? If I do that, resolving the variable works but of course it adds additional, repetetive work. Would it help to have a PHP Intelephense license for the full feature set?

Thank you for your thread and thanks to everyone who helps!

Best Regards

Don’t know, if you’re still looking, but just found this by @bnomei, which works like a charm…

Add it to the top of your template/snippet.

<?php
/** @var Kirby\Cms\App $kirby */
/** @var Kirby\Cms\Site $site */
/** @var Kirby\Cms\Page $page */
$page->children(); // <-- works now
1 Like

Yes that’s basically the information I posted in the first post of this thread. :wink: See the “Type hints for templates” part.

Not that I know of. If $kirby, $site or $page were global variables, it could be enough to use PHPDoc to declare them in one place:

<?php
/** @global Kirby\Cms\App $kirby */
/** @global Kirby\Cms\Site $site */
/** @global Kirby\Cms\Page $page */

And tools like Intelephense or PHPStorm might be clever enough to see that and apply those definitions in all files.

But Kirby does not declare those variables as globals. Instead, it provides those variables in templates, or provides them to specific functions (like controllers). If you lie to your type intelligence system by saying they’re globals, you’ll probably end up writing bugs (like trying to use $kirby in a config file).

Something that can help is using Kirby’s helper functions, which are available in templates and other contexts:

  • Instead of $page, use page()
  • Instead of $site, use site()
  • Instead of $kirby, use kirby()

In my experience, Intelephense and PhpStorm both recognize those functions and understand their return types, so you get the same benefit as declaring the type of $page, $site and $kirby, but in a less verbose way.

Personally I still use the /** @var */ declarations in templates, mostly because I have custom models for every template, and page() only gives me the parent Kirby\Cms\Page class, not my subclass. So I do stuff like:

<?php
/** @var PortfolioPage $page */
echo $page->someCustomFunction();
2 Likes

Sorry for not properly reading your original post - and thank you for the detailed answer. Learnt something again today and it might be of value for those, who find this thread :+1::pray:t3:

1 Like

Won’t fix the template issue but might be useful.

4 Likes