assign global vars not working

For questions and problems with the CMS core. This board is NOT for any 3rd party modules, addons, PHP scripts or anything NOT distributed with the CMS made simple package itself.
Locked
User avatar
rotezecke
Power Poster
Power Poster
Posts: 411
Joined: Fri Apr 18, 2008 9:34 pm
Location: Nimbin, Australia

assign global vars not working

Post by rotezecke »

in a freshly upgraded CMSMS2.0 i cannot assign vars and access those vars from template:.

e.g, in news template (or cgblog) detail template (same problem with summary templates though)

Code: Select all

{assign var='news_id' value=$entry->id scope=global} 
or

Code: Select all

{if !empty($actionparams['category_id']) && !empty($actionparams['junk'])}
 {$canonical = "{root_url}/xxxxxx/category/{$actionparams['category_id']}/{$actionparams['junk']}.html" scope=global}{/if}
when i pop a {get_template_vars} in content of page, i can see my assigned variables (from both news and CGBlog). but not in page template:

Code: Select all

{extends file='template:2015_base'}

{block name="title"}

{if $page_alias == 'archive'}{title} | {if isset($news_id)}Issue #{$news_id}{else}{description|escape:'html'}{/if}
{elseif $page_alias == 'links'}{linksTitle id=$news_id} | {title}
{elseif $page_alias == 'news-blog'}{$cgblogtitle}
{elseif (isset($pageTitle) && $pageTitle == 'nodescription') || $page_alias == 'error404' || {description} eq ''}
{title}
{else}
{title} | {description|escape:'html'}{/if}
{/block}
and the base template:

Code: Select all

...
{process_pagedata}
...
<title>{block name="title"}
{if {description} eq ''}
{title}
{else}
{title} | {description|escape:'html'}
{/if}
{/block}
</title>

{if isset($canonical)}<link rel="canonical" href="{$canonical}">{elseif isset($content_obj)}<link rel="canonical" href="{$content_obj->GetURL()}">{/if}
i cannot overwrite {$canonical} and have wrong/empty <title></title> for those pages that require $news_id or $cgblogtitle (assigned as globals in sub-templates). all this worked in 1.12.1

----------------------------------------------

Cms Version: 2.0

Installed Modules:

CMSMailer: 5.2.4
FileManager: 1.5
MenuManager: 1.50
ModuleManager: 2.0
News: 2.50
CGSmartImage: 1.20.2
Search: 1.50
TinyMCE: 2.9.12
CGSimpleSmarty: 2.0
CGExtensions: 1.49.7
CGBlog: 1.13.1
CGFeedback: 1.7.2
Captcha: 0.5.2
FormBuilder: 0.8.1.1
AdminSearch: 1.0
MicroTiny: 2.0
JQueryTools: 1.3.6
CMSContentManager: 1.0
DesignManager: 1.0
Navigator: 1.0


Config Information:

php_memory_limit:
max_upload_size: 2000000
url_rewriting: mod_rewrite
page_extension: .html
query_var: page
auto_alias_content: true
locale:
set_names: true
timezone: Australia/Sydney
permissive_smarty: false


Php Information:

phpversion: 5.4.44-1~dotdeb+7.1
md5_function: On (True)
json_function: On (True)
gd_version: 2
tempnam_function: On (True)
magic_quotes_runtime: Off (False)
E_STRICT: 2048
E_DEPRECATED: 8192
test_file_timedifference:
test_db_timedifference:
memory_limit: 128M
max_execution_time: 30
output_buffering: 4096
file_uploads: On (True)
post_max_size: 8M
upload_max_filesize: 2M
session_save_path: /var/lib/php5 (1733)
session_use_cookies: On (True)
xml_function: On (True)
xmlreader_class: On (True)


Performance Information:

allow_browser_cache: Off (False)
browser_cache_expiry: 0
php_opcache: Off (False)
smarty_cache: Off (False)
smarty_compilecheck: Off (False)
smarty_cache_udt: Off (False)
auto_clear_cache_age: On (True)

Server Information:

Server Api: apache2handler
Server Db Type: MySQL (mysql)
Server Db Version: 5.6.19
Server Db Grants: Found a "GRANT ALL" statement that appears to be suitable
Server Time Diff: No file system time difference found


