PHPStan for latte without Nette Application

Vaielab
Member | 5
+
0
-

Hello
I hope this is ok to ask a question that is only for Latte and not for Nette.

I'm currently using the framework PHPSlim with latte following this tutorial: https://latte.nette.org/…im-framework .

I'm trying to find a way to validate with PHPStan if the template I'm using actually exists, and if all the variables are correctly sended.
The only project I found that could do it is https://packagist.org/…hpstan-latte, but it seem to be made for nette application framework. At least I was not able to make it work with the tutorial, I only manage to get this error: “:-1 Latte template home.latte was not analysed.”.

Has anyone managed to make this PHPStan extension work without nette application framework, or know a other PHPStan extension that could work for me.

Thank you

mystik
Member | 304
+
0
-

Hello

I am one of developers of that phpstan latte extension. It should be possible to adapt it for any type of application easily. It requires writing custom TemplateResolver that defines where to start collecting latte context (defined variables, render calls,… ) for analysis. It can be just few lines of code.

Can you show me how your version of presenter/control looks like?

mystik
Member | 304
+
0
-

I just noticed you already wrote you use Slim. So you need to define TemplateResolver that matches all Action classes and their __invoke methods, right?

mystik
Member | 304
+
0
-

You can define template resolver like this to match __invoke methods in all classes extending My\Application\Action :


namespace My\Application;

use Efabrica\PHPStanLatte\LatteContext\Resolver\LatteContextResolverInterface;
use Efabrica\PHPStanLatte\LatteTemplateResolver\AbstractClassMethodTemplateResolver;

final class SlimActionTemplateResolver extends AbstractClassMethodTemplateResolver
{
    public function getSupportedClasses(): array
    {
        return ['My\Application\Action'];
    }

    protected function getClassMethodPattern(): string
    {
        return '/^__invoke$/';
    }
}

Then add it in your phpstan.neon:

services:
  - My\Application\SlimActionTemplateResolver

That should do the trick.

If your Action methods cannot be matched by common parent then it could be done too but is more complicated.

If you do not use classes at all but just functions or callbacks then it also can be done but would require fully custom TemplateResolver. I can help you with that too if it is the case.

Last edited by mystik (2023-05-04 09:27)

Marek Bartoš
Nette Blogger | 1246
+
0
-

Latte template home.latte was not analysed

@mystik This would deserve a phpstan built-in tip how to resolve the issue, e.g. with link to docs

Last edited by Marek Bartoš (2023-05-04 12:38)

Vaielab
Member | 5
+
0
-

Hello,

Thank you for the answer, I didn't think I'd have an answer from someone on the phpstan-latte team.
Sadly, I did not managed to make the code suggested work.
I made a small repo for a very basic php slim / latte template https://github.com/…LattePhpStan
I'd really appreciate if you could take a look.

I haven't decided how I'd like to load latte in the final application, so I've try 2 ways.

The application has 3 endpoints:
/test01 ⇒ It should load the template Test01.latte, and using the $this->engine->renderToString method directly from Latte
/test02 ⇒ It should load the template Test02.latte, and using a basic class App\Renderer\TemplateRenderer
/test03 ⇒ Trying to use the App\Renderer\TemplateRenderer to load Test03.latte but without the necessary variables so should return a error.

When I'm calling phpstan with ./vendor/bin/phpstan analyse –configuration phpstan.neon, I get all 3 “Latte template … was not analysed” error message.

I tried adding the TemplateResolver extends AbstractClassMethodTemplateResolver you suggested, but it didn't change the error message or anything.
I'm not sure where to go from here.

Thank you for your time

mystik
Member | 304
+
0
-

Problem here is that we need a way to identify controler classes. Easiest way is based on some parent or inteeface. But your controllers do not have common ancestor nor interface.

Possible solutions (from easiest to hardest):

  1. Define common anvestor or interface for controllers. This class/interface then should be returned from getSupportedClasses of TemplateResolver
  2. Alternative way is to return list of all controller classes from getSupportedClasses() but that would require manual update every time you add new Controller
  3. We can write more customised template resolver that would detect all conteoller classes automaticaly even without common ancestor
mystik
Member | 304
+
0
-

There might be some other problems but I would need to check that in more detail.

Vaielab
Member | 5
+
0
-

Hello,

Thank again for you help.
So I've updated the github and creating a MyController.php file and all my controllers (test01, test02 & test03) now extends from it.
I've also updated getSupportedClasses to return [‘App\Controllers\MyController’].

But still, I get the “Latte template … was not analysed” error message
I've also tried to make the method index of MyController as a abstract method, but I end up with the same problem (not currently on github)

Lulco
Member | 4
+
0
-

Hi, I'm the second contributor of phpstan-latte package. I think you News also variable collector and template path collector to be implemented. See https://github.com/…extension.md#…

mystik
Member | 304
+
0
-

Now I noticed you call render* methods directly on Engine not on Template. We currently does not support that (it is not used this way in Nette).

It would be easy fix (I will make it tommorow) but for now you can try replace

$string = $this->engine->renderToString('Test01.latte', ['items' => $items, 'title' => 'From Test01']);

by

$string = $this->engine->createTemplate()->renderToString('Test01.latte', ['items' => $items, 'title' => 'From Test01']);

Let me know if that helped.

Vaielab
Member | 5
+
0
-

Hello,

I look to change $this->engine->renderToString to something with createTemplate.
The closest thing that I manage to make work was

$template = $this->engine->createTemplate('Test01.latte', ['items' => $items, 'title' => 'From Test01']);
$template->render();

I could not found a way to return the template to a string, but anyway, even that way, I still can't manage to get an other error message.

For the variable collector and template path collector, I read the documentation, and I have to be honest, I'm kinda lost.

I'll wait for the next update if you have time to do it, and I'll try again.
Thank you!

Lulco
Member | 4
+
0
-

With return the index was marked as always terminated, I had to change your revolver little bit. But it works now (almost) check PR in your repo :)

I'm sorry you are lost at docs, we would like to hear some feedback to improve it

mystik
Member | 304
+
0
-

I implemented few fixes that simplified how it can be used and prepared fix of your repo where anylysis works. See https://github.com/…pStan/pull/2 (it requires dev-main version)

To make it work with $this->engine->renderToString only TemplateResolver is needed.

If you want to use custom wrapper for rendering like TemplateRenderer we also need custom TemplateRenderCollector that would extract parameters from call to TemplateRenderer::template. At this point is is quite complex but it works. We might add easier way to define custom render call collectors later.

Last edited by mystik (2023-05-05 14:18)

Vaielab
Member | 5
+
0
-

Wow, thank you so much both of you!
Everything work perfectly :)
I'll study both of your PR to understand what is happening.

If you wish to improve your doc, you could add an example with phpslim / engine standalone, I'm sure I'm not the only one who wish to have better validation with latte.

Thanks again for all your works, and for the PHPStan plugin!