简体   繁体   English

Angular JS和Symfony2

[英]Angular JS and Symfony2

I am currently working on a project using Symfony2 and seeking some advice on that. 我目前正在使用Symfony2进行一个项目,并就此寻求一些建议。

I am thinking of a hybrid application in two(2) different ways a) Login Page shall use traditional form with CRF Token and let symfonty2 handle it. 我正在考虑以两种不同的方式使用混合应用程序a)登录页面应使用带CRF令牌的传统形式,并让symfonty2处理它。 b) All Inner pages ( which potentially are modules ) I want them to be non AJAX, but the other activities inside that shall behave like a Single Page. b)所有内页(可能是模块)我希望它们是非AJAX,但其中的其他活动应该像单页一样。

For example I have an employee module . 例如,我有一个员工模块 When user clicks on that it is entirely loaded from Server ( all the templates and forms etc ) now each activity under employee module like add/update delete/view etc shall be loaded through AJAX and response to be returned in JSON ie AngularJS. 当用户点击它完全从服务器(所有模板和表单等)加载时,现在员工模块下的每个活动(如添加/更新删除/视图等)都将通过AJAX加载,并且响应将以JSON(即AngularJS)返回。

I am currently thinking of using FOSUserBundle to return html on initial request and then based on request type Accept: application/json it will return the JSON ( remember the add/updat delete/view part? ). 我目前正在考虑使用FOSUserBundle在初始请求时返回html然后根据请求类型接受:application / json它将返回JSON(还记得add / updat delete / view部分吗?)。

My question is it a better idea to use Angular Partials (html) files or Symfony2 Twig? 我的问题是使用Angular Partials(html)文件或Symfony2 Twig更好吗? or would it be better to use Angular JS, but let those partials be rendered by Symfony2 twig? 或者使用Angular JS会更好,但是让那些部分由Symfony2 twig渲染? ( I am thinking of Forms here, would want to validate that both from client and server side ) (我在想这里的Forms,想要从客户端和服务器端验证)

Has any one been through similar problem, if yes then what approach was used to develop HYBRID application using AngularJS and Symfony2 or any other framework? 有没有人经历过类似的问题,如果是,那么使用AngularJS和Symfony2或任何其他框架开发HYBRID应用程序的方法是什么? any relevant ideas are appreciated. 任何相关的想法表示赞赏。

I was in the same situation you are. 我和你的情况一样。 AngularJS+Symfony2 project, REST API, login using FOSUserBundle, etc. AngularJS + Symfony2项目,REST API,使用FOSUserBundle登录等。

... And every way has pros and cons, so there is no right way, i'm just gonna say exactly what i did. ......各方面都有利有弊,所以没有正确的方法,我只想说出我的所作所为。

I choose AngularJS native templates, no CSRF validation, a base template built using Twig, server-side validation, use of the FOSJSRoutingBundle, and some helpers (BuiltResponse and BaseController). 我选择AngularJS本机模板,没有CSRF验证,使用Twig构建的基本模板,服务器端验证,使用FOSJSRoutingBundle以及一些帮助程序(BuiltResponse和BaseController)。

Why native templates? 为什么原生模板?

With the use of verbatim, we solve the variable problems, but we gonna have a more complex logic in our templates. 通过逐字使用,我们解决了变量问题,但是我们的模板中会有更复杂的逻辑。

We also will have a less scalable application. 我们的应用程序也将具有不太可扩展性。 All our forms templates are doing a request in the Symfony application, and one of the best pros of the AngularJS is load our controllers, templates, etc from a storage service, like S3, or CDN, like Cloudfront. 我们所有的表单模板都在Symfony应用程序中执行请求,AngularJS的最佳专业人员之一是从存储服务(如S3)或CDN(如Cloudfront)加载我们的控制器,模板等。 As there is no server-side processing, our templates would load so much faster. 由于没有服务器端处理,我们的模板加载速度会快得多。 Even with caching, Twig is slower, obviously. 即使有缓存,Twig显然也比较慢。

And both, Twig and AngularJS templates, are really complex to manage, in my own experience. 根据我自己的经验,Twig和AngularJS模板都非常复杂。 I started making them together, but was painful to manage. 我开始将它们组合在一起,但管理起来很痛苦。

What i did? 我做了什么?

I created static templates in front-end, with the same field names, it's not really good. 我在前端创建了静态模板,使用相同的字段名称,这不是很好。 We need to update the templates every time we update the forms, manually. 我们需要在每次手动更新表单时更新模板。 But was the best way i found. 但这是我发现的最佳方式。 As the field names are equal, we won't have problems to ajust the model names in the Angular controllers. 由于字段名称相同,我们在调整Angular控制器中的模型名称时不会遇到任何问题。

And if you are creating the software as a service, you will need to do it anyway. 如果您要将软件创建为服务,则无论如何都需要执行此操作。 Will you not load the form templates from the application in a mobile app, right? 你不会在移动应用程序中加载应用程序中的表单模板吗?

Why no CSRF validation? 为什么没有CSRF验证?