----------------------------------------------
Last edited by rotezecke on Tue Oct 06, 2015 3:49 am, edited 2 times in total.
User avatar
Jo Morg
Dev Team Member
Dev Team Member
Posts: 1924
Joined: Mon Jan 29, 2007 4:47 pm

Re: assign global vars not working

Post by Jo Morg »

Although there has been an effort to limit these issues to a minimum, there are still cases where CMSMS architecture and Smarty architecture can collide now that we stopped allowing all variables to be on the global scope, both for security and good practice reasons. This solves a huge amount of problems front end developers where having where smarty variables got overwritten on complex templates.
Typically the global scope works perfectly except in cases where there is no easy way for CMSMS to know in which context a template has been created, thus being impossible to determine the parent/child relationship. In these particular cases the global scope is different and doesn't work as expected.
For this purpose CMSMS comes with a new plugin, {share_data} which is documented on it's own help page.
Typical use:

Code: Select all

{share_data scope=global data='title,canonical'}
This should solve all the issues related with the scope.
"There are 10 types of people in this world, those who understand binary... and those who don't."
* by the way: English is NOT my native language (sorry for any mistakes...).
Code of Condut | CMSMS Docs | Help Support CMSMS
My developer Page on the Forge
GeekMoot 2015 in Ghent, Belgium: I was there!
GeekMoot 2016 in Leicester, UK: I was there!
DevMoot 2023 in Cynwyd, Wales: I was there!
calguy1000
Support Guru
Support Guru
Posts: 8169
Joined: Tue Oct 19, 2004 6:44 pm
Location: Fernie British Columbia, Canada

Re: assign global vars not working

Post by calguy1000 »

I suspect that your page template has some advanced logic in it that is preventing CMSMS from dividing up the top, head, and body portions of the template.

This is because the symptoms you are specifying indicate that although the global variables are being assigned they are not being copied into your page template's scope properly.

For your information.... The way smarty works (and after extensive research by members of the Dev team we consider this to be a bug). is that assigned variables are actually just copied into the destination scope. And global variables are only copied into a template scope when that template object is fetched. not aferwards.

This means that (for example). if you had a simple page template like this:
{content}<h3>Foo is: {$foo}</h3>

And then created a page using that template. In that page you added
{$foo='bar' scope=global}

That 'bar' would NOT be output in the rendered page.

This is because as mentioned above, global variables would only be made available to the page template when the page template object was 'fetched'.

So, I think that your page template may actually be the problem here.

Thinks you can try:
a: use "scope=root" which will copy the variable into the root smarty object.
b: isolate the problem by using a simple page template (like Minimal) and making minor modifications to it.
Follow me on twitter
Please post system information from "Extensions >> System Information" (there is a bbcode option) on all posts asking for assistance.
--------------------
If you can't bother explaining your problem well, you shouldn't expect much in the way of assistance.
User avatar
Rolf
Power Poster
Power Poster
Posts: 7825
Joined: Wed Apr 23, 2008 7:53 am
Location: The Netherlands
Contact:

Re: assign global vars not working

Post by Rolf »

Is your default content block parsed through Smarty?

Add to the very top of your page template

Code: Select all

{$content = "{content}" scope=global}

And in the body

Code: Select all

{$content}
- + - + - + - + - + - + -
LATEST TUTORIAL AT CMS CAN BE SIMPLE:
Migrating Company Directory module to LISE
- + - + - + - + - + - + -
Image
User avatar
rotezecke
Power Poster
Power Poster
Posts: 411
Joined: Fri Apr 18, 2008 9:34 pm
Location: Nimbin, Australia

Re: assign global vars not working

Post by rotezecke »

Thanks for all the suggestions.
@Jo
i tried {share_data} in all sorts of places with no luck.
@Calguy
i tried root (and parent), no luck. the page template is indeed complex (and probably to blame). will keep digging
@Rolf
Yes thats what i'm doing

one thing i tried today (master template):

Code: Select all

{get_template_vars assign=msVars}
{block name="top"}
 {content label="Main Content of Page - cannot be empty" assign=bigContentBlock}
 {$bigContentBlock = $bigContentBlock scope=global}
{/block}
and {$msVars} in extended template.

