I have a function for smarty:
function smarty_function_false_() {
return false;
}
then if I do:
{if false_} false YES?? {else} false no {/if} <br>
{if not false_} not false yes {else} not false NO??? {/if}
And it evals to:
false YES??
not false NO???
I'm new to smarty, why is that happening?
The Smarty expression {if false_} does not evaluate any functions. It is equivalent to {if 'false_'}, which is in turn just the same as the PHP expression if ( 'false_' ). (Incidentally, if ( false_ ) in PHP also means the same thing, unless you have run define('false_', ...).)
Under PHP's "type juggling" rules, a string interpreted as a boolean is true as long as it is not the empty string (''). So {if false_} is equivalent to {if true}.
A Smarty "template function" is designed only to be called on its own, and return something to output to the template, e.g. {false_}.
The easiest way to have a callback that you can check inside an {if} condition is to define a "modifier" rather than a "function". Although a modifier will always be given at least one parameter, it can simply be ignored, so you could have the following:
function smarty_modifier_false_($whatever) {
return false;
}
And then in Smarty just pass any old string as the left of the modifier:
{if ''|false_} false_ is true!? {else} false_ is false. How reassuring. {/if}
Alternative approaches:
Set the Security settings in your template such that you can write {if false_()}, because false_ is a PHP function allowed directly in templates. (See documentation on {if} where it links to the details of Security.)
Register a block function. These are a little trickier to write, but would allow you to have your own custom if replacement, e.g. {if_false_} This text never appears {/if_false_}.
Related
<#if myVar = "test">
A
<#else>
B
<#/if>
If myVar is null / not defined, neither A nor B will be output. This is fixed by adding ! after the variable:
<#if myVar! = "test">
A
<#else>
B
<#/if>
Is this intended? Because if so, it is extremely confusing and I can't imagine any user would expect it to behave this way. It is suggesting that null = "test" is somehow neither true nor false. It seems clear that null = "test" should always be considered false -- what am I missing?
Note: we have configured Freemarker to replace unknown variables with an empty string:
config.setTemplateExceptionHandler((ex, environment, out) ->
{
if (ex instanceof InvalidReferenceException)
{
try
{
out.write("");
}
catch (IOException e)
{
throw new TemplateException("Error while handling template exception.", e, environment);
}
}
else
{
throw ex;
}
});
So this would (at least I thought it would) end up being:
<#if "" = "test">
A
<#else>
B
<#/if>
In which case, I'd expect the else to be entered for sure -- but it is not.
Given this example:
<#assign myVar = null/>
<#if myVar == "test">
A
<#else>
B
</#if>
This throws the following error:
The following has evaluated to null or missing:
==> null
myVar has been evaluated to null or missing -- this seems like the source of my confusion; Freemarker does not differentiate between missing and existing-but-null values, I guess?
It's irrelevant if it's #if/#else or any other directive call, because when an error occurs (any kind of TemplateException, not just "missing value"), the whole statement is skipped. Not the variable resolution, not even the whole expression, but the whole statement. That's what the Manual and the Javadoc says too, like see: https://freemarker.apache.org/docs/pgui_config_errorhandling.html. Therefore, templateExceptionHandler setting is not for providing defaults for missing values. It's for handling situations that are genuinely errors. Like, someone did a mistake, something is not operational.
As of why not take the #else still. When an error occurs while evaluating the condition, the template engine just can't tell which branch would have been taken if the developers (or whoever) did not make a mistake. Picking either branch of the if/else is a gamble. (It's not even a 50-50 gamble, as the positive branch tends to be the right one considering the real world meaning of the output, yet, if anything, people expect the template engine to bet on the else branch.) So, hoping that you will print some error indicator at least, it rather doesn't pick either branch. But it's really automatic, as the whole #if/#elseif/#else thing is one big statement.
<#assign myVar = "test"/>
<#if myVar?? && myVar == "test">
A
<#else>
B
</#if>
Yes it is intended. When a variable is not defined or null, freemarker will raise an error.
It is explained in the FAQ: Why is FreeMarker so picky about null-s and missing variables, and what to do with it?
This is a design choice from the initial author of the framework. If you are not confortable with this choice, you can use the Default value operator (use myVar! instead of myVar), or use another templating framework.
The custom exception handler you added doesn't replace the expression with an empty String, it replaces the full if/else expression.
I am using below code to search string in given string in smarty but below code not working
$MyError = "Attribute";
{if $MyError|strpos:'Attribute Registration Number with value'}
<p>Welcome</p>
{/if}
In Smarty, you can use the PHP function strpos to search a string in given string :
{if strpos('Attribute Registration Number with value', $MyError) !== false}
<p>Welcome</p>
{/if}
Here is an other post about it.
I have a function in a model that can return either true or false.
I use this function inside a view and first thing I discovered when I called it is
{{ Setting::isDesktop() }}
that it outputs 1 instead of true if I do that inside blade file. If I do dd({{ Setting::isDesktop() }}) then it will print true or false.
Second thing that is giving me a problem is that, if the value is false then nothing is printed when doing this from blade file. I need something to be printed either 1/0 or true/false
Why does boolean get converted to number inside blade files but not controllers? How can I get something printed when isDesktop returns false? Right now it prints nothing in that case.
There are few methods you can achieve your requirement.
Here are couple of them,
1. Use Ternary operator like below,
{{ Setting::isDesktop() ? 'true' : 'false' }}
2. Use var_export as shown below,
{{ var_export(Setting::isDesktop()) }}
In my template, I would like to include some default meta tags (90% of the time). However, when a specific property is set, I would like to show a different set of text.
I know I can set an anonymous struct and set a property with either "default" or "some-x". However, this means, I need to add an anonymous struct to 90% of my handlers that just currently pass nil.
Is there way to do something like
{{if eq . nil}}
// default meta tag
{{else if eq .MetaValue "some-x"}}
//other
{{end}}
If I try something like my above code, it compiles but doesn't do what I want. Appreciate any suggestions on how to handle it properly without adding a lot of boiler plate.
Thanks!
{{if not .}}
output when . is nil or otherwise empty including
false, 0, and any array, slice, map, or string of length zero
{{else if eq .MetaValue "some-x"}}
// some-x case
{{else}}
// other case
{{end}}
If you want to ensure you're only checking against nil and not 0, false, the empty string, or any other falsey type, you can use the kindIs function to accomplish this.
{{ if kindIs "invalid" . }}
// only if variable is literally nil. falsey values will fallthrough.
{{ else if eq .MetaValue "some-x" }}
// other
{{ else }}
// final case, if any
{{ end }}
I've been recently facing an issue with identifying nil vs 0 values in a Helm Chart (which uses Go templates, including sprig) and haven't found any solutions posted, so I thought I'd add mine here.
I came up with a kind of ugly solution which is to quote the value and then check for a string that matches "<nil>" (with quotes, so you'd actually be checking (quote .Values.thing | eq "\"<nil>\"")). This allows differentiating tests against empty values vs defined 0 values. In my case, I was trying to build a config file where some default options were non-0, so when 0 was explicitly set, I wanted to know that 0 was set instead of just omitted.
Hopefully this can be a help to someone else.
It would be nice to have a better way to do this, but so far I haven't found anything that doesn't require creating and adding my own template functions.
In a freemarker template I want to expand a boolean variable to a string like that:
<#assign booleanVar = "test".isEmpty() />
state: ${booleanVar} <#-- this throws an exception! -->
This is what I want to get as output:
state: false
The only way I found to reach this goal by now is:
state: <#if booleanVar>true<#else>false</#if>
Is there a easier way to do it?
booleanVar?string("true", "false")
Although true/false is default, so
booleanVar?string
should work fine.
Starting from FreeMarker 2.3.20, if you want to print true/false (because you are generating JavaScript or such), write ${booleanVar?c} (?c for "computer format", also used for numbers). ${booleanVar?string} is dangerous for that, since somebody can set the boolean_format setting to yes,no or something... (BTW, in that case ${booleanVar} will work too in 2.3.20, and you get yes and no.)
See: http://freemarker.org/docs/ref_builtins_boolean.html#ref_builtin_c_boolean