We don't use CSRF validation in a REST API, obviously. 显然,我们不在REST API中使用CSRF验证。 But, if you wanna do it, you need to make a request every time you load a form, to get the CSRF token. 但是,如果您想这样做,则需要在每次加载表单时发出请求以获取CSRF令牌。 It's really, really bad. 这真的非常糟糕。 So, we create a CRUD, and also we need to create a "csrf-CRUD", 4 routes more. 因此,我们创建了一个CRUD,我们还需要创建一个“csrf-CRUD”,更多4条路由。 That doesn't make any sense. 这没有任何意义。

What i did? 我做了什么?

I disabled the CSRF in the forms. 我在表单中禁用了CSRF。

Base template?! 基本模板?!

Yep. 是的。 A base template is just to load any route in our application. 基本模板只是在我们的应用程序中加载任何路由。 Here is what i'm doing: 这是我正在做的事情:

在此输入图像描述

This will help us to avoid errors when users are going directly to some Application URL if you are using html5 angularjs urls. 如果您使用的是html5 angularjs网址,这将有助于我们避免在用户直接访问某些应用程序URL时出错。 Simple like that. 很简单。

Server-side validation, why? 服务器端验证,为什么?

If we do a validation in the Angular, we need to do the same in the server-side, so we have 2 validation codes to maintain. 如果我们在Angular中进行验证,我们需要在服务器端执行相同的操作,因此我们需要维护2个验证代码。 That is painful. 那很痛苦。 Every change we do in the form, we need to change the validation in the front, validation in the back and also the Angular static form. 我们在表单中进行的每一项更改,都需要更改前面的验证,后面的验证以及Angular静态表单。 Really, really painful. 真的,真的很痛苦。

What i did? 我做了什么?

I basically did a server-side validation using the Symfony constraints. 我基本上使用Symfony约束进行了服务器端验证。 For every request, the application validates the form and check if any error was found, if yes, it gets the first one and send it as a response. 对于每个请求,应用程序验证表单并检查是否发现任何错误,如果是,则获取第一个并将其作为响应发送。

In the AngularJS, the application checks if there is any error inside of the errors key. 在AngularJS中,应用程序检查错误键内是否有任何错误。 So, we have a proccess used in all application to do any form request. 因此,我们在所有应用程序中都使用了一个进程来执行任何表单请求。 It's like that: 就像那样:

在此输入图像描述

And the routes? 和路线?

There is another problem: the routes. 还有另一个问题:路线。 Put the url directly is not a reliable way. 直接放url是不可靠的方法。 If we change anything in the url, that route is gone and the users won't like that. 如果我们更改了网址中的任何内容,那么该路由就会消失,用户也不会喜欢。

To fix that, we can use the FOSJsRoutingBundle . 为了解决这个问题,我们可以使用FOSJsRoutingBundle With that library, we can put the route name directly in the Angular controller, and it will fill with the exact url of the route. 使用该库,我们可以将路径名称直接放在Angular控制器中,它将填充路径的确切URL。 It's completely integrated with the Symfony, so parameters will work very well. 它与Symfony完全集成,因此参数可以很好地工作。

Instead using the url directly, we can do it: 而是直接使用url,我们可以这样做:

Routing.generate('panel_products_show', {id: $routeParams.product_id});

And voilá! 瞧! We get the route url. 我们得到路线网址。


That will solve the biggest part of the problems you have. 这将解决您遇到的最大问题。 But there are more. 但还有更多。

Problem 1 - Form inputs 问题1 - 表格输入

The forms from Symfony generally have a prefix, like "publish_product", so every field has a name like [publish_product]name . Symfony中的表单通常有一个前缀,如“publish_product”,因此每个字段都有一个名称,如[publish_product]name Ah, how that was a problem for me. 啊,这对我来说是怎么回事。

In the Angular, publish_product is not considered a array. 在Angular中,publish_product不被视为数组。 You need to put the single quote to do this, like ['publish_product']name . 您需要使用单引号来执行此操作,例如['publish_product']name And it's really bad, we need to change every key to use this format. 这真的很糟糕,我们需要更改每个键才能使用这种格式。 In AngularJS, i was doing like that: 在AngularJS中,我这样做:

{{ formData('[publish_product]name') }}

Absolutely stupid. 绝对愚蠢。

The best solution was simply remove the form prefix in the Symfony, using the createNamedBuilder method instead just createBuilder . 最好的解决方案是简单地删除Symfony中的表单前缀,使用createNamedBuilder方法而不是createBuilder I let the first parameter null, and yeah, we don't need to use the prefix anymore. 我让第一个参数为null,是的,我们不再需要使用前缀了。 Now, we use: 现在,我们使用:

{{ formData.name }}

So much better. 好多了。

Problem 2 - Routes hard do maintain 问题2 - 路线很难维护

Every request can return anything, i need to repeat much code. 每个请求都可以返回任何内容,我需要重复很多代码。 That is really hard to maintain, so i just create some application rules, built responses, a BaseController, etc. 这真的很难维护,所以我只创建一些应用程序规则,构建响应,BaseController等。

