PHPStan returns: ITemplate::render() invoked with 1 parameter, 0 required

medhi
Generous Backer | 255
+
0
-

What am I doing wrong, when PHPStan returns error:

Method Nette\Application\UI\ITemplate::render() invoked with 1 parameter, 0 required.

But I only follow the documentation about Components: https://doc.nette.org/…n/components#…
In other words, render() method must contain a parameter with the template path.

David Grudl
Nette Core | 8218
+
0
-

You're not doing anything wrong, only Phpstan is too strict on this old design.

Ages
Member | 128
+
+2
-

Hi i have the same issue.
Is this the correct way to prevent it?

assert($this->template instanceof Nette\Bridges\ApplicationLatte\Template);
$this->template->render(template.latte');
jspetrak
Member | 15
+
+2
-

Or you can put this error into phpstan baseline and let it be ignored.

Last edited by jspetrak (2021-05-18 11:17)

Ages
Member | 128
+
0
-

jspetrak wrote:

Or you can put this error into phpstan baseline and let it be ignored.

Ok, thank you.

Marek Bartoš
Nette Blogger | 1261
+
+5
-

I am just adding annotation on top of every presenter, to hint which Template class will be really used. I'ts useful when you use {templateType} macro and custom Template classes to be type-safe on both sides (presenter/control and latte)

So something like this:

/**
 * @property-read ExampleTemplate $template
 */
class ExamplePresenter extends \Nette\Application\UI\Presenter {}

If you use the default template instead of custom ones, then this should work:
@property-read Nette\Bridges\ApplicationLatte\DefaultTemplate&\stdClass $template

Eventually could be used this:

class ExamplePresenter extends \Nette\Application\UI\Presenter
{

	private ExampleTemplate $template;

	protected function beforeRender(): void
	{
		parent::beforeRender();
		$this->template = $this->createTemplate(ExampleTemplate::class);
	}

	public function renderDefault(): void
	{
		$this->sendTemplate($this->template);
	}

}

The sendTemplate() part is required, Nette does not know about the private $this->template property.
Note it's only possible, because $this->template property in Nette\Application\UI\Control is private and accessed via magically called getTemplate() method. In case of protected or public method would type override fail.

Last edited by Marek Bartoš (2021-05-18 11:43)

Ages
Member | 128
+
0
-

Marek Bartoš wrote:

I am just adding annotation on top of every presenter, to hint which Template class will be really used. I'ts useful when you use {templateType} macro and custom Template classes to be type-safe on both sides (presenter/control and latte)

So something like this:

/**
 * @property-read ExampleTemplate $template
 */
class ExamplePresenter extends \Nette\Application\UI\Presenter {}

If you use the default template instead of custom ones, then this should work:
@property-read Nette\Bridges\ApplicationLatte\DefaultTemplate&\stdClass $template

Eventually could be used this:

class ExamplePresenter extends \Nette\Application\UI\Presenter
{

	private ExampleTemplate $template;

	protected function beforeRender(): void
	{
		parent::beforeRender();
		$this->template = $this->createTemplate(ExampleTemplate::class);
	}

	public function renderDefault(): void
	{
		$this->sendTemplate($this->template);
	}

}

The sendTemplate() part is required, Nette does not know about the private $this->template property.
Note it's only possible, because $this->template property in Nette\Application\UI\Control is private and accessed via magically called getTemplate() method. In case of protected or public method would type override fail.

Well, this is the best way, I think.

Marek Bartoš
Nette Blogger | 1261
+
0
-

Ad. private ExampleTemplate $template; – method flashMessage() would fail. It assigns flashes into template from getTemplate() method, which means an otherwise unused template is created and flash messages are assigned to it instead of custom one. So, using annotation is still probably the best way.