pug-php / pug

Pug template engine for PHP
https://www.phug-lang.com
MIT License
391 stars 42 forks source link

Accessing helper functions in a namespace #230

Closed kylekatarnls closed 4 years ago

kylekatarnls commented 4 years ago

From comment https://github.com/phug-php/phug/issues/16#issuecomment-564333203

Issue with the following code:

namespace myNameSpace;

function fooBar() {
  return 'Hello';
}

\Phug\Phug::setOption('on_output', function (\Phug\Compiler\Event\OutputEvent $event) {
  $event->setOutput('<?php namespace myNameSpace; ?>' . $event->getOutput());
});

$pug = new \Pug\Pug([
  'strict' => true,
  'pretty' => true,
  'cache'  => '/tmp/',
]);

$content = $pug->renderString('p=fooBar()');

Expected to get:

<p>Hello</p>

Actually get:

Error: Using $this when not in object context
kylekatarnls commented 4 years ago

functionsNamespace option added in js-phpize/js-phpize 2.6.0

So you can run composer update then now use:

namespace myNameSpace;

function fooBar() {
  return 'Hello';
}

$pug = new \Pug\Pug([
    'module_options' => [
        'jsphpize' => [
            'functionsNamespace' => 'myNameSpace',
        ],
    ],
]);

$pug->display('p=fooBar()');

This is the new recommended way to call the functions from a custom namespace in templates.

windware-ono commented 4 years ago

Hi.

Thanks for a quick resolution. However, I still cannot apply it given the following code. Also, you misspelled functionsNamespace as functionNamespace in the example code above.

Your code works but perhaps it's because I'm calling it from a static method of a class?

<?php
namespace phugNamespace;
require('vendor/autoload.php');

class namespaceTest
{
    function __construct()
    {
        $pug = new \Pug\Pug([
            'module_options' => [
                'jsphpize' => [
                    'functionsNamespace' => 'phugNamespace',
                ],
            ],
        ]);

        print $pug->render('div=namespaceTest::templateMethod()');
    }

    static function templateMethod()
    {
        return 'Hello';
    }
}

new namespaceTest();

If I change div=namespaceTest::templateMethod() into div=\phugNamespace\namespaceTest::templateMethod(), then it will render fine.

I'm using php 7.4.0 and composer.json being,

{
    "require" : {
        "pug-php/pug" : "^3.0"
    }
}

which installed the following.

js-phpize/js-phpize                     2.6.0
js-phpize/js-phpize-phug                2.2.0
js-transformer/js-transformer           1.0.0
nodejs-php-fallback/nodejs-php-fallback 1.4.1
phug/js-transformer-filter              1.2.0
phug/phug                               1.4.0
pug-php/pug                             3.3.1
symfony/polyfill-mbstring               v1.13.1
symfony/var-dumper                      v5.0.1
kylekatarnls commented 4 years ago

functionsNamespace is for functions not for methods. I'm not sure we should allow calls of static class methods from inside the template in an easier way than \phugNamespace\namespaceTest::templateMethod()

It sounds to me like mixing responsibilities between your controller and your view and some kind of false OOP.

In your case, I recommend this approach:

<?php

namespace phugNamespace;

require 'vendor/autoload.php';

class namespaceTest
{
    public function __construct()
    {
        (new \Pug\Pug)->display('div=view.templateMethod()', [
            'view' => $this,
        ]);
    }

    public static function templateMethod()
    {
        return 'Hello';
    }
}

new namespaceTest();
windware-ono commented 4 years ago

Ok, thanks. I've changed my code to work like that.