placing {get_template_vars assign=msVars} before content block results in empty $canonical, placing it after the block, shows correct result. however, {$msVars = $canonical} in same place (after content block) shows nothing.

i had some success with calguys' workaround shown here: http://forum.cmsmadesimple.org/viewtopi ... =7&t=73344
but not where I need the same variable in multiple areas (page template and content)
calguy1000
Support Guru
Support Guru
Posts: 8169
Joined: Tue Oct 19, 2004 6:44 pm
Location: Fernie British Columbia, Canada

Re: assign global vars not working

Post by calguy1000 »

There are some issues in 2.0 with respect to smarty and scopes. Though I do not know if those issues are what you are encountering because there just isn't enough information.

The fixes for these issues are being tested right now for a 2.0.1 release in the next little while. The release date depends on testing, votes, and what else comes up between now and then.
Follow me on twitter
Please post system information from "Extensions >> System Information" (there is a bbcode option) on all posts asking for assistance.
--------------------
If you can't bother explaining your problem well, you shouldn't expect much in the way of assistance.
User avatar
rotezecke
Power Poster
Power Poster
Posts: 411
Joined: Fri Apr 18, 2008 9:34 pm
Location: Nimbin, Australia

Re: assign global vars not working

Post by rotezecke »

i just managed to find a workaround.

1) variables set in e.g. news template and needed in page template i used calguys my_get / my_set approach. works ok.

viewtopic.php?f=7&t=73344

2) variables set in e.g. news template and needed in content, the assign syntax work ok (scope=global)

3) neither of the above worked for append or assign from plugins ($smarty->assign(...)). my master template has this in the end

Code: Select all

{if !empty($readyJS)}
 {foreach from=$readyJS item=msFoo}{$msFoo|strip}{/foreach}
{/if}
which adds dynamic document ready functions set (appended) by custom plugins and elsewhere. this didnt work anymore.
i noticed that when i popped a {get_template_vars} in my page template (near the bottom) it did work however (??). based on that i came up with this UDT:

Code: Select all

//$smarty = cmsms()->GetSmarty(); 
if(! $smarty || !isset($params['var'])) { return; }

$str = $smarty->get_template_vars(trim($params['var']));

$smarty->assign(trim($params['var']),$str);
return;
and the retrieval of dynamic javascript:

Code: Select all

{my_var var=readyJS}
{if !empty($readyJS)}
 {foreach from=$readyJS item=msFoo}{$msFoo|strip}{/foreach}
{/if}
this seems to work fine for variables coming from plugins (in both page content and page template). hope this helps anyone.
or is there a way to tell $smarty->assign(...) to create a global variable?
Last edited by rotezecke on Thu Oct 08, 2015 2:57 am, edited 1 time in total.
lewishowles
Forum Members
Forum Members
Posts: 52
Joined: Tue Oct 25, 2011 4:45 pm
Location: Lancashire, UK

Re: [fudged] assign global vars not working

Post by lewishowles »

Hmm yes, I can confirm assigning variables from a plugin doesn't currently work (sort of). If it's at all helpful, I have a very simple (so far) plugin:

Code: Select all

function smarty_cms_function_validate_form() {
	$valid = true;
	$errors = [];

	if ($_POST['type'] == 'donate_single') {
		$donation_amount = preg_replace('/[^0-9.,]+/', '', $_POST['donation_amount']);

		# Validate Donation Amount
		if (!preg_match('/\b\d{1,3}(?:,?\d{3})*(?:\.\d{2})?\b/', $donation_amount)) {
			$valid = false;
			$errors['donation_amount'] = "Donation amount ($donation_amount) invalid.";
		}
	}

	$smarty = cmsms()->GetSmarty();
	$smarty->assign('valid', $valid);
	$smarty->assign('errors', $errors);
}
and in a Global Content Block, which is being called on a page, I have:

Code: Select all

{validate_form}
{get_template_vars}
<pre>valid: "{$valid}"</pre>
<pre>errors: "{$errors}"</pre>
{get_var var='valid'}
{get_var var='errors'}
<pre>valid (after): "{$valid}"</pre>
<pre>{$errors|@debug_print_var:4:400}</pre>
which is using rotezecke's idea.

