是否有一种方法来连接值(如枚举)从前端(JS)到后端(PHP/Ruby)没有重复


Is there a way to connect values (like enums) from frontend (JS) to backend (PHP/Ruby) without duplication?

给定一个后端基于PHP或ruby的web应用程序,并且在前端使用JavaScript编程,有时我们需要在两边定义值来处理通过api在前端和后端之间通信的数据。

在JavaScript中是这样的:

var options = {
        OPT_A : 1,
        OPT_B : 2,
        OPT_C : 3
    };
switch(data.type)
{
    case options.OPT_A:
        /* */
        break;
    case options.OPT_B:
        /* */
        break;
    case options.OPT_C:
        /* */
        break;
}

在php中是这样的:

const OPT_A = 1;
const OPT_B = 2;
const OPT_C = 3;

问题是你必须定义它们两次;每种语言各一次。这可能导致错误/不一致。

我想到的唯一方法是从服务器定义JavaScript部分,但我不喜欢JS代码由PHP/Ruby代码编写的想法。

有没有办法做到这一点没有代码重复?

这是一个如何创建PHP enum并将其作为对象发送到前端的解决方案。

在PHP中,我创建了一个enum类Food:

abstract class Food
{
    const BANANA = 0;
    const ORANGE = 1;
    const WATERMELON = 2;
    const BANANA_STRING = 'banana';
    const ORANGE_STRING = 'orange';
    const WATERMELON_STRING = 'watermelon';
    const MAP = [
        self::BANANA         => self::BANANA_STRING,
        self::ORANGE         => self::ORANGE_STRING,
        self::WATERMELON     => self::WATERMELON_STRING
    ];
    const REVERSEMAP = [
        self::BANANA_STRING          => self::BANANA,
        self::ORANGE_STRING          => self::ORANGE,
        self::WATERMELON_STRING      => self::WATERMELON
    ];
    static function toString($enum){
        return self::MAP[$enum];
    }
    static function toEnum($string){
        return self::REVERSEMAP[$string];
    }
}

我在接下来的步骤中使用Laravel框架,但根据你的项目,它应该是基本相同的。这里的重要部分是我使用了我在enum中创建的::MAP:

use PathToMyLibrary'MyLibrary'Enums'Food;
class FoodController extends Controller {
    public function foodView() {
        $title = "hello";
        $food_enum = Food::MAP;
        // attach these variables to the food view
        return view('food', compact('title', 'food_enum'));
    }
}

现在在我的food.blade.php文件(在Laravel中使用的PHP-html视图模板文件)中,我可以将这个$food_enum PHP对象转换为JavaScript对象。

@section('title')
    {{title}}
@endsection
@section('page_content')
    <div class="page-heading">
        <h1>{{title}}</h1>
    </div>
    <div id="food-app">...your content...</div>
@endsection
@section('includes')
    <script>
        // convert this $food_enum from a PHP object into a JavaScript object
        var food_enum = <?php echo json_encode($food_enum); ?>;
    </script>
@endsection
此时,JavaScript中的对象将与PHP中的enum对象匹配。

不再需要在PHP和JavaScript中维护一个冗余的枚举!

您将需要阅读有关web服务的内容。web服务本质上是一个函数。你传递给它一些参数,它会给你一些信息。通常用于允许程序访问外部数据。您几乎可以在任何API中看到它们的作用。查看stackexchange的api示例。

最小的例子:

#sinatra routing
get '/webservice/test' do
    content_type :json
    data = {options: {
        opt_a: 1,
        opt_b: 2,
        opt_c: 3
    }}
    JSON.pretty_generate(data)
end

所以,当你访问your-site.com/webservice/test时,你会得到:

{
  "options": {
    "opt_a": 1,
    "opt_b": 2,
    "opt_c": 3
  }
}

在javascript中使用这些数据变得微不足道:

var call = new XMLHttpRequest();
call.onreadystatechange = function() {
    if(call.readyState == XMLHttpRequest.DONE) {
        if(call.status == 200) {
            obj = JSON.parse(call.responseText);
            console.log(obj);
        } else if(xmlhttp.status == 400) {
            console.log("error 400");
        } else {
            alert("some other thing happened");
        }
    }
}
call.open("GET", "/webservice/test", true);
call.send(); 

现在您的数据已经在客户端了!具体来说,obj将是Object {options: Object},因此您将使用obj.options.opt_a访问您的3个选项以获得1

这里有一些关于webservice的简明英语解释。

如果您不熟悉http响应代码,您可以查看这里的完整列表。这是javascript代码的call.status部分。

如果你愿意,你可以用jQuery用$.getJSON("/webservice/test", function() ...)做同样的ajax调用。你可以在这里阅读更多信息

在我的项目中,我在API上创建一个端点,返回json中的enum。然后,我用redux存储它,以免每次访问页面时都要调用它。如果你不使用JS框架,你仍然可以创建一个由ajax请求触发的url,并提供你的javascript。你也可以创建一个json文件,存储在公共目录中,然后导入到javascript中,然后使用后端语言

获取文件内容