Adding global constant to latte

mrcosgrove
Member | 11
+
0
-

I am using Nette Application.

I have added a constant to common.neon file.

I am trying to get that constant to be always present in latte files.

Currently I am using beforeRender() in the presenter to push the constant in like:

public function beforeRender() {
$this->template->myconst = CONST;
 }

but I was looking for a way to make it always there without needing to define it in every presenter, similar to how $basePath is available in every latte template.

Is this possible to do?

m.brecher
Generous Backer | 872
+
+1
-

Hi,

there is a rather complicated way to push a variable authomatically in every latte template the same way as $basePath but I recommend to go the standard way via BasePresenter – an abstract class from which you inherit every final Presenter you have in your application.

Something like this:

abstract class BasePresenter extends Nette\Application\UI\Presenter
{

    public function beforeRender()
	{
		$this->template->const = CONST;
	}
}
final class FirstPresenter extends BasePresenter
{

......

    public function beforeRender()
    {
		parent::beforeRender();  // dont forger call the parent methed !!
        .......
    }
}

and all presenters extend from BasePresenter !

Last edited by m.brecher (2023-01-07 18:53)

mrcosgrove
Member | 11
+
0
-

ah yes of course, thank you!

dsar
Backer | 53
+
0
-

A more elegant way in my 2nd post here

mrcosgrove
Member | 11
+
0
-

I ended up just creating a base presenter file:

class BasePresenter extends Presenter {
    public function beforeRender() {
        $this->template->CONST = CONST;
    }
}

and then the presenters just extend the base presenter rather than presenter.

final class HomePresenter extends BasePresenter {}

simple but effective.

m.brecher
Generous Backer | 872
+
0
-

@mrcosgrove

I ended up just creating a base presenter file

Hierarchy of abstract presenters is traditional but still not bad architecture. In one place you may solve more settings for whole app or for part.

Another way is using traits, which is suitable in case, that you need distribute functionality into just a few presenters.

I recommend for apps with public and privat part use two levels of abstract presenters:

BasePresenter – whole app
FrontPresenter extends BasePresenter – for public part
AdminPresenters extends BasePresenter – for administration/private part

Many developers go this simple way. You can combine this architecture with traits and components. It is a good practice not to load too many tasks to the abstract presenters. But injecting data into all templates or layouts is exactly the job for abstract presenter.

dsar
Backer | 53
+
0
-

m.brecher wrote:

But injecting data into all templates or layouts is exactly the job for abstract presenter.

Yes but the less does the abstract presenter, the better ;-) creating a latte extension for injecting pervasive constants is more general. Twig already has a way to inject some global constants and I wished for something similar for Latte.

Furthermore some constants are very related to some specific deployments or customers, so it's better to keep them in a config file (that is not going to be committed in the repository). The ga_tracking variable in that link is one example

m.brecher
Generous Backer | 872
+
0
-

@dsar

Furthermore some constants are very related to some specific deployments or customers, so it's better to keep them in a config file

I partly agree with you. Theoretically some very global variables/constants might be better to inject directly into latte templates. But until now I haven't seen any single application in my development life where this would be smart solution – but my experiences are very limited. With one exception – $appDir – needed for including latte files in latte templates and render() methods of drawable components.

Even if it is not often used practice inject application-specific constants in every latte file (send me a sample from your portfolio, where it is smart), I agree that in special cases it might be handy and I would vote like you for that Twig-like simple way.

But more handy would be implement automatic injection of $appDir into presenter and latte the same way as $basePath. I´am wondering a litte bit that it is not so. May be internal developer team seem this unimportant because injecting by hand is not complicated.

I had already some discussion with other developers and know, that some of them would never use $appDir. This is because they have a simple projects, where they have no module directories + globally used templates located separately. I see using $appDir for including globally used templates as a MUST. Relative paths like ‘../../Front/Forms/templates/…’ are confused.

mrcosgrove
Member | 11
+
0
-

BasePresenter – whole app
FrontPresenter extends BasePresenter – for public part
AdminPresenters extends BasePresenter – for administration/private part

Just my opinion here:

Really, this should be the role of middleware rather than the presenter. It sounds like you would be using this to verify access to the admin area. Which, if Nette had a middleware layer, it could be done there prior to the Presenter rather than as part of the presenter.

While I don't think middleware actually exists in Nette (would love to see it) and your solution will do the job, its not really the presenters job to verify access, mainly because in a Controller (Presenter) there should be no logic.

Better to at least move the logic into some form of business logic and keep the presenter clean and just call the business logic for verifying access.

m.brecher
Generous Backer | 872
+
0
-

@mrcosgrove

Really, this should be the role of middleware rather than the presenter.

Until now my strategy is that authorization is a first job of presenter. But not directly, presenter ask some specialized component for authorization and throws exception. This strategy is sufficient in case that authorization isn't very complicated. In simple cms where you have two user roles for administration is no need for any middleware.

This is traditional but effective way how presenters should be used in Nette – not to do directly detailed jobs but forward specialized tasks to specialized components, but keep hierarchical control over important things.

Some middleware has been mentioned in one of @DavidGrudl articles of future development Nette, so I think that in near future we will see some new features ;).

Marek Bartoš
Nette Blogger | 1275
+
0
-

authorization is a first job of presenter

Authentication. Authorization is very individual – whole page (presenter) may have restricted access, sometimes it's just one button (part of component).

$this->template->CONST = CONST;

If it is really just a constant, why not use it as a constant?

{= PHP_VERSION_ID}
{if PHP_VERSION_ID < 80000}
	{* ... *}
{/if}
David Grudl
Nette Core | 8228
+
+3
-

I try to avoid unclear bindings, so that the programmer doesn't simply ask questions like “where does this variable in the template come from?” So I generally find it better to look at the presenter as a source of all the variables.

But it would probably make sense to create one special template variable, for example $config, to which variables from the configuration could be passed directly.

latte:
	variables:
		trackingID: 'UA-xxxxx-x'
<script>
	ga('create', {$config->trackingID});
	ga('send','pageview');
</script>
Marek Bartoš
Nette Blogger | 1275
+
0
-

@DavidGrudl Could it be limited to DefaultTemplate or combine property_exists check and variable type checks? I already have $config in my templates and it is strictly typed.

Or maybe even something like {$this->config->trackingId} (Yes, I do abuse $this in Latte templates sometimes, it is useful.)

David Grudl
Nette Core | 8228
+
0
-

It should not interfere with the own $config variable itself. Possible implementation here https://github.com/…da63c2b29c0f

Marek Bartoš
Nette Blogger | 1275
+
0
-

It fails when any global variable is set and constructed Template has typed $config property.
Cannot assign stdClass to property OriCMF\UI\Template\UITemplate::$config of type OriCMF\Config\ConfigProvider

Also I would not limit it to presenter template, because options may contain things like app name (used in header/footer components and emails)

David Grudl
Nette Core | 8228
+
+1
-

It fails when any global variable is set and constructed Template has typed $config property.

Yes, that's the intention.

m.brecher
Generous Backer | 872
+
0
-

@DavidGrudl

But it would probably make sense to create one special template variable, for example $config, to which variables from the configuration could be passed directly.

Yes, full agreement.

dsar
Backer | 53
+
0
-

David Grudl wrote:

Possible implementation here https://github.com/…da63c2b29c0f

Thank you, always wished for that.

It's fun that implementing it in Nette required less code than writing an extension :-)