createNamedBuilder createNamedBuilder

createNamedBuilder is a big method. createNamedBuilder是一个createNamedBuilder的方法。 We need to do this, for every form we have: 对于我们拥有的每种形式,我们都需要这样做:

在此输入图像描述

It's simple to solve. 解决起来很简单。 I just created a BaseController and i'm extending every controller from it. 我刚刚创建了一个BaseController,我正在扩展它的每个控制器。 I created a simple method that does it. 我创建了一个简单的方法来完成它。

在此输入图像描述

For every route, we do not need to repeat 3 lines, much better. 对于每条路线,我们不需要重复3条线,更好。

Responses 回应

When my application started growing, i had a serious problem: all my responses are different. 当我的应用程序开始增长时,我遇到了一个严重的问题:我的所有回答都不同。 That was really hard to maintain. 这真的很难维持。 For every request i was doing, sometimes i was using "response", sometimes "data", the error messages were lost in the response, etc. 对于我正在做的每个请求,有时我使用“响应”,有时“数据”,错误消息在响应中丢失等。

So, i decided to create a buildResponse, that i just need to set some parameters and i get the same result for every route, even GET routes. 所以,我决定创建一个buildResponse,我只需要设置一些参数,每个路由都得到相同的结果,甚至是GET路由。

在此输入图像描述

response key shows me the status and the message. response键显示状态和消息。 It can be error or success, and the message os a optional field, that can come blank. 它可能是错误或成功,并且消息是可选字段,可以是空白的。 For example, a success status with the message "You created the product". 例如,成功状态,显示消息“您创建了产品”。

data key shows me any information i need. data键显示我需要的任何信息。 For example, the user added the product, and now he needs the link to see it. 例如,用户添加了产品,现在他需要链接才能看到它。 In the data, i put the url of the post, and i easily can get it from the AngularJS controller. 在数据中,我把帖子的url,我很容易从AngularJS控制器获取它。

notifications is a specific key for my business logic. notifications是我的业务逻辑的特定键。 Every action can return a notification to the user. 每个操作都可以向用户返回通知。

It doesn't matter what keys you have. 你有什么钥匙并不重要。 The most important thing is have a standardized response, because when your application grows, it will be really helpful. 最重要的是有一个标准化的响应,因为当你的应用程序增长时,它将非常有用。

That is a route from my controller: 这是我的控制器的路线:

在此输入图像描述

Completely standardized. 完全标准化。 The Scrutinizer code quality tool says all my routes are duplicated. Scrutinizer代码质量工具说我的所有路由都是重复的。 :D :d

Have a BaseController and a builtResponse will help you so much. 有一个BaseController和一个builtResponse会帮助你这么多。 When i started refactoring my code, each route lost about 4-10 lines. 当我开始重构我的代码时,每条路线丢失了大约4-10行。


Details: getFormError return the first error of the form. 详细信息: getFormError返回表单的第一个错误。 Here is my method: 这是我的方法:

public function getFormError(FormInterface $form)
{
    if ($form->getErrors()->current()) {
        return $form->getErrors()->current()->getMessage();
    }

    return 'errors.unknown';
}

... And the parameters from the buildResponse are: 1. Status. ...而buildResponse的参数是:1。状态。 I get it from a constant in the BaseController. 我从BaseController中的常量中得到它。 It can be changed, so i believe is important do not use a string value in each route. 它可以改变,所以我认为重要的是不要在每条路线中使用字符串值。 2. The translation message. 2.翻译信息。 (I use a preg_match to check if it has a translation format, because getFormError already translates the error). (我使用preg_match来检查它是否有翻译格式,因为getFormError已经转换了错误)。 3. The data (array) parameter. 3.数据(数组)参数。 4. The notifications (array) parameter. 4.通知(数组)参数。

Other problem i'm gonna have 我还有其他问题

The project just have one supported language until now. 到目前为止,该项目只有一种受支持的语言。 When i start to work in a multilingual version, i'm gonna have another big problem: maintain 2 versions of the translations: the back-end messages and validations and the text from the front-end. 当我开始使用多语言版本时,我将遇到另一个大问题:维护两个版本的翻译:后端消息和验证以及前端的文本。 That probably will be a big problem. 这可能是个大问题。 When i get the best approach, i'll update this answer. 当我得到最好的方法时,我会更新这个答案。

I took some months to get the this approach. 我花了几个月才得到这种方法。 So many code refactorings and probaly much more in the future. 如此多的代码重构和未来可能会更多。 So i hope it help someone to do not need to do the same. 所以我希望它可以帮助别人不需要这样做。

1. If i get a better way to do this, i'll update this answer. 如果我有更好的方法来做到这一点,我会更新这个答案。

2. I'm not good at writing english, so this answer probably will have many grammatical errors. 我不擅长写英文,所以这个答案可能会有许多语法错误。 Sorry, i'm fixing what i'm seeing. 对不起,我正在修理我所看到的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM