Angular JS和Symfony2

Aft*_*eed 11 javascript php json symfony

我目前正在使用Symfony2进行一个项目,并就此寻求一些建议.

我正在考虑以两种不同的方式使用混合应用程序a)登录页面应使用带有CRF令牌的传统形式,并让symfonty2处理它.b)所有内页(可能是模块)我希望它们是非AJAX,但其中的其他活动应该像单页一样.

例如,我有一个员工模块.当用户点击它完全从服务器(所有模板和表单等)加载时,现在员工模块下的每个活动(如添加/更新删除/视图等)都将通过AJAX加载,并且响应将以JSON(即AngularJS)返回.

我目前正在考虑使用FOSUserBundle在初始请求时返回html然后根据请求类型接受:application/json它将返回JSON(还记得add/updat delete/view部分吗?).

我的问题是使用Angular Partials(html)文件或Symfony2 Twig更好吗?或者使用Angular JS会更好,但是让那些部分由Symfony2 twig渲染?(我在想这里的Forms,想要从客户端和服务器端验证)

有没有人经历过类似的问题,如果是,那么使用AngularJS和Symfony2或任何其他框架开发HYBRID应用程序的方法是什么?任何相关的想法表示赞赏.

Iag*_*ago 4

我和你的情况一样。AngularJS+Symfony2项目、REST API、使用FOSUserBundle登录等。

\n\n

...每种方法都有优点和缺点,所以没有正确的方法,我只是准确地说出我所做的。

\n\n

我选择 AngularJS 原生模板,没有 CSRF 验证,使用 Twig 构建的基本模板,服务器端验证,使用 FOSJSRoutingBundle 以及一些帮助程序(BuiltResponse 和 BaseController)。

\n\n

为什么选择原生模板?

\n\n

通过逐字记录,我们解决了变量问题,但我们的模板中会有更复杂的逻辑。

\n\n

我们还将有一个可扩展性较差的应用程序。我们所有的表单模板都在 Symfony 应用程序中执行请求,AngularJS 的最佳优点之一是从存储服务(如 S3 或 CDN,如 Cloudfront)加载我们的控制器、模板等。由于没有服务器端处理,我们的模板加载速度会快得多。即使有缓存,Twig 显然也更慢。

\n\n

根据我自己的经验,Twig 和 AngularJS 模板的管理都非常复杂。我开始把它们放在一起,但管理起来很痛苦。

\n\n

我做了什么?

\n\n

我在前端创建了静态模板,具有相同的字段名称,这不太好。每次更新表单时,我们都需要手动更新模板。但这是我发现的最好的方法。由于字段名称相同,因此我们在 Angular 控制器中调整模型名称时不会遇到问题。

\n\n

如果您将软件创建为服务,那么无论如何您都需要这样做。您不会从移动应用程序中的应用程序加载表单模板吗?

\n\n

为什么没有 CSRF 验证?

\n\n

显然,我们不在 REST API 中使用 CSRF 验证。但是,如果您想这样做,则需要在每次加载表单时发出请求,以获取 CSRF 令牌。这真的非常非常糟糕。因此,我们创建一个 CRUD,还需要创建一个“csrf-CRUD”,还有 4 个路由。这没有任何意义。

\n\n

我做了什么?

\n\n

我在表单中禁用了 CSRF。

\n\n

基础模板?!

\n\n

是的。基本模板只是在我们的应用程序中加载任何路由。这就是我正在做的事情:

\n\n

在此输入图像描述

\n\n

如果您使用 html5 angularjs url,这将帮助我们避免当用户直接访问某些应用程序 URL 时出现错误。就这么简单。

\n\n

服务器端验证,为什么?

\n\n

如果我们在 Angular 中进行验证,我们需要在服务器端执行相同的操作,因此我们需要维护 2 个验证代码。那是痛苦的。我们在表单中所做的每次更改,都需要更改前面的验证、后面的验证以及 Angular 静态表单。真的,真的很痛苦。

\n\n

我做了什么?

\n\n

我基本上使用 Symfony 约束进行了服务器端验证。对于每个请求,应用程序都会验证表单并检查是否发现任何错误,如果是,它会获取第一个请求并将其作为响应发送。

\n\n

在AngularJS中,应用程序检查errors键中是否有任何错误。因此,我们有一个在所有应用程序中使用的进程来执行任何表单请求。就像那样:

\n\n

在此输入图像描述

\n\n

还有路线?

\n\n

还有一个问题:路线。直接输入url并不是一个可靠的方法。如果我们更改 url 中的任何内容,该路由就会消失,用户不会喜欢这样。

\n\n

为了解决这个问题,我们可以使用FOSJsRoutingBundle。有了这个库,我们可以将路由名称直接放入 Angular 控制器中,它将填充路由的确切 url。它与 Symfony 完全集成,因此参数可以很好地工作。

