Arbit - project tracking

Dwoo

#27: PluginProxy drops function arguments

Issue revisions

  • closed by Marc Hodgins at 2009-M-09 21:28
Type bug bug
State closed closed
Priority normal normal
Resolution fixed fixed
Assigned to Jordi Boggiano
Scheduled for 1.1.0
Affected versions
Affected components Adapters
Last change Monday 9 March 2009 21:28:43 UTC by Marc Hodgins
Tested using the Zend Framework adapter, view helpers allowing for a variable number of function arguments do not receive the additional parameters.

h2. Example view helper:

<pre>
require_once 'Zend/View/Helper/Translate.php';

/**
 * Improved translation view helper
 * Extends Zend_View_Helper_Translate to implement sprintf substitution
 * directly against the translate view helper
 */
class My_View_Helper_Translate extends Zend_View_Helper_Translate
{
    /**
     * Translate with sprintf or vsprintf style substitution
     * @param string $messageId
     * @param array Parameters (or pass multiple parameters in sprintf style)
     * @return string
     */
    public function translate($messageId, $params = null)
    {
        if (func_num_args() > 2) {
            $params = array_slice(func_get_args(), 1); 
        }
        $translatedText = parent::translate($messageId); 
        return vsprintf($translatedText, $params);
    } 
}
</pre>

h2. Code required in bootstrap to override the default translation view helper with this custom helper:

<pre>
$viewInterface->addHelperPath('My/View/Helper/', 'My_View_Helper');
</pre>

h2. Template code:

<pre>
{translate('%s', 'Foo')}
{translate('%s %s', 'Foo', 'Bar')}
</pre>

h2. Expected output:

<pre>
Foo
Foo Bar
</pre>

h2. Actual output:

<pre>
Foo
Warning: vsprintf() [function.vsprintf]: Too few arguments in [path removed]\library\My\View\Helper\Translate.php on line 22
</pre>

I think this is because the translate() function is defined as function translate($messageId, $params) and therefore the proxy is only passing the first $param.  It should be passing all of the parameters so that func_get_args() can access them.
  • Jordi Boggiano at Tuesday 10 March 2009 00:54:27 UTC

    This is kind of unsolvable from the engine point of view, except by analysing the function body to guess if it might have more params than advertised, but I don't really want to go there. However there are two work-around possible :
    
    - Change the PluginProxy implementation to return a different callback, but then you lose some helpful debug info on all your proxied view helpers, so I wouldn't recommend. If you don't have a choice though, look at Adapters/ZendFramework/PluginProxy.php, line 66+ it explains it a bit.
    - Change your helper method declaration to:
    <pre>
        public function translate($messageId, array $rest = array())
        {
            $translatedText = parent::translate($messageId); 
            return vsprintf($translatedText, $rest);
        }
    </pre>
    
    The latest should work, unless you can't safely change the code from that helper. Let me know what happens :)
  • Marc Hodgins at Tuesday 10 March 2009 01:43:47 UTC

    Thanks. It is just disappointing because it breaks consistency between a standard Zend View and a Dwoo view. All of the other functions calls within templates seem to work as you'd expect them to.

    Is this limitation due to the reflection API being used to generate the function calls in compiled templates? Couldn't it catch that there are remaining unused function arguments and pass them through to the generated function call? Sorry, I haven't investigated your use of the reflection API sufficiently to be able to provide a solid suggestion. But, if you pass through extra unimplemented function arguments to a function, PHP simply discards them - so why couldn't they be harmlessly preserved and passed through by the Dwoo compiler?

    For example, this doesn't raise any errors with PHP so couldn't Dwoo just pass through all params passed to the function, regardless if it finds a matching argument name or not?

    <pre> function foo ($bar) {

    echo $bar;

    } foo('hello', 'world'); </pre>

  • Jordi Boggiano at Tuesday 10 March 2009 01:48:40 UTC

    You definitely have a point there, I'll investigate further tomorrow if I find some time.. gotta sleep now. But I think you're right, it should be doable to just append whatever's left at the end. Right now it reads the required params, puts the input in the right spot and discards the rest unless there is an "array $rest" parameter. Anyway I'll get back to you.

  • Jordi Boggiano at Tuesday 10 March 2009 19:46:42 UTC

    Applied in changeset r254.

  • Jordi Boggiano at Tuesday 10 March 2009 19:48:12 UTC

    Fixed it seems, got a test for it that passes, and it didn't break any other test so hopefully it didn't introduce an unexpected issue. Let me know how it goes for you.

  • Marc Hodgins at Tuesday 10 March 2009 19:58:15 UTC

    Indeed, looks to be resolved. Works great. Thank you!