Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow JavaScript statements in PHP $parameters used by PheryResponse #58

Open
holtkamp opened this issue Nov 10, 2016 · 6 comments
Open

Comments

@holtkamp
Copy link
Contributor

Currently, one can do

$parameters = new stdClass();
$parameters->foo = 'bar';
$parameters->min = 0;
$parameters->max = 10;

PheryResponse::factory('#elementId')->javascriptFunction($parameters);

The PheryResponse::typeCast() function will take care of encoding the provided $parameters object to JSON and hand them over the the client-side. Great!

Limitation
However, when trying to handover JavaScript functions/statements, this approach will (obviously) fail:

$parameters = new stdClass();
$parameters->callbackFunction = 'function() { console.log(this); }'

The string 'function() { console.log(this); }' will treated as a normal string and can not be used. This is a known limitation/feature of JSON, also described here:

Workaround
The workaround for now is to use the name of function that is already defined in JavaScript:

$parameters = new stdClass();
$parameters->callbackFunction = 'functionToInvokeAvailableInJavaScript'

Possible approach / suggestion
The Zend Framework came up with a way to wrap such statements. in a Zend\Json\Expr object and encode it with a flag to detect such expressions. Maybe this approach can be researched / adopted by Phery. I am not aware of other libraries that provide this functionality.

@pocesar
Copy link
Contributor

pocesar commented Nov 10, 2016

The wrapper in Phery is PheryFunction, it'll signal to the client-side that the current argument is actually a function body in string form. although I'm not sure if it would work as-is like $parameters->callbackFunction = PheryFunction::factory('console.log(this)') since the context of this would still be the window I guess.

@holtkamp
Copy link
Contributor Author

@pocesar ok, thanks, will have a look at PheryFunction and report back 👍

@holtkamp
Copy link
Contributor Author

holtkamp commented Nov 10, 2016

@pocesar, tried to use PheryFunction but it appears to result in an 'empty' string in the response. For the sake of completeness, a real-life example:

$parameters = new stdClass();
$parameters->interval = 60;
$parameters->min = array(9, 0);
$parameters->max = array(17, 0);
$parameters->enable = array(9, 10, 11, 12, 13, 14, 15, 16, 17)
$parameters->formatLabel = PheryFunction::factory('function(){ console.log(this); }');

return PheryResponse::factory('#timepickerId')->pickatime()->pickatime('picker')->set($parameters)->open();

results in (note the part of the formatLabel this should be a callback function)

{
    "#timepickerId": [{
        "c": "pickatime",
        "a": []
    }, {
        "c": "pickatime",
        "a": ["picker"]
    }, {
        "c": "set",
        "a": [{
            "interval": 60,
            "min": [9, 0],
            "max": [17, 0],
            "enable": [9, 10, 11, 12, 13, 14, 15, 16, 17],
            "formatLabel": []
        }]
    }, {
        "c": "open",
        "a": []
    }]
}

I guess this is because the PheryFunction is a property of another object (the stdClass), so it might not be detected when being typecasted since only arrays seem to be processed.

When using an array:

{
    "#timepickerId": [{
        "c": "pickatime",
        "a": []
    }, {
        "c": "pickatime",
        "a": ["picker"]
    }, {
        "c": "set",
        "a": [{
            "min": [9, 0],
            "max": [20, 0],
            "enable": [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
            "formatLabel": {
                "PF": "function(){alert(0);}"
            }
        }]
    }, {
        "c": "open",
        "a": []
    }]
}

@pocesar
Copy link
Contributor

pocesar commented Nov 10, 2016

hmm yeah, if I recall correctly, the typecast only happens on a limited depth.

first in https://github.com/pheryjs/phery/blob/3.0.0-alpha2/src/Phery/PheryResponse.php#L1405 and then in https://github.com/pheryjs/phery/blob/3.0.0-alpha2/src/Phery/PheryResponse.php#L1461

it won't try to go inside objects properties... although this could be added, but I'm not aware of potential edge cases that might have performance impacts. like detect if the argument is a object, then try to walk it trying to find nested phery responses and functions

@holtkamp
Copy link
Contributor Author

holtkamp commented Nov 10, 2016

@pocesar updated my comment with the result of using an array, this becomes:

"formatLabel": {
    "PF": "function(){alert(0);}"
}

which will not be properly processed by JavaScript...

Ok, lets for now mark it as a "known limitation", at least it is documented in an issue now 😄

@pocesar
Copy link
Contributor

pocesar commented Nov 10, 2016

phery transforms PF: "function(){}" objects to real functions https://github.com/pheryjs/phery/blob/3.0.0-alpha2/phery.js#L1202 and in a recursive manner. in theory it should work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants