Code Monkey home page Code Monkey logo

Comments (15)

ryan-mahoney avatar ryan-mahoney commented on May 23, 2024

@zordius my apologies. This comment I wrote is incorrect. The way this is working is consistent with the documentation.

My question now, is why does input work this way for helpers, but differently for hbhelpers? Why not have a consistent input methodology across both? I think both ways are valid, but it's just odd that they work differently.

from lightncandy.

zordius avatar zordius commented on May 23, 2024

Ya, in my original design, the helpers interface is different with handlebars' style. Because:

  1. In handlebars.js, one registerHelper() handles both 'single helper' and 'block helper' .
  2. In handlebars.js, custom helper function need to take care of different input parameter numbers , and take care of last parameter (options) . It also need to take care of 'calling inner block renderer' .
  3. The most important thing: there is no standard way for custom helper function to know it is be used as 'single custom helper' or as 'block custom helper' (My little trick is to check options.fn ....if it is there, then the custom helper is be executed as block custom helper)

So, I don't like the way of handlebars.js do it and decide to make something different. My idea is: let lightncandy handle inputs, and let custom helper in easy life.....So, I designed helpers and blockhelpers in another way.

If I am writing a custom helper: test , the helpers way can give me all inputs in one time no matter it is named argument or not. In handlebars.js , I need to get none named arguments from 1st to n-1 arguments, and all named input from last arguments.hash. Then, I may need to put similar statements in all my custom helper functions to handle these:

function test () {  // do not declare any params here, then I can handle Variable-length argument lists
   $arg_list = func_get_args();   // in javascript it is arguments
   $options = array_pop($arg_list);     //  in javascript options = arguments.pop();

   $all_named_args = $options['hash'];
   $all_nonamed_args = $arg_list;

   if (isset($options['fn'])) {
      // Do block custom helper things ....
   } else {
      // Do custom helper things ....
   }
}

And then, support handlebars' style is another story happened later.......the target of hbhelpers is to simulate handlebars.js behaviors , even when I still think it is not good. That's why helpers is different with hbhelpers .

  • helpers : If you do not care about "the interface should be same with handlebars.js" , and you think the input of custom helpers should be simple , you should use this.
  • hbhelpers : If you use handlebars.js, and you like to port your old custom helper javascript to PHP, you can use this to reduce code conversion issues.
  • blockhelpers : it only let custom helper to change context or skip the block. I do the design in this way and try to make people think about: prevent to do too many things in custom helper, you maybe put too many logic in template......it should be logicless. But, if you do not think so, you can still use hbhelpers to do heavy works in block custom helper.

from lightncandy.

zordius avatar zordius commented on May 23, 2024

I found a bad thing in my helpers design....

  • If people always use {{test a b c}} , then I can use test($a, $b, $c) .
  • If someone use {{test a b name=c}} , then I will change to use test($input) and $input will be Array(0=>a , 1=>b , name=>c) .

This still make custom helper code not consist in one way. Current design is only good for:

  • A: people always {{test a b c}} and function test ($a, $b, $c)
  • B: people always {{test a=0 b=2 c=3) and function test ($input)

If someone mix usage A and B, then he will run into trouble. I will think about this and find a better way to prevent the problem. Any suggestion?

from lightncandy.

ryan-mahoney avatar ryan-mahoney commented on May 23, 2024

If I had to choose, I would prefer the mechanism that is in place for hbhelpers to be applied uniformly.

So, you can use {{test a a="1" b="1"}} and:

  • "a" will be the "a" value from the context
  • $options will implicitly always be the last argument
  • $options contains a hash of "a" and "b" parameters
$helper = function ($a, $options) {
    echo $a;
    print_r($options['hash']);
};

this reduces the amount of effort inside each helper to organize/gather the input because it is neat and tidy. I think the ability to mix the two styles together is very powerful, and certainly superior to the other PHP handlebars implementations.

Ultimately, it is up to you. Ultimately, I'd don't see too much distinction between helpers and hbhelpers. I think that the user could use a hbhelper in a simple way, or they can take advantage of more complex capabilities of it. If the user uses a hbhelper as a helper, there is no harm

from lightncandy.

zordius avatar zordius commented on May 23, 2024

The problem is, if you create a helper as

$helper = function ($a, $options) {
    echo $a;
    print_r($options['hash']);
};

Then all helper user should apply 1 none named argument like:

  • {{helper "test" a=b c=d}}
  • {{helper a}}
  • {{helper a.b c="xxx"}}

If any template write in this way:

  • {{helper a b}} (options will be 3rd param)
  • {{helper a=b c=d}} (options will be 1st param)

Then the helper function will boooooooooom. That's the problem I talk about: when the number of input parameters is not consist , the helper function can not work correctly. This happened in both hbhelpers and helpers .

If I change the design of helpers to 'always use hash format' , then all helpers developer can use this style:

helper = function ($hash) {
    // $hash[0] or $hash['name'] ....use isset() to check.
}

Hmm, still not good enough............Maybe in this way:

helper = function ($params) {
    // $params = Array('named' => {...} , 'no_named' => [...] )
}

Then the number of params can be get by count($params['no_named']) .....I feel this is better then original helpers design, maybe I will add a option flag for this.

from lightncandy.

mendezcode avatar mendezcode commented on May 23, 2024

How about this:

  // {{my_helper 1 2 3 a="4" b="5" c="6"}}

  function my_helper($args, $options) {
    // $args = array(1,2,3);
    // $options = array("a"=>4, "$b"=>5, "c"=>6);
  }

Then we can just check for empty($args) to see if no arguments provided. And we got a nice $options array containing the named params.

from lightncandy.

zordius avatar zordius commented on May 23, 2024

good approach!

from lightncandy.

ryan-mahoney avatar ryan-mahoney commented on May 23, 2024

I like this approach as well.

Would it be same / similar for both helpers, hbhelpers and blockhelpers?

from lightncandy.

mendezcode avatar mendezcode commented on May 23, 2024

I think it would be a good idea to make it consistent, it would avoid bugs and confusion. Everything should have the same API so we can just use it whilst feeling intuitive.

One thing I didn't think was about the $options['fn'] and $options['inverse'] block callbacks. Should these be included in the $options array, reserving properties such as inverse and fn? No. Passing a third $block parameter which contains the block callbacks would make more sense.

Something like this:

function my_helper($args, $options, $block) {
  // $args = array(1,2,3);
  // $options = array("a"=>4, "$b"=>5, "c"=>6);
  // $block = array("fn"=>function, "inverse"=>function);
}

Three arguments is manageable, after that it becomes a hassle to remember. Also the order of the arguments is easy to remember. This would also have the added benefit of getting rid of the helpers separation, instead of having helpers, hbhelpers and blockhelpers, we would just have a common helper concept, which would simplify internals a lot.

Also, how would we know if it's a block helper? Easy as cake:

function my_helper($args, $options, $block) {
   if (isset($block)) {
      // It's a block helper
   } else {
      // Not a block helper
   }
}

If helper is called as a normal helper, like {{myhelper 1 2 3}}, then $block would be set to null, thus infering that there's no block. Semantic win.

If there's a block, like {{#myhelper 1 2 3}}...{{/myhelper}}, then $block would be an array populated with fn and optionally inverse. The latter being only specified if there's an {{else}} block, null otherwise.

Bacon!

from lightncandy.

ryan-mahoney avatar ryan-mahoney commented on May 23, 2024

I 100% support this comment. I really didn't see the benefit of differentiating between types of helpers.

Also, I would add that I don't think its necessary to implement this w/ a config flag, that in-general, helper support is so new in Lightncandy that breaking backwards compatibility is not a big deal IMHO.

@zordius when can you do this? ;)

from lightncandy.

ryan-mahoney avatar ryan-mahoney commented on May 23, 2024

@zordius any update? I'm migrating many helpers to this platform at the moment

from lightncandy.

zordius avatar zordius commented on May 23, 2024

I like new design and will do it on helpers , but can not decide to use it or not on hbhelper <= (it's supposed to be same with handlebars ) . More inputs are welcome, I will go helpers first today.

from lightncandy.

zordius avatar zordius commented on May 23, 2024

New testing version and document in this branch: https://github.com/zordius/lightncandy/tree/helper_interface_change
, please try it, thanks. ( helpers and blockhelpers are changed now , hbhelper still not be changed )

from lightncandy.

mendezcode avatar mendezcode commented on May 23, 2024

Thanks for the implementation 👍 you rock!

from lightncandy.

zordius avatar zordius commented on May 23, 2024

#58 already merged into master, so close this, thanks.

from lightncandy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.