json icon indicating copy to clipboard operation
json copied to clipboard

Add JsExpression to processData() function like in Yii2

Open aphraoh opened this issue 4 years ago • 15 comments

What steps will reproduce the problem?

Would like to be able to use JsExpression in Yii3, like in Yii2 making it possible to json encode javascript expressions. JsExpression seems to have been removed from Yii3

What is the expected result?

Passing Javascript Expressons as a JsExpression object to Json_encode, see usage in Yii2.

What do you get instead?

This much needed functionality seems to have been removed in Yii3... unless there is another way it is now being done!?

Additional info

Q A
Version 3
PHP version n/a
Operating system all

aphraoh avatar Feb 05 '21 16:02 aphraoh

Attaching possible solution which has...

  • Changes to existing class Yiisoft/Json/Json
  • New Class Yiisoft/Json/JsExpression (put in the same namespace as the Json class as JsExpression class does not make sense without the Json class)

Please review and merge if OK (not a GIT guru yet...)

JsonAndJsExpression.zip

aphraoh avatar Feb 05 '21 18:02 aphraoh

I did a PR with your changes. The main issue with it is that JS expressions aren't valid in JSON so the feature doesn't fit the "json" package well.

samdark avatar Feb 23 '21 07:02 samdark

Sorry, did not mean to close it...

aphraoh avatar Feb 23 '21 09:02 aphraoh

Thanx for getting back, the whole point of the JSExpression class is to overcome the fact that JS Expression is not valid json and yet you might like to pass JS Expression to json and so the only place to do it would be in the JSON class, see example below, I am passing an array to a widget which json encode, it has some js expressions, what would be the solution to encode them... also not sure if I mentioned this was the solution in Yii2, off course that does not mean it is correct but there is precedence.

echo Highstock::widget([
    // The highcharts initialization statement will be wrapped in a function
    // named 'mycallbackFunction' with one parameter: data.
    'callback' => 'myCallbackFunction',
    'options' => [
        'chart' => [
            'height'=> 320,
            'backgroundColor' => '#f8f9fa',
            'borderColor'=> '#ced4da',
            'borderRadius'=> 5,
            'borderWidth'=> 0.5,
        ],
        'legend' => ['enabled' => false],
        'navigator' => ['enabled' => false],
        'scrollbar' => ['enabled' => false],
        'credits' => ['enabled' => false],
        'rangeSelector' => ['inputEnabled' => false],
        'series' => [
            [
                'name' => $series_name,
                'data' => new JsExpression('data'), // Here we use the callback parameter, data
                'type' => 'areaspline',
                'threshold' => null,
                'tooltip' => [
                    'valueDecimals' => 3
                ],
                'fillColor' => [
                    'linearGradient' => [
                        'x1' => 0,
                        'y1' => 0,
                        'x2' => 0,
                        'y2' => 1
                    ],
                    'stops' => [
                        [0, new JsExpression('Highcharts.getOptions().colors[0]')],
                        [1, new JsExpression('Highcharts.color(Highcharts.getOptions().colors[0]).setOpacity(0).get("rgba")')]
                    ]
                ]
            ]
        ]
    ]
]);

aphraoh avatar Feb 23 '21 10:02 aphraoh

How do you plan to use Json for it?

samdark avatar Feb 23 '21 10:02 samdark

Alot of js libraries have have json as input, and alot of these libraries allow js expressions in the json, for example https://www.highcharts.com

This would be the solution for that...

aphraoh avatar Feb 23 '21 11:02 aphraoh

Can you share Highstock widget code?

samdark avatar Feb 23 '21 15:02 samdark

Hi, I have attached, it is a quick hack of miloschuman's yii2-highcharts for yii2 which I hacked for yii3 as a proof of concept...

highcharts.zip

aphraoh avatar Feb 23 '21 17:02 aphraoh

@samdark

I did a PR with your changes. The main issue with it is that JS expressions aren't valid in JSON so the feature doesn't fit the "json" package well.

Suggest

Create an interface in this package:

interface SafeJsonEntity {
  function toJsonEntity(): string;
}

In yiisoft/html package extend it:

class JsExpression implements SafeJsonEntity {
  // ...
  function __construct(string $expression) {
    //....
  }
  function toJsonEntity() : string {
    return $this->exression;
  }
}

kamarton avatar Sep 29 '22 15:09 kamarton

Thanx @kamarton , but tend to agree with @samdark , "...JS expressions aren't valid in JSON so the feature doesn't fit the "json" package well...", did not make sense to me then but makes sense now so closing

aphraoh avatar Oct 08 '22 11:10 aphraoh

@aphraoh "...JS expressions aren't valid in JSON so the feature doesn't fit the "json" package well..." BUT in web context use case is not allowed to ignore. In this package, it is sufficient to support its option, this does not affect the name of the package or standard functionality.

kamarton avatar Oct 08 '22 11:10 kamarton

@kamarton, how does making it and interface make things different from the code I attached here... https://github.com/yiisoft/json/issues/23#issuecomment-774195673

aphraoh avatar Oct 08 '22 22:10 aphraoh

I have run in a similar issue, trying to json_encode the arguments of a widget (including function/callbacks) to pass it to a JS library. The problem is that json_encode doesn't invoke any form of serializing/toString function on the JSExpression object which causes to serialize something like {'expression': 'actual JS code'} instead of {'actual JS code'}.

The magic __toString doesn't see to be called, and JSExpression doesn't implement a JsonSerializable interface.

It would be nice to just be able to json_encode the expression...

ldkafka avatar Sep 18 '23 00:09 ldkafka

Seems good to have JSExpression. Reopen it for more discussion

xepozz avatar Sep 18 '23 05:09 xepozz

This could be another method for encoding data with JsExpression, e.g. Json::encodeJS() or another class / packet.

Also convert PHP DateTimeInstance instances to JS Date objects.

Tigrov avatar Sep 19 '23 05:09 Tigrov