Closed narirou closed 5 years ago
It works the way you expect in pugjs, so indeed it's a case we didn't anticipated and implemented the wrong way.
I will fix it when I can. I assume there is no emergency as you can work around using an other variable name.
mixin paragraph(_text)
p= _text
Thanks for quick response! We avoided this problem temporarily by changing the variable name. (However, our app has complex block scopes, so maintenance is a bit difficult.)
Hi I can confirm the issue.
Here is a snippet that fails:
mixin Test (params={})
- const props = params
p=props.text
mixin Wrap(params={})
- const props = params
+Test({ text: "one"})
if props.label
+Test({ text: "two"})
+Wrap({ label: "yes"})
Expected output:
<p>one</p><p>two</p>
Actual:
<p>one</p>
In my scenario I heavily use nested mixins and changing variable names would be a bit painful.
Is there any way I could help in fixing this issue?
Just to add some more infos. I tested the same snippet useing php as expression language and the result is the same:
mixin Test ($params = [])
- $props = $params
p=$props["text"]
mixin Wrap($params = [])
- $props = $params
+Test(["text" => "one"])
if $props["label"]
+Test(["text" => "two"])
+Wrap(["label" => "yes"])
This issue is still under the radar but not my top priority, it's a deep change with major impact. I know how to handle it, I just need some time allocation to work on it.
~The work-around in you specific case is variable renaming: mixin Test(testParams = {})
, mixin Wrap(wrapParams = {})
~
Note than copying the variable to props
is not needed and as it's converted into array by PHP, you should avoid it, it uses twice more memory.
@kylekatarnls Ok thank you for the prompt reply.
Actually I stripped away a part of the mixin initialization code where I was usinga custom function to provide defaults:
mixin Wrap(params={})
- const props = assign({ ...}, params)
Where assign
maps to array_merge
in PHP (my production env) and Object.assign
in JS (my development env).
I've experimented a little bit more and looks like that somethign like this would work without changing the variable names:
use \Pug\Pug;
$pug = new Pug([
'pretty' => true,
'expressionLanguage' => 'js',
'cache' => false,
'globals' => [
'assign' => function ($src, $arr) {
return array_merge($src, $arr);
}
]
]);
$html = $pug->render('
mixin Test (params = {})
- params = assign({}, params)
p=params.text
mixin Wrap(params = {})
- params = assign({label: false}, params)
+Test({ text: "one" })
if params.label
+Test({ text: "two" })
+Wrap({ label: true })
');
var_dump($html);
It works correctly with pugjs as well.
Do you see any issue in this implementation?
Thanks again!
No indeed. I was wrong, the scope problem can happen when using block
or creating/changing variables with the same name inside mixins, but not with mixin arguments themsleves.
Ok, thank you.
Sorry to bother again, but could you give me an example of this scenario?
the scope problem can happen when using
block
The original message of this issue:
mixin paragraph(text)
p= text
block
doctype html
html
body
+paragraph('1')
+paragraph(text)
+paragraph(text)
Got it! Thank you again!
Hi, it has just been fixed in phug/formatter
0.5.45. Please composer update
and retry.
Cool! Thank you!
I will test it. Thank you for quick fix!
Hi I've tested the example template again but it looks like it is still failing. Rendered HTML is still:
<p>1</p>
<p>1</p>
<p>2</p>
composer.json
{
"name": "pug-php-test",
"type": "project",
"require": {
"pug-php/pug": "^3.2"
},
"authors": []
}
My PHP version is 7.1.19
I've uploaded a test project including vendors here: https://github.com/dwightjack/pug-php-demo
Am I missing something?
Hi, can you check your versions of the following packages please:
composer show phug/formatter
composer show phug/renderer
I will test your example soon.
Hi, thank you for the quick reply!
here is the output:
name : phug/formatter
descrip. : Pug (ex-Jade) formatter for PHP, HTML template engine structured by indentation
keywords : ast, dialect, html, jade, php, phtml, phug, presentation, pug, render, template, views
versions : * 0.5.45
type : library
license : MIT License (MIT) (OSI approved) https://spdx.org/licenses/MIT.html#licenseText
source : [git] https://github.com/phug-php/formatter.git 59c21f547c4c14a2b13955ee9e2cf5bd0d583244
dist : [zip] https://api.github.com/repos/phug-php/formatter/zipball/59c21f547c4c14a2b13955ee9e2cf5bd0d583244 59c21f547c4c14a2b13955ee9e2cf5bd0d583244
names : phug/formatter
autoload
psr-4
* => ./src
requires
php >=5.5.0
phug/dependency-injection ^1.3.0
phug/parser ^0.5.0
phug/util ^0.4.14
requires (dev)
phug/dev-tool ^0.1.0
name : phug/renderer
descrip. : Pug (ex-Jade) renderer for PHP, HTML template engine structured by indentation
keywords : compiler, dialect, html, jade, php, phtml, phug, presentation, pug, render, template, views
versions : * 0.4.6
type : library
license : MIT License (MIT) (OSI approved) https://spdx.org/licenses/MIT.html#licenseText
source : [git] https://github.com/phug-php/renderer.git 47f4044cdf6d3c2331abec4b8fa5486888a5e2a5
dist : [zip] https://api.github.com/repos/phug-php/renderer/zipball/47f4044cdf6d3c2331abec4b8fa5486888a5e2a5 47f4044cdf6d3c2331abec4b8fa5486888a5e2a5
names : phug/renderer
autoload
psr-4
* => ./src
requires
php >=5.5.0
phug/compiler ^0.5.20
phug/util ^0.4.15
symfony/var-dumper ^3.4 || ^4.0
requires (dev)
cebe/markdown ^1.1
js-phpize/js-phpize-phug ^1.1.2
nodejs-php-fallback/coffeescript ^1.0
nodejs-php-fallback/less ^1.0
nodejs-php-fallback/stylus ^1.0
nodejs-php-fallback/uglify ^1.0
phug/dev-tool ^0.1.0
I cloned your repo, ran index.php then get the bug. Indeed, it works with external variables like this:
$pug->displayFile('template.pug', array(
'text' => '3',
));
But not with variables created inside the template. I'm not sure we can support this with no risk but I will inspect.
Thank you!
Let me not if you need any further test
Now fixed via propagation level-by-level, so you can take phug/formatter 0.5.46 by running composer update
and retry.
Thank you! Right now I'm back home. I will try it tomorrow morning.
Thanks again!
Hi,
sorry to bother again. I've updated the test code with a more complicated use case and I still get the wrong output. I've updated the master branch of my demo repo (https://github.com/dwightjack/pug-php-demo) but the gist of the update is:
// template.php
mixin Test ($params = [])
- $props = $params
p= $props['text']
mixin Wrap($params = [])
- $props = $params
+Test(["text" => "one"])
p= json_encode($props)
if $props["label"] == true
+Test(["text" => "two"])
+Wrap(["label" => true])
Expected output:
<p>one</p>
<p>{ "label": true }</p>
<p>two</p>
Actual output:
<p>one</p>
<p>{ "text": "one" }</p>
My next test was to change the name of the $prop
variable to something more component specific:
mixin Test ($params = [])
- $testProps = array_merge([], $params)
p= $testProps['text']
block
mixin Wrap($params = [])
- $wrapProps = array_merge([], $params)
+Test(["text" => "one"])
p= json_encode($wrapProps)
if $wrapProps["label"] == true
+Test(["text" => "two"])
+Test(["text" => "three"])
+Wrap(["label" => true])
In this case I receive the correct output:
<p>one</p>
<p>{ "label" : true }</p>
<p>two</p>
<p>three</p>
Not sure if this can help you in further investigating the problem.
Thanks again for your work!
Note than in this particular case, you don't need to create a new variable as arrays are copied in PHP you can do:
mixin Test ($props = [])
- $props = array_merge([], $props)
p= $props['text']
mixin Wrap($props = [])
- $props = array_merge([], $props)
+Test(["text" => "one"])
p= json_encode($props)
if $props["label"] == true
+Test(["text" => "two"])
+Wrap(["label" => true])
Still I can try to find why it failed on copying the variable.
@kylekatarnls you're right, array_merge
is not needed. Thank you for pointing it out.
Even if you need array_merge
(for example to add default values), you can use the same variable name to avoid such conflict.
In fact, you get similar bug with pugjs:
mixin foo()
- num = 4
block
p= num
mixin bar()
- num = 5
+foo()
em= num
+bar()
It gives <p>4</p><em>4</em>
.
So if we fix it, we could create a gap with pugjs. I have a patch. But I must to be sure we want it.
In fact, it acts like there is no local variable to mixins (except for arguments/attributes) so you're always modifying global variables.
You can test this on pugjs and see you get the same behavior. So we will keep it consistent with pugjs.
You can use composer require phug/formatter:dev-mixin-local-variables
if you really want this behavior, but I will not merge this to a release and I'm not sure to keep this branch.
I agree with you. Exposing local variables to the global scope could lead to unexpected behaviors.
One thing you could do is to add to the docs some guidelines about writing pug-php compatible mixins and the rationale about it. JavaScript and PHP handling of parameters is different when it comes to objects and arrays and altering a function parameter is considered an anti-pattern in JS, but with some explanations about how the underlying pug-php engine works the proposed pattern is much more clear.
Thanks again!
The documentation is open-source and written in markdown, you can make a proposal.
Hi, I encountered an issue with the following code:
data
pug
I expected to get:
But I actually get:
php-pug(3.2.0)
will fail, butpugjs
will success.Thanks!