\n\n

我们可以直接使用 url,而不是直接使用 url:

\n\n
Routing.generate(\'panel_products_show\', {id: $routeParams.product_id});\n
Run Code Online (Sandbox Code Playgroud)\n\n

瞧\xc3\xa1!我们得到了路由 url。

\n\n
\n\n

这将解决您遇到的大部分问题。但还有更多。

\n\n

问题 1 - 表单输入

\n\n

Symfony 的表单通常有一个前缀,如“publish_product”,因此每个字段都有一个名称,如[publish_product]name. 啊,这对我来说是个问题。

\n\n

在 Angular 中,publish_product 不被视为数组。您需要添加单引号才能执行此操作,例如[\'publish_product\']name. 这真的很糟糕,我们需要更改每个键才能使用这种格式。在 AngularJS 中,我是这样做的:

\n\n
{{ formData(\'[publish_product]name\') }}\n
Run Code Online (Sandbox Code Playgroud)\n\n

绝对愚蠢。

\n\n

最好的解决方案是简单地删除 Symfony 中的表单前缀,使用createNamedBuilder方法代替createBuilder. 我让第一个参数为空,是的,我们不需要再使用前缀了。现在,我们使用:

\n\n
{{ formData.name }}\n
Run Code Online (Sandbox Code Playgroud)\n\n

好多了。

\n\n

问题 2 - 路线难以维护

\n\n

每个请求都可以返回任何内容,我需要重复很多代码。这确实很难维护,所以我只是创建一些应用程序规则、构建响应、BaseController 等。

\n\n

创建命名构建器

\n\n

createNamedBuilder是一个大方法。对于我们拥有的每种表单,我们都需要这样做:

\n\n

在此输入图像描述

\n\n

解决起来很简单。我刚刚创建了一个 BaseController,并从中扩展了每个控制器。我创建了一个简单的方法来做到这一点。

\n\n

在此输入图像描述

\n\n

对于每条路线,我们不需要重复3条线,这样就好多了。

\n\n

回应

\n\n

当我的应用程序开始增长时,我遇到了一个严重的问题:我所有的反应都是不同的。这确实很难维持。对于我所做的每个请求,有时我使用“响应”,有时使用“数据”,错误消息在响应中丢失,等等。

\n\n

因此,我决定创建一个 buildResponse,我只需要设置一些参数,并且每个路由(甚至是 GET 路由)都会得到相同的结果。

\n\n

在此输入图像描述

\n\n

response键显示状态和消息。它可以是错误或成功,并且消息是一个可选字段,可以为空。例如,带有消息“您创建了产品”的成功状态。

\n\n

data键显示我需要的任何信息。例如,用户添加了产品,现在他需要链接才能看到它。在数据中,我输入了帖子的 url,我可以轻松地从 AngularJS 控制器获取它。

\n\n

notifications是我的业务逻辑的特定键。每个操作都可以向用户返回通知。

\n\n

你有什么钥匙并不重要。最重要的是有一个标准化的响应,因为当你的应用程序增长时,它会非常有帮助。

\n\n

这是我的控制器的路线:

\n\n

在此输入图像描述

\n\n

完全标准化。Scrutinizer 代码质量工具显示我的所有路线都是重复的。:D

\n\n

拥有一个 BaseController 和一个builtResponse 会对你有很大帮助。当我开始重构代码时,每条路线丢失了大约 4-10 行。

\n\n
\n\n

详细信息: getFormError返回表单的第一个错误。这是我的方法:

\n\n
public function getFormError(FormInterface $form)\n{\n    if ($form->getErrors()->current()) {\n        return $form->getErrors()->current()->getMessage();\n    }\n\n    return \'errors.unknown\';\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

...来自 buildResponse 的参数是:\n1。地位。我从 BaseController 中的常量获取它。它可以更改,因此我认为重要的是不要在每个路由中使用字符串值。 \n2. 翻译消息。(我使用 preg_match 来检查它是否具有翻译格式,因为 getFormError 已经翻译了错误)。 \n3. 数据(数组)参数。\n4. 通知(数组)参数。

\n\n

我还会遇到其他问题

\n\n

到目前为止,该项目仅支持一种语言。当我开始使用多语言版本时,我会遇到另一个大问题:维护两个版本的翻译:后端消息和验证以及来自前端的文本。这可能会是一个大问题。当我找到最好的方法时,我会更新这个答案。

\n\n

我花了几个月的时间才掌握这种方法。如此多的代码重构,未来可能还会有更多。所以我希望它可以帮助那些不需要做同样事情的人。

\n\n

1.如果我有更好的方法来做到这一点,我会更新这个答案。

\n\n

2. 我不擅长写英文,所以这个答案可能会有很多语法错误。抱歉,我正在修复我所看到的内容。

\n