How activate xen tags (not include in template) when injecting code inside templates

cclaerhout

Well-known member
My title is not the best one, I know. A simple example will be better. What I'm trying to do in the template hook listener:

PHP:
$mystring ="This is {xen:phrase myphrase}"; //It's just an example, this string is inside the database, I would like to avoid to capture the tag, then use PHP to activate the phrase
$template->setTemplate('MyVirtualTemplate', $mystring);
$templateObject = $template->create('MyVirtualTemplate', array());
 
//Then I would like to render my Virtual Template, but It doesn't want
$final = $templateObject->render();

I've got different kinds of errors: when xen tags used in $mystring:
Code:
Parse error: syntax error, unexpected ':'

Otherwise:
Code:
Parse error: syntax error, unexpected $end

All in "library/XenForo/Template/Abstract.php".

I've also tried with the XenForo_Template_Compiler, but nothing happens.

Is there a way, or to be parsed a xen tag must be in template first and can't be injected after?
 
My title is not the best one, I know. A simple example will be better. What I'm trying to do in the template hook listener:

PHP:
$mystring ="This is {xen:phrase myphrase}"; //It's just an example, this string is inside the database, I would like to avoid to capture the tag, then use PHP to activate the phrase
$template->setTemplate('MyVirtualTemplate', $mystring);
$templateObject = $template->create('MyVirtualTemplate', array());
 
//Then I would like to render my Virtual Template, but It doesn't want
$final = $templateObject->render();

I've got different kinds of errors: when xen tags used in $mystring:
Code:
Parse error: syntax error, unexpected ':'

Otherwise:
Code:
Parse error: syntax error, unexpected $end

All in "library/XenForo/Template/Abstract.php".

I've also tried with the XenForo_Template_Compiler, but nothing happens.

Is there a way, or to be parsed a xen tag must be in template first and can't be injected after?
Use
Rich (BB code):
$mystring ="This is ". new XenForo_Phrase('myphrase'); //It's just an example, this string is inside the database, I would like to avoid to capture the tag, then use PHP to activate the phrase
$template->setTemplate('MyVirtualTemplate', $mystring);
$templateObject = $template->create('MyVirtualTemplate', array());
 
//Then I would like to render my Virtual Template, but It doesn't want
$final = $templateObject->render();

Salud2
 
Use
Rich (BB code):
$mystring ="This is ". new XenForo_Phrase('myphrase'); //It's just an example, this string is inside the database, I would like to avoid to capture the tag, then use PHP to activate the phrase
$template->setTemplate('MyVirtualTemplate', $mystring);
$templateObject = $template->create('MyVirtualTemplate', array());
 
//Then I would like to render my Virtual Template, but It doesn't want
$final = $templateObject->render();

Salud2
That what I didn't want to use ^^ see the explanation at the right of the code. But thank you for your answer.
 
Im not so sure you are going the right way about this. If you are populating your own database table with template code would it not just be easier to progmatically add a template? Same difference right but less headache, surely?
 
As example I wrote simple addon. This addon is fully work, but is not good idea. The best solution is create permanent template and render it with parameters.
 

Attachments

As example I wrote simple addon. This addon is fully work, but is not good idea. The best solution is create permanent template and render it with parameters.
I had done the first line for compiler, but I was missing the three following ^^ Thank you very much for the code.

I already create templates with parameters, but this time I need a solution to parse phrase. My next addon will be the integration of a new editor to XenForo. I've done an admin interface with a button management system, which can deal the button command (it uses javascript). A command can for example inserts text in the editor. And if this text can support phrase management for language, it would be better. I can use my own tags to allow users to create their own phrases (regex to catch the phrase part then, "new XenForo_Phrase('capture')"), but I would have preferred a full automatic solution.

In my addon previous version, I was using one template for each button, but the management wasn't good enough. That's why I've chosen the Db solution which is... really good now ^^ Except for this phrase problem.


Infis, you say that it's "not a good idea", may I ask you why? Is it bad for performance?


P.S: another question, why do you use try and catch commands?
Edit: Oh I think I understand, it's faster than to do a if(isset$variable)) {} ; nice way !
 
I still dont understand why you just dont progmatically add templates to the template system as opposed to using your own tables.
 
Because it's not really a template... All those commands are a small part of a big JS code that I need to build inside the listener. Then inject inside the template. Same thing for CSS by the way.
Let's take an example of the URL button set code:
Code:
{name:'Link', key:'L', openWith:'[url=[![Url]!]]', closeWith:'[/url]', placeHolder:'Your text to link here...'},

This code can change, except the first "name:......", I can"t create a template with parameters to deal with all this.
 