As you can see from the attached screenshot, the variables are correctly assigned in get_template_vars, and only assigned to individual variables if passed through a UDT. Strange!
Attachments
variables.jpg
User avatar
rotezecke
Power Poster
Power Poster
Posts: 411
Joined: Fri Apr 18, 2008 9:34 pm
Location: Nimbin, Australia

Re: assign global vars not working

Post by rotezecke »

after 2.0.1.1 upgrade the previous fudge (UDT retrieving variables from "get_template_var scope") stopped working.

how can I append from a plugin to a global array? in another post there was something like assignGlobal, is there appendGlobal as well?
calguy1000
Support Guru
Support Guru
Posts: 8169
Joined: Tue Oct 19, 2004 6:44 pm
Location: Fernie British Columbia, Canada

Re: assign global vars not working

Post by calguy1000 »

You cannot assign variables to the global smarty object late in the processing game and expect them to work. This is because generic templates, the page top, head, and body, and generic templates, and numerous module actions are all in different smarty scopes.

This has advantages related to memory use and preventing one template from implicitly overwriting another templates variables. But introduces a learning curve for those writing plugins and templates.

Also complicating the issue is the way that smarty works. Variables are only copied into scope when a new template is created. assigning a variable in a child template and assigning it to the global scope will have no instantaneous effect on the parent template.

So in your page content/page template body if you have
{global_content name='foo'}
{$somevariable}

and in your 'foo' generic template if you have
{$foo=5}

It will not work... because the 'foo' generic template is in it's own scope.
and the parent template already has it's variables assigned (including global variables).
{$foo=5 scope=parent} MAY work.

Also. Assigning variables to the global smarty scope will not have effect on the current smarty scope. Those variables are only going to be available to the global smarty scope, and any of it's children.

$smarty->assignGlobal() is the same as {$foo=5 scope=global} or {assign var='foo' value=5 scope=global}. It does create a global variable, but you can only use it in subsequently created templates.

So this is a learning curve issue, not necessarily an issue with CMSMS. We have done some extensive testing and modifications to try to ensure that we understand what is happening.
Follow me on twitter
Please post system information from "Extensions >> System Information" (there is a bbcode option) on all posts asking for assistance.
--------------------
If you can't bother explaining your problem well, you shouldn't expect much in the way of assistance.
User avatar
rotezecke
Power Poster
Power Poster
Posts: 411
Joined: Fri Apr 18, 2008 9:34 pm
Location: Nimbin, Australia

Re: assign global vars not working

Post by rotezecke »

Fudged again. However:
$smarty->assignGlobal() is the same as {$foo=5 scope=global} or {assign var='foo' value=5 scope=global}.
What is the php equivalent for

Code: Select all

{append var='name' value='Bob' scope=global}
?

new code does use strings instead of arrays. Plugin:

Code: Select all

$jquery_inject = <<< EOT
	$("ul#$galleryID").tabs(">div.image_pane", {
	  rotate: $rotate
	  }).slideshow({clickable:$clickable, autoplay: $autoplay, interval: $interval });
EOT;
$temp = $smarty->get_template_vars('readyJS_str'); //get string
//the above fails in 1.12.1 ($temp is empty) but works in 2.0.1.1
$smarty->assignGlobal('readyJS_str',$temp.$jquery_inject); //append to string
in base template i still need to retrieve the global variable from the "get_template_vars scope" using UDT as describe somewhere above

Code: Select all

{my_var var=readyJS_str}
{if $readyJS_str}
<__script__>$(document).ready(function() { {$readyJS_str|strip} } )</__script>
{/if}
there was another problem in the mix that worked previously: <__script__> tags (and anything in between) cannot be assigned:

Code: Select all

$jquery_inject = <<< EOT
<__script__>
      $(document).ready(function() {     
	$("ul#$galleryID").tabs(">div.image_pane", {
	  rotate: $rotate
	  }).slideshow({clickable:$clickable, autoplay: $autoplay, interval: $interval })
      });
</__script>
EOT;
  $smarty->assignGlobal('readyJS2',$jquery_inject);

now results in an empty string !!!, whereas

Code: Select all

$jquery_inject = <<< EOT
      $(document).ready(function() {     
	$("ul#$galleryID").tabs(">div.image_pane", {
	  rotate: $rotate
	  }).slideshow({clickable:$clickable, autoplay: $autoplay, interval: $interval })
      });
EOT;
  $smarty->assignGlobal('readyJS2',$jquery_inject);
is available in template.
lewishowles
Forum Members
Forum Members
Posts: 52
Joined: Tue Oct 25, 2011 4:45 pm
Location: Lancashire, UK

Re: assign global vars not working

Post by lewishowles »

Just to weigh back in on this, after 2.0.1.1 the {get_var} still seems to be required (for the method I'm currently using to create templates). I'll give a more specific example and hopefully I'm understanding how it should work correctly.

I've created quite a few custom tags for CMSMS for our work, and they all follow a similar format:

Code: Select all

{twitter screen_name="{global_content|replace:'@':'' name='Twitter Username'}" count='3'}
This tag assigns a number of variables (using assignGlobal), and immediately after we'll have something like

Code: Select all

{if $tweets|@count > 0}
	<div class="tweets">
		<div class="row">
			{foreach from=$tweets item=tweet}
...
From Calguy's explanation I understand that the page variables are all assigned before the {tweets} tag is even called, so the {$tweets} variable is never going to be available.

So to get around that, I'm using the {get_var} tag to then assign the variable so I can use it immediately. That all makes sense.

Am I right to think that if instead, for example, I had something like

Code: Select all

{twitter screen_name="{global_content|replace:'@':'' name='Twitter Username'}" count='3'}
{global_content name='tweets'}
where the GCB had the {if $tweets...} code, that would then work, because the 'tweets' template was created after the variables were assigned from the {twitter} tag?

It gets somewhat difficult to manage Templates at the moment (as we end up with quite a few templates when combining Navigator, GCB, Pages etc and often needed to access a few types at once) so if I'm right I'll stick with the fudgey method for now!
calguy1000
Support Guru
Support Guru
Posts: 8169
Joined: Tue Oct 19, 2004 6:44 pm
Location: Fernie British Columbia, Canada

Re: assign global vars not working

Post by calguy1000 »

I think you're having problems with 'which' smarty you are using.
You should almost never, ever use the global smarty object. Not in plugins, not in modules, not in UDT's... ever. There is a fair bit of code that will have to change because of this.

Plugin files pass the correct smarty scope into a variable called $smarty or $template... you can see that in the function declaration. Use it.

UDT's are exactly the same as plugin files. They are smarty 'function plugins'. They pass in the correct smarty template object in a variable called $smarty.

[edit] this is not new. The proper $smarty template object has been in scope in UDT's and plugins for along time. And in module actions $smarty has always been available.

2.0.1 Fixed numerous issues to make sure that the 'proper' smarty template object was available for module actions and added a new module method to help with that, other things... and 2.0.1.1 fixed a minor omission.

The problem now is that code cannot assume that the global smarty object is the correct scope. (I will have more adjusting to do in some of my modules too). More advanced module code may have to be adjusted to pass the proper $smarty template object around.
[/edit]

I created a simple UDT called 'testudt' that simply had this code (and nothing more).

Code: Select all

$smarty->assign('foo','bar');
I then created a new content page and within it I placed:

Code: Select all

{testudt}<p>Foo is: {$foo}</p>
And it worked 100% properly.
Follow me on twitter
Please post system information from "Extensions >> System Information" (there is a bbcode option) on all posts asking for assistance.
--------------------
If you can't bother explaining your problem well, you shouldn't expect much in the way of assistance.
lewishowles
Forum Members
Forum Members
Posts: 52
Joined: Tue Oct 25, 2011 4:45 pm
Location: Lancashire, UK

Re: assign global vars not working

Post by lewishowles »

Yeah, now that UDTs error if you try to grab Smarty for yourself, it's more obvious that you're doing it wrong, whereas that doesn't happen in a plugin file so it's not as clear that it shouldn't be done.

It looks like whichever plugin I based the structure of mine on way back when didn't have the second smarty parameter in the function definition, but it sounds like adding it in should stop any weirdness.
Locked

Return to “CMSMS Core”