Infis, you say that it's "not a good idea", may I ask you why? Is it bad for performance?
Of course, the compilation is "on the fly" will be less productive than the pre-compilation. XenForo stores compiled templates just for this. It also allows multiple templates to use without sacrificing performance.
You can try to conclude a stored template, for example, in every post. And then do the same with the template generated "on the fly". Compare the page generation time.
P.S: another question, why do you use try and catch commands?
Edit: Oh I think I understand, it's faster than to do a if(isset$variable)) {} ; nice way !
I do not remember why. Perhaps it had to be treated with a "guest".
 
You can try to conclude a stored template, for example, in every post. And then do the same with the template generated "on the fly". Compare the page generation time.
Done.... you're absolutely right... The loaded time is multiply by 2... I'm going to forget this ^^ But thank you for the explanation ! It was very interesting.

Edit: nope, not by 2 sorry. => a connexion pb.
Edit2: i've check my previous code... my first line wasn't good too ^^ My bad.
 
I'm going to forget this
Poor performance of this solution was an obstacle to that, to allow further refinement of this addon. While this addon can be done without the use of syntax XenForo templates. For simple cases, such as inserting counter codes and other stuff in the hooks - only clear HTML code. I wrote it to get rid of writing addons for simple insertions into the hooks.
If we build upon it, then you need to write a good procedure to generate a list of hooks to choose rather than typing the name of the hook. I think that such a simple addon (without the use of syntax XenForo) will be quite popular. The main thing that is not abused by the use of hooks, which are in themselves degrade performance.
In general, such a addon is a different discussion thread :)
 
I've done tests again, and finally I don't see any differences. But I only do it to one short code (7000 characters once minified) whereas in your addon you did it for every hooks and with many foreach. May be it's why the performance are degradating.

So to use your solution with the first example give above, here the final code:

PHP:
            $mystring = "This is {xen:phrase myphrase}";
 
            $style_session = $template->getParam('visitorStyle');
            $style_id = $style_session['style_id'];
            $visitor = XenForo_Visitor::getInstance();
                    if (empty($visitor['language_id']))
                    {
                        $options = XenForo_Application::get('options');
                        $lang_id = $options->defaultLanguageId;
                    }
                    else
                    {
                        $lang_id = $visitor['language_id'];
                    }
 
            $compiler = new XenForo_Template_Compiler(html_entity_decode($mystring));
            $parsed = $compiler->lexAndParse();
            $compiled = $compiler->compileParsed($parsed, 'MyTemplateAddedToContent', $style_id, $lang_id);
            eval($compiled);
           
            $mystring = $__output;

By the way, you've made a small error inside your code with the third parameter of the compileParsed function:
Code:
compileParsed($segments, $title, $styleId, $languageId
You put twice the languade id.
 
I've done tests again, and finally I don't see any differences. But I only do it to one short code (7000 characters once minified) whereas in your addon you did it for every hooks and with many foreach. May be it's why the performance are degradating.
For one call this method is with minimal difference between permanent and "on the fly" templates. But for many calls this method is bad.
You put twice the languade id.
Oh, yes. Thank you for this bug.
 
A little update to the "final code" of post #12

I've noticed that if the string has "options" variables ($xenOptions), these variables were not retrieved. For example:
PHP:
$mystring = "This is {xen:phrase myphrase} coming from {$xenOptions.boardTitle}"

So here is a basic and easy solution to solve the problem:

PHP:
class MyClass
{
  public static function MyFunction()
  {
            $mystring = "This is {xen:phrase myphrase} coming from {$xenOptions.boardTitle}";
 
            $mystring = preg_replace_callback('#(?:{)?\$xenOptions\.([0-9a-z_]+)(?:\.)?([0-9a-z_]+)?(?:})?#i', 'MyClassName::MyRegexCallBackFunction', $Params['XenforoSet']);
 
            $style_session = $template->getParam('visitorStyle');
            $style_id = $style_session['style_id'];
            $visitor = XenForo_Visitor::getInstance();
                    if (empty($visitor['language_id']))
                    {
                        $options = XenForo_Application::get('options');
                        $lang_id = $options->defaultLanguageId;
                    }
                    else
                    {
                        $lang_id = $visitor['language_id'];
                    }
 
            $compiler = new XenForo_Template_Compiler(html_entity_decode($mystring));
            $parsed = $compiler->lexAndParse();
            $compiled = $compiler->compileParsed($parsed, 'MyTemplateAddedToContent', $style_id, $lang_id);
            eval($compiled);
     
            $mystring = $__output;
  }
 
  public static function MyRegexCallBackFunction($matches)
  {
        $options = XenForo_Application::get('options');
   
        if (isset($matches[2]))
        {
            return $options->$matches[1][$matches[2]]; // I'm not sure about this, but this part of code should be useful in some forms (ie: active state)
        }
        else
        {
            return $options->$matches[1];   
        }
  }
 
}
 
Top Bottom